@nitro-mlkit/object-detection 0.1.0-beta.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.
Files changed (55) hide show
  1. package/LICENSE +21 -0
  2. package/NitroMLKitObjects.podspec +34 -0
  3. package/README.md +57 -0
  4. package/android/CMakeLists.txt +12 -0
  5. package/android/build.gradle +77 -0
  6. package/android/src/main/AndroidManifest.xml +3 -0
  7. package/android/src/main/cpp/cpp-adapter.cpp +9 -0
  8. package/android/src/main/kotlin/com/margelo/nitro/nitromlkit/objects/HybridObjectDetector.kt +102 -0
  9. package/android/src/main/kotlin/com/nitromlkit/objects/NitroMLKitObjectsPackage.kt +19 -0
  10. package/expo-module.config.json +9 -0
  11. package/ios/HybridObjectDetector.swift +125 -0
  12. package/nitro.json +16 -0
  13. package/nitrogen/generated/.gitattributes +1 -0
  14. package/nitrogen/generated/android/NitroMLKitObjects+autolinking.cmake +81 -0
  15. package/nitrogen/generated/android/NitroMLKitObjects+autolinking.gradle +27 -0
  16. package/nitrogen/generated/android/NitroMLKitObjectsOnLoad.cpp +54 -0
  17. package/nitrogen/generated/android/NitroMLKitObjectsOnLoad.hpp +34 -0
  18. package/nitrogen/generated/android/c++/JBatchObjectResult.hpp +95 -0
  19. package/nitrogen/generated/android/c++/JDetectedObject.hpp +88 -0
  20. package/nitrogen/generated/android/c++/JHybridObjectDetectorSpec.cpp +131 -0
  21. package/nitrogen/generated/android/c++/JHybridObjectDetectorSpec.hpp +65 -0
  22. package/nitrogen/generated/android/c++/JObjectLabel.hpp +65 -0
  23. package/nitrogen/generated/android/c++/JObjectRect.hpp +69 -0
  24. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitromlkit/objects/BatchObjectResult.kt +66 -0
  25. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitromlkit/objects/DetectedObject.kt +61 -0
  26. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitromlkit/objects/HybridObjectDetectorSpec.kt +63 -0
  27. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitromlkit/objects/NitroMLKitObjectsOnLoad.kt +35 -0
  28. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitromlkit/objects/ObjectLabel.kt +61 -0
  29. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitromlkit/objects/ObjectRect.kt +66 -0
  30. package/nitrogen/generated/ios/NitroMLKitObjects+autolinking.rb +62 -0
  31. package/nitrogen/generated/ios/NitroMLKitObjects-Swift-Cxx-Bridge.cpp +57 -0
  32. package/nitrogen/generated/ios/NitroMLKitObjects-Swift-Cxx-Bridge.hpp +236 -0
  33. package/nitrogen/generated/ios/NitroMLKitObjects-Swift-Cxx-Umbrella.hpp +59 -0
  34. package/nitrogen/generated/ios/NitroMLKitObjectsAutolinking.mm +33 -0
  35. package/nitrogen/generated/ios/NitroMLKitObjectsAutolinking.swift +26 -0
  36. package/nitrogen/generated/ios/c++/HybridObjectDetectorSpecSwift.cpp +11 -0
  37. package/nitrogen/generated/ios/c++/HybridObjectDetectorSpecSwift.hpp +112 -0
  38. package/nitrogen/generated/ios/swift/BatchObjectResult.swift +63 -0
  39. package/nitrogen/generated/ios/swift/DetectedObject.swift +45 -0
  40. package/nitrogen/generated/ios/swift/Func_void_std__exception_ptr.swift +46 -0
  41. package/nitrogen/generated/ios/swift/Func_void_std__vector_BatchObjectResult_.swift +46 -0
  42. package/nitrogen/generated/ios/swift/Func_void_std__vector_DetectedObject_.swift +46 -0
  43. package/nitrogen/generated/ios/swift/HybridObjectDetectorSpec.swift +57 -0
  44. package/nitrogen/generated/ios/swift/HybridObjectDetectorSpec_cxx.swift +188 -0
  45. package/nitrogen/generated/ios/swift/ObjectLabel.swift +39 -0
  46. package/nitrogen/generated/ios/swift/ObjectRect.swift +44 -0
  47. package/nitrogen/generated/shared/c++/BatchObjectResult.hpp +99 -0
  48. package/nitrogen/generated/shared/c++/DetectedObject.hpp +96 -0
  49. package/nitrogen/generated/shared/c++/HybridObjectDetectorSpec.cpp +23 -0
  50. package/nitrogen/generated/shared/c++/HybridObjectDetectorSpec.hpp +71 -0
  51. package/nitrogen/generated/shared/c++/ObjectLabel.hpp +91 -0
  52. package/nitrogen/generated/shared/c++/ObjectRect.hpp +95 -0
  53. package/package.json +53 -0
  54. package/src/index.ts +20 -0
  55. package/src/specs/ObjectDetector.nitro.ts +54 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Gonzalo Polo
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,34 @@
1
+ require "json"
2
+
3
+ package = JSON.parse(File.read(File.join(__dir__, "package.json")))
4
+
5
+ Pod::Spec.new do |s|
6
+ s.name = "NitroMLKitObjects"
7
+ # Must match nitro.json's `ios.iosModuleName` — Nitrogen's generated bridge
8
+ # imports "NitroMLKitObjects-Swift.h", so the compiled Swift module name has to be NitroMLKitObjects.
9
+ s.module_name = "NitroMLKitObjects"
10
+ s.version = package["version"]
11
+ s.summary = package["description"]
12
+ s.homepage = package["repository"]["url"]
13
+ s.license = package["license"]
14
+ s.authors = package["author"]
15
+ s.source = { :git => "https://github.com/pologonzalo/react-native-nitro-mlkit.git", :tag => s.version }
16
+
17
+ s.platforms = { :ios => "15.5" }
18
+
19
+ s.source_files = [
20
+ "ios/**/*.{swift,h,m,mm,cpp}"
21
+ ]
22
+
23
+ s.dependency "GoogleMLKit/ObjectDetection", "~> 7.0"
24
+
25
+ s.pod_target_xcconfig = {
26
+ "SWIFT_VERSION" => "5.9"
27
+ }
28
+
29
+ # Add all files generated by Nitrogen (generated sources + NitroModules dep +
30
+ # the C++/Swift-interop build flags — same setup as the working
31
+ # NitroMLKitFaceDetection podspec).
32
+ load 'nitrogen/generated/ios/NitroMLKitObjects+autolinking.rb'
33
+ add_nitrogen_files(s)
34
+ end
package/README.md ADDED
@@ -0,0 +1,57 @@
1
+ # React Native ML Kit — Object Detection
2
+
3
+ **`@nitro-mlkit/object-detection`** · on-device Google ML Kit via [Nitro Modules](https://github.com/mrousavy/nitro) — JSI, no bridge.
4
+
5
+ > ⚠️ **Beta (`0.1.0-beta.x`).** Android verified on-device; iOS builds & links but
6
+ > device runtime is pending — see [Platform status](#platform-status).
7
+
8
+ High-performance, on-device **object detection & tracking** for React Native,
9
+ built with [Nitro Modules](https://github.com/mrousavy/nitro) (JSI, no bridge).
10
+
11
+ Powered by **Google ML Kit**. Detects prominent objects in an image with
12
+ bounding boxes and coarse category labels. **All on-device.**
13
+
14
+ ## Installation
15
+
16
+ ```bash
17
+ npm install @nitro-mlkit/object-detection@beta react-native-nitro-modules
18
+ ```
19
+
20
+ No config plugin (it's an autolinked Expo module). Just install and
21
+ `npx expo prebuild`. Not available in Expo Go.
22
+
23
+ ## Usage
24
+
25
+ ```ts
26
+ import { NitroObjects } from "@nitro-mlkit/object-detection";
27
+
28
+ const objects = await NitroObjects.detect(imageUri);
29
+ // → [{ bounds:{x,y,width,height}, trackingId, labels:[{text,confidence,index}] }]
30
+
31
+ // Native batch — one JSI call
32
+ const results = await NitroObjects.detectBatch(uris, 4 /* concurrency */);
33
+
34
+ NitroObjects.isAvailable(); // boolean
35
+ ```
36
+
37
+ Uses SINGLE_IMAGE_MODE with multiple objects + coarse classification. ML Kit's
38
+ default classifier covers broad categories (Fashion good, Home good, Food,
39
+ Place, Plant); it targets prominent *objects*, not faces/people.
40
+
41
+ ## Platform status
42
+
43
+ | Platform | Min | Status |
44
+ | -------- | --- | ------ |
45
+ | Android | API 21+ | ✅ Verified on-device (Pixel 9, API 36): `detect` runs in ~200 ms |
46
+ | iOS | 15.5+ | ⚠️ Swift impl written; on-device build & run pending¹ |
47
+ | tvOS/macOS | — | 🔜 Planned |
48
+
49
+ ¹ ML Kit's iOS pods ship no `arm64` Simulator slice; validate on a physical device.
50
+
51
+ ## Part of `nitro-mlkit`
52
+
53
+ The full ML Kit suite on Nitro — see the other `@nitro-mlkit/*` packages.
54
+
55
+ ## License
56
+
57
+ MIT © Gonzalo Polo
@@ -0,0 +1,12 @@
1
+ project(NitroMLKitObjects)
2
+ cmake_minimum_required(VERSION 3.9.0)
3
+
4
+ set(CMAKE_CXX_STANDARD 20)
5
+ set(CMAKE_CXX_STANDARD_REQUIRED ON)
6
+
7
+ add_library(NitroMLKitObjects SHARED
8
+ src/main/cpp/cpp-adapter.cpp
9
+ )
10
+
11
+ # Add all files generated by Nitrogen
12
+ include(${CMAKE_SOURCE_DIR}/../nitrogen/generated/android/NitroMLKitObjects+autolinking.cmake)
@@ -0,0 +1,77 @@
1
+ buildscript {
2
+ ext.safeExtGet = { prop, fallback ->
3
+ rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback
4
+ }
5
+ }
6
+
7
+ def reactNativeArchitectures() {
8
+ def value = rootProject.getProperties().get("reactNativeArchitectures")
9
+ return value ? value.split(",") : ["armeabi-v7a", "x86", "x86_64", "arm64-v8a"]
10
+ }
11
+
12
+ apply plugin: "com.android.library"
13
+ apply plugin: "kotlin-android"
14
+
15
+ android {
16
+ namespace "com.nitromlkit.objects"
17
+ compileSdkVersion safeExtGet("compileSdkVersion", 35)
18
+ ndkVersion safeExtGet("ndkVersion", "27.1.12297006")
19
+
20
+ defaultConfig {
21
+ minSdkVersion safeExtGet("minSdkVersion", 26)
22
+ targetSdkVersion safeExtGet("targetSdkVersion", 35)
23
+
24
+ externalNativeBuild {
25
+ cmake {
26
+ arguments "-DANDROID_STL=c++_shared"
27
+ abiFilters (*reactNativeArchitectures())
28
+ }
29
+ }
30
+ }
31
+
32
+ externalNativeBuild {
33
+ cmake {
34
+ path "CMakeLists.txt"
35
+ }
36
+ }
37
+
38
+ buildFeatures {
39
+ prefab true
40
+ }
41
+
42
+ compileOptions {
43
+ sourceCompatibility JavaVersion.VERSION_17
44
+ targetCompatibility JavaVersion.VERSION_17
45
+ }
46
+
47
+ kotlinOptions {
48
+ jvmTarget = "17"
49
+ }
50
+
51
+ sourceSets {
52
+ main {
53
+ java.srcDirs += [
54
+ "src/main/kotlin",
55
+ "../nitrogen/generated/android/kotlin"
56
+ ]
57
+ }
58
+ }
59
+ }
60
+
61
+ dependencies {
62
+ // MLKit
63
+ implementation "com.google.mlkit:object-detection:17.0.2"
64
+
65
+ // Nitro Modules
66
+ implementation project(":react-native-nitro-modules")
67
+
68
+ // Expo Modules (only used so autolinking calls our OnLoad at startup)
69
+ implementation project(":expo-modules-core")
70
+
71
+ // Kotlin coroutines
72
+ implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.9.0"
73
+ implementation "org.jetbrains.kotlinx:kotlinx-coroutines-play-services:1.9.0"
74
+
75
+ // React Native
76
+ implementation "com.facebook.react:react-android"
77
+ }
@@ -0,0 +1,3 @@
1
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android"
2
+ package="com.nitromlkit.objects">
3
+ </manifest>
@@ -0,0 +1,9 @@
1
+ #include <jni.h>
2
+ #include <fbjni/fbjni.h>
3
+ #include "NitroMLKitObjectsOnLoad.hpp"
4
+
5
+ JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void*) {
6
+ return facebook::jni::initialize(vm, []() {
7
+ margelo::nitro::mlkit::objects::registerAllNatives();
8
+ });
9
+ }
@@ -0,0 +1,102 @@
1
+ package com.margelo.nitro.nitromlkit.objects
2
+
3
+ import android.graphics.Bitmap
4
+ import android.graphics.BitmapFactory
5
+ import android.net.Uri
6
+ import com.google.mlkit.vision.common.InputImage
7
+ import com.google.mlkit.vision.objects.ObjectDetection
8
+ import com.google.mlkit.vision.objects.defaults.ObjectDetectorOptions
9
+ import com.margelo.nitro.NitroModules
10
+ import com.margelo.nitro.core.Promise
11
+ import kotlinx.coroutines.async
12
+ import kotlinx.coroutines.awaitAll
13
+ import kotlinx.coroutines.coroutineScope
14
+ import kotlinx.coroutines.tasks.await
15
+ import java.net.URL
16
+ import com.google.mlkit.vision.objects.DetectedObject as MlkitObject
17
+
18
+ /**
19
+ * Native Android implementation of ObjectDetector (MLKit object detection).
20
+ * SINGLE_IMAGE_MODE with multiple objects + coarse classification.
21
+ */
22
+ class HybridObjectDetector : HybridObjectDetectorSpec() {
23
+
24
+ private val detector by lazy {
25
+ ObjectDetection.getClient(
26
+ ObjectDetectorOptions.Builder()
27
+ .setDetectorMode(ObjectDetectorOptions.SINGLE_IMAGE_MODE)
28
+ .enableMultipleObjects()
29
+ .enableClassification()
30
+ .build()
31
+ )
32
+ }
33
+
34
+ override fun detect(imageUri: String): Promise<Array<DetectedObject>> {
35
+ return Promise.async { detectImage(imageUri) }
36
+ }
37
+
38
+ override fun detectBatch(imageUris: Array<String>, concurrency: Double): Promise<Array<BatchObjectResult>> {
39
+ return Promise.async {
40
+ val maxConcurrent = concurrency.toInt().coerceAtLeast(1)
41
+ val results = mutableListOf<BatchObjectResult>()
42
+ var start = 0
43
+ while (start < imageUris.size) {
44
+ val end = minOf(start + maxConcurrent, imageUris.size)
45
+ val chunk = coroutineScope {
46
+ (start until end).map { idx ->
47
+ async {
48
+ try {
49
+ BatchObjectResult(idx.toDouble(), detectImage(imageUris[idx]), true, null)
50
+ } catch (e: Exception) {
51
+ BatchObjectResult(idx.toDouble(), emptyArray(), false, e.message ?: "unknown error")
52
+ }
53
+ }
54
+ }.awaitAll()
55
+ }
56
+ results.addAll(chunk)
57
+ start = end
58
+ }
59
+ results.toTypedArray()
60
+ }
61
+ }
62
+
63
+ override fun isAvailable(): Boolean = true
64
+
65
+ private suspend fun detectImage(uri: String): Array<DetectedObject> {
66
+ val bitmap = loadBitmap(uri) ?: throw Error("Failed to load image: $uri")
67
+ val image = InputImage.fromBitmap(bitmap, 0)
68
+ val objects = detector.process(image).await()
69
+ return objects.map { mapObject(it) }.toTypedArray()
70
+ }
71
+
72
+ private fun mapObject(o: MlkitObject): DetectedObject {
73
+ val box = o.boundingBox
74
+ val labels = o.labels.map { ObjectLabel(it.text, it.confidence.toDouble(), it.index.toDouble()) }.toTypedArray()
75
+ return DetectedObject(
76
+ bounds = ObjectRect(
77
+ x = box.left.toDouble(),
78
+ y = box.top.toDouble(),
79
+ width = box.width().toDouble(),
80
+ height = box.height().toDouble(),
81
+ ),
82
+ trackingId = (o.trackingId ?: -1).toDouble(),
83
+ labels = labels,
84
+ )
85
+ }
86
+
87
+ private fun loadBitmap(uri: String): Bitmap? {
88
+ return try {
89
+ when {
90
+ uri.startsWith("file://") -> BitmapFactory.decodeFile(uri.removePrefix("file://"))
91
+ uri.startsWith("/") -> BitmapFactory.decodeFile(uri)
92
+ uri.startsWith("content://") -> {
93
+ val context = NitroModules.applicationContext ?: return null
94
+ context.contentResolver.openInputStream(Uri.parse(uri))?.use { BitmapFactory.decodeStream(it) }
95
+ }
96
+ else -> URL(uri).openStream().use { BitmapFactory.decodeStream(it) }
97
+ }
98
+ } catch (e: Exception) {
99
+ null
100
+ }
101
+ }
102
+ }
@@ -0,0 +1,19 @@
1
+ package com.nitromlkit.objects
2
+
3
+ import expo.modules.kotlin.modules.Module
4
+ import expo.modules.kotlin.modules.ModuleDefinition
5
+ import com.margelo.nitro.nitromlkit.objects.NitroMLKitObjectsOnLoad
6
+
7
+ /**
8
+ * Loads the native library and registers the ObjectDetector HybridObject at startup via
9
+ * Expo autolinking. Exposes no JS API of its own.
10
+ */
11
+ class NitroMLKitObjectsPackage : Module() {
12
+ init {
13
+ NitroMLKitObjectsOnLoad.initializeNative()
14
+ }
15
+
16
+ override fun definition() = ModuleDefinition {
17
+ Name("NitroMLKitObjects")
18
+ }
19
+ }
@@ -0,0 +1,9 @@
1
+ {
2
+ "platforms": ["ios", "android"],
3
+ "ios": {
4
+ "modules": []
5
+ },
6
+ "android": {
7
+ "modules": ["com.nitromlkit.objects.NitroMLKitObjectsPackage"]
8
+ }
9
+ }
@@ -0,0 +1,125 @@
1
+ import Foundation
2
+ import UIKit
3
+ import NitroModules
4
+ import MLKitObjectDetection
5
+ import MLKitObjectDetectionCommon
6
+ import MLKitVision
7
+
8
+ /**
9
+ * Native iOS implementation of ObjectDetector (MLKit object detection).
10
+ * Conforms to the Nitrogen-generated HybridObjectDetectorSpec protocol.
11
+ * SINGLE_IMAGE mode with multiple objects + coarse classification.
12
+ */
13
+ class HybridObjectDetector: HybridObjectDetectorSpec {
14
+
15
+ // MARK: - HybridObject boilerplate
16
+ var memorySize: Int { MemoryLayout<HybridObjectDetector>.size }
17
+
18
+ // MARK: - Lazy MLKit detector
19
+
20
+ private lazy var detector: ObjectDetector = {
21
+ let opts = ObjectDetectorOptions()
22
+ opts.detectorMode = .singleImage
23
+ opts.shouldEnableClassification = true
24
+ opts.shouldEnableMultipleObjects = true
25
+ return ObjectDetector.objectDetector(options: opts)
26
+ }()
27
+
28
+ // MARK: - Protocol methods
29
+
30
+ func detect(imageUri: String) throws -> Promise<[DetectedObject]> {
31
+ return Promise.async {
32
+ return try await self.detectImage(imageUri)
33
+ }
34
+ }
35
+
36
+ func detectBatch(imageUris: [String], concurrency: Double) throws -> Promise<[BatchObjectResult]> {
37
+ return Promise.async {
38
+ let maxConcurrent = max(1, Int(concurrency))
39
+ var results = [BatchObjectResult]()
40
+ results.reserveCapacity(imageUris.count)
41
+
42
+ for chunkStart in stride(from: 0, to: imageUris.count, by: maxConcurrent) {
43
+ let chunkEnd = min(chunkStart + maxConcurrent, imageUris.count)
44
+ let chunk = Array(imageUris[chunkStart..<chunkEnd])
45
+
46
+ let chunkResults = await withTaskGroup(of: (Int, BatchObjectResult).self) { group in
47
+ for (i, uri) in chunk.enumerated() {
48
+ let globalIdx = chunkStart + i
49
+ group.addTask {
50
+ do {
51
+ let objects = try await self.detectImage(uri)
52
+ return (globalIdx, BatchObjectResult(index: Double(globalIdx), objects: objects, success: true, error: nil))
53
+ } catch {
54
+ return (globalIdx, BatchObjectResult(index: Double(globalIdx), objects: [], success: false, error: error.localizedDescription))
55
+ }
56
+ }
57
+ }
58
+
59
+ var out = [(Int, BatchObjectResult)]()
60
+ for await result in group { out.append(result) }
61
+ return out.sorted(by: { $0.0 < $1.0 }).map(\.1)
62
+ }
63
+ results.append(contentsOf: chunkResults)
64
+ }
65
+ return results
66
+ }
67
+ }
68
+
69
+ func isAvailable() throws -> Bool {
70
+ return true
71
+ }
72
+
73
+ // MARK: - Private helpers
74
+
75
+ private func detectImage(_ uri: String) async throws -> [DetectedObject] {
76
+ guard let image = self.loadImage(from: uri) else {
77
+ throw RuntimeError.error(withMessage: "Failed to load image: \(uri)")
78
+ }
79
+ let visionImage = VisionImage(image: image)
80
+ visionImage.orientation = image.imageOrientation
81
+
82
+ let mlObjects = try await detector.process(visionImage)
83
+ return mlObjects.map { self.mapObject($0) }
84
+ }
85
+
86
+ private func mapObject(_ obj: Object) -> DetectedObject {
87
+ let frame = obj.frame
88
+ // `obj.labels` are MLKit ObjectLabel values; the unqualified `ObjectLabel`
89
+ // initializer below resolves to the Nitrogen-generated struct (same module).
90
+ var labels = [ObjectLabel]()
91
+ for label in obj.labels {
92
+ labels.append(ObjectLabel(
93
+ text: label.text,
94
+ confidence: Double(label.confidence),
95
+ index: Double(label.index)
96
+ ))
97
+ }
98
+
99
+ let trackingId = obj.trackingID?.doubleValue ?? -1
100
+
101
+ return DetectedObject(
102
+ bounds: ObjectRect(
103
+ x: Double(frame.origin.x),
104
+ y: Double(frame.origin.y),
105
+ width: Double(frame.width),
106
+ height: Double(frame.height)
107
+ ),
108
+ trackingId: trackingId,
109
+ labels: labels
110
+ )
111
+ }
112
+
113
+ private func loadImage(from uri: String) -> UIImage? {
114
+ let path: String
115
+ if uri.hasPrefix("file://") {
116
+ path = String(uri.dropFirst(7))
117
+ } else if uri.hasPrefix("/") {
118
+ path = uri
119
+ } else {
120
+ guard let url = URL(string: uri), let data = try? Data(contentsOf: url) else { return nil }
121
+ return UIImage(data: data)
122
+ }
123
+ return UIImage(contentsOfFile: path)
124
+ }
125
+ }
package/nitro.json ADDED
@@ -0,0 +1,16 @@
1
+ {
2
+ "cxxNamespace": ["mlkit", "objects"],
3
+ "ios": {
4
+ "iosModuleName": "NitroMLKitObjects"
5
+ },
6
+ "android": {
7
+ "androidNamespace": ["nitromlkit", "objects"],
8
+ "androidCxxLibName": "NitroMLKitObjects"
9
+ },
10
+ "autolinking": {
11
+ "ObjectDetector": {
12
+ "ios": { "language": "swift", "implementationClassName": "HybridObjectDetector" },
13
+ "android": { "language": "kotlin", "implementationClassName": "HybridObjectDetector" }
14
+ }
15
+ }
16
+ }
@@ -0,0 +1 @@
1
+ ** linguist-generated=true
@@ -0,0 +1,81 @@
1
+ #
2
+ # NitroMLKitObjects+autolinking.cmake
3
+ # This file was generated by nitrogen. DO NOT MODIFY THIS FILE.
4
+ # https://github.com/mrousavy/nitro
5
+ # Copyright © Marc Rousavy @ Margelo
6
+ #
7
+
8
+ # This is a CMake file that adds all files generated by Nitrogen
9
+ # to the current CMake project.
10
+ #
11
+ # To use it, add this to your CMakeLists.txt:
12
+ # ```cmake
13
+ # include(${CMAKE_SOURCE_DIR}/../nitrogen/generated/android/NitroMLKitObjects+autolinking.cmake)
14
+ # ```
15
+
16
+ # Define a flag to check if we are building properly
17
+ add_definitions(-DBUILDING_NITROMLKITOBJECTS_WITH_GENERATED_CMAKE_PROJECT)
18
+
19
+ # Enable Raw Props parsing in react-native (for Nitro Views)
20
+ add_definitions(-DRN_SERIALIZABLE_STATE)
21
+
22
+ # Add all headers that were generated by Nitrogen
23
+ include_directories(
24
+ "../nitrogen/generated/shared/c++"
25
+ "../nitrogen/generated/android/c++"
26
+ "../nitrogen/generated/android/"
27
+ )
28
+
29
+ # Add all .cpp sources that were generated by Nitrogen
30
+ target_sources(
31
+ # CMake project name (Android C++ library name)
32
+ NitroMLKitObjects PRIVATE
33
+ # Autolinking Setup
34
+ ../nitrogen/generated/android/NitroMLKitObjectsOnLoad.cpp
35
+ # Shared Nitrogen C++ sources
36
+ ../nitrogen/generated/shared/c++/HybridObjectDetectorSpec.cpp
37
+ # Android-specific Nitrogen C++ sources
38
+ ../nitrogen/generated/android/c++/JHybridObjectDetectorSpec.cpp
39
+ )
40
+
41
+ # From node_modules/react-native/ReactAndroid/cmake-utils/folly-flags.cmake
42
+ # Used in node_modules/react-native/ReactAndroid/cmake-utils/ReactNative-application.cmake
43
+ target_compile_definitions(
44
+ NitroMLKitObjects PRIVATE
45
+ -DFOLLY_NO_CONFIG=1
46
+ -DFOLLY_HAVE_CLOCK_GETTIME=1
47
+ -DFOLLY_USE_LIBCPP=1
48
+ -DFOLLY_CFG_NO_COROUTINES=1
49
+ -DFOLLY_MOBILE=1
50
+ -DFOLLY_HAVE_RECVMMSG=1
51
+ -DFOLLY_HAVE_PTHREAD=1
52
+ # Once we target android-23 above, we can comment
53
+ # the following line. NDK uses GNU style stderror_r() after API 23.
54
+ -DFOLLY_HAVE_XSI_STRERROR_R=1
55
+ )
56
+
57
+ # Add all libraries required by the generated specs
58
+ find_package(fbjni REQUIRED) # <-- Used for communication between Java <-> C++
59
+ find_package(ReactAndroid REQUIRED) # <-- Used to set up React Native bindings (e.g. CallInvoker/TurboModule)
60
+ find_package(react-native-nitro-modules REQUIRED) # <-- Used to create all HybridObjects and use the Nitro core library
61
+
62
+ # Link all libraries together
63
+ target_link_libraries(
64
+ NitroMLKitObjects
65
+ fbjni::fbjni # <-- Facebook C++ JNI helpers
66
+ ReactAndroid::jsi # <-- RN: JSI
67
+ react-native-nitro-modules::NitroModules # <-- NitroModules Core :)
68
+ )
69
+
70
+ # Link react-native (different prefab between RN 0.75 and RN 0.76)
71
+ if(ReactAndroid_VERSION_MINOR GREATER_EQUAL 76)
72
+ target_link_libraries(
73
+ NitroMLKitObjects
74
+ ReactAndroid::reactnative # <-- RN: Native Modules umbrella prefab
75
+ )
76
+ else()
77
+ target_link_libraries(
78
+ NitroMLKitObjects
79
+ ReactAndroid::react_nativemodule_core # <-- RN: TurboModules Core
80
+ )
81
+ endif()
@@ -0,0 +1,27 @@
1
+ ///
2
+ /// NitroMLKitObjects+autolinking.gradle
3
+ /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE.
4
+ /// https://github.com/mrousavy/nitro
5
+ /// Copyright © Marc Rousavy @ Margelo
6
+ ///
7
+
8
+ /// This is a Gradle file that adds all files generated by Nitrogen
9
+ /// to the current Gradle project.
10
+ ///
11
+ /// To use it, add this to your build.gradle:
12
+ /// ```gradle
13
+ /// apply from: '../nitrogen/generated/android/NitroMLKitObjects+autolinking.gradle'
14
+ /// ```
15
+
16
+ logger.warn("[NitroModules] 🔥 NitroMLKitObjects is boosted by nitro!")
17
+
18
+ android {
19
+ sourceSets {
20
+ main {
21
+ java.srcDirs += [
22
+ // Nitrogen files
23
+ "${project.projectDir}/../nitrogen/generated/android/kotlin"
24
+ ]
25
+ }
26
+ }
27
+ }
@@ -0,0 +1,54 @@
1
+ ///
2
+ /// NitroMLKitObjectsOnLoad.cpp
3
+ /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE.
4
+ /// https://github.com/mrousavy/nitro
5
+ /// Copyright © Marc Rousavy @ Margelo
6
+ ///
7
+
8
+ #ifndef BUILDING_NITROMLKITOBJECTS_WITH_GENERATED_CMAKE_PROJECT
9
+ #error NitroMLKitObjectsOnLoad.cpp is not being built with the autogenerated CMakeLists.txt project. Is a different CMakeLists.txt building this?
10
+ #endif
11
+
12
+ #include "NitroMLKitObjectsOnLoad.hpp"
13
+
14
+ #include <jni.h>
15
+ #include <fbjni/fbjni.h>
16
+ #include <NitroModules/HybridObjectRegistry.hpp>
17
+
18
+ #include "JHybridObjectDetectorSpec.hpp"
19
+ #include <NitroModules/DefaultConstructableObject.hpp>
20
+
21
+ namespace margelo::nitro::mlkit::objects {
22
+
23
+ int initialize(JavaVM* vm) {
24
+ return facebook::jni::initialize(vm, []() {
25
+ ::margelo::nitro::mlkit::objects::registerAllNatives();
26
+ });
27
+ }
28
+
29
+ struct JHybridObjectDetectorSpecImpl: public jni::JavaClass<JHybridObjectDetectorSpecImpl, JHybridObjectDetectorSpec::JavaPart> {
30
+ static constexpr auto kJavaDescriptor = "Lcom/margelo/nitro/nitromlkit/objects/HybridObjectDetector;";
31
+ static std::shared_ptr<JHybridObjectDetectorSpec> create() {
32
+ static const auto constructorFn = javaClassStatic()->getConstructor<JHybridObjectDetectorSpecImpl::javaobject()>();
33
+ jni::local_ref<JHybridObjectDetectorSpec::JavaPart> javaPart = javaClassStatic()->newObject(constructorFn);
34
+ return javaPart->getJHybridObjectDetectorSpec();
35
+ }
36
+ };
37
+
38
+ void registerAllNatives() {
39
+ using namespace margelo::nitro;
40
+ using namespace margelo::nitro::mlkit::objects;
41
+
42
+ // Register native JNI methods
43
+ margelo::nitro::mlkit::objects::JHybridObjectDetectorSpec::CxxPart::registerNatives();
44
+
45
+ // Register Nitro Hybrid Objects
46
+ HybridObjectRegistry::registerHybridObjectConstructor(
47
+ "ObjectDetector",
48
+ []() -> std::shared_ptr<HybridObject> {
49
+ return JHybridObjectDetectorSpecImpl::create();
50
+ }
51
+ );
52
+ }
53
+
54
+ } // namespace margelo::nitro::mlkit::objects