image-rs / image-png

PNG decoding and encoding library in pure Rust
https://docs.rs/png
Apache License 2.0
357 stars 140 forks source link

Compression filesize changes between v0.17.5 - v0.17.9 #404

Closed JamesMcGuigan closed 1 year ago

JamesMcGuigan commented 1 year ago

Recently run cargo update on my project and noticed differences in png file compression size between png versions v0.17.5-v0.17.9 for an otherwise identically rendered fractal.

I started with png="=0.17.5" in Cargo.toml and ran cargo update; ./fractal.sh. This would update Cargo.lock, perform a clean release build and regenerate the fractal images. This did not result in a git diff.

I incrementally version bumped png from v0.17.5 -> v0.17.9 and observed the following changes in filesize

CHANGE: fractal.png 21189 bytes (=0.17.5) 29596 bytes (=0.17.6) +40% 29596 bytes (=0.17.7) SAME 24981 bytes (=0.17.8) -20% 24981 bytes (=0.17.9) SAME == +20% overall

CHANGE: fractal.zoom.png 38284 bytes (=0.17.5) 50080 bytes (=0.17.6) +30% 50080 bytes (=0.17.7) SAME 45547 bytes (=0.17.8) -10% 45547 bytes (=0.17.9) SAME == +20% overall

Unsure if my fractal images count as a representative image sample, but it appears something in the png compression algorithm was refactored in versions 0.17.6 resulting in 30-40% filesize increase, following a second refactor in 0.17.8 that reduced filesize 10-20%, whilst still remaining 20% larger than 0.17.5

I have documented this testcase as a series of git commits, in this branch:

https://github.com/JamesMcGuigan/fractals/commit/331dd2498bcb43a50de1c436e1969b1289f38ce0

fractal.sh | png="=0.17.5" 

https://github.com/JamesMcGuigan/fractals/commit/15f12fbcc5bc398d2e086836d3b0c61a1d9a5a71

fractal.sh | png="=0.17.6"
cargo update
    Updating crates.io index
    Updating git repository `[https://github.com/yewstack/yew/`](https://github.com/yewstack/yew/%60)
    Removing adler32 v1.2.0
    Removing deflate v1.0.0
    Updating png v0.17.5 -> v0.17.6

CHANGE: fractal.png      | 21189 -> 29596 bytes (+40%)
CHANGE: fractal.zoom.png | 38284 -> 50080 bytes (+30%)

https://github.com/JamesMcGuigan/fractals/commit/a596fd3bd60e8a9c361e8ebc0ca2e5e65f95cfd9

fractal.sh | png="=0.17.7"
cargo update
    Updating crates.io index
    Updating git repository `[https://github.com/yewstack/yew/`](https://github.com/yewstack/yew/%60)
    Updating miniz_oxide v0.5.4 -> v0.6.2
    Updating png v0.17.6 -> v0.17.7

SAME: fractal.png      | 29596 bytes
SAME: fractal.zoom.png | 50080 bytes

https://github.com/JamesMcGuigan/fractals/commit/760699dd79aebc38551fe99e69ee0dca3710ed78

fractal.sh | png="=0.17.8"
cargo update
    Updating crates.io index
    Updating git repository `[https://github.com/yewstack/yew/`](https://github.com/yewstack/yew/%60)
      Adding fdeflate v0.3.0
    Removing miniz_oxide v0.6.2
    Updating png v0.17.7 -> v0.17.8

CHANGE: fractal.png      | 21189 -> 29596 -> 24981 bytes (+20% overall)
CHANGE: fractal.zoom.png | 38284 -> 50080 -> 45547 bytes (+20% overall)

https://github.com/JamesMcGuigan/fractals/commit/90707460916e18174ce0d0e9f97531962e1fd44d

fractal.sh | png="=0.17.9"
cargo update
    Updating crates.io index
    Updating git repository `[https://github.com/yewstack/yew/`](https://github.com/yewstack/yew/%60)
    Updating png v0.17.8 -> v0.17.9

SAME: fractal.png      | 24981 bytes
SAME: fractal.zoom.png | 45547 bytes
fintelia commented 1 year ago

We completely changed the compression libraries in 0.17.6 and again in 0.17.8!

As of 0.17.8, we use an extremely fast approach from fdeflate if you use Compression::Fast (which the image crate uses by default unless you override it) and use flate2 which is much slower but gets better compression ratios otherwise.