react-native-rectangle-doc-scanner 3.60.0 → 3.61.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/FullDocScanner.js +49 -29
- package/package.json +1 -1
- package/src/FullDocScanner.tsx +54 -32
package/dist/FullDocScanner.js
CHANGED
|
@@ -83,12 +83,15 @@ const FullDocScanner = ({ onResult, onClose, detectionConfig, overlayColor = '#3
|
|
|
83
83
|
try {
|
|
84
84
|
console.log('[FullDocScanner] openCropper called with path:', imagePath);
|
|
85
85
|
setProcessing(true);
|
|
86
|
-
//
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
86
|
+
// Clean path - remove file:// prefix for react-native-image-crop-picker
|
|
87
|
+
// The library handles the prefix internally and double prefixing causes issues
|
|
88
|
+
let cleanPath = imagePath;
|
|
89
|
+
if (cleanPath.startsWith('file://')) {
|
|
90
|
+
cleanPath = cleanPath.replace('file://', '');
|
|
91
|
+
}
|
|
92
|
+
console.log('[FullDocScanner] Clean path for cropper:', cleanPath);
|
|
93
|
+
const croppedImage = await react_native_image_crop_picker_1.default.openCropper({
|
|
94
|
+
path: cleanPath,
|
|
92
95
|
mediaType: 'photo',
|
|
93
96
|
width: cropWidth,
|
|
94
97
|
height: cropHeight,
|
|
@@ -98,10 +101,6 @@ const FullDocScanner = ({ onResult, onClose, detectionConfig, overlayColor = '#3
|
|
|
98
101
|
includeBase64: true,
|
|
99
102
|
compressImageQuality: 0.9,
|
|
100
103
|
});
|
|
101
|
-
const timeoutPromise = new Promise((_, reject) => {
|
|
102
|
-
setTimeout(() => reject(new Error('Cropper timeout after 30 seconds')), 30000);
|
|
103
|
-
});
|
|
104
|
-
const croppedImage = await Promise.race([cropperPromise, timeoutPromise]);
|
|
105
104
|
console.log('[FullDocScanner] Cropper returned:', {
|
|
106
105
|
path: croppedImage.path,
|
|
107
106
|
hasBase64: !!croppedImage.data,
|
|
@@ -134,14 +133,16 @@ const FullDocScanner = ({ onResult, onClose, detectionConfig, overlayColor = '#3
|
|
|
134
133
|
croppedPath: document.croppedPath,
|
|
135
134
|
initialPath: document.initialPath,
|
|
136
135
|
captureMode: captureModeRef.current,
|
|
136
|
+
captureInProgress: captureInProgressRef.current,
|
|
137
137
|
});
|
|
138
|
-
captureInProgressRef.current = false;
|
|
139
138
|
const captureMode = captureModeRef.current;
|
|
139
|
+
// Reset capture state
|
|
140
|
+
captureInProgressRef.current = false;
|
|
141
|
+
captureModeRef.current = null;
|
|
140
142
|
if (!captureMode) {
|
|
141
143
|
console.warn('[FullDocScanner] Missing capture mode for capture result, ignoring');
|
|
142
144
|
return;
|
|
143
145
|
}
|
|
144
|
-
captureModeRef.current = null;
|
|
145
146
|
const normalizedDoc = normalizeCapturedDocument(document);
|
|
146
147
|
if (captureMode === 'no-grid') {
|
|
147
148
|
console.log('[FullDocScanner] No grid at capture button press: opening cropper for manual selection');
|
|
@@ -184,12 +185,27 @@ const FullDocScanner = ({ onResult, onClose, detectionConfig, overlayColor = '#3
|
|
|
184
185
|
const captureMode = rectangleDetected ? 'grid' : 'no-grid';
|
|
185
186
|
captureModeRef.current = captureMode;
|
|
186
187
|
captureInProgressRef.current = true;
|
|
188
|
+
// Add timeout to reset state if capture hangs
|
|
189
|
+
const captureTimeout = setTimeout(() => {
|
|
190
|
+
if (captureInProgressRef.current) {
|
|
191
|
+
console.error('[FullDocScanner] Capture timeout - resetting state');
|
|
192
|
+
captureModeRef.current = null;
|
|
193
|
+
captureInProgressRef.current = false;
|
|
194
|
+
emitError(new Error('Capture timeout'), 'Capture timed out. Please try again.');
|
|
195
|
+
}
|
|
196
|
+
}, 10000);
|
|
187
197
|
scannerInstance.capture()
|
|
188
198
|
.then((result) => {
|
|
189
|
-
|
|
190
|
-
|
|
199
|
+
clearTimeout(captureTimeout);
|
|
200
|
+
console.log('[FullDocScanner] Manual capture promise resolved:', {
|
|
201
|
+
hasResult: !!result,
|
|
202
|
+
croppedImage: result?.croppedImage,
|
|
203
|
+
initialImage: result?.initialImage,
|
|
204
|
+
});
|
|
205
|
+
// Note: captureInProgressRef is reset in handleCapture
|
|
191
206
|
})
|
|
192
207
|
.catch((error) => {
|
|
208
|
+
clearTimeout(captureTimeout);
|
|
193
209
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
194
210
|
console.error('[FullDocScanner] Manual capture failed:', errorMessage, error);
|
|
195
211
|
captureModeRef.current = null;
|
|
@@ -265,29 +281,33 @@ const FullDocScanner = ({ onResult, onClose, detectionConfig, overlayColor = '#3
|
|
|
265
281
|
const stableCounter = event.stableCounter ?? 0;
|
|
266
282
|
const hasRectangle = Boolean(event.rectangleOnScreen ?? event.rectangleCoordinates);
|
|
267
283
|
const isGoodRectangle = hasRectangle && event.lastDetectionType === 0;
|
|
268
|
-
|
|
284
|
+
// Clear timeout immediately when rectangle is lost
|
|
285
|
+
if (!hasRectangle || !isGoodRectangle) {
|
|
286
|
+
if (rectangleTimeoutRef.current) {
|
|
287
|
+
clearTimeout(rectangleTimeoutRef.current);
|
|
288
|
+
rectangleTimeoutRef.current = null;
|
|
289
|
+
}
|
|
290
|
+
setRectangleDetected(false);
|
|
291
|
+
}
|
|
292
|
+
else {
|
|
293
|
+
// Rectangle detected - clear any existing timeout
|
|
269
294
|
if (rectangleTimeoutRef.current) {
|
|
270
295
|
clearTimeout(rectangleTimeoutRef.current);
|
|
271
296
|
}
|
|
297
|
+
setRectangleDetected(true);
|
|
298
|
+
// Set timeout to clear rectangle after brief period of no updates
|
|
272
299
|
rectangleTimeoutRef.current = setTimeout(() => {
|
|
273
300
|
rectangleTimeoutRef.current = null;
|
|
274
301
|
setRectangleDetected(false);
|
|
302
|
+
console.log('[FullDocScanner] Rectangle timeout - clearing detection');
|
|
275
303
|
}, 300);
|
|
276
304
|
}
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
console.log('[FullDocScanner] Rectangle detection update', {
|
|
284
|
-
lastDetectionType: event.lastDetectionType,
|
|
285
|
-
stableCounter,
|
|
286
|
-
hasRectangle,
|
|
287
|
-
isGoodRectangle,
|
|
288
|
-
});
|
|
289
|
-
}
|
|
290
|
-
return isGoodRectangle;
|
|
305
|
+
console.log('[FullDocScanner] Rectangle detection update', {
|
|
306
|
+
lastDetectionType: event.lastDetectionType,
|
|
307
|
+
stableCounter,
|
|
308
|
+
hasRectangle,
|
|
309
|
+
isGoodRectangle,
|
|
310
|
+
rectangleDetected: isGoodRectangle,
|
|
291
311
|
});
|
|
292
312
|
}, []);
|
|
293
313
|
(0, react_1.useEffect)(() => () => {
|
package/package.json
CHANGED
package/src/FullDocScanner.tsx
CHANGED
|
@@ -122,13 +122,16 @@ export const FullDocScanner: React.FC<FullDocScannerProps> = ({
|
|
|
122
122
|
console.log('[FullDocScanner] openCropper called with path:', imagePath);
|
|
123
123
|
setProcessing(true);
|
|
124
124
|
|
|
125
|
-
//
|
|
126
|
-
|
|
127
|
-
|
|
125
|
+
// Clean path - remove file:// prefix for react-native-image-crop-picker
|
|
126
|
+
// The library handles the prefix internally and double prefixing causes issues
|
|
127
|
+
let cleanPath = imagePath;
|
|
128
|
+
if (cleanPath.startsWith('file://')) {
|
|
129
|
+
cleanPath = cleanPath.replace('file://', '');
|
|
130
|
+
}
|
|
131
|
+
console.log('[FullDocScanner] Clean path for cropper:', cleanPath);
|
|
128
132
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
path: normalizedPath,
|
|
133
|
+
const croppedImage = await ImageCropPicker.openCropper({
|
|
134
|
+
path: cleanPath,
|
|
132
135
|
mediaType: 'photo',
|
|
133
136
|
width: cropWidth,
|
|
134
137
|
height: cropHeight,
|
|
@@ -139,12 +142,6 @@ export const FullDocScanner: React.FC<FullDocScannerProps> = ({
|
|
|
139
142
|
compressImageQuality: 0.9,
|
|
140
143
|
});
|
|
141
144
|
|
|
142
|
-
const timeoutPromise = new Promise((_, reject) => {
|
|
143
|
-
setTimeout(() => reject(new Error('Cropper timeout after 30 seconds')), 30000);
|
|
144
|
-
});
|
|
145
|
-
|
|
146
|
-
const croppedImage = await Promise.race([cropperPromise, timeoutPromise]) as any;
|
|
147
|
-
|
|
148
145
|
console.log('[FullDocScanner] Cropper returned:', {
|
|
149
146
|
path: croppedImage.path,
|
|
150
147
|
hasBase64: !!croppedImage.data,
|
|
@@ -186,19 +183,20 @@ export const FullDocScanner: React.FC<FullDocScannerProps> = ({
|
|
|
186
183
|
croppedPath: document.croppedPath,
|
|
187
184
|
initialPath: document.initialPath,
|
|
188
185
|
captureMode: captureModeRef.current,
|
|
186
|
+
captureInProgress: captureInProgressRef.current,
|
|
189
187
|
});
|
|
190
188
|
|
|
191
|
-
captureInProgressRef.current = false;
|
|
192
|
-
|
|
193
189
|
const captureMode = captureModeRef.current;
|
|
194
190
|
|
|
191
|
+
// Reset capture state
|
|
192
|
+
captureInProgressRef.current = false;
|
|
193
|
+
captureModeRef.current = null;
|
|
194
|
+
|
|
195
195
|
if (!captureMode) {
|
|
196
196
|
console.warn('[FullDocScanner] Missing capture mode for capture result, ignoring');
|
|
197
197
|
return;
|
|
198
198
|
}
|
|
199
199
|
|
|
200
|
-
captureModeRef.current = null;
|
|
201
|
-
|
|
202
200
|
const normalizedDoc = normalizeCapturedDocument(document);
|
|
203
201
|
|
|
204
202
|
if (captureMode === 'no-grid') {
|
|
@@ -253,12 +251,31 @@ export const FullDocScanner: React.FC<FullDocScannerProps> = ({
|
|
|
253
251
|
captureModeRef.current = captureMode;
|
|
254
252
|
captureInProgressRef.current = true;
|
|
255
253
|
|
|
254
|
+
// Add timeout to reset state if capture hangs
|
|
255
|
+
const captureTimeout = setTimeout(() => {
|
|
256
|
+
if (captureInProgressRef.current) {
|
|
257
|
+
console.error('[FullDocScanner] Capture timeout - resetting state');
|
|
258
|
+
captureModeRef.current = null;
|
|
259
|
+
captureInProgressRef.current = false;
|
|
260
|
+
emitError(
|
|
261
|
+
new Error('Capture timeout'),
|
|
262
|
+
'Capture timed out. Please try again.',
|
|
263
|
+
);
|
|
264
|
+
}
|
|
265
|
+
}, 10000);
|
|
266
|
+
|
|
256
267
|
scannerInstance.capture()
|
|
257
268
|
.then((result) => {
|
|
258
|
-
|
|
259
|
-
|
|
269
|
+
clearTimeout(captureTimeout);
|
|
270
|
+
console.log('[FullDocScanner] Manual capture promise resolved:', {
|
|
271
|
+
hasResult: !!result,
|
|
272
|
+
croppedImage: result?.croppedImage,
|
|
273
|
+
initialImage: result?.initialImage,
|
|
274
|
+
});
|
|
275
|
+
// Note: captureInProgressRef is reset in handleCapture
|
|
260
276
|
})
|
|
261
277
|
.catch((error: unknown) => {
|
|
278
|
+
clearTimeout(captureTimeout);
|
|
262
279
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
263
280
|
console.error('[FullDocScanner] Manual capture failed:', errorMessage, error);
|
|
264
281
|
captureModeRef.current = null;
|
|
@@ -353,29 +370,34 @@ export const FullDocScanner: React.FC<FullDocScannerProps> = ({
|
|
|
353
370
|
const hasRectangle = Boolean(event.rectangleOnScreen ?? event.rectangleCoordinates);
|
|
354
371
|
const isGoodRectangle = hasRectangle && event.lastDetectionType === 0;
|
|
355
372
|
|
|
356
|
-
|
|
373
|
+
// Clear timeout immediately when rectangle is lost
|
|
374
|
+
if (!hasRectangle || !isGoodRectangle) {
|
|
357
375
|
if (rectangleTimeoutRef.current) {
|
|
358
376
|
clearTimeout(rectangleTimeoutRef.current);
|
|
377
|
+
rectangleTimeoutRef.current = null;
|
|
359
378
|
}
|
|
379
|
+
setRectangleDetected(false);
|
|
380
|
+
} else {
|
|
381
|
+
// Rectangle detected - clear any existing timeout
|
|
382
|
+
if (rectangleTimeoutRef.current) {
|
|
383
|
+
clearTimeout(rectangleTimeoutRef.current);
|
|
384
|
+
}
|
|
385
|
+
setRectangleDetected(true);
|
|
386
|
+
|
|
387
|
+
// Set timeout to clear rectangle after brief period of no updates
|
|
360
388
|
rectangleTimeoutRef.current = setTimeout(() => {
|
|
361
389
|
rectangleTimeoutRef.current = null;
|
|
362
390
|
setRectangleDetected(false);
|
|
391
|
+
console.log('[FullDocScanner] Rectangle timeout - clearing detection');
|
|
363
392
|
}, 300);
|
|
364
|
-
} else if (rectangleTimeoutRef.current) {
|
|
365
|
-
clearTimeout(rectangleTimeoutRef.current);
|
|
366
|
-
rectangleTimeoutRef.current = null;
|
|
367
393
|
}
|
|
368
394
|
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
isGoodRectangle,
|
|
376
|
-
});
|
|
377
|
-
}
|
|
378
|
-
return isGoodRectangle;
|
|
395
|
+
console.log('[FullDocScanner] Rectangle detection update', {
|
|
396
|
+
lastDetectionType: event.lastDetectionType,
|
|
397
|
+
stableCounter,
|
|
398
|
+
hasRectangle,
|
|
399
|
+
isGoodRectangle,
|
|
400
|
+
rectangleDetected: isGoodRectangle,
|
|
379
401
|
});
|
|
380
402
|
}, []);
|
|
381
403
|
|