react-native-rectangle-doc-scanner 10.32.0 → 10.33.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.
@@ -442,7 +442,12 @@ class CameraController(
442
442
 
443
443
  if (viewWidth <= 0 || viewHeight <= 0) return null
444
444
 
445
- // Get sensor orientation to match transform rotation
445
+ // The image coordinates are in camera sensor space. We need to transform them
446
+ // to match how the TextureView displays the image (after rotation/scaling).
447
+
448
+ // CameraX provides images in sensor orientation. For a 90° sensor (most phones),
449
+ // the image is rotated 90° relative to natural portrait. We must rotate coordinates
450
+ // to match the final display orientation.
446
451
  val sensorOrientation = getCameraSensorOrientation()
447
452
  val displayRotationDegrees = when (textureView.display?.rotation ?: Surface.ROTATION_0) {
448
453
  Surface.ROTATION_0 -> 0
@@ -452,10 +457,21 @@ class CameraController(
452
457
  else -> 0
453
458
  }
454
459
 
455
- val tabletUpsideDownFix = if (sensorOrientation == 0 && displayRotationDegrees == 90) 180 else 0
456
- val rotationDegrees = ((displayRotationDegrees + tabletUpsideDownFix) % 360).toFloat()
460
+ // Calculate the rotation needed to display the image correctly in portrait mode.
461
+ // This must match the rotation applied in updateTextureViewTransform.
462
+ val rotationDegrees = when {
463
+ // Tablet with landscape sensor in portrait: add 180° fix for upside-down
464
+ sensorOrientation == 0 && displayRotationDegrees == 90 -> 270f
465
+ // Phone with 90° sensor in portrait: rotate 90° to match
466
+ sensorOrientation == 90 && displayRotationDegrees == 0 -> 90f
467
+ // Default: use display rotation
468
+ else -> displayRotationDegrees.toFloat()
469
+ }
470
+
471
+ Log.d(TAG, "[MAPPING] Image: ${imageWidth}x${imageHeight}, Sensor: ${sensorOrientation}°, " +
472
+ "Display: ${displayRotationDegrees}°, Final rotation: ${rotationDegrees}°")
457
473
 
458
- // First, apply rotation to point coordinates
474
+ // Apply rotation to coordinates to match display orientation
459
475
  fun rotatePoint(point: org.opencv.core.Point): org.opencv.core.Point {
460
476
  return when (rotationDegrees.toInt()) {
461
477
  90 -> org.opencv.core.Point(
@@ -474,7 +490,7 @@ class CameraController(
474
490
  }
475
491
  }
476
492
 
477
- // Determine rotated dimensions (same as transform)
493
+ // Determine dimensions after rotation
478
494
  val rotatedImageWidth = if (rotationDegrees == 90f || rotationDegrees == 270f) {
479
495
  imageHeight
480
496
  } else {
@@ -486,17 +502,17 @@ class CameraController(
486
502
  imageHeight
487
503
  }
488
504
 
489
- // Use same fit-scaling as transform
505
+ // Calculate scaling to fit the rotated image into the view (matching transform)
490
506
  val scaleX = viewWidth / rotatedImageWidth.toFloat()
491
507
  val scaleY = viewHeight / rotatedImageHeight.toFloat()
492
- val scale = scaleX.coerceAtMost(scaleY) // Fit (not fill)
508
+ val scale = scaleX.coerceAtMost(scaleY) // Fit (preserve aspect ratio)
493
509
 
494
510
  val scaledWidth = rotatedImageWidth * scale
495
511
  val scaledHeight = rotatedImageHeight * scale
496
512
  val offsetX = (viewWidth - scaledWidth) / 2f
497
513
  val offsetY = (viewHeight - scaledHeight) / 2f
498
514
 
499
- // Apply rotation first, then scale and offset
515
+ // Transform coordinates: rotate first, then scale and center
500
516
  fun transformPoint(point: org.opencv.core.Point): org.opencv.core.Point {
501
517
  val rotated = rotatePoint(point)
502
518
  return org.opencv.core.Point(
@@ -505,12 +521,17 @@ class CameraController(
505
521
  )
506
522
  }
507
523
 
508
- return Rectangle(
524
+ val result = Rectangle(
509
525
  transformPoint(rectangle.topLeft),
510
526
  transformPoint(rectangle.topRight),
511
527
  transformPoint(rectangle.bottomLeft),
512
528
  transformPoint(rectangle.bottomRight)
513
529
  )
530
+
531
+ Log.d(TAG, "[MAPPING] Original TL: (${rectangle.topLeft.x}, ${rectangle.topLeft.y}) → " +
532
+ "Transformed: (${result.topLeft.x}, ${result.topLeft.y})")
533
+
534
+ return result
514
535
  }
515
536
 
516
537
  fun getPreviewViewport(): android.graphics.RectF? {
@@ -550,10 +571,17 @@ class CameraController(
550
571
  val centerY = viewHeight / 2f
551
572
 
552
573
  // Calculate rotation from buffer to display coordinates.
553
- // CameraX accounts for sensor orientation via targetRotation. Some tablets with landscape
554
- // sensors report Display 90 in portrait but render upside down; add a 180° fix for that case.
555
- val tabletUpsideDownFix = if (sensorOrientation == 0 && displayRotationDegrees == 90) 180 else 0
556
- val rotationDegrees = ((displayRotationDegrees + tabletUpsideDownFix) % 360).toFloat()
574
+ // For portrait apps:
575
+ // - 90° sensor (phones): buffer is landscape need 90° rotation to portrait
576
+ // - sensor (tablets): buffer is portrait need displayRotation adjustment
577
+ val rotationDegrees = when {
578
+ // Tablet with landscape sensor in portrait: add 180° fix for upside-down
579
+ sensorOrientation == 0 && displayRotationDegrees == 90 -> 270f
580
+ // Phone with 90° sensor in portrait: rotate 90° to match
581
+ sensorOrientation == 90 && displayRotationDegrees == 0 -> 90f
582
+ // Default: use display rotation
583
+ else -> displayRotationDegrees.toFloat()
584
+ }
557
585
 
558
586
  Log.d(TAG, "[TRANSFORM] Applying rotation: ${rotationDegrees}°")
559
587
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-rectangle-doc-scanner",
3
- "version": "10.32.0",
3
+ "version": "10.33.0",
4
4
  "description": "Native-backed document scanner for React Native with customizable overlays.",
5
5
  "license": "MIT",
6
6
  "main": "dist/index.js",