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

mozjpeg experiments #1422

Closed
jcupitt opened this issue Sep 10, 2019 · 19 comments
Closed

mozjpeg experiments #1422

jcupitt opened this issue Sep 10, 2019 · 19 comments

Comments

@jcupitt
Copy link
Member

jcupitt commented Sep 10, 2019

In this twitter thread:

https://twitter.com/adityapatadia/status/1171376632419901440

Aditya Patadia wonders about mozjpeg speed and compression. I thought I'd open an issue to discuss this.

I made a dockerfile to show how to use libvips with mozjpeg:

https://github.com/jcupitt/docker-builds/tree/master/libvips-mozjpeg-ubuntu18.10

Running that test script, I see:

$ ./test.sh 
imagemagick, system libjpeg ...
-rw-r--r-- 1 john john 516331 Sep 10 14:41 pic-imagick.jpg
libvips with mozjpeg --Q=85 ... 0.88
-rw-r--r-- 1 root root 518535 Sep 10 14:41 'pic-mozjpeg-Q=85.jpg'
libvips with mozjpeg --optimize-scans ... 1.09
-rw-r--r-- 1 root root 515515 Sep 10 14:41 pic-mozjpeg-optimize-scans.jpg
libvips with mozjpeg --trellis-quant ... 1.08
-rw-r--r-- 1 root root 473371 Sep 10 14:41 pic-mozjpeg-trellis-quant.jpg
libvips with mozjpeg --overshoot-deringing ... 0.82
-rw-r--r-- 1 root root 518954 Sep 10 14:41 pic-mozjpeg-overshoot-deringing.jpg
  1. With no options, mozjpeg gives similar results to the system libjpeg
    (libjpeg-turbo in this case): 516331 and 518535 bytes.
  2. optimize-scans adds about 20% to runtime and saves 3kb.
  3. trellis-quant also adds about 20% to runtime and saves 46kb (10%).
  4. overshoot-deringing is free and does not affect filesize.
@adityapatadia
Copy link

Thanks @jcupitt for putting all tests together.

I am using this Dockerfile. Do you think that system jpeg might be used by libvips in any way?

https://gist.github.com/adityapatadia/ee2312f92dd60aee741e2f9e71965b94

@jcupitt
Copy link
Member Author

jcupitt commented Sep 10, 2019

I don't think so, but I'm just trying it now, hang on.

@adityapatadia
Copy link

My question is that when I use mozjpeg through NodeJS Sharp library which uses libvips, the encoding is much faster but when I use mozjpeg through https://github.com/danielgtaylor/jpeg-archive the speed is less.

Is there a possibility that these lines in mozjpeg are disabled when JCP_FASTEST flag is set by vips here?

@jcupitt
Copy link
Member Author

jcupitt commented Sep 10, 2019

I made a dockerfile based on yours that runs those tests and I see the same results:

https://github.com/jcupitt/docker-builds/tree/master/libvips-mozjpeg-buster

$ ./test.sh 
imagemagick, system libjpeg ...
-rw-r--r-- 1 john john 516331 Sep 10 15:16 pic-imagick.jpg
libvips with mozjpeg --Q=85 ... 0.90
-rw-r--r-- 1 root root 518535 Sep 10 15:16 'pic-mozjpeg-Q=85.jpg'
libvips with mozjpeg --optimize-scans ... 1.05
-rw-r--r-- 1 root root 515515 Sep 10 15:16 pic-mozjpeg-optimize-scans.jpg
libvips with mozjpeg --trellis-quant ... 1.07
-rw-r--r-- 1 root root 473371 Sep 10 15:16 pic-mozjpeg-trellis-quant.jpg
libvips with mozjpeg --overshoot-deringing ... 0.90
-rw-r--r-- 1 root root 518954 Sep 10 15:16 pic-mozjpeg-overshoot-deringing.jpg

So I think your dockerfile is working correctly.

@jcupitt
Copy link
Member Author

jcupitt commented Sep 10, 2019

(I made it use the latest mozjpeg and libvips, and I removed the libwebp build for clarity)

@jcupitt
Copy link
Member Author

jcupitt commented Sep 10, 2019

My understanding is that:

		jpeg_c_set_int_param( &write->cinfo, 
			JINT_COMPRESS_PROFILE, JCP_FASTEST );

Just sets the compression defaults. FASTEST here means use the libjpeg-turbo settings, ie. all mozjpeg extensions are off by default.

A few lines below, libvips enables trellis / quant / optim / etc. if those options have been set.

Perhaps libvips should have an option for max, ie. enable everything.

@jcupitt
Copy link
Member Author

jcupitt commented Sep 10, 2019

I tried swapping FASTEST for MAX and I see:

root@d3c9182bb179:/data# time vips copy pic.png x.jpg[Q=85,optimize-coding,strip,interlace]
real	0m0.552s
user	0m0.551s
sys	0m0.055s
root@d3c9182bb179:/data# ls -l x.jpg 
-rw-r--r-- 1 root root 431521 Sep 10 14:33 x.jpg

So up to about 20% saving now, nice!

With FASTEST, it's:

root@d3c9182bb179:/data# time vips copy pic.png x.jpg[Q=85,optimize-coding,strip,interlace]

real	0m0.182s
user	0m0.191s
sys	0m0.030s

So perhaps 3x slower encoding.

@adityapatadia
Copy link

I made a dockerfile based on yours that runs those tests and I see the same results:

https://github.com/jcupitt/docker-builds/tree/master/libvips-mozjpeg-buster

$ ./test.sh 
imagemagick, system libjpeg ...
-rw-r--r-- 1 john john 516331 Sep 10 15:16 pic-imagick.jpg
libvips with mozjpeg --Q=85 ... 0.90
-rw-r--r-- 1 root root 518535 Sep 10 15:16 'pic-mozjpeg-Q=85.jpg'
libvips with mozjpeg --optimize-scans ... 1.05
-rw-r--r-- 1 root root 515515 Sep 10 15:16 pic-mozjpeg-optimize-scans.jpg
libvips with mozjpeg --trellis-quant ... 1.07
-rw-r--r-- 1 root root 473371 Sep 10 15:16 pic-mozjpeg-trellis-quant.jpg
libvips with mozjpeg --overshoot-deringing ... 0.90
-rw-r--r-- 1 root root 518954 Sep 10 15:16 pic-mozjpeg-overshoot-deringing.jpg

So I think your dockerfile is working correctly.

Awesome!

@adityapatadia
Copy link

I tried swapping FASTEST for MAX and I see:

root@d3c9182bb179:/data# time vips copy pic.png x.jpg[Q=85,optimize-coding,strip,interlace]
real	0m0.552s
user	0m0.551s
sys	0m0.055s
root@d3c9182bb179:/data# ls -l x.jpg 
-rw-r--r-- 1 root root 431521 Sep 10 14:33 x.jpg

So up to about 20% saving now, nice!

With FASTEST, it's:

root@d3c9182bb179:/data# time vips copy pic.png x.jpg[Q=85,optimize-coding,strip,interlace]

real	0m0.182s
user	0m0.191s
sys	0m0.030s

So perhaps 3x slower encoding.

Exactly my thoughts. Just setting those options is not same as setting MAX. We are not utilising full potential of mozjpeg I think.

@adityapatadia
Copy link

adityapatadia commented Sep 10, 2019

I have very limited knowledge of C so it would be hard for me to create a PR but let me know whatever way I can help you. Let me know your thoughts about how do you plan to get this resolved.

@jcupitt
Copy link
Member Author

jcupitt commented Sep 10, 2019

Hey @lovell, sorry to ping you, what do you think about adding a max option to jpegsave?

It would simply turn on all the mozjpeg options that improve compression ratio. It looks like it might get us another 10% or so, though at a pretty high CPU cost.

@jcupitt
Copy link
Member Author

jcupitt commented Sep 10, 2019

Oh, don't worry about a PR, it's only ~10 lines of code.

jcupitt added a commit that referenced this issue Sep 10, 2019
turns all mozjpeg compression options on, if possible

see #1422
@jcupitt
Copy link
Member Author

jcupitt commented Sep 10, 2019

... I made a PR for testing.

@lovell
Copy link
Member

lovell commented Sep 10, 2019

Setting libvips' existing quant_table property to a value of 3 has the same effect as the mozjpeg defaults https://github.com/mozilla/mozjpeg/blob/cfb713852354b139ca25a8c382de4166a67d41a1/jcparam.c#L505-L506 and might account for (most of) the file size improvements seen with JCP_MAX_COMPRESSION.

@jcupitt
Copy link
Member Author

jcupitt commented Sep 10, 2019

Oh yes, I'd forgotten about quant_table. You're right, I see:

libvips with mozjpeg --quant_table=3 ... 0.92
-rw-r--r-- 1 root root 477569 Sep 10 18:06 'pic-mozjpeg-quant_table=3.jpg'
libvips with [optimize-scans,trellis-quant,quant_table=3] ... 1.24
-rw-r--r-- 1 root root 431216 Sep 10 18:06 pic-mozjpeg-max.jpg

So no need for max, just use:

optimize-coding,strip,interlace,optimize-scans,trellis-quant,quant_table=3

Thanks!

@jcupitt
Copy link
Member Author

jcupitt commented Sep 10, 2019

I tried MAX plus quant_table=3 and you also get 430kb, so MAX gives no advantage, for this test image at least.

@adityapatadia
Copy link

https://github.com/mozilla/mozjpeg/blob/cfb713852354b139ca25a8c382de4166a67d41a1/jcparam.c#L505-L506 and might account for (most of) the file size improvements seen with JCP_MAX_COMPRESSION.

Thanks @lovell for pointing out. I think then those DC and AC filters will have very small effect on final image size. @jcupitt does it affect quality in any way or quality also remains same?

If the quality remains same, we can close this issue after putting this in some documentation.

jcupitt added a commit that referenced this issue Sep 11, 2019
@jcupitt
Copy link
Member Author

jcupitt commented Sep 11, 2019

You'll get an image that looks slightly different, but it would be up to you to decide if it was better or worse. I'd do some experiments.

I'll add a note to the docs. Thank you everyone for this!

@jcupitt jcupitt closed this as completed Sep 11, 2019
@adityapatadia
Copy link

Thanks John for super quick benchmarks on this.

sandro added a commit to sandro/govips that referenced this issue Feb 10, 2021
jcupitt explains the mozjpeg parameters in this comment:
libvips/libvips#1422 (comment)

Additionally, look for references to mozjpeg in the documentation for
vips_jpegsave():
https://libvips.github.io/libvips/API/current/VipsForeignSave.html#VipsForeignJpegSubsample

These changes improved jpeg compression for my test image, especially
with the addition of overshoot_deringing when compresses a screenshot
that includes text.
sandro added a commit to sandro/govips that referenced this issue Feb 10, 2021
jcupitt explains the mozjpeg parameters in this comment:
libvips/libvips#1422 (comment)

Additionally, look for references to mozjpeg in the documentation for
vips_jpegsave():
https://libvips.github.io/libvips/API/current/VipsForeignSave.html#VipsForeignJpegSubsample

These changes improved jpeg compression for my test image, especially
with the addition of overshoot_deringing when compressing a screenshot
that includes text.
sandro added a commit to sandro/govips that referenced this issue Feb 22, 2021
jcupitt explains the mozjpeg parameters in this comment:
libvips/libvips#1422 (comment)

Additionally, look for references to mozjpeg in the documentation for
vips_jpegsave():
https://libvips.github.io/libvips/API/current/VipsForeignSave.html#VipsForeignJpegSubsample

These changes improved jpeg compression for my test image, especially
with the addition of overshoot_deringing when compressing a screenshot
that includes text.
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

3 participants