ext/webp_ffi/util.c in webp-ffi-0.0.1 vs ext/webp_ffi/util.c in webp-ffi-0.1.0
- old
+ new
@@ -1,16 +1,274 @@
#include "./util.h"
+#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
+#include <string.h>
+#include <png.h>
+
+#include <setjmp.h> // note: this must be included *after* png.h
+#include <jpeglib.h>
+
+#include "webp/decode.h"
+#include "webp/encode.h"
+
#if defined(__cplusplus) || defined(c_plusplus)
extern "C" {
#endif
+static int UtilReadYUV(FILE* in_file, WebPPicture* const pic) {
+ const int use_argb = pic->use_argb;
+ const int uv_width = (pic->width + 1) / 2;
+ const int uv_height = (pic->height + 1) / 2;
+ int y;
+ int ok = 0;
+
+ pic->use_argb = 0;
+ if (!WebPPictureAlloc(pic)) return ok;
+
+ for (y = 0; y < pic->height; ++y) {
+ if (fread(pic->y + y * pic->y_stride, pic->width, 1, in_file) != 1) {
+ goto End;
+ }
+ }
+ for (y = 0; y < uv_height; ++y) {
+ if (fread(pic->u + y * pic->uv_stride, uv_width, 1, in_file) != 1)
+ goto End;
+ }
+ for (y = 0; y < uv_height; ++y) {
+ if (fread(pic->v + y * pic->uv_stride, uv_width, 1, in_file) != 1)
+ goto End;
+ }
+ ok = 1;
+ if (use_argb) ok = WebPPictureYUVAToARGB(pic);
+
+ End:
+ 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);
+}
+
+static int UtilReadPNG(FILE* in_file, WebPPicture* const pic, int keep_alpha) {
+ png_structp png;
+ png_infop info;
+ int color_type, bit_depth, interlaced;
+ int has_alpha;
+ int num_passes;
+ int p;
+ int ok = 0;
+ png_uint_32 width, height, y;
+ int stride;
+ uint8_t* rgb = NULL;
+
+ png = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
+ if (png == NULL) {
+ goto End;
+ }
+
+ png_set_error_fn(png, 0, error_function, NULL);
+ if (setjmp(png_jmpbuf(png))) {
+ Error:
+ png_destroy_read_struct(&png, NULL, NULL);
+ free(rgb);
+ goto End;
+ }
+
+ info = png_create_info_struct(png);
+ if (info == NULL) goto Error;
+
+ png_init_io(png, in_file);
+ png_read_info(png, info);
+ if (!png_get_IHDR(png, info,
+ &width, &height, &bit_depth, &color_type, &interlaced,
+ NULL, NULL)) goto Error;
+
+ png_set_strip_16(png);
+ png_set_packing(png);
+ if (color_type == PNG_COLOR_TYPE_PALETTE) png_set_palette_to_rgb(png);
+ if (color_type == PNG_COLOR_TYPE_GRAY ||
+ color_type == PNG_COLOR_TYPE_GRAY_ALPHA) {
+ if (bit_depth < 8) {
+ png_set_expand_gray_1_2_4_to_8(png);
+ }
+ png_set_gray_to_rgb(png);
+ }
+ if (png_get_valid(png, info, PNG_INFO_tRNS)) {
+ png_set_tRNS_to_alpha(png);
+ has_alpha = 1;
+ } else {
+ has_alpha = !!(color_type & PNG_COLOR_MASK_ALPHA);
+ }
+
+ if (!keep_alpha) {
+ png_set_strip_alpha(png);
+ has_alpha = 0;
+ }
+
+ num_passes = png_set_interlace_handling(png);
+ png_read_update_info(png, info);
+ stride = (has_alpha ? 4 : 3) * width * sizeof(*rgb);
+ rgb = (uint8_t*)malloc(stride * height);
+ if (rgb == NULL) goto Error;
+ for (p = 0; p < num_passes; ++p) {
+ for (y = 0; y < height; ++y) {
+ png_bytep row = rgb + y * stride;
+ png_read_rows(png, &row, NULL, 1);
+ }
+ }
+ png_read_end(png, info);
+ png_destroy_read_struct(&png, &info, NULL);
+
+ pic->width = width;
+ pic->height = height;
+ ok = has_alpha ? WebPPictureImportRGBA(pic, rgb, stride)
+ : WebPPictureImportRGB(pic, rgb, stride);
+ free(rgb);
+
+ if (ok && has_alpha && keep_alpha == 2) {
+ WebPCleanupTransparentArea(pic);
+ }
+
+ End:
+ return ok;
+}
+
+static int UtilWritePNG(FILE* out_file, const WebPDecBuffer* const buffer) {
+ const uint32_t width = buffer->width;
+ const uint32_t height = buffer->height;
+ unsigned char* const rgb = buffer->u.RGBA.rgba;
+ const int stride = buffer->u.RGBA.stride;
+ const int has_alpha = (buffer->colorspace == MODE_RGBA);
+ png_structp png;
+ png_infop info;
+ png_uint_32 y;
+
+ png = png_create_write_struct(PNG_LIBPNG_VER_STRING,
+ NULL, error_function, NULL);
+ if (png == NULL) {
+ return 0;
+ }
+ info = png_create_info_struct(png);
+ if (info == NULL) {
+ png_destroy_write_struct(&png, NULL);
+ return 0;
+ }
+ if (setjmp(png_jmpbuf(png))) {
+ png_destroy_write_struct(&png, &info);
+ return 0;
+ }
+ png_init_io(png, out_file);
+ png_set_IHDR(png, info, width, height, 8,
+ has_alpha ? PNG_COLOR_TYPE_RGBA : PNG_COLOR_TYPE_RGB,
+ PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT,
+ PNG_FILTER_TYPE_DEFAULT);
+ png_write_info(png, info);
+ for (y = 0; y < height; ++y) {
+ png_bytep row = rgb + y * stride;
+ png_write_rows(png, &row, 1);
+ }
+ png_write_end(png, info);
+ png_destroy_write_struct(&png, &info);
+ return 1;
+}
+
+static InputFileFormat GetImageType(FILE* in_file) {
+ InputFileFormat format = UNSUPPORTED;
+ unsigned int magic;
+ unsigned char buf[4];
+
+ if ((fread(&buf[0], 4, 1, in_file) != 1) ||
+ (fseek(in_file, 0, SEEK_SET) != 0)) {
+ return format;
+ }
+
+ magic = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
+ if (magic == 0x89504E47U) {
+ format = PNG_;
+ } else if (magic >= 0xFFD8FF00U && magic <= 0xFFD8FFFFU) {
+ format = JPEG_;
+ } else if (magic == 0x49492A00 || magic == 0x4D4D002A) {
+ format = TIFF_;
+ }
+ return format;
+}
+
+int UtilReadPicture(const char* const filename, WebPPicture* const pic,
+ int keep_alpha) {
+ int ok = 0;
+ FILE* in_file = fopen(filename, "rb");
+ if (in_file == NULL) {
+ fprintf(stderr, "Error! Cannot open input file '%s'\n", filename);
+ return ok;
+ }
+
+ 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);
+ } else if (format == TIFF_) {
+ ok = ReadTIFF(filename, pic, keep_alpha);
+ }
+ */
+ } else {
+ // If image size is specified, infer it as YUV format.
+ ok = UtilReadYUV(in_file, pic);
+ }
+ if (!ok) {
+ fprintf(stderr, "Error! Could not process file %s\n", filename);
+ }
+
+ fclose(in_file);
+ return ok;
+}
+
+void UtilSaveOutput(const WebPDecBuffer* const buffer,
+ OutputFileFormat format, const char* const out_file) {
+ FILE* fout = NULL;
+ int ok = 1;
+
+ fout = fopen(out_file, "wb");
+ if (!fout) {
+ fprintf(stderr, "Error opening output file %s\n", out_file);
+ return;
+ }
+
+ if (format == PNG) {
+ ok &= UtilWritePNG(fout, buffer);
+ }
+ /*
+ } else if (format == PAM) {
+ ok &= WritePPM(fout, buffer, 1);
+ } else if (format == PPM) {
+ ok &= WritePPM(fout, buffer, 0);
+ } else if (format == PGM) {
+ ok &= WritePGM(fout, buffer);
+ } else if (format == ALPHA_PLANE_ONLY) {
+ ok &= WriteAlphaPlane(fout, buffer);
+ }
+ */
+ if (fout) {
+ fclose(fout);
+ }
+ if (ok) {
+ printf("Saved file %s\n", out_file);
+ } else {
+ fprintf(stderr, "Error writing file %s !!\n", out_file);
+ }
+}
+
// -----------------------------------------------------------------------------
// File I/O
-int WebpFfiReadFile(const char* const file_name,
+int UtilReadFile(const char* const file_name,
const uint8_t** data, size_t* data_size) {
int ok;
void* file_data;
size_t file_size;
FILE* in;