static void user_error_fn(png_structp png_ptr, png_const_charp error_msg) { fprintf(stderr, "%s\n", error_msg ); #if (PNG_LIBPNG_VER < 10500) longjmp(png_ptr->jmpbuf,1); #else png_longjmp (png_ptr, 1); #endif }
/* Error for from-web PNG images. */ static void img_my_png_error(png_structp png_ptr, png_const_charp error_string) { #if (PNG_LIBPNG_VER < 10500) longjmp(png_ptr->jmpbuf,1); #else png_longjmp(png_ptr,1); #endif }
static void #ifdef PNGAPI PNGAPI #endif error_fn( png_structp png_ptr, png_const_charp msg) { char * buf = ( char *) png_get_error_ptr( png_ptr); if ( buf) strncpy( buf, msg, 256); #if PNG_LIBPNG_VER_MAJOR == 1 && PNG_LIBPNG_VER_MINOR < 5 longjmp( png_ptr-> jmpbuf, 1); #else png_longjmp( png_ptr, 1); #endif }
static void PNGCBAPI makepng_error(png_structp png_ptr, png_const_charp message) { makepng_warning(png_ptr, message); png_longjmp(png_ptr, 1); }
void nsPNGDecoder::error_callback(png_structp png_ptr, png_const_charp error_msg) { MOZ_LOG(GetPNGLog(), LogLevel::Error, ("libpng error: %s\n", error_msg)); png_longjmp(png_ptr, 1); }
void nsPNGDecoder::row_callback(png_structp png_ptr, png_bytep new_row, png_uint_32 row_num, int pass) { /* libpng comments: * * this function is called for every row in the image. If the * image is interlacing, and you turned on the interlace handler, * this function will be called for every row in every pass. * Some of these rows will not be changed from the previous pass. * When the row is not changed, the new_row variable will be * nullptr. The rows and passes are called in order, so you don't * really need the row_num and pass, but I'm supplying them * because it may make your life easier. * * For the non-nullptr rows of interlaced images, you must call * png_progressive_combine_row() passing in the row and the * old row. You can call this function for nullptr rows (it will * just return) and for non-interlaced images (it just does the * memcpy for you) if it will make the code easier. Thus, you * can just do this for all cases: * * png_progressive_combine_row(png_ptr, old_row, new_row); * * where old_row is what was displayed for previous rows. Note * that the first pass (pass == 0 really) will completely cover * the old row, so the rows do not have to be initialized. After * the first pass (and only for interlaced images), you will have * to pass the current row, and the function will combine the * old row and the new row. */ nsPNGDecoder* decoder = static_cast<nsPNGDecoder*>(png_get_progressive_ptr(png_ptr)); // skip this frame if (decoder->mFrameIsHidden) { return; } if (row_num >= (png_uint_32) decoder->mFrameRect.height) { return; } if (new_row) { int32_t width = decoder->mFrameRect.width; uint32_t iwidth = decoder->mFrameRect.width; png_bytep line = new_row; if (decoder->interlacebuf) { line = decoder->interlacebuf + (row_num * decoder->mChannels * width); png_progressive_combine_row(png_ptr, line, new_row); } uint32_t bpr = width * sizeof(uint32_t); uint32_t* cptr32 = (uint32_t*)(decoder->mImageData + (row_num*bpr)); if (decoder->mTransform) { if (decoder->mCMSLine) { qcms_transform_data(decoder->mTransform, line, decoder->mCMSLine, iwidth); // copy alpha over uint32_t channels = decoder->mChannels; if (channels == 2 || channels == 4) { for (uint32_t i = 0; i < iwidth; i++) decoder->mCMSLine[4 * i + 3] = line[channels * i + channels - 1]; } line = decoder->mCMSLine; } else { qcms_transform_data(decoder->mTransform, line, line, iwidth); } } switch (decoder->format) { case gfx::SurfaceFormat::B8G8R8X8: { // counter for while() loops below uint32_t idx = iwidth; // copy as bytes until source pointer is 32-bit-aligned for (; (NS_PTR_TO_UINT32(line) & 0x3) && idx; --idx) { *cptr32++ = gfxPackedPixel(0xFF, line[0], line[1], line[2]); line += 3; } // copy pixels in blocks of 4 while (idx >= 4) { GFX_BLOCK_RGB_TO_FRGB(line, cptr32); idx -= 4; line += 12; cptr32 += 4; } // copy remaining pixel(s) while (idx--) { // 32-bit read of final pixel will exceed buffer, so read bytes *cptr32++ = gfxPackedPixel(0xFF, line[0], line[1], line[2]); line += 3; } } break; case gfx::SurfaceFormat::B8G8R8A8: { if (!decoder->mDisablePremultipliedAlpha) { for (uint32_t x=width; x>0; --x) { *cptr32++ = gfxPackedPixel(line[3], line[0], line[1], line[2]); line += 4; } } else { for (uint32_t x=width; x>0; --x) { *cptr32++ = gfxPackedPixelNoPreMultiply(line[3], line[0], line[1], line[2]); line += 4; } } } break; default: png_longjmp(decoder->mPNG, 1); } if (decoder->mNumFrames <= 1) { // Only do incremental image display for the first frame // XXXbholley - this check should be handled in the superclass nsIntRect r(0, row_num, width, 1); decoder->PostInvalidation(r); } } }
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 = nullptr; 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) { png_longjmp(decoder->mPNG, 1); } // Post our size to the superclass decoder->PostSize(width, height); if (decoder->HasError()) { // Setting the size led to an error. png_longjmp(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)) { 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 (bug #428045) if (bit_depth < 16) { png_uint_16 sample_max = (1 << bit_depth) - 1; if ((color_type == PNG_COLOR_TYPE_GRAY && trans_values->gray > sample_max) || (color_type == PNG_COLOR_TYPE_RGB && (trans_values->red > sample_max || trans_values->green > sample_max || 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); num_trans = 0; } } if (num_trans != 0) { png_set_expand(png_ptr); } } if (bit_depth == 16) { png_set_scale_16(png_ptr); } qcms_data_type inType = QCMS_DATA_RGBA_8; uint32_t intent = -1; uint32_t 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 == uint32_t(-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()) // //---------------------------------------------------------------// if (channels == 1 || channels == 3) { decoder->format = gfx::SurfaceFormat::B8G8R8X8; } else if (channels == 2 || channels == 4) { decoder->format = gfx::SurfaceFormat::B8G8R8A8; } else { png_longjmp(decoder->mPNG, 1); // invalid number of channels } #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, nullptr); } if (png_get_first_frame_is_hidden(png_ptr, info_ptr)) { decoder->mFrameIsHidden = 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)) { uint32_t bpp[] = { 0, 3, 4, 3, 4 }; decoder->mCMSLine = (uint8_t*)malloc(bpp[channels] * width); if (!decoder->mCMSLine) { png_longjmp(decoder->mPNG, 5); // NS_ERROR_OUT_OF_MEMORY } } if (interlace_type == PNG_INTERLACE_ADAM7) { if (height < INT32_MAX / (width * channels)) { decoder->interlacebuf = (uint8_t*)malloc(channels * width * height); } if (!decoder->interlacebuf) { png_longjmp(decoder->mPNG, 5); // NS_ERROR_OUT_OF_MEMORY } } if (decoder->NeedsNewFrame()) { // We know that we need a new frame, so pause input so the decoder // infrastructure can give it to us. png_process_data_pause(png_ptr, /* save = */ 1); } }