diff --git a/.gitignore b/.gitignore index bf3a8eb..4cbe00a 100644 --- a/.gitignore +++ b/.gitignore @@ -22,4 +22,8 @@ build .idea /app/release/output-metadata.json libsparkyuv.a -jxlcoder/src/main/cpp/sparkyuv \ No newline at end of file +jxlcoder/src/main/cpp/sparkyuv +third_party +/app/src/main/assets/ +/app/release +.kotlin/ \ No newline at end of file diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 670a391..8cf1e29 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -2,7 +2,7 @@ plugins { id("com.android.application") id("org.jetbrains.kotlin.android") id("com.google.devtools.ksp") - id("org.jetbrains.kotlin.plugin.compose") version "2.2.0" + id("org.jetbrains.kotlin.plugin.compose") version "2.2.10" } android { diff --git a/app/src/main/java/com/awxkee/jxlcoder/MainActivity.kt b/app/src/main/java/com/awxkee/jxlcoder/MainActivity.kt index 620e3a8..09f4437 100644 --- a/app/src/main/java/com/awxkee/jxlcoder/MainActivity.kt +++ b/app/src/main/java/com/awxkee/jxlcoder/MainActivity.kt @@ -2,8 +2,10 @@ package com.awxkee.jxlcoder import android.graphics.Bitmap import android.graphics.BitmapFactory +import android.graphics.ColorSpace import android.graphics.Matrix import android.graphics.drawable.Drawable +import android.hardware.DataSpace import android.os.Build import android.os.Bundle import android.util.Log @@ -127,9 +129,8 @@ class MainActivity : ComponentActivity() { buffer4, width = largeImageSize.width / 3, height = largeImageSize.height / 3, - preferredColorConfig = PreferredColorConfig.RGBA_8888, + preferredColorConfig = PreferredColorConfig.RGBA_1010102, com.awxkee.jxlcoder.ScaleMode.FIT, - toneMapper = JxlToneMapper.REC2408, jxlResizeFilter = JxlResizeFilter.LANCZOS ) lifecycleScope.launch { diff --git a/build.gradle.kts b/build.gradle.kts index 8ff6c69..f704665 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,7 +1,7 @@ // Top-level build file where you can add configuration options common to all sub-projects/modules. plugins { - id("com.android.application") version "8.13.0" apply false - id("org.jetbrains.kotlin.android") version "2.2.0" apply false - id("com.android.library") version "8.13.0" apply false - id("com.google.devtools.ksp") version "2.2.0-2.0.2" apply false + id("com.android.application") version "9.0.0" apply false + id("org.jetbrains.kotlin.android") version "2.2.10" apply false + id("com.android.library") version "9.0.0" apply false + id("com.google.devtools.ksp") version "2.3.2" apply false } \ No newline at end of file diff --git a/gradle.properties b/gradle.properties index 7027330..1af28fb 100644 --- a/gradle.properties +++ b/gradle.properties @@ -24,3 +24,13 @@ android.nonTransitiveRClass=true SONATYPE_HOST=CENTRAL_PORTAL SONATYPE_AUTOMATIC_RELEASE=true +android.defaults.buildfeatures.resvalues=true +android.sdk.defaultTargetSdkToCompileSdkIfUnset=false +android.enableAppCompileTimeRClass=false +android.usesSdkInManifest.disallowed=false +android.uniquePackageNames=false +android.dependency.useConstraints=true +android.r8.strictFullModeForKeepRules=false +android.r8.optimizedResourceShrinking=false +android.builtInKotlin=false +android.newDsl=false diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 364a105..9e5471d 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ #Sun Aug 20 15:15:13 GET 2023 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-9.1.0-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/jxlcoder/src/main/cpp/CMakeLists.txt b/jxlcoder/src/main/cpp/CMakeLists.txt index 15a0190..1543939 100644 --- a/jxlcoder/src/main/cpp/CMakeLists.txt +++ b/jxlcoder/src/main/cpp/CMakeLists.txt @@ -22,12 +22,12 @@ add_library(${CMAKE_PROJECT_NAME} SHARED JxlAnimatedDecoderCoordinator.cpp JxlAnimatedEncoderCoordinator.cpp hwy/aligned_allocator.cc hwy/nanobenchmark.cc hwy/per_target.cc hwy/print.cc hwy/targets.cc hwy/timer.cc JXLJpegInterop.cpp EasyGifReader.cpp JXLConventions.cpp - conversion/RgbChannels.cpp colorspaces/ColorMatrix.cpp colorspaces/LogarithmicToneMapper.cpp + conversion/RgbChannels.cpp colorspaces/ColorMatrix.cpp colorspaces/Rec2408ToneMapper.cpp colorspaces/Trc.cpp imagebit/CopyUnalignedRGBA.cpp imagebit/half.cpp imagebit/Rgb565.cpp imagebit/Rgb1010102.cpp imagebit/Rgba8ToF16.cpp imagebit/Rgba16.cpp imagebit/RgbaF16bitNBitU8.cpp imagebit/RgbaF16bitToNBitU16.cpp - imagebit/RGBAlpha.cpp imagebit/RgbaU16toHF.cpp imagebit/ScanAlpha.cpp colorspaces/FilmicToneMapper.cpp - imagebit/RgbaToRgb.cpp colorspaces/AcesToneMapper.cpp + imagebit/RGBAlpha.cpp imagebit/RgbaU16toHF.cpp imagebit/ScanAlpha.cpp + imagebit/RgbaToRgb.cpp NativeColorSpace.cpp ) set_target_properties(jxlcoder libweaver PROPERTIES IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/lib/${ANDROID_ABI}/libweaver.a) diff --git a/jxlcoder/src/main/cpp/JniDecoding.cpp b/jxlcoder/src/main/cpp/JniDecoding.cpp index 73ce5f4..c1649f4 100644 --- a/jxlcoder/src/main/cpp/JniDecoding.cpp +++ b/jxlcoder/src/main/cpp/JniDecoding.cpp @@ -40,18 +40,17 @@ #include "colorspaces/ColorSpaceProfile.h" #include "hwy/highway.h" #include "imagebit/CopyUnalignedRGBA.h" +#include "NativeColorSpace.h" jobject decodeSampledImageImpl(JNIEnv *env, std::vector &imageData, jint scaledWidth, jint scaledHeight, jint javaPreferredColorConfig, - jint javaScaleMode, jint javaResizeFilter, jint javaToneMapper) { + jint javaScaleMode, jint javaResizeFilter) { ScaleMode scaleMode; PreferredColorConfig preferredColorConfig; XSampler sampler; - CurveToneMapper toneMapper; if (!checkDecodePreconditions(env, javaPreferredColorConfig, &preferredColorConfig, - javaScaleMode, &scaleMode, javaResizeFilter, &sampler, - javaToneMapper, &toneMapper)) { + javaScaleMode, &scaleMode, javaResizeFilter, &sampler)) { return nullptr; } @@ -136,31 +135,33 @@ jobject decodeSampledImageImpl(JNIEnv *env, std::vector &imageData, jin } } + bool toneMap = true; + if (preferEncoding && (colorEncoding.transfer_function == JXL_TRANSFER_FUNCTION_PQ || colorEncoding.transfer_function == JXL_TRANSFER_FUNCTION_HLG || colorEncoding.transfer_function == JXL_TRANSFER_FUNCTION_DCI || colorEncoding.transfer_function == JXL_TRANSFER_FUNCTION_709 || colorEncoding.transfer_function == JXL_TRANSFER_FUNCTION_GAMMA || colorEncoding.transfer_function == JXL_TRANSFER_FUNCTION_SRGB) - && colorEncoding.color_space == JXL_COLOR_SPACE_RGB) { + && colorEncoding.color_space == JXL_COLOR_SPACE_RGB && osVersion < 34) { Eigen::Matrix3f sourceProfile; TransferFunction transferFunction = TransferFunction::Srgb; if (colorEncoding.transfer_function == JXL_TRANSFER_FUNCTION_HLG) { transferFunction = TransferFunction::Hlg; } else if (colorEncoding.transfer_function == JXL_TRANSFER_FUNCTION_DCI) { - toneMapper = TONE_SKIP; + toneMap = false; transferFunction = TransferFunction::Smpte428; } else if (colorEncoding.transfer_function == JXL_TRANSFER_FUNCTION_PQ) { transferFunction = TransferFunction::Pq; } else if (colorEncoding.transfer_function == JXL_TRANSFER_FUNCTION_GAMMA) { - toneMapper = TONE_SKIP; + toneMap = false; // Make real gamma transferFunction = TransferFunction::Gamma2p2; } else if (colorEncoding.transfer_function == JXL_TRANSFER_FUNCTION_709) { - toneMapper = TONE_SKIP; + toneMap = false; transferFunction = TransferFunction::Itur709; } else if (colorEncoding.transfer_function == JXL_TRANSFER_FUNCTION_SRGB) { - toneMapper = TONE_SKIP; + toneMap = false; transferFunction = TransferFunction::Srgb; } @@ -210,7 +211,7 @@ jobject decodeSampledImageImpl(JNIEnv *env, std::vector &imageData, jin matrix, transferFunction, TransferFunction::Srgb, - toneMapper, + toneMap, coeffs, intensityTarget); } else { @@ -221,7 +222,7 @@ jobject decodeSampledImageImpl(JNIEnv *env, std::vector &imageData, jin matrix, transferFunction, TransferFunction::Srgb, - toneMapper, + toneMap, coeffs, intensityTarget); } } @@ -232,15 +233,33 @@ jobject decodeSampledImageImpl(JNIEnv *env, std::vector &imageData, jin finalWidth, finalHeight, &stride, &useBitmapFloats, &hwBuffer, alphaPremultiplied, hasAlphaInOrigin); + jobject colorSpace = nullptr; + if (androidOSVersion() >= 34) { + if (colorEncoding.primaries == JXL_PRIMARIES_2100 && colorEncoding.transfer_function == JXL_TRANSFER_FUNCTION_PQ) { + colorSpace = colorspace::getJNIColorSpace(env, NativeColorSpace::Pq2100); + } else if (colorEncoding.primaries == JXL_PRIMARIES_2100 && colorEncoding.transfer_function == JXL_TRANSFER_FUNCTION_HLG) { + colorSpace = colorspace::getJNIColorSpace(env, NativeColorSpace::Hlg2100); + } else if (colorEncoding.primaries == JXL_PRIMARIES_P3 && colorEncoding.transfer_function == JXL_TRANSFER_FUNCTION_SRGB) { + colorSpace = colorspace::getJNIColorSpace(env, NativeColorSpace::DisplayP3); + } else if (colorEncoding.primaries == JXL_PRIMARIES_SRGB && colorEncoding.transfer_function == JXL_TRANSFER_FUNCTION_LINEAR) { + colorSpace = colorspace::getJNIColorSpace(env, NativeColorSpace::LinearSrgb); + } else if (colorEncoding.primaries == JXL_PRIMARIES_P3 && colorEncoding.transfer_function == JXL_TRANSFER_FUNCTION_DCI) { + colorSpace = colorspace::getJNIColorSpace(env, NativeColorSpace::DciP3); + } else if (colorEncoding.primaries == JXL_PRIMARIES_SRGB && colorEncoding.transfer_function == JXL_TRANSFER_FUNCTION_709) { + colorSpace = colorspace::getJNIColorSpace(env, NativeColorSpace::Hlg2100); + } else { + colorSpace = colorspace::getJNIColorSpace(env, NativeColorSpace::DefaultSrgb); + } + } + if (bitmapPixelConfig == "HARDWARE") { jclass bitmapClass = env->FindClass("android/graphics/Bitmap"); jmethodID createBitmapMethodID = env->GetStaticMethodID(bitmapClass, "wrapHardwareBuffer", "(Landroid/hardware/HardwareBuffer;Landroid/graphics/ColorSpace;)Landroid/graphics/Bitmap;"); - jobject emptyObject = nullptr; jobject bitmapObj = env->CallStaticObjectMethod(bitmapClass, createBitmapMethodID, - hwBuffer, emptyObject); + hwBuffer, colorSpace); return bitmapObj; } @@ -251,13 +270,24 @@ jobject decodeSampledImageImpl(JNIEnv *env, std::vector &imageData, jin jobject rgba8888Obj = env->GetStaticObjectField(bitmapConfig, rgba8888FieldID); jclass bitmapClass = env->FindClass("android/graphics/Bitmap"); - jmethodID createBitmapMethodID = env->GetStaticMethodID(bitmapClass, - "createBitmap", - "(IILandroid/graphics/Bitmap$Config;)Landroid/graphics/Bitmap;"); - jobject bitmapObj = env->CallStaticObjectMethod(bitmapClass, createBitmapMethodID, - static_cast(finalWidth), - static_cast(finalHeight), - rgba8888Obj); + jobject bitmapObj; + if (androidOSVersion() >= 34 && colorSpace) { + jmethodID createBitmapMethodID = env->GetStaticMethodID(bitmapClass, + "createBitmap", + "(IILandroid/graphics/Bitmap$Config;ZLandroid/graphics/ColorSpace;)Landroid/graphics/Bitmap;"); + bitmapObj = env->CallStaticObjectMethod(bitmapClass, createBitmapMethodID, + static_cast(finalWidth), + static_cast(finalHeight), + rgba8888Obj, true, colorSpace); + } else { + jmethodID createBitmapMethodID = env->GetStaticMethodID(bitmapClass, + "createBitmap", + "(IILandroid/graphics/Bitmap$Config;)Landroid/graphics/Bitmap;"); + bitmapObj = env->CallStaticObjectMethod(bitmapClass, createBitmapMethodID, + static_cast(finalWidth), + static_cast(finalHeight), + rgba8888Obj); + } AndroidBitmapInfo info; if (AndroidBitmap_getInfo(env, bitmapObj, &info) < 0) { @@ -307,8 +337,7 @@ Java_com_awxkee_jxlcoder_JxlCoder_decodeSampledImpl(JNIEnv *env, jobject thiz, jint scaledHeight, jint javaPreferredColorConfig, jint javaScaleMode, - jint resizeSampler, - jint javaToneMapper) { + jint resizeSampler) { try { auto totalLength = env->GetArrayLength(byte_array); std::vector srcBuffer(totalLength); @@ -316,7 +345,7 @@ Java_com_awxkee_jxlcoder_JxlCoder_decodeSampledImpl(JNIEnv *env, jobject thiz, reinterpret_cast(srcBuffer.data())); return decodeSampledImageImpl(env, srcBuffer, scaledWidth, scaledHeight, javaPreferredColorConfig, javaScaleMode, - resizeSampler, javaToneMapper); + resizeSampler); } catch (std::bad_alloc &err) { std::string errorString = "Not enough memory to decode this image"; throwException(env, errorString); @@ -336,8 +365,7 @@ Java_com_awxkee_jxlcoder_JxlCoder_decodeByteBufferSampledImpl(JNIEnv *env, jobje jint scaledHeight, jint preferredColorConfig, jint scaleMode, - jint resizeSampler, - jint javaToneMapper) { + jint resizeSampler) { try { auto bufferAddress = reinterpret_cast(env->GetDirectBufferAddress(byteBuffer)); int length = (int) env->GetDirectBufferCapacity(byteBuffer); @@ -350,7 +378,7 @@ Java_com_awxkee_jxlcoder_JxlCoder_decodeByteBufferSampledImpl(JNIEnv *env, jobje std::copy(bufferAddress, bufferAddress + length, srcBuffer.begin()); return decodeSampledImageImpl(env, srcBuffer, scaledWidth, scaledHeight, preferredColorConfig, scaleMode, - resizeSampler, javaToneMapper); + resizeSampler); } catch (std::bad_alloc &err) { std::string errorString = "Not enough memory to decode this image"; throwException(env, errorString); diff --git a/jxlcoder/src/main/cpp/JxlAnimatedDecoderCoordinator.cpp b/jxlcoder/src/main/cpp/JxlAnimatedDecoderCoordinator.cpp index cd86f56..93276f0 100644 --- a/jxlcoder/src/main/cpp/JxlAnimatedDecoderCoordinator.cpp +++ b/jxlcoder/src/main/cpp/JxlAnimatedDecoderCoordinator.cpp @@ -38,6 +38,7 @@ #include "hwy/highway.h" #include "colorspaces/ColorSpaceProfile.h" #include "imagebit/CopyUnalignedRGBA.h" +#include "NativeColorSpace.h" using namespace std; @@ -47,15 +48,12 @@ Java_com_awxkee_jxlcoder_JxlAnimatedImage_createCoordinator(JNIEnv *env, jobject jobject byteBuffer, jint javaPreferredColorConfig, jint javaScaleMode, - jint javaJxlResizeSampler, - jint javaToneMapper) { + jint javaJxlResizeSampler) { ScaleMode scaleMode; PreferredColorConfig preferredColorConfig; XSampler sampler; - CurveToneMapper toneMapper; if (!checkDecodePreconditions(env, javaPreferredColorConfig, &preferredColorConfig, - javaScaleMode, &scaleMode, javaJxlResizeSampler, &sampler, - javaToneMapper, &toneMapper)) { + javaScaleMode, &scaleMode, javaJxlResizeSampler, &sampler)) { return 0; } @@ -78,7 +76,7 @@ Java_com_awxkee_jxlcoder_JxlAnimatedImage_createCoordinator(JNIEnv *env, jobject copy(bufferAddress, bufferAddress + length, srcBuffer.begin()); auto decoder = new JxlAnimatedDecoder(srcBuffer); auto coordinator = new JxlAnimatedDecoderCoordinator( - decoder, scaleMode, preferredColorConfig, sampler, toneMapper + decoder, scaleMode, preferredColorConfig, sampler ); return reinterpret_cast(coordinator); } catch (AnimatedDecoderError &err) { @@ -98,15 +96,12 @@ Java_com_awxkee_jxlcoder_JxlAnimatedImage_createCoordinatorByteArray(JNIEnv *env jbyteArray byteArray, jint javaPreferredColorConfig, jint javaScaleMode, - jint javaJxlResizeSampler, - jint javaToneMapper) { + jint javaJxlResizeSampler) { ScaleMode scaleMode; PreferredColorConfig preferredColorConfig; XSampler sampler; - CurveToneMapper toneMapper; if (!checkDecodePreconditions(env, javaPreferredColorConfig, &preferredColorConfig, - javaScaleMode, &scaleMode, javaJxlResizeSampler, &sampler, - javaToneMapper, &toneMapper)) { + javaScaleMode, &scaleMode, javaJxlResizeSampler, &sampler)) { return 0; } @@ -117,7 +112,7 @@ Java_com_awxkee_jxlcoder_JxlAnimatedImage_createCoordinatorByteArray(JNIEnv *env reinterpret_cast(srcBuffer.data())); auto decoder = new JxlAnimatedDecoder(srcBuffer); auto coordinator = new JxlAnimatedDecoderCoordinator( - decoder, scaleMode, preferredColorConfig, sampler, toneMapper + decoder, scaleMode, preferredColorConfig, sampler ); return reinterpret_cast(coordinator); } catch (AnimatedDecoderError &err) { @@ -181,6 +176,8 @@ Java_com_awxkee_jxlcoder_JxlAnimatedImage_getFrameImpl(JNIEnv *env, jobject thiz auto preferEncoding = frame.preferColorEncoding; auto colorEncoding = frame.colorEncoding; + int osVersion = androidOSVersion(); + uint32_t stride = coordinator->getWidth() * 4 * static_cast(useFloat16 ? sizeof(uint16_t) : sizeof(uint8_t)); if (preferEncoding && (colorEncoding.transfer_function == JXL_TRANSFER_FUNCTION_PQ || @@ -189,29 +186,29 @@ Java_com_awxkee_jxlcoder_JxlAnimatedImage_getFrameImpl(JNIEnv *env, jobject thiz colorEncoding.transfer_function == JXL_TRANSFER_FUNCTION_709 || colorEncoding.transfer_function == JXL_TRANSFER_FUNCTION_GAMMA || colorEncoding.transfer_function == JXL_TRANSFER_FUNCTION_SRGB) - && colorEncoding.color_space == JXL_COLOR_SPACE_RGB) { + && colorEncoding.color_space == JXL_COLOR_SPACE_RGB && osVersion < 34) { Eigen::Matrix3f sourceProfile; TransferFunction transferFunction = TransferFunction::Srgb; - CurveToneMapper toneMapper = CurveToneMapper::TONE_SKIP; + bool tonemap = true; bool useChromaticAdaptation = false; float gamma = 2.2f; if (colorEncoding.transfer_function == JXL_TRANSFER_FUNCTION_HLG) { transferFunction = TransferFunction::Hlg; } else if (colorEncoding.transfer_function == JXL_TRANSFER_FUNCTION_DCI) { - toneMapper = TONE_SKIP; + tonemap = false; transferFunction = TransferFunction::Smpte428; } else if (colorEncoding.transfer_function == JXL_TRANSFER_FUNCTION_PQ) { transferFunction = TransferFunction::Pq; } else if (colorEncoding.transfer_function == JXL_TRANSFER_FUNCTION_GAMMA) { - toneMapper = TONE_SKIP; + tonemap = false; // Make real gamma transferFunction = TransferFunction::Gamma2p2; gamma = 1.f / colorEncoding.gamma; } else if (colorEncoding.transfer_function == JXL_TRANSFER_FUNCTION_709) { - toneMapper = TONE_SKIP; + tonemap = false; transferFunction = TransferFunction::Itur709; } else if (colorEncoding.transfer_function == JXL_TRANSFER_FUNCTION_SRGB) { - toneMapper = TONE_SKIP; + tonemap = false; transferFunction = TransferFunction::Srgb; } @@ -263,7 +260,7 @@ Java_com_awxkee_jxlcoder_JxlAnimatedImage_getFrameImpl(JNIEnv *env, jobject thiz matrix, transferFunction, TransferFunction::Srgb, - toneMapper, + tonemap, coeffs, 255.); } @@ -302,15 +299,33 @@ Java_com_awxkee_jxlcoder_JxlAnimatedImage_getFrameImpl(JNIEnv *env, jobject thiz finalWidth, finalHeight, &stride, &useFloat16, &hwBuffer, alphaPremultiplied, frame.hasAlphaInOrigin); + jobject colorSpace = nullptr; + if (androidOSVersion() >= 34) { + if (colorEncoding.primaries == JXL_PRIMARIES_2100 && colorEncoding.transfer_function == JXL_TRANSFER_FUNCTION_PQ) { + colorSpace = colorspace::getJNIColorSpace(env, NativeColorSpace::Pq2100); + } else if (colorEncoding.primaries == JXL_PRIMARIES_2100 && colorEncoding.transfer_function == JXL_TRANSFER_FUNCTION_HLG) { + colorSpace = colorspace::getJNIColorSpace(env, NativeColorSpace::Hlg2100); + } else if (colorEncoding.primaries == JXL_PRIMARIES_P3 && colorEncoding.transfer_function == JXL_TRANSFER_FUNCTION_SRGB) { + colorSpace = colorspace::getJNIColorSpace(env, NativeColorSpace::DisplayP3); + } else if (colorEncoding.primaries == JXL_PRIMARIES_SRGB && colorEncoding.transfer_function == JXL_TRANSFER_FUNCTION_LINEAR) { + colorSpace = colorspace::getJNIColorSpace(env, NativeColorSpace::LinearSrgb); + } else if (colorEncoding.primaries == JXL_PRIMARIES_P3 && colorEncoding.transfer_function == JXL_TRANSFER_FUNCTION_DCI) { + colorSpace = colorspace::getJNIColorSpace(env, NativeColorSpace::DciP3); + } else if (colorEncoding.primaries == JXL_PRIMARIES_SRGB && colorEncoding.transfer_function == JXL_TRANSFER_FUNCTION_709) { + colorSpace = colorspace::getJNIColorSpace(env, NativeColorSpace::Hlg2100); + } else { + colorSpace = colorspace::getJNIColorSpace(env, NativeColorSpace::DefaultSrgb); + } + } + if (bitmapPixelConfig == "HARDWARE") { jclass bitmapClass = env->FindClass("android/graphics/Bitmap"); jmethodID createBitmapMethodID = env->GetStaticMethodID(bitmapClass, "wrapHardwareBuffer", "(Landroid/hardware/HardwareBuffer;Landroid/graphics/ColorSpace;)Landroid/graphics/Bitmap;"); - jobject emptyObject = nullptr; jobject bitmapObj = env->CallStaticObjectMethod(bitmapClass, createBitmapMethodID, - hwBuffer, emptyObject); + hwBuffer, colorSpace); return bitmapObj; } @@ -321,12 +336,24 @@ Java_com_awxkee_jxlcoder_JxlAnimatedImage_getFrameImpl(JNIEnv *env, jobject thiz jobject rgba8888Obj = env->GetStaticObjectField(bitmapConfig, rgba8888FieldID); jclass bitmapClass = env->FindClass("android/graphics/Bitmap"); - jmethodID createBitmapMethodID = env->GetStaticMethodID(bitmapClass, "createBitmap", - "(IILandroid/graphics/Bitmap$Config;)Landroid/graphics/Bitmap;"); - jobject bitmapObj = env->CallStaticObjectMethod(bitmapClass, createBitmapMethodID, - static_cast(finalWidth), - static_cast(finalHeight), - rgba8888Obj); + jobject bitmapObj; + if (androidOSVersion() >= 34 && colorSpace) { + jmethodID createBitmapMethodID = env->GetStaticMethodID(bitmapClass, + "createBitmap", + "(IILandroid/graphics/Bitmap$Config;ZLandroid/graphics/ColorSpace;)Landroid/graphics/Bitmap;"); + bitmapObj = env->CallStaticObjectMethod(bitmapClass, createBitmapMethodID, + static_cast(finalWidth), + static_cast(finalHeight), + rgba8888Obj, true, colorSpace); + } else { + jmethodID createBitmapMethodID = env->GetStaticMethodID(bitmapClass, + "createBitmap", + "(IILandroid/graphics/Bitmap$Config;)Landroid/graphics/Bitmap;"); + bitmapObj = env->CallStaticObjectMethod(bitmapClass, createBitmapMethodID, + static_cast(finalWidth), + static_cast(finalHeight), + rgba8888Obj); + } AndroidBitmapInfo info; if (AndroidBitmap_getInfo(env, bitmapObj, &info) < 0) { diff --git a/jxlcoder/src/main/cpp/JxlAnimatedDecoderCoordinator.h b/jxlcoder/src/main/cpp/JxlAnimatedDecoderCoordinator.h index a5aa0c5..70c0bc5 100644 --- a/jxlcoder/src/main/cpp/JxlAnimatedDecoderCoordinator.h +++ b/jxlcoder/src/main/cpp/JxlAnimatedDecoderCoordinator.h @@ -42,10 +42,10 @@ class JxlAnimatedDecoderCoordinator { JxlAnimatedDecoderCoordinator(JxlAnimatedDecoder *decoder, ScaleMode scaleMode, PreferredColorConfig preferredColorConfig, - XSampler sample, CurveToneMapper curveToneMapper) : + XSampler sample) : decoder(decoder), scaleMode(scaleMode), preferredColorConfig(preferredColorConfig), - sampler(sample), toneMapper(curveToneMapper) { + sampler(sample) { } @@ -69,10 +69,6 @@ class JxlAnimatedDecoderCoordinator { return decoder->nextFrame(); } - CurveToneMapper getToneMapper() { - return toneMapper; - } - ~JxlAnimatedDecoderCoordinator() { if (decoder) { delete decoder; @@ -109,7 +105,6 @@ class JxlAnimatedDecoderCoordinator { ScaleMode scaleMode; PreferredColorConfig preferredColorConfig; XSampler sampler; - CurveToneMapper toneMapper; }; #endif //JXLCODER_JXLANIMATEDDECODERCOORDINATOR_H diff --git a/jxlcoder/src/main/cpp/NativeColorSpace.cpp b/jxlcoder/src/main/cpp/NativeColorSpace.cpp new file mode 100644 index 0000000..733c371 --- /dev/null +++ b/jxlcoder/src/main/cpp/NativeColorSpace.cpp @@ -0,0 +1,69 @@ +// +// Created by Radzivon Bartoshyk on 28/01/2026. +// + +#include +#include +#include + +namespace colorspace { +jobject searchForNamed(JNIEnv *env, std::string &named) { + jclass bitmapCls = env->FindClass("android/graphics/Bitmap"); + jclass csCls = env->FindClass("android/graphics/ColorSpace"); + jclass csNamedCls = env->FindClass("android/graphics/ColorSpace$Named"); + +// Get BT2020_PQ enum + jfieldID pqField = env->GetStaticFieldID( + csNamedCls, named.c_str(), "Landroid/graphics/ColorSpace$Named;" + ); + jobject pqEnum = env->GetStaticObjectField(csNamedCls, pqField); + + jmethodID csGet = env->GetStaticMethodID( + csCls, "get", + "(Landroid/graphics/ColorSpace$Named;)Landroid/graphics/ColorSpace;" + ); + jobject pqColorSpace = env->CallStaticObjectMethod(csCls, csGet, pqEnum); + return pqColorSpace; +} + +jobject getJNIColorSpace(JNIEnv *env, NativeColorSpace nativeColorSpace) { + switch (nativeColorSpace) { + case Pq2100: { + std::string name = "BT2020_PQ"; + return searchForNamed(env, name); + break; + } + case Hlg2100: { + std::string name = "BT2020_HLG"; + return searchForNamed(env, name); + break; + } + case DisplayP3: { + std::string name = "DISPLAY_P3"; + return searchForNamed(env, name); + break; + } + case DciP3: { + std::string name = "DCI_P3"; + return searchForNamed(env, name); + break; + } + case LinearSrgb: { + std::string name = "LINEAR_SRGB"; + return searchForNamed(env, name); + break; + } + case Bt709: { + std::string name = "BT709"; + return searchForNamed(env, name); + break; + } + case DefaultSrgb: { + std::string name = "SRGB"; + return searchForNamed(env, name); + break; + } + } + return nullptr; +} +} \ No newline at end of file diff --git a/jxlcoder/src/main/cpp/NativeColorSpace.h b/jxlcoder/src/main/cpp/NativeColorSpace.h new file mode 100644 index 0000000..62a05f6 --- /dev/null +++ b/jxlcoder/src/main/cpp/NativeColorSpace.h @@ -0,0 +1,24 @@ +// +// Created by Radzivon Bartoshyk on 28/01/2026. +// + +#ifndef JXLCODER_JXLCODER_SRC_MAIN_CPP_NATIVECOLORSPACE_H_ +#define JXLCODER_JXLCODER_SRC_MAIN_CPP_NATIVECOLORSPACE_H_ + +#include + +enum NativeColorSpace { + Pq2100, + Hlg2100, + DisplayP3, + DciP3, + LinearSrgb, + Bt709, + DefaultSrgb +}; + +namespace colorspace { +jobject getJNIColorSpace(JNIEnv *env, NativeColorSpace nativeColorSpace); +} + +#endif //JXLCODER_JXLCODER_SRC_MAIN_CPP_NATIVECOLORSPACE_H_ diff --git a/jxlcoder/src/main/cpp/Support.cpp b/jxlcoder/src/main/cpp/Support.cpp index 5e42eb7..507e1f9 100644 --- a/jxlcoder/src/main/cpp/Support.cpp +++ b/jxlcoder/src/main/cpp/Support.cpp @@ -34,7 +34,7 @@ bool checkDecodePreconditions(JNIEnv *env, jint javaColorspace, PreferredColorConfig *config, jint javaScaleMode, ScaleMode *scaleMode, jint javaSampler, - XSampler *sampler, jint javaToneMapper, CurveToneMapper *toneMapper) { + XSampler *sampler) { auto preferredColorConfig = static_cast(javaColorspace); if (!preferredColorConfig) { std::string errorString = @@ -85,17 +85,8 @@ bool checkDecodePreconditions(JNIEnv *env, jint javaColorspace, PreferredColorCo return false; } - auto xToneMapper = static_cast(javaToneMapper); - if (!xToneMapper) { - std::string errorString = - "Invalid Tone Mapper: " + std::to_string(javaToneMapper) + " was passed"; - throwException(env, errorString); - return false; - } - *scaleMode = mScaleMode; *config = preferredColorConfig; *sampler = xSampler; - *toneMapper = xToneMapper; return true; } \ No newline at end of file diff --git a/jxlcoder/src/main/cpp/Support.h b/jxlcoder/src/main/cpp/Support.h index b30f872..52a9bfd 100644 --- a/jxlcoder/src/main/cpp/Support.h +++ b/jxlcoder/src/main/cpp/Support.h @@ -45,6 +45,6 @@ enum PreferredColorConfig { bool checkDecodePreconditions(JNIEnv *env, jint javaColorspace, PreferredColorConfig *config, jint javaScaleMode, ScaleMode *scaleMode, jint javaSampler, - XSampler *sampler, jint javaToneMapper, CurveToneMapper *toneMapper); + XSampler *sampler); #endif //AVIF_SUPPORT_H diff --git a/jxlcoder/src/main/cpp/colorspaces/AcesToneMapper.cpp b/jxlcoder/src/main/cpp/colorspaces/AcesToneMapper.cpp deleted file mode 100644 index bef27d5..0000000 --- a/jxlcoder/src/main/cpp/colorspaces/AcesToneMapper.cpp +++ /dev/null @@ -1,66 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2024 Radzivon Bartoshyk - * jxl-coder [https://github.com/awxkee/jxl-coder] - * - * Created by Radzivon Bartoshyk on 12/11/2024 - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - */ - -#include "AcesToneMapper.h" -#include "colorspaces/Oklab.hpp" -#include - -void AcesToneMapper::transferTone(float *inPlace, uint32_t width) { - float *targetPlace = inPlace; - - for (uint32_t x = 0; x < width; ++x) { - float r = targetPlace[0]; - float g = targetPlace[1]; - float b = targetPlace[2]; - - auto mulInput = [](const coder::Rgb &color) { - float a = 0.59719f * color.r + 0.35458f * color.g + 0.04823f * color.b, - b = 0.07600f * color.r + 0.90834f * color.g + 0.01566f * color.b, - c = 0.02840f * color.r + 0.13383f * color.g + 0.83777f * color.b; - return coder::Rgb(a, b, c); - }; - - auto mulOutput = [](const coder::Rgb &color) { - float a = 1.60475f * color.r - 0.53108f * color.g - 0.07367f * color.b, - b = -0.10208f * color.r + 1.10813f * color.g - 0.00605f * color.b, - c = -0.00327f * color.r - 0.07276f * color.g + 1.07602f * color.b; - return coder::Rgb(a, b, c); - }; - - auto colorIn = mulInput(coder::Rgb(r, g, b)); - auto ca = colorIn * (colorIn + 0.0245786f) - 0.000090537f; - auto cb = colorIn * (0.983729f * colorIn + 0.4329510f) + 0.238081f; - auto cOut = mulOutput(ca / cb); - - targetPlace[0] = std::min(cOut.r, 1.f); - targetPlace[1] = std::min(cOut.g, 1.f); - targetPlace[2] = std::min(cOut.b, 1.f); - - targetPlace += 3; - } -} \ No newline at end of file diff --git a/jxlcoder/src/main/cpp/colorspaces/AcesToneMapper.h b/jxlcoder/src/main/cpp/colorspaces/AcesToneMapper.h deleted file mode 100644 index b596192..0000000 --- a/jxlcoder/src/main/cpp/colorspaces/AcesToneMapper.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2024 Radzivon Bartoshyk - * jxl-coder [https://github.com/awxkee/jxl-coder] - * - * Created by Radzivon Bartoshyk on 12/11/2024 - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - */ - -#ifndef JXLCODER_ACES_H_ -#define JXLCODER_ACES_H_ - -#include - -class AcesToneMapper { - public: - AcesToneMapper() { - - } - - static void transferTone(float *inPlace, uint32_t width); - - private: - - -}; - -#endif //JXLCODER_ACES_H_ diff --git a/jxlcoder/src/main/cpp/colorspaces/ColorMatrix.cpp b/jxlcoder/src/main/cpp/colorspaces/ColorMatrix.cpp index a907d25..5c1955f 100644 --- a/jxlcoder/src/main/cpp/colorspaces/ColorMatrix.cpp +++ b/jxlcoder/src/main/cpp/colorspaces/ColorMatrix.cpp @@ -30,14 +30,11 @@ #include "concurrency.hpp" #include "definitions.h" #include "Rec2408ToneMapper.h" -#include "LogarithmicToneMapper.h" #include "ITUR.h" -#include "FilmicToneMapper.h" -#include "AcesToneMapper.h" void applyColorMatrix(uint8_t *inPlace, uint32_t stride, uint32_t width, uint32_t height, const float *matrix, TransferFunction intoLinear, TransferFunction intoGamma, - CurveToneMapper toneMapper, ITURColorCoefficients coeffs, + bool tonemap, ITURColorCoefficients coeffs, float contentBrightness) { float c0 = matrix[0]; float c1 = matrix[1]; @@ -77,18 +74,9 @@ void applyColorMatrix(uint8_t *inPlace, uint32_t stride, uint32_t width, uint32_ } float mCoeffs[3] = {coeffs.kr, coeffs.kg, coeffs.kb}; - if (toneMapper == CurveToneMapper::REC2408 || toneMapper == CurveToneMapper::REC2408_PERCEPTUAL) { - Rec2408ToneMapper mToneMapper(contentBrightness, 250.f, 203.f, mCoeffs, toneMapper == CurveToneMapper::REC2408_PERCEPTUAL); + if (tonemap) { + Rec2408ToneMapper mToneMapper(contentBrightness, 250.f, 203.f, mCoeffs); mToneMapper.transferTone(rowVector.data(), width); - } else if (toneMapper == CurveToneMapper::LOGARITHMIC) { - LogarithmicToneMapper mToneMapper(mCoeffs); - mToneMapper.transferTone(rowVector.data(), width); - } else if (toneMapper == CurveToneMapper::FILMIC) { - FilmicToneMapper filmicToneMapper; - filmicToneMapper.transferTone(rowVector.data(), width); - } else if (toneMapper == CurveToneMapper::ACES) { - AcesToneMapper acesToneMapper; - acesToneMapper.transferTone(rowVector.data(), width); } float *iter = rowVector.data(); @@ -138,7 +126,7 @@ void applyColorMatrix16Bit(uint16_t *inPlace, const float *matrix, TransferFunction intoLinear, TransferFunction intoGamma, - CurveToneMapper toneMapper, + bool tonemap, ITURColorCoefficients coeffs, float contentBrightness) { @@ -185,18 +173,9 @@ void applyColorMatrix16Bit(uint16_t *inPlace, } float mCoeffs[3] = {coeffs.kr, coeffs.kg, coeffs.kb}; - if (toneMapper == CurveToneMapper::REC2408 || toneMapper == CurveToneMapper::REC2408_PERCEPTUAL) { - Rec2408ToneMapper mToneMapper(contentBrightness, 250.f, 203.f, mCoeffs, toneMapper == CurveToneMapper::REC2408_PERCEPTUAL); - mToneMapper.transferTone(rowVector.data(), width); - } else if (toneMapper == CurveToneMapper::LOGARITHMIC) { - LogarithmicToneMapper mToneMapper(mCoeffs); + if (tonemap) { + Rec2408ToneMapper mToneMapper(contentBrightness, 250.f, 203.f, mCoeffs); mToneMapper.transferTone(rowVector.data(), width); - } else if (toneMapper == CurveToneMapper::FILMIC) { - FilmicToneMapper filmicToneMapper; - filmicToneMapper.transferTone(rowVector.data(), width); - } else if (toneMapper == CurveToneMapper::ACES) { - AcesToneMapper acesToneMapper; - acesToneMapper.transferTone(rowVector.data(), width); } float *iter = rowVector.data(); diff --git a/jxlcoder/src/main/cpp/colorspaces/ColorMatrix.h b/jxlcoder/src/main/cpp/colorspaces/ColorMatrix.h index 039ee8f..156c367 100644 --- a/jxlcoder/src/main/cpp/colorspaces/ColorMatrix.h +++ b/jxlcoder/src/main/cpp/colorspaces/ColorMatrix.h @@ -32,12 +32,11 @@ #include #include #include "Trc.h" -#include "ToneMapper.h" #include "ITUR.h" void applyColorMatrix(uint8_t *inPlace, uint32_t stride, uint32_t width, uint32_t height, const float *matrix, TransferFunction intoLinear, TransferFunction intoGamma, - CurveToneMapper toneMapper, ITURColorCoefficients coeffs, float contentBrightness); + bool tonemap, ITURColorCoefficients coeffs, float contentBrightness); void applyColorMatrix16Bit(uint16_t *inPlace, uint32_t stride, @@ -47,7 +46,7 @@ void applyColorMatrix16Bit(uint16_t *inPlace, const float *matrix, TransferFunction intoLinear, TransferFunction intoGamma, - CurveToneMapper toneMapper, + bool tonemap, ITURColorCoefficients coeffs, float contentBrightness); diff --git a/jxlcoder/src/main/cpp/colorspaces/FilmicToneMapper.cpp b/jxlcoder/src/main/cpp/colorspaces/FilmicToneMapper.cpp deleted file mode 100644 index 1c66108..0000000 --- a/jxlcoder/src/main/cpp/colorspaces/FilmicToneMapper.cpp +++ /dev/null @@ -1,46 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2024 Radzivon Bartoshyk - * jxl-coder [https://github.com/awxkee/jxl-coder] - * - * Created by Radzivon Bartoshyk on 10/11/2024 - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - */ - - -#include "FilmicToneMapper.h" -#include "Oklab.hpp" - -void FilmicToneMapper::transferTone(float *inPlace, uint32_t width) { - float *targetPlace = inPlace; - - for (uint32_t x = 0; x < width; ++x) { - float r = targetPlace[0]; - float g = targetPlace[1]; - float b = targetPlace[2]; - - targetPlace[0] = std::min(FilmicToneMapper::uncharted2_filmic(r), 1.f); - targetPlace[1] = std::min(FilmicToneMapper::uncharted2_filmic(g), 1.f); - targetPlace[2] = std::min(FilmicToneMapper::uncharted2_filmic(b), 1.f); - targetPlace += 3; - } -} \ No newline at end of file diff --git a/jxlcoder/src/main/cpp/colorspaces/FilmicToneMapper.h b/jxlcoder/src/main/cpp/colorspaces/FilmicToneMapper.h deleted file mode 100644 index 34caaad..0000000 --- a/jxlcoder/src/main/cpp/colorspaces/FilmicToneMapper.h +++ /dev/null @@ -1,66 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2024 Radzivon Bartoshyk - * jxl-coder [https://github.com/awxkee/jxl-coder] - * - * Created by Radzivon Bartoshyk on 10/11/2024 - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - */ - -#ifndef AVIF_FILMIC_TONEMAPPER_H_ -#define AVIF_FILMIC_TONEMAPPER_H_ - -#include - -class FilmicToneMapper { - public: - FilmicToneMapper() { - - } - - static void transferTone(float *inPlace, uint32_t width); - - private: - float exposure; - - static float uncharted2_tonemap_partial(float x) { - float A = 0.15f; - float B = 0.50f; - float C = 0.10f; - float D = 0.20f; - float E = 0.02f; - float F = 0.30f; - return ((x * (A * x + C * B) + D * E) / (x * (A * x + B) + D * F)) - E / F; - } - - static float uncharted2_filmic(float v) { - float exposure_bias = 2.0f; - float curr = uncharted2_tonemap_partial(v * exposure_bias); - - float W = 11.2f; - float white_scale = 1.0f / uncharted2_tonemap_partial(W); - return curr * white_scale; - } - -}; - -#endif //AVIF_FILMIC_TONEMAPPER_H_ diff --git a/jxlcoder/src/main/cpp/colorspaces/LogarithmicToneMapper.cpp b/jxlcoder/src/main/cpp/colorspaces/LogarithmicToneMapper.cpp deleted file mode 100644 index 050a1dd..0000000 --- a/jxlcoder/src/main/cpp/colorspaces/LogarithmicToneMapper.cpp +++ /dev/null @@ -1,54 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2024 Radzivon Bartoshyk - * jxl-coder [https://github.com/awxkee/jxl-coder] - * - * Created by Radzivon Bartoshyk on 13/10/2024 - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - */ - -#include "LogarithmicToneMapper.h" -#include "Oklab.hpp" - -void LogarithmicToneMapper::transferTone(float *inPlace, uint32_t width) const { - float *targetPlace = inPlace; - - const float vDen = this->den; - - for (uint32_t x = 0; x < width; ++x) { - float r = targetPlace[0]; - float g = targetPlace[1]; - float b = targetPlace[2]; - coder::Oklab oklab = coder::Oklab::fromLinearRGB(r, g, b); - if (oklab.L == 0) { - continue; - } - float Lout = std::logf(std::abs(1.f + oklab.L)) * vDen; - float shScale = Lout / oklab.L; - oklab.L = oklab.L * shScale; - coder::Rgb linearRgb = oklab.toLinearRGB(); - targetPlace[0] = std::min(linearRgb.r, 1.f); - targetPlace[1] = std::min(linearRgb.g, 1.f); - targetPlace[2] = std::min(linearRgb.b, 1.f); - targetPlace += 3; - } -} \ No newline at end of file diff --git a/jxlcoder/src/main/cpp/colorspaces/LogarithmicToneMapper.h b/jxlcoder/src/main/cpp/colorspaces/LogarithmicToneMapper.h deleted file mode 100644 index 80fc120..0000000 --- a/jxlcoder/src/main/cpp/colorspaces/LogarithmicToneMapper.h +++ /dev/null @@ -1,52 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2024 Radzivon Bartoshyk - * jxl-coder [https://github.com/awxkee/jxl-coder] - * - * Created by Radzivon Bartoshyk on 13/10/2024 - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - */ - -#ifndef AVIF_LOGARITHMICTONEMAPPER_H -#define AVIF_LOGARITHMICTONEMAPPER_H - -#include - -class LogarithmicToneMapper { -public: - LogarithmicToneMapper(const float primaries[3]) { - std::copy(primaries, primaries + 3, lumaPrimaries); - - float Lmax = 1; - float exposure = 1.f; - den = static_cast(1) / log(static_cast(1 + Lmax * exposure)); - } - - void transferTone(float *inPlace, uint32_t width) const; - -private: - float lumaPrimaries[3] = {0}; - float den; -}; - - -#endif //AVIF_LOGARITHMICTONEMAPPER_H diff --git a/jxlcoder/src/main/cpp/colorspaces/Oklab.hpp b/jxlcoder/src/main/cpp/colorspaces/Oklab.hpp deleted file mode 100644 index 64355a1..0000000 --- a/jxlcoder/src/main/cpp/colorspaces/Oklab.hpp +++ /dev/null @@ -1,93 +0,0 @@ -// -// Created by Radzivon Bartoshyk on 10/11/2024. -// - -#ifndef AVIF_OKLAB -#define AVIF_OKLAB - -#include - -namespace coder { -class Rgb { - public: - float r, g, b; - Rgb(float r_, float g_, float b_) : r(r_), g(g_), b(b_) {} - - Rgb operator+(const Rgb& other) const { - return {r + other.r, g + other.g, b + other.b}; - } - Rgb operator-(const Rgb& other) const { - return {r - other.r, g - other.g, b - other.b}; - } - Rgb operator*(const Rgb& other) const { - return {r * other.r, g * other.g, b * other.b}; - } - - Rgb operator/(float scalar) const { - return {r / scalar, g / scalar, b / scalar}; - } - - Rgb operator+(float scalar) const { - return {r + scalar, g + scalar, b + scalar}; - } - - Rgb operator*(float scalar) const { - return {r * scalar, g * scalar, b * scalar}; - } - - friend Rgb operator*(float scalar, const Rgb& color) { - return {color.r * scalar, color.g * scalar, color.b * scalar}; - } - - Rgb operator-(float scalar) const { - return {r - scalar, g - scalar, b - scalar}; - } - Rgb operator/(const Rgb& other) const { - return {r / other.r, g / other.g, b / other.b}; - } -}; - -class Oklab { - public: - // Public member variables for Oklab components - float L, a, b; - - // Constructor to initialize Oklab color components - constexpr Oklab(float l = 0.0f, float a_ = 0.0f, float b_ = 0.0f) - : L(l), a(a_), b(b_) {} - - [[nodiscard]] static constexpr Oklab fromLinearRGB(float r, float g, float rgb_b) { - float l = 0.4122214708f * r + 0.5363325363f * g + 0.0514459929f * rgb_b; - float m = 0.2119034982f * r + 0.6806995451f * g + 0.1073969566f * rgb_b; - float s = 0.0883024619f * r + 0.2817188376f * g + 0.6299787005f * rgb_b; - - float l_ = std::cbrtf(l); - float m_ = std::cbrtf(m); - float s_ = std::cbrtf(s); - - float oklab_l = 0.2104542553f * l_ + 0.7936177850f * m_ - 0.0040720468f * s_; - float oklab_a = 1.9779984951f * l_ - 2.4285922050f * m_ + 0.4505937099f * s_; - float oklab_b = 0.0259040371f * l_ + 0.7827717662f * m_ - 0.8086757660f * s_; - - return {oklab_l, oklab_a, oklab_b}; - } - - [[nodiscard]] Rgb toLinearRGB() const { - float l_ = this->L + 0.3963377774f * this->a + 0.2158037573f * this->b; - float m_ = this->L - 0.1055613458f * this->a - 0.0638541728f * this->b; - float s_ = this->L - 0.0894841775f * this->a - 1.2914855480f * this->b; - - float l = l_ * l_ * l_; - float m = m_ * m_ * m_; - float s = s_ * s_ * s_; - - float linear_r = 4.0767416621f * l - 3.3077115913f * m + 0.2309699292f * s; - float linear_g = -1.2684380046f * l + 2.6097574011f * m - 0.3413193965f * s; - float linear_b = -0.0041960863f * l - 0.7034186147f * m + 1.7076147010f * s; - - return {linear_r, linear_g, linear_b}; - } -}; -} - -#endif //AVIF_OKLAB diff --git a/jxlcoder/src/main/cpp/colorspaces/Rec2408ToneMapper.cpp b/jxlcoder/src/main/cpp/colorspaces/Rec2408ToneMapper.cpp index b776f04..12008a2 100644 --- a/jxlcoder/src/main/cpp/colorspaces/Rec2408ToneMapper.cpp +++ b/jxlcoder/src/main/cpp/colorspaces/Rec2408ToneMapper.cpp @@ -28,7 +28,6 @@ #include "Rec2408ToneMapper.h" #include "Trc.h" -#include "Oklab.hpp" float rec2408_pq(float intensity, const float intensity_target) { // Lb, Lw, Lmin, Lmax @@ -79,44 +78,23 @@ float rec2408_pq(float intensity, const float intensity_target) { } void Rec2408ToneMapper::transferTone(float *inPlace, uint32_t width) const { - if (this->perceptual) { - float *targetPlace = inPlace; + float *targetPlace = inPlace; - const float vWeightA = this->weightA; - const float vWeightB = this->weightB; + const float vWeightA = this->weightA; + const float vWeightB = this->weightB; - for (uint32_t x = 0; x < width; ++x) { - float r = targetPlace[0]; - float g = targetPlace[1]; - float b = targetPlace[2]; - coder::Oklab oklab = coder::Oklab::fromLinearRGB(r, g, b); - float shScale = (1.f + vWeightA * oklab.L) / (1.f + vWeightB * oklab.L); - oklab.L = oklab.L * shScale; - coder::Rgb linearRgb = oklab.toLinearRGB(); - targetPlace[0] = std::min(linearRgb.r, 1.f); - targetPlace[1] = std::min(linearRgb.g, 1.f); - targetPlace[2] = std::min(linearRgb.b, 1.f); - targetPlace += 3; - } - } else { - float *targetPlace = inPlace; - - const float vWeightA = this->weightA; - const float vWeightB = this->weightB; - - for (uint32_t x = 0; x < width; ++x) { - float r = targetPlace[0]; - float g = targetPlace[1]; - float b = targetPlace[2]; - float inLight = 0.2627f * static_cast(r) + 0.6780f * static_cast(g) + 0.0593f * static_cast(b); - if (inLight == 0) { - continue; - } - float scale = (1.f + vWeightA * inLight) / (1.f + vWeightB * inLight); - targetPlace[0] = std::min(r * scale, 1.f); - targetPlace[1] = std::min(g * scale, 1.f); - targetPlace[2] = std::min(b * scale, 1.f); - targetPlace += 3; + for (uint32_t x = 0; x < width; ++x) { + float r = targetPlace[0]; + float g = targetPlace[1]; + float b = targetPlace[2]; + float inLight = 0.2627f * static_cast(r) + 0.6780f * static_cast(g) + 0.0593f * static_cast(b); + if (inLight == 0) { + continue; } + float scale = (1.f + vWeightA * inLight) / (1.f + vWeightB * inLight); + targetPlace[0] = std::min(r * scale, 1.f); + targetPlace[1] = std::min(g * scale, 1.f); + targetPlace[2] = std::min(b * scale, 1.f); + targetPlace += 3; } } \ No newline at end of file diff --git a/jxlcoder/src/main/cpp/colorspaces/Rec2408ToneMapper.h b/jxlcoder/src/main/cpp/colorspaces/Rec2408ToneMapper.h index c1d3c80..571681d 100644 --- a/jxlcoder/src/main/cpp/colorspaces/Rec2408ToneMapper.h +++ b/jxlcoder/src/main/cpp/colorspaces/Rec2408ToneMapper.h @@ -36,7 +36,7 @@ class Rec2408ToneMapper { Rec2408ToneMapper(const float contentMaxBrightness, const float displayMaxBrightness, const float whitePoint, - const float primaries[3], bool perceptual): perceptual(perceptual) { + const float primaries[3]) { std::copy(primaries, primaries + 3, lumaPrimaries); this->Ld = contentMaxBrightness / whitePoint; @@ -49,7 +49,6 @@ class Rec2408ToneMapper { private: float lumaPrimaries[3] = {0}; float Ld = 0; - bool perceptual; float weightA = 0; float weightB = 0; }; diff --git a/jxlcoder/src/main/cpp/colorspaces/ToneMapper.h b/jxlcoder/src/main/cpp/colorspaces/ToneMapper.h deleted file mode 100644 index 45c5cbe..0000000 --- a/jxlcoder/src/main/cpp/colorspaces/ToneMapper.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2024 Radzivon Bartoshyk - * jxl-coder [https://github.com/awxkee/jxl-coder] - * - * Created by Radzivon Bartoshyk on 13/10/2024 - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - */ - -#ifndef AVIF_TONEMAPPER_H -#define AVIF_TONEMAPPER_H - -enum CurveToneMapper { - REC2408 = 1, LOGARITHMIC = 2, FILMIC = 3, ACES = 4, REC2408_PERCEPTUAL = 5, TONE_SKIP = 6 -}; - -#endif //AVIF_TONEMAPPER_H diff --git a/jxlcoder/src/main/java/com/awxkee/jxlcoder/JxlAnimatedImage.kt b/jxlcoder/src/main/java/com/awxkee/jxlcoder/JxlAnimatedImage.kt index 099cc8e..36da303 100644 --- a/jxlcoder/src/main/java/com/awxkee/jxlcoder/JxlAnimatedImage.kt +++ b/jxlcoder/src/main/java/com/awxkee/jxlcoder/JxlAnimatedImage.kt @@ -50,7 +50,6 @@ class JxlAnimatedImage : Closeable { preferredColorConfig: Int, scaleMode: Int, jxlResizeSampler: Int, - javaToneMapper: Int, ): Long private external fun createCoordinatorByteArray( @@ -58,8 +57,7 @@ class JxlAnimatedImage : Closeable { preferredColorConfig: Int, scaleMode: Int, jxlResizeSampler: Int, - javaToneMapper: Int, - ): Long + ): Long val scaleMode: ScaleMode @@ -69,7 +67,6 @@ class JxlAnimatedImage : Closeable { preferredColorConfig: PreferredColorConfig = PreferredColorConfig.DEFAULT, scaleMode: ScaleMode = ScaleMode.FIT, jxlResizeFilter: JxlResizeFilter = JxlResizeFilter.BILINEAR, - toneMapper: JxlToneMapper = JxlToneMapper.LOGARITHMIC, ) { if (Build.VERSION.SDK_INT >= 21) { System.loadLibrary("jxlcoder") @@ -80,7 +77,6 @@ class JxlAnimatedImage : Closeable { preferredColorConfig.value, scaleMode.value, jxlResizeFilter.value, - toneMapper.value, ) } @@ -90,7 +86,6 @@ class JxlAnimatedImage : Closeable { preferredColorConfig: PreferredColorConfig = PreferredColorConfig.DEFAULT, scaleMode: ScaleMode = ScaleMode.FIT, jxlResizeFilter: JxlResizeFilter = JxlResizeFilter.BILINEAR, - toneMapper: JxlToneMapper = JxlToneMapper.LOGARITHMIC, ) { if (Build.VERSION.SDK_INT >= 21) { System.loadLibrary("jxlcoder") @@ -101,7 +96,6 @@ class JxlAnimatedImage : Closeable { preferredColorConfig.value, scaleMode.value, jxlResizeFilter.value, - toneMapper.value, ) } diff --git a/jxlcoder/src/main/java/com/awxkee/jxlcoder/JxlCoder.kt b/jxlcoder/src/main/java/com/awxkee/jxlcoder/JxlCoder.kt index 702498d..cfb9f2d 100644 --- a/jxlcoder/src/main/java/com/awxkee/jxlcoder/JxlCoder.kt +++ b/jxlcoder/src/main/java/com/awxkee/jxlcoder/JxlCoder.kt @@ -51,7 +51,6 @@ object JxlCoder { byteArray: ByteArray, preferredColorConfig: PreferredColorConfig = PreferredColorConfig.DEFAULT, scaleMode: ScaleMode = ScaleMode.FIT, - toneMapper: JxlToneMapper = JxlToneMapper.REC2408, ): Bitmap { return decodeSampledImpl( byteArray, @@ -60,7 +59,6 @@ object JxlCoder { preferredColorConfig.value, scaleMode.value, JxlResizeFilter.CATMULL_ROM.value, - jxlToneMapper = toneMapper.value, ) } @@ -74,7 +72,6 @@ object JxlCoder { preferredColorConfig: PreferredColorConfig = PreferredColorConfig.DEFAULT, scaleMode: ScaleMode = ScaleMode.FIT, jxlResizeFilter: JxlResizeFilter = JxlResizeFilter.MITCHELL_NETRAVALI, - toneMapper: JxlToneMapper = JxlToneMapper.REC2408, ): Bitmap { return decodeSampledImpl( byteArray, @@ -83,7 +80,6 @@ object JxlCoder { preferredColorConfig.value, scaleMode.value, jxlResizeFilter.value, - jxlToneMapper = toneMapper.value, ) } @@ -97,7 +93,6 @@ object JxlCoder { preferredColorConfig: PreferredColorConfig = PreferredColorConfig.DEFAULT, scaleMode: ScaleMode = ScaleMode.FIT, jxlResizeFilter: JxlResizeFilter = JxlResizeFilter.MITCHELL_NETRAVALI, - toneMapper: JxlToneMapper = JxlToneMapper.REC2408, ): Bitmap { return decodeByteBufferSampledImpl( byteArray, @@ -106,7 +101,6 @@ object JxlCoder { preferredColorConfig.value, scaleMode.value, jxlResizeFilter.value, - jxlToneMapper = toneMapper.value, ) } @@ -225,7 +219,6 @@ object JxlCoder { preferredColorConfig: Int, scaleMode: Int, jxlResizeSampler: Int, - jxlToneMapper: Int, ): Bitmap private external fun decodeByteBufferSampledImpl( @@ -235,7 +228,6 @@ object JxlCoder { preferredColorConfig: Int, scaleMode: Int, jxlResizeSampler: Int, - jxlToneMapper: Int, ): Bitmap private external fun encodeImpl( diff --git a/jxlcoder/src/main/java/com/awxkee/jxlcoder/JxlToneMapper.kt b/jxlcoder/src/main/java/com/awxkee/jxlcoder/JxlToneMapper.kt deleted file mode 100644 index 508e2e5..0000000 --- a/jxlcoder/src/main/java/com/awxkee/jxlcoder/JxlToneMapper.kt +++ /dev/null @@ -1,33 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2024 Radzivon Bartoshyk - * jxl-coder [https://github.com/awxkee/jxl-coder] - * - * Created by Radzivon Bartoshyk on 14/1/2024 - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - */ - -package com.awxkee.jxlcoder - -enum class JxlToneMapper(val value: Int) { - REC2408(1), LOGARITHMIC(2), FILMIC(3), ACES(4), REC2408_PERCEPTUAL(5), -} \ No newline at end of file