Post

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 visa-versa converter following the format specifications file (pdf).

Specifications

QOI start with a header that includes width, height, number of channels (RGB or RGBA) and the colorspace. Then the image data is stored in 6 different type of chunks. They can be categorised into 4 groups:

  • A run of previous pixel
  • An index of last seen pixels array
  • A difference from last pixel (2 types depending on the difference size)
  • A raw pixel (RGB or RGBA)

QOI_OP_RGB & QOI_OP_RGBA

They start with a 1 byte flag that indicates the operation type. Then the next 3 or 4 bytes are the pixel data. The flag is b11111110 for RGB and b11111111 for RGBA. The alpha value remains same as the previous pixel for RGB type of chunk.

QOI_OP_RUN

This is a 1 byte chunk. First two bits are b11, the flag for this operation type. The next 6 bits store the run-length. The previous pixel is repeated for the number of times indicated by the run-length.

QOI_OP_INDEX

The qoi encoder/decoder should store the last 64 pixels in an array. This operation type is used to store the index of a pixel in a single byte. The flag is b00 and the next 6 bits store the index value.

QOI_OP_DIFF

This operation type is used when the difference between the previous pixel and the current pixel is small enough to be stored in 1 byte. The flag is b00 and the next 6 bits store the difference value. In groups of 2 bits, the first group is for red, second for green and third for blue. They indicate a signed 2-bit integer value ranging from -2 to 1.

QOI_OP_LUMA

This operation type can be used to store a larger difference between the previous in 2 bytes. The flag is b10. The next 6 bits store the difference in green value ranging between -32 and 31, next 4 bits is for red and the last 4 bits is for blue. They indicate a signed integer value ranging from -8 to 7 in a similar way. An important note here is that green channel also indicates a general change, so the actual difference is calculated by adding the green difference to the red and blue differences.

Further Reading

This post is licensed under CC BY 4.0 by the author.

Trending Tags