diff options
| author | Mattias Andrée <m@maandree.se> | 2025-11-23 21:33:38 +0100 |
|---|---|---|
| committer | Mattias Andrée <m@maandree.se> | 2025-11-23 21:33:38 +0100 |
| commit | 226d807bb8bc0cdbc011b2e616ac02881e74c542 (patch) | |
| tree | e35bcc0f0b2bad8abfbb5da6db5580a813ca48bc /libquanta.h | |
| download | libquanta-226d807bb8bc0cdbc011b2e616ac02881e74c542.tar.gz libquanta-226d807bb8bc0cdbc011b2e616ac02881e74c542.tar.bz2 libquanta-226d807bb8bc0cdbc011b2e616ac02881e74c542.tar.xz | |
First commit
Signed-off-by: Mattias Andrée <m@maandree.se>
Diffstat (limited to 'libquanta.h')
| -rw-r--r-- | libquanta.h | 253 |
1 files changed, 253 insertions, 0 deletions
diff --git a/libquanta.h b/libquanta.h new file mode 100644 index 0000000..89c2fa0 --- /dev/null +++ b/libquanta.h @@ -0,0 +1,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 |
