Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to achieve same quality as libjpeg? #13

Closed
romanzes opened this issue Oct 3, 2020 · 6 comments
Closed

How to achieve same quality as libjpeg? #13

romanzes opened this issue Oct 3, 2020 · 6 comments

Comments

@romanzes
Copy link

romanzes commented Oct 3, 2020

I'm working on a rendering utility that can save images as JPEGs with specified quality. For a weird reason, I need the images saved by my utility to look the same as the ones produced by libjpeg's cjpeg. As there is no convenient libjpeg bindings for Rust, I'm using mozjpeg-rust, but the output looks very different for the same quality. Is it possible to configure the compressor in mozjpeg-rust to make it look similar in terms of the amount of artefacts? This is an example of what the output images currently look like:

libjpeg

libjpeg_30

mozjpeg

mozjpeg_30

It's easy to notice that the mozjpeg one has much more artefacts than libjpeg.

The libjpeg image was produced by converting the image saved with 100 quality:

djpeg original.jpg | cjpeg -quality 30 > libjpeg_30.jpg

Original

original

And this is how I call mozjpeg-rust from my code:

    let mut compressor = Compress::new(ColorSpace::JCS_EXT_RGBA);
    compressor.set_quality(30.0);
    compressor.set_size(320, 240);
    compressor.set_mem_dest();
    compressor.start_compress();
    compressor.write_scanlines(&scanlines);
    compressor.finish_compress();

PS: if it's currently not possible in mozjpeg-rust, but possible in mozjpeg, that might help too.

@kornelski
Copy link
Member

kornelski commented Oct 3, 2020

The difference is due to chroma subsampling.

compressor.components_mut() has component.h_samp_factor and .v_samp_factor

Search v_samp_factor here for more info https://github.com/libjpeg-turbo/libjpeg-turbo/blob/master/libjpeg.txt

@romanzes
Copy link
Author

romanzes commented Oct 4, 2020

The difference is due to chroma subsampling.

compressor.components_mut() has component.h_samp_factor and .v_samp_factor

Search v_samp_factor here for more info https://github.com/libjpeg-turbo/libjpeg-turbo/blob/master/libjpeg.txt

Thanks for your reponse! Do I understand it right that I should disable subsampling in order to achieve the desired result? I modified my code in the following way:

    let mut compressor = Compress::new(ColorSpace::JCS_EXT_RGBA);
    compressor.set_quality(30.0);
    compressor.set_size(320, 240);
    let mut components = compressor.components_mut();
    for component in components {
        component.h_samp_factor = 1;
        component.v_samp_factor = 1;
    }
    compressor.set_mem_dest();
    compressor.start_compress();
    compressor.write_scanlines(&scanlines);
    compressor.finish_compress();

It led to a result that is closer to what I need, but still not quite the same:

converter_30

@kornelski
Copy link
Member

The rest is up to quality setting.

MozJPEG defaults to quantization table optimized for photographic content, and not icons with sharp edges.

@romanzes
Copy link
Author

romanzes commented Oct 6, 2020

The rest is up to quality setting.

MozJPEG defaults to quantization table optimized for photographic content, and not icons with sharp edges.

I tried specifying every possible value for -quant-table argument and no result was the same as libjpeg. This is the command I used:

djpeg original.jpg | cjpeg -quality 30 -quant-table <N> -sample 1x1 > libjpeg_30.jpg

However, then I noticed that -revert param does the trick:

djpeg original.jpg | cjpeg -revert -quality 30 > libjpeg_30.jpg

For those wondering how to do it in Rust code, you need to call Compress::set_fastest_defaults() method. It needs to be called before you set quality or other settings, otherwise it will overwrite them.

@romanzes romanzes closed this as completed Oct 6, 2020
@kornelski
Copy link
Member

kornelski commented Oct 6, 2020

Please note that -revert/fastest_defaults disables all compression improvements too. It completely turns off all MozJPEG features, as if didn't exist. You get plain libjpeg-turbo with an old encoder.

@romanzes
Copy link
Author

romanzes commented Oct 6, 2020

Please note that -revert/fastest_defaults disables all compression improvements too. It completely turns off all MozJPEG features, as if didn't exist. You get plain libjpeg-turbo with an old encoder.

Thanks for clarifying that. At the current stage of my project this is exactly what I need, but later I'll be able to turn MozJPEG features back on as I won't need to match images produced by libjpeg anymore.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants