react-native-rectangle-doc-scanner 15.1.0 → 15.3.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.d.ts +5 -0
- package/dist/DocScanner.js +2 -0
- package/dist/FullDocScanner.js +87 -4
- package/package.json +1 -1
- package/src/DocScanner.tsx +3 -0
- package/src/FullDocScanner.tsx +98 -6
package/dist/DocScanner.d.ts
CHANGED
|
@@ -33,6 +33,11 @@ export type DocScannerCapture = {
|
|
|
33
33
|
width: number;
|
|
34
34
|
height: number;
|
|
35
35
|
origin: 'auto' | 'manual';
|
|
36
|
+
pages?: Array<{
|
|
37
|
+
path: string;
|
|
38
|
+
width: number;
|
|
39
|
+
height: number;
|
|
40
|
+
}> | null;
|
|
36
41
|
};
|
|
37
42
|
export interface DetectionConfig {
|
|
38
43
|
processingWidth?: number;
|
package/dist/DocScanner.js
CHANGED
|
@@ -121,6 +121,7 @@ const ActivityScanner = (0, react_1.forwardRef)(({ onCapture, children, showManu
|
|
|
121
121
|
width: event.width ?? 0,
|
|
122
122
|
height: event.height ?? 0,
|
|
123
123
|
origin,
|
|
124
|
+
pages: event.pages ?? null,
|
|
124
125
|
});
|
|
125
126
|
}
|
|
126
127
|
if (captureResolvers.current) {
|
|
@@ -321,6 +322,7 @@ const VisionCameraScanner = (0, react_1.forwardRef)(({ onCapture, overlayColor =
|
|
|
321
322
|
width: event.width ?? 0,
|
|
322
323
|
height: event.height ?? 0,
|
|
323
324
|
origin,
|
|
325
|
+
pages: event.pages ?? null,
|
|
324
326
|
});
|
|
325
327
|
}
|
|
326
328
|
setDetectedRectangle(null);
|
package/dist/FullDocScanner.js
CHANGED
|
@@ -207,7 +207,12 @@ const FullDocScanner = ({ onResult, onClose, detectionConfig, overlayColor = '#3
|
|
|
207
207
|
secondPrompt: strings?.secondPrompt ?? strings?.secondBtn ?? 'Capture Back Side?',
|
|
208
208
|
originalBtn: strings?.originalBtn ?? 'Use Original',
|
|
209
209
|
}), [strings]);
|
|
210
|
-
const autoEnhancementEnabled = (0, react_1.useMemo)(() =>
|
|
210
|
+
const autoEnhancementEnabled = (0, react_1.useMemo)(() => {
|
|
211
|
+
if (usesAndroidScannerActivity) {
|
|
212
|
+
return false;
|
|
213
|
+
}
|
|
214
|
+
return typeof pdfScannerManager?.applyColorControls === 'function';
|
|
215
|
+
}, [pdfScannerManager, usesAndroidScannerActivity]);
|
|
211
216
|
const ensureBase64ForImage = (0, react_1.useCallback)(async (image) => {
|
|
212
217
|
if (image.base64) {
|
|
213
218
|
return image;
|
|
@@ -420,6 +425,18 @@ const FullDocScanner = ({ onResult, onClose, detectionConfig, overlayColor = '#3
|
|
|
420
425
|
console.warn('[FullDocScanner] Missing capture mode for capture result, ignoring');
|
|
421
426
|
return;
|
|
422
427
|
}
|
|
428
|
+
if (usesAndroidScannerActivity) {
|
|
429
|
+
const pages = document.pages?.length
|
|
430
|
+
? document.pages
|
|
431
|
+
: [{ path: document.path, width: document.width, height: document.height }];
|
|
432
|
+
const results = pages.map((page) => ({
|
|
433
|
+
path: stripFileUri(page.path),
|
|
434
|
+
rotationDegrees: 0,
|
|
435
|
+
}));
|
|
436
|
+
onResult(results);
|
|
437
|
+
resetScannerView({ remount: true });
|
|
438
|
+
return;
|
|
439
|
+
}
|
|
423
440
|
const normalizedDoc = normalizeCapturedDocument(document);
|
|
424
441
|
const shouldOpenAndroidCropEditor = isAndroidCropEditorAvailable &&
|
|
425
442
|
captureMode === 'grid' &&
|
|
@@ -459,11 +476,42 @@ const FullDocScanner = ({ onResult, onClose, detectionConfig, overlayColor = '#3
|
|
|
459
476
|
}, [
|
|
460
477
|
emitError,
|
|
461
478
|
isAndroidCropEditorAvailable,
|
|
479
|
+
onResult,
|
|
462
480
|
openAndroidCropEditor,
|
|
463
481
|
openCropper,
|
|
464
482
|
preparePreviewImage,
|
|
465
483
|
resetScannerView,
|
|
484
|
+
usesAndroidScannerActivity,
|
|
466
485
|
]);
|
|
486
|
+
const startAndroidScan = (0, react_1.useCallback)(async () => {
|
|
487
|
+
if (!usesAndroidScannerActivity || !pdfScannerManager?.startDocumentScanner) {
|
|
488
|
+
throw new Error('document_scanner_not_available');
|
|
489
|
+
}
|
|
490
|
+
if (captureInProgressRef.current) {
|
|
491
|
+
throw new Error('capture_in_progress');
|
|
492
|
+
}
|
|
493
|
+
captureInProgressRef.current = true;
|
|
494
|
+
captureModeRef.current = 'grid';
|
|
495
|
+
try {
|
|
496
|
+
const payload = await pdfScannerManager.startDocumentScanner({ pageLimit: 2 });
|
|
497
|
+
const normalizedPath = stripFileUri(payload?.initialImage ?? payload?.croppedImage ?? '');
|
|
498
|
+
const capturePayload = {
|
|
499
|
+
path: normalizedPath,
|
|
500
|
+
initialPath: payload?.initialImage ? stripFileUri(payload.initialImage) : normalizedPath,
|
|
501
|
+
croppedPath: payload?.croppedImage ? stripFileUri(payload.croppedImage) : normalizedPath,
|
|
502
|
+
quad: null,
|
|
503
|
+
rectangle: null,
|
|
504
|
+
width: payload?.width ?? 0,
|
|
505
|
+
height: payload?.height ?? 0,
|
|
506
|
+
origin: 'manual',
|
|
507
|
+
pages: payload?.pages ?? null,
|
|
508
|
+
};
|
|
509
|
+
await handleCapture(capturePayload);
|
|
510
|
+
}
|
|
511
|
+
finally {
|
|
512
|
+
captureInProgressRef.current = false;
|
|
513
|
+
}
|
|
514
|
+
}, [handleCapture, pdfScannerManager, usesAndroidScannerActivity]);
|
|
467
515
|
const triggerManualCapture = (0, react_1.useCallback)(() => {
|
|
468
516
|
const scannerInstance = docScannerRef.current;
|
|
469
517
|
const hasScanner = !!scannerInstance;
|
|
@@ -489,6 +537,19 @@ const FullDocScanner = ({ onResult, onClose, detectionConfig, overlayColor = '#3
|
|
|
489
537
|
return;
|
|
490
538
|
}
|
|
491
539
|
if (!hasScanner) {
|
|
540
|
+
if (usesAndroidScannerActivity) {
|
|
541
|
+
startAndroidScan().catch((error) => {
|
|
542
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
543
|
+
console.error('[FullDocScanner] Android scan failed:', errorMessage, error);
|
|
544
|
+
if (errorMessage.includes('SCAN_CANCELLED')) {
|
|
545
|
+
resetScannerView({ remount: true });
|
|
546
|
+
onClose?.();
|
|
547
|
+
return;
|
|
548
|
+
}
|
|
549
|
+
emitError(error instanceof Error ? error : new Error(String(error)), 'Failed to capture image. Please try again.');
|
|
550
|
+
});
|
|
551
|
+
return;
|
|
552
|
+
}
|
|
492
553
|
console.error('[FullDocScanner] DocScanner ref not available');
|
|
493
554
|
return;
|
|
494
555
|
}
|
|
@@ -522,13 +583,24 @@ const FullDocScanner = ({ onResult, onClose, detectionConfig, overlayColor = '#3
|
|
|
522
583
|
captureModeRef.current = null;
|
|
523
584
|
captureInProgressRef.current = false;
|
|
524
585
|
if (errorMessage.includes('SCAN_CANCELLED')) {
|
|
586
|
+
resetScannerView({ remount: true });
|
|
587
|
+
onClose?.();
|
|
525
588
|
return;
|
|
526
589
|
}
|
|
527
590
|
if (error instanceof Error && error.message !== 'capture_in_progress') {
|
|
528
591
|
emitError(error, 'Failed to capture image. Please try again.');
|
|
529
592
|
}
|
|
530
593
|
});
|
|
531
|
-
}, [
|
|
594
|
+
}, [
|
|
595
|
+
emitError,
|
|
596
|
+
onClose,
|
|
597
|
+
processing,
|
|
598
|
+
rectangleDetected,
|
|
599
|
+
rectangleHint,
|
|
600
|
+
captureReady,
|
|
601
|
+
resetScannerView,
|
|
602
|
+
usesAndroidScannerActivity,
|
|
603
|
+
]);
|
|
532
604
|
const handleGalleryPick = (0, react_1.useCallback)(async () => {
|
|
533
605
|
console.log('[FullDocScanner] handleGalleryPick called');
|
|
534
606
|
if (processing || isGalleryOpen) {
|
|
@@ -642,7 +714,18 @@ const FullDocScanner = ({ onResult, onClose, detectionConfig, overlayColor = '#3
|
|
|
642
714
|
setCurrentPhotoIndex(0);
|
|
643
715
|
}
|
|
644
716
|
resetScannerView({ remount: true });
|
|
645
|
-
|
|
717
|
+
if (usesAndroidScannerActivity) {
|
|
718
|
+
requestAnimationFrame(() => {
|
|
719
|
+
triggerManualCapture();
|
|
720
|
+
});
|
|
721
|
+
}
|
|
722
|
+
}, [
|
|
723
|
+
capturedPhotos.length,
|
|
724
|
+
isBusinessMode,
|
|
725
|
+
resetScannerView,
|
|
726
|
+
triggerManualCapture,
|
|
727
|
+
usesAndroidScannerActivity,
|
|
728
|
+
]);
|
|
646
729
|
const handleRectangleDetect = (0, react_1.useCallback)((event) => {
|
|
647
730
|
const stableCounter = event.stableCounter ?? 0;
|
|
648
731
|
const rectangleCoordinates = event.rectangleOnScreen ?? event.rectangleCoordinates;
|
|
@@ -785,7 +868,7 @@ const FullDocScanner = ({ onResult, onClose, detectionConfig, overlayColor = '#3
|
|
|
785
868
|
react_1.default.createElement(react_native_1.TouchableOpacity, { style: [styles.confirmButton, styles.retakeButton], onPress: handleCropEditorCancel, accessibilityLabel: mergedStrings.retake, accessibilityRole: "button", disabled: processing },
|
|
786
869
|
react_1.default.createElement(react_native_1.Text, { style: styles.confirmButtonText }, mergedStrings.retake)),
|
|
787
870
|
react_1.default.createElement(react_native_1.TouchableOpacity, { style: [styles.confirmButton, styles.confirmButtonPrimary], onPress: handleCropEditorConfirm, accessibilityLabel: mergedStrings.confirm, accessibilityRole: "button", disabled: processing },
|
|
788
|
-
react_1.default.createElement(react_native_1.Text, { style: styles.confirmButtonText }, mergedStrings.confirm))))) : (react_1.default.createElement(react_native_1.View, { style: styles.flex },
|
|
871
|
+
react_1.default.createElement(react_native_1.Text, { style: styles.confirmButtonText }, mergedStrings.confirm))))) : usesAndroidScannerActivity ? (react_1.default.createElement(react_native_1.View, { style: styles.flex })) : (react_1.default.createElement(react_native_1.View, { style: styles.flex },
|
|
789
872
|
react_1.default.createElement(DocScanner_1.DocScanner, { key: scannerSession, ref: docScannerRef, autoCapture: false, overlayColor: overlayColor, showGrid: showGrid, gridColor: resolvedGridColor, gridLineWidth: gridLineWidth, minStableFrames: minStableFrames ?? 6, detectionConfig: detectionConfig, onCapture: handleCapture, onRectangleDetect: handleRectangleDetect, showManualCaptureButton: false, enableTorch: flashEnabled },
|
|
790
873
|
react_1.default.createElement(react_native_1.View, { style: styles.overlayTop, pointerEvents: "box-none" },
|
|
791
874
|
react_1.default.createElement(react_native_1.TouchableOpacity, { style: [
|
package/package.json
CHANGED
package/src/DocScanner.tsx
CHANGED
|
@@ -48,6 +48,7 @@ export type DocScannerCapture = {
|
|
|
48
48
|
width: number;
|
|
49
49
|
height: number;
|
|
50
50
|
origin: 'auto' | 'manual';
|
|
51
|
+
pages?: Array<{ path: string; width: number; height: number }> | null;
|
|
51
52
|
};
|
|
52
53
|
|
|
53
54
|
const isFiniteNumber = (value: unknown): value is number =>
|
|
@@ -192,6 +193,7 @@ const ActivityScanner = forwardRef<DocScannerHandle, Props>(
|
|
|
192
193
|
width: event.width ?? 0,
|
|
193
194
|
height: event.height ?? 0,
|
|
194
195
|
origin,
|
|
196
|
+
pages: event.pages ?? null,
|
|
195
197
|
});
|
|
196
198
|
}
|
|
197
199
|
|
|
@@ -480,6 +482,7 @@ const VisionCameraScanner = forwardRef<DocScannerHandle, Props>(
|
|
|
480
482
|
width: event.width ?? 0,
|
|
481
483
|
height: event.height ?? 0,
|
|
482
484
|
origin,
|
|
485
|
+
pages: event.pages ?? null,
|
|
483
486
|
});
|
|
484
487
|
}
|
|
485
488
|
|
package/src/FullDocScanner.tsx
CHANGED
|
@@ -293,10 +293,12 @@ export const FullDocScanner: React.FC<FullDocScannerProps> = ({
|
|
|
293
293
|
[strings],
|
|
294
294
|
);
|
|
295
295
|
|
|
296
|
-
const autoEnhancementEnabled = useMemo(
|
|
297
|
-
()
|
|
298
|
-
|
|
299
|
-
|
|
296
|
+
const autoEnhancementEnabled = useMemo(() => {
|
|
297
|
+
if (usesAndroidScannerActivity) {
|
|
298
|
+
return false;
|
|
299
|
+
}
|
|
300
|
+
return typeof pdfScannerManager?.applyColorControls === 'function';
|
|
301
|
+
}, [pdfScannerManager, usesAndroidScannerActivity]);
|
|
300
302
|
|
|
301
303
|
const ensureBase64ForImage = useCallback(
|
|
302
304
|
async (image: PreviewImageInfo): Promise<PreviewImageInfo> => {
|
|
@@ -580,6 +582,19 @@ export const FullDocScanner: React.FC<FullDocScannerProps> = ({
|
|
|
580
582
|
return;
|
|
581
583
|
}
|
|
582
584
|
|
|
585
|
+
if (usesAndroidScannerActivity) {
|
|
586
|
+
const pages = document.pages?.length
|
|
587
|
+
? document.pages
|
|
588
|
+
: [{ path: document.path, width: document.width, height: document.height }];
|
|
589
|
+
const results: FullDocScannerResult[] = pages.map((page) => ({
|
|
590
|
+
path: stripFileUri(page.path),
|
|
591
|
+
rotationDegrees: 0,
|
|
592
|
+
}));
|
|
593
|
+
onResult(results);
|
|
594
|
+
resetScannerView({ remount: true });
|
|
595
|
+
return;
|
|
596
|
+
}
|
|
597
|
+
|
|
583
598
|
const normalizedDoc = normalizeCapturedDocument(document);
|
|
584
599
|
|
|
585
600
|
const shouldOpenAndroidCropEditor =
|
|
@@ -630,13 +645,49 @@ export const FullDocScanner: React.FC<FullDocScannerProps> = ({
|
|
|
630
645
|
[
|
|
631
646
|
emitError,
|
|
632
647
|
isAndroidCropEditorAvailable,
|
|
648
|
+
onResult,
|
|
633
649
|
openAndroidCropEditor,
|
|
634
650
|
openCropper,
|
|
635
651
|
preparePreviewImage,
|
|
636
652
|
resetScannerView,
|
|
653
|
+
usesAndroidScannerActivity,
|
|
637
654
|
],
|
|
638
655
|
);
|
|
639
656
|
|
|
657
|
+
const startAndroidScan = useCallback(async () => {
|
|
658
|
+
if (!usesAndroidScannerActivity || !pdfScannerManager?.startDocumentScanner) {
|
|
659
|
+
throw new Error('document_scanner_not_available');
|
|
660
|
+
}
|
|
661
|
+
|
|
662
|
+
if (captureInProgressRef.current) {
|
|
663
|
+
throw new Error('capture_in_progress');
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
captureInProgressRef.current = true;
|
|
667
|
+
captureModeRef.current = 'grid';
|
|
668
|
+
|
|
669
|
+
try {
|
|
670
|
+
const payload = await pdfScannerManager.startDocumentScanner({ pageLimit: 2 });
|
|
671
|
+
const normalizedPath = stripFileUri(payload?.initialImage ?? payload?.croppedImage ?? '');
|
|
672
|
+
|
|
673
|
+
const capturePayload: DocScannerCapture = {
|
|
674
|
+
path: normalizedPath,
|
|
675
|
+
initialPath: payload?.initialImage ? stripFileUri(payload.initialImage) : normalizedPath,
|
|
676
|
+
croppedPath: payload?.croppedImage ? stripFileUri(payload.croppedImage) : normalizedPath,
|
|
677
|
+
quad: null,
|
|
678
|
+
rectangle: null,
|
|
679
|
+
width: payload?.width ?? 0,
|
|
680
|
+
height: payload?.height ?? 0,
|
|
681
|
+
origin: 'manual',
|
|
682
|
+
pages: payload?.pages ?? null,
|
|
683
|
+
};
|
|
684
|
+
|
|
685
|
+
await handleCapture(capturePayload);
|
|
686
|
+
} finally {
|
|
687
|
+
captureInProgressRef.current = false;
|
|
688
|
+
}
|
|
689
|
+
}, [handleCapture, pdfScannerManager, usesAndroidScannerActivity]);
|
|
690
|
+
|
|
640
691
|
const triggerManualCapture = useCallback(() => {
|
|
641
692
|
const scannerInstance = docScannerRef.current;
|
|
642
693
|
const hasScanner = !!scannerInstance;
|
|
@@ -666,6 +717,22 @@ export const FullDocScanner: React.FC<FullDocScannerProps> = ({
|
|
|
666
717
|
}
|
|
667
718
|
|
|
668
719
|
if (!hasScanner) {
|
|
720
|
+
if (usesAndroidScannerActivity) {
|
|
721
|
+
startAndroidScan().catch((error: unknown) => {
|
|
722
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
723
|
+
console.error('[FullDocScanner] Android scan failed:', errorMessage, error);
|
|
724
|
+
if (errorMessage.includes('SCAN_CANCELLED')) {
|
|
725
|
+
resetScannerView({ remount: true });
|
|
726
|
+
onClose?.();
|
|
727
|
+
return;
|
|
728
|
+
}
|
|
729
|
+
emitError(
|
|
730
|
+
error instanceof Error ? error : new Error(String(error)),
|
|
731
|
+
'Failed to capture image. Please try again.',
|
|
732
|
+
);
|
|
733
|
+
});
|
|
734
|
+
return;
|
|
735
|
+
}
|
|
669
736
|
console.error('[FullDocScanner] DocScanner ref not available');
|
|
670
737
|
return;
|
|
671
738
|
}
|
|
@@ -707,6 +774,8 @@ export const FullDocScanner: React.FC<FullDocScannerProps> = ({
|
|
|
707
774
|
captureInProgressRef.current = false;
|
|
708
775
|
|
|
709
776
|
if (errorMessage.includes('SCAN_CANCELLED')) {
|
|
777
|
+
resetScannerView({ remount: true });
|
|
778
|
+
onClose?.();
|
|
710
779
|
return;
|
|
711
780
|
}
|
|
712
781
|
|
|
@@ -717,7 +786,16 @@ export const FullDocScanner: React.FC<FullDocScannerProps> = ({
|
|
|
717
786
|
);
|
|
718
787
|
}
|
|
719
788
|
});
|
|
720
|
-
}, [
|
|
789
|
+
}, [
|
|
790
|
+
emitError,
|
|
791
|
+
onClose,
|
|
792
|
+
processing,
|
|
793
|
+
rectangleDetected,
|
|
794
|
+
rectangleHint,
|
|
795
|
+
captureReady,
|
|
796
|
+
resetScannerView,
|
|
797
|
+
usesAndroidScannerActivity,
|
|
798
|
+
]);
|
|
721
799
|
|
|
722
800
|
const handleGalleryPick = useCallback(async () => {
|
|
723
801
|
console.log('[FullDocScanner] handleGalleryPick called');
|
|
@@ -863,7 +941,19 @@ export const FullDocScanner: React.FC<FullDocScannerProps> = ({
|
|
|
863
941
|
}
|
|
864
942
|
|
|
865
943
|
resetScannerView({ remount: true });
|
|
866
|
-
|
|
944
|
+
|
|
945
|
+
if (usesAndroidScannerActivity) {
|
|
946
|
+
requestAnimationFrame(() => {
|
|
947
|
+
triggerManualCapture();
|
|
948
|
+
});
|
|
949
|
+
}
|
|
950
|
+
}, [
|
|
951
|
+
capturedPhotos.length,
|
|
952
|
+
isBusinessMode,
|
|
953
|
+
resetScannerView,
|
|
954
|
+
triggerManualCapture,
|
|
955
|
+
usesAndroidScannerActivity,
|
|
956
|
+
]);
|
|
867
957
|
|
|
868
958
|
const handleRectangleDetect = useCallback((event: RectangleDetectEvent) => {
|
|
869
959
|
const stableCounter = event.stableCounter ?? 0;
|
|
@@ -1142,6 +1232,8 @@ export const FullDocScanner: React.FC<FullDocScannerProps> = ({
|
|
|
1142
1232
|
</TouchableOpacity>
|
|
1143
1233
|
</View>
|
|
1144
1234
|
</View>
|
|
1235
|
+
) : usesAndroidScannerActivity ? (
|
|
1236
|
+
<View style={styles.flex} />
|
|
1145
1237
|
) : (
|
|
1146
1238
|
<View style={styles.flex}>
|
|
1147
1239
|
<DocScanner
|