react-native-rectangle-doc-scanner 3.110.0 → 3.112.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.d.ts +2 -0
- package/dist/FullDocScanner.js +14 -140
- package/package.json +1 -1
- package/src/FullDocScanner.tsx +16 -183
package/dist/FullDocScanner.d.ts
CHANGED
|
@@ -8,6 +8,8 @@ export interface FullDocScannerResult {
|
|
|
8
8
|
base64?: string;
|
|
9
9
|
/** Original captured document info */
|
|
10
10
|
original?: CapturedDocument;
|
|
11
|
+
/** Rotation angle applied by user (0, 90, 180, 270) */
|
|
12
|
+
rotationDegrees?: number;
|
|
11
13
|
}
|
|
12
14
|
export interface FullDocScannerStrings {
|
|
13
15
|
captureHint?: string;
|
package/dist/FullDocScanner.js
CHANGED
|
@@ -44,26 +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
47
|
try {
|
|
49
48
|
ImageManipulator = require('expo-image-manipulator');
|
|
50
49
|
}
|
|
51
50
|
catch (error) {
|
|
52
|
-
console.warn('[FullDocScanner] expo-image-manipulator module unavailable.
|
|
53
|
-
}
|
|
54
|
-
try {
|
|
55
|
-
const rotateModule = require('react-native-image-rotate');
|
|
56
|
-
ImageRotate = (rotateModule?.default ?? rotateModule);
|
|
57
|
-
}
|
|
58
|
-
catch (error) {
|
|
59
|
-
console.warn('[FullDocScanner] react-native-image-rotate module unavailable. Image rotation fallback disabled.', error);
|
|
51
|
+
console.warn('[FullDocScanner] expo-image-manipulator module unavailable.', error);
|
|
60
52
|
}
|
|
61
53
|
let expoManipulatorUnavailable = false;
|
|
62
54
|
const isExpoImageManipulatorAvailable = () => !!ImageManipulator?.manipulateAsync && !expoManipulatorUnavailable;
|
|
63
|
-
|
|
64
|
-
const isImageRotationSupported = () =>
|
|
55
|
+
// 회전은 항상 지원됨 (회전 각도를 반환하고 tdb 앱에서 처리)
|
|
56
|
+
const isImageRotationSupported = () => true;
|
|
65
57
|
const stripFileUri = (value) => value.replace(/^file:\/\//, '');
|
|
66
|
-
const ensureFileUri = (value) => (value.startsWith('file://') ? value : `file://${value}`);
|
|
67
58
|
const CROPPER_TIMEOUT_MS = 8000;
|
|
68
59
|
const CROPPER_TIMEOUT_CODE = 'cropper_timeout';
|
|
69
60
|
const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
@@ -363,22 +354,6 @@ const FullDocScanner = ({ onResult, onClose, detectionConfig, overlayColor = '#3
|
|
|
363
354
|
const handleFlashToggle = (0, react_1.useCallback)(() => {
|
|
364
355
|
setFlashEnabled(prev => !prev);
|
|
365
356
|
}, []);
|
|
366
|
-
const rotateImageWithFallback = (0, react_1.useCallback)((uri, angle) => {
|
|
367
|
-
return new Promise((resolve, reject) => {
|
|
368
|
-
if (!ImageRotate?.rotateImage) {
|
|
369
|
-
reject(new Error('react-native-image-rotate unavailable'));
|
|
370
|
-
return;
|
|
371
|
-
}
|
|
372
|
-
ImageRotate.rotateImage(uri, angle, (rotatedUri) => resolve(rotatedUri), (error) => {
|
|
373
|
-
const message = typeof error === 'string'
|
|
374
|
-
? error
|
|
375
|
-
: error && typeof error === 'object' && 'message' in error
|
|
376
|
-
? String(error.message)
|
|
377
|
-
: 'Unknown rotation error';
|
|
378
|
-
reject(new Error(message));
|
|
379
|
-
});
|
|
380
|
-
});
|
|
381
|
-
}, []);
|
|
382
357
|
const handleRotateImage = (0, react_1.useCallback)((degrees) => {
|
|
383
358
|
if (!isImageRotationSupported()) {
|
|
384
359
|
console.warn('[FullDocScanner] Image rotation requested but no rotation module is available.');
|
|
@@ -399,118 +374,17 @@ const FullDocScanner = ({ onResult, onClose, detectionConfig, overlayColor = '#3
|
|
|
399
374
|
if (!croppedImageData) {
|
|
400
375
|
return;
|
|
401
376
|
}
|
|
402
|
-
//
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
// 회전 각도 정규화 (0, 90, 180, 270)
|
|
414
|
-
const rotationNormalized = ((rotationDegrees % 360) + 360) % 360;
|
|
415
|
-
console.log('[FullDocScanner] Rotation degrees:', rotationDegrees, 'normalized:', rotationNormalized);
|
|
416
|
-
if (rotationNormalized === 0) {
|
|
417
|
-
console.log('[FullDocScanner] Normalized to 0, returning original image');
|
|
418
|
-
onResult({
|
|
419
|
-
path: croppedImageData.path,
|
|
420
|
-
base64: croppedImageData.base64,
|
|
421
|
-
});
|
|
422
|
-
setProcessing(false);
|
|
423
|
-
return;
|
|
424
|
-
}
|
|
425
|
-
// expo-image-manipulator 시도
|
|
426
|
-
if (isExpoImageManipulatorAvailable() && ImageManipulator?.manipulateAsync) {
|
|
427
|
-
try {
|
|
428
|
-
console.log('[FullDocScanner] Using expo-image-manipulator for rotation');
|
|
429
|
-
const inputUri = ensureFileUri(croppedImageData.path);
|
|
430
|
-
const result = await ImageManipulator.manipulateAsync(inputUri, [{ rotate: rotationNormalized }], {
|
|
431
|
-
compress: 0.9,
|
|
432
|
-
format: ImageManipulator.SaveFormat.JPEG,
|
|
433
|
-
base64: true,
|
|
434
|
-
});
|
|
435
|
-
console.log('[FullDocScanner] Rotation complete via expo-image-manipulator:', {
|
|
436
|
-
path: result.uri,
|
|
437
|
-
hasBase64: !!result.base64,
|
|
438
|
-
});
|
|
439
|
-
onResult({
|
|
440
|
-
path: stripFileUri(result.uri),
|
|
441
|
-
base64: result.base64,
|
|
442
|
-
});
|
|
443
|
-
setProcessing(false);
|
|
444
|
-
return;
|
|
445
|
-
}
|
|
446
|
-
catch (manipulatorError) {
|
|
447
|
-
const code = manipulatorError && typeof manipulatorError === 'object' && 'code' in manipulatorError
|
|
448
|
-
? String(manipulatorError.code)
|
|
449
|
-
: undefined;
|
|
450
|
-
console.error('[FullDocScanner] expo-image-manipulator error:', manipulatorError);
|
|
451
|
-
if (code === 'ERR_UNAVAILABLE') {
|
|
452
|
-
expoManipulatorUnavailable = true;
|
|
453
|
-
console.warn('[FullDocScanner] expo-image-manipulator unavailable at runtime. Trying react-native-image-rotate.');
|
|
454
|
-
}
|
|
455
|
-
else {
|
|
456
|
-
throw manipulatorError;
|
|
457
|
-
}
|
|
458
|
-
}
|
|
459
|
-
}
|
|
460
|
-
// react-native-image-rotate 시도 (ImageStore 사용 안 함)
|
|
461
|
-
if (isImageRotateAvailable && ImageRotate?.rotateImage) {
|
|
462
|
-
console.log('[FullDocScanner] Using react-native-image-rotate for rotation');
|
|
463
|
-
const sourceUri = ensureFileUri(croppedImageData.path);
|
|
464
|
-
try {
|
|
465
|
-
const rotatedUri = await rotateImageWithFallback(sourceUri, rotationNormalized);
|
|
466
|
-
console.log('[FullDocScanner] Image rotated via react-native-image-rotate:', rotatedUri);
|
|
467
|
-
// rotatedUri를 파일로 저장하고 base64 생성
|
|
468
|
-
const destinationPath = `${react_native_fs_1.default.CachesDirectoryPath}/rotated_img_${Date.now()}.jpeg`;
|
|
469
|
-
// rotatedUri는 이미 file://로 시작하므로 stripFileUri로 정리
|
|
470
|
-
const cleanRotatedUri = stripFileUri(rotatedUri);
|
|
471
|
-
// 파일 복사
|
|
472
|
-
await react_native_fs_1.default.copyFile(cleanRotatedUri, destinationPath);
|
|
473
|
-
console.log('[FullDocScanner] Copied rotated file to:', destinationPath);
|
|
474
|
-
// Base64 생성
|
|
475
|
-
const base64Data = await react_native_fs_1.default.readFile(destinationPath, 'base64');
|
|
476
|
-
console.log('[FullDocScanner] Got result:', {
|
|
477
|
-
path: destinationPath,
|
|
478
|
-
hasBase64: true,
|
|
479
|
-
base64Length: base64Data.length,
|
|
480
|
-
});
|
|
481
|
-
onResult({
|
|
482
|
-
path: destinationPath,
|
|
483
|
-
base64: base64Data,
|
|
484
|
-
});
|
|
485
|
-
setProcessing(false);
|
|
486
|
-
return;
|
|
487
|
-
}
|
|
488
|
-
catch (rotateError) {
|
|
489
|
-
console.error('[FullDocScanner] react-native-image-rotate error:', rotateError);
|
|
490
|
-
throw rotateError;
|
|
491
|
-
}
|
|
492
|
-
}
|
|
493
|
-
// 회전 불가능한 경우 경고 후 원본 반환
|
|
494
|
-
console.warn('[FullDocScanner] Rotation requested but no supported rotation module is available. Returning original image.');
|
|
495
|
-
react_native_1.Alert.alert('알림', '이미지 회전 기능을 사용할 수 없습니다. 원본 이미지를 사용합니다.');
|
|
496
|
-
onResult({
|
|
497
|
-
path: croppedImageData.path,
|
|
498
|
-
base64: croppedImageData.base64,
|
|
499
|
-
});
|
|
500
|
-
setProcessing(false);
|
|
501
|
-
}
|
|
502
|
-
catch (error) {
|
|
503
|
-
console.error('[FullDocScanner] Image rotation error on confirm:', error);
|
|
504
|
-
setProcessing(false);
|
|
505
|
-
const errorMessage = error && typeof error === 'object' && 'message' in error ? error.message : String(error);
|
|
506
|
-
react_native_1.Alert.alert('회전 실패', `이미지 회전 중 오류가 발생했습니다.\n원본 이미지를 사용합니다.\n\n오류: ${errorMessage}`);
|
|
507
|
-
// 에러 발생 시 원본 이미지 반환
|
|
508
|
-
onResult({
|
|
509
|
-
path: croppedImageData.path,
|
|
510
|
-
base64: croppedImageData.base64,
|
|
511
|
-
});
|
|
512
|
-
}
|
|
513
|
-
}, [croppedImageData, rotationDegrees, onResult, rotateImageWithFallback]);
|
|
377
|
+
// 회전 각도 정규화 (0, 90, 180, 270)
|
|
378
|
+
const rotationNormalized = ((rotationDegrees % 360) + 360) % 360;
|
|
379
|
+
console.log('[FullDocScanner] Confirm - rotation degrees:', rotationDegrees, 'normalized:', rotationNormalized);
|
|
380
|
+
// 원본 이미지와 회전 각도를 함께 반환
|
|
381
|
+
// tdb 앱에서 expo-image-manipulator를 사용해서 회전 처리
|
|
382
|
+
onResult({
|
|
383
|
+
path: croppedImageData.path,
|
|
384
|
+
base64: croppedImageData.base64,
|
|
385
|
+
rotationDegrees: rotationNormalized,
|
|
386
|
+
});
|
|
387
|
+
}, [croppedImageData, rotationDegrees, onResult]);
|
|
514
388
|
const handleRetake = (0, react_1.useCallback)(() => {
|
|
515
389
|
console.log('[FullDocScanner] Retake - clearing cropped image and resetting scanner');
|
|
516
390
|
setCroppedImageData(null);
|
package/package.json
CHANGED
package/src/FullDocScanner.tsx
CHANGED
|
@@ -22,33 +22,14 @@ import type {
|
|
|
22
22
|
} from './DocScanner';
|
|
23
23
|
|
|
24
24
|
type ImageManipulatorModule = typeof import('expo-image-manipulator');
|
|
25
|
-
type ImageRotateModule = {
|
|
26
|
-
rotateImage: (
|
|
27
|
-
uri: string,
|
|
28
|
-
angle: number,
|
|
29
|
-
onSuccess: (uri: string) => void,
|
|
30
|
-
onError: (error: unknown) => void,
|
|
31
|
-
) => void;
|
|
32
|
-
} | null;
|
|
33
25
|
|
|
34
26
|
let ImageManipulator: ImageManipulatorModule | null = null;
|
|
35
|
-
let ImageRotate: ImageRotateModule = null;
|
|
36
27
|
|
|
37
28
|
try {
|
|
38
29
|
ImageManipulator = require('expo-image-manipulator') as ImageManipulatorModule;
|
|
39
30
|
} catch (error) {
|
|
40
31
|
console.warn(
|
|
41
|
-
'[FullDocScanner] expo-image-manipulator module unavailable.
|
|
42
|
-
error,
|
|
43
|
-
);
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
try {
|
|
47
|
-
const rotateModule = require('react-native-image-rotate');
|
|
48
|
-
ImageRotate = (rotateModule?.default ?? rotateModule) as ImageRotateModule;
|
|
49
|
-
} catch (error) {
|
|
50
|
-
console.warn(
|
|
51
|
-
'[FullDocScanner] react-native-image-rotate module unavailable. Image rotation fallback disabled.',
|
|
32
|
+
'[FullDocScanner] expo-image-manipulator module unavailable.',
|
|
52
33
|
error,
|
|
53
34
|
);
|
|
54
35
|
}
|
|
@@ -56,11 +37,10 @@ try {
|
|
|
56
37
|
let expoManipulatorUnavailable = false;
|
|
57
38
|
const isExpoImageManipulatorAvailable = () =>
|
|
58
39
|
!!ImageManipulator?.manipulateAsync && !expoManipulatorUnavailable;
|
|
59
|
-
|
|
60
|
-
const isImageRotationSupported = () =>
|
|
40
|
+
// 회전은 항상 지원됨 (회전 각도를 반환하고 tdb 앱에서 처리)
|
|
41
|
+
const isImageRotationSupported = () => true;
|
|
61
42
|
|
|
62
43
|
const stripFileUri = (value: string) => value.replace(/^file:\/\//, '');
|
|
63
|
-
const ensureFileUri = (value: string) => (value.startsWith('file://') ? value : `file://${value}`);
|
|
64
44
|
|
|
65
45
|
const CROPPER_TIMEOUT_MS = 8000;
|
|
66
46
|
const CROPPER_TIMEOUT_CODE = 'cropper_timeout';
|
|
@@ -142,6 +122,8 @@ export interface FullDocScannerResult {
|
|
|
142
122
|
base64?: string;
|
|
143
123
|
/** Original captured document info */
|
|
144
124
|
original?: CapturedDocument;
|
|
125
|
+
/** Rotation angle applied by user (0, 90, 180, 270) */
|
|
126
|
+
rotationDegrees?: number;
|
|
145
127
|
}
|
|
146
128
|
|
|
147
129
|
export interface FullDocScannerStrings {
|
|
@@ -494,30 +476,6 @@ export const FullDocScanner: React.FC<FullDocScannerProps> = ({
|
|
|
494
476
|
setFlashEnabled(prev => !prev);
|
|
495
477
|
}, []);
|
|
496
478
|
|
|
497
|
-
const rotateImageWithFallback = useCallback((uri: string, angle: number) => {
|
|
498
|
-
return new Promise<string>((resolve, reject) => {
|
|
499
|
-
if (!ImageRotate?.rotateImage) {
|
|
500
|
-
reject(new Error('react-native-image-rotate unavailable'));
|
|
501
|
-
return;
|
|
502
|
-
}
|
|
503
|
-
|
|
504
|
-
ImageRotate.rotateImage(
|
|
505
|
-
uri,
|
|
506
|
-
angle,
|
|
507
|
-
(rotatedUri) => resolve(rotatedUri),
|
|
508
|
-
(error) => {
|
|
509
|
-
const message =
|
|
510
|
-
typeof error === 'string'
|
|
511
|
-
? error
|
|
512
|
-
: error && typeof error === 'object' && 'message' in error
|
|
513
|
-
? String((error as any).message)
|
|
514
|
-
: 'Unknown rotation error';
|
|
515
|
-
reject(new Error(message));
|
|
516
|
-
},
|
|
517
|
-
);
|
|
518
|
-
});
|
|
519
|
-
}, []);
|
|
520
|
-
|
|
521
479
|
const handleRotateImage = useCallback(
|
|
522
480
|
(degrees: -90 | 90) => {
|
|
523
481
|
if (!isImageRotationSupported()) {
|
|
@@ -544,143 +502,18 @@ export const FullDocScanner: React.FC<FullDocScannerProps> = ({
|
|
|
544
502
|
return;
|
|
545
503
|
}
|
|
546
504
|
|
|
547
|
-
//
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
onResult({
|
|
551
|
-
path: croppedImageData.path,
|
|
552
|
-
base64: croppedImageData.base64,
|
|
553
|
-
});
|
|
554
|
-
return;
|
|
555
|
-
}
|
|
556
|
-
|
|
557
|
-
try {
|
|
558
|
-
setProcessing(true);
|
|
559
|
-
|
|
560
|
-
// 회전 각도 정규화 (0, 90, 180, 270)
|
|
561
|
-
const rotationNormalized = ((rotationDegrees % 360) + 360) % 360;
|
|
562
|
-
console.log('[FullDocScanner] Rotation degrees:', rotationDegrees, 'normalized:', rotationNormalized);
|
|
563
|
-
|
|
564
|
-
if (rotationNormalized === 0) {
|
|
565
|
-
console.log('[FullDocScanner] Normalized to 0, returning original image');
|
|
566
|
-
onResult({
|
|
567
|
-
path: croppedImageData.path,
|
|
568
|
-
base64: croppedImageData.base64,
|
|
569
|
-
});
|
|
570
|
-
setProcessing(false);
|
|
571
|
-
return;
|
|
572
|
-
}
|
|
573
|
-
|
|
574
|
-
// expo-image-manipulator 시도
|
|
575
|
-
if (isExpoImageManipulatorAvailable() && ImageManipulator?.manipulateAsync) {
|
|
576
|
-
try {
|
|
577
|
-
console.log('[FullDocScanner] Using expo-image-manipulator for rotation');
|
|
578
|
-
const inputUri = ensureFileUri(croppedImageData.path);
|
|
579
|
-
|
|
580
|
-
const result = await ImageManipulator.manipulateAsync(
|
|
581
|
-
inputUri,
|
|
582
|
-
[{ rotate: rotationNormalized }],
|
|
583
|
-
{
|
|
584
|
-
compress: 0.9,
|
|
585
|
-
format: ImageManipulator.SaveFormat.JPEG,
|
|
586
|
-
base64: true,
|
|
587
|
-
},
|
|
588
|
-
);
|
|
505
|
+
// 회전 각도 정규화 (0, 90, 180, 270)
|
|
506
|
+
const rotationNormalized = ((rotationDegrees % 360) + 360) % 360;
|
|
507
|
+
console.log('[FullDocScanner] Confirm - rotation degrees:', rotationDegrees, 'normalized:', rotationNormalized);
|
|
589
508
|
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
});
|
|
599
|
-
setProcessing(false);
|
|
600
|
-
return;
|
|
601
|
-
} catch (manipulatorError) {
|
|
602
|
-
const code =
|
|
603
|
-
manipulatorError && typeof manipulatorError === 'object' && 'code' in manipulatorError
|
|
604
|
-
? String((manipulatorError as any).code)
|
|
605
|
-
: undefined;
|
|
606
|
-
|
|
607
|
-
console.error('[FullDocScanner] expo-image-manipulator error:', manipulatorError);
|
|
608
|
-
|
|
609
|
-
if (code === 'ERR_UNAVAILABLE') {
|
|
610
|
-
expoManipulatorUnavailable = true;
|
|
611
|
-
console.warn(
|
|
612
|
-
'[FullDocScanner] expo-image-manipulator unavailable at runtime. Trying react-native-image-rotate.',
|
|
613
|
-
);
|
|
614
|
-
} else {
|
|
615
|
-
throw manipulatorError;
|
|
616
|
-
}
|
|
617
|
-
}
|
|
618
|
-
}
|
|
619
|
-
|
|
620
|
-
// react-native-image-rotate 시도 (ImageStore 사용 안 함)
|
|
621
|
-
if (isImageRotateAvailable && ImageRotate?.rotateImage) {
|
|
622
|
-
console.log('[FullDocScanner] Using react-native-image-rotate for rotation');
|
|
623
|
-
const sourceUri = ensureFileUri(croppedImageData.path);
|
|
624
|
-
|
|
625
|
-
try {
|
|
626
|
-
const rotatedUri = await rotateImageWithFallback(sourceUri, rotationNormalized);
|
|
627
|
-
console.log('[FullDocScanner] Image rotated via react-native-image-rotate:', rotatedUri);
|
|
628
|
-
|
|
629
|
-
// rotatedUri를 파일로 저장하고 base64 생성
|
|
630
|
-
const destinationPath = `${RNFS.CachesDirectoryPath}/rotated_img_${Date.now()}.jpeg`;
|
|
631
|
-
|
|
632
|
-
// rotatedUri는 이미 file://로 시작하므로 stripFileUri로 정리
|
|
633
|
-
const cleanRotatedUri = stripFileUri(rotatedUri);
|
|
634
|
-
|
|
635
|
-
// 파일 복사
|
|
636
|
-
await RNFS.copyFile(cleanRotatedUri, destinationPath);
|
|
637
|
-
console.log('[FullDocScanner] Copied rotated file to:', destinationPath);
|
|
638
|
-
|
|
639
|
-
// Base64 생성
|
|
640
|
-
const base64Data = await RNFS.readFile(destinationPath, 'base64');
|
|
641
|
-
console.log('[FullDocScanner] Got result:', {
|
|
642
|
-
path: destinationPath,
|
|
643
|
-
hasBase64: true,
|
|
644
|
-
base64Length: base64Data.length,
|
|
645
|
-
});
|
|
646
|
-
|
|
647
|
-
onResult({
|
|
648
|
-
path: destinationPath,
|
|
649
|
-
base64: base64Data,
|
|
650
|
-
});
|
|
651
|
-
setProcessing(false);
|
|
652
|
-
return;
|
|
653
|
-
} catch (rotateError) {
|
|
654
|
-
console.error('[FullDocScanner] react-native-image-rotate error:', rotateError);
|
|
655
|
-
throw rotateError;
|
|
656
|
-
}
|
|
657
|
-
}
|
|
658
|
-
|
|
659
|
-
// 회전 불가능한 경우 경고 후 원본 반환
|
|
660
|
-
console.warn(
|
|
661
|
-
'[FullDocScanner] Rotation requested but no supported rotation module is available. Returning original image.',
|
|
662
|
-
);
|
|
663
|
-
Alert.alert('알림', '이미지 회전 기능을 사용할 수 없습니다. 원본 이미지를 사용합니다.');
|
|
664
|
-
onResult({
|
|
665
|
-
path: croppedImageData.path,
|
|
666
|
-
base64: croppedImageData.base64,
|
|
667
|
-
});
|
|
668
|
-
setProcessing(false);
|
|
669
|
-
} catch (error) {
|
|
670
|
-
console.error('[FullDocScanner] Image rotation error on confirm:', error);
|
|
671
|
-
setProcessing(false);
|
|
672
|
-
|
|
673
|
-
const errorMessage =
|
|
674
|
-
error && typeof error === 'object' && 'message' in error ? (error as Error).message : String(error);
|
|
675
|
-
Alert.alert('회전 실패', `이미지 회전 중 오류가 발생했습니다.\n원본 이미지를 사용합니다.\n\n오류: ${errorMessage}`);
|
|
676
|
-
|
|
677
|
-
// 에러 발생 시 원본 이미지 반환
|
|
678
|
-
onResult({
|
|
679
|
-
path: croppedImageData.path,
|
|
680
|
-
base64: croppedImageData.base64,
|
|
681
|
-
});
|
|
682
|
-
}
|
|
683
|
-
}, [croppedImageData, rotationDegrees, onResult, rotateImageWithFallback]);
|
|
509
|
+
// 원본 이미지와 회전 각도를 함께 반환
|
|
510
|
+
// tdb 앱에서 expo-image-manipulator를 사용해서 회전 처리
|
|
511
|
+
onResult({
|
|
512
|
+
path: croppedImageData.path,
|
|
513
|
+
base64: croppedImageData.base64,
|
|
514
|
+
rotationDegrees: rotationNormalized,
|
|
515
|
+
});
|
|
516
|
+
}, [croppedImageData, rotationDegrees, onResult]);
|
|
684
517
|
|
|
685
518
|
const handleRetake = useCallback(() => {
|
|
686
519
|
console.log('[FullDocScanner] Retake - clearing cropped image and resetting scanner');
|