Does using 8bit PNG with transparency increase file size significantly? No! PNG transparency compression is simple but clever.

Web images
compression
graphics
png
I discover my assumptions about how 8-bit PNGs store transparency are wrong, and it uses a clever technique meaning images with transparency can be smaller than those without.
Published

November 20, 2024

8bit PNGs with transparency can be smaller than without!

I’ve learnt a new thing. I’ll be using transparent 8-bit PNGs for my images from now onwards. This caused me to go down a bit of a rabbit hole to find out how transparency compression works in 8-bit PNGs.

Previously I have done various experiments looking at different methods of saving diagrams and images with a lot of flat colour (as opposed to photographs, which are best saved as JPEG or WebP). You can read about those experiments here:

Image tests: format and size

In those tests I didn’t look at using transparency (technically known as an alpha channel), because I assumed that adding an alpha channel would add a lot to the file size. However, I’ve recently realized that assumption may be wrong — alpha channels probably compress very well. So let’s do some tests.

Below is an image of some notes I made on the train this morning:

The following processes have been applied to this image:

This is the same process I apply to all of my hand-drawn and coloured images I make for this site.

I always change the background colour to be the same as the colour I use here (#FAF6EA, which I’ve just discovered is named “old lace”). But what if I should want to change that colour in the future, or use the images in another setting where I want the background colour to be different? It would make sense to use a transparent background if there is not much overhead.

The image above is 126KB. What about if I export it as an 8-bit PNG with a transparent background? Let’s see. Here it is:

Ok, doesn’t look any different, which is good. What about the size? Apparently it’s 107KB! Much smaller! That makes no sense, as it needs to store both the image data and the transparency data. Why would that occur? Well perhaps that’s an idiosyncrasy of this image — the text is just black and white, so with transparency no colour data needs to be stored at all. That’s interesting, but makes sense. So what about an image with colour?

Let’s see what happens with the following image, which is 1920 by 1080. Here it is as an 8-bit PNG without transparency:

This is 390 KB after all my processes are applied. This is it as an 8-bit PNG with transparency:

The transparent version is 380Kb. Also a little bit smaller. Wow, well that’s a surprise. Why? Let’s find out. I’ll ask ChatGPT o1-preview, as this is a tricky problem that requires a bit of thought I think… Here is a summary of what it says:

So, I’ve learnt something new — using transparency can actually result in more efficient image compression, at least with my style of images. So how does compression of transparency actually work? This has sent me down a bit of a rabbit hole…

How does transparency compression in 8-bit PNG files work?

I had assumed that there was essentially a separate representation of transparency, containing 256 levels, that was combined with the colour image — in such a scheme it would be impossible for the transparent version of the image to be smaller than the colour only version, because the transparent version would be the colour version plus the transparency map. But that’s not how it works. Take a look at section 4.2.1. Transparency information in this document:

PNG (Portable Network Graphics) Specification, Version 1.2

In 8-bit PNGs there is basically another chunk added to colour values, for transparency. If this addition is not there, the colour is treated as solid, This means that an individual colour can have a number of values in the colour index, being that colour at several different levels of transparency. If you imagine my black text above, that means at the edges of the text, there will be several different colours in the colour index. Since in 8-bit PNGs you only have 256 values to play with, the compressor optimizes the number of values in the index, so you will only get a limited number of transparency values (which is fine for edges, it will be impossible to notice visually. This also means that you only need to store those additional values for colours at the edges. So this method works very efficiently for flat colour diagrams and text.

There is another level of compression on top of this one — Deflate compression — which is also very efficient for images with lots of flat colour

One final thing — transparent images and Dark Mode

But, I have also thought of an issue — what about the web pages in Dark Mode? If I have dark text and someone has their browser set to Dark Mode, then they won’t be able to see the text. Is there a solution to that? I haven’t actually implemented Dark Mode on this site. It’s something I need to experiment with. I have added it to my list of things to do.

Hang on, I’ve just thought of a solution. If I add CSS to add an underlay on images then that will fix it. I’ll do that now. Here is the code:

/* Add a #FAF6EA background to all PNG images */
img[src$=".png"] {
    background-color: #FAF6EA;
}