This Zig program encodes a subset of Portable Arbitrary Map (PAM) images into the Quite OK Image Format (QOI). It is a freestanding implementation, existing entirely in one file. The QOI format is a simple, lossless image format designed for fast encoding and decoding.
I wrote this mostly as a learning exercise, and I was heavily inspired by the Simplified QOI Codec Library, a one header file library for encoding and decoding QOI files written in C.
These are some rudimentary, unscientific benchmarks performed on a Linux system running a Core i7-13700k with the poop
benchmarking utility. The qoi-zig
binary was built in ReleaseFast mode, and we're using FFmpeg n6.1.1 from the Arch repos.
- This first benchmark was run on a
big2.pam
image that I haven't included in theexamples
directory because it is rather large at 59.8 MB for a massive 5468x3644 image. I'll link a lossless JPEG-XL encode here if you'd like to take a look for yourself.
13700k :: ~ » poop -d 25000 'ffmpeg -y -i big2.pam -frames:v 1 big2.qoi' 'qoi-zig big2.pam big2.qoi 0'
Benchmark 1 (104 runs): ffmpeg -y -i big2.pam -frames:v 1 big2.qoi
measurement mean ± σ min … max outliers delta
wall_time 242ms ± 8.53ms 229ms … 277ms 2 ( 2%) 0%
peak_rss 244MB ± 261KB 243MB … 245MB 7 ( 7%) 0%
cpu_cycles 945M ± 10.2M 877M … 961M 9 ( 9%) 0%
instructions 2.11G ± 17.2M 1.96G … 2.12G 13 (13%) 0%
cache_references 5.66M ± 432K 3.88M … 5.98M 23 (22%) 0%
cache_misses 3.42M ± 320K 2.04M … 3.66M 13 (13%) 0%
branch_misses 15.7M ± 136K 14.5M … 15.8M 13 (13%) 0%
Benchmark 2 (128 runs): qoi-zig big2.pam big2.qoi 0
measurement mean ± σ min … max outliers delta
wall_time 196ms ± 3.80ms 185ms … 211ms 6 ( 5%) ⚡- 18.7% ± 0.7%
peak_rss 119MB ± 654KB 118MB … 121MB 0 ( 0%) ⚡- 51.0% ± 0.1%
cpu_cycles 756M ± 3.83M 741M … 772M 8 ( 6%) ⚡- 20.0% ± 0.2%
instructions 1.82G ± 3.34M 1.79G … 1.82G 11 ( 9%) ⚡- 13.7% ± 0.1%
cache_references 6.07M ± 109K 5.23M … 6.15M 12 ( 9%) 💩+ 7.1% ± 1.4%
cache_misses 2.22M ± 68.3K 2.07M … 2.57M 6 ( 5%) ⚡- 35.2% ± 1.7%
branch_misses 15.2M ± 48.5K 14.9M … 15.4M 6 ( 5%) ⚡- 3.3% ± 0.2%
- This benchmark was performed on the
qoi_logo.pam
image included in this repo'sexamples
directory.
13700k :: ~ » poop 'ffmpeg -y -i qoi_logo.pam -frames:v 1 qoi_logo.qoi' 'qoi-zig qoi_logo.pam qoi_logo.qoi 0'
Benchmark 1 (178 runs): ffmpeg -y -i qoi_logo.pam -frames:v 1 qoi_logo.qoi
measurement mean ± σ min … max outliers delta
wall_time 28.1ms ± 3.17ms 25.5ms … 42.5ms 17 (10%) 0%
peak_rss 54.3MB ± 311KB 53.5MB … 55.0MB 0 ( 0%) 0%
cpu_cycles 91.0M ± 2.03M 72.5M … 93.6M 11 ( 6%) 0%
instructions 159M ± 3.45M 124M … 161M 21 (12%) 0%
cache_references 675K ± 27.4K 534K … 765K 9 ( 5%) 0%
cache_misses 226K ± 16.7K 133K … 254K 4 ( 2%) 0%
branch_misses 647K ± 15.3K 506K … 675K 19 (11%) 0%
Benchmark 2 (3107 runs): qoi-zig qoi_logo.pam qoi_logo.qoi 0
measurement mean ± σ min … max outliers delta
wall_time 1.55ms ± 537us 227us … 11.6ms 262 ( 8%) ⚡- 94.5% ± 0.5%
peak_rss 844KB ± 28.3KB 635KB … 848KB 87 ( 3%) ⚡- 98.4% ± 0.0%
cpu_cycles 66.1K ± 59.7K 0 … 186K 0 ( 0%) ⚡- 99.9% ± 0.1%
instructions 142K ± 137K 0 … 281K 0 ( 0%) ⚡- 99.9% ± 0.1%
cache_references 447 ± 296 0 … 1.58K 23 ( 1%) ⚡- 99.9% ± 0.1%
cache_misses 2.69 ± 4.68 0 … 93 197 ( 6%) ⚡-100.0% ± 0.3%
branch_misses 666 ± 624 0 … 1.70K 0 ( 0%) ⚡- 99.9% ± 0.1%
FFmpeg is pretty fast, but it is evident there is more going on under the hood there. Even so, we'll take what we can get!
In order to build this program, you will need to have the latest version of the Zig programming language (at least version 0.13.0
) installed on your system as well as git
. You can find instructions for installing Zig on the official website. Once that is set up, follow the steps below for building the qoi-zig
binary:
git clone https://github.com/gianni-rosato/qoi-enc-zig # Clone the repo
cd qoi-enc-zig # Enter the directory
zig build -Doptimize=ReleaseFast # Build the program
Note: A previous version of this program encoded RGB source images, and had a smaller codebase. If you'd like to build that verion, simply run git reset --hard 36317c52896d8642ae10c3c18774991f4f68bf22
in the cloned directory before running zig build
. The old README.md will also be present in the reset directory if you would like to see the old usage instructions.
The program is run from the command line with the following arguments:
qoi-zig -h
Freestanding QOI Encoder in Zig
Example usage: qoi-zig [input.pam] [output] [colorspace] [color_depth] [dither]
Colorspace:
0: sRGB w/ Linear Alpha
1: Linear RGB
Color Depth:
0: Same as Source
*: Palletize
Dithering:
0: None
1: Sierra Lite
input.pam
: The input PAM image file to encode.output
: The output QOI image file to create.colorspace
: The colorspace of the image. Use0
for sRGB with linear alpha and1
for linear RGB.color_depth
: The color depth of the image. Use0
for the same as the source image (lossless), and any other number to lossily palletize the image to that specified color depth.dither
: The dithering algorithm to use. Use0
for no dithering and1
for Sierra Lite dithering.
If the input file is too small for the specified image dimensions & channels, an error message is printed.
If you're just interested in testing this program, you can use the PAM files in the examples/
directory. If you want to create your own PAM files, you can use FFmpeg like so:
Create an 8-bit RGB PAM file from an input image:
ffmpeg -i [input] -pix_fmt rgb24 -c pam -update 1 -f image2 output_rgb.pam
Create an 8-bit RGBA PAM file from an input image:
ffmpeg -i [input] -pix_fmt rgba -c pam -update 1 -f image2 output_rgba.pam
Note: This program's encoder will only encode 8-bit PAM files with 3 or 4 color channels. It will not encode 16-bit PAM files or PAM files with more than 4 color channels.
There are some compatible PAM examples provided in the examples/
directory. You can use these to test the program and see how it works.
Encode plants.pam
in sRGB with linear alpha:
qoi-zig plants.pam plants.qoi 0
Encode photograph.pam
in linear RGB (even though this image is meant to be encoded in sRGB w/ linear alpha):
qoi-zig photograph.pam photograph.qoi 1
These commands will create QOI image files from the inputs shown. The original and compressed file sizes are printed upon successful encoding.
This program does not perform any error checking on the input file. It is assumed that the file is a compatible PAM file. Incorrect inputs can lead to unexpected results or program crashes; always ensure that your input data is correct before running the program.
This program requires the Zig programming language, at least version 0.13.0
. It also uses the standard library provided with Zig. No other dependencies are required.
This program is released under the BSD 3-Clause License. You are free to use, modify, and distribute the program under the terms of this license.
Thank you to the authors of the Simplified QOI Codec Library, and Cancername for their expert consulting on the Zig programming language! Much appreciated!