summaryrefslogtreecommitdiff
path: root/test/nsgif.c
diff options
context:
space:
mode:
Diffstat (limited to 'test/nsgif.c')
-rw-r--r--test/nsgif.c171
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 */