@mleonard9/vin-scanner 0.2.5 → 0.2.7
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/README.md +9 -0
- package/android/src/main/java/com/visioncamerabarcodescanner/VisionCameraBarcodeScannerModule.kt +96 -54
- package/android/src/main/java/com/visioncamerabarcodescanner/VisionCameraBarcodeScannerPackage.kt +2 -2
- package/android/src/main/java/com/visioncameratextrecognition/VisionCameraTextRecognitionModule.kt +139 -95
- package/ios/VisionCameraBarcodeScanner.m +87 -37
- package/ios/VisionCameraTextRecognition.m +130 -56
- package/lib/commonjs/scanBarcodes.js +76 -6
- package/lib/commonjs/scanBarcodes.js.map +1 -1
- package/lib/commonjs/scanText.js +78 -4
- package/lib/commonjs/scanText.js.map +1 -1
- package/lib/commonjs/useVinScanner.js +20 -3
- package/lib/commonjs/useVinScanner.js.map +1 -1
- package/lib/commonjs/vinUtils.js +7 -3
- package/lib/commonjs/vinUtils.js.map +1 -1
- package/lib/module/scanBarcodes.js +76 -6
- package/lib/module/scanBarcodes.js.map +1 -1
- package/lib/module/scanText.js +78 -4
- package/lib/module/scanText.js.map +1 -1
- package/lib/module/useVinScanner.js +20 -3
- package/lib/module/useVinScanner.js.map +1 -1
- package/lib/module/vinUtils.js +7 -3
- package/lib/module/vinUtils.js.map +1 -1
- package/lib/typescript/src/scanBarcodes.d.ts.map +1 -1
- package/lib/typescript/src/scanText.d.ts.map +1 -1
- package/lib/typescript/src/types.d.ts +21 -2
- package/lib/typescript/src/types.d.ts.map +1 -1
- package/lib/typescript/src/useVinScanner.d.ts.map +1 -1
- package/lib/typescript/src/vinUtils.d.ts +3 -1
- package/lib/typescript/src/vinUtils.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/scanBarcodes.ts +90 -8
- package/src/scanText.ts +93 -4
- package/src/types.ts +31 -2
- package/src/useVinScanner.ts +30 -3
- package/src/vinUtils.ts +11 -0
package/README.md
CHANGED
|
@@ -102,8 +102,17 @@ type VinScannerEvent = {
|
|
|
102
102
|
| `options.detection.preferBarcode` | boolean | Prefer barcode hits when selecting the best VIN | `true` |
|
|
103
103
|
| `options.detection.validateChecksum` | boolean | Run VIN checksum validation | `true` |
|
|
104
104
|
| `options.detection.emitDuplicates` | boolean | Emit unchanged payloads every frame | `false` for `'best'`, `true` for `'all'` |
|
|
105
|
+
| `options.detection.maxFrameRate` | number | Max FPS budget for frame processing (drops surplus frames to avoid blocking) | `30` |
|
|
106
|
+
| `options.detection.forceOrientation` | `'portrait' \| 'portrait-upside-down' \| 'landscape-left' \| 'landscape-right'` | Forces ML Kit to interpret every frame using the given orientation (useful when the UI is locked to portrait but the sensor reports landscape) | `null` |
|
|
105
107
|
| `options.onResult` | `(result, event) => void` | Convenience callback when using `useVinScanner`; receives either the best candidate, all candidates, or `null` plus the raw event | `undefined` |
|
|
106
108
|
|
|
109
|
+
### Advanced frame-processor controls
|
|
110
|
+
|
|
111
|
+
- **Per-frame plugin overrides:** both barcode and text frame processor plugins accept per-frame arguments, so you can dynamically change ML Kit barcode formats or text recognition language without reinitializing the plugin. Call `barcodeScanner.scanBarcodes(frame, { 'pdf-417': true })` or `textScanner.scanText(frame, { language: 'japanese' })` inside your worklet to override the resolved defaults for a single frame.
|
|
112
|
+
- **Orientation overrides:** If your UI is locked to portrait (e.g., iPad kiosks) but VisionCamera streams landscape buffers, set `detection.forceOrientation: 'portrait'`. The JS hook forwards that override to the native plugins so ML Kit always interprets frames with the requested rotation, eliminating the “upside-down unless I flip the paper” problem described in the [VisionCamera orientation guide](https://react-native-vision-camera.com/docs/guides/orientation).
|
|
113
|
+
- **Shared bounding boxes:** native plugins now stream bounding box coordinates via zero-copy shared arrays, minimizing JSI serialization. The hook translates these buffers into the familiar `BoundingBox` structures before running VIN heuristics, so no API change is required.
|
|
114
|
+
- **Orientation-safe processing:** the native plugins forward VisionCamera’s frame orientation metadata directly into ML Kit as recommended in the [VisionCamera orientation guide](https://react-native-vision-camera.com/docs/guides/orientation), ensuring portrait VIN scans stay upright.
|
|
115
|
+
|
|
107
116
|
### Hook-only usage
|
|
108
117
|
|
|
109
118
|
If you prefer to configure `react-native-vision-camera` yourself, grab the frame processor from the hook:
|
package/android/src/main/java/com/visioncamerabarcodescanner/VisionCameraBarcodeScannerModule.kt
CHANGED
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
package com.visioncamerabarcodescanner
|
|
2
2
|
|
|
3
3
|
import android.media.Image
|
|
4
|
-
import com.facebook.react.bridge.WritableNativeArray
|
|
5
|
-
import com.facebook.react.bridge.WritableNativeMap
|
|
6
4
|
import com.google.android.gms.tasks.Task
|
|
7
5
|
import com.google.android.gms.tasks.Tasks
|
|
8
6
|
import com.google.mlkit.vision.barcode.BarcodeScannerOptions
|
|
@@ -25,69 +23,113 @@ import com.google.mlkit.vision.barcode.common.Barcode.FORMAT_EAN_13
|
|
|
25
23
|
import com.google.mlkit.vision.common.InputImage
|
|
26
24
|
import com.mrousavy.camera.frameprocessors.Frame
|
|
27
25
|
import com.mrousavy.camera.frameprocessors.FrameProcessorPlugin
|
|
26
|
+
import com.mrousavy.camera.frameprocessors.SharedArray
|
|
28
27
|
import com.mrousavy.camera.frameprocessors.VisionCameraProxy
|
|
28
|
+
import java.nio.ByteOrder
|
|
29
|
+
import java.util.HashMap
|
|
29
30
|
|
|
30
|
-
|
|
31
|
+
private const val BOX_STRIDE = 6
|
|
31
32
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
else if (arguments?.get("data-matrix").toString().toBoolean()) optionsBuilder.setBarcodeFormats(FORMAT_DATA_MATRIX)
|
|
48
|
-
else if (arguments?.get("all").toString().toBoolean()) optionsBuilder.setBarcodeFormats(FORMAT_ALL_FORMATS)
|
|
49
|
-
else optionsBuilder.setBarcodeFormats(FORMAT_ALL_FORMATS)
|
|
33
|
+
class VisionCameraBarcodeScannerModule(
|
|
34
|
+
private val proxy : VisionCameraProxy,
|
|
35
|
+
options: Map<String, Any>?
|
|
36
|
+
): FrameProcessorPlugin() {
|
|
37
|
+
|
|
38
|
+
private val initializerOptions: Map<String, Any> = options ?: emptyMap()
|
|
39
|
+
|
|
40
|
+
private fun mergedOptions(overrides: Map<String, Any>?): Map<String, Any> {
|
|
41
|
+
if (overrides == null || overrides.isEmpty()) {
|
|
42
|
+
return initializerOptions
|
|
43
|
+
}
|
|
44
|
+
val merged = HashMap(initializerOptions)
|
|
45
|
+
merged.putAll(overrides)
|
|
46
|
+
return merged
|
|
47
|
+
}
|
|
50
48
|
|
|
51
|
-
|
|
49
|
+
private fun buildScannerOptions(effective: Map<String, Any>): BarcodeScannerOptions {
|
|
50
|
+
val builder = BarcodeScannerOptions.Builder()
|
|
51
|
+
when {
|
|
52
|
+
effective["code-128"].toString().toBoolean() -> builder.setBarcodeFormats(FORMAT_CODE_128)
|
|
53
|
+
effective["code-39"].toString().toBoolean() -> builder.setBarcodeFormats(FORMAT_CODE_39)
|
|
54
|
+
effective["code-93"].toString().toBoolean() -> builder.setBarcodeFormats(FORMAT_CODE_93)
|
|
55
|
+
effective["codabar"].toString().toBoolean() -> builder.setBarcodeFormats(FORMAT_CODABAR)
|
|
56
|
+
effective["ean-13"].toString().toBoolean() -> builder.setBarcodeFormats(FORMAT_EAN_13)
|
|
57
|
+
effective["ean-8"].toString().toBoolean() -> builder.setBarcodeFormats(FORMAT_EAN_8)
|
|
58
|
+
effective["itf"].toString().toBoolean() -> builder.setBarcodeFormats(FORMAT_ITF)
|
|
59
|
+
effective["upc-e"].toString().toBoolean() -> builder.setBarcodeFormats(FORMAT_UPC_E)
|
|
60
|
+
effective["upc-a"].toString().toBoolean() -> builder.setBarcodeFormats(FORMAT_UPC_A)
|
|
61
|
+
effective["qr"].toString().toBoolean() -> builder.setBarcodeFormats(FORMAT_QR_CODE)
|
|
62
|
+
effective["pdf-417"].toString().toBoolean() -> builder.setBarcodeFormats(FORMAT_PDF417)
|
|
63
|
+
effective["aztec"].toString().toBoolean() -> builder.setBarcodeFormats(FORMAT_AZTEC)
|
|
64
|
+
effective["data-matrix"].toString().toBoolean() -> builder.setBarcodeFormats(FORMAT_DATA_MATRIX)
|
|
65
|
+
effective["all"].toString().toBoolean() -> builder.setBarcodeFormats(FORMAT_ALL_FORMATS)
|
|
66
|
+
else -> builder.setBarcodeFormats(FORMAT_ALL_FORMATS)
|
|
67
|
+
}
|
|
68
|
+
return builder.build()
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
private fun orientationToDegrees(orientation: String?): Int? {
|
|
72
|
+
return when (orientation) {
|
|
73
|
+
"portrait" -> 0
|
|
74
|
+
"portrait-upside-down" -> 180
|
|
75
|
+
"landscape-left" -> 90
|
|
76
|
+
"landscape-right" -> 270
|
|
77
|
+
else -> null
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
override fun callback(frame: Frame, arguments: Map<String, Any>?): Any {
|
|
82
|
+
return try {
|
|
83
|
+
val options = mergedOptions(arguments)
|
|
84
|
+
val scanner = BarcodeScanning.getClient(buildScannerOptions(options))
|
|
52
85
|
val mediaImage: Image = frame.image
|
|
53
|
-
val
|
|
86
|
+
val rotationOverride = orientationToDegrees(options["orientation"] as? String)
|
|
87
|
+
val rotationDegrees = rotationOverride ?: frame.imageProxy.imageInfo.rotationDegrees
|
|
88
|
+
val image = InputImage.fromMediaImage(mediaImage, rotationDegrees)
|
|
54
89
|
val task: Task<List<Barcode>> = scanner.process(image)
|
|
55
90
|
val barcodes: List<Barcode> = Tasks.await(task)
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
91
|
+
|
|
92
|
+
val detections = ArrayList<Map<String, Any?>>()
|
|
93
|
+
val sharedArray =
|
|
94
|
+
if (barcodes.isNotEmpty()) SharedArray(proxy, barcodes.size * BOX_STRIDE * java.lang.Float.BYTES)
|
|
95
|
+
else null
|
|
96
|
+
val floatBuffer = sharedArray?.byteBuffer
|
|
97
|
+
?.order(ByteOrder.nativeOrder())
|
|
98
|
+
?.asFloatBuffer()
|
|
99
|
+
|
|
100
|
+
barcodes.forEachIndexed { index, barcode ->
|
|
101
|
+
val detection = HashMap<String, Any?>()
|
|
102
|
+
detection["rawValue"] = barcode.rawValue
|
|
103
|
+
detection["displayValue"] = barcode.displayValue
|
|
104
|
+
detection["format"] = barcode.format
|
|
105
|
+
detection["boxIndex"] = index
|
|
106
|
+
floatBuffer?.let { buffer ->
|
|
107
|
+
val bounds = barcode.boundingBox
|
|
108
|
+
val floatIndex = index * BOX_STRIDE
|
|
109
|
+
if (bounds != null) {
|
|
110
|
+
buffer.put(floatIndex, bounds.top.toFloat())
|
|
111
|
+
buffer.put(floatIndex + 1, bounds.bottom.toFloat())
|
|
112
|
+
buffer.put(floatIndex + 2, bounds.left.toFloat())
|
|
113
|
+
buffer.put(floatIndex + 3, bounds.right.toFloat())
|
|
114
|
+
buffer.put(floatIndex + 4, bounds.width().toFloat())
|
|
115
|
+
buffer.put(floatIndex + 5, bounds.height().toFloat())
|
|
116
|
+
} else {
|
|
117
|
+
for (offset in 0 until BOX_STRIDE) {
|
|
118
|
+
buffer.put(floatIndex + offset, -1f)
|
|
119
|
+
}
|
|
83
120
|
}
|
|
84
121
|
}
|
|
85
|
-
|
|
122
|
+
detections.add(detection)
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
val response = HashMap<String, Any?>()
|
|
126
|
+
response["detections"] = detections
|
|
127
|
+
if (sharedArray != null) {
|
|
128
|
+
response["boxes"] = sharedArray
|
|
86
129
|
}
|
|
87
|
-
|
|
130
|
+
response
|
|
88
131
|
} catch (e: Exception) {
|
|
89
|
-
|
|
132
|
+
throw Exception("Error processing barcode scanner: $e")
|
|
90
133
|
}
|
|
91
134
|
}
|
|
92
|
-
|
|
93
135
|
}
|
package/android/src/main/java/com/visioncamerabarcodescanner/VisionCameraBarcodeScannerPackage.kt
CHANGED
|
@@ -10,10 +10,10 @@ import com.visioncameratextrecognition.VisionCameraTextRecognitionModule
|
|
|
10
10
|
class VisionCameraBarcodeScannerPackage : ReactPackage {
|
|
11
11
|
companion object {
|
|
12
12
|
init {
|
|
13
|
-
FrameProcessorPluginRegistry.addFrameProcessorPlugin("
|
|
13
|
+
FrameProcessorPluginRegistry.addFrameProcessorPlugin("vinScannerBarcode") {proxy,options ->
|
|
14
14
|
VisionCameraBarcodeScannerModule(proxy,options)
|
|
15
15
|
}
|
|
16
|
-
FrameProcessorPluginRegistry.addFrameProcessorPlugin("
|
|
16
|
+
FrameProcessorPluginRegistry.addFrameProcessorPlugin("vinScannerText") { proxy, options ->
|
|
17
17
|
VisionCameraTextRecognitionModule(proxy, options)
|
|
18
18
|
}
|
|
19
19
|
}
|
package/android/src/main/java/com/visioncameratextrecognition/VisionCameraTextRecognitionModule.kt
CHANGED
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
package com.visioncameratextrecognition
|
|
2
2
|
|
|
3
3
|
import android.media.Image
|
|
4
|
-
import com.facebook.react.bridge.WritableNativeArray
|
|
5
|
-
import com.facebook.react.bridge.WritableNativeMap
|
|
6
4
|
import com.google.android.gms.tasks.Task
|
|
7
5
|
import com.google.android.gms.tasks.Tasks
|
|
8
6
|
import com.google.mlkit.vision.common.InputImage
|
|
@@ -14,114 +12,160 @@ import com.google.mlkit.vision.text.devanagari.DevanagariTextRecognizerOptions
|
|
|
14
12
|
import com.google.mlkit.vision.text.japanese.JapaneseTextRecognizerOptions
|
|
15
13
|
import com.google.mlkit.vision.text.korean.KoreanTextRecognizerOptions
|
|
16
14
|
import com.google.mlkit.vision.text.latin.TextRecognizerOptions
|
|
17
|
-
import com.mrousavy.camera.
|
|
18
|
-
import com.mrousavy.camera.
|
|
19
|
-
import com.mrousavy.camera.
|
|
20
|
-
import com.mrousavy.camera.
|
|
15
|
+
import com.mrousavy.camera.frameprocessors.Frame
|
|
16
|
+
import com.mrousavy.camera.frameprocessors.FrameProcessorPlugin
|
|
17
|
+
import com.mrousavy.camera.frameprocessors.SharedArray
|
|
18
|
+
import com.mrousavy.camera.frameprocessors.VisionCameraProxy
|
|
19
|
+
import java.nio.ByteOrder
|
|
20
|
+
import java.util.HashMap
|
|
21
21
|
import java.util.ArrayList
|
|
22
22
|
|
|
23
|
+
private const val TEXT_BOX_STRIDE = 12
|
|
23
24
|
|
|
24
|
-
class VisionCameraTextRecognitionModule(
|
|
25
|
-
private
|
|
26
|
-
|
|
25
|
+
class VisionCameraTextRecognitionModule(
|
|
26
|
+
private val proxy : VisionCameraProxy,
|
|
27
|
+
options: Map<String, Any>?
|
|
28
|
+
): FrameProcessorPlugin() {
|
|
29
|
+
private var language = options?.get("language").toString().ifEmpty { "latin" }
|
|
30
|
+
private val recognizers = mutableMapOf<String, TextRecognizer>()
|
|
27
31
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
32
|
+
private fun recognizerFor(languageCode: String): TextRecognizer {
|
|
33
|
+
return recognizers.getOrPut(languageCode) {
|
|
34
|
+
when (languageCode) {
|
|
35
|
+
"latin" -> TextRecognition.getClient(TextRecognizerOptions.DEFAULT_OPTIONS)
|
|
36
|
+
"chinese" -> TextRecognition.getClient(ChineseTextRecognizerOptions.Builder().build())
|
|
37
|
+
"devanagari" -> TextRecognition.getClient(DevanagariTextRecognizerOptions.Builder().build())
|
|
38
|
+
"japanese" -> TextRecognition.getClient(JapaneseTextRecognizerOptions.Builder().build())
|
|
39
|
+
"korean" -> TextRecognition.getClient(KoreanTextRecognizerOptions.Builder().build())
|
|
40
|
+
else -> TextRecognition.getClient(TextRecognizerOptions.DEFAULT_OPTIONS)
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
private fun orientationToDegrees(orientation: String?): Int? {
|
|
46
|
+
return when (orientation) {
|
|
47
|
+
"portrait" -> 0
|
|
48
|
+
"portrait-upside-down" -> 180
|
|
49
|
+
"landscape-left" -> 90
|
|
50
|
+
"landscape-right" -> 270
|
|
51
|
+
else -> null
|
|
36
52
|
}
|
|
37
53
|
}
|
|
38
|
-
|
|
54
|
+
|
|
55
|
+
override fun callback(frame: Frame, arguments: Map<String, Any>?): Any {
|
|
39
56
|
try {
|
|
40
57
|
val mediaImage: Image = frame.image
|
|
41
|
-
val
|
|
42
|
-
val
|
|
43
|
-
val
|
|
58
|
+
val rotationOverride = orientationToDegrees(arguments?.get("orientation") as? String)
|
|
59
|
+
val rotationDegrees = rotationOverride ?: frame.imageProxy.imageInfo.rotationDegrees
|
|
60
|
+
val requestedLanguage = arguments?.get("language")?.toString()?.ifEmpty { null }
|
|
61
|
+
val effectiveLanguage = requestedLanguage ?: language
|
|
62
|
+
val recognizer = recognizerFor(effectiveLanguage)
|
|
63
|
+
val image = InputImage.fromMediaImage(mediaImage, rotationDegrees)
|
|
44
64
|
val task: Task<Text> = recognizer.process(image)
|
|
45
65
|
val result: Text? = Tasks.await(task)
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
66
|
+
val resultText = result?.text
|
|
67
|
+
val detections = ArrayList<Map<String, Any?>>()
|
|
68
|
+
val boxValues = ArrayList<FloatArray>()
|
|
69
|
+
|
|
70
|
+
result?.textBlocks?.forEach { block ->
|
|
71
|
+
val blockBounds = block.boundingBox
|
|
72
|
+
if (block.lines.isEmpty()) {
|
|
73
|
+
val detection = HashMap<String, Any?>()
|
|
74
|
+
detection["resultText"] = resultText
|
|
75
|
+
detection["blockText"] = block.text
|
|
76
|
+
detection["boxIndex"] = boxValues.size
|
|
77
|
+
detections.add(detection)
|
|
78
|
+
boxValues.add(
|
|
79
|
+
floatArrayOf(
|
|
80
|
+
blockBounds?.top?.toFloat() ?: -1f,
|
|
81
|
+
blockBounds?.bottom?.toFloat() ?: -1f,
|
|
82
|
+
blockBounds?.left?.toFloat() ?: -1f,
|
|
83
|
+
blockBounds?.right?.toFloat() ?: -1f,
|
|
84
|
+
-1f,
|
|
85
|
+
-1f,
|
|
86
|
+
-1f,
|
|
87
|
+
-1f,
|
|
88
|
+
-1f,
|
|
89
|
+
-1f,
|
|
90
|
+
-1f,
|
|
91
|
+
-1f,
|
|
92
|
+
)
|
|
93
|
+
)
|
|
94
|
+
}
|
|
95
|
+
block.lines.forEach { line ->
|
|
96
|
+
if (line.elements.isEmpty()) {
|
|
97
|
+
val detection = HashMap<String, Any?>()
|
|
98
|
+
detection["resultText"] = resultText
|
|
99
|
+
detection["blockText"] = block.text
|
|
100
|
+
detection["lineText"] = line.text
|
|
101
|
+
detection["boxIndex"] = boxValues.size
|
|
102
|
+
detections.add(detection)
|
|
103
|
+
boxValues.add(
|
|
104
|
+
floatArrayOf(
|
|
105
|
+
blockBounds?.top?.toFloat() ?: -1f,
|
|
106
|
+
blockBounds?.bottom?.toFloat() ?: -1f,
|
|
107
|
+
blockBounds?.left?.toFloat() ?: -1f,
|
|
108
|
+
blockBounds?.right?.toFloat() ?: -1f,
|
|
109
|
+
line.boundingBox?.top?.toFloat() ?: -1f,
|
|
110
|
+
line.boundingBox?.bottom?.toFloat() ?: -1f,
|
|
111
|
+
line.boundingBox?.left?.toFloat() ?: -1f,
|
|
112
|
+
line.boundingBox?.right?.toFloat() ?: -1f,
|
|
113
|
+
-1f,
|
|
114
|
+
-1f,
|
|
115
|
+
-1f,
|
|
116
|
+
-1f,
|
|
117
|
+
)
|
|
118
|
+
)
|
|
68
119
|
}
|
|
69
|
-
|
|
70
|
-
|
|
120
|
+
line.elements.forEach { element ->
|
|
121
|
+
val detection = HashMap<String, Any?>()
|
|
122
|
+
detection["resultText"] = resultText
|
|
123
|
+
detection["blockText"] = block.text
|
|
124
|
+
detection["lineText"] = line.text
|
|
125
|
+
detection["elementText"] = element.text
|
|
126
|
+
detection["boxIndex"] = boxValues.size
|
|
127
|
+
detections.add(detection)
|
|
128
|
+
boxValues.add(
|
|
129
|
+
floatArrayOf(
|
|
130
|
+
blockBounds?.top?.toFloat() ?: -1f,
|
|
131
|
+
blockBounds?.bottom?.toFloat() ?: -1f,
|
|
132
|
+
blockBounds?.left?.toFloat() ?: -1f,
|
|
133
|
+
blockBounds?.right?.toFloat() ?: -1f,
|
|
134
|
+
line.boundingBox?.top?.toFloat() ?: -1f,
|
|
135
|
+
line.boundingBox?.bottom?.toFloat() ?: -1f,
|
|
136
|
+
line.boundingBox?.left?.toFloat() ?: -1f,
|
|
137
|
+
line.boundingBox?.right?.toFloat() ?: -1f,
|
|
138
|
+
element.boundingBox?.top?.toFloat() ?: -1f,
|
|
139
|
+
element.boundingBox?.bottom?.toFloat() ?: -1f,
|
|
140
|
+
element.boundingBox?.left?.toFloat() ?: -1f,
|
|
141
|
+
element.boundingBox?.right?.toFloat() ?: -1f,
|
|
142
|
+
)
|
|
143
|
+
)
|
|
71
144
|
}
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
map.putString("lineText",lineText)
|
|
75
|
-
val lineCornerPoints = line.cornerPoints?.size
|
|
76
|
-
if (lineCornerPoints != null) {
|
|
77
|
-
map.putInt("size",lineCornerPoints)
|
|
78
|
-
}
|
|
79
|
-
val lineFrameBottom = line.boundingBox?.bottom
|
|
80
|
-
val lineFrameTop = line.boundingBox?.top
|
|
81
|
-
val lineFrameLeft = line.boundingBox?.left
|
|
82
|
-
val lineFrameRight = line.boundingBox?.right
|
|
83
|
-
if (lineFrameBottom != null) {
|
|
84
|
-
map.putInt("lineFrameBottom",lineFrameBottom)
|
|
85
|
-
}
|
|
86
|
-
if (lineFrameLeft != null) {
|
|
87
|
-
map.putInt("lineFrameLeft",lineFrameLeft)
|
|
88
|
-
}
|
|
89
|
-
if (lineFrameTop != null) {
|
|
90
|
-
map.putInt("lineFrameTop",lineFrameTop)
|
|
91
|
-
}
|
|
92
|
-
if (lineFrameRight != null) {
|
|
93
|
-
map.putInt("lineFrameRight",lineFrameRight)
|
|
94
|
-
}
|
|
95
|
-
for (element in line.elements) {
|
|
96
|
-
val elementText = element.text
|
|
97
|
-
map.putString("elementText",elementText)
|
|
98
|
-
|
|
99
|
-
val elementCornerPoints = line.cornerPoints?.size
|
|
100
|
-
if (elementCornerPoints != null) {
|
|
101
|
-
map.putInt("size",elementCornerPoints)
|
|
102
|
-
}
|
|
103
|
-
val elementFrameBottom = line.boundingBox?.bottom
|
|
104
|
-
val elementFrameTop = line.boundingBox?.top
|
|
105
|
-
val elementFrameLeft = line.boundingBox?.left
|
|
106
|
-
val elementFrameRight = line.boundingBox?.right
|
|
107
|
-
if (elementFrameBottom != null) {
|
|
108
|
-
map.putInt("elementFrameBottom",elementFrameBottom)
|
|
109
|
-
}
|
|
110
|
-
if (elementFrameLeft != null) {
|
|
111
|
-
map.putInt("elementFrameLeft",elementFrameLeft)
|
|
112
|
-
}
|
|
113
|
-
if (elementFrameTop != null) {
|
|
114
|
-
map.putInt("elementFrameTop",elementFrameTop)
|
|
115
|
-
}
|
|
116
|
-
if (elementFrameRight != null) {
|
|
117
|
-
map.putInt("elementFrameRight",elementFrameRight)
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
array.pushMap(map)
|
|
145
|
+
}
|
|
146
|
+
}
|
|
121
147
|
|
|
148
|
+
val sharedArray =
|
|
149
|
+
if (boxValues.isNotEmpty()) SharedArray(proxy, boxValues.size * TEXT_BOX_STRIDE * java.lang.Float.BYTES)
|
|
150
|
+
else null
|
|
151
|
+
val floatBuffer = sharedArray?.byteBuffer
|
|
152
|
+
?.order(ByteOrder.nativeOrder())
|
|
153
|
+
?.asFloatBuffer()
|
|
154
|
+
floatBuffer?.let { buffer ->
|
|
155
|
+
boxValues.forEachIndexed { index, values ->
|
|
156
|
+
val floatIndex = index * TEXT_BOX_STRIDE
|
|
157
|
+
for (offset in 0 until TEXT_BOX_STRIDE) {
|
|
158
|
+
buffer.put(floatIndex + offset, values[offset])
|
|
122
159
|
}
|
|
123
160
|
}
|
|
124
|
-
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
val response = HashMap<String, Any?>()
|
|
164
|
+
response["detections"] = detections
|
|
165
|
+
if (sharedArray != null) {
|
|
166
|
+
response["boxes"] = sharedArray
|
|
167
|
+
}
|
|
168
|
+
return response
|
|
125
169
|
} catch (e: Exception) {
|
|
126
170
|
throw Exception("Error processing text recognition: $e ")
|
|
127
171
|
}
|