react-native-rectangle-doc-scanner 15.0.0 → 15.2.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/android/src/main/kotlin/com/reactnativerectangledocscanner/DocumentScannerModule.kt +1 -1
- package/dist/DocScanner.d.ts +5 -0
- package/dist/DocScanner.js +2 -0
- package/dist/FullDocScanner.js +67 -4
- package/package.json +1 -1
- package/src/DocScanner.tsx +3 -0
- package/src/FullDocScanner.tsx +74 -6
|
@@ -54,7 +54,7 @@ class DocumentScannerModule(reactContext: ReactApplicationContext) :
|
|
|
54
54
|
.setScannerMode(GmsDocumentScannerOptions.SCANNER_MODE_FULL)
|
|
55
55
|
.setResultFormats(GmsDocumentScannerOptions.RESULT_FORMAT_JPEG)
|
|
56
56
|
.setPageLimit(pageLimit.coerceAtMost(2))
|
|
57
|
-
.setGalleryImportAllowed(
|
|
57
|
+
.setGalleryImportAllowed(true)
|
|
58
58
|
.build()
|
|
59
59
|
|
|
60
60
|
val scanner = GmsDocumentScanning.getClient(scannerOptions)
|
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
|
@@ -149,6 +149,7 @@ const FullDocScanner = ({ onResult, onClose, detectionConfig, overlayColor = '#3
|
|
|
149
149
|
const [scannerSession, setScannerSession] = (0, react_1.useState)(0);
|
|
150
150
|
const [cropEditorDocument, setCropEditorDocument] = (0, react_1.useState)(null);
|
|
151
151
|
const [cropEditorRectangle, setCropEditorRectangle] = (0, react_1.useState)(null);
|
|
152
|
+
const [androidScanAutoRequested, setAndroidScanAutoRequested] = (0, react_1.useState)(false);
|
|
152
153
|
const resolvedGridColor = gridColor ?? overlayColor;
|
|
153
154
|
const docScannerRef = (0, react_1.useRef)(null);
|
|
154
155
|
const captureModeRef = (0, react_1.useRef)(null);
|
|
@@ -165,6 +166,7 @@ const FullDocScanner = ({ onResult, onClose, detectionConfig, overlayColor = '#3
|
|
|
165
166
|
setCroppedImageData(null);
|
|
166
167
|
setCropEditorDocument(null);
|
|
167
168
|
setCropEditorRectangle(null);
|
|
169
|
+
setAndroidScanAutoRequested(false);
|
|
168
170
|
setRotationDegrees(0);
|
|
169
171
|
setRectangleDetected(false);
|
|
170
172
|
setRectangleHint(false);
|
|
@@ -205,7 +207,12 @@ const FullDocScanner = ({ onResult, onClose, detectionConfig, overlayColor = '#3
|
|
|
205
207
|
secondPrompt: strings?.secondPrompt ?? strings?.secondBtn ?? 'Capture Back Side?',
|
|
206
208
|
originalBtn: strings?.originalBtn ?? 'Use Original',
|
|
207
209
|
}), [strings]);
|
|
208
|
-
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]);
|
|
209
216
|
const ensureBase64ForImage = (0, react_1.useCallback)(async (image) => {
|
|
210
217
|
if (image.base64) {
|
|
211
218
|
return image;
|
|
@@ -418,6 +425,18 @@ const FullDocScanner = ({ onResult, onClose, detectionConfig, overlayColor = '#3
|
|
|
418
425
|
console.warn('[FullDocScanner] Missing capture mode for capture result, ignoring');
|
|
419
426
|
return;
|
|
420
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
|
+
}
|
|
421
440
|
const normalizedDoc = normalizeCapturedDocument(document);
|
|
422
441
|
const shouldOpenAndroidCropEditor = isAndroidCropEditorAvailable &&
|
|
423
442
|
captureMode === 'grid' &&
|
|
@@ -457,10 +476,12 @@ const FullDocScanner = ({ onResult, onClose, detectionConfig, overlayColor = '#3
|
|
|
457
476
|
}, [
|
|
458
477
|
emitError,
|
|
459
478
|
isAndroidCropEditorAvailable,
|
|
479
|
+
onResult,
|
|
460
480
|
openAndroidCropEditor,
|
|
461
481
|
openCropper,
|
|
462
482
|
preparePreviewImage,
|
|
463
483
|
resetScannerView,
|
|
484
|
+
usesAndroidScannerActivity,
|
|
464
485
|
]);
|
|
465
486
|
const triggerManualCapture = (0, react_1.useCallback)(() => {
|
|
466
487
|
const scannerInstance = docScannerRef.current;
|
|
@@ -519,11 +540,25 @@ const FullDocScanner = ({ onResult, onClose, detectionConfig, overlayColor = '#3
|
|
|
519
540
|
console.error('[FullDocScanner] Manual capture failed:', errorMessage, error);
|
|
520
541
|
captureModeRef.current = null;
|
|
521
542
|
captureInProgressRef.current = false;
|
|
543
|
+
if (errorMessage.includes('SCAN_CANCELLED')) {
|
|
544
|
+
resetScannerView({ remount: true });
|
|
545
|
+
onClose?.();
|
|
546
|
+
return;
|
|
547
|
+
}
|
|
522
548
|
if (error instanceof Error && error.message !== 'capture_in_progress') {
|
|
523
549
|
emitError(error, 'Failed to capture image. Please try again.');
|
|
524
550
|
}
|
|
525
551
|
});
|
|
526
|
-
}, [
|
|
552
|
+
}, [
|
|
553
|
+
emitError,
|
|
554
|
+
onClose,
|
|
555
|
+
processing,
|
|
556
|
+
rectangleDetected,
|
|
557
|
+
rectangleHint,
|
|
558
|
+
captureReady,
|
|
559
|
+
resetScannerView,
|
|
560
|
+
usesAndroidScannerActivity,
|
|
561
|
+
]);
|
|
527
562
|
const handleGalleryPick = (0, react_1.useCallback)(async () => {
|
|
528
563
|
console.log('[FullDocScanner] handleGalleryPick called');
|
|
529
564
|
if (processing || isGalleryOpen) {
|
|
@@ -637,7 +672,18 @@ const FullDocScanner = ({ onResult, onClose, detectionConfig, overlayColor = '#3
|
|
|
637
672
|
setCurrentPhotoIndex(0);
|
|
638
673
|
}
|
|
639
674
|
resetScannerView({ remount: true });
|
|
640
|
-
|
|
675
|
+
if (usesAndroidScannerActivity) {
|
|
676
|
+
requestAnimationFrame(() => {
|
|
677
|
+
triggerManualCapture();
|
|
678
|
+
});
|
|
679
|
+
}
|
|
680
|
+
}, [
|
|
681
|
+
capturedPhotos.length,
|
|
682
|
+
isBusinessMode,
|
|
683
|
+
resetScannerView,
|
|
684
|
+
triggerManualCapture,
|
|
685
|
+
usesAndroidScannerActivity,
|
|
686
|
+
]);
|
|
641
687
|
const handleRectangleDetect = (0, react_1.useCallback)((event) => {
|
|
642
688
|
const stableCounter = event.stableCounter ?? 0;
|
|
643
689
|
const rectangleCoordinates = event.rectangleOnScreen ?? event.rectangleCoordinates;
|
|
@@ -709,6 +755,23 @@ const FullDocScanner = ({ onResult, onClose, detectionConfig, overlayColor = '#3
|
|
|
709
755
|
setCaptureReady(true);
|
|
710
756
|
}
|
|
711
757
|
}, [usesAndroidScannerActivity]);
|
|
758
|
+
(0, react_1.useEffect)(() => {
|
|
759
|
+
if (!usesAndroidScannerActivity) {
|
|
760
|
+
return;
|
|
761
|
+
}
|
|
762
|
+
if (androidScanAutoRequested || croppedImageData || cropEditorDocument || processing) {
|
|
763
|
+
return;
|
|
764
|
+
}
|
|
765
|
+
setAndroidScanAutoRequested(true);
|
|
766
|
+
triggerManualCapture();
|
|
767
|
+
}, [
|
|
768
|
+
androidScanAutoRequested,
|
|
769
|
+
cropEditorDocument,
|
|
770
|
+
croppedImageData,
|
|
771
|
+
processing,
|
|
772
|
+
triggerManualCapture,
|
|
773
|
+
usesAndroidScannerActivity,
|
|
774
|
+
]);
|
|
712
775
|
const activePreviewImage = croppedImageData ? getActivePreviewImage(croppedImageData) : null;
|
|
713
776
|
return (react_1.default.createElement(react_native_1.View, { style: styles.container },
|
|
714
777
|
react_native_1.Platform.OS === 'android' && (react_1.default.createElement(react_native_1.StatusBar, { translucent: true, backgroundColor: "transparent" })),
|
|
@@ -763,7 +826,7 @@ const FullDocScanner = ({ onResult, onClose, detectionConfig, overlayColor = '#3
|
|
|
763
826
|
react_1.default.createElement(react_native_1.TouchableOpacity, { style: [styles.confirmButton, styles.retakeButton], onPress: handleCropEditorCancel, accessibilityLabel: mergedStrings.retake, accessibilityRole: "button", disabled: processing },
|
|
764
827
|
react_1.default.createElement(react_native_1.Text, { style: styles.confirmButtonText }, mergedStrings.retake)),
|
|
765
828
|
react_1.default.createElement(react_native_1.TouchableOpacity, { style: [styles.confirmButton, styles.confirmButtonPrimary], onPress: handleCropEditorConfirm, accessibilityLabel: mergedStrings.confirm, accessibilityRole: "button", disabled: processing },
|
|
766
|
-
react_1.default.createElement(react_native_1.Text, { style: styles.confirmButtonText }, mergedStrings.confirm))))) : (react_1.default.createElement(react_native_1.View, { style: styles.flex },
|
|
829
|
+
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 },
|
|
767
830
|
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 },
|
|
768
831
|
react_1.default.createElement(react_native_1.View, { style: styles.overlayTop, pointerEvents: "box-none" },
|
|
769
832
|
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
|
@@ -220,6 +220,7 @@ export const FullDocScanner: React.FC<FullDocScannerProps> = ({
|
|
|
220
220
|
const [scannerSession, setScannerSession] = useState(0);
|
|
221
221
|
const [cropEditorDocument, setCropEditorDocument] = useState<CapturedDocument | null>(null);
|
|
222
222
|
const [cropEditorRectangle, setCropEditorRectangle] = useState<Rectangle | null>(null);
|
|
223
|
+
const [androidScanAutoRequested, setAndroidScanAutoRequested] = useState(false);
|
|
223
224
|
const resolvedGridColor = gridColor ?? overlayColor;
|
|
224
225
|
const docScannerRef = useRef<DocScannerHandle | null>(null);
|
|
225
226
|
const captureModeRef = useRef<'grid' | 'no-grid' | null>(null);
|
|
@@ -240,6 +241,7 @@ export const FullDocScanner: React.FC<FullDocScannerProps> = ({
|
|
|
240
241
|
setCroppedImageData(null);
|
|
241
242
|
setCropEditorDocument(null);
|
|
242
243
|
setCropEditorRectangle(null);
|
|
244
|
+
setAndroidScanAutoRequested(false);
|
|
243
245
|
setRotationDegrees(0);
|
|
244
246
|
setRectangleDetected(false);
|
|
245
247
|
setRectangleHint(false);
|
|
@@ -291,10 +293,12 @@ export const FullDocScanner: React.FC<FullDocScannerProps> = ({
|
|
|
291
293
|
[strings],
|
|
292
294
|
);
|
|
293
295
|
|
|
294
|
-
const autoEnhancementEnabled = useMemo(
|
|
295
|
-
()
|
|
296
|
-
|
|
297
|
-
|
|
296
|
+
const autoEnhancementEnabled = useMemo(() => {
|
|
297
|
+
if (usesAndroidScannerActivity) {
|
|
298
|
+
return false;
|
|
299
|
+
}
|
|
300
|
+
return typeof pdfScannerManager?.applyColorControls === 'function';
|
|
301
|
+
}, [pdfScannerManager, usesAndroidScannerActivity]);
|
|
298
302
|
|
|
299
303
|
const ensureBase64ForImage = useCallback(
|
|
300
304
|
async (image: PreviewImageInfo): Promise<PreviewImageInfo> => {
|
|
@@ -578,6 +582,19 @@ export const FullDocScanner: React.FC<FullDocScannerProps> = ({
|
|
|
578
582
|
return;
|
|
579
583
|
}
|
|
580
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
|
+
|
|
581
598
|
const normalizedDoc = normalizeCapturedDocument(document);
|
|
582
599
|
|
|
583
600
|
const shouldOpenAndroidCropEditor =
|
|
@@ -628,10 +645,12 @@ export const FullDocScanner: React.FC<FullDocScannerProps> = ({
|
|
|
628
645
|
[
|
|
629
646
|
emitError,
|
|
630
647
|
isAndroidCropEditorAvailable,
|
|
648
|
+
onResult,
|
|
631
649
|
openAndroidCropEditor,
|
|
632
650
|
openCropper,
|
|
633
651
|
preparePreviewImage,
|
|
634
652
|
resetScannerView,
|
|
653
|
+
usesAndroidScannerActivity,
|
|
635
654
|
],
|
|
636
655
|
);
|
|
637
656
|
|
|
@@ -704,6 +723,12 @@ export const FullDocScanner: React.FC<FullDocScannerProps> = ({
|
|
|
704
723
|
captureModeRef.current = null;
|
|
705
724
|
captureInProgressRef.current = false;
|
|
706
725
|
|
|
726
|
+
if (errorMessage.includes('SCAN_CANCELLED')) {
|
|
727
|
+
resetScannerView({ remount: true });
|
|
728
|
+
onClose?.();
|
|
729
|
+
return;
|
|
730
|
+
}
|
|
731
|
+
|
|
707
732
|
if (error instanceof Error && error.message !== 'capture_in_progress') {
|
|
708
733
|
emitError(
|
|
709
734
|
error,
|
|
@@ -711,7 +736,16 @@ export const FullDocScanner: React.FC<FullDocScannerProps> = ({
|
|
|
711
736
|
);
|
|
712
737
|
}
|
|
713
738
|
});
|
|
714
|
-
}, [
|
|
739
|
+
}, [
|
|
740
|
+
emitError,
|
|
741
|
+
onClose,
|
|
742
|
+
processing,
|
|
743
|
+
rectangleDetected,
|
|
744
|
+
rectangleHint,
|
|
745
|
+
captureReady,
|
|
746
|
+
resetScannerView,
|
|
747
|
+
usesAndroidScannerActivity,
|
|
748
|
+
]);
|
|
715
749
|
|
|
716
750
|
const handleGalleryPick = useCallback(async () => {
|
|
717
751
|
console.log('[FullDocScanner] handleGalleryPick called');
|
|
@@ -857,7 +891,19 @@ export const FullDocScanner: React.FC<FullDocScannerProps> = ({
|
|
|
857
891
|
}
|
|
858
892
|
|
|
859
893
|
resetScannerView({ remount: true });
|
|
860
|
-
|
|
894
|
+
|
|
895
|
+
if (usesAndroidScannerActivity) {
|
|
896
|
+
requestAnimationFrame(() => {
|
|
897
|
+
triggerManualCapture();
|
|
898
|
+
});
|
|
899
|
+
}
|
|
900
|
+
}, [
|
|
901
|
+
capturedPhotos.length,
|
|
902
|
+
isBusinessMode,
|
|
903
|
+
resetScannerView,
|
|
904
|
+
triggerManualCapture,
|
|
905
|
+
usesAndroidScannerActivity,
|
|
906
|
+
]);
|
|
861
907
|
|
|
862
908
|
const handleRectangleDetect = useCallback((event: RectangleDetectEvent) => {
|
|
863
909
|
const stableCounter = event.stableCounter ?? 0;
|
|
@@ -941,6 +987,26 @@ export const FullDocScanner: React.FC<FullDocScannerProps> = ({
|
|
|
941
987
|
}
|
|
942
988
|
}, [usesAndroidScannerActivity]);
|
|
943
989
|
|
|
990
|
+
useEffect(() => {
|
|
991
|
+
if (!usesAndroidScannerActivity) {
|
|
992
|
+
return;
|
|
993
|
+
}
|
|
994
|
+
|
|
995
|
+
if (androidScanAutoRequested || croppedImageData || cropEditorDocument || processing) {
|
|
996
|
+
return;
|
|
997
|
+
}
|
|
998
|
+
|
|
999
|
+
setAndroidScanAutoRequested(true);
|
|
1000
|
+
triggerManualCapture();
|
|
1001
|
+
}, [
|
|
1002
|
+
androidScanAutoRequested,
|
|
1003
|
+
cropEditorDocument,
|
|
1004
|
+
croppedImageData,
|
|
1005
|
+
processing,
|
|
1006
|
+
triggerManualCapture,
|
|
1007
|
+
usesAndroidScannerActivity,
|
|
1008
|
+
]);
|
|
1009
|
+
|
|
944
1010
|
const activePreviewImage = croppedImageData ? getActivePreviewImage(croppedImageData) : null;
|
|
945
1011
|
|
|
946
1012
|
return (
|
|
@@ -1116,6 +1182,8 @@ export const FullDocScanner: React.FC<FullDocScannerProps> = ({
|
|
|
1116
1182
|
</TouchableOpacity>
|
|
1117
1183
|
</View>
|
|
1118
1184
|
</View>
|
|
1185
|
+
) : usesAndroidScannerActivity ? (
|
|
1186
|
+
<View style={styles.flex} />
|
|
1119
1187
|
) : (
|
|
1120
1188
|
<View style={styles.flex}>
|
|
1121
1189
|
<DocScanner
|