|
jonnyawsom3
|
2025-03-09 06:51:33
|
I set djxl to use level 1 zlib IIRC, so oxipng is doing the same without filtering, or any of the JXL en/decoding
|
|
2025-03-09 08:49:11
|
I'm working on some Resampling tweaks and noticed this... There's 3 different types? `DownsampleImage2_Iterative`, `DownsampleImage2_Sharper` and `DownsampleImage`
The comment at the top says regular should be used if shaper isn't fixed, and the comment I've replaced (also tagged `lode`) said iterative was too slow for squirrel and it should be raised, which I did. Testing seems to show roughly equal visual quality between iterative and sharper, so I made it effort 11 since lossy does nothing there currently, but how does regular compare to the other two?
|
|
2025-03-09 08:53:57
|
Iterative seems to retain the original details of the image better, but the lower resolution makes it look like a sharpen filter with ringing artifacs on non-photo content. Combined with the 2x slowdown (10x slowdown at effort 7) and 3x memory increase, I considered disabling it entirely or making it an experimental flag
|
|
2025-03-09 12:40:38
|
Well, I got all 3 downsampling methods. Orginal, Downsample, Sharper, Iterative
|
|
|
spider-mario
|
2025-03-09 01:20:49
|
last one seems best to me
|
|
2025-03-09 01:21:18
|
similar sharpness as the third image (second downsampled) but with slightly less aliasing
|
|
|
jonnyawsom3
|
2025-03-09 01:43:10
|
It scores around 1 point higher in ssimulacra, but varies image to image. Particularly on non-photo, the last downsampling method causes severe ringing
|
|
2025-03-09 01:43:51
|
|
|
|
Iterative seems to retain the original details of the image better, but the lower resolution makes it look like a sharpen filter with ringing artifacs on non-photo content. Combined with the 2x slowdown (10x slowdown at effort 7) and 3x memory increase, I considered disabling it entirely or making it an experimental flag
|
|
2025-03-09 01:49:30
|
For now, I set the last method to enable only at effort 11 lossy, since it's a relatively large slowdown for highly varied results (And e11 does nothing different to e10 otherwise). If/when it's sped up and the TODOs are cleared, it can be re-enabled at standard effort settings
|
|
2025-03-09 01:54:06
|
I actually wanted to ask. I know distance is capped to 25 in cjxl, but I also know you can override it and set whatever you want using the library/a dev build. I got resampling 4 to look competitive at distance 25 compared to resampling 2, but should I add this to compensate for values above 25 `2.5 + ((Distance - 25) * 0.25)`, or just explicitly set the value since it's the cap?
|
|
2025-03-09 01:55:25
|
~~If I had a cracked build I could set resampling 8 too~~
|
|
2025-03-09 03:31:51
|
Scrapped the resampling 4, made anything below 1440p far too blurry to be useful. Noticed one or two images that actually had significantly higher bpp and quality than no resampling, but it was an issue with the current settings too so I didn't bother tweaking it and breaking the other images
|
|
2025-03-09 04:42:31
|
bpp is a smidge higher, but it's faster, more memory efficient and scores a lot better
|
|
|
monad
|
2025-03-09 06:06:06
|
comparing to git head is probably safer. adding bits to increase fidelity is totally unremarkable (assuming ssimu2 captures reality in this context), so the compelling thing would be the speedup if density doesn't diverge from expectation in general
|
|
|
spider-mario
|
2025-03-09 06:11:22
|
having curves of bpp vs score might make it easier to compare two versions without having to match the bpp exactly
|
|
|
jonnyawsom3
|
2025-03-09 06:26:31
|
That's git head at distance 10, my PR at distance 10, and git head manually set to resample with the same parameters as my PR for the speed/memory comparison
|
|
2025-03-09 06:28:26
|
The slight bpp and SSIMULACRA2 difference with the same parameters is from me disabling the iterative downsampling at effort 7, which gave the speed and memory improvements
|
|
|
monad
|
2025-03-09 06:32:33
|
hm, version/commit hash indicates differently
|
|
|
jonnyawsom3
|
|
monad
hm, version/commit hash indicates differently
|
|
2025-03-09 06:38:17
|
Have some hashes, fresh out the workflow
|
|
2025-03-09 06:49:40
|
The problem is the image content changes the effectiveness and the internal butter scores. So on some the bpp is higher and on others it's lower, but overall the quality is higher than the bytes otherwise
|
|
2025-03-09 06:52:26
|
I was originally using `3 + ((Distance - 10) * 0.25)` to calculate the resampled distances, but on some images it was half the bpp and lower quality.
So I raised it to `2.5 + ((Distance - 10) * 0.25)` which seemed to be a good middleground
|
|
|
Traneptora
|
|
I was originally using `3 + ((Distance - 10) * 0.25)` to calculate the resampled distances, but on some images it was half the bpp and lower quality.
So I raised it to `2.5 + ((Distance - 10) * 0.25)` which seemed to be a good middleground
|
|
2025-03-10 11:53:16
|
this is just distance / 4
|
|
|
jonnyawsom3
|
|
Traneptora
this is just distance / 4
|
|
2025-03-10 12:03:35
|
If you input `-d 15`, it does 15 - 10, then 5 / 4, followed by 2.5 + 1.25 to give a final result of `--resampling 2 -d 3.75` instead. This usually results in equal or lower bpp, but at higher quality. Some images it's too low, some it's too high, but I thought I'd aim for the higher end.
|
|
|
Traneptora
|
|
If you input `-d 15`, it does 15 - 10, then 5 / 4, followed by 2.5 + 1.25 to give a final result of `--resampling 2 -d 3.75` instead. This usually results in equal or lower bpp, but at higher quality. Some images it's too low, some it's too high, but I thought I'd aim for the higher end.
|
|
2025-03-10 12:04:42
|
15 / 4 = 3.75
|
|
2025-03-10 12:05:28
|
expand it out. `(distance - 10) * 0.25 = distance * 0.25 - 10 * 0.25` and `10 * 0.25 = 2.5`
|
|
2025-03-10 12:05:41
|
so you're just taking `distance * 0.25` and then subtracting and adding `2.5`
|
|
|
jonnyawsom3
|
2025-03-10 12:07:14
|
Right, yeah. Because 2.5 is already 1/4 of 10. Didn't catch that since lowering from 3 was a last minute decision
|
|
2025-03-10 12:08:34
|
So if it is the right value, that can just be changed to distance / 4, but if it's any other value then it probably needs the equation
|
|
|
Traneptora
|
|
So if it is the right value, that can just be changed to distance / 4, but if it's any other value then it probably needs the equation
|
|
2025-03-10 12:08:56
|
if you want to add 3 instead then change it to distance/4 + 0.5
|
|
2025-03-10 12:09:01
|
still much simpler
|
|
2025-03-10 12:09:11
|
and notably, much more readable code
|
|
|
jonnyawsom3
|
2025-03-10 12:10:55
|
The current/original line was `p->butteraugli_distance = 6 + ((p->butteraugli_distance - 20) * 0.25);` so I just assumed there was a reason for it... Thanks for spotting that
|
|
2025-03-10 12:25:31
|
Added to the PR, thanks again
|
|
2025-03-10 12:56:39
|
This is the worst case I've had so far. 0.340 bpp on the left, 0.438 bpp with the PR in the middle. It seems to focus more on the whole image than things like text. Going to 3 instead of 2.5 reduces it to 0.358 bpp, but I'd have to test more images to see if it's worse for other types of content
|
|
2025-03-10 01:08:55
|
It's essentially a balance of photo vs non-photo. 2.5 means it aligns with difficult photos, but overshoots on non-photo. 3 means it's equal on non-photo but undershoots on photos
Guess I'll add 0.25 to put it in the middle
|
|
|
Demiurge
|
|
This is the worst case I've had so far. 0.340 bpp on the left, 0.438 bpp with the PR in the middle. It seems to focus more on the whole image than things like text. Going to 3 instead of 2.5 reduces it to 0.358 bpp, but I'd have to test more images to see if it's worse for other types of content
|
|
2025-03-10 03:10:10
|
The first image has unacceptable quality imo
|
|
2025-03-10 03:10:21
|
The other two are slightly better
|
|
2025-03-10 03:10:41
|
I don't think the first image is usable quality at all
|
|
|
jonnyawsom3
|
2025-03-10 03:10:49
|
Yeah, it seems like butteraugli is falling flat on it's face for some reason
|
|
|
Demiurge
|
2025-03-10 03:11:07
|
It's a useless and ruined image
|
|
2025-03-10 03:11:35
|
The other two are more acceptable and usable
|
|
2025-03-10 03:13:20
|
The one in the middle looks the least distorted
|
|
|
jonnyawsom3
|
2025-03-10 03:14:04
|
For now, I've changed the PR *yet again* to use a setting between the last two. Distance 2.75 at 0.380 bpp. 40 higher than main, but 60 lower than the second image. In my opinion the best quality without drastically changing size between distance 9.9 and 10
|
|
2025-03-10 03:45:03
|
15% higher bpp for 20% higher score in the worst case. On a random photo it's -7% and 11%, generally with visual inspection looking better than SSIMULACRA2 scores anyway.
This is the quality 0 to 18 range, so really people shouldn't be going this low anyway... But at least if they do, they get usable results now
|
|
2025-03-10 03:45:43
|
In the end, as with most things in cjxl, it depends on the image :P
|
|
|
Demiurge
|
2025-03-11 12:21:31
|
Which pr
|
|
|
jonnyawsom3
|
|
Demiurge
Which pr
|
|
2025-03-11 05:06:31
|
https://github.com/libjxl/libjxl/pull/4147
|
|
|
Demiurge
|
2025-03-11 05:19:33
|
This doesn't change anything except when distance >=10?
|
|
2025-03-11 05:20:15
|
I hope people aren't actually compressing images at libjxl distance 10...
|
|
2025-03-11 05:21:43
|
0.5 to 1.5 is the recommended range I think.
|
|
2025-03-11 05:22:21
|
I would even be in favor of making those the hard minimum/maximum distance values
|
|
2025-03-11 05:22:46
|
But I'm radical like that
|
|
2025-03-11 05:24:33
|
I think software should be designed to not give people a big red "DO NOT PRESS" button since they're always GUNNA press it thinking they know better. 😂
|
|
2025-03-11 05:25:09
|
People who know better can always fork or make a pull request
|
|
|
jonnyawsom3
|
|
Demiurge
This doesn't change anything except when distance >=10?
|
|
2025-03-11 05:30:09
|
Yeah, at that point resampling is competitive, which says a lot about what kinda quality you're using...
But it is better, usually smaller and multiple times faster to encode
|
|
|
Demiurge
|
2025-03-11 05:30:46
|
And decode.
|
|
|
jonnyawsom3
|
2025-03-11 05:31:07
|
Surprisingly not in my minor testing
|
|
|
Demiurge
|
2025-03-11 05:31:19
|
But nothing would be lost either if distance values were just hard clamped to 0.5-1.5
|
|
2025-03-11 05:32:18
|
At that point I would say libjxl is not adequate or competitive there
|
|
2025-03-11 05:32:51
|
Unless it were to receive a lot of specific tuning
|
|
|
jonnyawsom3
|
2025-03-11 05:32:56
|
It's mostly people comparing it to AVIF, which unfortunately is quite often. The PR actually increases quality at distance 25 compared to main, but otherwise the images are unusable
|
|
|
Demiurge
|
|
It's mostly people comparing it to AVIF, which unfortunately is quite often. The PR actually increases quality at distance 25 compared to main, but otherwise the images are unusable
|
|
2025-03-11 05:33:10
|
All the more reason to clamp the values
|
|
2025-03-11 05:33:31
|
To prevent bogus automated comparisons that are done without actual visual confirmation
|
|
2025-03-11 05:33:51
|
Like the comparison the avif team did at absurdly bad quality settings
|
|
|
jonnyawsom3
|
2025-03-11 05:34:11
|
That does raise a point....
|
|
|
Demiurge
|
2025-03-11 05:34:38
|
You made me realize that it's actually a serious issue and now I strongly suggest clamping the values unless MORON_MODE=1
|
|
2025-03-11 05:34:58
|
And change it from "expert options..."
|
|
2025-03-11 05:35:18
|
It's not for experts, it's for crazy people 😂
|
|
|
jonnyawsom3
|
|
Demiurge
The one in the middle looks the least distorted
|
|
2025-03-11 05:35:19
|
The best looking images actually scored lowest, probably due to the DCT noise you love so much, caused by the resampling forcing it to use smaller blocks
|
|
|
Demiurge
|
|
The best looking images actually scored lowest, probably due to the DCT noise you love so much, caused by the resampling forcing it to use smaller blocks
|
|
2025-03-11 05:36:00
|
What metric?
|
|
|
jonnyawsom3
|
2025-03-11 05:36:35
|
SSIMULACRA2, I can rub some butter on it when I have my computer on
|
|
|
Demiurge
|
2025-03-11 05:36:50
|
I just choose the image that has the most discernible features and doesn't look like someone smeared their fingers all over an oil painting
|
|
|
jonnyawsom3
|
2025-03-11 05:37:31
|
It's ironic. Resampling the image to half the resolution brings *back* fine details
|
|
|
Demiurge
|
2025-03-11 05:38:19
|
Yeah I don't trust ssimu2 at all sadly, it sounds exciting when I first heard of it but it loves zeroing out crucial image data and visual features
|
|
|
jonnyawsom3
|
2025-03-11 05:38:29
|
0.8 has the same resampling gains, just with both scoring higher than main
|
|
|
Demiurge
|
2025-03-11 05:39:30
|
It's not a good sign when a codec performs a lot worse or better with resampling.
|
|
2025-03-11 05:40:10
|
These are good ways to stress test the encoder though I guess
|
|
|
The best looking images actually scored lowest, probably due to the DCT noise you love so much, caused by the resampling forcing it to use smaller blocks
|
|
2025-03-11 05:41:51
|
DCT noise only looks bad if there are obvious block boundaries and if that noise doesn't blend into the image behind it.
|
|
|
jonnyawsom3
|
2025-03-11 05:42:02
|
The biggest thing I noticed was chroma noise at high distances. Large banding areas of yellow across flat surfaces, so while resampling was sometimes a dubious fidelity improvement, it removed the most distracting artifacts
|
|
2025-03-11 05:43:02
|
Tends to distribute bits across the entire image instead of focusing on the 'attention points' like the UI in the game screenshot above
|
|
|
Demiurge
|
2025-03-11 05:43:38
|
Imagine an image codec that looks like an analog picture getting static interference when the compression is too strong 😂
|
|
2025-03-11 05:44:19
|
That would kinda be a cool idea. The artifacts would be honest, easy to tell when they are there and easy to see underneath them
|
|
2025-03-11 05:44:44
|
Just like the stated goals of jxl
|
|
|
jonnyawsom3
|
2025-03-11 05:44:46
|
Oh, you reminded me. I have a natural example of an image aligning with the DCT coefficients
|
|
2025-03-11 05:45:35
|
The roof of my church image has a single block that remains perfectly sharp even at distance 25 or intensity targets like 1 (IIRC)
|
|
|
Demiurge
|
2025-03-11 05:47:33
|
Jon I think spoke a great deal about how dangerous and undesirable deceptive artifacts like blurring and smearing can be in avif for example. But shortly afterwards, libaom became a lot less blurry and libjxl became a lot more blurry, so the roles were reversed.
|
|
2025-03-11 05:52:31
|
It's a little embarrassing especially considering how the creator of avif is trying to wield his influence over Chromium to prevent jxl from coexisting and competing with his avif and webp
|
|
2025-03-11 05:54:17
|
libaom made some real strides in the psychovisual quality
|
|
|
jonnyawsom3
|
|
Well, I got all 3 downsampling methods. Orginal, Downsample, Sharper, Iterative
|
|
2025-03-11 04:15:36
|
<@207980494892040194>
|
|
|
K
|
2025-03-12 09:08:40
|
TagStudio (a tagging software) is trying to support jxl but there is some incompatible at the moment.
If anyone like to help out feel free!
Or just want to use this software in general.
PS. I'm just an user, so dont bother asking me any technical questions.
Here is the git:
https://github.com/TagStudioDev/TagStudio
|
|
2025-03-12 09:10:11
|
And here is their discord
https://discord.gg/hRNnVKhF2G
|
|
|
K
TagStudio (a tagging software) is trying to support jxl but there is some incompatible at the moment.
If anyone like to help out feel free!
Or just want to use this software in general.
PS. I'm just an user, so dont bother asking me any technical questions.
Here is the git:
https://github.com/TagStudioDev/TagStudio
|
|
2025-03-12 09:12:01
|
Or should this be posted in <#794206170445119489>
|
|
|
Xarvex
|
2025-03-12 09:13:00
|
Hi, TagStudio maintainer, to correct the above: there’s no incompatibility with JXL, there was a small build issue related to a [Pillow](<https://pypi.org/project/pillow>) plugin used for JXL that’s now been fixed. Not at all related to libJXL itself.
|
|
|
K
|
2025-03-12 09:16:23
|
PS. It was all a ruse to advertise for more contribute so version 9.6 will be e release*yesterday*
|
|
|
Xarvex
|
2025-03-12 09:16:36
|
Please, no
|
|
2025-03-12 09:20:16
|
We have nothing to do with the above, nor condone it. Please disregard it and I hope everyone is enjoying their day. Sorry for the disturbance
|
|
|
jonnyawsom3
|
2025-03-12 09:57:53
|
Regardless, good to know it has support. I don't think we were aware of it before
|
|
|
Xarvex
|
2025-03-12 10:01:24
|
yes, we make use of [pillow-jpegxl-plugin](https://github.com/Isotr0py/pillow-jpegxl-plugin) which seems to be the same thing hydrus uses according to https://discord.com/channels/794206087879852103/803574970180829194/1335062020269150208
|
|
2025-03-12 10:14:33
|
one thing im a tad wary on is how things will look in an eventual rust rewrite, but thats my issue to tackle, it does look though that with this plugin being part rust it obviously does work. im just confused because i know mozilla is waiting on the completion of jxl_rs
|
|
|
Demiurge
|
2025-03-12 04:47:08
|
libjxl can benefit a great deal from a rewrite or major overhaul. Regardless of Rust or not.
|
|
|
Xarvex
|
2025-03-12 05:10:29
|
Interesting, so some of this is being propagated by libjxl at the “top” needing some rework?
|
|
|
Demiurge
|
2025-03-13 02:36:02
|
It's not something to be wary of. The codebase is showing its age. It was originally 2 separate codecs written by different people, merged together into one. So the seams and stitches are showing.
|
|
2025-03-13 02:36:28
|
What I mean is, a rewrite would be more concise and simpler to maintain.
|
|
|
Xarvex
|
2025-03-13 02:41:28
|
gotcha, i see what youre saying
|
|
|
Meow
|
2025-03-13 03:20:04
|
That's why some people consider jxl-rs as the ultimate solution
|
|
|
Xarvex
|
2025-03-13 03:23:51
|
for some reason i glanced over the mention of it being a reimplementation
|
|
2025-03-13 03:24:20
|
when i was looking at the pillow plugin i kinda assumed it was a wrapper for the C lib
|
|
2025-03-13 03:24:30
|
i see now thats not the case
|
|
|
username
|
2025-03-13 03:32:17
|
huh? but it is? wait what are y'all even talking about?
|
|
|
Xarvex
|
2025-03-13 03:37:42
|
jxl-rs being a reimplementation rather than a wrapper
|
|
|
username
|
2025-03-13 03:44:10
|
the pillow plugin isn't using jxl-rs. jxl-rs isn't even ready for use
|
|
|
Xarvex
|
2025-03-13 03:48:28
|
i dont believe i said it did, if i gave such an appearance i apologize for the confusion
|
|
|
username
|
2025-03-13 03:49:16
|
ah it's fine \👍 also sorry if I came across as rude
|
|
|
Xarvex
|
2025-03-13 03:50:07
|
no worries at all!
|
|
|
A homosapien
|
2025-03-13 04:11:12
|
jpegxl-rs is the wrapper, jxl-rs is the reimplementation
|
|
2025-03-13 04:11:21
|
I got confused as well
|
|
2025-03-13 04:11:31
|
the names are very similar
|
|
|
Xarvex
|
2025-03-13 04:14:15
|
Working on TagStudio is the reason I ever heard of JXL, so I’m trying to figure out all this stuff haha
|
|
|
Demiurge
|
2025-03-13 07:08:12
|
Hey that's cool, it's nice to have more tools for viewing and modifying and converting metadata
|
|
2025-03-13 07:08:18
|
Other than exiftool
|
|
|
jonnyawsom3
|
2025-03-13 08:43:26
|
It should be noted, jxl-rs is only a decoder, and jxl-oxide is an existing rust decoder too
|
|
|
Demiurge
|
2025-03-13 12:51:40
|
It's likely to expand to encoding later. Decoding is the hard part
|
|
2025-03-13 12:52:23
|
And decoding happens more often than encoding
|
|
|
|
Hello71
|
2025-03-14 07:49:34
|
is libjxl_extras_codec.a supposed to be installed?
|
|
|
Demiurge
|
|
intelfx
|
2025-03-15 07:36:05
|
Hey.
(Apologies if this channel is not for general peanut gallery questions, redirect me if so.)
Is it expected that progressive lossless encoding (not JPEG→XL reconstruction!) with `cjxl` can be very slow for large inputs?
Input:
```
$ magick identify /path/to/input/jpeg
/path/to/input/jpeg JPEG 24316x18544 24316x18544+0+0 8-bit sRGB 142.977MiB 0.000u 0:00.001
```
Command line:
```
cjxl -v -v -e 7 -j 0 -p /path/to/input/jpeg /path/to/output/jxl
```
Cumulative CPU time is 2h08:33 so far (on a ~4.5 GHz Zen 3 desktop chip), and what seems to be a ~18 GiB working set.
|
|
|
jonnyawsom3
|
|
intelfx
Hey.
(Apologies if this channel is not for general peanut gallery questions, redirect me if so.)
Is it expected that progressive lossless encoding (not JPEG→XL reconstruction!) with `cjxl` can be very slow for large inputs?
Input:
```
$ magick identify /path/to/input/jpeg
/path/to/input/jpeg JPEG 24316x18544 24316x18544+0+0 8-bit sRGB 142.977MiB 0.000u 0:00.001
```
Command line:
```
cjxl -v -v -e 7 -j 0 -p /path/to/input/jpeg /path/to/output/jxl
```
Cumulative CPU time is 2h08:33 so far (on a ~4.5 GHz Zen 3 desktop chip), and what seems to be a ~18 GiB working set.
|
|
2025-03-15 08:13:42
|
Could you try with effort 4 instead? Progressive lossless has density bugs at effort 5+, along with disabling chunked encoding, causing patches to be enabled at effort 5+ (very expensive on large images), IIRC
|
|
|
monad
|
2025-03-15 08:23:29
|
2h still seems excessive, are you hitting swap?
|
|
|
intelfx
|
|
monad
2h still seems excessive, are you hitting swap?
|
|
2025-03-15 08:24:55
|
I did, briefly, at one point, but that was really tiny portion of total runtime
|
|
|
Could you try with effort 4 instead? Progressive lossless has density bugs at effort 5+, along with disabling chunked encoding, causing patches to be enabled at effort 5+ (very expensive on large images), IIRC
|
|
2025-03-15 08:26:54
|
yup, `-e 4` finished the entire batch in 3 minutes _and_ generated 20% smaller files
|
|
|
Quackdoc
|
2025-03-15 08:29:08
|
I never even touch the -p flag anymore I have had results that are just too funky
|
|
|
intelfx
|
2025-03-15 08:29:32
|
funky, as in...?
|
|
|
Quackdoc
|
2025-03-15 08:30:30
|
one time I had a file size that was 8x the size of using `--progressive_dc` instead. another time it made it take 3x longer to decode
|
|
|
intelfx
|
2025-03-15 08:31:25
|
what does `--progressive_{ac,dc}` mean?
|
|
|
jonnyawsom3
|
2025-03-15 08:33:22
|
The issue is the chunked encoding I mentioned. Usually it disallows progressive files due to requiring the TOC at the start of the file, to contain data only written at the end. Or something to that effect
|
|
|
Quackdoc
|
2025-03-15 08:34:33
|
iirc progressive_dc encodes a second small second image that has a good amount of progressiveness it adds very little file size and is IMO one of cjxls best features
|
|
|
intelfx
|
2025-03-15 08:37:29
|
what exactly do "DC" and "AC" even mean in this context?
|
|
|
jonnyawsom3
|
2025-03-15 08:37:34
|
https://github.com/libjxl/libjxl/issues/3823
|
|
|
intelfx
what does `--progressive_{ac,dc}` mean?
|
|
2025-03-15 08:45:35
|
DC is the 1:8 scale image of lossy encoding, usually the first preview before the rest of the file.
Progressive DC can turn that into another lossy image, with a second DC, now 1:64 of the original image for further progressive steps.
Progressive AC is how the remaining data is ordered. There are 2 modes, the QAC which simply sends the least significant bits last for a more blocky image. And 'regular' AC, which has a rougher initial image but better quality passes, if that makes sense
|
|
|
intelfx
|
|
DC is the 1:8 scale image of lossy encoding, usually the first preview before the rest of the file.
Progressive DC can turn that into another lossy image, with a second DC, now 1:64 of the original image for further progressive steps.
Progressive AC is how the remaining data is ordered. There are 2 modes, the QAC which simply sends the least significant bits last for a more blocky image. And 'regular' AC, which has a rougher initial image but better quality passes, if that makes sense
|
|
2025-03-15 09:12:40
|
I tried to read whatever docs I could find on the conceptual overview of the format and encoder, but I still can't understand what exactly "DC" and "AC" are
|
|
|
_wb_
|
2025-03-15 10:05:22
|
DC = direct component, AC = alternating component; if you do a DCT (or other types of frequency transforms) you end up with one coefficient representing the block average (this is the DC) and a bunch of other coefficients representing 'waves' at various frequencies
|
|
2025-03-15 10:08:04
|
in the jxl spec we use the terminology LF and HF instead (low frequency / high frequency) since we mix DC and AC coefficients a bit to harmonize variable block size data into a low frequency part corresponding to an 1:8 image (in case of the old JPEG which only uses DCT8x8, that's just the DC) and a high frequency part which is the bulk of the data corresponding to the remaining image data.
|
|
|
Demiurge
|
2025-03-16 06:19:40
|
DCT is not used for lossless
|
|
2025-03-16 06:20:03
|
Wasn't the question about lossless?
|
|
2025-03-16 06:35:33
|
Progressive lossless is not well tested or optimized afaik
|
|
2025-03-18 06:40:08
|
|
|
2025-03-18 06:40:09
|
Is this a bug others can reproduce? Maybe an issue on github can be opened.
|
|
|
jonnyawsom3
|
2025-03-18 05:30:04
|
A random thought, would multithreaded extra channel and layer decoding require a format extension? I'm not sure if the decoder can tell if they reference other channels/frames beforehand (Using `-E` or blend modes)
|
|
2025-03-18 11:50:29
|
https://github.com/libjxl/libjxl/issues/4156
|
|
2025-03-18 11:50:38
|
.....what?
|
|
2025-03-18 11:51:28
|
They want to completely replace the encoding methods so it beats ZPAQ
|
|
|
A homosapien
|
2025-03-19 01:19:59
|
Breaking the spec now would be one of the worst things to do as adoption is ramping up
|
|
2025-03-19 01:20:34
|
Also isn't ZPAQ like super slow and single threaded? That would be unusable for larger images imo
|
|
|
TheBigBadBoy - 𝙸𝚛
|
2025-03-19 07:11:19
|
Breaking the spec *bc some dude asked chatgpt how to beat zpaq* <:KekDog:805390049033191445>
|
|
|
_wb_
|
2025-03-19 07:34:59
|
Everyone is free to fork libjxl and make a research prototype thing out of it, but no way the spec is going to change in breaking ways.
|
|
|
monad
|
|
A homosapien
Also isn't ZPAQ like super slow and single threaded? That would be unusable for larger images imo
|
|
2025-03-19 07:36:46
|
it's not single-threaded, but the CM is slow and aging. obviously density improvements are possible for jxl, but the particular comparison is amusing
|
|
|
Demiurge
|
|
_wb_
Everyone is free to fork libjxl and make a research prototype thing out of it, but no way the spec is going to change in breaking ways.
|
|
2025-03-19 08:15:24
|
It could still be possible to make small, breaking changes, as long as existing old files will always work, but if future files would change in breaking ways, you just keep it disabled in the encoder until no one is using an old enough decoder anymore for it to be an issue any longer.
|
|
2025-03-19 08:17:06
|
You can add experimental features to the encoder but keep them disabled indefinitely until there's literally no one using an old enough decoder
|
|
2025-03-19 08:18:16
|
It would have to be important enough to be worth it, but if it's something you really think is worth it, I don't think you should feel like your hands are completely tied
|
|
2025-03-19 08:18:52
|
It's still pretty early into the life of "next gen alien technology from the future."
|
|
2025-03-19 08:20:34
|
You wouldn't even have to announce it or make a big deal about it. It could be something done completely behind the scenes. Adding support to the decoder and the spec first, and waiting until everyone updates before changing the encoder.
|
|
|
_wb_
|
2025-03-19 08:47:41
|
even such breaking changes are quite undesirable, it is really hard to tell when "no one is using an old decoder anymore" so it really complicates interoperability. If there's a really good reason to do it, it can of course be considered, but something like just some compression improvement is not enough of a reason imo...
|
|
|
A homosapien
|
2025-03-19 09:01:02
|
Isn't the AVIF team using the "added to decoder/disabled in encoder" method for lossless YCoCg support?
|
|
|
Demiurge
|
|
_wb_
even such breaking changes are quite undesirable, it is really hard to tell when "no one is using an old decoder anymore" so it really complicates interoperability. If there's a really good reason to do it, it can of course be considered, but something like just some compression improvement is not enough of a reason imo...
|
|
2025-03-19 11:03:15
|
At this point in time, it's not THAT difficult to tell, yet, at this stage.
|
|
2025-03-19 11:04:32
|
And you can always wait a few years AFTER the spec+decoders have all been updated and you THINK everyone already switched, BEFORE allowing the encoder to generate a new bitstream that wouldn't work with an old decoder.
|
|
2025-03-19 11:05:33
|
I kinda doubt there's an important issue that's big enough to warrant this methodology. Since the spec was so thoughtfully designed to begin with. I'm just saying that if there WAS, I wouldn't want you feeling as if your hands were completely tied.
|
|
2025-03-19 11:07:13
|
But I think all the "hindsight regrets" were all pretty minor, weren't they?
|
|
2025-03-19 11:07:39
|
Just minor little things that could make things slightly more neat and cool
|
|
2025-03-19 11:08:30
|
Probably not big enough to warrant a new incompatible bitstream structure.
|
|
2025-03-19 11:09:07
|
Or maybe, small and harmless enough to be added and co-exist with the existing one?
|
|
2025-03-19 11:10:22
|
For use in the distant future, when there don't exist any incompatible decoders anymore.
|
|
|
spider-mario
|
2025-03-20 08:33:32
|
> CMYK-tailored predictors optimized for print-oriented content.
that would be jxl’s killer feature, for sure
|
|
|
jonnyawsom3
|
2025-03-20 02:01:25
|
MA trees and dots/patches should be able to do half toning and crosshatching, ect
|
|
2025-03-21 03:15:16
|
Seems to be causing a lot of failures https://github.com/libjxl/libjxl/pull/4132
|
|
2025-03-21 03:15:32
|
https://github.com/libjxl/libjxl/issues/4157
|
|
2025-03-21 03:15:34
|
https://github.com/libjxl/libjxl/issues/4159
|
|
|
A homosapien
|
2025-03-21 03:21:58
|
Bring it up it in <#848189884614705192>?
|
|
|
jonnyawsom3
|
2025-03-21 03:25:20
|
Equal visibility here and Jon is already in the PR, just thought I'd make the rest of you aware
|
|
|
_wb_
|
2025-03-21 06:59:52
|
<@1346460706345848868> can you take a look? Looks like you have an edge case not handled
|
|
2025-03-21 10:13:06
|
Some int arithmetic was replaced by float arithmetic in RebalanceHistogram(), I bet this is causing some shenanigans.
Ideally that function should just never return false and that template option `minimize_error_of_sum` should not be needed, but if that's too tricky then at least it should never return false when `minimize_error_of_sum==true`. I guess it's hard to test this exhaustively since the number of possible inputs is too huge and it probably only fails in rare cases, so I suppose we need to use brains and math and stuff.
|
|
|
Demiurge
|
2025-03-21 01:33:24
|
Oh no! Not brains and math and stuff! Anything but that!
|
|
|
Melirius
|
|
_wb_
<@1346460706345848868> can you take a look? Looks like you have an edge case not handled
|
|
2025-03-22 01:04:40
|
Yeah, will take a look.
|
|
|
_wb_
Some int arithmetic was replaced by float arithmetic in RebalanceHistogram(), I bet this is causing some shenanigans.
Ideally that function should just never return false and that template option `minimize_error_of_sum` should not be needed, but if that's too tricky then at least it should never return false when `minimize_error_of_sum==true`. I guess it's hard to test this exhaustively since the number of possible inputs is too huge and it probably only fails in rare cases, so I suppose we need to use brains and math and stuff.
|
|
2025-03-22 01:46:23
|
I tried to find a mathematically correct way to rebalance any histogram, but due to the increase of low frequencies to 1/2048 and coarsing by `SmallestIncrementNonzero` it got too complicated quickly and I have not succeed.
|
|
2025-03-22 04:45:30
|
Fix is ready https://github.com/libjxl/libjxl/pull/4160
|
|
2025-03-24 05:07:49
|
I've put an experimental version of rebalance that cannot produce invalid histograms, testing it now on a large corpus of images
|
|
|
Lilli
|
2025-03-24 05:27:14
|
Hello there! I wanted to integrate the format into my program on my raspi. It works great, but I noticed an recurring artifact present in the images.
I am using my raspi as an intermediate where I compress rather large TIFF images (>200Mo, 16bits) of astronomical observations into jxl.
The images are split into bits, so there's no problem there (even though I'd like to make it a tiled jxl, I did not figure that out yet).
My problem is:
- blue boxes appearing around stars (close to dirac)
See below a few images, one with lower quality (d=0.085) and one with good quality (d=0.001), and the stock image. These are closeups to see the issue, and the histogram has been way stretched since it's 16bits. The original tiff is there: https://we.tl/t-Ri6XFzZtkH
I noticed that when using cjxl PNG->JXL, this artifact is not present.
When exporting to regular PNG from my solf, I also do not experience this. Only when using libJXL.
Note that I load the tiff in a `uint16_t*`, which I pass directly to libjxl using
` JxlPixelFormat pixel_format = {image.getChannels(), JXL_TYPE_UINT16, JXL_NATIVE_ENDIAN, 0};`
Here are my settings:
```
basic_info.uses_original_profile = JXL_TRUE;
basic_info.exponent_bits_per_sample = 0;
color_encoding.color_space = JXL_COLOR_SPACE_RGB;
color_encoding.white_point = JXL_WHITE_POINT_E;
color_encoding.transfer_function = JXL_TRANSFER_FUNCTION_LINEAR;
color_encoding.primaries = JXL_PRIMARIES_SRGB;
color_encoding.rendering_intent = JXL_RENDERING_INTENT_PERCEPTUAL;
```
When passing the same buffer to PNG, no artifact, so there is something in my settings I suppose.
Where does this artifact come from, and what kind of settings are likely to modify it? I have tried changing the distance and the effort with no luck.
|
|
2025-03-24 05:27:41
|
Should I create an issue on git?
|
|
|
RaveSteel
|
2025-03-24 05:48:03
|
Is lossy a requirement?
|
|
|
Lilli
|
2025-03-24 05:59:30
|
I need about 10 - 12x compression ratio, it will be hard to get with lossy I presume. Being on embedded device, I also cannot use process-intensive operation, the processor isn't that great. This 300Mo file gets compressed in about 20seconds on target, which is about twice as fast as jp2.
|
|
|
spider-mario
|
|
Lilli
Hello there! I wanted to integrate the format into my program on my raspi. It works great, but I noticed an recurring artifact present in the images.
I am using my raspi as an intermediate where I compress rather large TIFF images (>200Mo, 16bits) of astronomical observations into jxl.
The images are split into bits, so there's no problem there (even though I'd like to make it a tiled jxl, I did not figure that out yet).
My problem is:
- blue boxes appearing around stars (close to dirac)
See below a few images, one with lower quality (d=0.085) and one with good quality (d=0.001), and the stock image. These are closeups to see the issue, and the histogram has been way stretched since it's 16bits. The original tiff is there: https://we.tl/t-Ri6XFzZtkH
I noticed that when using cjxl PNG->JXL, this artifact is not present.
When exporting to regular PNG from my solf, I also do not experience this. Only when using libJXL.
Note that I load the tiff in a `uint16_t*`, which I pass directly to libjxl using
` JxlPixelFormat pixel_format = {image.getChannels(), JXL_TYPE_UINT16, JXL_NATIVE_ENDIAN, 0};`
Here are my settings:
```
basic_info.uses_original_profile = JXL_TRUE;
basic_info.exponent_bits_per_sample = 0;
color_encoding.color_space = JXL_COLOR_SPACE_RGB;
color_encoding.white_point = JXL_WHITE_POINT_E;
color_encoding.transfer_function = JXL_TRANSFER_FUNCTION_LINEAR;
color_encoding.primaries = JXL_PRIMARIES_SRGB;
color_encoding.rendering_intent = JXL_RENDERING_INTENT_PERCEPTUAL;
```
When passing the same buffer to PNG, no artifact, so there is something in my settings I suppose.
Where does this artifact come from, and what kind of settings are likely to modify it? I have tried changing the distance and the effort with no luck.
|
|
2025-03-24 06:03:44
|
how sure are you that you have absolutely no over/underflow in the values you pass?
|
|
|
Lilli
|
2025-03-24 06:05:14
|
Images come from the TIFF. They are in uint16_t, so I believe over/underflow are not possible there
|
|
|
spider-mario
how sure are you that you have absolutely no over/underflow in the values you pass?
|
|
2025-03-24 06:10:50
|
I added a little more details to make sure this is clear 🙂
Thank you for asking clarifications!
|
|
|
Quackdoc
|
2025-03-24 06:14:52
|
I wonder if there is a significant difference between modular and vardct with this issue
|
|
|
spider-mario
|
2025-03-24 06:28:15
|
I wonder if perhaps underflow occurs because of the conversion to linear sRGB
|
|
2025-03-24 06:28:42
|
does the problem still occur if you change the white point from E to D65?
|
|
2025-03-24 06:28:55
|
(E is a bit of an unusual choice)
|
|
2025-03-24 06:29:45
|
also, which decoder produced the result with the green square?
|
|
|
jonnyawsom3
|
|
Lilli
Hello there! I wanted to integrate the format into my program on my raspi. It works great, but I noticed an recurring artifact present in the images.
I am using my raspi as an intermediate where I compress rather large TIFF images (>200Mo, 16bits) of astronomical observations into jxl.
The images are split into bits, so there's no problem there (even though I'd like to make it a tiled jxl, I did not figure that out yet).
My problem is:
- blue boxes appearing around stars (close to dirac)
See below a few images, one with lower quality (d=0.085) and one with good quality (d=0.001), and the stock image. These are closeups to see the issue, and the histogram has been way stretched since it's 16bits. The original tiff is there: https://we.tl/t-Ri6XFzZtkH
I noticed that when using cjxl PNG->JXL, this artifact is not present.
When exporting to regular PNG from my solf, I also do not experience this. Only when using libJXL.
Note that I load the tiff in a `uint16_t*`, which I pass directly to libjxl using
` JxlPixelFormat pixel_format = {image.getChannels(), JXL_TYPE_UINT16, JXL_NATIVE_ENDIAN, 0};`
Here are my settings:
```
basic_info.uses_original_profile = JXL_TRUE;
basic_info.exponent_bits_per_sample = 0;
color_encoding.color_space = JXL_COLOR_SPACE_RGB;
color_encoding.white_point = JXL_WHITE_POINT_E;
color_encoding.transfer_function = JXL_TRANSFER_FUNCTION_LINEAR;
color_encoding.primaries = JXL_PRIMARIES_SRGB;
color_encoding.rendering_intent = JXL_RENDERING_INTENT_PERCEPTUAL;
```
When passing the same buffer to PNG, no artifact, so there is something in my settings I suppose.
Where does this artifact come from, and what kind of settings are likely to modify it? I have tried changing the distance and the effort with no luck.
|
|
2025-03-24 08:55:36
|
`basic_info.uses_original_profile` should be false for lossy, as XYB is used internally instead of RGB
|
|
|
spider-mario
|
2025-03-24 09:17:05
|
oh, yeah, missed that
|
|
2025-03-24 09:17:40
|
it also means that what I said doesn’t apply
|
|
|
jonnyawsom3
|
2025-03-24 10:09:20
|
...why does that exist? Lossy only works with it set to false, and lossless isn't lossless unless it's true, right?
|
|
|
spider-mario
|
2025-03-24 10:14:30
|
it does seem to be a source of a lot of confusion
|
|
2025-03-24 10:16:06
|
I know too little about this application to say whether this might be one of the instances in which there might be a case to be made for it
|
|
|
CrushedAsian255
|
|
...why does that exist? Lossy only works with it set to false, and lossless isn't lossless unless it's true, right?
|
|
2025-03-24 10:20:52
|
Lossy modular may find a need for it
|
|
|
jonnyawsom3
|
2025-03-24 10:39:29
|
Lossy modular still uses XYB interally (by default)
|
|
|
A homosapien
|
|
spider-mario
it does seem to be a source of a lot of confusion
|
|
2025-03-25 12:01:54
|
I assume its because Jpeg XL is the first of its kind, where color information is part of the encoding and decoding process. Every other image format has optional color space information defined in an icc profile. Very few are aware that Jpeg XL handles all color internally.
|
|
|
0xC0000054
|
|
A homosapien
I assume its because Jpeg XL is the first of its kind, where color information is part of the encoding and decoding process. Every other image format has optional color space information defined in an icc profile. Very few are aware that Jpeg XL handles all color internally.
|
|
2025-03-25 12:35:14
|
AVIF also has per-frame color information through the CICP metadata.
|
|
|
A homosapien
|
2025-03-25 12:44:50
|
You can opt out of all color management in AVIF with cicp 2/2/2 (Not that's a good idea). Jpeg XL *has* to be color managed every step of the way. We should really have a big fat warning with red text in the docs saying, "DO NOT USE LOSSY COMPRESSION WITH THIS OPTION ON". RGB compression is a sin.
|
|
|
username
|
|
A homosapien
You can opt out of all color management in AVIF with cicp 2/2/2 (Not that's a good idea). Jpeg XL *has* to be color managed every step of the way. We should really have a big fat warning with red text in the docs saying, "DO NOT USE LOSSY COMPRESSION WITH THIS OPTION ON". RGB compression is a sin.
|
|
2025-03-25 12:51:02
|
I presume RGB lossy could be made to not be *horrible* as I assume it's just the encoder not being tuned/setup for it at all really, though it doesn't make much sense to put effort towards fixing it up currently since if you are doing lossy then XYB is the way to go for most use cases. But yeah with how many people keep mistakenly using RGB lossy it should probably be pointed out in the docs.
|
|
|
Quackdoc
|
|
A homosapien
You can opt out of all color management in AVIF with cicp 2/2/2 (Not that's a good idea). Jpeg XL *has* to be color managed every step of the way. We should really have a big fat warning with red text in the docs saying, "DO NOT USE LOSSY COMPRESSION WITH THIS OPTION ON". RGB compression is a sin.
|
|
2025-03-25 12:52:29
|
rgb compression is probably a lot better then xyb if you want a fast decode option
|
|
2025-03-25 12:52:37
|
that can be 4 xD
|
|
2025-03-25 12:56:17
|
I wonder whats faster, jxl-oxide or yuvxyb
https://cdn.discordapp.com/emojis/1113499891314991275?size=64
|
|
|
CrushedAsian255
|
|
username
I presume RGB lossy could be made to not be *horrible* as I assume it's just the encoder not being tuned/setup for it at all really, though it doesn't make much sense to put effort towards fixing it up currently since if you are doing lossy then XYB is the way to go for most use cases. But yeah with how many people keep mistakenly using RGB lossy it should probably be pointed out in the docs.
|
|
2025-03-25 12:58:54
|
im assuming the loss accured through rgb->xyb->rgb roundtrip is significantly lower than the actual lossy nature of the codec
|
|
|
username
|
|
A homosapien
I assume its because Jpeg XL is the first of its kind, where color information is part of the encoding and decoding process. Every other image format has optional color space information defined in an icc profile. Very few are aware that Jpeg XL handles all color internally.
|
|
2025-03-25 01:01:31
|
maybe a better way to put it would be that with JPEG XL color management is apart of the **full** pipeline and not something that can be ignored like in other formats.
Jon/wb worded it nicely here: https://discord.com/channels/794206087879852103/794206170445119489/1281531968688750664
Also this blog post from Kampidh showcases the kind of negatives that come with not treating color management as first class: https://saklistudio.com/miniblog/modern-image-format-linear-color-analysis/
<@833420862334042152> sorry for the direct ping but Discord doesn't seem to have a way to reply to multiple messages at the same time.
|
|
|
username
maybe a better way to put it would be that with JPEG XL color management is apart of the **full** pipeline and not something that can be ignored like in other formats.
Jon/wb worded it nicely here: https://discord.com/channels/794206087879852103/794206170445119489/1281531968688750664
Also this blog post from Kampidh showcases the kind of negatives that come with not treating color management as first class: https://saklistudio.com/miniblog/modern-image-format-linear-color-analysis/
<@833420862334042152> sorry for the direct ping but Discord doesn't seem to have a way to reply to multiple messages at the same time.
|
|
2025-03-25 01:01:46
|
animated examples from that blog post:
https://saklistudio.com/miniblog/blog-img/jxlvother/1bpp-anim.webp
https://saklistudio.com/miniblog/blog-img/jxlvother/06bpp-anim.webp
|
|
|
Demiurge
|
2025-03-25 02:00:43
|
Using the vips api might be easier <@1353777338843795608>
|
|
2025-03-25 02:01:03
|
Compared to libjxl directly
|
|
|
jonnyawsom3
|
|
CrushedAsian255
im assuming the loss accured through rgb->xyb->rgb roundtrip is significantly lower than the actual lossy nature of the codec
|
|
2025-03-25 02:19:58
|
IIRC the transformation is fully reversible
|
|
|
CrushedAsian255
|
|
IIRC the transformation is fully reversible
|
|
2025-03-25 03:12:07
|
I’m thinking like floating point math weirdness
|
|
|
jonnyawsom3
|
|
`basic_info.uses_original_profile` should be false for lossy, as XYB is used internally instead of RGB
|
|
2025-03-25 03:12:23
|
Maybe it should be changed to `basic_info.uses_xyb_internally` or something similar. Since the output *is* the original profile, just not used for the internal compression
|
|
|
CrushedAsian255
I’m thinking like floating point math weirdness
|
|
2025-03-25 03:14:58
|
32float can represent up to 24int with exact precision, so for any normal 8int or 16int input it shouldn't be an issue
|
|
|
Demiurge
|
|
Lilli
Hello there! I wanted to integrate the format into my program on my raspi. It works great, but I noticed an recurring artifact present in the images.
I am using my raspi as an intermediate where I compress rather large TIFF images (>200Mo, 16bits) of astronomical observations into jxl.
The images are split into bits, so there's no problem there (even though I'd like to make it a tiled jxl, I did not figure that out yet).
My problem is:
- blue boxes appearing around stars (close to dirac)
See below a few images, one with lower quality (d=0.085) and one with good quality (d=0.001), and the stock image. These are closeups to see the issue, and the histogram has been way stretched since it's 16bits. The original tiff is there: https://we.tl/t-Ri6XFzZtkH
I noticed that when using cjxl PNG->JXL, this artifact is not present.
When exporting to regular PNG from my solf, I also do not experience this. Only when using libJXL.
Note that I load the tiff in a `uint16_t*`, which I pass directly to libjxl using
` JxlPixelFormat pixel_format = {image.getChannels(), JXL_TYPE_UINT16, JXL_NATIVE_ENDIAN, 0};`
Here are my settings:
```
basic_info.uses_original_profile = JXL_TRUE;
basic_info.exponent_bits_per_sample = 0;
color_encoding.color_space = JXL_COLOR_SPACE_RGB;
color_encoding.white_point = JXL_WHITE_POINT_E;
color_encoding.transfer_function = JXL_TRANSFER_FUNCTION_LINEAR;
color_encoding.primaries = JXL_PRIMARIES_SRGB;
color_encoding.rendering_intent = JXL_RENDERING_INTENT_PERCEPTUAL;
```
When passing the same buffer to PNG, no artifact, so there is something in my settings I suppose.
Where does this artifact come from, and what kind of settings are likely to modify it? I have tried changing the distance and the effort with no luck.
|
|
2025-03-25 04:33:13
|
lossy image formats try to approximate low "perceptual" distortion but this TIFF is raw sensor data with no hints about how to interpret the brightness values, so there's no way of knowing what type of distortion is "perceptible" or not. I see you added some color encoding info with the libjxl API, but... there's still no way of telling how bright the pixels are, and therefore how much distortion is acceptable or not. I think that weird square you're getting might be a separate bug though.
|
|
2025-03-25 05:09:41
|
Also, lossless is about 1/3rd of the size of the TIFF and it's extremely fast on effort 1 and 2. Higher effort doesn't compress the file any smaller.
|
|
|
Lilli
|
|
spider-mario
also, which decoder produced the result with the green square?
|
|
2025-03-25 08:12:07
|
Thank you all for your excellent responses!
I chose E because my images are mostly black and I thought this would better suit my data, but I will try with D65.
I used multiple decoders: decoded the jxl directly in gimp, also tried decoding it through my own means with libjxl and converted to TIFF.
|
|
|
`basic_info.uses_original_profile` should be false for lossy, as XYB is used internally instead of RGB
|
|
2025-03-25 08:12:58
|
I did not understand this, thank you !
|
|
2025-03-25 08:22:31
|
Okay, so I tested with
`basic_info.uses_original_profile = JXL_FALSE;`
And the squares vanished!
I did not try to put the white point to D65 as it seems the issue is now resolved.
If this is actually a bug with `uses_original_profile`, I can provide data and code to reproduce it.
I will further experiment, but everything seems ok now
|
|
|
Demiurge
lossy image formats try to approximate low "perceptual" distortion but this TIFF is raw sensor data with no hints about how to interpret the brightness values, so there's no way of knowing what type of distortion is "perceptible" or not. I see you added some color encoding info with the libjxl API, but... there's still no way of telling how bright the pixels are, and therefore how much distortion is acceptable or not. I think that weird square you're getting might be a separate bug though.
|
|
2025-03-25 08:25:30
|
I see. Is there a way to give better hints to the encoder ?
|
|
|
_wb_
|
2025-03-25 08:51:06
|
The most important thing is to get the encoder to see the image in the same way as a human. If you decode to png, it should be a png you can view in a browser or other standard png viewer without adjustments. One of the causes of bad lossy compression is doing things like storing 12-bit RGB values in a 16-bit PNG with the padding in the most significant bits instead of in the least significant bits, which means you're effectively making the image near-black and the encoder will compress it too aggressively.
|
|
2025-03-25 08:54:49
|
at d=1 the image should be more or less visually lossless when viewed without zooming, if that's not the case then something is not right
|
|
|
Lilli
|
2025-03-25 08:57:51
|
I see, this seems close to what I am doing, but I do need the large dynamic. Stars are bright, nebulaes aren't !
This is an intermediate format for transfer over wifi (because fast compression, fast decompression and good image quality)
The image is supposed to be processed after, on a more powerful device, so we need as little artifacts as possible but still in linear. It's not an image meant to be viewed right away, it doesn't have any gamma applied to it yet!
|
|
|
_wb_
|
2025-03-25 09:02:21
|
I understand, but if in the postprocessing you're going to increase brightness a lot in the darker regions, then probably it's a good idea to give the encoder an image that is closer to the brightest it may get after processing rather than letting it think it's very dark
|
|
|
Lilli
|
2025-03-25 09:11:05
|
So I would get better compression performance if I pre-gamma it as I understand. That could be done, performing a simple gamma is relatively reversible.
|
|
2025-03-25 09:12:17
|
This is the input
|
|
2025-03-25 09:12:43
|
and this is the processed output
|
|
2025-03-25 09:12:49
|
same region
|
|
|
_wb_
I understand, but if in the postprocessing you're going to increase brightness a lot in the darker regions, then probably it's a good idea to give the encoder an image that is closer to the brightest it may get after processing rather than letting it think it's very dark
|
|
2025-03-25 09:29:59
|
I will try to spread the dynamic a bit better, and report back with the results if that's of any interest to you 🙂
|
|
|
jonnyawsom3
|
2025-03-25 09:42:37
|
Some light related reading <https://github.com/libjxl/libjxl/issues/314#issuecomment-880620569>
|
|
|
Lilli
|
2025-03-25 09:47:05
|
Good read thanks !
|
|
2025-03-25 03:54:07
|
I come to report my findings.
I applied a moderately complex gamma. A simple exponent wouldn't do, so I had to use a curve (for which I do not have the exact values, I did it on gimp)
I then fed this "proper" image into my lib using jxl and noticed a few things:
- the "-d" parameter now behaves as expected, a value of about 0.9 - 0.8 yields similar compression rate (x12) to previously 0.065
- the compression is worse in places of high intensity, as in, the center of the galaxy is badly compressed, whereas it was fine on the unprocessed input
You can see clearly the blocks in the output that had a gamma on it already.
Should the parameter given to `transfer_function` be something else than LINEAR in this case?
|
|
2025-03-25 04:04:13
|
|
|
2025-03-25 04:05:43
|
In summary, in my use case so far, it seems that using the pipeline
TIFF->JXL (->gamma for display)
is better than
TIFF -> gamma -> JXL (-> Ungamma if necessary)
|
|
|
spider-mario
|
2025-03-25 04:08:54
|
it might be that using a higher-than-default `intensity_target` is a justifiable alternative in your case
|
|
2025-03-25 04:09:41
|
except with PQ images, `intensity_target=N` means that (1, 1, 1) in the image has a luminance of `N` cd/m²
|
|
2025-03-25 04:09:46
|
the default is 255
|
|
|
Lilli
|
2025-03-25 04:12:30
|
Ah! Even for a 16bits image?
|
|
|
spider-mario
|
2025-03-25 04:44:12
|
yes, that 255 doesn’t have _that_ much to do with 2⁸ − 1
|
|
2025-03-25 04:44:34
|
it’s numerically equal to it but these days, you can treat that as a coincidence
|
|
2025-03-25 04:45:12
|
maybe there is less of a temptation to relate it to that if it’s written as 255.0
|
|
|
Demiurge
|
2025-03-25 09:17:14
|
You sure you can't just compress the 300M tiff to a 117M lossless jxl?
|
|
2025-03-25 09:17:37
|
It's even faster than lossy compression.
|
|
|
spider-mario
maybe there is less of a temptation to relate it to that if it’s written as 255.0
|
|
2025-03-25 09:19:46
|
Maybe just change the default to 300? Then there's even less confusion. And I agree it's very common for people to be confused about the uses_original_profile thing, something should be done to prevent it from being misused by developers.
|
|
2025-03-25 09:20:12
|
Making the libjxl api less confusing to use is very important
|
|
2025-03-25 09:20:31
|
And reducing the chances of mistakes.
|
|
|
CrushedAsian255
|
|
Demiurge
Maybe just change the default to 300? Then there's even less confusion. And I agree it's very common for people to be confused about the uses_original_profile thing, something should be done to prevent it from being misused by developers.
|
|
2025-03-25 09:34:47
|
Intensity target is in nits correct?
|
|
|
_wb_
|
2025-03-25 09:58:40
|
Yes
|
|
2025-03-25 09:59:26
|
And the default value is in the spec, you can of course signal any value but the value you get by not signaling anything is 255
|
|
|
Demiurge
|
2025-03-25 10:25:40
|
I need to read the spec more thoroughly some day...
|
|
|
Quackdoc
|
2025-03-25 10:29:09
|
need tirr's jxl document <:PepeHands:808829977608323112>
|
|
|
damian101
|
|
Quackdoc
rgb compression is probably a lot better then xyb if you want a fast decode option
|
|
2025-03-26 01:14:20
|
no, yuv rgb conversion is very fast
|
|
|
username
I presume RGB lossy could be made to not be *horrible* as I assume it's just the encoder not being tuned/setup for it at all really, though it doesn't make much sense to put effort towards fixing it up currently since if you are doing lossy then XYB is the way to go for most use cases. But yeah with how many people keep mistakenly using RGB lossy it should probably be pointed out in the docs.
|
|
2025-03-26 01:15:06
|
no, not really, isolating luminance into its own channel is crucial
|
|
|
Quackdoc
|
|
no, yuv rgb conversion is very fast
|
|
2025-03-26 01:15:41
|
A) it still takes time, and when you want the lowest possible decode speed, its a waste of time
B) xyb to rgb iirc it a bit more involved then yuv to rgb
|
|
2025-03-26 01:15:53
|
or maybe im thinking of xyb to yuv
|
|
2025-03-26 01:16:00
|
in any case, its extra operations
|
|
|
damian101
|
|
Quackdoc
A) it still takes time, and when you want the lowest possible decode speed, its a waste of time
B) xyb to rgb iirc it a bit more involved then yuv to rgb
|
|
2025-03-26 01:16:44
|
It's never a waste of time, because encoding in YUV is way more efficient, and chroma subsampling gives a performance boost way beyond the minuscule speed boost of skipping YUV<->RGB conversion
|
|
|
Quackdoc
|
2025-03-26 01:17:00
|
wrong
|
|
2025-03-26 01:17:08
|
if I need faster decode, i need faster decode
|
|
|
A homosapien
|
2025-03-26 01:17:12
|
If it's good enough for jpegli, it's good enough for us
|
|
|
damian101
|
|
Quackdoc
A) it still takes time, and when you want the lowest possible decode speed, its a waste of time
B) xyb to rgb iirc it a bit more involved then yuv to rgb
|
|
2025-03-26 01:17:18
|
you were talking about XYB to RGB?
|
|
|
Quackdoc
|
|
damian101
|
2025-03-26 01:17:33
|
well that changes things
|
|
2025-03-26 01:17:35
|
but still
|
|
|
Quackdoc
|
2025-03-26 01:17:40
|
even then yuv to rgb still takes time
|
|
|
damian101
|
2025-03-26 01:17:54
|
directly encoding in RGB is awfully inefficient
|
|
|
Quackdoc
|
2025-03-26 01:18:16
|
sure
|
|
2025-03-26 01:18:22
|
no one said differently
|
|
|
A homosapien
|
2025-03-26 01:20:21
|
For the fastest possible decode speed just use ppm
|
|
|
Quackdoc
|
2025-03-26 01:24:14
|
some comression still needed
https://cdn.discordapp.com/emojis/867794291652558888?size=64
|
|
|
A homosapien
|
2025-03-26 01:26:18
|
But then it's not the fastest decode speed possible as you said
|
|
2025-03-26 01:26:27
|
Come on. You're basically asking for magic
|
|
|
jonnyawsom3
|
2025-03-26 02:29:05
|
PPM with filesystem compression
|
|
|
Demiurge
|
|
Quackdoc
if I need faster decode, i need faster decode
|
|
2025-03-26 04:23:19
|
If you use libjpeg-turbo you don't need to ever worry about decode speed. And chroma subsampling is a significant computational reduction too, meaning speed boost. You would probably gain much more speed than the negligible, absolutely marginal amount of time yuv conversion costs...
|
|
|
Quackdoc
even then yuv to rgb still takes time
|
|
2025-03-26 04:25:03
|
Unless you actually measured the difference in time it actually takes, saying this does not matter at all. Premature ejaculation is the root of all evil.
|
|
|
Quackdoc
|
2025-03-26 04:33:47
|
chroma subsampling is actually not super cheap if you want a high quality upsample
|
|
|
jonnyawsom3
|
|
Quackdoc
if I need faster decode, i need faster decode
|
|
2025-03-26 04:37:48
|
You already said you don't care about encoding efficency, so low quality upsampling shouldn't matter
|
|
|
Quackdoc
|
2025-03-26 04:38:11
|
it matters a shit ton in an NLE,
|
|
|
Lilli
|
|
spider-mario
except with PQ images, `intensity_target=N` means that (1, 1, 1) in the image has a luminance of `N` cd/m²
|
|
2025-03-26 09:43:19
|
I increased it to a 1000, now I need to have d=3 to get x12 compression. The image is still worse than the input without an applied gamma in critical parts. I will keep the original image mostly black as it's still the easiest for me (no gamma - ungamma procedure) and no parameter setup. I might tweak the intensity to bias it toward compressing the noise but apart from that, I'm satisfied of the lib and happy with the results 🙂
Thank you all for your support and insights!
|
|
|
jonnyawsom3
|
|
Lilli
I increased it to a 1000, now I need to have d=3 to get x12 compression. The image is still worse than the input without an applied gamma in critical parts. I will keep the original image mostly black as it's still the easiest for me (no gamma - ungamma procedure) and no parameter setup. I might tweak the intensity to bias it toward compressing the noise but apart from that, I'm satisfied of the lib and happy with the results 🙂
Thank you all for your support and insights!
|
|
2025-03-26 09:50:48
|
If I understand correctly, I'd actually suggest trying an intensity target of 10,000 on the original very dark image. That should give all areas roughly equal quality regardless of brightness. In the end, what works, works. So feel free to stick with your own solution. Could definitely do with a 'Range extender' option that doesn't crush blacks and over smoothen whites
|
|
|
Lilli
|
2025-03-26 09:59:33
|
I see ! Okay I will try that 🙂 Thank you
Maybe this use case is a bit too specific, it's hard to ask for a format to be that versatile.
|
|
|
jonnyawsom3
|
2025-03-26 10:08:33
|
As you've proved by lowering the distance to 0.1 and 0.001, it is possible, just not very easily currently.
We've had a few people doing satellite/multispectral imagery, along with people using it for photography where they want to change exposure after. There's even multiple issues on Github about this exact problem, but no easy way to fix it other than changing the input, using the intensity target workaround or lowering the distance drastically as you did
|
|
|
spider-mario
|
|
Lilli
I increased it to a 1000, now I need to have d=3 to get x12 compression. The image is still worse than the input without an applied gamma in critical parts. I will keep the original image mostly black as it's still the easiest for me (no gamma - ungamma procedure) and no parameter setup. I might tweak the intensity to bias it toward compressing the noise but apart from that, I'm satisfied of the lib and happy with the results 🙂
Thank you all for your support and insights!
|
|
2025-03-26 10:24:17
|
oh, right, I meant without the gamma
|
|
2025-03-26 10:24:30
|
just the same as you were doing before but with the higher intensity_target on top
|
|
|
Demiurge
|
2025-03-26 10:43:56
|
Hell yeah. +1 for "range extender mode" for raw sensor data!
|
|
|
Lilli
|
|
spider-mario
just the same as you were doing before but with the higher intensity_target on top
|
|
2025-03-26 11:54:52
|
I see! yes then what you suggested did what it was supposed to do. In the end what I'm doing is trying different combinations of distance and intensity target to keep the compression ratio the same, and checking which one suits the requirements best (more compression on noise, less on signal) Thank you for the pointer in the right direction
|
|
|
CrushedAsian255
|
|
Lilli
I see ! Okay I will try that 🙂 Thank you
Maybe this use case is a bit too specific, it's hard to ask for a format to be that versatile.
|
|
2025-03-26 12:40:26
|
> it's hard to ask for a format to be that versatile
Well, given enough tuning (or a custom encoder), JXL can be that format!
|
|
|
Lilli
|
2025-03-27 12:20:43
|
I'm noticing that depending on the images, I'm not getting the same compression (which makes sense). I know there is a way to specify a target compression with cjxl, but how to do it from libjxl?
|
|
|
spider-mario
|
2025-03-27 12:30:50
|
which `cjxl` option are you thinking of? I don’t believe we still have it nowadays
|
|
|
jonnyawsom3
|
2025-03-27 12:43:06
|
target size is in benchmark_xl only
|
|
|
Lilli
|
2025-03-27 12:47:43
|
I see :/
|
|
2025-03-27 12:51:06
|
Is there a way to achieve that anyway?
|
|
|
jonnyawsom3
|
2025-03-27 12:55:06
|
IIRC it was just a trial and error binary search for the nearest match to a certain threshold
|
|
|
spider-mario
|
2025-03-27 01:08:55
|
indeed
|
|
|
Lilli
|
2025-03-27 02:16:54
|
I see, so it compresses the whole thing several times? Argh. JPEG2000's quality parameter was quite consistent in giving the same compression ratio on all my images.
Sounds like I should just hope for the best then :/
|
|
|
HCrikki
|
2025-03-27 02:24:32
|
it was never consistent or made sense for other formats, just a best effort that worked because it tried quality % until it approached the kilobyte number/ratio you asked for
|
|
2025-03-27 02:25:18
|
jxl should do these approximations a lot quicker and since it identifies the most detailled parts of images can tune compression more agressively for those regions (without redoing compression for the rest or the full image - or the opposite, if youd prefer preserving those details)
|
|
|
jonnyawsom3
|
2025-03-27 02:26:42
|
The other, much more jank way, would be progressive encoding and then truncating the file. But only jxl-oxide can decode that currently. That's essentially what JPEG2000 did.
There's no compression ratio target since images can have vastly different requirements, and we don't want people shooting themselves in the foot when a simple image is wasting a lot of data and complex images look unrecognisable
|
|
2025-03-27 02:27:57
|
You could try `--disable_perceptual_optimizations` which might also remove the need for `--intensity_target` but memory usage and encode speed will suffer drastically
|
|
|
Lilli
|
2025-03-27 03:18:44
|
Oh! interesting... Speed and memory usage are both very important because it's time sensitive and on embedded device... So I'll just hope for the best 🙂
|
|
|
_wb_
|
2025-03-27 03:27:10
|
Keeping compression ratio constant means the same thing as having wildly inconsistent quality. There are few use cases where that is useful, notable exception being cases where there is a hard filesize limit imposed and you want to fully use it even if it is not needed.
|
|
|
jonnyawsom3
|
|
Lilli
Oh! interesting... Speed and memory usage are both very important because it's time sensitive and on embedded device... So I'll just hope for the best 🙂
|
|
2025-03-27 03:34:35
|
A bit of a far fetch, but I don't suppose you're trying to do JXL encoding on a satellite before downlinking?
|
|
|
Lilli
|
2025-03-27 03:47:05
|
No, it's astrophoto sensor data
|
|
2025-03-27 03:48:44
|
but onboard memory and processing capabilities are busy doing something else so these images should have as little impact as possible.
|
|
|
_wb_
Keeping compression ratio constant means the same thing as having wildly inconsistent quality. There are few use cases where that is useful, notable exception being cases where there is a hard filesize limit imposed and you want to fully use it even if it is not needed.
|
|
2025-03-27 04:01:23
|
Yes the filesize isn't a strictly speaking hard requirement, but transfer time should be low for transfer stability reasons. Having a bit of a swing is expected, but basically what I'd like is "at least this much compression rate", then I have to roll with the quality that goes with it. In all likelihood, It'll be easiest to compress images with less noise, and what I want to compress is precisely the bottom of the histogram, the noise. In any case, if we find that we need a bit more quality, then we'll increase the quality.
|
|
|
Demiurge
|
|
Lilli
Yes the filesize isn't a strictly speaking hard requirement, but transfer time should be low for transfer stability reasons. Having a bit of a swing is expected, but basically what I'd like is "at least this much compression rate", then I have to roll with the quality that goes with it. In all likelihood, It'll be easiest to compress images with less noise, and what I want to compress is precisely the bottom of the histogram, the noise. In any case, if we find that we need a bit more quality, then we'll increase the quality.
|
|
2025-03-27 08:54:53
|
It sounds like a custom encoder could be more than 100 times more effective in speed/quality for what you want, rather than stock standard libjxl
|
|
2025-03-27 09:01:13
|
libjxl doesn't have the capability to target a specific average bitrate, and I don't think the quantizer is designed to compress a really, really dark image with a faint signal peeking through the noise
|
|
2025-03-27 09:05:19
|
The libjxl devs also said they are afraid of making drastic changes to the lossy encoder cuz they're afraid of regressions and the lack of alternative encoders if they mess things up. Which is very poor reasoning in my opinion but whatevers.
|
|
|
Lilli
|
2025-03-28 08:51:02
|
I see :/ For sure a custom encoder would be miles better, but I don't have the knowledge nor the time. The devs could always hide the implementation behind an opt-in flag, so that doesn't seem very reasonable to say they're afraid of regressions ._.
|
|
|
jonnyawsom3
|
2025-03-28 09:25:17
|
If transfer stability is an issue, this may be of interest too https://github.com/libjxl/libjxl/pull/4062
|
|
2025-03-28 09:28:09
|
Another idea... How much of the 16bit range is actually used? Maybe you could bitshift the image to raise the levels, similar to the [prior example](<https://github.com/libjxl/libjxl/issues/314#issuecomment-880620569>) where a PNG was incorrectly padded
|
|
|
Lilli
|
2025-03-28 09:49:57
|
The entire range except for the first ~200 values (dark offset of the sensor)
|
|
2025-03-28 09:50:55
|
Interesting, this streaming option. I think it's gonna be just a file transfert though, and not stream-decoded, but having the option is great for a later iteration
|
|
|
Lilli
The entire range except for the first ~200 values (dark offset of the sensor)
|
|
2025-03-28 09:51:36
|
It's just the middle part of the image is quite empty as nebulas are faint but stars are bright :/
|
|
2025-03-28 09:51:52
|
(middle as in "histogram space", i.e. the middle values)
|
|
2025-03-28 10:56:20
|
By the way, is there a standardized way to compress an image tile by tile? I couldn't really find information about that, except adding several frames.
|
|
|
_wb_
|
2025-03-28 12:01:42
|
There's a chunked encode api
|
|
|
Lilli
|
2025-03-28 12:37:37
|
I assume it is:`JxlChunkedFrameInputSource`
I thought it was for streaming but maybe that's the same thing. Is this transparent for the decoder?
|
|
|
Demiurge
|
2025-03-28 02:24:51
|
You still get just a normal jxl file in the end
|
|
|
Melirius
|
2025-03-29 08:58:37
|
Interesting, this new balancing histogram approach improves compression of large JPEG files up to 5 %. And it restores normal size sequence from effort 7 to 9: files become smaller, instead of paradoxical growth before between 7 and 8.
|
|
2025-03-29 09:01:34
|
I think it is the result of getting closer to theoretically best histogram on nearly flat histos..
|
|
|
_wb_
|
2025-03-29 09:03:33
|
Nice!
|
|
2025-03-29 09:04:51
|
5% is a huge amount, are you sure?
|
|
|
Melirius
|
2025-03-29 09:05:09
|
Yep, I was surprised as well
|
|
2025-03-29 09:05:36
|
|
|
2025-03-29 09:05:49
|
Default effort
|
|
2025-03-29 09:06:42
|
Left is before - right after
|
|
2025-03-29 09:06:55
|
Note 70MPix result
|
|
2025-03-29 09:10:27
|
There is a jump from slight improvement of 2-3*10^-3 % to percents between 52 and 70 MPix size
|
|
|
jonnyawsom3
|
2025-03-29 09:11:07
|
Now if only I had enough RAM for 70MP Transcoding xD
|
|
|
Melirius
|
2025-03-29 09:13:43
|
The problem to get the best histo is interesting, but I suspect is NP-complete
|
|
|
lonjil
|
|
CrushedAsian255
|
|
Melirius
The problem to get the best histo is interesting, but I suspect is NP-complete
|
|
2025-03-29 09:15:55
|
What is the “best” histogram even mean
|
|
|
Melirius
|
|
CrushedAsian255
What is the “best” histogram even mean
|
|
2025-03-29 09:19:09
|
For the most compact encoding we need to prescribe frequencies of tokens is exact correspondence with their real frequency, but it is not possible with finite accuracy (1/4096 currently). So we need to choose a histogram "quite close" to the theoretically best with given accuracy of each bin. This is achieved by maximizing entropy of the histogram
|
|
|
CrushedAsian255
|
|
Melirius
For the most compact encoding we need to prescribe frequencies of tokens is exact correspondence with their real frequency, but it is not possible with finite accuracy (1/4096 currently). So we need to choose a histogram "quite close" to the theoretically best with given accuracy of each bin. This is achieved by maximizing entropy of the histogram
|
|
2025-03-29 09:20:09
|
So basically optimising for the quantisation of the histogram?
|
|
|
Melirius
|
|
CrushedAsian255
So basically optimising for the quantisation of the histogram?
|
|
2025-03-29 09:20:57
|
Yes, taking into account balancing histogram technique from the standard
|
|
|
jonnyawsom3
|
2025-03-29 09:21:07
|
Is there any speed or memory penalty to this?
|
|
|
Melirius
|
|
Is there any speed or memory penalty to this?
|
|
2025-03-29 09:21:48
|
Very small, usually only several improvement steps are taken
|
|
|
jonnyawsom3
|
2025-03-29 09:22:18
|
Nice, worth checking
|
|
|
CrushedAsian255
|
2025-03-29 09:22:26
|
Why can’t the histogram just increased the accuracy
|
|
|
Tirr
|
2025-03-29 09:23:34
|
12-bit precision is from the spec
|
|
|
Melirius
|
|
CrushedAsian255
Why can’t the histogram just increased the accuracy
|
|
2025-03-29 09:23:38
|
It is possible by the standard (up to 16 bit, IFAICR) - but then you loose space on encoding the histograms themselves
|
|
|
Tirr
|
2025-03-29 09:24:08
|
ah 12-bit is for ANS, I think it's something like 15-bit for prefix code?
|
|
2025-03-29 09:24:19
|
not very sure though
|
|
|
_wb_
|
2025-03-29 09:24:28
|
I will have to revisit https://github.com/libjxl/libjxl/pull/4130 after the better histogram balancing
|
|
|
CrushedAsian255
|
2025-03-29 09:24:31
|
Ah so the histogram also is signalled. Is it one histogram column for each hybrid uint configuration?
|
|
|
Tirr
|
2025-03-29 09:25:09
|
distributions are clustered, then there's one histogram and hybrid uint config for each cluster
|
|
2025-03-29 09:26:02
|
where there are at most 256 clusters
|
|
|
CrushedAsian255
|
2025-03-29 09:26:33
|
I mean for inside the histogram the histogram is predicting of the each type of uint?
|
|
|
_wb_
|
2025-03-29 09:27:11
|
ANS histogram precision is 12-bit. Histogram signaling itself is a bit complicated.
|
|
|
Melirius
|
2025-03-29 09:27:48
|
What is puzzling me - that threshold of improvement, I suspect 64MiPix, but had not investigated yet
|
|
|
CrushedAsian255
|
2025-03-29 09:28:06
|
As in like does the histogram store the probables of each hybrid uint type?
|
|
|
Melirius
|
|
CrushedAsian255
As in like does the histogram store the probables of each hybrid uint type?
|
|
2025-03-29 09:29:06
|
No, first best uint and histo accuracy is chosen, and then stored
|
|
|
CrushedAsian255
|
2025-03-29 09:29:19
|
what?
|
|
2025-03-29 09:29:43
|
isn’t the uint a type of value in the clustering of the accurate histogram, and then it quantises the bit depth?
|
|
2025-03-29 09:29:53
|
Then clustering?
|
|
|
Melirius
|
|
CrushedAsian255
what?
|
|
2025-03-29 09:30:08
|
Depending on effort, different uints and accuracies are probed
|
|
|
CrushedAsian255
|
2025-03-29 09:30:42
|
Like each cluster of 256 clusters gets its own histogram
|
|
2025-03-29 09:31:17
|
I don’t mean the encoding I am thinking of how this theory work of the how the theoretically stored and how the abstract data types
|
|
2025-03-29 09:31:28
|
Like I am trying to understand the fundamental theorem here
|
|
2025-03-29 09:31:45
|
Does the histogram store the probabilities of each hybrid uint?
|
|
2025-03-29 09:32:08
|
Like hybrid uint config 1 is 53/4096 and config 2 is 124/4096
|
|
|
Melirius
|
|
CrushedAsian255
Like I am trying to understand the fundamental theorem here
|
|
2025-03-29 09:33:56
|
As far as I got it, each hybrid uint provides different separation between literal bits and remainder bits of each value to be encoded. Then literals should be compressed the best possible way - that is where histogram of literals distribution comes into play
|
|
2025-03-29 09:34:37
|
Each uint produces different histogram and different number of remainder bits
|
|
|
jonnyawsom3
|
2025-03-29 09:35:01
|
On the topic of histograms, is there a reason LZ77 gets disabled in certain cases? I'm trying to debug why cjxl is outputting completely uncompressed files with certain parameters, and keep finding switches that set LZ77 to kNone
I'd have expected that worst case it's a en/decode speed hit
|
|
|
_wb_
|
2025-03-29 09:42:01
|
The hybriduint config is per (clustered) context. The config defines how a symbol is split into a token and raw bits. E.g. in a typical config, symbol values 0..15 get their own tokens (with no raw bits) while for higher symbol values, the token represents only the exponent and some of the most significant bits, while the least significant bits are raw bits.
This allows not needing a huge number of tokens even if the range of the symbols is large, while still getting most of the benefit of entropy coding — the raw bits are not entropy coded but since they are least significant bits that are usually pretty noisy, entropy coding wouldn't help anyway.
The histograms represent the probability of each token value.
|
|
2025-03-29 09:46:36
|
LZ77 is pretty much orthogonal to all of this: if enabled, a range of tokens is added to represent lz77 (distance,length) copy instructions. The main reason why libjxl doesn't use it much is because it generally doesn't help much for the type of data we are encoding (DCT coefficients, or in case of lossless, prediction residuals with variable predictors), while it is expensive on the encoder side to do the search.
|
|
|
jonnyawsom3
|
|
On the topic of histograms, is there a reason LZ77 gets disabled in certain cases? I'm trying to debug why cjxl is outputting completely uncompressed files with certain parameters, and keep finding switches that set LZ77 to kNone
I'd have expected that worst case it's a en/decode speed hit
|
|
2025-03-29 09:52:41
|
The reason I ask is lossless faster_decoding 3 and 4 are meant to use LZ77 instead of an MA tree, but 3 and 4 disable LZ77...
|
|
2025-03-29 09:55:00
|
Not to mention the switches seem flipped in cjxl but I'll dig into that later. I'm slowly working on a PR to fix both faster_decoding and progressive lossless.
Thanks for the insight around it, I suppose using a fixed predictor makes it slightly more worthwhile
|
|
|
CrushedAsian255
|
|
_wb_
The hybriduint config is per (clustered) context. The config defines how a symbol is split into a token and raw bits. E.g. in a typical config, symbol values 0..15 get their own tokens (with no raw bits) while for higher symbol values, the token represents only the exponent and some of the most significant bits, while the least significant bits are raw bits.
This allows not needing a huge number of tokens even if the range of the symbols is large, while still getting most of the benefit of entropy coding — the raw bits are not entropy coded but since they are least significant bits that are usually pretty noisy, entropy coding wouldn't help anyway.
The histograms represent the probability of each token value.
|
|
2025-03-29 10:10:57
|
Oh I get it, I thought a hybrid uint config was a singular set of (exponent,implied bits), what you are called a token. So now it makes sense the histogram is storing the probability of each token?
|
|
2025-03-29 10:11:15
|
And the hybrid config is stored along side
|
|
|
_wb_
|
2025-03-29 10:11:52
|
yes, every context has a hybriduint config plus a histogram for the tokens
|
|
|
CrushedAsian255
|
2025-03-29 10:13:16
|
So the first 2^split tokens are literals and then from there the tokens store (exponent-split, msb’s / lsb’s) ?
|
|
|
_wb_
|
|
CrushedAsian255
|
2025-03-29 10:14:42
|
ah that makes so much sense now! tanks
|
|
|
Traneptora
|
|
The reason I ask is lossless faster_decoding 3 and 4 are meant to use LZ77 instead of an MA tree, but 3 and 4 disable LZ77...
|
|
2025-03-29 06:44:58
|
RLE is still just lz77, it just changes the search algorithm to essentially only look back one symbol
|
|
2025-03-29 06:45:30
|
it keeps reading until it sees a different symbol and then it dumps a L/D pair
|
|
|
CrushedAsian255
So the first 2^split tokens are literals and then from there the tokens store (exponent-split, msb’s / lsb’s) ?
|
|
2025-03-29 06:46:47
|
yup, smaller tokens are literals, otherwise what it does it the token splits into a higher order half and a lower order half
|
|
2025-03-29 06:46:50
|
with RAW bits in the middle
|
|
2025-03-29 06:47:15
|
how many of those most-significant-bits and least-significant-bits are in the token itself and not residue is determined by the hybrid-uint-config
|
|
2025-03-29 06:49:18
|
for example, 4-0-0 means 0-15 are literals, and 16+ are hybrids. 16+ have 16 subtracted
|
|
2025-03-29 06:49:55
|
`lsb_in_token = 0` means that 0 bits of the lower-order of the final result, are actually part of the token
|
|
2025-03-29 06:50:23
|
`msb_in_token = 0` means that 0 bits of the higher-order of the final result are actually part of the token
|
|
2025-03-29 06:50:30
|
both 0 means the entire symbol is residue
|
|
2025-03-29 06:51:42
|
in this case, the value encoded by the token tells us how many bits of residue to read
|
|
2025-03-29 06:52:27
|
or rather, that value - 16
|
|
2025-03-29 06:52:28
|
but yea
|
|
2025-03-29 06:52:42
|
so for a 4-0-0 config there's a fasttrack
|
|
2025-03-29 06:52:53
|
`token < 16 ? token : readBits(token - 16)`
|
|
|
jonnyawsom3
|
|
Traneptora
RLE is still just lz77, it just changes the search algorithm to essentially only look back one symbol
|
|
2025-03-29 06:53:00
|
Yeah, but look at the last line of the second image. If speed tier is >=3, and modular mode is used, it's set to kNone instead of kRLE or kLZ77
|
|
|
Traneptora
|
2025-03-29 06:53:37
|
I think that may be intentional since RLE helps very little when you have modular predictions
|
|
2025-03-29 06:54:03
|
unless the MA tree is perfect, it makes more sense to disable lz77 than to try to go for rle
|
|
2025-03-29 06:54:07
|
overhead not worth it
|
|
|
jonnyawsom3
|
2025-03-29 06:56:09
|
In the first image, speed tier >=3 disables MA trees and predictors too
|
|
2025-03-29 06:57:04
|
So it causes a completely uncompressed JXL even larger than the image in memory
|
|
|
Traneptora
|
2025-03-29 07:00:32
|
it also disdables MA trees and predictors?
|
|
2025-03-29 07:00:42
|
well disable MA tree I assume means use a dummy one
|
|
2025-03-29 07:00:44
|
you can't disble both at once
|
|
2025-03-29 07:01:16
|
I wonder if we just hardcode gradiant predictor and call it a day if that's easier
|
|
2025-03-29 07:01:33
|
or at least, west only
|
|
|
username
|
2025-03-29 07:01:42
|
isn't there a "none" predictor?
|
|
|
Traneptora
|
2025-03-29 07:01:47
|
zero, but yea
|
|
2025-03-29 07:01:54
|
I figure disabling it means always predicting zero
|
|
2025-03-29 07:02:03
|
which would allow you to just encode the actual value as a residue
|
|
2025-03-29 07:02:21
|
that said I don't see much harm in using west-only for higher modes
|
|
2025-03-29 07:02:29
|
doesn't require fast memory access
|
|
2025-03-29 07:02:40
|
simdable across lines
|
|
2025-03-29 07:02:40
|
etc.
|
|
|
jonnyawsom3
|
2025-03-29 10:43:16
|
Any of the first 5 predictors are fast, since they're standalone while the others are combinations of directions, using 6 directions for AvgAll. Fixed MA trees are also fast. Effort 2 decode is almost as fast as faster decoding 4 already. Lots of room for improvement, so gonna run some tests and see what works. At the very least, remove that if statement so it stops outputting uncompressed files
|
|
|
CrushedAsian255
|
|
So it causes a completely uncompressed JXL even larger than the image in memory
|
|
2025-03-29 10:47:53
|
Does it also disable entropy encoding?
|
|
|
jonnyawsom3
|
|
CrushedAsian255
Does it also disable entropy encoding?
|
|
2025-03-29 10:55:44
|
Seems like it
|
|
|
Melirius
|
|
_wb_
I will have to revisit https://github.com/libjxl/libjxl/pull/4130 after the better histogram balancing
|
|
2025-03-30 09:51:26
|
Heh, that size improvement is not my histogram - it is your extending counters in `ComputeCoeffOrder`
|
|
|
_wb_
|
2025-03-30 09:55:43
|
Oh, right, I suppose those counters would overflow for large jpegs
|
|
|
Melirius
|
|
_wb_
Oh, right, I suppose those counters would overflow for large jpegs
|
|
2025-03-30 10:13:25
|
Yeah, I applied only extension (even without new buckets structure) and it gives this size drop
|
|
|
_wb_
Oh, right, I suppose those counters would overflow for large jpegs
|
|
2025-03-30 10:17:51
|
BTW, do you think it will worth it to apply more sophisticated algo to find best coefficient order? Now it is simple zero counts histogram, and it can be prone to coefficients correlations
|
|
|
_wb_
|
2025-03-30 10:24:47
|
Maybe?
|
|
|
Melirius
|
2025-03-30 10:27:16
|
That is a variant of patching consecutive ones property problem, that is unfortunately again NP-complete, but some heuristics can be applied
|
|
|
Demiurge
|
2025-03-31 01:23:24
|
|
|
2025-03-31 01:23:27
|
webp definitely retains a lot more detail here. I know libjxl is not meant to be optimized for this low quality setting, but maybe it's indicative of a more underlying problem with the encoder's visual decisions?
|
|
|
jonnyawsom3
|
2025-03-31 07:53:56
|
I've got some theorys on it, for now my resampling PR seems to compensate for it, but v0.8 also improves with the resampling for much higher quality results. So something can be changed
|
|
|
Demiurge
|
2025-03-31 08:22:51
|
I think there are more fundamental problems with the encoder that affect both the low-quality and high-quality range.
|
|
2025-03-31 08:28:30
|
Only a few very specific issues are specific to a certain quality range. Most changes have a similar effect on all quality levels.
|
|
2025-03-31 08:44:39
|
There are lots of possible techniques and optimizations that are much more useful at low bitrates and completely useless at higher bitrates, but libjxl does not do anything like that since it's optimized for high bitrates, so that's not relevant here. Even without any optimizations for low bitrates, libjxl is performing a lot worse than it should there.
|
|
2025-03-31 08:46:34
|
The most important issue is in the amount of psychovisual info preserved in the DCT transform itself
|
|
2025-03-31 08:46:49
|
Always will be, always has been
|
|
|
Lilli
|
2025-03-31 03:21:33
|
I could not make the chunked API work. Is there an example somewhere, where it is used? I could not find one after looking for quite a while. :/
I set up `JxlChunkedFrameInputSource` with callbacks, which I then feed to
`JxlEncoderAddChunkedFrame(frame_settings, true, chunked)`
This essentially replaces the call to `JxlEncoderAddImageFrame(frame_settings, &pixel_format, image_data, image_data_size)`
|
|
2025-03-31 03:22:14
|
for reference here are my callbacks:
```c++
struct ChunkingState {
const uint8_t* image;
uint32_t width;
uint32_t offset; // Current offset in the image data
uint32_t channels;
};
void get_color_channels_pixel_format(void* opaque, JxlPixelFormat* pixel_format) {
const auto* state = static_cast<ChunkingState*>(opaque);
pixel_format->num_channels = state->channels;
pixel_format->data_type = JXL_TYPE_UINT16;
pixel_format->endianness = JXL_NATIVE_ENDIAN;
pixel_format->align = 0;
}
const void* get_color_channel_data_at(void* opaque, size_t xpos, size_t ypos, size_t xsize, size_t ysize, size_t* row_offset) {
const auto* state = static_cast<ChunkingState*>(opaque);
const uint8_t* image = state->image;
// Calculate the starting position in the image data
size_t start = ypos * state->width * state->channels + xpos * state->channels;
*row_offset = state->width * state->channels;
// Return a pointer to the requested data
return image + start;
}
void release_buffer(void* opaque, const void* buf) {
}
```
|
|
|
jonnyawsom3
|
|
Traneptora
I think that may be intentional since RLE helps very little when you have modular predictions
|
|
2025-03-31 06:10:17
|
Well, with <@207980494892040194>'s help, enabling LZ77 fixes both faster decoding and progressive lossless (Somewhat)
|
|
2025-03-31 06:11:27
|
Need to do some more tweaking, but promising for just commenting out 3 lines
|
|
2025-03-31 06:23:21
|
Worst case, it is faster *de*coding, so slower encode should be a decent trade-off. We'll see what we can figure out though
|
|
2025-03-31 06:29:04
|
I did want to check, <@794205442175402004> I noticed libjxl has a function called `MakeFixedTree`. I always thought the fixed tree was an effort 1 and 2 specific thing, with the decoder using a lookup table to skip most of the MA traversal. Are fixed trees a more universal concept, signalled globally and traversed once then re-used or something similar? Wondering if using the fixed tree for faster decoding is a good idea, or if it doesn't apply to other decoders and could be broken (Much slower) if the tree is changed in future inside libjxl
|
|
2025-03-31 06:29:32
|
Hopefully that makes sense
|
|
|
_wb_
|
2025-03-31 07:00:07
|
Effort 1 uses no tree at all (fixed tree with single node, I guess), MakeFixedTree is used for effort 2 and 3. But it is also used for some of the modular-coded stuff in VarDCT, including LF, iirc.
|
|
|
Tirr
|
2025-03-31 07:13:49
|
some MA trees have structure that can be fused into single lookup table to speed up tree traversal (which jxl-oxide also does), I think that's what MakeFixedTree is for
|
|
|
_wb_
|
2025-03-31 07:16:09
|
These fixed trees do have that property, since they're using a single split property
|
|
2025-03-31 07:18:25
|
But the tree traversal speedup also works for non-fixed trees iirc, if it locally has a subtree that uses a single decision property
|
|
|
jonnyawsom3
|
2025-03-31 07:19:14
|
Okay, so it is a specialised speedup rather than a general rule, good to know
|
|
2025-03-31 07:22:27
|
We'll probably have to test the faster decoding parameters on djxl, Oxide and Latte to make sure it's not an isolated improvement. Don't want to inadvertently create files that are *only* faster in libjxl
|
|
|
Tirr
|
2025-03-31 07:26:09
|
"textbook" MA tree traversal can be very very slow since it's super branchy and (maybe) cache unfriendly. I'd expect decoders that are advanced enough to implement at least some of the optimization techniques like lookup table thing
|
|
|
_wb_
|
2025-03-31 07:33:05
|
I think it's indeed reasonable to assume that decoders will implement fast paths. There is still room to do more btw. I am dreaming of some kind of JIT compilation of MA trees. It's just that those are dreams that are nightmares for people worrying about security surface, understandably.
|
|
2025-03-31 07:35:05
|
(I think it can be done without serious security issues, termination can be trivially assured so it is very different from JIT compilation of some Turing complete language, but I can still understand some nervousness)
|
|
|
Demiurge
|
2025-04-01 05:10:45
|
An image codec with self modifying code...
|
|
2025-04-01 05:16:34
|
I think it's inherently unsafe for executable memory to be modified based on untrusted input. Web browsers get away with it by using a separate process with the OS kernel enforcing restrictions on what that process is allowed to access.
|
|
2025-04-01 05:18:42
|
There's no cross platform way to do that
|
|
2025-04-01 05:19:12
|
Which is a shame because it really should be the norm
|
|
2025-04-01 05:28:38
|
Plan9 has process namespaces where each process has a restricted view of the system. And instead of linking binary code into a single process, multiple processes can communicate using the same read and write commands as everything else, if you want shared libraries that are isolated in their own restricted process. But other operating systems do not make it easy to write secure code. Therefore software is always going to be insecure by design until it's no longer difficult to write secure code. Nobody except web browsers want to write platform specific code for each platform they want to support having a sandboxed JIT
|
|
|
_wb_
|
2025-04-01 05:43:40
|
The 'programming language' would be just MA trees, so no loops, no writes, no reads besides to well defined previously decoded pixels, etc. Something very different from something like JavaScript.
|
|
|
Tirr
|
|
Demiurge
|
2025-04-01 05:59:53
|
But it's pretty inherently risky to give untrusted input the ability to modify executable memory. Also, to be honest I'm not sure how a JIT compiler can be made to run on a system with W^X enforcement
|
|
2025-04-01 06:00:14
|
That's a gap in my knowledge
|
|
|
_wb_
The 'programming language' would be just MA trees, so no loops, no writes, no reads besides to well defined previously decoded pixels, etc. Something very different from something like JavaScript.
|
|
2025-04-01 06:05:41
|
With a little cleverness you can probably make a very basic JIT with guaranteed safety, but the main security risk is the lack of separation of process and privilege namespaces inherent to modern programming.
|
|
2025-04-01 06:09:08
|
None of this would be an issue if it was the norm for libraries to run in separate processes with minimum privileges instead of linking code into one process and running all processes with the same privileges as the "user"
|
|
2025-04-01 06:09:24
|
It's a flaw in modern OS design
|
|
2025-04-01 06:12:51
|
It's possible to make a library that handles untrusted input by creating a separate process that revokes its own privileges, but it's a real PITA
|
|
2025-04-01 06:17:24
|
It's a shame. I wish security was easy and convenient instead of an afterthought today.
|
|
|
intelfx
|
|
Tirr
|
|
2025-04-01 02:49:10
|
Yup, this! Did someone say WASM? :D
|
|
2025-04-01 02:49:24
|
Sounds like a no-brainer for any kind of untrusted code thing
|
|
2025-04-01 02:50:27
|
Also, prior art: harfbuzz supports a font hinting/shaping bytecode which _is_ WASM
|
|
2025-04-01 02:50:50
|
If you want a laugh: https://fuglede.github.io/llama.ttf/
|
|
|
Demiurge
|
2025-04-01 03:53:27
|
WASM is way slower and way more complicated than having libraries running in a separate process and opening/reading/writing to file descriptors instead of linking binary code into a single process, and having the OS and kernel isolate processes into their own namespace with limited access to the system.
|
|
2025-04-01 03:55:15
|
Basically if the OS was better designed and provided easy to use APIs for writing multiprocess code that revokes privileges and communicates with other processes through file descriptors, similar to Plan9
|
|
2025-04-01 03:56:01
|
But security is not a priority for OS devs
|
|
|
intelfx
|
2025-04-01 03:56:03
|
then everything would be slower due to context switches 🙃
|
|
|
Demiurge
|
2025-04-01 03:56:34
|
Not as slow as WASM, no.
|
|
2025-04-01 03:57:13
|
Linux already has namespaces and multiple processes running as different users and in different namespaces and containers and it isn't slow at all. It's fast as native.
|
|
2025-04-01 03:57:43
|
There's nothing slow about this at all. Linux already technically has all of these abilities but they are not made convenient and easy to use.
|
|
|
intelfx
|
|
Demiurge
Not as slow as WASM, no.
|
|
2025-04-01 03:58:47
|
Sure about that?
|
|
|
Demiurge
|
2025-04-01 03:58:50
|
And developers also have this mindset that linking code into a single process is taken for granted as the "normal" assumption of how to do things without questioning if it makes sense or if it's actually good or bad design
|
|
|
intelfx
|
2025-04-01 03:59:20
|
Besides, what you are asking for already exists and is called seccomp mode 1
|
|
2025-04-01 03:59:35
|
Plan 9 isn't the be-all and end-all of OS design
|
|
|
Demiurge
|
|
intelfx
Sure about that?
|
|
2025-04-01 03:59:43
|
Try creating a separate namespace with systemd-nspawn and run some benchmarks inside the container, and see if it's any slower. It shouldn't be.
|
|
|
intelfx
|
|
Demiurge
Try creating a separate namespace with systemd-nspawn and run some benchmarks inside the container, and see if it's any slower. It shouldn't be.
|
|
2025-04-01 04:00:25
|
You were talking about passing data between processes via file descriptors, not about benchmarks in a namespace.
|
|
|
Demiurge
|
|
intelfx
Plan 9 isn't the be-all and end-all of OS design
|
|
2025-04-01 04:00:37
|
Of course not, but it's a shame that no one learned anything from the mistakes of the past.
|
|
|
intelfx
|
2025-04-01 04:00:53
|
Linux namespaces have pretty much no relation to secure computing-only processes
|
|
|
Demiurge
|
|
intelfx
You were talking about passing data between processes via file descriptors, not about benchmarks in a namespace.
|
|
2025-04-01 04:01:27
|
Well then the main slowness there would probably be serialization and copying of data, since it would be going from 1 process into 2.
|
|
|
intelfx
|
2025-04-01 04:01:40
|
Correct. That's what I'm talking about.
|
|
|
Demiurge
|
2025-04-01 04:01:50
|
But that is a necessary payment for the security of process separation
|
|
2025-04-01 04:01:59
|
Well worth the cost
|
|
|
intelfx
|
2025-04-01 04:02:07
|
Which can also be achieved without process separation by WASM.
|
|
|
Demiurge
|
2025-04-01 04:02:22
|
Suddenly, you don't have to worry about malicious input anymore. That's a ridiculously massive win
|
|
2025-04-01 04:02:56
|
WASM is an even bigger compromise, and it's way more architecturally complicated.
|
|
|
intelfx
|
2025-04-01 04:03:24
|
"Architecturally complicated" is subjective, and could you share data on why exactly it is a bigger compromise?
|
|
|
Demiurge
|
2025-04-01 04:03:26
|
It's a JIT compiler
|
|
|
intelfx
|
2025-04-01 04:03:31
|
Yes, and?
|
|
2025-04-01 04:03:53
|
It is also architecture-independent.
|
|
|
Demiurge
|
2025-04-01 04:03:55
|
It has the same overhead and complexity as trying to mix Java and C together
|
|
|
intelfx
|
|
Demiurge
It has the same overhead and complexity as trying to mix Java and C together
|
|
2025-04-01 04:04:01
|
That's just not true.
|
|
|
Demiurge
|
2025-04-01 04:04:58
|
with multiple processes it's all plain old boring ass code
|
|
2025-04-01 04:05:01
|
native code
|
|
2025-04-01 04:05:47
|
with wasm you would have multiple processes anyways. Unless everything is all compiled to WASM together
|
|
2025-04-01 04:06:02
|
You don't gain or save anything
|
|
|
intelfx
|
2025-04-01 04:06:04
|
Who said that? That's just blatantly wrong.
|
|
|
Demiurge
|
2025-04-01 04:06:18
|
maybe I'm misunderstanding something?
|
|