react-native-rectangle-doc-scanner 7.61.0 → 7.63.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.
@@ -355,11 +355,13 @@ class CameraController(
355
355
  captureSize = chooseBestSize(captureSizes, previewAspect, null, preferClosestAspect = true)
356
356
  ?: captureSizes?.maxByOrNull { it.width * it.height }
357
357
 
358
- val previewDiff = previewSize?.let { abs(it.width.toDouble() / it.height.toDouble() - targetPreviewAspect) }
358
+ val viewAspectNormalized = max(viewAspect, 1.0 / viewAspect)
359
+ val previewAspectNormalized = max(previewAspect, 1.0 / previewAspect)
360
+ val previewDiff = abs(previewAspectNormalized - viewAspectNormalized)
359
361
  Log.d(
360
362
  TAG,
361
- "[SIZE_SELECTION] targetAspect=$targetPreviewAspect viewAspect=$viewAspect " +
362
- "previewAspect=$previewAspect diff=$previewDiff selected=${previewSize?.width}x${previewSize?.height}"
363
+ "[SIZE_SELECTION] targetAspect=$viewAspectNormalized viewAspect=$viewAspectNormalized " +
364
+ "previewAspect=$previewAspectNormalized diff=$previewDiff selected=${previewSize?.width}x${previewSize?.height}"
363
365
  )
364
366
 
365
367
  setupImageReaders()
@@ -661,49 +663,85 @@ class CameraController(
661
663
  if (viewWidth == 0f || viewHeight == 0f) return
662
664
 
663
665
  val rotationDegrees = computeRotationDegrees()
664
- val transformRotation = rotationDegrees
665
- Log.d(
666
- TAG,
667
- "[TRANSFORM] rotation=$transformRotation view=${viewWidth}x${viewHeight} preview=${preview.width}x${preview.height}"
668
- )
666
+ val displayRotation = displayRotationDegrees()
669
667
 
670
- val matrix = Matrix()
671
668
  val viewRect = RectF(0f, 0f, viewWidth, viewHeight)
672
669
  val centerX = viewRect.centerX()
673
670
  val centerY = viewRect.centerY()
674
671
 
675
- val isSwapped = transformRotation == 90 || transformRotation == 270
676
- val bufferWidth = if (isSwapped) preview.height.toFloat() else preview.width.toFloat()
677
- val bufferHeight = if (isSwapped) preview.width.toFloat() else preview.height.toFloat()
678
- val bufferRect = RectF(0f, 0f, bufferWidth, bufferHeight)
679
- bufferRect.offset(centerX - bufferRect.centerX(), centerY - bufferRect.centerY())
672
+ fun buildTransform(appliedRotation: Int): Pair<Matrix, FloatArray> {
673
+ val candidate = Matrix()
674
+ val swap = appliedRotation == 90 || appliedRotation == 270
675
+ val bufferWidth = if (swap) preview.height.toFloat() else preview.width.toFloat()
676
+ val bufferHeight = if (swap) preview.width.toFloat() else preview.height.toFloat()
677
+ val bufferRect = RectF(0f, 0f, bufferWidth, bufferHeight)
678
+ bufferRect.offset(centerX - bufferRect.centerX(), centerY - bufferRect.centerY())
679
+
680
+ candidate.setRectToRect(viewRect, bufferRect, Matrix.ScaleToFit.FILL)
681
+ val scale = max(viewWidth / bufferRect.width(), viewHeight / bufferRect.height())
682
+ candidate.postScale(scale, scale, centerX, centerY)
683
+ if (appliedRotation != 0) {
684
+ candidate.postRotate(appliedRotation.toFloat(), centerX, centerY)
685
+ }
686
+
687
+ val pts = floatArrayOf(
688
+ 0f, 0f,
689
+ bufferWidth, 0f,
690
+ 0f, bufferHeight,
691
+ bufferWidth, bufferHeight
692
+ )
693
+ candidate.mapPoints(pts)
694
+ return Pair(candidate, pts)
695
+ }
696
+
697
+ fun scoreCoverage(pts: FloatArray): Float {
698
+ val minX = min(min(pts[0], pts[2]), min(pts[4], pts[6]))
699
+ val maxX = max(max(pts[0], pts[2]), max(pts[4], pts[6]))
700
+ val minY = min(min(pts[1], pts[3]), min(pts[5], pts[7]))
701
+ val maxY = max(max(pts[1], pts[3]), max(pts[5], pts[7]))
680
702
 
681
- matrix.setRectToRect(bufferRect, viewRect, Matrix.ScaleToFit.FILL)
682
- val scale = max(viewWidth / bufferWidth, viewHeight / bufferHeight)
683
- matrix.postScale(scale, scale, centerX, centerY)
684
- if (transformRotation != 0) {
685
- matrix.postRotate(transformRotation.toFloat(), centerX, centerY)
703
+ val left = max(viewRect.left, minX)
704
+ val top = max(viewRect.top, minY)
705
+ val right = min(viewRect.right, maxX)
706
+ val bottom = min(viewRect.bottom, maxY)
707
+ val intersection = if (right > left && bottom > top) (right - left) * (bottom - top) else 0f
708
+ val viewArea = viewRect.width() * viewRect.height()
709
+ return if (viewArea > 0f) intersection / viewArea else 0f
686
710
  }
687
711
 
688
- previewView.setTransform(matrix)
689
- latestTransform = Matrix(matrix)
712
+ val positive = rotationDegrees
713
+ val negative = if (rotationDegrees == 0) 0 else (360 - rotationDegrees) % 360
714
+ val (matrixPos, ptsPos) = buildTransform(positive)
715
+ val (matrixNeg, ptsNeg) = buildTransform(negative)
716
+ val scorePos = scoreCoverage(ptsPos)
717
+ val scoreNeg = scoreCoverage(ptsNeg)
718
+
719
+ val appliedRotation = if (scoreNeg > scorePos) negative else positive
720
+ val appliedMatrix = if (appliedRotation == positive) matrixPos else matrixNeg
721
+ val appliedPts = if (appliedRotation == positive) ptsPos else ptsNeg
722
+
723
+ Log.d(
724
+ TAG,
725
+ "[TRANSFORM] rotations sensor=$sensorOrientation display=$displayRotation computed=$rotationDegrees applied=$appliedRotation " +
726
+ "view=${viewWidth}x${viewHeight} preview=${preview.width}x${preview.height}"
727
+ )
728
+
729
+ previewView.setTransform(appliedMatrix)
730
+ latestTransform = Matrix(appliedMatrix)
690
731
  latestBufferWidth = preview.width
691
732
  latestBufferHeight = preview.height
692
- latestTransformRotation = transformRotation
733
+ latestTransformRotation = appliedRotation
693
734
 
694
- val pts = floatArrayOf(
695
- 0f, 0f,
696
- bufferWidth, 0f,
697
- 0f, bufferHeight,
698
- bufferWidth, bufferHeight
699
- )
700
- matrix.mapPoints(pts)
701
735
  Log.d(
702
736
  TAG,
703
- "[TRANSFORM] viewClass=${previewView.javaClass.name} isTextureView=${previewView is TextureView} " +
704
- "buffer=${bufferWidth}x${bufferHeight} scale=$scale center=${centerX}x${centerY} matrix=$matrix " +
705
- "pts=[${pts[0]},${pts[1]} ${pts[2]},${pts[3]} ${pts[4]},${pts[5]} ${pts[6]},${pts[7]}]"
737
+ "[TRANSFORM] appliedRotation=$appliedRotation scores pos=$scorePos neg=$scoreNeg viewClass=${previewView.javaClass.name} " +
738
+ "isTextureView=${previewView is TextureView} matrix=$appliedMatrix " +
739
+ "pts=[${appliedPts[0]},${appliedPts[1]} ${appliedPts[2]},${appliedPts[3]} ${appliedPts[4]},${appliedPts[5]} ${appliedPts[6]},${appliedPts[7]}]"
706
740
  )
741
+ val recomputed = computeRotationDegrees()
742
+ if (rotationDegrees != recomputed) {
743
+ Log.e(TAG, "[TRANSFORM] rotation mismatch computed=$rotationDegrees recomputed=$recomputed")
744
+ }
707
745
  Log.d(TAG, "[TRANSFORM] Matrix applied successfully")
708
746
  }
709
747
 
@@ -738,7 +776,9 @@ class CameraController(
738
776
  fun aspectDiff(size: Size): Double {
739
777
  val w = size.width.toDouble()
740
778
  val h = size.height.toDouble()
741
- return abs(w / h - targetAspect)
779
+ val aspect = max(w, h) / min(w, h)
780
+ val target = max(targetAspect, 1.0 / targetAspect)
781
+ return abs(aspect - target)
742
782
  }
743
783
 
744
784
  if (preferClosestAspect) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-rectangle-doc-scanner",
3
- "version": "7.61.0",
3
+ "version": "7.63.0",
4
4
  "description": "Native-backed document scanner for React Native with customizable overlays.",
5
5
  "license": "MIT",
6
6
  "main": "dist/index.js",