react-native-vision-camera-spoof-detector 1.0.4 → 1.0.6

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 (65) hide show
  1. package/android/.cxx/Debug/2a1it684/arm64-v8a/.cmake/api/v1/reply/{codemodel-v2-390962e2784a6a84fa3e.json → codemodel-v2-6c7de80461af72f456a3.json} +2 -2
  2. package/android/.cxx/Debug/2a1it684/arm64-v8a/.cmake/api/v1/reply/{index-2025-11-24T13-21-59-0659.json → index-2025-11-24T17-41-56-0411.json} +2 -2
  3. package/android/.cxx/Debug/2a1it684/arm64-v8a/.cmake/api/v1/reply/{target-yuv-Debug-1e27b8a2bdcddd47b87d.json → target-yuv-Debug-32bc4eddd343848e1c25.json} +4 -4
  4. package/android/.cxx/Debug/2a1it684/arm64-v8a/.cmake/api/v1/reply/{target-yuv_shared-Debug-ac9194487d1fc1268a87.json → target-yuv_shared-Debug-75ea769bf76a12914d29.json} +4 -4
  5. package/android/.cxx/Debug/2a1it684/arm64-v8a/.ninja_deps +0 -0
  6. package/android/.cxx/Debug/2a1it684/arm64-v8a/.ninja_log +125 -125
  7. package/android/.cxx/Debug/2a1it684/arm64-v8a/configure_fingerprint.bin +14 -14
  8. package/android/.cxx/Debug/2a1it684/armeabi-v7a/.ninja_deps +0 -0
  9. package/android/.cxx/Debug/2a1it684/armeabi-v7a/.ninja_log +118 -119
  10. package/android/.cxx/Debug/2a1it684/armeabi-v7a/configure_fingerprint.bin +14 -14
  11. package/android/.cxx/Debug/2a1it684/x86/.ninja_deps +0 -0
  12. package/android/.cxx/Debug/2a1it684/x86/.ninja_log +110 -111
  13. package/android/.cxx/Debug/2a1it684/x86/configure_fingerprint.bin +14 -14
  14. package/android/.cxx/Debug/2a1it684/x86_64/.ninja_deps +0 -0
  15. package/android/.cxx/Debug/2a1it684/x86_64/.ninja_log +109 -109
  16. package/android/.cxx/Debug/2a1it684/x86_64/configure_fingerprint.bin +14 -14
  17. package/android/build/.transforms/4ebf3dd0dca4f83fe1776360e21ded81/transformed/classes/classes_dex/classes.dex +0 -0
  18. package/android/build/.transforms/c0a07cd9442d741ad3cef3760159211f/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/faceantispoof/AntiSpoofingResult.dex +0 -0
  19. package/android/build/.transforms/c0a07cd9442d741ad3cef3760159211f/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/faceantispoof/FaceAntiSpoofFrameProcessor.dex +0 -0
  20. package/android/build/.transforms/c0a07cd9442d741ad3cef3760159211f/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/faceantispoof/FaceAntiSpoofingAdvanced$SpoofDetectionResult.dex +0 -0
  21. package/android/build/.transforms/c0a07cd9442d741ad3cef3760159211f/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/faceantispoof/FaceAntiSpoofingAdvanced.dex +0 -0
  22. package/android/build/.transforms/c0a07cd9442d741ad3cef3760159211f/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/faceantispoof/ImageFormatEncoder.dex +0 -0
  23. package/android/build/.transforms/c0a07cd9442d741ad3cef3760159211f/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/faceantispoof/YuvToFloatArrayConverter.dex +0 -0
  24. package/android/build/intermediates/compile_library_classes_jar/debug/bundleLibCompileToJarDebug/classes.jar +0 -0
  25. package/android/build/intermediates/cxx/Debug/2a1it684/logs/arm64-v8a/build_stdout_targets.txt +49 -49
  26. package/android/build/intermediates/cxx/Debug/2a1it684/logs/arm64-v8a/generate_cxx_metadata_2688_timing.txt +9 -0
  27. package/android/build/intermediates/cxx/Debug/2a1it684/logs/armeabi-v7a/build_stdout_targets.txt +44 -44
  28. package/android/build/intermediates/cxx/Debug/2a1it684/logs/armeabi-v7a/{generate_cxx_metadata_2653_timing.txt → generate_cxx_metadata_2687_timing.txt} +1 -1
  29. package/android/build/intermediates/cxx/Debug/2a1it684/logs/x86/build_stdout_targets.txt +40 -40
  30. package/android/build/intermediates/cxx/Debug/2a1it684/logs/x86/{generate_cxx_metadata_2653_timing.txt → generate_cxx_metadata_2687_timing.txt} +1 -1
  31. package/android/build/intermediates/cxx/Debug/2a1it684/logs/x86_64/build_stdout_targets.txt +43 -43
  32. package/android/build/intermediates/cxx/Debug/2a1it684/logs/x86_64/generate_cxx_metadata_2687_timing.txt +9 -0
  33. package/android/build/intermediates/incremental/debug/packageDebugResources/compile-file-map.properties +1 -1
  34. package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/faceantispoof/AntiSpoofingResult.class +0 -0
  35. package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/faceantispoof/FaceAntiSpoofFrameProcessor.class +0 -0
  36. package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/faceantispoof/FaceAntiSpoofingAdvanced$SpoofDetectionResult.class +0 -0
  37. package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/faceantispoof/FaceAntiSpoofingAdvanced.class +0 -0
  38. package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/faceantispoof/ImageFormatEncoder.class +0 -0
  39. package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/faceantispoof/YuvToFloatArrayConverter.class +0 -0
  40. package/android/build/intermediates/runtime_library_classes_jar/debug/bundleLibRuntimeToJarDebug/classes.jar +0 -0
  41. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab +0 -0
  42. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab.values.at +0 -0
  43. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab +0 -0
  44. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab.keystream +0 -0
  45. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab.keystream.len +0 -0
  46. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab.len +0 -0
  47. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab.values.at +0 -0
  48. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab_i +0 -0
  49. package/android/build/kotlin/compileDebugKotlin/cacheable/last-build.bin +0 -0
  50. package/android/build/kotlin/compileDebugKotlin/classpath-snapshot/shrunk-classpath-snapshot.bin +0 -0
  51. package/android/build/kotlin/compileDebugKotlin/local-state/build-history.bin +0 -0
  52. package/android/build/tmp/kotlin-classes/debug/com/faceantispoof/AntiSpoofingResult.class +0 -0
  53. package/android/build/tmp/kotlin-classes/debug/com/faceantispoof/FaceAntiSpoofFrameProcessor.class +0 -0
  54. package/android/build/tmp/kotlin-classes/debug/com/faceantispoof/FaceAntiSpoofingAdvanced$SpoofDetectionResult.class +0 -0
  55. package/android/build/tmp/kotlin-classes/debug/com/faceantispoof/FaceAntiSpoofingAdvanced.class +0 -0
  56. package/android/build/tmp/kotlin-classes/debug/com/faceantispoof/ImageFormatEncoder.class +0 -0
  57. package/android/build/tmp/kotlin-classes/debug/com/faceantispoof/YuvToFloatArrayConverter.class +0 -0
  58. package/android/src/main/java/com/faceantispoof/FaceAntiSpoofFrameProcessor.kt +25 -6
  59. package/android/src/main/java/com/faceantispoof/FaceAntiSpoofingAdvanced.kt +46 -16
  60. package/android/src/main/java/com/faceantispoof/ImageFormatEncoder.kt +99 -21
  61. package/android/src/main/java/com/faceantispoof/YuvToFloatArrayConverter.kt +103 -12
  62. package/package.json +3 -3
  63. package/android/build/intermediates/cxx/Debug/2a1it684/logs/arm64-v8a/generate_cxx_metadata_2655_timing.txt +0 -9
  64. package/android/build/intermediates/cxx/Debug/2a1it684/logs/x86_64/generate_cxx_metadata_2653_timing.txt +0 -9
  65. /package/android/.cxx/Debug/2a1it684/x86_64/.cmake/api/v1/reply/{index-2025-11-24T13-22-20-0304.json → index-2025-11-24T17-42-56-0679.json} +0 -0
@@ -88,11 +88,27 @@ object ImageFormatEncoder {
88
88
  return try {
89
89
  validateImageDimensions(width, height)
90
90
 
91
+ if (rgbFloats.isEmpty()) {
92
+ Log.e(TAG, "RGB float array is empty")
93
+ return null
94
+ }
95
+
96
+ val expectedSize = width * height * 3
97
+ if (rgbFloats.size < expectedSize) {
98
+ Log.e(TAG, "RGB float array too small: expected $expectedSize, got ${rgbFloats.size}")
99
+ return null
100
+ }
101
+
91
102
  // Convert float array (normalized 0-1) to byte array (0-255)
92
- val rgbBytes = ByteArray(width * height * 3)
103
+ val rgbBytes = ByteArray(expectedSize)
93
104
  var idx = 0
94
- for (i in rgbFloats.indices) {
95
- rgbBytes[idx++] = (rgbFloats[i] * 255f).toInt().coerceIn(0, 255).toByte()
105
+ for (i in 0 until expectedSize) {
106
+ if (idx >= rgbFloats.size) {
107
+ Log.e(TAG, "Float array index out of bounds at $idx")
108
+ return null
109
+ }
110
+ val floatVal = rgbFloats[idx++].coerceIn(0f, 1f)
111
+ rgbBytes[i] = (floatVal * 255f).toInt().coerceIn(0, 255).toByte()
96
112
  }
97
113
 
98
114
  rgbToBase64(rgbBytes, width, height, format, quality)
@@ -124,12 +140,25 @@ object ImageFormatEncoder {
124
140
  validateRgbData(rgbData, width, height)
125
141
 
126
142
  val bitmap = createBitmapFromRgb(rgbData, width, height)
127
- val imageBytes = when (format) {
128
- ImageFormat.JPEG -> compressBitmapToBytes(bitmap, format, quality)
129
- ImageFormat.PNG -> compressBitmapToBytes(bitmap, format, 100)
130
- ImageFormat.BMP -> compressBitmapToBytes(bitmap, format, 100)
143
+ ?: return null
144
+
145
+ val imageBytes = try {
146
+ when (format) {
147
+ ImageFormat.JPEG -> compressBitmapToBytes(bitmap, format, quality)
148
+ ImageFormat.PNG -> compressBitmapToBytes(bitmap, format, 100)
149
+ ImageFormat.BMP -> compressBitmapToBytes(bitmap, format, 100)
150
+ }
151
+ } catch (e: Exception) {
152
+ Log.e(TAG, "Error compressing bitmap: ${e.message}", e)
153
+ null
154
+ } finally {
155
+ try {
156
+ bitmap.recycle()
157
+ } catch (e: Exception) {
158
+ Log.w(TAG, "Error recycling bitmap: ${e.message}")
159
+ }
131
160
  }
132
- bitmap.recycle()
161
+
133
162
  imageBytes
134
163
  } catch (e: Exception) {
135
164
  Log.e(TAG, "Failed to convert RGB to ${format.name} bytes: ${e.message}", e)
@@ -200,17 +229,47 @@ object ImageFormatEncoder {
200
229
  * Create Bitmap from RGB byte array.
201
230
  * RGB format: RGBRGBRGB... (3 bytes per pixel, no alpha)
202
231
  */
203
- private fun createBitmapFromRgb(rgbData: ByteArray, width: Int, height: Int): Bitmap {
204
- // Convert RGB to ARGB for Bitmap (Android uses ARGB_8888)
205
- val pixels = IntArray(width * height)
206
- var rgbIdx = 0
207
- for (i in pixels.indices) {
208
- val r = rgbData[rgbIdx++].toInt() and 0xFF
209
- val g = rgbData[rgbIdx++].toInt() and 0xFF
210
- val b = rgbData[rgbIdx++].toInt() and 0xFF
211
- pixels[i] = 0xFF000000.toInt() or (r shl 16) or (g shl 8) or b // ARGB
232
+ private fun createBitmapFromRgb(rgbData: ByteArray, width: Int, height: Int): Bitmap? {
233
+ return try {
234
+ if (rgbData.isEmpty()) {
235
+ Log.e(TAG, "RGB data is empty")
236
+ return null
237
+ }
238
+ if (width <= 0 || height <= 0) {
239
+ Log.e(TAG, "Invalid dimensions: width=$width, height=$height")
240
+ return null
241
+ }
242
+
243
+ val expectedSize = width * height * 3
244
+ if (rgbData.size < expectedSize) {
245
+ Log.e(TAG, "RGB data too small: expected at least $expectedSize, got ${rgbData.size}")
246
+ return null
247
+ }
248
+
249
+ // Convert RGB to ARGB for Bitmap (Android uses ARGB_8888)
250
+ val pixels = IntArray(width * height)
251
+ var rgbIdx = 0
252
+ for (i in pixels.indices) {
253
+ if (rgbIdx + 2 >= rgbData.size) {
254
+ Log.e(TAG, "RGB buffer index out of bounds at pixel $i")
255
+ return null
256
+ }
257
+ val r = rgbData[rgbIdx++].toInt() and 0xFF
258
+ val g = rgbData[rgbIdx++].toInt() and 0xFF
259
+ val b = rgbData[rgbIdx++].toInt() and 0xFF
260
+ pixels[i] = 0xFF000000.toInt() or (r shl 16) or (g shl 8) or b // ARGB
261
+ }
262
+
263
+ val bitmap = Bitmap.createBitmap(pixels, width, height, Bitmap.Config.ARGB_8888)
264
+ if (bitmap == null) {
265
+ Log.e(TAG, "Failed to create bitmap")
266
+ return null
267
+ }
268
+ bitmap
269
+ } catch (e: Exception) {
270
+ Log.e(TAG, "Error creating bitmap from RGB: ${e.message}", e)
271
+ null
212
272
  }
213
- return Bitmap.createBitmap(pixels, width, height, Bitmap.Config.ARGB_8888)
214
273
  }
215
274
 
216
275
  /**
@@ -221,9 +280,28 @@ object ImageFormatEncoder {
221
280
  format: ImageFormat,
222
281
  quality: Int
223
282
  ): ByteArray {
224
- val outputStream = ByteArrayOutputStream()
225
- bitmap.compress(format.compressFormat, quality, outputStream)
226
- return outputStream.toByteArray()
283
+ return try {
284
+ if (bitmap.width <= 0 || bitmap.height <= 0) {
285
+ throw IllegalArgumentException("Invalid bitmap dimensions: ${bitmap.width}×${bitmap.height}")
286
+ }
287
+
288
+ val outputStream = ByteArrayOutputStream()
289
+ val compressed = bitmap.compress(format.compressFormat, quality, outputStream)
290
+
291
+ if (!compressed) {
292
+ Log.w(TAG, "Bitmap compression returned false for ${format.name}")
293
+ }
294
+
295
+ val bytes = outputStream.toByteArray()
296
+ if (bytes.isEmpty()) {
297
+ Log.w(TAG, "Compressed image bytes are empty")
298
+ }
299
+
300
+ bytes
301
+ } catch (e: Exception) {
302
+ Log.e(TAG, "Error compressing bitmap: ${e.message}", e)
303
+ ByteArray(0)
304
+ }
227
305
  }
228
306
 
229
307
  /**
@@ -27,28 +27,55 @@ class YuvToFloatArrayConverter {
27
27
  targetHeight: Int = height,
28
28
  outputRgbFloat: FloatArray? = null
29
29
  ): FloatArray {
30
+ if (nv21.isEmpty()) {
31
+ throw IllegalArgumentException("NV21 array is empty")
32
+ }
33
+ if (width <= 0 || height <= 0) {
34
+ throw IllegalArgumentException("Invalid frame dimensions: width=$width, height=$height")
35
+ }
36
+ if (targetWidth <= 0 || targetHeight <= 0) {
37
+ throw IllegalArgumentException("Invalid target dimensions: targetWidth=$targetWidth, targetHeight=$targetHeight")
38
+ }
39
+
30
40
  val outputSize = targetWidth * targetHeight * 3
31
41
  val output = outputRgbFloat?.takeIf { it.size >= outputSize } ?: FloatArray(outputSize)
32
42
 
33
43
  val ySize = width * height
34
44
  val uvPixelStride = 2
45
+
46
+ // Validate NV21 buffer size
47
+ val minExpectedSize = width * height + (width * height) / 2
48
+ if (nv21.size < minExpectedSize) {
49
+ throw IllegalArgumentException("NV21 buffer too small: expected at least $minExpectedSize, got ${nv21.size}")
50
+ }
35
51
 
36
52
  var outIdx = 0
37
53
 
38
54
  for (targetY in 0 until targetHeight) {
39
- // Map target Y to original frame Y (nearest-neighbor)
40
55
  val srcY = (targetY * height) / targetHeight
56
+ if (srcY >= height) {
57
+ throw IndexOutOfBoundsException("Source Y index out of bounds: srcY=$srcY, height=$height")
58
+ }
41
59
  val srcRowOffset = srcY * width
42
60
 
43
61
  for (targetX in 0 until targetWidth) {
44
- // Map target X to original frame X (nearest-neighbor)
45
62
  val srcX = (targetX * width) / targetWidth
63
+ if (srcX >= width) {
64
+ throw IndexOutOfBoundsException("Source X index out of bounds: srcX=$srcX, width=$width")
65
+ }
46
66
 
47
67
  // Get Y component
48
- val yVal = nv21[srcRowOffset + srcX].toInt() and 0xFF
68
+ val yIdx = srcRowOffset + srcX
69
+ if (yIdx >= nv21.size) {
70
+ throw IndexOutOfBoundsException("Y index out of bounds: yIdx=$yIdx, nv21.size=${nv21.size}")
71
+ }
72
+ val yVal = nv21[yIdx].toInt() and 0xFF
49
73
 
50
74
  // Get U and V components (NV21 layout: UV interleaved in second half)
51
75
  val uvIndex = ySize + (srcY / 2) * width + (srcX / 2) * uvPixelStride
76
+ if (uvIndex + 1 >= nv21.size) {
77
+ throw IndexOutOfBoundsException("UV index out of bounds: uvIndex=$uvIndex, nv21.size=${nv21.size}")
78
+ }
52
79
  val vVal = nv21[uvIndex].toInt() and 0xFF
53
80
  val uVal = nv21[uvIndex + 1].toInt() and 0xFF
54
81
 
@@ -62,9 +89,13 @@ class YuvToFloatArrayConverter {
62
89
  val b = (yf + 1.772f * uf).coerceIn(0f, 255f)
63
90
 
64
91
  // Normalize to [0, 1]
65
- output[outIdx++] = r / 255f
66
- output[outIdx++] = g / 255f
67
- output[outIdx++] = b / 255f
92
+ if (outIdx + 2 < output.size) {
93
+ output[outIdx++] = r / 255f
94
+ output[outIdx++] = g / 255f
95
+ output[outIdx++] = b / 255f
96
+ } else {
97
+ throw IndexOutOfBoundsException("Output array index out of bounds: outIdx=$outIdx, output.size=${output.size}")
98
+ }
68
99
  }
69
100
  }
70
101
 
@@ -176,20 +207,48 @@ class YuvToFloatArrayConverter {
176
207
  targetHeight: Int = height,
177
208
  outputGrayscale: IntArray? = null
178
209
  ): IntArray {
210
+ if (nv21.isEmpty()) {
211
+ throw IllegalArgumentException("NV21 array is empty")
212
+ }
213
+ if (width <= 0 || height <= 0) {
214
+ throw IllegalArgumentException("Invalid frame dimensions: width=$width, height=$height")
215
+ }
216
+ if (targetWidth <= 0 || targetHeight <= 0) {
217
+ throw IllegalArgumentException("Invalid target dimensions: targetWidth=$targetWidth, targetHeight=$targetHeight")
218
+ }
219
+
179
220
  val outputSize = targetWidth * targetHeight
180
221
  val output = outputGrayscale?.takeIf { it.size >= outputSize } ?: IntArray(outputSize)
181
222
 
182
223
  val ySize = width * height
224
+ val minExpectedSize = width * height + (width * height) / 2
225
+ if (nv21.size < minExpectedSize) {
226
+ throw IllegalArgumentException("NV21 buffer too small: expected at least $minExpectedSize, got ${nv21.size}")
227
+ }
183
228
 
184
229
  var outIdx = 0
185
230
  for (targetY in 0 until targetHeight) {
186
231
  val srcY = (targetY * height) / targetHeight
232
+ if (srcY >= height) {
233
+ throw IndexOutOfBoundsException("Source Y out of bounds: srcY=$srcY, height=$height")
234
+ }
187
235
  val srcRowOffset = srcY * width
188
236
 
189
237
  for (targetX in 0 until targetWidth) {
190
238
  val srcX = (targetX * width) / targetWidth
191
- val yVal = nv21[srcRowOffset + srcX].toInt() and 0xFF
192
- output[outIdx++] = yVal
239
+ if (srcX >= width) {
240
+ throw IndexOutOfBoundsException("Source X out of bounds: srcX=$srcX, width=$width")
241
+ }
242
+ val yIdx = srcRowOffset + srcX
243
+ if (yIdx >= nv21.size) {
244
+ throw IndexOutOfBoundsException("Y index out of bounds: yIdx=$yIdx, nv21.size=${nv21.size}")
245
+ }
246
+ val yVal = nv21[yIdx].toInt() and 0xFF
247
+ if (outIdx < output.size) {
248
+ output[outIdx++] = yVal
249
+ } else {
250
+ throw IndexOutOfBoundsException("Output index out of bounds: outIdx=$outIdx, output.size=${output.size}")
251
+ }
193
252
  }
194
253
  }
195
254
 
@@ -217,26 +276,54 @@ class YuvToFloatArrayConverter {
217
276
  targetHeight: Int = height,
218
277
  outputRgbBytes: ByteArray? = null
219
278
  ): ByteArray {
279
+ if (nv21.isEmpty()) {
280
+ throw IllegalArgumentException("NV21 array is empty")
281
+ }
282
+ if (width <= 0 || height <= 0) {
283
+ throw IllegalArgumentException("Invalid frame dimensions: width=$width, height=$height")
284
+ }
285
+ if (targetWidth <= 0 || targetHeight <= 0) {
286
+ throw IllegalArgumentException("Invalid target dimensions: targetWidth=$targetWidth, targetHeight=$targetHeight")
287
+ }
288
+
220
289
  val outputSize = targetWidth * targetHeight * 3
221
290
  val output = outputRgbBytes?.takeIf { it.size >= outputSize } ?: ByteArray(outputSize)
222
291
 
223
292
  val ySize = width * height
224
293
  val uvPixelStride = 2
294
+
295
+ val minExpectedSize = width * height + (width * height) / 2
296
+ if (nv21.size < minExpectedSize) {
297
+ throw IllegalArgumentException("NV21 buffer too small: expected at least $minExpectedSize, got ${nv21.size}")
298
+ }
225
299
 
226
300
  var outIdx = 0
227
301
 
228
302
  for (targetY in 0 until targetHeight) {
229
303
  val srcY = (targetY * height) / targetHeight
304
+ if (srcY >= height) {
305
+ throw IndexOutOfBoundsException("Source Y out of bounds: srcY=$srcY, height=$height")
306
+ }
230
307
  val srcRowOffset = srcY * width
231
308
 
232
309
  for (targetX in 0 until targetWidth) {
233
310
  val srcX = (targetX * width) / targetWidth
311
+ if (srcX >= width) {
312
+ throw IndexOutOfBoundsException("Source X out of bounds: srcX=$srcX, width=$width")
313
+ }
234
314
 
235
315
  // Get Y component
236
- val yVal = nv21[srcRowOffset + srcX].toInt() and 0xFF
316
+ val yIdx = srcRowOffset + srcX
317
+ if (yIdx >= nv21.size) {
318
+ throw IndexOutOfBoundsException("Y index out of bounds: yIdx=$yIdx, nv21.size=${nv21.size}")
319
+ }
320
+ val yVal = nv21[yIdx].toInt() and 0xFF
237
321
 
238
322
  // Get U and V components (NV21 layout: UV interleaved in second half)
239
323
  val uvIndex = ySize + (srcY / 2) * width + (srcX / 2) * uvPixelStride
324
+ if (uvIndex + 1 >= nv21.size) {
325
+ throw IndexOutOfBoundsException("UV index out of bounds: uvIndex=$uvIndex, nv21.size=${nv21.size}")
326
+ }
240
327
  val vVal = nv21[uvIndex].toInt() and 0xFF
241
328
  val uVal = nv21[uvIndex + 1].toInt() and 0xFF
242
329
 
@@ -249,9 +336,13 @@ class YuvToFloatArrayConverter {
249
336
  val g = (yf - 0.34414f * uf - 0.71414f * vf).coerceIn(0f, 255f).toInt().toByte()
250
337
  val b = (yf + 1.772f * uf).coerceIn(0f, 255f).toInt().toByte()
251
338
 
252
- output[outIdx++] = r
253
- output[outIdx++] = g
254
- output[outIdx++] = b
339
+ if (outIdx + 2 < output.size) {
340
+ output[outIdx++] = r
341
+ output[outIdx++] = g
342
+ output[outIdx++] = b
343
+ } else {
344
+ throw IndexOutOfBoundsException("Output index out of bounds: outIdx=$outIdx, output.size=${output.size}")
345
+ }
255
346
  }
256
347
  }
257
348
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-vision-camera-spoof-detector",
3
- "version": "1.0.4",
3
+ "version": "1.0.6",
4
4
  "description": "High-performance face anti-spoofing and liveness detection module for React Native Vision Camera. Uses TensorFlow Lite with GPU acceleration and optimized YUV processing.",
5
5
  "homepage": "https://github.com/jescon-tech/react-native-vision-camera-spoof-detector",
6
6
  "repository": {
@@ -10,10 +10,10 @@
10
10
  "bugs": {
11
11
  "url": "https://github.com/jescon-tech/react-native-vision-camera-spoof-detector/issues"
12
12
  },
13
- "license": "JESCON TECHNOLOGIES PVT LTD",
13
+ "license": "MIT",
14
14
  "author": {
15
15
  "name": "PRAFULDAS M M",
16
- "company": "JESCON TECHNOLOGIES PVT LTD THRISSUR,KERALA,INDIA",
16
+ "company": "JESCON TECHNOLOGIES PVT LTD",
17
17
  "email": "jescontechnologies@gmail.com"
18
18
  },
19
19
  "main": "index.js",
@@ -1,9 +0,0 @@
1
- # C/C++ build system timings
2
- generate_cxx_metadata
3
- execute-generate-process
4
- exec-configure 962ms
5
- [gap of 23ms]
6
- execute-generate-process completed in 986ms
7
- [gap of 17ms]
8
- generate_cxx_metadata completed in 1012ms
9
-
@@ -1,9 +0,0 @@
1
- # C/C++ build system timings
2
- generate_cxx_metadata
3
- execute-generate-process
4
- exec-configure 563ms
5
- [gap of 39ms]
6
- execute-generate-process completed in 603ms
7
- [gap of 14ms]
8
- generate_cxx_metadata completed in 625ms
9
-