The Quite OK Image Format
Introduction
The Quite OK Image Format (QOI) is a lossless image format that is designed to be quite ok. While it is not designed to be the best format for any particular use case, it achieves much faster speeds in both encoding and decoding compared to png.
I tried implementing it in C++ as a png-to-qoi and vice versa converter following the format specifications file (pdf).
The Mindset
For compression the first thing you should consider is the type of your data. And in this case we have an image to store. Then you can start thinking about the structure of this data. For example text may have many repeating words, some common letters and some uncommon letters. To compress it you find a way to represent them with a smaller footprint.
For the qoi format, the data is an image and the most common features of images are; they do not change tend to change slowly across neighbouring pixels. For example in a selfie your face has similar colors within close pixels and they may even not change at all. So, one of our goals is to minimize the size when storing close/repeating colors. And this info is actually enough to create a decent storage system for images.
Specs
QOI starts with a header that includes width, height, number of channels (RGB or RGBA) and the colorspace. Then the image data is stored in six different type of chunks.
The six types of chunks in qoi can be categorised into four groups:
- A raw pixel (RGB or RGBA) [4-5 bytes]
- A run of the previous pixel [1 byte]
- An index of last seen pixels array [1 byte]
- A difference from last pixel [1-2 bytes]
We can see that for any new or unique pixels we need 1 extra byte but for similar enough or repeating pixels we only need 1-2 bytes. And it turns out a large portion of images include these kinds of pixels. With this implementation QOI achieves ~10x encode/decode speed and only around 16% larger file size.