Skip to content

Commit d4d0ca7

Browse files
committed
Tonemap improvements
1 parent 726d4d2 commit d4d0ca7

File tree

8 files changed

+95
-29
lines changed

8 files changed

+95
-29
lines changed

app/src/main/java/com/awxkee/jxlcoder/MainActivity.kt

Lines changed: 47 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,9 @@ class MainActivity : ComponentActivity() {
206206

207207
var assets =
208208
(this@MainActivity.assets.list("") ?: return@launch).toList()
209-
assets = assets.filter { it.contains("20181110_213419__MMC1561-HDR.jxl") }
209+
// assets = assets.filter { it.contains("20181110_213419__MMC1561-HDR.jxl") }
210+
// assets = assets.take(15)
211+
assets = assets.filter { it.contains("cow_image_jxl.jxl") }
210212
for (asset in assets) {
211213
try {
212214
val buffer4 =
@@ -215,21 +217,62 @@ class MainActivity : ComponentActivity() {
215217

216218
val largeImageSize = JxlCoder.getSize(buffer4)
217219
if (largeImageSize != null) {
220+
val decodingTime = measureTimeMillis {
221+
val srcImage = JxlCoder.decode(
222+
buffer4,
223+
preferredColorConfig = PreferredColorConfig.HARDWARE,
224+
com.awxkee.jxlcoder.ScaleMode.FIT,
225+
toneMapper = JxlToneMapper.REC2408,
226+
)
227+
}
228+
Log.d("JXLMain", "Decoding time ${decodingTime}ms")
218229
val time = measureTimeMillis {
219-
val srcImage = JxlCoder.decodeSampled(
230+
// val srcImage = JxlCoder.decodeSampled(
231+
// buffer4,
232+
// largeImageSize.width / 2,
233+
// largeImageSize.height / 2,
234+
// preferredColorConfig = PreferredColorConfig.HARDWARE,
235+
// com.awxkee.jxlcoder.ScaleMode.FIT,
236+
// toneMapper = JxlToneMapper.REC2408,
237+
// )
238+
val srcImage = JxlCoder.decode(
220239
buffer4,
221-
-1,
222-
largeImageSize.height / 2,
223240
preferredColorConfig = PreferredColorConfig.HARDWARE,
224241
com.awxkee.jxlcoder.ScaleMode.FIT,
225242
toneMapper = JxlToneMapper.REC2408,
226243
)
244+
val fosRec2408 = FileOutputStream(File(cacheDir, File(asset).nameWithoutExtension + ".jpg"))
245+
fosRec2408.use {
246+
srcImage.compress(Bitmap.CompressFormat.JPEG, 90, it)
247+
it.flush()
248+
}
249+
// val srcPerceptual = JxlCoder.decodeSampled(
250+
// buffer4,
251+
// largeImageSize.width / 2,
252+
// largeImageSize.height / 2,
253+
// preferredColorConfig = PreferredColorConfig.HARDWARE,
254+
// com.awxkee.jxlcoder.ScaleMode.FIT,
255+
// toneMapper = JxlToneMapper.REC2408_PERCEPTUAL,
256+
// )
257+
val srcPerceptual = JxlCoder.decode(
258+
buffer4,
259+
preferredColorConfig = PreferredColorConfig.HARDWARE,
260+
com.awxkee.jxlcoder.ScaleMode.FIT,
261+
toneMapper = JxlToneMapper.REC2408_PERCEPTUAL,
262+
)
263+
val fosRec2408Perc = FileOutputStream(File(cacheDir, File(asset).nameWithoutExtension + "_perceptual.jpg"))
264+
fosRec2408Perc.use {
265+
srcPerceptual.compress(Bitmap.CompressFormat.JPEG, 90, it)
266+
it.flush()
267+
}
227268
// val srcImage = JxlCoder.decode(buffer4,
228269
// preferredColorConfig = PreferredColorConfig.RGB_565,
229270
// toneMapper = JxlToneMapper.REC2408)
230271
lifecycleScope.launch {
231272
imagesArray.add(srcImage)
273+
imagesArray.add(srcPerceptual)
232274
}
275+
233276
}
234277
Log.d("JXLCoder", "Decoding done in ${time}ms")
235278
}

build.gradle.kts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// Top-level build file where you can add configuration options common to all sub-projects/modules.
22
plugins {
3-
id("com.android.application") version "8.8.0-rc02" apply false
3+
id("com.android.application") version "8.8.0" apply false
44
id("org.jetbrains.kotlin.android") version "2.0.20" apply false
5-
id("com.android.library") version "8.8.0-rc02" apply false
5+
id("com.android.library") version "8.8.0" apply false
66
id("com.google.devtools.ksp") version "2.0.20-1.0.25" apply false
77
}

jxlcoder/src/main/cpp/JXLConventions.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@ Java_com_awxkee_jxlcoder_JxlCoder_gif2JXLImpl(JNIEnv *env, jobject thiz, jbyteAr
144144
for (const EasyGifReader::Frame &frame : gifReader) {
145145
const std::uint32_t *framePixels = frame.pixels();
146146
int frameDuration = frame.duration().milliseconds();
147-
const uint8_t *mSource = reinterpret_cast<const uint8_t *>(framePixels);
147+
const auto *mSource = reinterpret_cast<const uint8_t *>(framePixels);
148148
std::copy(mSource, mSource + frameSize, mPixelStore.begin());
149149
encoder.addFrame(mPixelStore, frameDuration);
150150
}

jxlcoder/src/main/cpp/colorspaces/ColorMatrix.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -77,8 +77,8 @@ void applyColorMatrix(uint8_t *inPlace, uint32_t stride, uint32_t width, uint32_
7777
}
7878

7979
float mCoeffs[3] = {coeffs.kr, coeffs.kg, coeffs.kb};
80-
if (toneMapper == CurveToneMapper::REC2408) {
81-
Rec2408ToneMapper mToneMapper(contentBrightness, 250.f, 203.f, mCoeffs);
80+
if (toneMapper == CurveToneMapper::REC2408 || toneMapper == CurveToneMapper::REC2408_PERCEPTUAL) {
81+
Rec2408ToneMapper mToneMapper(contentBrightness, 250.f, 203.f, mCoeffs, toneMapper == CurveToneMapper::REC2408_PERCEPTUAL);
8282
mToneMapper.transferTone(rowVector.data(), width);
8383
} else if (toneMapper == CurveToneMapper::LOGARITHMIC) {
8484
LogarithmicToneMapper mToneMapper(mCoeffs);
@@ -185,8 +185,8 @@ void applyColorMatrix16Bit(uint16_t *inPlace,
185185
}
186186

187187
float mCoeffs[3] = {coeffs.kr, coeffs.kg, coeffs.kb};
188-
if (toneMapper == CurveToneMapper::REC2408) {
189-
Rec2408ToneMapper mToneMapper(contentBrightness, 250.f, 203.f, mCoeffs);
188+
if (toneMapper == CurveToneMapper::REC2408 || toneMapper == CurveToneMapper::REC2408_PERCEPTUAL) {
189+
Rec2408ToneMapper mToneMapper(contentBrightness, 250.f, 203.f, mCoeffs, toneMapper == CurveToneMapper::REC2408_PERCEPTUAL);
190190
mToneMapper.transferTone(rowVector.data(), width);
191191
} else if (toneMapper == CurveToneMapper::LOGARITHMIC) {
192192
LogarithmicToneMapper mToneMapper(mCoeffs);

jxlcoder/src/main/cpp/colorspaces/Rec2408ToneMapper.cpp

Lines changed: 37 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -79,22 +79,44 @@ float rec2408_pq(float intensity, const float intensity_target) {
7979
}
8080

8181
void Rec2408ToneMapper::transferTone(float *inPlace, uint32_t width) const {
82-
float *targetPlace = inPlace;
82+
if (this->perceptual) {
83+
float *targetPlace = inPlace;
8384

84-
const float vWeightA = this->weightA;
85-
const float vWeightB = this->weightB;
85+
const float vWeightA = this->weightA;
86+
const float vWeightB = this->weightB;
8687

87-
for (uint32_t x = 0; x < width; ++x) {
88-
float r = targetPlace[0];
89-
float g = targetPlace[1];
90-
float b = targetPlace[2];
91-
coder::Oklab oklab = coder::Oklab::fromLinearRGB(r, g, b);
92-
float shScale = (1.f + vWeightA * oklab.L) / (1.f + vWeightB * oklab.L);
93-
oklab.L = oklab.L * shScale;
94-
coder::Rgb linearRgb = oklab.toLinearRGB();
95-
targetPlace[0] = std::min(linearRgb.r, 1.f);
96-
targetPlace[1] = std::min(linearRgb.g, 1.f);
97-
targetPlace[2] = std::min(linearRgb.b, 1.f);
98-
targetPlace += 3;
88+
for (uint32_t x = 0; x < width; ++x) {
89+
float r = targetPlace[0];
90+
float g = targetPlace[1];
91+
float b = targetPlace[2];
92+
coder::Oklab oklab = coder::Oklab::fromLinearRGB(r, g, b);
93+
float shScale = (1.f + vWeightA * oklab.L) / (1.f + vWeightB * oklab.L);
94+
oklab.L = oklab.L * shScale;
95+
coder::Rgb linearRgb = oklab.toLinearRGB();
96+
targetPlace[0] = std::min(linearRgb.r, 1.f);
97+
targetPlace[1] = std::min(linearRgb.g, 1.f);
98+
targetPlace[2] = std::min(linearRgb.b, 1.f);
99+
targetPlace += 3;
100+
}
101+
} else {
102+
float *targetPlace = inPlace;
103+
104+
const float vWeightA = this->weightA;
105+
const float vWeightB = this->weightB;
106+
107+
for (uint32_t x = 0; x < width; ++x) {
108+
float r = targetPlace[0];
109+
float g = targetPlace[1];
110+
float b = targetPlace[2];
111+
float inLight = 0.2627f * static_cast<float>(r) + 0.6780f * static_cast<float>(g) + 0.0593f * static_cast<float>(b);
112+
if (inLight == 0) {
113+
continue;
114+
}
115+
float scale = (1.f + vWeightA * inLight) / (1.f + vWeightB * inLight);
116+
targetPlace[0] = std::min(r * scale, 1.f);
117+
targetPlace[1] = std::min(g * scale, 1.f);
118+
targetPlace[2] = std::min(b * scale, 1.f);
119+
targetPlace += 3;
120+
}
99121
}
100122
}

jxlcoder/src/main/cpp/colorspaces/Rec2408ToneMapper.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ class Rec2408ToneMapper {
3636
Rec2408ToneMapper(const float contentMaxBrightness,
3737
const float displayMaxBrightness,
3838
const float whitePoint,
39-
const float primaries[3]) {
39+
const float primaries[3], bool perceptual): perceptual(perceptual) {
4040
std::copy(primaries, primaries + 3, lumaPrimaries);
4141

4242
this->Ld = contentMaxBrightness / whitePoint;
@@ -49,6 +49,7 @@ class Rec2408ToneMapper {
4949
private:
5050
float lumaPrimaries[3] = {0};
5151
float Ld = 0;
52+
bool perceptual;
5253
float weightA = 0;
5354
float weightB = 0;
5455
};

jxlcoder/src/main/cpp/colorspaces/ToneMapper.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
#define AVIF_TONEMAPPER_H
3131

3232
enum CurveToneMapper {
33-
REC2408 = 1, LOGARITHMIC = 2, FILMIC = 3, ACES = 4, TONE_SKIP = 5
33+
REC2408 = 1, LOGARITHMIC = 2, FILMIC = 3, ACES = 4, REC2408_PERCEPTUAL = 5, TONE_SKIP = 6
3434
};
3535

3636
#endif //AVIF_TONEMAPPER_H

jxlcoder/src/main/java/com/awxkee/jxlcoder/JxlToneMapper.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,5 +29,5 @@
2929
package com.awxkee.jxlcoder
3030

3131
enum class JxlToneMapper(val value: Int) {
32-
REC2408(1), LOGARITHMIC(2), FILMIC(3), ACES(4)
32+
REC2408(1), LOGARITHMIC(2), FILMIC(3), ACES(4), REC2408_PERCEPTUAL(5),
3333
}

0 commit comments

Comments
 (0)