react-native-rectangle-doc-scanner 3.93.0 → 3.95.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.
@@ -41,6 +41,7 @@ const react_1 = __importStar(require("react"));
41
41
  const react_native_1 = require("react-native");
42
42
  const react_native_image_picker_1 = require("react-native-image-picker");
43
43
  const react_native_image_crop_picker_1 = __importDefault(require("react-native-image-crop-picker"));
44
+ const react_native_image_rotate_1 = __importDefault(require("react-native-image-rotate"));
44
45
  const DocScanner_1 = require("./DocScanner");
45
46
  const stripFileUri = (value) => value.replace(/^file:\/\//, '');
46
47
  const CROPPER_TIMEOUT_MS = 8000;
@@ -329,53 +330,44 @@ const FullDocScanner = ({ onResult, onClose, detectionConfig, overlayColor = '#3
329
330
  const handleFlashToggle = (0, react_1.useCallback)(() => {
330
331
  setFlashEnabled(prev => !prev);
331
332
  }, []);
332
- const handleRotateImage = (0, react_1.useCallback)((degrees) => {
333
+ const handleRotateImage = (0, react_1.useCallback)(async (degrees) => {
333
334
  if (!croppedImageData)
334
335
  return;
335
- setRotationDegrees(prev => {
336
- const newRotation = (prev + degrees + 360) % 360;
337
- return newRotation;
338
- });
339
- }, [croppedImageData]);
340
- const handleConfirm = (0, react_1.useCallback)(async () => {
341
- if (!croppedImageData)
342
- return;
343
- // 회전이 필요한 경우 실제로 이미지를 회전
344
- if (rotationDegrees !== 0) {
345
- try {
346
- const rotatedImage = await react_native_image_crop_picker_1.default.openCropper({
347
- path: croppedImageData.path,
348
- mediaType: 'photo',
349
- cropping: true,
350
- freeStyleCropEnabled: true,
351
- includeBase64: true,
352
- compressImageQuality: 0.9,
353
- cropperToolbarTitle: ' ',
354
- cropperChooseText: '완료',
355
- cropperCancelText: '취소',
356
- cropperRotateButtonsHidden: false,
357
- });
358
- onResult({
359
- path: rotatedImage.path,
360
- base64: rotatedImage.data ?? undefined,
361
- });
362
- }
363
- catch (error) {
364
- console.error('[FullDocScanner] Image rotation error:', error);
365
- // 에러 발생 시 원본 이미지 전송
366
- onResult({
367
- path: croppedImageData.path,
368
- base64: croppedImageData.base64,
369
- });
370
- }
336
+ try {
337
+ // UI 회전 상태 먼저 업데이트 (즉각 반응)
338
+ setRotationDegrees(prev => {
339
+ const newRotation = (prev + degrees + 360) % 360;
340
+ return newRotation;
341
+ });
342
+ console.log('[FullDocScanner] Starting image rotation...');
343
+ // ImageRotate를 사용해서 실제로 이미지 회전 (UI 없이)
344
+ const rotatedImagePath = await react_native_image_rotate_1.default.rotateImage(croppedImageData.path, degrees);
345
+ console.log('[FullDocScanner] Image rotated successfully:', rotatedImagePath);
346
+ // 회전된 이미지로 교체
347
+ setCroppedImageData({
348
+ path: rotatedImagePath,
349
+ base64: undefined, // base64는 다시 읽어야 함
350
+ });
351
+ // rotation degrees는 0으로 리셋 (이미 실제 파일에 적용되었으므로)
352
+ setRotationDegrees(0);
371
353
  }
372
- else {
373
- onResult({
374
- path: croppedImageData.path,
375
- base64: croppedImageData.base64,
354
+ catch (error) {
355
+ console.error('[FullDocScanner] Image rotation error:', error);
356
+ // 에러 발생 시 UI rotation 원복
357
+ setRotationDegrees(prev => {
358
+ const revertRotation = (prev - degrees + 360) % 360;
359
+ return revertRotation;
376
360
  });
377
361
  }
378
- }, [croppedImageData, rotationDegrees, onResult]);
362
+ }, [croppedImageData]);
363
+ const handleConfirm = (0, react_1.useCallback)(() => {
364
+ if (!croppedImageData)
365
+ return;
366
+ onResult({
367
+ path: croppedImageData.path,
368
+ base64: croppedImageData.base64,
369
+ });
370
+ }, [croppedImageData, onResult]);
379
371
  const handleRetake = (0, react_1.useCallback)(() => {
380
372
  console.log('[FullDocScanner] Retake - clearing cropped image and resetting scanner');
381
373
  setCroppedImageData(null);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-rectangle-doc-scanner",
3
- "version": "3.93.0",
3
+ "version": "3.95.0",
4
4
  "description": "Native-backed document scanner for React Native with customizable overlays.",
5
5
  "license": "MIT",
6
6
  "main": "dist/index.js",
@@ -33,15 +33,19 @@
33
33
  "peerDependencies": {
34
34
  "react": "*",
35
35
  "react-native": "*",
36
- "react-native-image-picker": "*",
37
36
  "react-native-image-crop-picker": "*",
37
+ "react-native-image-picker": "*",
38
+ "react-native-image-rotate": "*",
38
39
  "react-native-svg": "*"
39
40
  },
40
41
  "devDependencies": {
41
42
  "@types/react": "^18.2.41",
42
43
  "@types/react-native": "0.73.0",
43
- "react-native-image-picker": "^7.1.2",
44
44
  "react-native-image-crop-picker": "^0.41.2",
45
+ "react-native-image-picker": "^7.1.2",
45
46
  "typescript": "^5.3.3"
47
+ },
48
+ "dependencies": {
49
+ "react-native-image-rotate": "^2.1.0"
46
50
  }
47
51
  }
@@ -11,6 +11,7 @@ import {
11
11
  } from 'react-native';
12
12
  import { launchImageLibrary } from 'react-native-image-picker';
13
13
  import ImageCropPicker from 'react-native-image-crop-picker';
14
+ import ImageRotate from 'react-native-image-rotate';
14
15
  import { DocScanner } from './DocScanner';
15
16
  import type { CapturedDocument } from './types';
16
17
  import type {
@@ -440,53 +441,52 @@ export const FullDocScanner: React.FC<FullDocScannerProps> = ({
440
441
  setFlashEnabled(prev => !prev);
441
442
  }, []);
442
443
 
443
- const handleRotateImage = useCallback((degrees: -90 | 90) => {
444
+ const handleRotateImage = useCallback(async (degrees: -90 | 90) => {
444
445
  if (!croppedImageData) return;
445
446
 
446
- setRotationDegrees(prev => {
447
- const newRotation = (prev + degrees + 360) % 360;
448
- return newRotation;
449
- });
450
- }, [croppedImageData]);
447
+ try {
448
+ // UI 회전 상태 먼저 업데이트 (즉각 반응)
449
+ setRotationDegrees(prev => {
450
+ const newRotation = (prev + degrees + 360) % 360;
451
+ return newRotation;
452
+ });
451
453
 
452
- const handleConfirm = useCallback(async () => {
453
- if (!croppedImageData) return;
454
+ console.log('[FullDocScanner] Starting image rotation...');
454
455
 
455
- // 회전이 필요한 경우 실제로 이미지를 회전
456
- if (rotationDegrees !== 0) {
457
- try {
458
- const rotatedImage = await ImageCropPicker.openCropper({
459
- path: croppedImageData.path,
460
- mediaType: 'photo',
461
- cropping: true,
462
- freeStyleCropEnabled: true,
463
- includeBase64: true,
464
- compressImageQuality: 0.9,
465
- cropperToolbarTitle: ' ',
466
- cropperChooseText: '완료',
467
- cropperCancelText: '취소',
468
- cropperRotateButtonsHidden: false,
469
- });
456
+ // ImageRotate를 사용해서 실제로 이미지 회전 (UI 없이)
457
+ const rotatedImagePath = await ImageRotate.rotateImage(
458
+ croppedImageData.path,
459
+ degrees,
460
+ );
470
461
 
471
- onResult({
472
- path: rotatedImage.path,
473
- base64: rotatedImage.data ?? undefined,
474
- });
475
- } catch (error) {
476
- console.error('[FullDocScanner] Image rotation error:', error);
477
- // 에러 발생 시 원본 이미지 전송
478
- onResult({
479
- path: croppedImageData.path,
480
- base64: croppedImageData.base64,
481
- });
482
- }
483
- } else {
484
- onResult({
485
- path: croppedImageData.path,
486
- base64: croppedImageData.base64,
462
+ console.log('[FullDocScanner] Image rotated successfully:', rotatedImagePath);
463
+
464
+ // 회전된 이미지로 교체
465
+ setCroppedImageData({
466
+ path: rotatedImagePath,
467
+ base64: undefined, // base64는 다시 읽어야 함
468
+ });
469
+
470
+ // rotation degrees는 0으로 리셋 (이미 실제 파일에 적용되었으므로)
471
+ setRotationDegrees(0);
472
+ } catch (error) {
473
+ console.error('[FullDocScanner] Image rotation error:', error);
474
+ // 에러 발생 시 UI rotation 원복
475
+ setRotationDegrees(prev => {
476
+ const revertRotation = (prev - degrees + 360) % 360;
477
+ return revertRotation;
487
478
  });
488
479
  }
489
- }, [croppedImageData, rotationDegrees, onResult]);
480
+ }, [croppedImageData]);
481
+
482
+ const handleConfirm = useCallback(() => {
483
+ if (!croppedImageData) return;
484
+
485
+ onResult({
486
+ path: croppedImageData.path,
487
+ base64: croppedImageData.base64,
488
+ });
489
+ }, [croppedImageData, onResult]);
490
490
 
491
491
  const handleRetake = useCallback(() => {
492
492
  console.log('[FullDocScanner] Retake - clearing cropped image and resetting scanner');
@@ -0,0 +1,8 @@
1
+ declare module 'react-native-image-rotate' {
2
+ export default class ImageRotate {
3
+ static rotateImage(
4
+ imagePath: string,
5
+ degrees: number,
6
+ ): Promise<string>;
7
+ }
8
+ }