react-native-rectangle-doc-scanner 3.108.0 → 3.109.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.
@@ -59,9 +59,10 @@ try {
59
59
  catch (error) {
60
60
  console.warn('[FullDocScanner] react-native-image-rotate module unavailable. Image rotation fallback disabled.', error);
61
61
  }
62
- const isExpoImageManipulatorAvailable = !!ImageManipulator?.manipulateAsync;
62
+ let expoManipulatorUnavailable = false;
63
+ const isExpoImageManipulatorAvailable = () => !!ImageManipulator?.manipulateAsync && !expoManipulatorUnavailable;
63
64
  const isImageRotateAvailable = !!ImageRotate?.rotateImage;
64
- const isImageRotationSupported = isExpoImageManipulatorAvailable || isImageRotateAvailable;
65
+ const isImageRotationSupported = () => isExpoImageManipulatorAvailable() || isImageRotateAvailable;
65
66
  const stripFileUri = (value) => value.replace(/^file:\/\//, '');
66
67
  const ensureFileUri = (value) => (value.startsWith('file://') ? value : `file://${value}`);
67
68
  const getBase64FromImageStore = async (uri) => {
@@ -398,7 +399,7 @@ const FullDocScanner = ({ onResult, onClose, detectionConfig, overlayColor = '#3
398
399
  });
399
400
  }, []);
400
401
  const handleRotateImage = (0, react_1.useCallback)((degrees) => {
401
- if (!isImageRotationSupported) {
402
+ if (!isImageRotationSupported()) {
402
403
  console.warn('[FullDocScanner] Image rotation requested but no rotation module is available.');
403
404
  return;
404
405
  }
@@ -436,18 +437,32 @@ const FullDocScanner = ({ onResult, onClose, detectionConfig, overlayColor = '#3
436
437
  });
437
438
  return;
438
439
  }
439
- if (isExpoImageManipulatorAvailable && ImageManipulator?.manipulateAsync) {
440
- // expo-image-manipulator로 이미지 회전
441
- const result = await ImageManipulator.manipulateAsync(croppedImageData.path, [{ rotate: rotationNormalized }], {
442
- compress: 0.9,
443
- format: ImageManipulator.SaveFormat.JPEG,
444
- base64: true,
445
- });
446
- onResult({
447
- path: result.uri,
448
- base64: result.base64,
449
- });
450
- return;
440
+ if (isExpoImageManipulatorAvailable() && ImageManipulator?.manipulateAsync) {
441
+ try {
442
+ // expo-image-manipulator로 이미지 회전
443
+ const result = await ImageManipulator.manipulateAsync(croppedImageData.path, [{ rotate: rotationNormalized }], {
444
+ compress: 0.9,
445
+ format: ImageManipulator.SaveFormat.JPEG,
446
+ base64: true,
447
+ });
448
+ onResult({
449
+ path: result.uri,
450
+ base64: result.base64,
451
+ });
452
+ return;
453
+ }
454
+ catch (manipulatorError) {
455
+ const code = manipulatorError && typeof manipulatorError === 'object' && 'code' in manipulatorError
456
+ ? String(manipulatorError.code)
457
+ : undefined;
458
+ if (code === 'ERR_UNAVAILABLE') {
459
+ expoManipulatorUnavailable = true;
460
+ console.warn('[FullDocScanner] expo-image-manipulator unavailable at runtime. Falling back to react-native-image-rotate if possible.');
461
+ }
462
+ else {
463
+ throw manipulatorError;
464
+ }
465
+ }
451
466
  }
452
467
  if (isImageRotateAvailable && ImageRotate?.rotateImage) {
453
468
  const sourceUri = ensureFileUri(croppedImageData.path);
@@ -559,7 +574,7 @@ const FullDocScanner = ({ onResult, onClose, detectionConfig, overlayColor = '#3
559
574
  croppedImageData ? (
560
575
  // check_DP: Show confirmation screen
561
576
  react_1.default.createElement(react_native_1.View, { style: styles.confirmationContainer },
562
- isImageRotationSupported ? (react_1.default.createElement(react_native_1.View, { style: styles.rotateButtonsCenter },
577
+ isImageRotationSupported() ? (react_1.default.createElement(react_native_1.View, { style: styles.rotateButtonsCenter },
563
578
  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" },
564
579
  react_1.default.createElement(react_native_1.Text, { style: styles.rotateIconText }, "\u21BA"),
565
580
  react_1.default.createElement(react_native_1.Text, { style: styles.rotateButtonLabel }, "\uC88C\uB85C 90\u00B0")),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-rectangle-doc-scanner",
3
- "version": "3.108.0",
3
+ "version": "3.109.0",
4
4
  "description": "Native-backed document scanner for React Native with customizable overlays.",
5
5
  "license": "MIT",
6
6
  "main": "dist/index.js",
@@ -64,9 +64,11 @@ try {
64
64
  );
65
65
  }
66
66
 
67
- const isExpoImageManipulatorAvailable = !!ImageManipulator?.manipulateAsync;
67
+ let expoManipulatorUnavailable = false;
68
+ const isExpoImageManipulatorAvailable = () =>
69
+ !!ImageManipulator?.manipulateAsync && !expoManipulatorUnavailable;
68
70
  const isImageRotateAvailable = !!ImageRotate?.rotateImage;
69
- const isImageRotationSupported = isExpoImageManipulatorAvailable || isImageRotateAvailable;
71
+ const isImageRotationSupported = () => isExpoImageManipulatorAvailable() || isImageRotateAvailable;
70
72
 
71
73
  const stripFileUri = (value: string) => value.replace(/^file:\/\//, '');
72
74
  const ensureFileUri = (value: string) => (value.startsWith('file://') ? value : `file://${value}`);
@@ -555,7 +557,7 @@ export const FullDocScanner: React.FC<FullDocScannerProps> = ({
555
557
 
556
558
  const handleRotateImage = useCallback(
557
559
  (degrees: -90 | 90) => {
558
- if (!isImageRotationSupported) {
560
+ if (!isImageRotationSupported()) {
559
561
  console.warn(
560
562
  '[FullDocScanner] Image rotation requested but no rotation module is available.',
561
563
  );
@@ -602,23 +604,39 @@ export const FullDocScanner: React.FC<FullDocScannerProps> = ({
602
604
  return;
603
605
  }
604
606
 
605
- if (isExpoImageManipulatorAvailable && ImageManipulator?.manipulateAsync) {
606
- // expo-image-manipulator로 이미지 회전
607
- const result = await ImageManipulator.manipulateAsync(
608
- croppedImageData.path,
609
- [{ rotate: rotationNormalized }],
610
- {
611
- compress: 0.9,
612
- format: ImageManipulator.SaveFormat.JPEG,
613
- base64: true,
614
- },
615
- );
607
+ if (isExpoImageManipulatorAvailable() && ImageManipulator?.manipulateAsync) {
608
+ try {
609
+ // expo-image-manipulator로 이미지 회전
610
+ const result = await ImageManipulator.manipulateAsync(
611
+ croppedImageData.path,
612
+ [{ rotate: rotationNormalized }],
613
+ {
614
+ compress: 0.9,
615
+ format: ImageManipulator.SaveFormat.JPEG,
616
+ base64: true,
617
+ },
618
+ );
616
619
 
617
- onResult({
618
- path: result.uri,
619
- base64: result.base64,
620
- });
621
- return;
620
+ onResult({
621
+ path: result.uri,
622
+ base64: result.base64,
623
+ });
624
+ return;
625
+ } catch (manipulatorError) {
626
+ const code =
627
+ manipulatorError && typeof manipulatorError === 'object' && 'code' in manipulatorError
628
+ ? String((manipulatorError as any).code)
629
+ : undefined;
630
+
631
+ if (code === 'ERR_UNAVAILABLE') {
632
+ expoManipulatorUnavailable = true;
633
+ console.warn(
634
+ '[FullDocScanner] expo-image-manipulator unavailable at runtime. Falling back to react-native-image-rotate if possible.',
635
+ );
636
+ } else {
637
+ throw manipulatorError;
638
+ }
639
+ }
622
640
  }
623
641
 
624
642
  if (isImageRotateAvailable && ImageRotate?.rotateImage) {
@@ -750,7 +768,7 @@ export const FullDocScanner: React.FC<FullDocScannerProps> = ({
750
768
  // check_DP: Show confirmation screen
751
769
  <View style={styles.confirmationContainer}>
752
770
  {/* 회전 버튼들 - 가운데 정렬 */}
753
- {isImageRotationSupported ? (
771
+ {isImageRotationSupported() ? (
754
772
  <View style={styles.rotateButtonsCenter}>
755
773
  <TouchableOpacity
756
774
  style={styles.rotateButtonTop}