package com.pixeldata import com.facebook.react.bridge.* import kotlinx.coroutines.* /** * React Native module for extracting pixel data from images */ class PixelDataModule(private val reactContext: ReactApplicationContext) : ReactContextBaseJavaModule(reactContext) { private val scope = CoroutineScope(Dispatchers.Default + SupervisorJob()) override fun getName(): String = "PixelData" override fun onCatalystInstanceDestroy() { super.onCatalystInstanceDestroy() scope.cancel() } /** * Get pixel data from a single image */ @ReactMethod fun getPixelData(options: ReadableMap, promise: Promise) { scope.launch { try { val parsedOptions = GetPixelDataOptions.fromMap(options) val context = reactContext.applicationContext val bitmap = ImageLoader.loadImage(context, parsedOptions.source) val result = PixelProcessor.process(bitmap, parsedOptions) withContext(Dispatchers.Main) { promise.resolve(result.toWritableMap()) } } catch (e: PixelDataException) { withContext(Dispatchers.Main) { promise.reject(e.code, e.message) } } catch (e: Exception) { withContext(Dispatchers.Main) { promise.reject("UNKNOWN", e.message ?: "Unknown error occurred") } } } } /** * Get pixel data from multiple images with concurrency control */ @ReactMethod fun batchGetPixelData( optionsArray: ReadableArray, batchOptions: ReadableMap, promise: Promise ) { scope.launch { val startTime = System.nanoTime() val context = reactContext.applicationContext val batchOpts = BatchOptions.fromMap(batchOptions) val results = Arguments.createArray() val semaphore = kotlinx.coroutines.sync.Semaphore(batchOpts.concurrency) val jobs = (0 until optionsArray.size()).map { index -> async { semaphore.acquire() try { val optionsMap = optionsArray.getMap(index) ?: throw PixelDataException("INVALID_SOURCE", "Invalid options at index $index") val parsedOptions = GetPixelDataOptions.fromMap(optionsMap) val bitmap = ImageLoader.loadImage(context, parsedOptions.source) val result = PixelProcessor.process(bitmap, parsedOptions) Pair(index, result.toWritableMap()) } catch (e: PixelDataException) { val errorMap = Arguments.createMap().apply { putBoolean("error", true) putString("message", e.message) putString("code", e.code) putInt("index", index) } Pair(index, errorMap) } catch (e: Exception) { val errorMap = Arguments.createMap().apply { putBoolean("error", true) putString("message", e.message ?: "Unknown error") putString("code", "UNKNOWN") putInt("index", index) } Pair(index, errorMap) } finally { semaphore.release() } } } // Collect results in order val orderedResults = jobs.map { it.await() } .sortedBy { it.first } .map { it.second } orderedResults.forEach { results.pushMap(it) } val endTime = System.nanoTime() val totalTimeMs = (endTime - startTime) / 1_000_000.0 val response = Arguments.createMap().apply { putArray("results", results) putDouble("totalTimeMs", totalTimeMs) } withContext(Dispatchers.Main) { promise.resolve(response) } } } }