Skip to content

Instantly share code, notes, and snippets.

@barthap
Created October 28, 2021 16:44
Show Gist options
  • Save barthap/6068d1eb0b0508ba239ad2e61037fac9 to your computer and use it in GitHub Desktop.
Save barthap/6068d1eb0b0508ba239ad2e61037fac9 to your computer and use it in GitHub Desktop.
Kotlin utils for React Native WritableMap/WritableArray
package com.barthap.rn.mlkit.ocr
import android.graphics.Point
import android.graphics.Rect
import com.facebook.react.bridge.WritableArray
import com.facebook.react.bridge.WritableMap
import com.facebook.react.bridge.WritableNativeArray
import com.facebook.react.bridge.WritableNativeMap
import java.lang.IllegalArgumentException
inline fun <reified T> Iterable<T>.toNativeArray() = WritableNativeArray().apply {
forEach { el ->
when (el) {
is Int -> pushInt(el)
is String -> pushString(el)
is Double -> pushDouble(el)
is Boolean -> pushBoolean(el)
is Point -> pushMap(el.toNativeDict())
is Rect -> pushMap(el.toNativeDict())
is WritableMap -> pushMap(el)
is WritableArray -> pushArray(el)
// is Iterable<*> -> pushArray(el.toNativeArray())
// is Array<*> -> pushArray(el.toList().toNativeArray())
// is Map<String, *> -> pushMap(el.toNativeMap())
null -> pushNull()
else -> throw IllegalArgumentException("Unknown element type: " + T::class.qualifiedName)
}
}
}
inline fun <reified T> Map<String, T>.toNativeMap() =
WritableNativeMap().also { nativeMap ->
for ((k, v) in this.entries) {
when(v) {
null -> nativeMap.putNull(k)
is String -> nativeMap.putString(k, v)
is Int -> nativeMap.putInt(k, v)
is Double -> nativeMap.putDouble(k, v)
is Boolean -> nativeMap.putBoolean(k, v)
is Point -> nativeMap.putMap(k, v.toNativeDict())
is Rect -> nativeMap.putMap(k, v.toNativeDict())
is Iterable<*> -> nativeMap.putArray(k, v.toNativeArray())
is Array<*> -> nativeMap.putArray(k, v.toList().toNativeArray())
// is Map<*, *> -> nativeMap.putMap(k, v.toNativeMap())
is WritableArray -> nativeMap.putArray(k, v)
is WritableMap -> nativeMap.putMap(k, v)
else -> throw IllegalArgumentException("Unknown type: " + T::class.qualifiedName)
}
}
}
fun nativeMapOf(vararg pairs: Pair<String, Any?>): WritableMap =
mapOf(*pairs).toNativeMap()
fun nativeArrayOf(vararg elements: Any?): WritableArray
= listOf(*elements).toNativeArray()
fun Point.toNativeDict() = nativeMapOf(
"x" to this.x,
"y" to this.y
)
fun Rect.toNativeDict() = nativeMapOf(
"origin" to Point(left, top),
"width" to width(),
"height" to height()
)
package com.barthap.rn.mlkit.ocr
import android.net.Uri
import com.facebook.react.bridge.*
import com.google.mlkit.vision.common.InputImage
import com.google.mlkit.vision.text.Text
import com.google.mlkit.vision.text.TextRecognition
import com.google.mlkit.vision.text.latin.TextRecognizerOptions
class MLKitOcrModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaModule(reactContext) {
override fun getName() = "MLKitOcr"
@ReactMethod
fun recognizeText(uri: String, promise: Promise) {
try {
val image = InputImage.fromFilePath(reactApplicationContext, Uri.parse(uri))
val textRecognizer = TextRecognition.getClient(TextRecognizerOptions.DEFAULT_OPTIONS)
textRecognizer.process(image)
.addOnSuccessListener { visionText ->
promise.resolve(convertResult(visionText))
}.addOnFailureListener { e ->
promise.reject(e)
e.printStackTrace()
}
} catch (e: Exception) {
promise.reject(e)
e.printStackTrace()
}
}
private fun convertResult(result: Text): WritableMap {
val blocks = result.textBlocks.map(::convertBlock).toNativeArray()
return nativeMapOf(
"text" to result.text,
"blocks" to blocks
)
}
private fun convertBlock(block: Text.TextBlock): WritableMap {
val blockLines = block.lines
.map { line ->
val elements = line.elements.map { element ->
nativeMapOf(
"text" to element.text,
"frame" to element.boundingBox,
"cornerPoints" to element.cornerPoints
)
}.toNativeArray()
nativeMapOf(
"text" to line.text,
"elements" to elements,
"recognizedLanguages" to convertRecognizedLang(line.recognizedLanguage),
"frame" to line.boundingBox,
"cornerPoints" to line.cornerPoints
)
}.toNativeArray()
return nativeMapOf(
"text" to block.text,
"lines" to blockLines,
"recognizedLanguages" to convertRecognizedLang(block.recognizedLanguage),
"frame" to block.boundingBox,
"cornerPoints" to block.cornerPoints
)
}
/**
* converts `languageCode: string` into `[{ languageCode: string }]`
*/
private fun convertRecognizedLang(lang: String?) = nativeArrayOf(nativeMapOf(
"languageCode" to lang
))
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment