?? pluginpng.cpp
字號:
// ==========================================================
// 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)
//
// 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!
// ==========================================================
#pragma warning (disable : 4786) // identifier was truncated to 'number' characters
#include "FreeImage.h"
#include "Utilities.h"
#include "../Metadata/FreeImageTag.h"
// ----------------------------------------------------------
#define PNG_ASSEMBLER_CODE_SUPPORTED
#define PNG_BYTES_TO_CHECK 8
// ----------------------------------------------------------
#include "../LibPNG/png.h"
// ----------------------------------------------------------
static FreeImageIO *s_io;
static fi_handle s_handle;
/////////////////////////////////////////////////////////////////////////////
// libpng interface
//
static void
_ReadProc(struct png_struct_def *, unsigned char *data, png_size_t size) {
s_io->read_proc(data, size, 1, s_handle);
}
static void
_WriteProc(struct png_struct_def *, unsigned char *data, png_size_t size) {
s_io->write_proc(data, size, 1, s_handle);
}
static void
_FlushProc(png_structp png_ptr) {
// empty flush implementation
}
static void
error_handler(struct png_struct_def *, const char *error) {
throw error;
}
// in FreeImage warnings disabled
static void
warning_handler(struct png_struct_def *, const char *warning) {
}
// ==========================================================
// Metadata routines
// ==========================================================
static BOOL
ReadMetadata(png_structp png_ptr, png_infop info_ptr, FIBITMAP *dib) {
// XMP keyword
char *g_png_xmp_keyword = "XML:com.adobe.xmp";
png_textp text_ptr = 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++) {
FITAG tag;
memset(&tag, 0, sizeof(FITAG));
tag.length = MAX(text_ptr[i].text_length, text_ptr[i].itxt_length);
tag.count = tag.length;
tag.type = FIDT_ASCII;
tag.value = (char*)text_ptr[i].text;
if(strcmp(text_ptr[i].key, g_png_xmp_keyword) == 0) {
// store the tag as XMP
tag.key = g_TagLib_XMPFieldName;
FreeImage_SetMetadata(FIMD_XMP, dib, tag.key, &tag);
} else {
// store the tag as a comment
tag.key = text_ptr[i].key;
FreeImage_SetMetadata(FIMD_COMMENTS, dib, tag.key, &tag);
}
}
}
return TRUE;
}
static BOOL
WriteMetadata(png_structp png_ptr, png_infop info_ptr, FIBITMAP *dib) {
// XMP keyword
char *g_png_xmp_keyword = "XML:com.adobe.xmp";
FITAG *tag = NULL;
FIMETADATA *mdhandle = NULL;
BOOL bResult = TRUE;
png_text text_metadata;
int num_text = 0;
// 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 = tag->key; // keyword, 1-79 character description of "text"
text_metadata.text = (char*)tag->value; // comment, may be an empty string (ie "")
text_metadata.text_length = tag->length; // length of the text string
text_metadata.itxt_length = tag->length; // 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 && tag->length) {
memset(&text_metadata, 0, sizeof(png_text));
text_metadata.compression = 1; // iTXt, none
text_metadata.key = g_png_xmp_keyword; // keyword, 1-79 character description of "text"
text_metadata.text = (char*)tag->value; // comment, may be an empty string (ie "")
text_metadata.text_length = tag->length; // length of the text string
text_metadata.itxt_length = tag->length; // 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;
}
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() {
return "image/png";
}
static BOOL DLL_CALLCONV
Validate(FreeImageIO *io, fi_handle handle) {
BYTE png_signature[8] = { 137, 80, 78, 71, 13, 10, 26, 10 };
BYTE signature[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
io->read_proc(&signature, 1, 8, handle);
return (memcmp(png_signature, signature, 8) == 0);
}
static BOOL DLL_CALLCONV
SupportsExportDepth(int depth) {
return (
(depth == 1) ||
(depth == 4) ||
(depth == 8) ||
(depth == 24) ||
(depth == 32)
);
}
static BOOL DLL_CALLCONV
SupportsExportType(FREE_IMAGE_TYPE type) {
return (
(type == FIT_BITMAP) ||
(type == FIT_UINT16)
);
}
static BOOL DLL_CALLCONV
SupportsICCProfiles() {
return TRUE;
}
// ----------------------------------------------------------
static FIBITMAP * DLL_CALLCONV
Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) {
png_structp png_ptr;
png_infop info_ptr;
png_uint_32 width, height;
png_colorp png_palette;
int color_type, palette_entries;
int bit_depth, pixel_depth; // pixel_depth = bit_depth * channels
FIBITMAP *dib = NULL;
RGBQUAD *palette = NULL; // pointer to dib palette
png_bytepp row_pointers = NULL;
int i;
s_io = io;
s_handle = handle;
if (handle) {
try {
// check to see if the file is in fact a PNG file
unsigned char 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)error_handler, 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, info_ptr, _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);
pixel_depth = info_ptr->pixel_depth;
// get image data type (assume standard image type)
FREE_IMAGE_TYPE image_type = FIT_BITMAP;
if (bit_depth == 16) {
if (color_type == PNG_COLOR_TYPE_GRAY) {
image_type = FIT_UINT16;
#ifndef FREEIMAGE_BIGENDIAN
// turn on 16 bit byte swapping
png_set_swap(png_ptr);
#endif
} else {
// tell libpng to strip 16 bit/color files down to 8 bits/color
png_set_strip_16(png_ptr);
bit_depth = 8;
}
}
// set some additional flags
switch(color_type) {
case PNG_COLOR_TYPE_RGB:
case PNG_COLOR_TYPE_RGB_ALPHA:
#ifndef FREEIMAGE_BIGENDIAN
// flip the RGB pixels to BGR (or RGBA to BGRA)
png_set_bgr(png_ptr);
#endif
break;
case PNG_COLOR_TYPE_PALETTE:
// expand palette images to the full 8 bits from 2 or 4 bits/pixel
if ((pixel_depth == 2) || (pixel_depth == 4)) {
png_set_packing(png_ptr);
pixel_depth = 8;
}
break;
case PNG_COLOR_TYPE_GRAY:
// expand grayscale images to the full 8 bits from 2 or 4 bits/pixel
if ((pixel_depth == 2) || (pixel_depth == 4)) {
png_set_expand(png_ptr);
pixel_depth = 8;
}
break;
case PNG_COLOR_TYPE_GRAY_ALPHA:
// expand 8-bit greyscale + 8-bit alpha to 32-bit
png_set_gray_to_rgb(png_ptr);
#ifndef FREEIMAGE_BIGENDIAN
// flip the RGBA pixels to BGRA
png_set_bgr(png_ptr);
#endif
pixel_depth = 32;
break;
default:
throw "PNG format not supported";
}
// 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;
}
// if this image has transparency, store the trns values
png_bytep trans = NULL;
int num_trans = 0;
png_color_16p trans_values = NULL;
png_uint_32 transparent_value = png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, &trans_values);
// unlike the example in the libpng documentation, we have *no* idea where
// this file may have come from--so if it doesn't have a file gamma, don't
// do any correction ("do no harm")
double gamma = 0;
double screen_gamma = 2.2;
if (png_get_gAMA(png_ptr, info_ptr, &gamma) && ( flags & PNG_IGNOREGAMMA ) != PNG_IGNOREGAMMA)
png_set_gamma(png_ptr, screen_gamma, gamma);
// all transformations have been registered; now update info_ptr data
png_read_update_info(png_ptr, info_ptr);
// color type may have changed, due to our transformations
color_type = png_get_color_type(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:
png_set_invert_alpha(png_ptr);
dib = FreeImage_Allocate(width, height, 24, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK);
break;
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -