Isotr0py / pillow-jpegxl-plugin

Pillow plugin for JPEG-XL, using Rust for bindings.
GNU General Public License v3.0
18 stars 5 forks source link

quality parameter seems to have no effect #58

Closed skjerns closed 2 weeks ago

skjerns commented 2 weeks ago

I'm trying to find a good compression ratio for my images

import pillow_jxl
from PIL import Image

original_file='IMG_0058.jpg'
for quality in range(10, 100, 10):
    with Image.open(original_file) as img:
        # Save the image in JPEG XL format 
        img.save(original_file + f'{quality:03d}.jxl', format="JXL", quality=quality)

However, it seems all files are the same size. Is this a bug? Or is something in my code wrong?

- 491K IMG_0058.jpg010.jxl
- 491K IMG_0058.jpg020.jxl
- 491K IMG_0058.jpg030.jxl
- 491K IMG_0058.jpg040.jxl
- 491K IMG_0058.jpg050.jxl
- 491K IMG_0058.jpg060.jxl
- 491K IMG_0058.jpg070.jxl
- 491K IMG_0058.jpg080.jxl
- 491K IMG_0058.jpg090.jxl

I checked and it seems to be properly forwarded in the Encoder in this line, but has no effect inside the compiled .so. https://github.com/Isotr0py/pillow-jpegxl-plugin/blob/6a14e391d89be9135a4bc2da31b8b5a90f358e9b/pillow_jxl/JpegXLImagePlugin.py#L98-L106

pillow == 10.4.0
pillow-jxl-plugin==1.2.6
Isotr0py commented 2 weeks ago

This is because if you are encoding a jpeg image, we will use jpeg reconstruction to create a lossless jxl image instead of encoding the data directly, which is the default behavior of cjxl as well.

As a result, the quality flag won't work (or always set to 100 for lossless in other words).

BTW, if you passed -q when using cjxl to encode a jpeg image, it will raise:

$ cjxl -q 98 test/images/sample.jpg -
JPEG XL encoder v0.10.3 0.10.3 [AVX2,SSE4,SSE2]
Must not set quality below 100 in combination with --lossless_jpeg=1, which is set by default

So this is not a bug, but a intended behavior designed for the encoder.

skjerns commented 2 weeks ago

I think this is highly confusing and should result at least in a warning. Usually the user is not aware what backend is used or wrapped and how that backend behaves. If I set the quality parameter, I would expect that it does exactly what advertised