react-native-rectangle-doc-scanner 3.109.0 → 3.111.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 +45 -82
- package/package.json +1 -1
- package/src/FullDocScanner.tsx +54 -123
package/dist/FullDocScanner.js
CHANGED
|
@@ -44,45 +44,17 @@ const react_native_image_crop_picker_1 = __importDefault(require("react-native-i
|
|
|
44
44
|
const react_native_fs_1 = __importDefault(require("react-native-fs"));
|
|
45
45
|
const DocScanner_1 = require("./DocScanner");
|
|
46
46
|
let ImageManipulator = null;
|
|
47
|
-
let ImageRotate = null;
|
|
48
|
-
const ImageStoreManager = react_native_1.NativeModules.ImageStoreManager;
|
|
49
47
|
try {
|
|
50
48
|
ImageManipulator = require('expo-image-manipulator');
|
|
51
49
|
}
|
|
52
50
|
catch (error) {
|
|
53
|
-
console.warn('[FullDocScanner] expo-image-manipulator module unavailable.
|
|
54
|
-
}
|
|
55
|
-
try {
|
|
56
|
-
const rotateModule = require('react-native-image-rotate');
|
|
57
|
-
ImageRotate = (rotateModule?.default ?? rotateModule);
|
|
58
|
-
}
|
|
59
|
-
catch (error) {
|
|
60
|
-
console.warn('[FullDocScanner] react-native-image-rotate module unavailable. Image rotation fallback disabled.', error);
|
|
51
|
+
console.warn('[FullDocScanner] expo-image-manipulator module unavailable.', error);
|
|
61
52
|
}
|
|
62
53
|
let expoManipulatorUnavailable = false;
|
|
63
54
|
const isExpoImageManipulatorAvailable = () => !!ImageManipulator?.manipulateAsync && !expoManipulatorUnavailable;
|
|
64
|
-
const
|
|
65
|
-
const isImageRotationSupported = () => isExpoImageManipulatorAvailable() || isImageRotateAvailable;
|
|
55
|
+
const isImageRotationSupported = () => isExpoImageManipulatorAvailable();
|
|
66
56
|
const stripFileUri = (value) => value.replace(/^file:\/\//, '');
|
|
67
57
|
const ensureFileUri = (value) => (value.startsWith('file://') ? value : `file://${value}`);
|
|
68
|
-
const getBase64FromImageStore = async (uri) => {
|
|
69
|
-
const getBase64ForTag = ImageStoreManager?.getBase64ForTag?.bind(ImageStoreManager);
|
|
70
|
-
if (!getBase64ForTag) {
|
|
71
|
-
throw new Error('ImageStoreManager.getBase64ForTag unavailable');
|
|
72
|
-
}
|
|
73
|
-
return new Promise((resolve, reject) => {
|
|
74
|
-
getBase64ForTag(uri, (base64) => resolve(base64), (error) => {
|
|
75
|
-
const message = typeof error === 'string'
|
|
76
|
-
? error
|
|
77
|
-
: error && typeof error === 'object' && 'message' in error
|
|
78
|
-
? String(error.message)
|
|
79
|
-
: 'Failed to read from ImageStore';
|
|
80
|
-
reject(new Error(message));
|
|
81
|
-
});
|
|
82
|
-
}).finally(() => {
|
|
83
|
-
ImageStoreManager?.removeImageForTag?.(uri);
|
|
84
|
-
});
|
|
85
|
-
};
|
|
86
58
|
const CROPPER_TIMEOUT_MS = 8000;
|
|
87
59
|
const CROPPER_TIMEOUT_CODE = 'cropper_timeout';
|
|
88
60
|
const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
@@ -382,22 +354,6 @@ const FullDocScanner = ({ onResult, onClose, detectionConfig, overlayColor = '#3
|
|
|
382
354
|
const handleFlashToggle = (0, react_1.useCallback)(() => {
|
|
383
355
|
setFlashEnabled(prev => !prev);
|
|
384
356
|
}, []);
|
|
385
|
-
const rotateImageWithFallback = (0, react_1.useCallback)((uri, angle) => {
|
|
386
|
-
return new Promise((resolve, reject) => {
|
|
387
|
-
if (!ImageRotate?.rotateImage) {
|
|
388
|
-
reject(new Error('react-native-image-rotate unavailable'));
|
|
389
|
-
return;
|
|
390
|
-
}
|
|
391
|
-
ImageRotate.rotateImage(uri, angle, (rotatedUri) => resolve(rotatedUri), (error) => {
|
|
392
|
-
const message = typeof error === 'string'
|
|
393
|
-
? error
|
|
394
|
-
: error && typeof error === 'object' && 'message' in error
|
|
395
|
-
? String(error.message)
|
|
396
|
-
: 'Unknown rotation error';
|
|
397
|
-
reject(new Error(message));
|
|
398
|
-
});
|
|
399
|
-
});
|
|
400
|
-
}, []);
|
|
401
357
|
const handleRotateImage = (0, react_1.useCallback)((degrees) => {
|
|
402
358
|
if (!isImageRotationSupported()) {
|
|
403
359
|
console.warn('[FullDocScanner] Image rotation requested but no rotation module is available.');
|
|
@@ -418,8 +374,9 @@ const FullDocScanner = ({ onResult, onClose, detectionConfig, overlayColor = '#3
|
|
|
418
374
|
if (!croppedImageData) {
|
|
419
375
|
return;
|
|
420
376
|
}
|
|
421
|
-
// 회전이
|
|
377
|
+
// 회전이 없으면 기존 데이터 그대로 전달
|
|
422
378
|
if (rotationDegrees === 0) {
|
|
379
|
+
console.log('[FullDocScanner] No rotation, returning original image');
|
|
423
380
|
onResult({
|
|
424
381
|
path: croppedImageData.path,
|
|
425
382
|
base64: croppedImageData.base64,
|
|
@@ -430,76 +387,82 @@ const FullDocScanner = ({ onResult, onClose, detectionConfig, overlayColor = '#3
|
|
|
430
387
|
setProcessing(true);
|
|
431
388
|
// 회전 각도 정규화 (0, 90, 180, 270)
|
|
432
389
|
const rotationNormalized = ((rotationDegrees % 360) + 360) % 360;
|
|
390
|
+
console.log('[FullDocScanner] Rotation degrees:', rotationDegrees, 'normalized:', rotationNormalized);
|
|
433
391
|
if (rotationNormalized === 0) {
|
|
392
|
+
console.log('[FullDocScanner] Normalized to 0, returning original image');
|
|
434
393
|
onResult({
|
|
435
394
|
path: croppedImageData.path,
|
|
436
395
|
base64: croppedImageData.base64,
|
|
437
396
|
});
|
|
397
|
+
setProcessing(false);
|
|
438
398
|
return;
|
|
439
399
|
}
|
|
400
|
+
// expo-image-manipulator 시도
|
|
440
401
|
if (isExpoImageManipulatorAvailable() && ImageManipulator?.manipulateAsync) {
|
|
441
402
|
try {
|
|
442
|
-
|
|
443
|
-
const
|
|
403
|
+
console.log('[FullDocScanner] Using expo-image-manipulator for rotation');
|
|
404
|
+
const inputUri = ensureFileUri(croppedImageData.path);
|
|
405
|
+
const result = await ImageManipulator.manipulateAsync(inputUri, [{ rotate: rotationNormalized }], {
|
|
444
406
|
compress: 0.9,
|
|
445
407
|
format: ImageManipulator.SaveFormat.JPEG,
|
|
446
408
|
base64: true,
|
|
447
409
|
});
|
|
448
|
-
|
|
410
|
+
console.log('[FullDocScanner] Rotation complete via expo-image-manipulator:', {
|
|
449
411
|
path: result.uri,
|
|
412
|
+
hasBase64: !!result.base64,
|
|
413
|
+
});
|
|
414
|
+
onResult({
|
|
415
|
+
path: stripFileUri(result.uri),
|
|
450
416
|
base64: result.base64,
|
|
451
417
|
});
|
|
418
|
+
setProcessing(false);
|
|
452
419
|
return;
|
|
453
420
|
}
|
|
454
421
|
catch (manipulatorError) {
|
|
455
422
|
const code = manipulatorError && typeof manipulatorError === 'object' && 'code' in manipulatorError
|
|
456
423
|
? String(manipulatorError.code)
|
|
457
424
|
: undefined;
|
|
425
|
+
console.error('[FullDocScanner] expo-image-manipulator error:', manipulatorError);
|
|
458
426
|
if (code === 'ERR_UNAVAILABLE') {
|
|
459
427
|
expoManipulatorUnavailable = true;
|
|
460
|
-
console.warn('[FullDocScanner] expo-image-manipulator unavailable at runtime.
|
|
428
|
+
console.warn('[FullDocScanner] expo-image-manipulator unavailable at runtime. Trying react-native-image-rotate.');
|
|
461
429
|
}
|
|
462
430
|
else {
|
|
463
431
|
throw manipulatorError;
|
|
464
432
|
}
|
|
465
433
|
}
|
|
466
434
|
}
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
});
|
|
486
|
-
return;
|
|
487
|
-
}
|
|
488
|
-
console.warn('[FullDocScanner] Rotation requested but no supported rotation module is available. Returning original image.');
|
|
489
|
-
onResult({
|
|
490
|
-
path: croppedImageData.path,
|
|
491
|
-
base64: croppedImageData.base64,
|
|
492
|
-
});
|
|
435
|
+
// expo-image-manipulator를 사용할 수 없는 경우 에러 처리
|
|
436
|
+
console.error('[FullDocScanner] Rotation requested but expo-image-manipulator is not available.');
|
|
437
|
+
setProcessing(false);
|
|
438
|
+
react_native_1.Alert.alert('회전 불가', 'expo-image-manipulator가 설치되지 않아 이미지 회전을 수행할 수 없습니다.\n\n패키지를 설치해주세요:\nnpm install expo-image-manipulator', [
|
|
439
|
+
{
|
|
440
|
+
text: '원본 사용',
|
|
441
|
+
onPress: () => {
|
|
442
|
+
onResult({
|
|
443
|
+
path: croppedImageData.path,
|
|
444
|
+
base64: croppedImageData.base64,
|
|
445
|
+
});
|
|
446
|
+
},
|
|
447
|
+
},
|
|
448
|
+
{
|
|
449
|
+
text: '취소',
|
|
450
|
+
style: 'cancel',
|
|
451
|
+
},
|
|
452
|
+
]);
|
|
493
453
|
}
|
|
494
454
|
catch (error) {
|
|
495
455
|
console.error('[FullDocScanner] Image rotation error on confirm:', error);
|
|
496
|
-
const errorMessage = error && typeof error === 'object' && 'message' in error ? error.message : '';
|
|
497
|
-
react_native_1.Alert.alert('회전 실패', '이미지 회전 중 오류가 발생했습니다: ' + errorMessage);
|
|
498
|
-
}
|
|
499
|
-
finally {
|
|
500
456
|
setProcessing(false);
|
|
457
|
+
const errorMessage = error && typeof error === 'object' && 'message' in error ? error.message : String(error);
|
|
458
|
+
react_native_1.Alert.alert('회전 실패', `이미지 회전 중 오류가 발생했습니다.\n원본 이미지를 사용합니다.\n\n오류: ${errorMessage}`);
|
|
459
|
+
// 에러 발생 시 원본 이미지 반환
|
|
460
|
+
onResult({
|
|
461
|
+
path: croppedImageData.path,
|
|
462
|
+
base64: croppedImageData.base64,
|
|
463
|
+
});
|
|
501
464
|
}
|
|
502
|
-
}, [croppedImageData, rotationDegrees, onResult
|
|
465
|
+
}, [croppedImageData, rotationDegrees, onResult]);
|
|
503
466
|
const handleRetake = (0, react_1.useCallback)(() => {
|
|
504
467
|
console.log('[FullDocScanner] Retake - clearing cropped image and resetting scanner');
|
|
505
468
|
setCroppedImageData(null);
|
package/package.json
CHANGED
package/src/FullDocScanner.tsx
CHANGED
|
@@ -8,7 +8,6 @@ import {
|
|
|
8
8
|
Text,
|
|
9
9
|
TouchableOpacity,
|
|
10
10
|
View,
|
|
11
|
-
NativeModules,
|
|
12
11
|
} from 'react-native';
|
|
13
12
|
import { launchImageLibrary } from 'react-native-image-picker';
|
|
14
13
|
import ImageCropPicker from 'react-native-image-crop-picker';
|
|
@@ -23,43 +22,14 @@ import type {
|
|
|
23
22
|
} from './DocScanner';
|
|
24
23
|
|
|
25
24
|
type ImageManipulatorModule = typeof import('expo-image-manipulator');
|
|
26
|
-
type ImageRotateModule = {
|
|
27
|
-
rotateImage: (
|
|
28
|
-
uri: string,
|
|
29
|
-
angle: number,
|
|
30
|
-
onSuccess: (uri: string) => void,
|
|
31
|
-
onError: (error: unknown) => void,
|
|
32
|
-
) => void;
|
|
33
|
-
} | null;
|
|
34
|
-
|
|
35
|
-
type ImageStoreModule = {
|
|
36
|
-
getBase64ForTag?: (
|
|
37
|
-
uri: string,
|
|
38
|
-
success: (base64: string) => void,
|
|
39
|
-
failure: (error: unknown) => void,
|
|
40
|
-
) => void;
|
|
41
|
-
removeImageForTag?: (uri: string) => void;
|
|
42
|
-
} | undefined;
|
|
43
25
|
|
|
44
26
|
let ImageManipulator: ImageManipulatorModule | null = null;
|
|
45
|
-
let ImageRotate: ImageRotateModule = null;
|
|
46
|
-
const ImageStoreManager: ImageStoreModule = NativeModules.ImageStoreManager;
|
|
47
27
|
|
|
48
28
|
try {
|
|
49
29
|
ImageManipulator = require('expo-image-manipulator') as ImageManipulatorModule;
|
|
50
30
|
} catch (error) {
|
|
51
31
|
console.warn(
|
|
52
|
-
'[FullDocScanner] expo-image-manipulator module unavailable.
|
|
53
|
-
error,
|
|
54
|
-
);
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
try {
|
|
58
|
-
const rotateModule = require('react-native-image-rotate');
|
|
59
|
-
ImageRotate = (rotateModule?.default ?? rotateModule) as ImageRotateModule;
|
|
60
|
-
} catch (error) {
|
|
61
|
-
console.warn(
|
|
62
|
-
'[FullDocScanner] react-native-image-rotate module unavailable. Image rotation fallback disabled.',
|
|
32
|
+
'[FullDocScanner] expo-image-manipulator module unavailable.',
|
|
63
33
|
error,
|
|
64
34
|
);
|
|
65
35
|
}
|
|
@@ -67,38 +37,11 @@ try {
|
|
|
67
37
|
let expoManipulatorUnavailable = false;
|
|
68
38
|
const isExpoImageManipulatorAvailable = () =>
|
|
69
39
|
!!ImageManipulator?.manipulateAsync && !expoManipulatorUnavailable;
|
|
70
|
-
const
|
|
71
|
-
const isImageRotationSupported = () => isExpoImageManipulatorAvailable() || isImageRotateAvailable;
|
|
40
|
+
const isImageRotationSupported = () => isExpoImageManipulatorAvailable();
|
|
72
41
|
|
|
73
42
|
const stripFileUri = (value: string) => value.replace(/^file:\/\//, '');
|
|
74
43
|
const ensureFileUri = (value: string) => (value.startsWith('file://') ? value : `file://${value}`);
|
|
75
44
|
|
|
76
|
-
const getBase64FromImageStore = async (uri: string): Promise<string> => {
|
|
77
|
-
const getBase64ForTag = ImageStoreManager?.getBase64ForTag?.bind(ImageStoreManager);
|
|
78
|
-
|
|
79
|
-
if (!getBase64ForTag) {
|
|
80
|
-
throw new Error('ImageStoreManager.getBase64ForTag unavailable');
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
return new Promise<string>((resolve, reject) => {
|
|
84
|
-
getBase64ForTag(
|
|
85
|
-
uri,
|
|
86
|
-
(base64: string) => resolve(base64),
|
|
87
|
-
(error: unknown) => {
|
|
88
|
-
const message =
|
|
89
|
-
typeof error === 'string'
|
|
90
|
-
? error
|
|
91
|
-
: error && typeof error === 'object' && 'message' in error
|
|
92
|
-
? String((error as any).message)
|
|
93
|
-
: 'Failed to read from ImageStore';
|
|
94
|
-
reject(new Error(message));
|
|
95
|
-
},
|
|
96
|
-
);
|
|
97
|
-
}).finally(() => {
|
|
98
|
-
ImageStoreManager?.removeImageForTag?.(uri);
|
|
99
|
-
});
|
|
100
|
-
};
|
|
101
|
-
|
|
102
45
|
const CROPPER_TIMEOUT_MS = 8000;
|
|
103
46
|
const CROPPER_TIMEOUT_CODE = 'cropper_timeout';
|
|
104
47
|
|
|
@@ -531,30 +474,6 @@ export const FullDocScanner: React.FC<FullDocScannerProps> = ({
|
|
|
531
474
|
setFlashEnabled(prev => !prev);
|
|
532
475
|
}, []);
|
|
533
476
|
|
|
534
|
-
const rotateImageWithFallback = useCallback((uri: string, angle: number) => {
|
|
535
|
-
return new Promise<string>((resolve, reject) => {
|
|
536
|
-
if (!ImageRotate?.rotateImage) {
|
|
537
|
-
reject(new Error('react-native-image-rotate unavailable'));
|
|
538
|
-
return;
|
|
539
|
-
}
|
|
540
|
-
|
|
541
|
-
ImageRotate.rotateImage(
|
|
542
|
-
uri,
|
|
543
|
-
angle,
|
|
544
|
-
(rotatedUri) => resolve(rotatedUri),
|
|
545
|
-
(error) => {
|
|
546
|
-
const message =
|
|
547
|
-
typeof error === 'string'
|
|
548
|
-
? error
|
|
549
|
-
: error && typeof error === 'object' && 'message' in error
|
|
550
|
-
? String((error as any).message)
|
|
551
|
-
: 'Unknown rotation error';
|
|
552
|
-
reject(new Error(message));
|
|
553
|
-
},
|
|
554
|
-
);
|
|
555
|
-
});
|
|
556
|
-
}, []);
|
|
557
|
-
|
|
558
477
|
const handleRotateImage = useCallback(
|
|
559
478
|
(degrees: -90 | 90) => {
|
|
560
479
|
if (!isImageRotationSupported()) {
|
|
@@ -581,8 +500,9 @@ export const FullDocScanner: React.FC<FullDocScannerProps> = ({
|
|
|
581
500
|
return;
|
|
582
501
|
}
|
|
583
502
|
|
|
584
|
-
// 회전이
|
|
503
|
+
// 회전이 없으면 기존 데이터 그대로 전달
|
|
585
504
|
if (rotationDegrees === 0) {
|
|
505
|
+
console.log('[FullDocScanner] No rotation, returning original image');
|
|
586
506
|
onResult({
|
|
587
507
|
path: croppedImageData.path,
|
|
588
508
|
base64: croppedImageData.base64,
|
|
@@ -595,20 +515,26 @@ export const FullDocScanner: React.FC<FullDocScannerProps> = ({
|
|
|
595
515
|
|
|
596
516
|
// 회전 각도 정규화 (0, 90, 180, 270)
|
|
597
517
|
const rotationNormalized = ((rotationDegrees % 360) + 360) % 360;
|
|
518
|
+
console.log('[FullDocScanner] Rotation degrees:', rotationDegrees, 'normalized:', rotationNormalized);
|
|
598
519
|
|
|
599
520
|
if (rotationNormalized === 0) {
|
|
521
|
+
console.log('[FullDocScanner] Normalized to 0, returning original image');
|
|
600
522
|
onResult({
|
|
601
523
|
path: croppedImageData.path,
|
|
602
524
|
base64: croppedImageData.base64,
|
|
603
525
|
});
|
|
526
|
+
setProcessing(false);
|
|
604
527
|
return;
|
|
605
528
|
}
|
|
606
529
|
|
|
530
|
+
// expo-image-manipulator 시도
|
|
607
531
|
if (isExpoImageManipulatorAvailable() && ImageManipulator?.manipulateAsync) {
|
|
608
532
|
try {
|
|
609
|
-
|
|
533
|
+
console.log('[FullDocScanner] Using expo-image-manipulator for rotation');
|
|
534
|
+
const inputUri = ensureFileUri(croppedImageData.path);
|
|
535
|
+
|
|
610
536
|
const result = await ImageManipulator.manipulateAsync(
|
|
611
|
-
|
|
537
|
+
inputUri,
|
|
612
538
|
[{ rotate: rotationNormalized }],
|
|
613
539
|
{
|
|
614
540
|
compress: 0.9,
|
|
@@ -617,10 +543,16 @@ export const FullDocScanner: React.FC<FullDocScannerProps> = ({
|
|
|
617
543
|
},
|
|
618
544
|
);
|
|
619
545
|
|
|
620
|
-
|
|
546
|
+
console.log('[FullDocScanner] Rotation complete via expo-image-manipulator:', {
|
|
621
547
|
path: result.uri,
|
|
548
|
+
hasBase64: !!result.base64,
|
|
549
|
+
});
|
|
550
|
+
|
|
551
|
+
onResult({
|
|
552
|
+
path: stripFileUri(result.uri),
|
|
622
553
|
base64: result.base64,
|
|
623
554
|
});
|
|
555
|
+
setProcessing(false);
|
|
624
556
|
return;
|
|
625
557
|
} catch (manipulatorError) {
|
|
626
558
|
const code =
|
|
@@ -628,10 +560,12 @@ export const FullDocScanner: React.FC<FullDocScannerProps> = ({
|
|
|
628
560
|
? String((manipulatorError as any).code)
|
|
629
561
|
: undefined;
|
|
630
562
|
|
|
563
|
+
console.error('[FullDocScanner] expo-image-manipulator error:', manipulatorError);
|
|
564
|
+
|
|
631
565
|
if (code === 'ERR_UNAVAILABLE') {
|
|
632
566
|
expoManipulatorUnavailable = true;
|
|
633
567
|
console.warn(
|
|
634
|
-
'[FullDocScanner] expo-image-manipulator unavailable at runtime.
|
|
568
|
+
'[FullDocScanner] expo-image-manipulator unavailable at runtime. Trying react-native-image-rotate.',
|
|
635
569
|
);
|
|
636
570
|
} else {
|
|
637
571
|
throw manipulatorError;
|
|
@@ -639,48 +573,45 @@ export const FullDocScanner: React.FC<FullDocScannerProps> = ({
|
|
|
639
573
|
}
|
|
640
574
|
}
|
|
641
575
|
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
576
|
+
// expo-image-manipulator를 사용할 수 없는 경우 에러 처리
|
|
577
|
+
console.error(
|
|
578
|
+
'[FullDocScanner] Rotation requested but expo-image-manipulator is not available.',
|
|
579
|
+
);
|
|
580
|
+
setProcessing(false);
|
|
581
|
+
Alert.alert(
|
|
582
|
+
'회전 불가',
|
|
583
|
+
'expo-image-manipulator가 설치되지 않아 이미지 회전을 수행할 수 없습니다.\n\n패키지를 설치해주세요:\nnpm install expo-image-manipulator',
|
|
584
|
+
[
|
|
585
|
+
{
|
|
586
|
+
text: '원본 사용',
|
|
587
|
+
onPress: () => {
|
|
588
|
+
onResult({
|
|
589
|
+
path: croppedImageData.path,
|
|
590
|
+
base64: croppedImageData.base64,
|
|
591
|
+
});
|
|
592
|
+
},
|
|
593
|
+
},
|
|
594
|
+
{
|
|
595
|
+
text: '취소',
|
|
596
|
+
style: 'cancel',
|
|
597
|
+
},
|
|
598
|
+
],
|
|
599
|
+
);
|
|
600
|
+
} catch (error) {
|
|
601
|
+
console.error('[FullDocScanner] Image rotation error on confirm:', error);
|
|
602
|
+
setProcessing(false);
|
|
659
603
|
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
});
|
|
664
|
-
return;
|
|
665
|
-
}
|
|
604
|
+
const errorMessage =
|
|
605
|
+
error && typeof error === 'object' && 'message' in error ? (error as Error).message : String(error);
|
|
606
|
+
Alert.alert('회전 실패', `이미지 회전 중 오류가 발생했습니다.\n원본 이미지를 사용합니다.\n\n오류: ${errorMessage}`);
|
|
666
607
|
|
|
667
|
-
|
|
668
|
-
'[FullDocScanner] Rotation requested but no supported rotation module is available. Returning original image.',
|
|
669
|
-
);
|
|
608
|
+
// 에러 발생 시 원본 이미지 반환
|
|
670
609
|
onResult({
|
|
671
610
|
path: croppedImageData.path,
|
|
672
611
|
base64: croppedImageData.base64,
|
|
673
612
|
});
|
|
674
|
-
} catch (error) {
|
|
675
|
-
console.error('[FullDocScanner] Image rotation error on confirm:', error);
|
|
676
|
-
|
|
677
|
-
const errorMessage =
|
|
678
|
-
error && typeof error === 'object' && 'message' in error ? (error as Error).message : '';
|
|
679
|
-
Alert.alert('회전 실패', '이미지 회전 중 오류가 발생했습니다: ' + errorMessage);
|
|
680
|
-
} finally {
|
|
681
|
-
setProcessing(false);
|
|
682
613
|
}
|
|
683
|
-
}, [croppedImageData, rotationDegrees, onResult
|
|
614
|
+
}, [croppedImageData, rotationDegrees, onResult]);
|
|
684
615
|
|
|
685
616
|
const handleRetake = useCallback(() => {
|
|
686
617
|
console.log('[FullDocScanner] Retake - clearing cropped image and resetting scanner');
|