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 &&
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
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