ext/webp_ffi/util.c in webp-ffi-0.1.0 vs ext/webp_ffi/util.c in webp-ffi-0.1.1

- old
+ new

@@ -7,10 +7,12 @@ #include <png.h> #include <setjmp.h> // note: this must be included *after* png.h #include <jpeglib.h> +#include <tiffio.h> + #include "webp/decode.h" #include "webp/encode.h" #if defined(__cplusplus) || defined(c_plusplus) extern "C" { @@ -44,10 +46,92 @@ End: return ok; } +struct my_error_mgr { + struct jpeg_error_mgr pub; + jmp_buf setjmp_buffer; +}; + +static void my_error_exit(j_common_ptr dinfo) { + struct my_error_mgr* myerr = (struct my_error_mgr*) dinfo->err; + (*dinfo->err->output_message) (dinfo); + longjmp(myerr->setjmp_buffer, 1); +} + +static int UtilReadJPEG(FILE* in_file, WebPPicture* const pic) { + int ok = 0; + int stride, width, height; + uint8_t* rgb = NULL; + uint8_t* row_ptr = NULL; + struct jpeg_decompress_struct dinfo; + struct my_error_mgr jerr; + JSAMPARRAY buffer; + + dinfo.err = jpeg_std_error(&jerr.pub); + jerr.pub.error_exit = my_error_exit; + + if (setjmp(jerr.setjmp_buffer)) { + Error: + jpeg_destroy_decompress(&dinfo); + goto End; + } + + jpeg_create_decompress(&dinfo); + jpeg_stdio_src(&dinfo, in_file); + jpeg_read_header(&dinfo, TRUE); + + dinfo.out_color_space = JCS_RGB; + dinfo.dct_method = JDCT_IFAST; + dinfo.do_fancy_upsampling = TRUE; + + jpeg_start_decompress(&dinfo); + + if (dinfo.output_components != 3) { + goto Error; + } + + width = dinfo.output_width; + height = dinfo.output_height; + stride = dinfo.output_width * dinfo.output_components * sizeof(*rgb); + + rgb = (uint8_t*)malloc(stride * height); + if (rgb == NULL) { + goto End; + } + row_ptr = rgb; + + buffer = (*dinfo.mem->alloc_sarray) ((j_common_ptr) &dinfo, + JPOOL_IMAGE, stride, 1); + if (buffer == NULL) { + goto End; + } + + while (dinfo.output_scanline < dinfo.output_height) { + if (jpeg_read_scanlines(&dinfo, buffer, 1) != 1) { + goto End; + } + memcpy(row_ptr, buffer[0], stride); + row_ptr += stride; + } + + jpeg_finish_decompress(&dinfo); + jpeg_destroy_decompress(&dinfo); + + // WebP conversion. + pic->width = width; + pic->height = height; + ok = WebPPictureImportRGB(pic, rgb, stride); + + End: + if (rgb) { + free(rgb); + } + return ok; +} + static void PNGAPI error_function(png_structp png, png_const_charp dummy) { (void)dummy; // remove variable-unused warning longjmp(png_jmpbuf(png), 1); } @@ -172,10 +256,61 @@ png_write_end(png, info); png_destroy_write_struct(&png, &info); return 1; } +static int UtilReadTIFF(const char* const filename, + WebPPicture* const pic, int keep_alpha) { + TIFF* const tif = TIFFOpen(filename, "r"); + uint32 width, height; + uint32* raster; + int ok = 0; + int dircount = 1; + + if (tif == NULL) { + fprintf(stderr, "Error! Cannot open TIFF file '%s'\n", filename); + return 0; + } + + while (TIFFReadDirectory(tif)) ++dircount; + + if (dircount > 1) { + fprintf(stderr, "Warning: multi-directory TIFF files are not supported.\n" + "Only the first will be used, %d will be ignored.\n", + dircount - 1); + } + + TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &width); + TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &height); + raster = (uint32*)_TIFFmalloc(width * height * sizeof(*raster)); + if (raster != NULL) { + if (TIFFReadRGBAImageOriented(tif, width, height, raster, + ORIENTATION_TOPLEFT, 1)) { + const int stride = width * sizeof(*raster); + pic->width = width; + pic->height = height; + // TIFF data is ABGR +#ifdef __BIG_ENDIAN__ + TIFFSwabArrayOfLong(raster, width * height); +#endif + ok = keep_alpha + ? WebPPictureImportRGBA(pic, (const uint8_t*)raster, stride) + : WebPPictureImportRGBX(pic, (const uint8_t*)raster, stride); + } + _TIFFfree(raster); + } else { + fprintf(stderr, "Error allocating TIFF RGBA memory!\n"); + } + + if (ok && keep_alpha == 2) { + WebPCleanupTransparentArea(pic); + } + + TIFFClose(tif); + return ok; +} + static InputFileFormat GetImageType(FILE* in_file) { InputFileFormat format = UNSUPPORTED; unsigned int magic; unsigned char buf[4]; @@ -207,18 +342,15 @@ if (pic->width == 0 || pic->height == 0) { // If no size specified, try to decode it as PNG/JPEG (as appropriate). const InputFileFormat format = GetImageType(in_file); if (format == PNG_) { ok = UtilReadPNG(in_file, pic, keep_alpha); - } - /* } else if (format == JPEG_) { - ok = ReadJPEG(in_file, pic); + ok = UtilReadJPEG(in_file, pic); } else if (format == TIFF_) { - ok = ReadTIFF(filename, pic, keep_alpha); + ok = UtilReadTIFF(filename, pic, keep_alpha); } - */ } else { // If image size is specified, infer it as YUV format. ok = UtilReadYUV(in_file, pic); } if (!ok) { @@ -227,11 +359,11 @@ fclose(in_file); return ok; } -void UtilSaveOutput(const WebPDecBuffer* const buffer, +int UtilSaveOutput(const WebPDecBuffer* const buffer, OutputFileFormat format, const char* const out_file) { FILE* fout = NULL; int ok = 1; fout = fopen(out_file, "wb"); @@ -255,14 +387,10 @@ } */ if (fout) { fclose(fout); } - if (ok) { - printf("Saved file %s\n", out_file); - } else { - fprintf(stderr, "Error writing file %s !!\n", out_file); - } + return ok; } // ----------------------------------------------------------------------------- // File I/O