16 static int verbose = 0;
17 static char *outname = "out";
18 static int usepalette = 1;
20 static const char *progname;
21 #define errmsg(fmt, ...) (\
22 fprintf(stderr, "%s: " fmt, progname, __VA_ARGS__)\
31 int parserange(struct lbx_imginfo *info, char *str, unsigned char *bits)
33 unsigned long start, end;
37 start = strtoul(str, &endptr, 0);
38 if (start >= info->nframes) {
39 errmsg("frame %lu out of range.\n", start);
44 errmsg("invalid frame range: %s.\n", str);
53 end = strtoul(endptr+1, &endptr, 0);
54 if (end >= info->nframes) {
55 errmsg("frame %lu out of range.\n", end);
60 end = info->nframes - 1;
63 errmsg("invalid frame range: %s.\n", str);
68 errmsg("invalid frame range: %s.\n", str);
72 for (i = start; i <= end; i++) {
73 bits[i / CHAR_BIT] |= 1 << (i % CHAR_BIT);
79 int outpng(unsigned int frameno, unsigned char **framedata,
80 unsigned int width, unsigned int height,
81 struct lbx_colour palette[static 256])
83 char name[strlen(outname) + sizeof ".65535.png"];
89 assert(frameno < 65536);
90 snprintf(name, sizeof name, "%s.%03d.png", outname, frameno);
92 of = fopen(name, "wb");
94 errmsg("failed to open %s: %s.\n", name, strerror(errno));
98 png = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
100 errmsg("failed to init libpng.\n", 0);
104 info = png_create_info_struct(png);
106 errmsg("failed to init libpng.\n", 0);
107 png_destroy_write_struct(&png, NULL);
111 if (setjmp(png_jmpbuf(png))) {
112 png_destroy_write_struct(&png, &info);
117 png_set_IHDR(png, info, width, height, 8,
118 usepalette ? PNG_COLOR_TYPE_PALETTE : PNG_COLOR_TYPE_GRAY,
119 PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT,
120 PNG_FILTER_TYPE_DEFAULT);
123 png_set_PLTE(png, info, (png_colorp)palette, 256);
124 png_set_rows(png, info, framedata);
126 png_init_io(png, of);
127 png_write_png(png, info, PNG_TRANSFORM_IDENTITY, NULL);
129 png_destroy_write_struct(&png, &info);
133 printf("wrote %s\n", name);
142 static int loadpalette(LBX_IMG *img, struct lbx_imginfo *info,
143 FILE *palf, struct lbx_colour palette[static 256])
147 for (i = 0; i < 256; i++)
148 palette[i] = (struct lbx_colour){0xff, 0x00, 0xff};
151 if (lbximg_loadpalette(palf, palette) == -1) {
152 errmsg("error reading palette: %s\n", lbx_strerror());
155 } else if (!info->haspalette) {
156 errmsg("no palette available.\n", 0);
160 if (lbximg_getpalette(img, palette) == -1) {
161 errmsg("error reading embedded palette: %s\n", lbx_strerror());
168 int decode(LBX_IMG *img, FILE *palf, FILE *override, char **argv)
170 unsigned char *framebits;
171 struct lbx_colour palette[256];
172 struct lbx_imginfo info;
176 lbximg_getinfo(img, &info);
178 framebits = malloc(info.nframes / CHAR_BIT + 1);
183 /* Figure out what images we're extracting. */
185 /* extract all images by default. */
186 memset(framebits, -1, info.nframes / CHAR_BIT + 1);
188 for (i = 0; argv[i]; i++) {
189 parserange(&info, argv[i], framebits);
193 if (usepalette && loadpalette(img, &info, palf, palette) == -1) {
198 LBX_IMG *overimg = lbximg_fopen(override);
199 struct lbx_imginfo info;
202 errmsg("failed to open override image: %s\n",
206 lbximg_getinfo(overimg, &info);
208 if (!info.haspalette) {
209 errmsg("override image has no palette.\n", 0);
210 lbximg_close(overimg);
214 if (lbximg_getpalette(overimg, palette) == -1) {
215 errmsg("error reading override palette: %s\n",
217 lbximg_close(overimg);
221 lbximg_close(overimg);
224 /* Extract the images, in order. */
225 for (i = 0; i < info.nframes; i++) {
226 unsigned char **framedata;
228 if (!(framebits[i / CHAR_BIT] & (1 << (i % CHAR_BIT))))
231 framedata = lbximg_getframe(img, i);
233 errmsg("error in frame %u: %s\n", i, lbx_strerror());
237 if (!outpng(i, framedata, info.width, info.height, palette)) {
243 errmsg("no frames extracted.\n", 0);
254 int main(int argc, char **argv)
256 int mode = MODE_NONE;
257 FILE *inf = stdin, *palf = NULL, *overf = NULL;
258 const char *name = "stdin";
262 static const char *sopts = "idvf:p:O:";
263 static const struct option lopts[] = {
264 { "info", 0, NULL, 'i' },
265 { "decode", 0, NULL, 'd' },
266 { "verbose", 0, NULL, 'v' },
267 { "file", 1, NULL, 'f' },
268 { "palette", 1, NULL, 'p' },
269 { "override", 1, NULL, 'p' },
271 { "nopalette", 0, &usepalette, 0 },
276 progname = "lbximg"; /* argv[0]; */
277 while ((opt = getopt_long(argc, argv, sopts, lopts, NULL)) != -1) {
289 if (strcmp(optarg, "-") == 0)
292 name = strrchr(optarg, '/');
293 name = name ? name+1 : optarg;
295 inf = fopen(optarg, "rb");
297 errmsg("failed to open %s: %m\n", optarg);
302 palf = fopen(optarg, "rb");
304 errmsg("failed to open %s: %m\n", optarg);
310 overf = fopen(optarg, "rb");
312 errmsg("failed to open %s: %m\n", optarg);
322 if (mode == MODE_NONE) {
323 errmsg("you must specify a mode.\n", 0);
327 img = lbximg_fopen(inf);
329 errmsg("failed to open image: %s.\n", lbx_strerror());
333 if (verbose || mode == MODE_IDENT) {
334 struct lbx_imginfo info;
335 lbximg_getinfo(img, &info);
337 printf("%s is %ux%u LBX image, %u frame(s)%s%s\n",
338 name, info.width, info.height, info.nframes,
339 info.haspalette ? ", embedded palette" : "",
340 info.looping ? ", loops" : "");
345 if (decode(img, palf, overf, &argv[optind])) {