react-native-rectangle-doc-scanner 3.249.0 → 3.251.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.
@@ -70,7 +70,6 @@ class CameraController(
70
70
  .enableMultipleObjects()
71
71
  .build()
72
72
  )
73
- private var lastRefineTimestamp = 0L
74
73
  private var lastRectangle: Rectangle? = null
75
74
  private var lastRectangleTimestamp = 0L
76
75
 
@@ -78,7 +77,6 @@ class CameraController(
78
77
 
79
78
  companion object {
80
79
  private const val TAG = "CameraController"
81
- private const val ANALYSIS_MAX_AREA = 1920 * 1080
82
80
  private const val ANALYSIS_ASPECT_TOLERANCE = 0.15
83
81
  }
84
82
 
@@ -220,7 +218,7 @@ class CameraController(
220
218
  previewSize = chooseBestSize(previewSizes, viewAspect, null, preferClosestAspect = true)
221
219
 
222
220
  val analysisSizes = streamConfigMap.getOutputSizes(ImageFormat.YUV_420_888)
223
- analysisSize = chooseBestSize(analysisSizes, viewAspect, ANALYSIS_MAX_AREA)
221
+ analysisSize = chooseBestSize(analysisSizes, viewAspect, null, preferClosestAspect = true)
224
222
 
225
223
  val captureSizes = streamConfigMap.getOutputSizes(ImageFormat.JPEG)
226
224
  captureSize = captureSizes?.maxByOrNull { it.width * it.height }
@@ -412,13 +410,7 @@ class CameraController(
412
410
  box.width() * box.height()
413
411
  }
414
412
  val mlBox = best?.boundingBox
415
- val rectangle = when {
416
- mlBox == null -> null
417
- shouldRefineWithOpenCv() ->
418
- refineWithOpenCv(nv21, imageWidth, imageHeight, rotationDegrees, mlBox)
419
- ?: boxToRectangle(mlBox)
420
- else -> boxToRectangle(mlBox)
421
- }
413
+ val rectangle = refineWithOpenCv(nv21, imageWidth, imageHeight, rotationDegrees, mlBox)
422
414
 
423
415
  val frameWidth = if (rotationDegrees == 90 || rotationDegrees == 270) imageHeight else imageWidth
424
416
  val frameHeight = if (rotationDegrees == 90 || rotationDegrees == 270) imageWidth else imageHeight
@@ -426,6 +418,15 @@ class CameraController(
426
418
  }
427
419
  .addOnFailureListener { e ->
428
420
  Log.e(TAG, "[CAMERA2] ML Kit detection failed", e)
421
+ val rectangle = try {
422
+ DocumentDetector.detectRectangleInYUV(nv21, imageWidth, imageHeight, rotationDegrees)
423
+ } catch (detectError: Exception) {
424
+ Log.w(TAG, "[CAMERA2] OpenCV fallback failed", detectError)
425
+ null
426
+ }
427
+ val frameWidth = if (rotationDegrees == 90 || rotationDegrees == 270) imageHeight else imageWidth
428
+ val frameHeight = if (rotationDegrees == 90 || rotationDegrees == 270) imageWidth else imageHeight
429
+ onFrameAnalyzed?.invoke(smoothRectangle(rectangle), frameWidth, frameHeight)
429
430
  }
430
431
  .addOnCompleteListener {
431
432
  analysisInFlight.set(false)
@@ -568,38 +569,32 @@ class CameraController(
568
569
  return Bitmap.createBitmap(bitmap, 0, 0, bitmap.width, bitmap.height, matrix, true)
569
570
  }
570
571
 
571
- private fun shouldRefineWithOpenCv(): Boolean {
572
- val now = System.currentTimeMillis()
573
- if (now - lastRefineTimestamp < 150) {
574
- return false
575
- }
576
- lastRefineTimestamp = now
577
- return true
578
- }
579
-
580
572
  private fun refineWithOpenCv(
581
573
  nv21: ByteArray,
582
574
  imageWidth: Int,
583
575
  imageHeight: Int,
584
576
  rotationDegrees: Int,
585
- mlBox: Rect
577
+ mlBox: Rect?
586
578
  ): Rectangle? {
587
579
  return try {
588
580
  val uprightWidth = if (rotationDegrees == 90 || rotationDegrees == 270) imageHeight else imageWidth
589
581
  val uprightHeight = if (rotationDegrees == 90 || rotationDegrees == 270) imageWidth else imageHeight
590
- val expanded = expandRect(mlBox, uprightWidth, uprightHeight, 0.2f)
591
- val openCvRect = DocumentDetector.detectRectangleInYUVWithRoi(
592
- nv21,
593
- imageWidth,
594
- imageHeight,
595
- rotationDegrees,
596
- expanded
597
- )
582
+ val openCvRect = if (mlBox != null) {
583
+ val expanded = expandRect(mlBox, uprightWidth, uprightHeight, 0.2f)
584
+ DocumentDetector.detectRectangleInYUVWithRoi(
585
+ nv21,
586
+ imageWidth,
587
+ imageHeight,
588
+ rotationDegrees,
589
+ expanded
590
+ )
591
+ } else {
592
+ DocumentDetector.detectRectangleInYUV(nv21, imageWidth, imageHeight, rotationDegrees)
593
+ }
598
594
  if (openCvRect == null) {
599
- null
595
+ mlBox?.let { boxToRectangle(it) }
600
596
  } else {
601
- val openRectBounds = rectangleBounds(openCvRect)
602
- if (computeIoU(openRectBounds, mlBox) >= 0.2f) openCvRect else null
597
+ openCvRect
603
598
  }
604
599
  } catch (e: Exception) {
605
600
  Log.w(TAG, "[CAMERA2] OpenCV refine failed", e)
@@ -630,32 +625,16 @@ class CameraController(
630
625
  val now = System.currentTimeMillis()
631
626
  val last = lastRectangle
632
627
  if (current == null) {
633
- if (last != null && now - lastRectangleTimestamp < 250) {
628
+ if (last != null && now - lastRectangleTimestamp < 150) {
634
629
  return last
635
630
  }
636
631
  lastRectangle = null
637
632
  return null
638
633
  }
639
634
 
640
- val smoothed = if (last != null && now - lastRectangleTimestamp < 500) {
641
- val t = 0.35
642
- Rectangle(
643
- Point(lerp(last.topLeft.x, current.topLeft.x, t), lerp(last.topLeft.y, current.topLeft.y, t)),
644
- Point(lerp(last.topRight.x, current.topRight.x, t), lerp(last.topRight.y, current.topRight.y, t)),
645
- Point(lerp(last.bottomLeft.x, current.bottomLeft.x, t), lerp(last.bottomLeft.y, current.bottomLeft.y, t)),
646
- Point(lerp(last.bottomRight.x, current.bottomRight.x, t), lerp(last.bottomRight.y, current.bottomRight.y, t))
647
- )
648
- } else {
649
- current
650
- }
651
-
652
- lastRectangle = smoothed
635
+ lastRectangle = current
653
636
  lastRectangleTimestamp = now
654
- return smoothed
655
- }
656
-
657
- private fun lerp(start: Double, end: Double, t: Double): Double {
658
- return start + (end - start) * t
637
+ return current
659
638
  }
660
639
 
661
640
  private fun rectangleBounds(rectangle: Rectangle): Rect {
@@ -666,17 +645,6 @@ class CameraController(
666
645
  return Rect(left.toInt(), top.toInt(), right.toInt(), bottom.toInt())
667
646
  }
668
647
 
669
- private fun computeIoU(a: Rect, b: Rect): Float {
670
- val left = max(a.left, b.left)
671
- val top = max(a.top, b.top)
672
- val right = minOf(a.right, b.right)
673
- val bottom = minOf(a.bottom, b.bottom)
674
- if (right <= left || bottom <= top) return 0f
675
- val intersection = (right - left).toFloat() * (bottom - top).toFloat()
676
- val union = (a.width() * a.height() + b.width() * b.height() - intersection).toFloat()
677
- return if (union <= 0f) 0f else intersection / union
678
- }
679
-
680
648
  private fun imageToNv21(image: Image): ByteArray {
681
649
  val width = image.width
682
650
  val height = image.height
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-rectangle-doc-scanner",
3
- "version": "3.249.0",
3
+ "version": "3.251.0",
4
4
  "description": "Native-backed document scanner for React Native with customizable overlays.",
5
5
  "license": "MIT",
6
6
  "main": "dist/index.js",