react-native-rectangle-doc-scanner 3.239.0 → 3.240.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.
package/android/build.gradle
CHANGED
|
@@ -68,6 +68,9 @@ dependencies {
|
|
|
68
68
|
// OpenCV for document detection
|
|
69
69
|
implementation 'org.opencv:opencv:4.9.0'
|
|
70
70
|
|
|
71
|
+
// ML Kit object detection for live rectangle hints
|
|
72
|
+
implementation 'com.google.mlkit:object-detection:17.0.1'
|
|
73
|
+
|
|
71
74
|
// Coroutines for async operations
|
|
72
75
|
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3'
|
|
73
76
|
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3'
|
|
@@ -23,6 +23,10 @@ import android.util.Size
|
|
|
23
23
|
import android.view.Surface
|
|
24
24
|
import android.view.TextureView
|
|
25
25
|
import androidx.core.content.ContextCompat
|
|
26
|
+
import com.google.mlkit.vision.common.InputImage
|
|
27
|
+
import com.google.mlkit.vision.objects.ObjectDetection
|
|
28
|
+
import com.google.mlkit.vision.objects.defaults.ObjectDetectorOptions
|
|
29
|
+
import org.opencv.core.Point
|
|
26
30
|
import java.io.File
|
|
27
31
|
import java.io.FileOutputStream
|
|
28
32
|
import java.util.concurrent.atomic.AtomicReference
|
|
@@ -58,6 +62,12 @@ class CameraController(
|
|
|
58
62
|
|
|
59
63
|
private val pendingCapture = AtomicReference<PendingCapture?>()
|
|
60
64
|
private val analysisInFlight = AtomicBoolean(false)
|
|
65
|
+
private val objectDetector = ObjectDetection.getClient(
|
|
66
|
+
ObjectDetectorOptions.Builder()
|
|
67
|
+
.setDetectorMode(ObjectDetectorOptions.STREAM_MODE)
|
|
68
|
+
.enableMultipleObjects()
|
|
69
|
+
.build()
|
|
70
|
+
)
|
|
61
71
|
|
|
62
72
|
var onFrameAnalyzed: ((Rectangle?, Int, Int) -> Unit)? = null
|
|
63
73
|
|
|
@@ -179,6 +189,7 @@ class CameraController(
|
|
|
179
189
|
|
|
180
190
|
fun shutdown() {
|
|
181
191
|
stopCamera()
|
|
192
|
+
objectDetector.close()
|
|
182
193
|
cameraThread.quitSafely()
|
|
183
194
|
analysisThread.quitSafely()
|
|
184
195
|
}
|
|
@@ -352,21 +363,42 @@ class CameraController(
|
|
|
352
363
|
}
|
|
353
364
|
|
|
354
365
|
private fun analyzeImage(image: Image) {
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
val rectangle = DocumentDetector.detectRectangleInYUV(nv21, image.width, image.height, rotationDegrees)
|
|
359
|
-
|
|
360
|
-
val frameWidth = if (rotationDegrees == 90 || rotationDegrees == 270) image.height else image.width
|
|
361
|
-
val frameHeight = if (rotationDegrees == 90 || rotationDegrees == 270) image.width else image.height
|
|
362
|
-
|
|
363
|
-
onFrameAnalyzed?.invoke(rectangle, frameWidth, frameHeight)
|
|
366
|
+
val rotationDegrees = computeRotationDegrees()
|
|
367
|
+
val inputImage = try {
|
|
368
|
+
InputImage.fromMediaImage(image, rotationDegrees)
|
|
364
369
|
} catch (e: Exception) {
|
|
365
|
-
Log.e(TAG, "[CAMERA2]
|
|
366
|
-
} finally {
|
|
370
|
+
Log.e(TAG, "[CAMERA2] Failed to create InputImage", e)
|
|
367
371
|
image.close()
|
|
368
372
|
analysisInFlight.set(false)
|
|
373
|
+
return
|
|
369
374
|
}
|
|
375
|
+
|
|
376
|
+
objectDetector.process(inputImage)
|
|
377
|
+
.addOnSuccessListener { objects ->
|
|
378
|
+
val best = objects.maxByOrNull { obj ->
|
|
379
|
+
val box = obj.boundingBox
|
|
380
|
+
box.width() * box.height()
|
|
381
|
+
}
|
|
382
|
+
val rectangle = best?.boundingBox?.let { box ->
|
|
383
|
+
Rectangle(
|
|
384
|
+
Point(box.left.toDouble(), box.top.toDouble()),
|
|
385
|
+
Point(box.right.toDouble(), box.top.toDouble()),
|
|
386
|
+
Point(box.left.toDouble(), box.bottom.toDouble()),
|
|
387
|
+
Point(box.right.toDouble(), box.bottom.toDouble())
|
|
388
|
+
)
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
val frameWidth = if (rotationDegrees == 90 || rotationDegrees == 270) image.height else image.width
|
|
392
|
+
val frameHeight = if (rotationDegrees == 90 || rotationDegrees == 270) image.width else image.height
|
|
393
|
+
onFrameAnalyzed?.invoke(rectangle, frameWidth, frameHeight)
|
|
394
|
+
}
|
|
395
|
+
.addOnFailureListener { e ->
|
|
396
|
+
Log.e(TAG, "[CAMERA2] ML Kit detection failed", e)
|
|
397
|
+
}
|
|
398
|
+
.addOnCompleteListener {
|
|
399
|
+
image.close()
|
|
400
|
+
analysisInFlight.set(false)
|
|
401
|
+
}
|
|
370
402
|
}
|
|
371
403
|
|
|
372
404
|
private fun processCapture(image: Image, pending: PendingCapture) {
|
|
@@ -497,48 +529,6 @@ class CameraController(
|
|
|
497
529
|
return Bitmap.createBitmap(bitmap, 0, 0, bitmap.width, bitmap.height, matrix, true)
|
|
498
530
|
}
|
|
499
531
|
|
|
500
|
-
private fun Image.toNv21(): ByteArray {
|
|
501
|
-
val width = width
|
|
502
|
-
val height = height
|
|
503
|
-
val ySize = width * height
|
|
504
|
-
val uvSize = width * height / 2
|
|
505
|
-
val nv21 = ByteArray(ySize + uvSize)
|
|
506
|
-
|
|
507
|
-
val yBuffer = planes[0].buffer
|
|
508
|
-
val uBuffer = planes[1].buffer
|
|
509
|
-
val vBuffer = planes[2].buffer
|
|
510
|
-
|
|
511
|
-
val yRowStride = planes[0].rowStride
|
|
512
|
-
val yPixelStride = planes[0].pixelStride
|
|
513
|
-
var outputOffset = 0
|
|
514
|
-
for (row in 0 until height) {
|
|
515
|
-
var inputOffset = row * yRowStride
|
|
516
|
-
for (col in 0 until width) {
|
|
517
|
-
nv21[outputOffset++] = yBuffer.get(inputOffset)
|
|
518
|
-
inputOffset += yPixelStride
|
|
519
|
-
}
|
|
520
|
-
}
|
|
521
|
-
|
|
522
|
-
val uvRowStride = planes[1].rowStride
|
|
523
|
-
val uvPixelStride = planes[1].pixelStride
|
|
524
|
-
val vRowStride = planes[2].rowStride
|
|
525
|
-
val vPixelStride = planes[2].pixelStride
|
|
526
|
-
val uvHeight = height / 2
|
|
527
|
-
val uvWidth = width / 2
|
|
528
|
-
for (row in 0 until uvHeight) {
|
|
529
|
-
var uInputOffset = row * uvRowStride
|
|
530
|
-
var vInputOffset = row * vRowStride
|
|
531
|
-
for (col in 0 until uvWidth) {
|
|
532
|
-
nv21[outputOffset++] = vBuffer.get(vInputOffset)
|
|
533
|
-
nv21[outputOffset++] = uBuffer.get(uInputOffset)
|
|
534
|
-
uInputOffset += uvPixelStride
|
|
535
|
-
vInputOffset += vPixelStride
|
|
536
|
-
}
|
|
537
|
-
}
|
|
538
|
-
|
|
539
|
-
return nv21
|
|
540
|
-
}
|
|
541
|
-
|
|
542
532
|
private fun hasCameraPermission(): Boolean {
|
|
543
533
|
return ContextCompat.checkSelfPermission(context, Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED
|
|
544
534
|
}
|
package/package.json
CHANGED