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

username
2025-01-01 05:38:59
not even just libjxl it's also the format itself correct?
VcSaJen
2025-01-01 05:39:11
yea
Demiurge
0xC0000054 That was the issue, thanks. I think the origin of the bug was my misunderstanding of how `uses_original_profile` interacts with ICC profiles, I had thought that `uses_original_profile` was required for embedding ICC profiles.
2025-01-01 06:18:05
Ohhh, I see... so it should never be set to true when lossy. You can still embed whatever color profile you want, though, in the jxl file. It won't affect how the binary image data itself is encoded though
2025-01-01 06:18:35
It will just be there in case someone wants to know what the original or intended profile is
Quackdoc
2025-01-02 07:58:22
I have a question regarding the jxl-rs BT.709 PR, it looks like it is using oetf and the inverse oetf when going to linear. As far as I know according to BT.2087 one should use either 2.4 power or a 2 power for doing conversion. Is there any reason why jxl-rs should have the inverse function? or even the encoding function considering it's use is supposedly purely for a "source" capacity?
Demiurge
2025-01-02 09:32:29
It makes sense to add encoding to jxl-rs later down the line
2025-01-02 09:33:07
It may be beyond the scope right now, but that might not hold true in the future
2025-01-02 09:34:32
It will almost certainly outclass libjxl at decoding and might become the preferred jxl support library
2025-01-02 09:35:49
Once it's complete it's possible many projects that don't need encode will stop using libjxl entirely
2025-01-02 09:38:18
It's likely to be much cleaner and simpler for outside developers to read and start hacking on too, since it's written from scratch.
Quackdoc
2025-01-02 09:39:07
even then, I can understand maybe having the encode function for an encoder since maybe some sensor wants to be able to pipe data directly to libjxl/jxl-rs if it does get encode support, but I don't believe there is a lot of sense in having the inverse function
dogelition
2025-01-02 09:40:39
agree, the oetf has nothing to do with how images should be displayed, so 2.4 would make way more sense
Demiurge
2025-01-02 09:58:51
What about in the case of decoding an arbitrary lossless image with an arbitrary colorspace, to an arbitrary output colorspace
Quackdoc
2025-01-02 10:06:52
in that case the chances that you want the inverse oetf is extremely slim [av1_dogelol](https://cdn.discordapp.com/emojis/867794291652558888.webp?size=48&name=av1_dogelol)
Tirr
2025-01-02 10:15:14
it's copied from jxl-oxide. oetf is used when decoding xyb encoded images, because xyb-to-rgb procedure returns linear samples. inverse oetf is used when the input is lossless and some other color encoding is requested. lossless samples are already encoded with a specific transfer function, so it needs to be converted back to linear.
2025-01-02 10:16:53
(of course the result won't be lossless in that case ๐Ÿ˜›, but jxl-oxide allows requesting other color encoding)
Demiurge
2025-01-02 10:18:18
It won't be lossless but sometimes you want to decode to whatever it's going to be displayed as
dogelition
2025-01-02 10:20:16
right, but the bt.709 oetf exists to achieve a certain non-unity end-to-end gamma, and really shouldn't be used for anything other than encoding scene light and for image colorimetry, you always (?) want to work with display light instead
Quackdoc
2025-01-02 10:21:18
doing inverse oetf -> xyb -> some other format will result in a wrong image. Like wise, any processing done may also result in the wrong image assuming the processing is supposed to take into account the stuffs.
dogelition
dogelition right, but the bt.709 oetf exists to achieve a certain non-unity end-to-end gamma, and really shouldn't be used for anything other than encoding scene light and for image colorimetry, you always (?) want to work with display light instead
2025-01-02 10:21:30
(and the only use for the inverse oetf that i'm aware of is making certain adjustments like exposure in scene light)
Quackdoc
2025-01-02 10:24:12
also likewise, going from XYB -> "rec 709" should almost certainly be done using BT.1886 unless you are dumping raw camera info into an xyb encode without doing the pre-requisite processing
2025-01-02 10:24:48
There is a case to be had for that granted, but im just not sure how that pipeline would look and if the oetf would be valid there.
veluca
2025-01-02 10:27:52
pretty sure libjxl does the same, fwiw
Tirr
2025-01-02 10:28:00
well the spec says "As specified in ITU-R BT.709-6" for `k709` transfer function kind, so I think we should follow that. if BT.1886 is intended then it can still be signalled as gamma 2.4
veluca pretty sure libjxl does the same, fwiw
2025-01-02 10:28:27
I was also going to say that ๐Ÿ˜„
2025-01-02 10:29:10
uh well it seems that bt.709 refers to bt.1886
2025-01-02 10:30:03
maybe not, color specifications are such a mess
veluca
2025-01-02 10:30:57
I usually invoke <@604964375924834314> whenever I have doubts about this stuff
Demiurge
2025-01-02 10:31:01
Just one tiny nitpick. It's < 0.018 not <=
2025-01-02 10:32:03
Likewise for 0.081
2025-01-02 10:32:31
At least according to wikipedia
veluca
2025-01-02 10:33:01
doesn't really make a difference ๐Ÿ˜›
Tirr
2025-01-02 10:33:14
it's supposed to be continuous so it shouldn't matter so much
Demiurge
2025-01-02 10:36:24
The difference is arguably infinitesimally small even
Quackdoc
2025-01-02 10:37:14
in the end, as far as I know, bt.1886 is intended to be the "accurate as possible" way to decode rec.709 footage while taking into consideration issues that CRT's "generally had" as for the hard "it should be decoded using a pure 2.4 or 2.0 power" comes from https://www.itu.int/dms_pubrec/itu-r/rec/bt/R-REC-BT.2087-0-201510-I!!PDF-E.pdf page 3 (of the document, page 5 of the pdf)
Demiurge
2025-01-02 10:37:22
But it does save you 2 less characters
Quackdoc
2025-01-02 10:38:27
``` Non-linear to linear conversion from normalized Rโ€ฒGโ€ฒBโ€ฒ colour signals Eโ€ฒREโ€ฒGEโ€ฒB (Rec. 709) to linearly represented, normalized RGB colour signals EREGEB (Rec. 709) is accomplished by one of two equations which produce slightly different colours from each other: Case #1: In the case where the goal is to preserve colours seen on a Rec. 709 display1 when displayed on a Rec. 2020 display2, an approximation of the electro-optical transfer function (EOTF) from Recommendation ITU-R BT.1886 (Rec. 1886) is used: ๐ธ = (๐ธโ€ฒ)2.40, 0 โ‰ค ๐ธโ€ฒ โ‰ค 1 Case #2: In the case where the source is a direct camera output and the goal is to match the colours of a direct Rec. 2020 camera output, an approximation of the Rec. 709 inverse opto-electronic transfer function (OETF) is used (see Annex 2): ๐ธ = (๐ธโ€ฒ)2, 0 โ‰ค ๐ธโ€ฒ โ‰ค 1 ```
2025-01-02 10:38:52
well I was hoping copy and paste would format that a bit better, dunno why, it never does.
dogelition
2025-01-02 10:40:46
note: 2.4 gamma isn't just an approximation, but it's exactly what you get on a display with 0 black levels (e.g. oled)
Quackdoc
2025-01-02 10:41:37
it's not that 2.4 is an approximation, it's that 0 black levels is an approximation [av1_dogelol](https://cdn.discordapp.com/emojis/867794291652558888.webp?size=48&name=av1_dogelol)
Tirr
2025-01-04 07:13:51
so it seems that bt.709 basically says, use bt.1886 eotf when decoding to display
2025-01-04 07:15:36
and jxl decodes xyb to display-referred linear (this is why we need hlg ootf when encoding back to hlg signal) so we need bt.1886 inverse eotf
Quackdoc
2025-01-04 07:31:40
not only when decoding to display, but also when decoding to linear for the purposes of color conversion, since jxl want's to keep the intent of any color, decoding and encoding using 2.4 is prefered
Traneptora
Tirr so it seems that bt.709 basically says, use bt.1886 eotf when decoding to display
2025-01-04 05:04:58
yes, though it gets complicated, since TRC and EOTF/OETF aren't quite teh same thing
2025-01-04 05:05:17
if the TRC is tagged as BT.709, by spec, if you're linearizing for the purpose of presentation you should use BT.1886
2025-01-04 05:05:48
If you're linearizing *not* for the purpose of presentation (e.g. if you're scaling in linear light) then you use the inverse of the TRC of BT.709 specified in H.273, and then you use the forward on the way back
Quackdoc
Traneptora If you're linearizing *not* for the purpose of presentation (e.g. if you're scaling in linear light) then you use the inverse of the TRC of BT.709 specified in H.273, and then you use the forward on the way back
2025-01-04 06:38:22
really? I've always used 2.4 as per rec.2087 even while doing things like colorwork, while rec is specifically about rec 709 -> rec 2020 I have found that to be the optimal results.
dogelition
Traneptora If you're linearizing *not* for the purpose of presentation (e.g. if you're scaling in linear light) then you use the inverse of the TRC of BT.709 specified in H.273, and then you use the forward on the way back
2025-01-04 07:53:22
but if you use the bt.709 oetf (+ its inverse), you're specifically scaling in scene light and not display light. which is almost never what you want
2025-01-04 07:54:05
unless you're specifically trying to simulate something like an exposure adjustment in a camera that uses the oetf
Quackdoc
dogelition but if you use the bt.709 oetf (+ its inverse), you're specifically scaling in scene light and not display light. which is almost never what you want
2025-01-04 08:01:10
I think you might be confused? scene light, or more accurately referred to as scene referred or scene linear, *is* linear light. Linear is the direct energy values of light. Display light is the signal when the oetf is applied. you typically, not always but usually, want to scale in linear colorspace.
dogelition
2025-01-04 08:01:49
not sure if i'm using the terms right, but what i meant by those is: scene light: the linear light in the real world that goes into a camera display light: the linear light that's emitted by a display when showing the picture
Quackdoc
2025-01-04 08:03:36
Yes, Display light is light that has been modified by an OETF and Scene light is the linear representation of light in essence, it can get a bit more complicated but in the end, "scene light" is what most scalers typically will prefer to work
2025-01-04 08:21:33
the issue with the rec709 transform is that it was in essence "a transform to make content look OK on a CRT" which means it had to be both computationally simple and "generic". Rec.709 is *Not* a hard spec, it is a recommendation for cameras to use, and camera's almost always modified the spec to make it look good, because not all cameras look the same, and not all displays looked the same. However we *do* know that regardless of source image, rec709 encodes are designed to do one of two things, Look good on a CRT, or look good on BT.1886, which is a result of trying to emulate CRT displays. If the intended destination of your encode is a 2.4, or at least, can be most reliably represented with 2.4, then using the inverse oetf is wrong. while in **some** cases you may better preserve the source data, you do not preserve the *intended data* from the artist or device. Using the inverse rec 709 oetf to me only make sense in an authoring workflow and only when you know the source data is encoded in an actual 709 oetf, which as I stated before, is not always the case, and for context I will leave a quote from jack holm https://community.acescentral.com/t/where-exact-numbers-of-rec709-formula-came-from-and-a-question-about-p3/3940/5 ``` Itโ€™s all about what results in a pleasing image on the display! ... The Rec 709 OETF is a โ€œreferenceโ€ OETF โ€“ a reference for camera makers and for conversions of scene-referred colorimetry to the Rec 709 encoding. In practice, camera makers may use slightly different OETFs to optimize results for specific camera characteristics and to produce their desired default looks for their cameras. ... It is not reliable to assume that the Rec 709 OETF has actually been used, unless this is known to be the case. ... A far better reference for the desired colorimetry is the Rec 1886 EOTF, and even in this case one is assuming the content was mastered for the Rec 1886 reference display and viewing conditions. ```
2025-01-04 08:26:00
the reason why this doesn't really apply to sRGB is because A) the "collection of official and unofficial sRGB specs" have a long history of contradictory information that has caused both displays and produces to encode and display sRGB content in a wide variety of wrong ways. B) It is generally safe to assume that content that has been produced via a linear -> display transform would have been done using the sRGB oetf, however when doing color work, this discrepancy in how the author likely wanted it to be displayed needs to be taken into consideration and compensation needs to be done C) no one cares about sRGB, everyone just kinda agrees that sRGB will never really be consistent so we can only do a "best guess"
Traneptora
Quackdoc the issue with the rec709 transform is that it was in essence "a transform to make content look OK on a CRT" which means it had to be both computationally simple and "generic". Rec.709 is *Not* a hard spec, it is a recommendation for cameras to use, and camera's almost always modified the spec to make it look good, because not all cameras look the same, and not all displays looked the same. However we *do* know that regardless of source image, rec709 encodes are designed to do one of two things, Look good on a CRT, or look good on BT.1886, which is a result of trying to emulate CRT displays. If the intended destination of your encode is a 2.4, or at least, can be most reliably represented with 2.4, then using the inverse oetf is wrong. while in **some** cases you may better preserve the source data, you do not preserve the *intended data* from the artist or device. Using the inverse rec 709 oetf to me only make sense in an authoring workflow and only when you know the source data is encoded in an actual 709 oetf, which as I stated before, is not always the case, and for context I will leave a quote from jack holm https://community.acescentral.com/t/where-exact-numbers-of-rec709-formula-came-from-and-a-question-about-p3/3940/5 ``` Itโ€™s all about what results in a pleasing image on the display! ... The Rec 709 OETF is a โ€œreferenceโ€ OETF โ€“ a reference for camera makers and for conversions of scene-referred colorimetry to the Rec 709 encoding. In practice, camera makers may use slightly different OETFs to optimize results for specific camera characteristics and to produce their desired default looks for their cameras. ... It is not reliable to assume that the Rec 709 OETF has actually been used, unless this is known to be the case. ... A far better reference for the desired colorimetry is the Rec 1886 EOTF, and even in this case one is assuming the content was mastered for the Rec 1886 reference display and viewing conditions. ```
2025-01-05 12:23:06
tbf if the input is tagged as rec709 with cicp or similar, you have nothing else to work with other than the assumption of reference
2025-01-05 12:23:31
so if your goal is to do some sort of image processing (e.g. scaling) in linear light, then roundtripping through the function defined in H.273 (and its inverse) is kinda the best you got
2025-01-05 12:24:31
also, for sRGB, it's not fair to say that you never know. if, for example, libjxl receives an image tagged as sRGB (without an icc profile, just tagged, e.g. sRGB chunk png) then it will use a specific linearization when converting to XYB, so if you're decoding a lossy JXL, it's safe to assume that the formula in H.273 is the correct one if you want to produce a PNG file tagged as sRGB
2025-01-05 12:25:00
since all current JXL encoders use that formula to linearize before applying the Opsin matrix, then any decoder can reasonably use it after applying the Opsin Inverse Matrix
Demiurge
2025-01-05 05:51:54
It's just a transfer curve...
Quackdoc
Traneptora tbf if the input is tagged as rec709 with cicp or similar, you have nothing else to work with other than the assumption of reference
2025-01-05 07:19:18
thats not really true though. We can reliably assume the destination is going to be either BT.1886, a CRT, or a display that roughly mimics a CRT's characteristics. also for sRGB while what JXL does is reliable, it's not reliable to assume how the png itself was crafted. we don't know if the host monitor was a pure 2.2 decode, or an inverse sRGB oetf, nor do we know if the source application used a pure 2.2. The best thing we can do is guess in that case. sRGB will always be a mess lol. even if jxl's solution is perfect, garbage in garbage out
Traneptora
Quackdoc thats not really true though. We can reliably assume the destination is going to be either BT.1886, a CRT, or a display that roughly mimics a CRT's characteristics. also for sRGB while what JXL does is reliable, it's not reliable to assume how the png itself was crafted. we don't know if the host monitor was a pure 2.2 decode, or an inverse sRGB oetf, nor do we know if the source application used a pure 2.2. The best thing we can do is guess in that case. sRGB will always be a mess lol. even if jxl's solution is perfect, garbage in garbage out
2025-01-05 07:24:31
in that case, we should roundtrip with the bt.709 curve defined in H.273
Quackdoc
2025-01-05 07:36:41
I don't really see the benefits of that. since we know that a pure 2.4 power curve is the most accurate for decoding rec709 as bt.1886 establishes, doing work in a 2.4 linearization seems to be the most accurate when it comes to doing processing. rec 2087 also concurrs that when doing rec 708 -> rec 2020, you should do linearization utilizing the the approximation of the bt.1886, the pure 2.4 power curve. It does also explicitly acknowledges that when the source is a direct camera output, and the goal is to match the colors of a "rec 2020 camera output" that you should use an approximation of the inverse 709, which they use a 2 power for. In nearly all cases that we would care about, the goal should be to preserve the colors as seen on a rec 709 display, and only in the cases were we know for sure that this isn't the goal, should we use the inverse 709 oetf, or an approximation of it
2025-01-05 07:40:29
ofc that's not to say the inverse oetf should never be used, if I am recording footage and importing said footage into a video editor, I will often default to using the inverse oetf, but that's simply because the color is better to work with, and im using it to craft ofter things. If you are taking already mastered content, the 2.4 should be used.
jonnyawsom3
2025-01-05 08:45:40
Perhaps <#1288790874016190505> so people can find this more easily later?
Tirr
2025-01-05 09:14:30
uh maybe https://github.com/tirr-c/jxl-oxide/issues/318 is actually related to this
2025-01-05 09:20:34
yeah, it seems to preserve colors if I modify libjxl to use gamma2.4 on BT.709 input
2025-01-05 09:27:42
nevermind, I was comparing with wrong image
2025-01-05 09:39:00
I forgot to modify ICC profile generation part; when I modify it to generate gamma2.4 trc, it does preserve colors
Quackdoc
2025-01-05 09:53:35
the discrepancy between offsets wouldn't cause such a harsh difference in general, though it would cause some
Tirr
2025-01-05 10:06:19
like, without the fix, bt709 to jxl-xyb to srgb doesn't roundtrip visually
2025-01-05 10:08:49
srgb-decoded version looks too bright on dark areas
Quackdoc
2025-01-05 10:15:25
im not sure im following
2025-01-05 10:15:31
ill try to re-read the issue
Tirr
2025-01-05 10:26:35
Encode an image tagged as BT.709 to jxl. Then decode the jxl to BT.709 (no options) and sRGB (`--color_space=RGB_D65_SRG_Rel_SRG`). I expect those two decoded images should look identical, but with current libjxl the sRGB one looks too bright.
2025-01-05 10:27:24
(yeah, now I think this isn't a roundtrip)
2025-01-05 10:28:56
when I modify libjxl to use gamma2.4 on BT.709, two decoded images look identical
Quackdoc
2025-01-05 10:32:11
ah I see. sorry, had a hard time following.
Tirr
2025-01-05 10:34:42
so libjxl is currently applying inverse OETF to encode a BT.709 image so it's encoding in scene light. libjxl also applies OETF when decoding so it works okay when decoding to BT.709, but it breaks when sRGB is requested, because sRGB inverse EOTF works on display light (if I'm getting this right)
spider-mario
2025-01-05 10:36:15
thatโ€™s oddย โ€“ in an ICC workflow, they should look identical regardless of the curve, because the curve thatโ€™s used in decoding should match the one in the ICC profile that is attached to the file
2025-01-05 10:36:37
are you maybe viewing them in Chrome and itโ€™s giving precedence to the CICP chunk?
Tirr
2025-01-05 10:37:55
because libjxl doesn't use ICC workflow when decoding XYB image? I guess it's just FromLinear stage that ignores tagged transfer curve
spider-mario
2025-01-05 10:38:13
I meant in viewing the image
Tirr
2025-01-05 10:38:49
well macOS Preview, Chrome and Firefox all agree that sRGB one is brighter than BT.709 one
Quackdoc
2025-01-05 10:38:52
im a little confused, ill try to break this down. jxl gets image - applies inverse oetf - converts to xyb - converts to linear sRGB - applies rec 709 oetf - rec709.png jxl gets image - applies inverse oetf - converts to xyb - converts to linear sRGB - applies srgb inverse oetf - srgb.png ? the first one will look fine since it is undoing the transfer effectively, but as far as I am aware, the latter will look wrong.
spider-mario
2025-01-05 10:39:06
libjxl will ignore the tagged curve when requesting a specific output colorspace, but which one is requested shouldnโ€™t affect how the decoded image looks, because libjxl should attach an ICC profile to it that matches the curve it effectively used
2025-01-05 10:39:51
if the โ€œoriginal image -> xybโ€ part is wrong, it should be wrong equally for both of them
2025-01-05 10:41:11
that the original image happened to be in BT.709 should be relevant only to whether the decoded image looks like the original
2025-01-05 10:41:19
not whether the two decoded images look the same
2025-01-05 10:41:44
at least as far as I can tell
Tirr
2025-01-05 10:42:20
ah I think I got what you mean, yeah they seem to give precedence to cicp tag then
Quackdoc im a little confused, ill try to break this down. jxl gets image - applies inverse oetf - converts to xyb - converts to linear sRGB - applies rec 709 oetf - rec709.png jxl gets image - applies inverse oetf - converts to xyb - converts to linear sRGB - applies srgb inverse oetf - srgb.png ? the first one will look fine since it is undoing the transfer effectively, but as far as I am aware, the latter will look wrong.
2025-01-05 10:47:34
that's what I think libjxl is doing, yeah
2025-01-05 10:53:12
Chrome shows images look identical if I remove cicp tag from the ICC profile, but in a way that looks too bright
Quackdoc
2025-01-05 02:36:30
in general the top one is fine since you are just reversing the change, the real issue comes when you apply the inverse oetf and go to different spaces. It may not be so bad in many cases, but in others it might be a rather different result
anonymguy
2025-01-05 09:20:35
Hey, I extracted the zip file jxl-x64-windows-static and added it to my PATH, but I still cant use it. (I am on windows 10)
jonnyawsom3
anonymguy Hey, I extracted the zip file jxl-x64-windows-static and added it to my PATH, but I still cant use it. (I am on windows 10)
2025-01-05 09:21:18
What command are you trying to run?
anonymguy
2025-01-05 09:21:34
djxl --version
jonnyawsom3
2025-01-05 09:22:32
Hmm
2025-01-06 09:57:59
https://github.com/google/jpegli
HCrikki
2025-01-06 11:24:17
any nightly binaries that are also accessible publicly ?
Waterpicker
2025-01-06 06:22:52
is there ready avaialble simple package for a .dll .so and .dylib builds of libjxl?
jonnyawsom3
2025-01-07 09:14:10
I originally discounted this as 'higher effort is higher quality' or patches being used, but twice the file size in an image where no patches should be found... It might be worth looking into as a bug, especially as it's a 16bit image https://www.reddit.com/r/jpegxl/comments/1htswuo/comment/m5unvcc/
2025-01-07 09:14:39
> The reference image is a blender rendering for GNOME wallpapers (this particular image is this). I got the original blender assets and re-rendered myself to a higher quality and preserve noise, which is what I'm encoding in the screenshot. The image has some unpredictable noise, but the results seemed pretty good for the file size. It is a reduction from ~400MB (5000x5000x16bit) to some megabytes. I simply found strage the file increase the better the effort.
A homosapien
> The reference image is a blender rendering for GNOME wallpapers (this particular image is this). I got the original blender assets and re-rendered myself to a higher quality and preserve noise, which is what I'm encoding in the screenshot. The image has some unpredictable noise, but the results seemed pretty good for the file size. It is a reduction from ~400MB (5000x5000x16bit) to some megabytes. I simply found strage the file increase the better the effort.
2025-01-07 11:57:00
I don't think its a bug. For images with a large flat areas, the more context libjxl has the better it can achieve its target quality. It seems to detect that it's wildly under shooting the desired butteraugli score and increases the bitrate to compensate.``` cjxl glass-chip-d.jxl glass-chip-compressed.jxl -d 0.5 -e 9 Compressed to 2669.4 kB (1.273 bpp). SSIM2 Score = 84.56 butteraugli = 1.36 cjxl glass-chip-d.jxl glass-chip-compressed.jxl -d 0.5 -e 10 Compressed to 4550.3 kB (2.170 bpp). SSIM2 Score = 88.63 butteraugli = 0.72 ```
2025-01-07 11:58:00
A ssimulacra2 score of 84 is quite low for a distance of 0.5.
2025-01-08 01:40:12
Granted I'm working with the lossy image from the reddit post but I'm gonna retest with a clean source.
Traneptora
2025-01-08 03:27:46
higher file size for higher effort usually means that the lower efforts are undershooting the quality target
jonnyawsom3
A homosapien Granted I'm working with the lossy image from the reddit post but I'm gonna retest with a clean source.
2025-01-08 04:06:55
His image source is 16bit and 5K instead of 4K, and with real rendering noise instead of photon noise. Though, the results you've posted do match rather well
2025-01-08 04:07:54
I doubt you can relay the find as a comment on Reddit?
A homosapien
2025-01-08 04:12:53
I do have a reddit, lemme dust off my old account and get to it.
jonnyawsom3
2025-01-08 09:40:56
Still thinking about this... I wonder how much tweaking and tuning it'll take to be as good as the old method. It seemed to make encoding slower and result in worse Ssimulacra2 scores, which our eyes have been agreeing with ever since https://github.com/libjxl/libjxl/pull/2836
_wb_
2025-01-08 09:49:24
It would be nice to have multiple completely different approaches for encoder heuristics, either with multiple settings of libjxl or by having more alternative encoders.
jonnyawsom3
2025-01-08 09:53:19
It'd be nice, but the use would be limited to those who know what setting fits that particular image best. Back to `-tune`... Since this regression was caused by the metrics giving different results, and only Ssimulacra2 was right, it could even hurt performance
_wb_
2025-01-08 10:07:06
I am not in favor of manual per-image tuning, but having some healthy competition between encoders (all aiming to be good general-purpose encoders) could be a good thing that over time leads to improvements.
2025-01-08 10:12:29
Currently with only one good encoder, we're a bit suffering from the problem that only small incremental changes are made at this point since doing big changes is too scary. That would be less of an issue if there are multiple experimental encoders around...
jonnyawsom3
2025-01-08 10:18:14
Yeah. Looking at the Hydrium encode I just made, it's even using the same block decisions as `-e 7 -d 0.6`. So we haven't seen any other strategies past using cjxl 0.8
2025-01-13 03:22:29
Looking forward to trying this https://github.com/libjxl/libjxl/pull/4062
2025-01-13 03:23:25
Though is the corrupt DC setting the output black, or only the DC so the AC can still show?
_wb_
2025-01-13 04:41:42
The thing is that AC metadata is sent together in the same section with DC groups so if DC is corrupt, the AC metadata will also be corrupt.
2025-01-13 04:42:13
So you cannot really decode or show AC if something is wrong with the corresponding DC group
jonnyawsom3
2025-01-13 04:52:27
Ahh right
Demiurge
_wb_ Currently with only one good encoder, we're a bit suffering from the problem that only small incremental changes are made at this point since doing big changes is too scary. That would be less of an issue if there are multiple experimental encoders around...
2025-01-13 05:12:01
Someone should fork libjxl-ng
2025-01-13 05:12:16
Maybe those psy tuning avif guys...
2025-01-13 05:12:49
But it really just needs a massive code cleanup more than anything
2025-01-13 05:13:59
Simplifying the directory tree and separating out the main library code from the tool code
2025-01-13 05:14:44
That would make it way easier for newcomers to hack on it
AccessViolation_
_wb_ Currently with only one good encoder, we're a bit suffering from the problem that only small incremental changes are made at this point since doing big changes is too scary. That would be less of an issue if there are multiple experimental encoders around...
2025-01-13 05:50:18
why not an `experiments` branch for the encoder, or specific branches for specific experiments?
A homosapien
2025-01-13 06:43:56
I've been talking to the psy av1 guys and they have been working on a psy fork for jxl
Demiurge
2025-01-13 09:27:13
Currently libjxl has multiple different very distinct encoders or encoding modes. It's more accurate to call it a single common frontend to multiple different encoders than to pretend that it's just a single encoder.
2025-01-13 09:29:56
The vardct stuff is pretty separate and contained and so is fjxl
2025-01-13 09:31:57
Also the Squeeze mode has incredible, insane potential considering how it looks better than vardct despite vardct getting all the tuning
2025-01-13 09:35:03
Also I heard there's another interesting palette based encode mode that seems super promising too especially for near-lossless coding
2025-01-13 09:35:29
I forgot the name though
2025-01-13 09:36:05
Honestly all these different encoders could be split into separate folders or something and fjxl can be the default
2025-01-13 09:37:18
Since the speed will instantly knock peoples' socks off and you can never go wrong with lossless
spider-mario
Demiurge I forgot the name though
2025-01-13 10:06:43
ฮ” palette?
Demiurge
2025-01-13 10:07:00
Yeah, lossy palette or delta palette
2025-01-13 10:07:05
Something like that
2025-01-13 10:07:53
Seems like a promising and underused/underrated option
AccessViolation_
2025-01-13 10:10:14
With this many coding tools which can be combined in interesting ways, I wonder if we're going to see encoders tuned for every specific purposes. Like one specifically for screenshots that might eagerly use patches for text, a frame with most of the rest of the image in Modular mode and a VarDCT frame for photographic sections that happen to be in the screenshot, like a wallpaper photo
2025-01-13 10:13:56
Maybe JPEG XL could do with an encoder *engine*(?). A library which gives you the low level building blocks a JXL encoder would need, and allows you to create an encoder tuned for a specific purpose yourself. In a similar sense to Smithay, which is not a Wayland compositor but provides the things you need to build a Wayland compositor, which several compositors are using
2025-01-13 10:15:17
But I'm just thinking aloud
2025-01-13 10:23:06
If you wanted to create an encoder that makes use of a specific combination of coding tools that seem useful for your purpose, you bind to the library and write relatively little code to define the logic of your encoder. Though maybe this can already be achieved with the libjxl API, I just remembered that's a thing and I'm not familiar with it
Cesar
2025-01-13 10:35:51
I have tested `webp` `libx264` `libx265` `AVIF` `AVIF` produces smallest size but biggest CPU usage then `x265` `x264` was the smallest cpu usage with a medium size `webp` good quality and size but also high cpu My software will encode images constantly send them through a websocket and decode them on the server side What about libjxl
AccessViolation_
2025-01-13 10:42:33
I haven't compared them, but with cjxl you can fairly easily change the CPU usage of the encoding process using the effort flag `-e`
spider-mario
Cesar I have tested `webp` `libx264` `libx265` `AVIF` `AVIF` produces smallest size but biggest CPU usage then `x265` `x264` was the smallest cpu usage with a medium size `webp` good quality and size but also high cpu My software will encode images constantly send them through a websocket and decode them on the server side What about libjxl
2025-01-13 10:44:20
webp and libjxl both have a range of possible speeds, but at any given speed, libjxl compresses better https://cloudinary.com/blog/jpeg-xl-and-the-pareto-front#the_pareto_front
AccessViolation_
2025-01-13 10:44:27
you can experiment with `-d` or `-q` for quality and `-e` for encoding effort (how hard it'll try) to strike a balance that fits your purpose
spider-mario
2025-01-13 10:44:49
here is lossless compression
AccessViolation_
2025-01-13 10:44:50
unlike avif encoders which I wouldn't personally even attempt to configure
Cesar
spider-mario here is lossless compression
2025-01-13 10:45:25
Cool, i'll try the c lib
2025-01-13 10:46:05
I'm encoding images of size 960x540, while trying to maintain a quality of around 60%
2025-01-13 10:48:00
The graphic you shared doesnt include `libjpeg-turbo`, have you ever tested it?
spider-mario
2025-01-13 10:48:41
this graphic is for lossless, which libjpeg-turbo doesnโ€™t do
2025-01-13 10:48:45
see further down in the article for lossy
2025-01-13 10:48:52
(where libjpeg-turbo is featured)
Cesar
2025-01-13 10:55:49
There's a package on vcpkg listed as `libjxl:x64-windows` but its not mentioned in the [documentation](https://github.com/libjxl/libjxl/blob/main/doc/developing_in_windows_vcpkg.md), is it "official"?
RaveSteel
2025-01-13 11:25:44
libjpeg-turbo actually does do lossless, but it is pretty much always worse than PNG
CrushedAsian255
AccessViolation_ With this many coding tools which can be combined in interesting ways, I wonder if we're going to see encoders tuned for every specific purposes. Like one specifically for screenshots that might eagerly use patches for text, a frame with most of the rest of the image in Modular mode and a VarDCT frame for photographic sections that happen to be in the screenshot, like a wallpaper photo
2025-01-13 11:34:07
So libjxl could be a common front end and have some way of selecting the best backend encoder for each image (or even section of image)?
Cesar
2025-01-13 11:44:34
Is it not possible to cache the encoder, frame and frame settings?
CrushedAsian255
2025-01-14 12:42:18
Cache the encoder?
2025-01-14 12:42:24
Like CPU cache?
2025-01-14 12:42:34
Or like if an image is being re encoded ?
Cesar
2025-01-14 12:49:43
```c++ class Jxl { public: struct Data { int width = 0; int height = 0; int stride = 0; BYTE* Scan0 = nullptr; using client = websocketpp::client<websocketpp::config::asio_client>; client* wsClient; websocketpp::connection_hdl* connection; } _; std::vector<uint8_t> _compressedData; JxlEncoderPtr _enc; JxlBasicInfo _basicInfo; JxlPixelFormat _format = { 3, JXL_TYPE_UINT8, JXL_NATIVE_ENDIAN, 0 }; JxlEncoderFrameSettings* _frameSettings; Jxl(const Data&& data) : _(data) { _compressedData.resize(223887); JxlEncoderInitBasicInfo(&_basicInfo); _basicInfo.xsize = _.width; _basicInfo.ysize = _.height; _basicInfo.num_color_channels = 3; _basicInfo.bits_per_sample = 8; init(); } bool init() { _enc = JxlEncoderMake(nullptr); if (!_enc) throw std::runtime_error("JXL encoder initialization failed"); JxlEncoderSetBasicInfo(_enc.get(), &_basicInfo); if (_frameSettings) { JxlEncoderFrameSettingsCreate(_enc.get(), _frameSettings); //_enc.get()->encoder_options.emplace_back(_frameSettings); } else { _frameSettings = JxlEncoderFrameSettingsCreate(_enc.get(), nullptr); // Testing encoding settings similar to WebP JxlEncoderSetFrameLossless(_frameSettings, false); JxlEncoderSetFrameDistance(_frameSettings, 13); JxlEncoderFrameSettingsSetOption(_frameSettings, JXL_ENC_FRAME_SETTING_EFFORT, 1); } return true; } bool encode() { if (!init()) throw std::runtime_error("JXL encoder initialization failed"); if (JxlEncoderAddImageFrame( _frameSettings, &_format, static_cast<void*>(_.Scan0), _.stride * _.height) != JXL_ENC_SUCCESS) { return false; } JxlEncoderCloseFrames(_enc.get()); uint8_t* next_out = _compressedData.data(); size_t avail_out = _compressedData.size(); JxlEncoderStatus processResult; do { processResult = JxlEncoderProcessOutput(_enc.get(), &next_out, &avail_out); if (processResult == JXL_ENC_NEED_MORE_OUTPUT) { size_t offset = next_out - _compressedData.data(); _compressedData.resize(_compressedData.size() * 2); next_out = _compressedData.data() + offset; avail_out = _compressedData.size() - offset; } } while (processResult == JXL_ENC_NEED_MORE_OUTPUT); if (processResult != JXL_ENC_SUCCESS) return false; _compressedData.resize(_compressedData.size() - avail_out); websocketpp::lib::error_code ec; _.wsClient->send(*_.connection, _compressedData.data(), _compressedData.size(), websocketpp::frame::opcode::binary); //_compressedData.clear(); return true; } }; ```
2025-01-14 12:55:31
```c++ class Webp { public: WebPConfig _config; WebPPicture _pic; WebPMemoryWriter _writer; struct Data { int width = 0; int height = 0; int stride = 0; BYTE* Scan0 = nullptr; using client = websocketpp::client<websocketpp::config::asio_client>; client* wsClient; websocketpp::connection_hdl* connection; } _; Webp(const Data&& data) : _(data) { WebPConfigInit(&_config); _config.quality = 60; // 0-100, lower = smaller file _config.method = 0; // 0-6, higher = better compression but slower _config.lossless = 0; // Use lossy compression _config.pass = 1; // Number of encoder passes _config.thread_level = 0; // Enable multi-threading //config.near_lossless = 90; WebPPictureInit(&_pic); _pic.width = _.width; _pic.height = _.height; _pic.use_argb = 0; WebPPictureAlloc(&_pic); WebPMemoryWriterInit(&_writer); _pic.custom_ptr = &_writer; _pic.writer = WebPMemoryWrite; } bool encode() { if (!WebPPictureImportRGB(&_pic, _.Scan0, _.stride)) { WebPPictureFree(&_pic); return false; } if (!WebPEncode(&_config, &_pic)) { WebPPictureFree(&_pic); return false; } websocketpp::lib::error_code ec; _.wsClient->send(*_.connection, _writer.mem, _writer.size, websocketpp::frame::opcode::binary); WebPPictureFree(&_pic); WebPMemoryWriterClear(&_writer); return true; } }; ```
2025-01-14 12:56:10
I'm asking if its possible to "cache" the encoder, create it and its settings only once and reuse to encode next images. I'm more constrained by CPU usage.
Demiurge
2025-01-14 04:36:31
Can you use the same context to encode multiple images?
AccessViolation_ With this many coding tools which can be combined in interesting ways, I wonder if we're going to see encoders tuned for every specific purposes. Like one specifically for screenshots that might eagerly use patches for text, a frame with most of the rest of the image in Modular mode and a VarDCT frame for photographic sections that happen to be in the screenshot, like a wallpaper photo
2025-01-14 04:42:47
You shouldn't need to... I think the best possible approach is to optimize each encoding tool as much as possible, even if some tools like patch detection need to be run in their own separate pass, and then make it easier for the individual tools to be combined in effective ways, depending on the effort level.
2025-01-14 04:44:08
Like with more effective image decomposition and layering techniques than just patches
2025-01-14 04:45:57
Grain detection, spline detection, cartoon layer decomposition even
2025-01-14 04:49:02
Imagine if the encoder could automatically tell when DCT is ineffective
2025-01-14 04:49:36
So you don't have to manually specify different options for different types of images
2025-01-14 04:49:54
That's the dream
2025-01-14 04:50:58
Then you don't have to worry about those cases where lossless is actually smaller than dct
A homosapien
2025-01-14 04:53:30
These are plans for the far future though, the major milestone this year is the completion of the rust decoder and (hopefully) its adoption by Mozilla.
AccessViolation_
Demiurge You shouldn't need to... I think the best possible approach is to optimize each encoding tool as much as possible, even if some tools like patch detection need to be run in their own separate pass, and then make it easier for the individual tools to be combined in effective ways, depending on the effort level.
2025-01-14 08:21:48
Yeah this would be good, but heuristics will always be hard to get right. So if you know you're only going to be encoding certain types of images you can specifically tune your encoder for those, instead of hoping the one true encoder makes the right guesses. For example a scanner in 'document mode' would spend more effort on patch detection, and using splines for lines like borders of tables and pen strokes like signatures, while in 'photo mode' it might just spend a lot of effort on the VarDCT stuff
A homosapien
2025-01-14 08:44:51
Just because it's hard doesn't mean we shouldn't pursue it. I don't believe adding tunes is the right direction for libjxl. It's certainly the easy way out but I think it would make things more complicated later on. There is *so much* that can be done to make the encoder smarter. I believe with good heuristics the codec can make good decisions 99% of the time. It's hard to imagine a "dumb codec" existing in the far future.
AccessViolation_
2025-01-14 09:04:57
To be clear I wasn't suggesting these domain specific encoders be made a part of libjxl or developed by the core devs. Rather just existing on their own where they would be useful. I agree that a smarter encoder should be what the effort is poured into for libjxl. It's just that I could see some use cases where you basically know what your data will generally look like ahead of time, and then you could save massively on encode time if it's not trying really hard to figure out things that you already know
jonnyawsom3
Cesar I'm asking if its possible to "cache" the encoder, create it and its settings only once and reuse to encode next images. I'm more constrained by CPU usage.
2025-01-14 09:15:55
At such low effort settings, libjxl essentially works as a JPEG encoder <https://github.com/libjxl/libjxl/blob/main/doc/encode_effort.md> I'd maybe suggest looking at jpegli if not checking what version libjxl you're using and that hardware instructions (SSE, AVX, ect) are enabled properly. On my tests cjxl is working at identical speeds to cwebp following your settings above (Though the webp is 70KB and much higher quality than the 19KB JXL I got...)
Cesar
At such low effort settings, libjxl essentially works as a JPEG encoder <https://github.com/libjxl/libjxl/blob/main/doc/encode_effort.md> I'd maybe suggest looking at jpegli if not checking what version libjxl you're using and that hardware instructions (SSE, AVX, ect) are enabled properly. On my tests cjxl is working at identical speeds to cwebp following your settings above (Though the webp is 70KB and much higher quality than the 19KB JXL I got...)
2025-01-14 09:26:10
I didn't test `jpegli` ill try it, do you? I also tested turbojpeg and from all libs i have tested until now, it was the one with lowest CPU usage.
jonnyawsom3
Demiurge Yeah, lossy palette or delta palette
2025-01-14 10:08:16
Finally got round to checking if it's working in Krita, and yep. A lot of settings seem to have no effect on it, but it scores 5 lower in ssimulacra while preserving more texture to my eyes at a similar bpp to VarDCT (Around distance 0.5) Original, VarDCT, Delta
2025-01-14 10:08:41
2025-01-14 10:11:45
Also <@274048677851430913> the EPF setting in Krita's export dialogue can't be set to -1 to let the encoder choose. Group ordering wasn't working either but you already fixed that for the next release IIRC
Demiurge
2025-01-14 10:38:16
Metrics are guiding people into blindly (literally) making really bad decisions
A homosapien
2025-01-14 10:48:00
I kinda agree with ssimulacra2 here. Lining up the images side-by-side, I could see that delta palette has a somewhat fuzzier look compared to the original even at 1x zoom. VarDCT was a tiny bit smoother but I had to zoom in 2-3x with a flicker test to see it.
Demiurge
2025-01-14 10:56:27
I'm on a phone atm and can't compare them
2025-01-14 10:58:07
Those shadows look ridiculously bad though
2025-01-14 10:59:05
I don't understand why Unreal engine is so ugly and bad these days
Oleksii Matiash
2025-01-14 11:25:43
DeltaDoggo is sharpened a bit comparing to the original or vardct
jonnyawsom3
A homosapien I kinda agree with ssimulacra2 here. Lining up the images side-by-side, I could see that delta palette has a somewhat fuzzier look compared to the original even at 1x zoom. VarDCT was a tiny bit smoother but I had to zoom in 2-3x with a flicker test to see it.
2025-01-14 11:33:39
I was on Irfanview so it resampled at 'full' size, then I went to 500% to spot the differences. Delta has more noise, as expected with reduced colors essentially dithering to compensate, but to me it was preferable to the slight smoothing. In the end, both are good enough and it's surprising how well Delta Palette holds up for not being tweaked in years
Demiurge I don't understand why Unreal engine is so ugly and bad these days
2025-01-14 11:33:45
That was actually over 2 years ago
2025-01-14 11:40:29
At 100% I can't see any difference to the original, 200% I start noticing the noise around high contrast edges, 500% I can see the pallete reduction affecting gradients and the edges are obvious, but ignoring areas like the mouth, I could still think it's the original
Demiurge
A homosapien These are plans for the far future though, the major milestone this year is the completion of the rust decoder and (hopefully) its adoption by Mozilla.
2025-01-14 11:58:54
Mozilla hardly matters at all anymore, hardly anyone uses firefox now that it's essentially in maintenance mode aka life support
2025-01-14 11:59:26
What matters is reversing the decision to remove it from chromium
2025-01-14 12:01:32
Maybe Firefox support would be the tipping point for that? But that is kinda silly considering Safari has way more users
A homosapien
2025-01-14 12:01:52
I think the rust decoder has more leverage than people think
2025-01-14 12:02:04
Maybe I'm being a bit naive
Demiurge
2025-01-14 12:03:53
Maybe I'm being a bit naive in underestimating the influence mozilla has because of their history and (former) reputation despite having almost no users anymore
HCrikki
2025-01-14 12:05:55
imo it has pull power. sites with a proper jxl strategy could end up more lightweight than on other browsers - saving money, becoming profitable instead of not breaking even, having more room for instantly loading ads that dont slow site
2025-01-14 12:07:53
just making usable good code isnt everything though, there should still be militant adoption lobbying for important services like image hosts, cdns
Demiurge
2025-01-14 12:08:13
Also I know js/wasm decoders have disadvantages like waiting for DOM to load for example but most of the time no one is going to notice and you can even have progressive decoding in browsers that don't support it yet using that method
2025-01-14 12:08:29
So I'm honestly surprised it's not used more often
2025-01-14 12:09:31
If people just started using it more often with js/wasm fallback there would be more impetus for browsers to integrate native support
HCrikki
2025-01-14 12:09:35
custom webdev is hard enough, wasm should be part of that but many webdevs arent even aware jxl exists or how people can consume it without safari
Demiurge
2025-01-14 12:09:53
Nothing is really stopping all websites from using it immediately
2025-01-14 12:10:00
In all browsers
2025-01-14 12:10:25
You literally just add 1 line of code to your html pointing to the js decoder
2025-01-14 12:11:11
It requires no brains at all to start using
HCrikki
2025-01-14 12:11:18
link it ?
2025-01-14 12:11:37
im aware of a ludicrously outdated one, anything better ?
Kampidh
Also <@274048677851430913> the EPF setting in Krita's export dialogue can't be set to -1 to let the encoder choose. Group ordering wasn't working either but you already fixed that for the next release IIRC
2025-01-14 12:12:59
oh thanks for the report, on it
Demiurge
2025-01-14 12:13:00
https://github.com/niutech/jxl.js
2025-01-14 12:13:40
I just know about this one. It's braindead simple and just works so what more is there to ask for
HCrikki
2025-01-14 12:14:36
iinm magick wasm can handle jxl but some of such solutions are supposed to be part of custom webdev
2025-01-14 12:16:15
small sites wouldnt move the needle though, ones with high reach/impact ought to push (highest being cdns then photo/image hosts)
2025-01-14 12:17:13
take flickr or photobucket, its 2025 and neither supports dng 1.7
2025-01-14 12:17:56
flickr is egregious since its parent company (smugmug?) supported jxl
jonnyawsom3
2025-01-14 12:18:07
There was this on Reddit recently too https://bevara.com/
Demiurge
HCrikki small sites wouldnt move the needle though, ones with high reach/impact ought to push (highest being cdns then photo/image hosts)
2025-01-14 12:20:13
Disagree strongly. People aren't even aware that it exists rn. People just need to start using it, doesn't matter who, just to prove it's possible and so people start running into it more often
jonnyawsom3
HCrikki take flickr or photobucket, its 2025 and neither supports dng 1.7
2025-01-14 12:20:44
DNG 1.7 is mostly unsupported due to libraw not releasing with support yet. I think that was resolved but the next release is still months away. Then RawTherapee were concerned about the Adobe SDK with the libjxl decoder causing licence issues. https://github.com/Beep6581/RawTherapee/pull/6887#issuecomment-2241745859
Demiurge
2025-01-14 12:21:37
It's much easier for small sites to flip the switch than big ones
2025-01-14 12:21:52
Less process and bureaucracy
Oleksii Matiash
DNG 1.7 is mostly unsupported due to libraw not releasing with support yet. I think that was resolved but the next release is still months away. Then RawTherapee were concerned about the Adobe SDK with the libjxl decoder causing licence issues. https://github.com/Beep6581/RawTherapee/pull/6887#issuecomment-2241745859
2025-01-14 12:27:20
Unfortunately even the apps from the LibRaw developer still does not support jxl-in-dng
jonnyawsom3
2025-01-14 12:27:47
Yeah, it's in a 2024-03 snapshot, but not an actual release yet https://github.com/LibRaw/LibRaw/issues/615#issuecomment-2027946301
HCrikki
2025-01-14 12:30:29
i think the raw plugin for windows 10/11 got upated with that wip code without waiting for the next big update, worth rechecking
jonnyawsom3
2025-01-14 12:31:33
We checked it a while ago but there was a bug causing it to error
HCrikki i think the raw plugin for windows 10/11 got upated with that wip code without waiting for the next big update, worth rechecking
2025-01-14 12:41:02
JPEG XL DNGs with JPEG previews load, but JPEG XL previews fail
2025-01-14 12:45:08
```[EXIF] Subfile Type : Full-resolution image [EXIF] Image Width : 5712 [EXIF] Image Height : 4284 [EXIF] Bits Per Sample : 16 16 16 [EXIF] Compression : JPEG XL [EXIF] Photometric Interpretation : Linear Raw [EXIF] Subfile Type : Reduced-resolution image [EXIF] Image Width : 5712 [EXIF] Image Height : 4284 [EXIF] Bits Per Sample : 8 8 8 [EXIF] Compression : JPEG [EXIF] Photometric Interpretation : YCbCr```
monad
spider-mario here is lossless compression
2025-01-14 05:10:32
remember those results represent the specific case tested and should not be assumed general <https://github.com/jxl-community/jxl-community.github.io/issues/41>
_wb_
2025-01-14 06:51:47
It would be an interesting research project to create a corpus of ~10k images that is representative (in terms of compression) for "all images". How to construct/collect such a set is very nontrivial though. Just crawling the web will not do, since the set of images on the public web is not representative for all actual images (e.g. private photos, medical images, game graphics etc would be underrepresented), and also because you typically only get lossy downscaled images that way, not originals.
AccessViolation_
2025-01-14 07:05:28
Wikimedia Commons might be a good starting poing
_wb_
2025-01-14 07:29:25
Yeah but that is only representative for the specific category of images suitable for wikipedia, which is likely not distributed in the same way as "all images", e.g. it will have more diagrams, logos, maps, and pictures of famous people and landmarks, and fewer random holiday pictures, insurance claim pictures, medical images, etc.
AccessViolation_
2025-01-14 07:31:25
Wikimedia Commons has tagged images (or more like categories it seems) with a lot of different genres, I was just looking at the "pictures of art" category but there are many. I expect those present on Wikipedia (which is its own category) are probably a large portion of all images though yeah
2025-01-14 07:32:59
some examples
2025-01-14 07:34:31
And yeah those random images you mention, probably not many of those
_wb_
2025-01-14 07:35:24
I guess the question is: how to estimate the distribution of non-public images, like stock photography, medical archives, images on all kinds of forums, chats and social networks, screenshots people keep on their phones or computers, etc.
2025-01-14 07:36:20
But yeah, maybe a representative sample of wikimedia would be at least representative of _something_ that is also relevant.
AccessViolation_
2025-01-14 07:43:43
Estimating the distribution of types of images sounds hard yeah. It would still be interesting to see if it does particularly poorly on certain types of images without initially knowing how common they are. You could figure out how common that type of images is as a second step
Quackdoc
2025-01-14 07:45:03
allow people to publicly submit images I guess? 10k would be small, you would wind up getting like, 100k xD
jonnyawsom3
2025-01-14 07:45:43
God forbid a troll finds the upload button
AccessViolation_
2025-01-14 07:46:31
Ask our Google Research Zurich friends to send over a copy of all the pictures on Google Photos
2025-01-14 07:47:08
a few trillion images should do it
jonnyawsom3
AccessViolation_ a few trillion images should do it
2025-01-14 07:50:11
https://youtu.be/tVQsxLfKPNI
AccessViolation_
God forbid a troll finds the upload button
2025-01-14 08:07:26
honestly images uploaded by trolls probably make up a significant amount of all images in general so it'll be good representation in the dataset <:galaxybrain:821831336372338729>
jonnyawsom3
2025-01-14 08:21:49
Soyjack detection algorithms
_wb_
AccessViolation_ Ask our Google Research Zurich friends to send over a copy of all the pictures on Google Photos
2025-01-14 08:50:55
I guess that would have a disproportional amount of photos taken on Android phones, and they're usually already JPEG-compressed before getting uploaded (and I guess often further transcoded by Google Photos)..
AccessViolation_
2025-01-14 08:51:24
Yeah I think Google Photos turns them into WebP lol
2025-01-14 08:52:08
Unless you have the subscription to store them uncompressed (is it still a subscription? I haven't used google photos in years)
2025-01-14 08:54:16
To be clear it wasn't a serious suggestion to use random people's Google Photos data, BUT if someone generously donated their whole uncompressed Google Photos library and tried several encoding options including lossless JPEG transcoding, the results might be appealing to the Photos team, possibly making them take an interest in JXL? ๐Ÿ‘€
A homosapien
2025-01-14 08:54:36
It's a subscription for Google's cloud service to store them uncompressed
_wb_
2025-01-14 08:55:14
I have been thinking about extracting a corpus from all images on Cloudinary (if I can get something like that cleared with Legal, since the images are owned by our customers, not by us, so I have to be very careful), which would also of course only be representative of Cloudinary's customers/users, but still, that might be a diverse enough set of use cases. Question then is: how to do it. Extracting randomly gets you a lot of long-tail images that are not at all representative for typical web traffic, but extracting weighted by popularity will bias it the other way towards landing page hero images and logos and stuff like that.
AccessViolation_
2025-01-14 08:57:47
I think this might be subject to selection bias. People will manually seek 'efficient' images for those that see lots of traffic. If there is a connection between traffic volume and image characteristics at all, that correlation is the only one I could see it being
_wb_
2025-01-14 08:58:57
also there are bunch of use cases that still wouldn't be covered, either because our terms & conditions don't allow it or because we're not a good fit for such use cases. E.g. porn, military imagery, medical images etc. And probably e-commerce would be overrepresented.
AccessViolation_
2025-01-14 09:01:15
I'm not a lawyer, but I feel like it might be more legal and less controversial to do all the comparisons in-memory and just save the statistics in the end. So instead of creating a corpus, you're just using (some subset of) all images for every experiment. But this of course prevents others from using it, unless they can request an experiment to be run on your images or something
_wb_
2025-01-14 09:05:01
Yeah having a corpus that can be shared would be nice but that's really hard to do since you need to get a license for every single image. An alternative is a list of URLs, if the images are on the public web, which circumvents the issue but is prone to link rot.
AccessViolation_
2025-01-14 09:07:41
I wonder if you can get a giant dump of images from the Internet Archive
2025-01-14 09:09:02
Even if they're not representative of all images in general, knowing how valuable JXL is in use cases like the Internet Archive, or Wikimedia Commons, is valuable in itself, because these are orgs that just have lots of images, regardless of what types of images, and probably would have an interest in storing them efficiently
veluca
2025-01-14 09:10:41
I have at some point gotten a dump of images from the google indexer, but of course that's of limited use to everyone not at G (and also to many people at G xD)
_wb_
2025-01-14 09:15:35
Storing already-lossy images is something quite different from compressing a pristine image though.
AccessViolation_
2025-01-14 09:19:33
I don't remember what it's called, but there's a site that has collections of raw files from various camera models. It might be possible to automate some software like Darktable that develops them and exports them to a lossless format, and then you have a corpus of real photographs from from various camera and lens combinations. The processing done wouldn't be identical to what the camera itself would do though
2025-01-14 09:20:47
So then you effectively have a bunch of photographs from right before the final "encode to jpeg" step
2025-01-14 09:21:58
I mean in practice collecting original lossless things just sounds hard, I imagine lots of pngs online are just screenshots of jpegs... you'd need to filter that or it inadvertently becomes a generation loss experiment instead... sounds like a mess
HCrikki
2025-01-14 09:42:36
dpreview ?
AccessViolation_
2025-01-14 09:54:25
Nah, some other site just dedicated to collecting raws
spider-mario
2025-01-14 10:09:22
https://raw.pixls.us/ ?
AccessViolation_
2025-01-14 10:27:34
That might be it
jonnyawsom3
AccessViolation_ So then you effectively have a bunch of photographs from right before the final "encode to jpeg" step
2025-01-15 04:55:15
If RawTherapee can get the PR done, they'll have native JXL export, so you could just directly use the command line *and* use the automatic preview matching to try and be similar to the in-camera processing
AccessViolation_
2025-01-15 12:20:14
Hang on, automatic preview matching actually sounds amazing
2025-01-15 12:20:42
I've had a hard time trying to recreate the original of my out of camera JPEGs in Darktable
lucius
2025-01-15 06:51:10
I am experimenting with the API and have made a puzzling observation: My program reads a lossless uint16 Jxl image (created in Lightroom) into a buffer, decodes it twice (first as uint16 and then as float), and saves both versions. Both display nicely in XnView and are reported by jxlinfo to be: "JPEG XL image, 4745x3163, lossy, 16-bit RGB" "JPEG XL image, 4745x3163, lossy, 32-bit float (8 exponent bits) RGB" What puzzles me is that the two saved images have exactly the same size, and a byte-by-byte comparison shows they are more than 99.999% identical. The remaining five differences are located near the beginning of the file: 0000002E E2 92 0000002F 27 4B 00000030 A1 28 00000031 B8 2E 00000032 10 04 Is it possible for a uint16 image and a float image based on the same source image to have JPEG XL representations that are so similar? I would have expected no resemblance at all due to the different bit formats of the datatypes, and I would have expected the float version to be much larger than the uint16 version. I have taken steps to verify that the code path that I *think* is executing actually is the one that *is* executing, such as adding a tiny float value to each RGB component. This removes all similarity, and leads to a modest increase in size of the float version (456 bytes). I would appreciate it if someone could take a look at the images at https://www.bosnes.net/ and help me figure out what is going on.
jonnyawsom3
2025-01-15 07:01:56
Lossy JXL is always stored as float32, the only difference is the metadata specifying what format to decode to
2025-01-15 07:03:14
If you tried with lossless, you'd see the differences you expected
lucius
2025-01-15 07:14:43
Thank you for the swift response! This also explains another puzzling thing I had noticed: why images "stored as" float16 and byte also have approximately the same size
jonnyawsom3
lucius Thank you for the swift response! This also explains another puzzling thing I had noticed: why images "stored as" float16 and byte also have approximately the same size
2025-01-15 07:33:34
Any time. I'd recommend trying to decode them to pfm files, they should be identical if I'm right. I also tried to find a relevant portion of the spec but this is the closest I found
_wb_
lucius Thank you for the swift response! This also explains another puzzling thing I had noticed: why images "stored as" float16 and byte also have approximately the same size
2025-01-15 07:56:50
In case of lossy, the bit depth is just metadata in the header but the actual encoding does not depend on it. It is just a suggestion of what bit depth to decode it to, if you decode to RGB.
lucius
2025-01-15 08:06:42
Thank you both! Much appreciated
Demiurge
2025-01-15 08:35:48
I'm pretty sure float32 can perfectly represent any int16 value too
AccessViolation_
Lossy JXL is always stored as float32, the only difference is the metadata specifying what format to decode to
2025-01-15 09:28:23
That's interesting, what's the reason for this? Just simplifying the format/code by always using f32 in lossy?
jonnyawsom3
AccessViolation_ That's interesting, what's the reason for this? Just simplifying the format/code by always using f32 in lossy?
2025-01-15 09:31:34
I know float16 for a 'low precision encoder' has been mentioned a few times, so I think mostly for simplicity and to avoid unnecessary precision loss causing banding during quanization/decoding
2025-01-15 09:32:52
Pretty old, but seems relevant still https://www.reddit.com/r/jpegxl/comments/l6rv3u/comment/gl7fc7i/
2025-01-15 09:33:42
I really wish Reddit didn't cut off the message with a gradient...
AccessViolation_
2025-01-15 09:40:41
I wonder if/how redlib does previews https://redlib.nl/r/jpegxl/comments/l6rv3u/comment/gl7fc7i/
2025-01-15 09:40:50
poorly, it seems
2025-01-15 09:41:32
Anyway thanks for the info
_wb_
I know float16 for a 'low precision encoder' has been mentioned a few times, so I think mostly for simplicity and to avoid unnecessary precision loss causing banding during quanization/decoding
2025-01-15 10:37:40
There is a compile flag for lower precision in certain decode stages, iirc it uses int16 instead of float32 for the XYB to RGB. But yes, in general most things are float32 so there is just a single code path.
2025-01-16 03:09:47
does djxl --allow_partial_files work for anyone? doesn't seem to work for me
jonnyawsom3
2025-01-16 03:12:29
When I tried deleting bytes instead of zeroing for leniency testing, it asked for the parameter and worked for me. I can try again when I get home, but IIRC it never actually decoded partial files when trying to test progressiveness, just errored
_wb_
2025-01-16 03:17:11
I seem to always just get "Input file is truncated and there is no preview available yet."
2025-01-16 03:26:54
oh, I guess this is a side effect of defaulting to chunked encode
jonnyawsom3
2025-01-16 03:33:06
Oh... *Ohhh that makes sense* I don't think I tried the truncated argument since learning --progressive_dc=1 fixes progressiveness
CrushedAsian255
2025-01-16 03:33:10
Didnโ€™t someone find out HfGlobal is written at the end when using chunked?
jonnyawsom3
2025-01-16 03:33:29
LfGlobal IIRC but yeah
CrushedAsian255
2025-01-16 03:34:11
https://discord.com/channels/794206087879852103/805176455658733570/1314895435730649108
2025-01-16 03:35:10
https://discord.com/channels/794206087879852103/805176455658733570/1314868178140266546
2025-01-16 03:35:19
Turns out in different situations itโ€™s both!
jonnyawsom3
CrushedAsian255 https://discord.com/channels/794206087879852103/805176455658733570/1314868178140266546
2025-01-16 08:25:50
That might've just been me getting confused
_wb_
2025-01-16 08:46:36
We should really make some jxltran tool that can reshuffle the sections into an order more suitable for progressive decode
2025-01-16 08:47:34
It's not super critical since for image sizes under 2048x2048 it will be progressive anyway, and that still covers most web images.
2025-01-16 08:52:02
But still, it would be nice to have. If you make it as a tool that requires an input file in which it can freely seek (as opposed to the streaming io model libjxl uses), it should be pretty easy to implement all kinds of bitstream remixing stuff.
jonnyawsom3
2025-01-16 08:53:46
I've said it before, but cjxl already buffers the output unless `--streaming_output` is specified, so the HfGlobal could theoretically already be moved without issue. At least for manual encodes
2025-01-17 10:57:52
I might slowly go though the github issues and comment on any that have since been fixed. There's quite a few high memory usage ones from 2021/22 that never got closed after v0.10 Don't want to be spammy though, so thought I'd ask here first
_wb_
2025-01-17 04:45:13
Sure, any help with reducing the amount of open issues would be appreciated!
AccessViolation_
If RawTherapee can get the PR done, they'll have native JXL export, so you could just directly use the command line *and* use the automatic preview matching to try and be similar to the in-camera processing
2025-01-17 05:01:13
The preview matching in this is so good thanks for mentioning it
2025-01-17 05:02:13
I can finally stop messing around in Darktable to get my raws to look like the out of camera jpegs
jonnyawsom3
2025-01-17 05:44:03
My DNGs don't actually have a preview, but the matching still gives the same image that my phone does when viewing them so I'm happy enough (The JPEGs have far too much smoothing/AI upscaling)
2025-01-17 08:21:25
Looking into this a little while I'm cleaning up old issues https://github.com/libjxl/libjxl/issues/1470
2025-01-17 08:22:10
Do jpegli and libjxl use the same upsampling for the chroma channels?
2025-01-17 08:26:49
I'm noticing a slight hue shift towards red, as if the chroma is bleeding or was sharpened slightly
2025-01-17 08:49:59
I forgor about the CFL, but it's still.. Strange. Jpegli almost seems to do some kind of local correction. The mosquito noise is lessened and the region matches the orignal better, but high contrast details are desaturated too
_wb_ Sure, any help with reducing the amount of open issues would be appreciated!
2025-01-18 01:34:08
May god help your notifications xD Up to page 6 of 14 so far
veluca
2025-01-18 09:36:24
you could also have closed them while you were going through them ๐Ÿ˜›
CrushedAsian255
veluca you could also have closed them while you were going through them ๐Ÿ˜›
2025-01-18 10:05:17
don't think they have write perms on the repo
veluca
2025-01-18 10:08:19
Ah you need write permissions to close?
2025-01-18 10:08:22
Sigh
_wb_
2025-01-18 10:09:16
is JxlEncoderOutputProcessor assuming the buffers are write-only? or can you assume that if it supports seeking, then reading would also be ok?
2025-01-18 10:15:57
it might be nice to have a way to avoid the non/less-progressiveness of streaming encode, at least as an option. That requires having HfGlobal before HfGroups, and to make room for that you'd need to do seek/read/write, but that is probably usually not a big problem/overhead.
2025-01-18 10:17:14
Actually, what is in HfGlobal that is only available after writing HfGroups but is not needed to write HfGroups?
jonnyawsom3
veluca Ah you need write permissions to close?
2025-01-18 10:20:02
Yeah, letting anyone close other people's issues wouldn't be a *great* idea usually. But someone might have to sort by "Last Updated" when I'm done and close the ones I marked (some are asking for additional info or answering questions)
veluca
_wb_ is JxlEncoderOutputProcessor assuming the buffers are write-only? or can you assume that if it supports seeking, then reading would also be ok?
2025-01-18 10:22:26
Uh, I don't think it assumes much
_wb_
2025-01-18 10:24:17
I think it currently is doing write-only
veluca
2025-01-18 10:24:55
Yes, I think so too
jonnyawsom3
2025-01-18 10:40:35
It might not be related, but could chunked JPEG Transcoding be feasable too? Or would that need a new API for the bitstream input
_wb_
2025-01-18 10:51:42
If it's a sequential jpeg then I guess in principle it could be possible to do it in a chunked way. With a progressive one though... I don't think so.
Traneptora
_wb_ it might be nice to have a way to avoid the non/less-progressiveness of streaming encode, at least as an option. That requires having HfGlobal before HfGroups, and to make room for that you'd need to do seek/read/write, but that is probably usually not a big problem/overhead.
2025-01-19 07:17:49
Do you put HFGlobal after the PassGroups using a TOC permutation?
_wb_
2025-01-19 07:18:26
Yes
Traneptora
2025-01-19 07:19:00
Toc permutations is how I did it in hydrium
2025-01-19 07:19:14
but hfglobal is fixed there
2025-01-19 07:19:31
so I just put it at the front because it's only one
2025-01-19 07:20:17
Or rather, wait no that has the histograms
2025-01-19 07:20:26
hm
2025-01-19 07:26:53
I just double checked, apparently what hydrium does is buffer the HF coefficients, build the histograms, then entropy-encode
2025-01-19 07:27:13
since I tend to only output one lf group at a time I can do that without being memory greedy
_wb_
2025-01-19 07:28:14
You write multiple frames, right?
Traneptora
2025-01-19 07:30:05
yes, unless `--one-frame` is passed on the CLI
2025-01-19 07:30:47
then it only writes one frame. I think I might still buffer all the HF coefficients, but I've found it doesn't use that much more memory
_wb_
2025-01-19 07:30:50
I suppose you could also make histograms when encoding the first LF group and then in the other LF groups just encode the HF with fixed histograms. Then you could write everything in a single frame, and probably get some speedups since less need to buffer/compute histograms, at the cost of some compression but probably not that much.
Traneptora
2025-01-19 07:32:13
doing some benchmarking I found that doing 2048x2048 frames was the fastest. doing one frame was almost as fast, and 256x256 frames were notably slower. but also used like 2MiB of memory so it's a different use
_wb_
2025-01-19 07:32:18
Might even compress better since there's less histogram / frame header signaling overhead
Traneptora
2025-01-19 07:32:43
using one histogram for each 2048x2048 gave the best ratio
2025-01-19 07:32:53
in my benchmarking
2025-01-19 07:33:06
because the histograms were most accurate to the tile they were encoding
2025-01-19 07:33:31
using one frame with one histogram had lower signalling overhead, but the histograms weren't always as correct for each tile
_wb_
2025-01-19 07:38:48
Makes sense
Traneptora
2025-01-19 07:39:31
``` malloc(): unsorted double linked list corrupted Aborted (core dumped) ``` ooo, fun. I don't know what this means
2025-01-19 07:42:51
time for a valgrind run
2025-01-19 08:42:04
valgrind is so useful, bug found and fixed
_wb_ Makes sense
2025-01-19 08:55:22
at least, that was my observation, and it's the guess that veluca came up with as to why that observation was holding
2025-01-19 08:56:56
I just tested on a *massive* PNG
2025-01-19 08:57:20
got 160.41 MiB for the one-frame-per-LF-group and 161.20 MiB for one frame total
2025-01-19 08:57:36
turns out for the massive massive files it does inflate memory usage quite a bit to encode one frame
2025-01-19 08:57:42
which is why I don't really recommend it
jonnyawsom3
Traneptora turns out for the massive massive files it does inflate memory usage quite a bit to encode one frame
2025-01-19 09:32:54
'quite a bit' meaning the 0.8 MiB? Or do mean something else
Traneptora
'quite a bit' meaning the 0.8 MiB? Or do mean something else
2025-01-19 09:34:58
that's file size
2025-01-19 09:35:05
4.5 GiB vs ~700 MiB
jonnyawsom3
2025-01-19 09:35:20
Ohhh right, yeah that sounds more like my results
lucius
2025-01-20 11:18:30
I am experimenting with the libjxl API, and have an anomalous result when writing and retrieving extra channels. I add extra channels to an image by using the green channels from images that have the same dimensions as the main image. When I use lossless compression, the size of the main image and the sizes of the added images add up nicely to the size of the main image with the extra channels added: 12 955 437 ExtraChan_0.jxl 13 094 838 ExtraChan_1.jxl 40 001 982 MainImage.jxl 66 043 467 MainImage_2_extra_channels.jxl >jxlinfo MainImage_2_extra_channels.jxl JPEG XL file format container (ISO/IEC 18181-2) JPEG XL image, 2560x1920, (possibly) lossless, 32-bit float (8 exponent bits) RGB+Alpha+Thermal Color space: 940-byte ICC profile, CMM type: "KCMS", color space: "RGB ", rendering intent: 0 When using lossy compression, however, the size of the main image with extra channels added, is more than 10 times the sum of its components. In fact, it matches the size of the lossily compressed main image plus the sizes of the losslessly compressed extra channels: 786 095 ExtraChan_0.jxl 610 665 ExtraChan_1.jxl 877 991 MainImage.jxl 26 985 570 MainImage_2_extra_channels.jxl >jxlinfo MainImage_2_extra_channels.jxl JPEG XL file format container (ISO/IEC 18181-2) JPEG XL image, 2560x1920, lossy, 32-bit float (8 exponent bits) RGB+Alpha+Thermal Color space: 940-byte ICC profile, CMM type: "KCMS", color space: "RGB ", rendering intent: 0 I suspect that the reason for the large size, is that lossless compression has been applied to the extra channels even though the main image was compressed lossily. Is there something I should have done to tell the API that I wanted lossy compression of the extra channels?
jonnyawsom3
2025-01-20 11:31:29
<@1328688054348812390> you want `JxlEncoderSetExtraChannelDistance` though this will set the distance for all extra channels, there's no individual control currently <https://github.com/libjxl/libjxl/issues/1707> <https://github.com/libjxl/libjxl/issues/3906>
2025-01-20 11:32:10
It's set to lossless by default due to Alpha usually compressing better
lucius
2025-01-21 01:09:03
Thank you, that makes sense, but unfortunately, it didn't make much difference to the size of the image with extra channels. I made the call to JxlEncoderSetExtraChannelDistance just after the calls to JxlEncoderFrameSettingsCreate and JxlEncoderSetFrameDistance. I used value 3.0 for distance, and called the function once for each index. JxlEncoderFrameSettingsCreate returned success, and I confirmed that the value in frame_settings->values.cparams.ec_distance[index] still was 3.0 at the time JxlEncoderSetExtraChannelBuffer was called. Its late here, but I will try and debug further tomorrow. Any pointers as to how I can proceed, will be much appreciated. Thank you for your help!
Me
2025-01-21 07:34:27
I'm trying to use the cjxl/djxl command line tools to do progressive with middle-out. I'd really like to be able to get a file that just getting the first, say, 24k lets me do something meaningful and then scale quality as i get up to a meg or whatever. Application is for a student-built satellite with a 4800 baud modem that expects to download ~72kbytes on a typical pass; would be cool to get meaningful previews of 3 images in a way that "counts" towards downloading the entire file
CrushedAsian255
2025-01-21 08:40:23
If attempting that use JXL-oxide as libjxl doesnโ€™t support full progressive decoding
Meow
2025-01-21 11:21:02
Even worse for converting Greyscale now
2025-01-21 11:22:51
Fine without Alpha but the file size still increases much more like before
jonnyawsom3
Me I'm trying to use the cjxl/djxl command line tools to do progressive with middle-out. I'd really like to be able to get a file that just getting the first, say, 24k lets me do something meaningful and then scale quality as i get up to a meg or whatever. Application is for a student-built satellite with a 4800 baud modem that expects to download ~72kbytes on a typical pass; would be cool to get meaningful previews of 3 images in a way that "counts" towards downloading the entire file
2025-01-21 11:49:23
You want to use `cjxl --progressive_dc 1 --group_order 1` to make sure it's progressive and loads centre first. Depending on the hardware and image resolution, quality and encoding speed could be adjusted too. As Jia said, you should probably use jxl-oxide to decode the partial files. That allows decoding down to 0.1% loaded in some cases, though there is a PR for libjxl that allows decoding corrupt files if the transmission isn't stable
2025-01-21 02:46:37
I've thought about doing this for satellite imagery for quite a while, so by all means share the results and give us updates if you can. Just give me a ping or ask here again if you have any questions or encounter any issues
Meow
2025-01-21 02:56:56
What kind of satellite imageries do you use?
Me
You want to use `cjxl --progressive_dc 1 --group_order 1` to make sure it's progressive and loads centre first. Depending on the hardware and image resolution, quality and encoding speed could be adjusted too. As Jia said, you should probably use jxl-oxide to decode the partial files. That allows decoding down to 0.1% loaded in some cases, though there is a PR for libjxl that allows decoding corrupt files if the transmission isn't stable
2025-01-21 03:07:20
Hey, thank you, this is is very helpful. I've been using those command line options but didn't realize djxl had trouble on partial decode. I will try jxl-oxide.
Meow What kind of satellite imageries do you use?
2025-01-21 03:08:26
It's just going to be pictures from a raspberry pi camera. About a third of the frame is one side of the satellite, and if we have attitude control, the other 2/3rds will be the Earth
Meow
2025-01-21 03:10:16
2025-01-21 03:10:17
I was thinking of you being able to generate imageries like this
jonnyawsom3
Me It's just going to be pictures from a raspberry pi camera. About a third of the frame is one side of the satellite, and if we have attitude control, the other 2/3rds will be the Earth
2025-01-21 03:35:02
Do you know the resolution? And how much memory will be available for encoding? The downside to progressive currently is quite a large memory hit due to buffering the entire image, but it's being worked on https://discord.com/channels/794206087879852103/804324493420920833/1330118476731383838
Me
Do you know the resolution? And how much memory will be available for encoding? The downside to progressive currently is quite a large memory hit due to buffering the entire image, but it's being worked on https://discord.com/channels/794206087879852103/804324493420920833/1330118476731383838
2025-01-21 04:21:13
We've got a little baby spacecraft computer that buffers the images for downlink and runs things, but we've got a pi zero 2 w with 512MB of ram and cycles to compress images. 3840x2464 is full res but we'll often be thinking about half in each dim or one quarter in each dim. Downlink is really where we're constrained. So many bytes of image data, so little ability to send it down. Sending a kilobyte costs us 10 joules; running the computer in the imaging subsystem for a second costs 2 joules.
2025-01-21 04:23:44
(We also have science and technology development payloads fighting for that downlink time and energy)
2025-01-21 04:28:54
OK, very nice: ``` mlyle@sliver avif % cjxl -v -v -q 85 --lossless_jpeg=0 --container=1 --progressive --progressive_dc=2 --group_order=1 bluemarb.jpg trial.jxl JPEG XL encoder v0.11.1 0.11.1 [NEON] Read 3000x3002 image, 6486234 bytes, 477.5 MP/s Encoding [Container | VarDCT, d1.450, effort: 7] Compressed to 901.2 kB including container (0.801 bpp). 3000 x 3002, 11.503 MP/s [11.50, 11.50], , 1 reps, 16 threads. mlyle@sliver avif % ls -al trial.jxl -rw-r--r--@ 1 mlyle staff 901238 Jan 21 08:27 trial.jxl mlyle@sliver avif % dd if=trial.jxl of=test.jxl bs=1024 count=4 && jxl-oxide test.jxl -o test.png && open test.png ```
2025-01-21 04:31:04
``` mlyle@sliver avif % dd if=trial.jxl of=test.jxl bs=1024 count=32 && jxl-oxide test.jxl -o test.png && open test.png 32+0 records in 32+0 records out 32768 bytes transferred in 0.000158 secs (207392405 bytes/sec) ``` I notice the group-order only applies to the final image in the progressive sequence
AccessViolation_
2025-01-21 04:37:58
I wonder why some of the lower quality tiles look pixelated while others look blurred
Me
2025-01-21 04:38:36
Yah, I thought that interesting. Also, jxl-oxide is not able to decode the full image. Only when it truncates relatively early
jonnyawsom3
2025-01-21 05:15:39
`--progressive_dc` 1 gives an image at `9600 bytes 1.2%` and 2 gives an image at `5600 bytes 0.6%` loaded
2025-01-21 05:16:23
2 loads sooner, but has higher bpp so you get less in the same amount of data
2025-01-21 05:22:46
This was the original for comparison, a game screenshot but 4K so should be close to your images at full resolution (Though memory may require half res)
AccessViolation_ I wonder why some of the lower quality tiles look pixelated while others look blurred
2025-01-21 06:01:42
Progressive DC 2 makes it into Modular 1:64 and VarDCT 1:8 LF frames, so the blur is likely the VarDCT and the pixilation is probably the Modular
2025-01-21 06:02:57
```Frame #0 Modular (maybe lossless) Frame type: LF, level 2 (64x downsampled) 60x34 Frame #1 VarDCT (lossy) Frame type: LF, level 1 (8x downsampled) 480x270 Frame #2 (keyframe) VarDCT (lossy) Frame type: Regular 3840x2160; (0, 0)```
2025-01-21 06:04:59
Oh, also <@526322998521888768> you can use `jxl-oxide -I --all-frames --with-offset` to get some debug info about the JXL files and when scans of the image should be loaded. Might be useful to calibrate how much data to send per pass
2025-01-21 06:06:09
Apologies for all the pings, you gave us something to do haha
Me
2025-01-21 06:19:53
Hey, no, I really appreciate all the support and help!
2025-01-21 06:20:16
I'm hoping we can be dumb and just send a few K, then a few K more of interesting images, and so on
AccessViolation_
Progressive DC 2 makes it into Modular 1:64 and VarDCT 1:8 LF frames, so the blur is likely the VarDCT and the pixilation is probably the Modular
2025-01-21 06:20:43
Is there anything in JXL that can signal how certain layers should be interpolated, or is that completely up to implementations?
jonnyawsom3
AccessViolation_ Is there anything in JXL that can signal how certain layers should be interpolated, or is that completely up to implementations?
2025-01-21 06:33:39
Uhh, you mean like upsampling algorythms?
Tirr
2025-01-21 06:34:21
partial files are not considered by the spec as those are invalid bitstreams
2025-01-21 06:35:37
libjxl does non-separable upsampling, and jxl-oxide does nearest neighbor
AccessViolation_
Uhh, you mean like upsampling algorythms?
2025-01-21 06:36:19
No, more like when the image has finished decoding already, how the viewer is supposed to handle interpolation when the user zooms in. (I asked about layer specific interpolation, but this doesn't make sense when talking about about an image that has finished decoding, so ignore that)
2025-01-21 06:37:13
Like usually this is a setting in the viewer but I could see at least some use cases for this to be specified in the format itself
Tirr
2025-01-21 06:38:24
then nope, the spec only defines 1x zoom
AccessViolation_
2025-01-21 06:38:49
Ah okay. Honestly fair, was just curious
jonnyawsom3
2025-01-21 06:42:52
I mean, there is this https://github.com/libjxl/libjxl/pull/2571
2025-01-21 06:45:29
*Technically* an insane viewer could increase the upsampling scale as you zoom in, but it's a lot more effort than it's probably worth
AccessViolation_
2025-01-21 06:51:02
Huh so JXL supports that, it's an encoder thing
2025-01-21 06:51:08
Kinda cool
A homosapien
2025-01-21 06:55:03
The benefit of having an expressive format
_wb_
2025-01-21 08:19:43
If you want the upsampling to be baked into the image and done by the jxl decoder, you can use the 2x/4x/8x nonseparable upsampling defined in the spec, either with default filter weights (which are nice imo) or with something custom.
AccessViolation_
2025-01-21 08:32:46
I think upsampling to x8 basically removes the need for the image to signal how it wants to be interpolated when zooming yeah
jonnyawsom3
2025-01-21 08:36:33
Issue then is, normal decoders will honor the 8x upscale regardless of zoom level. So you'd need a closed ecosystem for what you want
Me
2025-01-22 04:16:04
Visualization of the blue marble image, compressed as ```cjxl -v -v -q 85 --lossless_jpeg=0 --container=1 --progressive --progressive_dc=2 --group_order=1 bluemarb.jpg trial.jxl``` and then having the first n kilobytes peeled off, where n is 1, 9, 17, ...up to 217k (out of 901k total size). Progressive rendering definitely works, but some of the choices the encoder makes are interesting.
CrushedAsian255
2025-01-22 09:18:12
https://music.apple.com/au/album/not-alone/1746873815?i=1746873826
2025-01-22 09:18:36
Oops wrong server
eustas
Yeah, letting anyone close other people's issues wouldn't be a *great* idea usually. But someone might have to sort by "Last Updated" when I'm done and close the ones I marked (some are asking for additional info or answering questions)
2025-01-22 01:47:57
Hi, Jonathan. Thanks for your awesome contribution in triaging JXL issues. And welcome - you will obtain "triage" role and will be able to close the issues (hopefully).
jonnyawsom3
2025-01-22 04:13:23
Thank you, I'll check it out soon
Me Visualization of the blue marble image, compressed as ```cjxl -v -v -q 85 --lossless_jpeg=0 --container=1 --progressive --progressive_dc=2 --group_order=1 bluemarb.jpg trial.jxl``` and then having the first n kilobytes peeled off, where n is 1, 9, 17, ...up to 217k (out of 901k total size). Progressive rendering definitely works, but some of the choices the encoder makes are interesting.
2025-01-22 04:14:04
Also, if you're re-encoding JPEGs, there's likely EXIF data too correct? `--brotli_effort 11` will increase the compression time spent on metadata
Me
2025-01-22 04:15:04
Cool, thanks for the tip. I had had a command line argument to strip EXIF but I had taken it out when things were failing
2025-01-22 04:15:25
I should probably ensure our toolchain puts some meaningful metadata in (and then compress it well)
jonnyawsom3
eustas Hi, Jonathan. Thanks for your awesome contribution in triaging JXL issues. And welcome - you will obtain "triage" role and will be able to close the issues (hopefully).
2025-01-22 05:21:46
Seems to have worked, thanks again and hopefully I can lend a hand in future
Me
Me Visualization of the blue marble image, compressed as ```cjxl -v -v -q 85 --lossless_jpeg=0 --container=1 --progressive --progressive_dc=2 --group_order=1 bluemarb.jpg trial.jxl``` and then having the first n kilobytes peeled off, where n is 1, 9, 17, ...up to 217k (out of 901k total size). Progressive rendering definitely works, but some of the choices the encoder makes are interesting.
2025-01-22 06:59:34
Does anyone understand this of how it is choosing to fill in the blocks ... how it does the left two thirds of the image top to bottom, then the right two thirds? I'd really prefer it to be middle out. (The last phase is middle out, but this one is weird)
AccessViolation_
Me Does anyone understand this of how it is choosing to fill in the blocks ... how it does the left two thirds of the image top to bottom, then the right two thirds? I'd really prefer it to be middle out. (The last phase is middle out, but this one is weird)
2025-01-22 07:12:33
It might be this, I also noticed this behavior for some other image test a while ago https://discord.com/channels/794206087879852103/794206170445119489/1285551387647938580
2025-01-22 07:14:07
For your convenience: > It says group_order=1 is center first, is that the one where it spirals outward like the example from the whitepaper? It doesn't look like that's what it's doing, it looks more like a scanline pattern on three columns, doing the center one first, but it's hard to tell > I see what you mean now, and I think I know why. > That happens during the DC/LF part of the image, which are 2048 blocks instead of 256. So it probably is a spiral, but there's only 3 blocks so it just goes middle, left, right (probably)
jonnyawsom3
2025-01-22 07:51:58
I mentioned it before, but I think with `jxl-oxide -I --all-frames --with-offset` you can actually see the center-first reordering, and it doesn't seem to have applied to the DC
Me
2025-01-22 08:48:54
yah, I have a hard time knowing the group number to spatial relation. I do see how pass_idx=2 they start near the middle. This is already a huge win for us. Seems like the win could be much bigger I could control frame #1 a little bit. 47x47 is great from 64x downsampling on frame #0-- down to 6k or so, able to send a lot of these per satellite contact. But frame #1 at 8x downsampling -- 115k before we get through the first group of the first pass, and the ordering isn't great. I suspect I either want frame #1 to be 4x downsampled -- so that the middle-out does something useful -- or to be 16x downsampled so that it is just smaller.
jonnyawsom3
2025-01-22 09:05:58
I wonder if it could be done by editing libjxl to do a 2x or 4x downsample for DC 2 instead of 8x. I can't find anything in the spec mentioning something like `--progressive_dc 2`, only stating that VarDCT requires a 1:8 image for it's LF frame
Me
2025-01-22 09:09:25
``` cjxl -v -v -q 85 -m 0 --lossless_jpeg=0 --container=1 --progressive --progressive_dc=1 --group_order=1 -x strip=exif,xmp,jumbf bluemarb.jpg trial.jxl ``` This is with progressive_dc=1 .. e.g. no intermediate frame. Seems to be much more usefully "progressive" in practice (and smaller in size)
2025-01-22 09:09:39
same 8k chunks of file
2025-01-22 09:09:42
per frame
jonnyawsom3
2025-01-22 09:14:00
Yeah, DC 2 essentially embeds a 1:64 preview of the image, so using DC 1 you get more value for your bytes, but takes twice as many for a first image. Depending how far you want to go, you could parse the TOC and send the bare minimum 'first image' per file. It's a shame we don't have a better test image, since the 1/3 satellite could increase the size due to fine details. Though, if you use half-resolution like you mentioned, you could also increase the effort setting for smaller files and higher quality for a memory increase
Me
2025-01-22 09:16:02
Yah, but that 1:64 is tiny.. 6k there's something more going on
2025-01-22 09:17:16
This is 41k . better than the progressive_dc=2 image gets by 80k
2025-01-22 09:17:18
2025-01-22 09:18:26
let me pull progressive_dc=2 at 80k
2025-01-22 09:21:09
2025-01-22 09:22:36
trial == progressive_dc=1, trial2 == progressive_dc=2
2025-01-22 09:23:21
Two pngs above corresponding to progressive_dc=1 at 41 kilobytes, and progressive_dc=2 at 80 kilobytes
jonnyawsom3
2025-01-22 09:36:39
A slight improvement, modular arguments still apply to VarDCT's modular LF frame. Adding `-g 3 -E 3 -I 100` shaved off 1.5 KiB from progressive_dc=1 for me `LfGlobal: 134708 (0x20e34) bytes` `LfGlobal: 133237 (0x20875) bytes` My exact command was this, the container is automatically enabled/disabled depending on metadata and some arguments have short variants `cjxl -v -v -q 85 -m 0 -j 0 -p --progressive_dc=1 --group_order=1 -x strip=all -E 3 -I 100`
2025-01-22 09:38:46
Oh...
2025-01-22 09:39:03
embed
2025-01-22 09:39:08
https://embed.moe/https://cdn.discordapp.com/attachments/804324493420920833/1331739938294595675/Test.jxl?ex=6792b6f7&is=67916577&hm=826ab605bd614e2eaaac2e753180ffbf92d69a44206ee977609c17e68c22f1c2&
jonnyawsom3
2025-01-22 09:39:36
Maybe the modular arguements aren't meant to work...
2025-01-22 09:41:23
Turns out it was group size, didn't effect filesize anyway so I edited the command above
Me This is 41k . better than the progressive_dc=2 image gets by 80k
2025-01-22 09:43:28
Almost seems like a bug, I don't think `--progressive_dc=2` has been tested much
AccessViolation_
2025-01-22 09:55:04
All these LF things are isolated to their groups right? So can't you make the group sizes smaller so that center first actually does something for the first few passes
2025-01-22 09:55:39
Instead of the whole image, or a lot of it of it, being in a single group
jonnyawsom3
https://embed.moe/https://cdn.discordapp.com/attachments/804324493420920833/1331739938294595675/Test.jxl?ex=6792b6f7&is=67916577&hm=826ab605bd614e2eaaac2e753180ffbf92d69a44206ee977609c17e68c22f1c2&
2025-01-22 09:56:49
Making groups bigger did that, I imagine smaller might corrupt it too, but <@526322998521888768> could try adding `-g 0` and see what happens
Me
2025-01-22 09:57:56
yah -m 0 does nothing. I have to go teach a competitive math class but i'll be back later
2025-01-22 09:57:59
to play with it more
AccessViolation_
2025-01-22 09:59:05
what if you make the group size the height/width of the image divided by three (rounding up to not create groups that just contain an edge of pixels)
2025-01-22 09:59:38
That should give you a center group that is decoded first
2025-01-22 10:00:03
or should be rather
Me
2025-01-22 10:00:04
I will play with encoding settings and middle out. I think I'm most concerned that progressive_dc=2 looks much worse for every size than progressive_dc=1
2025-01-22 10:00:31
progressive_dc=2 adds a 6k small preview but then is worse at sizes 40-60k larger than progressive_dc=1
jonnyawsom3
AccessViolation_ what if you make the group size the height/width of the image divided by three (rounding up to not create groups that just contain an edge of pixels)
2025-01-22 10:01:09
Group size is fixed at 128x128, 256x256 (Default), 512x512 or 1024x1024
AccessViolation_
2025-01-22 10:01:54
Oh huh, I thought they could be anything up to 1024x1024
2025-01-22 10:02:05
good to know
jonnyawsom3
2025-01-22 10:02:06
One sec, I'll check the spec Well that was fast `naturally aligned rectangle covering up to 2n ร— 2n input pixels, with n between 7 and 10, inclusive`
Me
2025-01-22 10:03:27
You get whatI'm saying? I'd expect 2 to be, say, 4k "behind" 1 in quality if there's a 6k lowres first, not 60k+ "behind" to reach same quality
jonnyawsom3
2025-01-22 10:04:33
Yeah, maybe <@794205442175402004> has some idea what's going on
2025-01-22 10:06:51
`--progressive_dc=2` is taking twice the data to reach the same progressive qualityhttps://discord.com/channels/794206087879852103/804324493420920833/1331734747914965074
Me
2025-01-22 10:24:51
Yay, test being proctored. Re: satellite in frame. I expect it to not use too many bits, because it's going to be lowpass filtered --- out of focus ๐Ÿ˜„
Meow
2025-01-23 03:40:03
2025-01-23 03:40:04
This didn't get response. Is this a bug?
2025-01-23 03:40:49
This is similar to what libheif would cause
Tirr
2025-01-23 03:42:02
I think it's a macOS bug
2025-01-23 03:43:07
grayscale jxl doesn't work well in Preview or Finder for some reason
Meow
2025-01-23 03:44:29
I'll test again when I can access my own computer later today (or tomorrow for some)
Tirr grayscale jxl doesn't work well in Preview or Finder for some reason
2025-01-23 03:45:24
Grayscale+Alpha for this
novomesk
2025-01-23 09:29:21
One GIMP3 user complained about ugly blue artifact when he uses distance 0.1 and 8-bit JXL with uses_original_profile = JXL_TRUE in BasicInfo + ICC. I have impression that it was already mentioned somewhere, but not sure. He shared picture in https://gitlab.gnome.org/GNOME/gimp/-/issues/12785#note_2328039
A homosapien
novomesk One GIMP3 user complained about ugly blue artifact when he uses distance 0.1 and 8-bit JXL with uses_original_profile = JXL_TRUE in BasicInfo + ICC. I have impression that it was already mentioned somewhere, but not sure. He shared picture in https://gitlab.gnome.org/GNOME/gimp/-/issues/12785#note_2328039
2025-01-23 11:58:04
I can replicate, unchecking the "save original profile" fixes the issue
2025-01-23 11:59:06
```jxlinfo bubbles-save-original-profile.jxl JPEG XL image, 1920x1200, (possibly) lossless, 8-bit RGB Color space: 672-byte ICC profile, CMM type: "lcms", color space: "RGB ", rendering intent: 0 jxlinfo bubbles-no-icc.jxl JPEG XL image, 1920x1200, lossy, 8-bit RGB Color space: RGB, D65, sRGB primaries, sRGB transfer function, rendering intent: Relative```
2025-01-23 12:01:17
GIMP is definitely doing something wrong here
Tirr
2025-01-23 12:05:16
iirc `uses_original_profile` shouldn't be set to true when doing lossy
2025-01-23 12:06:51
ICC profile will always be embedded if there's one (but the encoded image will be in XYB), but I'm not very sure
veluca
Tirr iirc `uses_original_profile` shouldn't be set to true when doing lossy
2025-01-23 12:10:04
yes, please don't do that ๐Ÿ™‚
2025-01-23 12:10:18
maybe we should rename that flag, the amount of people that get confused by it is a bit high
2025-01-23 12:10:56
I'm not sure there's ever a good reason to have that flag be different from "I am doing lossless"
2025-01-23 12:11:12
(well, maybe with modular lossy...)
CrushedAsian255
2025-01-23 12:12:30
what does the flag actually do? force decoding using the colour space defined at encode time?
veluca
2025-01-23 12:23:12
it disables XYB
A homosapien
2025-01-23 12:25:32
so it compresses in RGB ๐Ÿคข
veluca
2025-01-23 12:26:35
yes
spider-mario
2025-01-23 12:26:44
you see the problem
CrushedAsian255
A homosapien so it compresses in RGB ๐Ÿคข
2025-01-23 12:33:37
oh geez, ahhhhhhh
Meow
Tirr I think it's a macOS bug
2025-01-23 12:37:21
You're possibly right. Only Affinity series on my macOS can display Grayscale+Alpha JXL correctly
2025-01-23 12:40:22
The JXL one is only 0.2% smaller
novomesk
veluca yes, please don't do that ๐Ÿ™‚
2025-01-23 02:24:32
I set uses_original_profile when encoding CMYK. Doesn't it mean that lossy CMYK is also not a good idea?
veluca
2025-01-23 02:26:21
I would not set uses_original_profile ๐Ÿ™‚
2025-01-23 02:27:06
although if I had to say I know what the encoder does with CMYK I would lie
2025-01-23 02:27:18
<@794205442175402004> probably knows better than me
_wb_
2025-01-23 05:18:21
Lossy CMYK is not tested at all, probably does not work.
2025-01-23 05:33:52
I mean, YCC like in CMYK jpegs should work (but we have no encoder for that). Using XYB with CMYK is a bit weird since the XYB only represents the CMY components, and I am not sure if the spec is sufficiently clear on how XYB should be converted to CMY - I think we intended to define it to do the XYB to CMY conversion by pretending it is producing sRGB. In any case the XYB will be abused as "just a transform" as opposed to being the absolute color space it is supposed to be, since the K component cannot be factored in.
2025-01-23 05:35:10
I don't really see the use case for lossy CMYK tbh. If you want lossy, you can just as well use a sufficiently wide gamut RGB space imo.
Me
2025-01-23 06:08:59
<@794205442175402004> Did you see the thing I had above? ```--progressive_dc=2``` resulted in a 64x downsampled modular frame that was like 5-6k at the beginning of the file, but then quality from 10-50k is 50k+ behind ```--progressive_dc=1``` (I'd expect to be paying a tax that was more like a fraction of the 6k spent on that first downsampled frame)
2025-01-23 06:09:31
e.g. progressive_dc=1 at 40k truncation looks way better than progressive_dc=2 at 80k truncation
_wb_
2025-01-23 06:10:17
Yeah that makes sense actually
Me
2025-01-23 06:10:24
(progressive_dc2 is also like 100k larger)
2025-01-23 06:10:59
Oh, I found it surprising. I'd expect for it to be worse / a few K behind, but not that much worse
_wb_
2025-01-23 06:11:19
Progressive DC > 1 is not really useful unless the image is super huge and even then it is not useful for better progression, just for better performance
Me
2025-01-23 06:11:41
as it stands now, i'd be better off sending a 5k PNG + a progressive_dc1 file -- better quality at any number of bytes received
2025-01-23 06:12:23
well, progressive_dc=2 is better when less than 5k is received
2025-01-23 06:12:34
but way worse from 5k on
_wb_
2025-01-23 06:12:44
Progressive_dc=1 does the 1:8 image using modular with squeeze, which already is as progressive as it gets
2025-01-23 06:13:20
Progressive_dc does the 1:8 image as VarDCT and only the 1:64 image as Modular with squeeze
Me
2025-01-23 06:14:16
Does modular with squeeze benefit in any way from a prior frame layer, or does only VarDCT?
2025-01-23 06:15:06
Sorry for noob questions. I don't really know image compression
2025-01-23 06:15:18
Application is for constrained downlink from a small student-built satellite.
2025-01-23 06:17:14
In any case, thank you very much for your help / listening. Jpeg-XL is a big win for us, but it'd be an much bigger win if we had something with the very-short-truncation performance of progressive_dc=2 but something closer to the longer-truncation performance of progressive_dc=1
AccessViolation_
Me as it stands now, i'd be better off sending a 5k PNG + a progressive_dc1 file -- better quality at any number of bytes received
2025-01-23 06:18:55
You can always replace the PNG with a lossless JXL that should work out to about half the size :)
Me
2025-01-23 06:19:36
๐Ÿ˜‰ Handling thumbnails and lots of files adds a whole lot of complexity to what students have to do