Enable JPEG-XL configurable lossy quality setting and fix modular mode encoding
This MR adds ability to configure JPEG-XL export lossy encoding quality/bitrate using libjxl JxlEncoderSetFrameDistance function.
However, using "Distance" as a parameter is slightly unintuitive, as an artist myself I'm more used to "Quality" parameter. So here I linearly mapped the value from (0..100) to (25..1) to represent a low quality/bitrate to high quality/bitrate setting(see below). The max distance of 25 is derived from libjxl's cjxl allowable maximum distance, while min distance 1 is the default for "visually lossless".
I also added the "Use modular mode" toggle on General tab as a quick access to enforce the JXL lossy encoding modular mode. Because from my testing, lossy modular mode results in a better quality in non-photographic content like illustration, text, and graphs than VarDCT mode. So user can quickly determine the encoding mode based on the content rather than fumbling around in Advanced tab (which has so many parameters to look into!).
I also attempted to fix the typo(?) in Modular encoding entry in advanced tab, where modular mode should be have a value of 1 instead of -1. Now the modular mode works as expected. I also added an enforce modular encoding toggle for lossy encoding.
Quality to Distance mapping rationale
Originally, I implemented a linear mapping of quality to libjxl's distance parameter. However, even though it performs pretty linearly on DSSIM score test, it doesn't represent how a typical JPEG quality parameter behaves. One implementation reference is on libjxl, where they implemented some kind of transfer curve: libjxl/cjxl_main.cc. The difference is that, libjxl implements lossless at quality 100. If implemented here, this becomes redundant in our case, where we already have a checkbox to toggle between lossy and lossless encoding. It is possible though to remove the lossless quality from libjxl's function, but then the map becomes [0.1..25.0]. Here I tried to implement using a inverse gamma of 2.2 instead to mimic the curve, so that the lower end of the quality didn't crunched too much.
Anyway, here's the comparison results using DSSIM for the metrics:
Opinions needed: So do I have to change to mimic libjxl's implementation (without lossless at 100), or should I stick with my own implementation of inverse gamma function?
PS: Do take note that when viewing JXL file with distance >= 20, at least libjxl 0.7.0 is required (referenced to this bug: https://github.com/libjxl/libjxl/issues/1732).
Pardon for my English, also it's my first time hacking krita and using GitLab.
Test Plan
Build Krita. Try to export JPEG-XL with different quality settings and with/without modular mode.
Formalities Checklist
-
I confirmed this builds. -
I confirmed Krita ran and the relevant functions work. -
I tested the relevant unit tests and can confirm they are not broken. (If not possible, don't hesitate to ask for help!) -
I made sure my commits build individually and have good descriptions as per KDE guidelines. -
I made sure my code conforms to the standards set in the HACKING file. -
I can confirm the code is licensed and attributed appropriately, and that unattributed code is mine, as per KDE Licensing Policy.