Fix CMYK blending order: blend in CMYK space then convert to RGB#646
Fix CMYK blending order: blend in CMYK space then convert to RGB#646hjanuschka wants to merge 2 commits intolibjxl:mainfrom
Conversation
159f225 to
6170405
Compare
Benchmark @ 6bc7538Comparing: 90a2bb2a (Base) vs fbe56cd9 (PR)
|
|
For multi-layer images, not only in the case of CMYK, the frame blending has to be done in the image space, not in the final decoded image space. This also makes a difference in the RGB case, e.g. if the image space is linear Rec2020 (i.e. that's what the imageheader says), and we're decoding to sRGB, then frames have to be kept in or converted to linear Rec2020 for frame blending and only after blending the result should be converted to the final decode space. Are we doing this correctly? |
c13e3cb to
771540b
Compare
|
Tried generalizing this to all blending cases but it breaks conformance. So it seems libjxl blends after XybStage but before CMS for non-CMYK? |
Yes, blending should be done after converting XYB to RGB, in particular whatever RGB space the image is tagged to be in. For example if an image is tagged as sRGB, encoded with XYB, and we're decoding to Linear P3 (just for the sake of the example), then the correct flow should be this:
This is somewhat annoying because of the double conversions but we cannot define blending to be done in whatever decode space you like (since that would give different results) and we also cannot define it has to be done in the encoded space (XYB in this example) because then it would also look different between a lossy encoding and a lossless one that would use sRGB as the encoding space in this example. In particular existing GIF or APNG files cannot be losslessly represented (neither accurately in a lossy way) if we don't define blending to have to happen in the image space. Same with existing layered images like XCF or PSD files, which also have the convention that layer blending is done in image space. |
For multi-layer images, blending must happen in the image's native color space, not in the output/decode color space. This ensures blending results are independent of the requested output space, matching the behavior of formats like GIF, APNG, XCF, and PSD. The correct pipeline order for XYB images decoded to a different space: 1. XybStage: XYB -> linear image-space 2. FromLinearStage: apply image TF -> image-space 3. Blend in image space 4. Save reference frame in image space 5. CMS: image-space -> output-space Previously this was only done for CMYK; now generalized to all cases. When CMS is deferred, it receives non-linear image-space data, so CMS is initialized with the non-linear input profile instead of the linearized one.
771540b to
502d970
Compare
|
generalized the CMS deferral to all blending cases now, not just CMYK.The key insight for making it work was two-fold:So the pipeline order is now: |
Summary
Fix multi-layer CMYK image blending by deferring CMS conversion until after blending operations complete.
Problem: For CMYK images with alpha blending across multiple layers, blending in RGB space (after CMS conversion) produces incorrect results. The correct approach is to blend in CMYK space first, then convert to RGB.
Solution: Defer CMS conversion for CMYK images when:
save_before_ct=false)This ensures reference frames are saved in CMYK space so subsequent frames blend correctly before final CMS conversion.
Changes
jxl/src/frame/render.rs: Restructured CMS stage application to support deferred execution for CMYK blendingCredit
Based on the fix from @lilith in lilith/jxl-rs.