Alien-FreeImage
view release on metacpan or search on metacpan
src/Source/FreeImage/PluginPNG.cpp view on Meta::CPAN
// PNG Loader and Writer
//
// Design and implementation by
// - Floris van den Berg (flvdberg@wxs.nl)
// - Herve Drolon (drolon@infonie.fr)
// - Detlev Vendt (detlev.vendt@brillit.de)
// - Aaron Shumate (trek@startreker.com)
// - Tanner Helland (tannerhelland@users.sf.net)
//
// This file is part of FreeImage 3
//
// COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTY
// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES
// THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE
// OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED
// CODE IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT
// THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY
// SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL
// PART OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER
// THIS DISCLAIMER.
//
// Use at your own risk!
// ==========================================================
#ifdef _MSC_VER
#pragma warning (disable : 4786) // identifier was truncated to 'number' characters
#endif
#include "FreeImage.h"
#include "Utilities.h"
#include "../Metadata/FreeImageTag.h"
// ----------------------------------------------------------
#define PNG_BYTES_TO_CHECK 8
#undef PNG_Z_DEFAULT_COMPRESSION // already used in ../LibPNG/pnglibconf.h
// ----------------------------------------------------------
#include "../ZLib/zlib.h"
#include "../LibPNG/png.h"
// ----------------------------------------------------------
typedef struct {
FreeImageIO *s_io;
fi_handle s_handle;
} fi_ioStructure, *pfi_ioStructure;
// ==========================================================
// libpng interface
// ==========================================================
static void
_ReadProc(png_structp png_ptr, unsigned char *data, png_size_t size) {
pfi_ioStructure pfio = (pfi_ioStructure)png_get_io_ptr(png_ptr);
unsigned n = pfio->s_io->read_proc(data, (unsigned int)size, 1, pfio->s_handle);
if(size && (n == 0)) {
throw "Read error: invalid or corrupted PNG file";
}
}
static void
_WriteProc(png_structp png_ptr, unsigned char *data, png_size_t size) {
pfi_ioStructure pfio = (pfi_ioStructure)png_get_io_ptr(png_ptr);
pfio->s_io->write_proc(data, (unsigned int)size, 1, pfio->s_handle);
}
static void
_FlushProc(png_structp png_ptr) {
(png_structp)png_ptr;
// empty flush implementation
}
static void
error_handler(png_structp png_ptr, const char *error) {
(png_structp)png_ptr;
throw error;
}
// in FreeImage warnings disabled
static void
warning_handler(png_structp png_ptr, const char *warning) {
(png_structp)png_ptr;
(char*)warning;
}
// ==========================================================
// Metadata routines
// ==========================================================
static BOOL
ReadMetadata(png_structp png_ptr, png_infop info_ptr, FIBITMAP *dib) {
// XMP keyword
const char *g_png_xmp_keyword = "XML:com.adobe.xmp";
FITAG *tag = NULL;
png_textp text_ptr = NULL;
png_timep mod_time = NULL;
int num_text = 0;
// iTXt/tEXt/zTXt chuncks
if(png_get_text(png_ptr, info_ptr, &text_ptr, &num_text) > 0) {
for(int i = 0; i < num_text; i++) {
// create a tag
tag = FreeImage_CreateTag();
if(!tag) return FALSE;
DWORD tag_length = (DWORD) MAX(text_ptr[i].text_length, text_ptr[i].itxt_length);
FreeImage_SetTagLength(tag, tag_length);
FreeImage_SetTagCount(tag, tag_length);
FreeImage_SetTagType(tag, FIDT_ASCII);
FreeImage_SetTagValue(tag, text_ptr[i].text);
if(strcmp(text_ptr[i].key, g_png_xmp_keyword) == 0) {
// store the tag as XMP
FreeImage_SetTagKey(tag, g_TagLib_XMPFieldName);
FreeImage_SetMetadata(FIMD_XMP, dib, FreeImage_GetTagKey(tag), tag);
} else {
// store the tag as a comment
FreeImage_SetTagKey(tag, text_ptr[i].key);
FreeImage_SetMetadata(FIMD_COMMENTS, dib, FreeImage_GetTagKey(tag), tag);
}
// destroy the tag
FreeImage_DeleteTag(tag);
}
}
// timestamp chunk
if(png_get_tIME(png_ptr, info_ptr, &mod_time)) {
char timestamp[32];
// create a tag
tag = FreeImage_CreateTag();
if(!tag) return FALSE;
src/Source/FreeImage/PluginPNG.cpp view on Meta::CPAN
png_bytepp row_pointers = NULL;
fi_ioStructure fio;
fio.s_handle = handle;
fio.s_io = io;
if (handle) {
BOOL header_only = (flags & FIF_LOAD_NOPIXELS) == FIF_LOAD_NOPIXELS;
try {
// check to see if the file is in fact a PNG file
BYTE png_check[PNG_BYTES_TO_CHECK];
io->read_proc(png_check, PNG_BYTES_TO_CHECK, 1, handle);
if (png_sig_cmp(png_check, (png_size_t)0, PNG_BYTES_TO_CHECK) != 0) {
return NULL; // Bad signature
}
// create the chunk manage structure
png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, (png_voidp)NULL, error_handler, warning_handler);
if (!png_ptr) {
return NULL;
}
// create the info structure
info_ptr = png_create_info_struct(png_ptr);
if (!info_ptr) {
png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL);
return NULL;
}
// init the IO
png_set_read_fn(png_ptr, &fio, _ReadProc);
if (setjmp(png_jmpbuf(png_ptr))) {
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
return NULL;
}
// because we have already read the signature...
png_set_sig_bytes(png_ptr, PNG_BYTES_TO_CHECK);
// read the IHDR chunk
png_read_info(png_ptr, info_ptr);
png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, NULL, NULL, NULL);
// configure the decoder
FREE_IMAGE_TYPE image_type = FIT_BITMAP;
if(!ConfigureDecoder(png_ptr, info_ptr, flags, &image_type)) {
throw FI_MSG_ERROR_UNSUPPORTED_FORMAT;
}
// update image info
color_type = png_get_color_type(png_ptr, info_ptr);
bit_depth = png_get_bit_depth(png_ptr, info_ptr);
pixel_depth = bit_depth * png_get_channels(png_ptr, info_ptr);
// create a dib and write the bitmap header
// set up the dib palette, if needed
switch (color_type) {
case PNG_COLOR_TYPE_RGB:
case PNG_COLOR_TYPE_RGB_ALPHA:
dib = FreeImage_AllocateHeaderT(header_only, image_type, width, height, pixel_depth, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK);
break;
case PNG_COLOR_TYPE_PALETTE:
dib = FreeImage_AllocateHeaderT(header_only, image_type, width, height, pixel_depth, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK);
if(dib) {
png_colorp png_palette = NULL;
int palette_entries = 0;
png_get_PLTE(png_ptr,info_ptr, &png_palette, &palette_entries);
palette_entries = MIN((unsigned)palette_entries, FreeImage_GetColorsUsed(dib));
// store the palette
RGBQUAD *palette = FreeImage_GetPalette(dib);
for(int i = 0; i < palette_entries; i++) {
palette[i].rgbRed = png_palette[i].red;
palette[i].rgbGreen = png_palette[i].green;
palette[i].rgbBlue = png_palette[i].blue;
}
}
break;
case PNG_COLOR_TYPE_GRAY:
dib = FreeImage_AllocateHeaderT(header_only, image_type, width, height, pixel_depth, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK);
if(dib && (pixel_depth <= 8)) {
RGBQUAD *palette = FreeImage_GetPalette(dib);
const int palette_entries = 1 << pixel_depth;
for(int i = 0; i < palette_entries; i++) {
palette[i].rgbRed =
palette[i].rgbGreen =
palette[i].rgbBlue = (BYTE)((i * 255) / (palette_entries - 1));
}
}
break;
default:
throw FI_MSG_ERROR_UNSUPPORTED_FORMAT;
}
if(!dib) {
throw FI_MSG_ERROR_DIB_MEMORY;
}
// store the transparency table
if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
// array of alpha (transparency) entries for palette
png_bytep trans_alpha = NULL;
// number of transparent entries
int num_trans = 0;
// graylevel or color sample values of the single transparent color for non-paletted images
png_color_16p trans_color = NULL;
png_get_tRNS(png_ptr, info_ptr, &trans_alpha, &num_trans, &trans_color);
if((color_type == PNG_COLOR_TYPE_GRAY) && trans_color) {
// single transparent color
if (trans_color->gray < 256) {
BYTE table[256];
memset(table, 0xFF, 256);
table[trans_color->gray] = 0;
FreeImage_SetTransparencyTable(dib, table, 256);
}
// check for a full transparency table, too
else if ((trans_alpha) && (pixel_depth <= 8)) {
FreeImage_SetTransparencyTable(dib, (BYTE *)trans_alpha, num_trans);
}
} else if((color_type == PNG_COLOR_TYPE_PALETTE) && trans_alpha) {
// transparency table
FreeImage_SetTransparencyTable(dib, (BYTE *)trans_alpha, num_trans);
}
}
// store the background color (only supported for FIT_BITMAP types)
if ((image_type == FIT_BITMAP) && png_get_valid(png_ptr, info_ptr, PNG_INFO_bKGD)) {
// Get the background color to draw transparent and alpha images over.
// Note that even if the PNG file supplies a background, you are not required to
// use it - you should use the (solid) application background if it has one.
png_color_16p image_background = NULL;
RGBQUAD rgbBkColor;
if (png_get_bKGD(png_ptr, info_ptr, &image_background)) {
rgbBkColor.rgbRed = (BYTE)image_background->red;
rgbBkColor.rgbGreen = (BYTE)image_background->green;
rgbBkColor.rgbBlue = (BYTE)image_background->blue;
rgbBkColor.rgbReserved = 0;
FreeImage_SetBackgroundColor(dib, &rgbBkColor);
}
}
// get physical resolution
if (png_get_valid(png_ptr, info_ptr, PNG_INFO_pHYs)) {
png_uint_32 res_x, res_y;
// we'll overload this var and use 0 to mean no phys data,
// since if it's not in meters we can't use it anyway
( run in 1.026 second using v1.01-cache-2.11-cpan-cdf2f3d4e48 )