Skip to main content

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:

A web page showing a hand-drawn diagram with some red text, and a black background which makes the diagram impossible to follow. The same web page, but now the diagram has a transparent background and shows through the white of the underlying page. The diagram is now legible.
Left: a screenshot taken in Safari on iOS 16, loading the AVIF image. Right: a screenshot taken with the original PNG image.

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.