qoi.h
Go to the documentation of this file.
1 /*
2 
3 SPDX-FileCopyrightText: Copyright (c) 2021, Dominic Szablewski - https://phoboslab.org
4 SPDX-License-Identifier: MIT
5 
6 
7 QOI - The "Quite OK Image" format for fast, lossless image compression
8 
9 -- About
10 
11 QOI encodes and decodes images in a lossless format. Compared to stb_image and
12 stb_image_write QOI offers 20x-50x faster encoding, 3x-4x faster decoding and
13 20% better compression.
14 
15 
16 -- Synopsis
17 
18 // Encode and store an RGBA buffer to the file system. The qoi_desc describes
19 // the input pixel data.
20 qoi_write("image_new.qoi", rgba_pixels, &(qoi_desc){
21  .width = 1920,
22  .height = 1080,
23  .channels = 4,
24  .colorspace = QOI_SRGB
25 });
26 
27 // Load and decode a QOI image from the file system into a 32bbp RGBA buffer.
28 // The qoi_desc struct will be filled with the width, height, number of channels
29 // and colorspace read from the file header.
30 qoi_desc desc;
31 void *rgba_pixels = qoi_read("image.qoi", &desc, 4);
32 
33 
34 
35 -- Documentation
36 
37 This library provides the following functions;
38 - qoi_read -- read and decode a QOI file
39 - qoi_decode -- decode the raw bytes of a QOI image from memory
40 - qoi_write -- encode and write a QOI file
41 - qoi_encode -- encode an rgba buffer into a QOI image in memory
42 
43 See the function declaration below for the signature and more information.
44 
45 If you don't want/need the qoi_read and qoi_write functions, you can define
46 QOI_NO_STDIO before including this library.
47 
48 This library uses malloc() and free(). To supply your own malloc implementation
49 you can define QOI_MALLOC and QOI_FREE before including this library.
50 
51 This library uses memset() to zero-initialize the index. To supply your own
52 implementation you can define QOI_ZEROARR before including this library.
53 
54 
55 -- Data Format
56 
57 A QOI file has a 14 byte header, followed by any number of data "chunks" and an
58 8-byte end marker.
59 
60 struct qoi_header_t {
61  char magic[4]; // magic bytes "qoif"
62  uint32_t width; // image width in pixels (BE)
63  uint32_t height; // image height in pixels (BE)
64  uint8_t channels; // 3 = RGB, 4 = RGBA
65  uint8_t colorspace; // 0 = sRGB with linear alpha, 1 = all channels linear
66 };
67 
68 Images are encoded row by row, left to right, top to bottom. The decoder and
69 encoder start with {r: 0, g: 0, b: 0, a: 255} as the previous pixel value. An
70 image is complete when all pixels specified by width * height have been covered.
71 
72 Pixels are encoded as
73  - a run of the previous pixel
74  - an index into an array of previously seen pixels
75  - a difference to the previous pixel value in r,g,b
76  - full r,g,b or r,g,b,a values
77 
78 The color channels are assumed to not be premultiplied with the alpha channel
79 ("un-premultiplied alpha").
80 
81 A running array[64] (zero-initialized) of previously seen pixel values is
82 maintained by the encoder and decoder. Each pixel that is seen by the encoder
83 and decoder is put into this array at the position formed by a hash function of
84 the color value. In the encoder, if the pixel value at the index matches the
85 current pixel, this index position is written to the stream as QOI_OP_INDEX.
86 The hash function for the index is:
87 
88  index_position = (r * 3 + g * 5 + b * 7 + a * 11) % 64
89 
90 Each chunk starts with a 2- or 8-bit tag, followed by a number of data bits. The
91 bit length of chunks is divisible by 8 - i.e. all chunks are byte aligned. All
92 values encoded in these data bits have the most significant bit on the left.
93 
94 The 8-bit tags have precedence over the 2-bit tags. A decoder must check for the
95 presence of an 8-bit tag first.
96 
97 The byte stream's end is marked with 7 0x00 bytes followed a single 0x01 byte.
98 
99 
100 The possible chunks are:
101 
102 
103 .- QOI_OP_INDEX ----------.
104 | Byte[0] |
105 | 7 6 5 4 3 2 1 0 |
106 |-------+-----------------|
107 | 0 0 | index |
108 `-------------------------`
109 2-bit tag b00
110 6-bit index into the color index array: 0..63
111 
112 A valid encoder must not issue 2 or more consecutive QOI_OP_INDEX chunks to the
113 same index. QOI_OP_RUN should be used instead.
114 
115 
116 .- QOI_OP_DIFF -----------.
117 | Byte[0] |
118 | 7 6 5 4 3 2 1 0 |
119 |-------+-----+-----+-----|
120 | 0 1 | dr | dg | db |
121 `-------------------------`
122 2-bit tag b01
123 2-bit red channel difference from the previous pixel between -2..1
124 2-bit green channel difference from the previous pixel between -2..1
125 2-bit blue channel difference from the previous pixel between -2..1
126 
127 The difference to the current channel values are using a wraparound operation,
128 so "1 - 2" will result in 255, while "255 + 1" will result in 0.
129 
130 Values are stored as unsigned integers with a bias of 2. E.g. -2 is stored as
131 0 (b00). 1 is stored as 3 (b11).
132 
133 The alpha value remains unchanged from the previous pixel.
134 
135 
136 .- QOI_OP_LUMA -------------------------------------.
137 | Byte[0] | Byte[1] |
138 | 7 6 5 4 3 2 1 0 | 7 6 5 4 3 2 1 0 |
139 |-------+-----------------+-------------+-----------|
140 | 1 0 | green diff | dr - dg | db - dg |
141 `---------------------------------------------------`
142 2-bit tag b10
143 6-bit green channel difference from the previous pixel -32..31
144 4-bit red channel difference minus green channel difference -8..7
145 4-bit blue channel difference minus green channel difference -8..7
146 
147 The green channel is used to indicate the general direction of change and is
148 encoded in 6 bits. The red and blue channels (dr and db) base their diffs off
149 of the green channel difference and are encoded in 4 bits. I.e.:
150  dr_dg = (cur_px.r - prev_px.r) - (cur_px.g - prev_px.g)
151  db_dg = (cur_px.b - prev_px.b) - (cur_px.g - prev_px.g)
152 
153 The difference to the current channel values are using a wraparound operation,
154 so "10 - 13" will result in 253, while "250 + 7" will result in 1.
155 
156 Values are stored as unsigned integers with a bias of 32 for the green channel
157 and a bias of 8 for the red and blue channel.
158 
159 The alpha value remains unchanged from the previous pixel.
160 
161 
162 .- QOI_OP_RUN ------------.
163 | Byte[0] |
164 | 7 6 5 4 3 2 1 0 |
165 |-------+-----------------|
166 | 1 1 | run |
167 `-------------------------`
168 2-bit tag b11
169 6-bit run-length repeating the previous pixel: 1..62
170 
171 The run-length is stored with a bias of -1. Note that the run-lengths 63 and 64
172 (b111110 and b111111) are illegal as they are occupied by the QOI_OP_RGB and
173 QOI_OP_RGBA tags.
174 
175 
176 .- QOI_OP_RGB ------------------------------------------.
177 | Byte[0] | Byte[1] | Byte[2] | Byte[3] |
178 | 7 6 5 4 3 2 1 0 | 7 .. 0 | 7 .. 0 | 7 .. 0 |
179 |-------------------------+---------+---------+---------|
180 | 1 1 1 1 1 1 1 0 | red | green | blue |
181 `-------------------------------------------------------`
182 8-bit tag b11111110
183 8-bit red channel value
184 8-bit green channel value
185 8-bit blue channel value
186 
187 The alpha value remains unchanged from the previous pixel.
188 
189 
190 .- QOI_OP_RGBA ---------------------------------------------------.
191 | Byte[0] | Byte[1] | Byte[2] | Byte[3] | Byte[4] |
192 | 7 6 5 4 3 2 1 0 | 7 .. 0 | 7 .. 0 | 7 .. 0 | 7 .. 0 |
193 |-------------------------+---------+---------+---------+---------|
194 | 1 1 1 1 1 1 1 1 | red | green | blue | alpha |
195 `-----------------------------------------------------------------`
196 8-bit tag b11111111
197 8-bit red channel value
198 8-bit green channel value
199 8-bit blue channel value
200 8-bit alpha channel value
201 
202 */
203 
204 #pragma once
205 
206 #ifdef __cplusplus
207 extern "C" {
208 #endif
209 
210 /* A pointer to a qoi_desc struct has to be supplied to all of qoi's functions.
211 It describes either the input format (for qoi_write and qoi_encode), or is
212 filled with the description read from the file header (for qoi_read and
213 qoi_decode).
214 
215 The colorspace in this qoi_desc is an enum where
216  0 = sRGB, i.e. gamma scaled RGB channels and a linear alpha channel
217  1 = all channels are linear
218 You may use the constants QOI_SRGB or QOI_LINEAR. The colorspace is purely
219 informative. It will be saved to the file header, but does not affect
220 how chunks are en-/decoded. */
221 
222 #define QOI_SRGB 0
223 #define QOI_LINEAR 1
224 
226 typedef struct
227 {
228  unsigned int width;
229  unsigned int height;
230  unsigned char channels;
231  unsigned char colorspace;
232 } qoi_desc;
233 
244 void *qoi_encode(const void *data, const qoi_desc *desc, int *out_len);
245 
257 void *qoi_decode(const void *data, int size, qoi_desc *desc, int channels);
258 
259 #ifdef __cplusplus
260 }
261 #endif
qoi_desc::width
unsigned int width
Width of the image in pixels.
Definition: qoi.h:228
qoi_desc::colorspace
unsigned char colorspace
QOI_SRGB or QOI_LINEAR. Purely indicative.
Definition: qoi.h:231
qoi_desc::channels
unsigned char channels
3 or 4, specifying RGB or RGBA data.
Definition: qoi.h:230
qoi_decode
void * qoi_decode(const void *data, int size, qoi_desc *desc, int channels)
Decode a QOI image from memory.
qoi_encode
void * qoi_encode(const void *data, const qoi_desc *desc, int *out_len)
Encode raw RGB or RGBA pixels into a QOI image in memory.
qoi_desc
Descriptor of image to be compressed.
Definition: qoi.h:226
qoi_desc::height
unsigned int height
Height of the image in pixels.
Definition: qoi.h:229


qoi_image_transport
Author(s): Martin Pecka
autogenerated on Sat Apr 5 2025 03:02:01