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