{
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.");
}
}
- 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. */
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;
}
}
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
+#include <stdbool.h>
#include <setjmp.h>
#include <png.h>
}
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];
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;
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
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);