JPEG XL

Info

rules 57
github 35276
reddit 647

JPEG XL

tools 4225
website 1655
adoption 20712
image-compression-forum 0

General chat

welcome 3810
introduce-yourself 291
color 1414
photography 3435
other-codecs 23765
on-topic 24923
off-topic 22701

Voice Channels

General 2147

Archived

bot-spam 4380

libjxl

Demiurge
<@318186133320237058> That was in response to your blue noise mention by the way, if Fab made you miss it
2024-01-11 09:13:41
Hey that's exactly what I was looking for actually, I switched PCs and was trying to find that link
veluca
Demiurge But still theoretically it's cooler and visually at lower bit depths it does preserve more detail
2024-01-11 09:19:05
sure, but no need to go for more complex things if the simple ones work 🙂 and libjxl doesn't decode to <8 bit anyway...
Demiurge
2024-01-11 09:59:45
blue noise definitely looks the best, unless you compare it with error diffusion algorithms
2024-01-11 10:00:45
And theoretically it's no more complex than a bayer matrix, you just replace the bayer matrix with a blue noise matrix
2024-01-11 10:24:52
https://surma.dev/lab/ditherpunk/lab
2024-01-11 10:25:09
https://surma.dev/things/ditherpunk/index.html
190n
2024-01-11 11:02:51
oooo
2024-01-11 11:07:02
wtf 3 years old, how had i not come across that article before 😅
2024-01-11 11:07:06
blue noise looks cool
2024-01-11 11:07:27
https://tannerhelland.com/2012/12/28/dithering-eleven-algorithms-source-code.html this article is also good, it focuses almost exclusively on different error diffusion algorithms with nice comparisons
_wb_
2024-01-11 11:23:38
Just simple 4x4 or 8x8 ordered dither is good enough for dithering to 8bit sRGB or P3. I don't see a need to do anything fancier.
Demiurge
2024-01-11 11:47:08
Well, it IS ordered dither, it's just a different matrix
2024-01-11 11:48:00
and 8x8 is going to be significantly better than 4x4, even for a bayer matrix
2024-01-11 11:48:21
and 16x16 or 32x32 is also going to be better but there are diminishing returns of course
2024-01-11 11:49:07
and a matrix generated with the "void and cluster" method is going to look better than a bayer matrix
2024-01-11 11:51:18
It would be a pretty trivial change to simply modify the matrix values, and possibly even the size of the matrix to make it larger.
2024-01-11 11:57:10
It's ordered dither, that looks just as good as error-diffusion dither, without the cost of error diffusion.
190n https://tannerhelland.com/2012/12/28/dithering-eleven-algorithms-source-code.html this article is also good, it focuses almost exclusively on different error diffusion algorithms with nice comparisons
2024-01-11 11:58:51
Yeah, this is a good article, basically seems like Sierra is the best error-diffusion method.
190n
_wb_ Just simple 4x4 or 8x8 ordered dither is good enough for dithering to 8bit sRGB or P3. I don't see a need to do anything fancier.
2024-01-11 11:59:20
yeah, it's definitely much less visible when the destination is truecolor or better
2024-01-11 11:59:42
i think my raytracer does floyd-steinberg even to go from f32 to int8, just because i didn't want to implement two algorithms
Demiurge
2024-01-12 12:05:26
Burkes dithering also seems better than 2-row Sierra
2024-01-12 12:05:47
I guess I like 3-row Sierra and Burkes best.
2024-01-12 12:05:54
As far as error-diffusion goes
veluca
Demiurge blue noise definitely looks the best, unless you compare it with error diffusion algorithms
2024-01-12 08:16:48
I'm not disputing that, I am just saying that I would be surprised if the difference is perceivable when dithering to truecolor... but also I don't want to be the person that makes this decision and it should be <@532010383041363969> xD
Demiurge
veluca I'm not disputing that, I am just saying that I would be surprised if the difference is perceivable when dithering to truecolor... but also I don't want to be the person that makes this decision and it should be <@532010383041363969> xD
2024-01-12 08:55:56
Yeah, dither patterns would probably be hard to notice at that bit depth. probably.
2024-01-12 09:12:23
Another big issue with dither is that it often changes the perceived brightness
2024-01-12 09:13:29
since the dither algorithm isn't aware of what brightness means
2024-01-12 09:13:47
or what a gamma curve is probably
Traneptora
2024-01-12 05:04:48
Yea, and dithering in linear light doesn't work, because you don't want to turn 8bit linear light into sRGB
damian101
veluca I'm not disputing that, I am just saying that I would be surprised if the difference is perceivable when dithering to truecolor... but also I don't want to be the person that makes this decision and it should be <@532010383041363969> xD
2024-01-12 05:12:12
how perceivable it is first depends on transfer curve, primaries, and if the image is later transformed further...
2024-01-12 05:12:48
worst case would be linear
Traneptora Yea, and dithering in linear light doesn't work, because you don't want to turn 8bit linear light into sRGB
2024-01-12 05:13:30
how do you mean, doesn't work...
2024-01-12 05:14:04
good dithering is most essential there
spider-mario
how do you mean, doesn't work...
2024-01-12 05:20:39
one aspect is that the amount of linear noise that dithers low values enough once back in sRGB will not be enough for bright values
2024-01-12 05:20:54
conversely, if you use enough dither for the bright values, you’ll overdither the dark ones
damian101
spider-mario conversely, if you use enough dither for the bright values, you’ll overdither the dark ones
2024-01-12 05:22:51
The dither noise is only there to prevent rounding errors during bit depth reduction. When you then convert to a different transfer curve in high bit depth, it is not neded. If you then reduce bit depth again, you of course have to also dither again.
spider-mario
2024-01-12 05:23:34
right, but so this means that dithering in linear light to prepare for 8-bit sRGB is not going to be effective
damian101
spider-mario conversely, if you use enough dither for the bright values, you’ll overdither the dark ones
2024-01-12 05:23:44
you usually don't apply dither noise at once for multiple transformed versions of the image, that would be mere cope for a bad processing pipeline
spider-mario right, but so this means that dithering in linear light to prepare for 8-bit sRGB is not going to be effective
2024-01-12 05:24:01
yes, true
Traneptora
how do you mean, doesn't work...
2024-01-12 05:39:04
the problem is not that you can't dither down to 8-bit data in linear light but you need the precision to be higher when going from linear light to sRGB
2024-01-12 05:39:08
since the transfer function is nonlinear
damian101
Traneptora the problem is not that you can't dither down to 8-bit data in linear light but you need the precision to be higher when going from linear light to sRGB
2024-01-12 05:39:49
you always do transfer conversion in high bit depth first, THEN dither down to the desired bit depth
2024-01-12 05:39:54
well, ideally
Traneptora
2024-01-12 05:40:04
indeed, that's why you can't dither to 8-bit in linear light
2024-01-12 05:40:05
:D
damian101
Traneptora indeed, that's why you can't dither to 8-bit in linear light
2024-01-12 05:40:12
you can
Traneptora
2024-01-12 05:40:23
(if the intent is to end up with an 8-bit sRGB image)
damian101
2024-01-12 05:40:32
ah
Traneptora
2024-01-12 05:40:46
you can always have 8-bit linear light, but it's usually not what you want or the end goal
damian101
2024-01-12 05:41:10
low bit depth linear is generally to be avoided
Traneptora
2024-01-12 05:41:28
indeed. my point wasn't that it couldn't be done but rather it didn't make sense to do it
damian101
2024-01-12 05:41:29
32-bit float linear as intermediate step in processing is fine
Traneptora
2024-01-12 05:41:33
since dithering has to be the last step
damian101
2024-01-12 05:41:42
yes
_wb_
2024-01-13 08:13:21
Dithering to 8-bit is essentially just a way to make the low-freq signal effectively 9 or 10-bit. It's not really important to do that in a great way, since the step sizes are small (unless you want to do HDR in 8-bit or something, but I assume this is only something you do for SDR spaces). Doing dithering to go from continuous-tone to bilevel (1-bit pixels, or e.g. halftoning) does require nice methods with error diffusion etc to avoiding visible dithering patterns. For going from rgb888 to 8-bit palettes or to rgb555 or rgba4444 it is still important to do it nicely, since the step size in these target bitdepths is still large enough to cause serious banding or color shifts. But 8-bit sRGB is already more or less banding-free at its reference viewing brightness of 80 nits. When viewing on a modern 400-nits display, the steps become a bit too large and you do get visible banding, so it is useful to apply some dithering. It has to be done during the final colorspace conversion (to the display space), which is why we needed to first add a decode API that can guarantee to return a buffer in the desired colorspace. Now we have that, we can add an option for dithering. <@179701849576833024> how about we add an option to enable dithering, and then we can decide later if we want this option enabled or disabled by default? (I'd say enabled, but I am open to arguments against that)
veluca
2024-01-13 08:30:32
There's no option, it's just enabled 😛
Demiurge
2024-01-13 09:20:14
Lots of early adopters were vocally surprised by the startling ugliness of libjxl due to the lack of dither. Most of them do not know that it isn't a problem with the compression itself, but just the decoding.
_wb_
veluca There's no option, it's just enabled 😛
2024-01-13 11:12:27
oh ok, I missed that it was done already 🙂
lonjil
2024-01-13 11:20:02
dithering should be done after resizing the image when zooming in or out, right?
Demiurge
2024-01-13 11:22:35
Yes, mostly when zooming out
2024-01-13 11:23:24
Zooming out will undo the dither
damian101
lonjil dithering should be done after resizing the image when zooming in or out, right?
2024-01-14 04:25:16
Always before/when reducing bit depth. Dither noise appropriate for a certain bit depth will not necessarily survive scaling done before the bit depth reduction at a high enough level to prevent banding.
Demiurge
2024-01-14 05:09:24
If you resize to a smaller size you need to redither.
2024-01-14 05:11:06
And a blue noise pattern is profoundly better than a bayer pattern from what I see.
w
2024-01-14 05:11:30
yeah dithering should be done after
Demiurge
2024-01-14 05:16:18
Dithering can't be done after
2024-01-14 05:21:02
Well, it's done after resizing but before reducing bit depth
2024-01-14 05:21:37
When you resize it should be in a higher precision to avoid banding
w
2024-01-14 05:40:27
i mean dither after resizing at same bit depth
2024-01-14 05:40:33
or dither after reducing bit depth
Demiurge
2024-01-14 06:26:50
You have to do the resizing at a higher bit depth.
2024-01-14 06:26:56
than the original
2024-01-14 06:28:07
Then you dither when going back down to the original bit depth.
2024-01-14 06:28:29
Same when resampling audio.
w
2024-01-14 06:28:35
my problem is the wording of that
2024-01-14 06:28:43
you cant dither when going down
2024-01-14 06:28:45
you do it after
2024-01-14 06:28:50
it doesnt make any sense
2024-01-14 06:28:53
theyre two different operations
Demiurge
2024-01-14 06:29:11
You dither before reducing the bit depth.
w
2024-01-14 06:29:21
if you dither before then you can get banding
2024-01-14 06:29:25
you need to do it after
2024-01-14 06:29:49
it's more like if you dither before then the dithering is undone when you reduce bit depth
Demiurge
2024-01-14 06:29:54
And often it isn't a separate operation. Often truncation is built into the dithering algorithm.
w if you dither before then you can get banding
2024-01-14 06:30:38
No, if you reduce bit depth before you dither, then the banding is already there and cannot be removed.
2024-01-14 06:30:51
Unless you reduce the bit depth even further.
w
2024-01-14 06:33:07
if there's no banding before and you dither then it wont do anything
2024-01-14 06:33:23
and after you reduce bit depth then it will be banded
Demiurge
2024-01-14 06:33:42
No, after you reduce bit depth, the dither you added will prevent the banding. That is what dither is for.
2024-01-14 06:34:16
That's why it's there
2024-01-14 06:34:27
It increases dynamic range
w
2024-01-14 06:46:01
i think i understand now
2024-01-14 06:46:30
so the noise has to be greater magnitude than a unit of the lower bit depth
_wb_
2024-01-14 07:13:05
The noise has the amplitude of half of the least significant bit step size in the target bitdepth.
2024-01-14 07:17:46
So if you go from float32 in range 0..1 to uint8, it's basically `result = round_and_clamp( input * 255.f + random number between -0.5 and +0.5 )`
Demiurge
2024-01-14 07:34:10
Exactly. It's between 0.5 and -0.5 the amplitude of the smallest possible step (the least significant bit)
damian101
w i mean dither after resizing at same bit depth
2024-01-14 07:34:26
you normally resize in float, practically no rounding errors
Demiurge
2024-01-14 07:34:42
That dither signal is added to the signal first, and then the result is truncated to the target bit depth.
w
2024-01-14 07:35:13
yeah but who resizes in float
2024-01-14 07:35:16
that's expensive
Demiurge
2024-01-14 07:35:30
Is it really?
w
2024-01-14 07:35:35
yes
Demiurge
2024-01-14 07:36:00
libjxl DCT is float and it's fast
damian101
w or dither after reducing bit depth
2024-01-14 07:36:02
bit depth reduction without dithering creates rounding errors that can not be removed by dithering afterwards
w it's more like if you dither before then the dithering is undone when you reduce bit depth
2024-01-14 07:37:01
eh, please check Wikipedia or something on how dithering works...
Tirr
2024-01-14 07:37:08
float division is generally faster than integer division
w
2024-01-14 07:37:11
yeah i already get it
2024-01-14 07:37:28
read til the end
Demiurge
2024-01-14 07:38:02
Most image processing applications do processing in higher precision before quantizing to lower precision as the final step
2024-01-14 07:38:30
But not all the time
2024-01-14 07:39:18
If you don't do things like resizing in higher precision, then you're gunna get banding
2024-01-14 07:39:36
And if you don't dither before saving to lower precision, you'll get banding
w
2024-01-14 07:41:00
video games always have banding
Demiurge
2024-01-14 07:41:26
Because people don't implement cheap and easy dither into the render pipeline
2024-01-14 07:41:39
Because people who make video games don't always know what they're doing all the time
damian101
w video games always have banding
2024-01-14 07:41:43
some don't
Demiurge
2024-01-14 07:42:05
By the way, this is the exact same dithering algorithm, "ordered dither," but one is using a bayer pattern and one is using a blue noise pattern. The only difference is the LUT. Check out this comparison. https://en.wikipedia.org/wiki/File:Michelangelo%27s_David_-_Bayer.png https://en.wikipedia.org/wiki/File:Michelangelo%27s_David_-_Void-and-Cluster.png
2024-01-14 07:44:42
I know that at 8 bits the difference might be a lot harder to notice, but it's the same algorithm, only the LUT matrix needs to change. So I think this is enough reason to change it, even if the change will be hard to notice at 8-bit depth...
2024-01-14 07:45:18
I mean look at how cool that is, the cool factor is there :D
damian101
2024-01-14 08:13:11
I actually expected blue noise to be used, with the whole theme of perceptual uniformity throughout the codec's design...
spider-mario
2024-01-14 08:55:16
one way to get an intuition about dither is to imagine a signal that is constant and equal to 0.4
2024-01-14 08:55:20
you want to round it to integers
2024-01-14 08:56:07
if you add uniform noise in [-0.5, 0.5], that means that 60% of the time, you end up in [-0.1, 0.5] and therefore round to 0; and 40% of the time, in [0.5, 0.9], which you round to 1
2024-01-14 08:56:31
and 60% 0 and 40% 1 has the correct average, 0.4
2024-01-14 08:57:03
you just happen to oscillate around that average
2024-01-14 08:57:45
whereas if you were to round without dithering, you’d just get 0
2024-01-14 08:57:57
a constant error of 0.4
veluca
Tirr float division is generally faster than integer division
2024-01-14 10:03:03
you don't really need division to resize though 🙂 but then unless you do 16-bit, float *multiplication* is also faster, so...
2024-01-14 10:03:27
(integers of course have a massive advantage for addition)
Demiurge
2024-01-14 11:38:20
Blue noise is... a lot of coolness, with very little that needs to change.
Traneptora
veluca you don't really need division to resize though 🙂 but then unless you do 16-bit, float *multiplication* is also faster, so...
2024-01-14 04:17:43
if float multiplication is faster why does anyone make fixed point algorithms
veluca
2024-01-14 04:19:37
Well... (a) on x86, not on other CPUs/hardware (b) there's addition too 😛 (c) with 16-bit integers, fixpoint *is* faster (d) integers are usually more HW independent
2024-01-14 04:22:45
AFAIU at low bit counts multiplies are effectively quadratic in bit lengths (at least in terms of surface area), which would explain a few things (float multiplies are effectively 24-bit multiplies + some extra logic)
_wb_
2024-01-14 06:58:28
For video specs, fixed point makes more sense: dedicated hw can have the exact bit width needed for a given profile/level, and you need to spec bit exact decoding because errors would otherwise propagate/accumulate arbitrarily.
lonjil
veluca Well... (a) on x86, not on other CPUs/hardware (b) there's addition too 😛 (c) with 16-bit integers, fixpoint *is* faster (d) integers are usually more HW independent
2024-01-14 07:08:03
is 16-bit integer math actually faster than 32-bit on typical 32 and 64 bit CPUs?
veluca
2024-01-14 08:43:34
one, no
2024-01-14 08:43:54
a vector of those, not sure if it's faster *per se*, but it's also twice as many elements 😉
lonjil
2024-01-14 08:49:27
what a disappointing omission!
veluca
2024-01-14 08:52:01
disappointing but unsurprising 😛
2024-01-14 08:52:35
also the table is missing the magical instruction "(u16 x u16) >> 15"
2024-01-14 08:52:50
(or maybe i16, not sure)
2024-01-14 08:53:16
it can be pretty useful for fixpoint arithmetic 😛
lonjil
2024-01-14 08:56:02
a shift by 15? 🤔
veluca
2024-01-14 08:56:17
i16 (_mm256_mulhrs_epi16)
2024-01-14 08:56:19
yeah
2024-01-14 08:56:46
it basically implements fixed point multiplication by any constant < 1 if using 15 digits past the "decimal" point
lonjil
2024-01-14 08:57:51
ah! that was listed way further down in the "other" section
2024-01-14 08:58:43
they don't describe it with a bit shift heh > Briefly: for each signed WORD, calculate (1) * (2) / 32768, and set the rounded result to (3).
2024-01-14 09:00:42
wonder why there's no unsigned version 🤔
JendaLinda
2024-01-14 09:02:27
The dithering is applied always, even if the source material was already 8 bits. Is this necessary? In lossless the dithering is no-op, and in lossy, as far I can see, the dithering only takes effect on compression artifacts.
Traneptora
veluca Well... (a) on x86, not on other CPUs/hardware (b) there's addition too 😛 (c) with 16-bit integers, fixpoint *is* faster (d) integers are usually more HW independent
2024-01-14 09:08:28
I ask because part of the design of libhydrium is that it's supposed to be hardware-agnostic
2024-01-14 09:08:37
which means explicitly no simd or intrinsics
2024-01-14 09:08:54
in that scenario is there actually much to gain from fixed-point arithmetic?
veluca
2024-01-14 09:11:07
depends on your autovectorizer...
Traneptora
2024-01-14 09:11:37
well, on embedded ARM chips how true is what you said
2024-01-14 09:12:32
basically, if I'm trying to avoid manually writing assembly, including the magical u16*u16>>15 instruction, I'm wondering if there's actual value in trying to stick with integers
lonjil
Traneptora well, on embedded ARM chips how true is what you said
2024-01-14 09:13:15
Cortex-M chips?
2024-01-14 09:13:47
some of the newer ones probably have pretty cool math instructions, I'll check
Traneptora
2024-01-14 09:13:57
¯\_(ツ)_/¯
lonjil
2024-01-14 09:19:04
apparently recent ARM microcontrollers have straight up fairly normal SIMD support lol
veluca
2024-01-14 09:24:51
huh
2024-01-14 09:24:58
I'd have guessed floats would be fairly slow there
2024-01-14 09:25:30
I guess the days of software floats are over 😛
lonjil
2024-01-14 09:26:19
it's an evolution of earlier DSP functionality, and it *seems* the logic block implementing it is optional, so customers who don't want fancy FP support don't need to pay the cost
2024-01-14 09:27:51
mostly limited to 32-bit and smaller elements, as you might expect
veluca
2024-01-14 09:28:53
well, that depends on the instruction - things like vpconflictd are actually easier to implement with larger elements xD
lonjil
2024-01-14 09:29:06
2024-01-14 09:31:27
> Helium provides support for Q15 and Q31 numbers. There is a sign bit to show whether the number is positive or negative, followed by a binary point and then 15 or 31 binary digits. The 16- or 32-bit value is being used to represent the range from −1 to 1. For example, the decimal value 0.75 represented as a signed Q15 value would be the integer value 0x6000. Fixed-point arithmetic allows fractional numbers to be handled using only integer hardware. looks like it would probably handle the above discussed case well.
veluca
2024-01-14 09:32:19
a couple years ago a 16-bit fixpoint DCT was 2-3x faster on "common android phones" wrt the fixpoint one
lonjil
2024-01-14 09:33:30
I assume you mean compared to the FP one?
veluca
2024-01-14 09:33:36
err yep
JendaLinda
2024-01-14 09:33:59
Is VarDCT always 32 bit float, no matter what was the source bit depth?
veluca
2024-01-14 09:34:10
in libjxl, yep
JendaLinda
2024-01-14 09:35:52
So I suppose the only meaning of the bit depth info in the file is to choose the more appropriate bit depth when decoding to png.
2024-01-14 09:41:22
For me at least, VarDCT decodes faster than modular, so floats are not an issue, I guess.
lonjil
veluca disappointing but unsurprising 😛
2024-01-14 09:56:06
seems like SVE has a rich set of 8x8 multiplcation instructions, including that magical fixed point thing. Intel can't compete.
veluca
2024-01-14 10:06:31
now if only I could actually get my hands on a CPU that implements those...
lonjil
2024-01-14 10:09:15
I wonder if recent Qualcomm laptops have SVE2, since it's supposed to be mandatory in Armv9.
2024-01-14 10:27:45
apparently Qualcomm laptop ships are way behind their mobile chips 🤦‍♀️
damian101
JendaLinda The dithering is applied always, even if the source material was already 8 bits. Is this necessary? In lossless the dithering is no-op, and in lossy, as far I can see, the dithering only takes effect on compression artifacts.
2024-01-14 11:52:48
Yes, dither noise is mostly lost during lossy encoding, when reducing bit depth from float to 8 bit again, dithering needs to be done again.
Traneptora
JendaLinda For me at least, VarDCT decodes faster than modular, so floats are not an issue, I guess.
2024-01-15 05:38:05
although that's because modular is inherently branchy and hard to vectorize/parallelize
_wb_
2024-01-15 07:34:46
Modular _can_ be inherently branchy, if you use stuff like arbitrary MA trees and the Weighted Predictor. If you restrict yourself to a subset like what is produced by e1/e2 encoding, most or all of the branchy-ness can be avoided and you can have a specialized decoder that is faster.
2024-01-15 08:18:34
``` In file included from /Users/jonsneyers/dev/libjxl/lib/extras/alpha_blend.cc:6: In file included from /Users/jonsneyers/dev/libjxl/lib/extras/alpha_blend.h:9: /Users/jonsneyers/dev/libjxl/lib/extras/packed_image.h:201:21: error: use of undeclared identifier 'JxlChunkedFrameInputSource' std::function<JxlChunkedFrameInputSource()> get_input_source) ^ /Users/jonsneyers/dev/libjxl/lib/extras/packed_image.h:201:21: error: template argument for template type parameter must be a type std::function<JxlChunkedFrameInputSource()> get_input_source) ^~~~~~~~~~~~~~~~~~~~~~~~~~~~ ```
2024-01-15 08:19:42
getting this build error when trying to build on macos
2024-01-15 08:19:47
``` /Library/Developer/CommandLineTools/SDKs/MacOSX14.2.sdk/usr/include/c++/v1/__functional/function.h:78:16: note: template parameter is declared here template<class _Fp> class _LIBCPP_TEMPLATE_VIS function; // undefined ```
2024-01-15 08:24:47
nevermind, I had something old somewhere
JendaLinda
2024-01-15 09:21:12
Dithering also shows up when decoding losslessly transcoded jpegs, those were originally encoded from 8 bit source. That's interesting to see that the old jpeg encoding produced additional levels between the original 8 bit levels.
2024-01-15 12:08:15
I mean, regular jpeg decodes don't take the inbetween levels into account, jxl decoder does.
jonnyawsom3
2024-01-15 12:11:54
If I recall, the JXL decoder will also use extra precision if the Jpeg's values haven't been rounded yet. Or at least something similar to that. Just woke up and the mention of it was months ago
spider-mario
2024-01-15 12:18:18
correct, it’s possible to extract more than 8 bits of precision from the jpeg format
2024-01-15 12:18:41
jpegli takes advantage of this, making HDR in traditional JPEGs potentially a realistic option
2024-01-15 12:18:48
(when decoded by jpegli or libjxl)
jonnyawsom3
2024-01-15 12:20:09
(Actual HDR too, not just merging images or using gainmaps)
spider-mario
2024-01-15 12:53:47
such JPEGs are already possible to make, and they’ll display as HDR in Chrome, but with more banding than if they were decoded by libjxl or jpegli
jonnyawsom3
2024-01-15 01:48:48
I would be curious to see one already, I assumed it had yet to be implemented into jpegli
spider-mario
2024-01-15 02:43:15
unless I messed up, this should be one
2024-01-15 02:48:19
maybe not the best example because the sky is a bit noisy, which provides a bit of dithering
2024-01-15 02:48:52
(this is from just one shot, not a merged bracket)
jonnyawsom3
2024-01-15 04:01:14
Last I recalled Discord re-encodes jpegs if you upload them normally, might have to remove the extension
username
2024-01-15 04:04:31
it doesn't re-encode (atleast the last time I checked) it just strips extra stuff like metadata
2024-01-15 04:05:16
though "extra data" can be a lot more then just text
spider-mario
2024-01-15 11:10:55
it’s preserved the ICC, at least
jonnyawsom3
2024-01-15 11:14:49
I couldn't find any noticable difference decoding with libjxl versus a standard jpeg decoder, although I did run my own test with a 16 bit Rec2020 gradient, turned into XYB with jpegli. Seemed to work, decoding back to png with jpegli resulted in no noticeable banding, but opening with normal jpeg viewers had severe banding (Unless that's just XYB without the extra bits anyway)
2024-01-15 11:16:13
For some reason cjxl fails to transcode it too though
2024-01-15 11:22:43
(Supposedly) 247 colors in the standard jpeg decode, 117,000 colors in the jpegli png output set to 16 bit (Still defaults to 8 bit where banding is noticable)
2024-01-15 11:34:58
Original 16 bit Rec.2020, XYB Jpeg, 16 bit Jpegli Output
2024-01-15 11:35:23
All naturally looking like blobs because Discord doesn't support ICC profiles
lonjil
2024-01-15 11:36:06
wow the original looks real bad in firefox
jonnyawsom3
2024-01-15 11:39:03
Yeah, not sure what's going on there but all seem a bit broken in Discord and Browser, locally works fine though (I don't have HDR but the banding goes away at least)
2024-01-15 11:40:39
One thing I love is that the lossless JXL is naturally even smaller than the jpeg thanks to the gradient predictor
Traneptora
_wb_ Modular _can_ be inherently branchy, if you use stuff like arbitrary MA trees and the Weighted Predictor. If you restrict yourself to a subset like what is produced by e1/e2 encoding, most or all of the branchy-ness can be avoided and you can have a specialized decoder that is faster.
2024-01-16 12:31:06
yea, that's true, but it's still an inherently sequential operation as a whole unlike VarDCT
spider-mario it’s preserved the ICC, at least
2024-01-16 12:32:24
interesting, discord strips jpegli --xyb iccs inline but not when you open in browser
lonjil wow the original looks real bad in firefox
2024-01-16 12:33:36
for weesen.jpg? looks identical in firefox as it does in mpv for me
2024-01-16 12:34:04
however my monitor is SDR (i.e. sRGB)
jonnyawsom3
Traneptora interesting, discord strips jpegli --xyb iccs inline but not when you open in browser
2024-01-16 12:44:49
It has the ICC, Discord just ignores them when decoding, for whatever reason
Traneptora for weesen.jpg? looks identical in firefox as it does in mpv for me
2024-01-16 12:45:20
I assume they meant the one I posted, which looks like a brown-green smear in Discord
Traneptora
2024-01-16 12:48:14
oh that one, yea it looks like an orange -> geren gradiant but it's got terrible banding in firefox
jonnyawsom3
2024-01-16 01:36:14
Some of the banding gets mitigated at 100% zoom, including viewing locally to get a band free image for me, but there's still a difference between the images at least
Demiurge
2024-01-16 03:58:24
why does the last one look so horrible?
2024-01-16 04:00:39
oh wait it's not the last one it's the first one
2024-01-16 04:02:37
In Gwenview, the JPEG has banding but the other two are silky smooth.
2024-01-16 04:02:54
In Firefox, all of them have banding but the original looks butt fugly
2024-01-16 04:03:05
weird
2024-01-16 04:06:09
Also, jpegli --xyb produces 420 by default instead of 444. Unless you use a really long parameter to tell it to use xyb444
2024-01-16 04:06:33
Isn't this a bug or oversight? since libjxl cannot losslessly recompress it unless it's 444
2024-01-16 04:07:04
Also, jpegli --xyb seems to make images noticeably a lot darker.
2024-01-16 04:07:27
I don't have a github account, someone should open an issue...
2024-01-16 04:07:36
Or I should stop being lazy and create one...
2024-01-16 04:11:37
Wow, what the hell? Here's another weird thing with libjxl
2024-01-16 04:12:53
`cjxl -d 0 -e 8 Gradient.png Gradient.png.jxl` -> 17,775 bytes
2024-01-16 04:13:45
`cjxl -d 0 -e 9 Gradient.png Gradient.png.jxl` -> 77.985 bytes
2024-01-16 04:20:40
so effort 9 produces a file that is over 400% bigger than effort 8
2024-01-16 04:20:47
How does that make sense?
2024-01-16 04:20:58
This is using 0.8.2 by the way since arch linux is slow to update
jonnyawsom3
Demiurge In Gwenview, the JPEG has banding but the other two are silky smooth.
2024-01-16 04:30:09
The last image is the same jpeg decoded through jpegli and output to a png, so at least they worked like I expected
Demiurge Also, jpegli --xyb produces 420 by default instead of 444. Unless you use a really long parameter to tell it to use xyb444
2024-01-16 04:30:57
That would explain the subsampling values I saw while analysing the files, I assumed it was just an error from the tool not understanding XYB
Demiurge Isn't this a bug or oversight? since libjxl cannot losslessly recompress it unless it's 444
2024-01-16 04:32:16
Huh, really? I know there were issues transcoding in the past due to subsampling the blue but that was meant to be fixed
Demiurge so effort 9 produces a file that is over 400% bigger than effort 8
2024-01-16 04:34:06
Huh, I used e 9 but forced the predictor to 5 for gradient only, assuming it would make the most sense. Got smaller than the default at least but apparently e 8 found a whole lot better
Demiurge
2024-01-16 04:35:00
Yeah, why is e 8 producing a file so much smaller than e9?
Huh, really? I know there were issues transcoding in the past due to subsampling the blue but that was meant to be fixed
2024-01-16 04:36:06
it's not fixed. jpegli still produces 4:2:0 XYB unless you use a really long extra parameter to disable chroma subsampling
jonnyawsom3
2024-01-16 04:36:43
Huh... Guess that also means the gradient could be even smoother too
Demiurge
2024-01-16 04:38:25
In latest git version, e8 is also much better than e9
2024-01-16 04:38:48
Also the compression ratio is worse than 0.8.2
eddie.zato
2024-01-16 05:42:43
When building libjxl tools, should libjxl be built with jpegli and sjpeg support, or is it better to choose one or the other since they are both jpeg encoders?
_wb_
Demiurge so effort 9 produces a file that is over 400% bigger than effort 8
2024-01-16 06:31:58
That is weird. Can you open an issue about it? With the image for which this happens.
Demiurge
Original 16 bit Rec.2020, XYB Jpeg, 16 bit Jpegli Output
2024-01-16 06:33:47
The image is the original here
2024-01-16 06:34:03
Gradient.png
2024-01-16 06:37:16
I don't have a github account yet.
2024-01-16 07:17:32
And I wouldn't recommend waiting until I make one to file an issue...
_wb_
2024-01-16 08:20:27
ok thanks, I can reproduce the issue
2024-01-16 08:45:36
wait I can reproduce with cjxl 0.9.1 but with current git I cannot even encode that image anymore: ``` JPEG XL encoder v0.10.0 7b1d243a [NEON] Encoding [Modular, lossless, effort: 9] lib/jxl/cms/jxl_cms.cc:971: JXL_RETURN_IF_ERROR code=1: skcms_Parse(icc_data, icc_size, &profile) lib/jxl/cms/color_encoding_cms.h:520: JXL_RETURN_IF_ERROR code=1: cms.set_fields_from_icc(cms.set_fields_data, new_icc.data(), new_icc.size(), &external, &new_cmyk) lib/jxl/encode.cc:1098: ICC profile could not be set JxlEncoderSetICCProfile() failed. EncodeImageJXL() failed. ```
Demiurge
2024-01-16 08:47:58
I was able to encode it just fine on git build I made yesterday
_wb_
2024-01-16 09:47:44
maybe it's an lcms vs skcms thing
veluca
2024-01-16 10:26:33
I see headaches coming here...
lonjil
Traneptora for weesen.jpg? looks identical in firefox as it does in mpv for me
2024-01-16 12:03:50
I mean Gradient.png
oupson
2024-01-16 12:30:04
I'm adding thumbnail support on my lib for android, is there any way to create jxl files with preview or any existing files to test on ?
jonnyawsom3
2024-01-16 02:54:28
One way to do preview is partially load progressive files
oupson
One way to do preview is partially load progressive files
2024-01-16 03:20:12
I was looking for ways to try JXL_DEC_PREVIEW_IMAGE, as I already implemented a solution based on JxlDecoderSetProgressiveDetail
yoochan
2024-01-16 04:39:05
If I understood properly, decoding a jxl file up to the first group should give you a 1:8th thumbnail...
2024-01-16 04:39:49
But I didn't played enough with the libjxl to give you more details
Demiurge
2024-01-16 05:47:18
I notice jxl files have a tiny jxlp in the beginning and a much larger jxlp at the end
Traneptora
Demiurge I notice jxl files have a tiny jxlp in the beginning and a much larger jxlp at the end
2024-01-16 06:17:17
libjxl does this in order to put codestream-level metadata earlier in the file
oupson I'm adding thumbnail support on my lib for android, is there any way to create jxl files with preview or any existing files to test on ?
2024-01-16 06:20:23
JXL codestreams support embedded preview frames, but as far as I'm aware libjxl doesn't have an API to produce them yet
oupson
Traneptora JXL codestreams support embedded preview frames, but as far as I'm aware libjxl doesn't have an API to produce them yet
2024-01-16 06:20:49
Ok, thank you !
Traneptora
2024-01-16 06:21:04
You could open an issue to allow them to track the feature
Demiurge
2024-01-16 06:37:34
What about progressive encode mode?
jonnyawsom3
2024-01-16 07:05:35
There's a few ways to do it. Depending on how much effort you want to put in, you could first try finding a thumbnail frame, if that fails then try checking for a progressive scan, if that fails then fallback to standard decoding (Or whatever you'd usually do)
Demiurge so effort 9 produces a file that is over 400% bigger than effort 8
2024-01-17 12:29:47
Did a quick test and group size seems to be a large factor, at `-e 9` it was `-g 0 0.305 bpp` `-g 1 0.301 bpp` `-g 2 0.049 bpp` `-g 3 0.596 bpp`
2024-01-17 12:30:29
Strange that it finds such an efficient path at 512x512, but nothing else near the rest
Traneptora
2024-01-17 01:12:54
now that's interesting, but this is valuable insight to see what it's doing with a group size shift of 2
2024-01-17 01:13:05
and to try to figure out why it isn't doing that with the others
_wb_
2024-01-17 09:23:41
i'll try to understand what is going on here. I'm thinking maybe some catastrophically bad choices in palette or channel palette decisions...
Tirr
2024-01-17 09:26:03
I remember I sometimes get better results with palette disabled completely
_wb_
2024-01-17 10:08:03
hm, in both the e9g2 (which is good) and the default e9 (which is very bad) it does apply a global channel palette on the R and on the B, reducing the 16-bit range to 1919 colors each. Looks like the G doesn't get reduced globally. Then in every group, in both cases it applies a local 3-channel palette, which has about 300 colors in the case of 256x256 groups and about 600 colors in the case of 512x512 groups.
2024-01-17 10:27:30
<@179701849576833024> the only difference I can see between the 19kb e8 and the 77kb e9 jxl files, is that the e9 uses a different MA tree for the palette-indexed group data (it has 69 nodes at e9 and 61 nodes at e8, haven't checked how different the trees are), that apparently leads to a lot worse compression (2-5 times as many bytes in every group). Everything else (i.e. the global/local transforms) seems to be identical.
2024-01-17 10:30:12
it's a rather spectacular case of tree learning producing a worse outcome at a higher effort, which might indicate a bug...
2024-01-17 10:34:09
the thing with MA tree learning is that whatever tree the encoder uses, we won't detect a bug because it will still be a valid bitstream that losslessly represents the image data, so functionally nothing is wrong except compression becomes suboptimal — though even with a really bad tree, ctx clustering will limit the damage...
veluca
_wb_ it's a rather spectacular case of tree learning producing a worse outcome at a higher effort, which might indicate a bug...
2024-01-17 10:34:10
I mean, it's a heuristic, so not sure if we are that lucky xD
_wb_
2024-01-17 10:35:04
yeah but it's supposed to be based on an entropy estimate that should be more or less accurate, no?
veluca
2024-01-17 10:35:07
I really should get down to do that MA tree variant where a bunch of layers are computer at once (and all use the same property)
_wb_ yeah but it's supposed to be based on an entropy estimate that should be more or less accurate, no?
2024-01-17 10:35:18
Yes, but it's greedy
2024-01-17 10:35:32
So you never know if the second layer would be able to do magic
_wb_
2024-01-17 10:38:00
yeah, I just didn't expect the greedy result to be able to get that much worse than another greedy result (where presumably the bad greedy choice is simply pruned from the search space because of the lower effort, so by luck it arrives at something better)
veluca
2024-01-17 10:39:49
That's greedy algorithms for you 😛
_wb_
2024-01-17 10:40:04
this means that the potential for some less greedy approach to compress better is more significant than what I assumed
veluca
veluca I really should get down to do that MA tree variant where a bunch of layers are computer at once (and all use the same property)
2024-01-17 10:42:18
The nice thing of doing that is that you also get to decode faster
_wb_
2024-01-17 10:52:25
yes, so it could lead to both better compression (because less greedy) and faster decode. Until now I was assuming that it would be mostly useful for faster decode at the cost of worse compression (because no arbitrary trees but some forced structure), but now I'm starting to think that the advantage of seeing more than one binary split at a time could very well outweigh the issue of no-arbitrary-trees — especially because we're doing ctx clustering at the end anyway, so it doesn't matter that much if the tree is bigger than it could be when not forcing a structure that allows avoiding branching by doing a bunch of layers at a time as a lookup.
veluca
2024-01-17 06:39:42
<@853026420792360980> will you give a shot at fixing the gdk pixbuf?
Traneptora
veluca <@853026420792360980> will you give a shot at fixing the gdk pixbuf?
2024-01-17 06:40:05
I can put it on my to-do list but I can't necessarily get to it today
2024-01-17 06:40:16
I did figure out what the issue was last night (per the comment on that issue)
veluca
2024-01-17 06:40:25
yep I did see that
Traneptora
2024-01-17 06:40:25
and it's both a bug in libjxl and a bug in the plugin
veluca
2024-01-17 06:41:07
😭
Traneptora
2024-01-17 06:41:12
I'm prepping for a meeting that's in 1.5 hours. depending on how long that meeting lasts I might have time to get to it afterward
2024-01-17 06:45:18
btw wrt https://github.com/libjxl/libjxl/issues/3131
2024-01-17 06:45:34
the issue with *this one* is that the ICC is invalid but cjxl doesn't notice that
2024-01-17 06:45:53
it occurred to me in general though that the design of the ICC transform to make it more compressible might not work for invalid ICCs
2024-01-17 06:46:20
and I'm wondering what the general idea for that is, in general
2024-01-17 06:46:43
e.g. in the above scenario, with an invalid JPEG ICC
2024-01-17 06:47:46
(1) refuse to losslessly transcode and error out? (2) refuse to losslessly transcode unless --strip is passed? (3) assume that an invalid ICC is not present, and encode as sRGB, with a warning (4) possibly store the invalid ICC in the jbrd box somehow so it could be reconstructed anyway?
2024-01-17 06:47:53
I don't know how futureproof jbrd is
veluca
Traneptora it occurred to me in general though that the design of the ICC transform to make it more compressible might not work for invalid ICCs
2024-01-17 07:00:17
wdym not work?
Traneptora
2024-01-17 07:00:53
I mean, the forward-transform on the ICC profile to make it more compressible assumes the ICC is valid, right?
2024-01-17 07:01:42
what if it isn't?
2024-01-17 07:01:55
for example, what if there's a length mismatch? what if it's too small? etc.
2024-01-17 07:02:13
these sorts of invalid ICCs can be embedded in png and jpg files in the wild, and can be passed to the library
veluca
2024-01-17 07:05:45
Mhhh I think it will just do stuff that gives you a less compressible icc, it shouldn't fail
Traneptora
2024-01-17 07:17:34
in the above issue it produces an invalid jxl file and reports success
2024-01-17 07:17:40
which is definitely wrong
veluca
2024-01-17 07:21:26
I do agree that cjxl should probably give an error
2024-01-17 07:21:34
in case the ICC profile is broken
_wb_
2024-01-17 07:35:49
We don't really specify that a jxl file with a broken ICC profile is invalid, or do we? In principle we can still represent such a jpeg file and reconstruct it too.
veluca
2024-01-17 08:05:11
welll things such as modular use the ICC to read channel counts no?
Traneptora
veluca welll things such as modular use the ICC to read channel counts no?
2024-01-18 12:12:23
modular uses the ImageMetadata bundle for that
2024-01-18 12:13:04
The ICC isn't actually needed to decode an otherwise-valid JXL file - you can decode the compressed entropy stream and ignore what's in it
2024-01-18 12:13:22
the problem is that in the image above, it doesn't attempt to ignore what's in it and instead de-mangle it, and that process fails
veluca
2024-01-18 12:17:12
mhhh fair point
_wb_
2024-01-18 06:36:06
I think three things: 1. It would be better for a decoder not to fail when faced with an ICC profile it cannot understand, but produce a warning and replace it with the assumption that it's sRGB or something. 2. It would be better for an encoder to at least produce a warning when it gets invalid ICC input (could be a warning if it doesn't need to convert colors, an error if it does) 3. We should probably consider jxl files with an invalid ICC profile as invalid files, so decoders can do whatever (refuse to decode or do something best effort). In particular, libjxl could still reconstruct jpegs but refuse to render them to pixels.
Traneptora
2024-01-18 08:49:47
Well, now that's interesting
2024-01-18 08:50:18
``` ==18868== Process terminating with default action of signal 11 (SIGSEGV): dumping core ==18868== Access not within mapped region at address 0x1 ==18868== at 0x668133D: JxlDecoderGetICCProfileSize (decode.cc:2261) ==18868== by 0xF26C26B: load_increment (pixbufloader-jxl.c:426) ```
2024-01-18 08:51:38
the line number is wrong though
2024-01-18 08:52:15
this is the line that's erroring out
2024-01-18 08:52:22
``` if (size) { *size = jxl_color_encoding->ICC().size(); } ```
2024-01-18 08:52:36
this implies that `0x1` is being passed
2024-01-18 08:52:59
but the pixbuf loader is passing an address
2024-01-18 08:53:20
like it's using the & operator to pass the address of a stack variable
2024-01-18 08:53:24
so it shouldn't be passing 1
2024-01-18 08:54:39
oh, I see what's happening, this is the ABI break that occurred between 0.8 and 0.9
spider-mario
2024-01-18 08:55:07
is it loading the wrong libjxl at runtime?
Traneptora
2024-01-18 08:55:15
it must be loading the system libjxl, which is 0.8.2
2024-01-18 08:55:26
but the pixbuf loader I'm testing is not that
2024-01-18 08:55:36
this is the ABI breakage where the `JxlPixelFormat *` argument was removed from the middle of a function signature
2024-01-18 08:57:50
however, using LD_PRELOAD=`build/lib/libjxl.so` doesn't appaer to help
veluca
2024-01-18 08:58:32
what's `ldd` saying?
Traneptora
2024-01-18 08:58:36
and running `ldd` on the pixbuf loader is saying it's already linked
veluca
2024-01-18 08:58:44
ah
2024-01-18 08:58:55
perhaps it linked the system one at build time ~statically?
2024-01-18 08:58:57
kinda weird though
Traneptora
2024-01-18 08:59:02
``` $ ldd build/plugins/gdk-pixbuf/libpixbufloader-jxl.so linux-vdso.so.1 (0x00007ffd10563000) libjxl.so.0.10 => /home/leo/Development/libjxl/build/lib/libjxl.so.0.10 (0x00007efdf4200000) libjxl_threads.so.0.10 => /home/leo/Development/libjxl/build/lib/libjxl_threads.so.0.10 (0x00007efdf45a3000) libgdk_pixbuf-2.0.so.0 => /usr/lib/libgdk_pixbuf-2.0.so.0 (0x00007efdf4533000) libgobject-2.0.so.0 => /usr/lib/libgobject-2.0.so.0 (0x00007efdf419e000) libglib-2.0.so.0 => /usr/lib/libglib-2.0.so.0 (0x00007efdf4052000) libc.so.6 => /usr/lib/libc.so.6 (0x00007efdf3e70000) libjxl_cms.so.0.10 => /home/leo/Development/libjxl/build/lib/libjxl_cms.so.0.10 (0x00007efdf3e30000) ``` plus some additional system libraries
veluca
2024-01-18 08:59:13
yeah, seems right
2024-01-18 08:59:29
how are you running the loader?
2024-01-18 08:59:46
perhaps whatever you use loads libjxl.so for other reasons
Traneptora
2024-01-18 08:59:53
``` LD_PRELOAD=build/plugins/gdk-pixbuf/libpixbufloader-jxl.so eom red-room.jxl ```
veluca
2024-01-18 09:00:22
I'd strace to see when libjxl gets loaded 😄
Traneptora
2024-01-18 09:01:23
I'm not sure how to do that, can you please elaborate?
veluca
2024-01-18 09:03:50
something like `LD_PRELOAD=build/plugins/gdk-pixbuf/libpixbufloader-jxl.so strace -ff eom red-room.jxl 2>&1 | grep -C 5 libjxl`
Traneptora
2024-01-18 09:06:56
oh well that's a lot of system calls
veluca
2024-01-18 09:08:01
ah yes, yes it is
Traneptora
2024-01-18 09:08:40
okay I can see the system call where it opens /usr/lib/libjxl.so.0.8
2024-01-18 09:09:03
it's right after `[pid 20601] openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 14`
2024-01-18 09:09:57
and then an mmap and then a close
2024-01-18 09:10:11
more specifically
2024-01-18 09:10:15
``` [pid 20601] openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 14 [pid 20601] newfstatat(14, "", {st_mode=S_IFREG|0644, st_size=171219, ...}, AT_EMPTY_PATH) = 0 [pid 20601] mmap(NULL, 171219, PROT_READ, MAP_PRIVATE, 14, 0) = 0x7f74c8133000 [pid 20601] close(14) = 0 [pid 20601] openat(AT_FDCWD, "/usr/lib/libjxl.so.0.8", O_RDONLY|O_CLOEXEC) = 14 ```
2024-01-18 09:16:25
LD_PRELOADing the built libjxl doesn't change it
spider-mario
2024-01-18 09:18:36
and just to be sure, it doesn’t load libjxl.so if you don’t load the plugin, right?
Traneptora
2024-01-18 09:21:27
if I don't LD_PRELOAD anything then it loads the system libjxl and system pixbuf loader
2024-01-18 09:22:00
(which works fine)
ProfPootis
2024-01-23 06:20:56
This might be more of a bash question, but is there any way to output a jxl with the same filename as the input, just with the .jxl extension? The plan is to have input be *.jpg and there's only one in the directory
spider-mario
2024-01-23 06:21:29
I tend to use `parallel` even then
2024-01-23 06:22:04
```console $ parallel cjxl '{}' '{.}.jxl' ::: *.jpg ```
ProfPootis
2024-01-23 06:22:50
ooh thanks!
spider-mario
2024-01-23 06:22:58
but if you don’t want to do that: ```bash shopt -s nullglob for f in *.jpg; do cjxl "$f" "${f%.jpg}.jxl" done ```
Traneptora
ProfPootis This might be more of a bash question, but is there any way to output a jxl with the same filename as the input, just with the .jxl extension? The plan is to have input be *.jpg and there's only one in the directory
2024-01-23 06:45:22
yea, generally speaking you use `"${var%foo}"` to expand `"$var"` but with a trailing `foo` removed
2024-01-23 06:45:29
useful for replacing file extensions with another one
yoochan
2024-01-23 07:10:18
nice ! in zsh you can do `${var:r}.jxl`
ProfPootis
2024-01-23 07:10:57
tysm!
qdwang
2024-01-24 05:43:56
Hi guys, what does `uses_original_profile` acutally mean? It seems changing this parameter in `libjxl` can affect the result size a lot.
Traneptora
2024-01-24 06:14:55
if `uses_original_profile` is set to *false* it tells libjxl to use XYB-encoding when encoding the output image
2024-01-24 06:15:15
which means that it encodes it in the XYB color space, which is an absolute, perceptual space
2024-01-24 06:15:24
this is typically what you want to be doing for lossy encodes
2024-01-24 06:15:37
`uses_original_profile` set to *true* disables colorspace conversions on encode
2024-01-24 06:15:52
which is usually not what you want, unless you're encoding losslessly
2024-01-24 06:15:56
if you're doing lossless it's required to set it to true
2024-01-24 06:16:09
but otherwise you usually want to set it to false
qdwang
Traneptora `uses_original_profile` set to *true* disables colorspace conversions on encode
2024-01-24 07:18:39
so if the input is raw RGB values and `uses_original_profile` is set to `false`, and still the process is set to lossy encoding, what will happen? I've tried some tests, sometimes `uses_original_profile=true` generates larger file and sometimes doesn't
2024-01-24 07:19:33
If it doesn't convert to XYB, does it process the compress in RGB mode?
Traneptora
so if the input is raw RGB values and `uses_original_profile` is set to `false`, and still the process is set to lossy encoding, what will happen? I've tried some tests, sometimes `uses_original_profile=true` generates larger file and sometimes doesn't
2024-01-24 07:21:01
if `uses_original_profile = false` it will use XYB encoding the file size may be larger or smaller based on the number of factors, but XYB should give significantly better quality at a similar filesize for lossy
qdwang
2024-01-24 07:21:29
Oh sorry, I mean `true`
Traneptora
If it doesn't convert to XYB, does it process the compress in RGB mode?
2024-01-24 07:21:35
that's correct, if it doesn't convert it to XYB then it just leaves the pixel data in the original color space
2024-01-24 07:21:45
that's why the option is called `uses_original_profile`
2024-01-24 07:21:48
profile referring to color profile
qdwang
Traneptora that's correct, if it doesn't convert it to XYB then it just leaves the pixel data in the original color space
2024-01-24 07:21:57
Thank you, this solves my question.
Traneptora
2024-01-24 07:22:05
do note that XYB is an internal optimization
2024-01-24 07:22:12
which you typically want enabled
2024-01-24 07:22:18
libjxl does the conversions for you
2024-01-24 07:22:47
so if you ask libjxl for pixel data from an xyb-encoded jxl file, it will return RGB
2024-01-24 07:23:10
in whatever space you request (which is probaby sRGB, or the tagged space)
qdwang
2024-01-24 07:24:41
sure, now I understand this parameter.
_wb_
2024-01-25 04:20:29
I dunno what the desired behavior would be in this case. Produce anything else than the original jpeg file and you break the promise of lossless JPEG recompression...
Traneptora
2024-01-25 04:21:07
How do you attach XMP to a jxl after lossless transcoding?
2024-01-25 04:21:22
and if you do that, should you even expect it to be preserved when converting back to jpeg?
_wb_
2024-01-25 04:21:39
I guess we could try to identify which boxes have been ignored and warn about ignored boxes, but that'll get tricky to implement
Traneptora
2024-01-25 04:22:04
It's unclear that the user in the linked issue uses a lossless JPG transcode though
_wb_
Traneptora How do you attach XMP to a jxl after lossless transcoding?
2024-01-25 04:22:33
Just add a box with some isobmff tool
Traneptora
2024-01-25 04:22:33
> I have jxl image with integrated xmp data inside (lightroom). After conversioning jxl to jpg this data (editions history, keywords, faces and e.t.c.) is gone from jpg file It's possible they're using pixels-to-jpeg
2024-01-25 04:22:53
since they referenced lightroom, which just supports JXL
2024-01-25 04:24:21
tho it *is* a reconstructed jpeg
2024-01-25 04:24:28
I just checked the sample in the issue
2024-01-25 04:24:37
not sure why lightroom is exporting jxl as a recontructed jpeg
_wb_ Just add a box with some isobmff tool
2024-01-25 04:25:50
looks like that's what happened the box layout of the JXL file is `JXL `, `ftyp`, `jxlp`, `jbrd`, `jxlp`, `Exif`, `xml `, EOF
_wb_
Traneptora not sure why lightroom is exporting jxl as a recontructed jpeg
2024-01-25 04:26:15
That's kind of weird indeed. It can also just output real jxl...
Traneptora
2024-01-26 04:42:04
If you got that image by exporting from lightroom, then yes
2024-01-26 08:30:49
why does ubuntu msan randomly fail
2024-01-26 08:31:01
2024-01-26 08:31:02
e.g.
Moritz Firsching
2024-01-26 09:55:41
weird. seems like the failing test is third_party/zlib/test/example.c
spider-mario
2024-01-26 10:28:19
there’s an upstream bug to make it optional https://github.com/madler/zlib/issues/308
2024-01-26 10:28:24
but the maintainer is reluctant
2024-01-26 10:28:48
(I almost wrote “obsolete” instead of “optional” – Freudian slip?)
2024-01-26 10:29:19
(I actually did write it, but caught myself in time before sending)
Traneptora
2024-01-26 10:48:15
it may be a good idea just to not include zlib as a sumbodule
2024-01-26 10:48:26
how many systems don't actually have it built-in
2024-01-26 10:51:31
even windows has deflate built-in although I don't know if they expose a zlib-like API
veluca
2024-01-26 11:50:46
You cannot do msan tests with system libraries
2024-01-26 11:50:53
Or rather, you can, but they will fail
Moritz Firsching
2024-01-27 12:05:25
let's see if updating to a more recent version of zlib helps...
damian101
_wb_ I dunno what the desired behavior would be in this case. Produce anything else than the original jpeg file and you break the promise of lossless JPEG recompression...
2024-01-27 01:19:55
Pretty simple imo: Always transfer JPEG metadata to JXL metadata and all possible JXL metadata to JPEG metadata, and nothing else. JXL should have no special knowledge of the original JPEG metadata.
_wb_
Pretty simple imo: Always transfer JPEG metadata to JXL metadata and all possible JXL metadata to JPEG metadata, and nothing else. JXL should have no special knowledge of the original JPEG metadata.
2024-01-27 03:19:49
JPEG bitstream reconstruction is designed to reproduce exactly the same JPEG file. You would change that and make it produce a different JPEG file that is like the original JPEG but with extra metadata? I think it might be a bit confusing to keep the `jbrd` box around (which is supposed to allow you to reconstruct the exact same jpeg file) while also changing or adding metadata (or changing the image data for that matter), which means you can't reconstruct the exact jpeg file any longer anyway.
jonnyawsom3
2024-01-27 03:26:18
At best, it'd have to be with a warning or specific flag, at worst it would break systems assuming the file to be bit-identical
Traneptora
2024-01-27 03:26:25
If you want to add metadata to the JPEG-transcode JXL then yea you'd have to convert it back to JPEG, add metadata, and then re-encode it to JXL
2024-01-27 03:26:30
at the moment
2024-01-27 03:26:49
theoretically libjxl should be able to modify the file to prevent the roundtrip
2024-01-27 03:27:00
but atm it can't
_wb_
2024-01-27 03:38:46
Maybe instead of making jpeg reconstruction a "succeeds or fails" thing, we could also allow it to produce a jpeg file with the same image data but with different metadata than what the original had. That is, currently if you take a jpeg with xmp metadata, recompress it losslessly as jxl, then modify the xmp so its number of bytes changes, and then try to reconstruct the jpeg, it will just fail (xmp size does not match what was expected for reconstruction). We could instead make it still work but produce some warning return code...
damian101
_wb_ JPEG bitstream reconstruction is designed to reproduce exactly the same JPEG file. You would change that and make it produce a different JPEG file that is like the original JPEG but with extra metadata? I think it might be a bit confusing to keep the `jbrd` box around (which is supposed to allow you to reconstruct the exact same jpeg file) while also changing or adding metadata (or changing the image data for that matter), which means you can't reconstruct the exact jpeg file any longer anyway.
2024-01-27 04:22:01
Right, I don't think anyone really cares about getting the bit-exact input back, as long as the new JPEG is still decoded identically, including essential color metadata, and non-essential metadata as well in case of a simple JPEG -> JXL -> JPEG process... The ability to compress and completely reconstruct the original JPEG sounds quite impressive, but a bit like a waste of space as well... And also like a privacy risk, as metadata can be preserved that the user did not expect to be preserved. The fact that this jbrd box is not essential and can be simply removed is good to know, though... Is there a flag that causes cjxl to not create it in the first place?
Traneptora
Right, I don't think anyone really cares about getting the bit-exact input back, as long as the new JPEG is still decoded identically, including essential color metadata, and non-essential metadata as well in case of a simple JPEG -> JXL -> JPEG process... The ability to compress and completely reconstruct the original JPEG sounds quite impressive, but a bit like a waste of space as well... And also like a privacy risk, as metadata can be preserved that the user did not expect to be preserved. The fact that this jbrd box is not essential and can be simply removed is good to know, though... Is there a flag that causes cjxl to not create it in the first place?
2024-01-27 05:33:13
being able to get the bit-exactness of input back does matter to a lot of people for archival purposes
damian101
2024-01-27 05:33:27
but why
Traneptora
2024-01-27 05:33:33
for archival purposes
2024-01-27 05:33:53
the people who care about bit-exactness of the input file aren't going to be the same people who will be modifying the metadata of the transcoded JXLs
damian101
2024-01-27 05:33:58
why would those people mind lossless recompression
Traneptora
2024-01-27 05:34:01
but they're both important use cases
why would those people mind lossless recompression
2024-01-27 05:34:16
for archival purposes
damian101
Traneptora for archival purposes
2024-01-27 05:34:31
how is anything but the image data and metadata relevant
Traneptora
2024-01-27 05:34:39
for archival purposes
damian101
2024-01-27 05:35:05
those people wouldn't use JXL in the first place
Traneptora
2024-01-27 05:35:13
they would if it guarantees bit-exact reconstruction
2024-01-27 05:35:16
which it does
2024-01-27 05:37:09
what you're basically saying is that for *your* purposes, a perfect reconstruction of the original file is not necessary but that's not the case for everyone
MSLP
Traneptora what you're basically saying is that for *your* purposes, a perfect reconstruction of the original file is not necessary but that's not the case for everyone
2024-01-27 06:25:44
are you thinking "for archival purposes"? 😁
monad
Right, I don't think anyone really cares about getting the bit-exact input back, as long as the new JPEG is still decoded identically, including essential color metadata, and non-essential metadata as well in case of a simple JPEG -> JXL -> JPEG process... The ability to compress and completely reconstruct the original JPEG sounds quite impressive, but a bit like a waste of space as well... And also like a privacy risk, as metadata can be preserved that the user did not expect to be preserved. The fact that this jbrd box is not essential and can be simply removed is good to know, though... Is there a flag that causes cjxl to not create it in the first place?
2024-01-27 07:46:30
Dropbox built [Lepton](https://dropbox.tech/infrastructure/lepton-image-compression-saving-22-losslessly-from-images-at-15mbs) to save space in their cloud storage service, where integrity of user data is essential. Other use-cases could include preserving cultural artifacts or storing digital evidence.
Traneptora
2024-01-27 10:15:42
huh, lepton GH page suggests using jxl
w
2024-01-27 10:43:07
I don't use cjxl for photos because I want to keep the camera metadata
2024-01-27 10:43:46
but if jxl is meant for photos...
2024-01-27 10:43:50
it's fail
Traneptora
w I don't use cjxl for photos because I want to keep the camera metadata
2024-01-27 10:45:05
doesn't it?
2024-01-27 10:45:13
should be a bit perfect reconstruction of the original file
w
2024-01-27 10:45:31
not for non jpeg reconstruction
Traneptora
2024-01-27 10:45:43
are you talking about camera raw -> jxl?
2024-01-27 10:45:48
what does jxl do here that jpeg doesn't
w
2024-01-27 10:46:06
exactly they all suck
Traneptora
2024-01-27 10:46:20
the camera metadata is usually Exif isn't it?
w
2024-01-27 10:46:26
yeah
Traneptora
2024-01-27 10:46:30
which both formats support
2024-01-27 10:46:59
if your camera raw software can't export the exif metadata properly that sounds like an issue with a specific camera raw software, not an issue with jxl or jpeg
w
2024-01-28 02:22:29
is there just nothing that can read it all?
yurume
2024-01-28 02:45:38
I guess exiftool simply lacks support for that, it's not fundamentally difficult to do especially when it's in a container
w
2024-01-28 02:51:02
yurume
2024-01-28 03:02:44
I mean, png and jxl are different formats so exiftool needs to learn more about jxl to support it
w
2024-01-28 03:04:40
but having libjxl to convert it back?
yurume
2024-01-28 03:04:57
well libjxl does know that
w
2024-01-28 03:05:04
yeah and it's still all gone
yurume
2024-01-28 03:06:13
uh I seem to have missed the context then. so you meant that png -> jxl -> png doesn't retain exif tags while some tags are retained, right?
w
2024-01-28 03:06:30
yeah so that makes it appear that exiftool is reading all that's in the jxl
2024-01-28 03:06:41
and it's simply cjxl is not copying it all
yurume
2024-01-28 03:06:42
(and the exiftool warning seems to suggest that this might be the issue of the file itself, see the warning)
w
2024-01-28 03:07:28
I see
2024-01-28 03:09:49
grr what kind of intermediary should I be using if tif isn't supported
yurume
2024-01-28 03:13:15
I tried to look at exiftool but I can't pinpoint the exact origion of that warning message... wat
w
2024-01-28 03:15:14
the metadata is similar(mostly gone) when i use magick directly from tif to jxl
2024-01-28 03:17:11
this is a sucky experience
2024-01-28 03:17:21
jxl is just like webp!
yurume
2024-01-28 03:18:39
ugh found one, https://github.com/exiftool/exiftool/blob/2766977eee43be0f2ac602e7e42fb12c54b33e35/lib/Image/ExifTool/PNG.pm#L1579
2024-01-28 03:18:53
(did you know that exiftool was written in perl?)
2024-01-28 03:20:23
so it's simply warning `tEXt` `zTXt` `iTXt` `eXIf` tags coming after either `IDAT` `JDAT` `JDAA` tags
2024-01-28 03:24:07
https://github.com/libjxl/libjxl/blob/1f9b04f743530c47ef9c0feba31e164ce7390f73/lib/extras/enc/apng.cc#L109-L110 ultimately the culprit turned out to be this
2024-01-28 03:24:34
so libjxl does correctly read `eXIF` chunk, but doesn't yet write `eXIF` chunk by itself
w
2024-01-28 03:24:56
so im not crazy
MSLP
2024-01-28 09:55:21
hmm.... for me it seems to pass around exif metadata. <@288069412857315328> could you try using `cjxl --compress_boxes=0` or using more recent exiftool (support for jxl brotli compressed boxes was added in exiftool 12.63 (June 8, 2023), and also requires perl IO::Compress::Brotli module)
2024-01-28 09:59:07
maybe it's a regression in v0.10; on 0.9 the procedure `jpeg -(convert)-> png -(cjxl)-> jxl -(djxl)-> png` preserves exif till the end
w
2024-01-28 10:29:41
it doesnt pass all of it
2024-01-28 10:29:58
yurume found the issue
Traneptora
veluca <@853026420792360980> will you give a shot at fixing the gdk pixbuf?
2024-01-29 02:28:11
https://github.com/libjxl/libjxl/pull/3218
veluca
2024-01-29 02:30:41
thanks 🙂
Traneptora
veluca thanks 🙂
2024-01-29 02:40:48
looks like all the vcpkg builds failed, but it's not clear why to me or if my change had anything to do with it
2024-01-29 02:40:51
CI seems really fragile
veluca
2024-01-29 02:42:52
> D:\a\libjxl\libjxl\lib\jxl\enc_icc_codec.cc(241,1): error C3493: 'kSizeLimit' cannot be implicitly captured because no default capture mode has been specified [D:\a\libjxl\libjxl\build\lib\jxl_enc-obj.vcxproj]
2024-01-29 02:42:55
yeah not your fault
2024-01-29 02:43:03
I thought that that might happen
Traneptora
2024-01-29 02:43:36
https://github.com/libjxl/libjxl/commit/f5a4d64e5f91069f76ac086984053a1264e885c1
2024-01-29 02:43:39
looks like this is the culprit
veluca
2024-01-29 02:43:42
yep
Traneptora
2024-01-29 02:43:43
prior commit passed
2024-01-29 02:44:01
I don't really see the point of having all these CI checks if merges that break them will happen anyway
veluca
2024-01-29 02:44:02
writing C++ for multiple compilers is the stuff of nightmares, lemme tell you...
2024-01-29 02:44:25
did you set the CI:full label perhaps?
Traneptora
2024-01-29 02:44:32
Nope, I just opened an MR
veluca
2024-01-29 02:44:50
then I am very confused
Traneptora
2024-01-29 02:44:51
only label on the PR is the one you added which is `merge-0.9`
veluca
2024-01-29 02:45:12
it should either have failed in the OOB PR too or in nothing at all
Traneptora
2024-01-29 02:45:16