diff --git a/CMakeLists.txt b/CMakeLists.txt index ad37da7..2519a8f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -159,6 +159,7 @@ set(SOURCES_CG src/r61524/r61524.c # Image library src/image/image_alloc.c + src/image/image_alloc_palette.c src/image/image_alpha.c src/image/image_clear.c src/image/image_copy.c @@ -171,11 +172,15 @@ set(SOURCES_CG src/image/image_fill.c src/image/image_free.c src/image/image_get_pixel.c - src/image/image_palette_size.c + src/image/image_hflip.c + src/image/image_hflip_alloc.c + src/image/image_set_palette.c src/image/image_set_pixel.c src/image/image_sub.c src/image/image_target.c src/image/image_valid.c + src/image/image_vflip.c + src/image/image_vflip_alloc.c # Rendering src/render-cg/dclear.c src/render-cg/dpixel.c diff --git a/include/gint/image.h b/include/gint/image.h index 42519bb..e6aad53 100644 --- a/include/gint/image.h +++ b/include/gint/image.h @@ -314,11 +314,6 @@ int image_decode_pixel(image_t const *img, int pixel); image's data array, and might be much larger than the sub-image. */ int image_data_size(image_t const *img); -/* image_palette_size(): Compute the size of the [palette] array - This function returns the size of the palette array, in bytes. This can be - used to duplicate the palette. For images without a palette, returns -1. */ -int image_palette_size(image_t const *img); - //--- // Basic image modifications //--- @@ -457,6 +452,10 @@ image_t *image_sub(image_t const *src, int x, int y, int w, int h, void image_hflip(image_t const *src, image_t *dst); image_t *image_hflip_alloc(image_t const *src); +/* image_vflip(): Flip vertically (supports in-place) */ +void image_vflip(image_t const *src, image_t *dst); +image_t *image_vflip_alloc(image_t const *src); + /* TODO: Geometric transforms */ //--- diff --git a/src/image/image_alloc_palette.c b/src/image/image_alloc_palette.c index 1afe5a2..040ba2e 100644 --- a/src/image/image_alloc_palette.c +++ b/src/image/image_alloc_palette.c @@ -1,30 +1,31 @@ #include #include #include +#include bool image_alloc_palette(image_t *img, int size) { - if(!img || !IMAGE_IS_INDEXED(img)) - return; - if(img->flags & IMAGE_FLAGS_PALETTE_OWN) + if(!img || !IMAGE_IS_INDEXED(img->format)) + return false; + if(img->flags & IMAGE_FLAGS_PALETTE_ALLOC) free(img->palette); - if(IMAGE_IS_P8(img)) { + if(IMAGE_IS_P8(img->format)) { size = (size <= 0) ? 256 : min(size, 256); } - if(IMAGE_IS_P4(img)) { + if(IMAGE_IS_P4(img->format)) { size = 16; } img->palette = calloc(size, 2); img->color_count = 0; - img->flags &= ~IMAGE_FLAGS_PALETTE_OWN; + img->flags &= ~IMAGE_FLAGS_PALETTE_ALLOC; if(!img->palette) return false; memset(img->palette, 0, 2*size); img->color_count = size; - img->flags |= IMAGE_FLAGS_PALETTE_OWN; + img->flags |= IMAGE_FLAGS_PALETTE_ALLOC; return true; } diff --git a/src/image/image_hflip.c b/src/image/image_hflip.c new file mode 100644 index 0000000..4a540c1 --- /dev/null +++ b/src/image/image_hflip.c @@ -0,0 +1,47 @@ +#include + +void image_hflip(image_t const *src, image_t *dst) +{ + if(!image_target(src, dst, DATA_RW, SAME_DEPTH, SAME_SIZE)) + return; + + void *src_px = src->data; + void *dst_px = dst->data; + int src_alpha = image_alpha(src->format); + int dst_alpha = image_alpha(dst->format); + int h = src->height; + + if(IMAGE_IS_RGB16(src->format)) { + while(h-- > 0) { + for(int x1 = 0; x1 < (src->width + 1) >> 1; x1++) { + int x2 = src->width - 1 - x1; + int px1 = ((uint16_t *)src_px)[x1]; + int px2 = ((uint16_t *)src_px)[x2]; + + if(px1 != src_alpha) + ((uint16_t *)dst_px)[x2] = px1 - (px1 == dst_alpha); + if(px2 != src_alpha) + ((uint16_t *)dst_px)[x1] = px2 - (px2 == dst_alpha); + } + src_px += src->stride; + dst_px += dst->stride; + } + } + else if(IMAGE_IS_P8(src->format)) { + while(h-- > 0) { + for(int x1 = 0; x1 < (src->width + 1) >> 1; x1++) { + int x2 = src->width - 1 - x1; + + int px1 = ((int8_t *)src_px)[x1]; + int px2 = ((int8_t *)src_px)[x2]; + + if(px1 != src_alpha) + ((int8_t *)dst_px)[x2] = px1; + if(px2 != src_alpha) + ((int8_t *)dst_px)[x1] = px2; + } + src_px += src->stride; + dst_px += dst->stride; + } + } +} diff --git a/src/image/image_hflip_alloc.c b/src/image/image_hflip_alloc.c new file mode 100644 index 0000000..6d9f0fc --- /dev/null +++ b/src/image/image_hflip_alloc.c @@ -0,0 +1,17 @@ +#include + +image_t *image_hflip_alloc(image_t const *src) +{ + if(!image_valid(src)) + return NULL; + + image_t *dst = image_alloc(src->width, src->height, src->format); + if(!dst || !image_copy_palette(src, dst, -1)) { + image_free(dst); + return NULL; + } + + image_clear(dst); + image_hflip(src, dst); + return dst; +} diff --git a/src/image/image_palette_size.c b/src/image/image_palette_size.c deleted file mode 100644 index 2953059..0000000 --- a/src/image/image_palette_size.c +++ /dev/null @@ -1,7 +0,0 @@ -#include - -int image_palette_size(image_t const *img) -{ - return (img->color_count >= 0) ? img->color_count* 2 : -1; -} - diff --git a/src/image/image_set_palette.c b/src/image/image_set_palette.c index 021b823..4da4f2c 100644 --- a/src/image/image_set_palette.c +++ b/src/image/image_set_palette.c @@ -3,16 +3,16 @@ void image_set_palette(image_t *img, uint16_t *palette, int size, bool owns) { - if(!img || !IMAGE_IS_INDEXED(img)) + if(!img || !IMAGE_IS_INDEXED(img->format)) return; - if(img->flags & IMAGE_FLAGS_PALETTE_OWN) + if(img->flags & IMAGE_FLAGS_PALETTE_ALLOC) free(img->palette); img->palette = palette; img->color_count = size; if(owns) - img->flags |= IMAGE_FLAGS_PALETTE_OWN; + img->flags |= IMAGE_FLAGS_PALETTE_ALLOC; else - img->flags &= ~IMAGE_FLAGS_PALETTE_OWN; + img->flags &= ~IMAGE_FLAGS_PALETTE_ALLOC; } diff --git a/src/image/image_vflip.c b/src/image/image_vflip.c new file mode 100644 index 0000000..1c4f324 --- /dev/null +++ b/src/image/image_vflip.c @@ -0,0 +1,62 @@ +#include +#include +#include + +static void copy_row_rgb16(uint16_t *src, uint16_t *dst, int src_alpha, + int dst_alpha, int width) +{ + for(int x = 0; x < width; x++) { + int px = src[x]; + if(px != src_alpha) + dst[x] = px - (px == dst_alpha); + } +} + +static void copy_row_p8(int8_t *src, int8_t *dst, int src_alpha, int width) +{ + for(int x = 0; x < width; x++) { + int px = src[x]; + if(px != src_alpha) + dst[x] = px; + } +} + +void image_vflip(image_t const *src, image_t *dst) +{ + if(!image_target(src, dst, DATA_RW, SAME_DEPTH, SAME_SIZE)) + return; + + int h = src->height; + void *src_top = src->data; + void *src_bot = src->data + (h - 1) * src->stride; + void *dst_top = dst->data; + void *dst_bot = dst->data + (h - 1) * dst->stride; + + int src_alpha = image_alpha(src->format); + int dst_alpha = image_alpha(dst->format); + + int row_length = src->stride; + void *row = malloc(row_length); + if(!row) + return; + + for(int y = 0; y < (h + 1) >> 1; y++) { + memcpy(row, src_top, row_length); + + if(IMAGE_IS_RGB16(src->format)) { + copy_row_rgb16(src_bot, dst_top, src_alpha, dst_alpha, src->width); + copy_row_rgb16(row, dst_bot, src_alpha, dst_alpha, src->width); + } + else { + copy_row_p8(src_bot, dst_top, src_alpha, src->width); + copy_row_p8(row, dst_bot, src_alpha, src->width); + } + + src_top += src->stride; + src_bot -= src->stride; + dst_top += dst->stride; + dst_bot -= dst->stride; + } + + free(row); +} diff --git a/src/image/image_vflip_alloc.c b/src/image/image_vflip_alloc.c new file mode 100644 index 0000000..ef26c91 --- /dev/null +++ b/src/image/image_vflip_alloc.c @@ -0,0 +1,17 @@ +#include + +image_t *image_vflip_alloc(image_t const *src) +{ + if(!image_valid(src)) + return NULL; + + image_t *dst = image_alloc(src->width, src->height, src->format); + if(!dst || !image_copy_palette(src, dst, -1)) { + image_free(dst); + return NULL; + } + + image_clear(dst); + image_vflip(src, dst); + return dst; +}