react-native-vision-camera-spoof-detector 1.0.8 → 1.0.9

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 (114) hide show
  1. package/android/.cxx/Debug/2a1it684/arm64-v8a/.cmake/api/v1/reply/{codemodel-v2-501c3f4eb817726556cc.json → codemodel-v2-83ca4b3bde3a78057c1f.json} +2 -2
  2. package/android/.cxx/Debug/2a1it684/arm64-v8a/.cmake/api/v1/reply/{index-2025-11-25T16-55-22-0685.json → index-2025-11-27T05-30-44-0002.json} +2 -2
  3. package/android/.cxx/Debug/2a1it684/arm64-v8a/.cmake/api/v1/reply/{target-yuv-Debug-63fdb78450b0b16b8484.json → target-yuv-Debug-a4349d98b162d7b162c2.json} +4 -4
  4. package/android/.cxx/Debug/2a1it684/arm64-v8a/.cmake/api/v1/reply/{target-yuv_shared-Debug-5c8b5c6f50bc8769a5bd.json → target-yuv_shared-Debug-f13b6c904c5f79494e23.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/CMakeFiles/CMakeOutput.log +22 -22
  8. package/android/.cxx/Debug/2a1it684/arm64-v8a/configure_fingerprint.bin +15 -15
  9. package/android/.cxx/Debug/2a1it684/armeabi-v7a/.cmake/api/v1/reply/{codemodel-v2-053850119b681f93cecc.json → codemodel-v2-52ac1d8b40b69596389b.json} +2 -2
  10. package/android/.cxx/Debug/2a1it684/armeabi-v7a/.cmake/api/v1/reply/{index-2025-11-25T16-21-43-0410.json → index-2025-11-27T04-19-25-0344.json} +2 -2
  11. package/android/.cxx/Debug/2a1it684/armeabi-v7a/.cmake/api/v1/reply/{target-yuv-Debug-a12ad49ff79080871bce.json → target-yuv-Debug-97f9e822dbd84a186d44.json} +2 -2
  12. package/android/.cxx/Debug/2a1it684/armeabi-v7a/.cmake/api/v1/reply/{target-yuv_shared-Debug-2b00e64621a56b8dd632.json → target-yuv_shared-Debug-3730d20e27c3481c06b2.json} +2 -2
  13. package/android/.cxx/Debug/2a1it684/armeabi-v7a/.ninja_deps +0 -0
  14. package/android/.cxx/Debug/2a1it684/armeabi-v7a/.ninja_log +119 -176
  15. package/android/.cxx/Debug/2a1it684/armeabi-v7a/CMakeFiles/CMakeOutput.log +20 -20
  16. package/android/.cxx/Debug/2a1it684/armeabi-v7a/configure_fingerprint.bin +15 -15
  17. package/android/.cxx/Debug/2a1it684/x86/.ninja_deps +0 -0
  18. package/android/.cxx/Debug/2a1it684/x86/.ninja_log +111 -164
  19. package/android/.cxx/Debug/2a1it684/x86/CMakeFiles/CMakeOutput.log +20 -20
  20. package/android/.cxx/Debug/2a1it684/x86/configure_fingerprint.bin +15 -15
  21. package/android/.cxx/Debug/2a1it684/x86_64/.ninja_deps +0 -0
  22. package/android/.cxx/Debug/2a1it684/x86_64/.ninja_log +109 -109
  23. package/android/.cxx/Debug/2a1it684/x86_64/CMakeFiles/CMakeOutput.log +20 -20
  24. package/android/.cxx/Debug/2a1it684/x86_64/configure_fingerprint.bin +15 -15
  25. package/android/build/.transforms/4ebf3dd0dca4f83fe1776360e21ded81/transformed/classes/classes_dex/classes.dex +0 -0
  26. package/android/build/.transforms/c0a07cd9442d741ad3cef3760159211f/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/faceantispoof/AntiSpoofingResult.dex +0 -0
  27. package/android/build/.transforms/c0a07cd9442d741ad3cef3760159211f/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/faceantispoof/FaceAntiSpoofingAdvanced$Companion.dex +0 -0
  28. package/android/build/.transforms/c0a07cd9442d741ad3cef3760159211f/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/faceantispoof/FaceAntiSpoofingAdvanced$EnvironmentAssessment.dex +0 -0
  29. package/android/build/.transforms/c0a07cd9442d741ad3cef3760159211f/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/faceantispoof/FaceAntiSpoofingAdvanced$SpoofDetectionResult.dex +0 -0
  30. package/android/build/.transforms/c0a07cd9442d741ad3cef3760159211f/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/faceantispoof/FaceAntiSpoofingAdvanced.dex +0 -0
  31. package/android/build/.transforms/c0a07cd9442d741ad3cef3760159211f/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/faceantispoof/ImageFormatEncoder$ImageFormat.dex +0 -0
  32. package/android/build/.transforms/c0a07cd9442d741ad3cef3760159211f/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/faceantispoof/ImageFormatEncoder.dex +0 -0
  33. package/android/build/.transforms/c0a07cd9442d741ad3cef3760159211f/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/faceantispoof/YuvToFloatArrayConverter$Companion.dex +0 -0
  34. package/android/build/.transforms/c0a07cd9442d741ad3cef3760159211f/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/faceantispoof/YuvToFloatArrayConverter.dex +0 -0
  35. package/android/build/intermediates/compile_library_classes_jar/debug/bundleLibCompileToJarDebug/classes.jar +0 -0
  36. package/android/build/intermediates/cxx/Debug/2a1it684/logs/arm64-v8a/build_stdout_targets.txt +53 -53
  37. package/android/build/intermediates/cxx/Debug/2a1it684/logs/arm64-v8a/generate_cxx_metadata_947_timing.txt +9 -0
  38. package/android/build/intermediates/cxx/Debug/2a1it684/logs/armeabi-v7a/build_stdout_targets.txt +46 -46
  39. package/android/build/intermediates/cxx/Debug/2a1it684/logs/armeabi-v7a/{generate_cxx_metadata_1042_timing.txt → generate_cxx_metadata_944_timing.txt} +1 -1
  40. package/android/build/intermediates/cxx/Debug/2a1it684/logs/x86/build_stdout_targets.txt +40 -40
  41. package/android/build/intermediates/cxx/Debug/2a1it684/logs/x86_64/build_stdout_targets.txt +43 -43
  42. package/android/build/intermediates/cxx/Debug/2a1it684/logs/x86_64/generate_cxx_metadata_944_timing.txt +9 -0
  43. package/android/build/intermediates/incremental/debug/packageDebugResources/compile-file-map.properties +1 -1
  44. package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/faceantispoof/AntiSpoofingResult.class +0 -0
  45. package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/faceantispoof/FaceAntiSpoofingAdvanced$Companion.class +0 -0
  46. package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/faceantispoof/FaceAntiSpoofingAdvanced$EnvironmentAssessment.class +0 -0
  47. package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/faceantispoof/FaceAntiSpoofingAdvanced$SpoofDetectionResult.class +0 -0
  48. package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/faceantispoof/FaceAntiSpoofingAdvanced.class +0 -0
  49. package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/faceantispoof/ImageFormatEncoder$ImageFormat.class +0 -0
  50. package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/faceantispoof/ImageFormatEncoder.class +0 -0
  51. package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/faceantispoof/YuvToFloatArrayConverter$Companion.class +0 -0
  52. package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/faceantispoof/YuvToFloatArrayConverter.class +0 -0
  53. package/android/build/intermediates/runtime_library_classes_jar/debug/bundleLibRuntimeToJarDebug/classes.jar +0 -0
  54. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/inputs/source-to-output.tab +0 -0
  55. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/inputs/source-to-output.tab.values.at +0 -0
  56. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab +0 -0
  57. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab.keystream +0 -0
  58. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab.keystream.len +0 -0
  59. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab.len +0 -0
  60. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab.values.at +0 -0
  61. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab_i +0 -0
  62. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab +0 -0
  63. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab.keystream +0 -0
  64. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab.keystream.len +0 -0
  65. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab.len +0 -0
  66. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab.values.at +0 -0
  67. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab_i +0 -0
  68. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/constants.tab +0 -0
  69. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/constants.tab.keystream +0 -0
  70. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/constants.tab.keystream.len +0 -0
  71. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/constants.tab.len +0 -0
  72. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/constants.tab.values.at +0 -0
  73. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/constants.tab_i +0 -0
  74. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab +0 -0
  75. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab.keystream +0 -0
  76. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab.keystream.len +0 -0
  77. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab.len +0 -0
  78. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab.values.at +0 -0
  79. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab_i +0 -0
  80. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab +0 -0
  81. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab.keystream +0 -0
  82. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab.keystream.len +0 -0
  83. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab.len +0 -0
  84. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab.values.at +0 -0
  85. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab_i +0 -0
  86. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab +0 -0
  87. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab.values.at +0 -0
  88. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab +0 -0
  89. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab.keystream +0 -0
  90. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab.keystream.len +0 -0
  91. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab.len +0 -0
  92. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab.values.at +0 -0
  93. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab_i +0 -0
  94. package/android/build/kotlin/compileDebugKotlin/cacheable/last-build.bin +0 -0
  95. package/android/build/kotlin/compileDebugKotlin/classpath-snapshot/shrunk-classpath-snapshot.bin +0 -0
  96. package/android/build/kotlin/compileDebugKotlin/local-state/build-history.bin +0 -0
  97. package/android/build/tmp/kotlin-classes/debug/com/faceantispoof/AntiSpoofingResult.class +0 -0
  98. package/android/build/tmp/kotlin-classes/debug/com/faceantispoof/FaceAntiSpoofingAdvanced$Companion.class +0 -0
  99. package/android/build/tmp/kotlin-classes/debug/com/faceantispoof/FaceAntiSpoofingAdvanced$EnvironmentAssessment.class +0 -0
  100. package/android/build/tmp/kotlin-classes/debug/com/faceantispoof/FaceAntiSpoofingAdvanced$SpoofDetectionResult.class +0 -0
  101. package/android/build/tmp/kotlin-classes/debug/com/faceantispoof/FaceAntiSpoofingAdvanced.class +0 -0
  102. package/android/build/tmp/kotlin-classes/debug/com/faceantispoof/ImageFormatEncoder$ImageFormat.class +0 -0
  103. package/android/build/tmp/kotlin-classes/debug/com/faceantispoof/ImageFormatEncoder.class +0 -0
  104. package/android/build/tmp/kotlin-classes/debug/com/faceantispoof/YuvToFloatArrayConverter$Companion.class +0 -0
  105. package/android/build/tmp/kotlin-classes/debug/com/faceantispoof/YuvToFloatArrayConverter.class +0 -0
  106. package/android/src/main/java/com/faceantispoof/FaceAntiSpoofingAdvanced.kt +72 -19
  107. package/android/src/main/java/com/faceantispoof/ImageFormatEncoder.kt +92 -6
  108. package/android/src/main/java/com/faceantispoof/YuvToFloatArrayConverter.kt +203 -2
  109. package/package.json +1 -1
  110. package/android/build/intermediates/cxx/Debug/2a1it684/logs/arm64-v8a/generate_cxx_metadata_1041_timing.txt +0 -9
  111. package/android/build/intermediates/cxx/Debug/2a1it684/logs/x86_64/generate_cxx_metadata_1042_timing.txt +0 -9
  112. /package/android/.cxx/Debug/2a1it684/x86/.cmake/api/v1/reply/{index-2025-11-25T16-21-51-0349.json → index-2025-11-27T04-19-33-0139.json} +0 -0
  113. /package/android/.cxx/Debug/2a1it684/x86_64/.cmake/api/v1/reply/{index-2025-11-25T16-55-39-0849.json → index-2025-11-27T05-31-26-0486.json} +0 -0
  114. /package/android/build/intermediates/cxx/Debug/2a1it684/logs/x86/{generate_cxx_metadata_1042_timing.txt → generate_cxx_metadata_944_timing.txt} +0 -0
@@ -1,15 +1,36 @@
1
1
  package com.faceantispoof
2
2
 
3
3
  import java.nio.ByteBuffer
4
+ import kotlin.math.abs
4
5
 
5
6
  /**
6
7
  * Converts YUV NV21 data directly to normalized RGB float arrays without creating Bitmaps.
7
- * Supports downsampling/resizing in-place using nearest-neighbor interpolation.
8
+ * Supports high-quality bilinear interpolation for resizing to minimize blur.
9
+ * Includes motion/stability detection and frame quality assessment.
8
10
  */
9
11
  class YuvToFloatArrayConverter {
12
+
13
+ // Motion detection and frame stability
14
+ private var previousGrayscale: IntArray? = null
15
+ private var frameMotionScore = 0f
16
+ private var isFrameStable = false
17
+ private var consecutiveStableFrames = 0
18
+ private val STABILITY_THRESHOLD = 0.05f // Lower = more stable frames required
19
+ private val STABLE_FRAMES_REQUIRED = 3
20
+
21
+ companion object {
22
+ // Interpolation quality modes
23
+ const val INTERPOLATION_NEAREST = 0
24
+ const val INTERPOLATION_BILINEAR = 1
25
+ const val INTERPOLATION_BICUBIC = 2
26
+
27
+ // Default to bilinear for better quality
28
+ private val DEFAULT_INTERPOLATION = INTERPOLATION_BILINEAR
29
+ }
10
30
 
11
31
  /**
12
32
  * Convert NV21 YUV data directly to a normalized RGB float array.
33
+ * Uses high-quality bilinear interpolation to preserve image sharpness.
13
34
  * Output array is [height][width][3] where RGB channels are normalized to [0, 1].
14
35
  * @param nv21 NV21 encoded YUV data
15
36
  * @param width Original frame width
@@ -25,7 +46,8 @@ class YuvToFloatArrayConverter {
25
46
  height: Int,
26
47
  targetWidth: Int = width,
27
48
  targetHeight: Int = height,
28
- outputRgbFloat: FloatArray? = null
49
+ outputRgbFloat: FloatArray? = null,
50
+ interpolationMode: Int = DEFAULT_INTERPOLATION
29
51
  ): FloatArray {
30
52
  if (nv21.isEmpty()) {
31
53
  throw IllegalArgumentException("NV21 array is empty")
@@ -49,6 +71,12 @@ class YuvToFloatArrayConverter {
49
71
  throw IllegalArgumentException("NV21 buffer too small: expected at least $minExpectedSize, got ${nv21.size}")
50
72
  }
51
73
 
74
+ // Use bilinear interpolation for high-quality resizing
75
+ if (interpolationMode == INTERPOLATION_BILINEAR && (width != targetWidth || height != targetHeight)) {
76
+ return nv21ToRgbFloatArrayBilinear(nv21, width, height, targetWidth, targetHeight, output)
77
+ }
78
+
79
+ // Fallback to nearest neighbor
52
80
  var outIdx = 0
53
81
 
54
82
  for (targetY in 0 until targetHeight) {
@@ -102,6 +130,125 @@ class YuvToFloatArrayConverter {
102
130
  return output
103
131
  }
104
132
 
133
+ /**
134
+ * High-quality bilinear interpolation for resizing YUV to RGB.
135
+ * Significantly better quality than nearest-neighbor, reduces blur artifacts.
136
+ */
137
+ private fun nv21ToRgbFloatArrayBilinear(
138
+ nv21: ByteArray,
139
+ width: Int,
140
+ height: Int,
141
+ targetWidth: Int,
142
+ targetHeight: Int,
143
+ output: FloatArray
144
+ ): FloatArray {
145
+ val ySize = width * height
146
+ val uvPixelStride = 2
147
+ val scaleX = width.toFloat() / targetWidth
148
+ val scaleY = height.toFloat() / targetHeight
149
+
150
+ var outIdx = 0
151
+
152
+ for (targetY in 0 until targetHeight) {
153
+ val srcY = targetY * scaleY
154
+ val y1 = srcY.toInt()
155
+ val y2 = (y1 + 1).coerceAtMost(height - 1)
156
+ val fracY = srcY - y1
157
+
158
+ for (targetX in 0 until targetWidth) {
159
+ val srcX = targetX * scaleX
160
+ val x1 = srcX.toInt()
161
+ val x2 = (x1 + 1).coerceAtMost(width - 1)
162
+ val fracX = srcX - x1
163
+
164
+ // Sample 4 neighboring pixels in YUV space and interpolate
165
+ val (r, g, b) = bilinearInterpolateYuv(
166
+ nv21, width, height, ySize, uvPixelStride,
167
+ x1, y1, x2, y2, fracX, fracY
168
+ )
169
+
170
+ if (outIdx + 2 < output.size) {
171
+ output[outIdx++] = r / 255f
172
+ output[outIdx++] = g / 255f
173
+ output[outIdx++] = b / 255f
174
+ }
175
+ }
176
+ }
177
+
178
+ return output
179
+ }
180
+
181
+ /**
182
+ * Bilinear interpolation for YUV pixel sampling.
183
+ * Returns interpolated RGB values.
184
+ */
185
+ private fun bilinearInterpolateYuv(
186
+ nv21: ByteArray,
187
+ width: Int,
188
+ height: Int,
189
+ ySize: Int,
190
+ uvPixelStride: Int,
191
+ x1: Int,
192
+ y1: Int,
193
+ x2: Int,
194
+ y2: Int,
195
+ fracX: Float,
196
+ fracY: Float
197
+ ): Triple<Float, Float, Float> {
198
+ // Sample all 4 corners
199
+ val samples = arrayOf(
200
+ yuvToRgb(nv21, width, ySize, uvPixelStride, x1, y1),
201
+ yuvToRgb(nv21, width, ySize, uvPixelStride, x2, y1),
202
+ yuvToRgb(nv21, width, ySize, uvPixelStride, x1, y2),
203
+ yuvToRgb(nv21, width, ySize, uvPixelStride, x2, y2)
204
+ )
205
+
206
+ // Bilinear interpolation
207
+ val top = lerp(samples[0], samples[1], fracX)
208
+ val bottom = lerp(samples[2], samples[3], fracX)
209
+ return lerp(top, bottom, fracY)
210
+ }
211
+
212
+ /**
213
+ * Linear interpolation helper.
214
+ */
215
+ private fun lerp(a: Triple<Float, Float, Float>, b: Triple<Float, Float, Float>, t: Float): Triple<Float, Float, Float> {
216
+ return Triple(
217
+ a.first * (1 - t) + b.first * t,
218
+ a.second * (1 - t) + b.second * t,
219
+ a.third * (1 - t) + b.third * t
220
+ )
221
+ }
222
+
223
+ /**
224
+ * Convert a single YUV pixel to RGB.
225
+ */
226
+ private fun yuvToRgb(
227
+ nv21: ByteArray,
228
+ width: Int,
229
+ ySize: Int,
230
+ uvPixelStride: Int,
231
+ x: Int,
232
+ y: Int
233
+ ): Triple<Float, Float, Float> {
234
+ val yIdx = y * width + x
235
+ val yVal = nv21[yIdx].toInt() and 0xFF
236
+
237
+ val uvIndex = ySize + (y / 2) * width + (x / 2) * uvPixelStride
238
+ val vVal = nv21[uvIndex].toInt() and 0xFF
239
+ val uVal = nv21[uvIndex + 1].toInt() and 0xFF
240
+
241
+ val yf = yVal.toFloat()
242
+ val uf = uVal - 128f
243
+ val vf = vVal - 128f
244
+
245
+ val r = (yf + 1.402f * vf).coerceIn(0f, 255f)
246
+ val g = (yf - 0.34414f * uf - 0.71414f * vf).coerceIn(0f, 255f)
247
+ val b = (yf + 1.772f * uf).coerceIn(0f, 255f)
248
+
249
+ return Triple(r, g, b)
250
+ }
251
+
105
252
  /**
106
253
  * Convert NV21 directly to a flat RGB float buffer (single channel interleaving).
107
254
  * @param nv21 NV21 encoded YUV data
@@ -257,6 +404,7 @@ class YuvToFloatArrayConverter {
257
404
 
258
405
  /**
259
406
  * Convert NV21 directly to RGB byte array without float conversion.
407
+ * Uses high-quality bilinear interpolation for resizing.
260
408
  * Optimized for JPEG encoding (where RGB bytes are needed directly).
261
409
  * Output format: RGBRGBRGB... (no alpha channel)
262
410
  *
@@ -297,6 +445,12 @@ class YuvToFloatArrayConverter {
297
445
  throw IllegalArgumentException("NV21 buffer too small: expected at least $minExpectedSize, got ${nv21.size}")
298
446
  }
299
447
 
448
+ // Use bilinear interpolation for better quality
449
+ if (width != targetWidth || height != targetHeight) {
450
+ return nv21ToRgbByteArrayBilinear(nv21, width, height, targetWidth, targetHeight, output)
451
+ }
452
+
453
+ // Direct copy with nearest neighbor
300
454
  var outIdx = 0
301
455
 
302
456
  for (targetY in 0 until targetHeight) {
@@ -348,4 +502,51 @@ class YuvToFloatArrayConverter {
348
502
 
349
503
  return output
350
504
  }
505
+
506
+ /**
507
+ * High-quality bilinear interpolation for RGB byte array resizing.
508
+ */
509
+ private fun nv21ToRgbByteArrayBilinear(
510
+ nv21: ByteArray,
511
+ width: Int,
512
+ height: Int,
513
+ targetWidth: Int,
514
+ targetHeight: Int,
515
+ output: ByteArray
516
+ ): ByteArray {
517
+ val ySize = width * height
518
+ val uvPixelStride = 2
519
+ val scaleX = width.toFloat() / targetWidth
520
+ val scaleY = height.toFloat() / targetHeight
521
+
522
+ var outIdx = 0
523
+
524
+ for (targetY in 0 until targetHeight) {
525
+ val srcY = targetY * scaleY
526
+ val y1 = srcY.toInt()
527
+ val y2 = (y1 + 1).coerceAtMost(height - 1)
528
+ val fracY = srcY - y1
529
+
530
+ for (targetX in 0 until targetWidth) {
531
+ val srcX = targetX * scaleX
532
+ val x1 = srcX.toInt()
533
+ val x2 = (x1 + 1).coerceAtMost(width - 1)
534
+ val fracX = srcX - x1
535
+
536
+
537
+ val (r, g, b) = bilinearInterpolateYuv(
538
+ nv21, width, height, ySize, uvPixelStride,
539
+ x1, y1, x2, y2, fracX, fracY
540
+ )
541
+
542
+ if (outIdx + 2 < output.size) {
543
+ output[outIdx++] = r.toInt().toByte()
544
+ output[outIdx++] = g.toInt().toByte()
545
+ output[outIdx++] = b.toInt().toByte()
546
+ }
547
+ }
548
+ }
549
+
550
+ return output
551
+ }
351
552
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-vision-camera-spoof-detector",
3
- "version": "1.0.8",
3
+ "version": "1.0.9",
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": {
@@ -1,9 +0,0 @@
1
- # C/C++ build system timings
2
- generate_cxx_metadata
3
- execute-generate-process
4
- exec-configure 785ms
5
- [gap of 26ms]
6
- execute-generate-process completed in 812ms
7
- [gap of 18ms]
8
- generate_cxx_metadata completed in 837ms
9
-
@@ -1,9 +0,0 @@
1
- # C/C++ build system timings
2
- generate_cxx_metadata
3
- execute-generate-process
4
- exec-configure 464ms
5
- [gap of 23ms]
6
- execute-generate-process completed in 489ms
7
- [gap of 17ms]
8
- generate_cxx_metadata completed in 521ms
9
-