/* See LICENSE file for copyright and license details. */ #ifndef LIBQUANTA_H #define LIBQUANTA_H #include #include #include /** * 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