From 256bcecd3a9a7666c81bb175095402f984379b77 Mon Sep 17 00:00:00 2001 From: Nick Bowler Date: Mon, 31 Dec 2007 02:25:15 -0500 Subject: [PATCH] Implement decoding for lbximg. --- src/lbximg.c | 197 ++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 195 insertions(+), 2 deletions(-) diff --git a/src/lbximg.c b/src/lbximg.c index 0770049..409936a 100644 --- a/src/lbximg.c +++ b/src/lbximg.c @@ -2,11 +2,20 @@ #include #include #include +#include +#include #include +#include + +#include #include "image.h" #include "lbx.h" +/* Global flags */ +static int verbose = 0; +static char *outname = "out"; + static const char *progname; #define errmsg(fmt, ...) (\ fprintf(stderr, "%s: " fmt, progname, __VA_ARGS__)\ @@ -18,9 +27,190 @@ enum { MODE_IDENT, }; +int parserange(struct lbx_imginfo *info, char *str, unsigned char *bits) +{ + unsigned long start, end; + unsigned int i; + char *endptr; + + start = strtoul(str, &endptr, 0); + if (start >= info->nframes) { + errmsg("frame %lu out of range.\n", start); + return -1; + } + + if (endptr == str) { + errmsg("invalid frame range: %s.\n", str); + return -1; + } + + switch (*endptr) { + case '\0': + end = start; + break; + case '-': + end = strtoul(endptr+1, &endptr, 0); + if (end >= info->nframes) { + errmsg("frame %lu out of range.\n", end); + return -1; + } + + if (endptr == str) + end = info->nframes - 1; + break; + default: + errmsg("invalid frame range: %s.\n", str); + return -1; + } + + if (end < start) { + errmsg("invalid frame range: %s.\n", str); + return -1; + } + + for (i = start; i <= end; i++) { + bits[i / CHAR_BIT] |= 1 << (i % CHAR_BIT); + } + + return 0; +} + +int outpng(unsigned int frameno, unsigned char **framedata, + unsigned int width, unsigned int height, + struct lbx_colour palette[static 256]) +{ + char name[strlen(outname) + sizeof ".65535.png"]; + FILE *of; + + png_structp png; + png_infop info; + + assert(frameno < 65536); + snprintf(name, sizeof name, "%s.%03d.png", outname, frameno); + + of = fopen(name, "wb"); + if (!of) { + errmsg("failed to open %s: %s.\n", name, strerror(errno)); + return -1; + } + + png = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); + if (!png) { + errmsg("failed to init libpng.\n", 0); + goto err; + } + + info = png_create_info_struct(png); + if (!info) { + errmsg("failed to init libpng.\n", 0); + png_destroy_write_struct(&png, NULL); + goto err; + } + + if (setjmp(png_jmpbuf(png))) { + png_destroy_write_struct(&png, &info); + goto err; + } + + png_set_IHDR(png, info, width, height, 8, PNG_COLOR_TYPE_PALETTE, + PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, + PNG_FILTER_TYPE_DEFAULT); + png_set_PLTE(png, info, (png_colorp)palette, 256); + png_set_rows(png, info, framedata); + + png_init_io(png, of); + png_write_png(png, info, PNG_TRANSFORM_IDENTITY, NULL); + + png_destroy_write_struct(&png, &info); + fclose(of); + + if (verbose) + printf("wrote %s\n", name); + + return 0; +err: + fclose(of); + remove(name); + return -1; +} + +int decode(LBX_IMG *img, FILE *palf, char **argv) +{ + unsigned char *framebits; + struct lbx_colour palette[256]; + struct lbx_imginfo info; + int extracted = 0; + unsigned int i; + + lbximg_getinfo(img, &info); + + framebits = malloc(info.nframes / CHAR_BIT + 1); + if (!framebits) { + return -1; + } + + /* Figure out what images we're extracting. */ + if (!argv[0]) { + /* extract all images by default. */ + memset(framebits, -1, info.nframes / CHAR_BIT + 1); + } else { + for (i = 0; argv[i]; i++) { + parserange(&info, argv[i], framebits); + } + } + + /* Read image palette */ + if (palf) { + if (lbximg_loadpalette(palf, palette) == -1) { + errmsg("error reading palette: %s\n", lbx_strerror()); + goto err; + } + } else { + fprintf(stderr, "warning: no palette specified; " + "decoded images will likely be very pink.\n"); + + for (i = 0; i < 256; i++) + palette[i] = (struct lbx_colour){0xff, 0x00, 0xff}; + } + + if (lbximg_getpalette(img, palette) == -1) { + errmsg("error reading palette override: %s\n", lbx_strerror()); + goto err; + } + + /* Extract the images, in order. */ + for (i = 0; i < info.nframes; i++) { + unsigned char **framedata; + + if (!(framebits[i / CHAR_BIT] & (1 << (i % CHAR_BIT)))) + continue; + + framedata = lbximg_getframe(img, i); + if (!framedata) { + errmsg("error in frame %u: %s\n", i, lbx_strerror()); + continue; + } + + if (!outpng(i, framedata, info.width, info.height, palette)) { + extracted = 1; + } + } + + if (!extracted) { + errmsg("no frames extracted.\n", 0); + goto err; + } + + free(framebits); + return EXIT_SUCCESS; +err: + free(framebits); + return EXIT_FAILURE; +} + int main(int argc, char **argv) { - int mode = MODE_NONE, verbose = 0; + int mode = MODE_NONE; FILE *inf = stdin, *palf = NULL; const char *name = "stdin"; LBX_IMG *img; @@ -96,7 +286,10 @@ int main(int argc, char **argv) switch (mode) { case MODE_DECODE: - errmsg("decode function not yet implemented.\n", 0); + if (decode(img, palf, &argv[optind])) { + lbximg_close(img); + return EXIT_FAILURE; + } break; } -- 2.43.2