react-native-rectangle-doc-scanner 3.53.0 → 3.55.0
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/DocScanner.js +2 -1
- package/dist/FullDocScanner.js +39 -7
- package/package.json +1 -1
- package/src/DocScanner.tsx +4 -2
- package/src/FullDocScanner.tsx +42 -9
package/dist/DocScanner.js
CHANGED
|
@@ -205,8 +205,9 @@ exports.DocScanner = (0, react_1.forwardRef)(({ onCapture, overlayColor = DEFAUL
|
|
|
205
205
|
}), [capture]);
|
|
206
206
|
const overlayPolygon = detectedRectangle?.rectangleOnScreen ?? detectedRectangle?.rectangleCoordinates ?? null;
|
|
207
207
|
const overlayIsActive = autoCapture ? isAutoCapturing : (detectedRectangle?.stableCounter ?? 0) > 0;
|
|
208
|
+
const detectionThreshold = autoCapture ? minStableFrames : 9999;
|
|
208
209
|
return (react_1.default.createElement(react_native_1.View, { style: styles.container },
|
|
209
|
-
react_1.default.createElement(react_native_document_scanner_1.default, { ref: scannerRef, style: styles.scanner, detectionCountBeforeCapture:
|
|
210
|
+
react_1.default.createElement(react_native_document_scanner_1.default, { ref: scannerRef, style: styles.scanner, detectionCountBeforeCapture: detectionThreshold, overlayColor: overlayColor, enableTorch: enableTorch, quality: normalizedQuality, useBase64: useBase64, manualOnly: !autoCapture, detectionConfig: detectionConfig, onPictureTaken: handlePictureTaken, onError: handleError, onRectangleDetect: handleRectangleDetect }),
|
|
210
211
|
showGrid && overlayPolygon && (react_1.default.createElement(overlay_1.ScannerOverlay, { active: overlayIsActive, color: gridColor ?? overlayColor, lineWidth: gridLineWidth, polygon: overlayPolygon })),
|
|
211
212
|
showManualCaptureButton && (react_1.default.createElement(react_native_1.TouchableOpacity, { style: styles.button, onPress: handleManualCapture })),
|
|
212
213
|
children));
|
package/dist/FullDocScanner.js
CHANGED
|
@@ -61,6 +61,8 @@ const FullDocScanner = ({ onResult, onClose, detectionConfig, overlayColor = '#3
|
|
|
61
61
|
const resolvedGridColor = gridColor ?? overlayColor;
|
|
62
62
|
const docScannerRef = (0, react_1.useRef)(null);
|
|
63
63
|
const captureModeRef = (0, react_1.useRef)(null);
|
|
64
|
+
const captureInProgressRef = (0, react_1.useRef)(false);
|
|
65
|
+
const rectangleTimeoutRef = (0, react_1.useRef)(null);
|
|
64
66
|
const mergedStrings = (0, react_1.useMemo)(() => ({
|
|
65
67
|
captureHint: strings?.captureHint,
|
|
66
68
|
manualHint: strings?.manualHint,
|
|
@@ -122,6 +124,7 @@ const FullDocScanner = ({ onResult, onClose, detectionConfig, overlayColor = '#3
|
|
|
122
124
|
initialPath: document.initialPath,
|
|
123
125
|
captureMode: captureModeRef.current,
|
|
124
126
|
});
|
|
127
|
+
captureInProgressRef.current = false;
|
|
125
128
|
if (document.origin === 'auto') {
|
|
126
129
|
console.log('[FullDocScanner] Ignoring auto capture result');
|
|
127
130
|
return;
|
|
@@ -150,33 +153,39 @@ const FullDocScanner = ({ onResult, onClose, detectionConfig, overlayColor = '#3
|
|
|
150
153
|
await openCropper(normalizedDoc.path);
|
|
151
154
|
}, [openCropper]);
|
|
152
155
|
const triggerManualCapture = (0, react_1.useCallback)(() => {
|
|
156
|
+
const scannerInstance = docScannerRef.current;
|
|
157
|
+
const hasScanner = !!scannerInstance;
|
|
153
158
|
console.log('[FullDocScanner] triggerManualCapture called', {
|
|
154
159
|
processing,
|
|
155
|
-
hasRef:
|
|
160
|
+
hasRef: hasScanner,
|
|
156
161
|
rectangleDetected,
|
|
157
162
|
currentCaptureMode: captureModeRef.current,
|
|
163
|
+
captureInProgress: captureInProgressRef.current,
|
|
158
164
|
});
|
|
159
165
|
if (processing) {
|
|
160
166
|
console.log('[FullDocScanner] Already processing, skipping manual capture');
|
|
161
167
|
return;
|
|
162
168
|
}
|
|
163
|
-
|
|
164
|
-
if (captureModeRef.current !== null) {
|
|
169
|
+
if (captureInProgressRef.current) {
|
|
165
170
|
console.log('[FullDocScanner] Capture already in progress, skipping');
|
|
166
171
|
return;
|
|
167
172
|
}
|
|
168
|
-
if (!
|
|
173
|
+
if (!hasScanner) {
|
|
169
174
|
console.error('[FullDocScanner] DocScanner ref not available');
|
|
170
175
|
return;
|
|
171
176
|
}
|
|
172
177
|
console.log('[FullDocScanner] Starting manual capture, grid detected:', rectangleDetected);
|
|
173
|
-
|
|
174
|
-
|
|
178
|
+
const captureMode = rectangleDetected ? 'grid' : 'no-grid';
|
|
179
|
+
captureModeRef.current = captureMode;
|
|
180
|
+
captureInProgressRef.current = true;
|
|
181
|
+
scannerInstance.capture()
|
|
175
182
|
.then((result) => {
|
|
176
183
|
console.log('[FullDocScanner] Manual capture success:', result);
|
|
184
|
+
captureInProgressRef.current = false;
|
|
177
185
|
})
|
|
178
186
|
.catch((error) => {
|
|
179
187
|
captureModeRef.current = null;
|
|
188
|
+
captureInProgressRef.current = false;
|
|
180
189
|
console.error('[FullDocScanner] Manual capture failed:', error);
|
|
181
190
|
if (error instanceof Error && error.message !== 'capture_in_progress') {
|
|
182
191
|
emitError(error, 'Failed to capture image.');
|
|
@@ -227,6 +236,11 @@ const FullDocScanner = ({ onResult, onClose, detectionConfig, overlayColor = '#3
|
|
|
227
236
|
setProcessing(false);
|
|
228
237
|
setRectangleDetected(false);
|
|
229
238
|
captureModeRef.current = null;
|
|
239
|
+
captureInProgressRef.current = false;
|
|
240
|
+
if (rectangleTimeoutRef.current) {
|
|
241
|
+
clearTimeout(rectangleTimeoutRef.current);
|
|
242
|
+
rectangleTimeoutRef.current = null;
|
|
243
|
+
}
|
|
230
244
|
// Reset DocScanner state
|
|
231
245
|
if (docScannerRef.current?.reset) {
|
|
232
246
|
docScannerRef.current.reset();
|
|
@@ -235,7 +249,20 @@ const FullDocScanner = ({ onResult, onClose, detectionConfig, overlayColor = '#3
|
|
|
235
249
|
const handleRectangleDetect = (0, react_1.useCallback)((event) => {
|
|
236
250
|
const stableCounter = event.stableCounter ?? 0;
|
|
237
251
|
const hasRectangle = Boolean(event.rectangleOnScreen ?? event.rectangleCoordinates);
|
|
238
|
-
const isGoodRectangle = event.lastDetectionType === 0
|
|
252
|
+
const isGoodRectangle = hasRectangle && event.lastDetectionType === 0;
|
|
253
|
+
if (hasRectangle) {
|
|
254
|
+
if (rectangleTimeoutRef.current) {
|
|
255
|
+
clearTimeout(rectangleTimeoutRef.current);
|
|
256
|
+
}
|
|
257
|
+
rectangleTimeoutRef.current = setTimeout(() => {
|
|
258
|
+
rectangleTimeoutRef.current = null;
|
|
259
|
+
setRectangleDetected(false);
|
|
260
|
+
}, 300);
|
|
261
|
+
}
|
|
262
|
+
else if (rectangleTimeoutRef.current) {
|
|
263
|
+
clearTimeout(rectangleTimeoutRef.current);
|
|
264
|
+
rectangleTimeoutRef.current = null;
|
|
265
|
+
}
|
|
239
266
|
setRectangleDetected((prev) => {
|
|
240
267
|
if (prev !== isGoodRectangle) {
|
|
241
268
|
console.log('[FullDocScanner] Rectangle detection update', {
|
|
@@ -248,6 +275,11 @@ const FullDocScanner = ({ onResult, onClose, detectionConfig, overlayColor = '#3
|
|
|
248
275
|
return isGoodRectangle;
|
|
249
276
|
});
|
|
250
277
|
}, []);
|
|
278
|
+
(0, react_1.useEffect)(() => () => {
|
|
279
|
+
if (rectangleTimeoutRef.current) {
|
|
280
|
+
clearTimeout(rectangleTimeoutRef.current);
|
|
281
|
+
}
|
|
282
|
+
}, []);
|
|
251
283
|
return (react_1.default.createElement(react_native_1.View, { style: styles.container },
|
|
252
284
|
croppedImageData ? (
|
|
253
285
|
// check_DP: Show confirmation screen
|
package/package.json
CHANGED
package/src/DocScanner.tsx
CHANGED
|
@@ -293,12 +293,14 @@ export const DocScanner = forwardRef<DocScannerHandle, Props>(
|
|
|
293
293
|
const overlayPolygon = detectedRectangle?.rectangleOnScreen ?? detectedRectangle?.rectangleCoordinates ?? null;
|
|
294
294
|
const overlayIsActive = autoCapture ? isAutoCapturing : (detectedRectangle?.stableCounter ?? 0) > 0;
|
|
295
295
|
|
|
296
|
-
|
|
296
|
+
const detectionThreshold = autoCapture ? minStableFrames : 9999;
|
|
297
|
+
|
|
298
|
+
return (
|
|
297
299
|
<View style={styles.container}>
|
|
298
300
|
<DocumentScanner
|
|
299
301
|
ref={scannerRef}
|
|
300
302
|
style={styles.scanner}
|
|
301
|
-
detectionCountBeforeCapture={
|
|
303
|
+
detectionCountBeforeCapture={detectionThreshold}
|
|
302
304
|
overlayColor={overlayColor}
|
|
303
305
|
enableTorch={enableTorch}
|
|
304
306
|
quality={normalizedQuality}
|
package/src/FullDocScanner.tsx
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React, { useCallback, useMemo, useRef, useState } from 'react';
|
|
1
|
+
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
2
2
|
import {
|
|
3
3
|
ActivityIndicator,
|
|
4
4
|
Alert,
|
|
@@ -89,6 +89,8 @@ export const FullDocScanner: React.FC<FullDocScannerProps> = ({
|
|
|
89
89
|
const resolvedGridColor = gridColor ?? overlayColor;
|
|
90
90
|
const docScannerRef = useRef<DocScannerHandle | null>(null);
|
|
91
91
|
const captureModeRef = useRef<'grid' | 'no-grid' | null>(null);
|
|
92
|
+
const captureInProgressRef = useRef(false);
|
|
93
|
+
const rectangleTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);
|
|
92
94
|
|
|
93
95
|
const mergedStrings = useMemo(
|
|
94
96
|
() => ({
|
|
@@ -169,6 +171,8 @@ export const FullDocScanner: React.FC<FullDocScannerProps> = ({
|
|
|
169
171
|
captureMode: captureModeRef.current,
|
|
170
172
|
});
|
|
171
173
|
|
|
174
|
+
captureInProgressRef.current = false;
|
|
175
|
+
|
|
172
176
|
if (document.origin === 'auto') {
|
|
173
177
|
console.log('[FullDocScanner] Ignoring auto capture result');
|
|
174
178
|
return;
|
|
@@ -207,11 +211,14 @@ export const FullDocScanner: React.FC<FullDocScannerProps> = ({
|
|
|
207
211
|
);
|
|
208
212
|
|
|
209
213
|
const triggerManualCapture = useCallback(() => {
|
|
214
|
+
const scannerInstance = docScannerRef.current;
|
|
215
|
+
const hasScanner = !!scannerInstance;
|
|
210
216
|
console.log('[FullDocScanner] triggerManualCapture called', {
|
|
211
217
|
processing,
|
|
212
|
-
hasRef:
|
|
218
|
+
hasRef: hasScanner,
|
|
213
219
|
rectangleDetected,
|
|
214
220
|
currentCaptureMode: captureModeRef.current,
|
|
221
|
+
captureInProgress: captureInProgressRef.current,
|
|
215
222
|
});
|
|
216
223
|
|
|
217
224
|
if (processing) {
|
|
@@ -219,27 +226,30 @@ export const FullDocScanner: React.FC<FullDocScannerProps> = ({
|
|
|
219
226
|
return;
|
|
220
227
|
}
|
|
221
228
|
|
|
222
|
-
|
|
223
|
-
if (captureModeRef.current !== null) {
|
|
229
|
+
if (captureInProgressRef.current) {
|
|
224
230
|
console.log('[FullDocScanner] Capture already in progress, skipping');
|
|
225
231
|
return;
|
|
226
232
|
}
|
|
227
233
|
|
|
228
|
-
if (!
|
|
234
|
+
if (!hasScanner) {
|
|
229
235
|
console.error('[FullDocScanner] DocScanner ref not available');
|
|
230
236
|
return;
|
|
231
237
|
}
|
|
232
238
|
|
|
233
239
|
console.log('[FullDocScanner] Starting manual capture, grid detected:', rectangleDetected);
|
|
234
240
|
|
|
235
|
-
|
|
241
|
+
const captureMode = rectangleDetected ? 'grid' : 'no-grid';
|
|
242
|
+
captureModeRef.current = captureMode;
|
|
243
|
+
captureInProgressRef.current = true;
|
|
236
244
|
|
|
237
|
-
|
|
245
|
+
scannerInstance.capture()
|
|
238
246
|
.then((result) => {
|
|
239
247
|
console.log('[FullDocScanner] Manual capture success:', result);
|
|
248
|
+
captureInProgressRef.current = false;
|
|
240
249
|
})
|
|
241
250
|
.catch((error: unknown) => {
|
|
242
251
|
captureModeRef.current = null;
|
|
252
|
+
captureInProgressRef.current = false;
|
|
243
253
|
console.error('[FullDocScanner] Manual capture failed:', error);
|
|
244
254
|
if (error instanceof Error && error.message !== 'capture_in_progress') {
|
|
245
255
|
emitError(
|
|
@@ -304,6 +314,11 @@ export const FullDocScanner: React.FC<FullDocScannerProps> = ({
|
|
|
304
314
|
setProcessing(false);
|
|
305
315
|
setRectangleDetected(false);
|
|
306
316
|
captureModeRef.current = null;
|
|
317
|
+
captureInProgressRef.current = false;
|
|
318
|
+
if (rectangleTimeoutRef.current) {
|
|
319
|
+
clearTimeout(rectangleTimeoutRef.current);
|
|
320
|
+
rectangleTimeoutRef.current = null;
|
|
321
|
+
}
|
|
307
322
|
// Reset DocScanner state
|
|
308
323
|
if (docScannerRef.current?.reset) {
|
|
309
324
|
docScannerRef.current.reset();
|
|
@@ -313,7 +328,20 @@ export const FullDocScanner: React.FC<FullDocScannerProps> = ({
|
|
|
313
328
|
const handleRectangleDetect = useCallback((event: RectangleDetectEvent) => {
|
|
314
329
|
const stableCounter = event.stableCounter ?? 0;
|
|
315
330
|
const hasRectangle = Boolean(event.rectangleOnScreen ?? event.rectangleCoordinates);
|
|
316
|
-
const isGoodRectangle = event.lastDetectionType === 0
|
|
331
|
+
const isGoodRectangle = hasRectangle && event.lastDetectionType === 0;
|
|
332
|
+
|
|
333
|
+
if (hasRectangle) {
|
|
334
|
+
if (rectangleTimeoutRef.current) {
|
|
335
|
+
clearTimeout(rectangleTimeoutRef.current);
|
|
336
|
+
}
|
|
337
|
+
rectangleTimeoutRef.current = setTimeout(() => {
|
|
338
|
+
rectangleTimeoutRef.current = null;
|
|
339
|
+
setRectangleDetected(false);
|
|
340
|
+
}, 300);
|
|
341
|
+
} else if (rectangleTimeoutRef.current) {
|
|
342
|
+
clearTimeout(rectangleTimeoutRef.current);
|
|
343
|
+
rectangleTimeoutRef.current = null;
|
|
344
|
+
}
|
|
317
345
|
|
|
318
346
|
setRectangleDetected((prev) => {
|
|
319
347
|
if (prev !== isGoodRectangle) {
|
|
@@ -324,11 +352,16 @@ export const FullDocScanner: React.FC<FullDocScannerProps> = ({
|
|
|
324
352
|
isGoodRectangle,
|
|
325
353
|
});
|
|
326
354
|
}
|
|
327
|
-
|
|
328
355
|
return isGoodRectangle;
|
|
329
356
|
});
|
|
330
357
|
}, []);
|
|
331
358
|
|
|
359
|
+
useEffect(() => () => {
|
|
360
|
+
if (rectangleTimeoutRef.current) {
|
|
361
|
+
clearTimeout(rectangleTimeoutRef.current);
|
|
362
|
+
}
|
|
363
|
+
}, []);
|
|
364
|
+
|
|
332
365
|
return (
|
|
333
366
|
<View style={styles.container}>
|
|
334
367
|
{croppedImageData ? (
|