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.
- package/android/.cxx/Debug/2a1it684/arm64-v8a/.cmake/api/v1/reply/{codemodel-v2-6c7de80461af72f456a3.json → codemodel-v2-390962e2784a6a84fa3e.json} +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
- package/android/.cxx/Debug/2a1it684/arm64-v8a/.cmake/api/v1/reply/{target-yuv-Debug-32bc4eddd343848e1c25.json → target-yuv-Debug-1e27b8a2bdcddd47b87d.json} +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
- package/android/.cxx/Debug/2a1it684/arm64-v8a/.ninja_deps +0 -0
- package/android/.cxx/Debug/2a1it684/arm64-v8a/.ninja_log +125 -63
- package/android/.cxx/Debug/2a1it684/arm64-v8a/CMakeFiles/CMakeOutput.log +22 -22
- package/android/.cxx/Debug/2a1it684/arm64-v8a/configure_fingerprint.bin +15 -15
- package/android/.cxx/Debug/2a1it684/armeabi-v7a/.cmake/api/v1/reply/{codemodel-v2-52ac1d8b40b69596389b.json → codemodel-v2-053850119b681f93cecc.json} +2 -2
- 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
- package/android/.cxx/Debug/2a1it684/armeabi-v7a/.cmake/api/v1/reply/{target-yuv-Debug-97f9e822dbd84a186d44.json → target-yuv-Debug-a12ad49ff79080871bce.json} +2 -2
- 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
- package/android/.cxx/Debug/2a1it684/armeabi-v7a/.ninja_deps +0 -0
- package/android/.cxx/Debug/2a1it684/armeabi-v7a/.ninja_log +119 -117
- package/android/.cxx/Debug/2a1it684/armeabi-v7a/CMakeFiles/CMakeOutput.log +20 -20
- package/android/.cxx/Debug/2a1it684/armeabi-v7a/configure_fingerprint.bin +15 -15
- package/android/.cxx/Debug/2a1it684/x86/.ninja_deps +0 -0
- package/android/.cxx/Debug/2a1it684/x86/.ninja_log +111 -109
- package/android/.cxx/Debug/2a1it684/x86/CMakeFiles/CMakeOutput.log +20 -20
- package/android/.cxx/Debug/2a1it684/x86/configure_fingerprint.bin +15 -15
- package/android/.cxx/Debug/2a1it684/x86_64/.ninja_deps +0 -0
- package/android/.cxx/Debug/2a1it684/x86_64/.ninja_log +109 -55
- package/android/.cxx/Debug/2a1it684/x86_64/CMakeFiles/CMakeOutput.log +20 -20
- package/android/.cxx/Debug/2a1it684/x86_64/configure_fingerprint.bin +15 -15
- package/android/build/.transforms/4ebf3dd0dca4f83fe1776360e21ded81/transformed/classes/classes_dex/classes.dex +0 -0
- package/android/build/.transforms/c0a07cd9442d741ad3cef3760159211f/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/faceantispoof/AntiSpoofingResult.dex +0 -0
- package/android/build/.transforms/c0a07cd9442d741ad3cef3760159211f/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/faceantispoof/ByteBufferPool$Companion.dex +0 -0
- package/android/build/.transforms/c0a07cd9442d741ad3cef3760159211f/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/faceantispoof/ByteBufferPool.dex +0 -0
- package/android/build/.transforms/c0a07cd9442d741ad3cef3760159211f/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/faceantispoof/FaceAntiSpoofFrameProcessor.dex +0 -0
- package/android/build/.transforms/c0a07cd9442d741ad3cef3760159211f/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/faceantispoof/FaceAntiSpoofingAdvanced$Companion.dex +0 -0
- package/android/build/.transforms/c0a07cd9442d741ad3cef3760159211f/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/faceantispoof/FaceAntiSpoofingAdvanced$EnvironmentAssessment.dex +0 -0
- package/android/build/.transforms/c0a07cd9442d741ad3cef3760159211f/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/faceantispoof/FaceAntiSpoofingAdvanced$SpoofDetectionResult.dex +0 -0
- package/android/build/.transforms/c0a07cd9442d741ad3cef3760159211f/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/faceantispoof/FaceAntiSpoofingAdvanced.dex +0 -0
- package/android/build/.transforms/c0a07cd9442d741ad3cef3760159211f/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/faceantispoof/ImageFormatEncoder$ImageFormat.dex +0 -0
- package/android/build/.transforms/c0a07cd9442d741ad3cef3760159211f/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/faceantispoof/ImageFormatEncoder$WhenMappings.dex +0 -0
- package/android/build/.transforms/c0a07cd9442d741ad3cef3760159211f/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/faceantispoof/ImageFormatEncoder.dex +0 -0
- package/android/build/.transforms/c0a07cd9442d741ad3cef3760159211f/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/faceantispoof/JpegEncoder$Companion.dex +0 -0
- package/android/build/.transforms/c0a07cd9442d741ad3cef3760159211f/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/faceantispoof/JpegEncoder.dex +0 -0
- package/android/build/.transforms/c0a07cd9442d741ad3cef3760159211f/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/faceantispoof/YuvToFloatArrayConverter.dex +0 -0
- package/android/build/intermediates/compile_library_classes_jar/debug/bundleLibCompileToJarDebug/classes.jar +0 -0
- package/android/build/intermediates/cxx/Debug/2a1it684/logs/arm64-v8a/build_stdout_targets.txt +62 -1
- package/android/build/intermediates/cxx/Debug/2a1it684/logs/arm64-v8a/generate_cxx_metadata_2655_timing.txt +9 -0
- package/android/build/intermediates/cxx/Debug/2a1it684/logs/armeabi-v7a/build_stdout_targets.txt +58 -1
- package/android/build/intermediates/cxx/Debug/2a1it684/logs/armeabi-v7a/{generate_cxx_metadata_2399_timing.txt → generate_cxx_metadata_2653_timing.txt} +1 -1
- package/android/build/intermediates/cxx/Debug/2a1it684/logs/x86/build_stdout_targets.txt +54 -1
- 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
- package/android/build/intermediates/cxx/Debug/2a1it684/logs/x86_64/build_stdout_targets.txt +54 -1
- package/android/build/intermediates/cxx/Debug/2a1it684/logs/x86_64/generate_cxx_metadata_2653_timing.txt +9 -0
- package/android/build/intermediates/incremental/debug/packageDebugResources/compile-file-map.properties +1 -1
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/faceantispoof/AntiSpoofingResult.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/faceantispoof/ByteBufferPool$Companion.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/faceantispoof/ByteBufferPool.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/faceantispoof/FaceAntiSpoofFrameProcessor.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/faceantispoof/FaceAntiSpoofingAdvanced$Companion.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/faceantispoof/FaceAntiSpoofingAdvanced$EnvironmentAssessment.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/faceantispoof/FaceAntiSpoofingAdvanced$SpoofDetectionResult.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/faceantispoof/FaceAntiSpoofingAdvanced.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/faceantispoof/ImageFormatEncoder$ImageFormat.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/faceantispoof/ImageFormatEncoder$WhenMappings.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/faceantispoof/ImageFormatEncoder.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/faceantispoof/JpegEncoder$Companion.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/faceantispoof/JpegEncoder.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/faceantispoof/YuvToFloatArrayConverter.class +0 -0
- package/android/build/intermediates/runtime_library_classes_jar/debug/bundleLibRuntimeToJarDebug/classes.jar +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/inputs/source-to-output.tab +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/inputs/source-to-output.tab.keystream +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/inputs/source-to-output.tab.keystream.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/inputs/source-to-output.tab.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/inputs/source-to-output.tab.values.at +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/inputs/source-to-output.tab_i +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab.keystream +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab.keystream.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab.values.at +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab_i +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab.keystream +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab.keystream.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab.values.at +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab_i +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/constants.tab +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/constants.tab.values.at +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab.keystream +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab.keystream.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab.values.at +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab_i +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab.keystream +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab.keystream.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab.values.at +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab_i +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab.keystream +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab.keystream.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab.values.at +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab_i +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/subtypes.tab +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/subtypes.tab.keystream +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/subtypes.tab.keystream.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/subtypes.tab.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/subtypes.tab.values.at +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/subtypes.tab_i +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/supertypes.tab +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/supertypes.tab.keystream +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/supertypes.tab.keystream.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/supertypes.tab.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/supertypes.tab.values.at +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/supertypes.tab_i +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/counters.tab +1 -1
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/file-to-id.tab +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/file-to-id.tab.keystream +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/file-to-id.tab.keystream.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/file-to-id.tab.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/file-to-id.tab.values.at +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/file-to-id.tab_i +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/id-to-file.tab +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/id-to-file.tab.keystream +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/id-to-file.tab.keystream.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/id-to-file.tab.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/id-to-file.tab.values.at +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/id-to-file.tab_i +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab.keystream +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab.keystream.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab.values.at +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab_i +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/last-build.bin +0 -0
- package/android/build/kotlin/compileDebugKotlin/classpath-snapshot/shrunk-classpath-snapshot.bin +0 -0
- package/android/build/kotlin/compileDebugKotlin/local-state/build-history.bin +0 -0
- package/android/build/tmp/kotlin-classes/debug/com/faceantispoof/AntiSpoofingResult.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/com/faceantispoof/ByteBufferPool$Companion.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/com/faceantispoof/ByteBufferPool.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/com/faceantispoof/FaceAntiSpoofFrameProcessor.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/com/faceantispoof/FaceAntiSpoofingAdvanced$Companion.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/com/faceantispoof/FaceAntiSpoofingAdvanced$EnvironmentAssessment.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/com/faceantispoof/FaceAntiSpoofingAdvanced$SpoofDetectionResult.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/com/faceantispoof/FaceAntiSpoofingAdvanced.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/com/faceantispoof/ImageFormatEncoder$ImageFormat.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/com/faceantispoof/ImageFormatEncoder$WhenMappings.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/com/faceantispoof/ImageFormatEncoder.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/com/faceantispoof/JpegEncoder$Companion.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/com/faceantispoof/JpegEncoder.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/com/faceantispoof/YuvToFloatArrayConverter.class +0 -0
- package/android/src/main/java/com/faceantispoof/ByteBufferPool.kt +68 -0
- package/android/src/main/java/com/faceantispoof/FaceAntiSpoofFrameProcessor.kt +6 -1
- package/android/src/main/java/com/faceantispoof/FaceAntiSpoofingAdvanced.kt +194 -8
- package/android/src/main/java/com/faceantispoof/ImageFormatEncoder.kt +247 -0
- package/android/src/main/java/com/faceantispoof/JpegEncoder.kt +204 -0
- package/android/src/main/java/com/faceantispoof/YuvToFloatArrayConverter.kt +62 -0
- package/package.json +3 -3
- package/android/build/intermediates/cxx/Debug/2a1it684/logs/arm64-v8a/generate_cxx_metadata_2398_timing.txt +0 -9
- package/android/build/intermediates/cxx/Debug/2a1it684/logs/arm64-v8a/generate_cxx_metadata_2614_timing.txt +0 -9
- package/android/build/intermediates/cxx/Debug/2a1it684/logs/x86/generate_cxx_metadata_2399_timing.txt +0 -3
- package/android/build/intermediates/cxx/Debug/2a1it684/logs/x86/generate_cxx_metadata_2616_timing.txt +0 -3
- package/android/build/intermediates/cxx/Debug/2a1it684/logs/x86_64/generate_cxx_metadata_2399_timing.txt +0 -9
- package/android/build/intermediates/cxx/Debug/2a1it684/logs/x86_64/generate_cxx_metadata_2616_timing.txt +0 -9
- /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
- /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
|
Binary file
|
package/android/build/tmp/kotlin-classes/debug/com/faceantispoof/YuvToFloatArrayConverter.class
CHANGED
|
Binary file
|
|
@@ -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.
|
|
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 =
|
|
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
|
+
}
|