int R2Image::
ReadPNG(const char *filename)
{
  // Open file
  FILE *fp = fopen(filename, "rb");
  if (!fp) {
    fprintf(stderr, "Unable to open PNG file %s\n", filename);
    return 0;
   }

  // Create and initialize the png_struct 
  png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
  if (png_ptr == NULL) {
    fclose(fp);
    return 0;
  }

  // Allocate/initialize the memory for image information. 
  png_infop info_ptr = png_create_info_struct(png_ptr);
  if (info_ptr == NULL) {
    fclose(fp);
    png_destroy_read_struct(&png_ptr, NULL, NULL);
    return 0;
  }

  // Set up the input control if you are using standard C streams 
  png_init_io(png_ptr, fp);

  // Read the png info 
  png_read_info(png_ptr, info_ptr);

  // Extract image info 
  png_byte color_type = png_get_color_type(png_ptr, info_ptr);
  width = png_get_image_width(png_ptr, info_ptr);
  height = png_get_image_height(png_ptr, info_ptr);

  // Set nchannels
  nchannels = 0;
  if (color_type == PNG_COLOR_TYPE_GRAY) nchannels = 1;
  else if (color_type == PNG_COLOR_TYPE_GRAY_ALPHA) nchannels = 2;
  else if (color_type == PNG_COLOR_TYPE_RGB) nchannels = 3;
  else if (color_type == PNG_COLOR_TYPE_RGB_ALPHA) nchannels = 4;
  else { 
    fclose(fp);
    png_destroy_read_struct(&png_ptr, NULL, NULL);
    return 0;
  }

  // Allocate the pixels and row pointers 
  int rowsize = png_get_rowbytes(png_ptr, info_ptr);
  assert(rowsize >= width * nchannels);
  png_bytep buffer = new unsigned char [ height * rowsize * png_sizeof(png_bytep) ]; 
  png_bytep *row_pointers = (png_bytep *) png_malloc(png_ptr, height * png_sizeof(png_bytep));
  for (int i = 0; i < height; i++) row_pointers[i] = &buffer[ (height - i - 1) * rowsize ];

  // Read the pixels 
  png_read_image(png_ptr, row_pointers);

  // Finish reading 
  png_read_end(png_ptr, info_ptr);

  // Copy pixels from temporary buffer
  pixels = new double [ height * width * nchannels ];
  for (int j = 0; j < height; j++) {
    for (int i = 0; i < width * nchannels; i++) {
      pixels[j*width*nchannels + i] = buffer[j*width*nchannels + i] / 255.0;
    }
  }

  // Free the row pointers 
  png_free(png_ptr, row_pointers);

  // Clean up after the read, and free any memory allocated  
  png_destroy_read_struct(&png_ptr, &info_ptr, NULL);

  // Close the file 
  fclose(fp);

  // Delete temporary buffer
  delete [] buffer;

  // Return success 
  return 1;
}
 ~PNGAutoClean() {
     png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL);
 }
Exemple #3
0
struct gl_texture_t *ReadPNGFromFile (const char *filename) 
{
	
	FILE *fp;
	png_byte magic[8];
	
	/* Open image file */
	fp = fopen (filename, "rb");
	if (!fp) {
		fprintf (stderr, "error: couldn't open \"%s\"!\n", filename);
		return NULL;
	}
	
	/* Read magic number */
	fread (magic, 1, sizeof (magic), fp);
	
	/* Check for valid magic number */
	if (!png_check_sig (magic, sizeof (magic))) {
		fprintf (stderr, "error: \"%s\" is not a valid PNG image!\n",filename);
		fclose (fp);
		return NULL;
	}
	
	png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
	if (!png_ptr) {
		fclose (fp);
		return NULL;
	}
	
	/* Create a png info struct */
	png_infop info_ptr = png_create_info_struct(png_ptr);
	if (!info_ptr) {
		fclose (fp);
		png_destroy_read_struct (&png_ptr, NULL, NULL);
		return NULL;
	}
	
	/* Create our OpenGL texture object */
	struct gl_texture_t *texinfo = (struct gl_texture_t *) malloc (sizeof (struct gl_texture_t));
	
	/* Initialize the setjmp for returning properly after a libpng
     error occured */
	if (setjmp (png_jmpbuf(png_ptr))) {
		fclose (fp);
		png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
		
		if (texinfo) {
			if (texinfo->texels)
				free (texinfo->texels);      
			free (texinfo);
		}    
		return NULL;
	}
	
	/* Setup libpng for using standard C fread() function
     with our FILE pointer */
	png_init_io (png_ptr, fp);
	
	/* Tell libpng that we have already read the magic number */
	png_set_sig_bytes (png_ptr, sizeof (magic));
	
	/* Read png info */
	png_read_info (png_ptr, info_ptr);
	
	int bit_depth, color_type;
	
	/* Get some usefull information from header */
	bit_depth = png_get_bit_depth (png_ptr, info_ptr);
	color_type = png_get_color_type (png_ptr, info_ptr);
	
	/* Convert index color images to RGB images */
	if (color_type == PNG_COLOR_TYPE_PALETTE)
		png_set_palette_to_rgb (png_ptr);
	
	/* Convert 1-2-4 bits grayscale images to 8 bits
     grayscale. */
	if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
		png_set_gray_1_2_4_to_8 (png_ptr);
	
	if (png_get_valid (png_ptr, info_ptr, PNG_INFO_tRNS))
		png_set_tRNS_to_alpha (png_ptr);
	if (bit_depth == 16)
		png_set_strip_16 (png_ptr);
	else if (bit_depth < 8)
		png_set_packing (png_ptr);
	
	/* Update info structure to apply transformations */
	png_read_update_info (png_ptr, info_ptr);
	
	/* Retrieve updated information */
	png_uint_32 w, h;
	
	png_get_IHDR (png_ptr, info_ptr, &w, &h, &bit_depth,&color_type, NULL, NULL, NULL);
	texinfo->width = w;
	texinfo->height = h;
	switch (color_type) {
		case PNG_COLOR_TYPE_GRAY:
			texinfo->format = GL_LUMINANCE;
			texinfo->internalFormat = 1;
			break;
			
		case PNG_COLOR_TYPE_GRAY_ALPHA:
			texinfo->format = GL_LUMINANCE_ALPHA;
			texinfo->internalFormat = 2;
			break;
			
		case PNG_COLOR_TYPE_RGB:
			texinfo->format = GL_RGB;
			texinfo->internalFormat = 3;
			break;
			
		case PNG_COLOR_TYPE_RGB_ALPHA:
			texinfo->format = GL_RGBA;
			texinfo->internalFormat = 4;
			break;
			
		default:
			/* Badness */
			break;
	}
	/* We can now allocate memory for storing pixel data */
	texinfo->texels = (GLubyte *)malloc (sizeof (GLubyte)*texinfo->width*texinfo->height*texinfo->internalFormat);
	
	png_bytep *row_pointers;
	
	/* Setup a pointer array.  Each one points at the begening of a row. */
	row_pointers = (png_bytep *)malloc (sizeof (png_bytep) * texinfo->height);
	
	for (int i = 0; i < texinfo->height; ++i) 
		row_pointers[i] = (png_bytep)(texinfo->texels + ((texinfo->height - (i + 1)) * texinfo->width * texinfo->internalFormat));
	
	/* Read pixel data using row pointers */
	png_read_image(png_ptr, row_pointers);
	
	/* We don't need row pointers anymore */
	free (row_pointers);
	
	return(texinfo);
	
}
Exemple #4
0
/* Read a PNG file.  You may want to return an error code if the read
 * fails (depending upon the failure).  There are two "prototypes" given
 * here - one where we are given the filename, and we need to open the
 * file, and the other where we are given an open file (possibly with
 * some or all of the magic bytes read - see comments above).
 */
#ifdef open_file /* prototype 1 */
void read_png(char *file_name)  /* We need to open the file */
{
   png_structp png_ptr;
   png_infop info_ptr;
   unsigned int sig_read = 0;
   png_uint_32 width, height;
   int bit_depth, color_type, interlace_type;
   FILE *fp;

   if ((fp = fopen(file_name, "rb")) == NULL)
      return (ERROR);
#else no_open_file /* prototype 2 */
void read_png(FILE *fp, unsigned int sig_read)  /* file is already open */
{
   png_structp png_ptr;
   png_infop info_ptr;
   png_uint_32 width, height;
   int bit_depth, color_type, interlace_type;
#endif no_open_file /* only use one prototype! */

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

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

   /* Allocate/initialize the memory for image information.  REQUIRED. */
   info_ptr = png_create_info_struct(png_ptr);
   if (info_ptr == NULL)
   {
      fclose(fp);
      png_destroy_read_struct(&png_ptr, png_infopp_NULL, png_infopp_NULL);
      return (ERROR);
   }

   /* Set error handling if you are using the setjmp/longjmp method (this is
    * the normal method of doing things with libpng).  REQUIRED unless you
    * set up your own error handlers in the png_create_read_struct() earlier.
    */

   if (setjmp(png_jmpbuf(png_ptr)))
   {
      /* Free all of the memory associated with the png_ptr and info_ptr */
      png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL);
      fclose(fp);
      /* If we get here, we had a problem reading the file */
      return (ERROR);
   }

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

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

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

#ifdef hilevel
   /*
    * If you have enough memory to read in the entire image at once,
    * and you need to specify only transforms that can be controlled
    * with one of the PNG_TRANSFORM_* bits (this presently excludes
    * dithering, filling, setting background, and doing gamma
    * adjustment), then you can read the entire image (including
    * pixels) into the info structure with this call:
    */
   png_read_png(png_ptr, info_ptr, png_transforms, png_voidp_NULL);
#else
   /* OK, you're doing it the hard way, with the lower-level functions */

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

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

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

   /* tell libpng to strip 16 bit/color files down to 8 bits/color */
   png_set_strip_16(png_ptr);

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

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

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

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

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

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

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

   png_color_16 my_background, *image_background;

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

   /* Some suggestions as to how to get a screen gamma value */

   /* Note that screen gamma is the display_exponent, which includes
    * the CRT_exponent and any correction for viewing conditions */
   if (/* We have a user-defined screen gamma value */)
   {
      screen_gamma = user-defined screen_gamma;
   }
   /* This is one way that applications share the same screen gamma value */
   else if ((gamma_str = getenv("SCREEN_GAMMA")) != NULL)
void t_RenderClass::loadTexture(int target, const char *filename)
{
   FILE *theFile = fopen(filename,"rb");

   if (!theFile)
   {
      LOGI("Fopen failed");
      exit(1);
   }

   char header[8];
   fread(header,1,8,theFile);

   if (ferror(theFile))
   {
      LOGI("Fread failed");
      exit(1);
   }

   if (png_sig_cmp((png_byte *) header,0,8))
   {
      LOGI("The file is not a png\n");
      exit(1);
   }

   png_structp png_ptr = png_create_read_struct(
                            PNG_LIBPNG_VER_STRING,
                            NULL,NULL,NULL
                         );

   if (!png_ptr)
   {
      printf("Failed initialization of png_ptr\n");
      exit(1);
   }

   png_infop info_ptr = png_create_info_struct(png_ptr);

   if (!info_ptr)
   {
      png_destroy_read_struct(&png_ptr,
                              (png_infopp)NULL, (png_infopp)NULL);
      printf("Info ptr creation failed\n");
      exit(1);
   }

   png_infop end_info = png_create_info_struct(png_ptr);

   if (!end_info)
   {
      png_destroy_read_struct(&png_ptr, &info_ptr,
                              (png_infopp)NULL);
      printf("Info ptr creation failed\n");
      exit(1);
   }

   png_init_io(png_ptr,theFile);
   png_set_sig_bytes(png_ptr,8);

   png_read_info(png_ptr,info_ptr);
   int width = png_get_image_width(png_ptr,info_ptr);
   int height = png_get_image_width(png_ptr,info_ptr);
   int depth = png_get_bit_depth(png_ptr,info_ptr);
   int rowbytes = png_get_rowbytes(png_ptr, info_ptr);

   png_byte* image_data = new png_byte[rowbytes * height];

   png_bytep *row_pointers = new png_bytep [height];

   for (int i = 0; i < height; ++i)
   {
      row_pointers[i] = image_data + i * rowbytes;
   }


   LOGI("I have read the image with width %d, height %d, depth %d, rowbytes %d\n",width,height,depth,rowbytes);

   png_read_image(png_ptr,row_pointers);

   png_read_end(png_ptr,NULL);
   png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);


   glTexImage2D(GL_TEXTURE_2D,0,GL_RGBA,width,height,0,GL_RGBA,GL_UNSIGNED_BYTE,image_data);
   checkGlError("glClear");

   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
   checkGlError("glClear");

   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
   checkGlError("glClear");

   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
   checkGlError("glClear");

   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
   checkGlError("glClear");
}
Exemple #6
0
unsigned char *read_png_file(const char* file_name, int *width, int *height,
                             int *stride) {

   png_byte color_type;
   png_byte bit_depth;

   png_structp png_ptr;
   png_infop info_ptr;
   int number_of_passes;
   png_bytep* row_pointers;
   int y;

   unsigned char header[8];   // 8 is the maximum size that can be checked
   unsigned char *buf;
   FILE *fp;

   /* open file and test for it being a png */
   fp = fopen(file_name, "rb");
   if (!fp) return NULL;

   fread(header, 1, 8, fp);
   if (png_sig_cmp(header, 0, 8)) {
      roadmap_log (ROADMAP_ERROR,
         "[read_png_file] File %s is not recognized as a PNG file",
         file_name);
      fclose(fp);
      return NULL;
   }

   /* initialize stuff */
   png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);

   if (!png_ptr) {
      roadmap_log (ROADMAP_ERROR,
                  "[read_png_file] png_create_read_struct failed");
      fclose(fp);
      return NULL;
   }

   info_ptr = png_create_info_struct(png_ptr);

   if (!info_ptr) {
      roadmap_log (ROADMAP_ERROR,
            "[read_png_file] png_create_info_struct failed");
      fclose(fp);
      return NULL;
   }

   if (setjmp(png_jmpbuf(png_ptr))) {
      roadmap_log (ROADMAP_ERROR, "[read_png_file] Error during init_io");
      fclose(fp);
      return NULL;
   }

   png_init_io(png_ptr, fp);
   png_set_sig_bytes(png_ptr, 8);

   png_read_info(png_ptr, info_ptr);

   *width = info_ptr->width;
   *height = info_ptr->height;
   *stride = info_ptr->rowbytes;
   color_type = info_ptr->color_type;
   bit_depth = info_ptr->bit_depth;

   number_of_passes = png_set_interlace_handling(png_ptr);
   png_read_update_info(png_ptr, info_ptr);

   /* read file */
   if (setjmp(png_jmpbuf(png_ptr))) {
      roadmap_log (ROADMAP_ERROR, "[read_png_file] Error during read_image");
      fclose(fp);
      return NULL;
   }

   row_pointers = (png_bytep*) malloc(sizeof(png_bytep) * *height);
   buf = malloc (*height * info_ptr->rowbytes);
   for (y=0; y<*height; y++) {
      row_pointers[y] = (png_byte*) (buf + y * info_ptr->rowbytes);
   }

   png_read_image(png_ptr, row_pointers);
   png_read_end(png_ptr, NULL);
   png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
   free (row_pointers);

   fclose(fp);

   return buf;
}
Exemple #7
0
uint8_t* ImageDecoder::decodePNGImpl(png_structp pngPtr, uint32_t* width, uint32_t* height)
{
	png_bytep* rowPtrs = NULL;
	uint8_t* outData = NULL;
	png_infop infoPtr = png_create_info_struct(pngPtr);
	if (!infoPtr)
	{
		LOG(LOG_ERROR,"Couldn't initialize png info struct");
		png_destroy_read_struct(&pngPtr, (png_infopp)0, (png_infopp)0);
		return NULL;
	}

	if (setjmp(png_jmpbuf(pngPtr)))
	{
		png_destroy_read_struct(&pngPtr, &infoPtr,(png_infopp)0);
		if (rowPtrs != NULL) delete [] rowPtrs;
		if (outData != NULL) delete [] outData;

		LOG(LOG_ERROR,"error during reading of the png file");

		return NULL;
	}

	png_read_info(pngPtr, infoPtr);

	*width =  png_get_image_width(pngPtr, infoPtr);
	*height = png_get_image_height(pngPtr, infoPtr);

	//bits per CHANNEL! note: not per pixel!
	png_uint_32 bitdepth = png_get_bit_depth(pngPtr, infoPtr);
	//Number of channels
	png_uint_32 channels = png_get_channels(pngPtr, infoPtr);
	//Color type. (RGB, RGBA, Luminance, luminance alpha... palette... etc)
	png_uint_32 color_type = png_get_color_type(pngPtr, infoPtr);

	// Transform everything into 24 bit RGB
	switch (color_type)
	{
		case PNG_COLOR_TYPE_PALETTE:
			png_set_palette_to_rgb(pngPtr);
			// png_set_palette_to_rgb wil convert into 32
			// bit, but we don't want the alpha
			png_set_strip_alpha(pngPtr);
			break;
		case PNG_COLOR_TYPE_GRAY:
			if (bitdepth < 8)
				png_set_gray_to_rgb(pngPtr);
			break;
	}

	if (bitdepth == 16)
	{
		png_set_strip_16(pngPtr);
	}

	if (channels > 3)
	{
		LOG(LOG_NOT_IMPLEMENTED, "Alpha channel not supported in PNG");
		png_set_strip_alpha(pngPtr);
	}

	// Update the infoPtr to reflect the transformations set
	// above. Read new values by calling png_get_* again.
	png_read_update_info(pngPtr, infoPtr);

	//bitdepth = png_get_bit_depth(pngPtr, infoPtr);
	//color_type = png_get_color_type(pngPtr, infoPtr);

	channels = png_get_channels(pngPtr, infoPtr);
	if (channels != 3)
	{
		// Should never get here because of the
		// transformations
		LOG(LOG_NOT_IMPLEMENTED, "Unexpected number of channels in PNG!");

		png_destroy_read_struct(&pngPtr, &infoPtr,(png_infopp)0);

		return NULL;
	}

	const unsigned int stride = png_get_rowbytes(pngPtr, infoPtr);

	outData = new uint8_t[(*height) * stride];
	rowPtrs = new png_bytep[(*height)];
	for (size_t i = 0; i < (*height); i++)
	{
		rowPtrs[i] = (png_bytep)outData + i* stride;
	}

	png_read_image(pngPtr, rowPtrs);
	png_read_end(pngPtr, NULL);
	png_destroy_read_struct(&pngPtr, &infoPtr,(png_infopp)0);
	delete[] (png_bytep)rowPtrs;

	return outData;
}
Exemple #8
0
int load_png_image(const char *filepath,
                   struct pngload_attribute *png_attr)
{
    FILE *fp;
    png_structp png_ptr;
    png_infop info_ptr;
    png_bytep* row_pointers;
    char buf[PNG_BYTES_TO_CHECK];
    int w, h, x, y, temp, color_type;

    fp = fopen( filepath, "rb" );
    if( fp == NULL ) { 
        return -1;
    }

    png_ptr = png_create_read_struct( PNG_LIBPNG_VER_STRING, 0, 0, 0 );
    info_ptr = png_create_info_struct( png_ptr );

    setjmp( png_jmpbuf(png_ptr) ); 
    /* 读取PNG_BYTES_TO_CHECK个字节的数据 */
    temp = fread( buf, 1, PNG_BYTES_TO_CHECK, fp );
    /* 若读到的数据并没有PNG_BYTES_TO_CHECK个字节 */
    if( temp < PNG_BYTES_TO_CHECK ) {
        fclose(fp);
        png_destroy_read_struct( &png_ptr, &info_ptr, 0);
        return -3;
    }
    /* 检测数据是否为PNG的签名 */
    temp = png_sig_cmp( (png_bytep)buf, (png_size_t)0, PNG_BYTES_TO_CHECK );
    /* 如果不是PNG的签名,则说明该文件不是PNG文件 */
    if( temp != 0 ) {
        fclose(fp);
        png_destroy_read_struct( &png_ptr, &info_ptr, 0);
        return -4;
    }
        
    /* 复位文件指针 */
    rewind( fp );
    /* 开始读文件 */
    png_init_io( png_ptr, fp ); 
    /* 读取PNG图片信息 */
    png_read_png( png_ptr, info_ptr, PNG_TRANSFORM_EXPAND, 0 );
    /* 获取图像的色彩类型 */
    color_type = png_get_color_type( png_ptr, info_ptr );
    /* 获取图像的宽高 */
    png_attr->width = w = png_get_image_width( png_ptr, info_ptr );
    png_attr->height = h = png_get_image_height( png_ptr, info_ptr );
    printf("w=%d,h=%d\n", w, h);
    /* 获取图像的所有行像素数据,row_pointers里边就是rgba数据 */
    row_pointers = png_get_rows( png_ptr, info_ptr );
    unsigned char *data;
    int index = 0;

    /* 根据不同的色彩类型进行相应处理 */
    png_attr->color_type = color_type;
    switch( color_type ) {
    case PNG_COLOR_TYPE_RGB_ALPHA:
        printf("rgba\n");
        data = malloc(w*h*4);
        png_attr->buf = data;
        for( y=0; y<h; ++y ) {
            for( x=0; x<w*4; ) {
                /* 以下是RGBA数据,需要自己补充代码,保存RGBA数据 */
                data[index++] = row_pointers[y][x++]; // red
                data[index++] = row_pointers[y][x++]; // green
                data[index++] = row_pointers[y][x++]; // blue
                data[index++] = row_pointers[y][x++]; // alpha
            }
        }
        break;

    case PNG_COLOR_TYPE_RGB:
        printf("rgb\n");
        data = malloc(w*h*3);
        png_attr->buf = data;
        for( y=0; y<h; ++y ) {
            for( x=0; x<w*3; ) {
                data[index++] = row_pointers[y][x++]; // red
                data[index++] = row_pointers[y][x++]; // green
                data[index++] = row_pointers[y][x++]; // blue
            }
        }
        break;
        /* 其它色彩类型的图像就不读了 */
    default:
        fclose(fp);
        png_destroy_read_struct( &png_ptr, &info_ptr, 0);
        return -2;
    }
    png_destroy_read_struct( &png_ptr, &info_ptr, 0);
    return 0;
}
// Loads a PNG image
//
// filename - name of the targa file to load
// image_data - allocated storage for the bitmap
//
// returns - true if succesful, false otherwise
//
int png_read_bitmap(char *real_filename, ubyte *image_data, ubyte *bpp, int dest_size, int cf_type)
{
	char filename[MAX_FILENAME_LEN];
	png_infop info_ptr;
	png_structp png_ptr;
	png_bytepp row_pointers;
	unsigned int i, len;

	png_file = NULL;

	strcpy_s( filename, real_filename );
	char *p = strchr( filename, '.' );
	if ( p ) *p = 0;
	strcat_s( filename, ".png" );

	png_file = cfopen(filename, "rb", CFILE_NORMAL, cf_type);

	if (png_file == NULL)
		return PNG_ERROR_READING;

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

	if (png_ptr == NULL)
	{
		mprintf(("png_read_bitmap: png_ptr went wrong\n"));
		cfclose(png_file);
		return PNG_ERROR_READING;
	}

	/* Allocate/initialize the memory for image information.  REQUIRED. */
	info_ptr = png_create_info_struct(png_ptr);
	if (info_ptr == NULL)
	{
		mprintf(("png_read_bitmap: info_ptr went wrong\n"));
		cfclose(png_file);
		png_destroy_read_struct(&png_ptr, NULL, NULL);
		return PNG_ERROR_READING;
	}

	if (setjmp(png_jmpbuf(png_ptr)))
	{
		mprintf(("png_read_bitmap: something went wrong\n"));
		/* Free all of the memory associated with the png_ptr and info_ptr */
		png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
		cfclose(png_file);
		/* If we get here, we had a problem reading the file */
		return PNG_ERROR_READING;
	}

	png_set_read_fn(png_ptr, &png_file, png_scp_read_data);

	png_read_png(png_ptr, info_ptr, PNG_TRANSFORM_BGR | PNG_TRANSFORM_EXPAND | PNG_TRANSFORM_STRIP_16, NULL);
	len = png_get_rowbytes(png_ptr, info_ptr);

	row_pointers = png_get_rows(png_ptr, info_ptr);

	if(bpp)
		*bpp = (ubyte)(len / png_get_image_width(png_ptr, info_ptr)) << 3;

	//copy row data to image
	unsigned int height = png_get_image_height(png_ptr, info_ptr);
	for (i = 0; i < height; i++) {
		memcpy(&image_data[i * len], row_pointers[i], len);
	}

	png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
	cfclose(png_file);

	return PNG_ERROR_NONE;
}
Exemple #10
0
unsigned char *readpng_get_image( png_store* pngdata)
{
    double  gamma;
    png_uint_32  i, rowbytes;
    png_bytepp  row_pointers = NULL;
    png_structp png_ptr = pngdata->png_ptr;
    png_infop info_ptr = pngdata->info_ptr;
    int color_type = pngdata->colortype;
    int bit_depth = pngdata->bitdepth;
    int height = pngdata->height;
    double display_exponent = DISPLAY_EXPONENT;
    int *pChannels = &(pngdata->channels);
    unsigned long *pRowbytes = &(pngdata->rowbytes);
    unsigned char * image_data;
    /* setjmp() must be called in every function that calls a PNG-reading
     * libpng function */

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

    /* expand palette images to RGB, low-bit-depth grayscale images to 8 bits,
     * transparency chunks to full alpha channel; strip 16-bit-per-sample
     * images to 8 bits per sample; and convert grayscale to RGB[A] */

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


    /* unlike the example in the libpng documentation, we have *no* idea where
     * this file may have come from--so if it doesn't have a file gamma, don't
     * do any correction ("do no harm") */

    if (png_get_gAMA(png_ptr, info_ptr, &gamma))
        png_set_gamma(png_ptr, display_exponent, gamma);


    /* all transformations have been registered; now update info_ptr data,
     * get rowbytes and channels, and allocate image memory */

    png_read_update_info(png_ptr, info_ptr);

    *pRowbytes = rowbytes = png_get_rowbytes(png_ptr, info_ptr);
    *pChannels = (int)png_get_channels(png_ptr, info_ptr);

    if ((image_data = (unsigned char *)malloc(rowbytes*height)) == NULL) {
        png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
        return NULL;
    }
    if ((row_pointers = (png_bytepp)malloc(height*sizeof(png_bytep))) == NULL) {
        png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
        free(image_data);
        image_data = NULL;
        return NULL;
    }

    /* set the individual row_pointers to point at the correct offsets */

    for (i = 0;  i < height;  ++i)
        row_pointers[i] = image_data + i*rowbytes;

    /* now we can go ahead and just read the whole image */

    png_read_image(png_ptr, row_pointers);


    /* and we're done!  (png_read_end() can be omitted if no processing of
     * post-IDAT text/time/etc. is desired) */

//    free(row_pointers);
//    row_pointers = NULL;

    png_read_end(png_ptr, NULL);

    pngdata->image_data = image_data;
    pngdata->row_pointers =  row_pointers;

    return image_data;
}
Exemple #11
0
int readpng_init(FILE *infile, png_store *pngdata)
{
    unsigned char sig[8];
    long width,height;
    int  bit_depth, color_type;
 

    /* first do a quick check that the file really is a PNG image; could
     * have used slightly more general png_sig_cmp() function instead */

    size_t fr = fread(sig, 1, 8, infile);
    if(fr != 1*8)
        return 1;   /* bad signature */

    if (!png_check_sig(sig, 8))
        return 1;   /* bad signature */


    /* could pass pointers to user-defined error handlers instead of NULLs: */

    png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
    if (!png_ptr)
        return 4;   /* out of memory */

    png_infop info_ptr = png_create_info_struct(png_ptr);
    if (!info_ptr) {
        png_destroy_read_struct(&png_ptr, NULL, NULL);
        return 4;   /* out of memory */
    }


    /* we could create a second info struct here (end_info), but it's only
     * useful if we want to keep pre- and post-IDAT chunk info separated
     * (mainly for PNG-aware image editors and converters) */


    /* setjmp() must be called in every function that calls a PNG-reading
     * libpng function */

    if (setjmp(png_jmpbuf(png_ptr))) {
        png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
        return 2;
    }


    png_init_io(png_ptr, infile);
    png_set_sig_bytes(png_ptr, 8);  /* we already read the 8 signature bytes */

    png_read_info(png_ptr, info_ptr);  /* read all PNG info up to image data */


    /* alternatively, could make separate calls to png_get_image_width(),
     * etc., but want bit_depth and color_type for later [don't care about
     * compression_type and filter_type => NULLs] */

    png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,
      NULL, NULL, NULL);
	pngdata->width = width;
	pngdata->height = height;
	pngdata->bitdepth = bit_depth;
	pngdata->colortype = color_type;
	pngdata->png_ptr = png_ptr;
	pngdata->info_ptr = info_ptr;

    /* OK, that's all we need for now; return happy */

    return 0;
}
/**
  The constructor loads the named PNG image from the given png filename.
  <P>The destructor free all memory and server resources that are used by
  the image.
*/
void LoadPNG(const char *png) // I - File to read
{
  int		i;			// Looping var
  FILE		*fp;			// File pointer
  int		channels;		// Number of color channels
  png_structp	pp;			// PNG read pointer
  png_infop	info;			// PNG info pointers
  png_bytep	*rows;			// PNG row pointers


  // Open the PNG file...
  if ((fp = fopen(png, "rb")) == NULL) return;

  // Setup the PNG data structures...
  pp   = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
  info = png_create_info_struct(pp);

  if (setjmp(pp->jmpbuf))
  {
	  int debug = 1;
	  return;
  }

  // Initialize the PNG read "engine"...
  png_init_io(pp, fp);

  // Get the image dimensions and convert to grayscale or RGB...
  png_read_info(pp, info);

  if (info->color_type == PNG_COLOR_TYPE_PALETTE)
    png_set_expand(pp);

  if (info->color_type & PNG_COLOR_MASK_COLOR)
    channels = 3;
  else
    channels = 1;

  if ((info->color_type & PNG_COLOR_MASK_ALPHA) || info->num_trans)
    channels ++;

  int w = (int)(info->width);
  int h = (int)(info->height);
  int d = channels;
  pictureWidth = w;
  pictureHeight = h;

  if (info->bit_depth < 8)
  {
    png_set_packing(pp);
    png_set_expand(pp);
  }
  else if (info->bit_depth == 16)
    png_set_strip_16(pp);

#  if defined(HAVE_PNG_GET_VALID) && defined(HAVE_PNG_SET_TRNS_TO_ALPHA)
  // Handle transparency...
  if (png_get_valid(pp, info, PNG_INFO_tRNS))
    png_set_tRNS_to_alpha(pp);
#  endif // HAVE_PNG_GET_VALID && HAVE_PNG_SET_TRNS_TO_ALPHA

  unsigned char *array = (unsigned char *)pictureS;

  // Allocate pointers...
  rows = new png_bytep[h];

  for (i = 0; i < h; i ++)
    rows[i] = (png_bytep)(array + i * w * d); // we flip it

  // Read the image, handling interlacing as needed...
  for (i = png_set_interlace_handling(pp); i > 0; i --)
    png_read_rows(pp, rows, NULL, h);

#ifdef WIN32
  // Some Windows graphics drivers don't honor transparency when RGB == white
  if (channels == 4) 
  {
    // Convert RGB to 0 when alpha == 0...
    unsigned char *ptr = (unsigned char *)array;
    for (i = w * h; i > 0; i --, ptr += 4)
      if (!ptr[3]) ptr[0] = ptr[1] = ptr[2] = 0;
  }
#endif // WIN32

  if (channels == 3)
  {
	  unsigned char *array2 = new unsigned char[pictureWidth * pictureHeight * 4];
	  for (int i = w * h - 1; i >= 0; --i)
	  {
		  array2[i*4+0] = array[i*3+0];
		  array2[i*4+1] = array[i*3+1];
		  array2[i*4+2] = array[i*3+2];
		  array2[i*4+3] = 255;
	  }
	  memcpy(array, array2, w * h * 4);
	  delete[] array2;
  }

  // Free memory and return...
  delete[] rows;

  png_read_end(pp, info);
  png_destroy_read_struct(&pp, &info, NULL);

  fclose(fp);
}
Exemple #13
0
static rt_bool_t rtgui_image_png_load(struct rtgui_image *image, struct rtgui_filerw *file, rt_bool_t load)
{
    png_uint_32 width;
    png_uint_32 height;
    int bit_depth;
    int color_type;
    double gamma;
    struct rtgui_image_png *png;

    png = (struct rtgui_image_png *) rtgui_malloc(sizeof(struct rtgui_image_png));
    png->png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
    if (png->png_ptr == RT_NULL)
    {
        rtgui_free(png);
        return RT_FALSE;
    }

    png->info_ptr = png_create_info_struct(png->png_ptr);
    if (png->info_ptr == RT_NULL)
    {
        png_destroy_read_struct(&png->png_ptr, NULL, NULL);
        rtgui_free(png);
        return RT_FALSE;
    }

    png->filerw = file;
    png_set_read_fn(png->png_ptr, png->filerw, rtgui_image_png_read_data);

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

    /* set image information */
    image->w = width;
    image->h = height;
    image->engine = &rtgui_image_png_engine;
    image->data = png;

    if (bit_depth == 16)
        png_set_strip_16(png->png_ptr);
    if (color_type == PNG_COLOR_TYPE_PALETTE)
        png_set_expand(png->png_ptr);
    if (bit_depth < 8)
        png_set_expand(png->png_ptr);
    if (png_get_valid(png->png_ptr, png->info_ptr, PNG_INFO_tRNS))
        png_set_expand(png->png_ptr);
    if (color_type == PNG_COLOR_TYPE_GRAY ||
            color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
        png_set_gray_to_rgb(png->png_ptr);

    /* Ignore background color */

    /* set gamma conversion */
    if (png_get_gAMA(png->png_ptr, png->info_ptr, &gamma))
        png_set_gamma(png->png_ptr, (double)2.2, gamma);

    png_read_update_info(png->png_ptr, png->info_ptr);

    if (load == RT_TRUE)
    {
        /* load all pixels */
        png->pixels = rtgui_malloc(image->w * image->h * sizeof(rtgui_color_t));
        if (png->pixels == RT_NULL)
        {
            png_read_end(png->png_ptr, RT_NULL);

            /* destroy png struct */
            png_destroy_info_struct(png->png_ptr, &png->info_ptr);
            png_destroy_read_struct(&png->png_ptr, RT_NULL, RT_NULL);

            /* release data */
            rtgui_free(png);
            return RT_FALSE;
        }

        rtgui_image_png_process(png->png_ptr, png->info_ptr, png);
    }
    else
    {
        png->pixels = RT_NULL;
    }

    return RT_TRUE;
}
Exemple #14
0
 ~png_struct_guard()
 {
     png_destroy_read_struct(p_,i_,0);
 }
char *sng_load_png_texture(const char *filename, int flipVertical, int flipHorizontal, int pre_multiply_alpha,
	int *w, int *h, int *hasAlpha, char *whynot, int whynotlen)
{
#ifndef WITHOUTOPENGL
	int i, j, bit_depth, color_type, row_bytes, image_data_row_bytes;
	png_byte header[8];
	png_uint_32 tw, th;
	png_structp png_ptr = NULL;
	png_infop info_ptr = NULL;
	png_infop end_info = NULL;
	png_byte *image_data = NULL;

	FILE *fp = fopen(filename, "rb");
	if (!fp) {
		snprintf(whynot, whynotlen, "Failed to open '%s': %s",
			filename, strerror(errno));
		return 0;
	}

	if (fread(header, 1, 8, fp) != 8) {
		snprintf(whynot, whynotlen, "Failed to read 8 byte header from '%s'\n",
				filename);
		goto cleanup;
	}
	if (png_sig_cmp(header, 0, 8)) {
		snprintf(whynot, whynotlen, "'%s' isn't a png file.",
			filename);
		goto cleanup;
	}

	png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,
							NULL, NULL, NULL);
	if (!png_ptr) {
		snprintf(whynot, whynotlen,
			"png_create_read_struct() returned NULL");
		goto cleanup;
	}

	info_ptr = png_create_info_struct(png_ptr);
	if (!info_ptr) {
		snprintf(whynot, whynotlen,
			"png_create_info_struct() returned NULL");
		goto cleanup;
	}

	end_info = png_create_info_struct(png_ptr);
	if (!end_info) {
		snprintf(whynot, whynotlen,
			"2nd png_create_info_struct() returned NULL");
		goto cleanup;
	}

	if (setjmp(png_jmpbuf(png_ptr))) {
		snprintf(whynot, whynotlen, "libpng encounted an error");
		goto cleanup;
	}

	png_init_io(png_ptr, fp);
	png_set_sig_bytes(png_ptr, 8);

	/*
	 * PNG_TRANSFORM_STRIP_16 |
	 * PNG_TRANSFORM_PACKING  forces 8 bit
	 * PNG_TRANSFORM_EXPAND forces to expand a palette into RGB
	 */
	png_read_png(png_ptr, info_ptr, PNG_TRANSFORM_STRIP_16 | PNG_TRANSFORM_PACKING | PNG_TRANSFORM_EXPAND, NULL);

	png_get_IHDR(png_ptr, info_ptr, &tw, &th, &bit_depth, &color_type, NULL, NULL, NULL);

	if (bit_depth != 8) {
		snprintf(whynot, whynotlen, "load_png_texture only supports 8-bit image channel depth");
		goto cleanup;
	}

	if (color_type != PNG_COLOR_TYPE_RGB && color_type != PNG_COLOR_TYPE_RGB_ALPHA) {
		snprintf(whynot, whynotlen, "load_png_texture only supports RGB and RGBA");
		goto cleanup;
	}

	if (w)
		*w = tw;
	if (h)
		*h = th;
	int has_alpha = (color_type == PNG_COLOR_TYPE_RGB_ALPHA);
	if (hasAlpha)
		*hasAlpha = has_alpha;

	row_bytes = png_get_rowbytes(png_ptr, info_ptr);
	image_data_row_bytes = row_bytes;

	/* align to 4 byte boundary */
	if (image_data_row_bytes & 0x03)
		image_data_row_bytes += 4 - (image_data_row_bytes & 0x03);

	png_bytepp row_pointers = png_get_rows(png_ptr, info_ptr);

	image_data = malloc(image_data_row_bytes * th * sizeof(png_byte) + 15);
	if (!image_data) {
		snprintf(whynot, whynotlen, "malloc failed in load_png_texture");
		goto cleanup;
	}

	int bytes_per_pixel = (color_type == PNG_COLOR_TYPE_RGB_ALPHA ? 4 : 3);

	for (i = 0; i < th; i++) {
		png_byte *src_row;
		png_byte *dest_row = image_data + i * image_data_row_bytes;

		if (flipVertical)
			src_row = row_pointers[th - i - 1];
		else
			src_row = row_pointers[i];

		if (flipHorizontal) {
			for (j = 0; j < tw; j++) {
				png_byte *src = src_row + bytes_per_pixel * j;
				png_byte *dest = dest_row + bytes_per_pixel * (tw - j - 1);
				memcpy(dest, src, bytes_per_pixel);
			}
		} else {
			memcpy(dest_row, src_row, row_bytes);
		}

		if (has_alpha && pre_multiply_alpha) {
			for (j = 0; j < tw; j++) {
				png_byte *pixel = dest_row + bytes_per_pixel * j;
				float alpha = pixel[3] / 255.0;
				pixel[0] = pixel[0] * alpha;
				pixel[1] = pixel[1] * alpha;
				pixel[2] = pixel[2] * alpha;
			}
		}
	}

	png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
	fclose(fp);
	return (char *)image_data;

cleanup:
	if (image_data)
		free(image_data);
	png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
	fclose(fp);
#else
	snprintf(whynot, whynotlen, "load_png_texture: compiled without opengl support.");
#endif
	return 0;
}
// Reads header information from the PNG file into the bitmap pointer
//
// filename - name of the PNG bitmap file
// w - (output) width of the bitmap
// h - (output) height of the bitmap
// bpp - (output) bits per pixel of the bitmap
//
// returns - PNG_ERROR_NONE if successful, otherwise error code
//
int png_read_header(char *real_filename, CFILE *img_cfp, int *w, int *h, int *bpp, ubyte *palette)
{
	char filename[MAX_FILENAME_LEN];
	png_infop info_ptr;
	png_structp png_ptr;

	png_file = NULL;

	//mprintf(("png_read_header: %s\n", real_filename));

	if (img_cfp == NULL) {
		strcpy_s( filename, real_filename );

		char *p = strchr( filename, '.' );

		if ( p )
			*p = 0;

		strcat_s( filename, ".png" );

		png_file = cfopen( filename , "rb" );

		if ( !png_file ) {
			return PNG_ERROR_READING;
		}
	} else {
		png_file = img_cfp;
	}

	Assert( png_file != NULL );

	if (png_file == NULL)
		return PNG_ERROR_READING;

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

	if (png_ptr == NULL)
	{
		mprintf(("png_read_header: error creating read struct\n"));
		cfclose(png_file);
		return PNG_ERROR_READING;
	}

	/* Allocate/initialize the memory for image information.  REQUIRED. */
	info_ptr = png_create_info_struct(png_ptr);
	if (info_ptr == NULL)
	{
		mprintf(("png_read_header: error creating info struct\n"));
		cfclose(png_file);
		png_destroy_read_struct(&png_ptr, NULL, NULL);
		return PNG_ERROR_READING;
	}

	if (setjmp(png_jmpbuf(png_ptr)))
	{
		mprintf(("png_read_header: something went wrong\n"));
		/* Free all of the memory associated with the png_ptr and info_ptr */
		png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
		cfclose(png_file);
		/* If we get here, we had a problem reading the file */
		return PNG_ERROR_READING;
	}

	png_set_read_fn(png_ptr, &png_file, png_scp_read_data);

	png_read_info(png_ptr, info_ptr);

	if (w) *w = png_get_image_width(png_ptr, info_ptr);
	if (h) *h = png_get_image_height(png_ptr, info_ptr);
	// this turns out to be near useless, but meh
	if (bpp) *bpp = (png_get_channels(png_ptr, info_ptr) * png_get_bit_depth(png_ptr, info_ptr));

	if (img_cfp == NULL) {
		cfclose(png_file);
		png_file = NULL;
	}

	png_destroy_read_struct(&png_ptr, &info_ptr, NULL);

	return PNG_ERROR_NONE;
}
Exemple #17
0
g_error png_load(hwrbitmap *hbmp, const u8 *data, u32 datalen) {
  png_structp png_ptr;
  png_infop info_ptr;
  struct datablock d;
  png_bytep *row_pointers;
  png_uint_32 width, height;
  int bit_depth,colortype,interlace;
  int x,y;
  u8 r,g,b,a;
  pgcolor c;
  png_bytep p;
  g_error e;
  png_colorp palette;
  int num_palette;
  png_colorp pp;
  png_bytep trans;
  int num_trans = 0;
#ifdef CONFIG_DITHER
  hwrdither dither;
#endif

  png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
  if (!png_ptr)
    return mkerror(PG_ERRT_IO, 68);   /* Error initializing libpng */
  
  info_ptr = png_create_info_struct(png_ptr);
  if (!info_ptr) {
    png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL);
    return mkerror(PG_ERRT_IO, 68);   /* Error initializing libpng */
  }

  /* Set libpng error handler */
  if (setjmp(png_jmpbuf(png_ptr))) {
    png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
    return mkerror(PG_ERRT_IO, 71);   /* Error reading PNG */
  }

  /* Set libpng read handler */
  d.data = data;
  d.length = datalen;
  png_set_read_fn(png_ptr, &d, (png_rw_ptr) &png_user_read_data);

  /* Read the png into memory */
  png_read_png(png_ptr, info_ptr, 
	       PNG_TRANSFORM_STRIP_16 | 
	       PNG_TRANSFORM_PACKING, 
	       NULL);
  row_pointers = png_get_rows(png_ptr, info_ptr);
  png_get_IHDR(png_ptr, info_ptr, &width, &height,
	       &bit_depth, &colortype, &interlace, NULL, NULL);
  if (colortype == PNG_COLOR_TYPE_PALETTE) {
    png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette);
    png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, NULL);
  }
  if (interlace != PNG_INTERLACE_NONE)
    fprintf(stderr, "png loader: OOPS... interlaced image, will b0rk\n");
  
  /* Allocate the picogui bitmap
   *
   * Important note: normally we create bitmaps at the display's
   *                 color depth, but if we have an alpha channel
   *                 we need room for ARGB colors.
   */
  if (colortype == PNG_COLOR_TYPE_GRAY_ALPHA ||
      colortype == PNG_COLOR_TYPE_RGB_ALPHA ||
      num_trans)
    e = vid->bitmap_new(hbmp,width,height,32);
  else
    e = vid->bitmap_new(hbmp,width,height,vid->bpp);
  if (iserror(e))
    png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);    
  errorcheck;

#ifdef CONFIG_DITHER
  /* Start dithering */
  e = vid->dither_start(&dither, *hbmp, 0,0,0,width,height);
  errorcheck;
#endif

  /* Transcribe it into a picogui bitmap. 
   * This method is slow, but ensures compatibility 
   */
  for (y=0;y<height;y++) {
    p = row_pointers[y];
    for (x=0;x<width;x++) {
      switch (colortype) {

      case PNG_COLOR_TYPE_GRAY:
	g = *(p++);
	c = mkcolor(g,g,g);
	break;

      case PNG_COLOR_TYPE_GRAY_ALPHA:
	g = *(p++);
	a = *(p++);
	c = mkcolora(a>>1,g,g,g);
	break;

      case PNG_COLOR_TYPE_PALETTE:
	pp = &palette[ (*p) % num_palette ];
	if (*p < num_trans)
	  c = mkcolora(trans[*p]>>1, pp->red, pp->green, pp->blue);
	else if (num_trans)
	  c = mkcolora(0x7f, pp->red, pp->green, pp->blue);
	else
	  c = mkcolor(pp->red, pp->green, pp->blue);
	p++;
	break;

      case PNG_COLOR_TYPE_RGB:
	r = *(p++);
	g = *(p++);
	b = *(p++);
	c = mkcolor(r,g,b);
	break;

      case PNG_COLOR_TYPE_RGB_ALPHA:
	r = *(p++);
	g = *(p++);
	b = *(p++);
	a = *(p++);
	c = mkcolora(a>>1,r,g,b);
	break;
	
      }
#ifdef CONFIG_DITHER
      vid->dither_store(dither, c, PG_LGOP_NONE);
#else
      vid->pixel(*hbmp,x,y,VID(color_pgtohwr)(c),PG_LGOP_NONE);
#endif
    }
  }
Exemple #18
0
void CachedTexture::reload() {
    //..... load file ......
    GLenum internal_format = GL_RGB;
    GLenum data_format = GL_RGB;
    unsigned char *data = NULL;
    if (filename.size() >= 4 && filename.substr(filename.size()-4,4) == ".png") {
        //Load a png file, as per the libpng docs:
        FILE *fp = fopen(filename.c_str(), "rb");
        if (!fp) {
            cerr << "  cannot open file." << endl;
            return;
        }
        png_structp png = png_create_read_struct(PNG_LIBPNG_VER_STRING, (png_voidp)NULL, (png_error_ptr)NULL, (png_error_ptr)NULL);
        if (!png) {
            cerr << "  cannot alloc read struct." << endl;
            fclose(fp);
            return;
        }
        png_infop info = png_create_info_struct(png);
        if (!info) {
            cerr << "  cannot alloc info struct." << endl;
            png_destroy_read_struct(&png, (png_infopp)NULL, (png_infopp)NULL);
            fclose(fp);
            return;
        }
        png_bytep *row_pointers = NULL;
        if (setjmp(png_jmpbuf(png))) {
            cerr << "  png interal error." << endl;
            png_destroy_read_struct(&png, &info, (png_infopp)NULL);
            if (data != NULL) delete[] data;
            if (row_pointers != NULL) delete[] row_pointers;
            fclose(fp);
            return;
        }
        png_init_io(png, fp);
        png_read_info(png, info);
        w = png_get_image_width(png, info);
        h = png_get_image_height(png, info);
        {   //find power-of-two dimensions...
            tw = 1;
            while (tw < w) tw *= 2;
            th = 1;
            while (th < h) th *= 2;
        }
        if (!pad && (tw != w || th != h)) {
            if (!have_ARB_texture_non_power_of_two()) {
                cerr << "WARNING: trying to load texture of size " << w << " x " << h << ", but non-power-of-two textures not supported." << endl;
            }
            tw = w;
            th = h;
        }
        if (png_get_color_type(png, info) == PNG_COLOR_TYPE_PALETTE)
            png_set_palette_to_rgb(png);
        if (png_get_bit_depth(png, info) < 8)
            png_set_packing(png);
        if (png_get_bit_depth(png,info) == 16)
            png_set_strip_16(png);
        png_read_update_info(png, info);
        unsigned int rowbytes = png_get_rowbytes(png, info);
        //Make sure it's the format we think it is...
        bool problem = false;
        if (png_get_color_type(png, info) == PNG_COLOR_TYPE_GRAY) {
            data_format = internal_format = GL_LUMINANCE;
            if (rowbytes != w*1) problem = true;
        } else if (png_get_color_type(png, info) == PNG_COLOR_TYPE_GRAY_ALPHA) {
            data_format = internal_format = GL_LUMINANCE_ALPHA;
            if (rowbytes != w*2) problem = true;
        } else if (png_get_color_type(png, info) == PNG_COLOR_TYPE_PALETTE || png_get_color_type(png, info) == PNG_COLOR_TYPE_RGB) {
            data_format = internal_format = GL_RGB;
            if (rowbytes != w*3) problem = true;
        } else if (png_get_color_type(png, info) == PNG_COLOR_TYPE_RGB_ALPHA) {
            data_format = internal_format = GL_RGBA;
            if (rowbytes != w*4) problem = true;
        } else {
            cerr << "  unknown color format." << endl;
            problem = true;
        }
        if (problem) {
            cerr << "  color format problem. (rowbytes: " << rowbytes << " w:" << w << ")" << endl;
            png_destroy_read_struct(&png, &info, NULL);
            fclose(fp);
            return;
        }

        unsigned int pixelbytes = rowbytes / w;
        assert(rowbytes == pixelbytes * w); //sanity check, should have bailed earlier if this was the case.
        data = new uint8_t[th*tw*pixelbytes];
        row_pointers = new png_bytep[th];
        if (flip) {
            //texture origin goes top-left, as in most images:
            for (unsigned int r = 0; r < th; ++r) {
                row_pointers[r] = (png_bytep)(data + r*pixelbytes*tw);
            }
        } else {
            //texture origin goes bottom-left, as GL says:
            for (unsigned int r = 0; r < th; ++r) {
                row_pointers[th-1-r] = (png_bytep)(data + r*tw*pixelbytes);
            }
        }
        png_read_image(png, row_pointers);
        png_destroy_read_struct(&png, &info, NULL);
        fclose(fp);
        delete[] row_pointers;

        if (pad && h != 0 && w != 0) {
            //duplicate the last column accross the texture:
            for (unsigned int r = 0; r < h; ++r) {
                for (unsigned int c = w; c < tw; ++c) {
                    memcpy(&(data[(r*tw+c)*pixelbytes]), &(data[(r*tw+w-1)*pixelbytes]),pixelbytes);
                }
            }
            //duplicate the last row down the texture:
            for (unsigned int r = h; r < th; ++r) {
                memcpy(&(data[r*pixelbytes*tw]), &(data[(h-1)*pixelbytes*tw]), pixelbytes*tw);
            }
        }
    } else {
        //well, not a supported image type I'm afraid.
        cerr << "  unknown image type." << endl;
        return;
    }

    glGenTextures(1, &obj);
    glBindTexture(GL_TEXTURE_2D, obj);
    glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glPushClientAttrib(GL_CLIENT_PIXEL_STORE_BIT);
    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
    glTexImage2D(GL_TEXTURE_2D, 0, internal_format, tw, th, 0, data_format, GL_UNSIGNED_BYTE, data);
    glBindTexture(GL_TEXTURE_2D, 0);
    glPopClientAttrib();
    delete[] data;

    loaded = true;
    gl_errors("CachedTexture::reload()");

}
Exemple #19
0
	bool Image::loadPngImage(char *name, int &outWidth, int &outHeight, bool &outHasAlpha, unsigned char** outData)
	{
		    png_structp png_ptr;
    png_infop info_ptr;
    unsigned int sig_read = 0;
    FILE *fp;
 
    if ((fp = fopen(name, "rb")) == NULL)
        return false;
 
    /* Create and initialize the png_struct with the desired error handler
     * functions.  If you want to use the default stderr and longjump method,
     * you can supply NULL for the last three parameters.  We also supply the
     * the compiler header file version, so that we know if the application
     * was compiled with a compatible version of the library.  REQUIRED
     */
    png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,
            NULL, NULL, NULL);
 
    if (png_ptr == NULL) {
        fclose(fp);
        return false;
    }
 
    // Allocate/initialize the memory for image information.  REQUIRED.
    info_ptr = png_create_info_struct(png_ptr);
    if (info_ptr == NULL) {
        fclose(fp);
        png_destroy_read_struct(&png_ptr, png_infopp_NULL, png_infopp_NULL);
        return false;
    }
 
    /* Set error handling if you are using the setjmp/longjmp method
     * (this is the normal method of doing things with libpng).
     * REQUIRED unless you  set up your own error handlers in
     * the png_create_read_struct() earlier.
     */
    if (setjmp(png_jmpbuf(png_ptr))) {
        /* Free all of the memory associated with the png_ptr and info_ptr */
        png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL);
        fclose(fp);
        /* If we get here, we had a problem reading the file */
        return false;
    }
 
    /* Set up the output control if you are using standard C streams */
    png_init_io(png_ptr, fp);
 
    /* If we have already read some of the signature */
    png_set_sig_bytes(png_ptr, sig_read);
 
    /*
     * If you have enough memory to read in the entire image at once, and
     * you need to specify only transforms that can be controlled
     * with one of the PNG_TRANSFORM_* bits (this presently excludes
     * dithering, filling, setting background, and doing gamma
     * adjustment), then you can read the entire image (including pixels)
     * into the info structure with this call
     *
     * PNG_TRANSFORM_STRIP_16 |
     * PNG_TRANSFORM_PACKING  forces 8 bit
     * PNG_TRANSFORM_EXPAND forces to
     *  expand a palette into RGB
     */
    png_read_png(png_ptr, info_ptr, PNG_TRANSFORM_STRIP_16 | PNG_TRANSFORM_PACKING | PNG_TRANSFORM_EXPAND, png_voidp_NULL);
 
    outWidth = png_get_image_width(png_ptr,info_ptr); // ширина изображение
    outHeight = png_get_image_height(png_ptr,info_ptr); // высота изображения
 
   // проверка на наличие альфа-канала
    switch (png_get_color_type(png_ptr,info_ptr)) {
        case PNG_COLOR_TYPE_RGBA:
            outHasAlpha = true;
            break;
        case PNG_COLOR_TYPE_RGB:
            outHasAlpha = false;
            break;
        default:
            std::cout << "Color type " << png_get_color_type(png_ptr,info_ptr) << " not supported" << std::endl;
            png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
            fclose(fp);
            return false;
    }
    unsigned int row_bytes = png_get_rowbytes(png_ptr, info_ptr);
    *outData = (unsigned char*) malloc(row_bytes * outHeight);
 
    png_bytepp row_pointers = png_get_rows(png_ptr, info_ptr);
 
    for (int i = 0; i < outHeight; i++) {
        // note that png is ordered top to bottom, but OpenGL expect it bottom to top
        // so the order or swapped
        memcpy(*outData+(row_bytes * (outHeight-1-i)), row_pointers[i], row_bytes);
    }
 
    /* Clean up after the read, and free any memory allocated */
    png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL);
 
    /* Close the file */
    fclose(fp);
 
    return true;
	}
Exemple #20
0
static void
display_clean_read(struct display *dp)
{
   if (dp->read_pp != NULL)
      png_destroy_read_struct(&dp->read_pp, &dp->read_ip, NULL);
}
Exemple #21
0
int fh_png_load(const char *name, unsigned char *buffer, int x, int y)
{
	static const png_color_16 my_background = {0, 0, 0, 0, 0};

	png_structp png_ptr;
	png_infop info_ptr;
	png_uint_32 width, height;
	unsigned int i;
	int bit_depth, color_type, interlace_type;
	int number_passes, pass;
	png_byte * fbptr;
	FILE * fh;

	if (!(fh = fopen(name, "rb")))
		return(FH_ERROR_FILE);

	png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
	if (png_ptr == NULL) 
		return(FH_ERROR_FORMAT);
	info_ptr = png_create_info_struct(png_ptr);
	if (info_ptr == NULL)
	{
		png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL);
		fclose(fh); 
		return(FH_ERROR_FORMAT);
	}

	if (setjmp(png_ptr->jmpbuf))
	{
		png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
		fclose(fh); 
		return(FH_ERROR_FORMAT);
	}

	png_init_io(png_ptr, fh);

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

	if (color_type == PNG_COLOR_TYPE_PALETTE)
	{
		png_set_palette_to_rgb(png_ptr);
		png_set_background(png_ptr, (png_color_16 *)&my_background, PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0);
		/* other possibility for png_set_background: use png_get_bKGD */
	}

	if (color_type == PNG_COLOR_TYPE_GRAY        ||
	    color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
	{
		png_set_gray_to_rgb(png_ptr);
		png_set_background(png_ptr, (png_color_16 *)&my_background, PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0);
	}

	if (color_type & PNG_COLOR_MASK_ALPHA)
		png_set_strip_alpha(png_ptr);

	if (bit_depth < 8)
		png_set_packing(png_ptr);

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

/* on Intel PC ?:
	if (bit_depth == 16)
		png_set_swap(png_ptr);
*/

	number_passes = png_set_interlace_handling(png_ptr);
	png_read_update_info(png_ptr, info_ptr);

	if (width * 3 != png_get_rowbytes(png_ptr, info_ptr))
	{
		printf("[png.cpp]: Error processing %s - please report (including image).\n", name);
		return(FH_ERROR_FORMAT);
	}

	for(pass = 0; pass < number_passes; pass++)
	{
		fbptr = (png_byte *)buffer;
		for (i = 0; i < height; i++, fbptr += width * 3)
		{
			png_read_row(png_ptr, fbptr, NULL);
		}
	}
	png_read_end(png_ptr, info_ptr);
	png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
	fclose(fh);
	return(FH_ERROR_OK);
}
int read_png_file(const char *file, int32 *pwidth, int32 *pheight, uint8 **image_data_ptr)
{
	FILE         *infile;         /* PNG file pointer */
	png_structp   png_ptr;        /* internally used by libpng */
	png_infop     info_ptr;       /* user requested transforms */
	
	uint8 *image_data;      /* raw png image data */
	char         sig[8];           /* PNG signature array */
	/*char         **row_pointers;   */
	
	int           bit_depth;
	int           color_type;
	
	png_uint_32 width;            /* PNG image width in pixels */
	png_uint_32 height;           /* PNG image height in pixels */
	unsigned int rowbytes;         /* raw bytes at row n in image */
	
	image_data = NULL;
	int i;
	png_bytepp row_pointers = NULL;
	
	/* Open the file. */
	infile = fopen(file, "rb");
	if (!infile) {
		
		return 0;
	}
	
	
	/*
	 * 		13.3 readpng_init()
	 */
	
	/* Check for the 8-byte signature */
	fread(sig, 1, 8, infile);
	
	if (png_sig_cmp((unsigned char *) sig, 0, 8) != 0) {
		fclose(infile);
		return 0;
	}
	
	/* 
	 * Set up the PNG structs 
	 */
	png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
	if (!png_ptr) {
		fclose(infile);
		return 4;    /* out of memory */
	}
	
	info_ptr = png_create_info_struct(png_ptr);
	if (!info_ptr) {
		png_destroy_read_struct(&png_ptr, (png_infopp) NULL, (png_infopp) NULL);
		fclose(infile);
		return 4;    /* out of memory */
	}
	
	
	/*
	 * block to handle libpng errors, 
	 * then check whether the PNG file had a bKGD chunk
	 */
	if (setjmp(png_jmpbuf(png_ptr))) {
		png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
		fclose(infile);
		return 0;
	}
	
	/* 
	 * takes our file stream pointer (infile) and 
	 * stores it in the png_ptr struct for later use.
	 */
	/* png_ptr->io_ptr = (png_voidp)infile;*/
	png_init_io(png_ptr, infile);
	
	/*
	 * lets libpng know that we already checked the 8 
	 * signature bytes, so it should not expect to find 
	 * them at the current file pointer location
	 */
	png_set_sig_bytes(png_ptr, 8);
	
	/* Read the image info.*/
	
	/*
	 * reads and processes not only the PNG file's IHDR chunk 
	 * but also any other chunks up to the first IDAT 
	 * (i.e., everything before the image data).
	 */
	
	/* read all the info up to the image data  */
	png_read_info(png_ptr, info_ptr);
	
	png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, 
				 &color_type, NULL, NULL, NULL);
	
	*pwidth = width;
	*pheight = height;

	if (bit_depth > 8) {
		png_set_strip_16(png_ptr);
	}
#if defined(__DAVAENGINE_WIN32__)
	if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) png_set_gray_1_2_4_to_8(png_ptr);
#endif
    
	if (color_type == PNG_COLOR_TYPE_GRAY ||
		color_type == PNG_COLOR_TYPE_GRAY_ALPHA) {
		png_set_gray_to_rgb(png_ptr);
		png_set_filler(png_ptr, 0xFFFF, PNG_FILLER_AFTER);
	}
	if (color_type == PNG_COLOR_TYPE_PALETTE) {
		png_set_palette_to_rgb(png_ptr);
		png_set_filler(png_ptr, 0xFFFF, PNG_FILLER_AFTER);
	}

	if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
	{
		png_set_tRNS_to_alpha(png_ptr);
		if (CommandLineParser::Instance()->GetVerbose())
			printf("*** TOCHECK: convert tRNS to alpha\n");
	}

	if (color_type == PNG_COLOR_TYPE_RGB)
	{	
		if (CommandLineParser::Instance()->GetVerbose())
			printf("*** Converting %s from RGB to RGBA\n", file);
		png_set_filler(png_ptr, 0xFFFF, PNG_FILLER_AFTER);
	}
		
	/* Update the png info struct.*/
	png_read_update_info(png_ptr, info_ptr);
	
	/* Rowsize in bytes. */
	rowbytes = png_get_rowbytes(png_ptr, info_ptr);
	
	char string_format[16];
	strcpy(string_format, "undefined");
	if (color_type == PNG_COLOR_TYPE_RGBA)
	{
		strcpy(string_format, "RGBA");
	}
	
	
	if (CommandLineParser::Instance()->GetVerbose())
	{
		printf("* Reading PNG file: %s format: %s bit_depth:%d bytes_per_pixel:%d\n", 
		   file,
		   string_format,
		   bit_depth,
		   rowbytes / width);
	}	
	
	/* Allocate the image_data buffer. */
	// printf("r/w: %d %d\n" , rowbytes / width, bit_depth); 
	
	
	if ((image_data = new uint8 [rowbytes * height]) ==NULL) 
	{
		memset(image_data, 0, rowbytes * height);
		png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
		return 4;
    }
	
	if ((row_pointers = (png_bytepp)malloc(height*sizeof(png_bytep))) == NULL) 
	{
        png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
        delete [] (image_data);
        image_data = NULL;
        return 4;
    }
	
	
    /* set the individual row_pointers to point at the correct offsets */
	
    for (i = 0;  i < (int)height;  ++i)
        row_pointers[i] = image_data + i*rowbytes;
	
	
    /* now we can go ahead and just read the whole image */
    png_read_image(png_ptr, row_pointers);
	
    /* and we're done!  (png_read_end() can be omitted if no processing of
     * post-IDAT text/time/etc. is desired) */
	
	/* Clean up. */
	free(row_pointers);
	
	/* Clean up. */
	png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
	fclose(infile);
	
	*image_data_ptr = image_data;
	
	return 1;
}
Exemple #23
0
/* This routine is based in part on the Chapter 13 demo code in
 * "PNG: The Definitive Guide" (http://www.libpng.org/pub/png/book/).
 */
BGD_DECLARE(gdImagePtr) gdImageCreateFromPngCtx (gdIOCtx * infile)
{
	png_byte sig[8];
#ifdef PNG_SETJMP_SUPPORTED
	jmpbuf_wrapper jbw;
#endif
	png_structp png_ptr;
	png_infop info_ptr;
	png_uint_32 width, height, rowbytes, w, h, res_x, res_y;
	int bit_depth, color_type, interlace_type, unit_type;
	int num_palette, num_trans;
	png_colorp palette;
	png_color_16p trans_gray_rgb;
	png_color_16p trans_color_rgb;
	png_bytep trans;
	png_bytep image_data = NULL;
	png_bytepp row_pointers = NULL;
	gdImagePtr im = NULL;
	int i, j, *open = NULL;
	volatile int transparent = -1;
	volatile int palette_allocated = FALSE;

	/* Make sure the signature can't match by dumb luck -- TBB */
	/* GRR: isn't sizeof(infile) equal to the size of the pointer? */
	memset (sig, 0, sizeof (sig));

	/* first do a quick check that the file really is a PNG image; could
	 * have used slightly more general png_sig_cmp() function instead */
	if (gdGetBuf (sig, 8, infile) < 8) {
		return NULL;
	}

	if (png_sig_cmp(sig, 0, 8) != 0) { /* bad signature */
		return NULL;		/* bad signature */
	}

#ifdef PNG_SETJMP_SUPPORTED
	png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, &jbw, gdPngErrorHandler, NULL);
#else
	png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
#endif
	if (png_ptr == NULL) {
		gd_error("gd-png error: cannot allocate libpng main struct\n");
		return NULL;
	}

	info_ptr = png_create_info_struct (png_ptr);
	if (info_ptr == NULL) {
		gd_error("gd-png error: cannot allocate libpng info struct\n");
		png_destroy_read_struct (&png_ptr, NULL, NULL);

		return NULL;
	}

	/* we could create a second info struct here (end_info), but it's only
	 * useful if we want to keep pre- and post-IDAT chunk info separated
	 * (mainly for PNG-aware image editors and converters)
	 */

	/* setjmp() must be called in every non-callback function that calls a
	 * PNG-reading libpng function */
#ifdef PNG_SETJMP_SUPPORTED
	if (setjmp(jbw.jmpbuf)) {
		gd_error("gd-png error: setjmp returns error condition 1\n");
		png_destroy_read_struct (&png_ptr, &info_ptr, NULL);

		return NULL;
	}
#endif

	png_set_sig_bytes (png_ptr, 8);	/* we already read the 8 signature bytes */

	png_set_read_fn (png_ptr, (void *) infile, gdPngReadData);
	png_read_info (png_ptr, info_ptr);	/* read all PNG info up to image data */

	png_get_IHDR (png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, NULL, NULL);
	if ((color_type == PNG_COLOR_TYPE_RGB) || (color_type == PNG_COLOR_TYPE_RGB_ALPHA)
	        || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) {
		im = gdImageCreateTrueColor ((int) width, (int) height);
	} else {
		im = gdImageCreate ((int) width, (int) height);
	}
	if (im == NULL) {
		gd_error("gd-png error: cannot allocate gdImage struct\n");
		png_destroy_read_struct (&png_ptr, &info_ptr, NULL);

		return NULL;
	}

	if (bit_depth == 16) {
		png_set_strip_16 (png_ptr);
	} else if (bit_depth < 8) {
		png_set_packing (png_ptr);	/* expand to 1 byte per pixel */
	}

	/* setjmp() must be called in every non-callback function that calls a
	 * PNG-reading libpng function
	 */
#ifdef PNG_SETJMP_SUPPORTED
	if (setjmp(jbw.jmpbuf)) {
		gd_error("gd-png error: setjmp returns error condition 2\n");
		png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
		gdFree(image_data);
		gdFree(row_pointers);
		if (im) {
			gdImageDestroy(im);
		}
		return NULL;
	}
#endif

#ifdef PNG_pHYs_SUPPORTED
	/* check if the resolution is specified */
	if (png_get_valid(png_ptr, info_ptr, PNG_INFO_pHYs)) {
		if (png_get_pHYs(png_ptr, info_ptr, &res_x, &res_y, &unit_type)) {
			switch (unit_type) {
			case PNG_RESOLUTION_METER:
				im->res_x = DPM2DPI(res_x);
				im->res_y = DPM2DPI(res_y);
				break;
			}
		}
	}
#endif

	switch (color_type) {
	case PNG_COLOR_TYPE_PALETTE:
		png_get_PLTE (png_ptr, info_ptr, &palette, &num_palette);
#ifdef DEBUG
		gd_error("gd-png color_type is palette, colors: %d\n", num_palette);
#endif /* DEBUG */
		if (png_get_valid (png_ptr, info_ptr, PNG_INFO_tRNS)) {
			/* gd 2.0: we support this rather thoroughly now. Grab the
			 * first fully transparent entry, if any, as the value of
			 * the simple-transparency index, mostly for backwards
			 * binary compatibility. The alpha channel is where it's
			 * really at these days.
			 */
			int firstZero = 1;
			png_get_tRNS (png_ptr, info_ptr, &trans, &num_trans, NULL);
			for (i = 0; i < num_trans; ++i) {
				im->alpha[i] = gdAlphaMax - (trans[i] >> 1);
				if ((trans[i] == 0) && (firstZero)) {
					/* 2.0.5: long-forgotten patch from Wez Furlong */
					transparent = i;
					firstZero = 0;
				}
			}
		}
		break;

	case PNG_COLOR_TYPE_GRAY:
		/* create a fake palette and check for single-shade transparency */
		if ((palette = (png_colorp) gdMalloc (256 * sizeof (png_color))) == NULL) {
			gd_error("gd-png error: cannot allocate gray palette\n");
			png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
			return NULL;
		}
		palette_allocated = TRUE;
		if (bit_depth < 8) {
			num_palette = 1 << bit_depth;
			for (i = 0; i < 256; ++i) {
				j = (255 * i) / (num_palette - 1);
				palette[i].red = palette[i].green = palette[i].blue = j;
			}
		} else {
			num_palette = 256;
			for (i = 0; i < 256; ++i) {
				palette[i].red = palette[i].green = palette[i].blue = i;
			}
		}
		if (png_get_valid (png_ptr, info_ptr, PNG_INFO_tRNS)) {
			png_get_tRNS (png_ptr, info_ptr, NULL, NULL, &trans_gray_rgb);
			if (bit_depth == 16) {	/* png_set_strip_16() not yet in effect */
				transparent = trans_gray_rgb->gray >> 8;
			} else {
				transparent = trans_gray_rgb->gray;
			}
			/* Note slight error in 16-bit case:  up to 256 16-bit shades
			 * may get mapped to a single 8-bit shade, and only one of them
			 * is supposed to be transparent.  IOW, both opaque pixels and
			 * transparent pixels will be mapped into the transparent entry.
			 * There is no particularly good way around this in the case
			 * that all 256 8-bit shades are used, but one could write some
			 * custom 16-bit code to handle the case where there are gdFree
			 * palette entries.  This error will be extremely rare in
			 * general, though.  (Quite possibly there is only one such
			 * image in existence.) */
		}
		~PngContext() {
			png_destroy_read_struct(&png, &info, &endinfo);
		}
bool SkPNGImageDecoderMy::onDecodeInit(SkStream* sk_stream,
        png_structp *png_ptrp, png_infop *info_ptrp)
{
    /* 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.  */
    png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,
        NULL, sk_error_fn, NULL);
    //   png_voidp user_error_ptr, user_error_fn, user_warning_fn);
    if (png_ptr == NULL) {
        return false;
    }
    *png_ptrp = png_ptr;

    /* Allocate/initialize the memory for image information. */
    png_infop info_ptr = png_create_info_struct(png_ptr);
    if (info_ptr == NULL) {
        png_destroy_read_struct(&png_ptr, png_infopp_NULL, png_infopp_NULL);
        return false;
    }
    *info_ptrp = info_ptr;

    /* 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))) {
        return false;
    }

    /* If you are using replacement read functions, instead of calling
    * png_init_io() here you would call:
    */
    png_set_read_fn(png_ptr, (void *)sk_stream, sk_read_fn);
    png_set_seek_fn(png_ptr, sk_seek_fn);
    /* where user_io_ptr is a structure you want available to the callbacks */
    /* If we have already read some of the signature */
    // png_set_sig_bytes(png_ptr, 0 /* sig_read */ );

    // hookup our peeker so we can see any user-chunks the caller may be interested in
    png_set_keep_unknown_chunks(png_ptr, PNG_HANDLE_CHUNK_ALWAYS, (png_byte*)"", 0);
    if (this->getPeeker()) {
        png_set_read_user_chunk_fn(png_ptr, (png_voidp)this->getPeeker(), sk_read_user_chunk);
    }

    /* The call to png_read_info() gives us all of the information from the
    * PNG file before the first IDAT (image data chunk). */
    png_read_info(png_ptr, info_ptr);
    png_uint_32 origWidth, origHeight;
    int bit_depth, color_type, interlace_type;
    png_get_IHDR(png_ptr, info_ptr, &origWidth, &origHeight, &bit_depth,
            &color_type, &interlace_type, int_p_NULL, int_p_NULL);

    /* tell libpng to strip 16 bit/color files down to 8 bits/color */
    if (bit_depth == 16) {
        png_set_strip_16(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). */
    if (bit_depth < 8) {
        png_set_packing(png_ptr);
    }
    /* Expand grayscale images to the full 8 bits from 1, 2, or 4 bits/pixel */
    if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) {
        png_set_gray_1_2_4_to_8(png_ptr);
    }

    /* Make a grayscale image into RGB. */
    if (color_type == PNG_COLOR_TYPE_GRAY ||
        color_type == PNG_COLOR_TYPE_GRAY_ALPHA) {
        png_set_gray_to_rgb(png_ptr);
    }
    return true;
}
Exemple #26
0
short load_inp_png_file(ImageData& img, const std::string& fname_inp, ProgramOptions& opts)
{
    FILE* pngfile = fopen(fname_inp.c_str(),"rb");
    if (pngfile == NULL) {
        perror(fname_inp.c_str());
        return ERR_CANT_OPEN;
    }
    png_byte header[8];
    if (fread(header,8,1,pngfile) != 1) {
        perror(fname_inp.c_str());
        fclose(pngfile);
        return ERR_FILE_READ;
    }
    if (png_sig_cmp(header,0,8)) {
        LogErr("%s: Not a PNG file",fname_inp.c_str());
        fclose(pngfile);
        return ERR_BAD_FILE;
    }

    img.png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
    if (!img.png_ptr)
    {
        LogErr("%s: png_create_read_struct error",fname_inp.c_str());
        fclose(pngfile);
        return ERR_BAD_FILE;
    }

    img.info_ptr=png_create_info_struct(img.png_ptr);
    if (!img.info_ptr)
    {
        png_destroy_read_struct(&img.png_ptr, (png_infopp)NULL, (png_infopp)NULL);
        LogErr("%s: png_create_info_struct error",fname_inp.c_str());
        fclose(pngfile);
        return ERR_BAD_FILE;
    }

    img.end_info=png_create_info_struct(img.png_ptr);
    if (!img.end_info)
    {
        png_destroy_read_struct(&img.png_ptr, &img.info_ptr, (png_infopp)NULL);
        LogErr("%s: png_create_info_struct error",fname_inp.c_str());
        fclose(pngfile);
        return ERR_BAD_FILE;
    }

    if (setjmp(png_jmpbuf(img.png_ptr)))
    {
        png_destroy_read_struct(&img.png_ptr, &img.info_ptr, &img.end_info);
        LogErr("%s: PNG error",fname_inp.c_str());
        fclose(pngfile);
        exit(1);
    }

    png_init_io(img.png_ptr, pngfile);
    png_set_sig_bytes(img.png_ptr,8);
    int trafo=PNG_TRANSFORM_PACKING|PNG_TRANSFORM_STRIP_16|PNG_TRANSFORM_EXPAND;
    png_read_png(img.png_ptr, img.info_ptr, trafo , NULL);

    int bit_depth, interlace_type, compression_type, filter_method;
    png_get_IHDR(img.png_ptr, img.info_ptr, &img.width, &img.height, &bit_depth, &img.color_type,
        &interlace_type, &compression_type, &filter_method);

    if ((img.color_type & PNG_COLOR_MASK_COLOR)==0)
    {
        LogErr("%s: Grayscale image not supported",fname_inp.c_str());
        fclose(pngfile);
        return ERR_BAD_FILE;
    }

    fclose(pngfile);

    if (img.color_type==PNG_COLOR_TYPE_PALETTE)
    {
        LogErr("Invalid format. This shouldn't happen. PNG_TRANSFORM_EXPAND transforms image to RGB.");
        return ERR_BAD_FILE;
    }

    if (img.color_type & PNG_COLOR_MASK_ALPHA) {
        img.col_bits = 32;
    } else {
        img.col_bits = 24;
    }

    return ERR_OK;
}
int main(int argc, char *argv[])
{
char filename1[MAXNAMELENGTH], filename2[MAXNAMELENGTH];
int idx, k, j;
FILE *fd, *lut=NULL;
byte *imgarr;
int userfill=-1;
int colorstyle=GRAYSCALE;
int red, green, blue, alpha;
int redarr[256], greenarr[256], bluearr[256], alphaarr[256];
unsigned char lutname[MAXNAMELENGTH];
unsigned char verbose=FALSE;

png_structp png_ptr;
png_infop info_ptr;
png_colorp png_palette;
png_colorp dest_pal;
unsigned char *png_trans;

png_structp in_png_ptr;
png_infop in_info_ptr;
png_uint_32 width, height;
int bit_depth, color_type, interlace_type;
FILE *fp;

png_uint_32  i, rowbytes;
byte  *image_data = NULL;
png_bytepp  row_pointers = NULL;
int bytesperpixel;
int found;

int num_not_found=0;
int rednotfound[MAX_NOT_FOUND], greennotfound[MAX_NOT_FOUND], bluenotfound[MAX_NOT_FOUND];
int return_code=0;

  filename1[0] = '\0';
  filename2[0] = '\0';
  lutname[0] = '\0';

  if (argc < 2) {
    fprintf(stderr, "Usage: RGBApng2Palpng [-v] -lut=<ColorMap file (must contain RGBA)> -fill=<LUT index value> -of=<output palette PNG file> <input RGBA PNG file>\n");
    exit(-1);
  }

  for (j=1; j<argc; j++)
    if ( strcmp(argv[j], "-v") == 0 ) {
      fprintf(stderr, "Verbose mode requested.\n");
      verbose = TRUE;
    }

  for (j=1; j<argc; j++) {
    if (strstr(argv[j], "-of=") == argv[j] ) {
        if ( sscanf(argv[j], "-of=%s", filename2) != 1 ) {
          fprintf(stderr, "Cannot read output file\n");
          exit(-1);
        }
        if (verbose)
          fprintf(stderr, "Output file: %s\n", filename2);
    } else if (strstr(argv[j], "-lut=") == argv[j] ) {
        if ( sscanf(argv[j], "-lut=%s", lutname) != 1 ) {
          fprintf(stderr, "Cannot parse LUT name\n");
          exit(-1);
        }
        if (verbose)
          fprintf(stderr, "Color LUT: %s\n", lutname);
        colorstyle = COLOR;
    } else if (strstr(argv[j], "-fill=") == argv[j] ) {
        if (sscanf(argv[j], "-fill=%d", &userfill) != 1) {
          fprintf(stderr, "Cannot read user fill value\n");
          exit(-1);
        }
        if ( userfill < 0 || userfill > 255 ) {
          fprintf(stderr, "User fill value must be between 0 and 255\n");
          exit(-1);
        }
        if (verbose)
          fprintf(stderr, "User fill value: %d\n", userfill);
    } else if ( strlen(filename2) == 0 &&
                strcmp(argv[j], "-") == 0 ) {
        strcpy(filename2, "stdout");
        if (verbose)
          fprintf(stderr, "Output file: %s\n", filename2);
    } else if ( strcmp(argv[j], "-v") != 0 ) {
        strcpy(filename1, argv[j]);
        if (verbose)
          fprintf(stderr, "Input file: %s\n", filename1);
    }
  }

  if ( strlen(filename1) == 0  ||
       strlen(filename2) == 0  ||
       strlen(lutname) == 0  ||
       userfill < 0 ) {
    fprintf(stderr, "Unable to get all arguments\n");
    exit(-1);
  }

  if ((fp = fopen(filename1, "rb")) == NULL) {
    fprintf(stderr, "Unable to open input file: %s\n", filename1);
    exit(-1);
  }

  in_png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);

  if (in_png_ptr == NULL) {
    fclose(fp);
    fprintf(stderr, "Could not allocate PNG read struct\n");
    return (-1);
  }

  in_info_ptr = png_create_info_struct(in_png_ptr);
  if (in_info_ptr == NULL) {
    fclose(fp);
    png_destroy_read_struct(&in_png_ptr, png_infopp_NULL, png_infopp_NULL);
    fprintf(stderr, "Could not allocate input PNG info struct\n");
    return (-1);
  }

  if (setjmp(png_jmpbuf(in_png_ptr))) {
    /* Free all of the memory associated with the png_ptr and info_ptr */
    png_destroy_read_struct(&in_png_ptr, &in_info_ptr, png_infopp_NULL);
    fclose(fp);
    /* If we get here, we had a problem reading the file */
    return (-1);
  }

  /* Set up the input control if you are using standard C streams */
  png_init_io(in_png_ptr, fp);

  png_read_info(in_png_ptr, in_info_ptr);

  png_get_IHDR(in_png_ptr, in_info_ptr, &width, &height, &bit_depth, &color_type,
       &interlace_type, int_p_NULL, int_p_NULL);

  if (verbose) {
    fprintf(stderr, "Width: %d\n", width);
    fprintf(stderr, "Height: %d\n", height);
    fprintf(stderr, "Bit Depth: %d\n", bit_depth);
    switch(color_type) {
          case 0:
            fprintf(stderr, "Color Type: Gray (0)\n");
            break;
          case 3:
            fprintf(stderr, "Color Type: Palette (3)\n");
            break;
          case 2:
            fprintf(stderr, "Color Type: RGB (2)\n");
            break;
          case 6:
            fprintf(stderr, "Color Type: RGB Alpha (6)\n");
            break;
          case 4:
            fprintf(stderr, "Color Type: Gray Alpha (4)\n");
            break;
          default:
            fprintf(stderr, "Unknown Color Type: %d\n", color_type);
    }
    switch(interlace_type) {
          case 0:
            fprintf(stderr, "Interlace Type: None (0)\n");
            break;
          case 1:
            fprintf(stderr, "Interlace Type: Adam7 (1)\n");
            break;
          default:
            fprintf(stderr, "Unknown Interlace Type: %d\n", interlace_type);
    }
  }

  rowbytes = png_get_rowbytes(in_png_ptr, in_info_ptr);

  if ( verbose ) fprintf(stderr, "Number of bytes per row: %d\n", rowbytes);

  if ((image_data = (byte *)malloc(rowbytes*height)) == NULL) {
    png_destroy_read_struct(&in_png_ptr, &in_info_ptr, NULL);
    exit(-1);
  }

  if ((row_pointers = (png_bytepp)malloc(height*sizeof(png_bytep))) == NULL) {
    png_destroy_read_struct(&in_png_ptr, &in_info_ptr, NULL);
    free(image_data);
    image_data = NULL;
    exit(-1);
  }

  for (i = 0;  i < height;  ++i)
    row_pointers[i] = image_data + i*rowbytes;

  /* now we can go ahead and just read the whole image */

  png_read_image(in_png_ptr, row_pointers);

  imgarr = (byte *) malloc(height * width * sizeof(byte));

  png_palette = (png_colorp)malloc( 256 * sizeof( png_color) );
  dest_pal = png_palette;
  if (colorstyle == GRAYSCALE)
    for (j=0; j<256; j++) {
      dest_pal->red = dest_pal->green = dest_pal->blue = j;
      dest_pal++;
      
      redarr[j] = greenarr[j] = bluearr[j] = j;
      alphaarr[j] = 255;
  } else {
    if ( (lut = fopen(lutname, "r")) != NULL ) {
    	if (strlen(lutname) > 4 && ((!strcmp(lutname + strlen(lutname) - 4, ".xml")))) {
    		fprintf(stderr, "Opening colormap file %s\n", lutname);

    		if (lut) {
    			int size = 1024, pos;
    			int c;
    			int j = 0;
    			char *buffer = (char *)malloc(size);
    			const char *entry_key = "ColorMapEntry";
    			const char *rgb_key = "rgb=";
    			const char *transparent_key = "transparent=";
    			const char *true_str = "\"true\"";
    			
    			do { // read all lines in file
					pos = 0;
					do { // read one line
					c = fgetc(lut);
					if(c != EOF) buffer[pos++] = (char)c;
						if(pos >= size - 1) { // increase buffer length - leave room for 0
							size *=2;
							buffer = (char*)realloc(buffer, size);
						}
					} while(c != EOF && c != '\n');
					buffer[pos] = 0;

					char *entry = strstr(buffer,entry_key);
					char *rgb = strstr(buffer,rgb_key);
					char *transparent = strstr(buffer,transparent_key);
					
					// GIBS colormap RGB values
					if (rgb != NULL && entry != NULL) {
	        			char rgb_string[11];
						int rgb_length = strlen(rgb);
						int rgb_pos = pos - rgb_length;
						memcpy(rgb_string, &buffer[rgb_pos+5], 11);
						rgb_string[11] = '\0';
						// break rgb string into int values
						int rgb_array[3];
						int i = 0;
						char *rgb_values = strtok(rgb_string, ",");
						while (rgb_values != NULL) {
							rgb_array[i++] = strtol(rgb_values,NULL,10);
							rgb_values = strtok(NULL, ",");
						}
						red = rgb_array[0]; green = rgb_array[1]; blue = rgb_array[2];
						dest_pal->red = red;
						dest_pal->green = green;
						dest_pal->blue = blue;

						alpha = strstr(transparent, true_str) != NULL ? 0 : 255;
						
						dest_pal++;
						redarr[j] = red;
						greenarr[j] = green;
						bluearr[j] = blue;
						alphaarr[j] = alpha;
						if ( verbose ) fprintf(stderr, "RGBA: %d %d %d %d \n", redarr[j], greenarr[j] , bluearr[j], alphaarr[j]);
						j++;
					}
    			} while(c != EOF);;
    		    fclose(lut);
    		    free(buffer);
    		}

    	} else {
			for (j=0; j<256; j++)
			  if ( fscanf(lut, "%d %d %d %d", &red, &green, &blue, &alpha) != 4 ) {
				  fprintf(stderr, "Cannot read color index %d in LUT file\n", j);
				  exit(-1);
			  } else {
				  dest_pal->red = red;
				  dest_pal->green = green;
				  dest_pal->blue = blue;
				  dest_pal++;
				  
				  redarr[j] = red;
				  greenarr[j] = green;
				  bluearr[j] = blue;
				  alphaarr[j] = alpha;
			  }
			fclose(lut);
    	}
    } else {
        fprintf(stderr, "Cannot open LUT file %s.\n", lutname);
        exit(-1);
    }
  }

  png_trans = (unsigned char *)malloc(256 * sizeof(unsigned char));
  for (j=0; j<256; j++) {
    png_trans[j] = alphaarr[j];
  }

  switch(color_type) {
    case(PNG_COLOR_TYPE_GRAY): bytesperpixel = 1;
                               break;
    case(PNG_COLOR_TYPE_PALETTE): bytesperpixel = 1;
                               break;
    case(PNG_COLOR_TYPE_RGB): bytesperpixel = 3;
                               break;
    case(PNG_COLOR_TYPE_RGB_ALPHA): bytesperpixel = 4;
                               break;
    case(PNG_COLOR_TYPE_GRAY_ALPHA): bytesperpixel = 2;
                               break;
    default:
            fprintf(stderr, "Unknown Color Type: %d\n", color_type);
            exit(-1);
  }

  if ( color_type != PNG_COLOR_TYPE_RGB && color_type != PNG_COLOR_TYPE_RGB_ALPHA ) {
    fprintf(stderr, "Color Type must be RGB or RGBA.\n");
    exit(-1);
  }
  
  if ( verbose ) fprintf(stderr, "Bytes per Pixel: %d\n", bytesperpixel);

  for (i = 0;  i < height;  i++) {
    for (j = 0;  j < width;  j++) {

      idx = i*width+j;
      red = image_data[i*width*bytesperpixel+j*bytesperpixel];
      green = image_data[i*width*bytesperpixel+j*bytesperpixel+1];
      blue = image_data[i*width*bytesperpixel+j*bytesperpixel+2];
  
      found = FALSE;
      for (k = 0;  k < 256;  k++) {

        if ( red == redarr[k] &&
             green == greenarr[k] &&
             blue == bluearr[k] ) {
              imgarr[idx] = (unsigned char) k;
              found = TRUE;
              break;
        }
      }
      if ( !found ) {
        imgarr[idx] = (unsigned char) userfill;
        found = FALSE;
        if ( num_not_found < MAX_NOT_FOUND ) {
          for (k = 0; k < num_not_found; k++) {
            if ( red == rednotfound[k] &&
                 green == greennotfound[k] &&
                 blue == bluenotfound[k] ) {
              found = TRUE;
              break;
            }
          }
          if ( !found ) {
            rednotfound[num_not_found] = red;
            greennotfound[num_not_found] = green;
            bluenotfound[num_not_found] = blue;
            num_not_found++;
          }
        }
      }
    }
  }

  if ( num_not_found > 0 ) {
    return_code = num_not_found;
    fprintf(stderr, "%d Colors in image not found in color table\n", num_not_found);
    for (k = 0; k < num_not_found; k++) {
      fprintf(stderr, "%3d %3d %3d\n", rednotfound[k], greennotfound[k], bluenotfound[k]);
    }
  }

  // Done with the read, clean up
  free(row_pointers);
  row_pointers = NULL;

  png_read_end(in_png_ptr, NULL);
  
  free(image_data);
  image_data = NULL;

  fclose(fp);

  // Start the write

  if (strcmp(filename2, "stdout") == 0)
    fd = stdout;
  else if ( (fd = fopen(filename2, "wb")) == NULL ) {
    fprintf(stderr, "Cannot open file %s.\n", filename2);
    exit(-1);
  }

  // Initialize write structure
  png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
  if (png_ptr == NULL) {
    fprintf(stderr, "Could not allocate PNG write struct\n");
    exit(-1);
  }

  // Initialize info structure
  info_ptr = png_create_info_struct(png_ptr);
  if (info_ptr == NULL) {
    fprintf(stderr, "Could not allocate PNG info struct\n");
    exit(-1);
  }

  if (setjmp(png_jmpbuf(png_ptr))) {
    fprintf(stderr, "Error during PNG init_io\n");
    exit(-1);
  }

  png_init_io(png_ptr, fd);

  if (setjmp(png_jmpbuf(png_ptr))) {
    fprintf(stderr, "Error during PNG set header\n");
    exit(-1);
  }

  // Write header (8 bit colour depth)
  png_set_IHDR(png_ptr, info_ptr, width, height,
         8, PNG_COLOR_TYPE_PALETTE, PNG_INTERLACE_NONE,
         PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);

  if (setjmp(png_jmpbuf(png_ptr))) {
    fprintf(stderr, "Error during PNG set pallette\n");
    exit(-1);
  }

  png_set_PLTE(png_ptr, info_ptr, png_palette, 256);

  if (setjmp(png_jmpbuf(png_ptr))) {
    fprintf(stderr, "Error during PNG set transparency\n");
    exit(-1);
  }

  png_set_tRNS(png_ptr, info_ptr, png_trans, 256, NULL);

  if (setjmp(png_jmpbuf(png_ptr))) {
    fprintf(stderr, "Error during PNG write info\n");
    exit(-1);
  }

  png_write_info(png_ptr, info_ptr);

  if (setjmp(png_jmpbuf(png_ptr))) {
    fprintf(stderr, "Error during PNG write row\n");
    exit(-1);
  }

  for (k=0; k<height; k++) {
    idx = k * width;
    png_write_row(png_ptr, &imgarr[idx]);
  }

  if (setjmp(png_jmpbuf(png_ptr))) {
    fprintf(stderr, "Error during PNG write end\n");
    exit(-1);
  }

  // End write
  png_write_end(png_ptr, NULL);

  fclose(fd);
  free(imgarr);
  free(png_palette);
  free(png_trans);

  if (info_ptr != NULL) png_free_data(png_ptr, info_ptr, PNG_FREE_ALL, -1);
  if (png_ptr != NULL) png_destroy_write_struct(&png_ptr, (png_infopp)NULL);

  return return_code;

}
Exemple #28
0
struct IplImage *ipl_readimg(char *path, int mode)
{
	FILE *f;
	unsigned char head[8];
	int numb = 8, w, h, nchans = 3, y; 
	size_t sznumb;
	struct IplImage *res;
	png_bytep* rows;
	png_structp pngp;
	png_infop infop;
	
	if (!(f = fopen(path, "rb"))) { 
		perror("error opening file\n");
		return NULL;
	}

	sznumb = fread(head, sizeof(char), numb, f);
	
	if (png_sig_cmp(head, 0, 8)) {
		perror("is not png");
		fclose(f);
		return NULL;
	}
	
	if (!(pngp = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL))) {
		perror("can't create read struct");
		fclose(f);
		return NULL;
	}
	
	if (!(infop = png_create_info_struct(pngp))) {
		perror("can't create info");
		png_destroy_read_struct(&pngp, NULL, NULL);
		fclose(f);
		return NULL;
	}

	if (setjmp(png_jmpbuf(pngp))) {
		perror("error in jumpbuf");
		png_destroy_read_struct(&pngp, &infop, NULL);
		fclose(f);
		return NULL;
	}

	png_init_io(pngp, f);
	png_set_sig_bytes(pngp, sznumb);

	png_read_info(pngp, infop);
	
	png_set_strip_alpha(pngp);	
	png_set_strip_16(pngp);
	if (mode) {
		nchans = 3;
		png_set_palette_to_rgb(pngp);
	} else {	
		nchans = 1;
		png_set_rgb_to_gray(pngp, 1, 0.0f, 0.0f);
		png_set_expand_gray_1_2_4_to_8(pngp);
	}
	
	png_set_interlace_handling(pngp);
	png_read_update_info(pngp, infop);

	w = png_get_image_width(pngp, infop);
	h = png_get_image_height(pngp, infop);

	rows = (png_bytep *)malloc(sizeof(png_bytep) * h);
	for (y = 0; y < h; y++) {
		rows[y] = (png_byte *)malloc(png_get_rowbytes(pngp, infop));
	}

	png_read_image(pngp, rows);

	
	
	res = (struct IplImage *)malloc(sizeof(struct IplImage));
	res->width = w;
	res->height = h;
	res->nchans = nchans;
	res->data = (unsigned char *)malloc(sizeof(unsigned char) * w * h * 3);

	for (y = 0; y < h; y++) 
		memcpy(&(res->data[nchans * y * w]), rows[y], sizeof(png_byte) * png_get_rowbytes(pngp, infop));
 
	for (y = 0; y < h; y++)
		free(rows[y]); 
	
	free(rows);

	fclose(f);
	return res;
}
Exemple #29
0
int
png_include_image (pdf_ximage *ximage, FILE *png_file)
{
  pdf_obj  *stream;
  pdf_obj  *stream_dict;
  pdf_obj  *colorspace, *mask, *intent;
  png_bytep stream_data_ptr;
  int       trans_type;
  ximage_info info;
  /* Libpng stuff */
  png_structp png_ptr;
  png_infop   png_info_ptr;
  png_byte    bpc, color_type;
  png_uint_32 width, height, rowbytes;

  pdf_ximage_init_image_info(&info);

  stream      = NULL;
  stream_dict = NULL;
  colorspace  = mask = intent = NULL;

  rewind (png_file);
  png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, warn);
  if (png_ptr == NULL ||
      (png_info_ptr = png_create_info_struct (png_ptr)) == NULL) {
    WARN("%s: Creating Libpng read/info struct failed.", PNG_DEBUG_STR);
    if (png_ptr)
      png_destroy_read_struct(&png_ptr, NULL, NULL);
    return -1;
  }

#if PNG_LIBPNG_VER >= 10603
  /* ignore possibly incorrect CMF bytes */
  png_set_option(png_ptr, PNG_MAXIMUM_INFLATE_WINDOW, PNG_OPTION_ON);
#endif

  /* Inititializing file IO. */
  png_init_io (png_ptr, png_file);

  /* Read PNG info-header and get some info. */
  png_read_info(png_ptr, png_info_ptr);
  color_type = png_get_color_type  (png_ptr, png_info_ptr);
  width      = png_get_image_width (png_ptr, png_info_ptr);
  height     = png_get_image_height(png_ptr, png_info_ptr);
  bpc        = png_get_bit_depth   (png_ptr, png_info_ptr);

  /* We do not need 16-bpc color. Ask libpng to convert down to 8-bpc. */
  if (bpc > 8) {
    png_set_strip_16(png_ptr);
    bpc = 8;
  }
  /* Ask libpng to gamma-correct.
   * It is wrong to assume screen gamma value 2.2 but...
   * We do gamma correction here only when uncalibrated color space is used. 
   */
  if (!png_get_valid(png_ptr, png_info_ptr, PNG_INFO_iCCP) &&
      !png_get_valid(png_ptr, png_info_ptr, PNG_INFO_sRGB) &&
      !png_get_valid(png_ptr, png_info_ptr, PNG_INFO_cHRM) &&
      !png_get_valid(png_ptr, png_info_ptr, PNG_INFO_sRGB) &&
       png_get_valid(png_ptr, png_info_ptr, PNG_INFO_gAMA)) {
    double G = 1.0;
    png_get_gAMA (png_ptr, png_info_ptr, &G);
    png_set_gamma(png_ptr, 2.2, G);
  }

  trans_type = check_transparency(png_ptr, png_info_ptr);
  /* check_transparency() does not do updata_info() */
  png_read_update_info(png_ptr, png_info_ptr);
  rowbytes = png_get_rowbytes(png_ptr, png_info_ptr);

  /* Values listed below will not be modified in the remaining process. */
  info.width  = width;
  info.height = height;
  info.bits_per_component = bpc;

  if (compat_mode)
    info.xdensity = info.ydensity = 72.0 / 100.0;
  else
  {
    png_uint_32 xppm = png_get_x_pixels_per_meter(png_ptr, png_info_ptr);
    png_uint_32 yppm = png_get_y_pixels_per_meter(png_ptr, png_info_ptr);

    if (xppm > 0)
      info.xdensity = 72.0 / 0.0254 / xppm;
    if (yppm > 0)
      info.ydensity = 72.0 / 0.0254 / yppm;
  }

  stream      = pdf_new_stream (STREAM_COMPRESS);
  stream_dict = pdf_stream_dict(stream);

  stream_data_ptr = (png_bytep) NEW(rowbytes*height, png_byte);
  read_image_data(png_ptr, stream_data_ptr, height, rowbytes);

  /* Non-NULL intent means there is valid sRGB chunk. */
  intent = get_rendering_intent(png_ptr, png_info_ptr);
  if (intent)
    pdf_add_dict(stream_dict, pdf_new_name("Intent"), intent);

  switch (color_type) {
  case PNG_COLOR_TYPE_PALETTE:

    colorspace = create_cspace_Indexed(png_ptr, png_info_ptr);

    switch (trans_type) {
    case PDF_TRANS_TYPE_BINARY:
      /* Color-key masking */
      mask = create_ckey_mask(png_ptr, png_info_ptr);
      break;
    case PDF_TRANS_TYPE_ALPHA:
      /* Soft mask */
      mask = create_soft_mask(png_ptr, png_info_ptr, stream_data_ptr, width, height);
      break;
    default:
      /* Nothing to be done here.
       * No tRNS chunk or image already composited with background color.
       */
      break;
    }
    break;
  case PNG_COLOR_TYPE_RGB:
  case PNG_COLOR_TYPE_RGB_ALPHA:

    if (png_get_valid(png_ptr, png_info_ptr, PNG_INFO_iCCP))
      colorspace = create_cspace_ICCBased(png_ptr, png_info_ptr);
    else if (intent) {
      colorspace = create_cspace_sRGB(png_ptr, png_info_ptr);
    } else {
      colorspace = create_cspace_CalRGB(png_ptr, png_info_ptr);
    }
    if (!colorspace)
      colorspace = pdf_new_name("DeviceRGB");

    switch (trans_type) {
    case PDF_TRANS_TYPE_BINARY:
      mask = create_ckey_mask(png_ptr, png_info_ptr);
      break;
    /* rowbytes changes 4 to 3 at here */
    case PDF_TRANS_TYPE_ALPHA:
      mask = strip_soft_mask(png_ptr, png_info_ptr,
                             stream_data_ptr, &rowbytes, width, height);
      break;
    default:
      mask = NULL;
    }
    info.num_components = 3;
    break;

  case PNG_COLOR_TYPE_GRAY:
  case PNG_COLOR_TYPE_GRAY_ALPHA:

    if (png_get_valid(png_ptr, png_info_ptr, PNG_INFO_iCCP))
      colorspace = create_cspace_ICCBased(png_ptr, png_info_ptr);
    else if (intent) {
      colorspace = create_cspace_sRGB(png_ptr, png_info_ptr);
    } else {
      colorspace = create_cspace_CalGray(png_ptr, png_info_ptr);
    }
    if (!colorspace)
      colorspace = pdf_new_name("DeviceGray");

    switch (trans_type) {
    case PDF_TRANS_TYPE_BINARY:
      mask = create_ckey_mask(png_ptr, png_info_ptr);
      break;
    case PDF_TRANS_TYPE_ALPHA:
      mask = strip_soft_mask(png_ptr, png_info_ptr,
                             stream_data_ptr, &rowbytes, width, height);
      break;
    default:
      mask = NULL;
    }
    info.num_components = 1;
    break;

  default:
    WARN("%s: Unknown PNG colortype %d.", PNG_DEBUG_STR, color_type);
  }
  pdf_add_dict(stream_dict, pdf_new_name("ColorSpace"), colorspace);

  pdf_add_stream(stream, stream_data_ptr, rowbytes*height);
  RELEASE(stream_data_ptr);

  if (mask) {
    if (trans_type == PDF_TRANS_TYPE_BINARY)
      pdf_add_dict(stream_dict, pdf_new_name("Mask"), mask);
    else if (trans_type == PDF_TRANS_TYPE_ALPHA) {
      pdf_add_dict(stream_dict, pdf_new_name("SMask"), pdf_ref_obj(mask));
      pdf_release_obj(mask);
    } else {
      WARN("%s: Unknown transparency type...???", PNG_DEBUG_STR);
      pdf_release_obj(mask);
    }
  }

  /* Finally read XMP Metadata
   * See, XMP Specification Part 3, Storage in Files
   * http://www.adobe.com/jp/devnet/xmp.html
   *
   * We require libpng version >= 1.6.14 since prior versions
   * of libpng had a bug that incorrectly treat the compression
   * flag of iTxt chunks.
   */
#if PNG_LIBPNG_VER >= 10614
  if (pdf_get_version() >= 4) {
    png_textp text_ptr;
    pdf_obj  *XMP_stream, *XMP_stream_dict;
    int       i, num_text;
    int       have_XMP = 0;

    num_text = png_get_text(png_ptr, png_info_ptr, &text_ptr, NULL);
    for (i = 0; i < num_text; i++) {
      if (!memcmp(text_ptr[i].key, "XML:com.adobe.xmp", 17)) {
        /* XMP found */
        if (text_ptr[i].compression != PNG_ITXT_COMPRESSION_NONE ||
            text_ptr[i].itxt_length == 0)
          WARN("%s: Invalid value(s) in iTXt chunk for XMP Metadata.", PNG_DEBUG_STR);
        else if (have_XMP)
          WARN("%s: Multiple XMP Metadata. Don't know how to treat it.", PNG_DEBUG_STR);
        else {
          /* We compress XMP metadata for included images here.
           * It is not recommended to compress XMP metadata for PDF documents but
           * we compress XMP metadata for included images here to avoid confusing
           * application programs that only want PDF document global XMP metadata
           * and scan for that.
           */
          XMP_stream = pdf_new_stream(STREAM_COMPRESS);
          XMP_stream_dict = pdf_stream_dict(XMP_stream);
          pdf_add_dict(XMP_stream_dict,
                       pdf_new_name("Type"), pdf_new_name("Metadata"));
          pdf_add_dict(XMP_stream_dict,
                       pdf_new_name("Subtype"), pdf_new_name("XML"));
          pdf_add_stream(XMP_stream, text_ptr[i].text, text_ptr[i].itxt_length);
          pdf_add_dict(stream_dict,
                       pdf_new_name("Metadata"), pdf_ref_obj(XMP_stream));
          pdf_release_obj(XMP_stream);
          have_XMP = 1;
        }
      }
    }
  }
#endif /* PNG_LIBPNG_VER */

  png_read_end(png_ptr, NULL);

  /* Cleanup */
  if (png_info_ptr)
    png_destroy_info_struct(png_ptr, &png_info_ptr);
  if (png_ptr)
    png_destroy_read_struct(&png_ptr, NULL, NULL);

  pdf_ximage_set_image(ximage, &info, stream);

  return 0;
}
static HPDF_STATUS
LoadPngData  (HPDF_Dict     image,
              HPDF_Xref     xref,
              HPDF_Stream   png_data,
              HPDF_BOOL     delayed_loading)

{
	HPDF_STATUS ret = HPDF_OK;

	png_structp png_ptr = NULL;
	png_infop info_ptr = NULL;

	HPDF_PTRACE ((" HPDF_Image_LoadPngImage\n"));

	/* create read_struct. */
	png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING,
			image->error, PngErrorFunc, PngErrorFunc);

	if (png_ptr == NULL) {
		HPDF_SetError (image->error, HPDF_FAILD_TO_ALLOC_MEM, 0);
		return HPDF_FAILD_TO_ALLOC_MEM;
	}

	/* create info-struct */
	info_ptr = png_create_info_struct (png_ptr);

	if (info_ptr == NULL) {
		HPDF_SetError (image->error, HPDF_FAILD_TO_ALLOC_MEM, 0);
		goto Exit;
	}

	png_set_sig_bytes (png_ptr, HPDF_PNG_BYTES_TO_CHECK);
	png_set_read_fn (png_ptr, (void *)png_data, (png_rw_ptr)&PngReadFunc);

	/* reading info structure. */
	png_read_info(png_ptr, info_ptr);
	if (image->error->error_no != HPDF_OK) {
		goto Exit;
	}

	/* 16bit images are not supported. */
	if (info_ptr->bit_depth == 16) {
		png_set_strip_16(png_ptr);
	}

	png_read_update_info(png_ptr, info_ptr);
	if (image->error->error_no != HPDF_OK) {
		goto Exit;
	}

	/* check palette-based images for transparent areas and load them immediately if found */
	if (xref && PNG_COLOR_TYPE_PALETTE & info_ptr->color_type) {
		png_bytep trans;
		int num_trans;
		HPDF_Dict smask;
		png_bytep smask_data;

		if (!png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS) || 
			!png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, NULL)) {
			goto no_transparent_color_in_palette;
		}

		smask = HPDF_DictStream_New (image->mmgr, xref);
		if (!smask) {
			ret = HPDF_FAILD_TO_ALLOC_MEM;
			goto Exit;
		}

		smask->header.obj_class |= HPDF_OSUBCLASS_XOBJECT;
		ret = HPDF_Dict_AddName (smask, "Type", "XObject");
		ret += HPDF_Dict_AddName (smask, "Subtype", "Image");
		ret += HPDF_Dict_AddNumber (smask, "Width", (HPDF_UINT)info_ptr->width);
		ret += HPDF_Dict_AddNumber (smask, "Height", (HPDF_UINT)info_ptr->height);
		ret += HPDF_Dict_AddName (smask, "ColorSpace", "DeviceGray");
		ret += HPDF_Dict_AddNumber (smask, "BitsPerComponent", (HPDF_UINT)info_ptr->bit_depth);

		if (ret != HPDF_OK) {
			HPDF_Dict_Free(smask);
			ret = HPDF_INVALID_PNG_IMAGE;
			goto Exit;
		}

		smask_data = HPDF_GetMem(image->mmgr, info_ptr->width * info_ptr->height);
		if (!smask_data) {
			HPDF_Dict_Free(smask);
			ret = HPDF_FAILD_TO_ALLOC_MEM;
			goto Exit;
		}

		if (ReadTransparentPaletteData(image, png_ptr, info_ptr, smask_data, trans, num_trans) != HPDF_OK) {
			HPDF_FreeMem(image->mmgr, smask_data);
			HPDF_Dict_Free(smask);
			ret = HPDF_INVALID_PNG_IMAGE;
			goto Exit;
		}

		if (HPDF_Stream_Write(smask->stream, smask_data, info_ptr->width * info_ptr->height) != HPDF_OK) {
			HPDF_FreeMem(image->mmgr, smask_data);
			HPDF_Dict_Free(smask);
			ret = HPDF_FILE_IO_ERROR;
			goto Exit;
		}
		HPDF_FreeMem(image->mmgr, smask_data);


		ret += CreatePallet(image, png_ptr, info_ptr);
		ret += HPDF_Dict_AddNumber (image, "Width", (HPDF_UINT)info_ptr->width);
		ret += HPDF_Dict_AddNumber (image, "Height", (HPDF_UINT)info_ptr->height);
		ret += HPDF_Dict_AddNumber (image, "BitsPerComponent",	(HPDF_UINT)info_ptr->bit_depth);
		ret += HPDF_Dict_Add (image, "SMask", smask);

		png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
		return HPDF_OK;
	}

no_transparent_color_in_palette:

	/* read images with alpha channel right away 
	   we have to do this because image transparent mask must be added to the Xref */
	if (xref && PNG_COLOR_MASK_ALPHA & info_ptr->color_type) {
		HPDF_Dict smask;
		png_bytep smask_data;

		smask = HPDF_DictStream_New (image->mmgr, xref);
		if (!smask) {
			ret = HPDF_FAILD_TO_ALLOC_MEM;
			goto Exit;
		}

		smask->header.obj_class |= HPDF_OSUBCLASS_XOBJECT;
		ret = HPDF_Dict_AddName (smask, "Type", "XObject");
		ret += HPDF_Dict_AddName (smask, "Subtype", "Image");
		ret += HPDF_Dict_AddNumber (smask, "Width", (HPDF_UINT)info_ptr->width);
		ret += HPDF_Dict_AddNumber (smask, "Height", (HPDF_UINT)info_ptr->height);
		ret += HPDF_Dict_AddName (smask, "ColorSpace", "DeviceGray");
		ret += HPDF_Dict_AddNumber (smask, "BitsPerComponent", (HPDF_UINT)info_ptr->bit_depth);

		if (ret != HPDF_OK) {
			HPDF_Dict_Free(smask);
			ret = HPDF_INVALID_PNG_IMAGE;
			goto Exit;
		}

		smask_data = HPDF_GetMem(image->mmgr, info_ptr->width * info_ptr->height);
		if (!smask_data) {
			HPDF_Dict_Free(smask);
			ret = HPDF_FAILD_TO_ALLOC_MEM;
			goto Exit;
		}

		if (ReadTransparentPngData(image, png_ptr, info_ptr, smask_data) != HPDF_OK) {
			HPDF_FreeMem(image->mmgr, smask_data);
			HPDF_Dict_Free(smask);
			ret = HPDF_INVALID_PNG_IMAGE;
			goto Exit;
		}

		if (HPDF_Stream_Write(smask->stream, smask_data, info_ptr->width * info_ptr->height) != HPDF_OK) {
			HPDF_FreeMem(image->mmgr, smask_data);
			HPDF_Dict_Free(smask);
			ret = HPDF_FILE_IO_ERROR;
			goto Exit;
		}
		HPDF_FreeMem(image->mmgr, smask_data);

		ret += HPDF_Dict_AddName (image, "ColorSpace", "DeviceRGB");
		ret += HPDF_Dict_AddNumber (image, "Width", (HPDF_UINT)info_ptr->width);
		ret += HPDF_Dict_AddNumber (image, "Height", (HPDF_UINT)info_ptr->height);
		ret += HPDF_Dict_AddNumber (image, "BitsPerComponent",	(HPDF_UINT)info_ptr->bit_depth);
		ret += HPDF_Dict_Add (image, "SMask", smask);

		png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
		return HPDF_OK;
	}

	/* if the image has color palette, copy the pallet of the image to
	 * create color map.
	 */
	if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
		ret = CreatePallet(image, png_ptr, info_ptr);
	else if (info_ptr->color_type == PNG_COLOR_TYPE_GRAY)
		ret = HPDF_Dict_AddName (image, "ColorSpace", "DeviceGray");
	else
		ret = HPDF_Dict_AddName (image, "ColorSpace", "DeviceRGB");

	if (ret != HPDF_OK)
		goto Exit;

	/* read image-data
	 * if the image is interlaced, read whole image at once.
	 * if delayed_loading is HPDF_TRUE, the data does not load this phase.
	 */
	if (delayed_loading) {
		image->before_write_fn = PngBeforeWrite;
		image->after_write_fn = PngAfterWrite;
	} else {
		if (png_get_interlace_type(png_ptr, info_ptr) != PNG_INTERLACE_NONE)
			ret = ReadPngData_Interlaced(image, png_ptr, info_ptr);
		else
			ret = ReadPngData(image, png_ptr, info_ptr);

		if (ret != HPDF_OK)
			goto Exit;
	}

	/* setting the info of the image. */
	if (HPDF_Dict_AddNumber (image, "Width", (HPDF_UINT)info_ptr->width)
			!= HPDF_OK)
		goto Exit;

	if (HPDF_Dict_AddNumber (image, "Height", (HPDF_UINT)info_ptr->height)
			!= HPDF_OK)
		goto Exit;

	if (HPDF_Dict_AddNumber (image, "BitsPerComponent",
				(HPDF_UINT)info_ptr->bit_depth) != HPDF_OK)
		goto Exit;

	/* clean up */
	png_destroy_read_struct(&png_ptr, &info_ptr, NULL);

	return HPDF_OK;

Exit:
	png_destroy_read_struct(&png_ptr, &info_ptr, NULL);

	if (ret != HPDF_OK) {
		return ret;
	}
	return image->error->error_no;
}