From: Nick Bowler Date: Fri, 14 Jun 2013 01:16:36 +0000 (-0400) Subject: lbximg: Push no-palette mode down into the PNG writer. X-Git-Url: http://git.draconx.ca/gitweb/liblbx.git/commitdiff_plain/4ec9360786d0bb19cffc76818c1a4c33043f68e1 lbximg: Push no-palette mode down into the PNG writer. This allows the writer to select the most appropriate output format to support this mode. Switch the PNG writer to emit true grayscale images in this case. --- diff --git a/src/lbximg.c b/src/lbximg.c index c761c17..a7c60c6 100644 --- a/src/lbximg.c +++ b/src/lbximg.c @@ -172,15 +172,6 @@ static int loadpalette(struct lbx_image *img, struct lbx_imginfo *info, { int i; - /* In no-palette mode, use palette indices for colour. */ - if (!usepalette) { - for (i = 0; i < 256; i++) { - palette[i] = (struct lbx_colour){i,i,i}; - } - - return 0; - } - /* For sanity. */ if (!palf && !info->palettesz && !override) { tool_err(-1, "no palette available."); @@ -237,8 +228,10 @@ int decode(struct lbx_image *img, FILE *palf, FILE *override, char **argv) } } - if (loadpalette(img, &info, palf, override, palette) == -1) { - goto err; + if (usepalette) { + if (loadpalette(img, &info, palf, override, palette) == -1) { + goto err; + } } /* Extract the images, in order. */ @@ -257,7 +250,8 @@ int decode(struct lbx_image *img, FILE *palf, FILE *override, char **argv) mask = lbx_img_getmask(img); - if (!outpng(i, data, mask, img->width, img->height, palette)) { + if (!outpng(i, data, mask, img->width, img->height, + usepalette ? palette : NULL)) { extracted = 1; } } diff --git a/src/png.c b/src/png.c index ee5d0a5..288cf77 100644 --- a/src/png.c +++ b/src/png.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include @@ -135,8 +136,47 @@ write_rgba_frame(png_structp png, png_infop info, } static void -write_index_frame(png_structp png, png_infop info, unsigned char **framedata, - struct lbx_colour *palette) +write_masked_index_frame(png_structp png, png_infop info, + unsigned char **framedata, unsigned char **mask) +{ + png_uint_32 width = png_get_image_width(png, info); + png_uint_32 height = png_get_image_height(png, info); + unsigned char (*row)[2]; + jmp_buf parent; + + if (width >= PNG_UINT_32_MAX / sizeof *row) + fatal(png, -1, "image too wide to allocate row buffer"); + + row = png_malloc(png, width * sizeof *row); + + /* + * We need to establish our own error handler to free the row buffer. + * Some care must be taken to save/restore the caller's handler. + */ + memcpy(&parent, &png_jmpbuf(png), sizeof parent); + if (setjmp(png_jmpbuf(png))) { + png_free(png, row); + + memcpy(&png_jmpbuf(png), &parent, sizeof parent); + png_longjmp(png, 1); + } + + png_write_info(png, info); + for (png_uint_32 y = 0; y < height; y++) { + for (png_uint_32 x = 0; x < width; x++) { + row[x][0] = framedata[y][x]; + row[x][1] = mask[y][x] ? -1 : 0; + } + png_write_row(png, (void *)row); + } + png_write_end(png, NULL); + + memcpy(&png_jmpbuf(png), &parent, sizeof parent); +} + +static void +write_palette_frame(png_structp png, png_infop info, + unsigned char **framedata, struct lbx_colour *palette) { png_color png_palette[256]; @@ -153,11 +193,19 @@ write_index_frame(png_structp png, png_infop info, unsigned char **framedata, png_write_png(png, info, PNG_TRANSFORM_IDENTITY, NULL); } +static void +write_index_frame(png_structp png, png_infop info, unsigned char **framedata) +{ + png_set_rows(png, info, framedata); + png_write_png(png, info, PNG_TRANSFORM_IDENTITY, NULL); +} + int img_output_png(FILE *f, const char *filename, unsigned width, unsigned height, unsigned char **framedata, unsigned char **mask, struct lbx_colour *palette) { + bool masked = is_masked(mask, width, height); struct file_info file = { filename, f }; png_structp png; png_infop info; @@ -183,7 +231,7 @@ int img_output_png(FILE *f, const char *filename, png_set_error_fn(png, NULL, error_fn, warning_fn); png_set_write_fn(png, &file, write_data, flush_data); - if (is_masked(mask, width, height)) { + if (palette && masked) { /* * Indexed colour mode can only be used for images without * transparency, since indexed PNG requires sacrificing one or @@ -196,13 +244,27 @@ int img_output_png(FILE *f, const char *filename, PNG_FILTER_TYPE_DEFAULT); write_rgba_frame(png, info, framedata, mask, palette); - } else { + } else if (palette) { png_set_IHDR(png, info, width, height, 8, PNG_COLOR_TYPE_PALETTE, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); - write_index_frame(png, info, framedata, palette); + write_palette_frame(png, info, framedata, palette); + } else if (masked) { + png_set_IHDR(png, info, width, height, 8, + PNG_COLOR_TYPE_GRAY_ALPHA, PNG_INTERLACE_NONE, + PNG_COMPRESSION_TYPE_DEFAULT, + PNG_FILTER_TYPE_DEFAULT); + + write_masked_index_frame(png, info, framedata, mask); + } else { + png_set_IHDR(png, info, width, height, 8, + PNG_COLOR_TYPE_GRAY, PNG_INTERLACE_NONE, + PNG_COMPRESSION_TYPE_DEFAULT, + PNG_FILTER_TYPE_DEFAULT); + + write_index_frame(png, info, framedata); } png_destroy_write_struct(&png, &info);