From de7f7b384c07a3ee82aa7bd11b93a79558ea1e65 Mon Sep 17 00:00:00 2001 From: Rangi42 Date: Tue, 28 Nov 2023 22:04:22 -0500 Subject: [PATCH] Miscellaneous refactoring --- src/bmpwrite.c | 12 ++-- src/color.c | 44 +++++++-------- src/framebounds.c | 67 +++++++++------------- src/gifwrite.c | 139 ++++++++++++++++------------------------------ src/inline.h | 2 +- src/pngcompress.c | 2 +- src/pngwrite.c | 4 +- src/store.c | 22 ++++---- 8 files changed, 116 insertions(+), 176 deletions(-) diff --git a/src/bmpwrite.c b/src/bmpwrite.c index f22487c..3b0ecec 100644 --- a/src/bmpwrite.c +++ b/src/bmpwrite.c @@ -337,22 +337,22 @@ void generate_BMP_RGB_data (struct context * context, unsigned char * offset_poi if ((context -> source -> color_format & PLUM_COLOR_MASK) == PLUM_COLOR_32) data = context -> source -> data; else { - data = ctxmalloc(context, sizeof *data * context -> source -> width * context -> source -> height); - plum_convert_colors(data, context -> source -> data, (size_t) context -> source -> width * context -> source -> height, - PLUM_COLOR_32, context -> source -> color_format); + size_t size = (size_t) context -> source -> width * context -> source -> height; + data = ctxmalloc(context, sizeof *data * size); + plum_convert_colors(data, context -> source -> data, size, PLUM_COLOR_32, context -> source -> color_format); } size_t rowsize = (size_t) context -> source -> width * 3, padding = 0; if (rowsize & 3) { padding = 4 - (rowsize & 3); rowsize += padding; } - unsigned char * out = append_output_node(context, rowsize * context -> source -> height); + unsigned char * output = append_output_node(context, rowsize * context -> source -> height); uint_fast32_t row = context -> source -> height - 1; do { size_t pos = (size_t) row * context -> source -> width; for (uint_fast32_t remaining = context -> source -> width; remaining; pos ++, remaining --) - out += byteappend(out, data[pos] >> 16, data[pos] >> 8, data[pos]); - for (uint_fast32_t p = 0; p < padding; p ++) *(out ++) = 0; + output += byteappend(output, data[pos] >> 16, data[pos] >> 8, data[pos]); + for (uint_fast32_t p = 0; p < padding; p ++) *(output ++) = 0; } while (row --); if (data != context -> source -> data) ctxfree(context, data); } diff --git a/src/color.c b/src/color.c index a52eaff..40e89ca 100644 --- a/src/color.c +++ b/src/color.c @@ -1,28 +1,26 @@ #include "proto.h" +#define formatpair(from, to) (((from) << 2) & (PLUM_COLOR_MASK << 2) | (to) & PLUM_COLOR_MASK) + void plum_convert_colors (void * restrict destination, const void * restrict source, size_t count, unsigned long to, unsigned long from) { if (!(source && destination && count)) return; - if ((from & (PLUM_COLOR_MASK | PLUM_ALPHA_INVERT)) == (to & (PLUM_COLOR_MASK | PLUM_ALPHA_INVERT))) { - memcpy(destination, source, plum_color_buffer_size(count, to)); - return; - } - #define convert(sp) do \ - if ((to & PLUM_COLOR_MASK) == PLUM_COLOR_16) \ - for (uint16_t * dp = destination; count; count --) *(dp ++) = plum_convert_color(*(sp ++), from, to); \ - else if ((to & PLUM_COLOR_MASK) == PLUM_COLOR_64) \ - for (uint64_t * dp = destination; count; count --) *(dp ++) = plum_convert_color(*(sp ++), from, to); \ - else \ - for (uint32_t * dp = destination; count; count --) *(dp ++) = plum_convert_color(*(sp ++), from, to); \ - while (false) - if ((from & PLUM_COLOR_MASK) == PLUM_COLOR_16) { - const uint16_t * sp = source; - convert(sp); - } else if ((from & PLUM_COLOR_MASK) == PLUM_COLOR_64) { - const uint64_t * sp = source; - convert(sp); - } else { - const uint32_t * sp = source; - convert(sp); + #define convert(frombits, tobits) do { \ + const uint ## frombits ## _t * sp = source; \ + uint ## tobits ## _t * dp = destination; \ + while (count --) *(dp ++) = plum_convert_color(*(sp ++), from, to); \ + } while (false) + switch (formatpair(from, to)) { + case formatpair(PLUM_COLOR_16, PLUM_COLOR_64): convert(16, 64); break; + case formatpair(PLUM_COLOR_64, PLUM_COLOR_16): convert(64, 16); break; + case formatpair(PLUM_COLOR_16, PLUM_COLOR_32X): + case formatpair(PLUM_COLOR_16, PLUM_COLOR_32): convert(16, 32); break; + case formatpair(PLUM_COLOR_64, PLUM_COLOR_32): + case formatpair(PLUM_COLOR_64, PLUM_COLOR_32X): convert(64, 32); break; + case formatpair(PLUM_COLOR_32, PLUM_COLOR_16): + case formatpair(PLUM_COLOR_32X, PLUM_COLOR_16): convert(32, 16); break; + case formatpair(PLUM_COLOR_32, PLUM_COLOR_64): + case formatpair(PLUM_COLOR_32X, PLUM_COLOR_64): convert(32, 64); break; + default: memcpy(destination, source, plum_color_buffer_size(count, to)); } #undef convert } @@ -34,7 +32,6 @@ uint64_t plum_convert_color (uint64_t color, unsigned long from, unsigned long t from &= 0xffffu; else if ((from & PLUM_COLOR_MASK) != PLUM_COLOR_64) from &= 0xffffffffu; - #define formatpair(from, to) (((from) << 2) & (PLUM_COLOR_MASK << 2) | (to) & PLUM_COLOR_MASK) switch (formatpair(from, to)) { case formatpair(PLUM_COLOR_32, PLUM_COLOR_32): case formatpair(PLUM_COLOR_64, PLUM_COLOR_64): @@ -82,11 +79,12 @@ uint64_t plum_convert_color (uint64_t color, unsigned long from, unsigned long t case formatpair(PLUM_COLOR_32X, PLUM_COLOR_16): result = ((color >> 5) & 0x1f) | ((color >> 10) & 0x3e0) | ((color >> 15) & 0x7c00) | ((color >> 16) & 0x8000u); } - #undef formatpair if ((to ^ from) & PLUM_ALPHA_INVERT) result ^= alpha_component_masks[to & PLUM_COLOR_MASK]; return result; } +#undef formatpair + void plum_remove_alpha (struct plum_image * image) { if (!(image && image -> data && plum_check_valid_image_size(image -> width, image -> height, image -> frames))) return; void * colordata; diff --git a/src/framebounds.c b/src/framebounds.c index c9419fd..67c85a1 100644 --- a/src/framebounds.c +++ b/src/framebounds.c @@ -21,6 +21,26 @@ struct plum_rectangle * get_frame_boundaries (struct context * context, bool anc void adjust_frame_boundaries (const struct plum_image * image, struct plum_rectangle * restrict boundaries) { uint64_t empty_color = get_empty_color(image); + #define checkframe(type) do \ + for (uint_fast32_t frame = 0; frame < image -> frames; frame ++) { \ + for (size_t remaining = (size_t) boundaries[frame].top * image -> width; remaining; remaining --) \ + if (notempty(type)) goto done ## type; \ + if (boundaries[frame].left || boundaries[frame].width != image -> width) \ + for (uint_fast32_t row = 0; row < boundaries[frame].height; row ++) { \ + for (uint_fast32_t col = 0; col < boundaries[frame].left; col ++) if (notempty(type)) goto done ## type; \ + index += boundaries[frame].width; \ + for (uint_fast32_t col = boundaries[frame].left + boundaries[frame].width; col < image -> width; col ++) \ + if (notempty(type)) goto done ## type; \ + } \ + else \ + index += (size_t) boundaries[frame].height * image -> width; \ + for (size_t remaining = (size_t) (image -> height - boundaries[frame].top - boundaries[frame].height) * image -> width; remaining; remaining --) \ + if (notempty(type)) goto done ## type; \ + continue; \ + done ## type: \ + boundaries[frame] = (struct plum_rectangle) {.left = 0, .top = 0, .width = image -> width, .height = image -> height}; \ + } \ + while (false) if (image -> palette) { bool empty[256]; switch (image -> color_format & PLUM_COLOR_MASK) { @@ -34,55 +54,20 @@ void adjust_frame_boundaries (const struct plum_image * image, struct plum_recta for (size_t p = 0; p <= image -> max_palette_index; p ++) empty[p] = image -> palette32[p] == empty_color; } size_t index = 0; - for (uint_fast32_t frame = 0; frame < image -> frames; frame ++) { - bool adjust = true; - for (size_t remaining = (size_t) boundaries[frame].top * image -> width; remaining; remaining --) - if (!empty[image -> data8[index ++]]) goto paldone; - if (boundaries[frame].left || boundaries[frame].width != image -> width) - for (uint_fast32_t row = 0; row < boundaries[frame].height; row ++) { - for (uint_fast32_t col = 0; col < boundaries[frame].left; col ++) if (!empty[image -> data8[index ++]]) goto paldone; - index += boundaries[frame].width; - for (uint_fast32_t col = boundaries[frame].left + boundaries[frame].width; col < image -> width; col ++) - if (!empty[image -> data8[index ++]]) goto paldone; - } - else - index += (size_t) boundaries[frame].height * image -> width; - for (size_t remaining = (size_t) (image -> height - boundaries[frame].top - boundaries[frame].height) * image -> width; remaining; remaining --) - if (!empty[image -> data8[index ++]]) goto paldone; - adjust = false; - paldone: - if (adjust) boundaries[frame] = (struct plum_rectangle) {.left = 0, .top = 0, .width = image -> width, .height = image -> height}; - } + #define notempty(...) (!empty[image -> data8[index ++]]) + checkframe(pal); } else { size_t index = 0; - #define checkframe(bits) do \ - for (uint_fast32_t frame = 0; frame < image -> frames; frame ++) { \ - bool adjust = true; \ - for (size_t remaining = (size_t) boundaries[frame].top * image -> width; remaining; remaining --) \ - if (image -> data ## bits[index ++] != empty_color) goto done ## bits; \ - if (boundaries[frame].left || boundaries[frame].width != image -> width) \ - for (uint_fast32_t row = 0; row < boundaries[frame].height; row ++) { \ - for (uint_fast32_t col = 0; col < boundaries[frame].left; col ++) if (image -> data ## bits[index ++] != empty_color) goto done ## bits; \ - index += boundaries[frame].width; \ - for (uint_fast32_t col = boundaries[frame].left + boundaries[frame].width; col < image -> width; col ++) \ - if (image -> data ## bits[index ++] != empty_color) goto done ## bits; \ - } \ - else \ - index += (size_t) boundaries[frame].height * image -> width; \ - for (size_t remaining = (size_t) (image -> height - boundaries[frame].top - boundaries[frame].height) * image -> width; remaining; remaining --) \ - if (image -> data ## bits[index ++] != empty_color) goto done ## bits; \ - adjust = false; \ - done ## bits: \ - if (adjust) boundaries[frame] = (struct plum_rectangle) {.left = 0, .top = 0, .width = image -> width, .height = image -> height}; \ - } \ - while (false) + #undef notempty + #define notempty(bits) (image -> data ## bits[index ++] != empty_color) switch (image -> color_format & PLUM_COLOR_MASK) { case PLUM_COLOR_16: checkframe(16); break; case PLUM_COLOR_64: checkframe(64); break; default: checkframe(32); } - #undef checkframe } + #undef notempty + #undef checkframe } bool image_rectangles_have_transparency (const struct plum_image * image, const struct plum_rectangle * rectangles) { diff --git a/src/gifwrite.c b/src/gifwrite.c index 6036185..c3d3104 100644 --- a/src/gifwrite.c +++ b/src/gifwrite.c @@ -12,8 +12,7 @@ void generate_GIF_data (struct context * context) { if ((uint8_t) (depth >> 8) > overall) overall = depth >> 8; if ((uint8_t) (depth >> 16) > overall) overall = depth >> 16; if (overall > 8) overall = 8; - header[4] = (overall - 1) << 4; - header[5] = header[6] = 0; + bytewrite(header + 4, (overall - 1) << 4, 0, 0); if (context -> source -> palette) generate_GIF_data_with_palette(context, header); else @@ -21,6 +20,50 @@ void generate_GIF_data (struct context * context) { byteoutput(context, 0x3b); } +#define checkboundaries(buffertype, buffer, frame) do { \ + size_t index = 0; \ + if (boundaries) { \ + while (index < context -> source -> width * boundaries[frame].top) if (buffer[index ++] != transparent) goto findbounds; \ + for (uint_fast16_t row = 0; row < boundaries[frame].height; row ++) { \ + for (uint_fast16_t col = 0; col < boundaries[frame].left; col ++) if (buffer[index ++] != transparent) goto findbounds; \ + index += boundaries[frame].width; \ + for (uint_fast16_t col = boundaries[frame].left + boundaries[frame].width; col < context -> source -> width; col ++) \ + if (buffer[index ++] != transparent) goto findbounds; \ + } \ + while (index < framesize) if (buffer[index ++] != transparent) goto findbounds; \ + left = boundaries[frame].left; \ + top = boundaries[frame].top; \ + width = boundaries[frame].width; \ + height = boundaries[frame].height; \ + } else { \ + findbounds: \ + for (index = 0; index < framesize; index ++) if (buffer[index] != transparent) break; \ + if (index == framesize) \ + width = height = 1; \ + else { \ + top = index / width; \ + height -= top; \ + for (index = 0; index < framesize; index ++) if (buffer[framesize - 1 - index] != transparent) break; \ + height -= index / width; \ + for (left = 0; left < width; left ++) for (index = top; index < top + height; index ++) \ + if (buffer[index * context -> source -> width + left] != transparent) goto leftdone; \ + leftdone: \ + width -= left; \ + uint_fast16_t col; \ + for (col = 0; col < width; col ++) for (index = top; index < top + height; index ++) \ + if (buffer[(index + 1) * context -> source -> width - 1 - col] != transparent) goto rightdone; \ + rightdone: \ + width -= col; \ + } \ + } \ + if (left || width != context -> source -> width) { \ + buffertype * target = buffer; \ + for (uint_fast16_t row = 0; row < height; row ++) for (uint_fast16_t col = 0; col < width; col ++) \ + *(target ++) = buffer[context -> source -> width * (row + top) + col + left]; \ + } else if (top) \ + memmove(buffer, buffer + context -> source -> width * top, sizeof *buffer * context -> source -> width * height); \ +} while (false) + void generate_GIF_data_with_palette (struct context * context, unsigned char * header) { uint_fast16_t colors = context -> source -> max_palette_index + 1; uint32_t * palette = ctxcalloc(context, 256 * sizeof *palette); @@ -66,50 +109,7 @@ void generate_GIF_data_with_palette (struct context * context, unsigned char * h else memcpy(framebuffer, context -> source -> data8 + frame * framesize, framesize); uint_fast16_t left = 0, top = 0, width = context -> source -> width, height = context -> source -> height; - if (transparent >= 0) { - size_t index = 0; - if (boundaries) { - while (index < context -> source -> width * boundaries[frame].top) if (framebuffer[index ++] != transparent) goto findbounds; - for (uint_fast16_t row = 0; row < boundaries[frame].height; row ++) { - for (uint_fast16_t col = 0; col < boundaries[frame].left; col ++) if (framebuffer[index ++] != transparent) goto findbounds; - index += boundaries[frame].width; - for (uint_fast16_t col = boundaries[frame].left + boundaries[frame].width; col < context -> source -> width; col ++) - if (framebuffer[index ++] != transparent) goto findbounds; - } - while (index < framesize) if (framebuffer[index ++] != transparent) goto findbounds; - left = boundaries[frame].left; - top = boundaries[frame].top; - width = boundaries[frame].width; - height = boundaries[frame].height; - goto gotbounds; - } - findbounds: - for (index = 0; index < framesize; index ++) if (framebuffer[index] != transparent) break; - if (index == framesize) - width = height = 1; - else { - top = index / width; - height -= top; - for (index = 0; index < framesize; index ++) if (framebuffer[framesize - 1 - index] != transparent) break; - height -= index / width; - for (left = 0; left < width; left ++) for (index = top; index < top + height; index ++) - if (framebuffer[index * context -> source -> width + left] != transparent) goto leftdone; - leftdone: - width -= left; - uint_fast16_t col; - for (col = 0; col < width; col ++) for (index = top; index < top + height; index ++) - if (framebuffer[(index + 1) * context -> source -> width - 1 - col] != transparent) goto rightdone; - rightdone: - width -= col; - } - gotbounds: - if (left || width != context -> source -> width) { - unsigned char * target = framebuffer; - for (uint_fast16_t row = 0; row < height; row ++) for (uint_fast16_t col = 0; col < width; col ++) - *(target ++) = framebuffer[context -> source -> width * (row + top) + col + left]; - } else if (top) - memmove(framebuffer, framebuffer + context -> source -> width * top, context -> source -> width * height); - } + if (transparent >= 0) checkboundaries(unsigned char, framebuffer, frame); write_GIF_frame(context, framebuffer, NULL, colorcount, transparent, frame, left, top, width, height, durations, disposals, &duration_remainder); } ctxfree(context, boundaries); @@ -153,50 +153,7 @@ void generate_GIF_frame_data (struct context * context, uint32_t * restrict pixe } else pixels[index] &= 0xffffffu; uint_fast16_t left = 0, top = 0, width = context -> source -> width, height = context -> source -> height; - if (transparent) { - size_t index = 0; - if (boundaries) { - while (index < context -> source -> width * boundaries -> top) if (pixels[index ++] != transparent) goto findbounds; - for (uint_fast16_t row = 0; row < boundaries -> height; row ++) { - for (uint_fast16_t col = 0; col < boundaries -> left; col ++) if (pixels[index ++] != transparent) goto findbounds; - index += boundaries -> width; - for (uint_fast16_t col = boundaries -> left + boundaries -> width; col < context -> source -> width; col ++) - if (pixels[index ++] != transparent) goto findbounds; - } - while (index < framesize) if (pixels[index ++] != transparent) goto findbounds; - left = boundaries -> left; - top = boundaries -> top; - width = boundaries -> width; - height = boundaries -> height; - goto gotbounds; - } - findbounds: - for (index = 0; index < framesize; index ++) if (pixels[index] != transparent) break; - if (index == framesize) - width = height = 1; - else { - top = index / width; - height -= top; - for (index = 0; index < framesize; index ++) if (pixels[framesize - 1 - index] != transparent) break; - height -= index / width; - for (left = 0; left < width; left ++) for (index = top; index < top + height; index ++) - if (pixels[index * context -> source -> width + left] != transparent) goto leftdone; - leftdone: - width -= left; - uint_fast16_t col; - for (col = 0; col < width; col ++) for (index = top; index < top + height; index ++) - if (pixels[(index + 1) * context -> source -> width - 1 - col] != transparent) goto rightdone; - rightdone: - width -= col; - } - gotbounds: - if (left || width != context -> source -> width) { - uint32_t * target = pixels; - for (uint_fast16_t row = 0; row < height; row ++) for (uint_fast16_t col = 0; col < width; col ++) - *(target ++) = pixels[context -> source -> width * (row + top) + col + left]; - } else if (top) - memmove(pixels, pixels + context -> source -> width * top, sizeof *pixels * context -> source -> width * height); - } + if (transparent) checkboundaries(uint32_t, pixels, 0); uint32_t * palette = ctxcalloc(context, 256 * sizeof *palette); int colorcount = plum_convert_colors_to_indexes(framebuffer, pixels, palette, (size_t) width * height, PLUM_COLOR_32); if (colorcount < 0) throw(context, -colorcount); @@ -210,6 +167,8 @@ void generate_GIF_frame_data (struct context * context, uint32_t * restrict pixe ctxfree(context, palette); } +#undef checkboundaries + int_fast32_t get_GIF_background_color (struct context * context) { const struct plum_metadata * metadata = plum_find_metadata(context -> source, PLUM_METADATA_BACKGROUND); if (!metadata) return -1; diff --git a/src/inline.h b/src/inline.h index cc74dfd..6f56242 100644 --- a/src/inline.h +++ b/src/inline.h @@ -46,7 +46,7 @@ static inline uint16_t bitextend16 (uint16_t value, unsigned width) { static inline void * append_output_node (struct context * context, size_t size) { struct data_node * node = ctxmalloc(context, sizeof *node + size); *node = (struct data_node) {.size = size, .previous = context -> output, .next = NULL}; - if (context -> output) context -> output -> next = node; + if (node -> previous) node -> previous -> next = node; context -> output = node; return node -> data; } diff --git a/src/pngcompress.c b/src/pngcompress.c index 2781435..a869226 100644 --- a/src/pngcompress.c +++ b/src/pngcompress.c @@ -109,7 +109,7 @@ size_t compute_uncompressed_PNG_block_size (const unsigned char * restrict data, if (length) { score += length - 1; if (score >= 16) break; - } else if (score > 0) + } else if (score) score --; append_PNG_reference(data, current_offset, references); } diff --git a/src/pngwrite.c b/src/pngwrite.c index 6951cda..9ee07b9 100644 --- a/src/pngwrite.c +++ b/src/pngwrite.c @@ -92,9 +92,7 @@ void append_PNG_header_chunks (struct context * context, unsigned type, uint32_t unsigned char header[13]; write_be32_unaligned(header, context -> image -> width); write_be32_unaligned(header + 4, context -> image -> height); - header[8] = (type < 4) ? 1 << type : (8 << (type >= 6)); - header[9] = (type >= 4) ? 2 + 4 * (type & 1) : 3; - bytewrite(header + 10, 0, 0, 0); + bytewrite(header + 8, (type < 4) ? 1 << type : (8 << (type >= 6)), (type >= 4) ? 2 + 4 * (type & 1) : 3, 0, 0, 0); output_PNG_chunk(context, 0x49484452u, sizeof header, header); // IHDR unsigned char depthdata[4]; write_le32_unaligned(depthdata, depth); // this will write each byte of depth in the expected position diff --git a/src/store.c b/src/store.c index 9e3ccef..f86b4f4 100644 --- a/src/store.c +++ b/src/store.c @@ -28,11 +28,11 @@ size_t plum_store_image (const struct plum_image * image, void * restrict buffer write_generated_image_data_to_file(context, buffer); break; case PLUM_MODE_BUFFER: { - void * out = malloc(output_size); - if (!out) throw(context, PLUM_ERR_OUT_OF_MEMORY); + void * output = malloc(output_size); + if (!output) throw(context, PLUM_ERR_OUT_OF_MEMORY); // the function must succeed after reaching this point (otherwise, memory would be leaked) - *(struct plum_buffer *) buffer = (struct plum_buffer) {.size = output_size, .data = out}; - write_generated_image_data(out, context -> output); + *(struct plum_buffer *) buffer = (struct plum_buffer) {.size = output_size, .data = output}; + write_generated_image_data(output, context -> output); } break; case PLUM_MODE_CALLBACK: write_generated_image_data_to_callback(context, buffer); @@ -90,17 +90,17 @@ void write_generated_image_data_to_callback (struct context * context, const str void write_generated_image_data (void * restrict buffer, const struct data_node * data) { const struct data_node * node; for (node = data; node -> previous; node = node -> previous); - for (unsigned char * out = buffer; node; node = node -> next) { - memcpy(out, node -> data, node -> size); - out += node -> size; + for (unsigned char * output = buffer; node; node = node -> next) { + memcpy(output, node -> data, node -> size); + output += node -> size; } } size_t get_total_output_size (struct context * context) { - size_t result = 0; + size_t output_size = 0; for (const struct data_node * node = context -> output; node; node = node -> previous) { - if (result + node -> size < result) throw(context, PLUM_ERR_IMAGE_TOO_LARGE); - result += node -> size; + if (output_size + node -> size < output_size) throw(context, PLUM_ERR_IMAGE_TOO_LARGE); + output_size += node -> size; } - return result; + return output_size; }