示例#1
0
static PngInfo read_and_update_info(const png_structp png_ptr, const png_infop info_ptr)
{
	png_uint_32 width, height;
	int bit_depth, color_type;

	png_read_info(png_ptr, info_ptr);
	png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, NULL, NULL, NULL);

	// Convert transparency to full alpha
	if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
    {
        png_set_tRNS_to_alpha(png_ptr);
    }

	// Convert grayscale, if needed.
	if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
    {
        png_set_expand_gray_1_2_4_to_8(png_ptr);
    }

	// Convert paletted images, if needed.
	if (color_type == PNG_COLOR_TYPE_PALETTE)
    {
        png_set_palette_to_rgb(png_ptr);
    }

	// Add alpha channel, if there is none (rationale: GL_RGBA is faster than GL_RGB on many GPUs)
	if (color_type == PNG_COLOR_TYPE_PALETTE || color_type == PNG_COLOR_TYPE_RGB)
    {
        png_set_add_alpha(png_ptr, 0xFF, PNG_FILLER_AFTER);
    }

	// Ensure 8-bit packing
	if (bit_depth < 8)
    {
        png_set_packing(png_ptr);
    }
	else if (bit_depth == 16)
    {
        png_set_scale_16(png_ptr);
    }

	png_read_update_info(png_ptr, info_ptr);

	// Read the new color type after updates have been made.
	color_type = png_get_color_type(png_ptr, info_ptr);

	return (PngInfo) {width, height, color_type};
}
示例#2
0
void setformat_rgba8(
    png_structp png, png_infop info,
    int bitdepth, int colortype )
{
    double gamma;
    if( png_get_gAMA( png, info, &gamma ) )
    {
        png_set_gamma( png, 2.2, gamma );
    }
    else
    {
        png_set_gamma( png, 2.2, 0.45455 );
    }
    if( colortype == PNG_COLOR_TYPE_PALETTE )
    {
        png_set_palette_to_rgb( png );
    }
    if( colortype == PNG_COLOR_TYPE_GRAY && bitdepth < 8 )
    {
        png_set_expand_gray_1_2_4_to_8( png );
    }
    if( png_get_valid( png, info, PNG_INFO_tRNS ) )
    {
        png_set_tRNS_to_alpha( png );
    }
    else
    {
        int channels = png_get_channels( png, info );
        if( channels == 1 || channels == 3 )
        {
            png_set_add_alpha( png, 255, PNG_FILLER_AFTER );
        }
    }
    if( colortype == PNG_COLOR_TYPE_GRAY ||
            colortype == PNG_COLOR_TYPE_GRAY_ALPHA )
    {
        png_set_gray_to_rgb( png );
    }
    if( bitdepth == 16 )
    {
        png_set_scale_16( png );
    }
}
示例#3
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);
  }
}
示例#4
0
文件: example.c 项目: Alexpux/ResIL
/* Read a PNG file.  You may want to return an error code if the read
 * fails (depending upon the failure).  There are two "prototypes" given
 * here - one where we are given the filename, and we need to open the
 * file, and the other where we are given an open file (possibly with
 * some or all of the magic bytes read - see comments above).
 */
#ifdef open_file /* prototype 1 */
void read_png(char *file_name)  /* We need to open the file */
{
   png_structp png_ptr;
   png_infop info_ptr;
   unsigned int sig_read = 0;
   png_uint_32 width, height;
   int bit_depth, color_type, interlace_type;
   FILE *fp;

   if ((fp = fopen(file_name, "rb")) == NULL)
      return (ERROR);

#else no_open_file /* prototype 2 */
void read_png(FILE *fp, unsigned int sig_read)  /* File is already open */
{
   png_structp png_ptr;
   png_infop info_ptr;
   png_uint_32 width, height;
   int bit_depth, color_type, interlace_type;
#endif no_open_file /* Only use one prototype! */

   /* Create and initialize the png_struct with the desired error handler
    * functions.  If you want to use the default stderr and longjump method,
    * you can supply NULL for the last three parameters.  We also supply the
    * the compiler header file version, so that we know if the application
    * was compiled with a compatible version of the library.  REQUIRED
    */
   png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,
      png_voidp user_error_ptr, user_error_fn, user_warning_fn);

   if (png_ptr == NULL)
   {
      fclose(fp);
      return (ERROR);
   }

   /* Allocate/initialize the memory for image information.  REQUIRED. */
   info_ptr = png_create_info_struct(png_ptr);
   if (info_ptr == NULL)
   {
      fclose(fp);
      png_destroy_read_struct(&png_ptr, NULL, 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, NULL);
      fclose(fp);
      /* If we get here, we had a problem reading the file */
      return (ERROR);
   }

   /* One of the following I/O initialization methods is REQUIRED */
#ifdef streams /* PNG file I/O method 1 */
   /* Set up the input control if you are using standard C streams */
   png_init_io(png_ptr, fp);

#else no_streams /* PNG file I/O method 2 */
   /* If you are using replacement read functions, instead of calling
    * png_init_io() here you would call:
    */
   png_set_read_fn(png_ptr, (void *)user_io_ptr, user_read_fn);
   /* where user_io_ptr is a structure you want available to the callbacks */
#endif no_streams /* Use only one I/O method! */

   /* If we have already read some of the signature */
   png_set_sig_bytes(png_ptr, sig_read);

#ifdef hilevel
   /*
    * If you have enough memory to read in the entire image at once,
    * and you need to specify only transforms that can be controlled
    * with one of the PNG_TRANSFORM_* bits (this presently excludes
    * quantizing, filling, setting background, and doing gamma
    * adjustment), then you can read the entire image (including
    * pixels) into the info structure with this call:
    */
   png_read_png(png_ptr, info_ptr, png_transforms, NULL);

#else
   /* OK, you're doing it the hard way, with the lower-level functions */

   /* The call to png_read_info() gives us all of the information from the
    * PNG file before the first IDAT (image data chunk).  REQUIRED
    */
   png_read_info(png_ptr, info_ptr);

   png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,
       &interlace_type, NULL, NULL);

   /* Set up the data transformations you want.  Note that these are all
    * optional.  Only call them if you want/need them.  Many of the
    * transformations only work on specific types of images, and many
    * are mutually exclusive.
    */

   /* Tell libpng to strip 16 bit/color files down to 8 bits/color.
    * Use accurate scaling if it's available, otherwise just chop off the
    * low byte.
    */
#ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED
    png_set_scale_16(png_ptr);
#else
   png_set_strip_16(png_ptr);
#endif

   /* Strip alpha bytes from the input data without combining with the
    * background (not recommended).
    */
   png_set_strip_alpha(png_ptr);

   /* Extract multiple pixels with bit depths of 1, 2, and 4 from a single
    * byte into separate bytes (useful for paletted and grayscale images).
    */
   png_set_packing(png_ptr);

   /* Change the order of packed pixels to least significant bit first
    * (not useful if you are using png_set_packing). */
   png_set_packswap(png_ptr);

   /* Expand paletted colors into true RGB triplets */
   if (color_type == PNG_COLOR_TYPE_PALETTE)
      png_set_palette_to_rgb(png_ptr);

   /* Expand grayscale images to the full 8 bits from 1, 2, or 4 bits/pixel */
   if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
      png_set_expand_gray_1_2_4_to_8(png_ptr);

   /* Expand paletted or RGB images with transparency to full alpha channels
    * so the data will be available as RGBA quartets.
    */
   if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
      png_set_tRNS_to_alpha(png_ptr);

   /* Set the background color to draw transparent and alpha images over.
    * It is possible to set the red, green, and blue components directly
    * for paletted images instead of supplying a palette index.  Note that
    * even if the PNG file supplies a background, you are not required to
    * use it - you should use the (solid) application background if it has one.
    */

   png_color_16 my_background, *image_background;

   if (png_get_bKGD(png_ptr, info_ptr, &image_background))
      png_set_background(png_ptr, image_background,
                         PNG_BACKGROUND_GAMMA_FILE, 1, 1.0);
   else
      png_set_background(png_ptr, &my_background,
                         PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0);

   /* Some suggestions as to how to get a screen gamma value
    *
    * Note that screen gamma is the display_exponent, which includes
    * the CRT_exponent and any correction for viewing conditions
    */
   if (/* We have a user-defined screen gamma value */)
   {
      screen_gamma = user-defined screen_gamma;
   }
   /* This is one way that applications share the same screen gamma value */
   else if ((gamma_str = getenv("SCREEN_GAMMA")) != NULL)
示例#5
0
image_file_t *image_from_file( const char *filename ) /* {{{ */
{
	unsigned char header[8];
	image_file_t *image;
	png_structp png_ptr;
	png_infop info_ptr;
	png_bytepp row_pointers;
	int tmp, y;

	image = malloc( sizeof( image_file_t ) );

	FILE *fp = fopen( filename, "rb" );
	if ( !fp )
		die( "Cannot open file '%s'", filename );

	fread( header, 1, 8, fp );
	if ( png_sig_cmp( header, 0, 8 ) )
		die( "File '%s' is not a png", filename );

	png_ptr = png_create_read_struct( PNG_LIBPNG_VER_STRING, NULL, NULL, NULL );
	if ( ! png_ptr )
		die( "png_create_read_struct failed" );

	info_ptr = png_create_info_struct( png_ptr );
	if ( ! info_ptr )
		die( "png_create_info_struct failed" );

	if ( setjmp( png_jmpbuf( png_ptr ) ) )
	{
		/* XXX: handle errors here */
		die( "Error during image initialization" );
	}

	png_init_io( png_ptr, fp );
	png_set_sig_bytes( png_ptr, 8 );
	png_read_info( png_ptr, info_ptr );
	png_set_add_alpha( png_ptr, 255, PNG_FILLER_AFTER );
	png_set_gray_to_rgb( png_ptr );
	png_set_palette_to_rgb( png_ptr );
	png_set_expand( png_ptr );
	png_set_scale_16( png_ptr );

	image->width = png_get_image_width( png_ptr, info_ptr );
	image->height = png_get_image_height( png_ptr, info_ptr );

	tmp = png_set_interlace_handling( png_ptr );

	png_read_update_info( png_ptr, info_ptr );

	tmp = png_get_color_type( png_ptr, info_ptr );
	if ( tmp != PNG_COLOR_TYPE_RGBA )
		die( "Color type is %d, but it should be %d", tmp, PNG_COLOR_TYPE_RGBA );

	tmp = png_get_bit_depth( png_ptr, info_ptr );
	if ( tmp != BITS_PER_CHANNEL )
		die( "Color depth is %d, but is should be %d", tmp, BITS_PER_CHANNEL );
	
	if ( setjmp( png_jmpbuf( png_ptr ) ) )
	{
		/* XXX: handle errors here */
		die( "Error during image read" );
	}

	image->row_pointers = row_pointers =
		malloc( sizeof(png_bytep) * image->height );
	if ( !row_pointers )
		die( "Cannot allocate pointer memory" );

	for ( y = 0; y < image->height; y++ )
	{
		row_pointers[ y ] = malloc( image->width * BYTES_PER_PIXEL );
		if ( !row_pointers[ y ] )
			die( "Cannot allocate pointer memory for row %d", y );
	}

	png_read_image( png_ptr, row_pointers );
	png_read_end( png_ptr, info_ptr );

	fclose( fp );

	png_destroy_read_struct( &png_ptr, &info_ptr, NULL );

	return image;
} /* }}} */
示例#6
0
void PLPNGDecoder::Open(PLDataSource *pDataSrc) {
  png_uint_32 width, height;

  m_png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, user_error_fn, user_warning_fn);
  PLASSERT(m_png_ptr);

  m_info_ptr = png_create_info_struct(m_png_ptr);
  PLASSERT(m_info_ptr);

  png_set_read_fn(m_png_ptr, (void*)pDataSrc, my_read_data);

  /* 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(m_png_ptr, m_info_ptr);

#ifdef DUMP_PNG_DATA
  debugLog("%s", toString(*m_png_ptr).cstr());
#endif

  png_get_IHDR(m_png_ptr, m_info_ptr, &width, &height, &m_bit_depth
              ,&m_color_type, NULL, NULL, NULL);


  if(  (m_color_type != PNG_COLOR_TYPE_RGB_ALPHA) 
   &&  (m_color_type != PNG_COLOR_TYPE_GRAY_ALPHA) 
   && ((m_color_type != PNG_COLOR_TYPE_RGB) || (m_bit_depth < 16))
    ) {

#ifdef PNG_READ_16_TO_8_SUPPORTED
    if(m_bit_depth == 16) {
#ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED
      png_set_scale_16(png_ptr);
#else
      png_set_strip_16(png_ptr);
#endif
    }
#endif

    if(m_color_type == PNG_COLOR_TYPE_PALETTE) {
      png_set_expand(m_png_ptr);
    }
    if(m_bit_depth < 8) {
      png_set_expand(m_png_ptr);
    }
    if(png_get_valid(m_png_ptr, m_info_ptr, PNG_INFO_tRNS)) {
      png_set_expand(m_png_ptr);
    }
    if((m_color_type == PNG_COLOR_TYPE_GRAY) || (m_color_type == PNG_COLOR_TYPE_GRAY_ALPHA)) {
      png_set_gray_to_rgb(m_png_ptr);
    }

    /* set the background color to draw transparent and alpha images over */
    png_color_16 *pBackground;
    png_color     bkgColor = {127, 127, 127};
    if(png_get_bKGD(m_png_ptr, m_info_ptr, &pBackground)) {
      png_set_background(m_png_ptr, pBackground, PNG_BACKGROUND_GAMMA_FILE, 1, 1.0);
      bkgColor.red   = (png_byte)pBackground->red;
      bkgColor.green = (png_byte)pBackground->green;
      bkgColor.blue  = (png_byte)pBackground->blue;

#ifdef DUMP_PNG_DATA
      debugLog("  Background         : (%d,%d,%d)\n", bkgColor.red, bkgColor.green, bkgColor.blue);
#endif
  }

    /* if required set gamma conversion */
    double dGamma;
    if(png_get_gAMA(m_png_ptr, m_info_ptr, &dGamma)) {
      png_set_gamma(m_png_ptr, (double)2.2, dGamma);
    }

    /* after the transformations are registered, update info_ptr data */
    png_read_update_info(m_png_ptr, m_info_ptr);

    png_get_IHDR(m_png_ptr, m_info_ptr, &width, &height, &m_bit_depth
                ,&m_color_type, NULL, NULL, NULL);

  }

  PLPixelFormat pf;
  switch(m_color_type) {
    case PNG_COLOR_TYPE_RGB:  
      pf = PLPixelFormat::R8G8B8;
      break;
    case PNG_COLOR_TYPE_RGB_ALPHA:      
      pf = PLPixelFormat::A8R8G8B8;
      break;
    case PNG_COLOR_TYPE_GRAY:
      pf = PLPixelFormat::L8;
      break;
    case PNG_COLOR_TYPE_GRAY_ALPHA:      
      png_set_gray_to_rgb(m_png_ptr);
      png_set_expand(m_png_ptr);      
      pf = PLPixelFormat::A8R8G8B8;
      break;
    case PNG_COLOR_TYPE_PALETTE:
      if(m_bit_depth != 16) {
        pf = PLPixelFormat::I8;
      } else { // 16-bit palette image
        png_set_expand(m_png_ptr);        
        pf = PLPixelFormat::R8G8B8;
      }
      break;
  }

  if((pf.GetBitsPerPixel() == 32) || (pf.GetBitsPerPixel() == 24)) { 
    png_set_bgr(m_png_ptr);
  }

  SetBmpInfo(PLPoint(width, height), PLPoint(0,0), pf);

  png_uint_32 XRes, YRes;
  int UnitType;
  png_get_pHYs(m_png_ptr, m_info_ptr, &XRes, &YRes, &UnitType);
  if(UnitType == PNG_RESOLUTION_METER) {
    m_Resolution = PLPoint(int (XRes/39.37f+0.5), int (YRes/39.37f+0.5));
  }
}
示例#7
0
bool
loadPngFile(
    IMAGE_T* image,
    FILE *file)
{
    png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,
                                                 NULL,
                                                 NULL,
                                                 NULL);

    if (png_ptr == NULL)
    {
        return false;
    }

    png_infop info_ptr = png_create_info_struct(png_ptr);

    if (info_ptr == NULL)
    {
        png_destroy_read_struct(&png_ptr, 0, 0);
        return false;
    }

    if (setjmp(png_jmpbuf(png_ptr)))
    {
        png_destroy_read_struct(&png_ptr, &info_ptr, 0);
        return false;
    }

    //---------------------------------------------------------------------

    png_init_io(png_ptr, file);

    png_read_info(png_ptr, info_ptr);

    //---------------------------------------------------------------------

    png_byte colour_type = png_get_color_type(png_ptr, info_ptr);
    png_byte bit_depth = png_get_bit_depth(png_ptr, info_ptr);

    VC_IMAGE_TYPE_T type = VC_IMAGE_RGB888;

    if (colour_type & PNG_COLOR_MASK_ALPHA)
    {
        type = VC_IMAGE_RGBA32;
    }

    initImage(image,
              type,
              png_get_image_width(png_ptr, info_ptr),
              png_get_image_height(png_ptr, info_ptr),
              false);

    //---------------------------------------------------------------------

    double gamma = 0.0;

    if (png_get_gAMA(png_ptr, info_ptr, &gamma))
    {
        png_set_gamma(png_ptr, 2.2, gamma);
    }

    //---------------------------------------------------------------------

    if (colour_type == PNG_COLOR_TYPE_PALETTE) 
    {
        png_set_palette_to_rgb(png_ptr);
    }

    if ((colour_type == PNG_COLOR_TYPE_GRAY) && (bit_depth < 8))
    {
        png_set_expand_gray_1_2_4_to_8(png_ptr);
    }

    if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
    {
        png_set_tRNS_to_alpha(png_ptr);
    }

    if (bit_depth == 16)
    {
#ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED
        png_set_scale_16(png_ptr);
#else
        png_set_strip_16(png_ptr);
#endif
    }

    if (colour_type == PNG_COLOR_TYPE_GRAY ||
        colour_type == PNG_COLOR_TYPE_GRAY_ALPHA)
    {
        png_set_gray_to_rgb(png_ptr);
    }

    //---------------------------------------------------------------------

    png_read_update_info(png_ptr, info_ptr);

    //---------------------------------------------------------------------

    png_bytepp row_pointers = malloc(image->height * sizeof(png_bytep));

    png_uint_32 j = 0;
    for (j = 0 ; j < image->height ; ++j)
    {
        row_pointers[j] = image->buffer + (j * image->pitch);
    }

    //---------------------------------------------------------------------

    png_read_image(png_ptr, row_pointers);

    //---------------------------------------------------------------------

    free(row_pointers);

    png_destroy_read_struct(&png_ptr, &info_ptr, 0);

    return true;
}
示例#8
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 led to an error.
        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_scale_16(png_ptr);

    qcms_data_type inType;
    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()) */
    /*---------------------------------------------------------------*/

    // This code is currently unused, but it will be needed for bug 517713.
#if 0
    int32_t 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;
        }
    }
#endif

    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 = 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 *)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 < INT32_MAX / (width * channels))
            decoder->interlacebuf = (uint8_t *)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;
}
示例#9
0
static vita2d_texture *_vita2d_load_PNG_generic(const void *io_ptr, png_rw_ptr read_data_fn)
{
	png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
	if (png_ptr == NULL) {
		goto error_create_read;
	}

	png_infop info_ptr = png_create_info_struct(png_ptr);
	if (info_ptr == NULL) {
		goto error_create_info;
	}

	png_bytep *row_ptrs = NULL;

	if (setjmp(png_jmpbuf(png_ptr))) {
		png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)0);
		if (row_ptrs != NULL)
			free(row_ptrs);
		return NULL;
	}

	png_set_read_fn(png_ptr, (png_voidp)io_ptr, read_data_fn);
	png_set_sig_bytes(png_ptr, PNG_SIGSIZE);
	png_read_info(png_ptr, info_ptr);

	unsigned int width, height;
	int bit_depth, color_type;

	png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth,
		&color_type, NULL, NULL, NULL);

	if ((color_type == PNG_COLOR_TYPE_PALETTE && bit_depth <= 8)
		|| (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
		|| png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)
		|| (bit_depth == 16)) {
			png_set_expand(png_ptr);
	}

	if (bit_depth == 16)
		png_set_scale_16(png_ptr);

	if (bit_depth == 8 && color_type == PNG_COLOR_TYPE_RGB)
		png_set_filler(png_ptr, 0xFF, PNG_FILLER_AFTER);

	if (color_type == PNG_COLOR_TYPE_GRAY ||
	    color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
		png_set_gray_to_rgb(png_ptr);

	if (color_type == PNG_COLOR_TYPE_PALETTE) {
		png_set_palette_to_rgb(png_ptr);
		png_set_filler(png_ptr, 0xFF, PNG_FILLER_AFTER);
	}

	if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
		png_set_expand_gray_1_2_4_to_8(png_ptr);

	if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
		png_set_tRNS_to_alpha(png_ptr);

	if (bit_depth < 8)
		png_set_packing(png_ptr);

	png_read_update_info(png_ptr, info_ptr);

	row_ptrs = (png_bytep *)malloc(sizeof(png_bytep) * height);
	if (!row_ptrs)
		goto error_alloc_rows;

	vita2d_texture *texture = vita2d_create_empty_texture(width, height);
	if (!texture)
		goto error_create_tex;

	void *texture_data = vita2d_texture_get_datap(texture);
	unsigned int stride = vita2d_texture_get_stride(texture);

	int i;
	for (i = 0; i < height; i++) {
		row_ptrs[i] = (png_bytep)(texture_data + i*stride);
	}

	png_read_image(png_ptr, row_ptrs);

	png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)0);
	free(row_ptrs);

	return texture;

error_create_tex:
	free(row_ptrs);
error_alloc_rows:
	png_destroy_info_struct(png_ptr, &info_ptr);
error_create_info:
	png_destroy_read_struct(&png_ptr, (png_infopp)0, (png_infopp)0);
error_create_read:
	return NULL;
}
示例#10
0
文件: img-png.c 项目: z24/skippy-xd
pictw_t *
spng_read(session_t *ps, const char *path) {
	assert(path);

	char sig[SPNG_SIGBYTES] = "";
	pictw_t *pictw = NULL;
	png_structp png_ptr = NULL;
	png_infop info_ptr = NULL;
	FILE *fp = fopen(path, "rb");
	bool need_premultiply = false;
	if (unlikely(!fp)) {
		printfef("(\"%s\"): Failed to open file.", path);
		goto spng_read_end;
	}
	if (unlikely(SPNG_SIGBYTES != fread(&sig, 1, SPNG_SIGBYTES, fp))) {
		printfef("(\"%s\"): Failed to read %d-byte signature.",
				path, SPNG_SIGBYTES);
		goto spng_read_end;
	}
	if (unlikely(png_sig_cmp((png_bytep) sig, 0, SPNG_SIGBYTES))) {
		printfef("(\"%s\"): PNG signature invalid.", path);
		goto spng_read_end;
	}
	png_ptr = allocchk(png_create_read_struct(PNG_LIBPNG_VER_STRING,
				NULL, NULL, NULL));
	info_ptr = allocchk(png_create_info_struct(png_ptr));
	if (setjmp(png_jmpbuf(png_ptr)))
		goto spng_read_end;
	png_init_io(png_ptr, fp);
	png_set_sig_bytes(png_ptr, SPNG_SIGBYTES);
	png_read_info(png_ptr, info_ptr);
	png_uint_32 width = 0, height = 0;

	// Set transformations
	int bit_depth = 0, color_type = 0;
	{
		int interlace_type = 0;
		png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth,
				&color_type, &interlace_type, NULL, NULL);

		// Scale or strip 16-bit colors
		if (bit_depth == 16) {
			printfdf("(\"%s\"): Scaling 16-bit colors.", path);
#if PNG_LIBPNG_VER >= 10504
			png_set_scale_16(png_ptr);
#else
			png_set_strip_16(png_ptr);
#endif
			bit_depth = 8;
		}

		/* if (bit_depth < 8)
			png_set_packing(png_ptr); */

		// No idea why this is needed...
		png_set_bgr(png_ptr);

		// Convert palette to RGB
		if (color_type == PNG_COLOR_TYPE_PALETTE) {
			printfdf("(\"%s\"): Converting palette PNG to RGB.", path);
			png_set_palette_to_rgb(png_ptr);
			color_type = PNG_COLOR_TYPE_RGB;
		}

		if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
			printfdf("(\"%s\"): Converting rDNS to full alpha.", path);
			png_set_tRNS_to_alpha(png_ptr);
		}

		if (color_type == PNG_COLOR_TYPE_GRAY
				|| PNG_COLOR_TYPE_GRAY_ALPHA == color_type) {
			printfdf("(\"%s\"): Converting gray (+ alpha) PNG to RGB.", path);
			png_set_gray_to_rgb(png_ptr);
			if (PNG_COLOR_TYPE_GRAY == color_type)
				color_type = PNG_COLOR_TYPE_RGB;
			else
				color_type = PNG_COLOR_TYPE_RGB_ALPHA;
		}

		/*
		if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) {
			printfdf("(\"%s\"): Converting 1/2/4 bit gray PNG to 8-bit.", path);
#if PNG_LIBPNG_VER >= 10209
			png_set_expand_gray_1_2_4_to_8(png_ptr);
#else
			png_set_gray_1_2_4_to_8(png_ptr);
#endif
			bit_depth = 8;
		}
		*/

		// Somehow XImage requires 24-bit visual to use 32 bits per pixel
		if (color_type == PNG_COLOR_TYPE_RGB) {
			printfdf("(\"%s\"): Appending filler alpha values.", path);
			png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER);
		}

		// Premultiply alpha
		if (PNG_COLOR_TYPE_RGB_ALPHA == color_type) {
#if PNG_LIBPNG_VER >= 10504
			png_set_alpha_mode(png_ptr, PNG_ALPHA_STANDARD, 1.0);
#else
			need_premultiply = true;
#endif
		}

		/*
		int number_passes = 1;
#ifdef PNG_READ_INTERLACING_SUPPORTED
		number_passes = png_set_interlace_handling(png_ptr);
#endif */

		if (PNG_INTERLACE_NONE != interlace_type)
			png_set_interlace_handling(png_ptr);
	}

	png_read_update_info(png_ptr, info_ptr);

	int depth = 0;
	png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth,
				&color_type, NULL, NULL, NULL);
	switch (color_type) {
		case PNG_COLOR_TYPE_GRAY:       depth = 1 * bit_depth; break;
		case PNG_COLOR_TYPE_RGB:        depth = 3 * bit_depth; break;
		case PNG_COLOR_TYPE_RGB_ALPHA:  depth = 4 * bit_depth; break;
		default:                        assert(0); break;
	}

	// Read data and fill to Picture
	{
		int rowbytes = png_get_rowbytes(png_ptr, info_ptr);
		png_bytep row_pointers[height];
		memset(row_pointers, 0, sizeof(row_pointers));
		row_pointers[0] = png_malloc(png_ptr, rowbytes * height);
		for (int row = 1; row < height; row++)
			row_pointers[row] = row_pointers[row - 1] + rowbytes;
		png_read_image(png_ptr, row_pointers);
		if (need_premultiply)
			for (int row = 0; row < height; row++)
				simg_data32_premultiply(row_pointers[row], width);
		if (unlikely(!(pictw = simg_data_to_pictw(ps, width, height, depth,
							row_pointers[0], rowbytes)))) {
			printfef("(\"%s\"): Failed to create Picture.", path);
			goto spng_read_end;
		}
	}

spng_read_end:
	if (png_ptr)
		png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
	if (fp)
		fclose(fp);

	return pictw;
}
示例#11
0
void* PNG_decode(JNIEnv* env, PatchHeadInputStream* patch_head_input_stream, bool partially)
{
  PNG *png = NULL;
  png_structp png_ptr = NULL;
  png_infop info_ptr = NULL;
  bool apng;
  unsigned int width;
  unsigned int height;
  int color_type;
  int bit_depth;
  bool is_opaque;
  unsigned char* buffer = NULL;
  unsigned int frame_count = 0;
  bool hide_first_frame = false;
  PNG_FRAME_INFO* frame_info_array = NULL;
  int i;

  png = (PNG *) malloc(sizeof(PNG));
  if (png == NULL) {
    WTF_OM;
    close_patch_head_input_stream(get_env(), patch_head_input_stream);
    destroy_patch_head_input_stream(get_env(), &patch_head_input_stream);
    return NULL;
  }

  png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, &user_error_fn, &user_warn_fn);
  if (png_ptr == NULL) {
    free(png);
    png = NULL;
    close_patch_head_input_stream(get_env(), patch_head_input_stream);
    destroy_patch_head_input_stream(get_env(), &patch_head_input_stream);
    return NULL;
  }

  info_ptr = png_create_info_struct(png_ptr);
  if (info_ptr == NULL) {
    png_destroy_read_struct(&png_ptr, NULL, NULL);
    free(png);
    png = NULL;
    close_patch_head_input_stream(get_env(), patch_head_input_stream);
    destroy_patch_head_input_stream(get_env(), &patch_head_input_stream);
    return NULL;
  }

  if (setjmp(png_jmpbuf(png_ptr))) {
    LOGE(EMSG("Error in png decode"));
    free_frame_info_array(frame_info_array, frame_count);
    frame_info_array = NULL;
    free(buffer);
    buffer = NULL;
    png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
    free(png);
    png = NULL;
    close_patch_head_input_stream(get_env(), patch_head_input_stream);
    destroy_patch_head_input_stream(get_env(), &patch_head_input_stream);
    return NULL;
  }

  // Set custom read function
  png_set_read_fn(png_ptr, patch_head_input_stream, &user_read_fn);

  // Get png info
  png_read_info(png_ptr, info_ptr);

  // Check apng
  if (png_get_valid(png_ptr, info_ptr, PNG_INFO_acTL)) {
    apng = true;
  } else {
    apng = false;
  }

  // PNG info
  width = png_get_image_width(png_ptr, info_ptr);
  height = 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);

  // Create buffer
  buffer = (unsigned char*) malloc(width * height * 4);
  if (buffer == NULL) {
    WTF_OM;
    png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
    free(png);
    png = NULL;
    close_patch_head_input_stream(get_env(), patch_head_input_stream);
    destroy_patch_head_input_stream(get_env(), &patch_head_input_stream);
    return NULL;
  }

  if (apng) {
    // Get frame count
    frame_count = png_get_num_frames(png_ptr, info_ptr);
    hide_first_frame = png_get_first_frame_is_hidden(png_ptr, info_ptr);
    if (hide_first_frame) {
      frame_count--;
    }

    // Create frame info array
    frame_info_array = (PNG_FRAME_INFO*) calloc(frame_count, sizeof(PNG_FRAME_INFO));
    if (frame_info_array == NULL) {
      WTF_OM;
      free(buffer);
      buffer = NULL;
      png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
      free(png);
      png = NULL;
      close_patch_head_input_stream(get_env(), patch_head_input_stream);
      destroy_patch_head_input_stream(get_env(), &patch_head_input_stream);
      return NULL;
    }
  }

  // Configure to ARGB
  png_set_expand(png_ptr);
  if (bit_depth == 16) {
    png_set_scale_16(png_ptr);
  }
  if (color_type == PNG_COLOR_TYPE_GRAY ||
      color_type == PNG_COLOR_TYPE_GRAY_ALPHA) {
    png_set_gray_to_rgb(png_ptr);
  }
  if (!(color_type & PNG_COLOR_MASK_ALPHA)) {
    is_opaque = true;
    png_set_add_alpha(png_ptr, 0xff, PNG_FILLER_AFTER);
  } else {
    is_opaque = false;
  }

  if (apng) {
    if (hide_first_frame) {
      // Skip first frame
      read_image(png_ptr, buffer, width, height);
    }

    // Read first frame
    read_frame(png_ptr, info_ptr, frame_info_array);
    // Fix dop
    if (frame_info_array->dop == PNG_DISPOSE_OP_PREVIOUS) {
      frame_info_array->dop = PNG_DISPOSE_OP_BACKGROUND;
    }

    if (!partially || frame_count == 1) {
      // Read all frame
      for (i = 1; i < frame_count; read_frame(png_ptr, info_ptr, frame_info_array + i++));

      // Generate pop
      generate_pop(frame_info_array, frame_count);

      // End read
      png_read_end(png_ptr, info_ptr);
      png_destroy_read_struct(&png_ptr, &info_ptr, NULL);

      // Close input stream
      close_patch_head_input_stream(env, patch_head_input_stream);
      destroy_patch_head_input_stream(env, &patch_head_input_stream);

      png->partially = false;
      png->png_ptr = NULL;
      png->info_ptr = NULL;
      png->patch_head_input_stream = NULL;
    } else {
      png->partially = true;
      png->png_ptr = png_ptr;
      png->info_ptr = info_ptr;
      png->patch_head_input_stream = patch_head_input_stream;
    }

    // Fill PNG
    png->width = width;
    png->height = height;
    png->is_opaque = is_opaque;
    png->buffer = buffer;
    png->apng = true;
    png->buffer_index = -1;
    png->frame_info_array = frame_info_array;
    png->frame_count = frame_count;
    png->backup = NULL;

    // Render first frame
    PNG_advance(png);
  } else {
    read_image(png_ptr, buffer, width, height);

    // End read
    png_read_end(png_ptr, info_ptr);
    png_destroy_read_struct(&png_ptr, &info_ptr, NULL);

    // Close input stream
    close_patch_head_input_stream(env, patch_head_input_stream);
    destroy_patch_head_input_stream(env, &patch_head_input_stream);

    // Fill PNG
    png->width = width;
    png->height = height;
    png->buffer = buffer;
    png->apng = false;
    png->buffer_index = 0;
    png->frame_info_array = NULL;
    png->frame_count = 0;
    png->backup = NULL;
    png->partially = false;
    png->png_ptr = NULL;
    png->info_ptr = NULL;
    png->patch_head_input_stream = NULL;
  }

  return png;
}
示例#12
0
	bool PNG::Decode (Resource *resource, ImageBuffer *imageBuffer) {
		
		unsigned char png_sig[PNG_SIG_SIZE];
		png_structp png_ptr;
		png_infop info_ptr;
		png_uint_32 width, height;
		int bit_depth, color_type, interlace_type;
		
		FILE_HANDLE *file = NULL;
		
		if (resource->path) {
			
			file = lime::fopen (resource->path, "rb");
			if (!file) return false;
			
			int read = lime::fread (png_sig, PNG_SIG_SIZE, 1, file);
			if (png_sig_cmp (png_sig, 0, PNG_SIG_SIZE)) {
				
				lime::fclose (file);
				return false;
				
			}
			
		} else {
			
			memcpy (png_sig, resource->data->Bytes (), PNG_SIG_SIZE);
			
			if (png_sig_cmp (png_sig, 0, PNG_SIG_SIZE)) {
				
				return false;
				
			}
			
		}
		
		if ((png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL)) == NULL) {
			
			if (file) lime::fclose (file);
			return false;
			
		}
		
		if ((info_ptr = png_create_info_struct (png_ptr)) == NULL) {
			
			png_destroy_read_struct (&png_ptr, (png_infopp)NULL, (png_infopp)NULL);
			if (file) lime::fclose (file);
			return false;
			
		}
		
		// sets the point which libpng will jump back to in the case of an error
		if (setjmp (png_jmpbuf (png_ptr))) {
			
			png_destroy_read_struct (&png_ptr, &info_ptr, (png_infopp)NULL);
			if (file) lime::fclose (file);
			return false;
			
		}
		
		if (file) {
			
			if (file->isFile ()) {
				
				png_init_io (png_ptr, file->getFile ());
				png_set_sig_bytes (png_ptr, PNG_SIG_SIZE);
				
			} else {
				
				ByteArray data = ByteArray (resource->path);
				ReadBuffer buffer (data.Bytes (), data.Size ());
				png_set_read_fn (png_ptr, &buffer, user_read_data_fn);
				
			}
			
		} else {
			
			ReadBuffer buffer (resource->data->Bytes (), resource->data->Size ());
			png_set_read_fn (png_ptr, &buffer, user_read_data_fn);
			
		}
		
		png_read_info (png_ptr, info_ptr);
		png_get_IHDR (png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, NULL, NULL);
		
		//bool has_alpha = (color_type == PNG_COLOR_TYPE_GRAY_ALPHA || color_type == PNG_COLOR_TYPE_RGB_ALPHA || png_get_valid (png_ptr, info_ptr, PNG_INFO_tRNS));
		
		png_set_expand (png_ptr);
		
		png_set_filler (png_ptr, 0xff, PNG_FILLER_AFTER);
		//png_set_gray_1_2_4_to_8 (png_ptr);
		png_set_palette_to_rgb (png_ptr);
		png_set_gray_to_rgb (png_ptr);
		
		if (bit_depth < 8) {
			
			png_set_packing (png_ptr);
			
		} else if (bit_depth == 16) {
			
			png_set_scale_16 (png_ptr);
			
		}
		
		//png_set_bgr (png_ptr);
		
		int bpp = 4;
		const unsigned int stride = width * bpp;
		imageBuffer->Resize (width, height, bpp);
		unsigned char *bytes = imageBuffer->data->Bytes ();
		
		int number_of_passes = png_set_interlace_handling (png_ptr);
		
		for (int pass = 0; pass < number_of_passes; pass++) {
			
			for (int i = 0; i < height; i++) {
				
				png_bytep anAddr = (png_bytep)(bytes + i * stride);
				png_read_rows (png_ptr, (png_bytepp) &anAddr, NULL, 1);
				
			}
			
		}
		
		png_read_end (png_ptr, NULL);
		png_destroy_read_struct (&png_ptr, &info_ptr, (png_infopp)NULL);
		
		if (file) lime::fclose (file);
		
		return true;
		
	}
示例#13
0
PNGImage::PNGImage(const char *full_file_path)
{
    FILE *file = fopen(full_file_path, "rb");

    if(file == nullptr)
    {
        throw ReadFileException("PNGImage", "PNG file specified is not valid.");
    }

    png_byte png_header[8];

    fread(png_header, 1u, 8u, file);

    if(ferror(file) != 0 || feof(file) != 0)
    {
        fclose(file);
        throw ReadFileException("PNGImage", "Cannot read the PNG file.");
    }

    if(png_sig_cmp(png_header, 0, 8) != 0)
    {
        fclose(file);
        throw ReadFileException("PNGImage", "Please select a valid PNG file.");
    }

    png_structp png_read_struct = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr);

    if(png_read_struct == nullptr)
    {
        fclose(file);
        throw ReadFileException("PNGImage", "Cannot initialize PNG read struct.");
    }

    png_infop png_info_struct = png_create_info_struct(png_read_struct);

    if(png_info_struct == nullptr)
    {
        png_destroy_read_struct(&png_read_struct, nullptr, nullptr);
        fclose(file);
        throw ReadFileException("PNGImage", "Cannot initialize PNG info struct.");
    }

    png_infop png_end_struct = png_create_info_struct(png_read_struct);

    if(png_info_struct == nullptr)
    {
        png_destroy_read_struct(&png_read_struct, &png_info_struct, nullptr);
        fclose(file);
        throw ReadFileException("PNGImage", "Cannot initialize PNG info struct.");
    }

    if(setjmp(png_jmpbuf(png_read_struct)))
    {
        png_destroy_read_struct(&png_read_struct, &png_info_struct, &png_end_struct);
        fclose(file);
        throw ReadFileException("PNGImage", "Error in libpng.");
    }

    png_init_io(png_read_struct, file);
    png_set_sig_bytes(png_read_struct, 8);
    png_read_info(png_read_struct, png_info_struct);

    int bit_depth, color_type;

    png_get_IHDR(png_read_struct, png_info_struct, &width, &height, &bit_depth, &color_type, nullptr, nullptr, nullptr);

    if(bit_depth == 16)
    {
        png_set_scale_16(png_read_struct);
        bit_depth = 8;
    }

    switch(color_type)
    {
        case PNG_COLOR_TYPE_RGB:
            color_space = GL_RGB;
            break;
        case PNG_COLOR_TYPE_RGB_ALPHA:
            color_space = GL_RGBA;
            break;
        default:
            png_destroy_read_struct(&png_read_struct, &png_info_struct, &png_end_struct);
            fclose(file);
            throw ReadFileException("PNGImage", "Unsupported color space.");
    }

    int row_bytes = png_get_rowbytes(png_read_struct, png_info_struct);

    row_bytes += 3 - ((row_bytes-1) % 4);

    output_buffer.reset(new (std::nothrow)png_byte[row_bytes * height * sizeof(png_byte) + 15]);

    if(output_buffer.get() == nullptr)
    {
        png_destroy_read_struct(&png_read_struct, &png_info_struct, &png_end_struct);
        fclose(file);
        throw ReadFileException("PNGImage", "Cannot allocate required memory.");
    }

    std::unique_ptr<png_byte *> row_pointers(new png_byte *[height]);

    if(row_pointers.get() == nullptr)
    {
        png_destroy_read_struct(&png_read_struct, &png_info_struct, &png_end_struct);
        fclose(file);
        throw ReadFileException("PNGImage", "Cannot allocate required memory.");
    }

    png_byte **_row_pointers = row_pointers.get();
    unsigned char *_output_buffer = output_buffer.get();

    for(unsigned int i = 0; i < height; ++i)
    {
        _row_pointers[height - 1 - i] = _output_buffer + i * row_bytes;
    }

    png_read_image(png_read_struct, _row_pointers);
    png_destroy_read_struct(&png_read_struct, &png_info_struct, &png_end_struct);
    fclose(file);
}