1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
|
/* See LICENSE file for copyright and license details. */
#ifndef LIBQUANTA_H
#define LIBQUANTA_H
#include <stdarg.h>
#include <stdint.h>
#include <stddef.h>
/**
* Colour-quantised image
*/
struct libquanta_image {
/**
* The image's width
*/
size_t width;
/**
* The image's height
*/
size_t height;
/**
* `.image[y * .width + x]` for `y` in [0, `.height`), `x` in [0, `.width`),
* will be the index of the colour at pixel (`x`, `y`). This index is the
* colour index in the colour palette stored separatedly in the `.palette`
* field of a `struct libquanta_palette`.
*/
size_t image[];
};
/**
* A colour channel from an image
*/
struct libquanta_channel {
/**
* The number of bits per input image colour value,
* must be between 1 and 64 (inclusive)
*/
size_t bits_in;
/**
* The number of bits per palette colour value,
* must be between 1 and `.bits_in` (inclusive)
*/
size_t bits_out;
/**
* The image's width in cells
*/
size_t image_width;
/**
* The image's height in cells
*/
size_t image_height;
/**
* If image is row-major:
* The number of bytes per row in the image
*
* If image is column-major:
* The number of bytes per cell in the image
*/
size_t image_row_size;
/**
* If image is row-major:
* The number of bytes per cell in the image
*
* If image is column-major:
* The number of bytes per column in the image
*/
size_t image_cell_size;
/**
* The image
*
* Must not be `NULL` unless `.image_width` or `.image_height` is 0
*
* `&((const char *).image)[y * .image_row_size + x * .image_cell_size]`
* shall point to the colour value for cell (`x`, `y`), for the colour
* channel`, encoded in host-native endian; for
* 1 ≤ `.bits_in` ≤ 8, it shall be a `uint8_t`, for
* 9 ≤ `.bits_in` ≤ 16, it shall be a `uint16_t`, for
* 17 ≤ `.bits_in` ≤ 32, it shall be a `uint32_t`, and for
* 33 ≤ `.bits_in` ≤ 64, it shall be a `uint64_t`
*/
const void *image;
};
/**
* Colour palette for an image
*/
struct libquanta_palette {
/**
* The number of colours stored in the palette, must be at least 1
*/
size_t size;
/**
* The colour palette
*
* If the image has N colour channels, colour channel value i (within [0, N))
* for palette colour j (within [0, `.size`)), is `.palette[j * N + i]`
*/
uint64_t palette[];
};
/**
* Get the allocation size for a `struct libquanta_palette`
*
* @param ncolours The number of colours the palette may hold
* @param nchannels The number of colour channels
* @param size_out Output parameter for the allocation size
* (may be `NULL`)
* @return 0 on success, -1 on failure
*
* @throws EOVERFLOW The palette is too large to be allocated
* @throws EINVAL `ncolours` or `nchannels` is 0
*/
int libquanta_palette_size(size_t ncolours, size_t nchannels, size_t *size_out);
/**
* Allocate and initialise a colour palette
*
* @param ncolours The number of colours the palette may hold, must be at least 1
* @param nchannels The number of colour channels, must be at least 1
* @return Colour palette object with `.size` set to `ncolours`,
* allocated using malloc(3) (caller is responsible for
* deallocating it using free(3); `NULL` on failure
*
* @throws ENOMEM The palette is too large to be allocated,
* or there is not enough memory to allocate it
* @throws EINVAL `ncolours` or `nchannels` is 0
*/
struct libquanta_palette *libquanta_malloc_palette(size_t ncolours, size_t nchannels);
/**
* Colour-quantise an image using some library-selected colour quantiser
*
* @param palette Colour palette to fill, `.size` must be set with the
* maximum number of colours, and will upon successful
* completion be set to the number of used colours
* @param args One `const struct libquanta_channel *` per colour
* channel, providing the image for each colour channel;
* the list shall be terminated by `NULL`
* @return Colour-quantised image, allocated using malloc(3)
* (caller is responsible for deallocating it using
* free(3); `NULL` on failure
*
* @throws EINVAL `palette` is `NULL`, `palette->size` is 0,
* or no colour channels are provided (the first argument
* stored in `args` is `NULL`)
* @throws ENOMEM Not enough memory available
*
* The function may write beyond to and beyond `&palette->palette[palette->size]`
* for `palette->size` as set after the function returns, but not as set when
* the function is called. The function may also have written to `palette->palette`
* even if the function fails.
*/
struct libquanta_image *libquanta_vquantise(struct libquanta_palette *palette, va_list args);
/**
* Colour-quantise an image using some library-selected colour quantiser
*
* @param palette Colour palette to fill, `.size` must be set with the
* maximum number of colours, and will upon successful
* completion be set to the number of used colours
* @param ... One `const struct libquanta_channel *` per colour
* channel, providing the image for each colour channel;
* the list shall be terminated by `NULL`
* @return Colour-quantised image, allocated using malloc(3)
* (caller is responsible for deallocating it using
* free(3); `NULL` on failure
*
* @throws EINVAL `palette` is `NULL`, `palette->size` is 0,
* or no colour channels are provided (second argument is `NULL`)
* @throws EINVAL One of the colour channel descriptions has an invalid configuration
* or the colour channel descriptions do not have the same image size
* configured
* @throws ENOMEM Not enough memory available
*
* The function may write beyond to and beyond `&palette->palette[palette->size]`
* for `palette->size` as set after the function returns, but not as set when
* the function is called. The function may also have written to `palette->palette`
* even if the function fails.
*/
struct libquanta_image *libquanta_quantise(struct libquanta_palette *palette, ...);
/**
* Colour-quantise an image using Wu's Colour Quantiser
*
* @param palette Colour palette to fill, `.size` must be set with the
* maximum number of colours, and will upon successful
* completion be set to the number of used colours
* @param args One `const struct libquanta_channel *` per colour
* channel, providing the image for each colour channel;
* the list shall be terminated by `NULL`
* @return Colour-quantised image, allocated using malloc(3)
* (caller is responsible for deallocating it using
* free(3); `NULL` on failure
*
* @throws EINVAL `palette` is `NULL`, `palette->size` is 0,
* or no colour channels are provided (the first argument
* stored in `args` is `NULL`)
* @throws EINVAL One of the colour channel descriptions has an invalid configuration
* or the colour channel descriptions do not have the same image size
* configured
* @throws ENOMEM Not enough memory available
*
* The function may write beyond to and beyond `&palette->palette[palette->size]`
* for `palette->size` as set after the function returns, but not as set when
* the function is called. The function may also have written to `palette->palette`
* even if the function fails.
*/
struct libquanta_image *libquanta_vquantise_wu(struct libquanta_palette *palette, va_list args);
/**
* Colour-quantise an image using Wu's Colour Quantiser
*
* @param palette Colour palette to fill, `.size` must be set with the
* maximum number of colours, and will upon successful
* completion be set to the number of used colours
* @param ... One `const struct libquanta_channel *` per colour
* channel, providing the image for each colour channel;
* the list shall be terminated by `NULL`
* @return Colour-quantised image, allocated using malloc(3)
* (caller is responsible for deallocating it using
* free(3); `NULL` on failure
*
* @throws EINVAL `palette` is `NULL`, `palette->size` is 0,
* or no colour channels are provided (second argument is `NULL`)
* @throws EINVAL One of the colour channel descriptions has an invalid configuration
* or the colour channel descriptions do not have the same image size
* configured
* @throws ENOMEM Not enough memory available
*
* The function may write beyond to and beyond `&palette->palette[palette->size]`
* for `palette->size` as set after the function returns, but not as set when
* the function is called. The function may also have written to `palette->palette`
* even if the function fails.
*/
struct libquanta_image *libquanta_quantise_wu(struct libquanta_palette *palette, ...);
#endif
|