Alien-FreeImage
view release on metacpan or search on metacpan
src/Source/FreeImage/PluginPNG.cpp view on Meta::CPAN
// ==========================================================
// 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;
// convert as 'yyyy:MM:dd hh:mm:ss'
sprintf(timestamp, "%4d:%02d:%02d %2d:%02d:%02d", mod_time->year, mod_time->month, mod_time->day, mod_time->hour, mod_time->minute, mod_time->second);
DWORD tag_length = (DWORD)strlen(timestamp) + 1;
FreeImage_SetTagLength(tag, tag_length);
FreeImage_SetTagCount(tag, tag_length);
FreeImage_SetTagType(tag, FIDT_ASCII);
FreeImage_SetTagID(tag, TAG_DATETIME);
FreeImage_SetTagValue(tag, timestamp);
// store the tag as Exif-TIFF
FreeImage_SetTagKey(tag, "DateTime");
FreeImage_SetMetadata(FIMD_EXIF_MAIN, dib, FreeImage_GetTagKey(tag), tag);
// destroy the tag
FreeImage_DeleteTag(tag);
}
return TRUE;
}
static BOOL
WriteMetadata(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;
FIMETADATA *mdhandle = NULL;
BOOL bResult = TRUE;
png_text text_metadata;
png_time mod_time;
// set the 'Comments' metadata as iTXt chuncks
mdhandle = FreeImage_FindFirstMetadata(FIMD_COMMENTS, dib, &tag);
if(mdhandle) {
do {
memset(&text_metadata, 0, sizeof(png_text));
text_metadata.compression = 1; // iTXt, none
text_metadata.key = (char*)FreeImage_GetTagKey(tag); // keyword, 1-79 character description of "text"
text_metadata.text = (char*)FreeImage_GetTagValue(tag); // comment, may be an empty string (ie "")
text_metadata.text_length = FreeImage_GetTagLength(tag);// length of the text string
text_metadata.itxt_length = FreeImage_GetTagLength(tag);// length of the itxt string
text_metadata.lang = 0; // language code, 0-79 characters or a NULL pointer
text_metadata.lang_key = 0; // keyword translated UTF-8 string, 0 or more chars or a NULL pointer
// set the tag
png_set_text(png_ptr, info_ptr, &text_metadata, 1);
} while(FreeImage_FindNextMetadata(mdhandle, &tag));
FreeImage_FindCloseMetadata(mdhandle);
bResult &= TRUE;
}
// set the 'XMP' metadata as iTXt chuncks
tag = NULL;
FreeImage_GetMetadata(FIMD_XMP, dib, g_TagLib_XMPFieldName, &tag);
if(tag && FreeImage_GetTagLength(tag)) {
memset(&text_metadata, 0, sizeof(png_text));
text_metadata.compression = 1; // iTXt, none
text_metadata.key = (char*)g_png_xmp_keyword; // keyword, 1-79 character description of "text"
text_metadata.text = (char*)FreeImage_GetTagValue(tag); // comment, may be an empty string (ie "")
text_metadata.text_length = FreeImage_GetTagLength(tag);// length of the text string
text_metadata.itxt_length = FreeImage_GetTagLength(tag);// length of the itxt string
text_metadata.lang = 0; // language code, 0-79 characters or a NULL pointer
text_metadata.lang_key = 0; // keyword translated UTF-8 string, 0 or more chars or a NULL pointer
// set the tag
png_set_text(png_ptr, info_ptr, &text_metadata, 1);
bResult &= TRUE;
}
// set the Exif-TIFF 'DateTime' metadata as a tIME chunk
tag = NULL;
FreeImage_GetMetadata(FIMD_EXIF_MAIN, dib, "DateTime", &tag);
if(tag && FreeImage_GetTagLength(tag)) {
int year, month, day, hour, minute, second;
const char *value = (char*)FreeImage_GetTagValue(tag);
if(sscanf(value, "%4d:%02d:%02d %2d:%02d:%02d", &year, &month, &day, &hour, &minute, &second) == 6) {
mod_time.year = (png_uint_16)year;
mod_time.month = (png_byte)month;
mod_time.day = (png_byte)day;
mod_time.hour = (png_byte)hour;
mod_time.minute = (png_byte)minute;
mod_time.second = (png_byte)second;
png_set_tIME (png_ptr, info_ptr, &mod_time);
}
}
return bResult;
}
// ==========================================================
// Plugin Interface
// ==========================================================
static int s_format_id;
// ==========================================================
// Plugin Implementation
// ==========================================================
static const char * DLL_CALLCONV
Format() {
return "PNG";
}
static const char * DLL_CALLCONV
Description() {
return "Portable Network Graphics";
}
static const char * DLL_CALLCONV
Extension() {
return "png";
}
static const char * DLL_CALLCONV
RegExpr() {
return "^.PNG\r";
}
static const char * DLL_CALLCONV
MimeType() {
src/Source/FreeImage/PluginPNG.cpp view on Meta::CPAN
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
int res_unit_type = PNG_RESOLUTION_UNKNOWN;
png_get_pHYs(png_ptr,info_ptr, &res_x, &res_y, &res_unit_type);
if (res_unit_type == PNG_RESOLUTION_METER) {
FreeImage_SetDotsPerMeterX(dib, res_x);
FreeImage_SetDotsPerMeterY(dib, res_y);
}
}
// get possible ICC profile
if (png_get_valid(png_ptr, info_ptr, PNG_INFO_iCCP)) {
png_charp profile_name = NULL;
png_bytep profile_data = NULL;
png_uint_32 profile_length = 0;
int compression_type;
png_get_iCCP(png_ptr, info_ptr, &profile_name, &compression_type, &profile_data, &profile_length);
// copy ICC profile data (must be done after FreeImage_AllocateHeader)
FreeImage_CreateICCProfile(dib, profile_data, profile_length);
}
// --- header only mode => clean-up and return
if (header_only) {
// get possible metadata (it can be located both before and after the image data)
ReadMetadata(png_ptr, info_ptr, dib);
if (png_ptr) {
// clean up after the read, and free any memory allocated - REQUIRED
png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
}
return dib;
}
// set the individual row_pointers to point at the correct offsets
row_pointers = (png_bytepp)malloc(height * sizeof(png_bytep));
if (!row_pointers) {
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
FreeImage_Unload(dib);
return NULL;
}
// read in the bitmap bits via the pointer table
// allow loading of PNG with minor errors (such as images with several IDAT chunks)
for (png_uint_32 k = 0; k < height; k++) {
row_pointers[height - 1 - k] = FreeImage_GetScanLine(dib, k);
}
png_set_benign_errors(png_ptr, 1);
png_read_image(png_ptr, row_pointers);
// check if the bitmap contains transparency, if so enable it in the header
if (FreeImage_GetBPP(dib) == 32) {
if (FreeImage_GetColorType(dib) == FIC_RGBALPHA) {
FreeImage_SetTransparent(dib, TRUE);
} else {
FreeImage_SetTransparent(dib, FALSE);
}
}
// cleanup
if (row_pointers) {
free(row_pointers);
row_pointers = NULL;
}
// read the rest of the file, getting any additional chunks in info_ptr
png_read_end(png_ptr, info_ptr);
// get possible metadata (it can be located both before and after the image data)
ReadMetadata(png_ptr, info_ptr, dib);
if (png_ptr) {
( run in 0.585 second using v1.01-cache-2.11-cpan-119454b85a5 )