Replace in-tree JPEG encoder with jpeg-encoder crate#2636
Replace in-tree JPEG encoder with jpeg-encoder crate#2636197g merged 22 commits intoimage-rs:mainfrom
Conversation
|
Note that while jpeg-encoder reports IJG license due to SIMD code ported from libjpeg-turbo, it's actually ZLIB licensed according to https://github.com/libjpeg-turbo/libjpeg-turbo/blob/main/LICENSE.md Both licenses are permissive so it shouldn't be a problem regardless |
|
Now that #2624 is merged I've incorporated its changes into this PR. |
…cy. It is a highly permissive license comparable to MIT.
There was a problem hiding this comment.
With the SemVer part resolved, I'm fine with the slight reduction in API surface. At least it's more consistent. Just great work all around that I'm happy to adopt instead of our in-tree part that is not any easier to maintain. I would not worry too much about pixel density indication; orientation of the image would seem more pressing and a coherent way of exposing those format details rather than just doing it for one jpeg option seems preferrable. With 1.0 we should paint ourselves out of that corner of configuring it on the encoder, which is inaccessible behind a trait abstraction.
This PR replaces the in-tree JPEG encoder with the jpeg-encoder crate. Closes #1885 and #2500.
Background
jpeg-encoder is a fork of our in-tree JPEG encoder with multiple enhancements (optimized huffman tables, more subsampling options, AVX optimizations). It is already used in production by Glycin (GNOME) instead of our built-in encoder.
Correctness
This encoder used by Glycin so it is pretty well tested. I've added tests for roundtripping Exif and ICC.
Performance
The end-to-end time for converting from PNG to JPEG with
wondermagickgoes down 2x, so the speedup for JPEG encoding alone has to be more than 2x. On x86 with AVX2 anyway; ARM doesn't gain as much because jpeg-encoder doesn't have a NEON implementation.Safety
Thanks to Rust 1.86 making most SIMD intrinsics safe, I've removed the vast majority of unsafe code in vstroebel/jpeg-encoder#17 and vstroebel/jpeg-encoder#18. The remaining small amount of
unsafeis trivial.New functionality
This PR also exposes functions to control chroma subsampling factor. Our old encoder only supported 4:2:2, while jpeg-encoder supports 4:4:4, 4:2:2, 4:2:0, and a bunch of more obscure configurations. This should improve compression ratio.
This PR also lets the user opt into optimizing the Huffman tables of the generated JPEG file, further reducing file size.
Breaking changes
A casualty of this migration is a JPEG-exclusive option to generate an image on the fly via a
GenericImageView, but with the planned changes to image views this would have to be removed anyway.pub fn encode()is also removed because its signature would have to change and there is no reason to keep it around when it just duplicateswrite_image()exactly.Future work
TODO: handle
PixelDensityUnit::PixelAspectRatiovariant: vstroebel/jpeg-encoder#21jpeg-encoder supports more in-depth customization of the encoding process such as encoding progressive JPEGs, restart markets, etc. Exposing that functionality is not part of this PR.