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.
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.
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.
Encode Level | Size (kb) | Time (ms) |
---|---|---|
o0 | 179.374532628942 | 23.1349091957336 |
o1 | 165.898539507831 | 85.5405015854713 |
o2 | 160.23779240361 | 144.963101758432 |
o3 | 159.198425292969 | 199.666474488325 |
o4 | 158.543611314562 | 287.304410492937 |
o5 | 158.511186105234 | 327.597866820409 |
o6 | 158.495791682491 | 351.707985010089 |
png | 206.70783102344 |
And you know what? I was right. (but then again, I also wrote this after I did the test :P).
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.
Encode Level | Size (kb) | Time (ms) |
---|---|---|
s10 | 318.854505750868 | 55.1542231190545 |
s9 | 318.854505750868 | 54.8074373018161 |
s8 | 263.749075147841 | 127.899394638224 |
s7 | 247.092412595396 | 317.610550590948 |
s6 | 215.985878555863 | 531.95387719804 |
s5 | 202.509392067238 | 1210.03401556645 |
s4 | 200.57342727096 | 1672.37964831364 |
s3 | 200.025493480541 | 2350.0446814644 |
s2 | 199.046503702799 | 4080.62611703661 |
png | 206.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.
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.
Encode Level | Size (kb) | Time (ms) |
---|---|---|
z0 | 177.581729465061 | 16.8714326895359 |
z1 | 134.785587452076 | 42.0409339867397 |
z2 | 129.950774581344 | 56.7033727298933 |
z3 | 121.020610668041 | 71.6439896223696 |
z4 | 120.943306251808 | 76.4716056500432 |
z5 | 120.845815022786 | 78.3196886710868 |
z6 | 118.781157882125 | 94.9619486883828 |
z7 | 117.970827455874 | 120.901124243298 |
z8 | 117.397220752857 | 154.703660997406 |
z9 | 115.091686672635 | 1518.39579129432 |
png | 206.70783102344 |
It’s very fast, and much more efficient than PNG (or even OxiPNG)
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.
Encode Level | Size (kb) | Time (ms) |
---|---|---|
e1 | 188.112508703161 | 11.9726145863361 |
e2 | 176.699457239222 | 26.0576535024503 |
e3 | 165.427878485786 | 34.0668780628423 |
e4 | 139.84437334979 | 167.959354280773 |
e5 | 122.819347805447 | 205.905736523494 |
e6 | 122.181942692509 | 205.368405880657 |
e7 | 117.581536187066 | 257.721821850677 |
e8 | 114.291725646708 | 590.539925050447 |
e9 | 108.15125582263 | 3488.09974055924 |
png | 206.70783102344 |
Wow. This is good.
So here’s a awful graph of them all 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.
o2
with 144.96ms average.z8
with 154ms average.e4
with 167ms average.s8
, with 127ms average (but over 110kb over the base filesize lol)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.
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.