Skip to content

Instantly share code, notes, and snippets.

@c4pt0r
Created June 26, 2014 09:42
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save c4pt0r/4758304c22673d909492 to your computer and use it in GitHub Desktop.
Save c4pt0r/4758304c22673d909492 to your computer and use it in GitHub Desktop.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <png.h>
#include <webp/encode.h>
#include <webp/mux.h>
static void PNGAPI error_function(png_structp png, png_const_charp dummy) {
(void)dummy; // remove variable-unused warning
longjmp(png_jmpbuf(png), 1);
}
/* read png file into webpicture */
static int ReadPNG(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;
}
if (keep_alpha && has_alpha) {
pic->colorspace |= WEBP_CSP_ALPHA_BIT;
}
num_passes = png_set_interlace_handling(png);
png_read_update_info(png, info);
stride = ((keep_alpha && 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 = (keep_alpha && has_alpha) ?
WebPPictureImportRGBA(pic, rgb, stride) :
WebPPictureImportRGB(pic, rgb, stride);
free(rgb);
End:
return ok;
}
static int FileWriter(const uint8_t* data, size_t data_size,
const WebPPicture* const pic) {
FILE* const out = (FILE*)pic->custom_ptr;
return data_size ? (fwrite(data, data_size, 1, out) == 1) : 1;
}
int PNG2WebP(const char* in, int q, uint8_t** out, size_t* out_sz) {
WebPPicture picture;
WebPConfig config;
WebPAuxStats stats;
WebPMemoryWriter memory_writer;
WebPMux* mux = NULL;
WebPMux* mux_single = NULL;
FILE* in_file;
FILE* out_file;
int keep_alpha = 1;
int alpha_q = 100;
int alpha_method = 1;
uint8_t* compressed_alpha = NULL;
size_t compressed_alpha_size = 0;
uint8_t* compressed_rgb = NULL;
size_t compressed_rgb_size = 0;
int ret = 0;
if (!WebPPictureInit(&picture) || !WebPConfigInit(&config)) {
ret = -1;
goto Error;
}
config.quality = q;
in_file = fopen(in, "rb");
if (!ReadPNG(in_file, &picture, keep_alpha)) {
ret = -2;
goto Error;
}
WebPMemoryWriterInit(&memory_writer);
picture.writer = WebPMemoryWrite;
picture.custom_ptr = (void*)&memory_writer;
//out_file = fopen("out.webp", "wb");
//picture.writer = FileWriter;
//picture.custom_ptr = (void*)out_file;
if (!WebPEncode(&config, &picture)) {
ret = -3;
goto Error;
}
*out_sz = memory_writer.size;
*out = (uint8_t*)malloc(memory_writer.size);
memcpy(*out, memory_writer.mem, memory_writer.size);
Error:
WebPPictureFree(&picture);
fclose(in_file);
return ret;
}
int main(int argc, const char *argv[]) {
uint8_t* out = NULL;
size_t sz = 0;
if (PNG2WebP(argv[1], 90, &out, &sz) == 0) {
printf("%ld", sz);
free(out);
}
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment