make ReadPNG and ReadJPEG take a filename instead of a FILE

-> read is a bit slower (memory allocation and such) than reading directly from disk.

-> we're not yet ready to accept stdin as input (-- -) because we still need to guess
the file type with GetImageType(). And since we can't rewind on stdin, this will need
a bit more work before being able to read from stdin.

Change-Id: I6491fac4b07d28d1854518325ead88669656ddbf
This commit is contained in:
Pascal Massimino 2015-12-06 09:23:17 +01:00
parent d478e58960
commit 4c60f63c64
5 changed files with 98 additions and 23 deletions

View File

@ -155,9 +155,9 @@ static int ReadPicture(const char* const filename, WebPPicture* const pic,
} }
format = GetImageType(in_file); format = GetImageType(in_file);
if (format == PNG_) { if (format == PNG_) {
ok = ReadPNG(in_file, pic, keep_alpha, metadata); ok = ReadPNG(filename, pic, keep_alpha, metadata);
} else if (format == JPEG_) { } else if (format == JPEG_) {
ok = ReadJPEG(in_file, pic, metadata); ok = ReadJPEG(filename, pic, metadata);
} else if (format == TIFF_) { } else if (format == TIFF_) {
ok = ReadTIFF(filename, pic, keep_alpha, metadata); ok = ReadTIFF(filename, pic, keep_alpha, metadata);
} else if (format == WEBP_) { } else if (format == WEBP_) {

View File

@ -19,11 +19,13 @@
#ifdef WEBP_HAVE_JPEG #ifdef WEBP_HAVE_JPEG
#include <jpeglib.h> #include <jpeglib.h>
#include <jerror.h>
#include <setjmp.h> #include <setjmp.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include "webp/encode.h" #include "webp/encode.h"
#include "./example_util.h"
#include "./metadata.h" #include "./metadata.h"
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
@ -208,13 +210,64 @@ static void my_error_exit(j_common_ptr dinfo) {
longjmp(myerr->setjmp_buffer, 1); longjmp(myerr->setjmp_buffer, 1);
} }
int ReadJPEG(FILE* in_file, WebPPicture* const pic, Metadata* const metadata) { typedef struct {
int ok = 0; struct jpeg_source_mgr pub;
const uint8_t* data;
size_t data_size;
} JPEGReadContext;
static void ContextInit(j_decompress_ptr cinfo) {
JPEGReadContext* const ctx = (JPEGReadContext*)cinfo->src;
ctx->pub.next_input_byte = ctx->data;
ctx->pub.bytes_in_buffer = ctx->data_size;
}
static int ContextFill(j_decompress_ptr cinfo) {
// we shouldn't get here.
ERREXIT(cinfo, JERR_FILE_READ);
return 0;
}
static void ContextSkip(j_decompress_ptr cinfo, long jump_size) {
JPEGReadContext* const ctx = (JPEGReadContext*)cinfo->src;
size_t jump = (size_t)jump_size;
if (jump > ctx->pub.bytes_in_buffer) { // Don't overflow the buffer.
jump = ctx->pub.bytes_in_buffer;
}
ctx->pub.bytes_in_buffer -= jump;
ctx->pub.next_input_byte += jump;
}
static void ContextTerm(j_decompress_ptr cinfo) {
(void)cinfo;
}
static void ContextSetup(volatile struct jpeg_decompress_struct* const cinfo,
JPEGReadContext* const ctx) {
cinfo->src = (struct jpeg_source_mgr*)ctx;
ctx->pub.init_source = ContextInit;
ctx->pub.fill_input_buffer = ContextFill;
ctx->pub.skip_input_data = ContextSkip;
ctx->pub.resync_to_restart = jpeg_resync_to_restart;
ctx->pub.term_source = ContextTerm;
ctx->pub.bytes_in_buffer = 0;
ctx->pub.next_input_byte = NULL;
}
int ReadJPEG(const char* const filename, WebPPicture* const pic,
Metadata* const metadata) {
volatile int ok = 0;
int stride, width, height; int stride, width, height;
volatile struct jpeg_decompress_struct dinfo; volatile struct jpeg_decompress_struct dinfo;
struct my_error_mgr jerr; struct my_error_mgr jerr;
uint8_t* volatile rgb = NULL; uint8_t* volatile rgb = NULL;
JSAMPROW buffer[1]; JSAMPROW buffer[1];
JPEGReadContext ctx;
memset(&ctx, 0, sizeof(ctx));
ok = ExUtilReadFile(filename, &ctx.data, &ctx.data_size);
if (!ok) goto End;
memset((j_decompress_ptr)&dinfo, 0, sizeof(dinfo)); // for setjmp sanity memset((j_decompress_ptr)&dinfo, 0, sizeof(dinfo)); // for setjmp sanity
dinfo.err = jpeg_std_error(&jerr.pub); dinfo.err = jpeg_std_error(&jerr.pub);
@ -228,7 +281,7 @@ int ReadJPEG(FILE* in_file, WebPPicture* const pic, Metadata* const metadata) {
} }
jpeg_create_decompress((j_decompress_ptr)&dinfo); jpeg_create_decompress((j_decompress_ptr)&dinfo);
jpeg_stdio_src((j_decompress_ptr)&dinfo, in_file); ContextSetup(&dinfo, &ctx);
if (metadata != NULL) SaveMetadataMarkers((j_decompress_ptr)&dinfo); if (metadata != NULL) SaveMetadataMarkers((j_decompress_ptr)&dinfo);
jpeg_read_header((j_decompress_ptr)&dinfo, TRUE); jpeg_read_header((j_decompress_ptr)&dinfo, TRUE);
@ -277,12 +330,14 @@ int ReadJPEG(FILE* in_file, WebPPicture* const pic, Metadata* const metadata) {
End: End:
free(rgb); free(rgb);
free((void*)ctx.data);
return ok; return ok;
} }
#else // !WEBP_HAVE_JPEG #else // !WEBP_HAVE_JPEG
int ReadJPEG(FILE* in_file, struct WebPPicture* const pic, int ReadJPEG(const char* const filename,
struct WebPPicture* const pic,
struct Metadata* const metadata) { struct Metadata* const metadata) {
(void)in_file; (void)filename;
(void)pic; (void)pic;
(void)metadata; (void)metadata;
fprintf(stderr, "JPEG support not compiled. Please install the libjpeg " fprintf(stderr, "JPEG support not compiled. Please install the libjpeg "

View File

@ -22,10 +22,11 @@ extern "C" {
struct Metadata; struct Metadata;
struct WebPPicture; struct WebPPicture;
// Reads a JPEG from 'in_file', returning the decoded output in 'pic'. // Reads a JPEG from 'filename', returning the decoded output in 'pic'.
// If 'filename' is equal '-', input is read from stdin.
// The output is RGB or YUV depending on pic->use_argb value. // The output is RGB or YUV depending on pic->use_argb value.
// Returns true on success. // Returns true on success.
int ReadJPEG(FILE* in_file, struct WebPPicture* const pic, int ReadJPEG(const char* const filename, struct WebPPicture* const pic,
struct Metadata* const metadata); struct Metadata* const metadata);
#ifdef __cplusplus #ifdef __cplusplus

View File

@ -18,12 +18,14 @@
#include <stdio.h> #include <stdio.h>
#ifdef WEBP_HAVE_PNG #ifdef WEBP_HAVE_PNG
#include <assert.h>
#include <png.h> #include <png.h>
#include <setjmp.h> // note: this must be included *after* png.h #include <setjmp.h> // note: this must be included *after* png.h
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include "webp/encode.h" #include "webp/encode.h"
#include "./example_util.h"
#include "./metadata.h" #include "./metadata.h"
static void PNGAPI error_function(png_structp png, png_const_charp error) { static void PNGAPI error_function(png_structp png, png_const_charp error) {
@ -188,24 +190,39 @@ static int ExtractMetadataFromPNG(png_structp png,
return 1; return 1;
} }
int ReadPNG(FILE* in_file, WebPPicture* const pic, int keep_alpha, typedef struct {
Metadata* const metadata) { const uint8_t* data;
volatile png_structp png; size_t data_size;
png_size_t offset;
} PNGReadContext;
static void ReadFunc(png_structp png_ptr, png_bytep data, png_size_t length) {
PNGReadContext* const ctx = (PNGReadContext*)png_get_io_ptr(png_ptr);
assert(ctx->offset + length <= ctx->data_size);
memcpy(data, ctx->data + ctx->offset, length);
ctx->offset += length;
}
int ReadPNG(const char* const filename, struct WebPPicture* const pic,
int keep_alpha, struct Metadata* const metadata) {
volatile png_structp png = NULL;
volatile png_infop info = NULL; volatile png_infop info = NULL;
volatile png_infop end_info = NULL; volatile png_infop end_info = NULL;
PNGReadContext context = { NULL, 0, 0 };
int color_type, bit_depth, interlaced; int color_type, bit_depth, interlaced;
int has_alpha; int has_alpha;
int num_passes; int num_passes;
int p; int p;
int ok = 0; volatile int ok = 0;
png_uint_32 width, height, y; png_uint_32 width, height, y;
png_uint_32 stride; png_uint_32 stride;
uint8_t* volatile rgb = NULL; uint8_t* volatile rgb = NULL;
ok = ExUtilReadFile(filename, &context.data, &context.data_size);
if (!ok) goto End;
png = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0); png = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
if (png == NULL) { if (png == NULL) goto End;
goto End;
}
png_set_error_fn(png, 0, error_function, NULL); png_set_error_fn(png, 0, error_function, NULL);
if (setjmp(png_jmpbuf(png))) { if (setjmp(png_jmpbuf(png))) {
@ -219,7 +236,7 @@ int ReadPNG(FILE* in_file, WebPPicture* const pic, int keep_alpha,
end_info = png_create_info_struct(png); end_info = png_create_info_struct(png);
if (end_info == NULL) goto Error; if (end_info == NULL) goto Error;
png_init_io(png, in_file); png_set_read_fn(png, &context, ReadFunc);
png_read_info(png, info); png_read_info(png, info);
if (!png_get_IHDR(png, info, if (!png_get_IHDR(png, info,
&width, &height, &bit_depth, &color_type, &interlaced, &width, &height, &bit_depth, &color_type, &interlaced,
@ -282,13 +299,14 @@ int ReadPNG(FILE* in_file, WebPPicture* const pic, int keep_alpha,
png_destroy_read_struct((png_structpp)&png, png_destroy_read_struct((png_structpp)&png,
(png_infopp)&info, (png_infopp)&end_info); (png_infopp)&info, (png_infopp)&end_info);
} }
free((void*)context.data);
free(rgb); free(rgb);
return ok; return ok;
} }
#else // !WEBP_HAVE_PNG #else // !WEBP_HAVE_PNG
int ReadPNG(FILE* in_file, struct WebPPicture* const pic, int keep_alpha, int ReadPNG(const char* const filename, struct WebPPicture* const pic,
struct Metadata* const metadata) { int keep_alpha, struct Metadata* const metadata) {
(void)in_file; (void)filename;
(void)pic; (void)pic;
(void)keep_alpha; (void)keep_alpha;
(void)metadata; (void)metadata;

View File

@ -21,13 +21,14 @@ extern "C" {
struct Metadata; struct Metadata;
struct WebPPicture; struct WebPPicture;
// Reads a PNG from 'in_file', returning the decoded output in 'pic'. // Reads a PNG from 'filename', returning the decoded output in 'pic'.
// If 'filename' is equal '-', input is read from stdin.
// Output is RGBA or YUVA, depending on pic->use_argb value. // 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 // 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. // or YUVA. Otherwise, alpha channel is dropped and output is RGB or YUV.
// Returns true on success. // Returns true on success.
int ReadPNG(FILE* in_file, struct WebPPicture* const pic, int keep_alpha, int ReadPNG(const char* const filename, struct WebPPicture* const pic,
struct Metadata* const metadata); int keep_alpha, struct Metadata* const metadata);
#ifdef __cplusplus #ifdef __cplusplus
} // extern "C" } // extern "C"