diff options
Diffstat (limited to 'test/nsgif.c')
-rw-r--r-- | test/nsgif.c | 171 |
1 files changed, 127 insertions, 44 deletions
diff --git a/test/nsgif.c b/test/nsgif.c index 173f70c..23fd3f3 100644 --- a/test/nsgif.c +++ b/test/nsgif.c @@ -17,8 +17,56 @@ #include "../include/nsgif.h" +#include "cli.h" +#include "cli.c" + #define BYTES_PER_PIXEL 4 +static struct nsgif_options { + const char *file; + const char *ppm; + uint64_t loops; + bool info; +} nsgif_options; + +static const struct cli_table_entry cli_entries[] = { + { + .s = 'm', + .l = "ppm", + .t = CLI_STRING, + .v.s = &nsgif_options.ppm, + .d = "Convert frames to PPM image at given path." + }, + { + .s = 'i', + .l = "info", + .t = CLI_BOOL, + .v.b = &nsgif_options.info, + .d = "Dump GIF info to stdout." + }, + { + .s = 'l', + .l = "loops", + .t = CLI_UINT, + .v.u = &nsgif_options.loops, + .d = "Loop through decoding all frames N times. " + "The default is 1." + }, + { + .p = true, + .l = "FILE", + .t = CLI_STRING, + .v.s = &nsgif_options.file, + .d = "Path to GIF file to load." + }, +}; + +const struct cli_table cli = { + .entries = cli_entries, + .count = (sizeof(cli_entries))/(sizeof(*cli_entries)), + .min_positional = 1, +}; + static void *bitmap_create(int width, int height) { /* Ensure a stupidly large bitmap is not created */ @@ -84,7 +132,31 @@ static void warning(const char *context, nsgif_error err) context, nsgif_strerror(err)); } -static void decode(FILE* fh, const char *name, nsgif *gif, bool write_ppm) +static void print_gif_info(const nsgif_info_t *info) +{ + fprintf(stdout, "gif:\n"); + fprintf(stdout, " width: %"PRIu32"\n", info->width); + fprintf(stdout, " height: %"PRIu32"\n", info->height); + fprintf(stdout, " max-loops: %"PRIu32"\n", info->loop_max); + fprintf(stdout, " frame-count: %"PRIu32"\n", info->frame_count); + fprintf(stdout, " frames:\n"); +} + +static void print_gif_frame_info(const nsgif_frame_info_t *info) +{ + const char *disposal = nsgif_str_disposal(info->disposal); + + fprintf(stdout, " - disposal-method: %s\n", disposal); + fprintf(stdout, " display: %s\n", info->display ? "yes" : "no"); + fprintf(stdout, " delay: %"PRIu32"\n", info->delay); + fprintf(stdout, " rect:\n"); + fprintf(stdout, " x: %"PRIu32"\n", info->rect.x0); + fprintf(stdout, " y: %"PRIu32"\n", info->rect.y0); + fprintf(stdout, " w: %"PRIu32"\n", info->rect.x1 - info->rect.x0); + fprintf(stdout, " h: %"PRIu32"\n", info->rect.y1 - info->rect.y0); +} + +static void decode(FILE* ppm, const char *name, nsgif *gif) { nsgif_error err; uint32_t frame_prev = 0; @@ -92,20 +164,24 @@ static void decode(FILE* fh, const char *name, nsgif *gif, bool write_ppm) info = nsgif_get_info(gif); - if (write_ppm) { - fprintf(fh, "P3\n"); - fprintf(fh, "# %s\n", name); - fprintf(fh, "# width %u \n", info->width); - fprintf(fh, "# height %u \n", info->height); - fprintf(fh, "# frame_count %u \n", info->frame_count); - fprintf(fh, "# loop_max %u \n", info->loop_max); - fprintf(fh, "%u %u 256\n", info->width, + if (ppm != NULL) { + fprintf(ppm, "P3\n"); + fprintf(ppm, "# %s\n", name); + fprintf(ppm, "# width %u \n", info->width); + fprintf(ppm, "# height %u \n", info->height); + fprintf(ppm, "# frame_count %u \n", info->frame_count); + fprintf(ppm, "# loop_max %u \n", info->loop_max); + fprintf(ppm, "%u %u 256\n", info->width, info->height * info->frame_count); } + if (nsgif_options.info == true) { + print_gif_info(info); + } + /* decode the frames */ while (true) { - nsgif_bitmap_t *buffer; + nsgif_bitmap_t *bitmap; const uint8_t *image; uint32_t frame_new; uint32_t delay_cs; @@ -120,31 +196,44 @@ static void decode(FILE* fh, const char *name, nsgif *gif, bool write_ppm) if (frame_new < frame_prev) { /* Must be an animation that loops. We only care about - * decoding each frame once. */ + * decoding each frame once in this utility. */ return; } frame_prev = frame_new; - err = nsgif_frame_decode(gif, frame_new, &buffer); + err = nsgif_frame_decode(gif, frame_new, &bitmap); if (err != NSGIF_OK) { warning("nsgif_decode_frame", err); return; } - if (write_ppm) { - fprintf(fh, "# frame %u:\n", frame_new); - image = (const uint8_t *) buffer; + if (nsgif_options.info == true) { + const nsgif_frame_info_t *f_info; + + f_info = nsgif_get_frame_info(gif, frame_new); + assert(f_info != NULL); + print_gif_frame_info(f_info); + } + + if (ppm != NULL) { + fprintf(ppm, "# frame %u:\n", frame_new); + image = (const uint8_t *) bitmap; for (uint32_t y = 0; y != info->height; y++) { for (uint32_t x = 0; x != info->width; x++) { size_t z = (y * info->width + x) * 4; - fprintf(fh, "%u %u %u ", + fprintf(ppm, "%u %u %u ", image[z], image[z + 1], image[z + 2]); } - fprintf(fh, "\n"); + fprintf(ppm, "\n"); } } + + if (delay_cs == NSGIF_INFINITE) { + /** This frame is the last. */ + return; + } } } @@ -159,40 +248,32 @@ int main(int argc, char *argv[]) size_t size; uint8_t *data; nsgif_error err; - FILE *outf = stdout; - bool no_write = false; - - if (argc < 2) { - fprintf(stderr, "Usage: %s image.gif [out]\n", argv[0]); - fprintf(stderr, "\n"); - fprintf(stderr, "If [out] is NOWRITE, the gif will be docoded " - "but not output.\n"); - fprintf(stderr, "Otherwise [out] is an output filename.\n"); - fprintf(stderr, "When [out] is unset, output is to stdout.\n"); - - return 1; + FILE *ppm = NULL; + + /* Override default options with any command line args */ + if (!cli_parse(&cli, argc, (void *)argv)) { + cli_help(&cli, argv[0]); + return EXIT_FAILURE; } - if (argc > 2) { - if (strcmp(argv[2], "NOWRITE") == 0) { - no_write = true; - } else { - outf = fopen(argv[2], "w+"); - if (outf == NULL) { - fprintf(stderr, "Unable to open %s for writing\n", argv[2]); - return 2; - } + if (nsgif_options.ppm != NULL) { + ppm = fopen(nsgif_options.ppm, "w+"); + if (ppm == NULL) { + fprintf(stderr, "Unable to open %s for writing\n", + nsgif_options.ppm); + return EXIT_FAILURE; } } /* create our gif animation */ err = nsgif_create(&bitmap_callbacks, &gif); if (err != NSGIF_OK) { - return 1; + warning("nsgif_create", err); + return EXIT_FAILURE; } /* load file into memory */ - data = load_file(argv[1], &size); + data = load_file(nsgif_options.file, &size); /* Scan the raw data */ err = nsgif_data_scan(gif, size, data); @@ -200,13 +281,15 @@ int main(int argc, char *argv[]) warning("nsgif_data_scan", err); nsgif_destroy(gif); free(data); - return 1; + return EXIT_FAILURE; } - decode(outf, argv[1], gif, !no_write); + for (uint64_t i = 0; i < nsgif_options.loops; i++) { + decode((i == 0) ? ppm : NULL, nsgif_options.file, gif); + } - if (argc > 2 && !no_write) { - fclose(outf); + if (ppm != NULL) { + fclose(ppm); } /* clean up */ |