diff --git a/src/bmpwrite.c b/src/bmpwrite.c index 3fc431e..263e5fe 100644 --- a/src/bmpwrite.c +++ b/src/bmpwrite.c @@ -333,22 +333,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/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..914e01d 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,51 @@ void generate_GIF_data (struct context * context) { byteoutput(context, 0x3b); } +#define handlebounds(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; \ + goto gotbounds; \ + } \ + 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; \ + } \ + gotbounds: \ + 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 +110,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) handlebounds(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 +154,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) handlebounds(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 +168,8 @@ void generate_GIF_frame_data (struct context * context, uint32_t * restrict pixe ctxfree(context, palette); } +#undef handlebounds + 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 d00fd46..6efa296 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 0a6bac4..22da40c 100644 --- a/src/pngwrite.c +++ b/src/pngwrite.c @@ -96,9 +96,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