//--------------------------------------------------------------------- inline void normalizePngInfo(png_struct* png_ptr, png_info* info_ptr) { int bit_depth, color_type; /* get some usefull information from header */ bit_depth = png_get_bit_depth (png_ptr, info_ptr); color_type = png_get_color_type (png_ptr, info_ptr); /* convert index color images to RGB images */ if (color_type == PNG_COLOR_TYPE_PALETTE) { png_set_palette_to_rgb(png_ptr); } /* convert 1-2-4 bits grayscale images to 8 bits grayscale. */ if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) { png_set_expand_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); } /* make each canal to use exactly 8 bits */ if (bit_depth == 16) { png_set_strip_16 (png_ptr); } else if (bit_depth < 8) { png_set_packing (png_ptr); } /* update info structure to apply transformations */ png_read_update_info(png_ptr, info_ptr); }
void read_png_file(char *filename) { FILE *fp = fopen(filename, "rb"); png_structp png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if(!png) abort(); png_infop info = png_create_info_struct(png); if(!info) abort(); if(setjmp(png_jmpbuf(png))) abort(); png_init_io(png, fp); png_read_info(png, info); width = png_get_image_width(png, info); height = png_get_image_height(png, info); color_type = png_get_color_type(png, info); bit_depth = png_get_bit_depth(png, info); // Read any color_type into 8bit depth, RGBA format. // See http://www.libpng.org/pub/png/libpng-manual.txt if(bit_depth == 16) png_set_strip_16(png); if(color_type == PNG_COLOR_TYPE_PALETTE) png_set_palette_to_rgb(png); // PNG_COLOR_TYPE_GRAY_ALPHA is always 8 or 16bit depth. if(color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) png_set_expand_gray_1_2_4_to_8(png); if(png_get_valid(png, info, PNG_INFO_tRNS)) png_set_tRNS_to_alpha(png); // These color_type don't have an alpha channel then fill it with 0xff. if(color_type == PNG_COLOR_TYPE_RGB || color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_PALETTE) png_set_filler(png, 0xFF, PNG_FILLER_AFTER); if(color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) png_set_gray_to_rgb(png); png_read_update_info(png, info); row_pointers = (png_bytep*)malloc(sizeof(png_bytep) * height); int y ; for( y = 0; y < height; y++) { row_pointers[y] = (png_byte*)malloc(png_get_rowbytes(png,info)); } png_read_image(png, row_pointers); fclose(fp); }
// part of this being separated allows for us to play nicely with the setjmp of libpng bool ImageSourcePng::loadHeader() { bool success = true; if( setjmp( png_jmpbuf(mPngPtr) ) ) { success = false; } else { png_read_info( mPngPtr, mInfoPtr ); png_uint_32 width, height; int bitDepth, colorType, interlaceType, compressionType, filterMethod; if( ! png_get_IHDR( mPngPtr, mInfoPtr, &width, &height, &bitDepth, &colorType, &interlaceType, &compressionType, &filterMethod ) ) { png_destroy_read_struct( &mPngPtr, &mInfoPtr, (png_infopp)NULL ); mPngPtr = 0; return false; } setSize( width, height ); setDataType( ( bitDepth == 16 ) ? ImageIo::UINT16 : ImageIo::UINT8 ); #ifdef CINDER_LITTLE_ENDIAN png_set_swap( mPngPtr ); #endif switch( colorType ) { case PNG_COLOR_TYPE_GRAY: setColorModel( ImageIo::CM_GRAY ); setChannelOrder( ImageIo::Y ); break; case PNG_COLOR_TYPE_GRAY_ALPHA: setColorModel( ImageIo::CM_GRAY ); setChannelOrder( ImageIo::YA ); break; case PNG_COLOR_TYPE_RGB: case PNG_COLOR_TYPE_PALETTE: setColorModel( ImageIo::CM_RGB ); setChannelOrder( ImageIo::RGB ); break; case PNG_COLOR_TYPE_RGB_ALPHA: setColorModel( ImageIo::CM_RGB ); setChannelOrder( ImageIo::RGBA ); break; default: throw ImageSourcePngException( "Unexpected png color type." ); } png_set_expand_gray_1_2_4_to_8( mPngPtr ); png_set_palette_to_rgb( mPngPtr ); png_set_tRNS_to_alpha( mPngPtr ); png_read_update_info( mPngPtr, mInfoPtr ); } return success; }
static void nspng_setup_transforms(png_structp png_ptr, png_infop info_ptr) { int bit_depth, color_type; #if 0 int intent; double gamma; #endif bit_depth = png_get_bit_depth(png_ptr, info_ptr); color_type = png_get_color_type(png_ptr, info_ptr); /* Set up our transformations */ if (color_type == PNG_COLOR_TYPE_PALETTE) { png_set_palette_to_rgb(png_ptr); } if ((color_type == PNG_COLOR_TYPE_GRAY) && (bit_depth < 8)) { png_set_expand_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 (bit_depth == 16) { png_set_strip_16(png_ptr); } if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) { png_set_gray_to_rgb(png_ptr); } if (!(color_type & PNG_COLOR_MASK_ALPHA)) { png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER); } #if 0 /* gamma correction - we use 2.2 as our screen gamma * this appears to be correct (at least in respect to !Browse) * see http://www.w3.org/Graphics/PNG/all_seven.html for a test case */ if (png_get_sRGB(png_ptr, info_ptr, &intent)) { png_set_gamma(png_ptr, 2.2, 0.45455); } else { if (png_get_gAMA(png_ptr, info_ptr, &gamma)) { png_set_gamma(png_ptr, 2.2, gamma); } else { png_set_gamma(png_ptr, 2.2, 0.45455); } } #endif png_read_update_info(png_ptr, info_ptr); }
static void info_callback(png_structp png, png_infop info) { int bit_depth, color_type, interlace, intent; double gamma; png_uint_32 width, height; /* Read the PNG details */ png_get_IHDR(png, info, &width, &height, &bit_depth, &color_type, &interlace, 0, 0); /* Set up our transformations */ if (color_type == PNG_COLOR_TYPE_PALETTE) png_set_palette_to_rgb(png); if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) png_set_expand_gray_1_2_4_to_8(png); if (png_get_valid(png, info, PNG_INFO_tRNS)) png_set_tRNS_to_alpha(png); if (bit_depth == 16) png_set_strip_16(png); if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) png_set_gray_to_rgb(png); if (!(color_type & PNG_COLOR_MASK_ALPHA)) png_set_filler(png, 0xff, PNG_FILLER_AFTER); /* gamma correction - we use 2.2 as our screen gamma * this appears to be correct (at least in respect to !Browse) * see http://www.w3.org/Graphics/PNG/all_seven.html for a test case */ if (png_get_sRGB(png, info, &intent)) png_set_gamma(png, 2.2, 0.45455); else { if (png_get_gAMA(png, info, &gamma)) png_set_gamma(png, 2.2, gamma); else png_set_gamma(png, 2.2, 0.45455); } png_read_update_info(png, info); rowbytes = png_get_rowbytes(png, info); interlace = (interlace == PNG_INTERLACE_ADAM7); raw_width = width; raw_height = height; rowstride = raw_width * 4; bitmap_data = malloc(rowstride * raw_height); }
static PngInfo read_and_update_info(const png_structp png_ptr, const png_infop info_ptr) { png_uint_32 width, height; int bit_depth, color_type; png_read_info(png_ptr, info_ptr); png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, NULL, NULL, NULL); // Convert transparency to full alpha if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { png_set_tRNS_to_alpha(png_ptr); } // Convert grayscale, if needed. if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) { png_set_expand_gray_1_2_4_to_8(png_ptr); } // Convert paletted images, if needed. if (color_type == PNG_COLOR_TYPE_PALETTE) { png_set_palette_to_rgb(png_ptr); } // Add alpha channel, if there is none (rationale: GL_RGBA is faster than GL_RGB on many GPUs) if (color_type == PNG_COLOR_TYPE_PALETTE || color_type == PNG_COLOR_TYPE_RGB) { png_set_add_alpha(png_ptr, 0xFF, PNG_FILLER_AFTER); } // Ensure 8-bit packing if (bit_depth < 8) { png_set_packing(png_ptr); } else if (bit_depth == 16) { png_set_scale_16(png_ptr); } png_read_update_info(png_ptr, info_ptr); // Read the new color type after updates have been made. color_type = png_get_color_type(png_ptr, info_ptr); return (PngInfo) {width, height, color_type}; }
// Do transformations to normalize the input to 8-bpp RGBA void LLPngWrapper::normalizeImage() { // 1. Expand any palettes // 2. Convert grayscales to RGB // 3. Create alpha layer from transparency // 4. Ensure 8-bpp for all images // 5. Set (or guess) gamma if (mColorType == PNG_COLOR_TYPE_PALETTE) { png_set_palette_to_rgb(mReadPngPtr); } if (mColorType == PNG_COLOR_TYPE_GRAY && mBitDepth < 8) { png_set_expand_gray_1_2_4_to_8(mReadPngPtr); } if (mColorType == PNG_COLOR_TYPE_GRAY || mColorType == PNG_COLOR_TYPE_GRAY_ALPHA) { png_set_gray_to_rgb(mReadPngPtr); } if (png_get_valid(mReadPngPtr, mReadInfoPtr, PNG_INFO_tRNS)) { png_set_tRNS_to_alpha(mReadPngPtr); } if (mBitDepth < 8) { png_set_packing(mReadPngPtr); } else if (mBitDepth == 16) { png_set_strip_16(mReadPngPtr); } #if LL_DARWIN const F64 SCREEN_GAMMA = 1.8; #else const F64 SCREEN_GAMMA = 2.2; #endif if (png_get_gAMA(mReadPngPtr, mReadInfoPtr, &mGamma)) { png_set_gamma(mReadPngPtr, SCREEN_GAMMA, mGamma); } else { png_set_gamma(mReadPngPtr, SCREEN_GAMMA, 1/SCREEN_GAMMA); } }
void setformat_rgba8( png_structp png, png_infop info, int bitdepth, int colortype ) { double gamma; if( png_get_gAMA( png, info, &gamma ) ) { png_set_gamma( png, 2.2, gamma ); } else { png_set_gamma( png, 2.2, 0.45455 ); } if( colortype == PNG_COLOR_TYPE_PALETTE ) { png_set_palette_to_rgb( png ); } if( colortype == PNG_COLOR_TYPE_GRAY && bitdepth < 8 ) { png_set_expand_gray_1_2_4_to_8( png ); } if( png_get_valid( png, info, PNG_INFO_tRNS ) ) { png_set_tRNS_to_alpha( png ); } else { int channels = png_get_channels( png, info ); if( channels == 1 || channels == 3 ) { png_set_add_alpha( png, 255, PNG_FILLER_AFTER ); } } if( colortype == PNG_COLOR_TYPE_GRAY || colortype == PNG_COLOR_TYPE_GRAY_ALPHA ) { png_set_gray_to_rgb( png ); } if( bitdepth == 16 ) { png_set_scale_16( png ); } }
static GstFlowReturn gst_pngdec_caps_create_and_set (GstPngDec * pngdec) { GstFlowReturn ret = GST_FLOW_OK; gint bpc = 0, color_type; png_uint_32 width, height; GstVideoFormat format = GST_VIDEO_FORMAT_UNKNOWN; g_return_val_if_fail (GST_IS_PNGDEC (pngdec), GST_FLOW_ERROR); /* Get bits per channel */ bpc = png_get_bit_depth (pngdec->png, pngdec->info); /* Get Color type */ color_type = png_get_color_type (pngdec->png, pngdec->info); /* Add alpha channel if 16-bit depth, but not for GRAY images */ if ((bpc > 8) && (color_type != PNG_COLOR_TYPE_GRAY)) { png_set_add_alpha (pngdec->png, 0xffff, PNG_FILLER_BEFORE); png_set_swap (pngdec->png); } #if 0 /* We used to have this HACK to reverse the outgoing bytes, but the problem * that originally required the hack seems to have been in videoconvert's * RGBA descriptions. It doesn't seem needed now that's fixed, but might * still be needed on big-endian systems, I'm not sure. J.S. 6/7/2007 */ if (color_type == PNG_COLOR_TYPE_RGB_ALPHA) png_set_bgr (pngdec->png); #endif /* Gray scale with alpha channel converted to RGB */ if (color_type == PNG_COLOR_TYPE_GRAY_ALPHA) { GST_LOG_OBJECT (pngdec, "converting grayscale png with alpha channel to RGB"); png_set_gray_to_rgb (pngdec->png); } /* Gray scale converted to upscaled to 8 bits */ if ((color_type == PNG_COLOR_TYPE_GRAY_ALPHA) || (color_type == PNG_COLOR_TYPE_GRAY)) { if (bpc < 8) { /* Convert to 8 bits */ GST_LOG_OBJECT (pngdec, "converting grayscale image to 8 bits"); #if PNG_LIBPNG_VER < 10400 png_set_gray_1_2_4_to_8 (pngdec->png); #else png_set_expand_gray_1_2_4_to_8 (pngdec->png); #endif } } /* Palette converted to RGB */ if (color_type == PNG_COLOR_TYPE_PALETTE) { GST_LOG_OBJECT (pngdec, "converting palette png to RGB"); png_set_palette_to_rgb (pngdec->png); } png_set_interlace_handling (pngdec->png); /* Update the info structure */ png_read_update_info (pngdec->png, pngdec->info); /* Get IHDR header again after transformation settings */ png_get_IHDR (pngdec->png, pngdec->info, &width, &height, &bpc, &pngdec->color_type, NULL, NULL, NULL); GST_LOG_OBJECT (pngdec, "this is a %dx%d PNG image", (gint) width, (gint) height); switch (pngdec->color_type) { case PNG_COLOR_TYPE_RGB: GST_LOG_OBJECT (pngdec, "we have no alpha channel, depth is 24 bits"); if (bpc == 8) format = GST_VIDEO_FORMAT_RGB; break; case PNG_COLOR_TYPE_RGB_ALPHA: GST_LOG_OBJECT (pngdec, "we have an alpha channel, depth is 32 or 64 bits"); if (bpc == 8) format = GST_VIDEO_FORMAT_RGBA; else if (bpc == 16) format = GST_VIDEO_FORMAT_ARGB64; break; case PNG_COLOR_TYPE_GRAY: GST_LOG_OBJECT (pngdec, "We have an gray image, depth is 8 or 16 (be) bits"); if (bpc == 8) format = GST_VIDEO_FORMAT_GRAY8; else if (bpc == 16) format = GST_VIDEO_FORMAT_GRAY16_BE; break; default: break; } if (format == GST_VIDEO_FORMAT_UNKNOWN) { GST_ELEMENT_ERROR (pngdec, STREAM, NOT_IMPLEMENTED, (NULL), ("pngdec does not support this color type")); ret = GST_FLOW_NOT_SUPPORTED; goto beach; } /* Check if output state changed */ if (pngdec->output_state) { GstVideoInfo *info = &pngdec->output_state->info; if (width == GST_VIDEO_INFO_WIDTH (info) && height == GST_VIDEO_INFO_HEIGHT (info) && GST_VIDEO_INFO_FORMAT (info) == format) { goto beach; } gst_video_codec_state_unref (pngdec->output_state); } pngdec->output_state = gst_video_decoder_set_output_state (GST_VIDEO_DECODER (pngdec), format, width, height, pngdec->input_state); gst_video_decoder_negotiate (GST_VIDEO_DECODER (pngdec)); GST_DEBUG ("Final %d %d", GST_VIDEO_INFO_WIDTH (&pngdec->output_state->info), GST_VIDEO_INFO_HEIGHT (&pngdec->output_state->info)); beach: return ret; }
static FIBITMAP * DLL_CALLCONV Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) { png_structp png_ptr = NULL; png_infop info_ptr; png_uint_32 width, height; png_colorp png_palette = NULL; int color_type, palette_entries = 0; 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; 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); pixel_depth = png_get_bit_depth(png_ptr, info_ptr) * png_get_channels(png_ptr, info_ptr); // get image data type (assume standard image type) FREE_IMAGE_TYPE image_type = FIT_BITMAP; if (bit_depth == 16) { if ((pixel_depth == 16) && (color_type == PNG_COLOR_TYPE_GRAY)) { image_type = FIT_UINT16; } else if ((pixel_depth == 48) && (color_type == PNG_COLOR_TYPE_RGB)) { image_type = FIT_RGB16; } else if ((pixel_depth == 64) && (color_type == PNG_COLOR_TYPE_RGB_ALPHA)) { image_type = FIT_RGBA16; } else { // tell libpng to strip 16 bit/color files down to 8 bits/color png_set_strip_16(png_ptr); bit_depth = 8; } } #ifndef FREEIMAGE_BIGENDIAN if((image_type == FIT_UINT16) || (image_type == FIT_RGB16) || (image_type == FIT_RGBA16)) { // turn on 16 bit byte swapping png_set_swap(png_ptr); } #endif // set some additional flags switch(color_type) { case PNG_COLOR_TYPE_RGB: case PNG_COLOR_TYPE_RGB_ALPHA: #if FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_BGR // flip the RGB pixels to BGR (or RGBA to BGRA) if(image_type == FIT_BITMAP) { png_set_bgr(png_ptr); } #endif break; case PNG_COLOR_TYPE_PALETTE: // expand palette images to the full 8 bits from 2 bits/pixel if (pixel_depth == 2) { png_set_packing(png_ptr); pixel_depth = 8; } break; case PNG_COLOR_TYPE_GRAY: // expand grayscale images to the full 8 bits from 2 bits/pixel // but *do not* expand fully transparent palette entries to a full alpha channel if (pixel_depth == 2) { png_set_expand_gray_1_2_4_to_8(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); #if FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_BGR // flip the RGBA pixels to BGRA png_set_bgr(png_ptr); #endif pixel_depth = 32; break; default: throw FI_MSG_ERROR_UNSUPPORTED_FORMAT; } // 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") if (png_get_valid(png_ptr, info_ptr, PNG_INFO_gAMA)) { 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); if(image_type == FIT_BITMAP) { dib = FreeImage_AllocateHeader(header_only, width, height, 24, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK); } else { dib = FreeImage_AllocateHeaderT(header_only, image_type, width, height, pixel_depth); } break; case PNG_COLOR_TYPE_RGB_ALPHA: if(image_type == FIT_BITMAP) { dib = FreeImage_AllocateHeader(header_only, width, height, 32, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK); } else { dib = FreeImage_AllocateHeaderT(header_only, image_type, width, height, pixel_depth); } break; case PNG_COLOR_TYPE_PALETTE: dib = FreeImage_AllocateHeader(header_only, width, height, pixel_depth); png_get_PLTE(png_ptr,info_ptr, &png_palette, &palette_entries); palette_entries = MIN((unsigned)palette_entries, FreeImage_GetColorsUsed(dib)); palette = FreeImage_GetPalette(dib); // store the palette for (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); if(pixel_depth <= 8) { palette = FreeImage_GetPalette(dib); palette_entries = 1 << pixel_depth; for (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; } // 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 < palette_entries) { BYTE table[256]; memset(table, 0xFF, palette_entries); table[trans_color->gray] = 0; FreeImage_SetTransparencyTable(dib, table, palette_entries); } } else if((color_type == PNG_COLOR_TYPE_PALETTE) && trans_alpha) { // transparency table FreeImage_SetTransparencyTable(dib, (BYTE *)trans_alpha, num_trans); } } // store the background color if (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) { // clean up after the read, and free any memory allocated - REQUIRED png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); } return dib; } catch (const char *text) { if (png_ptr) { png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); } if (row_pointers) { free(row_pointers); } if (dib) { FreeImage_Unload(dib); } FreeImage_OutputMessageProc(s_format_id, text); return NULL; } } return NULL; }
bool PngDecoder::readData( Mat& img ) { bool result = false; AutoBuffer<uchar*> _buffer(m_height); uchar** buffer = _buffer; int color = img.channels() > 1; uchar* data = img.data; int step = (int)img.step; if( m_png_ptr && m_info_ptr && m_end_info && m_width && m_height ) { png_structp png_ptr = (png_structp)m_png_ptr; png_infop info_ptr = (png_infop)m_info_ptr; png_infop end_info = (png_infop)m_end_info; if( setjmp( png_jmpbuf ( png_ptr ) ) == 0 ) { int y; if( img.depth() == CV_8U && m_bit_depth == 16 ) png_set_strip_16( png_ptr ); else if( !isBigEndian() ) png_set_swap( png_ptr ); if(img.channels() < 4) { /* observation: png_read_image() writes 400 bytes beyond * end of data when reading a 400x118 color png * "mpplus_sand.png". OpenCV crashes even with demo * programs. Looking at the loaded image I'd say we get 4 * bytes per pixel instead of 3 bytes per pixel. Test * indicate that it is a good idea to always ask for * stripping alpha.. 18.11.2004 Axel Walthelm */ png_set_strip_alpha( png_ptr ); } if( m_color_type == PNG_COLOR_TYPE_PALETTE ) png_set_palette_to_rgb( png_ptr ); if( m_color_type == PNG_COLOR_TYPE_GRAY && m_bit_depth < 8 ) #if (PNG_LIBPNG_VER_MAJOR*10000 + PNG_LIBPNG_VER_MINOR*100 + PNG_LIBPNG_VER_RELEASE >= 10209) || \ (PNG_LIBPNG_VER_MAJOR == 1 && PNG_LIBPNG_VER_MINOR == 0 && PNG_LIBPNG_VER_RELEASE >= 18) png_set_expand_gray_1_2_4_to_8( png_ptr ); #else png_set_gray_1_2_4_to_8( png_ptr ); #endif if( CV_MAT_CN(m_type) > 1 && color ) png_set_bgr( png_ptr ); // convert RGB to BGR else if( color ) png_set_gray_to_rgb( png_ptr ); // Gray->RGB else png_set_rgb_to_gray( png_ptr, 1, 0.299, 0.587 ); // RGB->Gray png_read_update_info( png_ptr, info_ptr ); for( y = 0; y < m_height; y++ ) buffer[y] = data + y*step; png_read_image( png_ptr, buffer ); png_read_end( png_ptr, end_info ); result = true; } } close(); return result; }
int read_header(const char *filename, dt_imageio_png_t *png) { png->f = fopen(filename, "rb"); if(!png->f) return 1; const size_t NUM_BYTES_CHECK = 8; png_byte dat[NUM_BYTES_CHECK]; size_t cnt = fread(dat, 1, NUM_BYTES_CHECK, png->f); if(cnt != NUM_BYTES_CHECK || png_sig_cmp(dat, (png_size_t)0, NUM_BYTES_CHECK)) { fclose(png->f); return 1; } png->png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if(!png->png_ptr) { fclose(png->f); return 1; } png->info_ptr = png_create_info_struct(png->png_ptr); if(!png->info_ptr) { fclose(png->f); png_destroy_read_struct(&png->png_ptr, NULL, NULL); return 1; } if(setjmp(png_jmpbuf(png->png_ptr))) { fclose(png->f); png_destroy_read_struct(&png->png_ptr, &png->info_ptr, NULL); return 1; } png_init_io(png->png_ptr, png->f); // we checked some bytes png_set_sig_bytes(png->png_ptr, NUM_BYTES_CHECK); // image info png_read_info(png->png_ptr, png->info_ptr); png->bit_depth = png_get_bit_depth(png->png_ptr, png->info_ptr); png->color_type = png_get_color_type(png->png_ptr, png->info_ptr); // image input transformations // palette => rgb if(png->color_type == PNG_COLOR_TYPE_PALETTE) png_set_palette_to_rgb(png->png_ptr); // 1, 2, 4 bit => 8 bit if(png->color_type == PNG_COLOR_TYPE_GRAY && png->bit_depth < 8) { png_set_expand_gray_1_2_4_to_8(png->png_ptr); png->bit_depth = 8; } // strip alpha channel if(png->color_type & PNG_COLOR_MASK_ALPHA) png_set_strip_alpha(png->png_ptr); // grayscale => rgb if(png->color_type == PNG_COLOR_TYPE_GRAY || png->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) png_set_gray_to_rgb(png->png_ptr); // png->bytespp = 3*bit_depth/8; png->width = png_get_image_width(png->png_ptr, png->info_ptr); png->height = png_get_image_height(png->png_ptr, png->info_ptr); return 0; }
Load_SBit_Png( FT_GlyphSlot slot, FT_Int x_offset, FT_Int y_offset, FT_Int pix_bits, TT_SBit_Metrics metrics, FT_Memory memory, FT_Byte* data, FT_UInt png_len, FT_Bool populate_map_and_metrics ) { FT_Bitmap *map = &slot->bitmap; FT_Error error = FT_Err_Ok; FT_StreamRec stream; png_structp png; png_infop info; png_uint_32 imgWidth, imgHeight; int bitdepth, color_type, interlace; FT_Int i; png_byte* *rows = NULL; /* pacify compiler */ if ( x_offset < 0 || y_offset < 0 ) { error = FT_THROW( Invalid_Argument ); goto Exit; } if ( !populate_map_and_metrics && ( x_offset + metrics->width > map->width || y_offset + metrics->height > map->rows || pix_bits != 32 || map->pixel_mode != FT_PIXEL_MODE_BGRA ) ) { error = FT_THROW( Invalid_Argument ); goto Exit; } FT_Stream_OpenMemory( &stream, data, png_len ); png = png_create_read_struct( PNG_LIBPNG_VER_STRING, &error, error_callback, warning_callback ); if ( !png ) { error = FT_THROW( Out_Of_Memory ); goto Exit; } info = png_create_info_struct( png ); if ( !info ) { error = FT_THROW( Out_Of_Memory ); png_destroy_read_struct( &png, NULL, NULL ); goto Exit; } if ( ft_setjmp( png_jmpbuf( png ) ) ) { error = FT_THROW( Invalid_File_Format ); goto DestroyExit; } png_set_read_fn( png, &stream, read_data_from_FT_Stream ); png_read_info( png, info ); png_get_IHDR( png, info, &imgWidth, &imgHeight, &bitdepth, &color_type, &interlace, NULL, NULL ); if ( error || ( !populate_map_and_metrics && ( (FT_Int)imgWidth != metrics->width || (FT_Int)imgHeight != metrics->height ) ) ) goto DestroyExit; if ( populate_map_and_metrics ) { FT_Long size; metrics->width = (FT_Int)imgWidth; metrics->height = (FT_Int)imgHeight; map->width = metrics->width; map->rows = metrics->height; map->pixel_mode = FT_PIXEL_MODE_BGRA; map->pitch = map->width * 4; map->num_grays = 256; size = map->rows * map->pitch; error = ft_glyphslot_alloc_bitmap( slot, size ); if ( error ) goto DestroyExit; } /* convert palette/gray image to rgb */ if ( color_type == PNG_COLOR_TYPE_PALETTE ) png_set_palette_to_rgb( png ); /* expand gray bit depth if needed */ if ( color_type == PNG_COLOR_TYPE_GRAY ) { #if PNG_LIBPNG_VER >= 10209 png_set_expand_gray_1_2_4_to_8( png ); #else png_set_gray_1_2_4_to_8( png ); #endif } /* transform transparency to alpha */ if ( png_get_valid(png, info, PNG_INFO_tRNS ) ) png_set_tRNS_to_alpha( png ); if ( bitdepth == 16 ) png_set_strip_16( png ); if ( bitdepth < 8 ) png_set_packing( png ); /* convert grayscale to RGB */ if ( color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA ) png_set_gray_to_rgb( png ); if ( interlace != PNG_INTERLACE_NONE ) png_set_interlace_handling( png ); png_set_filler( png, 0xFF, PNG_FILLER_AFTER ); /* recheck header after setting EXPAND options */ png_read_update_info(png, info ); png_get_IHDR( png, info, &imgWidth, &imgHeight, &bitdepth, &color_type, &interlace, NULL, NULL ); if ( bitdepth != 8 || !( color_type == PNG_COLOR_TYPE_RGB || color_type == PNG_COLOR_TYPE_RGB_ALPHA ) ) { error = FT_THROW( Invalid_File_Format ); goto DestroyExit; } switch ( color_type ) { default: /* Shouldn't happen, but fall through. */ case PNG_COLOR_TYPE_RGB_ALPHA: png_set_read_user_transform_fn( png, premultiply_data ); break; case PNG_COLOR_TYPE_RGB: /* Humm, this smells. Carry on though. */ png_set_read_user_transform_fn( png, convert_bytes_to_data ); break; } if ( FT_NEW_ARRAY( rows, imgHeight ) ) { error = FT_THROW( Out_Of_Memory ); goto DestroyExit; } for ( i = 0; i < (FT_Int)imgHeight; i++ ) rows[i] = map->buffer + ( y_offset + i ) * map->pitch + x_offset * 4; png_read_image( png, rows ); FT_FREE( rows ); png_read_end( png, info ); DestroyExit: png_destroy_read_struct( &png, &info, NULL ); FT_Stream_Close( &stream ); Exit: return error; }
TypedImage LoadPng(const std::string& filename) { PANGOLIN_UNUSED(filename); #ifdef HAVE_PNG FILE *in = fopen(filename.c_str(), "rb"); if( in ) { //check the header const size_t nBytes = 8; png_byte header[nBytes]; size_t nread = fread(header, 1, nBytes, in); int nIsPNG = png_sig_cmp(header, 0, nread); if ( nIsPNG != 0 ) { throw std::runtime_error( filename + " is not a PNG file" ); } //set up initial png structs png_structp png_ptr = png_create_read_struct( PNG_LIBPNG_VER_STRING, (png_voidp)NULL, NULL, &PngWarningsCallback); if (!png_ptr) { throw std::runtime_error( "PNG Init error 1" ); } png_infop info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL); throw std::runtime_error( "PNG Init error 2" ); } png_infop end_info = png_create_info_struct(png_ptr); if (!end_info) { png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); throw std::runtime_error( "PNG Init error 3" ); } png_init_io(png_ptr, in); png_set_sig_bytes(png_ptr, nBytes); //read the file png_read_png(png_ptr, info_ptr, PNG_TRANSFORM_SWAP_ENDIAN, NULL); if( png_get_bit_depth(png_ptr, info_ptr) == 1) { //Unpack bools to bytes to ease loading. png_set_packing(png_ptr); } else if( png_get_bit_depth(png_ptr, info_ptr) < 8) { //Expand nonbool colour depths up to 8bpp png_set_expand_gray_1_2_4_to_8(png_ptr); } //Get rid of palette, by transforming it to RGB if(png_get_color_type(png_ptr, info_ptr) == PNG_COLOR_TYPE_PALETTE) { png_set_palette_to_rgb(png_ptr); } if( png_get_interlace_type(png_ptr,info_ptr) != PNG_INTERLACE_NONE) { throw std::runtime_error( "Interlace not yet supported" ); } const size_t w = png_get_image_width(png_ptr,info_ptr); const size_t h = png_get_image_height(png_ptr,info_ptr); const size_t pitch = png_get_rowbytes(png_ptr, info_ptr); TypedImage img(w, h, PngFormat(png_ptr, info_ptr), pitch); png_bytepp rows = png_get_rows(png_ptr, info_ptr); for( unsigned int r = 0; r < h; r++) { memcpy( img.ptr + pitch*r, rows[r], pitch ); } png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); fclose(in); return img; } throw std::runtime_error("Unable to load PNG file, '" + filename + "'"); #else throw std::runtime_error("PNG Support not enabled. Please rebuild Pangolin."); #endif }
bool Image::initWithPngData(const unsigned char * data, ssize_t dataLen) { #if CC_USE_WIC return decodeWithWIC(data, dataLen); #else // length of bytes to check if it is a valid png file #define PNGSIGSIZE 8 bool ret = false; png_byte header[PNGSIGSIZE] = { 0 }; png_structp png_ptr = 0; png_infop info_ptr = 0; do { // png header len is 8 bytes CC_BREAK_IF(dataLen < PNGSIGSIZE); // check the data is png or not memcpy(header, data, PNGSIGSIZE); CC_BREAK_IF(png_sig_cmp(header, 0, PNGSIGSIZE)); // init png_struct png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0); CC_BREAK_IF(!png_ptr); // init png_info info_ptr = png_create_info_struct(png_ptr); CC_BREAK_IF(!info_ptr); #if (PARA_TARGET_PLATFORM != PARA_PLATFORM_BADA && PARA_TARGET_PLATFORM != PARA_PLATFORM_NACL && PARA_TARGET_PLATFORM != PARA_PLATFORM_TIZEN) CC_BREAK_IF(setjmp(png_jmpbuf(png_ptr))); #endif // set the read call back function tImageSource imageSource; imageSource.data = (unsigned char*)data; imageSource.size = dataLen; imageSource.offset = 0; png_set_read_fn(png_ptr, &imageSource, pngReadCallback); // read png header info // read png file info png_read_info(png_ptr, info_ptr); _width = png_get_image_width(png_ptr, info_ptr); _height = png_get_image_height(png_ptr, info_ptr); png_byte bit_depth = png_get_bit_depth(png_ptr, info_ptr); png_uint_32 color_type = png_get_color_type(png_ptr, info_ptr); //OUTPUT_LOG("color type %u", color_type); // force palette images to be expanded to 24-bit RGB // it may include alpha channel if (color_type == PNG_COLOR_TYPE_PALETTE) { png_set_palette_to_rgb(png_ptr); } // low-bit-depth grayscale images are to be expanded to 8 bits if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) { bit_depth = 8; png_set_expand_gray_1_2_4_to_8(png_ptr); } // expand any tRNS chunk data into a full alpha channel if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { png_set_tRNS_to_alpha(png_ptr); } // reduce images with 16-bit samples to 8 bits if (bit_depth == 16) { png_set_strip_16(png_ptr); } // Expanded earlier for grayscale, now take care of palette and rgb if (bit_depth < 8) { png_set_packing(png_ptr); } // update info png_read_update_info(png_ptr, info_ptr); bit_depth = png_get_bit_depth(png_ptr, info_ptr); color_type = png_get_color_type(png_ptr, info_ptr); switch (color_type) { case PNG_COLOR_TYPE_GRAY: _renderFormat = Texture2D::PixelFormat::I8; break; case PNG_COLOR_TYPE_GRAY_ALPHA: _renderFormat = Texture2D::PixelFormat::AI88; break; case PNG_COLOR_TYPE_RGB: _renderFormat = Texture2D::PixelFormat::RGB888; break; case PNG_COLOR_TYPE_RGB_ALPHA: _renderFormat = Texture2D::PixelFormat::RGBA8888; break; default: break; } // read png data png_size_t rowbytes; png_bytep* row_pointers = (png_bytep*)malloc(sizeof(png_bytep) * _height); rowbytes = png_get_rowbytes(png_ptr, info_ptr); _dataLen = rowbytes * _height; _data = static_cast<unsigned char*>(malloc(_dataLen * sizeof(unsigned char))); if (!_data) { if (row_pointers != nullptr) { free(row_pointers); } break; } for (unsigned short i = 0; i < _height; ++i) { row_pointers[i] = _data + i*rowbytes; } png_read_image(png_ptr, row_pointers); png_read_end(png_ptr, nullptr); // premultiplied alpha for RGBA8888 if (PNG_PREMULTIPLIED_ALPHA_ENABLED && color_type == PNG_COLOR_TYPE_RGB_ALPHA) { premultipliedAlpha(); } if (row_pointers != nullptr) { free(row_pointers); } ret = true; } while (0); if (png_ptr) { png_destroy_read_struct(&png_ptr, (info_ptr) ? &info_ptr : 0, 0); } return ret; #endif }
unsigned char* load_png_data(char *filename, int *w, int *h) { FILE *fp = fopen(filename, "rb"); if(!fp) { return NULL; } png_byte header[8]; fread(header, 1, 8, fp); if(png_sig_cmp(header, 0, 8)) { return NULL; } png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if(!png_ptr) { return NULL; } png_infop info_ptr = png_create_info_struct(png_ptr); if(!info_ptr) { png_destroy_read_struct(&png_ptr, NULL, NULL); fclose(fp); return NULL; } png_infop end_ptr = png_create_info_struct(png_ptr); if(!end_ptr) { png_destroy_read_struct(&png_ptr, &info_ptr, NULL); fclose(fp); return NULL; } if(setjmp(png_jmpbuf(png_ptr))) { png_destroy_read_struct(&png_ptr, &info_ptr, &end_ptr); fclose(fp); return NULL; } png_init_io(png_ptr, fp); png_set_sig_bytes(png_ptr, 8); png_read_info(png_ptr, info_ptr); int bit_depth = png_get_bit_depth(png_ptr, info_ptr); switch(png_get_color_type(png_ptr, info_ptr)) { case PNG_COLOR_TYPE_PALETTE: png_set_palette_to_rgb(png_ptr); png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER); break; case PNG_COLOR_TYPE_GRAY: png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER); case PNG_COLOR_TYPE_GRAY_ALPHA: if(bit_depth < 8) png_set_expand_gray_1_2_4_to_8(png_ptr); if(bit_depth==16) png_set_strip_16(png_ptr); png_set_gray_to_rgb(png_ptr); break; case PNG_COLOR_TYPE_RGB: if(bit_depth < 8 ) png_set_packing(png_ptr); if(bit_depth == 16) png_set_strip_16(png_ptr); png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER); break; default: break; } png_read_update_info(png_ptr, info_ptr); *w = png_get_image_width(png_ptr, info_ptr); *h = png_get_image_height(png_ptr, info_ptr); int rowbytes = (int)png_get_rowbytes(png_ptr, info_ptr); png_bytep data = malloc((*h)*rowbytes*sizeof(*data)); png_bytep row_pointers[*h]; int i; for(i=0; i<(*h); ++i) { row_pointers[i] = &data[i*rowbytes]; } png_read_image(png_ptr, row_pointers); png_destroy_read_struct(&png_ptr, &info_ptr, &end_ptr); fclose(fp); return data; }
s_screen *pngToScreen(const void *data) { png_structp png_ptr; png_infop info_ptr; unsigned int sig_read = 0; png_uint_32 width, height; int bit_depth, color_type, interlace_type, y; u32 *line; s_screen *image; png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if(png_ptr == NULL) { goto error; } png_set_error_fn(png_ptr, (png_voidp) NULL, (png_error_ptr) NULL, png_warning_fn); info_ptr = png_create_info_struct(png_ptr); if(info_ptr == NULL) { goto error2; } if(setjmp(png_jmpbuf(png_ptr))) { goto error2; } png_set_read_fn(png_ptr, &data, png_read_fn); png_set_sig_bytes(png_ptr, sig_read); png_read_info(png_ptr, info_ptr); png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, NULL, NULL); png_set_strip_16(png_ptr); png_set_packing(png_ptr); if(color_type == PNG_COLOR_TYPE_PALETTE) { png_set_palette_to_rgb(png_ptr); } if(color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) { png_set_expand_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 WII png_set_filler(png_ptr, 0xff, PNG_FILLER_BEFORE); #else png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER); #endif image = allocscreen(width, height, PIXEL_32); if(image == NULL) { goto error2; } line = (u32 *)image->data; for(y = 0; y < height; y++) { png_read_row(png_ptr, (u8 *) line, NULL); line += width; } png_read_end(png_ptr, info_ptr); png_destroy_read_struct(&png_ptr, &info_ptr, NULL); return image; error2: png_destroy_read_struct(&png_ptr, NULL, NULL); error: return NULL; }
static png_bytepp eiio_png_read_rgb(const void *blob, size_t blob_size, int *width, int *height, int *channels) { png_structp png = NULL; png_infop info = NULL; blob_input_t blob_input; int bit_depth, color_type; png_bytepp rows = NULL; png_uint_32 uwidth, uheight; int i; png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (png == NULL){ return NULL; } info = png_create_info_struct(png); if(info == NULL){ png_destroy_read_struct(&png, NULL, NULL); return NULL; } if (setjmp(png_jmpbuf(png))) { png_destroy_read_struct(&png, &info, NULL); eiio_png_rows_free(&rows); return NULL; } blob_input.blob = blob; blob_input.offset = 0; blob_input.blob_size = blob_size; png_set_read_fn(png, &blob_input, read_blob); *width = *height = 0; png_read_info(png, info); png_get_IHDR(png, info, &uwidth, &uheight, &bit_depth, &color_type, NULL, NULL, NULL); if (uwidth > 0x7fffffff || uheight > 0x7fffffff) { png_destroy_read_struct(&png, &info, NULL); eiio_png_rows_free(&rows); return NULL; } *width = (int)uwidth; *height = (int)uheight; if (bit_depth == 16) { png_set_strip_16(png); } if ((color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) && bit_depth < 8) { png_set_expand_gray_1_2_4_to_8(png); //png_set_gray_1_2_4_to_8(png); } if (bit_depth < 8) { png_set_packing(png); } if (color_type & PNG_COLOR_MASK_ALPHA) { *channels = 4; } else { *channels = 3; } if (color_type & PNG_COLOR_MASK_PALETTE) { png_set_palette_to_rgb(png); } if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) { png_set_gray_to_rgb(png); } png_read_update_info(png, info); rows = (png_bytepp)eiio_malloc(sizeof(png_bytep) * (*height + 1)); if (rows == NULL) { png_destroy_read_struct(&png, &info, NULL); return NULL; } for (i = 0; i < *height; ++i) { rows[i] = (png_bytep)eiio_malloc(sizeof(png_byte) * *width * *channels); if (rows[i] == NULL) { png_destroy_read_struct(&png, &info, NULL); eiio_png_rows_free(&rows); return NULL; } } rows[*height] = NULL; /* null terminater */ png_read_image(png, rows); png_read_end(png, info); png_destroy_read_struct(&png, &info, NULL); return rows; }
/* Read a PNG file. You may want to return an error code if the read * fails (depending upon the failure). There are two "prototypes" given * here - one where we are given the filename, and we need to open the * file, and the other where we are given an open file (possibly with * some or all of the magic bytes read - see comments above). */ #ifdef open_file /* prototype 1 */ void read_png(char *file_name) /* We need to open the file */ { png_structp png_ptr; png_infop info_ptr; unsigned int sig_read = 0; png_uint_32 width, height; int bit_depth, color_type, interlace_type; FILE *fp; if ((fp = fopen(file_name, "rb")) == NULL) return (ERROR); #else no_open_file /* prototype 2 */ void read_png(FILE *fp, unsigned int sig_read) /* File is already open */ { png_structp png_ptr; png_infop info_ptr; png_uint_32 width, height; int bit_depth, color_type, interlace_type; #endif no_open_file /* Only use one prototype! */ /* Create and initialize the png_struct with the desired error handler * functions. If you want to use the default stderr and longjump method, * you can supply NULL for the last three parameters. We also supply the * the compiler header file version, so that we know if the application * was compiled with a compatible version of the library. REQUIRED */ png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, png_voidp user_error_ptr, user_error_fn, user_warning_fn); if (png_ptr == NULL) { fclose(fp); return (ERROR); } /* Allocate/initialize the memory for image information. REQUIRED. */ info_ptr = png_create_info_struct(png_ptr); if (info_ptr == NULL) { fclose(fp); png_destroy_read_struct(&png_ptr, png_infopp_NULL, png_infopp_NULL); return (ERROR); } /* Set error handling if you are using the setjmp/longjmp method (this is * the normal method of doing things with libpng). REQUIRED unless you * set up your own error handlers in the png_create_read_struct() earlier. */ if (setjmp(png_jmpbuf(png_ptr))) { /* Free all of the memory associated with the png_ptr and info_ptr */ png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL); fclose(fp); /* If we get here, we had a problem reading the file */ return (ERROR); } /* One of the following I/O initialization methods is REQUIRED */ #ifdef streams /* PNG file I/O method 1 */ /* Set up the input control if you are using standard C streams */ png_init_io(png_ptr, fp); #else no_streams /* PNG file I/O method 2 */ /* If you are using replacement read functions, instead of calling * png_init_io() here you would call: */ 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 * dithering, 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, png_voidp_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, int_p_NULL, int_p_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 */ png_set_strip_16(png_ptr); /* 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)) 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)) 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)
PNGImage LoadImagePNG(const char *path) { PNGImage loadedImage; loadedImage.loadedSuccessfully = GL_FALSE; FILE *PNG_file = fopen(path, "rb"); if (PNG_file == NULL) { printf("Can't open PNG file %s\n", path); return loadedImage; } GLubyte PNG_header[PNG_HEADER_SIZE]; fread(PNG_header, 1, PNG_HEADER_SIZE, PNG_file); if (png_sig_cmp(PNG_header, 0, PNG_HEADER_SIZE) != 0) { printf("%s is not a PNG file\n", path); return loadedImage; } png_structp PNG_reader = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (PNG_reader == NULL) { printf("Can't start reading PNG file %s\n", path); fclose(PNG_file); return loadedImage; } png_infop PNG_info = png_create_info_struct(PNG_reader); if (PNG_info == NULL) { printf("Can't get info for PNG file %s\n", path); png_destroy_read_struct(&PNG_reader, NULL, NULL); fclose(PNG_file); return loadedImage; } png_infop PNG_end_info = png_create_info_struct(PNG_reader); if (PNG_end_info == NULL) { printf("Can't get end info for PNG file %s\n", path); png_destroy_read_struct(&PNG_reader, &PNG_info, NULL); fclose(PNG_file); return loadedImage; } if (setjmp(png_jmpbuf(PNG_reader))) { printf("Can't load PNG file %s\n", path); png_destroy_read_struct(&PNG_reader, &PNG_info, &PNG_end_info); fclose(PNG_file); return loadedImage; } png_init_io(PNG_reader, PNG_file); png_set_sig_bytes(PNG_reader, PNG_HEADER_SIZE); png_read_info(PNG_reader, PNG_info); // we have to do a custom transformation to premultiply the alpha of the image png_set_read_user_transform_fn(PNG_reader, png_read_premultiply_alpha); png_uint_32 width, height; int bit_depth, color_type; png_get_IHDR(PNG_reader, PNG_info, &width, &height, &bit_depth, &color_type,NULL, NULL, NULL); if (color_type == PNG_COLOR_TYPE_PALETTE) { png_set_palette_to_rgb(PNG_reader); } if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) { png_set_expand_gray_1_2_4_to_8(PNG_reader); } if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) { png_set_gray_to_rgb(PNG_reader); } if (png_get_valid(PNG_reader, PNG_info, PNG_INFO_tRNS)) { png_set_tRNS_to_alpha(PNG_reader); } else { png_set_filler(PNG_reader, 0xff, PNG_FILLER_AFTER); } if (bit_depth == 16) { png_set_strip_16(PNG_reader); } png_read_update_info(PNG_reader, PNG_info); png_uint_32 widthPow2, heightPow2; widthPow2 = pow2(width); heightPow2 = pow2(height); png_byte* PNG_image_buffer = (png_byte*)malloc(4 * widthPow2 * heightPow2); memset(PNG_image_buffer,0,4*widthPow2*heightPow2); // clear image buffer png_byte** PNG_rows = (png_byte**)malloc(height * sizeof(png_byte*)); png_uint_32 rowBytes = widthPow2*4; // load the image from the bottom up /* image texture in mem looks like: -------- | | |xxxx | |xxxx | -------- where 'x's represent actual image data and the lines are the image buffer. so the image is aligned at the (0,0) texel coordinate of the image buffer. */ unsigned int row; for (row = 0; row < height; ++row) { PNG_rows[height-1-row] = PNG_image_buffer + (row * rowBytes); } png_read_image(PNG_reader, PNG_rows); free(PNG_rows); png_destroy_read_struct(&PNG_reader, &PNG_info, &PNG_end_info); fclose(PNG_file); GLuint textureID = 0; glGenTextures(1, &textureID); glBindTexture(GL_TEXTURE_2D, textureID); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, widthPow2, heightPow2, 0, GL_RGBA, GL_UNSIGNED_BYTE, PNG_image_buffer); free(PNG_image_buffer); loadedImage.width = width; loadedImage.height = height; loadedImage.widthPow2 = widthPow2; loadedImage.heightPow2 = heightPow2; loadedImage.textureId = textureID; loadedImage.loadedSuccessfully = GL_TRUE; return loadedImage; }
Image * readPNG(const char *filename) { FILE *fp; png_structp png_ptr; png_infop info_ptr; png_infop end_info; Image *image; fp = fopen(filename, "rb"); if (!fp) goto no_fp; png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!png_ptr) goto no_png; info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { png_destroy_read_struct(&png_ptr, NULL, NULL); goto no_png; } end_info = png_create_info_struct(png_ptr); if (!end_info) { png_destroy_read_struct(&png_ptr, &info_ptr, NULL); goto no_png; } if (setjmp(png_jmpbuf(png_ptr))) { png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); goto no_png; } png_init_io(png_ptr, fp); png_read_info(png_ptr, info_ptr); png_uint_32 width, height; int bit_depth, color_type, interlace_type, compression_type, filter_method; png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, &compression_type, &filter_method); image = new Image(width, height); if (!image) goto no_image; /* Convert to RGBA8 */ if (color_type == PNG_COLOR_TYPE_PALETTE) png_set_palette_to_rgb(png_ptr); if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) png_set_expand_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 (bit_depth == 16) png_set_strip_16(png_ptr); for (unsigned y = 0; y < height; ++y) { png_bytep row = (png_bytep)(image->pixels + y*width*4); png_read_row(png_ptr, row, NULL); } png_read_end(png_ptr, info_ptr); png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); fclose(fp); return image; no_image: png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); no_png: fclose(fp); no_fp: return NULL; }
/* For little endian systems, ARGB is equivalent to the int32 BGRA. * So, to read the image as RGB */ static SLang_Array_Type *read_image_internal (char *file, int flip, int *color_typep) { Png_Type *p; png_uint_32 width, height, rowbytes; png_struct *png; png_info *info; int bit_depth; int interlace_type; int color_type; unsigned int sizeof_type; SLindex_Type dims[2]; SLtype data_type; png_byte **image_pointers = NULL; png_byte *data = NULL; SLang_Array_Type *at; void (*fixup_array_fun) (SLang_Array_Type *); if (NULL == (p = open_png_file (file))) return NULL; png = p->png; if (setjmp (png_jmpbuf (png))) { free_png_type (p); if (data != NULL) SLfree ((char *) data); free_image_pointers (image_pointers); SLang_verror (SL_Read_Error, "Error encountered during I/O to %s", file); return NULL; } png_init_io (png, p->fp); png_set_sig_bytes (png, 8); info = p->info; png_read_info(png, info); width = png_get_image_width (png, info); height = png_get_image_height (png, info); interlace_type = png_get_interlace_type (png, info); bit_depth = png_get_bit_depth (png, info); if (bit_depth == 16) png_set_strip_16 (png); switch (png_get_color_type (png, info)) { case PNG_COLOR_TYPE_GRAY: #if defined(PNG_LIBPNG_VER) && (PNG_LIBPNG_VER >= 10209) if (bit_depth < 8) png_set_expand_gray_1_2_4_to_8 (png); #else /* deprecated */ if (bit_depth < 8) png_set_gray_1_2_4_to_8 (png); #endif break; case PNG_COLOR_TYPE_GRAY_ALPHA: /* png_set_gray_to_rgb (png); */ break; case PNG_COLOR_TYPE_PALETTE: png_set_palette_to_rgb (png); break; } if (png_get_valid(png, info, PNG_INFO_tRNS)) png_set_tRNS_to_alpha(png); png_read_update_info (png, info); color_type = png_get_color_type (png, info); switch (color_type) { case PNG_COLOR_TYPE_RGBA: sizeof_type = 4; fixup_array_fun = fixup_array_rgba; data_type = SLang_get_int_type (32); break; case PNG_COLOR_TYPE_RGB: sizeof_type = 4; fixup_array_fun = fixup_array_rgb; data_type = SLang_get_int_type (32); break; case PNG_COLOR_TYPE_GRAY_ALPHA: sizeof_type = 2; fixup_array_fun = fixup_array_ga; data_type = SLang_get_int_type (16); break; case PNG_COLOR_TYPE_GRAY: sizeof_type = 1; fixup_array_fun = NULL; data_type = SLANG_UCHAR_TYPE; break; default: SLang_verror (SL_Read_Error, "Unsupported PNG color-type"); free_png_type (p); return NULL; } *color_typep = color_type; /* Use the high-level interface */ rowbytes = png_get_rowbytes (png, info); if (rowbytes > width * sizeof_type) { SLang_verror (SL_INTERNAL_ERROR, "Unexpected value returned from png_get_rowbytes"); free_png_type (p); return NULL; } if (NULL == (data = (png_byte *) SLmalloc (height * width * sizeof_type))) { free_png_type (p); return NULL; } if (NULL == (image_pointers = allocate_image_pointers (height, data, width * sizeof_type, flip))) { SLfree ((char *) data); free_png_type (p); return NULL; } png_read_image(png, image_pointers); dims[0] = height; dims[1] = width; if (NULL == (at = SLang_create_array (data_type, 0, (VOID_STAR) data, dims, 2))) { SLfree ((char *) data); free_image_pointers (image_pointers); free_png_type (p); return NULL; } free_png_type (p); free_image_pointers (image_pointers); if (fixup_array_fun != NULL) (*fixup_array_fun) (at); return at; }
//---------------------------------------------------------------------------------- // //---------------------------------------------------------------------------------- bool PngTextureLoader::Load(void* data, int32_t size, bool rev) { #if __PNG_DDI auto global = GlobalAlloc(GMEM_MOVEABLE,size); auto buf = GlobalLock(global); CopyMemory(buf, data, size); GlobalUnlock(global); LPSTREAM stream = NULL; CreateStreamOnHGlobal( global, false, &stream); Gdiplus::Bitmap* bmp = Gdiplus::Bitmap::FromStream(stream); ES_SAFE_RELEASE(stream); GlobalFree(global); if( bmp != NULL && bmp->GetLastStatus() == Gdiplus::Ok ) { textureWidth = bmp->GetWidth(); textureHeight = bmp->GetHeight(); textureData.resize(textureWidth * textureHeight * 4); if(rev) { for(auto y = 0; y < textureHeight; y++ ) { for(auto x = 0; x < textureWidth; x++ ) { Gdiplus::Color color; bmp->GetPixel(x, textureHeight - y - 1, &color); textureData[(x + y * textureWidth) * 4 + 0] = color.GetR(); textureData[(x + y * textureWidth) * 4 + 1] = color.GetG(); textureData[(x + y * textureWidth) * 4 + 2] = color.GetB(); textureData[(x + y * textureWidth) * 4 + 3] = color.GetA(); } } } else { for(auto y = 0; y < textureHeight; y++ ) { for(auto x = 0; x < textureWidth; x++ ) { Gdiplus::Color color; bmp->GetPixel(x, y, &color); textureData[(x + y * textureWidth) * 4 + 0] = color.GetR(); textureData[(x + y * textureWidth) * 4 + 1] = color.GetG(); textureData[(x + y * textureWidth) * 4 + 2] = color.GetB(); textureData[(x + y * textureWidth) * 4 + 3] = color.GetA(); } } } return true; } else { ES_SAFE_DELETE(bmp); return false; } #else uint8_t* data_ = (uint8_t*) data; /* pngアクセス構造体を作成 */ png_structp png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); /* リードコールバック関数指定 */ png_set_read_fn(png, &data_, &PngReadData); /* png画像情報構造体を作成 */ png_infop png_info = png_create_info_struct(png); /* エラーハンドリング */ if (setjmp(png_jmpbuf(png))) { png_destroy_read_struct(&png, &png_info, NULL); return false; } /* IHDRチャンク情報を取得 */ png_read_info(png, png_info); png_uint_32 width, height; int bit_depth, color_type, interlace_type, comp_type, filter_type; png_get_IHDR(png, png_info, &width, &height, &bit_depth, &color_type, &interlace_type, &comp_type, &filter_type); /* RGBA8888フォーマットに変換する */ if (bit_depth < 8) { png_set_packing(png); } else if (bit_depth == 16) { png_set_strip_16(png); } uint32_t pixelBytes = 4; switch (color_type) { case PNG_COLOR_TYPE_PALETTE: png_set_palette_to_rgb(png); pixelBytes = 4; break; case PNG_COLOR_TYPE_GRAY: png_set_expand_gray_1_2_4_to_8(png); pixelBytes = 3; break; case PNG_COLOR_TYPE_RGB: pixelBytes = 3; break; case PNG_COLOR_TYPE_RGBA: break; } uint8_t* image = new uint8_t[width * height * pixelBytes]; uint32_t pitch = width * pixelBytes; /* イメージデータを読み込む */ textureWidth = width; textureHeight = height; textureData.resize(textureWidth * textureHeight * 4); if (rev) { for (uint32_t i = 0; i < height; i++) { png_read_row(png, &image[(height - 1 - i) * pitch], NULL); } } else { for (uint32_t i = 0; i < height; i++) { png_read_row(png, &image[i * pitch], NULL); } } if (pixelBytes == 4) { memcpy(textureData.data(), image, width * height * pixelBytes); } else { for (int32_t y = 0; y < height; y++) { for (int32_t x = 0; x < width; x++) { int32_t src = (x + y * width) * 3; int32_t dst = (x + y * width) * 4; textureData[dst + 0] = image[src + 0]; textureData[dst + 1] = image[src + 1]; textureData[dst + 2] = image[src + 2]; textureData[dst + 3] = 255; } } } delete [] image; png_destroy_read_struct(&png, &png_info, NULL); return true; #endif }
ImageIO::errorType ImageIO::loadPNG(const char * filename) { #ifdef ENABLE_PNG FILE *file = fopen(filename, "rb"); if (!file) { printf("Error in loadPNG: Cannot open file %s.\n", filename); return IO_ERROR; } // read the header of the image file const unsigned int pngHeaderBytes = 8; png_byte pngHeader[pngHeaderBytes]; if (fread(pngHeader, 1, pngHeaderBytes, file) != pngHeaderBytes) { printf("Error in loadPNG: cannot read the header of the png file.\n"); fclose(file); return (INVALID_FILE_FORMAT); }; int pngFlag = !png_sig_cmp(pngHeader, 0, pngHeaderBytes); if (!pngFlag) { printf("Error in loadPNG: %s is not a png file.\n", filename); fclose(file); return (INVALID_FILE_FORMAT); } // initialize png_struct and png_info png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!png_ptr) { printf("Error in loadPNG: Creating the internal structure failed.\n"); fclose(file); return (IO_ERROR); } png_infop info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL); printf("Error in loadPNG: Creating the information structure failed.\n"); fclose(file); return (IO_ERROR); } if (setjmp(png_jmpbuf(png_ptr))) { png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); fclose(file); printf("Error in loadPNG: cannot setup the error handling.\n"); return (IO_ERROR); } png_init_io(png_ptr, file); png_set_sig_bytes(png_ptr, pngHeaderBytes); png_read_info(png_ptr, info_ptr); int color_type; int bit_depth; png_get_IHDR(png_ptr, info_ptr, (png_uint_32*)(&width), (png_uint_32*)(&height), &bit_depth, &color_type, NULL, NULL, NULL); // !!ATTETNION!! The following transformations are designed in the order that they should occur. // DO NOT change the sequence!! bool setBackgroundNeeded = false; switch (color_type) { case PNG_COLOR_TYPE_PALETTE: png_set_palette_to_rgb(png_ptr); // change palette to RGB setBackgroundNeeded = true; break; case PNG_COLOR_TYPE_GRAY: if (bit_depth < BITS_PER_CHANNEL_8) // transforms grayscale images of less than 8 to 8 bits. { png_set_expand_gray_1_2_4_to_8(png_ptr); setBackgroundNeeded = true; } break; } // adds a full alpha channel if there is transparency information in a tRNS chunk if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) png_set_tRNS_to_alpha(png_ptr); // The image has 16 bits per channel for every pixel. Strip the pixels down to 8 bits. if (bit_depth == BITS_PER_CHANNEL_16) png_set_strip_16(png_ptr); // PNG files pack pixels of bit depths 1,2, and 4 into bytes. // The following code expands to 1 pixel per byte without changing the value of the pixels if (bit_depth < BITS_PER_CHANNEL_8) png_set_packing(png_ptr); // convert a grayscale image to be represented as RGB if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) { png_set_gray_to_rgb(png_ptr); setBackgroundNeeded = true; } // set background color if needed if (setBackgroundNeeded) { png_color_16 myBackground = {0, 0, 0, 0, 0}; png_color_16 * imageBackground; if (png_get_bKGD(png_ptr, info_ptr, &imageBackground)) png_set_background(png_ptr, imageBackground, PNG_BACKGROUND_GAMMA_FILE, 1, 1.0); else png_set_background(png_ptr, &myBackground, PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0); } // PNG files store 16 bit pixels in net work byte order (big-endian) // The following code may be needed on PC as to change the storage to the little-endian. // if (bit_depth == 16) // png_set_swap(png_ptr); // After setting the transformations, update the png_info structure to reflect any transformations you have requested png_read_update_info(png_ptr, info_ptr); // get color type again. It may be changed if any transformation is applied ?? color_type = png_get_color_type(png_ptr, info_ptr); switch (color_type) { case PNG_COLOR_TYPE_RGB: bytesPerPixel = IMAGE_IO_RGB; break; case PNG_COLOR_TYPE_RGB_ALPHA: bytesPerPixel = IMAGE_IO_RGB_ALPHA; break; default: printf("Error in loadPNG: image transformation failed.\n"); fclose(file); exit(0); // comment this out after debugging, use return IO_ERROR //return (IO_ERROR); break; } // sanity check here if (png_get_rowbytes(png_ptr, info_ptr) != bytesPerPixel * width) { printf("Error in loadPNG: the number of bytes per row, which is %lu, does not match bytesPerPixel * width, which is %d.\n", png_get_rowbytes(png_ptr, info_ptr), bytesPerPixel * width); fclose(file); exit(0); // comment this out after debugging, use return IO_ERROR return (IO_ERROR); } unsigned int bytesPerRow = bytesPerPixel * width; pixels = (unsigned char *) malloc (sizeof(unsigned char) * bytesPerRow * height); png_bytep * row_pointers = (png_bytep*) malloc (sizeof(png_bytep) * height); for(unsigned int row = 0; row < height; row++) row_pointers[row] = (png_byte*)(&pixels[(height - row - 1) * bytesPerRow]); png_read_image(png_ptr, row_pointers); png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); free(row_pointers); fclose(file); return OK; #else return INVALID_FILE_FORMAT; #endif }
int ReadPNG(const uint8_t* const data, size_t data_size, struct WebPPicture* const pic, int keep_alpha, struct Metadata* const metadata) { volatile png_structp png = NULL; volatile png_infop info = NULL; volatile png_infop end_info = NULL; PNGReadContext context = { NULL, 0, 0 }; int color_type, bit_depth, interlaced; int has_alpha; int num_passes; int p; volatile int ok = 0; png_uint_32 width, height, y; int64_t stride; uint8_t* volatile rgb = NULL; if (data == NULL || data_size == 0 || pic == NULL) return 0; context.data = data; context.data_size = data_size; png = png_create_read_struct_2(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL, NULL, MallocFunc, FreeFunc); if (png == NULL) goto End; png_set_error_fn(png, 0, error_function, NULL); if (setjmp(png_jmpbuf(png))) { Error: MetadataFree(metadata); goto End; } info = png_create_info_struct(png); if (info == NULL) goto Error; end_info = png_create_info_struct(png); if (end_info == NULL) goto Error; png_set_read_fn(png, &context, ReadFunc); png_read_info(png, info); if (!png_get_IHDR(png, info, &width, &height, &bit_depth, &color_type, &interlaced, NULL, NULL)) goto Error; png_set_strip_16(png); png_set_packing(png); if (color_type == PNG_COLOR_TYPE_PALETTE) { png_set_palette_to_rgb(png); } if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) { if (bit_depth < 8) { png_set_expand_gray_1_2_4_to_8(png); } png_set_gray_to_rgb(png); } if (png_get_valid(png, info, PNG_INFO_tRNS)) { png_set_tRNS_to_alpha(png); has_alpha = 1; } else { has_alpha = !!(color_type & PNG_COLOR_MASK_ALPHA); } // Apply gamma correction if needed. { double image_gamma = 1 / 2.2, screen_gamma = 2.2; int srgb_intent; if (png_get_sRGB(png, info, &srgb_intent) || png_get_gAMA(png, info, &image_gamma)) { png_set_gamma(png, screen_gamma, image_gamma); } } if (!keep_alpha) { png_set_strip_alpha(png); has_alpha = 0; } num_passes = png_set_interlace_handling(png); png_read_update_info(png, info); stride = (int64_t)(has_alpha ? 4 : 3) * width * sizeof(*rgb); if (stride != (int)stride || !ImgIoUtilCheckSizeArgumentsOverflow(stride, height)) { goto Error; } rgb = (uint8_t*)malloc((size_t)stride * height); if (rgb == NULL) goto Error; for (p = 0; p < num_passes; ++p) { png_bytep row = rgb; for (y = 0; y < height; ++y) { png_read_rows(png, &row, NULL, 1); row += stride; } } png_read_end(png, end_info); if (metadata != NULL && !ExtractMetadataFromPNG(png, info, end_info, metadata)) { fprintf(stderr, "Error extracting PNG metadata!\n"); goto Error; } pic->width = (int)width; pic->height = (int)height; ok = has_alpha ? WebPPictureImportRGBA(pic, rgb, (int)stride) : WebPPictureImportRGB(pic, rgb, (int)stride); if (!ok) { goto Error; } End: if (png != NULL) { png_destroy_read_struct((png_structpp)&png, (png_infopp)&info, (png_infopp)&end_info); } free(rgb); return ok; }
bool isis::codecs::png::DecoderImpl::init() { // checking PNG signature png_byte pngsig[8]; int bytes_read = source_->read(pngsig, 8); if (8 != bytes_read) return false; bool is_png = 0 == png_sig_cmp(pngsig, 0, 8); if (!is_png) return false; // creating png read struct png_ = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, report_error, report_warning); if (!png_) return false; // creating png info struct info_ = png_create_info_struct(png_); if (!info_) return false; // overriding read function png_set_read_fn(png_, reinterpret_cast<png_voidp>(source_.get()), read_png); // error handler if (setjmp(png_jmpbuf(png_))) { ISIS_LOG_COMMENT_LOCATION log_error("Reading error."); return false; } // reading info png_set_sig_bytes(png_, 8); png_read_info(png_, info_); // getting info // png_byte channels = png_get_channels( png, info ); png_uint_32 image_width = png_get_image_width(png_, info_); png_uint_32 image_height = png_get_image_height(png_, info_); png_byte bit_depth = png_get_bit_depth(png_, info_); png_byte colour_type = png_get_color_type(png_, info_); // png_byte filter_type = png_get_filter_type( png, info ); // png_byte interlace_type = png_get_interlace_type( png, info ); // png_byte compression_type = png_get_compression_type( png, info ); // converting any format to A8R8G8B8 switch (colour_type & ~PNG_COLOR_MASK_ALPHA) { case PNG_COLOR_TYPE_GRAY: if (bit_depth < 8) png_set_expand_gray_1_2_4_to_8(png_); png_set_gray_to_rgb(png_); break; case PNG_COLOR_TYPE_RGB: // do nothing break; case PNG_COLOR_TYPE_PALETTE: png_set_palette_to_rgb(png_); break; } // narrow 16bit channels if (bit_depth == 16) png_set_strip_16(png_); // add alpha channel if none if (!(colour_type & PNG_COLOR_MASK_ALPHA)) { // use tRNS if present, otherwise just add 0xFF alpha if (png_get_valid(png_, info_, PNG_INFO_tRNS)) png_set_tRNS_to_alpha(png_); else png_set_add_alpha(png_, 0xFF, PNG_FILLER_AFTER); } // BGR -> RGB png_set_bgr(png_); size_ = {(int)image_width, (int)image_height}; bit_depth_ = 32; // all images are converted to A8R8G8B8 return true; }
/* ================= image_png_load ================= */ GNUC_NONNULL static erbool image_png_load (const char *name, image_t *im) { fs_file_t f; int size, r, width, height, inc; png_byte *image = NULL, *p = NULL; png_structp pngst; png_infop info = NULL; png_byte depth, color_type; if (NULL == (f = fs_open(name, FS_RDONLY, &size, false))) return false; if (NULL == (pngst = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, &epng_error, &epng_warn))) { sys_printf("failed to create png read struct\n"); fs_close(f); return false; } if (NULL == (info = png_create_info_struct(pngst))) { sys_printf("failed to create png info struct\n"); goto error; } if (setjmp(png_jmpbuf(pngst))) goto error; png_set_user_limits(pngst, IMAGE_MAX_WIDTH, IMAGE_MAX_HEIGHT); png_set_read_fn(pngst, f, &epng_read); png_read_info(pngst, info); width = png_get_image_width(pngst, info); height = png_get_image_height(pngst, info); depth = png_get_bit_depth(pngst, info); if (16 == depth) { /* 16 -> 8 */ png_set_strip_16(pngst); depth = 8; } color_type = png_get_color_type(pngst, info); /* 1/2/4 gray -> 8 gray */ if (PNG_COLOR_TYPE_GRAY == color_type && depth < 8) png_set_expand_gray_1_2_4_to_8(pngst); /* gray/palette -> rgb */ if (PNG_COLOR_TYPE_GRAY == color_type || PNG_COLOR_TYPE_GRAY_ALPHA == color_type) png_set_gray_to_rgb(pngst); else if (PNG_COLOR_TYPE_PALETTE) png_set_palette_to_rgb(pngst); /* transparency -> alpha */ if (png_get_valid(pngst, info, PNG_INFO_tRNS)) { png_set_tRNS_to_alpha(pngst); } else { /* to rgba */ if (PNG_COLOR_TYPE_RGB_ALPHA != color_type && PNG_COLOR_TYPE_GRAY_ALPHA != color_type) png_set_add_alpha(pngst, 0xff, PNG_FILLER_AFTER); } /* deinterlace */ png_set_interlace_handling(pngst); /* read */ inc = width * 4; p = image = mem_alloc(image_mempool, height * inc); for (r = 0; r < height ;r++, p += inc) png_read_row(pngst, p, NULL); png_read_end(pngst, NULL); png_destroy_read_struct(&pngst, &info, NULL); fs_close(f); im->width = width; im->height = height; im->data = image; return true; error: if (NULL != f) fs_close(f); png_destroy_read_struct(&pngst, NULL != info ? &info : NULL, NULL); if (NULL != image) mem_free(image); return false; }
int read_png(const std::string & file_name, image_t & image) { png_structp png; png_infop info; int color_type, bit_depth, interlaced; int has_alpha; int num_passes; int p; int ok = 0; png_uint_32 width, height, y; int stride; uint8_t* rgb = NULL; FILE * fp; #ifdef LINUX fp = fopen(file_name.c_str(), "rb"); #endif #ifdef WINDOWS fopen_s(&fp, file_name.c_str(), "rb"); #endif if (fp == NULL) throw webp::exception::FileOperationException(); png = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0); if (png == NULL) { goto End; } png_set_error_fn(png, 0, error_function, NULL); if (setjmp(png_jmpbuf(png))) { Error: png_destroy_read_struct(&png, NULL, NULL); free(rgb); goto End; } info = png_create_info_struct(png); if (info == NULL) goto Error; png_init_io(png, fp); png_read_info(png, info); if (!png_get_IHDR(png, info, &width, &height, &bit_depth, &color_type, &interlaced, NULL, NULL)) goto Error; png_set_strip_16(png); png_set_packing(png); if (color_type == PNG_COLOR_TYPE_PALETTE) png_set_palette_to_rgb(png); if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) { if (bit_depth < 8) { png_set_expand_gray_1_2_4_to_8(png); } png_set_gray_to_rgb(png); } if (png_get_valid(png, info, PNG_INFO_tRNS)) { png_set_tRNS_to_alpha(png); has_alpha = 1; } else { has_alpha = !!(color_type & PNG_COLOR_MASK_ALPHA); } num_passes = png_set_interlace_handling(png); png_read_update_info(png, info); stride = (has_alpha ? 4 : 3) * width * sizeof(*rgb); rgb = (uint8_t*)malloc(stride * height); if (rgb == NULL) goto Error; for (p = 0; p < num_passes; ++p) { for (y = 0; y < height; ++y) { png_bytep row = rgb + y * stride; png_read_rows(png, &row, NULL, 1); } } png_read_end(png, info); png_destroy_read_struct(&png, &info, NULL); image.width = width; image.height = height; image.image.realloc(height * width); for(size_t y = 0; y < height; y++) for(size_t x = 0; x < width; x++){ size_t i = y * width + x; if (has_alpha) { *webp::utils::ALPHA(image.image[i]) = rgb[stride * y + x * 4]; *webp::utils::RED(image.image[i]) = rgb[stride * y + x * 4 + 1]; *webp::utils::GREEN(image.image[i]) = rgb[stride * y + x * 4 + 2]; *webp::utils::BLUE(image.image[i]) = rgb[stride * y + x * 4 + 3]; } else{ *webp::utils::ALPHA(image.image[i]) = 0xFF; *webp::utils::RED(image.image[i]) = rgb[stride * y + x * 3]; *webp::utils::GREEN(image.image[i]) = rgb[stride * y + x * 3 + 1]; *webp::utils::BLUE(image.image[i]) = rgb[stride * y + x * 3 + 2]; } } free(rgb); End: fclose(fp); return ok; }
bool ply_image_load (ply_image_t *image) { png_struct *png; png_info *info; png_uint_32 width, height, row; int bits_per_pixel, color_type, interlace_method; png_byte **rows; uint32_t *bytes; FILE *fp; assert (image != NULL); fp = fopen (image->filename, "r"); if (fp == NULL) return false; png = png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); assert (png != NULL); info = png_create_info_struct (png); assert (info != NULL); png_init_io (png, fp); if (setjmp (png_jmpbuf (png)) != 0) { fclose (fp); return false; } png_read_info (png, info); png_get_IHDR (png, info, &width, &height, &bits_per_pixel, &color_type, &interlace_method, NULL, NULL); if (color_type == PNG_COLOR_TYPE_PALETTE) png_set_palette_to_rgb (png); if ((color_type == PNG_COLOR_TYPE_GRAY) && (bits_per_pixel < 8)) png_set_expand_gray_1_2_4_to_8 (png); if (png_get_valid (png, info, PNG_INFO_tRNS)) png_set_tRNS_to_alpha (png); if (bits_per_pixel == 16) png_set_strip_16 (png); if (bits_per_pixel < 8) png_set_packing (png); if ((color_type == PNG_COLOR_TYPE_GRAY) || (color_type == PNG_COLOR_TYPE_GRAY_ALPHA)) png_set_gray_to_rgb (png); if (interlace_method != PNG_INTERLACE_NONE) png_set_interlace_handling (png); png_set_filler (png, 0xff, PNG_FILLER_AFTER); png_set_read_user_transform_fn (png, transform_to_argb32); png_read_update_info (png, info); rows = malloc (height * sizeof (png_byte *)); image->buffer = ply_pixel_buffer_new (width, height); bytes = ply_pixel_buffer_get_argb32_data (image->buffer); for (row = 0; row < height; row++) rows[row] = (png_byte*) &bytes[row * width]; png_read_image (png, rows); free (rows); png_read_end (png, info); fclose (fp); png_destroy_read_struct (&png, &info, NULL); return true; }
void LinuxAppPlatform::loadPNG(ImageData& imgData, const std::string& path, bool b) { std::cout << "loadPNG: " << path << "(from assets: " << b << ")" << "\n"; FILE* file = fopen(getImagePath(path, b).c_str(), "rb"); if (file == NULL) { std::cout << "failed to open file\n"; return; } png_structp png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!png) { std::cout << "png_create_read_struct failed\n"; abort(); return; } png_infop info = png_create_info_struct(png); if (!info) { std::cout << "png_create_info_struct failed\n"; abort(); return; } unsigned char header[8]; if(fread(header, 8, 1, file) != 1) { std::cout << "failed to read png header\n"; return; } if(png_sig_cmp(header, 0, 8)) { std::cout << "header is invalid\n"; return; } if (setjmp(png_jmpbuf(png))) { std::cout << "failed to load png\n"; abort(); return; } png_init_io(png, file); png_set_sig_bytes(png, 8); png_read_info(png, info); imgData.w = (int) png_get_image_width(png, info); imgData.h = (int) png_get_image_height(png, info); imgData.format = TextureFormat::U8888; imgData.mipLevel = 0; png_byte bitDepth = png_get_bit_depth(png, info); png_byte colorType = png_get_color_type(png, info); switch(colorType){ case PNG_COLOR_TYPE_PALETTE: png_set_palette_to_rgb(png); break; case PNG_COLOR_TYPE_RGB: if(png_get_valid(png, info, PNG_INFO_tRNS)) { png_set_tRNS_to_alpha(png); } else { png_set_filler(png, 0xff, PNG_FILLER_AFTER); } break; case PNG_COLOR_TYPE_RGB_ALPHA: break; case PNG_COLOR_TYPE_GRAY: if(bitDepth < 8) { png_set_expand_gray_1_2_4_to_8(png); } default: std::cout << "png: unsupported color type\n"; } if(bitDepth == 16) { png_set_strip_16(png); } png_read_update_info(png, info); png_size_t rowBytes = png_get_rowbytes(png, info); std::vector<char> data(rowBytes * imgData.h); png_byte* rows[imgData.h]; for (int i = 0; i < imgData.h; i++) { rows[i] = (png_byte*) &data[i * rowBytes]; } png_read_image(png, rows); fclose(file); { std::string empty; ((void **) &imgData.data)[0] = ((void **) &empty)[0]; imgData.data = " "; } imgData.data = std::string(&data[0], rowBytes * imgData.h); }