react-native-rectangle-doc-scanner 3.118.0 → 3.120.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 +1 -0
- package/dist/DocScanner.js +12 -3
- package/dist/FullDocScanner.js +46 -3
- package/package.json +1 -1
- package/src/DocScanner.tsx +15 -3
- package/src/FullDocScanner.tsx +67 -6
package/dist/DocScanner.d.ts
CHANGED
|
@@ -7,6 +7,7 @@ type PictureEvent = {
|
|
|
7
7
|
width?: number;
|
|
8
8
|
height?: number;
|
|
9
9
|
rectangleCoordinates?: NativeRectangle | null;
|
|
10
|
+
rectangleOnScreen?: NativeRectangle | null;
|
|
10
11
|
};
|
|
11
12
|
export type RectangleDetectEvent = Omit<RectangleEventPayload, 'rectangleCoordinates' | 'rectangleOnScreen'> & {
|
|
12
13
|
rectangleCoordinates?: Rectangle | null;
|
package/dist/DocScanner.js
CHANGED
|
@@ -118,7 +118,9 @@ exports.DocScanner = (0, react_1.forwardRef)(({ onCapture, overlayColor = DEFAUL
|
|
|
118
118
|
height: event.height,
|
|
119
119
|
});
|
|
120
120
|
setIsAutoCapturing(false);
|
|
121
|
-
const normalizedRectangle = normalizeRectangle(event.rectangleCoordinates ?? null) ??
|
|
121
|
+
const normalizedRectangle = normalizeRectangle(event.rectangleCoordinates ?? null) ??
|
|
122
|
+
normalizeRectangle(event.rectangleOnScreen ?? null) ??
|
|
123
|
+
lastRectangleRef.current;
|
|
122
124
|
const quad = normalizedRectangle ? (0, coordinate_1.rectangleToQuad)(normalizedRectangle) : null;
|
|
123
125
|
const origin = captureOriginRef.current;
|
|
124
126
|
captureOriginRef.current = 'auto';
|
|
@@ -286,8 +288,8 @@ exports.DocScanner = (0, react_1.forwardRef)(({ onCapture, overlayColor = DEFAUL
|
|
|
286
288
|
setIsAutoCapturing(false);
|
|
287
289
|
}
|
|
288
290
|
}
|
|
289
|
-
if (payload.rectangleCoordinates) {
|
|
290
|
-
lastRectangleRef.current = payload.rectangleCoordinates;
|
|
291
|
+
if (payload.rectangleCoordinates || payload.rectangleOnScreen) {
|
|
292
|
+
lastRectangleRef.current = payload.rectangleCoordinates ?? payload.rectangleOnScreen ?? null;
|
|
291
293
|
}
|
|
292
294
|
const isGoodRectangle = payload.lastDetectionType === 0;
|
|
293
295
|
const hasValidRectangle = isGoodRectangle && rectangleOnScreen;
|
|
@@ -321,6 +323,13 @@ exports.DocScanner = (0, react_1.forwardRef)(({ onCapture, overlayColor = DEFAUL
|
|
|
321
323
|
captureResolvers.current.reject(new Error('reset'));
|
|
322
324
|
captureResolvers.current = null;
|
|
323
325
|
}
|
|
326
|
+
if (rectangleClearTimeoutRef.current) {
|
|
327
|
+
clearTimeout(rectangleClearTimeoutRef.current);
|
|
328
|
+
rectangleClearTimeoutRef.current = null;
|
|
329
|
+
}
|
|
330
|
+
lastRectangleRef.current = null;
|
|
331
|
+
setDetectedRectangle(null);
|
|
332
|
+
setIsAutoCapturing(false);
|
|
324
333
|
captureOriginRef.current = 'auto';
|
|
325
334
|
},
|
|
326
335
|
}), [capture]);
|
package/dist/FullDocScanner.js
CHANGED
|
@@ -207,6 +207,10 @@ const FullDocScanner = ({ onResult, onClose, detectionConfig, overlayColor = '#3
|
|
|
207
207
|
errorMessage.includes('cancelled') ||
|
|
208
208
|
errorMessage.includes('cancel')) {
|
|
209
209
|
console.log('[FullDocScanner] User cancelled cropper');
|
|
210
|
+
// DocScanner 상태를 리셋하여 카메라가 다시 작동하도록 함
|
|
211
|
+
if (docScannerRef.current?.reset) {
|
|
212
|
+
docScannerRef.current.reset();
|
|
213
|
+
}
|
|
210
214
|
}
|
|
211
215
|
else {
|
|
212
216
|
emitError(error instanceof Error ? error : new Error(errorMessage), 'Failed to crop image. Please try again.');
|
|
@@ -515,9 +519,14 @@ const FullDocScanner = ({ onResult, onClose, detectionConfig, overlayColor = '#3
|
|
|
515
519
|
croppedImageData ? (
|
|
516
520
|
// check_DP: Show confirmation screen
|
|
517
521
|
react_1.default.createElement(react_native_1.View, { style: styles.confirmationContainer },
|
|
518
|
-
isBusinessMode && (react_1.default.createElement(react_native_1.View, { style: styles.
|
|
519
|
-
react_1.default.createElement(react_native_1.
|
|
520
|
-
|
|
522
|
+
isBusinessMode && isImageRotationSupported() ? (react_1.default.createElement(react_native_1.View, { style: styles.businessHeaderRow },
|
|
523
|
+
react_1.default.createElement(react_native_1.TouchableOpacity, { style: styles.rotateButtonLeft, onPress: () => handleRotateImage(-90), accessibilityLabel: "\uC67C\uCABD\uC73C\uB85C 90\uB3C4 \uD68C\uC804", accessibilityRole: "button" },
|
|
524
|
+
react_1.default.createElement(react_native_1.Text, { style: styles.rotateIconText }, "\u21BA")),
|
|
525
|
+
react_1.default.createElement(react_native_1.View, { style: styles.photoHeaderCenter },
|
|
526
|
+
react_1.default.createElement(react_native_1.Text, { style: styles.photoHeaderText }, currentPhotoIndex === 0 ? mergedStrings.first : mergedStrings.second)),
|
|
527
|
+
react_1.default.createElement(react_native_1.TouchableOpacity, { style: styles.rotateButtonRight, onPress: () => handleRotateImage(90), accessibilityLabel: "\uC624\uB978\uCABD\uC73C\uB85C 90\uB3C4 \uD68C\uC804", accessibilityRole: "button" },
|
|
528
|
+
react_1.default.createElement(react_native_1.Text, { style: styles.rotateIconText }, "\u21BB")))) : isBusinessMode ? (react_1.default.createElement(react_native_1.View, { style: styles.photoHeader },
|
|
529
|
+
react_1.default.createElement(react_native_1.Text, { style: styles.photoHeaderText }, currentPhotoIndex === 0 ? mergedStrings.first : mergedStrings.second))) : isImageRotationSupported() ? (react_1.default.createElement(react_native_1.View, { style: styles.rotateButtonsCenter },
|
|
521
530
|
react_1.default.createElement(react_native_1.TouchableOpacity, { style: styles.rotateButtonTop, onPress: () => handleRotateImage(-90), accessibilityLabel: "\uC67C\uCABD\uC73C\uB85C 90\uB3C4 \uD68C\uC804", accessibilityRole: "button" },
|
|
522
531
|
react_1.default.createElement(react_native_1.Text, { style: styles.rotateIconText }, "\u21BA"),
|
|
523
532
|
react_1.default.createElement(react_native_1.Text, { style: styles.rotateButtonLabel }, "\uC88C\uB85C 90\u00B0")),
|
|
@@ -817,4 +826,38 @@ const styles = react_native_1.StyleSheet.create({
|
|
|
817
826
|
borderColor: '#fff',
|
|
818
827
|
overflow: 'hidden',
|
|
819
828
|
},
|
|
829
|
+
businessHeaderRow: {
|
|
830
|
+
position: 'absolute',
|
|
831
|
+
top: 80,
|
|
832
|
+
left: 0,
|
|
833
|
+
right: 0,
|
|
834
|
+
flexDirection: 'row',
|
|
835
|
+
justifyContent: 'space-between',
|
|
836
|
+
alignItems: 'center',
|
|
837
|
+
paddingHorizontal: 20,
|
|
838
|
+
zIndex: 10,
|
|
839
|
+
},
|
|
840
|
+
rotateButtonLeft: {
|
|
841
|
+
width: 48,
|
|
842
|
+
height: 48,
|
|
843
|
+
borderRadius: 24,
|
|
844
|
+
backgroundColor: 'rgba(50,50,50,0.8)',
|
|
845
|
+
justifyContent: 'center',
|
|
846
|
+
alignItems: 'center',
|
|
847
|
+
borderWidth: 1,
|
|
848
|
+
borderColor: 'rgba(255,255,255,0.3)',
|
|
849
|
+
},
|
|
850
|
+
rotateButtonRight: {
|
|
851
|
+
width: 48,
|
|
852
|
+
height: 48,
|
|
853
|
+
borderRadius: 24,
|
|
854
|
+
backgroundColor: 'rgba(50,50,50,0.8)',
|
|
855
|
+
justifyContent: 'center',
|
|
856
|
+
alignItems: 'center',
|
|
857
|
+
borderWidth: 1,
|
|
858
|
+
borderColor: 'rgba(255,255,255,0.3)',
|
|
859
|
+
},
|
|
860
|
+
photoHeaderCenter: {
|
|
861
|
+
alignItems: 'center',
|
|
862
|
+
},
|
|
820
863
|
});
|
package/package.json
CHANGED
package/src/DocScanner.tsx
CHANGED
|
@@ -28,6 +28,7 @@ type PictureEvent = {
|
|
|
28
28
|
width?: number;
|
|
29
29
|
height?: number;
|
|
30
30
|
rectangleCoordinates?: NativeRectangle | null;
|
|
31
|
+
rectangleOnScreen?: NativeRectangle | null;
|
|
31
32
|
};
|
|
32
33
|
|
|
33
34
|
export type RectangleDetectEvent = Omit<RectangleEventPayload, 'rectangleCoordinates' | 'rectangleOnScreen'> & {
|
|
@@ -195,7 +196,9 @@ export const DocScanner = forwardRef<DocScannerHandle, Props>(
|
|
|
195
196
|
setIsAutoCapturing(false);
|
|
196
197
|
|
|
197
198
|
const normalizedRectangle =
|
|
198
|
-
normalizeRectangle(event.rectangleCoordinates ?? null) ??
|
|
199
|
+
normalizeRectangle(event.rectangleCoordinates ?? null) ??
|
|
200
|
+
normalizeRectangle(event.rectangleOnScreen ?? null) ??
|
|
201
|
+
lastRectangleRef.current;
|
|
199
202
|
const quad = normalizedRectangle ? rectangleToQuad(normalizedRectangle) : null;
|
|
200
203
|
const origin = captureOriginRef.current;
|
|
201
204
|
captureOriginRef.current = 'auto';
|
|
@@ -390,8 +393,8 @@ export const DocScanner = forwardRef<DocScannerHandle, Props>(
|
|
|
390
393
|
}
|
|
391
394
|
}
|
|
392
395
|
|
|
393
|
-
if (payload.rectangleCoordinates) {
|
|
394
|
-
lastRectangleRef.current = payload.rectangleCoordinates;
|
|
396
|
+
if (payload.rectangleCoordinates || payload.rectangleOnScreen) {
|
|
397
|
+
lastRectangleRef.current = payload.rectangleCoordinates ?? payload.rectangleOnScreen ?? null;
|
|
395
398
|
}
|
|
396
399
|
|
|
397
400
|
const isGoodRectangle = payload.lastDetectionType === 0;
|
|
@@ -432,6 +435,15 @@ export const DocScanner = forwardRef<DocScannerHandle, Props>(
|
|
|
432
435
|
captureResolvers.current.reject(new Error('reset'));
|
|
433
436
|
captureResolvers.current = null;
|
|
434
437
|
}
|
|
438
|
+
|
|
439
|
+
if (rectangleClearTimeoutRef.current) {
|
|
440
|
+
clearTimeout(rectangleClearTimeoutRef.current);
|
|
441
|
+
rectangleClearTimeoutRef.current = null;
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
lastRectangleRef.current = null;
|
|
445
|
+
setDetectedRectangle(null);
|
|
446
|
+
setIsAutoCapturing(false);
|
|
435
447
|
captureOriginRef.current = 'auto';
|
|
436
448
|
},
|
|
437
449
|
}),
|
package/src/FullDocScanner.tsx
CHANGED
|
@@ -291,6 +291,10 @@ export const FullDocScanner: React.FC<FullDocScannerProps> = ({
|
|
|
291
291
|
errorMessage.includes('cancel')
|
|
292
292
|
) {
|
|
293
293
|
console.log('[FullDocScanner] User cancelled cropper');
|
|
294
|
+
// DocScanner 상태를 리셋하여 카메라가 다시 작동하도록 함
|
|
295
|
+
if (docScannerRef.current?.reset) {
|
|
296
|
+
docScannerRef.current.reset();
|
|
297
|
+
}
|
|
294
298
|
} else {
|
|
295
299
|
emitError(
|
|
296
300
|
error instanceof Error ? error : new Error(errorMessage),
|
|
@@ -672,17 +676,40 @@ export const FullDocScanner: React.FC<FullDocScannerProps> = ({
|
|
|
672
676
|
{croppedImageData ? (
|
|
673
677
|
// check_DP: Show confirmation screen
|
|
674
678
|
<View style={styles.confirmationContainer}>
|
|
675
|
-
{/* 헤더
|
|
676
|
-
{isBusinessMode && (
|
|
679
|
+
{/* Business 모드: 회전 버튼(왼쪽/오른쪽) + 헤더(가운데) 한 줄 배치 */}
|
|
680
|
+
{isBusinessMode && isImageRotationSupported() ? (
|
|
681
|
+
<View style={styles.businessHeaderRow}>
|
|
682
|
+
<TouchableOpacity
|
|
683
|
+
style={styles.rotateButtonLeft}
|
|
684
|
+
onPress={() => handleRotateImage(-90)}
|
|
685
|
+
accessibilityLabel="왼쪽으로 90도 회전"
|
|
686
|
+
accessibilityRole="button"
|
|
687
|
+
>
|
|
688
|
+
<Text style={styles.rotateIconText}>↺</Text>
|
|
689
|
+
</TouchableOpacity>
|
|
690
|
+
|
|
691
|
+
<View style={styles.photoHeaderCenter}>
|
|
692
|
+
<Text style={styles.photoHeaderText}>
|
|
693
|
+
{currentPhotoIndex === 0 ? mergedStrings.first : mergedStrings.second}
|
|
694
|
+
</Text>
|
|
695
|
+
</View>
|
|
696
|
+
|
|
697
|
+
<TouchableOpacity
|
|
698
|
+
style={styles.rotateButtonRight}
|
|
699
|
+
onPress={() => handleRotateImage(90)}
|
|
700
|
+
accessibilityLabel="오른쪽으로 90도 회전"
|
|
701
|
+
accessibilityRole="button"
|
|
702
|
+
>
|
|
703
|
+
<Text style={styles.rotateIconText}>↻</Text>
|
|
704
|
+
</TouchableOpacity>
|
|
705
|
+
</View>
|
|
706
|
+
) : isBusinessMode ? (
|
|
677
707
|
<View style={styles.photoHeader}>
|
|
678
708
|
<Text style={styles.photoHeaderText}>
|
|
679
709
|
{currentPhotoIndex === 0 ? mergedStrings.first : mergedStrings.second}
|
|
680
710
|
</Text>
|
|
681
711
|
</View>
|
|
682
|
-
)
|
|
683
|
-
|
|
684
|
-
{/* 회전 버튼들 - 가운데 정렬 */}
|
|
685
|
-
{isImageRotationSupported() ? (
|
|
712
|
+
) : isImageRotationSupported() ? (
|
|
686
713
|
<View style={styles.rotateButtonsCenter}>
|
|
687
714
|
<TouchableOpacity
|
|
688
715
|
style={styles.rotateButtonTop}
|
|
@@ -1105,4 +1132,38 @@ const styles = StyleSheet.create({
|
|
|
1105
1132
|
borderColor: '#fff',
|
|
1106
1133
|
overflow: 'hidden',
|
|
1107
1134
|
},
|
|
1135
|
+
businessHeaderRow: {
|
|
1136
|
+
position: 'absolute',
|
|
1137
|
+
top: 80,
|
|
1138
|
+
left: 0,
|
|
1139
|
+
right: 0,
|
|
1140
|
+
flexDirection: 'row',
|
|
1141
|
+
justifyContent: 'space-between',
|
|
1142
|
+
alignItems: 'center',
|
|
1143
|
+
paddingHorizontal: 20,
|
|
1144
|
+
zIndex: 10,
|
|
1145
|
+
},
|
|
1146
|
+
rotateButtonLeft: {
|
|
1147
|
+
width: 48,
|
|
1148
|
+
height: 48,
|
|
1149
|
+
borderRadius: 24,
|
|
1150
|
+
backgroundColor: 'rgba(50,50,50,0.8)',
|
|
1151
|
+
justifyContent: 'center',
|
|
1152
|
+
alignItems: 'center',
|
|
1153
|
+
borderWidth: 1,
|
|
1154
|
+
borderColor: 'rgba(255,255,255,0.3)',
|
|
1155
|
+
},
|
|
1156
|
+
rotateButtonRight: {
|
|
1157
|
+
width: 48,
|
|
1158
|
+
height: 48,
|
|
1159
|
+
borderRadius: 24,
|
|
1160
|
+
backgroundColor: 'rgba(50,50,50,0.8)',
|
|
1161
|
+
justifyContent: 'center',
|
|
1162
|
+
alignItems: 'center',
|
|
1163
|
+
borderWidth: 1,
|
|
1164
|
+
borderColor: 'rgba(255,255,255,0.3)',
|
|
1165
|
+
},
|
|
1166
|
+
photoHeaderCenter: {
|
|
1167
|
+
alignItems: 'center',
|
|
1168
|
+
},
|
|
1108
1169
|
});
|