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

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 (165) hide show
  1. package/android/.cxx/Debug/2a1it684/arm64-v8a/.cmake/api/v1/reply/{codemodel-v2-6c7de80461af72f456a3.json → codemodel-v2-390962e2784a6a84fa3e.json} +2 -2
  2. package/android/.cxx/Debug/2a1it684/arm64-v8a/.cmake/api/v1/reply/{index-2025-11-18T17-52-03-0810.json → index-2025-11-24T13-21-59-0659.json} +2 -2
  3. package/android/.cxx/Debug/2a1it684/arm64-v8a/.cmake/api/v1/reply/{target-yuv-Debug-32bc4eddd343848e1c25.json → target-yuv-Debug-1e27b8a2bdcddd47b87d.json} +4 -4
  4. package/android/.cxx/Debug/2a1it684/arm64-v8a/.cmake/api/v1/reply/{target-yuv_shared-Debug-75ea769bf76a12914d29.json → target-yuv_shared-Debug-ac9194487d1fc1268a87.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 -63
  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-52ac1d8b40b69596389b.json → codemodel-v2-053850119b681f93cecc.json} +2 -2
  10. package/android/.cxx/Debug/2a1it684/armeabi-v7a/.cmake/api/v1/reply/{index-2025-11-18T16-28-36-0058.json → index-2025-11-18T18-09-57-0510.json} +2 -2
  11. package/android/.cxx/Debug/2a1it684/armeabi-v7a/.cmake/api/v1/reply/{target-yuv-Debug-97f9e822dbd84a186d44.json → target-yuv-Debug-a12ad49ff79080871bce.json} +2 -2
  12. package/android/.cxx/Debug/2a1it684/armeabi-v7a/.cmake/api/v1/reply/{target-yuv_shared-Debug-3730d20e27c3481c06b2.json → target-yuv_shared-Debug-2b00e64621a56b8dd632.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 -117
  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 -109
  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 -55
  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/ByteBufferPool$Companion.dex +0 -0
  28. package/android/build/.transforms/c0a07cd9442d741ad3cef3760159211f/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/faceantispoof/ByteBufferPool.dex +0 -0
  29. package/android/build/.transforms/c0a07cd9442d741ad3cef3760159211f/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/faceantispoof/FaceAntiSpoofFrameProcessor.dex +0 -0
  30. package/android/build/.transforms/c0a07cd9442d741ad3cef3760159211f/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/faceantispoof/FaceAntiSpoofingAdvanced$Companion.dex +0 -0
  31. package/android/build/.transforms/c0a07cd9442d741ad3cef3760159211f/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/faceantispoof/FaceAntiSpoofingAdvanced$EnvironmentAssessment.dex +0 -0
  32. package/android/build/.transforms/c0a07cd9442d741ad3cef3760159211f/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/faceantispoof/FaceAntiSpoofingAdvanced$SpoofDetectionResult.dex +0 -0
  33. package/android/build/.transforms/c0a07cd9442d741ad3cef3760159211f/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/faceantispoof/FaceAntiSpoofingAdvanced.dex +0 -0
  34. package/android/build/.transforms/c0a07cd9442d741ad3cef3760159211f/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/faceantispoof/ImageFormatEncoder$ImageFormat.dex +0 -0
  35. package/android/build/.transforms/c0a07cd9442d741ad3cef3760159211f/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/faceantispoof/ImageFormatEncoder$WhenMappings.dex +0 -0
  36. package/android/build/.transforms/c0a07cd9442d741ad3cef3760159211f/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/faceantispoof/ImageFormatEncoder.dex +0 -0
  37. package/android/build/.transforms/c0a07cd9442d741ad3cef3760159211f/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/faceantispoof/JpegEncoder$Companion.dex +0 -0
  38. package/android/build/.transforms/c0a07cd9442d741ad3cef3760159211f/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/faceantispoof/JpegEncoder.dex +0 -0
  39. package/android/build/.transforms/c0a07cd9442d741ad3cef3760159211f/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/faceantispoof/YuvToFloatArrayConverter.dex +0 -0
  40. package/android/build/intermediates/compile_library_classes_jar/debug/bundleLibCompileToJarDebug/classes.jar +0 -0
  41. package/android/build/intermediates/cxx/Debug/2a1it684/logs/arm64-v8a/build_stdout_targets.txt +62 -1
  42. package/android/build/intermediates/cxx/Debug/2a1it684/logs/arm64-v8a/generate_cxx_metadata_2655_timing.txt +9 -0
  43. package/android/build/intermediates/cxx/Debug/2a1it684/logs/armeabi-v7a/build_stdout_targets.txt +58 -1
  44. package/android/build/intermediates/cxx/Debug/2a1it684/logs/armeabi-v7a/{generate_cxx_metadata_2399_timing.txt → generate_cxx_metadata_2653_timing.txt} +1 -1
  45. package/android/build/intermediates/cxx/Debug/2a1it684/logs/x86/build_stdout_targets.txt +54 -1
  46. package/android/build/intermediates/cxx/Debug/2a1it684/logs/{armeabi-v7a/generate_cxx_metadata_2616_timing.txt → x86/generate_cxx_metadata_2653_timing.txt} +1 -1
  47. package/android/build/intermediates/cxx/Debug/2a1it684/logs/x86_64/build_stdout_targets.txt +54 -1
  48. package/android/build/intermediates/cxx/Debug/2a1it684/logs/x86_64/generate_cxx_metadata_2653_timing.txt +9 -0
  49. package/android/build/intermediates/incremental/debug/packageDebugResources/compile-file-map.properties +1 -1
  50. package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/faceantispoof/AntiSpoofingResult.class +0 -0
  51. package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/faceantispoof/ByteBufferPool$Companion.class +0 -0
  52. package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/faceantispoof/ByteBufferPool.class +0 -0
  53. package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/faceantispoof/FaceAntiSpoofFrameProcessor.class +0 -0
  54. package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/faceantispoof/FaceAntiSpoofingAdvanced$Companion.class +0 -0
  55. package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/faceantispoof/FaceAntiSpoofingAdvanced$EnvironmentAssessment.class +0 -0
  56. package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/faceantispoof/FaceAntiSpoofingAdvanced$SpoofDetectionResult.class +0 -0
  57. package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/faceantispoof/FaceAntiSpoofingAdvanced.class +0 -0
  58. package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/faceantispoof/ImageFormatEncoder$ImageFormat.class +0 -0
  59. package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/faceantispoof/ImageFormatEncoder$WhenMappings.class +0 -0
  60. package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/faceantispoof/ImageFormatEncoder.class +0 -0
  61. package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/faceantispoof/JpegEncoder$Companion.class +0 -0
  62. package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/faceantispoof/JpegEncoder.class +0 -0
  63. package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/faceantispoof/YuvToFloatArrayConverter.class +0 -0
  64. package/android/build/intermediates/runtime_library_classes_jar/debug/bundleLibRuntimeToJarDebug/classes.jar +0 -0
  65. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/inputs/source-to-output.tab +0 -0
  66. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/inputs/source-to-output.tab.keystream +0 -0
  67. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/inputs/source-to-output.tab.keystream.len +0 -0
  68. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/inputs/source-to-output.tab.len +0 -0
  69. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/inputs/source-to-output.tab.values.at +0 -0
  70. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/inputs/source-to-output.tab_i +0 -0
  71. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab +0 -0
  72. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab.keystream +0 -0
  73. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab.keystream.len +0 -0
  74. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab.len +0 -0
  75. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab.values.at +0 -0
  76. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab_i +0 -0
  77. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab +0 -0
  78. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab.keystream +0 -0
  79. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab.keystream.len +0 -0
  80. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab.len +0 -0
  81. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab.values.at +0 -0
  82. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab_i +0 -0
  83. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/constants.tab +0 -0
  84. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/constants.tab.values.at +0 -0
  85. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab +0 -0
  86. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab.keystream +0 -0
  87. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab.keystream.len +0 -0
  88. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab.len +0 -0
  89. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab.values.at +0 -0
  90. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab_i +0 -0
  91. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab +0 -0
  92. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab.keystream +0 -0
  93. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab.keystream.len +0 -0
  94. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab.len +0 -0
  95. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab.values.at +0 -0
  96. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab_i +0 -0
  97. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab +0 -0
  98. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab.keystream +0 -0
  99. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab.keystream.len +0 -0
  100. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab.len +0 -0
  101. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab.values.at +0 -0
  102. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab_i +0 -0
  103. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/subtypes.tab +0 -0
  104. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/subtypes.tab.keystream +0 -0
  105. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/subtypes.tab.keystream.len +0 -0
  106. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/subtypes.tab.len +0 -0
  107. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/subtypes.tab.values.at +0 -0
  108. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/subtypes.tab_i +0 -0
  109. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/supertypes.tab +0 -0
  110. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/supertypes.tab.keystream +0 -0
  111. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/supertypes.tab.keystream.len +0 -0
  112. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/supertypes.tab.len +0 -0
  113. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/supertypes.tab.values.at +0 -0
  114. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/supertypes.tab_i +0 -0
  115. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/counters.tab +1 -1
  116. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/file-to-id.tab +0 -0
  117. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/file-to-id.tab.keystream +0 -0
  118. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/file-to-id.tab.keystream.len +0 -0
  119. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/file-to-id.tab.len +0 -0
  120. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/file-to-id.tab.values.at +0 -0
  121. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/file-to-id.tab_i +0 -0
  122. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/id-to-file.tab +0 -0
  123. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/id-to-file.tab.keystream +0 -0
  124. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/id-to-file.tab.keystream.len +0 -0
  125. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/id-to-file.tab.len +0 -0
  126. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/id-to-file.tab.values.at +0 -0
  127. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/id-to-file.tab_i +0 -0
  128. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab +0 -0
  129. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab.keystream +0 -0
  130. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab.keystream.len +0 -0
  131. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab.len +0 -0
  132. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab.values.at +0 -0
  133. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab_i +0 -0
  134. package/android/build/kotlin/compileDebugKotlin/cacheable/last-build.bin +0 -0
  135. package/android/build/kotlin/compileDebugKotlin/classpath-snapshot/shrunk-classpath-snapshot.bin +0 -0
  136. package/android/build/kotlin/compileDebugKotlin/local-state/build-history.bin +0 -0
  137. package/android/build/tmp/kotlin-classes/debug/com/faceantispoof/AntiSpoofingResult.class +0 -0
  138. package/android/build/tmp/kotlin-classes/debug/com/faceantispoof/ByteBufferPool$Companion.class +0 -0
  139. package/android/build/tmp/kotlin-classes/debug/com/faceantispoof/ByteBufferPool.class +0 -0
  140. package/android/build/tmp/kotlin-classes/debug/com/faceantispoof/FaceAntiSpoofFrameProcessor.class +0 -0
  141. package/android/build/tmp/kotlin-classes/debug/com/faceantispoof/FaceAntiSpoofingAdvanced$Companion.class +0 -0
  142. package/android/build/tmp/kotlin-classes/debug/com/faceantispoof/FaceAntiSpoofingAdvanced$EnvironmentAssessment.class +0 -0
  143. package/android/build/tmp/kotlin-classes/debug/com/faceantispoof/FaceAntiSpoofingAdvanced$SpoofDetectionResult.class +0 -0
  144. package/android/build/tmp/kotlin-classes/debug/com/faceantispoof/FaceAntiSpoofingAdvanced.class +0 -0
  145. package/android/build/tmp/kotlin-classes/debug/com/faceantispoof/ImageFormatEncoder$ImageFormat.class +0 -0
  146. package/android/build/tmp/kotlin-classes/debug/com/faceantispoof/ImageFormatEncoder$WhenMappings.class +0 -0
  147. package/android/build/tmp/kotlin-classes/debug/com/faceantispoof/ImageFormatEncoder.class +0 -0
  148. package/android/build/tmp/kotlin-classes/debug/com/faceantispoof/JpegEncoder$Companion.class +0 -0
  149. package/android/build/tmp/kotlin-classes/debug/com/faceantispoof/JpegEncoder.class +0 -0
  150. package/android/build/tmp/kotlin-classes/debug/com/faceantispoof/YuvToFloatArrayConverter.class +0 -0
  151. package/android/src/main/java/com/faceantispoof/ByteBufferPool.kt +68 -0
  152. package/android/src/main/java/com/faceantispoof/FaceAntiSpoofFrameProcessor.kt +6 -1
  153. package/android/src/main/java/com/faceantispoof/FaceAntiSpoofingAdvanced.kt +194 -8
  154. package/android/src/main/java/com/faceantispoof/ImageFormatEncoder.kt +247 -0
  155. package/android/src/main/java/com/faceantispoof/JpegEncoder.kt +204 -0
  156. package/android/src/main/java/com/faceantispoof/YuvToFloatArrayConverter.kt +62 -0
  157. package/package.json +3 -3
  158. package/android/build/intermediates/cxx/Debug/2a1it684/logs/arm64-v8a/generate_cxx_metadata_2398_timing.txt +0 -9
  159. package/android/build/intermediates/cxx/Debug/2a1it684/logs/arm64-v8a/generate_cxx_metadata_2614_timing.txt +0 -9
  160. package/android/build/intermediates/cxx/Debug/2a1it684/logs/x86/generate_cxx_metadata_2399_timing.txt +0 -3
  161. package/android/build/intermediates/cxx/Debug/2a1it684/logs/x86/generate_cxx_metadata_2616_timing.txt +0 -3
  162. package/android/build/intermediates/cxx/Debug/2a1it684/logs/x86_64/generate_cxx_metadata_2399_timing.txt +0 -9
  163. package/android/build/intermediates/cxx/Debug/2a1it684/logs/x86_64/generate_cxx_metadata_2616_timing.txt +0 -9
  164. /package/android/.cxx/Debug/2a1it684/x86/.cmake/api/v1/reply/{index-2025-11-18T16-28-43-0678.json → index-2025-11-18T18-10-04-0841.json} +0 -0
  165. /package/android/.cxx/Debug/2a1it684/x86_64/.cmake/api/v1/reply/{index-2025-11-18T17-52-04-0655.json → index-2025-11-24T13-22-20-0304.json} +0 -0
@@ -0,0 +1,68 @@
1
+ package com.faceantispoof
2
+
3
+ import android.util.Log
4
+ import java.util.concurrent.atomic.AtomicInteger
5
+
6
+ /**
7
+ * Buffer pool manager for efficient reuse of large byte arrays.
8
+ * Reduces garbage collection pressure during continuous frame processing.
9
+ */
10
+ class ByteBufferPool(private val bufferSize: Int) {
11
+ companion object {
12
+ private const val TAG = "ByteBufferPool"
13
+ }
14
+
15
+ private val availableBuffers = mutableListOf<ByteArray>()
16
+ private val allocatedCount = AtomicInteger(0)
17
+ private val maxPoolSize = 3 // Keep max 3 buffers in pool
18
+
19
+ /**
20
+ * Acquire a buffer from the pool or allocate a new one if needed.
21
+ */
22
+ fun acquire(): ByteArray {
23
+ synchronized(availableBuffers) {
24
+ val buffer = if (availableBuffers.isNotEmpty()) {
25
+ availableBuffers.removeAt(0)
26
+ } else {
27
+ allocatedCount.incrementAndGet()
28
+ Log.d(TAG, "Allocated new buffer ($allocatedCount allocated)")
29
+ ByteArray(bufferSize)
30
+ }
31
+ return buffer
32
+ }
33
+ }
34
+
35
+ /**
36
+ * Return a buffer to the pool for reuse.
37
+ */
38
+ fun release(buffer: ByteArray) {
39
+ if (buffer.size != bufferSize) {
40
+ Log.w(TAG, "Buffer size mismatch: expected $bufferSize, got ${buffer.size}")
41
+ return
42
+ }
43
+
44
+ synchronized(availableBuffers) {
45
+ if (availableBuffers.size < maxPoolSize) {
46
+ availableBuffers.add(buffer)
47
+ Log.d(TAG, "Buffer returned to pool (available: ${availableBuffers.size})")
48
+ } else {
49
+ Log.d(TAG, "Pool is full, discarding buffer")
50
+ }
51
+ }
52
+ }
53
+
54
+ /**
55
+ * Get current pool statistics.
56
+ */
57
+ fun getStats(): String {
58
+ return "ByteBufferPool(size=$bufferSize, allocated=$allocatedCount, available=${availableBuffers.size})"
59
+ }
60
+
61
+ fun clear() {
62
+ synchronized(availableBuffers) {
63
+ availableBuffers.clear()
64
+ Log.d(TAG, "Buffer pool cleared")
65
+ }
66
+ }
67
+ }
68
+
@@ -131,7 +131,12 @@ class FaceAntiSpoofFrameProcessor : FrameProcessorPlugin() {
131
131
  "label" to result.label,
132
132
  "neuralNetworkScore" to result.neuralNetworkScore.toDouble(),
133
133
  "laplacianScore" to result.laplacianScore,
134
- "combinedScore" to result.combinedScore.toDouble()
134
+ "combinedScore" to result.combinedScore.toDouble(),
135
+ "recognitionImageBase64" to result.recognitionImageBase64,
136
+ // Image format metadata
137
+ "imageFormat" to result.imageFormat,
138
+ "imageResolution" to result.imageResolution,
139
+ "imageQuality" to result.imageQuality
135
140
  )
136
141
 
137
142
  // Update the latest result for the next callback
@@ -14,15 +14,18 @@ import java.nio.ByteOrder
14
14
  import java.util.*
15
15
  import android.util.Log
16
16
  import kotlin.collections.ArrayList
17
+ import android.util.Base64
18
+ import com.faceantispoof.ImageFormatEncoder
19
+ import com.faceantispoof.ImageFormatEncoder.ImageFormat
17
20
 
18
21
  class FaceAntiSpoofingAdvanced(private val assetManager: AssetManager) {
19
22
 
20
23
  companion object {
21
24
  const val INPUT_IMAGE_SIZE = 256
22
- const val BASE_THRESHOLD = 0.1f
25
+ const val BASE_THRESHOLD = 0.2f
23
26
  const val ROUTE_INDEX = 6
24
27
  const val LAPLACE_THRESHOLD = 50
25
- const val LAPLACIAN_THRESHOLD = 10000
28
+ const val LAPLACIAN_THRESHOLD = 1000
26
29
  const val MODEL_FILE = "FaceAntiSpoofing.tflite"
27
30
  private const val TAG = "FaceAntiSpoofing"
28
31
 
@@ -31,6 +34,12 @@ class FaceAntiSpoofingAdvanced(private val assetManager: AssetManager) {
31
34
  const val ACCELERATOR_GPU = "GPU"
32
35
  const val ACCELERATOR_NNAPI = "NNAPI"
33
36
 
37
+ // Image format configuration for face recognition systems
38
+ // Supported: JPEG (compressed), PNG (lossless), BMP (uncompressed)
39
+ const val DEFAULT_IMAGE_FORMAT = "JPEG" // Options: "JPEG", "PNG", "BMP"
40
+ const val DEFAULT_JPEG_QUALITY = 85 // 0-100, higher = better quality but larger
41
+ const val DEFAULT_OUTPUT_RESOLUTION = 640 // 640×640 for face recognition
42
+
34
43
  // Advanced spoof detection constants
35
44
  private const val HISTORY_SIZE = 10
36
45
  private const val TEMPORAL_CONSISTENCY_THRESHOLD = 0.08f
@@ -47,6 +56,11 @@ class FaceAntiSpoofingAdvanced(private val assetManager: AssetManager) {
47
56
  private var gpuDelegate: GpuDelegate? = null
48
57
  private var currentAccelerator: String = ACCELERATOR_CPU
49
58
 
59
+ // Image format configuration for face recognition
60
+ private var outputImageFormat: String = DEFAULT_IMAGE_FORMAT
61
+ private var outputImageQuality: Int = DEFAULT_JPEG_QUALITY
62
+ private var outputImageResolution: Int = DEFAULT_OUTPUT_RESOLUTION
63
+
50
64
  // Reusable buffers to avoid per-frame allocations
51
65
  private val inputImageSize = INPUT_IMAGE_SIZE
52
66
  private val inputBuffer: ByteBuffer = ByteBuffer.allocateDirect(4 * inputImageSize * inputImageSize * 3).order(ByteOrder.nativeOrder())
@@ -141,6 +155,57 @@ class FaceAntiSpoofingAdvanced(private val assetManager: AssetManager) {
141
155
 
142
156
  fun getAccelerator(): String = currentAccelerator
143
157
 
158
+ /**
159
+ * Configure output image format for face recognition system.
160
+ * Supports JPEG (compressed), PNG (lossless), or BMP (uncompressed).
161
+ *
162
+ * @param format Image format: "JPEG" (default), "PNG", or "BMP"
163
+ * @param quality JPEG quality 0-100 (only applies to JPEG, ignored for PNG/BMP)
164
+ * @param resolution Output resolution in pixels (640 for 640×640, etc.)
165
+ */
166
+ fun setImageFormatConfig(
167
+ format: String = "JPEG",
168
+ quality: Int = 85,
169
+ resolution: Int = 640
170
+ ) {
171
+ val uppercaseFormat = format.uppercase()
172
+ outputImageFormat = if (uppercaseFormat in listOf("JPEG", "PNG", "BMP")) {
173
+ uppercaseFormat
174
+ } else {
175
+ "JPEG"
176
+ }
177
+ outputImageQuality = quality.coerceIn(1, 100)
178
+ outputImageResolution = resolution.coerceIn(64, 2048)
179
+ Log.d(TAG, "Image format config: $outputImageFormat quality=$outputImageQuality resolution=${outputImageResolution}×${outputImageResolution}")
180
+ }
181
+
182
+ /**
183
+ * Get current image format configuration.
184
+ * @return Map containing format, quality, and resolution
185
+ */
186
+ fun getImageFormatConfig(): Map<String, Any> {
187
+ return mapOf(
188
+ "format" to outputImageFormat,
189
+ "quality" to outputImageQuality,
190
+ "resolution" to outputImageResolution,
191
+ "estimatedSize" to estimateImageSize()
192
+ )
193
+ }
194
+
195
+ /**
196
+ * Estimate output image size for current format configuration.
197
+ * Useful for memory and network planning.
198
+ */
199
+ private fun estimateImageSize(): Long {
200
+ val pixelCount = outputImageResolution.toLong() * outputImageResolution
201
+ return when (outputImageFormat) {
202
+ "JPEG" -> (pixelCount * (100 - outputImageQuality) * 0.0012).toLong() // Quality-based estimation
203
+ "PNG" -> (pixelCount * 0.5).toLong() // PNG typically 2-4x larger than JPEG
204
+ "BMP" -> pixelCount * 3 // Uncompressed RGB
205
+ else -> (pixelCount * 0.12).toLong()
206
+ }
207
+ }
208
+
144
209
  fun advancedAntiSpoofing(nv21: ByteArray, width: Int, height: Int): AntiSpoofingResult {
145
210
  if (!isInitialized) {
146
211
  return AntiSpoofingResult(
@@ -153,18 +218,23 @@ class FaceAntiSpoofingAdvanced(private val assetManager: AssetManager) {
153
218
  isLive = false,
154
219
  confidence = 0f,
155
220
  label = "Not Initialized",
156
- spoofType = "UNKNOWN"
221
+ spoofType = "UNKNOWN",
222
+ imageFormat = outputImageFormat,
223
+ imageResolution = outputImageResolution,
224
+ imageQuality = outputImageQuality
157
225
  )
158
226
  }
159
227
 
160
228
  // Enhanced input validation
161
229
  if (nv21.isEmpty()) {
162
- return AntiSpoofingResult(0f, 0, 0, 0f, 0f, 0f, false, 0f, "Error: Invalid NV21 buffer", "INVALID_INPUT")
230
+ return AntiSpoofingResult(0f, 0, 0, 0f, 0f, 0f, false, 0f, "Error: Invalid NV21 buffer", "INVALID_INPUT",
231
+ imageFormat = outputImageFormat, imageResolution = outputImageResolution, imageQuality = outputImageQuality)
163
232
  }
164
233
 
165
234
  val expectedSize = width * height + (width * height) / 2
166
235
  if (nv21.size < expectedSize) {
167
- return AntiSpoofingResult(0f, 0, 0, 0f, 0f, 0f, false, 0f, "Error: Buffer size mismatch", "INVALID_INPUT")
236
+ return AntiSpoofingResult(0f, 0, 0, 0f, 0f, 0f, false, 0f, "Error: Buffer size mismatch", "INVALID_INPUT",
237
+ imageFormat = outputImageFormat, imageResolution = outputImageResolution, imageQuality = outputImageQuality)
168
238
  }
169
239
 
170
240
  return try {
@@ -200,6 +270,27 @@ class FaceAntiSpoofingAdvanced(private val assetManager: AssetManager) {
200
270
  spoofDetection
201
271
  )
202
272
 
273
+ // Generate recognition image (JPEG/PNG/BMP) Base64 when face is live
274
+ var recognitionImageBase64: String? = null
275
+ val DEBUG_FORCE_BASE64 = false // Set to true to force Base64 generation for testing
276
+
277
+ if (isLive || DEBUG_FORCE_BASE64) {
278
+ Log.d(TAG, "🔍 isLive=$isLive (DEBUG_FORCE_BASE64=$DEBUG_FORCE_BASE64) - generating ${outputImageResolution}×${outputImageResolution} $outputImageFormat Base64...")
279
+ try {
280
+ recognitionImageBase64 = generateRecognitionImageBase64(nv21, width, height)
281
+ if (recognitionImageBase64 != null) {
282
+ Log.d(TAG, " Generated 640x640 JPEG Base64 for recognition API (size: ${recognitionImageBase64.length} bytes)")
283
+ } else {
284
+ Log.w(TAG, " generate640x640JpegBase64 returned null")
285
+ }
286
+ } catch (e: Exception) {
287
+ Log.w(TAG, " Failed to generate 640x640 JPEG Base64: ${e.message}", e)
288
+ // Continue without the image - it's not critical
289
+ }
290
+ } else {
291
+ Log.d(TAG, " isLive is FALSE - skipping Base64 generation")
292
+ }
293
+
203
294
  AntiSpoofingResult(
204
295
  neuralNetworkScore = nnScore,
205
296
  laplacianScore = laplacianScore,
@@ -210,11 +301,16 @@ class FaceAntiSpoofingAdvanced(private val assetManager: AssetManager) {
210
301
  isLive = isLive,
211
302
  confidence = confidence,
212
303
  label = if (isLive) "Live Face" else "Spoof Face: ${spoofDetection.type}",
213
- spoofType = spoofDetection.type
304
+ spoofType = spoofDetection.type,
305
+ recognitionImageBase64 = recognitionImageBase64,
306
+ imageFormat = outputImageFormat,
307
+ imageResolution = outputImageResolution,
308
+ imageQuality = outputImageQuality
214
309
  )
215
310
  } catch (e: Exception) {
216
311
  Log.e(TAG, "Error in advancedAntiSpoofing", e)
217
- AntiSpoofingResult(0f, 0, 0, 0f, 0f, 0f, false, 0f, "Error: ${e.message}", "PROCESSING_ERROR")
312
+ AntiSpoofingResult(0f, 0, 0, 0f, 0f, 0f, false, 0f, "Error: ${e.message}", "PROCESSING_ERROR",
313
+ imageFormat = outputImageFormat, imageResolution = outputImageResolution, imageQuality = outputImageQuality)
218
314
  }
219
315
  }
220
316
 
@@ -272,6 +368,91 @@ class FaceAntiSpoofingAdvanced(private val assetManager: AssetManager) {
272
368
  }
273
369
  }
274
370
 
371
+ /**
372
+ * Generate image as Base64 string for face recognition API.
373
+ * Supports JPEG, PNG, and BMP formats with configurable resolution.
374
+ * Compatible with OpenCV cv2.imdecode() for face recognition systems.
375
+ *
376
+ * @param nv21 NV21 encoded YUV frame
377
+ * @param width Original frame width
378
+ * @param height Original frame height
379
+ * @return Base64 encoded image string, or null if generation fails
380
+ */
381
+ private fun generateRecognitionImageBase64(nv21: ByteArray, width: Int, height: Int): String? {
382
+ return try {
383
+ Log.d(TAG, "Starting ${outputImageResolution}×${outputImageResolution} $outputImageFormat generation. Input: ${width}x${height}, NV21 size: ${nv21.size}")
384
+
385
+ // Convert NV21 to RGB byte array directly (configurable resolution)
386
+ val rgbBytes = ByteArray(outputImageResolution * outputImageResolution * 3)
387
+ Log.d(TAG, "Allocated RGB buffer: ${rgbBytes.size} bytes")
388
+
389
+ val startConvert = System.currentTimeMillis()
390
+ val convertedRgb = yuvConverter.nv21ToRgbByteArray(
391
+ nv21, width, height,
392
+ outputImageResolution, outputImageResolution,
393
+ rgbBytes
394
+ )
395
+ val convertTime = System.currentTimeMillis() - startConvert
396
+ Log.d(TAG, "YUV to RGB conversion completed in ${convertTime}ms. RGB data: ${convertedRgb.size} bytes")
397
+
398
+ // Encode RGB to target format (JPEG, PNG, or BMP) and Base64
399
+ val startEncode = System.currentTimeMillis()
400
+ val format = when (outputImageFormat) {
401
+ "PNG" -> ImageFormatEncoder.ImageFormat.PNG
402
+ "BMP" -> ImageFormatEncoder.ImageFormat.BMP
403
+ else -> ImageFormatEncoder.ImageFormat.JPEG
404
+ }
405
+
406
+ val base64Result = ImageFormatEncoder.rgbToBase64(
407
+ convertedRgb,
408
+ outputImageResolution,
409
+ outputImageResolution,
410
+ format,
411
+ outputImageQuality
412
+ )
413
+ val encodeTime = System.currentTimeMillis() - startEncode
414
+
415
+ if (base64Result != null) {
416
+ Log.d(TAG, "$outputImageFormat encoding completed in ${encodeTime}ms. Base64 size: ${base64Result.length} bytes")
417
+ Log.d(TAG, "✅ Generated ${outputImageResolution}×${outputImageResolution} $outputImageFormat Base64 for recognition API (total: ${convertTime + encodeTime}ms)")
418
+ val estSize = estimateImageSize()
419
+ Log.d(TAG, "Format: $outputImageFormat, Quality: $outputImageQuality, Estimated: ${estSize / 1024}KB")
420
+ } else {
421
+ Log.w(TAG, "⚠️ ImageFormatEncoder returned null")
422
+ }
423
+
424
+ base64Result
425
+ } catch (e: Exception) {
426
+ Log.e(TAG, "❌ Error generating ${outputImageResolution}×${outputImageResolution} $outputImageFormat Base64: ${e.message}", e)
427
+ e.printStackTrace()
428
+ null
429
+ }
430
+ }
431
+
432
+ /**
433
+ * Legacy method: Generate 640×640 JPEG image as Base64 string.
434
+ * Kept for backward compatibility. Use generateRecognitionImageBase64() for new code.
435
+ */
436
+ @Deprecated("Use generateRecognitionImageBase64() instead", ReplaceWith("generateRecognitionImageBase64(nv21, width, height)"))
437
+ private fun generate640x640JpegBase64(nv21: ByteArray, width: Int, height: Int): String? {
438
+ // Temporarily set format to JPEG for backward compatibility
439
+ val savedFormat = outputImageFormat
440
+ outputImageFormat = "JPEG"
441
+ val savedQuality = outputImageQuality
442
+ outputImageQuality = 85
443
+ val savedResolution = outputImageResolution
444
+ outputImageResolution = 640
445
+
446
+ val result = generateRecognitionImageBase64(nv21, width, height)
447
+
448
+ // Restore original config
449
+ outputImageFormat = savedFormat
450
+ outputImageQuality = savedQuality
451
+ outputImageResolution = savedResolution
452
+
453
+ return result
454
+ }
455
+
275
456
  private fun leafScore1(clssPred: Array<FloatArray>, leafNodeMask: Array<FloatArray>): Float {
276
457
  var score = 0f
277
458
  for (i in 0 until 8) {
@@ -572,5 +753,10 @@ data class AntiSpoofingResult(
572
753
  val isLive: Boolean,
573
754
  val confidence: Float,
574
755
  val label: String,
575
- val spoofType: String
756
+ val spoofType: String,
757
+ val recognitionImageBase64: String? = null,
758
+ // Image format metadata
759
+ val imageFormat: String = "JPEG", // Format: JPEG, PNG, BMP
760
+ val imageResolution: Int = 640, // 640×640, 1280×720, etc.
761
+ val imageQuality: Int = 85 // Quality for JPEG (0-100)
576
762
  )
@@ -0,0 +1,247 @@
1
+ package com.faceantispoof
2
+
3
+ import android.graphics.Bitmap
4
+ import android.graphics.Bitmap.CompressFormat
5
+ import android.util.Base64
6
+ import android.util.Log
7
+ import java.io.ByteArrayOutputStream
8
+
9
+ /**
10
+ * Multi-format image encoder supporting JPEG, PNG, and BMP.
11
+ * Handles RGB data conversion to various image formats for compatibility
12
+ * with face recognition systems (OpenCV cv2.imdecode compatible).
13
+ *
14
+ * Supported formats:
15
+ * - JPEG: Compressed, good for network transmission (~80-100 KB at quality 85)
16
+ * - PNG: Lossless, larger file size (~200-300 KB)
17
+ * - BMP: Raw uncompressed, largest size (~2-3 MB for 640×640)
18
+ *
19
+ * Optimized for common resolutions:
20
+ * - 640×480 (VGA)
21
+ * - 1280×720 (HD)
22
+ * - 1920×1080 (Full HD)
23
+ * - 640×640 (Custom square format for face recognition)
24
+ */
25
+ object ImageFormatEncoder {
26
+
27
+ private const val TAG = "ImageFormatEncoder"
28
+
29
+ /**
30
+ * Supported image formats for face recognition system
31
+ */
32
+ enum class ImageFormat(val compressFormat: CompressFormat, val mimeType: String) {
33
+ JPEG(CompressFormat.JPEG, "image/jpeg"),
34
+ PNG(CompressFormat.PNG, "image/png"),
35
+ BMP(CompressFormat.WEBP, "image/bmp") // Android uses WebP as fallback for BMP
36
+ }
37
+
38
+ /**
39
+ * Convert RGB data to specified image format and return as Base64 string.
40
+ * Compatible with OpenCV cv2.imdecode() for face recognition systems.
41
+ *
42
+ * @param rgbData RGB data as byte array (format: RGBRGBRGB..., 3 channels)
43
+ * @param width Image width (pixels)
44
+ * @param height Image height (pixels)
45
+ * @param format Target image format (JPEG, PNG, BMP)
46
+ * @param quality Compression quality for JPEG (0-100), ignored for PNG/BMP
47
+ * @return Base64 encoded image string, or null if encoding fails
48
+ */
49
+ fun rgbToBase64(
50
+ rgbData: ByteArray,
51
+ width: Int,
52
+ height: Int,
53
+ format: ImageFormat = ImageFormat.JPEG,
54
+ quality: Int = 85
55
+ ): String? {
56
+ return try {
57
+ validateImageDimensions(width, height)
58
+ validateRgbData(rgbData, width, height)
59
+
60
+ val imageBytes = rgbToImageBytes(rgbData, width, height, format, quality)
61
+ ?: return null
62
+
63
+ Base64.encodeToString(imageBytes, Base64.NO_WRAP)
64
+ } catch (e: Exception) {
65
+ Log.e(TAG, "Failed to convert RGB to ${format.name} Base64: ${e.message}", e)
66
+ null
67
+ }
68
+ }
69
+
70
+ /**
71
+ * Convert RGB float array (normalized 0-1) to image format and return as Base64.
72
+ * Each pixel is stored as 3 floats (R, G, B).
73
+ *
74
+ * @param rgbFloats RGB data as float array (normalized to 0-1)
75
+ * @param width Image width
76
+ * @param height Image height
77
+ * @param format Target image format
78
+ * @param quality Compression quality for JPEG
79
+ * @return Base64 encoded image string
80
+ */
81
+ fun rgbFloatToBase64(
82
+ rgbFloats: FloatArray,
83
+ width: Int,
84
+ height: Int,
85
+ format: ImageFormat = ImageFormat.JPEG,
86
+ quality: Int = 85
87
+ ): String? {
88
+ return try {
89
+ validateImageDimensions(width, height)
90
+
91
+ // Convert float array (normalized 0-1) to byte array (0-255)
92
+ val rgbBytes = ByteArray(width * height * 3)
93
+ var idx = 0
94
+ for (i in rgbFloats.indices) {
95
+ rgbBytes[idx++] = (rgbFloats[i] * 255f).toInt().coerceIn(0, 255).toByte()
96
+ }
97
+
98
+ rgbToBase64(rgbBytes, width, height, format, quality)
99
+ } catch (e: Exception) {
100
+ Log.e(TAG, "Failed to convert RGB float to ${format.name} Base64: ${e.message}", e)
101
+ null
102
+ }
103
+ }
104
+
105
+ /**
106
+ * Convert RGB data to raw image bytes (not Base64).
107
+ *
108
+ * @param rgbData RGB data as byte array
109
+ * @param width Image width
110
+ * @param height Image height
111
+ * @param format Target image format
112
+ * @param quality Compression quality for JPEG
113
+ * @return Raw image bytes, or null if encoding fails
114
+ */
115
+ fun rgbToImageBytes(
116
+ rgbData: ByteArray,
117
+ width: Int,
118
+ height: Int,
119
+ format: ImageFormat = ImageFormat.JPEG,
120
+ quality: Int = 85
121
+ ): ByteArray? {
122
+ return try {
123
+ validateImageDimensions(width, height)
124
+ validateRgbData(rgbData, width, height)
125
+
126
+ 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)
131
+ }
132
+ bitmap.recycle()
133
+ imageBytes
134
+ } catch (e: Exception) {
135
+ Log.e(TAG, "Failed to convert RGB to ${format.name} bytes: ${e.message}", e)
136
+ null
137
+ }
138
+ }
139
+
140
+ /**
141
+ * Get optimal image format based on use case.
142
+ * Returns format recommendation for face recognition systems.
143
+ *
144
+ * @param useCase One of: "network" (JPEG), "storage" (PNG), "opencv" (JPEG)
145
+ * @return Recommended ImageFormat
146
+ */
147
+ fun getOptimalFormat(useCase: String = "network"): ImageFormat {
148
+ return when (useCase.lowercase()) {
149
+ "network" -> ImageFormat.JPEG // Smaller size for transmission
150
+ "storage" -> ImageFormat.PNG // Lossless for long-term storage
151
+ "opencv" -> ImageFormat.JPEG // OpenCV optimized
152
+ else -> ImageFormat.JPEG
153
+ }
154
+ }
155
+
156
+ /**
157
+ * Get estimated output size for given resolution and format.
158
+ * Helps with memory allocation and network planning.
159
+ *
160
+ * @param width Image width
161
+ * @param height Image height
162
+ * @param format Image format
163
+ * @param quality JPEG quality if applicable
164
+ * @return Estimated size in bytes
165
+ */
166
+ fun estimateOutputSize(
167
+ width: Int,
168
+ height: Int,
169
+ format: ImageFormat = ImageFormat.JPEG,
170
+ quality: Int = 85
171
+ ): Long {
172
+ val pixelCount = width.toLong() * height
173
+ return when (format) {
174
+ ImageFormat.JPEG -> {
175
+ // Estimated: 0.1 - 0.15 bytes per pixel at quality 85
176
+ (pixelCount * 0.12).toLong()
177
+ }
178
+ ImageFormat.PNG -> {
179
+ // PNG typically 2-4x larger than JPEG
180
+ (pixelCount * 0.5).toLong()
181
+ }
182
+ ImageFormat.BMP -> {
183
+ // BMP uncompressed: 3 bytes per pixel
184
+ pixelCount * 3
185
+ }
186
+ }
187
+ }
188
+
189
+ /**
190
+ * Get format information string for logging.
191
+ */
192
+ fun getFormatInfo(format: ImageFormat, width: Int, height: Int, quality: Int = 85): String {
193
+ val estimatedSize = estimateOutputSize(width, height, format, quality)
194
+ return "${format.name} (${width}×${height}) est. ${estimatedSize / 1024}KB"
195
+ }
196
+
197
+ // ============ Private Helper Methods ============
198
+
199
+ /**
200
+ * Create Bitmap from RGB byte array.
201
+ * RGB format: RGBRGBRGB... (3 bytes per pixel, no alpha)
202
+ */
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
212
+ }
213
+ return Bitmap.createBitmap(pixels, width, height, Bitmap.Config.ARGB_8888)
214
+ }
215
+
216
+ /**
217
+ * Compress Bitmap to specified format bytes.
218
+ */
219
+ private fun compressBitmapToBytes(
220
+ bitmap: Bitmap,
221
+ format: ImageFormat,
222
+ quality: Int
223
+ ): ByteArray {
224
+ val outputStream = ByteArrayOutputStream()
225
+ bitmap.compress(format.compressFormat, quality, outputStream)
226
+ return outputStream.toByteArray()
227
+ }
228
+
229
+ /**
230
+ * Validate image dimensions are within reasonable bounds.
231
+ */
232
+ private fun validateImageDimensions(width: Int, height: Int) {
233
+ require(width > 0 && width <= 4096) { "Image width must be 1-4096 pixels, got $width" }
234
+ require(height > 0 && height <= 4096) { "Image height must be 1-4096 pixels, got $height" }
235
+ }
236
+
237
+ /**
238
+ * Validate RGB data buffer is correct size.
239
+ * RGB format requires exactly width * height * 3 bytes
240
+ */
241
+ private fun validateRgbData(rgbData: ByteArray, width: Int, height: Int) {
242
+ val expectedSize = width * height * 3
243
+ require(rgbData.size >= expectedSize) {
244
+ "RGB data size mismatch: expected $expectedSize bytes for ${width}×${height}, got ${rgbData.size}"
245
+ }
246
+ }
247
+ }