react-native-rectangle-doc-scanner 3.247.0 → 3.248.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.
@@ -16,6 +16,7 @@ import androidx.lifecycle.Lifecycle
16
16
  import androidx.lifecycle.LifecycleOwner
17
17
  import androidx.lifecycle.LifecycleRegistry
18
18
  import com.facebook.react.bridge.Arguments
19
+ import com.facebook.react.bridge.ReadableMap
19
20
  import com.facebook.react.bridge.WritableMap
20
21
  import com.facebook.react.uimanager.ThemedReactContext
21
22
  import com.facebook.react.uimanager.events.RCTEventEmitter
@@ -54,6 +55,7 @@ class DocumentScannerView(context: ThemedReactContext) : FrameLayout(context), L
54
55
  private var lastDetectedRectangle: Rectangle? = null
55
56
  private var lastDetectedImageWidth = 0
56
57
  private var lastDetectedImageHeight = 0
58
+ private var lastRectangleOnScreen: Rectangle? = null
57
59
 
58
60
  // Coroutine scope for async operations
59
61
  private val scope = CoroutineScope(Dispatchers.Main + SupervisorJob())
@@ -201,6 +203,7 @@ class DocumentScannerView(context: ThemedReactContext) : FrameLayout(context), L
201
203
  } else {
202
204
  null
203
205
  }
206
+ lastRectangleOnScreen = rectangleOnScreen
204
207
  val quality = when {
205
208
  rectangleOnScreen != null && width > 0 && height > 0 ->
206
209
  DocumentDetector.evaluateRectangleQualityInView(rectangleOnScreen, width, height)
@@ -329,14 +332,26 @@ class DocumentScannerView(context: ThemedReactContext) : FrameLayout(context), L
329
332
  Log.w(TAG, "Rectangle detection failed, using original image", e)
330
333
  null
331
334
  }
332
- if (detectedRectangle == null && lastDetectedRectangle != null && lastDetectedImageWidth > 0 && lastDetectedImageHeight > 0) {
333
- detectedRectangle = scaleRectangleToBitmap(
334
- lastDetectedRectangle!!,
335
- lastDetectedImageWidth,
336
- lastDetectedImageHeight,
337
- bitmap.width,
338
- bitmap.height
339
- )
335
+ if (detectedRectangle == null && lastDetectedImageWidth > 0 && lastDetectedImageHeight > 0) {
336
+ val rectangleFromView = lastRectangleOnScreen?.let {
337
+ viewToImageRectangle(
338
+ it,
339
+ width,
340
+ height,
341
+ lastDetectedImageWidth,
342
+ lastDetectedImageHeight
343
+ )
344
+ }
345
+ val fallbackRect = rectangleFromView ?: lastDetectedRectangle
346
+ if (fallbackRect != null) {
347
+ detectedRectangle = scaleRectangleToBitmap(
348
+ fallbackRect,
349
+ lastDetectedImageWidth,
350
+ lastDetectedImageHeight,
351
+ bitmap.width,
352
+ bitmap.height
353
+ )
354
+ }
340
355
  }
341
356
 
342
357
  // Process image with detected rectangle
@@ -420,14 +435,20 @@ class DocumentScannerView(context: ThemedReactContext) : FrameLayout(context), L
420
435
  imageWidth: Int,
421
436
  imageHeight: Int
422
437
  ) {
438
+ val density = resources.displayMetrics.density.takeIf { it > 0f } ?: 1f
423
439
  val event = Arguments.createMap().apply {
424
440
  putInt("stableCounter", stableCounter)
425
441
  putInt("lastDetectionType", quality.ordinal)
426
442
  putMap("rectangleCoordinates", rectangleCoordinates?.toMap()?.toWritableMap())
427
- putMap("rectangleOnScreen", rectangleOnScreen?.toMap()?.toWritableMap())
443
+ putMap("rectangleOnScreen", rectangleOnScreen?.toMap()?.toWritableMap()?.apply {
444
+ putMap("topLeft", mapPointToDp(getMap("topLeft"), density))
445
+ putMap("topRight", mapPointToDp(getMap("topRight"), density))
446
+ putMap("bottomLeft", mapPointToDp(getMap("bottomLeft"), density))
447
+ putMap("bottomRight", mapPointToDp(getMap("bottomRight"), density))
448
+ })
428
449
  putMap("previewSize", Arguments.createMap().apply {
429
- putInt("width", width)
430
- putInt("height", height)
450
+ putInt("width", (width / density).toInt())
451
+ putInt("height", (height / density).toInt())
431
452
  })
432
453
  putMap("imageSize", Arguments.createMap().apply {
433
454
  putInt("width", imageWidth)
@@ -600,6 +621,52 @@ class DocumentScannerView(context: ThemedReactContext) : FrameLayout(context), L
600
621
  }
601
622
  }
602
623
 
624
+ private fun mapPointToDp(point: ReadableMap?, density: Float): WritableMap? {
625
+ if (point == null) return null
626
+ val map = Arguments.createMap()
627
+ val x = if (point.hasKey("x")) point.getDouble("x") else 0.0
628
+ val y = if (point.hasKey("y")) point.getDouble("y") else 0.0
629
+ map.putDouble("x", x / density)
630
+ map.putDouble("y", y / density)
631
+ return map
632
+ }
633
+
634
+ private fun viewToImageRectangle(
635
+ rectangle: Rectangle,
636
+ viewWidth: Int,
637
+ viewHeight: Int,
638
+ imageWidth: Int,
639
+ imageHeight: Int
640
+ ): Rectangle {
641
+ if (viewWidth == 0 || viewHeight == 0 || imageWidth == 0 || imageHeight == 0) {
642
+ return rectangle
643
+ }
644
+ val scale = max(
645
+ viewWidth.toDouble() / imageWidth.toDouble(),
646
+ viewHeight.toDouble() / imageHeight.toDouble()
647
+ )
648
+ val scaledImageWidth = imageWidth * scale
649
+ val scaledImageHeight = imageHeight * scale
650
+ val offsetX = (scaledImageWidth - viewWidth) / 2.0
651
+ val offsetY = (scaledImageHeight - viewHeight) / 2.0
652
+
653
+ fun mapPoint(point: Point): Point {
654
+ val x = (point.x + offsetX) / scale
655
+ val y = (point.y + offsetY) / scale
656
+ return Point(
657
+ x.coerceIn(0.0, imageWidth.toDouble()),
658
+ y.coerceIn(0.0, imageHeight.toDouble())
659
+ )
660
+ }
661
+
662
+ return Rectangle(
663
+ mapPoint(rectangle.topLeft),
664
+ mapPoint(rectangle.topRight),
665
+ mapPoint(rectangle.bottomLeft),
666
+ mapPoint(rectangle.bottomRight)
667
+ )
668
+ }
669
+
603
670
  private fun scaleRectangleToBitmap(
604
671
  rectangle: Rectangle,
605
672
  srcWidth: Int,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-rectangle-doc-scanner",
3
- "version": "3.247.0",
3
+ "version": "3.248.0",
4
4
  "description": "Native-backed document scanner for React Native with customizable overlays.",
5
5
  "license": "MIT",
6
6
  "main": "dist/index.js",