Пример #1
0
void
nsPNGDecoder::end_callback(png_structp png_ptr, png_infop info_ptr)
{
  /* libpng comments:
   *
   * this function is called when the whole image has been read,
   * including any chunks after the image (up to and including
   * the IEND).  You will usually have the same info chunk as you
   * had in the header, although some data may have been added
   * to the comments and time fields.
   *
   * Most people won't do much here, perhaps setting a flag that
   * marks the image as finished.
   */

  nsPNGDecoder* decoder =
               static_cast<nsPNGDecoder*>(png_get_progressive_ptr(png_ptr));

  // We shouldn't get here if we've hit an error
  MOZ_ASSERT(!decoder->HasError(), "Finishing up PNG but hit error!");

  int32_t loop_count = 0;
#ifdef PNG_APNG_SUPPORTED
  if (png_get_valid(png_ptr, info_ptr, PNG_INFO_acTL)) {
    int32_t num_plays = png_get_num_plays(png_ptr, info_ptr);
    loop_count = num_plays - 1;
  }
#endif

  // Send final notifications
  decoder->EndImageFrame();
  decoder->PostDecodeDone(loop_count);
}
Пример #2
0
// got the header of a new frame that's coming
void
nsPNGDecoder::frame_info_callback(png_structp png_ptr, png_uint_32 frame_num)
{
  png_uint_32 x_offset, y_offset;
  int32_t width, height;

  nsPNGDecoder* decoder =
               static_cast<nsPNGDecoder*>(png_get_progressive_ptr(png_ptr));

  // old frame is done
  decoder->EndImageFrame();

  // Only the first frame can be hidden, so unhide unconditionally here.
  decoder->mFrameIsHidden = false;

  x_offset = png_get_next_frame_x_offset(png_ptr, decoder->mInfo);
  y_offset = png_get_next_frame_y_offset(png_ptr, decoder->mInfo);
  width = png_get_next_frame_width(png_ptr, decoder->mInfo);
  height = png_get_next_frame_height(png_ptr, decoder->mInfo);

  decoder->CreateFrame(x_offset, y_offset, width, height, decoder->format);

  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);
  }
}
Пример #3
0
static void read_data_fn(png_structp png_ptr, png_bytep data, png_size_t length)
{
	struct png_t* png = (struct png_t*)png_get_progressive_ptr(png_ptr);
	if(png->pos + length > png->size) png_error(png_ptr, "Read Error");
	memcpy(data, &png->data[png->pos], length);
	png->pos += length;
}
Пример #4
0
void PngReader::end_callback(
    png_structp png, png_infop info )
{
    PngReader* reader =
        ( PngReader* )png_get_progressive_ptr( png );
    reader->m_finished = true;
}
Пример #5
0
/* Called after reading the entire image */
static void
png_end_callback   (png_structp png_read_ptr,
                    png_infop   png_info_ptr)
{
        LoadContext* lc;

        lc = png_get_progressive_ptr(png_read_ptr);

        if (lc->fatal_error_occurred)
                return;
}
Пример #6
0
void pngDecEndCallback(png_structp png_ptr, png_infop info)
{
	PngStream* stream = (PngStream*)png_get_progressive_ptr(png_ptr);
	if (!stream)
	{
		cellPngDec.error("Failed to obtain streamPtr in endCallback.");
		return;
	}

	stream->endOfFile = true;
}
Пример #7
0
void pngDecInfoCallback(png_structp png_ptr, png_infop info)
{
	PngStream* stream = (PngStream*)png_get_progressive_ptr(png_ptr);
	if (!stream)
	{
		cellPngDec.error("Failed to obtain streamPtr in rowCallback.");
		return;
	}

	const size_t remaining = png_process_data_pause(png_ptr, false);
	stream->buffer->cursor += (stream->buffer->length - remaining);
}
Пример #8
0
static void row_callback(png_structp png_s, png_bytep new_row,
			 png_uint_32 row_num, int pass)
{
	nspng_content *png_c = png_get_progressive_ptr(png_s);
	unsigned long rowbytes = png_c->rowbytes;
	unsigned char *buffer, *row;

	/* Give up if there's no bitmap */
	if (png_c->bitmap == NULL)
		return;

	/* Abort if we've not got any data */
	if (new_row == NULL)
		return;

	/* Get bitmap buffer */
	buffer = bitmap_get_buffer(png_c->bitmap);
	if (buffer == NULL) {
		/* No buffer, bail out */
		longjmp(png_jmpbuf(png_s), 1);
	}

	/* Calculate address of row start */
	row = buffer + (png_c->rowstride * row_num);

	/* Handle interlaced sprites using the Adam7 algorithm */
	if (png_c->interlace) {
		unsigned long dst_off;
		unsigned long src_off = 0;
		unsigned int start, step;

		start = interlace_start[pass];
		step = interlace_step[pass];
		row_num = interlace_row_start[pass] +
			interlace_row_step[pass] * row_num;

		/* Copy the data to our current row taking interlacing
		 * into consideration */
		row = buffer + (png_c->rowstride * row_num);

		for (dst_off = start; dst_off < rowbytes; dst_off += step) {
			row[dst_off++] = new_row[src_off++];
			row[dst_off++] = new_row[src_off++];
			row[dst_off++] = new_row[src_off++];
			row[dst_off++] = new_row[src_off++];
		}
	} else {
		/* Do a fast memcpy of the row data */
		memcpy(row, new_row, rowbytes);
	}
}
Пример #9
0
void PngReader::row_callback(
    png_structp png, png_bytep row,
    png_uint_32 rowpos, int pass )
{
    if( !row )
    {
        return;
    }
    PngReader* reader =
        ( PngReader* )png_get_progressive_ptr( png );
    png_progressive_combine_row(
        png,
        reader->m_data->m_data +
        reader->m_stride * ( reader->m_height - rowpos - 1 ),
        row );
}
Пример #10
0
static void _png_get_row_func(png_structp png_ptr,
                              png_bytep new_row,
                              png_uint_32 row_num,
                              int pass) {
  FXPNG_Context* p = (FXPNG_Context*)png_get_progressive_ptr(png_ptr);
  if (!p)
    return;

  CCodec_PngModule* pModule = (CCodec_PngModule*)p->parent_ptr;
  uint8_t* src_buf = nullptr;
  if (!pModule->AskScanlineBufCallback(p->child_ptr, row_num, src_buf)) {
    png_error(png_ptr, "Ask Scanline buffer Callback Error");
  }
  if (src_buf) {
    png_progressive_combine_row(png_ptr, src_buf, new_row);
  }
  pModule->FillScanlineBufCompletedCallback(p->child_ptr, pass, row_num);
}
Пример #11
0
    bool decode(const SharedBuffer& data, bool sizeOnly)
    {
        m_decodingSizeOnly = sizeOnly;
        PNGImageDecoder* decoder = static_cast<PNGImageDecoder*>(png_get_progressive_ptr(m_png));

        // We need to do the setjmp here. Otherwise bad things will happen.
        if (setjmp(JMPBUF(m_png)))
            return decoder->setFailed();

        const char* segment;
        while (unsigned segmentLength = data.getSomeData(segment, m_readOffset)) {
            m_readOffset += segmentLength;
            m_currentBufferSize = m_readOffset;
            png_process_data(m_png, m_info, reinterpret_cast<png_bytep>(const_cast<char*>(segment)), segmentLength);
            // We explicitly specify the superclass isSizeAvailable() because we
            // merely want to check if we've managed to set the size, not
            // (recursively) trigger additional decoding if we haven't.
            if (sizeOnly ? decoder->ImageDecoder::isSizeAvailable() : decoder->isComplete())
                return true;
        }
        return false;
    }
Пример #12
0
/* Called for each row; note that you will get duplicate row numbers
   for interlaced PNGs */
static void
png_row_callback   (png_structp png_read_ptr,
                    png_bytep   new_row,
                    png_uint_32 row_num,
                    int pass_num)
{
        LoadContext* lc;
        guchar* old_row = NULL;

        lc = png_get_progressive_ptr(png_read_ptr);

        if (lc->fatal_error_occurred)
                return;

        if (row_num >= lc->pixbuf->height) {
                lc->fatal_error_occurred = TRUE;
                if (lc->error && *lc->error == NULL) {
                        g_set_error_literal (lc->error,
                                             GDK_PIXBUF_ERROR,
                                             GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
                                             _("Fatal error reading PNG image file"));
                }
                return;
        }

        if (lc->first_row_seen_in_chunk < 0) {
                lc->first_row_seen_in_chunk = row_num;
                lc->first_pass_seen_in_chunk = pass_num;
        }

        lc->max_row_seen_in_chunk = MAX(lc->max_row_seen_in_chunk, ((gint)row_num));
        lc->last_row_seen_in_chunk = row_num;
        lc->last_pass_seen_in_chunk = pass_num;
        
        old_row = lc->pixbuf->pixels + (row_num * lc->pixbuf->rowstride);

        png_progressive_combine_row(lc->png_read_ptr, old_row, new_row);
}
Пример #13
0
void PngReader::info_callback(
    png_structp png, png_infop info )
{
    PngReader* reader =
        ( PngReader* )png_get_progressive_ptr( png );
    int bitdepth;
    int colortype;
    png_get_IHDR( png, info,
                  ( png_uint_32* )&reader->m_width,
                  ( png_uint_32* )&reader->m_height,
                  &bitdepth, &colortype, 0, 0, 0 );
    formattable[ reader->m_format ].setformat(
        png, info, bitdepth, colortype );
    png_set_interlace_handling( png );
    png_read_update_info( png, info );
    reader->m_stride =
        reader->m_width *
        formattable[ reader->m_format ].pixelstride;
    size_t size = reader->m_stride * reader->m_height;
    reader->m_data = DataBuffer::create(
                         size, size, 0 );
    memset( reader->m_data->m_data, 0, size );
}
Пример #14
0
void pngDecRowCallback(png_structp png_ptr, png_bytep new_row, png_uint_32 row_num, int pass)
{
	PngStream* stream = (PngStream*)png_get_progressive_ptr(png_ptr);
	if (!stream)
	{
		cellPngDec.error("Failed to obtain streamPtr in rowCallback.");
		return;
	}

	// we have to check this everytime as this func can be called multiple times per row, and/or only once per row
	if (stream->nextRow + stream->outputCounts == row_num)
		stream->nextRow = row_num;

	if (stream->ppuContext && (stream->nextRow == row_num  || pass > 0))
	{
		if (pass > 0 )
		{
			stream->cbDispInfo->scanPassCount = pass;
			stream->cbDispInfo->nextOutputStartY = row_num;
		}
		else {
			stream->cbDispInfo->scanPassCount = 0;
			stream->cbDispInfo->nextOutputStartY = 0;
		}

		stream->cbDispInfo->outputImage = stream->cbDispParam->nextOutputImage;
		stream->cbCtrlDisp.cbCtrlDispFunc(*stream->ppuContext, stream->cbDispInfo, stream->cbDispParam, stream->cbCtrlDisp.cbCtrlDispArg);
		stream->cbDispInfo->outputStartY = row_num;
	}
	u8* data;
	if (pass > 0)
		data = static_cast<u8*>(stream->cbDispParam->nextOutputImage.get_ptr());
	else
		data = static_cast<u8*>(stream->cbDispParam->nextOutputImage.get_ptr()) + ((row_num - stream->cbDispInfo->outputStartY) * stream->cbDispInfo->outputFrameWidthByte);

	png_progressive_combine_row(png_ptr, data, new_row);
}
Пример #15
0
/**
 * info_callback -- PNG header has been completely received, prepare to process
 * image data
 */
static void info_callback(png_structp png_s, png_infop info)
{
	int interlace;
	png_uint_32 width, height;
	nspng_content *png_c = png_get_progressive_ptr(png_s);

	width = png_get_image_width(png_s, info);
	height = png_get_image_height(png_s, info);
	interlace = png_get_interlace_type(png_s, info);

	png_c->base.width = width;
	png_c->base.height = height;
	png_c->base.size += width * height * 4;

	/* see if progressive-conversion should continue */
	if (image_cache_speculate((struct content *)png_c) == false) {
		longjmp(png_jmpbuf(png_s), CBERR_NOPRE);
	}

	/* Claim the required memory for the converted PNG */
	png_c->bitmap = bitmap_create(width, height, BITMAP_NEW);
	if (png_c->bitmap == NULL) {
		/* Failed to create bitmap skip pre-conversion */
		longjmp(png_jmpbuf(png_s), CBERR_NOPRE);
	}

	png_c->rowstride = bitmap_get_rowstride(png_c->bitmap);
	png_c->bpp = bitmap_get_bpp(png_c->bitmap);

	nspng_setup_transforms(png_s, info);

	png_c->rowbytes = png_get_rowbytes(png_s, info);
	png_c->interlace = (interlace == PNG_INTERLACE_ADAM7);

	LOG(("size %li * %li, rowbytes %zu", (unsigned long)width,
	     (unsigned long)height, png_c->rowbytes));
}
Пример #16
0
// got the header of a new frame that's coming
void
nsPNGDecoder::frame_info_callback(png_structp png_ptr, png_uint_32 frame_num)
{
#ifdef PNG_APNG_SUPPORTED
  png_uint_32 x_offset, y_offset;
  PRInt32 width, height;

  nsPNGDecoder *decoder =
               static_cast<nsPNGDecoder*>(png_get_progressive_ptr(png_ptr));

  // old frame is done
  decoder->EndImageFrame();

  // Only the first frame can be hidden, so unhide unconditionally here.
  decoder->mFrameIsHidden = PR_FALSE;

  x_offset = png_get_next_frame_x_offset(png_ptr, decoder->mInfo);
  y_offset = png_get_next_frame_y_offset(png_ptr, decoder->mInfo);
  width = png_get_next_frame_width(png_ptr, decoder->mInfo);
  height = png_get_next_frame_height(png_ptr, decoder->mInfo);

  decoder->CreateFrame(x_offset, y_offset, width, height, decoder->format);
#endif
}
Пример #17
0
static void readpng2_info_callback(png_structp png_ptr, png_infop info_ptr)
{
    mainprog_info  *mainprog_ptr;
    int  color_type, bit_depth;
    png_uint_32 width, height;
#ifdef PNG_FLOATING_POINT_SUPPORTED
    double  gamma;
#else
    png_fixed_point gamma;
#endif


    /* setjmp() doesn't make sense here, because we'd either have to exit(),
     * longjmp() ourselves, or return control to libpng, which doesn't want
     * to see us again.  By not doing anything here, libpng will instead jump
     * to readpng2_decode_data(), which can return an error value to the main
     * program. */


    /* retrieve the pointer to our special-purpose struct, using the png_ptr
     * that libpng passed back to us (i.e., not a global this time--there's
     * no real difference for a single image, but for a multithreaded browser
     * decoding several PNG images at the same time, one needs to avoid mixing
     * up different images' structs) */

    mainprog_ptr = png_get_progressive_ptr(png_ptr);

    if (mainprog_ptr == NULL) {         /* we be hosed */
        fprintf(stderr,
          "readpng2 error:  main struct not recoverable in info_callback.\n");
        fflush(stderr);
        return;
        /*
         * Alternatively, we could call our error-handler just like libpng
         * does, which would effectively terminate the program.  Since this
         * can only happen if png_ptr gets redirected somewhere odd or the
         * main PNG struct gets wiped, we're probably toast anyway.  (If
         * png_ptr itself is NULL, we would not have been called.)
         */
    }


    /* this is just like in the non-progressive case */

    png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,
       NULL, NULL, NULL);
    mainprog_ptr->width = (ulg)width;
    mainprog_ptr->height = (ulg)height;


    /* since we know we've read all of the PNG file's "header" (i.e., up
     * to IDAT), we can check for a background color here */

    if (mainprog_ptr->need_bgcolor &&
        png_get_valid(png_ptr, info_ptr, PNG_INFO_bKGD))
    {
        png_color_16p pBackground;

        /* it is not obvious from the libpng documentation, but this function
         * takes a pointer to a pointer, and it always returns valid red,
         * green and blue values, regardless of color_type: */
        png_get_bKGD(png_ptr, info_ptr, &pBackground);

        /* however, it always returns the raw bKGD data, regardless of any
         * bit-depth transformations, so check depth and adjust if necessary */
        if (bit_depth == 16) {
            mainprog_ptr->bg_red   = pBackground->red   >> 8;
            mainprog_ptr->bg_green = pBackground->green >> 8;
            mainprog_ptr->bg_blue  = pBackground->blue  >> 8;
        } else if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) {
Пример #18
0
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;
}
Пример #19
0
static void _png_get_header_func(png_structp png_ptr, png_infop info_ptr) {
  FXPNG_Context* p = (FXPNG_Context*)png_get_progressive_ptr(png_ptr);
  if (!p)
    return;

  CCodec_PngModule* pModule = (CCodec_PngModule*)p->parent_ptr;
  if (!pModule)
    return;

  png_uint_32 width = 0, height = 0;
  int bpc = 0, color_type = 0, color_type1 = 0, pass = 0;
  double gamma = 1.0;
  png_get_IHDR(png_ptr, info_ptr, &width, &height, &bpc, &color_type, nullptr,
               nullptr, nullptr);
  color_type1 = color_type;
  if (bpc > 8) {
    png_set_strip_16(png_ptr);
  } else if (bpc < 8) {
    png_set_expand_gray_1_2_4_to_8(png_ptr);
  }
  bpc = 8;
  if (color_type == PNG_COLOR_TYPE_PALETTE) {
    png_set_palette_to_rgb(png_ptr);
  }
  pass = png_set_interlace_handling(png_ptr);
  if (!pModule->ReadHeaderCallback(p->child_ptr, width, height, bpc, pass,
                                   &color_type, &gamma)) {
    png_error(p->png_ptr, "Read Header Callback Error");
  }
  int intent;
  if (png_get_sRGB(png_ptr, info_ptr, &intent)) {
    png_set_gamma(png_ptr, gamma, 0.45455);
  } else {
    double image_gamma;
    if (png_get_gAMA(png_ptr, info_ptr, &image_gamma)) {
      png_set_gamma(png_ptr, gamma, image_gamma);
    } else {
      png_set_gamma(png_ptr, gamma, 0.45455);
    }
  }
  switch (color_type) {
    case PNG_COLOR_TYPE_GRAY:
    case PNG_COLOR_TYPE_GRAY_ALPHA: {
      if (color_type1 & PNG_COLOR_MASK_COLOR) {
        png_set_rgb_to_gray(png_ptr, 1, 0.299, 0.587);
      }
    } break;
    case PNG_COLOR_TYPE_PALETTE:
      if (color_type1 != PNG_COLOR_TYPE_PALETTE) {
        png_error(p->png_ptr, "Not Support Output Palette Now");
      }
    case PNG_COLOR_TYPE_RGB:
    case PNG_COLOR_TYPE_RGB_ALPHA:
      if (!(color_type1 & PNG_COLOR_MASK_COLOR)) {
        png_set_gray_to_rgb(png_ptr);
      }
      png_set_bgr(png_ptr);
      break;
  }
  if (!(color_type & PNG_COLOR_MASK_ALPHA)) {
    png_set_strip_alpha(png_ptr);
  }
  if (color_type & PNG_COLOR_MASK_ALPHA &&
      !(color_type1 & PNG_COLOR_MASK_ALPHA)) {
    png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER);
  }
  png_read_update_info(png_ptr, info_ptr);
}
Пример #20
0
 static void saveData(png_structp png_def, png_bytep data, png_size_t size )
 {
     FILE* f = (FILE*) png_get_progressive_ptr(png_def);
     if(fwrite(data, 1, size, f) != (size_t)size)
         throw std::runtime_error("File write error");
 }
Пример #21
0
void decodingFailed(png_structp png, png_const_charp errorMsg)
{
    static_cast<PNGImageDecoder*>(png_get_progressive_ptr(png))->decodingFailed();
    longjmp(png->jmpbuf, 1);
}
Пример #22
0
 /**
  *  Supplied to libpng to call when it has read enough data to determine
  *  bounds.
  */
 static void InfoCallback(png_structp png_ptr, png_infop info_ptr) {
     // png_get_progressive_ptr returns the pointer we set on the png_ptr with
     // png_set_progressive_read_fn
     static_cast<AutoCleanPng*>(png_get_progressive_ptr(png_ptr))->infoCallback();
 }
Пример #23
0
/* Called at the start of the progressive load, once we have image info */
static void
png_info_callback   (png_structp png_read_ptr,
                     png_infop   png_info_ptr)
{
        LoadContext* lc;
        png_uint_32 width, height;
        png_textp png_text_ptr;
        int i, num_texts;
        int color_type;
        gboolean have_alpha = FALSE;
        gchar *icc_profile_base64;
        const gchar *icc_profile_title;
        const gchar *icc_profile;
        png_uint_32 icc_profile_size;
        guint32 retval;
        gint compression_type;

        lc = png_get_progressive_ptr(png_read_ptr);

        if (lc->fatal_error_occurred)
                return;

        if (!setup_png_transformations(lc->png_read_ptr,
                                       lc->png_info_ptr,
                                       lc->error,
                                       &width, &height, &color_type)) {
                lc->fatal_error_occurred = TRUE;
                return;
        }

        /* If we have alpha, set a flag */
        if (color_type & PNG_COLOR_MASK_ALPHA)
                have_alpha = TRUE;
        
        if (lc->size_func) {
                gint w = width;
                gint h = height;
                (* lc->size_func) (&w, &h, lc->notify_user_data);
                
                if (w == 0 || h == 0) {
                        lc->fatal_error_occurred = TRUE;
                        if (lc->error && *lc->error == NULL) {
                                g_set_error_literal (lc->error,
                                                     GDK_PIXBUF_ERROR,
                                                     GDK_PIXBUF_ERROR_FAILED,
                                                     _("Transformed PNG has zero width or height."));
                        }
                        return;
                }
        }

        lc->pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, have_alpha, 8, width, height);

        if (lc->pixbuf == NULL) {
                /* Failed to allocate memory */
                lc->fatal_error_occurred = TRUE;
                if (lc->error && *lc->error == NULL) {
                        g_set_error (lc->error,
                                     GDK_PIXBUF_ERROR,
                                     GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
                                     _("Insufficient memory to store a %lu by %lu image; try exiting some applications to reduce memory usage"),
                                     (gulong) width, (gulong) height);
                }
                return;
        }

        /* Extract text chunks and attach them as pixbuf options */
        
        if (png_get_text (png_read_ptr, png_info_ptr, &png_text_ptr, &num_texts)) {
                for (i = 0; i < num_texts; i++) {
                        gchar *key, *value;

                        if (png_text_to_pixbuf_option (png_text_ptr[i],
                                                       &key, &value)) {
                                gdk_pixbuf_set_option (lc->pixbuf, key, value);
                                g_free (key);
                                g_free (value);
                        }
                }
        }

#if defined(PNG_cHRM_SUPPORTED)
        /* Extract embedded ICC profile */
        retval = png_get_iCCP (png_read_ptr, png_info_ptr,
                               (png_charpp) &icc_profile_title, &compression_type,
                               (png_bytepp) &icc_profile, &icc_profile_size);
        if (retval != 0) {
                icc_profile_base64 = g_base64_encode ((const guchar *) icc_profile, (gsize)icc_profile_size);
                gdk_pixbuf_set_option (lc->pixbuf, "icc-profile", icc_profile_base64);
                g_free (icc_profile_base64);
        }
#endif

        /* Notify the client that we are ready to go */

        if (lc->prepare_func)
                (* lc->prepare_func) (lc->pixbuf, NULL, lc->notify_user_data);

        return;
}
Пример #24
0
 static SkPngNormalDecoder* GetDecoder(png_structp png_ptr) {
     return static_cast<SkPngNormalDecoder*>(png_get_progressive_ptr(png_ptr));
 }
Пример #25
0
 static void InterlacedRowCallback(png_structp png_ptr, png_bytep row, png_uint_32 rowNum, int pass) {
     auto decoder = static_cast<SkPngInterlacedDecoder*>(png_get_progressive_ptr(png_ptr));
     decoder->interlacedRowCallback(row, rowNum, pass);
 }
Пример #26
0
// Called when a row is ready.
static void PNGAPI rowAvailable(png_structp png, png_bytep rowBuffer, png_uint_32 rowIndex, int interlacePass)
{
    static_cast<PNGImageDecoder*>(png_get_progressive_ptr(png))->rowAvailable(rowBuffer, rowIndex, interlacePass);
}
Пример #27
0
// Called when we have obtained the header information (including the size).
static void PNGAPI headerAvailable(png_structp png, png_infop)
{
    static_cast<PNGImageDecoder*>(png_get_progressive_ptr(png))->headerAvailable();
}
Пример #28
0
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);
  }
}
Пример #29
0
// Called when we have completely finished decoding the image.
static void PNGAPI pngComplete(png_structp png, png_infop)
{
    static_cast<PNGImageDecoder*>(png_get_progressive_ptr(png))->pngComplete();
}
Пример #30
0
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);
    }
  }
}