From a9947c3244c301a7342504444311ecc69842e334 Mon Sep 17 00:00:00 2001 From: Pascal Massimino Date: Tue, 8 Dec 2015 08:22:41 +0100 Subject: [PATCH] cwebp: add support for stdin input we map the input file into memory, even in the non-stdin case. This is less efficient than letting the png/jpeg/... decoding libraries use fread()'s, but more general. Change-Id: I4501cb9a1daf69593eb8e3326c115cd8cbdf92fd --- examples/cwebp.c | 107 ++++++++++++++++++++++----------------------- examples/jpegdec.c | 15 +++---- examples/jpegdec.h | 7 ++- examples/pngdec.c | 14 +++--- examples/pngdec.h | 8 ++-- examples/tiffdec.c | 70 ++++++++++++++++++++++++++--- examples/tiffdec.h | 6 ++- examples/webpdec.c | 15 ++++--- examples/webpdec.h | 5 ++- 9 files changed, 154 insertions(+), 93 deletions(-) diff --git a/examples/cwebp.c b/examples/cwebp.c index c326bba6..c7d0b713 100644 --- a/examples/cwebp.c +++ b/examples/cwebp.c @@ -48,63 +48,62 @@ extern void* VP8GetCPUInfo; // opaque forward declaration. static int verbose = 0; -static int ReadYUV(const char filename[], WebPPicture* const pic) { +static int ReadYUV(const uint8_t* const data, size_t data_size, + WebPPicture* const pic) { + int y; const int use_argb = pic->use_argb; const int uv_width = (pic->width + 1) / 2; const int uv_height = (pic->height + 1) / 2; const int uv_plane_size = uv_width * uv_height; - const uint8_t* data = NULL; - size_t data_size = 0; const size_t expected_data_size = pic->width * pic->height + 2 * uv_plane_size; - int ok = 0; - - pic->use_argb = 0; - - ok = ExUtilReadFile(filename, &data, &data_size); - if (!ok) goto End; if (data_size != expected_data_size) { fprintf(stderr, - "file '%s' doesn't have the expected size (%d instead of %d)\n", - filename, (int)data_size, (int)expected_data_size); - ok = 0; - goto End; + "input data doesn't have the expected size (%d instead of %d)\n", + (int)data_size, (int)expected_data_size); + return 0; } - pic->y_stride = pic->width; - pic->uv_stride = uv_width; - pic->y = (uint8_t*)data; - pic->u = pic->y + pic->height * pic->y_stride; - pic->v = pic->u + uv_plane_size; - // Grab ownership 'data' - pic->memory_ = (void*)data; - data = NULL; - ok = 1; - if (use_argb) ok = WebPPictureYUVAToARGB(pic); + pic->use_argb = 0; + if (!WebPPictureAlloc(pic)) return 0; - End: - free((void*)data); - return ok; + for (y = 0; y < pic->height; ++y) { + memcpy(pic->y + y * pic->y_stride, data + y * pic->width, + pic->width * sizeof(*pic->y)); + } + for (y = 0; y < uv_height; ++y) { + const uint8_t* const uv_data = data + pic->height * pic->y_stride; + memcpy(pic->u + y * pic->uv_stride, uv_data + y * uv_width, + uv_width * sizeof(*uv_data)); + memcpy(pic->v + y * pic->uv_stride, uv_data + y * uv_width + uv_plane_size, + uv_width * sizeof(*uv_data)); + } + return use_argb ? WebPPictureYUVAToARGB(pic) : 1; } #ifdef HAVE_WINCODEC_H static int ReadPicture(const char* const filename, WebPPicture* const pic, int keep_alpha, Metadata* const metadata) { - int ok; + int ok = 0; + const uint8_t* data = NULL; + size_t data_size = 0; if (pic->width != 0 && pic->height != 0) { - ok = ReadYUV(filename, pic); + ok = ExUtilReadFile(filename, &data, &data_size); + ok = ok && ReadYUV(data, data_size, pic); } else { // If no size specified, try to decode it using WIC. ok = ReadPictureWithWIC(filename, pic, keep_alpha, metadata); if (!ok) { - ok = ReadWebP(filename, pic, keep_alpha, metadata); + ok = ExUtilReadFile(filename, &data, &data_size); + ok = ok && ReadWebP(data, data_size, pic, keep_alpha, metadata); } } if (!ok) { fprintf(stderr, "Error! Could not process file %s\n", filename); } + free((void*)data); return ok; } @@ -118,18 +117,14 @@ typedef enum { UNSUPPORTED } InputFileFormat; -static InputFileFormat GetImageType(FILE* in_file) { +static uint32_t GetBE32(const uint8_t buf[]) { + return ((uint32_t)buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3]; +} + +static InputFileFormat GuessImageType(const uint8_t buf[12]) { InputFileFormat format = UNSUPPORTED; - uint32_t magic1, magic2; - uint8_t buf[12]; - - if ((fread(&buf[0], 12, 1, in_file) != 1) || - (fseek(in_file, 0, SEEK_SET) != 0)) { - return format; - } - - magic1 = ((uint32_t)buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3]; - magic2 = ((uint32_t)buf[8] << 24) | (buf[9] << 16) | (buf[10] << 8) | buf[11]; + const uint32_t magic1 = GetBE32(buf + 0); + const uint32_t magic2 = GetBE32(buf + 8); if (magic1 == 0x89504E47U) { format = PNG_; } else if (magic1 >= 0xFFD8FF00U && magic1 <= 0xFFD8FFFFU) { @@ -144,34 +139,36 @@ static InputFileFormat GetImageType(FILE* in_file) { static int ReadPicture(const char* const filename, WebPPicture* const pic, int keep_alpha, Metadata* const metadata) { + const uint8_t* data = NULL; + size_t data_size = 0; int ok = 0; + + ok = ExUtilReadFile(filename, &data, &data_size); + if (!ok) goto End; + if (pic->width == 0 || pic->height == 0) { - InputFileFormat format; - // If no size specified, try to decode it as PNG/JPEG (as appropriate). - FILE* in_file = fopen(filename, "rb"); - if (in_file == NULL) { - fprintf(stderr, "Error! Cannot open input file '%s'\n", filename); - return ok; - } - format = GetImageType(in_file); + ok = 0; + if (data_size >= 12) { + const InputFileFormat format = GuessImageType(data); if (format == PNG_) { - ok = ReadPNG(filename, pic, keep_alpha, metadata); + ok = ReadPNG(data, data_size, pic, keep_alpha, metadata); } else if (format == JPEG_) { - ok = ReadJPEG(filename, pic, metadata); + ok = ReadJPEG(data, data_size, pic, metadata); } else if (format == TIFF_) { - ok = ReadTIFF(filename, pic, keep_alpha, metadata); + ok = ReadTIFF(data, data_size, pic, keep_alpha, metadata); } else if (format == WEBP_) { - ok = ReadWebP(filename, pic, keep_alpha, metadata); + ok = ReadWebP(data, data_size, pic, keep_alpha, metadata); + } } - fclose(in_file); } else { // If image size is specified, infer it as YUV format. - ok = ReadYUV(filename, pic); + ok = ReadYUV(data, data_size, pic); } + End: if (!ok) { fprintf(stderr, "Error! Could not process file %s\n", filename); } - + free((void*)data); return ok; } diff --git a/examples/jpegdec.c b/examples/jpegdec.c index af72bfae..244502da 100644 --- a/examples/jpegdec.c +++ b/examples/jpegdec.c @@ -254,8 +254,8 @@ static void ContextSetup(volatile struct jpeg_decompress_struct* const cinfo, ctx->pub.next_input_byte = NULL; } -int ReadJPEG(const char* const filename, WebPPicture* const pic, - Metadata* const metadata) { +int ReadJPEG(const uint8_t* const data, size_t data_size, + WebPPicture* const pic, Metadata* const metadata) { volatile int ok = 0; int stride, width, height; volatile struct jpeg_decompress_struct dinfo; @@ -265,9 +265,8 @@ int ReadJPEG(const char* const filename, WebPPicture* const pic, JPEGReadContext ctx; memset(&ctx, 0, sizeof(ctx)); - - ok = ExUtilReadFile(filename, &ctx.data, &ctx.data_size); - if (!ok) goto End; + ctx.data = data; + ctx.data_size = data_size; memset((j_decompress_ptr)&dinfo, 0, sizeof(dinfo)); // for setjmp sanity dinfo.err = jpeg_std_error(&jerr.pub); @@ -330,14 +329,14 @@ int ReadJPEG(const char* const filename, WebPPicture* const pic, End: free(rgb); - free((void*)ctx.data); return ok; } #else // !WEBP_HAVE_JPEG -int ReadJPEG(const char* const filename, +int ReadJPEG(const uint8_t* const data, size_t data_size, struct WebPPicture* const pic, struct Metadata* const metadata) { - (void)filename; + (void)data; + (void)data_size; (void)pic; (void)metadata; fprintf(stderr, "JPEG support not compiled. Please install the libjpeg " diff --git a/examples/jpegdec.h b/examples/jpegdec.h index d6c126fb..68c042aa 100644 --- a/examples/jpegdec.h +++ b/examples/jpegdec.h @@ -22,12 +22,11 @@ extern "C" { struct Metadata; struct WebPPicture; -// Reads a JPEG from 'filename', returning the decoded output in 'pic'. -// If 'filename' is equal '-', input is read from stdin. +// Reads a JPEG from 'data', returning the decoded output in 'pic'. // The output is RGB or YUV depending on pic->use_argb value. // Returns true on success. -int ReadJPEG(const char* const filename, struct WebPPicture* const pic, - struct Metadata* const metadata); +int ReadJPEG(const uint8_t* const data, size_t data_size, + struct WebPPicture* const pic, struct Metadata* const metadata); #ifdef __cplusplus } // extern "C" diff --git a/examples/pngdec.c b/examples/pngdec.c index d1439547..85183621 100644 --- a/examples/pngdec.c +++ b/examples/pngdec.c @@ -203,7 +203,8 @@ static void ReadFunc(png_structp png_ptr, png_bytep data, png_size_t length) { ctx->offset += length; } -int ReadPNG(const char* const filename, struct WebPPicture* const pic, +int ReadPNG(const uint8_t* const data, size_t data_size, + struct WebPPicture* const pic, int keep_alpha, struct Metadata* const metadata) { volatile png_structp png = NULL; volatile png_infop info = NULL; @@ -218,8 +219,8 @@ int ReadPNG(const char* const filename, struct WebPPicture* const pic, png_uint_32 stride; uint8_t* volatile rgb = NULL; - ok = ExUtilReadFile(filename, &context.data, &context.data_size); - if (!ok) goto End; + context.data = data; + context.data_size = data_size; png = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0); if (png == NULL) goto End; @@ -299,14 +300,15 @@ int ReadPNG(const char* const filename, struct WebPPicture* const pic, png_destroy_read_struct((png_structpp)&png, (png_infopp)&info, (png_infopp)&end_info); } - free((void*)context.data); free(rgb); return ok; } #else // !WEBP_HAVE_PNG -int ReadPNG(const char* const filename, struct WebPPicture* const pic, +int ReadPNG(const uint8_t* const data, size_t data_size, + struct WebPPicture* const pic, int keep_alpha, struct Metadata* const metadata) { - (void)filename; + (void)data; + (void)data_size; (void)pic; (void)keep_alpha; (void)metadata; diff --git a/examples/pngdec.h b/examples/pngdec.h index f04bf526..062da932 100644 --- a/examples/pngdec.h +++ b/examples/pngdec.h @@ -12,7 +12,7 @@ #ifndef WEBP_EXAMPLES_PNGDEC_H_ #define WEBP_EXAMPLES_PNGDEC_H_ -#include +#include "webp/types.h" #ifdef __cplusplus extern "C" { @@ -21,13 +21,13 @@ extern "C" { struct Metadata; struct WebPPicture; -// Reads a PNG from 'filename', returning the decoded output in 'pic'. -// If 'filename' is equal '-', input is read from stdin. +// Reads a PNG from 'data', returning the decoded output in 'pic'. // Output is RGBA or YUVA, depending on pic->use_argb value. // If 'keep_alpha' is true and the PNG has an alpha channel, the output is RGBA // or YUVA. Otherwise, alpha channel is dropped and output is RGB or YUV. // Returns true on success. -int ReadPNG(const char* const filename, struct WebPPicture* const pic, +int ReadPNG(const uint8_t* const data, size_t data_size, + struct WebPPicture* const pic, int keep_alpha, struct Metadata* const metadata); #ifdef __cplusplus diff --git a/examples/tiffdec.c b/examples/tiffdec.c index 4af9b9ee..dc980dd4 100644 --- a/examples/tiffdec.c +++ b/examples/tiffdec.c @@ -16,6 +16,7 @@ #endif #include +#include #ifdef WEBP_HAVE_TIFF #include @@ -63,17 +64,71 @@ static int ExtractMetadataFromTIFF(TIFF* const tif, Metadata* const metadata) { return 1; } -int ReadTIFF(const char* const filename, +// Ad-hoc structure to supply read-from-memory functionalities. +typedef struct { + const uint8_t* data; + toff_t size; + toff_t pos; +} MyData; + +static int MyClose(thandle_t opaque) { + (void)opaque; + return 0; +} + +static toff_t MySize(thandle_t opaque) { + const MyData* const my_data = (MyData*)opaque; + return my_data->size; +} + +static toff_t MySeek(thandle_t opaque, toff_t offset, int whence) { + MyData* const my_data = (MyData*)opaque; + offset += (whence == SEEK_CUR) ? my_data->pos + : (whence == SEEK_SET) ? 0 + : my_data->size; + if (offset > my_data->size) return (toff_t)-1; + my_data->pos = offset; + return offset; +} + +static int MyMapFile(thandle_t opaque, void** base, toff_t* size) { + (void)opaque; + (void)base; + (void)size; + return 0; +} +static void MyUnmapFile(thandle_t opaque, void* base, toff_t size) { + (void)opaque; + (void)base; + (void)size; +} + +static tsize_t MyRead(thandle_t opaque, void* dst, tsize_t size) { + MyData* const my_data = (MyData*)opaque; + if (my_data->pos + size > my_data->size) { + size = my_data->size - my_data->pos; + } + if (size > 0) { + memcpy(dst, my_data->data + my_data->pos, size); + my_data->pos += size; + } + return size; +} + +int ReadTIFF(const uint8_t* const data, size_t data_size, WebPPicture* const pic, int keep_alpha, Metadata* const metadata) { - TIFF* const tif = TIFFOpen(filename, "r"); + MyData my_data = { data, (toff_t)data_size, 0 }; + TIFF* const tif = TIFFClientOpen("Memory", "r", &my_data, + MyRead, MyRead, MySeek, MyClose, + MySize, MyMapFile, MyUnmapFile); uint32 width, height; uint32* raster; int ok = 0; tdir_t dircount; if (tif == NULL) { - fprintf(stderr, "Error! Cannot open TIFF file '%s'\n", filename); + fprintf(stderr, "Error! Cannot parse TIFF file\n"); return 0; } @@ -87,7 +142,7 @@ int ReadTIFF(const char* const filename, if (!(TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &width) && TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &height))) { fprintf(stderr, "Error! Cannot retrieve TIFF image dimensions.\n"); - return 0; + goto End; } raster = (uint32*)_TIFFmalloc(width * height * sizeof(*raster)); if (raster != NULL) { @@ -119,15 +174,16 @@ int ReadTIFF(const char* const filename, } } } - + End: TIFFClose(tif); return ok; } #else // !WEBP_HAVE_TIFF -int ReadTIFF(const char* const filename, +int ReadTIFF(const uint8_t* const data, size_t data_size, struct WebPPicture* const pic, int keep_alpha, struct Metadata* const metadata) { - (void)filename; + (void)data; + (void)data_size; (void)pic; (void)keep_alpha; (void)metadata; diff --git a/examples/tiffdec.h b/examples/tiffdec.h index 1e7d50a4..0dab8b83 100644 --- a/examples/tiffdec.h +++ b/examples/tiffdec.h @@ -12,6 +12,8 @@ #ifndef WEBP_EXAMPLES_TIFFDEC_H_ #define WEBP_EXAMPLES_TIFFDEC_H_ +#include "webp/types.h" + #ifdef __cplusplus extern "C" { #endif @@ -19,12 +21,12 @@ extern "C" { struct Metadata; struct WebPPicture; -// Reads a TIFF from 'filename', returning the decoded output in 'pic'. +// Reads a TIFF from 'data', returning the decoded output in 'pic'. // Output is RGBA or YUVA, depending on pic->use_argb value. // If 'keep_alpha' is true and the TIFF has an alpha channel, the output is RGBA // or YUVA. Otherwise, alpha channel is dropped and output is RGB or YUV. // Returns true on success. -int ReadTIFF(const char* const filename, +int ReadTIFF(const uint8_t* const data, size_t data_size, struct WebPPicture* const pic, int keep_alpha, struct Metadata* const metadata); diff --git a/examples/webpdec.c b/examples/webpdec.c index 93a26b1b..376451a3 100644 --- a/examples/webpdec.c +++ b/examples/webpdec.c @@ -19,11 +19,10 @@ #include "./example_util.h" #include "./metadata.h" -int ReadWebP(const char* const in_file, WebPPicture* const pic, +int ReadWebP(const uint8_t* const data, size_t data_size, + WebPPicture* const pic, int keep_alpha, Metadata* const metadata) { int ok = 0; - size_t data_size = 0; - const uint8_t* data = NULL; VP8StatusCode status = VP8_STATUS_OK; WebPDecoderConfig config; WebPDecBuffer* const output_buffer = &config.output; @@ -39,7 +38,12 @@ int ReadWebP(const char* const in_file, WebPPicture* const pic, return 0; } - if (ExUtilLoadWebP(in_file, &data, &data_size, bitstream)) { + status = WebPGetFeatures(data, data_size, bitstream); + if (status != VP8_STATUS_OK) { + ExUtilPrintWebPError("input data", status); + return 0; + } + { const int has_alpha = keep_alpha && bitstream->has_alpha; // TODO(skal): use MODE_YUV(A), depending on the expected // input pic->use_argb. This would save some conversion steps. @@ -57,10 +61,9 @@ int ReadWebP(const char* const in_file, WebPPicture* const pic, } if (status != VP8_STATUS_OK) { - ExUtilPrintWebPError(in_file, status); + ExUtilPrintWebPError("input data", status); } - free((void*)data); WebPFreeDecBuffer(output_buffer); return ok; } diff --git a/examples/webpdec.h b/examples/webpdec.h index 257c78c0..28eb628a 100644 --- a/examples/webpdec.h +++ b/examples/webpdec.h @@ -12,6 +12,8 @@ #ifndef WEBP_EXAMPLES_WEBPDEC_H_ #define WEBP_EXAMPLES_WEBPDEC_H_ +#include "webp/types.h" + #ifdef __cplusplus extern "C" { #endif @@ -24,7 +26,8 @@ struct WebPPicture; // If 'keep_alpha' is true and the WebP has an alpha channel, the output is RGBA // or YUVA. Otherwise, alpha channel is dropped and output is RGB or YUV. // Returns true on success. -int ReadWebP(const char* const in_file, struct WebPPicture* const pic, +int ReadWebP(const uint8_t* const data, size_t data_size, + struct WebPPicture* const pic, int keep_alpha, struct Metadata* const metadata); #ifdef __cplusplus