A denser and slightly slower fork of the QOI image format.
Updated spec
Documentation updates
Remove QOIR-specific readme for now


browse log




QUAIL - the Quite Advanced Image Library - is a new image codec drawing on experience with QOI and QOI-Remix. After I designed QOI-R, I decided to start from scratch on a new nibble-oriented spec rather than continuing to modify QOI; QUAIL is the result of that effort. It uses the QOI harness and infrastructure (qbench/qconv) but is a largely clean-sheet encoding.

QUAIL gets solid density improvements against QOI/QOI-R with a moderate performance hit (and remains drastically higher-throughput than PNG.) Optimization will be a focus in the coming months, so throughput may improve. Additionally, I've been working to address some of what I consider to be QOI pain points - lack of support for very large images being a big one.

The spec should be considered very cold but not quite frozen. I don't expect to break compatibility, but it's not impossible. The code itself should be considered to be in a much higher state of flux than the spec.

QUAIL has been tested on Linux (Z, PPC64LE, ARM64, Itanium, x86_64) and HP-UX (Itanium.)

#What about QOI-R?

QOI-R remains present in the QUAIL tree, as does QOI. QOI-R work is effectively complete, with the exception that I intend to produce a spec at some point. The QOI-R format will not change.

README-QOIR.md contains the original QOI-R readme.

#QUAIL Encoding

This is extremely sparse right now and should be considered a work in progress. Much though I hate to say it, right now the code is the spec.



8-bit channels, optional alpha depending on source PNG.


r * 3 + g * 5 + b * 7 + a * 11 - this is the same hash used by QOI.


QUAIL uses three indexes - Microindex (8 entries), Macroindex (256 entries), Last Level Index (4096 entries). These work similarly to the single-level index on QOI; the pixel value is hashed using the algorithm above to access the index. If an identical pixel is present in the index, a Retrieve From Index word is emitted for this pixel; if it is not, then the pixel is inserted into the index for future use.

As an example, if a pixel is not present in the microindex and is instead emitted as a "diff" word, it is also added to the microindex and, unless evicted by another pixel with the same hash, can be used by a later identical pixel using a Retrieve From Microindex word.

#Encoding Words

  • 1iii - Retrieve From Microindex
  • 0010 llll - Short Run
  • 0100 iiii iiii - Retrieve From Macroindex
  • 0011 llll llll - Long Run
  • 000r rrgg gbbb - Diff
  • 0110 gggg ggrr rbbb - Microluma; like Medium Luma with shrunken fields
  • 0101 0010 iiii iiii iiii - Retrieve From Last Level Index
  • 0111 gggg ggrr rrrb bbbb - Medium Luma, where g is difference green, r is (difference red - difference green), b is (difference blue - difference green)
  • 0101 1ggg gggg rrrr rrbb bbbb - Megaluma; like Medium Luma with expanded fields
  • 0101 0001 rrrr rrrr gggg gggg bbbb bbbb - Immediate RGB pixel
  • 0101 0000 rrrr rrrr gggg gggg bbbb bbbb aaaa aaaa - Immediate RGBA pixel