react-native-rectangle-doc-scanner 3.249.0 → 3.250.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,7 @@ class CameraController(
78
77
 
79
78
  companion object {
80
79
  private const val TAG = "CameraController"
81
- private const val ANALYSIS_MAX_AREA = 1920 * 1080
80
+ private const val ANALYSIS_MAX_AREA = 2560 * 1920
82
81
  private const val ANALYSIS_ASPECT_TOLERANCE = 0.15
83
82
  }
84
83
 
@@ -412,13 +411,7 @@ class CameraController(
412
411
  box.width() * box.height()
413
412
  }
414
413
  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
- }
414
+ val rectangle = refineWithOpenCv(nv21, imageWidth, imageHeight, rotationDegrees, mlBox)
422
415
 
423
416
  val frameWidth = if (rotationDegrees == 90 || rotationDegrees == 270) imageHeight else imageWidth
424
417
  val frameHeight = if (rotationDegrees == 90 || rotationDegrees == 270) imageWidth else imageHeight
@@ -426,6 +419,15 @@ class CameraController(
426
419
  }
427
420
  .addOnFailureListener { e ->
428
421
  Log.e(TAG, "[CAMERA2] ML Kit detection failed", e)
422
+ val rectangle = try {
423
+ DocumentDetector.detectRectangleInYUV(nv21, imageWidth, imageHeight, rotationDegrees)
424
+ } catch (detectError: Exception) {
425
+ Log.w(TAG, "[CAMERA2] OpenCV fallback failed", detectError)
426
+ null
427
+ }
428
+ val frameWidth = if (rotationDegrees == 90 || rotationDegrees == 270) imageHeight else imageWidth
429
+ val frameHeight = if (rotationDegrees == 90 || rotationDegrees == 270) imageWidth else imageHeight
430
+ onFrameAnalyzed?.invoke(smoothRectangle(rectangle), frameWidth, frameHeight)
429
431
  }
430
432
  .addOnCompleteListener {
431
433
  analysisInFlight.set(false)
@@ -568,38 +570,32 @@ class CameraController(
568
570
  return Bitmap.createBitmap(bitmap, 0, 0, bitmap.width, bitmap.height, matrix, true)
569
571
  }
570
572
 
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
573
  private fun refineWithOpenCv(
581
574
  nv21: ByteArray,
582
575
  imageWidth: Int,
583
576
  imageHeight: Int,
584
577
  rotationDegrees: Int,
585
- mlBox: Rect
578
+ mlBox: Rect?
586
579
  ): Rectangle? {
587
580
  return try {
588
581
  val uprightWidth = if (rotationDegrees == 90 || rotationDegrees == 270) imageHeight else imageWidth
589
582
  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
- )
583
+ val openCvRect = if (mlBox != null) {
584
+ val expanded = expandRect(mlBox, uprightWidth, uprightHeight, 0.2f)
585
+ DocumentDetector.detectRectangleInYUVWithRoi(
586
+ nv21,
587
+ imageWidth,
588
+ imageHeight,
589
+ rotationDegrees,
590
+ expanded
591
+ )
592
+ } else {
593
+ DocumentDetector.detectRectangleInYUV(nv21, imageWidth, imageHeight, rotationDegrees)
594
+ }
598
595
  if (openCvRect == null) {
599
- null
596
+ mlBox?.let { boxToRectangle(it) }
600
597
  } else {
601
- val openRectBounds = rectangleBounds(openCvRect)
602
- if (computeIoU(openRectBounds, mlBox) >= 0.2f) openCvRect else null
598
+ openCvRect
603
599
  }
604
600
  } catch (e: Exception) {
605
601
  Log.w(TAG, "[CAMERA2] OpenCV refine failed", e)
@@ -630,32 +626,16 @@ class CameraController(
630
626
  val now = System.currentTimeMillis()
631
627
  val last = lastRectangle
632
628
  if (current == null) {
633
- if (last != null && now - lastRectangleTimestamp < 250) {
629
+ if (last != null && now - lastRectangleTimestamp < 150) {
634
630
  return last
635
631
  }
636
632
  lastRectangle = null
637
633
  return null
638
634
  }
639
635
 
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
636
+ lastRectangle = current
653
637
  lastRectangleTimestamp = now
654
- return smoothed
655
- }
656
-
657
- private fun lerp(start: Double, end: Double, t: Double): Double {
658
- return start + (end - start) * t
638
+ return current
659
639
  }
660
640
 
661
641
  private fun rectangleBounds(rectangle: Rectangle): Rect {
@@ -666,17 +646,6 @@ class CameraController(
666
646
  return Rect(left.toInt(), top.toInt(), right.toInt(), bottom.toInt())
667
647
  }
668
648
 
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
649
  private fun imageToNv21(image: Image): ByteArray {
681
650
  val width = image.width
682
651
  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.250.0",
4
4
  "description": "Native-backed document scanner for React Native with customizable overlays.",
5
5
  "license": "MIT",
6
6
  "main": "dist/index.js",