Inspired by the informative post from Jumping Rivers about selecting the correct image file type, I decided to optimise PNG file size as part of this blog’s CI pipeline.
OptiPNG
As suggested, I used optipng
. Let’s see how well this works on a large sample PNG file.
$ optipng moon.png
** Processing: moon.png
8192x4096 pixels, 3x8 bits/pixel, RGB
Input IDAT size = 55785027 bytes
Input file size = 55810891 bytes
Trying:
zc = 9 zm = 8 zs = 0 f = 5 IDAT size = 49789959
Selecting parameters:
zc = 9 zm = 8 zs = 0 f = 5 IDAT size = 49789959
Output IDAT size = 49789959 bytes (5995068 bytes decrease)
Output file size = 49795399 bytes (6015492 bytes = 10.78% decrease)
Not bad: a 10.78% decrease in file size from 54 MiB to 48 MiB.
I settled for the default level of optimisation (equivalent to -o2
). As the package authors note, there is unlikely to be a substantial improvement in image size with more aggressive optimisation, although it will take substantially longer.
Automating
I wanted all of the “larger” files on my blog to get optimised. And I, obviously, didn’t want to do this by hand, so I added it to the CI pipeline.
optimise:
stage: optimise
variables:
GIT_SUBMODULE_STRATEGY: none
script:
- find public/ -name "*.png" -size +50k -exec optipng {} \;
only:
- master
The -size +50k
option filters out files which are smaller than 50 kiB. This is an arbitrary threshold, but it doesn’t seem worthwhile using resources to optimise files which are already fairly small.
Now each time the master
branch is deployed, the larger PNG images are optimised.
Using a Hook
Another approach to integrating OptiPNG is to use the hook which is built into {knitr}
.
knitr::knit_hooks$set(optipng = knitr::hook_optipng)
# Suppress output.
knitr::opts_chunk$set(optipng = "-quiet")
Alternative Options
Here are some alternative options for optimising your PNG images (courtesy of the generous @jdblischak and @davdittrich):
- the
{tinieR}
package, which uses the TinyPNG service pngquant
- Leanify and
- Efficient-Compression-Tool .
I’ve tried out TinyPNG and it’s really effective, producing impressive compression ratios. However, it’s limited to only 500 images per month on the free plan. I’m going to stick with optipng
for the moment though because it’s 100% local.
Something to bear in mind is that optipng
is lossless, while TinyPNG uses “smart lossy compression”. Although TinyPNG might achieve better compression, the resulting image might be subtly changed (but at a level where it’s essentially imperceptible).
@datawookie I recommend trying the tinieR pkg by @jmablog. It uses the @tinypng API, and I get much better PNG compression compared to optipng. You get 500 free compressions per monthhttps://t.co/vJvQQzPjIW
— John Blischak (@jdblischak) February 21, 2021