Which Lossless Image Format is King?

June 14, 2024 in Software by Volkor5 minutes

Finding a new image format for my screenshot uploading script

(for <1 second encode times)

Last night I was reading https://siipo.la/blog/whats-the-best-lossless-image-format-comparing-png-webp-avif-and-jpeg-xl - Amazing testing, but a coupla things didn’t sit right with me.

  1. The post was made 3 years ago! Software has gotten better since then, so it should be nice to re-test.
  2. Their testing didn’t optimise for time. I’m looking for a replacement for PNG, so I’d like near instant encode times for a lower filesize.

So I decided to benchmark them all again. So I (ChatGPT) got to work. We drafted up a script that encodes my entire screenshots directory (3,4576 png files), timing how long each image takes, and the size difference between them.

After a few days of playing runescape (almost 99 thieving!) and waiting for the encoders to run in the background, it completed and I imported the data into libreoffice.

Each encoder was ran across multiple ’efficiency’ settings, so we’d be able to pick the best possible setting for each encoder to get the best ’time spent encoding vs filesize’ compromise.

OxiPNG

I like rust, you like rust, everyone likes rust. Surely a PNG Encoder written in rust should be fairly good. I don’t imagine this is going to be groundbreaking, but it should be better than normal stock standard PNG files.

oxipng

Encode LevelSize (kb)Time (ms)
o0179.37453262894223.1349091957336
o1165.89853950783185.5405015854713
o2160.23779240361144.963101758432
o3159.198425292969199.666474488325
o4158.543611314562287.304410492937
o5158.511186105234327.597866820409
o6158.495791682491351.707985010089
png206.70783102344

And you know what? I was right. (but then again, I also wrote this after I did the test :P).

AVIF

After seeing the excellent work that the AV1 team has done with their video format, I’d imagine AVIF is awesome and probably the new one to use.

How wrong I was.

The first few runs didn’t take too long overall, but as I got into the slower (but more efficient) options, the time increased much worse than the other formats.

avif

Encode LevelSize (kb)Time (ms)
s10318.85450575086855.1542231190545
s9318.85450575086854.8074373018161
s8263.749075147841127.899394638224
s7247.092412595396317.610550590948
s6215.985878555863531.95387719804
s5202.5093920672381210.03401556645
s4200.573427270961672.37964831364
s3200.0254934805412350.0446814644
s2199.0465037027994080.62611703661
png206.70783102344

This is crap. Yes, the slowest 2 settings beat PNG. but they took just over an hour for s3, and just under 4 hours for s2. I didn’t dare try s1, I’d be still encoding it.

So with that, AVIF is entirely out of the running, I’m not waiting anywhere between 41ms to 166 seconds to just encode a screenshot before uploading.

WebP

I really like WebP. I used to use it for a while for my screenshots, but coming back to it, I wanted to actually test it. I don’t like how it only supports 8-bit 4:2:0 format, how it’s had a few bad vulnerabilities and the lossy mode is useless. Wonderful for lossless though, so it’s still in the running.

webp

Encode LevelSize (kb)Time (ms)
z0177.58172946506116.8714326895359
z1134.78558745207642.0409339867397
z2129.95077458134456.7033727298933
z3121.02061066804171.6439896223696
z4120.94330625180876.4716056500432
z5120.84581502278678.3196886710868
z6118.78115788212594.9619486883828
z7117.970827455874120.901124243298
z8117.397220752857154.703660997406
z9115.0916866726351518.39579129432
png206.70783102344

It’s very fast, and much more efficient than PNG (or even OxiPNG)

JPEG XL

I have high hopes for this. Well… had. When I was doing basic research for this post, I learnt that it’s almost entirely unsupported in browsers. Googled added it to Chrome, then removed it a year later. It doesn’t work in any browser (except safari), and therefore also completely useless to me.

However, this may change, and I ran the tests before finding this out.

jpeg-xl

Encode LevelSize (kb)Time (ms)
e1188.11250870316111.9726145863361
e2176.69945723922226.0576535024503
e3165.42787848578634.0668780628423
e4139.84437334979167.959354280773
e5122.819347805447205.905736523494
e6122.181942692509205.368405880657
e7117.581536187066257.721821850677
e8114.291725646708590.539925050447
e9108.151255822633488.09974055924
png206.70783102344

Wow. This is good.

Overall

So here’s a awful graph of them all combined. combined

I’ve removed the excessive data points, ones that we’re definitely not going to be using and are useless for comparisons.

For my final comparison, I hand picked the best encoding speeds for each, and I found that an average of 144ms per image is fine. The largest screenshots can take up to 5 or 6 seconds to encode, but the large majority of my screenshots seem to be fairly small, and take no time at all to encode. The little bit of filesize I’d gain for needing to wait 5-6 seconds every few weeks seems fine to me.

So.

  1. OxiPNG - I chose o2 with 144.96ms average.
  2. WebP - I chose z8 with 154ms average.
  3. JPEG XL - I chose e4 with 167ms average.
  4. AVIF - I chose s8, with 127ms average (but over 110kb over the base filesize lol)

overall

This makes it fairly obvious. WebP is the winner. It’s got almost half the filesize of the stock PNG, and has reasonable encoding times.

What I could have done better(er)

After writing all this up, I should have probably got the script to encode all the encoding speeds in a loop, instead of manually editing and running the script after each run. Would have saved a lot of time (but I spent that time playing runescape, so it wasn’t that bad :p)

I probably should have also done some math stuff to better reflect the filesize difference based on the initial filesize, but I’m not smrt at math, and I got my answer without it anyway.