react-native-rectangle-doc-scanner 3.44.2 → 3.44.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/FullDocScanner.js
CHANGED
|
@@ -57,6 +57,7 @@ const FullDocScanner = ({ onResult, onClose, detectionConfig, overlayColor = '#3
|
|
|
57
57
|
const [processing, setProcessing] = (0, react_1.useState)(false);
|
|
58
58
|
const [croppedImageData, setCroppedImageData] = (0, react_1.useState)(null);
|
|
59
59
|
const [isGalleryOpen, setIsGalleryOpen] = (0, react_1.useState)(false);
|
|
60
|
+
const [rectangleDetected, setRectangleDetected] = (0, react_1.useState)(false);
|
|
60
61
|
const resolvedGridColor = gridColor ?? overlayColor;
|
|
61
62
|
const docScannerRef = (0, react_1.useRef)(null);
|
|
62
63
|
const manualCapturePending = (0, react_1.useRef)(false);
|
|
@@ -108,26 +109,34 @@ const FullDocScanner = ({ onResult, onClose, detectionConfig, overlayColor = '#3
|
|
|
108
109
|
console.log('[FullDocScanner] handleCapture called:', {
|
|
109
110
|
origin: document.origin,
|
|
110
111
|
path: document.path,
|
|
112
|
+
croppedPath: document.croppedPath,
|
|
113
|
+
initialPath: document.initialPath,
|
|
111
114
|
});
|
|
115
|
+
// Reset manual capture pending flag
|
|
112
116
|
if (manualCapturePending.current) {
|
|
117
|
+
console.log('[FullDocScanner] Resetting manualCapturePending');
|
|
113
118
|
manualCapturePending.current = false;
|
|
114
119
|
}
|
|
115
120
|
const normalizedDoc = normalizeCapturedDocument(document);
|
|
116
121
|
// Auto-capture: Use already cropped image, skip cropper
|
|
117
122
|
if (document.origin === 'auto' && normalizedDoc.croppedPath) {
|
|
118
|
-
console.log('[FullDocScanner] Auto-capture: using pre-cropped image');
|
|
123
|
+
console.log('[FullDocScanner] Auto-capture: using pre-cropped image', normalizedDoc.croppedPath);
|
|
119
124
|
setCroppedImageData({
|
|
120
125
|
path: normalizedDoc.croppedPath,
|
|
121
126
|
});
|
|
122
127
|
}
|
|
123
128
|
else {
|
|
124
129
|
// Manual capture or gallery: Open cropper
|
|
125
|
-
console.log('[FullDocScanner] Manual capture: opening cropper');
|
|
130
|
+
console.log('[FullDocScanner] Manual/Gallery capture: opening cropper with', normalizedDoc.path);
|
|
126
131
|
await openCropper(normalizedDoc.path);
|
|
127
132
|
}
|
|
128
133
|
}, [openCropper]);
|
|
129
134
|
const triggerManualCapture = (0, react_1.useCallback)(() => {
|
|
130
|
-
console.log('[FullDocScanner] triggerManualCapture called'
|
|
135
|
+
console.log('[FullDocScanner] triggerManualCapture called', {
|
|
136
|
+
processing,
|
|
137
|
+
manualCapturePending: manualCapturePending.current,
|
|
138
|
+
hasRef: !!docScannerRef.current,
|
|
139
|
+
});
|
|
131
140
|
if (processing) {
|
|
132
141
|
console.log('[FullDocScanner] Already processing, skipping manual capture');
|
|
133
142
|
return;
|
|
@@ -136,21 +145,33 @@ const FullDocScanner = ({ onResult, onClose, detectionConfig, overlayColor = '#3
|
|
|
136
145
|
console.log('[FullDocScanner] Manual capture already pending, skipping');
|
|
137
146
|
return;
|
|
138
147
|
}
|
|
139
|
-
|
|
148
|
+
if (!docScannerRef.current) {
|
|
149
|
+
console.error('[FullDocScanner] DocScanner ref not available');
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
console.log('[FullDocScanner] Starting manual capture');
|
|
140
153
|
manualCapturePending.current = true;
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
capturePromise
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
154
|
+
try {
|
|
155
|
+
const capturePromise = docScannerRef.current.capture();
|
|
156
|
+
console.log('[FullDocScanner] Capture promise:', capturePromise);
|
|
157
|
+
if (capturePromise && typeof capturePromise.then === 'function') {
|
|
158
|
+
capturePromise
|
|
159
|
+
.then((result) => {
|
|
160
|
+
console.log('[FullDocScanner] Manual capture success:', result);
|
|
161
|
+
manualCapturePending.current = false;
|
|
162
|
+
})
|
|
163
|
+
.catch((error) => {
|
|
164
|
+
console.error('[FullDocScanner] Manual capture failed:', error);
|
|
165
|
+
manualCapturePending.current = false;
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
else {
|
|
169
|
+
console.warn('[FullDocScanner] No promise returned from capture()');
|
|
148
170
|
manualCapturePending.current = false;
|
|
149
|
-
|
|
150
|
-
});
|
|
171
|
+
}
|
|
151
172
|
}
|
|
152
|
-
|
|
153
|
-
console.
|
|
173
|
+
catch (error) {
|
|
174
|
+
console.error('[FullDocScanner] Exception during capture:', error);
|
|
154
175
|
manualCapturePending.current = false;
|
|
155
176
|
}
|
|
156
177
|
}, [processing]);
|
|
@@ -193,7 +214,19 @@ const FullDocScanner = ({ onResult, onClose, detectionConfig, overlayColor = '#3
|
|
|
193
214
|
}
|
|
194
215
|
}, [croppedImageData, onResult]);
|
|
195
216
|
const handleRetake = (0, react_1.useCallback)(() => {
|
|
217
|
+
console.log('[FullDocScanner] Retake - clearing cropped image and resetting scanner');
|
|
196
218
|
setCroppedImageData(null);
|
|
219
|
+
setProcessing(false);
|
|
220
|
+
setRectangleDetected(false);
|
|
221
|
+
// Reset DocScanner state
|
|
222
|
+
if (docScannerRef.current?.reset) {
|
|
223
|
+
docScannerRef.current.reset();
|
|
224
|
+
}
|
|
225
|
+
}, []);
|
|
226
|
+
const handleRectangleDetect = (0, react_1.useCallback)((event) => {
|
|
227
|
+
// Update button color based on rectangle detection
|
|
228
|
+
const hasGoodRectangle = event.lastDetectionType === 0 && event.rectangleCoordinates !== null;
|
|
229
|
+
setRectangleDetected(hasGoodRectangle);
|
|
197
230
|
}, []);
|
|
198
231
|
return (react_1.default.createElement(react_native_1.View, { style: styles.container },
|
|
199
232
|
croppedImageData ? (
|
|
@@ -205,7 +238,7 @@ const FullDocScanner = ({ onResult, onClose, detectionConfig, overlayColor = '#3
|
|
|
205
238
|
react_1.default.createElement(react_native_1.Text, { style: styles.confirmButtonText }, mergedStrings.retake)),
|
|
206
239
|
react_1.default.createElement(react_native_1.TouchableOpacity, { style: [styles.confirmButton, styles.confirmButtonPrimary], onPress: handleConfirm, accessibilityLabel: mergedStrings.confirm, accessibilityRole: "button" },
|
|
207
240
|
react_1.default.createElement(react_native_1.Text, { style: styles.confirmButtonText }, mergedStrings.confirm))))) : (react_1.default.createElement(react_native_1.View, { style: styles.flex },
|
|
208
|
-
react_1.default.createElement(DocScanner_1.DocScanner, { ref: docScannerRef, autoCapture: !manualCapture && !isGalleryOpen, overlayColor: overlayColor, showGrid: showGrid, gridColor: resolvedGridColor, gridLineWidth: gridLineWidth, minStableFrames: minStableFrames ?? 6, detectionConfig: detectionConfig, onCapture: handleCapture, showManualCaptureButton: false },
|
|
241
|
+
react_1.default.createElement(DocScanner_1.DocScanner, { ref: docScannerRef, autoCapture: !manualCapture && !isGalleryOpen, overlayColor: overlayColor, showGrid: showGrid, gridColor: resolvedGridColor, gridLineWidth: gridLineWidth, minStableFrames: minStableFrames ?? 6, detectionConfig: detectionConfig, onCapture: handleCapture, onRectangleDetect: handleRectangleDetect, showManualCaptureButton: false },
|
|
209
242
|
react_1.default.createElement(react_native_1.View, { style: styles.overlayTop, pointerEvents: "box-none" },
|
|
210
243
|
react_1.default.createElement(react_native_1.TouchableOpacity, { style: styles.closeButton, onPress: handleClose, accessibilityLabel: mergedStrings.cancel, accessibilityRole: "button" },
|
|
211
244
|
react_1.default.createElement(react_native_1.Text, { style: styles.closeButtonLabel }, "\u00D7"))),
|
|
@@ -217,7 +250,10 @@ const FullDocScanner = ({ onResult, onClose, detectionConfig, overlayColor = '#3
|
|
|
217
250
|
enableGallery && (react_1.default.createElement(react_native_1.TouchableOpacity, { style: [styles.galleryButton, processing && styles.buttonDisabled], onPress: handleGalleryPick, disabled: processing, accessibilityLabel: mergedStrings.galleryButton, accessibilityRole: "button" },
|
|
218
251
|
react_1.default.createElement(react_native_1.Text, { style: styles.galleryButtonText }, "\uD83D\uDCC1"))),
|
|
219
252
|
react_1.default.createElement(react_native_1.TouchableOpacity, { style: [styles.shutterButton, processing && styles.buttonDisabled], onPress: triggerManualCapture, disabled: processing, accessibilityLabel: mergedStrings.manualHint, accessibilityRole: "button" },
|
|
220
|
-
react_1.default.createElement(react_native_1.View, { style:
|
|
253
|
+
react_1.default.createElement(react_native_1.View, { style: [
|
|
254
|
+
styles.shutterInner,
|
|
255
|
+
rectangleDetected && { backgroundColor: overlayColor }
|
|
256
|
+
] })))))),
|
|
221
257
|
processing && (react_1.default.createElement(react_native_1.View, { style: styles.processingOverlay },
|
|
222
258
|
react_1.default.createElement(react_native_1.ActivityIndicator, { size: "large", color: overlayColor }),
|
|
223
259
|
mergedStrings.processing && (react_1.default.createElement(react_native_1.Text, { style: styles.processingText }, mergedStrings.processing))))));
|
package/package.json
CHANGED
package/src/FullDocScanner.tsx
CHANGED
|
@@ -82,6 +82,7 @@ export const FullDocScanner: React.FC<FullDocScannerProps> = ({
|
|
|
82
82
|
const [processing, setProcessing] = useState(false);
|
|
83
83
|
const [croppedImageData, setCroppedImageData] = useState<{path: string; base64?: string} | null>(null);
|
|
84
84
|
const [isGalleryOpen, setIsGalleryOpen] = useState(false);
|
|
85
|
+
const [rectangleDetected, setRectangleDetected] = useState(false);
|
|
85
86
|
const resolvedGridColor = gridColor ?? overlayColor;
|
|
86
87
|
const docScannerRef = useRef<DocScannerHandle | null>(null);
|
|
87
88
|
const manualCapturePending = useRef(false);
|
|
@@ -151,9 +152,13 @@ export const FullDocScanner: React.FC<FullDocScannerProps> = ({
|
|
|
151
152
|
console.log('[FullDocScanner] handleCapture called:', {
|
|
152
153
|
origin: document.origin,
|
|
153
154
|
path: document.path,
|
|
155
|
+
croppedPath: document.croppedPath,
|
|
156
|
+
initialPath: document.initialPath,
|
|
154
157
|
});
|
|
155
158
|
|
|
159
|
+
// Reset manual capture pending flag
|
|
156
160
|
if (manualCapturePending.current) {
|
|
161
|
+
console.log('[FullDocScanner] Resetting manualCapturePending');
|
|
157
162
|
manualCapturePending.current = false;
|
|
158
163
|
}
|
|
159
164
|
|
|
@@ -161,13 +166,13 @@ export const FullDocScanner: React.FC<FullDocScannerProps> = ({
|
|
|
161
166
|
|
|
162
167
|
// Auto-capture: Use already cropped image, skip cropper
|
|
163
168
|
if (document.origin === 'auto' && normalizedDoc.croppedPath) {
|
|
164
|
-
console.log('[FullDocScanner] Auto-capture: using pre-cropped image');
|
|
169
|
+
console.log('[FullDocScanner] Auto-capture: using pre-cropped image', normalizedDoc.croppedPath);
|
|
165
170
|
setCroppedImageData({
|
|
166
171
|
path: normalizedDoc.croppedPath,
|
|
167
172
|
});
|
|
168
173
|
} else {
|
|
169
174
|
// Manual capture or gallery: Open cropper
|
|
170
|
-
console.log('[FullDocScanner] Manual capture: opening cropper');
|
|
175
|
+
console.log('[FullDocScanner] Manual/Gallery capture: opening cropper with', normalizedDoc.path);
|
|
171
176
|
await openCropper(normalizedDoc.path);
|
|
172
177
|
}
|
|
173
178
|
},
|
|
@@ -175,31 +180,50 @@ export const FullDocScanner: React.FC<FullDocScannerProps> = ({
|
|
|
175
180
|
);
|
|
176
181
|
|
|
177
182
|
const triggerManualCapture = useCallback(() => {
|
|
178
|
-
console.log('[FullDocScanner] triggerManualCapture called'
|
|
183
|
+
console.log('[FullDocScanner] triggerManualCapture called', {
|
|
184
|
+
processing,
|
|
185
|
+
manualCapturePending: manualCapturePending.current,
|
|
186
|
+
hasRef: !!docScannerRef.current,
|
|
187
|
+
});
|
|
188
|
+
|
|
179
189
|
if (processing) {
|
|
180
190
|
console.log('[FullDocScanner] Already processing, skipping manual capture');
|
|
181
191
|
return;
|
|
182
192
|
}
|
|
193
|
+
|
|
183
194
|
if (manualCapturePending.current) {
|
|
184
195
|
console.log('[FullDocScanner] Manual capture already pending, skipping');
|
|
185
196
|
return;
|
|
186
197
|
}
|
|
187
198
|
|
|
188
|
-
|
|
199
|
+
if (!docScannerRef.current) {
|
|
200
|
+
console.error('[FullDocScanner] DocScanner ref not available');
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
console.log('[FullDocScanner] Starting manual capture');
|
|
189
205
|
manualCapturePending.current = true;
|
|
190
206
|
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
capturePromise
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
207
|
+
try {
|
|
208
|
+
const capturePromise = docScannerRef.current.capture();
|
|
209
|
+
console.log('[FullDocScanner] Capture promise:', capturePromise);
|
|
210
|
+
|
|
211
|
+
if (capturePromise && typeof capturePromise.then === 'function') {
|
|
212
|
+
capturePromise
|
|
213
|
+
.then((result) => {
|
|
214
|
+
console.log('[FullDocScanner] Manual capture success:', result);
|
|
215
|
+
manualCapturePending.current = false;
|
|
216
|
+
})
|
|
217
|
+
.catch((error: unknown) => {
|
|
218
|
+
console.error('[FullDocScanner] Manual capture failed:', error);
|
|
219
|
+
manualCapturePending.current = false;
|
|
220
|
+
});
|
|
221
|
+
} else {
|
|
222
|
+
console.warn('[FullDocScanner] No promise returned from capture()');
|
|
223
|
+
manualCapturePending.current = false;
|
|
224
|
+
}
|
|
225
|
+
} catch (error) {
|
|
226
|
+
console.error('[FullDocScanner] Exception during capture:', error);
|
|
203
227
|
manualCapturePending.current = false;
|
|
204
228
|
}
|
|
205
229
|
}, [processing]);
|
|
@@ -253,7 +277,20 @@ export const FullDocScanner: React.FC<FullDocScannerProps> = ({
|
|
|
253
277
|
}, [croppedImageData, onResult]);
|
|
254
278
|
|
|
255
279
|
const handleRetake = useCallback(() => {
|
|
280
|
+
console.log('[FullDocScanner] Retake - clearing cropped image and resetting scanner');
|
|
256
281
|
setCroppedImageData(null);
|
|
282
|
+
setProcessing(false);
|
|
283
|
+
setRectangleDetected(false);
|
|
284
|
+
// Reset DocScanner state
|
|
285
|
+
if (docScannerRef.current?.reset) {
|
|
286
|
+
docScannerRef.current.reset();
|
|
287
|
+
}
|
|
288
|
+
}, []);
|
|
289
|
+
|
|
290
|
+
const handleRectangleDetect = useCallback((event: any) => {
|
|
291
|
+
// Update button color based on rectangle detection
|
|
292
|
+
const hasGoodRectangle = event.lastDetectionType === 0 && event.rectangleCoordinates !== null;
|
|
293
|
+
setRectangleDetected(hasGoodRectangle);
|
|
257
294
|
}, []);
|
|
258
295
|
|
|
259
296
|
return (
|
|
@@ -297,6 +334,7 @@ export const FullDocScanner: React.FC<FullDocScannerProps> = ({
|
|
|
297
334
|
minStableFrames={minStableFrames ?? 6}
|
|
298
335
|
detectionConfig={detectionConfig}
|
|
299
336
|
onCapture={handleCapture}
|
|
337
|
+
onRectangleDetect={handleRectangleDetect}
|
|
300
338
|
showManualCaptureButton={false}
|
|
301
339
|
>
|
|
302
340
|
<View style={styles.overlayTop} pointerEvents="box-none">
|
|
@@ -340,7 +378,10 @@ export const FullDocScanner: React.FC<FullDocScannerProps> = ({
|
|
|
340
378
|
accessibilityLabel={mergedStrings.manualHint}
|
|
341
379
|
accessibilityRole="button"
|
|
342
380
|
>
|
|
343
|
-
<View style={
|
|
381
|
+
<View style={[
|
|
382
|
+
styles.shutterInner,
|
|
383
|
+
rectangleDetected && { backgroundColor: overlayColor }
|
|
384
|
+
]} />
|
|
344
385
|
</TouchableOpacity>
|
|
345
386
|
</View>
|
|
346
387
|
</DocScanner>
|
|
@@ -474,6 +474,12 @@
|
|
|
474
474
|
|
|
475
475
|
[weakSelf hideGLKView:NO completion:nil];
|
|
476
476
|
completionHandler(image, initialImage, rectangleFeature);
|
|
477
|
+
} else {
|
|
478
|
+
// No rectangle detected, return original image
|
|
479
|
+
NSLog(@"[IPDFCameraViewController] No rectangle detected during manual capture, returning original image");
|
|
480
|
+
[weakSelf hideGLKView:NO completion:nil];
|
|
481
|
+
UIImage *initialImage = [UIImage imageWithData:imageData];
|
|
482
|
+
completionHandler(initialImage, initialImage, nil);
|
|
477
483
|
}
|
|
478
484
|
} else {
|
|
479
485
|
[weakSelf hideGLKView:NO completion:nil];
|