include
qoi_image_transport
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