react-native-rectangle-doc-scanner 10.32.0 → 10.34.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,24 @@ class CameraController(
452
457
  else -> 0
453
458
  }
454
459
 
460
+ // The TextureView transform handles display rotation, but the coordinates coming from
461
+ // ImageAnalysis are in the sensor's native orientation. We need to map those sensor-space
462
+ // coordinates to the final display orientation that the user sees.
463
+
464
+ // For coordinate mapping, we need to account for how the image was rotated by the TextureView.
465
+ // The TextureView applies: displayRotation + tabletFix
455
466
  val tabletUpsideDownFix = if (sensorOrientation == 0 && displayRotationDegrees == 90) 180 else 0
456
- val rotationDegrees = ((displayRotationDegrees + tabletUpsideDownFix) % 360).toFloat()
467
+ val textureViewRotation = ((displayRotationDegrees + tabletUpsideDownFix) % 360).toFloat()
468
+
469
+ // But the image analysis coordinates are in sensor orientation. So we need to apply
470
+ // the SAME rotation that the TextureView applies to align coordinates with display.
471
+ val rotationDegrees = textureViewRotation
457
472
 
458
- // First, apply rotation to point coordinates
473
+ Log.d(TAG, "[MAPPING] Image: ${imageWidth}x${imageHeight}, Sensor: ${sensorOrientation}°, " +
474
+ "Display: ${displayRotationDegrees}°, TextureView rotation: ${textureViewRotation}°, " +
475
+ "Coordinate rotation: ${rotationDegrees}°")
476
+
477
+ // Apply rotation to coordinates to match display orientation
459
478
  fun rotatePoint(point: org.opencv.core.Point): org.opencv.core.Point {
460
479
  return when (rotationDegrees.toInt()) {
461
480
  90 -> org.opencv.core.Point(
@@ -474,7 +493,7 @@ class CameraController(
474
493
  }
475
494
  }
476
495
 
477
- // Determine rotated dimensions (same as transform)
496
+ // Determine dimensions after rotation
478
497
  val rotatedImageWidth = if (rotationDegrees == 90f || rotationDegrees == 270f) {
479
498
  imageHeight
480
499
  } else {
@@ -486,17 +505,17 @@ class CameraController(
486
505
  imageHeight
487
506
  }
488
507
 
489
- // Use same fit-scaling as transform
508
+ // Calculate scaling to fit the rotated image into the view (matching transform)
490
509
  val scaleX = viewWidth / rotatedImageWidth.toFloat()
491
510
  val scaleY = viewHeight / rotatedImageHeight.toFloat()
492
- val scale = scaleX.coerceAtMost(scaleY) // Fit (not fill)
511
+ val scale = scaleX.coerceAtMost(scaleY) // Fit (preserve aspect ratio)
493
512
 
494
513
  val scaledWidth = rotatedImageWidth * scale
495
514
  val scaledHeight = rotatedImageHeight * scale
496
515
  val offsetX = (viewWidth - scaledWidth) / 2f
497
516
  val offsetY = (viewHeight - scaledHeight) / 2f
498
517
 
499
- // Apply rotation first, then scale and offset
518
+ // Transform coordinates: rotate first, then scale and center
500
519
  fun transformPoint(point: org.opencv.core.Point): org.opencv.core.Point {
501
520
  val rotated = rotatePoint(point)
502
521
  return org.opencv.core.Point(
@@ -505,12 +524,17 @@ class CameraController(
505
524
  )
506
525
  }
507
526
 
508
- return Rectangle(
527
+ val result = Rectangle(
509
528
  transformPoint(rectangle.topLeft),
510
529
  transformPoint(rectangle.topRight),
511
530
  transformPoint(rectangle.bottomLeft),
512
531
  transformPoint(rectangle.bottomRight)
513
532
  )
533
+
534
+ Log.d(TAG, "[MAPPING] Original TL: (${rectangle.topLeft.x}, ${rectangle.topLeft.y}) → " +
535
+ "Transformed: (${result.topLeft.x}, ${result.topLeft.y})")
536
+
537
+ return result
514
538
  }
515
539
 
516
540
  fun getPreviewViewport(): android.graphics.RectF? {
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.34.0",
4
4
  "description": "Native-backed document scanner for React Native with customizable overlays.",
5
5
  "license": "MIT",
6
6
  "main": "dist/index.js",