void PNGImageDecoder::headerAvailable() { png_structp png = reader()->pngPtr(); png_infop info = reader()->infoPtr(); png_uint_32 width = png->width; png_uint_32 height = png->height; // Protect against large images. if (png->width > cMaxPNGSize || png->height > cMaxPNGSize) { m_failed = true; longjmp(png->jmpbuf, 1); return; } // We can fill in the size now that the header is available. if (!ImageDecoder::isSizeAvailable()) { if (!setSize(width, height)) { // Size unreasonable, bail out. longjmp(png->jmpbuf, 1); return; } } int bitDepth, colorType, interlaceType, compressionType, filterType, channels; png_get_IHDR(png, info, &width, &height, &bitDepth, &colorType, &interlaceType, &compressionType, &filterType); // The options we set here match what Mozilla does. // Expand to ensure we use 24-bit for RGB and 32-bit for RGBA. if (colorType == PNG_COLOR_TYPE_PALETTE || (colorType == PNG_COLOR_TYPE_GRAY && bitDepth < 8)) png_set_expand(png); png_bytep trns = 0; int trnsCount = 0; if (png_get_valid(png, info, PNG_INFO_tRNS)) { png_get_tRNS(png, info, &trns, &trnsCount, 0); png_set_expand(png); } if (bitDepth == 16) png_set_strip_16(png); if (colorType == PNG_COLOR_TYPE_GRAY || colorType == PNG_COLOR_TYPE_GRAY_ALPHA) png_set_gray_to_rgb(png); // Deal with gamma and keep it under our control. double gamma; if (png_get_gAMA(png, info, &gamma)) { if ((gamma <= 0.0) || (gamma > cMaxGamma)) { gamma = cInverseGamma; png_set_gAMA(png, info, gamma); } png_set_gamma(png, cDefaultGamma, gamma); } else png_set_gamma(png, cDefaultGamma, cInverseGamma); // Tell libpng to send us rows for interlaced pngs. if (interlaceType == PNG_INTERLACE_ADAM7) png_set_interlace_handling(png); // Update our info now png_read_update_info(png, info); channels = png_get_channels(png, info); assert(channels == 3 || channels == 4); reader()->setHasAlpha(channels == 4); if (reader()->decodingSizeOnly()) { // If we only needed the size, halt the reader. reader()->setReadOffset(m_data->size() - png->buffer_size); png->buffer_size = 0; } }
bool PNGDecoder::loadStream(Common::SeekableReadStream &stream) { #ifdef USE_PNG destroy(); _stream = &stream; // First, check the PNG signature if (_stream->readUint32BE() != MKTAG(0x89, 'P', 'N', 'G')) { delete _stream; return false; } if (_stream->readUint32BE() != MKTAG(0x0d, 0x0a, 0x1a, 0x0a)) { delete _stream; return false; } // The following is based on the guide provided in: //http://www.libpng.org/pub/png/libpng-1.2.5-manual.html#section-3 //http://www.libpng.org/pub/png/libpng-1.4.0-manual.pdf // along with the png-loading code used in the sword25-engine. png_structp pngPtr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!pngPtr) { delete _stream; return false; } png_infop infoPtr = png_create_info_struct(pngPtr); if (!infoPtr) { png_destroy_read_struct(&pngPtr, NULL, NULL); delete _stream; return false; } png_infop endInfo = png_create_info_struct(pngPtr); if (!endInfo) { png_destroy_read_struct(&pngPtr, &infoPtr, NULL); delete _stream; return false; } png_set_error_fn(pngPtr, NULL, pngError, pngWarning); // TODO: The manual says errors should be handled via setjmp png_set_read_fn(pngPtr, _stream, pngReadFromStream); png_set_crc_action(pngPtr, PNG_CRC_DEFAULT, PNG_CRC_WARN_USE); // We already verified the PNG-header png_set_sig_bytes(pngPtr, 8); // Read PNG header png_read_info(pngPtr, infoPtr); // No handling for unknown chunks yet. int bitDepth, colorType, width, height, interlaceType; png_uint_32 w, h; png_get_IHDR(pngPtr, infoPtr, &w, &h, &bitDepth, &colorType, &interlaceType, NULL, NULL); width = w; height = h; // Allocate memory for the final image data. // To keep memory framentation low this happens before allocating memory for temporary image data. _outputSurface = new Graphics::Surface(); // Images of all color formats except PNG_COLOR_TYPE_PALETTE // will be transformed into ARGB images if (colorType == PNG_COLOR_TYPE_PALETTE && !png_get_valid(pngPtr, infoPtr, PNG_INFO_tRNS)) { int numPalette = 0; png_colorp palette = NULL; uint32 success = png_get_PLTE(pngPtr, infoPtr, &palette, &numPalette); if (success != PNG_INFO_PLTE) { png_destroy_read_struct(&pngPtr, &infoPtr, NULL); return false; } _paletteColorCount = numPalette; _palette = new byte[_paletteColorCount * 3]; for (int i = 0; i < _paletteColorCount; i++) { _palette[(i * 3)] = palette[i].red; _palette[(i * 3) + 1] = palette[i].green; _palette[(i * 3) + 2] = palette[i].blue; } _outputSurface->create(width, height, Graphics::PixelFormat::createFormatCLUT8()); png_set_packing(pngPtr); } else { bool isAlpha = (colorType & PNG_COLOR_MASK_ALPHA); if (png_get_valid(pngPtr, infoPtr, PNG_INFO_tRNS)) { isAlpha = true; png_set_expand(pngPtr); } _outputSurface->create(width, height, Graphics::PixelFormat(4, 8, 8, 8, isAlpha ? 8 : 0, 24, 16, 8, 0)); if (!_outputSurface->getPixels()) { error("Could not allocate memory for output image."); } if (bitDepth == 16) png_set_strip_16(pngPtr); if (bitDepth < 8) png_set_expand(pngPtr); if (colorType == PNG_COLOR_TYPE_GRAY || colorType == PNG_COLOR_TYPE_GRAY_ALPHA) png_set_gray_to_rgb(pngPtr); // PNGs are Big-Endian: #ifdef SCUMM_LITTLE_ENDIAN png_set_bgr(pngPtr); png_set_swap_alpha(pngPtr); if (colorType != PNG_COLOR_TYPE_RGB_ALPHA) png_set_filler(pngPtr, 0xff, PNG_FILLER_BEFORE); #else if (colorType != PNG_COLOR_TYPE_RGB_ALPHA) png_set_filler(pngPtr, 0xff, PNG_FILLER_AFTER); #endif } // After the transformations have been registered, the image data is read again. png_set_interlace_handling(pngPtr); png_read_update_info(pngPtr, infoPtr); png_get_IHDR(pngPtr, infoPtr, &w, &h, &bitDepth, &colorType, NULL, NULL, NULL); width = w; height = h; if (interlaceType == PNG_INTERLACE_NONE) { // PNGs without interlacing can simply be read row by row. for (int i = 0; i < height; i++) { png_read_row(pngPtr, (png_bytep)_outputSurface->getBasePtr(0, i), NULL); } } else { // PNGs with interlacing require us to allocate an auxillary // buffer with pointers to all row starts. // Allocate row pointer buffer png_bytep *rowPtr = new png_bytep[height]; if (!rowPtr) { error("Could not allocate memory for row pointers."); } // Initialize row pointers for (int i = 0; i < height; i++) rowPtr[i] = (png_bytep)_outputSurface->getBasePtr(0, i); // Read image data png_read_image(pngPtr, rowPtr); // Free row pointer buffer delete[] rowPtr; } // Read additional data at the end. png_read_end(pngPtr, NULL); // Destroy libpng structures png_destroy_read_struct(&pngPtr, &infoPtr, &endInfo); // We no longer need the file stream, thus close it here _stream = 0; return true; #else return false; #endif }
void PNGAPI png_read_png(png_structp png_ptr, png_infop info_ptr, int transforms, voidp params) { int row; #if defined(PNG_READ_INVERT_ALPHA_SUPPORTED) /* invert the alpha channel from opacity to transparency */ if (transforms & PNG_TRANSFORM_INVERT_ALPHA) png_set_invert_alpha(png_ptr); #endif /* The call to png_read_info() gives us all of the information from the * PNG file before the first IDAT (image data chunk). */ png_read_info(png_ptr, info_ptr); if (info_ptr->height > PNG_UINT_32_MAX/sizeof(png_bytep)) png_error(png_ptr,"Image is too high to process with png_read_png()"); /* -------------- image transformations start here ------------------- */ #if defined(PNG_READ_16_TO_8_SUPPORTED) /* tell libpng to strip 16 bit/color files down to 8 bits/color */ if (transforms & PNG_TRANSFORM_STRIP_16) png_set_strip_16(png_ptr); #endif #if defined(PNG_READ_STRIP_ALPHA_SUPPORTED) /* Strip alpha bytes from the input data without combining with the * background (not recommended). */ if (transforms & PNG_TRANSFORM_STRIP_ALPHA) png_set_strip_alpha(png_ptr); #endif #if defined(PNG_READ_PACK_SUPPORTED) && !defined(PNG_READ_EXPAND_SUPPORTED) /* Extract multiple pixels with bit depths of 1, 2, and 4 from a single * byte into separate bytes (useful for paletted and grayscale images). */ if (transforms & PNG_TRANSFORM_PACKING) png_set_packing(png_ptr); #endif #if defined(PNG_READ_PACKSWAP_SUPPORTED) /* Change the order of packed pixels to least significant bit first * (not useful if you are using png_set_packing). */ if (transforms & PNG_TRANSFORM_PACKSWAP) png_set_packswap(png_ptr); #endif #if defined(PNG_READ_EXPAND_SUPPORTED) /* Expand paletted colors into true RGB triplets * Expand grayscale images to full 8 bits from 1, 2, or 4 bits/pixel * Expand paletted or RGB images with transparency to full alpha * channels so the data will be available as RGBA quartets. */ if (transforms & PNG_TRANSFORM_EXPAND) if ((png_ptr->bit_depth < 8) || (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) || (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))) png_set_expand(png_ptr); #endif /* We don't handle background color or gamma transformation or dithering. */ #if defined(PNG_READ_INVERT_SUPPORTED) /* invert monochrome files to have 0 as white and 1 as black */ if (transforms & PNG_TRANSFORM_INVERT_MONO) png_set_invert_mono(png_ptr); #endif #if defined(PNG_READ_SHIFT_SUPPORTED) /* If you want to shift the pixel values from the range [0,255] or * [0,65535] to the original [0,7] or [0,31], or whatever range the * colors were originally in: */ if ((transforms & PNG_TRANSFORM_SHIFT) && png_get_valid(png_ptr, info_ptr, PNG_INFO_sBIT)) { png_color_8p sig_bit; png_get_sBIT(png_ptr, info_ptr, &sig_bit); png_set_shift(png_ptr, sig_bit); } #endif #if defined(PNG_READ_BGR_SUPPORTED) /* flip the RGB pixels to BGR (or RGBA to BGRA) */ if (transforms & PNG_TRANSFORM_BGR) png_set_bgr(png_ptr); #endif #if defined(PNG_READ_SWAP_ALPHA_SUPPORTED) /* swap the RGBA or GA data to ARGB or AG (or BGRA to ABGR) */ if (transforms & PNG_TRANSFORM_SWAP_ALPHA) png_set_swap_alpha(png_ptr); #endif #if defined(PNG_READ_SWAP_SUPPORTED) /* swap bytes of 16 bit files to least significant byte first */ if (transforms & PNG_TRANSFORM_SWAP_ENDIAN) png_set_swap(png_ptr); #endif /* We don't handle adding filler bytes */ /* Optional call to gamma correct and add the background to the palette * and update info structure. REQUIRED if you are expecting libpng to * update the palette for you (i.e., you selected such a transform above). */ png_read_update_info(png_ptr, info_ptr); /* -------------- image transformations end here ------------------- */ #ifdef PNG_FREE_ME_SUPPORTED png_free_data(png_ptr, info_ptr, PNG_FREE_ROWS, 0); #endif if(info_ptr->row_pointers == NULL) { info_ptr->row_pointers = (png_bytepp)png_malloc(png_ptr, info_ptr->height * sizeof(png_bytep)); #ifdef PNG_FREE_ME_SUPPORTED info_ptr->free_me |= PNG_FREE_ROWS; #endif for (row = 0; row < (int)info_ptr->height; row++) { info_ptr->row_pointers[row] = (png_bytep)png_malloc(png_ptr, png_get_rowbytes(png_ptr, info_ptr)); } } png_read_image(png_ptr, info_ptr->row_pointers); info_ptr->valid |= PNG_INFO_IDAT; /* read rest of file, and get additional chunks in info_ptr - REQUIRED */ png_read_end(png_ptr, info_ptr); if(transforms == 0 || params == NULL) /* quiet compiler warnings */ return; }
void nsPNGDecoder::info_callback(png_structp png_ptr, png_infop info_ptr) { /* int number_passes; NOT USED */ png_uint_32 width, height; int bit_depth, color_type, interlace_type, compression_type, filter_type; unsigned int channels; png_bytep trans = NULL; int num_trans = 0; nsPNGDecoder *decoder = static_cast<nsPNGDecoder*>(png_get_progressive_ptr(png_ptr)); /* always decode to 24-bit RGB or 32-bit RGBA */ png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, &compression_type, &filter_type); /* Are we too big? */ if (width > MOZ_PNG_MAX_DIMENSION || height > MOZ_PNG_MAX_DIMENSION) longjmp(png_jmpbuf(decoder->mPNG), 1); // Post our size to the superclass decoder->PostSize(width, height); if (decoder->HasError()) { // Setting the size lead to an error; this can happen when for example // a multipart channel sends an image of a different size. longjmp(png_jmpbuf(decoder->mPNG), 1); } if (color_type == PNG_COLOR_TYPE_PALETTE) png_set_expand(png_ptr); if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) png_set_expand(png_ptr); if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { int sample_max = (1 << bit_depth); png_color_16p trans_values; png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, &trans_values); /* libpng doesn't reject a tRNS chunk with out-of-range samples so we check it here to avoid setting up a useless opacity channel or producing unexpected transparent pixels when using libpng-1.2.19 through 1.2.26 (bug #428045) */ if ((color_type == PNG_COLOR_TYPE_GRAY && (int)trans_values->gray > sample_max) || (color_type == PNG_COLOR_TYPE_RGB && ((int)trans_values->red > sample_max || (int)trans_values->green > sample_max || (int)trans_values->blue > sample_max))) { /* clear the tRNS valid flag and release tRNS memory */ png_free_data(png_ptr, info_ptr, PNG_FREE_TRNS, 0); } else png_set_expand(png_ptr); } if (bit_depth == 16) png_set_strip_16(png_ptr); qcms_data_type inType; PRUint32 intent = -1; PRUint32 pIntent; if (decoder->mCMSMode != eCMSMode_Off) { intent = gfxPlatform::GetRenderingIntent(); decoder->mInProfile = PNGGetColorProfile(png_ptr, info_ptr, color_type, &inType, &pIntent); /* If we're not mandating an intent, use the one from the image. */ if (intent == PRUint32(-1)) intent = pIntent; } if (decoder->mInProfile && gfxPlatform::GetCMSOutputProfile()) { qcms_data_type outType; if (color_type & PNG_COLOR_MASK_ALPHA || num_trans) outType = QCMS_DATA_RGBA_8; else outType = QCMS_DATA_RGB_8; decoder->mTransform = qcms_transform_create(decoder->mInProfile, inType, gfxPlatform::GetCMSOutputProfile(), outType, (qcms_intent)intent); } else { png_set_gray_to_rgb(png_ptr); // only do gamma correction if CMS isn't entirely disabled if (decoder->mCMSMode != eCMSMode_Off) PNGDoGammaCorrection(png_ptr, info_ptr); if (decoder->mCMSMode == eCMSMode_All) { if (color_type & PNG_COLOR_MASK_ALPHA || num_trans) decoder->mTransform = gfxPlatform::GetCMSRGBATransform(); else decoder->mTransform = gfxPlatform::GetCMSRGBTransform(); } } /* let libpng expand interlaced images */ if (interlace_type == PNG_INTERLACE_ADAM7) { /* number_passes = */ png_set_interlace_handling(png_ptr); } /* now all of those things we set above are used to update various struct * members and whatnot, after which we can get channels, rowbytes, etc. */ png_read_update_info(png_ptr, info_ptr); decoder->mChannels = channels = png_get_channels(png_ptr, info_ptr); /*---------------------------------------------------------------*/ /* copy PNG info into imagelib structs (formerly png_set_dims()) */ /*---------------------------------------------------------------*/ PRInt32 alpha_bits = 1; if (channels == 2 || channels == 4) { /* check if alpha is coming from a tRNS chunk and is binary */ if (num_trans) { /* if it's not an indexed color image, tRNS means binary */ if (color_type == PNG_COLOR_TYPE_PALETTE) { for (int i=0; i<num_trans; i++) { if ((trans[i] != 0) && (trans[i] != 255)) { alpha_bits = 8; break; } } } } else { alpha_bits = 8; } } if (channels == 1 || channels == 3) decoder->format = gfxASurface::ImageFormatRGB24; else if (channels == 2 || channels == 4) decoder->format = gfxASurface::ImageFormatARGB32; #ifdef PNG_APNG_SUPPORTED if (png_get_valid(png_ptr, info_ptr, PNG_INFO_acTL)) png_set_progressive_frame_fn(png_ptr, nsPNGDecoder::frame_info_callback, NULL); if (png_get_first_frame_is_hidden(png_ptr, info_ptr)) { decoder->mFrameIsHidden = PR_TRUE; } else { #endif decoder->CreateFrame(0, 0, width, height, decoder->format); #ifdef PNG_APNG_SUPPORTED } #endif if (decoder->mTransform && (channels <= 2 || interlace_type == PNG_INTERLACE_ADAM7)) { PRUint32 bpp[] = { 0, 3, 4, 3, 4 }; decoder->mCMSLine = (PRUint8 *)moz_malloc(bpp[channels] * width); if (!decoder->mCMSLine) { longjmp(png_jmpbuf(decoder->mPNG), 5); // NS_ERROR_OUT_OF_MEMORY } } if (interlace_type == PNG_INTERLACE_ADAM7) { if (height < PR_INT32_MAX / (width * channels)) decoder->interlacebuf = (PRUint8 *)moz_malloc(channels * width * height); if (!decoder->interlacebuf) { longjmp(png_jmpbuf(decoder->mPNG), 5); // NS_ERROR_OUT_OF_MEMORY } } /* Reject any ancillary chunk after IDAT with a bad CRC (bug #397593). * It would be better to show the default frame (if one has already been * successfully decoded) before bailing, but it's simpler to just bail * out with an error message. */ png_set_crc_action(png_ptr, PNG_CRC_NO_CHANGE, PNG_CRC_ERROR_QUIT); return; }
void __fastcall TPngDecoder::Init(){ pfFile=fopen(FFileName.c_str(),"rb"); if(!pfFile) throw Exception ( "Can't open file" ); // first check the eight byte PNG signature fread(pbSig, 1, 8, pfFile); if (!png_check_sig(pbSig, 8)) throw Exception ( "Bad file format" ); // create the two png(-info) structures png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!png_ptr) throw Exception( "Not enough memory" ); info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { png_destroy_read_struct(&png_ptr, NULL, NULL); throw Exception( "Not enough memory" ); } /*точка возврата после обработки ошибки или предупреждения*/ if (setjmp(png_jmpbuf(png_ptr))) { // awp_res=*((long*)png_ptr->error_ptr); if(row_pointers){ for (i = 0; i < FNumScanLines; i++){ if(row_pointers[i]) free(row_pointers[i]); } free(row_pointers); } png_destroy_read_struct(&png_ptr, &info_ptr,NULL); if(pfFile) fclose(pfFile); throw Exception( "" );; } // initialize the input png file png_init_io(png_ptr, pfFile); //8 байт сигнатуры уже прочитанно png_set_sig_bytes(png_ptr, 8); /* 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); unsigned long width, hight; png_get_IHDR(png_ptr, info_ptr, &width, &hight, &iBitDepth, &iColorType, NULL, NULL, NULL); FWidth = width; FNumScanLines = hight; /**** 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 */ //может это не нужно? if (iBitDepth == 16) png_set_strip_16(png_ptr); if (iBitDepth < 8) png_set_expand(png_ptr); /* Expand paletted colors into true RGB triplets */ if (iColorType == PNG_COLOR_TYPE_PALETTE) png_set_expand(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_expand(png_ptr); /* tell libpng convert grayscale images to true rgd */ if (iColorType == PNG_COLOR_TYPE_GRAY|| iColorType == PNG_COLOR_TYPE_GRAY_ALPHA) png_set_gray_to_rgb(png_ptr); /*remove alpha channel instead combine with background*/ if (iColorType & PNG_COLOR_MASK_ALPHA) png_set_strip_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. */ // set the background color to draw transparent and alpha images over. if (png_get_bKGD(png_ptr, info_ptr, &pBackground)) png_set_background(png_ptr, pBackground, PNG_BACKGROUND_GAMMA_FILE, 1, 1.0); /* flip the RGB pixels to BGR (or RGBA to BGRA) */ if (iColorType & PNG_COLOR_MASK_COLOR) png_set_bgr(png_ptr); png_read_update_info(png_ptr, info_ptr); png_get_IHDR(png_ptr, info_ptr, &width, &hight, &iBitDepth, &iColorType, NULL, NULL, NULL); FWidth = width; FNumScanLines = hight; FBufferSize = png_get_rowbytes(png_ptr, info_ptr); FScanBuffer = new char[FBufferSize]; if(width>0x7fff||hight>0x7fff) throw Exception( "Format not supported" ); }
void LoadPNG(const char *name, byte ** pic, int *width, int *height, byte alphaByte) { int bit_depth; int color_type; png_uint_32 w; png_uint_32 h; unsigned int row; // size_t rowbytes; png_infop info; png_structp png; png_bytep *row_pointers; byte *data; byte *out; int size; // load png size = ri.FS_ReadFile(name, (void **)&data); if(!data) return; //png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); png = png_create_read_struct(PNG_LIBPNG_VER_STRING, (png_voidp) NULL, png_user_error_fn, png_user_warning_fn); if(!png) { ri.Printf(PRINT_WARNING, "LoadPNG: png_create_write_struct() failed for (%s)\n", name); ri.FS_FreeFile(data); return; } // allocate/initialize the memory for image information. REQUIRED info = png_create_info_struct(png); if(!info) { ri.Printf(PRINT_WARNING, "LoadPNG: png_create_info_struct() failed for (%s)\n", name); ri.FS_FreeFile(data); png_destroy_read_struct(&png, (png_infopp) NULL, (png_infopp) NULL); return; } /* * Set error handling if you are using the setjmp/longjmp method (this is * the common 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))) { // if we get here, we had a problem reading the file ri.Printf(PRINT_WARNING, "LoadPNG: first exception handler called for (%s)\n", name); ri.FS_FreeFile(data); png_destroy_read_struct(&png, (png_infopp) & info, (png_infopp) NULL); return; } //png_set_write_fn(png, buffer, png_write_data, png_flush_data); png_set_read_fn(png, data, png_read_data); png_set_sig_bytes(png, 0); // 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, info); // get picture info png_get_IHDR(png, info, (png_uint_32 *) & w, (png_uint_32 *) & h, &bit_depth, &color_type, NULL, NULL, NULL); // tell libpng to strip 16 bit/color files down to 8 bits/color png_set_strip_16(png); // expand paletted images to RGB triplets if(color_type & PNG_COLOR_MASK_PALETTE) png_set_expand(png); // expand gray-scaled images to RGB triplets if(!(color_type & PNG_COLOR_MASK_COLOR)) png_set_gray_to_rgb(png); // 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_gray_1_2_4_to_8(png); // 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, info, PNG_INFO_tRNS)) png_set_tRNS_to_alpha(png); // if there is no alpha information, fill with alphaByte if(!(color_type & PNG_COLOR_MASK_ALPHA)) png_set_filler(png, alphaByte, PNG_FILLER_AFTER); // expand pictures with less than 8bpp to 8bpp if(bit_depth < 8) png_set_packing(png); // update structure with the above settings png_read_update_info(png, info); // allocate the memory to hold the image *width = w; *height = h; *pic = out = (byte *) ri.Z_Malloc(w * h * 4); row_pointers = (png_bytep *) ri.Hunk_AllocateTempMemory(sizeof(png_bytep) * h); // set a new exception handler if(setjmp(png_jmpbuf(png))) { ri.Printf(PRINT_WARNING, "LoadPNG: second exception handler called for (%s)\n", name); ri.Hunk_FreeTempMemory(row_pointers); ri.FS_FreeFile(data); png_destroy_read_struct(&png, (png_infopp) & info, (png_infopp) NULL); return; } //rowbytes = png_get_rowbytes(png, info); for(row = 0; row < h; row++) row_pointers[row] = (png_bytep) (out + (row * 4 * w)); // read image data png_read_image(png, row_pointers); // read rest of file, and get additional chunks in info png_read_end(png, info); // clean up after the read, and free any memory allocated png_destroy_read_struct(&png, &info, (png_infopp) NULL); ri.Hunk_FreeTempMemory(row_pointers); ri.FS_FreeFile(data); }
bool vtImage::_ReadPNG(const char *filename) { FILE *fp = NULL; uchar header[8]; png_structp png; png_infop info; png_infop endinfo; png_bytep *row_p; png_uint_32 width, height; int depth, color; png_uint_32 i; png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!png) { // We compiled against the headers of one version of libpng, but // linked against the libraries from another version. If you get // this, fix the paths in your development environment. return false; } info = png_create_info_struct(png); endinfo = png_create_info_struct(png); fp = vtFileOpen(filename, "rb"); if (fp && fread(header, 1, 8, fp) && png_check_sig(header, 8)) png_init_io(png, fp); else { png_destroy_read_struct(&png, &info, &endinfo); return false; } png_set_sig_bytes(png, 8); png_read_info(png, info); png_get_IHDR(png, info, &width, &height, &depth, &color, NULL, NULL, NULL); if (color == PNG_COLOR_TYPE_GRAY || color == PNG_COLOR_TYPE_GRAY_ALPHA) png_set_gray_to_rgb(png); // never strip alpha // { // png_set_strip_alpha(png); // color &= ~PNG_COLOR_MASK_ALPHA; // } // Always expand paletted images if (color == PNG_COLOR_TYPE_PALETTE) png_set_expand(png); /*--GAMMA--*/ // checkForGammaEnv(); double screenGamma = 2.2 / 1.0; #if 0 // Getting the gamma from the PNG file is disabled here, since // PhotoShop writes bizarre gamma values like .227 (PhotoShop 5.0) // or .45 (newer versions) double fileGamma; if (png_get_gAMA(png, info, &fileGamma)) png_set_gamma(png, screenGamma, fileGamma); else #endif png_set_gamma(png, screenGamma, 1.0/2.2); png_read_update_info(png, info); m_pPngData = (png_bytep) malloc(png_get_rowbytes(png, info)*height); row_p = (png_bytep *) malloc(sizeof(png_bytep)*height); bool StandardOrientation = true; for (i = 0; i < height; i++) { if (StandardOrientation) row_p[height - 1 - i] = &m_pPngData[png_get_rowbytes(png, info)*i]; else row_p[i] = &m_pPngData[png_get_rowbytes(png, info)*i]; } png_read_image(png, row_p); free(row_p); int iBitCount; switch (color) { case PNG_COLOR_TYPE_GRAY: case PNG_COLOR_TYPE_RGB: case PNG_COLOR_TYPE_PALETTE: iBitCount = 24; break; case PNG_COLOR_TYPE_GRAY_ALPHA: case PNG_COLOR_TYPE_RGB_ALPHA: iBitCount = 32; break; default: return false; } png_read_end(png, endinfo); png_destroy_read_struct(&png, &info, &endinfo); // Don't free the data, we're going to pass it to OSG // free(m_pPngData); if (fp) fclose(fp); int pixelFormat; uint internalFormat; if (iBitCount == 24) pixelFormat = GL_RGB; else if (iBitCount == 32) pixelFormat = GL_RGBA; if (m_internalformat == -1) internalFormat = pixelFormat; // use default else internalFormat = m_internalformat; // use specific setImage(width, height, 1, internalFormat, // int internalFormat, pixelFormat, // uint pixelFormat GL_UNSIGNED_BYTE, // uint dataType m_pPngData, osg::Image::USE_MALLOC_FREE); return true; }
static unsigned char* _load_image_RGBA_png(const char *fileName, int *width, int *height) { // open the file FILE *fp = fopen(fileName, "rb"); if (!fp) return _load_img_error(width, height); // read the header const size_t HEADER_LENGTH = 8; png_byte header[HEADER_LENGTH]; size_t n = fread(header, 1, HEADER_LENGTH, fp); if (n != HEADER_LENGTH || png_sig_cmp(header, 0, HEADER_LENGTH)) return _load_img_error(width, height); // try to create the loading structures png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0); if (!png_ptr) { fclose(fp); return _load_img_error(width, height); } png_infop info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { png_destroy_read_struct(&png_ptr, (png_infopp) 0, (png_infopp) 0); fclose(fp); return _load_img_error(width, height); } png_infop end_info = png_create_info_struct(png_ptr); if (!end_info) { png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)0); fclose(fp); return _load_img_error(width, height); } if (setjmp(png_ptr->jmpbuf)) { png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); fclose(fp); return _load_img_error(width, height); } // start the io png_init_io(png_ptr, fp); // indicate that we have already read some of the hearder png_set_sig_bytes(png_ptr, HEADER_LENGTH); // read the image info, get some 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); int bit_depth = png_get_bit_depth(png_ptr, info_ptr); png_byte color_type = png_get_color_type(png_ptr, info_ptr); // force the image into RGBA, 8 bits per channel if (color_type != PNG_COLOR_TYPE_RGBA) png_set_expand(png_ptr); if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) png_set_gray_to_rgb(png_ptr); if (bit_depth < 8) png_set_packing(png_ptr); else if (bit_depth == 16) png_set_strip_16(png_ptr); if (color_type != PNG_COLOR_TYPE_RGBA) png_set_filler(png_ptr, 255, PNG_FILLER_AFTER); png_read_update_info(png_ptr, info_ptr); // make sure we're actually in rgba mode if ((int)png_get_rowbytes(png_ptr, info_ptr) != ((*width) * 4)) { png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); fclose(fp); return _load_img_error(width, height); } // finally, read the file unsigned char *buffer = (unsigned char *) malloc((*width) * (*height) * 4); png_bytep *row_pointers = new png_bytep[*height]; for (int y = 0 ; y < (*height) ; y++) { row_pointers[y] = (png_byte *) (buffer + ((*height) - 1 - y) * (*width) * 4); } png_read_rows(png_ptr, row_pointers, 0, (long unsigned int) (*height)); // deallocate memory and return fclose(fp); png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); return buffer; }
bool GR_Win32Image::_convertFromPNG(const UT_ByteBuf* pBB, UT_sint32 iDisplayWidth, UT_sint32 iDisplayHeight) { png_structp png_ptr; png_infop info_ptr; png_uint_32 width, height; int bit_depth, color_type, interlace_type; png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, (void*) NULL, NULL, NULL); if (png_ptr == NULL) { return false; } /* Allocate/initialize the memory for image information. REQUIRED. */ info_ptr = png_create_info_struct(png_ptr); if (info_ptr == NULL) { png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL); return false; } /* 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); /* If we get here, we had a problem reading the file */ return false; } struct _bb myBB; myBB.pBB = pBB; myBB.iCurPos = 0; png_set_read_fn(png_ptr, (void *)&myBB, _png_read); /* 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); /* 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); /* Expand paletted colors into true RGB triplets */ png_set_expand(png_ptr); /* If we've got images with 16 bits per channel, we don't need that much precision. We'll do fine with 8 bits per channel */ png_set_strip_16(png_ptr); /* For simplicity, treat grayscale as RGB */ png_set_gray_to_rgb(png_ptr); /* For simplicity, we'll ignore alpha */ png_set_strip_alpha(png_ptr); /* We want libpng to deinterlace the image for us */ UT_uint32 iInterlacePasses = png_set_interlace_handling(png_ptr); /* flip the RGB pixels to BGR (or RGBA to BGRA) */ png_set_bgr(png_ptr); UT_uint32 iBytesInRow = width * 3; if (iBytesInRow % 4) { iBytesInRow += (4 - (iBytesInRow % 4)); } m_pDIB = (BITMAPINFO*) g_try_malloc(sizeof(BITMAPINFOHEADER) + height * iBytesInRow); if (!m_pDIB) { png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); return false; } /* Note that we do NOT create a DIB of iDisplayWidth,iDisplayHeight, since DIBs can be stretched automatically by the Win32 API. So we simply remember the display size for drawing later. */ setDisplaySize(iDisplayWidth, iDisplayHeight); m_pDIB->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); m_pDIB->bmiHeader.biWidth = width; m_pDIB->bmiHeader.biHeight = height; m_pDIB->bmiHeader.biPlanes = 1; m_pDIB->bmiHeader.biBitCount = 24; m_pDIB->bmiHeader.biCompression = BI_RGB; m_pDIB->bmiHeader.biSizeImage = 0; m_pDIB->bmiHeader.biXPelsPerMeter = 0; m_pDIB->bmiHeader.biYPelsPerMeter = 0; m_pDIB->bmiHeader.biClrUsed = 0; m_pDIB->bmiHeader.biClrImportant = 0; UT_Byte* pBits = ((unsigned char*) m_pDIB) + m_pDIB->bmiHeader.biSize; for (; iInterlacePasses; iInterlacePasses--) { for (UT_uint32 iRow = 0; iRow < height; iRow++) { UT_Byte* pRow = pBits + (height - iRow - 1) * iBytesInRow; png_read_rows(png_ptr, &pRow, NULL, 1); } } /* read rest of file, and get additional chunks in info_ptr - REQUIRED */ png_read_end(png_ptr, info_ptr); /* clean up after the read, and g_free any memory allocated - REQUIRED */ png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); return true; }
void readPng(GImage* pImage, const unsigned char* pData, size_t nDataSize) { // Check for the PNG signature if(nDataSize < 8 || png_sig_cmp((png_bytep)pData, 0, 8) != 0) throw Ex("not a png file"); // Read all PNG data up until the image data chunk. GPNGReader reader(pData); png_set_read_fn(reader.m_pReadStruct, (png_voidp)&reader, (png_rw_ptr)readFunc); png_read_info(reader.m_pReadStruct, reader.m_pInfoStruct); // Get the image data int depth, color; png_uint_32 width, height; png_get_IHDR(reader.m_pReadStruct, reader.m_pInfoStruct, &width, &height, &depth, &color, NULL, NULL, NULL); if(depth != 8) throw Ex("unexpected depth"); pImage->resize(width, height); // Set gamma correction double dGamma; if (png_get_gAMA(reader.m_pReadStruct, reader.m_pInfoStruct, &dGamma)) png_set_gamma(reader.m_pReadStruct, 2.2, dGamma); else png_set_gamma(reader.m_pReadStruct, 2.2, 1.0 / 2.2); // 1.0 = viewing gamma, 2.2 = screen gamma // Update the 'info' struct with the gamma information png_read_update_info(reader.m_pReadStruct, reader.m_pInfoStruct); // Tell it to expand palettes to full channels png_set_expand(reader.m_pReadStruct); png_set_gray_to_rgb(reader.m_pReadStruct); // Allocate the row pointers unsigned long rowbytes = png_get_rowbytes(reader.m_pReadStruct, reader.m_pInfoStruct); unsigned long channels = rowbytes / width; png_bytep pRawData = (png_bytep)new unsigned char[rowbytes * height]; unsigned int i; { png_bytep* pRows = (png_bytep*)new unsigned char[sizeof(png_bytep) * height]; for(i = 0; i < height; i++) pRows[i] = pRawData + i * rowbytes; png_read_image(reader.m_pReadStruct, pRows); delete[] pRows; } // Copy to the GImage unsigned long nPixels = width * height; unsigned int* pRGBQuads = pImage->m_pPixels; unsigned char *pBytes = pRawData; if(channels > 3) { if(channels != 4) throw Ex("Unexpected number of channels"); for(i = 0; i < nPixels; i++) { *pRGBQuads = gARGB(pBytes[3], pBytes[0], pBytes[1], pBytes[2]); pBytes += channels; pRGBQuads++; } } else if(channels == 3) { for(i = 0; i < nPixels; i++) { *pRGBQuads = gARGB(0xff, pBytes[0], pBytes[1], pBytes[2]); pBytes += channels; pRGBQuads++; } } else { delete[] pRawData; throw Ex("Sorry, loading ", to_str(channels), "-channel png files is not yet supported"); } delete[] pRawData; // Check for additional tags png_read_end(reader.m_pReadStruct, reader.m_pEndInfoStruct); }
SDL_Surface *TCOD_sys_read_png(const char *filename) { png_uint_32 png_width,png_height,y; int png_bit_depth,png_color_type,png_interlace_type; png_structp png_ptr; png_infop info_ptr; FILE *fp; SDL_Surface *bitmap; png_bytep *row_pointers; if ((fp = fopen(filename, "rb")) == NULL) return NULL; /* 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,NULL, NULL, NULL); if (png_ptr == NULL) { fclose(fp); return NULL; } /* 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 NULL; } /* 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 NULL; } png_init_io(png_ptr, fp); /* * 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_TRANSFORM_IDENTITY, png_voidp_NULL); // get info about the image png_read_info(png_ptr,info_ptr); png_get_IHDR(png_ptr,info_ptr,&png_width,&png_height,&png_bit_depth,&png_color_type, &png_interlace_type,NULL,NULL); // convert the image to a format suitable with libtcod png_set_strip_16(png_ptr); // 16 bits channels => 8 bits channels png_set_packing(png_ptr); // 1,2,4 bits depth => 24/32 bits depth if ( png_color_type == PNG_COLOR_TYPE_GRAY ) png_set_expand(png_ptr); // grayscale => color if ( png_color_type == PNG_COLOR_TYPE_GRAY_ALPHA ) png_set_gray_to_rgb(png_ptr); // update the image information png_read_update_info(png_ptr,info_ptr); png_get_IHDR(png_ptr,info_ptr,&png_width,&png_height,&png_bit_depth,&png_color_type, &png_interlace_type,NULL,NULL); // create the SDL surface bitmap=TCOD_sys_get_surface(png_width,png_height,info_ptr->channels == 4); // get row data row_pointers=(png_bytep *)malloc(sizeof(png_bytep)*png_height); for (y=0; y< png_height; y++ ) { row_pointers[y]=(png_bytep)(Uint8 *)(bitmap->pixels) + y * bitmap->pitch; } // read png data directly into the SDL surface png_read_image(png_ptr,row_pointers); /* clean up after the read, and free any memory allocated - REQUIRED */ png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL); free(row_pointers); /* close the file */ fclose(fp); return bitmap; }
void PNGImageDecoder::headerAvailable() { png_structp png = m_reader->pngPtr(); png_infop info = m_reader->infoPtr(); png_uint_32 width = png_get_image_width(png, info); png_uint_32 height = png_get_image_height(png, info); // Protect against large PNGs. See http://bugzil.la/251381 for more details. const unsigned long maxPNGSize = 1000000UL; if (width > maxPNGSize || height > maxPNGSize) { longjmp(JMPBUF(png), 1); return; } // Set the image size now that the image header is available. if (!setSize(width, height)) { longjmp(JMPBUF(png), 1); return; } int bitDepth, colorType, interlaceType, compressionType, filterType, channels; png_get_IHDR(png, info, &width, &height, &bitDepth, &colorType, &interlaceType, &compressionType, &filterType); // The options we set here match what Mozilla does. // Expand to ensure we use 24-bit for RGB and 32-bit for RGBA. if (colorType == PNG_COLOR_TYPE_PALETTE || (colorType == PNG_COLOR_TYPE_GRAY && bitDepth < 8)) png_set_expand(png); png_bytep trns = 0; int trnsCount = 0; if (png_get_valid(png, info, PNG_INFO_tRNS)) { png_get_tRNS(png, info, &trns, &trnsCount, 0); png_set_expand(png); } if (bitDepth == 16) png_set_strip_16(png); if (colorType == PNG_COLOR_TYPE_GRAY || colorType == PNG_COLOR_TYPE_GRAY_ALPHA) png_set_gray_to_rgb(png); #if USE(QCMSLIB) if ((colorType & PNG_COLOR_MASK_COLOR) && !m_ignoreGammaAndColorProfile) { // We only support color profiles for color PALETTE and RGB[A] PNG. Supporting // color profiles for gray-scale images is slightly tricky, at least using the // CoreGraphics ICC library, because we expand gray-scale images to RGB but we // do not similarly transform the color profile. We'd either need to transform // the color profile or we'd need to decode into a gray-scale image buffer and // hand that to CoreGraphics. bool sRGB = false; ColorProfile colorProfile; getColorProfile(png, info, colorProfile, sRGB); bool imageHasAlpha = (colorType & PNG_COLOR_MASK_ALPHA) || trnsCount; m_reader->createColorTransform(colorProfile, imageHasAlpha, sRGB); m_hasColorProfile = !!m_reader->colorTransform(); } #endif if (!m_hasColorProfile) { // Deal with gamma and keep it under our control. const double inverseGamma = 0.45455; const double defaultGamma = 2.2; double gamma; if (!m_ignoreGammaAndColorProfile && png_get_gAMA(png, info, &gamma)) { const double maxGamma = 21474.83; if ((gamma <= 0.0) || (gamma > maxGamma)) { gamma = inverseGamma; png_set_gAMA(png, info, gamma); } png_set_gamma(png, defaultGamma, gamma); } else { png_set_gamma(png, defaultGamma, inverseGamma); } } // Tell libpng to send us rows for interlaced pngs. if (interlaceType == PNG_INTERLACE_ADAM7) png_set_interlace_handling(png); // Update our info now. png_read_update_info(png, info); channels = png_get_channels(png, info); ASSERT(channels == 3 || channels == 4); m_reader->setHasAlpha(channels == 4); if (m_reader->decodingSizeOnly()) { // If we only needed the size, halt the reader. #if PNG_LIBPNG_VER_MAJOR > 1 || (PNG_LIBPNG_VER_MAJOR == 1 && PNG_LIBPNG_VER_MINOR >= 5) // '0' argument to png_process_data_pause means: Do not cache unprocessed data. m_reader->setReadOffset(m_reader->currentBufferSize() - png_process_data_pause(png, 0)); #else m_reader->setReadOffset(m_reader->currentBufferSize() - png->buffer_size); png->buffer_size = 0; #endif } }
bool ossimPngReader::initReader() { bool result = true; ossim_uint32 height = png_get_image_height(m_pngReadPtr, m_pngReadInfoPtr); ossim_uint32 width = png_get_image_width(m_pngReadPtr, m_pngReadInfoPtr); m_bitDepth = png_get_bit_depth(m_pngReadPtr, m_pngReadInfoPtr); m_pngColorType = png_get_color_type(m_pngReadPtr, m_pngReadInfoPtr); m_imageRect = ossimIrect(0, 0, width - 1, height - 1); if (m_bitDepth == 16) { // png_set_strip_16 (m_pngReadPtr); m_bytePerPixelPerBand = 2; m_outputScalarType = OSSIM_UINT16; } else { m_bytePerPixelPerBand = 1; } // Set the read mode from scalar and color type. if (m_outputScalarType == OSSIM_UINT8) { if ( (m_pngColorType == PNG_COLOR_TYPE_RGB_ALPHA) || (m_pngColorType == PNG_COLOR_TYPE_GRAY_ALPHA) ) { m_readMode = ossimPngRead8a; } else { m_readMode = ossimPngRead8; } } else { if ( (m_pngColorType == PNG_COLOR_TYPE_RGB_ALPHA) || (m_pngColorType == PNG_COLOR_TYPE_GRAY_ALPHA) ) { m_readMode = ossimPngRead16a; } else { m_readMode = ossimPngRead16; } // Set the swap flag. PNG stores data in network byte order(big endian). if(ossim::byteOrder() == OSSIM_LITTLE_ENDIAN) { m_swapFlag = true; } } //--- // If png_set_expand used: // Expand data to 24-bit RGB, or 8-bit grayscale, // with alpha if available. //--- bool expandFlag = false; if ( m_pngColorType == PNG_COLOR_TYPE_PALETTE ) { expandFlag = true; } if ( (m_pngColorType == PNG_COLOR_TYPE_GRAY) && (m_bitDepth < 8) ) { expandFlag = true; } if ( png_get_valid(m_pngReadPtr, m_pngReadInfoPtr, PNG_INFO_tRNS) ) { expandFlag = true; } //--- // If png_set_packing used: // Use 1 byte per pixel in 1, 2, or 4-bit depth files. */ //--- bool packingFlag = false; if ( (m_bitDepth < 8) && (m_pngColorType == PNG_COLOR_TYPE_GRAY) ) { packingFlag = true; } if (expandFlag) { png_set_expand(m_pngReadPtr); } if (packingFlag) { png_set_packing(m_pngReadPtr); } // Gamma correction. // ossim_float64 gamma; // if (png_get_gAMA(m_pngReadPtr, m_pngReadInfoPtr, &gamma)) // { // png_set_gamma(png_ptr, display_exponent, gamma); // } //--- // Turn on interlace handling... libpng returns just 1 (ie single pass) // if the image is not interlaced //--- m_interlacePasses = png_set_interlace_handling (m_pngReadPtr); //--- // Update the info structures after the transformations take effect //--- png_read_update_info (m_pngReadPtr, m_pngReadInfoPtr); // TODO: // Add check for image offsets. // Add check for resolution. // Add check for colormap. switch (m_pngColorType) { case PNG_COLOR_TYPE_RGB: /* RGB */ { m_numberOfInputBands = 3; m_numberOfOutputBands = 3; break; } case PNG_COLOR_TYPE_RGB_ALPHA: /* RGBA */ { m_numberOfInputBands = 4; if (m_useAlphaChannelFlag) { m_numberOfOutputBands = 4; } else { m_numberOfOutputBands = 3; } break; } case PNG_COLOR_TYPE_GRAY: /* Grayscale */ { m_numberOfInputBands = 1; m_numberOfOutputBands = 1; break; } case PNG_COLOR_TYPE_GRAY_ALPHA: /* Grayscale + alpha */ { m_numberOfInputBands = 2; if (m_useAlphaChannelFlag) { m_numberOfOutputBands = 2; } else { m_numberOfOutputBands = 1; } break; } case PNG_COLOR_TYPE_PALETTE: /* Indexed */ { m_numberOfInputBands = 3; m_numberOfOutputBands = 3; break; } default: /* Unknown type */ { result = false; } } if ( result ) { m_lineBufferSizeInBytes = png_get_rowbytes(m_pngReadPtr, m_pngReadInfoPtr); // Set the max pixel value. setMaxPixelValue(); // Set to OSSIM_USHORT11 for use of specialized tile. if (m_maxPixelValue[0] == 2047.0) { m_outputScalarType = OSSIM_USHORT11; } // We're on row 0 or first line. m_currentRow = 0; if (traceDebug()) { ossimNotify(ossimNotifyLevel_DEBUG) << "ossimPngReader::initReader DEBUG:" << "\nm_imageRect: " << m_imageRect << "\nm_bitDepth: " << int(m_bitDepth) << "\nm_pngColorType: " << getPngColorTypeString().c_str() << "\nm_numberOfInputBands: " << m_numberOfInputBands << "\nm_numberOfOutputBands: " << m_numberOfOutputBands << "\nm_bytePerPixelPerBand: " << m_bytePerPixelPerBand << "\nm_lineBufferSizeInBytes: " << m_lineBufferSizeInBytes << "\nm_interlacePasses: " << m_interlacePasses << "\npalette expansion: " << (expandFlag?"on":"off") << "\npacking (1,2,4 bit to one byte): " << (packingFlag?"on":"off") << "\nm_readMode: " << m_readMode << "\nm_swapFlag: " << m_swapFlag << std::endl; for (ossim_uint32 band = 0; band < m_numberOfInputBands; ++band) { ossimNotify(ossimNotifyLevel_DEBUG) << "max[" << band << "]: " << m_maxPixelValue[band] << std::endl; } } } return result; } // End: ossimPngReader::initReader()
void ossimPngReader::restart() { if ( m_str ) { // Destroy the existing memory associated with png structs. if (m_pngReadPtr && m_pngReadInfoPtr) { png_destroy_read_struct(&m_pngReadPtr, &m_pngReadInfoPtr, NULL); } m_pngReadPtr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); m_pngReadInfoPtr = png_create_info_struct(m_pngReadPtr); if ( setjmp( png_jmpbuf(m_pngReadPtr) ) ) { ossimNotify(ossimNotifyLevel_WARN) << "Error while reading. File corrupted? " << theImageFile << std::endl; return; } // Reset the file pointer. m_str->seekg( m_restartPosition, std::ios_base::beg ); //--- // Pass the static read method to libpng to allow us to use our // c++ stream instead of doing "png_init_io (pp, ...);" with // c stream. //--- png_set_read_fn( m_pngReadPtr, (png_voidp)m_str, (png_rw_ptr)&ossimPngReader::pngReadData ); //--- // Note we won't do png_set_sig_bytes(png_ptr, 8) here because we are not // rechecking for png signature. //--- png_read_info(m_pngReadPtr, m_pngReadInfoPtr); //--- // If png_set_expand used: // Expand data to 24-bit RGB, or 8-bit grayscale, // with alpha if available. //--- bool expandFlag = false; if ( m_pngColorType == PNG_COLOR_TYPE_PALETTE ) { expandFlag = true; } if ( (m_pngColorType == PNG_COLOR_TYPE_GRAY) && (m_bitDepth < 8) ) { expandFlag = true; } if ( png_get_valid(m_pngReadPtr, m_pngReadInfoPtr, PNG_INFO_tRNS) ) { expandFlag = true; } //--- // If png_set_packing used: // Use 1 byte per pixel in 1, 2, or 4-bit depth files. */ //--- bool packingFlag = false; if ( (m_bitDepth < 8) && (m_pngColorType == PNG_COLOR_TYPE_GRAY) ) { packingFlag = true; } if (expandFlag) { png_set_expand(m_pngReadPtr); } if (packingFlag) { png_set_packing(m_pngReadPtr); } // Gamma correction. // ossim_float64 gamma; // if (png_get_gAMA(m_pngReadPtr, m_pngReadInfoPtr, &gamma)) // { // png_set_gamma(m_pngReadPtr, display_exponent, gamma); // } //--- // Turn on interlace handling... libpng returns just 1 (ie single pass) // if the image is not interlaced //--- png_set_interlace_handling (m_pngReadPtr); //--- // Update the info structures after the transformations take effect //--- png_read_update_info (m_pngReadPtr, m_pngReadInfoPtr); // We're back on row 0 or first line. m_currentRow = 0; } }
void* replaceBootImage(AbstractFile* imageWrapper, const unsigned int* key, const unsigned int* iv, AbstractFile* png, size_t *fileSize) { AbstractFile* imageFile; unsigned char header[8]; InfoIBootIM* info; png_uint_32 i; png_bytepp row_pointers; uint8_t* imageBuffer; void* buffer; png->read(png, header, 8); if(png_sig_cmp(header, 0, 8) != 0) { XLOG(0, "error: not a valid png file\n"); return NULL; } png->seek(png, 0); png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, pngError, pngWarn); if (!png_ptr) { return NULL; } 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); return NULL; } png_infop end_info = png_create_info_struct(png_ptr); if (!end_info) { png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); return NULL; } if (setjmp(png_jmpbuf(png_ptr))) { XLOG(0, "error reading png\n"); png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); free(buffer); return NULL; } png_set_read_fn(png_ptr, png, pngRead); png_read_info(png_ptr, info_ptr); if(png_get_bit_depth(png_ptr, info_ptr) > 8) { XLOG(0, "warning: bit depth per channel is greater than 8 (%d). Attempting to strip, but image quality will be degraded.\n", png_get_bit_depth(png_ptr, info_ptr)); } if(png_get_color_type(png_ptr, info_ptr) == PNG_COLOR_TYPE_GRAY || png_get_color_type(png_ptr, info_ptr) == PNG_COLOR_TYPE_RGB) { XLOG(0, "notice: attempting to add dummy transparency channel\n"); } if(png_get_color_type(png_ptr, info_ptr) == PNG_COLOR_TYPE_PALETTE) { XLOG(0, "notice: attempting to expand palette into full rgb\n"); } png_set_expand(png_ptr); png_set_strip_16(png_ptr); png_set_bgr(png_ptr); png_set_add_alpha(png_ptr, 0x0, PNG_FILLER_AFTER); png_set_invert_alpha(png_ptr); png_read_update_info(png_ptr, info_ptr); if(png_get_image_width(png_ptr, info_ptr) > 320 || png_get_image_height(png_ptr, info_ptr) > 480) { XLOG(0, "error: dimensions out of range, must be within 320x480, not %lux%lu\n", png_get_image_width(png_ptr, info_ptr), png_get_image_height(png_ptr, info_ptr)); png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); return NULL; } if(png_get_bit_depth(png_ptr, info_ptr) != 8) { XLOG(0, "error: bit depth per channel must be 8 not %d!\n", png_get_bit_depth(png_ptr, info_ptr)); png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); return NULL; } if(png_get_color_type(png_ptr, info_ptr) != PNG_COLOR_TYPE_GRAY_ALPHA && png_get_color_type(png_ptr, info_ptr) != PNG_COLOR_TYPE_RGB_ALPHA) { XLOG(0, "error: incorrect color type, must be greyscale with alpha, or rgb with alpha\n"); if(png_get_color_type(png_ptr, info_ptr) == PNG_COLOR_TYPE_GRAY || png_get_color_type(png_ptr, info_ptr) == PNG_COLOR_TYPE_RGB) { XLOG(0, "It appears you're missing an alpha channel. Add transparency to your image\n"); } if(png_get_color_type(png_ptr, info_ptr) == PNG_COLOR_TYPE_PALETTE) { XLOG(0, "This PNG is saved with the palette color type rather than ARGB.\n"); } png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); return NULL; } row_pointers = (png_bytepp) malloc(sizeof(png_bytep) * png_get_image_height(png_ptr, info_ptr)); imageBuffer = malloc(png_get_image_height(png_ptr, info_ptr) * png_get_rowbytes(png_ptr, info_ptr)); for(i = 0; i < png_get_image_height(png_ptr, info_ptr); i++) { row_pointers[i] = imageBuffer + (png_get_rowbytes(png_ptr, info_ptr) * i); } png_read_image(png_ptr, row_pointers); png_read_end(png_ptr, end_info); buffer = malloc(1); *fileSize = 0; if(key != NULL) { imageFile = duplicateAbstractFile2(imageWrapper, createAbstractFileFromMemoryFile((void**)&buffer, fileSize), key, iv, NULL); } else { imageFile = duplicateAbstractFile(imageWrapper, createAbstractFileFromMemoryFile((void**)&buffer, fileSize)); } info = (InfoIBootIM*) (imageFile->data); info->header.width = (uint16_t) png_get_image_width(png_ptr, info_ptr); info->header.height = (uint16_t) png_get_image_height(png_ptr, info_ptr); if(png_get_color_type(png_ptr, info_ptr) == PNG_COLOR_TYPE_GRAY_ALPHA) { info->header.format = IBOOTIM_GREY; } else { info->header.format = IBOOTIM_ARGB; } imageFile->write(imageFile, imageBuffer, png_get_image_height(png_ptr, info_ptr) * png_get_rowbytes(png_ptr, info_ptr)); imageFile->close(imageFile); png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); png->close(png); free(row_pointers); free(imageBuffer); return buffer; }
// This is the interesting function here. It sets up a PNG image as a texture. void loadPngTex(char * fname , struct tImagePNG * pImagePNG , int *hasAlpha ) { // The header of the file will be saved in here char buf[PNG_BYTES_TO_CHECK]; // images infos int bit_depth; int cType; double gamma; FILE *fp; // Open the file and check correct opening /* Open the prospective PNG file. */ if ((fp = fopen(fname, "rb")) == NULL) { printf( "Error: Could not open the texture file [%s]!" , fname ); throw 336; } // Read the PNG header, which is 8 bytes long. /* Read in some of the signature bytes */ if (fread(buf, 1, PNG_BYTES_TO_CHECK, fp) != PNG_BYTES_TO_CHECK) { printf( "Error: Incorrect PNG texture file [%s]!" , fname ); throw 336; } // Check whether the file is a PNG file // png_sig_cmp() checks the given PNG header and returns 0 if it could // be the start of a PNG file. We can use 8 bytes at max for // this comparison. if(png_sig_cmp((png_byte*)buf, (png_size_t)0, PNG_BYTES_TO_CHECK) != 0) { fclose( fp ); printf( "Error: Not a PNG file [%s]!" , fname ); throw 337; } // Create / initialize the png_struct // The png_struct isn't directly accessed by the user (us). // We will later create a png_info from this to get access to the // PNG's infos. // The three 0's in the arg list could be pointers to user defined error // handling functions. 0 means we don't want to specify them, but use // libPNG's default error handling instead. png_infop info_ptr; png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL , NULL , NULL ); if(!png_ptr) { fclose( fp ); printf( "Error: Couldn't create PNG read structure [%s]!" , fname ); throw 338; } // Create / initialize the png_info // The png_info grants the user access to the PNG infos. info_ptr = png_create_info_struct(png_ptr); if(!info_ptr) { // We need to destroy the read_struct png_destroy_read_struct(&png_ptr, NULL, NULL); fclose( fp ); printf( "Error: Couldn't create PNG info structure [%s]!" , fname ); throw 339; } // Setup error handler // This sets the point libPNG jumps back to is an error occurs. 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 */ printf( "Error: Couldn't setup PNG error handler [%s]!" , fname ); throw 340; } /* Set up the input control if you are using standard C streams */ png_init_io(png_ptr, fp); // This tells libPNG that we have already read 8 bytes from the start // of the file (for the header check above). png_set_sig_bytes(png_ptr, PNG_BYTES_TO_CHECK); // This reads the PNG file into the read and info structs /* * 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_info(png_ptr, info_ptr); // Get some basic infos about the image from png_info structure // width & height in px, bit depth // interlace_method, compression_method, & filter_method are ignored png_get_IHDR(png_ptr, info_ptr, &(pImagePNG->sizeX), &(pImagePNG->sizeY), &bit_depth, &cType, 0, 0, 0); // COLOR TYPE read and possible corrections - then reread // Color type: we handle RGB and RGB_ALPHA (with Alpha) // GRAY (luminance) and GRAY_ALPHA (luminance with Alpha) cType = png_get_color_type(png_ptr, info_ptr); // strip the pixels of a PNG stream with 16 bits per channel to 8 bits per channel if (bit_depth == 16) { png_set_strip_16(png_ptr); } // set transformation in png_ptr such that paletted images are expanded to RGB, // grayscale images of bit-depth less than 8 are expanded to 8-bit images // tRNS chunks are expanded to alpha channels if (cType == PNG_COLOR_TYPE_PALETTE) { png_set_expand(png_ptr); } if (bit_depth < 8) { png_set_expand(png_ptr); } if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { png_set_expand(png_ptr); } // if required set gamma conversion if (png_get_gAMA(png_ptr, info_ptr, &gamma)) { png_set_gamma(png_ptr, (double) 2.2, gamma); } // After the image transformations have been registered update info_ptr data png_read_update_info(png_ptr, info_ptr); // Gets again width, height and the new bit-depth and color-type png_get_IHDR(png_ptr, info_ptr, &(pImagePNG->sizeX), &(pImagePNG->sizeY), &bit_depth, &cType, 0, 0, 0); // We now calculate the *bytes* per pixel from the color type and the // bits per pixel. if((cType == PNG_COLOR_TYPE_RGB) && (bit_depth == 8)) { pImagePNG->bytesPerPixel = 3; *hasAlpha = false; } else if((cType == PNG_COLOR_TYPE_RGB_ALPHA) && (bit_depth == 8)) { pImagePNG->bytesPerPixel = 4; *hasAlpha = true; } else if((cType == PNG_COLOR_TYPE_GRAY) && (bit_depth == 8)) { pImagePNG->bytesPerPixel = 1; *hasAlpha = false; } else if((cType == PNG_COLOR_TYPE_GRAY_ALPHA) && (bit_depth == 8)) { pImagePNG->bytesPerPixel = 2; *hasAlpha = true; } else { /* clean up after the read, and free any memory allocated - REQUIRED */ png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL); fclose( fp ); printf( "Error: PNG image [%s] type (%d) bit depth (%d) is unsupported!" , fname , cType , bit_depth ); throw 336; } // rowbytes is the width x number of channels. channels is not used currently unsigned int rowbytes = png_get_rowbytes(png_ptr, info_ptr); // unsigned int channels = png_get_channels(png_ptr, info_ptr); // Allocates memory to store the image pImagePNG->data = new GLubyte[pImagePNG->sizeY * rowbytes]; // printf( "PNG image %ldx%ld (%d bitsperpixel/%d bytesPerPixel) size row %d total %ld\n" , // pImagePNG->sizeX , // pImagePNG->sizeY , bit_depth , pImagePNG->bytesPerPixel, // rowbytes , pImagePNG->sizeY * rowbytes); //// Alternate solution without explicit row pointers //// and image read through png_get_rows // Returns a pointer to the array of array of png_bytes that holds the // image data. // png_byte **imageData = png_get_rows(png_ptr, info_ptr); //// must read row after row // for( unsigned int i = 0 ; i < pImagePNG->sizeY ; i++ ) { // printf( "Ind %d\n" , i ); // memcpy(&pImagePNG->data[(pImagePNG->sizeY - i - 1) * rowbytes], // row[i], rowbytes); // } //// Alternate solution with explicit row pointers //// and image read through png_read_image // Allocates memory for an array of row-pointers png_byte ** row = new GLubyte * [pImagePNG->sizeY]; // Sets the row-pointers to point at the correct offsets for (unsigned int i = 0; i < pImagePNG->sizeY; i++) { row[i] = pImagePNG->data + (pImagePNG->sizeY - i - 1) * rowbytes; } // Reads the whole image png_read_image(png_ptr, row); // deallocate the now unuseful row pointers delete [] row; // Free the memory we used - we don't need it anymore /* clean up after the read, and free any memory allocated - REQUIRED */ png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL); fclose( fp ); }
uint8 *readpng_get_image(void * strsv, uint32 *pChannels, uint32 *pRowbytes, uint32 *pWidth, uint32 *pHeight) { readpng_structs_t * strs = (readpng_structs_t *)strsv; png_uint_32 width, height; int bit_depth, color_type; uint8 *image_data = NULL; png_uint_32 i, rowbytes; png_bytepp row_pointers = NULL; /* alternatively, could make separate calls to png_get_image_width(), * etc., but want bit_depth and color_type for later [don't care about * compression_type and filter_type => NULLs] */ png_get_IHDR(strs->png_ptr, strs->info_ptr, &width, &height, &bit_depth, &color_type, NULL, NULL, NULL); *pWidth = width; *pHeight = height; /* expand palette images to RGB, low-bit-depth grayscale images to 8 bits, * transparency chunks to full alpha channel; strip 16-bit-per-sample * images to 8 bits per sample; and convert grayscale to RGB[A] */ if (color_type == PNG_COLOR_TYPE_PALETTE) png_set_expand(strs->png_ptr); if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) png_set_expand(strs->png_ptr); if (png_get_valid(strs->png_ptr, strs->info_ptr, PNG_INFO_tRNS)) png_set_expand(strs->png_ptr); if (bit_depth == 16) png_set_strip_16(strs->png_ptr); if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) png_set_gray_to_rgb(strs->png_ptr); /* all transformations have been registered; now update info_ptr data, * get rowbytes and channels, and allocate image memory */ png_read_update_info(strs->png_ptr, strs->info_ptr); *pRowbytes = rowbytes = png_get_rowbytes(strs->png_ptr, strs->info_ptr); *pChannels = (int)png_get_channels(strs->png_ptr, strs->info_ptr); if ((image_data = (uint8 *)malloc(rowbytes*height)) == NULL) { png_destroy_read_struct(&strs->png_ptr, &strs->info_ptr, NULL); return NULL; } if ((row_pointers = (png_bytepp)malloc(height*sizeof(png_bytep))) == NULL) { png_destroy_read_struct(&strs->png_ptr, &strs->info_ptr, NULL); free(image_data); image_data = NULL; return NULL; } Trace((stderr, "readpng_get_image: channels = %d, rowbytes = %ld, height = %ld\n", *pChannels, rowbytes, height)); /* set the individual row_pointers to point at the correct offsets */ for (i = 0; i < height; ++i) row_pointers[i] = image_data + i*rowbytes; /* now we can go ahead and just read the whole image */ png_read_image(strs->png_ptr, row_pointers); free(row_pointers); row_pointers = NULL; png_read_end(strs->png_ptr, NULL); return image_data; }
int read_png_(char *file_name, int *w, int *h, int *rw, int *rh, unsigned char *pixout[], bool forgl, int *numchannel) { 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, compression_type, filter_type; FILE *fp; if ((fp = fopen(file_name, "rb")) == NULL) return (ERROR); /* 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, NULL, NULL, NULL); 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 */ /* Set up the input control if you are using standard C streams */ png_init_io(png_ptr, fp); /* If we have already read some of the signature */ 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, &compression_type, &filter_type); // The following code transforms grayscale images of less than 8 to 8 bits, // changes paletted images to RGB, and adds a full alpha channel if there // is transparency information in a tRNS chunk. if (color_type == PNG_COLOR_TYPE_PALETTE && bit_depth <= 8) png_set_expand(png_ptr); if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) png_set_expand(png_ptr); if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) png_set_expand(png_ptr); if (bit_depth == 16) //ensure 8-bit png_set_strip_16(png_ptr); if (bit_depth < 8) //ensure 8-bit png_set_packing(png_ptr); if (forgl) { //width and height must be powers of 2. *rh = height; //set the real return vals first *rw = width; //these are probably the only likely ranges if (width > 512) width = 1024; else if (width > 256) width = 512; else width = 256; if (height > 512) height = 1024; else if (height > 256) height = 512; else height = 256; } //printf("colortype %d %d\n",color_type,PNG_COLOR_TYPE_RGBA); *numchannel=3; if(color_type==PNG_COLOR_TYPE_RGBA||color_type==PNG_COLOR_TYPE_RGB_ALPHA) *numchannel=4; unsigned char *pixels = new unsigned char[width*height*sizeof(unsigned char)*(*numchannel)]; //for rgba png_byte **row_pointers = new png_byte*[height]; for (unsigned int k = 0; k < height; k++) row_pointers[k] = pixels + (k)* width*sizeof(unsigned char)*(*numchannel); //for r,g,b,a png_read_image(png_ptr, row_pointers); png_read_end(png_ptr, NULL); /* At this point you have read the entire image */ //set return values *h = height; *w = width; *pixout = pixels; /* clean up after the read, and free any memory allocated - REQUIRED */ png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL); /* close the file */ fclose(fp); /* that's it */ return (OK); }
/* read png image */ uch *read_png (EIF_POINTER p_file_name, EIF_POINTER pChannels, EIF_POINTER pRowbytes, EIF_POINTER pWidth, EIF_POINTER pHeight,EIF_POINTER pBitDepth,EIF_POINTER pColorType,EIF_POINTER pInterlaceType) { //parameters char *file_name; //locals //int cha png_structp png_ptr; png_infop info_ptr; png_uint_32 width; png_uint_32 height; png_uint_32 i, rowbytes; int bit_depth; int color_type; int interlace_type; FILE *fp; /* Current opened file */ png_color_16 my_background, *image_background; double gamma; png_bytepp row_pointers = NULL; // open file file_name=(char*)p_file_name; fp = fopen (file_name, "rb"); if (fp == NULL) { return NULL; } png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (png_ptr == NULL){ fclose (fp); return NULL; } /* Allocate/initialize the memory for image information. REQUIRED. */ info_ptr = png_create_info_struct(png_ptr); if (info_ptr == NULL) { png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL); fclose (fp); return NULL; } /* 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_ptr->jmpbuf)) { /* Free all of the memory associated with the png_ptr and info_ptr */ png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); /* If we get here, we had a problem reading the file */ fclose (fp); return NULL; } /* One of the following I/O initialization methods is REQUIRED */ /* Set up the input control if you are using standard C streams */ png_init_io(png_ptr, fp); /* 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. */ /* 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); /* Expand paletted colors into true RGB triplets */ if (color_type == PNG_COLOR_TYPE_PALETTE) png_set_expand(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(png_ptr); if (bit_depth == 16) png_set_strip_16(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_expand(png_ptr); /* invert monocrome files to have 0 as white and 1 as black */ //png_set_invert_mono(png_ptr); /* Add filler (or alpha) byte (before/after each RGB triplet) */ if (color_type == PNG_COLOR_TYPE_RGB_ALPHA || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) { png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER); } // after the transformations have been registered update info_ptr data png_read_update_info(png_ptr, info_ptr); // get again width, height and the new bit-depth and color-type png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, NULL, NULL); rowbytes = png_get_rowbytes(png_ptr, info_ptr); *((EIF_INTEGER*)pRowbytes) = (EIF_INTEGER) rowbytes; *((EIF_INTEGER*)pChannels) = (EIF_INTEGER) png_get_channels(png_ptr, info_ptr); *((EIF_INTEGER*)pWidth) = (EIF_INTEGER) width; *((EIF_INTEGER*)pHeight) = (EIF_INTEGER) height; *((EIF_INTEGER*)pBitDepth) = (EIF_INTEGER) bit_depth; *((EIF_INTEGER*)pColorType) = (EIF_INTEGER) color_type; *((EIF_INTEGER*)pInterlaceType) = (EIF_INTEGER) interlace_type; if ((image_data = (uch *)malloc(rowbytes*height)) == NULL) { png_destroy_read_struct(&png_ptr, &info_ptr, NULL); fclose (fp); return NULL; } if ((row_pointers = (png_bytepp)malloc(height*sizeof(png_bytep))) == NULL) { png_destroy_read_struct(&png_ptr, &info_ptr, NULL); free(image_data); image_data = NULL; fclose (fp); return NULL; } // Trace((stderr, "readpng_get_image: channels = %d, rowbytes = %ld, height = %ld\n", *pChannels, rowbytes, height)); /* set the individual row_pointers to point at the correct offsets */ for (i = 0; i < height; ++i) row_pointers[i] = image_data + i*rowbytes; /* now we can go ahead and just read the whole image */ png_read_image(png_ptr, row_pointers); /* and we're done! (png_read_end() can be omitted if no processing of * post-IDAT text/time/etc. is desired) */ free(row_pointers); row_pointers = NULL; png_read_end(png_ptr, NULL); /* clean up after the read, and free any memory allocated - REQUIRED */ png_destroy_read_struct(&png_ptr, &info_ptr, NULL); fclose (fp); return (EIF_POINTER) image_data; }
void PNGImageDecoder::headerAvailable() { png_structp png = m_reader->pngPtr(); png_infop info = m_reader->infoPtr(); png_uint_32 width = png_get_image_width(png, info); png_uint_32 height = png_get_image_height(png, info); // Protect against large images. if (width > cMaxPNGSize || height > cMaxPNGSize) { longjmp(JMPBUF(png), 1); return; } // We can fill in the size now that the header is available. Avoid memory // corruption issues by neutering setFailed() during this call; if we don't // do this, failures will cause |m_reader| to be deleted, and our jmpbuf // will cease to exist. Note that we'll still properly set the failure flag // in this case as soon as we longjmp(). m_doNothingOnFailure = true; bool result = setSize(width, height); #if ENABLE(IMAGE_DECODER_DOWN_SAMPLING) prepareScaleDataIfNecessary(FloatSize(requestedFrameSize().width(), requestedFrameSize().height())); #endif m_doNothingOnFailure = false; if (!result) { longjmp(JMPBUF(png), 1); return; } int bitDepth, colorType, interlaceType, compressionType, filterType, channels; png_get_IHDR(png, info, &width, &height, &bitDepth, &colorType, &interlaceType, &compressionType, &filterType); // The options we set here match what Mozilla does. // Expand to ensure we use 24-bit for RGB and 32-bit for RGBA. if (colorType == PNG_COLOR_TYPE_PALETTE || (colorType == PNG_COLOR_TYPE_GRAY && bitDepth < 8)) png_set_expand(png); png_bytep trns = 0; int trnsCount = 0; if (png_get_valid(png, info, PNG_INFO_tRNS)) { png_get_tRNS(png, info, &trns, &trnsCount, 0); png_set_expand(png); } if (bitDepth == 16) png_set_strip_16(png); if (colorType == PNG_COLOR_TYPE_GRAY || colorType == PNG_COLOR_TYPE_GRAY_ALPHA) png_set_gray_to_rgb(png); if ((colorType & PNG_COLOR_MASK_COLOR) && !m_ignoreGammaAndColorProfile) { // We only support color profiles for color PALETTE and RGB[A] PNG. Supporting // color profiles for gray-scale images is slightly tricky, at least using the // CoreGraphics ICC library, because we expand gray-scale images to RGB but we // do not similarly transform the color profile. We'd either need to transform // the color profile or we'd need to decode into a gray-scale image buffer and // hand that to CoreGraphics. readColorProfile(png, info, m_colorProfile); #if USE(QCMSLIB) bool decodedImageHasAlpha = (colorType & PNG_COLOR_MASK_ALPHA) || trnsCount; m_reader->createColorTransform(m_colorProfile, decodedImageHasAlpha); m_colorProfile.clear(); #endif } // Deal with gamma and keep it under our control. double gamma; if (!m_ignoreGammaAndColorProfile && png_get_gAMA(png, info, &gamma)) { if ((gamma <= 0.0) || (gamma > cMaxGamma)) { gamma = cInverseGamma; png_set_gAMA(png, info, gamma); } png_set_gamma(png, cDefaultGamma, gamma); } else png_set_gamma(png, cDefaultGamma, cInverseGamma); // Tell libpng to send us rows for interlaced pngs. if (interlaceType == PNG_INTERLACE_ADAM7) png_set_interlace_handling(png); // Update our info now. png_read_update_info(png, info); channels = png_get_channels(png, info); ASSERT(channels == 3 || channels == 4); m_reader->setHasAlpha(channels == 4); if (m_reader->decodingSizeOnly()) { // If we only needed the size, halt the reader. #if defined(PNG_LIBPNG_VER_MAJOR) && defined(PNG_LIBPNG_VER_MINOR) && (PNG_LIBPNG_VER_MAJOR > 1 || (PNG_LIBPNG_VER_MAJOR == 1 && PNG_LIBPNG_VER_MINOR >= 5)) // '0' argument to png_process_data_pause means: Do not cache unprocessed data. m_reader->setReadOffset(m_reader->currentBufferSize() - png_process_data_pause(png, 0)); #else m_reader->setReadOffset(m_reader->currentBufferSize() - png->buffer_size); png->buffer_size = 0; #endif } }
void png_reader::read(unsigned x0, unsigned y0,image_data_32& image) { FILE *fp=fopen(fileName_.c_str(),"rb"); if (!fp) throw image_reader_exception("cannot open image file "+fileName_); png_structp png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING,0,0,0); if (!png_ptr) { fclose(fp); throw image_reader_exception("failed to allocate png_ptr"); } png_infop info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { png_destroy_read_struct(&png_ptr,0,0); fclose(fp); throw image_reader_exception("failed to create info_ptr"); } png_set_read_fn(png_ptr, (png_voidp)fp, png_read_data); png_read_info(png_ptr, info_ptr); if (color_type_ == PNG_COLOR_TYPE_PALETTE) png_set_expand(png_ptr); if (color_type_ == PNG_COLOR_TYPE_GRAY && bit_depth_ < 8) png_set_expand(png_ptr); if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) png_set_expand(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); // quick hack -- only work in >=libpng 1.2.7 png_set_add_alpha(png_ptr,0xff,PNG_FILLER_AFTER); //rgba double gamma; if (png_get_gAMA(png_ptr, info_ptr, &gamma)) png_set_gamma(png_ptr, 2.2, gamma); png_read_update_info(png_ptr, info_ptr); //START read image rows unsigned w=std::min(unsigned(image.width()),width_); unsigned h=std::min(unsigned(image.height()),height_); unsigned rowbytes=png_get_rowbytes(png_ptr, info_ptr); boost::scoped_array<png_byte> row(new png_byte[rowbytes]); for (unsigned i=0;i<height_;++i) { png_read_row(png_ptr,row.get(),0); if (i>=y0 && i<h) { image.setRow(i-y0,reinterpret_cast<unsigned*>(&row[x0]),w); } } //END png_read_end(png_ptr,0); png_destroy_read_struct(&png_ptr, &info_ptr,0); fclose(fp); }
//-------------------------------------- static bool sReadPNG(Stream &stream, GBitmap *bitmap) { static const U32 cs_headerBytesChecked = 8; U8 header[cs_headerBytesChecked]; stream.read(cs_headerBytesChecked, header); bool isPng = png_check_sig(header, cs_headerBytesChecked) != 0; if (isPng == false) { AssertWarn(false, "GBitmap::readPNG: stream doesn't contain a PNG"); return false; } U32 prevWaterMark = FrameAllocator::getWaterMark(); png_structp png_ptr = png_create_read_struct_2(PNG_LIBPNG_VER_STRING, NULL, pngFatalErrorFn, pngWarningFn, NULL, pngRealMallocFn, pngRealFreeFn); if (png_ptr == NULL) { FrameAllocator::setWaterMark(prevWaterMark); return false; } png_infop info_ptr = png_create_info_struct(png_ptr); if (info_ptr == NULL) { png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL); FrameAllocator::setWaterMark(prevWaterMark); return false; } png_infop end_info = png_create_info_struct(png_ptr); if (end_info == NULL) { png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); FrameAllocator::setWaterMark(prevWaterMark); return false; } png_set_read_fn(png_ptr, &stream, pngReadDataFn); // Read off the info on the image. png_set_sig_bytes(png_ptr, cs_headerBytesChecked); png_read_info(png_ptr, info_ptr); // OK, at this point, if we have reached it ok, then we can reset the // image to accept the new data... // bitmap->deleteImage(); png_uint_32 width; png_uint_32 height; S32 bit_depth; S32 color_type; png_get_IHDR(png_ptr, info_ptr, &width, &height, // obv. &bit_depth, &color_type, // obv. NULL, // interlace NULL, // compression_type NULL); // filter_type // First, handle the color transformations. We need this to read in the // data as RGB or RGBA, _always_, with a maximal channel width of 8 bits. // bool transAlpha = false; GFXFormat format = GFXFormatR8G8B8; // Strip off any 16 bit info // if (bit_depth == 16 && color_type != PNG_COLOR_TYPE_GRAY) { png_set_strip_16(png_ptr); } // Expand a transparency channel into a full alpha channel... // if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { png_set_expand(png_ptr); transAlpha = true; } if (color_type == PNG_COLOR_TYPE_PALETTE) { png_set_expand(png_ptr); format = transAlpha ? GFXFormatR8G8B8A8 : GFXFormatR8G8B8; } else if (color_type == PNG_COLOR_TYPE_GRAY) { png_set_expand(png_ptr); if (bit_depth == 16) format = GFXFormatR5G6B5; else format = GFXFormatA8; } else if (color_type == PNG_COLOR_TYPE_GRAY_ALPHA) { png_set_expand(png_ptr); png_set_gray_to_rgb(png_ptr); format = GFXFormatR8G8B8A8; } else if (color_type == PNG_COLOR_TYPE_RGB) { format = transAlpha ? GFXFormatR8G8B8A8 : GFXFormatR8G8B8; png_set_expand(png_ptr); } else if (color_type == PNG_COLOR_TYPE_RGB_ALPHA) { png_set_expand(png_ptr); format = GFXFormatR8G8B8A8; } // Update the info pointer with the result of the transformations // above... png_read_update_info(png_ptr, info_ptr); const png_size_t rowBytes = png_get_rowbytes(png_ptr, info_ptr); if (format == GFXFormatR8G8B8) { AssertFatal(rowBytes == width * 3, "Error, our rowbytes are incorrect for this transform... (3)"); } else if (format == GFXFormatR8G8B8A8) { AssertFatal(rowBytes == width * 4, "Error, our rowbytes are incorrect for this transform... (4)"); } else if (format == GFXFormatR5G6B5) { AssertFatal(rowBytes == width * 2, "Error, our rowbytes are incorrect for this transform... (2)"); } // actually allocate the bitmap space... bitmap->allocateBitmap(width, height, false, // don't extrude miplevels... format); // use determined format... // Set up the row pointers... png_bytep* rowPointers = new png_bytep[ height ]; U8* pBase = (U8*)bitmap->getBits(); for (U32 i = 0; i < height; i++) rowPointers[i] = pBase + (i * rowBytes); // And actually read the image! png_read_image(png_ptr, rowPointers); // We're outta here, destroy the png structs, and release the lock // as quickly as possible... //png_read_end(png_ptr, end_info); delete [] rowPointers; png_read_end(png_ptr, NULL); png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); // Ok, the image is read in, now we need to finish up the initialization, // which means: setting up the detailing members, init'ing the palette // key, etc... // // actually, all of that was handled by allocateBitmap, so we're outta here // // Check this bitmap for transparency bitmap->checkForTransparency(); FrameAllocator::setWaterMark(prevWaterMark); return true; }
static void LoadPNGBuffer(byte * buffer, int size, byte ** pixels, int *width, int *height) { png_struct *png; png_info *info, *end; pngBuffer_t pb; int i, bitDepth, colorType, channels; png_uint_32 w, h; byte **rowPointers; /* dummy check */ if(buffer == NULL || size <= 0 || pixels == NULL || width == NULL || height == NULL) return; /* null out */ *pixels = 0; *width = 0; *height = 0; /* determine if this is a png file */ if(png_sig_cmp(buffer, 0, 8) != 0) { Sys_Printf("WARNING: Invalid PNG file\n"); return; } /* create png structs */ png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if(png == NULL) { Sys_Printf("WARNING: Unable to create PNG read struct\n"); return; } info = png_create_info_struct(png); if(info == NULL) { Sys_Printf("WARNING: Unable to create PNG info struct\n"); png_destroy_read_struct(&png, NULL, NULL); return; } end = png_create_info_struct(png); if(end == NULL) { Sys_Printf("WARNING: Unable to create PNG end info struct\n"); png_destroy_read_struct(&png, &info, NULL); return; } /* set read callback */ pb.buffer = buffer; pb.size = size; pb.offset = 0; png_set_read_fn(png, &pb, PNGReadData); png->io_ptr = &pb; /* hack! */ /* set error longjmp */ if(setjmp(png->jmpbuf)) { Sys_Printf("WARNING: An error occurred reading PNG image\n"); png_destroy_read_struct(&png, &info, &end); return; } /* fixme: add proper i/o stuff here */ /* read png info */ png_read_info(png, info); /* read image header chunk */ png_get_IHDR(png, info, &w, &h, &bitDepth, &colorType, NULL, NULL, NULL); /* read number of channels */ channels = png_get_channels(png, info); /* the following will probably bork on certain types of png images, but hey... */ /* force indexed/gray/trans chunk to rgb */ if((colorType == PNG_COLOR_TYPE_PALETTE && bitDepth <= 8) || (colorType == PNG_COLOR_TYPE_GRAY && bitDepth <= 8) || png_get_valid(png, info, PNG_INFO_tRNS)) png_set_expand(png); /* strip 16bpc -> 8bpc */ if(bitDepth == 16) png_set_strip_16(png); /* pad rgb to rgba */ if(bitDepth == 8 && colorType == PNG_COLOR_TYPE_RGB) png_set_filler(png, 255, PNG_FILLER_AFTER); /* create image pixel buffer */ *width = w; *height = h; *pixels = safe_malloc(w * h * 4); /* create row pointers */ rowPointers = safe_malloc(h * sizeof(byte *)); for(i = 0; i < h; i++) rowPointers[i] = *pixels + (i * w * 4); /* read the png */ png_read_image(png, rowPointers); /* clean up */ free(rowPointers); png_destroy_read_struct(&png, &info, &end); }
//----------------------------------------------------------------------------- bool abiword_document::garble_png( void*& data, size_t& size ) { png_bytep * dib; png_uint_32 width; png_uint_32 height; int compression_type; int filter_type; int interlace_type; int bit_depth; int color_type; png_uint_32 rowbytes; // read PNG data { png_structp png_ptr = png_create_read_struct( PNG_LIBPNG_VER_STRING, (void*) NULL, NULL, NULL ); if (!png_ptr) return false; 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 ); return false; } png_read_data _png_read_data = { data, size, 0 }; png_set_read_fn( png_ptr, (void*)&_png_read_data, &_png_read ); png_read_info( png_ptr, info_ptr ); png_get_IHDR( png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, &compression_type, &filter_type ); png_set_packing( png_ptr ); png_set_expand( png_ptr ); png_set_strip_16( png_ptr ); png_set_gray_to_rgb( png_ptr ); png_set_strip_alpha( png_ptr ); png_set_interlace_handling( png_ptr ); png_set_bgr( png_ptr ); rowbytes = png_get_rowbytes(png_ptr, info_ptr); png_destroy_read_struct( &png_ptr, &info_ptr, NULL ); } // we don't care about the image data itself, we just want a random garbled // image of the same size dib = (png_bytep*) malloc( sizeof(png_bytep) * height ); for (size_t i=0; i<height; ++i) { dib[i] = (png_byte*) malloc( rowbytes ); garble_image_line( reinterpret_cast<char*>( dib[i] ), rowbytes ); } bool result = false; { // write it back png_structp png_ptrw = png_create_write_struct( PNG_LIBPNG_VER_STRING, NULL, NULL, NULL ); if (png_ptrw) { png_infop info_ptrw = png_create_info_struct( png_ptrw ); png_set_IHDR( png_ptrw, info_ptrw, width, height, bit_depth, color_type, interlace_type, compression_type, filter_type ); string newdata; png_set_write_fn( png_ptrw, (void*)&newdata, &_png_write, NULL ); png_write_info( png_ptrw, info_ptrw ); png_write_image( png_ptrw, dib ); png_write_end( png_ptrw, NULL ); png_destroy_write_struct( &png_ptrw, NULL ); free(data); size = newdata.size(); data = malloc( size ); memcpy( data, &newdata[0], size ); result = true; } } // cleanup for (size_t i=0; i<height; i++) free( dib[i] ); free( dib ); return result; }
/* really_load_png: * Worker routine, used by load_png and load_memory_png. */ static BITMAP *really_load_png(png_structp png_ptr, png_infop info_ptr, RGB *pal) { BITMAP *bmp; PALETTE tmppal; png_uint_32 width, height, rowbytes; int bit_depth, color_type, interlace_type; double image_gamma, screen_gamma; int intent; int bpp, dest_bpp; int tRNS_to_alpha = FALSE; int number_passes, pass; ASSERT(png_ptr && info_ptr); /* The call to png_read_info() gives us all of the information from the * PNG file before the first IDAT (image data chunk). */ png_read_info(png_ptr, info_ptr); png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, NULL, NULL); /* 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); /* 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(png_ptr); /* 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); tRNS_to_alpha = TRUE; } /* Convert 16-bits per colour component to 8-bits per colour component. */ if (bit_depth == 16) png_set_strip_16(png_ptr); /* Convert grayscale to RGB triplets */ if ((color_type == PNG_COLOR_TYPE_GRAY) || (color_type == PNG_COLOR_TYPE_GRAY_ALPHA)) png_set_gray_to_rgb(png_ptr); /* Optionally, tell libpng to handle the gamma correction for us. */ if (_png_screen_gamma != 0.0) { screen_gamma = get_gamma(); if (png_get_sRGB(png_ptr, info_ptr, &intent)) png_set_gamma(png_ptr, screen_gamma, 0.45455); else { if (png_get_gAMA(png_ptr, info_ptr, &image_gamma)) png_set_gamma(png_ptr, screen_gamma, image_gamma); else png_set_gamma(png_ptr, screen_gamma, 0.45455); } } /* Turn on interlace handling. */ number_passes = png_set_interlace_handling(png_ptr); /* Call to gamma correct and add the background to the palette * and update info structure. */ png_read_update_info(png_ptr, info_ptr); /* Even if the user doesn't supply space for a palette, we want * one for the load process. */ if (!pal) pal = tmppal; /* Palettes. */ if (color_type & PNG_COLOR_MASK_PALETTE) { int num_palette, i; png_colorp palette; if (png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette)) { /* We don't actually dither, we just copy the palette. */ for (i = 0; ((i < num_palette) && (i < 256)); i++) { pal[i].r = palette[i].red >> 2; /* 256 -> 64 */ pal[i].g = palette[i].green >> 2; pal[i].b = palette[i].blue >> 2; } for (; i < 256; i++) pal[i].r = pal[i].g = pal[i].b = 0; } }
static int loadpng(const char *path, img_t *image) { png_structp png_ptr; png_infop info_ptr; FILE *fp; uint8_t *buf, header[8]; int w, h, cp, i, bit_depth; png_byte color_type; lprintf("loadpng %s\n", path); fp = fopen(path, "rb"); if(!fp) { lprintf("Failed to open file %s\n", path); return -1; } if(fread(header, 8, 1, fp) != 1) { lprintf("Error reading header\n"); fclose(fp); return -1; } if(png_sig_cmp(header, 0, 8)) { lprintf("Not a png file\n"); fclose(fp); return -1; } png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); info_ptr = png_create_info_struct(png_ptr); if(setjmp(png_jmpbuf(png_ptr))) { lprintf("Error reading png file header\n"); fclose(fp); return -1; } png_init_io(png_ptr, fp); png_set_sig_bytes(png_ptr, 8); png_read_info(png_ptr, info_ptr); w = png_get_image_width(png_ptr, info_ptr); h = png_get_image_height(png_ptr, info_ptr); color_type = png_get_color_type(png_ptr, info_ptr); bit_depth = png_get_bit_depth(png_ptr, info_ptr); png_read_update_info(png_ptr, info_ptr); switch(color_type) { case PNG_COLOR_TYPE_RGBA: cp = 3; png_set_strip_alpha(png_ptr); break; case PNG_COLOR_TYPE_RGB: cp = 3; break; case PNG_COLOR_TYPE_GRAY: if(bit_depth < 8) png_set_expand_gray_1_2_4_to_8(png_ptr); cp = 1; break; case PNG_COLOR_TYPE_GA: cp = 1; png_set_strip_alpha(png_ptr); break; case PNG_COLOR_TYPE_PALETTE: cp = 3; png_set_expand(png_ptr); break; default: cp = 0; } if(cp != 3 && cp != 1) { fclose(fp); lprintf("Unsupported number of color planes %d\n", cp); return -1; } if(bit_depth == 16) png_set_strip_16(png_ptr); buf = (uint8_t *)malloc(w * h * cp); png_bytep *rows = (png_bytep *)malloc(sizeof(png_bytep) * h); if(setjmp(png_jmpbuf(png_ptr))) { lprintf("Error reading png file\n"); fclose(fp); free(buf); free(rows); return -1; } for(i = 0; i < h; i++) rows[i] = buf + i * cp * w; png_read_image(png_ptr, rows); png_read_end(png_ptr, NULL); free(rows); fclose(fp); png_destroy_read_struct(&png_ptr, &info_ptr, NULL); lprintf("PNG (%d,%d,%d) loaded\n", w, h, cp); image->bitmap = buf; image->width = w; image->height = h; image->cp = cp; return 0; }
static void setup_qt(QImage& image, png_structp png_ptr, png_infop info_ptr, float screen_gamma=0.0) { if (screen_gamma != 0.0 && png_get_valid(png_ptr, info_ptr, PNG_INFO_gAMA)) { double file_gamma; png_get_gAMA(png_ptr, info_ptr, &file_gamma); png_set_gamma(png_ptr, screen_gamma, file_gamma); } png_uint_32 width; png_uint_32 height; int bit_depth; int color_type; png_bytep trans_alpha = 0; png_color_16p trans_color_p = 0; int num_trans; png_colorp palette = 0; int num_palette; png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, 0, 0, 0); png_set_interlace_handling(png_ptr); if (color_type == PNG_COLOR_TYPE_GRAY) { // Black & White or 8-bit grayscale if (bit_depth == 1 && png_get_channels(png_ptr, info_ptr) == 1) { png_set_invert_mono(png_ptr); png_read_update_info(png_ptr, info_ptr); if (image.size() != QSize(width, height) || image.format() != QImage::Format_Mono) { image = QImage(width, height, QImage::Format_Mono); if (image.isNull()) return; } image.setColorCount(2); image.setColor(1, qRgb(0,0,0)); image.setColor(0, qRgb(255,255,255)); } else if (bit_depth == 16 && png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { png_set_expand(png_ptr); png_set_strip_16(png_ptr); png_set_gray_to_rgb(png_ptr); if (image.size() != QSize(width, height) || image.format() != QImage::Format_ARGB32) { image = QImage(width, height, QImage::Format_ARGB32); if (image.isNull()) return; } if (QSysInfo::ByteOrder == QSysInfo::BigEndian) png_set_swap_alpha(png_ptr); png_read_update_info(png_ptr, info_ptr); } else { if (bit_depth == 16) png_set_strip_16(png_ptr); else if (bit_depth < 8) png_set_packing(png_ptr); int ncols = bit_depth < 8 ? 1 << bit_depth : 256; png_read_update_info(png_ptr, info_ptr); if (image.size() != QSize(width, height) || image.format() != QImage::Format_Indexed8) { image = QImage(width, height, QImage::Format_Indexed8); if (image.isNull()) return; } image.setColorCount(ncols); for (int i=0; i<ncols; i++) { int c = i*255/(ncols-1); image.setColor(i, qRgba(c,c,c,0xff)); } if (png_get_tRNS(png_ptr, info_ptr, &trans_alpha, &num_trans, &trans_color_p) && trans_color_p) { const int g = trans_color_p->gray; if (g < ncols) { image.setColor(g, 0); } } } } else if (color_type == PNG_COLOR_TYPE_PALETTE && png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette) && num_palette <= 256) { // 1-bit and 8-bit color if (bit_depth != 1) png_set_packing(png_ptr); png_read_update_info(png_ptr, info_ptr); png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, 0, 0, 0); QImage::Format format = bit_depth == 1 ? QImage::Format_Mono : QImage::Format_Indexed8; if (image.size() != QSize(width, height) || image.format() != format) { image = QImage(width, height, format); if (image.isNull()) return; } png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette); image.setColorCount(num_palette); int i = 0; if (png_get_tRNS(png_ptr, info_ptr, &trans_alpha, &num_trans, &trans_color_p) && trans_alpha) { while (i < num_trans) { image.setColor(i, qRgba( palette[i].red, palette[i].green, palette[i].blue, trans_alpha[i] ) ); i++; } } while (i < num_palette) { image.setColor(i, qRgba( palette[i].red, palette[i].green, palette[i].blue, 0xff ) ); i++; } } else { // 32-bit if (bit_depth == 16) png_set_strip_16(png_ptr); png_set_expand(png_ptr); if (color_type == PNG_COLOR_TYPE_GRAY_ALPHA) png_set_gray_to_rgb(png_ptr); QImage::Format format = QImage::Format_ARGB32; // Only add filler if no alpha, or we can get 5 channel data. if (!(color_type & PNG_COLOR_MASK_ALPHA) && !png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { png_set_filler(png_ptr, 0xff, QSysInfo::ByteOrder == QSysInfo::BigEndian ? PNG_FILLER_BEFORE : PNG_FILLER_AFTER); // We want 4 bytes, but it isn't an alpha channel format = QImage::Format_RGB32; } if (image.size() != QSize(width, height) || image.format() != format) { image = QImage(width, height, format); if (image.isNull()) return; } if (QSysInfo::ByteOrder == QSysInfo::BigEndian) png_set_swap_alpha(png_ptr); png_read_update_info(png_ptr, info_ptr); } // Qt==ARGB==Big(ARGB)==Little(BGRA) if (QSysInfo::ByteOrder == QSysInfo::LittleEndian) { png_set_bgr(png_ptr); } }
int /* O - Read status */ _cupsImageReadPNG( cups_image_t *img, /* IO - cupsImage */ FILE *fp, /* I - cupsImage file */ cups_icspace_t primary, /* I - Primary choice for colorspace */ cups_icspace_t secondary, /* I - Secondary choice for colorspace */ int saturation, /* I - Color saturation (%) */ int hue, /* I - Color hue (degrees) */ const cups_ib_t *lut) /* I - Lookup table for gamma/brightness */ { int y; /* Looping var */ png_structp pp; /* PNG read pointer */ png_infop info; /* PNG info pointers */ png_uint_32 width, /* Width of image */ height; /* Height of image */ int bit_depth, /* Bit depth */ color_type, /* Color type */ interlace_type, /* Interlace type */ compression_type, /* Compression type */ filter_type; /* Filter type */ png_uint_32 xppm, /* X pixels per meter */ yppm; /* Y pixels per meter */ int bpp; /* Bytes per pixel */ int pass, /* Current pass */ passes; /* Number of passes required */ cups_ib_t *in, /* Input pixels */ *inptr, /* Pointer into pixels */ *out; /* Output pixels */ png_color_16 bg; /* Background color */ /* * Setup the PNG data structures... */ pp = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); info = png_create_info_struct(pp); /* * Initialize the PNG read "engine"... */ png_init_io(pp, fp); /* * Get the image dimensions and load the output image... */ png_read_info(pp, info); png_get_IHDR(pp, info, &width, &height, &bit_depth, &color_type, &interlace_type, &compression_type, &filter_type); fprintf(stderr, "DEBUG: PNG image: %dx%dx%d, color_type=%x (%s%s%s)\n", (int)width, (int)height, bit_depth, color_type, (color_type & PNG_COLOR_MASK_COLOR) ? "RGB" : "GRAYSCALE", (color_type & PNG_COLOR_MASK_ALPHA) ? "+ALPHA" : "", (color_type & PNG_COLOR_MASK_PALETTE) ? "+PALETTE" : ""); if (color_type & PNG_COLOR_MASK_PALETTE) png_set_expand(pp); else if (bit_depth < 8) { png_set_packing(pp); png_set_expand(pp); } else if (bit_depth == 16) png_set_strip_16(pp); if (color_type & PNG_COLOR_MASK_COLOR) img->colorspace = (primary == CUPS_IMAGE_RGB_CMYK) ? CUPS_IMAGE_RGB : primary; else img->colorspace = secondary; if (width == 0 || width > CUPS_IMAGE_MAX_WIDTH || height == 0 || height > CUPS_IMAGE_MAX_HEIGHT) { fprintf(stderr, "DEBUG: PNG image has invalid dimensions %ux%u!\n", (unsigned)width, (unsigned)height); fclose(fp); return (1); } img->xsize = width; img->ysize = height; if ((xppm = png_get_x_pixels_per_meter(pp, info)) != 0 && (yppm = png_get_y_pixels_per_meter(pp, info)) != 0) { img->xppi = (int)((float)xppm * 0.0254); img->yppi = (int)((float)yppm * 0.0254); if (img->xppi == 0 || img->yppi == 0) { fprintf(stderr, "DEBUG: PNG image has invalid resolution %dx%d PPI\n", img->xppi, img->yppi); img->xppi = img->yppi = 128; } } cupsImageSetMaxTiles(img, 0); passes = png_set_interlace_handling(pp); /* * Handle transparency... */ if (png_get_valid(pp, info, PNG_INFO_tRNS)) png_set_tRNS_to_alpha(pp); bg.red = 65535; bg.green = 65535; bg.blue = 65535; png_set_background(pp, &bg, PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0); if (passes == 1) { /* * Load one row at a time... */ if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) in = malloc(img->xsize); else in = malloc(img->xsize * 3); } else { /* * Interlaced images must be loaded all at once... */ size_t bufsize; /* Size of buffer */ if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) { bufsize = img->xsize * img->ysize; if ((bufsize / img->xsize) != img->ysize) { fprintf(stderr, "DEBUG: PNG image dimensions (%ux%u) too large!\n", (unsigned)width, (unsigned)height); fclose(fp); return (1); } } else { bufsize = img->xsize * img->ysize * 3; if ((bufsize / (img->xsize * 3)) != img->ysize) { fprintf(stderr, "DEBUG: PNG image dimensions (%ux%u) too large!\n", (unsigned)width, (unsigned)height); fclose(fp); return (1); } } in = malloc(bufsize); } bpp = cupsImageGetDepth(img); out = malloc(img->xsize * bpp); if (!in || !out) { fputs("DEBUG: Unable to allocate memory for PNG image!\n", stderr); if (in) free(in); if (out) free(out); fclose(fp); return (1); } /* * Read the image, interlacing as needed... */ for (pass = 1; pass <= passes; pass ++) for (inptr = in, y = 0; y < img->ysize; y ++) { png_read_row(pp, (png_bytep)inptr, NULL); if (pass == passes) { /* * Output this row... */ if (color_type & PNG_COLOR_MASK_COLOR) { if ((saturation != 100 || hue != 0) && bpp > 1) cupsImageRGBAdjust(inptr, img->xsize, saturation, hue); switch (img->colorspace) { case CUPS_IMAGE_WHITE : cupsImageRGBToWhite(inptr, out, img->xsize); break; case CUPS_IMAGE_RGB : case CUPS_IMAGE_RGB_CMYK : cupsImageRGBToRGB(inptr, out, img->xsize); break; case CUPS_IMAGE_BLACK : cupsImageRGBToBlack(inptr, out, img->xsize); break; case CUPS_IMAGE_CMY : cupsImageRGBToCMY(inptr, out, img->xsize); break; case CUPS_IMAGE_CMYK : cupsImageRGBToCMYK(inptr, out, img->xsize); break; } } else { switch (img->colorspace) { case CUPS_IMAGE_WHITE : memcpy(out, inptr, img->xsize); break; case CUPS_IMAGE_RGB : case CUPS_IMAGE_RGB_CMYK : cupsImageWhiteToRGB(inptr, out, img->xsize); break; case CUPS_IMAGE_BLACK : cupsImageWhiteToBlack(inptr, out, img->xsize); break; case CUPS_IMAGE_CMY : cupsImageWhiteToCMY(inptr, out, img->xsize); break; case CUPS_IMAGE_CMYK : cupsImageWhiteToCMYK(inptr, out, img->xsize); break; } } if (lut) cupsImageLut(out, img->xsize * bpp, lut); _cupsImagePutRow(img, 0, y, img->xsize, out); } if (passes > 1) { if (color_type & PNG_COLOR_MASK_COLOR) inptr += img->xsize * 3; else inptr += img->xsize; } } png_read_end(pp, info); png_destroy_read_struct(&pp, &info, NULL); fclose(fp); free(in); free(out); return (0); }
PremultipliedImage decodePNG(const uint8_t* data, size_t size) { util::CharArrayBuffer dataBuffer { reinterpret_cast<const char*>(data), size }; std::istream stream(&dataBuffer); png_byte header[8] = { 0 }; stream.read(reinterpret_cast<char*>(header), 8); if (stream.gcount() != 8) throw std::runtime_error("PNG reader: Could not read image"); int is_png = !png_sig_cmp(header, 0, 8); if (!is_png) throw std::runtime_error("File or stream is not a png"); png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr); if (!png_ptr) throw std::runtime_error("failed to allocate png_ptr"); // catch errors in a custom way to avoid the need for setjmp png_set_error_fn(png_ptr, png_get_error_ptr(png_ptr), user_error_fn, user_warning_fn); png_infop info_ptr; png_struct_guard sguard(&png_ptr, &info_ptr); info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) throw std::runtime_error("failed to create info_ptr"); png_set_read_fn(png_ptr, &stream, png_read_data); png_set_sig_bytes(png_ptr, 8); png_read_info(png_ptr, info_ptr); png_uint_32 width = 0; png_uint_32 height = 0; int bit_depth = 0; int color_type = 0; png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, nullptr, nullptr, nullptr); UnassociatedImage image { static_cast<uint16_t>(width), static_cast<uint16_t>(height) }; if (color_type == PNG_COLOR_TYPE_PALETTE) png_set_expand(png_ptr); if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) png_set_expand(png_ptr); if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) png_set_expand(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); png_set_add_alpha(png_ptr, 0xff, PNG_FILLER_AFTER); if (png_get_interlace_type(png_ptr,info_ptr) == PNG_INTERLACE_ADAM7) { png_set_interlace_handling(png_ptr); // FIXME: libpng bug? // according to docs png_read_image // "..automatically handles interlacing, // so you don't need to call png_set_interlace_handling()" } png_read_update_info(png_ptr, info_ptr); // we can read whole image at once // alloc row pointers const std::unique_ptr<png_bytep[]> rows(new png_bytep[height]); for (unsigned row = 0; row < height; ++row) rows[row] = image.data.get() + row * width * 4; png_read_image(png_ptr, rows.get()); png_read_end(png_ptr, nullptr); return util::premultiply(std::move(image)); }
//============================================================================== static bool _decompressPNG(png_structp a_png_ptr, png_infop a_info_ptr, cImage* a_image) { int j; int bpp; // read in the header png_read_info(a_png_ptr, a_info_ptr); int width = png_get_image_width (a_png_ptr, a_info_ptr); int height = png_get_image_height(a_png_ptr, a_info_ptr); // get image info png_uint_32 tmpw, tmph; int bit_depth, color_type, interlace_type; png_get_IHDR(a_png_ptr, a_info_ptr, &tmpw, &tmph, &bit_depth, &color_type, &interlace_type, NULL, NULL); // strip 16 bit/color files down to 8 bits/color png_set_strip_16(a_png_ptr); // extract multiple pixels with bit depths of 1, 2, and 4 into separate bytes png_set_packing(a_png_ptr); // expand palette to RGB, grayscale to 8 bits, transparency to alpha png_set_expand(a_png_ptr); // set the bytes per pixel count if (color_type & PNG_COLOR_MASK_COLOR) bpp = 3; else bpp = 1; // if there is an alpha channel or some transparency, act accordingly if (color_type & PNG_COLOR_MASK_ALPHA || png_get_valid(a_png_ptr, a_info_ptr, PNG_INFO_tRNS)) bpp += 1; // allocate row buffers size_t rowsize = bpp*width; png_bytep *row_pointers = new png_bytep[height]; for (j=0; j<height; j++) row_pointers[j] = (png_bytep)png_malloc(a_png_ptr, rowsize); // read the entire image in one go png_read_image(a_png_ptr, row_pointers); // we allocate memory for image. By default we shall use OpenGL's RGB mode. if (bpp == 1 && !a_image->allocate(width, height, GL_LUMINANCE)) return false; if (bpp == 2 && !a_image->allocate(width, height, GL_LUMINANCE_ALPHA)) return false; if (bpp == 3 && !a_image->allocate(width, height, GL_RGB)) return false; if (bpp == 4 && !a_image->allocate(width, height, GL_RGBA)) return false; // retrieve pointer to image data unsigned char* data = a_image->getData(); // put rows neatly in the destination buffer for (j=0; j<height; j++) memcpy(data+bpp*j*width, row_pointers[height-1-j], rowsize); // clean up after the read and free any memory allocated delete [] row_pointers; png_read_end(a_png_ptr, NULL); // success return true; }