react-native-rectangle-doc-scanner 3.200.0 → 3.202.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.
@@ -22,6 +22,7 @@ import android.os.Handler
22
22
  import android.os.HandlerThread
23
23
  import android.util.Log
24
24
  import android.util.Size
25
+ import android.view.Gravity
25
26
  import android.view.Surface
26
27
  import android.view.TextureView
27
28
  import androidx.core.content.ContextCompat
@@ -43,6 +44,7 @@ class CameraController(
43
44
  private var imageReader: ImageReader? = null
44
45
  private var backgroundThread: HandlerThread? = null
45
46
  private var backgroundHandler: Handler? = null
47
+ private var previewLayoutListener: android.view.View.OnLayoutChangeListener? = null
46
48
 
47
49
  private var cameraId: String? = null
48
50
  private var sensorOrientation: Int = 0
@@ -61,8 +63,8 @@ class CameraController(
61
63
 
62
64
  companion object {
63
65
  private const val TAG = "CameraController"
64
- private const val MAX_PREVIEW_WIDTH = 1280
65
- private const val MAX_PREVIEW_HEIGHT = 720
66
+ private const val MAX_PREVIEW_WIDTH = 1920
67
+ private const val MAX_PREVIEW_HEIGHT = 1440
66
68
  }
67
69
 
68
70
  private data class LastFrame(
@@ -120,6 +122,13 @@ class CameraController(
120
122
  startBackgroundThread()
121
123
  chooseCamera()
122
124
 
125
+ if (previewLayoutListener == null) {
126
+ previewLayoutListener = android.view.View.OnLayoutChangeListener { _, _, _, _, _, _, _, _, _ ->
127
+ updatePreviewTransform()
128
+ }
129
+ previewView.addOnLayoutChangeListener(previewLayoutListener)
130
+ }
131
+
123
132
  if (previewView.isAvailable) {
124
133
  openCamera()
125
134
  } else {
@@ -129,6 +138,10 @@ class CameraController(
129
138
 
130
139
  fun stopCamera() {
131
140
  Log.d(TAG, "[CAMERA2] stopCamera called")
141
+ previewLayoutListener?.let { listener ->
142
+ previewView.removeOnLayoutChangeListener(listener)
143
+ }
144
+ previewLayoutListener = null
132
145
  try {
133
146
  captureSession?.close()
134
147
  captureSession = null
@@ -359,6 +372,8 @@ class CameraController(
359
372
 
360
373
  private fun updatePreviewTransform() {
361
374
  val previewSize = previewSize ?: return
375
+ adjustPreviewLayout(previewSize)
376
+
362
377
  val viewWidth = previewView.width
363
378
  val viewHeight = previewView.height
364
379
  if (viewWidth == 0 || viewHeight == 0) {
@@ -396,6 +411,45 @@ class CameraController(
396
411
  previewView.setTransform(matrix)
397
412
  }
398
413
 
414
+ private fun adjustPreviewLayout(previewSize: Size) {
415
+ val parentView = previewView.parent as? android.view.View ?: return
416
+ val parentWidth = parentView.width
417
+ val parentHeight = parentView.height
418
+ if (parentWidth == 0 || parentHeight == 0) {
419
+ return
420
+ }
421
+
422
+ val rotationDegrees = getRotationDegrees()
423
+ val bufferWidth = previewSize.width.toFloat()
424
+ val bufferHeight = previewSize.height.toFloat()
425
+ val bufferAspect = if (rotationDegrees == 90 || rotationDegrees == 270) {
426
+ bufferHeight / bufferWidth
427
+ } else {
428
+ bufferWidth / bufferHeight
429
+ }
430
+
431
+ val parentAspect = parentWidth.toFloat() / parentHeight.toFloat()
432
+ val targetWidth: Int
433
+ val targetHeight: Int
434
+
435
+ if (parentAspect > bufferAspect) {
436
+ targetHeight = parentHeight
437
+ targetWidth = (parentHeight * bufferAspect).toInt()
438
+ } else {
439
+ targetWidth = parentWidth
440
+ targetHeight = (parentWidth / bufferAspect).toInt()
441
+ }
442
+
443
+ val layoutParams = (previewView.layoutParams as? android.widget.FrameLayout.LayoutParams)
444
+ ?: android.widget.FrameLayout.LayoutParams(targetWidth, targetHeight)
445
+ if (layoutParams.width != targetWidth || layoutParams.height != targetHeight) {
446
+ layoutParams.width = targetWidth
447
+ layoutParams.height = targetHeight
448
+ layoutParams.gravity = Gravity.CENTER
449
+ previewView.layoutParams = layoutParams
450
+ }
451
+ }
452
+
399
453
  private fun handleImage(image: Image) {
400
454
  try {
401
455
  val rotationDegrees = getRotationDegrees()
@@ -522,21 +576,24 @@ class CameraController(
522
576
  val maxCandidates = choices.filter { it.width <= maxWidth && it.height <= maxHeight }
523
577
  val candidates = if (maxCandidates.isNotEmpty()) maxCandidates else choices.toList()
524
578
 
525
- val ratioFiltered = if (targetRatio != null) {
526
- candidates.filter { size ->
527
- val ratio = if (targetRatio < 1f) {
579
+ if (targetRatio == null) {
580
+ return candidates.sortedBy { it.width * it.height }.last()
581
+ }
582
+
583
+ val normalizedTarget = targetRatio
584
+ val sorted = candidates.sortedWith(
585
+ compareBy<Size> { size ->
586
+ val ratio = if (normalizedTarget < 1f) {
528
587
  size.height.toFloat() / size.width.toFloat()
529
588
  } else {
530
589
  size.width.toFloat() / size.height.toFloat()
531
590
  }
532
- kotlin.math.abs(ratio - targetRatio) <= 0.05f
591
+ kotlin.math.abs(ratio - normalizedTarget)
592
+ }.thenByDescending { size ->
593
+ size.width * size.height
533
594
  }
534
- } else {
535
- emptyList()
536
- }
537
-
538
- val pickFrom = if (ratioFiltered.isNotEmpty()) ratioFiltered else candidates
539
- return pickFrom.sortedBy { it.width * it.height }.last()
595
+ )
596
+ return sorted.first()
540
597
  }
541
598
 
542
599
  private fun startBackgroundThread() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-rectangle-doc-scanner",
3
- "version": "3.200.0",
3
+ "version": "3.202.0",
4
4
  "description": "Native-backed document scanner for React Native with customizable overlays.",
5
5
  "license": "MIT",
6
6
  "main": "dist/index.js",