From b60d205c290e843e05009cc709f2d3d1c1cd4aea Mon Sep 17 00:00:00 2001 From: Mattias Andrée Date: Sun, 2 Mar 2025 18:38:02 +0100 Subject: First commit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Mattias Andrée --- liblss16.h | 216 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 216 insertions(+) create mode 100644 liblss16.h (limited to 'liblss16.h') diff --git a/liblss16.h b/liblss16.h new file mode 100644 index 0000000..cf51ec0 --- /dev/null +++ b/liblss16.h @@ -0,0 +1,216 @@ +/* See LICENSE file for copyright and license details. */ +#ifndef LIBLSS16_H +#define LIBLSS16_H + +#include +#include + + +/** + * Image decoding state + */ +enum liblss16_decode_state { + /** + * End of image not yet reached + * + * File truncated if end of file reached + */ + LIBLSS16_DECODE_RUNNING, + + /** + * End of image reached + * + * Note that pixels may still be returned + * + * File holds unused data if end of file not reached + */ + LIBLSS16_DECODE_END_OF_IMAGE, + + /** + * A decoding error has occurred + * + * Processing most be aborted + */ + LIBLSS16_DECODE_ERROR +}; + + +/** + * Error values for image decoding + */ +enum liblss16_decode_error { + /** + * The file was at most 3 bytes long, but first + * bytes where {0x3D, 0x3F, 0x41} (up to the + * length of the file) + */ + LIBLSS16_DECODE_TRUNCATED_MAGIC, + + /** + * The file did not start with {0x3D, 0x3F, 0x41, 0x01} + * + * The number of consumed bytes, include the first bad + * byte in the magic. The number of consumed bytes is + * 1 if the first byte was wrong. + */ + LIBLSS16_DECODE_BAD_MAGIC, + + /** + * The file was too short to contain the full header + */ + LIBLSS16_DECODE_TRUNCATED_HEADER, + + /** + * At least one of the follow (you can check `.width` + * and `.height` to determine which apply): + * + * - The image width was set to 0 + * + * - The image height was set to 0 + * + * - The image height exceeded 32767 + */ + LIBLSS16_DECODE_BAD_IMAGE_SIZE, + + /** + * The colour map contain a colour that had at least + * once of the two high bits on the encoded byte set + * + * If you want to know which colour was bad (you can + * only find the first one), you have to calculate it + * from the number of bytes consumed before the failure + * occurred. If the number of consumed bytes is `N`, + * `(N - 9) / 3` is the index of the colour (the index + * of the first colour is 0), and the remainder maps + * to the channel: 0 = red, 1 = green, 2 = blue. + */ + LIBLSS16_DECODE_BAD_COLOUR, + + /** + * Row padding was not all zeroes + */ + LIBLSS16_DECODE_BAD_ROW_PADDING, + + /** + * Run-length encoding ran across two or more rows + */ + LIBLSS16_DECODE_EXCESSIVE_RUN_LENGTH, + + /** + * The file was too short to contain the full image + */ + LIBLSS16_DECODE_TRUNCATED_IMAGE +}; + + +/** + * sRGB colour values, with transfer function applied, + * encoded in values in [0, 255] + */ +struct liblss16_colour { + /** + * Red channel value + */ + uint8_t r; + + /** + * Green channel value + */ + uint8_t g; + + /** + * Blue channel value + */ + uint8_t b; +}; + + +/** + * Decode state + */ +struct liblss16_decoder { + /** + * The width of the raster + */ + uint16_t width; + + /** + * The height of the raster + */ + uint16_t height; + + /** + * Image colour map + */ + struct liblss16_colour colour_map[16]; + + + /** + * For internal use + */ + struct { + uint16_t x_rem; /**< number of pixels (after `.internal.kept`) until end of row */ + uint16_t y_rem; /**< number of row completions until end of image */ + uint16_t kept; /**< number of duplications held for next call */ + uint8_t previous; /**< previous pixel */ + uint8_t saved; /**< 0 or saved nibble plus 1 */ + uint8_t init_state; /**< number of header bytes read */ + uint8_t state; + } internal; +}; + + +/** + * Initialise a decoder + * + * @param decoder The decoder + */ +void liblss16_decoder_init(struct liblss16_decoder *decoder); + + +/** + * @param decoder Decoder state, must have been initialised with + * `liblss16_decoder_init` before the first call + * @param data Data to decode image from (may be partial) + * @param length The number of bytes available in `data`; + * end of file can be indicated using the value 0 + * @param consumed_out The number of bytes processed from `data` + * @param pixels Output buffer for the indicies of the colours + * for the pixels in the image. They are returned + * primarily from to the top down and secondarily + * from left to right. + * @param pixels_size The number of elements that may be stored in `pixels` + * @param npixels_out Output parameter for the number of elements stored + * in `pixels`. Always set. + * @param error_out Output parameter for the error; only set if + * `LIBLSS16_DECODE_ERROR` is returned; may be `NULL` + * @return The processing state: normally `LIBLSS16_DECODE_RUNNING`, + * but `LIBLSS16_DECODE_END_OF_IMAGE` when the image has + * been fully decoded, and `LIBLSS16_DECODE_ERROR` on error + * + * `decoder->width`, `decoder->height` and `decoder->colour_map` are + * set once `*npixels_out` is set to a non-zero value for the first + * time (or some time before that). `decoder->width` and `decoder->height` + * are also set if `LIBLSS16_DECODE_ERROR` is returned and `*error_out` + * is set to `LIBLSS16_DECODE_BAD_HEADER` + */ +enum liblss16_decode_state liblss16_decode_to_colour_index( + struct liblss16_decoder *decoder, + const void *data, size_t length, size_t *consumed_out, + uint8_t *pixels, size_t pixels_size, size_t *npixels_out, + enum liblss16_decode_error *error_out); + + +/** + * Get error description for an error code + * + * @param error The error code + * @return The error description + */ +#if defined(__GNUC__) +__attribute__((__const__)) +#endif +const char *liblss16_decode_strerror(enum liblss16_decode_error error); + + +#endif -- cgit v1.2.3-70-g09d2