static HPDF_STATUS
LoadPngData (HPDF_Dict image,
HPDF_Xref xref,
HPDF_Stream png_data,
HPDF_BOOL delayed_loading)
{
HPDF_STATUS ret = HPDF_OK;
png_uint_32 width, height;
int bit_depth, color_type;
png_structp png_ptr = NULL;
png_infop info_ptr = NULL;
HPDF_PTRACE ((" HPDF_Image_LoadPngImage\n"));
/* create read_struct. */
png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING,
image->error, PngErrorFunc, PngErrorFunc);
if (png_ptr == NULL) {
HPDF_SetError (image->error, HPDF_FAILD_TO_ALLOC_MEM, 0);
return HPDF_FAILD_TO_ALLOC_MEM;
}
/* create info-struct */
info_ptr = png_create_info_struct (png_ptr);
if (info_ptr == NULL) {
HPDF_SetError (image->error, HPDF_FAILD_TO_ALLOC_MEM, 0);
goto Exit;
}
png_set_sig_bytes (png_ptr, HPDF_PNG_BYTES_TO_CHECK);
png_set_read_fn (png_ptr, (void *)png_data, (png_rw_ptr)&PngReadFunc);
/* reading info structure. */
png_read_info(png_ptr, info_ptr);
if (image->error->error_no != HPDF_OK) {
goto Exit;
}
png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, NULL, NULL, NULL);
/* 16bit images are not supported. */
if (bit_depth == 16) {
png_set_strip_16(png_ptr);
}
png_read_update_info(png_ptr, info_ptr);
if (image->error->error_no != HPDF_OK) {
goto Exit;
}
/* check palette-based images for transparent areas and load them immediately if found */
if (xref && PNG_COLOR_TYPE_PALETTE & color_type) {
png_bytep trans;
int num_trans;
HPDF_Dict smask;
png_bytep smask_data;
if (!png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS) ||
!png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, NULL)) {
goto no_transparent_color_in_palette;
}
smask = HPDF_DictStream_New (image->mmgr, xref);
if (!smask) {
ret = HPDF_FAILD_TO_ALLOC_MEM;
goto Exit;
}
smask->header.obj_class |= HPDF_OSUBCLASS_XOBJECT;
ret = HPDF_Dict_AddName (smask, "Type", "XObject");
ret += HPDF_Dict_AddName (smask, "Subtype", "Image");
ret += HPDF_Dict_AddNumber (smask, "Width", (HPDF_UINT)width);
ret += HPDF_Dict_AddNumber (smask, "Height", (HPDF_UINT)height);
ret += HPDF_Dict_AddName (smask, "ColorSpace", "DeviceGray");
ret += HPDF_Dict_AddNumber (smask, "BitsPerComponent", (HPDF_UINT)bit_depth);
if (ret != HPDF_OK) {
HPDF_Dict_Free(smask);
ret = HPDF_INVALID_PNG_IMAGE;
goto Exit;
}
smask_data = HPDF_GetMem(image->mmgr, width * height);
if (!smask_data) {
HPDF_Dict_Free(smask);
ret = HPDF_FAILD_TO_ALLOC_MEM;
goto Exit;
}
if (ReadTransparentPaletteData(image, png_ptr, info_ptr, smask_data, trans, num_trans) != HPDF_OK) {
HPDF_FreeMem(image->mmgr, smask_data);
HPDF_Dict_Free(smask);
ret = HPDF_INVALID_PNG_IMAGE;
goto Exit;
}
if (HPDF_Stream_Write(smask->stream, smask_data, width * height) != HPDF_OK) {
//.........这里部分代码省略.........
开发者ID:AMHF,项目名称:core,代码行数:101,代码来源:hpdfimap.c
示例3: pngDecSetParameter
s32 pngDecSetParameter(PStream stream, PInParam in_param, POutParam out_param, PExtInParam extra_in_param = vm::null, PExtOutParam extra_out_param = vm::null)
{
if (in_param->outputPackFlag == CELL_PNGDEC_1BYTE_PER_NPIXEL)
{
fmt::throw_exception("Packing not supported! (%d)" HERE, in_param->outputPackFlag);
}
// flag to keep unknown chunks
png_set_keep_unknown_chunks(stream->png_ptr, PNG_HANDLE_CHUNK_IF_SAFE, 0, 0);
// Scale 16 bit depth down to 8 bit depth.
if (stream->info.bitDepth == 16 && in_param->outputBitDepth == 8)
{
// PS3 uses png_set_strip_16, since png_set_scale_16 wasn't available back then.
png_set_strip_16(stream->png_ptr);
}
// This shouldnt ever happen, but not sure what to do if it does, just want it logged for now
if (stream->info.bitDepth != 16 && in_param->outputBitDepth == 16)
cellPngDec.error("Output depth of 16 with non input depth of 16 specified!");
if (in_param->commandPtr != vm::null)
cellPngDec.warning("Ignoring CommandPtr.");
if (stream->info.colorSpace != in_param->outputColorSpace)
{
// check if we need to set alpha
const bool inputHasAlpha = cellPngColorSpaceHasAlpha(stream->info.colorSpace);
const bool outputWantsAlpha = cellPngColorSpaceHasAlpha(in_param->outputColorSpace);
if (outputWantsAlpha && !inputHasAlpha)
{
if (in_param->outputAlphaSelect == CELL_PNGDEC_FIX_ALPHA)
png_set_add_alpha(stream->png_ptr, in_param->outputColorAlpha, in_param->outputColorSpace == CELL_PNGDEC_ARGB ? PNG_FILLER_BEFORE : PNG_FILLER_AFTER);
else
{
// Check if we can steal the alpha from a trns block
if (png_get_valid(stream->png_ptr, stream->info_ptr, PNG_INFO_tRNS))
png_set_tRNS_to_alpha(stream->png_ptr);
// if not, just set default of 0xff
else
png_set_add_alpha(stream->png_ptr, 0xff, in_param->outputColorSpace == CELL_PNGDEC_ARGB ? PNG_FILLER_BEFORE : PNG_FILLER_AFTER);
}
}
else if (inputHasAlpha && !outputWantsAlpha)
png_set_strip_alpha(stream->png_ptr);
else if (in_param->outputColorSpace == CELL_PNGDEC_ARGB && stream->info.colorSpace == CELL_PNGDEC_RGBA)
png_set_swap_alpha(stream->png_ptr);
// Handle gray<->rgb colorspace conversions
// rgb output
if (in_param->outputColorSpace == CELL_PNGDEC_ARGB
|| in_param->outputColorSpace == CELL_PNGDEC_RGBA
|| in_param->outputColorSpace == CELL_PNGDEC_RGB)
{
if (stream->info.colorSpace == CELL_PNGDEC_PALETTE)
png_set_palette_to_rgb(stream->png_ptr);
if ((stream->info.colorSpace == CELL_PNGDEC_GRAYSCALE || stream->info.colorSpace == CELL_PNGDEC_GRAYSCALE_ALPHA)
&& stream->info.bitDepth < 8)
png_set_expand_gray_1_2_4_to_8(stream->png_ptr);
}
// grayscale output
else
{
if (stream->info.colorSpace == CELL_PNGDEC_ARGB
|| stream->info.colorSpace == CELL_PNGDEC_RGBA
|| stream->info.colorSpace == CELL_PNGDEC_RGB)
{
png_set_rgb_to_gray(stream->png_ptr, PNG_ERROR_ACTION_NONE, PNG_RGB_TO_GRAY_DEFAULT, PNG_RGB_TO_GRAY_DEFAULT);
}
else {
// not sure what to do here
cellPngDec.error("Grayscale / Palette to Grayscale / Palette conversion currently unsupported.");
}
}
}
stream->passes = png_set_interlace_handling(stream->png_ptr);
// Update the info structure
png_read_update_info(stream->png_ptr, stream->info_ptr);
stream->out_param.outputWidth = stream->info.imageWidth;
stream->out_param.outputHeight = stream->info.imageHeight;
stream->out_param.outputBitDepth = in_param->outputBitDepth;
stream->out_param.outputColorSpace = in_param->outputColorSpace;
stream->out_param.outputMode = in_param->outputMode;
stream->out_param.outputWidthByte = png_get_rowbytes(stream->png_ptr, stream->info_ptr);
stream->out_param.outputComponents = png_get_channels(stream->png_ptr, stream->info_ptr);
stream->packing = in_param->outputPackFlag;
// Set the memory usage. We currently don't actually allocate memory for libpng through the callbacks, due to libpng needing a lot more memory compared to PS3 variant.
stream->out_param.useMemorySpace = 0;
if (extra_in_param)
{
if (extra_in_param->bufferMode != CELL_PNGDEC_LINE_MODE)
//.........这里部分代码省略.........
//.........这里部分代码省略.........
png_set_read_fn(png_ptr, (void *)user_io_ptr, user_read_fn);
/* where user_io_ptr is a structure you want available to the callbacks */
#endif no_streams /* Use only one I/O method! */
/* If we have already read some of the signature */
png_set_sig_bytes(png_ptr, sig_read);
#ifdef hilevel
/*
* If you have enough memory to read in the entire image at once,
* and you need to specify only transforms that can be controlled
* with one of the PNG_TRANSFORM_* bits (this presently excludes
* quantizing, filling, setting background, and doing gamma
* adjustment), then you can read the entire image (including
* pixels) into the info structure with this call:
*/
png_read_png(png_ptr, info_ptr, png_transforms, NULL);
#else
/* OK, you're doing it the hard way, with the lower-level functions */
/* The call to png_read_info() gives us all of the information from the
* PNG file before the first IDAT (image data chunk). REQUIRED
*/
png_read_info(png_ptr, info_ptr);
png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,
&interlace_type, NULL, NULL);
/* Set up the data transformations you want. Note that these are all
* optional. Only call them if you want/need them. Many of the
* transformations only work on specific types of images, and many
* are mutually exclusive.
*/
/* Tell libpng to strip 16 bit/color files down to 8 bits/color.
* Use accurate scaling if it's available, otherwise just chop off the
* low byte.
*/
#ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED
png_set_scale_16(png_ptr);
#else
png_set_strip_16(png_ptr);
#endif
/* Strip alpha bytes from the input data without combining with the
* background (not recommended).
*/
png_set_strip_alpha(png_ptr);
/* Extract multiple pixels with bit depths of 1, 2, and 4 from a single
* byte into separate bytes (useful for paletted and grayscale images).
*/
png_set_packing(png_ptr);
/* Change the order of packed pixels to least significant bit first
* (not useful if you are using png_set_packing). */
png_set_packswap(png_ptr);
/* Expand paletted colors into true RGB triplets */
if (color_type == PNG_COLOR_TYPE_PALETTE)
png_set_palette_to_rgb(png_ptr);
/* Expand grayscale images to the full 8 bits from 1, 2, or 4 bits/pixel */
if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
png_set_expand_gray_1_2_4_to_8(png_ptr);
/* Expand paletted or RGB images with transparency to full alpha channels
* so the data will be available as RGBA quartets.
*/
if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS) != 0)
png_set_tRNS_to_alpha(png_ptr);
/* Set the background color to draw transparent and alpha images over.
* It is possible to set the red, green, and blue components directly
* for paletted images instead of supplying a palette index. 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_16 my_background, *image_background;
if (png_get_bKGD(png_ptr, info_ptr, &image_background) != 0)
png_set_background(png_ptr, image_background,
PNG_BACKGROUND_GAMMA_FILE, 1, 1.0);
else
png_set_background(png_ptr, &my_background,
PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0);
/* Some suggestions as to how to get a screen gamma value
*
* Note that screen gamma is the display_exponent, which includes
* the CRT_exponent and any correction for viewing conditions
*/
if (/* We have a user-defined screen gamma value */)
{
screen_gamma = user-defined screen_gamma;
}
/* This is one way that applications share the same screen gamma value */
else if ((gamma_str = getenv("SCREEN_GAMMA")) != NULL)
unsigned char* LoadPNGJPGFromMemory(const unsigned char* buffer, int len, int* width, int* height)
{
const int number=8;
// проверяем сигнатуру файла (первые number байт)
if ( !png_check_sig((png_bytep)buffer, number) )
{
// неизвестный формат
return LoadJPGWithAlphaFromMemory(buffer, len, width, height);
}
// создаем внутреннюю структуру png для работы с файлом
// последние параметры - структура, для функции обработки ошибок и варнинга (последн. 2 параметра)
png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
// создаем структуру с информацией о файле
png_infop info_ptr = png_create_info_struct(png_ptr);
PNGBuffer pngBuffer;
pngBuffer.data = (png_bytep)buffer;
pngBuffer.position = 8;
png_set_read_fn(png_ptr, (void*)&pngBuffer, PNGRead);
// говорим библиотеке, что мы уже прочли number байт, когда проверяли сигнатуру
png_set_sig_bytes(png_ptr, number);
// читаем всю информацию о файле
png_read_info(png_ptr, info_ptr);
// Эта функция возвращает инфу из info_ptr
png_uint_32 w = 0, h = 0; // размер картинки в пикселях
int bit_depth = 0; // глубина цвета (одного из каналов, может быть 1, 2, 4, 8, 16)
int color_type = 0; // описывает какие каналы присутствуют:
// PNG_COLOR_TYPE_GRAY, PNG_COLOR_TYPE_GRAY_ALPHA, PNG_COLOR_TYPE_PALETTE,
// PNG_COLOR_TYPE_RGB, PNG_COLOR_TYPE_RGB_ALPHA...
// последние 3 параметра могут быть нулями и обозначают: тип фильтра, тип компрессии и тип смещения
png_get_IHDR(png_ptr, info_ptr, &w, &h, &bit_depth, &color_type, 0, 0, 0);
// png формат может содержать 16 бит на канал, но нам нужно только 8, поэтому сужаем канал
if (bit_depth == 16) png_set_strip_16(png_ptr);
// преобразуем файл если он содержит палитру в нормальный RGB
if (color_type == PNG_COLOR_TYPE_PALETTE && bit_depth <= 8) png_set_palette_to_rgb(png_ptr);
// если в грэйскейле меньше бит на канал чем 8, то конвертим к нормальному 8-битному
//if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) png_set_gray_1_2_4_to_8(png_ptr);
// и добавляем полный альфа-канал
if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) png_set_tRNS_to_alpha(png_ptr);
if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
png_set_gray_to_rgb(png_ptr);
double gamma = 0.0f;
// если есть информация о гамме в файле, то устанавливаем на 2.2
if ( png_get_gAMA(png_ptr, info_ptr, &gamma) ) png_set_gamma(png_ptr, 2.2, gamma);
// иначе ставим дефолтную гамму для файла в 0.45455 (good guess for GIF images on PCs)
else png_set_gamma(png_ptr, 2.2, 0.45455);
// после всех трансформаций, апдейтим информацию в библиотеке
png_read_update_info(png_ptr, info_ptr);
// опять получаем все размеры и параметры обновленной картинки
png_get_IHDR(png_ptr, info_ptr, &w, &h, &bit_depth, &color_type, 0, 0, 0);
// определяем кол-во байт нужных для того чтобы вместить строку
png_uint_32 row_bytes = png_get_rowbytes(png_ptr, info_ptr);
// теперь, мы можем выделить память чтобы вместить картинку
png_byte* data = new png_byte[row_bytes * h];
// выделяем память, для указателей на каждую строку
png_byte **row_pointers = new png_byte * [h];
// сопоставляем массив указателей на строчки, с выделенными в памяти (res)
// т.к. изображение перевернутое, то указатели идут снизу вверх
for (unsigned int i = 0; i < h; i++)
row_pointers[i] = data + i * row_bytes;
// все, читаем картинку
png_read_image(png_ptr, row_pointers);
// освобождаем память от указателей на строки
delete []row_pointers;
// освобождаем память выделенную для библиотеки libpng
png_destroy_read_struct(&png_ptr, &info_ptr, 0);
*width=w;
*height=h;
return data;
}
//.........这里部分代码省略.........
end_info = png_create_info_struct(png_ptr);
if (!end_info)
longjmp( err_jmp, (int)errMemoryAllocation );
/* bamboozle the PNG longjmp buffer */
/*generic PNG error handler*/
/* error will always == 1 which == errLib */
// error = png_setjmp(png_ptr);
error = setjmp( png_jmpbuf( png_ptr ) );
if ( error > 0 )
longjmp( err_jmp, error );
/* set function pointers in the PNG library, for read callbacks */
png_set_read_fn(png_ptr, (png_voidp) file, user_read_data);
/*let the read functions know that we have already read the 1st 8 bytes */
png_set_sig_bytes( png_ptr, 8 );
/* read all PNG data up to the image data */
png_read_info( png_ptr, info_ptr );
/* extract the data we need to form the HBITMAP from the PNG header */
png_get_IHDR( png_ptr, info_ptr, &Width, &Height, &BitDepth, &ColorType,
&InterlaceType, NULL, NULL);
img->width = (unsigned int) Width;
img->height = (unsigned int) Height;
img->bits_per_pixel = (unsigned char)32;
img->scan_width = Width * 4;
/* convert 16-bit images to 8-bit images */
if (BitDepth == 16)
png_set_strip_16(png_ptr);
/* These are not really required per Rice format spec,
* but is done just in case someone uses them.
*/
/* convert palette color to rgb color */
if (ColorType == PNG_COLOR_TYPE_PALETTE) {
png_set_palette_to_rgb(png_ptr);
ColorType = PNG_COLOR_TYPE_RGB;
}
/* expand 1,2,4 bit gray scale to 8 bit gray scale */
if (ColorType == PNG_COLOR_TYPE_GRAY && BitDepth < 8)
png_set_expand_gray_1_2_4_to_8(png_ptr);
/* convert gray scale or gray scale + alpha to rgb color */
if (ColorType == PNG_COLOR_TYPE_GRAY ||
ColorType == PNG_COLOR_TYPE_GRAY_ALPHA) {
png_set_gray_to_rgb(png_ptr);
ColorType = PNG_COLOR_TYPE_RGB;
}
/* add alpha channel if any */
if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
png_set_tRNS_to_alpha(png_ptr);
ColorType = PNG_COLOR_TYPE_RGB_ALPHA;
}
/* convert rgb to rgba */
if (ColorType == PNG_COLOR_TYPE_RGB) {
png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER);
ColorType = PNG_COLOR_TYPE_RGB_ALPHA;
}
请发表评论