From b23a3ab831f91553d34a48f51370ed9525de07ac Mon Sep 17 00:00:00 2001 From: zlago Date: Tue, 24 Sep 2024 20:54:48 +0200 Subject: initial commit --- src/libplum.h | 394 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 394 insertions(+) create mode 100644 src/libplum.h (limited to 'src/libplum.h') diff --git a/src/libplum.h b/src/libplum.h new file mode 100644 index 0000000..99c676b --- /dev/null +++ b/src/libplum.h @@ -0,0 +1,394 @@ +#ifndef PLUM_HEADER + +#define PLUM_HEADER + +#define PLUM_VERSION 10029 + +#include +#ifndef PLUM_NO_STDINT +#include +#endif + +#if !defined(__cplusplus) && (__STDC_VERSION__ >= 199901L) +/* C99 or later, not C++, we can use restrict, and check for VLAs and anonymous struct members (C11) */ +/* indented preprocessor directives and // comments are also allowed here, but we'll avoid them for consistency */ +#define PLUM_RESTRICT restrict +#define PLUM_ANON_MEMBERS (__STDC_VERSION__ >= 201112L) +/* protect against really broken preprocessor implementations */ +#if !defined(__STDC_NO_VLA__) || !(__STDC_NO_VLA__ + 0) +#define PLUM_VLA_SUPPORT 1 +#else +#define PLUM_VLA_SUPPORT 0 +#endif +#elif defined(__cplusplus) +/* C++ allows anonymous unions as struct members, but not restrict or VLAs */ +#define PLUM_RESTRICT +#define PLUM_ANON_MEMBERS 1 +#define PLUM_VLA_SUPPORT 0 +#else +/* C89 (or, if we're really unlucky, non-standard C), so don't use any "advanced" C features */ +#define PLUM_RESTRICT +#define PLUM_ANON_MEMBERS 0 +#define PLUM_VLA_SUPPORT 0 +#endif + +#ifdef PLUM_NO_ANON_MEMBERS +#undef PLUM_ANON_MEMBERS +#define PLUM_ANON_MEMBERS 0 +#endif + +#ifdef PLUM_NO_VLA +#undef PLUM_VLA_SUPPORT +#define PLUM_VLA_SUPPORT 0 +#endif + +#define PLUM_MODE_FILENAME ((size_t) -1) +#define PLUM_MODE_BUFFER ((size_t) -2) +#define PLUM_MODE_CALLBACK ((size_t) -3) +#define PLUM_MAX_MEMORY_SIZE ((size_t) -4) + +/* legacy constants, for compatibility with the v0.4 API */ +#define PLUM_FILENAME PLUM_MODE_FILENAME +#define PLUM_BUFFER PLUM_MODE_BUFFER +#define PLUM_CALLBACK PLUM_MODE_CALLBACK + +enum plum_flags { + /* color formats */ + PLUM_COLOR_32 = 0, /* RGBA 8.8.8.8 */ + PLUM_COLOR_64 = 1, /* RGBA 16.16.16.16 */ + PLUM_COLOR_16 = 2, /* RGBA 5.5.5.1 */ + PLUM_COLOR_32X = 3, /* RGBA 10.10.10.2 */ + PLUM_COLOR_MASK = 3, + PLUM_ALPHA_INVERT = 4, + /* palettes */ + PLUM_PALETTE_NONE = 0, + PLUM_PALETTE_LOAD = 0x200, + PLUM_PALETTE_GENERATE = 0x400, + PLUM_PALETTE_FORCE = 0x600, + PLUM_PALETTE_MASK = 0x600, + /* palette sorting */ + PLUM_SORT_LIGHT_FIRST = 0, + PLUM_SORT_DARK_FIRST = 0x800, + /* other bit flags */ + PLUM_ALPHA_REMOVE = 0x100, + PLUM_SORT_EXISTING = 0x1000, + PLUM_PALETTE_REDUCE = 0x2000 +}; + +enum plum_image_types { + PLUM_IMAGE_NONE, + PLUM_IMAGE_BMP, + PLUM_IMAGE_GIF, + PLUM_IMAGE_PNG, + PLUM_IMAGE_APNG, + PLUM_IMAGE_JPEG, + PLUM_IMAGE_PNM, + PLUM_NUM_IMAGE_TYPES +}; + +enum plum_metadata_types { + PLUM_METADATA_NONE, + PLUM_METADATA_COLOR_DEPTH, + PLUM_METADATA_BACKGROUND, + PLUM_METADATA_LOOP_COUNT, + PLUM_METADATA_FRAME_DURATION, + PLUM_METADATA_FRAME_DISPOSAL, + PLUM_METADATA_FRAME_AREA, + PLUM_NUM_METADATA_TYPES +}; + +enum plum_frame_disposal_methods { + PLUM_DISPOSAL_NONE, + PLUM_DISPOSAL_BACKGROUND, + PLUM_DISPOSAL_PREVIOUS, + PLUM_DISPOSAL_REPLACE, + PLUM_DISPOSAL_BACKGROUND_REPLACE, + PLUM_DISPOSAL_PREVIOUS_REPLACE, + PLUM_NUM_DISPOSAL_METHODS +}; + +enum plum_errors { + PLUM_OK, + PLUM_ERR_INVALID_ARGUMENTS, + PLUM_ERR_INVALID_FILE_FORMAT, + PLUM_ERR_INVALID_METADATA, + PLUM_ERR_INVALID_COLOR_INDEX, + PLUM_ERR_TOO_MANY_COLORS, + PLUM_ERR_UNDEFINED_PALETTE, + PLUM_ERR_IMAGE_TOO_LARGE, + PLUM_ERR_NO_DATA, + PLUM_ERR_NO_MULTI_FRAME, + PLUM_ERR_FILE_INACCESSIBLE, + PLUM_ERR_FILE_ERROR, + PLUM_ERR_OUT_OF_MEMORY, + PLUM_NUM_ERRORS +}; + +#define PLUM_COLOR_VALUE_32(red, green, blue, alpha) ((uint32_t) (((uint32_t) (red) & 0xff) | (((uint32_t) (green) & 0xff) << 8) | \ + (((uint32_t) (blue) & 0xff) << 16) | (((uint32_t) (alpha) & 0xff) << 24))) +#define PLUM_COLOR_VALUE_64(red, green, blue, alpha) ((uint64_t) (((uint64_t) (red) & 0xffffu) | (((uint64_t) (green) & 0xffffu) << 16) | \ + (((uint64_t) (blue) & 0xffffu) << 32) | (((uint64_t) (alpha) & 0xffffu) << 48))) +#define PLUM_COLOR_VALUE_16(red, green, blue, alpha) ((uint16_t) (((uint16_t) (red) & 0x1f) | (((uint16_t) (green) & 0x1f) << 5) | \ + (((uint16_t) (blue) & 0x1f) << 10) | (((uint16_t) (alpha) & 1) << 15))) +#define PLUM_COLOR_VALUE_32X(red, green, blue, alpha) ((uint32_t) (((uint32_t) (red) & 0x3ff) | (((uint32_t) (green) & 0x3ff) << 10) | \ + (((uint32_t) (blue) & 0x3ff) << 20) | (((uint32_t) (alpha) & 3) << 30))) + +#define PLUM_RED_32(color) ((uint32_t) ((uint32_t) (color) & 0xff)) +#define PLUM_RED_64(color) ((uint64_t) ((uint64_t) (color) & 0xffffu)) +#define PLUM_RED_16(color) ((uint16_t) ((uint16_t) (color) & 0x1f)) +#define PLUM_RED_32X(color) ((uint32_t) ((uint32_t) (color) & 0x3ff)) +#define PLUM_GREEN_32(color) ((uint32_t) (((uint32_t) (color) >> 8) & 0xff)) +#define PLUM_GREEN_64(color) ((uint64_t) (((uint64_t) (color) >> 16) & 0xffffu)) +#define PLUM_GREEN_16(color) ((uint16_t) (((uint16_t) (color) >> 5) & 0x1f)) +#define PLUM_GREEN_32X(color) ((uint32_t) (((uint32_t) (color) >> 10) & 0x3ff)) +#define PLUM_BLUE_32(color) ((uint32_t) (((uint32_t) (color) >> 16) & 0xff)) +#define PLUM_BLUE_64(color) ((uint64_t) (((uint64_t) (color) >> 32) & 0xffffu)) +#define PLUM_BLUE_16(color) ((uint16_t) (((uint16_t) (color) >> 10) & 0x1f)) +#define PLUM_BLUE_32X(color) ((uint32_t) (((uint32_t) (color) >> 20) & 0x3ff)) +#define PLUM_ALPHA_32(color) ((uint32_t) (((uint32_t) (color) >> 24) & 0xff)) +#define PLUM_ALPHA_64(color) ((uint64_t) (((uint64_t) (color) >> 48) & 0xffffu)) +#define PLUM_ALPHA_16(color) ((uint16_t) (((uint16_t) (color) >> 15) & 1)) +#define PLUM_ALPHA_32X(color) ((uint32_t) (((uint32_t) (color) >> 30) & 3)) + +#define PLUM_RED_MASK_32 ((uint32_t) 0xff) +#define PLUM_RED_MASK_64 ((uint64_t) 0xffffu) +#define PLUM_RED_MASK_16 ((uint16_t) 0x1f) +#define PLUM_RED_MASK_32X ((uint32_t) 0x3ff) +#define PLUM_GREEN_MASK_32 ((uint32_t) 0xff00u) +#define PLUM_GREEN_MASK_64 ((uint64_t) 0xffff0000u) +#define PLUM_GREEN_MASK_16 ((uint16_t) 0x3e0) +#define PLUM_GREEN_MASK_32X ((uint32_t) 0xffc00u) +#define PLUM_BLUE_MASK_32 ((uint32_t) 0xff0000u) +#define PLUM_BLUE_MASK_64 ((uint64_t) 0xffff00000000u) +#define PLUM_BLUE_MASK_16 ((uint16_t) 0x7c00) +#define PLUM_BLUE_MASK_32X ((uint32_t) 0x3ff00000u) +#define PLUM_ALPHA_MASK_32 ((uint32_t) 0xff000000u) +#define PLUM_ALPHA_MASK_64 ((uint64_t) 0xffff000000000000u) +#define PLUM_ALPHA_MASK_16 ((uint16_t) 0x8000u) +#define PLUM_ALPHA_MASK_32X ((uint32_t) 0xc0000000u) + +#define PLUM_PIXEL_INDEX(image, col, row, frame) (((size_t) (frame) * (size_t) (image) -> height + (size_t) (row)) * (size_t) (image) -> width + (size_t) (col)) + +#define PLUM_PIXEL_8(image, col, row, frame) (((uint8_t *) (image) -> data)[PLUM_PIXEL_INDEX(image, col, row, frame)]) +#define PLUM_PIXEL_16(image, col, row, frame) (((uint16_t *) (image) -> data)[PLUM_PIXEL_INDEX(image, col, row, frame)]) +#define PLUM_PIXEL_32(image, col, row, frame) (((uint32_t *) (image) -> data)[PLUM_PIXEL_INDEX(image, col, row, frame)]) +#define PLUM_PIXEL_64(image, col, row, frame) (((uint64_t *) (image) -> data)[PLUM_PIXEL_INDEX(image, col, row, frame)]) + +#if PLUM_VLA_SUPPORT +#define PLUM_PIXEL_ARRAY_TYPE(image) ((*)[(image) -> height][(image) -> width]) +#define PLUM_PIXEL_ARRAY(declarator, image) ((* (declarator))[(image) -> height][(image) -> width]) + +#define PLUM_PIXELS_8(image) ((uint8_t PLUM_PIXEL_ARRAY_TYPE(image)) (image) -> data) +#define PLUM_PIXELS_16(image) ((uint16_t PLUM_PIXEL_ARRAY_TYPE(image)) (image) -> data) +#define PLUM_PIXELS_32(image) ((uint32_t PLUM_PIXEL_ARRAY_TYPE(image)) (image) -> data) +#define PLUM_PIXELS_64(image) ((uint64_t PLUM_PIXEL_ARRAY_TYPE(image)) (image) -> data) +#endif + +struct plum_buffer { + size_t size; + void * data; +}; + +#ifdef __cplusplus +extern "C" /* function pointer member requires an explicit extern "C" declaration to be passed safely from C++ to C */ +#endif +struct plum_callback { + int (* callback) (void * userdata, void * buffer, int size); + void * userdata; +}; + +struct plum_metadata { + int type; + size_t size; + void * data; + struct plum_metadata * next; +}; + +struct plum_image { + uint16_t type; + uint8_t max_palette_index; + uint8_t color_format; + uint32_t frames; + uint32_t height; + uint32_t width; + void * allocator; + struct plum_metadata * metadata; +#if PLUM_ANON_MEMBERS + union { +#endif + void * palette; +#if PLUM_ANON_MEMBERS + uint16_t * palette16; + uint32_t * palette32; + uint64_t * palette64; + }; + union { +#endif + void * data; +#if PLUM_ANON_MEMBERS + uint8_t * data8; + uint16_t * data16; + uint32_t * data32; + uint64_t * data64; + }; +#endif + void * userdata; +#ifdef __cplusplus +inline uint8_t & pixel8 (uint32_t col, uint32_t row, uint32_t frame = 0) { + return ((uint8_t *) this -> data)[PLUM_PIXEL_INDEX(this, col, row, frame)]; +} + +inline const uint8_t & pixel8 (uint32_t col, uint32_t row, uint32_t frame = 0) const { + return ((const uint8_t *) this -> data)[PLUM_PIXEL_INDEX(this, col, row, frame)]; +} + +inline uint16_t & pixel16 (uint32_t col, uint32_t row, uint32_t frame = 0) { + return ((uint16_t *) this -> data)[PLUM_PIXEL_INDEX(this, col, row, frame)]; +} + +inline const uint16_t & pixel16 (uint32_t col, uint32_t row, uint32_t frame = 0) const { + return ((const uint16_t *) this -> data)[PLUM_PIXEL_INDEX(this, col, row, frame)]; +} + +inline uint32_t & pixel32 (uint32_t col, uint32_t row, uint32_t frame = 0) { + return ((uint32_t *) this -> data)[PLUM_PIXEL_INDEX(this, col, row, frame)]; +} + +inline const uint32_t & pixel32 (uint32_t col, uint32_t row, uint32_t frame = 0) const { + return ((const uint32_t *) this -> data)[PLUM_PIXEL_INDEX(this, col, row, frame)]; +} + +inline uint64_t & pixel64 (uint32_t col, uint32_t row, uint32_t frame = 0) { + return ((uint64_t *) this -> data)[PLUM_PIXEL_INDEX(this, col, row, frame)]; +} + +inline const uint64_t & pixel64 (uint32_t col, uint32_t row, uint32_t frame = 0) const { + return ((const uint64_t *) this -> data)[PLUM_PIXEL_INDEX(this, col, row, frame)]; +} + +inline uint16_t & color16 (uint8_t index) { + return ((uint16_t *) this -> palette)[index]; +} + +inline const uint16_t & color16 (uint8_t index) const { + return ((const uint16_t *) this -> palette)[index]; +} + +inline uint32_t & color32 (uint8_t index) { + return ((uint32_t *) this -> palette)[index]; +} + +inline const uint32_t & color32 (uint8_t index) const { + return ((const uint32_t *) this -> palette)[index]; +} + +inline uint64_t & color64 (uint8_t index) { + return ((uint64_t *) this -> palette)[index]; +} + +inline const uint64_t & color64 (uint8_t index) const { + return ((const uint64_t *) this -> palette)[index]; +} +#endif +}; + +struct plum_rectangle { + uint32_t left; + uint32_t top; + uint32_t width; + uint32_t height; +}; + +/* keep declarations readable: redefine the "restrict" keyword, and undefine it later + (note that, if this expands to "#define restrict restrict", that will NOT expand recursively) */ +#define restrict PLUM_RESTRICT + +#ifdef __cplusplus +extern "C" { +#endif + +struct plum_image * plum_new_image(void); +struct plum_image * plum_copy_image(const struct plum_image * image); +void plum_destroy_image(struct plum_image * image); +struct plum_image * plum_load_image(const void * restrict buffer, size_t size_mode, unsigned flags, unsigned * restrict error); +struct plum_image * plum_load_image_limited(const void * restrict buffer, size_t size_mode, unsigned flags, size_t limit, unsigned * restrict error); +size_t plum_store_image(const struct plum_image * image, void * restrict buffer, size_t size_mode, unsigned * restrict error); +unsigned plum_validate_image(const struct plum_image * image); +const char * plum_get_error_text(unsigned error); +const char * plum_get_file_format_name(unsigned format); +uint32_t plum_get_version_number(void); +int plum_check_valid_image_size(uint32_t width, uint32_t height, uint32_t frames); +int plum_check_limited_image_size(uint32_t width, uint32_t height, uint32_t frames, size_t limit); +size_t plum_color_buffer_size(size_t size, unsigned flags); +size_t plum_pixel_buffer_size(const struct plum_image * image); +size_t plum_palette_buffer_size(const struct plum_image * image); +unsigned plum_rotate_image(struct plum_image * image, unsigned count, int flip); +void plum_convert_colors(void * restrict destination, const void * restrict source, size_t count, unsigned to, unsigned from); +uint64_t plum_convert_color(uint64_t color, unsigned from, unsigned to); +void plum_remove_alpha(struct plum_image * image); +unsigned plum_sort_palette(struct plum_image * image, unsigned flags); +unsigned plum_sort_palette_custom(struct plum_image * image, uint64_t (* callback) (void *, uint64_t), void * argument, unsigned flags); +unsigned plum_reduce_palette(struct plum_image * image); +const uint8_t * plum_validate_palette_indexes(const struct plum_image * image); +int plum_get_highest_palette_index(const struct plum_image * image); +int plum_convert_colors_to_indexes(uint8_t * restrict destination, const void * restrict source, void * restrict palette, size_t count, unsigned flags); +void plum_convert_indexes_to_colors(void * restrict destination, const uint8_t * restrict source, const void * restrict palette, size_t count, unsigned flags); +void plum_sort_colors(const void * restrict colors, uint8_t max_index, unsigned flags, uint8_t * restrict result); +void * plum_malloc(struct plum_image * image, size_t size); +void * plum_calloc(struct plum_image * image, size_t size); +void * plum_realloc(struct plum_image * image, void * buffer, size_t size); +void plum_free(struct plum_image * image, void * buffer); +struct plum_metadata * plum_allocate_metadata(struct plum_image * image, size_t size); +unsigned plum_append_metadata(struct plum_image * image, int type, const void * data, size_t size); +struct plum_metadata * plum_find_metadata(const struct plum_image * image, int type); + +#ifdef __cplusplus +} +#endif + +#undef restrict + +/* if PLUM_UNPREFIXED_MACROS is defined, include shorter, unprefixed alternatives for some common macros */ +/* this requires an explicit opt-in because it violates the principle of a library prefix as a namespace */ +#ifdef PLUM_UNPREFIXED_MACROS +#define PIXEL(image, col, row, frame) PLUM_PIXEL_INDEX(image, col, row, frame) + +#define PIXEL8(image, col, row, frame) PLUM_PIXEL_8(image, col, row, frame) +#define PIXEL16(image, col, row, frame) PLUM_PIXEL_16(image, col, row, frame) +#define PIXEL32(image, col, row, frame) PLUM_PIXEL_32(image, col, row, frame) +#define PIXEL64(image, col, row, frame) PLUM_PIXEL_64(image, col, row, frame) + +#if PLUM_VLA_SUPPORT +#define PIXARRAY_T(image) PLUM_PIXEL_ARRAY_TYPE(image) +#define PIXARRAY(declarator, image) PLUM_PIXEL_ARRAY(declarator, image) + +#define PIXELS8(image) PLUM_PIXELS_8(image) +#define PIXELS16(image) PLUM_PIXELS_16(image) +#define PIXELS32(image) PLUM_PIXELS_32(image) +#define PIXELS64(image) PLUM_PIXELS_64(image) +#endif + +#define COLOR32(red, green, blue, alpha) PLUM_COLOR_VALUE_32(red, green, blue, alpha) +#define COLOR64(red, green, blue, alpha) PLUM_COLOR_VALUE_64(red, green, blue, alpha) +#define COLOR16(red, green, blue, alpha) PLUM_COLOR_VALUE_16(red, green, blue, alpha) +#define COLOR32X(red, green, blue, alpha) PLUM_COLOR_VALUE_32X(red, green, blue, alpha) + +#define RED32(color) PLUM_RED_32(color) +#define RED64(color) PLUM_RED_64(color) +#define RED16(color) PLUM_RED_16(color) +#define RED32X(color) PLUM_RED_32X(color) +#define GREEN32(color) PLUM_GREEN_32(color) +#define GREEN64(color) PLUM_GREEN_64(color) +#define GREEN16(color) PLUM_GREEN_16(color) +#define GREEN32X(color) PLUM_GREEN_32X(color) +#define BLUE32(color) PLUM_BLUE_32(color) +#define BLUE64(color) PLUM_BLUE_64(color) +#define BLUE16(color) PLUM_BLUE_16(color) +#define BLUE32X(color) PLUM_BLUE_32X(color) +#define ALPHA32(color) PLUM_ALPHA_32(color) +#define ALPHA64(color) PLUM_ALPHA_64(color) +#define ALPHA16(color) PLUM_ALPHA_16(color) +#define ALPHA32X(color) PLUM_ALPHA_32X(color) +#endif + +#endif -- cgit 1.4.1-2-gfad0