Beware of transparent backgrounds when using AVIF with ImageMagick 6
One of the things I did over my Christmas break was redo all the image handling on this site. Mostly I’m catching up on the current “best practices” for images on the web. I’ve written a Jekyll plugin which allows me to use an image in a post like so:
{%
picture
filename="wc_500_error.png"
alt="An 'Internal Server Error' page."
width="582"
class="screenshot"
%}
This creates multiple copies of the image, in different sizes, which are sent to the browser in the <picture>
tag – so browsers can pick the best size for your device, which often makes pages smaller and faster than they were before.
It also includes image dimensions (width and aspect ratio), so a browser can work out how big an image will appear on the page before it’s been loaded. This reduces layout shift, and combined with the loading="lazy"
attribute can further save data.
But the big discovery for me was modern image formats like WebP and AVIF, which are much smaller than formats like JPEG and PNG. WebP is good, AVIF is unbelievably good – literally. When I first enabled AVIF support, I thought I’d broken something, because a 5x compression ratio over WebP (which is what I’m seeing for some images) seemed impossible.
I had it all tested and working, so imagine my dismay when I opened my latest post on my phone and discovered the images were broken:
I found the bug pretty quickly: I’d inadvertently downgraded from ImageMagick 7 to ImageMagick 6, and when you create an AVIF image in ImageMagick 6, it replaces transparent backgrounds with black ones. Oops. I hadn’t noticed because my desktop browser doesn’t have AVIF support yet; it was loading the WebP image, which looked fine.
I’ve upgraded back to ImageMagick 7 using the IMEI installer scripts, which seems to resolve the problem. I’ve also added a check for similar issues in future.
You can tell if an image has transparent pixels using the %[opaque]
format specifier:
$ identify -format '%[opaque]' image_with_transparency.png
False
$ identify -format '%[opaque]' image_without_transparency.png
True
Note that this tells you if an image has all-opaque pixels, so False
means the image is transparent, and True
means it isn’t.
I’ve added this to my Jekyll plugin: after it creates a new size/format of image, it checks to see if transparency has been lost in the conversion process. If it finds a blatted background, it will raise an error for me to investigate.
This is the downside of creating lots of image sizes/formats – even a few images in a post can spiral into dozens of derivatives, more than I can check by hand. I think I’ve fixed the issues now, but if you spot any more broken images, please do let me know.