efl/src/modules/evas/image_savers/png/evas_image_save_png.c

187 lines
4.5 KiB
C

#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <stdio.h>
#include <png.h>
#include <setjmp.h>
#ifdef HAVE_EVIL
# include <Evil.h>
#endif
#include "evas_common_private.h"
#include "evas_private.h"
static int evas_image_save_file_png(RGBA_Image *im, const char *file, const char *key, int quality, int compress, const char *encoding);
static Evas_Image_Save_Func evas_image_save_png_func =
{
evas_image_save_file_png
};
static int
save_image_png(RGBA_Image *im, const char *file, int do_compress, int interlace)
{
FILE *f;
png_structp png_ptr;
png_infop info_ptr;
DATA32 *ptr, *data = NULL;
unsigned int x, y, j;
png_bytep row_ptr, png_data = NULL;
png_color_8 sig_bit;
int num_passes = 1, pass;
if (!im || !im->image.data || !file)
return 0;
f = fopen(file, "wb");
if (!f) return 0;
png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
if (!png_ptr)
goto close_file;
info_ptr = png_create_info_struct(png_ptr);
if (!info_ptr)
{
png_destroy_write_struct(&png_ptr, NULL);
goto close_file;
}
if (setjmp(png_jmpbuf(png_ptr)))
{
png_destroy_write_struct(&png_ptr, (png_infopp) & info_ptr);
png_destroy_info_struct(png_ptr, (png_infopp) & info_ptr);
goto close_file;
}
if (interlace)
{
#ifdef PNG_WRITE_INTERLACING_SUPPORTED
interlace = PNG_INTERLACE_ADAM7;
#else
interlace = PNG_INTERLACE_NONE;
#endif
}
else
interlace = PNG_INTERLACE_NONE;
if (im->cache_entry.flags.alpha)
{
data = malloc(im->cache_entry.w * im->cache_entry.h * sizeof(DATA32));
if (!data)
{
png_destroy_write_struct(&png_ptr, (png_infopp) & info_ptr);
png_destroy_info_struct(png_ptr, (png_infopp) & info_ptr);
goto close_file;
}
memcpy(data, im->image.data, im->cache_entry.w * im->cache_entry.h * sizeof(DATA32));
evas_common_convert_argb_unpremul(data, im->cache_entry.w * im->cache_entry.h);
png_init_io(png_ptr, f);
png_set_IHDR(png_ptr, info_ptr, im->cache_entry.w, im->cache_entry.h, 8,
PNG_COLOR_TYPE_RGB_ALPHA, interlace,
PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
#ifdef WORDS_BIGENDIAN
png_set_swap_alpha(png_ptr);
#else
png_set_bgr(png_ptr);
#endif
}
else
{
data = im->image.data;
png_init_io(png_ptr, f);
png_set_IHDR(png_ptr, info_ptr, im->cache_entry.w, im->cache_entry.h, 8,
PNG_COLOR_TYPE_RGB, interlace,
PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
png_data = alloca(im->cache_entry.w * 3 * sizeof(char));
}
sig_bit.red = 8;
sig_bit.green = 8;
sig_bit.blue = 8;
sig_bit.alpha = 8;
png_set_sBIT(png_ptr, info_ptr, &sig_bit);
png_set_compression_level(png_ptr, do_compress);
png_write_info(png_ptr, info_ptr);
png_set_shift(png_ptr, &sig_bit);
png_set_packing(png_ptr);
#ifdef PNG_WRITE_INTERLACING_SUPPORTED
num_passes = png_set_interlace_handling(png_ptr);
#endif
for (pass = 0; pass < num_passes; pass++)
{
ptr = data;
for (y = 0; y < im->cache_entry.h; y++)
{
if (im->cache_entry.flags.alpha)
row_ptr = (png_bytep) ptr;
else
{
for (j = 0, x = 0; x < im->cache_entry.w; x++)
{
png_data[j++] = (ptr[x] >> 16) & 0xff;
png_data[j++] = (ptr[x] >> 8) & 0xff;
png_data[j++] = (ptr[x]) & 0xff;
}
row_ptr = (png_bytep) png_data;
}
png_write_rows(png_ptr, &row_ptr, 1);
ptr += im->cache_entry.w;
}
}
png_write_end(png_ptr, info_ptr);
png_destroy_write_struct(&png_ptr, (png_infopp) & info_ptr);
png_destroy_info_struct(png_ptr, (png_infopp) & info_ptr);
if (im->cache_entry.flags.alpha)
free(data);
fclose(f);
return 1;
close_file:
fclose(f);
return 0;
}
static int
evas_image_save_file_png(RGBA_Image *im, const char *file, const char *key EINA_UNUSED,
int quality EINA_UNUSED, int do_compress, const char *encoding EINA_UNUSED)
{
return save_image_png(im, file, do_compress, 0);
}
static int
module_open(Evas_Module *em)
{
if (!em) return 0;
em->functions = (void *)(&evas_image_save_png_func);
return 1;
}
static void
module_close(Evas_Module *em EINA_UNUSED)
{
}
static Evas_Module_Api evas_modapi =
{
EVAS_MODULE_API_VERSION,
"png",
"none",
{
module_open,
module_close
}
};
EVAS_MODULE_DEFINE(EVAS_MODULE_TYPE_IMAGE_SAVER, image_saver, png);
#ifndef EVAS_STATIC_BUILD_PNG
EVAS_EINA_MODULE_DEFINE(image_saver, png);
#endif