From 2bcad89b4c854c56e9fe8d24718ef1094f9dd2d7 Mon Sep 17 00:00:00 2001 From: skal Date: Wed, 12 Mar 2014 19:32:16 +0100 Subject: [PATCH] allow some more stdin/stout I/O * allow reading from stdin for dwebp / vwebp * allow writing to stdout for gif2webp by introducing a new function ExUtilReadFromStdin() Example use: cat in.webp | dwebp -o - -- - > out.png Note that the '-- -' option must appear *last* (as per general fashion for '--' option parsing) Change-Id: I8df0f3a246cc325925d6b6f668ba060f7dd81d68 --- examples/example_util.c | 45 +++++++++++++++++++++++++++++++++++++---- examples/example_util.h | 6 ++++++ examples/gif2webp.c | 9 +++++---- man/dwebp.1 | 10 ++++++++- man/gif2webp.1 | 3 ++- man/vwebp.1 | 9 ++++++++- 6 files changed, 71 insertions(+), 11 deletions(-) diff --git a/examples/example_util.c b/examples/example_util.c index d265f697..f2d49750 100644 --- a/examples/example_util.c +++ b/examples/example_util.c @@ -13,18 +13,54 @@ #include "./example_util.h" #include #include +#include // ----------------------------------------------------------------------------- // File I/O +static const size_t kBlockSize = 16384; // default initial size + +int ExUtilReadFromStdin(const uint8_t** data, size_t* data_size) { + size_t max_size = 0; + size_t size = 0; + uint8_t* input = NULL; + + if (data == NULL || data_size == NULL) return 0; + *data = NULL; + *data_size = 0; + + while (!feof(stdin)) { + // We double the buffer size each time and read as much as possible. + const size_t extra_size = (max_size == 0) ? kBlockSize : max_size; + void* const new_data = realloc(input, max_size + extra_size); + if (new_data == NULL) goto Error; + input = (uint8_t*)new_data; + max_size += extra_size; + size += fread(input + size, 1, extra_size, stdin); + if (size < max_size) break; + } + if (ferror(stdin)) goto Error; + *data = input; + *data_size = size; + return 1; + + Error: + free(input); + fprintf(stderr, "Could not read from stdin\n"); + return 0; +} + int ExUtilReadFile(const char* const file_name, const uint8_t** data, size_t* data_size) { int ok; void* file_data; size_t file_size; FILE* in; + const int from_stdin = (file_name == NULL) || !strcmp(file_name, "-"); - if (file_name == NULL || data == NULL || data_size == NULL) return 0; + if (from_stdin) return ExUtilReadFromStdin(data, data_size); + + if (data == NULL || data_size == NULL) return 0; *data = NULL; *data_size = 0; @@ -56,17 +92,18 @@ int ExUtilWriteFile(const char* const file_name, const uint8_t* data, size_t data_size) { int ok; FILE* out; + const int to_stdout = (file_name == NULL) || !strcmp(file_name, "-"); - if (file_name == NULL || data == NULL) { + if (data == NULL) { return 0; } - out = fopen(file_name, "wb"); + out = to_stdout ? stdout : fopen(file_name, "wb"); if (out == NULL) { fprintf(stderr, "Error! Cannot open output file '%s'\n", file_name); return 0; } ok = (fwrite(data, data_size, 1, out) == 1); - fclose(out); + if (out != stdout) fclose(out); return ok; } diff --git a/examples/example_util.h b/examples/example_util.h index b478025f..b191bd2a 100644 --- a/examples/example_util.h +++ b/examples/example_util.h @@ -22,10 +22,16 @@ extern "C" { // Allocates storage for entire file 'file_name' and returns contents and size // in 'data' and 'data_size'. Returns 1 on success, 0 otherwise. '*data' should // be deleted using free(). +// If 'file_name' is NULL or equal to "-", input is read from stdin by calling +// the function ExUtilReadFromStdin(). int ExUtilReadFile(const char* const file_name, const uint8_t** data, size_t* data_size); +// Same as ExUtilReadFile(), but reads until EOF from stdin instead. +int ExUtilReadFromStdin(const uint8_t** data, size_t* data_size); + // Write a data segment into a file named 'file_name'. Returns true if ok. +// If 'file_name' is NULL or equal to "-", output is written to stdout. int ExUtilWriteFile(const char* const file_name, const uint8_t* data, size_t data_size); diff --git a/examples/gif2webp.c b/examples/gif2webp.c index f360be1d..ed0640aa 100644 --- a/examples/gif2webp.c +++ b/examples/gif2webp.c @@ -501,7 +501,7 @@ int main(int argc, const char *argv[]) { if (data == NULL) goto End; // Loop count sub-block missing. if (data[0] != 3 && data[1] != 1) break; // wrong size/marker anim.loop_count = data[2] | (data[3] << 8); - if (verbose) printf("Loop count: %d\n", anim.loop_count); + if (verbose) fprintf(stderr, "Loop count: %d\n", anim.loop_count); } else { // An extension containing metadata. // We only store the first encountered chunk of each type, and // only if requested by the user. @@ -555,7 +555,8 @@ int main(int argc, const char *argv[]) { // Add metadata chunk. err = WebPMuxSetChunk(mux, fourccs[is_icc], &metadata, 1); if (verbose) { - printf("%s size: %d\n", features[is_icc], (int)metadata.size); + fprintf(stderr, "%s size: %d\n", + features[is_icc], (int)metadata.size); } WebPDataClear(&metadata); if (err != WEBP_MUX_OK) { @@ -621,11 +622,11 @@ int main(int argc, const char *argv[]) { goto End; } if (!quiet) { - printf("Saved output file: %s\n", out_file); + fprintf(stderr, "Saved output file: %s\n", out_file); } } else { if (!quiet) { - printf("Nothing written; use -o flag to save the result.\n"); + fprintf(stderr, "Nothing written; use -o flag to save the result.\n"); } } diff --git a/man/dwebp.1 b/man/dwebp.1 index 23243872..6ef505fa 100644 --- a/man/dwebp.1 +++ b/man/dwebp.1 @@ -1,5 +1,5 @@ .\" Hey, EMACS: -*- nroff -*- -.TH DWEBP 1 "January 11, 2014" +.TH DWEBP 1 "March 7, 2014" .SH NAME dwebp \- decompress a WebP file to an image file .SH SYNOPSIS @@ -25,6 +25,12 @@ Print the version number (as major.minor.revision) and exit. Specify the name of the output file (as PNG format by default). Using "-" as output name will direct output to 'stdout'. .TP +.BI \-\- " string +Explicitly specify the input file. This option is useful if the input +file starts with an '\-' for instance. This option must appear \fBlast\fP. +Any other options afterward will be ignored. If the input file is "\-", +the data will be read from \fIstdin\fP instead of a file. +.TP .B \-bmp Change the output format to uncompressed BMP. .TP @@ -104,6 +110,8 @@ dwebp picture.webp \-o output.png dwebp picture.webp \-ppm \-o output.ppm .br dwebp \-o output.ppm \-\- \-\-\-picture.webp +.br +cat picture.webp | dwebp \-o \- \-\- \- > output.ppm .SH AUTHORS \fBdwebp\fP was written by the WebP team. diff --git a/man/gif2webp.1 b/man/gif2webp.1 index 7f227bef..d41b423a 100644 --- a/man/gif2webp.1 +++ b/man/gif2webp.1 @@ -1,5 +1,5 @@ .\" Hey, EMACS: -*- nroff -*- -.TH GIF2WEBP 1 "December 17, 2013" +.TH GIF2WEBP 1 "March 7, 2014" .SH NAME gif2webp \- Convert a GIF image to WebP .SH SYNOPSIS @@ -18,6 +18,7 @@ The basic options are: .BI \-o " string Specify the name of the output WebP file. If omitted, \fBgif2webp\fP will perform conversion but only report statistics. +Using "\-" as output name will direct output to 'stdout'. .TP .B \-h, \-help Usage information. diff --git a/man/vwebp.1 b/man/vwebp.1 index 8b05f5ce..9115009b 100644 --- a/man/vwebp.1 +++ b/man/vwebp.1 @@ -1,5 +1,5 @@ .\" Hey, EMACS: -*- nroff -*- -.TH VWEBP 1 "January 08, 2014" +.TH VWEBP 1 "March 7, 2014" .SH NAME vwebp \- decompress a WebP file and display it in a window .SH SYNOPSIS @@ -39,6 +39,13 @@ Use multi-threading for decoding, if possible. .TP .B \-info Display image information on top of the decoded image. +.TP +.BI \-\- " string +Explicitly specify the input file. This option is useful if the input +file starts with an '\-' for instance. This option must appear \fBlast\fP. +Any other options afterward will be ignored. If the input file is "\-", +the data will be read from \fIstdin\fP instead of a file. +.TP .SH KEYBOARD SHORTCUTS .TP