Esempio n. 1
0
static int
png2vips_image( Read *read, VipsImage *out )
{
	int interlace_type = png_get_interlace_type( read->pPng, read->pInfo );
	VipsImage **t = (VipsImage **) 
		vips_object_local_array( VIPS_OBJECT( out ), 3 );

	if( interlace_type != PNG_INTERLACE_NONE ) { 
		/* Arg awful interlaced image. We have to load to a huge mem 
		 * buffer, then copy to out.
		 */
		t[0] = vips_image_new_memory();
		if( png2vips_header( read, t[0] ) ||
			png2vips_interlace( read, t[0] ) ||
			vips_image_write( t[0], out ) )
			return( -1 );
	}
	else {
		t[0] = vips_image_new();
		if( png2vips_header( read, t[0] ) ||
			vips_image_generate( t[0], 
				NULL, png2vips_generate, NULL, 
				read, NULL ) ||
			vips_sequential( t[0], &t[1], 
				"tile_height", 8,
				"access", read->readbehind ? 
					VIPS_ACCESS_SEQUENTIAL : 
					VIPS_ACCESS_SEQUENTIAL_UNBUFFERED,
				NULL ) ||
			vips_image_write( t[1], out ) )
			return( -1 );
	}

	return( 0 );
}
Esempio n. 2
0
void pngSetHeader(PngStream* stream)
{
	stream->info.imageWidth = png_get_image_width(stream->png_ptr, stream->info_ptr);
	stream->info.imageHeight = png_get_image_height(stream->png_ptr, stream->info_ptr);
	stream->info.numComponents = png_get_channels(stream->png_ptr, stream->info_ptr);
	stream->info.colorSpace = getPngDecColourType(png_get_color_type(stream->png_ptr, stream->info_ptr));
	stream->info.bitDepth = png_get_bit_depth(stream->png_ptr, stream->info_ptr);
	stream->info.interlaceMethod = png_get_interlace_type(stream->png_ptr, stream->info_ptr);
	stream->info.chunkInformation = pngDecGetChunkInformation(stream);
}
Esempio n. 3
0
void oil_libpng_read_scanline(struct oil_libpng *ol, unsigned char *outbuf)
{
	switch (png_get_interlace_type(ol->rpng, ol->rinfo)) {
	case PNG_INTERLACE_NONE:
		read_scanline(ol);
		break;
	case PNG_INTERLACE_ADAM7:
		read_scanline_interlaced(ol);
		break;
	}
	oil_scale_out(&ol->os, outbuf);
}
Esempio n. 4
0
int image_png_read_header(MediaScanImage *i, MediaScanResult *r) {
  int x;
  PNGData *p = malloc(sizeof(PNGData));
  i->_png = (void *)p;
  LOG_MEM("new PNGData @ %p\n", i->_png);

  p->buf = (Buffer *)r->_buf;
  p->fp = r->_fp;
  p->path = r->path;

  p->png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, (png_voidp) p, image_png_error, image_png_warning);
  if (!p->png_ptr)
    FATAL("Could not initialize libpng\n");

  p->info_ptr = png_create_info_struct(p->png_ptr);
  if (!p->info_ptr) {
    png_destroy_read_struct(&p->png_ptr, (png_infopp) NULL, (png_infopp) NULL);
    FATAL("Could not initialize libpng\n");
  }

  if (setjmp(png_jmpbuf(p->png_ptr))) {
    image_png_destroy(i);
    return 0;
  }

  png_set_read_fn(p->png_ptr, p, image_png_read_buf);

  png_read_info(p->png_ptr, p->info_ptr);

  i->width = png_get_image_width(p->png_ptr, p->info_ptr);
  i->height = png_get_image_height(p->png_ptr, p->info_ptr);
  i->channels = png_get_channels(p->png_ptr, p->info_ptr);
  i->has_alpha = 1;
  r->mime_type = MIME_IMAGE_PNG;

  // Match with DLNA profile
  // DLNA does not support interlaced images
  if (png_get_interlace_type(p->png_ptr, p->info_ptr) == PNG_INTERLACE_NONE) {
    for (x = 0; png_profiles_mapping[x].profile; x++) {
      if (i->width <= png_profiles_mapping[x].max_width && i->height <= png_profiles_mapping[x].max_height) {
        r->dlna_profile = png_profiles_mapping[x].profile->id;
        break;
      }
    }
  }

  return 1;
}
Esempio n. 5
0
int oil_libpng_init(struct oil_libpng *ol, png_structp rpng, png_infop rinfo,
	int out_width, int out_height)
{
	int ret, in_width, in_height, buf_len;
	enum oil_colorspace cs;

	ol->rpng = rpng;
	ol->rinfo = rinfo;
	ol->in_vpos = 0;
	ol->inbuf = NULL;
	ol->inimage = NULL;

	cs = png_cs_to_oil(png_get_color_type(rpng, rinfo));
	if (cs == OIL_CS_UNKNOWN) {
		return -1;
	}

	in_width = png_get_image_width(rpng, rinfo);
	in_height = png_get_image_height(rpng, rinfo);
	ret = oil_scale_init(&ol->os, in_height, out_height, in_width,
		out_width, cs);
	if (ret!=0) {
		free(ol->inbuf);
		return ret;
	}

	buf_len = png_get_rowbytes(rpng, rinfo);
	switch (png_get_interlace_type(rpng, rinfo)) {
	case PNG_INTERLACE_NONE:
		ol->inbuf = malloc(buf_len);
		if (!ol->inbuf) {
			oil_scale_free(&ol->os);
			return -2;
		}
		break;
	case PNG_INTERLACE_ADAM7:
		ol->inimage = alloc_full_image_buf(in_height, buf_len);
		if (!ol->inimage) {
			oil_scale_free(&ol->os);
			return -2;
		}
		png_read_image(rpng, ol->inimage);
		break;
	}

	return 0;
}
Esempio n. 6
0
/* Interlaced PNGs need to be entirely decompressed into memory then can be
 * served partially from there. Non-interlaced PNGs may be read sequentially.
 */
gboolean
vips__png_isinterlaced( const char *filename )
{
	VipsImage *image;
	Read *read;
	int interlace_type;

	image = vips_image_new();
	if( !(read = read_new_filename( image, filename, FALSE )) ) {
		g_object_unref( image );
		return( -1 );
	}
	interlace_type = png_get_interlace_type( read->pPng, read->pInfo );
	g_object_unref( image );

	return( interlace_type != PNG_INTERLACE_NONE );
}
Esempio n. 7
0
/* Interlaced PNGs need to be entirely decompressed into memory then can be
 * served partially from there. Non-interlaced PNGs may be read sequentially.
 */
gboolean
vips__png_isinterlaced_buffer( const void *buffer, size_t length )
{
	VipsImage *image;
	Read *read;
	int interlace_type;

	image = vips_image_new();

	if( !(read = read_new_buffer( image, buffer, length, TRUE )) ) { 
		g_object_unref( image );
		return( -1 );
	}
	interlace_type = png_get_interlace_type( read->pPng, read->pInfo );
	g_object_unref( image );

	return( interlace_type != PNG_INTERLACE_NONE );
}
Esempio n. 8
0
File: png.c Progetto: Gingar/port
void png_row_callback(png_structp png_ptr, png_bytep new_row, png_uint_32
	row_num, int pass)
{
	struct cached_image *cimg;
#ifdef REPACK_16
	unsigned char *tmp;
	int channels;
#endif /* #ifdef REPACK_16 */

	cimg=global_cimg;
#ifdef REPACK_16
	if (cimg->buffer_bytes_per_pixel>4)
	{
		channels=cimg->buffer_bytes_per_pixel/sizeof(unsigned
			short);
		if (PNG_INTERLACE_NONE==png_get_interlace_type(png_ptr,
			((struct png_decoder *)cimg->decoder)->info_ptr))
		{
			unsigned_short_from_2char((unsigned short *)(cimg->buffer+cimg
				->buffer_bytes_per_pixel *cimg->width
				*row_num), new_row, cimg->width
				*channels);
		}else{
			if ((unsigned)cimg->width > MAXINT / 2 / channels) overalloc();
			tmp=mem_alloc(cimg->width*2*channels);
			a2char_from_unsigned_short(tmp, (unsigned short *)(cimg->buffer
				+cimg->buffer_bytes_per_pixel
				*cimg->width*row_num), cimg->width*channels);
			png_progressive_combine_row(png_ptr, tmp, new_row);
			unsigned_short_from_2char((unsigned short *)(cimg->buffer
				+cimg->buffer_bytes_per_pixel
				*cimg->width*row_num), tmp, cimg->width*channels);
			mem_free(tmp);
		}
	}else
#endif /* #ifdef REPACK_16 */
	{
		png_progressive_combine_row(png_ptr,
			cimg->buffer+cimg->buffer_bytes_per_pixel
			*cimg->width*row_num, new_row);
	}
	cimg->rows_added=1;
}
Esempio n. 9
0
/**
 * info_callback -- PNG header has been completely received, prepare to process
 * image data
 */
static void info_callback(png_structp png_s, png_infop info)
{
	int interlace;
	png_uint_32 width, height;
	nspng_content *png_c = png_get_progressive_ptr(png_s);

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

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

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

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

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

	nspng_setup_transforms(png_s, info);

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

	LOG(("size %li * %li, rowbytes %zu", (unsigned long)width,
	     (unsigned long)height, png_c->rowbytes));
}
Esempio n. 10
0
/* For little endian systems, ARGB is equivalent to the int32 BGRA.
 * So, to read the image as RGB
 */
static SLang_Array_Type *read_image_internal (char *file, int flip, int *color_typep)
{
   Png_Type *p;
   png_uint_32 width, height, rowbytes;
   png_struct *png;
   png_info *info;
   int bit_depth;
   int interlace_type;
   int color_type;
   unsigned int sizeof_type;
   SLindex_Type dims[2];
   SLtype data_type;
   png_byte **image_pointers = NULL;
   png_byte *data = NULL;
   SLang_Array_Type *at;
   void (*fixup_array_fun) (SLang_Array_Type *);

   if (NULL == (p = open_png_file (file)))
     return NULL;

   png = p->png;
   if (setjmp (png_jmpbuf (png)))
     {
	free_png_type (p);
	if (data != NULL) SLfree ((char *) data);
	free_image_pointers (image_pointers);
	SLang_verror (SL_Read_Error, "Error encountered during I/O to %s", file);
	return NULL;
     }

   png_init_io (png, p->fp);
   png_set_sig_bytes (png, 8);
   info = p->info;
   png_read_info(png, info);

   width = png_get_image_width (png, info);
   height = png_get_image_height (png, info);
   interlace_type = png_get_interlace_type (png, info);
   bit_depth = png_get_bit_depth (png, info);

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

   switch (png_get_color_type (png, info))
     {
      case PNG_COLOR_TYPE_GRAY:
#if defined(PNG_LIBPNG_VER) && (PNG_LIBPNG_VER >= 10209)
	if (bit_depth < 8) png_set_expand_gray_1_2_4_to_8 (png);
#else				       /* deprecated */
	if (bit_depth < 8) png_set_gray_1_2_4_to_8 (png);
#endif
	break;
      case PNG_COLOR_TYPE_GRAY_ALPHA:
	/* png_set_gray_to_rgb (png); */
	break;

      case PNG_COLOR_TYPE_PALETTE:
	png_set_palette_to_rgb (png);
	break;
     }

   if (png_get_valid(png, info, PNG_INFO_tRNS))
     png_set_tRNS_to_alpha(png);

   png_read_update_info (png, info);

   color_type = png_get_color_type (png, info);
   switch (color_type)
     {
      case PNG_COLOR_TYPE_RGBA:
	sizeof_type = 4;
	fixup_array_fun = fixup_array_rgba;
	data_type = SLang_get_int_type (32);
	break;

      case PNG_COLOR_TYPE_RGB:
	sizeof_type = 4;
	fixup_array_fun = fixup_array_rgb;
	data_type = SLang_get_int_type (32);
	break;

      case PNG_COLOR_TYPE_GRAY_ALPHA:
	sizeof_type = 2;
	fixup_array_fun = fixup_array_ga;
	data_type = SLang_get_int_type (16);
	break;

      case PNG_COLOR_TYPE_GRAY:
	sizeof_type = 1;
	fixup_array_fun = NULL;
	data_type = SLANG_UCHAR_TYPE;
	break;

      default:
	SLang_verror (SL_Read_Error, "Unsupported PNG color-type");
	free_png_type (p);
	return NULL;
     }
   *color_typep = color_type;

   /* Use the high-level interface */
   rowbytes = png_get_rowbytes (png, info);
   if (rowbytes > width * sizeof_type)
     {
	SLang_verror (SL_INTERNAL_ERROR, "Unexpected value returned from png_get_rowbytes");
	free_png_type (p);
	return NULL;
     }

   if (NULL == (data = (png_byte *) SLmalloc (height * width * sizeof_type)))
     {
	free_png_type (p);
	return NULL;
     }

   if (NULL == (image_pointers = allocate_image_pointers (height, data, width * sizeof_type, flip)))
     {
	SLfree ((char *) data);
	free_png_type (p);
	return NULL;
     }
   png_read_image(png, image_pointers);

   dims[0] = height;
   dims[1] = width;

   if (NULL == (at = SLang_create_array (data_type, 0, (VOID_STAR) data, dims, 2)))
     {
	SLfree ((char *) data);
	free_image_pointers (image_pointers);
	free_png_type (p);
	return NULL;
     }
   free_png_type (p);
   free_image_pointers (image_pointers);
   if (fixup_array_fun != NULL)
     (*fixup_array_fun) (at);
   return at;
}
Esempio n. 11
0
s32 pngDecOpen(PPUThread& ppu, PHandle handle, PPStream png_stream, PSrc source, POpenInfo open_info, PCbControlStream control_stream = vm::null, POpenParam open_param = vm::null)
{
	// Check if partial image decoding is used
	if (control_stream || open_param)
	{
		throw EXCEPTION("Partial image decoding is not supported.");
	}

	// Allocate memory for the stream structure
	auto stream = vm::ptr<PngStream>::make(handle->malloc(ppu, sizeof(PngStream), handle->malloc_arg).addr());

	// Check if the allocation of memory for the stream structure failed
	if (!stream)
	{
		cellPngDec.error("PNG stream creation failed.");
		return CELL_PNGDEC_ERROR_FATAL;
	}

	// Set memory info
	open_info->initSpaceAllocated = sizeof(PngStream);

	// Set the stream source to the source give by the game
	stream->source = *source;

	// Indicate that a fixed alpha value isn't used, if not specified otherwise
	stream->fixed_alpha = false;

	// Use virtual memory address as a handle
	*png_stream = stream;

	// Allocate memory for the PNG buffer for decoding
	auto buffer = vm::ptr<PngBuffer>::make(handle->malloc(ppu, sizeof(PngBuffer), handle->malloc_arg).addr());

	// Check for if the buffer structure allocation failed
	if (!buffer)
	{
		throw EXCEPTION("Memory allocation for the PNG buffer structure failed.");
	}

	// We might not be reading from a file stream
	buffer->file = false;

	// Set the buffer pointer in the stream structure, so we can later deallocate it
	stream->buffer = buffer;

	// Open the buffer/file and check the header
	u8 header[8];

	// Need to test it somewhere
	if (stream->source.fileOffset != 0)
	{
		throw EXCEPTION("Non-0 file offset not supported.");
	}

	// Depending on the source type, get the first 8 bytes
	if (source->srcSelect == CELL_PNGDEC_FILE)
	{
		// Open a file stream
		fs::file file_stream(vfs::get(stream->source.fileName.get_ptr()));
		
		// Check if opening of the PNG file failed
		if (!file_stream)
		{
			cellPngDec.error("Opening of PNG failed. (%s)", stream->source.fileName.get_ptr());
			return CELL_PNGDEC_ERROR_OPEN_FILE;
		}

		// Read the header
		if (file_stream.read(header, 8) != 8)
		{
			cellPngDec.error("PNG header is too small.");
			return CELL_PNGDEC_ERROR_HEADER;
		}

		// Get the file descriptor
		buffer->fd = idm::make<lv2_file_t>(std::move(file_stream), 0, 0);

		// Indicate that we need to read from a file stream
		buffer->file = true;
	}
	else
	{
		// We can simply copy the first 8 bytes
		memcpy(header, stream->source.streamPtr.get_ptr(), 8);
	}

	// Check if the header indicates a valid PNG file
	if (png_sig_cmp(header, 0, 8))
	{
		cellPngDec.error("PNG signature is invalid.");
		return CELL_PNGDEC_ERROR_HEADER;
	}

	// Create a libpng structure, also pass our custom error/warning functions
	stream->png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, pngDecError, pngDecWarning);

	// Check if the creation of the structure failed
	if (!stream->png_ptr)
	{
		cellPngDec.error("Creation of png_structp failed.");
		return CELL_PNGDEC_ERROR_FATAL;
	}

	// Create a libpng info structure
	stream->info_ptr = png_create_info_struct(stream->png_ptr);

	// Check if the creation of the structure failed
	if (!stream->info_ptr)
	{
		throw EXCEPTION("Creation of png_infop failed.");
	}

	// Set a point to return to when an error occurs in libpng
	if (setjmp(png_jmpbuf(stream->png_ptr)))
	{
		throw EXCEPTION("Fatal error in libpng.");
	}

	// We must indicate, that we allocated more memory
	open_info->initSpaceAllocated += sizeof(PngBuffer);

	// Init the IO for either reading from a file or a buffer
	if (source->srcSelect == CELL_PNGDEC_BUFFER)
	{
		// Set the data pointer and the file size
		buffer->length = stream->source.fileSize;
		buffer->data = stream->source.streamPtr;

		// Since we already read the header, we start reading from position 8
		buffer->cursor = 8;
	}

	// Set the custom read function for decoding
	png_set_read_fn(stream->png_ptr, buffer.get_ptr(), pngDecReadBuffer);

	// We need to tell libpng, that we already read 8 bytes
	png_set_sig_bytes(stream->png_ptr, 8);

	// Read the basic info of the PNG file
	png_read_info(stream->png_ptr, stream->info_ptr);

	// Read the header info for future use
	stream->info.imageWidth = png_get_image_width(stream->png_ptr, stream->info_ptr);
	stream->info.imageHeight = png_get_image_height(stream->png_ptr, stream->info_ptr);
	stream->info.numComponents = png_get_channels(stream->png_ptr, stream->info_ptr);
	stream->info.colorSpace = getPngDecColourType(png_get_color_type(stream->png_ptr, stream->info_ptr));
	stream->info.bitDepth = png_get_bit_depth(stream->png_ptr, stream->info_ptr);
	stream->info.interlaceMethod = png_get_interlace_type(stream->png_ptr, stream->info_ptr);
	stream->info.chunkInformation = pngDecGetChunkInformation(stream);

	return CELL_OK;
}
Esempio n. 12
0
static int
read_png(FILE *fp)
{
   png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,0,0,0);
   png_infop info_ptr = NULL;
   png_bytep row = NULL, display = NULL;

   if (png_ptr == NULL)
      return 0;

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

   png_init_io(png_ptr, fp);

   info_ptr = png_create_info_struct(png_ptr);
   if (info_ptr == NULL)
      png_error(png_ptr, "OOM allocating info structure");

   png_set_keep_unknown_chunks(png_ptr, PNG_HANDLE_CHUNK_ALWAYS, NULL, 0);

   png_read_info(png_ptr, info_ptr);

   {
      png_size_t rowbytes = png_get_rowbytes(png_ptr, info_ptr);

      /* Failure to initialize these is harmless */
      row = malloc(rowbytes);
      display = malloc(rowbytes);

      if (row == NULL || display == NULL)
         png_error(png_ptr, "OOM allocating row buffers");

      {
         png_uint_32 height = png_get_image_height(png_ptr, info_ptr);
#        ifdef PNG_READ_INTERLACING_SUPPORTED
            int passes = png_set_interlace_handling(png_ptr);
#        else /* !READ_INTERLACING */
            int passes = png_get_interlace_type(png_ptr, info_ptr) ==
               PNG_INTERLACE_ADAM7 ? PNG_INTERLACE_ADAM7_PASSES : 1;
#        endif /* !READ_INTERLACING */
         int pass;

         png_start_read_image(png_ptr);

         for (pass = 0; pass < passes; ++pass)
         {
            png_uint_32 y = height;

#           ifndef PNG_READ_INTERLACING_SUPPORTED
               if (passes == PNG_INTERLACE_ADAM7_PASSES)
                  y = PNG_PASS_ROWS(y, pass);
#           endif /* READ_INTERLACING */

            /* NOTE: this trashes the row each time; interlace handling won't
             * work, but this avoids memory thrashing for speed testing.
             */
            while (y-- > 0)
               png_read_row(png_ptr, row, display);
         }
      }
   }

   /* Make sure to read to the end of the file: */
   png_read_end(png_ptr, info_ptr);
   png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
   free(row);
   free(display);
   return 1;
}
Esempio n. 13
0
int
main(int argc, char **argv)
{
    static char *usage="Usage:\n\t%s png__file\n";

    int i;
    FILE *fp_in = NULL;
    png_structp png_p;
    png_infop info_p;
    char header[8];
    int bit_depth;
    int color_type;
    png_color_16p input_backgrd;
    double gammaval;
    int file_width, file_height;
    png_int_32 xoff, yoff;
    png_uint_32 xres, yres;
    int unit_type;
    int rgb_intent;
    double white_x, white_y, red_x, red_y, green_x, green_y, blue_x, blue_y;
    png_timep mod_time;
    png_textp text;
    int num_text;
    unsigned char *image;
    unsigned char **rows;

    if (argc != 2) {
	bu_log(usage, argv[0]);
	bu_exit(EXIT_FAILURE, "Incorrect number of arguments!!\n");
    } else {
	if ((fp_in = fopen(argv[1], "rb")) == NULL) {
	    perror(argv[1]);
	    bu_log("png_onfo: cannot open \"%s\" for reading\n",
		   argv[1]);
	    bu_exit(EXIT_FAILURE, "Cannot open input file\n");
	}
    }

    if (fread(header, 8, 1, fp_in) != 1)
	bu_exit(EXIT_FAILURE, "ERROR: Failed while reading file header!!!\n");

    if (png_sig_cmp((png_bytep)header, 0, 8))
	bu_exit(EXIT_FAILURE, "This is not a PNG file!!!\n");

    png_p = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
    if (!png_p)
	bu_exit(EXIT_FAILURE, "png_create_read_struct() failed!!\n");

    info_p = png_create_info_struct(png_p);
    if (!info_p)
	bu_exit(EXIT_FAILURE, "png_create_info_struct() failed!!\n");

    png_init_io(png_p, fp_in);

    png_set_sig_bytes(png_p, 8);

    png_read_info(png_p, info_p);

    color_type = png_get_color_type(png_p, info_p);

    bit_depth = png_get_bit_depth(png_p, info_p);

    switch (color_type) {
	case PNG_COLOR_TYPE_GRAY:
	    bu_log("color type: b/w (bit depth=%d)\n", bit_depth);
	    break;
	case PNG_COLOR_TYPE_GRAY_ALPHA:
	    bu_log("color type: b/w with alpha channel (bit depth=%d)\n", bit_depth);
	    break;
	case PNG_COLOR_TYPE_PALETTE:
	    bu_log("color type: color palette (bit depth=%d)\n", bit_depth);
	    break;
	case PNG_COLOR_TYPE_RGB:
	    bu_log("color type: RGB (bit depth=%d)\n", bit_depth);
	    break;
	case PNG_COLOR_TYPE_RGB_ALPHA:
	    bu_log("color type: RGB with alpha channel (bit depth=%d)\n", bit_depth);
	    break;
	default:
	    bu_log("Unrecognized color type (bit depth=%d)\n", bit_depth);
	    break;
    }

    file_width = png_get_image_width(png_p, info_p);
    file_height = png_get_image_height(png_p, info_p);

    bu_log("Image size: %d X %d\n", file_width, file_height);

    /* allocate memory for image */
    image = (unsigned char *)bu_calloc(1, file_width*file_height*3, "image");

    /* create rows array */
    rows = (unsigned char **)bu_calloc(file_height, sizeof(unsigned char *), "rows");
    for (i=0; i<file_height; i++)
	rows[file_height-1-i] = image+(i*file_width*3);

    png_read_image(png_p, rows);

    if (png_get_oFFs(png_p, info_p, &xoff, &yoff, &unit_type)) {
	if (unit_type == PNG_OFFSET_PIXEL)
	    bu_log("X Offset: %d pixels\nY Offset: %d pixels\n", (int)xoff, (int)yoff);
	else if (unit_type == PNG_OFFSET_MICROMETER)
	    bu_log("X Offset: %d um\nY Offset: %d um\n", (int)xoff, (int)yoff);
    }

    if (png_get_pHYs(png_p, info_p, &xres, &yres, &unit_type)) {
	if (unit_type == PNG_RESOLUTION_UNKNOWN)
	    bu_log("Aspect ratio: %g (width/height)\n", (double)xres/(double)yres);
	else if (unit_type == PNG_RESOLUTION_METER)
	    bu_log("pixel density:\n\t%d pixels/m horizontal\n\t%d pixels/m vertical\n",
		   (int)xres, (int)yres);
    }

    if (png_get_interlace_type(png_p, info_p) == PNG_INTERLACE_NONE)
	bu_log("not interlaced\n");
    else
	bu_log("interlaced\n");

    if (color_type == PNG_COLOR_TYPE_GRAY_ALPHA ||
	color_type == PNG_COLOR_TYPE_RGB_ALPHA)
	if (png_get_bKGD(png_p, info_p, &input_backgrd))
	    bu_log("background color: %d %d %d\n", input_backgrd->red, input_backgrd->green, input_backgrd->blue);

    if (png_get_sRGB(png_p, info_p, &rgb_intent)) {
	bu_log("rendering intent: ");
	switch (rgb_intent) {
	    case PNG_sRGB_INTENT_SATURATION:
		bu_log("saturation\n");
		break;
	    case PNG_sRGB_INTENT_PERCEPTUAL:
		bu_log("perceptual\n");
		break;
	    case PNG_sRGB_INTENT_ABSOLUTE:
		bu_log("absolute\n");
		break;
	    case PNG_sRGB_INTENT_RELATIVE:
		bu_log("relative\n");
		break;
	}
    }

    if (png_get_gAMA(png_p, info_p, &gammaval))
	bu_log("gamma: %g\n", gammaval);

#if defined(PNG_READ_cHRM_SUPPORTED)
    if (png_get_cHRM(png_p, info_p, &white_x, &white_y, &red_x, &red_y, &green_x, &green_y, &blue_x, &blue_y)) {
	bu_log("Chromaticity:\n");
	bu_log("\twhite point\t(%g %g)\n\tred\t(%g %g)\n\tgreen\t(%g %g)\n\tblue\t(%g %g)\n",
	       white_x, white_y, red_x, red_y, green_x, green_y, blue_x, blue_y);
    }
#endif

    if (png_get_text(png_p, info_p, &text, &num_text))
	for (i=0; i<num_text; i++)
	    bu_log("%s: %s\n", text[i].key, text[i].text);

    if (png_get_tIME(png_p, info_p, &mod_time))
	bu_log("Last modified: %d/%d/%d %d:%d:%d\n", mod_time->month, mod_time->day,
	       mod_time->year, mod_time->hour, mod_time->minute, mod_time->second);
    return 0;
}
Esempio n. 14
0
PyObject *
load_png_fast_progressive (char *filename,
                           PyObject *get_buffer_callback)
{
  // Note: we are not using the method that libpng calls "Reading PNG
  // files progressively". That method would involve feeding the data
  // into libpng piece by piece, which is not necessary if we can give
  // libpng a simple FILE pointer.

  png_structp png_ptr = NULL;
  png_infop info_ptr = NULL;
  PyObject * result = NULL;
  FILE *fp = NULL;
  uint32_t width, height;
  uint32_t rows_left;
  png_byte color_type;
  png_byte bit_depth;
  bool have_alpha;
  char *cm_processing = NULL;

  // ICC profile-based colour conversion data.
  png_charp icc_profile_name = NULL;
  int icc_compression_type = 0;
#if PNG_LIBPNG_VER < 10500    // 1.5.0beta36, according to libpng CHANGES
  png_charp icc_profile = NULL;
#else
  png_bytep icc_profile = NULL;
#endif
  png_uint_32 icc_proflen = 0;

  // The sRGB flag has an intent field, which we ignore - 
  // the target gamut is sRGB already.
  int srgb_intent = 0;

  // Generic RGB space conversion params.
  // The assumptions we're making are those of sRGB,
  // but they'll be overridden by gammas or primaries in the file if used.
  bool generic_rgb_have_gAMA = false;
  bool generic_rgb_have_cHRM = false;
  double generic_rgb_file_gamma = 45455 / PNG_gAMA_scale;
  double generic_rgb_white_x = 31270 / PNG_cHRM_scale;
  double generic_rgb_white_y = 32900 / PNG_cHRM_scale;
  double generic_rgb_red_x   = 64000 / PNG_cHRM_scale;
  double generic_rgb_red_y   = 33000 / PNG_cHRM_scale;
  double generic_rgb_green_x = 30000 / PNG_cHRM_scale;
  double generic_rgb_green_y = 60000 / PNG_cHRM_scale;
  double generic_rgb_blue_x  = 15000 / PNG_cHRM_scale;
  double generic_rgb_blue_y  =  6000 / PNG_cHRM_scale;

  // Indicates the case where no CM information was present in the file and we
  // treated it as sRGB.
  bool possible_legacy_png = false;

  // LCMS stuff
  cmsHPROFILE input_buffer_profile = NULL;
  cmsHPROFILE nparray_data_profile = cmsCreate_sRGBProfile();
  cmsHTRANSFORM input_buffer_to_nparray = NULL;
  cmsToneCurve *gamma_transfer_func = NULL;
  cmsUInt32Number input_buffer_format = 0;

  cmsSetLogErrorHandler(log_lcms2_error);

  fp = fopen(filename, "rb");
  if (!fp) {
    PyErr_SetFromErrno(PyExc_IOError);
    //PyErr_Format(PyExc_IOError, "Could not open PNG file for writing: %s",
    //             filename);
    goto cleanup;
  }

  png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, (png_voidp)NULL,
                                    png_read_error_callback, NULL);
  if (!png_ptr) {
    PyErr_SetString(PyExc_MemoryError, "png_create_write_struct() failed");
    goto cleanup;
  }

  info_ptr = png_create_info_struct(png_ptr);
  if (!info_ptr) {
    PyErr_SetString(PyExc_MemoryError, "png_create_info_struct() failed");
    goto cleanup;
  }

  if (setjmp(png_jmpbuf(png_ptr))) {
    goto cleanup;
  }

  png_init_io(png_ptr, fp);

  png_read_info(png_ptr, info_ptr);

  // If there's an embedded ICC profile, use it in preference to any other
  // colour management information present.
  if (png_get_iCCP (png_ptr, info_ptr, &icc_profile_name,
                    &icc_compression_type, &icc_profile,
                    &icc_proflen))
  {
    input_buffer_profile = cmsOpenProfileFromMem(icc_profile, icc_proflen);
    if (! input_buffer_profile) {
      PyErr_SetString(PyExc_MemoryError, "cmsOpenProfileFromMem() failed");
      goto cleanup;
    }
    cm_processing = "iCCP (use embedded colour profile)";
  }

  // Shorthand for sRGB.
  else if (png_get_sRGB (png_ptr, info_ptr, &srgb_intent)) {
    input_buffer_profile = cmsCreate_sRGBProfile();
    cm_processing = "sRGB (explicit sRGB chunk)";
  }

  else {
    // We might have generic RGB transformation information in the form of
    // the chromaticities for R, G and B and a generic gamma curve.

    if (png_get_cHRM (png_ptr, info_ptr,
                      &generic_rgb_white_x, &generic_rgb_white_y,
                      &generic_rgb_red_x, &generic_rgb_red_y,
                      &generic_rgb_green_x, &generic_rgb_green_y,
                      &generic_rgb_blue_x, &generic_rgb_blue_y))
    {
      generic_rgb_have_cHRM = true;
    }
    if (png_get_gAMA(png_ptr, info_ptr, &generic_rgb_file_gamma)) {
      generic_rgb_have_gAMA = true;
    }
    if (generic_rgb_have_gAMA || generic_rgb_have_cHRM) {
      cmsCIExyYTRIPLE primaries = {{generic_rgb_red_x, generic_rgb_red_y},
                                   {generic_rgb_green_x, generic_rgb_green_y},
                                   {generic_rgb_blue_x, generic_rgb_blue_y}};
      cmsCIExyY white_point = {generic_rgb_white_x, generic_rgb_white_y};
      gamma_transfer_func = cmsBuildGamma(NULL, 1.0/generic_rgb_file_gamma);
      cmsToneCurve *transfer_funcs[3] = {gamma_transfer_func,
                                         gamma_transfer_func,
                                         gamma_transfer_func };
      input_buffer_profile = cmsCreateRGBProfile(&white_point, &primaries,
                                                transfer_funcs);
      cm_processing = "cHRM and/or gAMA (generic RGB space)";
    }

    // Possible legacy PNG, or rather one which might have been written with an
    // old version of MyPaint. Treat as sRGB, but flag the strangeness because
    // it might be important for PNGs in old OpenRaster files.
    else {
      possible_legacy_png = true;
      input_buffer_profile = cmsCreate_sRGBProfile();
      cm_processing = "sRGB (no CM chunks present)";
    }
  }

  if (png_get_interlace_type (png_ptr, info_ptr) != PNG_INTERLACE_NONE) {
    PyErr_SetString(PyExc_RuntimeError,
                    "Interlaced PNG files are not supported!");
    goto cleanup;
  }

  color_type = png_get_color_type(png_ptr, info_ptr);
  bit_depth = png_get_bit_depth(png_ptr, info_ptr);
  have_alpha = color_type & PNG_COLOR_MASK_ALPHA;

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

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

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

  if (bit_depth < 8) {
    png_set_packing(png_ptr);
  }

  if (!have_alpha) {
    png_set_add_alpha(png_ptr, 0xFF, PNG_FILLER_AFTER);
  }

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

  png_read_update_info(png_ptr, info_ptr);

  // Verify what we have done
  bit_depth = png_get_bit_depth(png_ptr, info_ptr);
  if (! (bit_depth == 8 || bit_depth == 16)) {
    PyErr_SetString(PyExc_RuntimeError, "Failed to convince libpng to convert "
                                        "to 8 or 16 bits per channel");
    goto cleanup;
  }
  if (png_get_color_type(png_ptr, info_ptr) != PNG_COLOR_TYPE_RGB_ALPHA) {
    PyErr_SetString(PyExc_RuntimeError, "Failed to convince libpng to convert "
                                        "to RGBA (wrong color_type)");
    goto cleanup;
  }
  if (png_get_channels(png_ptr, info_ptr) != 4) {
    PyErr_SetString(PyExc_RuntimeError, "Failed to convince libpng to convert "
                                        "to RGBA (wrong number of channels)");
    goto cleanup;
  }

  // PNGs use network byte order, i.e. big-endian in descending order
  // of bit significance. LittleCMS uses whatever's detected for the compiler.
  // ref: http://www.w3.org/TR/2003/REC-PNG-20031110/#7Integers-and-byte-order
  if (bit_depth == 16) {
#ifdef CMS_USE_BIG_ENDIAN
    input_buffer_format = TYPE_RGBA_16;
#else
    input_buffer_format = TYPE_RGBA_16_SE;
#endif
  }
  else {
    input_buffer_format = TYPE_RGBA_8;
  }

  input_buffer_to_nparray = cmsCreateTransform
        (input_buffer_profile, input_buffer_format,
         nparray_data_profile, TYPE_RGBA_8,
         INTENT_PERCEPTUAL, 0);

  width = png_get_image_width(png_ptr, info_ptr);
  height = png_get_image_height(png_ptr, info_ptr);
  rows_left = height;

  while (rows_left) {
    PyObject *pyarr = NULL;
    uint32_t rows = 0;
    uint32_t row = 0;
    const uint8_t input_buf_bytes_per_pixel = (bit_depth==8) ? 4 : 8;
    const uint32_t input_buf_row_stride = sizeof(png_byte) * width
                                          * input_buf_bytes_per_pixel;
    png_byte *input_buffer = NULL;
    png_bytep *input_buf_row_pointers = NULL;

    pyarr = PyObject_CallFunction(get_buffer_callback, "ii", width, height);
    if (! pyarr) {
      PyErr_Format(PyExc_RuntimeError, "Get-buffer callback failed");
      goto cleanup;
    }
#ifdef HEAVY_DEBUG
    //assert(PyArray_ISCARRAY(arr));
    assert(PyArray_NDIM(pyarr) == 3);
    assert(PyArray_DIM(pyarr, 1) == width);
    assert(PyArray_DIM(pyarr, 2) == 4);
    assert(PyArray_TYPE(pyarr) == NPY_UINT8);
    assert(PyArray_ISBEHAVED(pyarr));
    assert(PyArray_STRIDE(pyarr, 1) == 4*sizeof(uint8_t));
    assert(PyArray_STRIDE(pyarr, 2) ==   sizeof(uint8_t));
#endif
    rows = PyArray_DIM(pyarr, 0);

    if (rows > rows_left) {
      PyErr_Format(PyExc_RuntimeError,
                   "Attempt to read %d rows from the PNG, "
                   "but only %d are left",
                   rows, rows_left);
      goto cleanup;
    }

    input_buffer = (png_byte *) malloc(rows * input_buf_row_stride);
    input_buf_row_pointers = (png_bytep *)malloc(rows * sizeof(png_bytep));
    for (row=0; row<rows; row++) {
      input_buf_row_pointers[row] = input_buffer + (row * input_buf_row_stride);
    }

    png_read_rows(png_ptr, input_buf_row_pointers, NULL, rows);
    rows_left -= rows;

    for (row=0; row<rows; row++) {
      uint8_t *pyarr_row = (uint8_t *)PyArray_DATA(pyarr)
                         + row*PyArray_STRIDE(pyarr, 0);
      uint8_t *input_row = input_buf_row_pointers[row];
      // Really minimal fake colour management. Just remaps to sRGB.
      cmsDoTransform(input_buffer_to_nparray, input_row, pyarr_row, width);
      // lcms2 ignores alpha, so copy that verbatim
      // If it's 8bpc RGBA, use A.
      // If it's 16bpc RrGgBbAa, use A.
      for (uint32_t i=0; i<width; ++i) {
        const uint32_t pyarr_alpha_byte = (i*4) + 3;
        const uint32_t buf_alpha_byte = (i*input_buf_bytes_per_pixel)
                                       + ((bit_depth==8) ? 3 : 6);
        pyarr_row[pyarr_alpha_byte] = input_row[buf_alpha_byte];
      }
    }

    free(input_buf_row_pointers);
    free(input_buffer);

    Py_DECREF(pyarr);
  }

  png_read_end(png_ptr, NULL);

  result = Py_BuildValue("{s:b,s:i,s:i,s:s}",
                         "possible_legacy_png", possible_legacy_png,
                         "width", width,
                         "height", height,
                         "cm_conversions_applied", cm_processing);

 cleanup:
  if (info_ptr) png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
  // libpng's style is to free internally allocated stuff like the icc
  // tables in png_destroy_*(). I think.
  if (fp) fclose(fp);
  if (input_buffer_profile) cmsCloseProfile(input_buffer_profile);
  if (nparray_data_profile) cmsCloseProfile(nparray_data_profile);
  if (input_buffer_to_nparray) cmsDeleteTransform(input_buffer_to_nparray);
  if (gamma_transfer_func) cmsFreeToneCurve(gamma_transfer_func);

  return result;
}
Esempio n. 15
0
unsigned char *
ReadPNG(FILE *infile,int *width, int *height, XColor *colrs)
{

    unsigned char *pixmap;
    unsigned char *p;
    png_byte *q;

    png_struct *png_ptr;
    png_info *info_ptr;

    double screen_gamma;

    png_byte *png_pixels=NULL, **row_pointers=NULL;
    int i, j;

    unsigned int packets;

    png_color std_color_cube[216];

    
        /* first check to see if its a valid PNG file. If not, return. */
        /* we assume that infile is a valid filepointer */
    {
        int ret;
        png_byte buf[8];
        
        ret = fread(buf, 1, 8, infile);
        
        if(ret != 8)
            return 0;
        
        ret = png_check_sig(buf, 8);
        
        if(!ret)
            return(0);
    }

        /* OK, it is a valid PNG file, so let's rewind it, and start 
           decoding it */
    rewind(infile);

        /* allocate the structures */
    png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
    if(!png_ptr)
        return 0;

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

        /* Establish the setjmp return context for png_error to use. */
    if (setjmp(png_jmpbuf(png_ptr))) {
        
#ifndef DISABLE_TRACE
        if (srcTrace) {
            fprintf(stderr, "\n!!!libpng read error!!!\n");
        }
#endif

	png_destroy_read_struct(&png_ptr, &info_ptr, NULL);

        if(png_pixels != NULL)
            free((char *)png_pixels);
        if(row_pointers != NULL)
            free((png_byte **)row_pointers);
	png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
        
        return 0;
    }
    
        /* set up the input control */
    png_init_io(png_ptr, infile);
    
        /* read the file information */
    png_read_info(png_ptr, info_ptr);
    
        /* setup other stuff using the fields of png_info. */
    
    *width = (int)png_get_image_width(png_ptr, info_ptr);
    *height = (int)png_get_image_height(png_ptr, info_ptr);

#ifndef DISABLE_TRACE
    if (srcTrace) {

        fprintf(stderr,"\n\nBEFORE\nheight = %d\n", (int)png_get_image_width(png_ptr, info_ptr));
        fprintf(stderr,"width = %d\n", (int)png_get_image_height(png_ptr, info_ptr));
        fprintf(stderr,"bit depth = %d\n", png_get_bit_depth(png_ptr, info_ptr));
        fprintf(stderr,"color type = %d\n", png_get_color_type(png_ptr, info_ptr));
        fprintf(stderr,"compression type = %d\n", png_get_compression_type(png_ptr, info_ptr));
        fprintf(stderr,"filter type = %d\n", png_get_filter_type(png_ptr, info_ptr));
        fprintf(stderr,"interlace type = %d\n", png_get_interlace_type(png_ptr, info_ptr));
        fprintf(stderr,"num colors = %d\n", png_get_palette_max(png_ptr, info_ptr));
        fprintf(stderr,"rowbytes = %d\n", png_get_rowbytes(png_ptr, info_ptr));
    }
#endif


#if 0
        /* This handles alpha and transparency by replacing it with 
           a background value. */
        /* its #if'ed out for now cause I don't have anything to 
           test it with */
    {
        png_color_16 my_background;
	
        if (png_get_valid(png_ptr, info_ptr) & PNG_INFO_bKGD)
            png_set_background(png_ptr, &(info_ptr->background),
                               PNG_GAMMA_FILE, 1, 1.0);
        else
            png_set_background(png_ptr, &my_background,
                               PNG_GAMMA_SCREEN, 0, 1.0);
    }
#endif

        /* strip pixels in 16-bit images down to 8 bits */
    if (png_get_bit_depth(png_ptr, info_ptr) == 16)
        png_set_strip_16(png_ptr);


        /* If it is a color image then check if it has a palette. If not
           then dither the image to 256 colors, and make up a palette */
    if (png_get_color_type(png_ptr, info_ptr)==PNG_COLOR_TYPE_RGB ||
        png_get_color_type(png_ptr, info_ptr)==PNG_COLOR_TYPE_RGB_ALPHA) {

        if(! (png_get_valid(png_ptr, info_ptr, PNG_INFO_PLTE)) ) {

#ifndef DISABLE_TRACE
            if (srcTrace) {
                fprintf(stderr,"dithering (RGB->palette)...\n");
            }
#endif
                /* if there is is no valid palette, then we need to make
                   one up */
            for(i=0;i<216;i++) {
                    /* 255.0/5 = 51 */
                std_color_cube[i].red=(i%6)*51;
                std_color_cube[i].green=((i/6)%6)*51;
                std_color_cube[i].blue=(i/36)*51;
            }

                /* this should probably be dithering to 
                   Rdata.colors_per_inlined_image colors */
            png_set_quantize(png_ptr, std_color_cube,
                             216,
                             216, NULL, 1);
            
        } else {
#ifndef DISABLE_TRACE
            if (srcTrace) {
                fprintf(stderr,"dithering (RGB->file supplied palette)...\n");
            }
#endif
 
            png_colorp palette;
            int num_palette;
            png_get_PLTE(png_ptr, info_ptr, palette, &num_palette);

            png_uint_16p hist;
            png_get_hIST(png_ptr, info_ptr, &hist);

            png_set_quantize(png_ptr, palette,
                             num_palette,
                             get_pref_int(eCOLORS_PER_INLINED_IMAGE),
                             hist, 1);
            
        }
    }

        /* PNG files pack pixels of bit depths 1, 2, and 4 into bytes as
           small as they can. This expands pixels to 1 pixel per byte, and
           if a transparency value is supplied, an alpha channel is
           built.*/
    if (png_get_bit_depth(png_ptr, info_ptr) < 8)
        png_set_packing(png_ptr);


        /* have libpng handle the gamma conversion */

    if (get_pref_boolean(eUSE_SCREEN_GAMMA)) { /*SWP*/
        if (png_get_bit_depth(png_ptr, info_ptr) != 16) {  /* temporary .. glennrp */
            screen_gamma=(double)(get_pref_float(eSCREEN_GAMMA));
            
#ifndef DISABLE_TRACE
            if (srcTrace) {
                fprintf(stderr,"screen gamma=%f\n",screen_gamma);
            }
#endif
            if (png_get_valid(png_ptr, info_ptr, PNG_INFO_gAMA)) {
                double gamma;
                png_get_gAMA(png_ptr, info_ptr, &gamma);
#ifndef DISABLE_TRACE
                if (srcTrace) {
                    printf("setting gamma=%f\n",gamma);
                }
#endif
                png_set_gamma(png_ptr, screen_gamma, gamma);
            }
            else {
#ifndef DISABLE_TRACE
                if (srcTrace) {
                    fprintf(stderr,"setting gamma=%f\n",0.45);
                }
#endif
                png_set_gamma(png_ptr, screen_gamma, (double)0.45);
            }
        }
    }
    
    if (png_get_interlace_type(png_ptr, info_ptr))
        png_set_interlace_handling(png_ptr);

    png_read_update_info(png_ptr, info_ptr);
    
#ifndef DISABLE_TRACE
    if (srcTrace) {
        fprintf(stderr,"\n\nAFTER\nheight = %d\n", (int)png_get_image_width(png_ptr, info_ptr));
        fprintf(stderr,"width = %d\n", (int)png_get_image_height(png_ptr, info_ptr));
        fprintf(stderr,"bit depth = %d\n", png_get_bit_depth(png_ptr, info_ptr));
        fprintf(stderr,"color type = %d\n", png_get_color_type(png_ptr, info_ptr));
        fprintf(stderr,"compression type = %d\n", png_get_compression_type(png_ptr, info_ptr));
        fprintf(stderr,"filter type = %d\n", png_get_filter_type(png_ptr, info_ptr));
        fprintf(stderr,"interlace type = %d\n", png_get_interlace_type(png_ptr, info_ptr));
        fprintf(stderr,"num colors = %d\n", png_get_palette_max(png_ptr, info_ptr));
        fprintf(stderr,"rowbytes = %d\n", png_get_rowbytes(png_ptr, info_ptr));
    }
#endif

        /* allocate the pixel grid which we will need to send to 
           png_read_image(). */
    png_pixels = (png_byte *)malloc(png_get_rowbytes(png_ptr, info_ptr) * 
                                    (*height) * sizeof(png_byte));
    

    row_pointers = (png_byte **) malloc((*height) * sizeof(png_byte *));
    for (i=0; i < *height; i++)
        row_pointers[i]=png_pixels+(png_get_rowbytes(png_ptr, info_ptr)*i);

    
        /* FINALLY - read the darn thing. */
    png_read_image(png_ptr, row_pointers);
    
    
        /* now that we have the (transformed to 8-bit RGB) image, we have
           to copy the resulting palette to our colormap. */
    if (png_get_color_type(png_ptr, info_ptr) & PNG_COLOR_MASK_COLOR) {
        if (png_get_valid(png_ptr, info_ptr, PNG_INFO_PLTE)) {
            png_colorp palette;
            int num_palette = png_get_palette_max(png_ptr, info_ptr);

            for (i=0; i < num_palette; i++) {
                png_get_PLTE(png_ptr, info_ptr, &palette, i);

                colrs[i].red = palette->red << 8;
                colrs[i].green = palette->green << 8;
                colrs[i].blue = palette->blue << 8;
                colrs[i].pixel = i;
                colrs[i].flags = DoRed|DoGreen|DoBlue;
            }
        }
        else {
            for (i=0; i < 216; i++) {
                colrs[i].red = std_color_cube[i].red << 8;
                colrs[i].green = std_color_cube[i].green << 8;
                colrs[i].blue = std_color_cube[i].blue << 8;
                colrs[i].pixel = i;
                colrs[i].flags = DoRed|DoGreen|DoBlue;
            }	    
        }
    } else {
            /* grayscale image */
        
        for(i=0; i < 256; i++ ) {
            colrs[i].red = i << 8;
            colrs[i].green = i << 8; 	    
            colrs[i].blue = i << 8;
            colrs[i].pixel = i;
            colrs[i].flags = DoRed|DoGreen|DoBlue;    
        }
    }
    
        /* Now copy the pixel data from png_pixels to pixmap */
 
    pixmap = (png_byte *)malloc((*width) * (*height) * sizeof(png_byte));
    
    p = pixmap; q = png_pixels;

        /* if there is an alpha channel, we have to get rid of it in the
           pixmap, since I don't do anything with it yet */
    if (png_get_color_type(png_ptr, info_ptr) & PNG_COLOR_MASK_ALPHA) {

#ifndef DISABLE_TRACE
        if (srcTrace) {
            fprintf(stderr,"Getting rid of alpha channel\n");
        }
#endif
        for(i=0; i<*height; i++) {
            q = row_pointers[i];
            for(j=0; j<*width; j++) {
                *p++ = *q++; /*palette index*/
                q++; /* skip the alpha pixel */
            }
        }
        
        free((char *)png_pixels);
    }
    else {
        
#ifndef DISABLE_TRACE
        if (srcTrace) {
            fprintf(stderr,"No alpha channel\n");
        }
#endif
        
        for(i=0; i<*height; i++) {
            q = row_pointers[i];
            for(j=0; j<*width; j++) {
                *p++ = *q++; /*palette index*/
            }
        }
        
        free((char *)png_pixels);
        
    }

    free((png_byte **)row_pointers);
    
        /* clean up after the read, and free any memory allocated */

        /* free the structure */
        png_destroy_read_struct(&png_ptr, &info_ptr, NULL);

    return pixmap;
}
Esempio n. 16
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_uint_32 width, height;
	int bit_depth, color_type;
	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;
	}

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

	/* 16bit images are not supported. */
	if (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 & 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)width);
		ret += HPDF_Dict_AddNumber (smask, "Height", (HPDF_UINT)height);
		ret += HPDF_Dict_AddName (smask, "ColorSpace", "DeviceGray");
		ret += HPDF_Dict_AddNumber (smask, "BitsPerComponent", (HPDF_UINT)bit_depth);

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

		smask_data = HPDF_GetMem(image->mmgr, width * 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, width * 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)width);
		ret += HPDF_Dict_AddNumber (image, "Height", (HPDF_UINT)height);
		ret += HPDF_Dict_AddNumber (image, "BitsPerComponent",	(HPDF_UINT)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 & 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)width);
		ret += HPDF_Dict_AddNumber (smask, "Height", (HPDF_UINT)height);
		ret += HPDF_Dict_AddName (smask, "ColorSpace", "DeviceGray");
		ret += HPDF_Dict_AddNumber (smask, "BitsPerComponent", (HPDF_UINT)bit_depth);

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

		smask_data = HPDF_GetMem(image->mmgr, width * 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, width * 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);

		if (color_type == PNG_COLOR_TYPE_GRAY_ALPHA) {
			ret += HPDF_Dict_AddName (image, "ColorSpace", "DeviceGray");
		} else {
			ret += HPDF_Dict_AddName (image, "ColorSpace", "DeviceRGB");
		}
		ret += HPDF_Dict_AddNumber (image, "Width", (HPDF_UINT)width);
		ret += HPDF_Dict_AddNumber (image, "Height", (HPDF_UINT)height);
		ret += HPDF_Dict_AddNumber (image, "BitsPerComponent",	(HPDF_UINT)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 (color_type == PNG_COLOR_TYPE_PALETTE)
		ret = CreatePallet(image, png_ptr, info_ptr);
	else if (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)width)
			!= HPDF_OK)
		goto Exit;

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

	if (HPDF_Dict_AddNumber (image, "BitsPerComponent",
				(HPDF_UINT)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;
}
Esempio n. 17
0
int PngDecoder::validate()
{
    if (png_sig_cmp((png_bytep)buf->data(), 0, PNG_HEADER_SIZE)) {
        std::cout << "[PngDecoder] error: %s is not a PNG." << std::endl;
        return -1;
    }
    buf->drain(PNG_HEADER_SIZE);

    png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
    if (!png_ptr) {
        std::cout << "[PngDecoder] error: png_create_read_struct returned 0." << std::endl;
        return -1;
    }

    info_ptr = png_create_info_struct(png_ptr);
    if (!info_ptr) {
        std::cout << "[PngDecoder] error: png_create_info_struct returned 0." << std::endl;
        png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL);
        return -1;
    }

    end_info = png_create_info_struct(png_ptr);
    if (!end_info) {
        std::cout << "[PngDecoder] error: png_create_info_struct returned 0." << std::endl;
        png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp) NULL);
        return -1;
    }

    if (setjmp(png_jmpbuf(png_ptr))) {
        std::cout << "[PngDecoder] error from libpng" << std::endl;
        png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
        return -1;
    }

    png_set_read_fn(png_ptr, buf, pngDecoderReadFunction);

    png_set_sig_bytes(png_ptr, PNG_HEADER_SIZE);

    png_read_info(png_ptr, info_ptr);

    png_set_expand(png_ptr);
    png_set_strip_16(png_ptr);
    png_set_gray_to_rgb(png_ptr);
    png_set_add_alpha(png_ptr, 0xff, PNG_FILLER_AFTER);
    png_set_interlace_handling(png_ptr);

    png_read_update_info(png_ptr, info_ptr);

    imgInfo.width    = png_get_image_width(png_ptr, info_ptr);
    imgInfo.height   = png_get_image_height(png_ptr, info_ptr);

    imgInfo.color_type = png_get_color_type(png_ptr, info_ptr);
    imgInfo.channels = png_get_channels(png_ptr, info_ptr);
    imgInfo.bit_depth = png_get_bit_depth(png_ptr, info_ptr);
    imgInfo.interlance_type = png_get_interlace_type(png_ptr, info_ptr);
    imgInfo.rowbytes = png_get_rowbytes(png_ptr, info_ptr);

#ifdef _PNGDECODER_DEBUG
    std::cout << "[PngDecoder] Extracted w=" << imgInfo.width
              << " h="  << imgInfo.height
              << " color_type=" << imgInfo.color_type
              << " bit_depth="<< imgInfo.bit_depth
              << " rowbytes="<< imgInfo.rowbytes
              << " channels="<< imgInfo.channels
              << " interlance_type="<< imgInfo.interlance_type
              << std::endl;
#endif

    if (imgInfo.bit_depth != 8) {
        std::cout << "[PngDecoder] error: Unsupported bit depth=" << imgInfo.bit_depth <<". Must be 8." << std::endl;
        return -1;
    }

    switch(imgInfo.color_type) {
    case PNG_COLOR_TYPE_RGB:
        imgInfo.format = GL_RGB;
        break;
    case PNG_COLOR_TYPE_RGB_ALPHA:
        imgInfo.format = GL_RGBA;
        break;
    case PNG_COLOR_TYPE_PALETTE:
        if (imgInfo.color_type & PNG_COLOR_MASK_ALPHA) {
            imgInfo.format = GL_RGBA;
        } else if (imgInfo.color_type & PNG_COLOR_MASK_COLOR) {
            imgInfo.format = GL_RGB;
        }
        break;
    default:
        std::cout << "[PngDecoder] error: unknown libpng color type=" << imgInfo.color_type << " rgb=" << PNG_COLOR_TYPE_RGB << " rgba=" << PNG_COLOR_TYPE_RGBA << " palette=" << PNG_COLOR_TYPE_PALETTE << std::endl;
        return -1;
    }

    return 0;
}
Esempio n. 18
0
void PNGImageDecoder::rowAvailable(unsigned char* rowBuffer, unsigned rowIndex, int)
{
    if (m_frameBufferCache.isEmpty())
        return;

    // Initialize the framebuffer if needed.
    ImageFrame& buffer = m_frameBufferCache[0];
    if (buffer.status() == ImageFrame::FrameEmpty) {
        png_structp png = m_reader->pngPtr();
        if (!buffer.setSize(size().width(), size().height())) {
            longjmp(JMPBUF(png), 1);
            return;
        }

        unsigned colorChannels = m_reader->hasAlpha() ? 4 : 3;
        if (PNG_INTERLACE_ADAM7 == png_get_interlace_type(png, m_reader->infoPtr())) {
            m_reader->createInterlaceBuffer(colorChannels * size().width() * size().height());
            if (!m_reader->interlaceBuffer()) {
                longjmp(JMPBUF(png), 1);
                return;
            }
        }

#if USE(QCMSLIB)
        if (m_reader->colorTransform()) {
            m_reader->createRowBuffer(colorChannels * size().width());
            if (!m_reader->rowBuffer()) {
                longjmp(JMPBUF(png), 1);
                return;
            }
        }
#endif
        buffer.setStatus(ImageFrame::FramePartial);
        buffer.setHasAlpha(false);

        // For PNGs, the frame always fills the entire image.
        buffer.setOriginalFrameRect(IntRect(IntPoint(), size()));
    }

    /* libpng comments (here to explain what follows).
     *
     * this function is called for every row in the image. If the
     * image is interlacing, and you turned on the interlace handler,
     * this function will be called for every row in every pass.
     * Some of these rows will not be changed from the previous pass.
     * When the row is not changed, the new_row variable will be NULL.
     * The rows and passes are called in order, so you don't really
     * need the row_num and pass, but I'm supplying them because it
     * may make your life easier.
     */

    // Nothing to do if the row is unchanged, or the row is outside
    // the image bounds: libpng may send extra rows, ignore them to
    // make our lives easier.
    if (!rowBuffer)
        return;
    int y = rowIndex;
    if (y < 0 || y >= size().height())
        return;

    /* libpng comments (continued).
     *
     * For the non-NULL rows of interlaced images, you must call
     * png_progressive_combine_row() passing in the row and the
     * old row.  You can call this function for NULL rows (it will
     * just return) and for non-interlaced images (it just does the
     * memcpy for you) if it will make the code easier. Thus, you
     * can just do this for all cases:
     *
     *    png_progressive_combine_row(png_ptr, old_row, new_row);
     *
     * where old_row is what was displayed for previous rows. Note
     * that the first pass (pass == 0 really) will completely cover
     * the old row, so the rows do not have to be initialized. After
     * the first pass (and only for interlaced images), you will have
     * to pass the current row, and the function will combine the
     * old row and the new row.
     */

    bool hasAlpha = m_reader->hasAlpha();
    png_bytep row = rowBuffer;

    if (png_bytep interlaceBuffer = m_reader->interlaceBuffer()) {
        unsigned colorChannels = hasAlpha ? 4 : 3;
        row = interlaceBuffer + (rowIndex * colorChannels * size().width());
        png_progressive_combine_row(m_reader->pngPtr(), row, rowBuffer);
    }

#if USE(QCMSLIB)
    if (qcms_transform* transform = m_reader->colorTransform()) {
        qcms_transform_data(transform, row, m_reader->rowBuffer(), size().width());
        row = m_reader->rowBuffer();
    }
#endif

    // Write the decoded row pixels to the frame buffer. The repetitive
    // form of the row write loops is for speed.
    ImageFrame::PixelData* address = buffer.getAddr(0, y);
    unsigned alphaMask = 255;
    int width = size().width();

    png_bytep pixel = row;
    if (hasAlpha) {
        if (buffer.premultiplyAlpha()) {
            for (int x = 0; x < width; ++x, pixel += 4) {
                buffer.setRGBAPremultiply(address++, pixel[0], pixel[1], pixel[2], pixel[3]);
                alphaMask &= pixel[3];
            }
        } else {
            for (int x = 0; x < width; ++x, pixel += 4) {
                buffer.setRGBARaw(address++, pixel[0], pixel[1], pixel[2], pixel[3]);
                alphaMask &= pixel[3];
            }
        }
    } else {
        for (int x = 0; x < width; ++x, pixel += 3) {
            buffer.setRGBARaw(address++, pixel[0], pixel[1], pixel[2], 255);
        }
    }

    if (alphaMask != 255 && !buffer.hasAlpha())
        buffer.setHasAlpha(true);

    buffer.setPixelsChanged(true);
}
Esempio n. 19
0
int simpl_gray_load_png(SimplGrayImage **image,
                        SimplInStream istream,
                        const SimplColorToGrayMethods method,
                        const SimplPixel bk_value)
{
	png_structp png_ptr;
	png_infop info_ptr;
	png_byte color_type, bitdepth, *row_data=NULL;
	png_bytep* row_ptrs=NULL;
	
	png_uint_32 i, j, x, width, height, row_size;
	
	SimplColorPixel *pixels=NULL;
	SimplPixel *iptr, *alpha=NULL;
	
	int value, out = SIMPL_INTERNAL;
	
	/* Create a read struct. */
	if (!(png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0))) {
		return SIMPL_INTERNAL;
	}
	
	/* Create an info struct. */
	if (!(info_ptr = png_create_info_struct(png_ptr))) {
		goto error;
	}
	
	/* Handle libpng errors with a magic setjmp. */
	if (setjmp(png_jmpbuf(png_ptr))) {
		goto error;
	}
	
	/* Set the stream-based data source. */
	png_set_read_fn(png_ptr, istream, StreamReadData);
	
	/* Read the info chunk. */
	png_read_info(png_ptr, info_ptr);
	
	/* Get the dimensions and color information. */
	width = png_get_image_width(png_ptr, info_ptr);
	height = png_get_image_height(png_ptr, info_ptr);
	bitdepth = png_get_bit_depth(png_ptr, info_ptr);
	color_type = png_get_color_type(png_ptr, info_ptr);
	
	/* If palette, low bit depth gray, transparent w/o alpha, or 16 bit, fix it. */
	if (color_type == PNG_COLOR_TYPE_PALETTE) {
		png_set_palette_to_rgb(png_ptr);
		color_type = png_get_color_type(png_ptr, info_ptr);
	} else if (color_type == PNG_COLOR_TYPE_GRAY) {
		if (bitdepth<8) png_set_expand_gray_1_2_4_to_8(png_ptr);
		bitdepth = 8;
	}
	
	if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
		png_set_tRNS_to_alpha(png_ptr);
		color_type = png_get_color_type(png_ptr, info_ptr);
	}
	
	png_set_strip_16(png_ptr);
	
	/* Either allocate a row, or load the entire image into a buffer. This is
	 * because single row access uses less memory but doesn't work for
	 * interlaced PNGs.
	 */
	row_size = png_get_rowbytes(png_ptr, info_ptr);
	if (png_get_interlace_type(png_ptr, info_ptr)==PNG_INTERLACE_NONE) {
		row_data = (png_byte *)malloc(sizeof(png_byte) * row_size);
		if (!row_data) {
			out = SIMPL_NOMEM;
			goto error;
		}
	} else {
		row_ptrs = (png_bytep*)calloc(height, sizeof(png_bytep));
		if (!row_ptrs) {
			out = SIMPL_NOMEM;
			goto error;
		}
		
		for (j=0; j<height; ++j) {
			row_ptrs[j] = (png_byte *)malloc(sizeof(png_byte) * row_size);
			if (!row_ptrs[j]) {
				out = SIMPL_NOMEM;
				goto error;
			}
		}
		
		png_read_image(png_ptr, row_ptrs);
	}
	
	/* Allocate an image of the specified size. */
	out = simpl_gray(image, width, height);
	if (out != SIMPL_OK) goto error;
	
	/* Decode the image line by line. */
	if (color_type == PNG_COLOR_TYPE_RGB || color_type == PNG_COLOR_TYPE_RGB_ALPHA) {
		pixels = (SimplColorPixel *)malloc(sizeof(SimplColorPixel) * width);
		if (!pixels) {
			out = SIMPL_NOMEM;
			goto error;
		}
		
		alpha = (SimplPixel *)malloc(sizeof(SimplPixel) * width);
		if (!alpha) {
			out = SIMPL_NOMEM;
			goto error;
		}
		memset(alpha, 255, width);
		
		for (j=0; j<height; j++) {
			if (row_ptrs) row_data = row_ptrs[j];
			else png_read_row(png_ptr, row_data, NULL);
			iptr = (*image)->image + j * width;
			
			if (color_type==PNG_COLOR_TYPE_RGB) {
				for (x=i=0; x<width; ++x, i+=3) {
					pixels[x].red   = row_data[i];
					pixels[x].green = row_data[i+1];
					pixels[x].blue  = row_data[i+2];
				}
			} else {
				for (x=i=0; x<width; ++x, i+=4) {
					pixels[x].red   = row_data[i];
					pixels[x].green = row_data[i+1];
					pixels[x].blue  = row_data[i+2];
					alpha[x]        = row_data[i+3];
				}
			}
			
			switch(method) {
			case COLOR_TO_GRAY_RED:
				for (i=0; i<width; ++i) iptr[i] = pixels[i].red;
				break;
				
			case COLOR_TO_GRAY_GREEN:
				for (i=0; i<width; ++i) iptr[i] = pixels[i].green;
				break;
				
			case COLOR_TO_GRAY_BLUE:
				for (i=0; i<width; ++i) iptr[i] = pixels[i].blue;
				break;
				
			case COLOR_TO_GRAY_ALPHA:
				for (i=0; i<width; ++i) iptr[i] = alpha[i];
				break;
				
			case COLOR_TO_GRAY_CIE:
				if (color_type==PNG_COLOR_TYPE_RGB_ALPHA) {
					for (i=0; i<width; ++i) {
						value = (6969*pixels[i].red + 23434*pixels[i].green + 2365*pixels[i].blue)>>15;
						value = (alpha[i]*value + (255-alpha[i])*bk_value) / 255;
						iptr[i] = (value>255)?255:value;
					}
				} else {
					for (i=0; i<width; ++i) {
						value = (6969*pixels[i].red + 23434*pixels[i].green + 2365*pixels[i].blue)>>15;
						iptr[i] = (value>255)?255:value;
					}
				}
				break;
				
			case COLOR_TO_GRAY_MEAN:
			default:
				if (color_type==PNG_COLOR_TYPE_RGB_ALPHA) {
					for (i=0; i<width; ++i) {
						value = (pixels[i].red + pixels[i].green + pixels[i].blue)/3;
						value = (alpha[i]*value + (255-alpha[i])*bk_value) / 255;
						iptr[i] = (value>255)?255:value;
					}
				} else {
					for (i=0; i<width; ++i) {
						value = (pixels[i].red + pixels[i].green + pixels[i].blue)/3;
						iptr[i] = (value>255)?255:value;
					}
				}
				break;
			}
		}
Esempio n. 20
0
int simpl_image_load_png(SimplImage **image,
                         SimplInStream istream)
{
	png_structp png_ptr;
	png_infop info_ptr;
	png_byte color_type, bitdepth, *row_data=NULL;
	png_bytep* row_ptrs=NULL;
	
	png_uint_32 i, j, width, height, row_size;
	
	SimplColorPixel *iptr;
	SimplPixel *aptr;
	
	int out = SIMPL_INTERNAL;
	
	/* Create a read struct. */
	if (!(png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0))) {
		return SIMPL_INTERNAL;
	}
	
	/* Create an info struct. */
	if (!(info_ptr = png_create_info_struct(png_ptr))) {
		goto error;
	}
	
	/* Handle libpng errors with a magic setjmp. */
	if (setjmp(png_jmpbuf(png_ptr))) {
		goto error;
	}
	
	/* Set the stream-based data source. */
	png_set_read_fn(png_ptr, istream, StreamReadData);
	
	/* Read the info chunk. */
	png_read_info(png_ptr, info_ptr);
	
	/* Get the dimensions and color information. */
	width = png_get_image_width(png_ptr, info_ptr);
	height = png_get_image_height(png_ptr, info_ptr);
	bitdepth = png_get_bit_depth(png_ptr, info_ptr);
	color_type = png_get_color_type(png_ptr, info_ptr);
	
	/* If palette, low bit depth gray, transparent w/o alpha, or 16 bit, fix it. */
	if (color_type == PNG_COLOR_TYPE_PALETTE) {
		png_set_palette_to_rgb(png_ptr);
		color_type = png_get_color_type(png_ptr, info_ptr);
	} else if (color_type == PNG_COLOR_TYPE_GRAY) {
		if (bitdepth<8) png_set_expand_gray_1_2_4_to_8(png_ptr);
		bitdepth = 8;
	}
	
	if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
		png_set_tRNS_to_alpha(png_ptr);
		color_type = png_get_color_type(png_ptr, info_ptr);
	}
	
	png_set_strip_16(png_ptr);
	
	/* Either allocate a row, or load the entire image into a buffer. This is
	 * because single row access uses less memory but doesn't work for
	 * interlaced PNGs.
	 */
	row_size = png_get_rowbytes(png_ptr, info_ptr);
	if (png_get_interlace_type(png_ptr, info_ptr)==PNG_INTERLACE_NONE) {
		row_data = (png_byte *)malloc(sizeof(png_byte) * row_size);
		if (!row_data) {
			out = SIMPL_NOMEM;
			goto error;
		}
	} else {
		row_ptrs = (png_bytep*)calloc(height, sizeof(png_bytep));
		if (!row_ptrs) {
			out = SIMPL_NOMEM;
			goto error;
		}
		
		for (j=0; j<height; ++j) {
			row_ptrs[j] = (png_byte *)malloc(sizeof(png_byte) * row_size);
			if (!row_ptrs[j]) {
				out = SIMPL_NOMEM;
				goto error;
			}
		}
		
		png_read_image(png_ptr, row_ptrs);
	}
		
	/* Allocate an image of the specified size. */
	out = simpl_image(image, width, height);
	if (out != SIMPL_OK) goto error;
		
	/* Store the decoded image into our format. */
	if (color_type == PNG_COLOR_TYPE_RGB) {
		for (j=0; j<height; j++) {
			if (row_ptrs) row_data = row_ptrs[j];
			else png_read_row(png_ptr, row_data, NULL);
			
			iptr = (*image)->image + j * width;
			for (i=0; i<3*width; i+=3) {
				iptr->red   = row_data[i];
				iptr->green = row_data[i+1];
				iptr->blue  = row_data[i+2];
				iptr++;
			}
		}
	} else if (color_type == PNG_COLOR_TYPE_RGB_ALPHA) {
		simpl_alpha_create(*image);
		for (j=0; j<height; j++) {
			if (row_ptrs) row_data = row_ptrs[j];
			else png_read_row(png_ptr, row_data, NULL);
			
			iptr = (*image)->image + j * width;
			aptr = (*image)->alpha + j * width;
			for (i=0; i<4*width; i+=4) {
				iptr->red   = row_data[i];
				iptr->green = row_data[i+1];
				iptr->blue  = row_data[i+2];
				iptr++;
			
				*aptr++ = row_data[i+3];
			}
		}
	} else if (color_type == PNG_COLOR_TYPE_GRAY) {
		for (j=0; j<height; j++) {
			if (row_ptrs) row_data = row_ptrs[j];
			else png_read_row(png_ptr, row_data, NULL);
			
			iptr = (*image)->image + j * width;
			for (i=0; i<width; i++) {
				iptr->red   = row_data[i];
				iptr->green = row_data[i];
				iptr->blue  = row_data[i];
				iptr++;
			}
		}
	} else if (color_type == PNG_COLOR_TYPE_GRAY_ALPHA) {
		simpl_alpha_create(*image);
		for (j=0; j<height; j++) {
			if (row_ptrs) row_data = row_ptrs[j];
			else png_read_row(png_ptr, row_data, NULL);
			
			iptr = (*image)->image + j * width;
			aptr = (*image)->alpha + j * width;
			for (i=0; i<2*width; i+=2) {
				iptr->red   = row_data[i];
				iptr->green = row_data[i];
				iptr->blue  = row_data[i];
				iptr++;
			
				*aptr++ = row_data[i+1];
			}
		}
	} else goto error;
	
error:
	if (row_ptrs) {
		for (j=0; j<height; ++j) {
			if (row_ptrs[j]) free((void *)row_ptrs[j]);
		}
		
		free((void *)row_ptrs);
	} else {
		if (row_data) free((void *)row_data);
	}
	
	png_destroy_read_struct(&png_ptr, &info_ptr, 0);
	return out;
}
Esempio n. 21
0
int
xps_decode_png(xps_context_t *ctx, byte *rbuf, int rlen, xps_image_t *image)
{
    png_structp png;
    png_infop info;
    struct xps_png_io_s io;
    int npasses;
    int pass;
    int y;

    /*
     * Set up PNG structs and input source
     */

    io.ptr = rbuf;
    io.lim = rbuf + rlen;

    png = png_create_read_struct_2(PNG_LIBPNG_VER_STRING,
            NULL, NULL, NULL,
            ctx->memory, xps_png_malloc, xps_png_free);
    if (!png)
        return gs_throw(-1, "png_create_read_struct");

    info = png_create_info_struct(png);
    if (!info)
        return gs_throw(-1, "png_create_info_struct");

    png_set_read_fn(png, &io, xps_png_read);
    png_set_crc_action(png, PNG_CRC_WARN_USE, PNG_CRC_WARN_USE);

    /*
     * Jump to here on errors.
     */

    if (setjmp(png_jmpbuf(png)))
    {
        png_destroy_read_struct(&png, &info, NULL);
        return gs_throw(-1, "png reading failed");
    }

    /*
     * Read PNG header
     */

    png_read_info(png, info);

    if (png_get_interlace_type(png, info) == PNG_INTERLACE_ADAM7)
    {
        npasses = png_set_interlace_handling(png);
    }
    else
    {
        npasses = 1;
    }

    if (png_get_color_type(png, info) == PNG_COLOR_TYPE_PALETTE)
    {
        png_set_palette_to_rgb(png);
    }

    if (png_get_valid(png, info, PNG_INFO_tRNS))
    {
        /* this will also expand the depth to 8-bits */
        png_set_tRNS_to_alpha(png);
    }

    png_read_update_info(png, info);

    image->width = png_get_image_width(png, info);
    image->height = png_get_image_height(png, info);
    image->comps = png_get_channels(png, info);
    image->bits = png_get_bit_depth(png, info);

    /* See if we have an icc profile */
    if (info->iccp_profile != NULL)
    {
        image->profilesize = info->iccp_proflen;
        image->profile = xps_alloc(ctx, info->iccp_proflen);
        if (image->profile)
        {
            /* If we can't create it, just ignore */
            memcpy(image->profile, info->iccp_profile, info->iccp_proflen);
        }
    }

    switch (png_get_color_type(png, info))
    {
    case PNG_COLOR_TYPE_GRAY:
        image->colorspace = ctx->gray;
        image->hasalpha = 0;
        break;

    case PNG_COLOR_TYPE_RGB:
        image->colorspace = ctx->srgb;
        image->hasalpha = 0;
        break;

    case PNG_COLOR_TYPE_GRAY_ALPHA:
        image->colorspace = ctx->gray;
        image->hasalpha = 1;
        break;

    case PNG_COLOR_TYPE_RGB_ALPHA:
        image->colorspace = ctx->srgb;
        image->hasalpha = 1;
        break;

    default:
        return gs_throw(-1, "cannot handle this png color type");
    }

    /*
     * Extract DPI, default to 96 dpi
     */

    image->xres = 96;
    image->yres = 96;

    if (info->valid & PNG_INFO_pHYs)
    {
        png_uint_32 xres, yres;
        int unit;
        png_get_pHYs(png, info, &xres, &yres, &unit);
        if (unit == PNG_RESOLUTION_METER)
        {
            image->xres = xres * 0.0254 + 0.5;
            image->yres = yres * 0.0254 + 0.5;
        }
    }

    /*
     * Read rows, filling transformed output into image buffer.
     */

    image->stride = (image->width * image->comps * image->bits + 7) / 8;

    image->samples = xps_alloc(ctx, image->stride * image->height);

    for (pass = 0; pass < npasses; pass++)
    {
        for (y = 0; y < image->height; y++)
        {
            png_read_row(png, image->samples + (y * image->stride), NULL);
        }
    }

    /*
     * Clean up memory.
     */

    png_destroy_read_struct(&png, &info, NULL);

    return gs_okay;
}
Esempio n. 22
0
TypedImage LoadPng(std::istream& source)
{
#ifdef HAVE_PNG
    //so First, we validate our stream with the validate function I just mentioned
    if (!pango_png_validate(source)) {
        throw std::runtime_error("Not valid PNG header");
    }

    //set up initial png structs
    png_structp png_ptr = png_create_read_struct( PNG_LIBPNG_VER_STRING, (png_voidp)NULL, NULL, &PngWarningsCallback);
    if (!png_ptr) {
        throw std::runtime_error( "PNG Init error 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);
        throw std::runtime_error( "PNG Init error 2" );
    }

    png_infop end_info = png_create_info_struct(png_ptr);
    if (!end_info) {
        png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
        throw std::runtime_error( "PNG Init error 3" );
    }

    png_set_read_fn(png_ptr,(png_voidp)&source, pango_png_stream_read);

    png_set_sig_bytes(png_ptr, PNGSIGSIZE);

    // Setup transformation options
    if( png_get_bit_depth(png_ptr, info_ptr) == 1)  {
        //Unpack bools to bytes to ease loading.
        png_set_packing(png_ptr);
    } else if( png_get_bit_depth(png_ptr, info_ptr) < 8) {
        //Expand nonbool colour depths up to 8bpp
        png_set_expand_gray_1_2_4_to_8(png_ptr);
    }

    //Get rid of palette, by transforming it to RGB
    if(png_get_color_type(png_ptr, info_ptr) == PNG_COLOR_TYPE_PALETTE) {
        png_set_palette_to_rgb(png_ptr);
    }

    //read the file
    png_read_png(png_ptr, info_ptr, PNG_TRANSFORM_SWAP_ENDIAN, NULL);

    if( png_get_interlace_type(png_ptr,info_ptr) != PNG_INTERLACE_NONE) {
        throw std::runtime_error( "Interlace not yet supported" );
    }

    const size_t w = png_get_image_width(png_ptr,info_ptr);
    const size_t h = png_get_image_height(png_ptr,info_ptr);
    const size_t pitch = png_get_rowbytes(png_ptr, info_ptr);

    TypedImage img(w, h, PngFormat(png_ptr, info_ptr), pitch);

    png_bytepp rows = png_get_rows(png_ptr, info_ptr);
    for( unsigned int r = 0; r < h; r++) {
        memcpy( img.ptr + pitch*r, rows[r], pitch );
    }
    png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);

    return img;
#else
    PANGOLIN_UNUSED(source);
    throw std::runtime_error("Rebuild Pangolin for PNG support.");
#endif // HAVE_PNG
}
Esempio n. 23
0
void PNGImageDecoder::rowAvailable(unsigned char* rowBuffer, unsigned rowIndex, int interlacePass)
{
    if (m_frameBufferCache.isEmpty())
        return;

    // Initialize the framebuffer if needed.
    ImageFrame& buffer = m_frameBufferCache[0];
    if (buffer.status() == ImageFrame::FrameEmpty) {
        if (!buffer.setSize(scaledSize().width(), scaledSize().height())) {
            longjmp(JMPBUF(m_reader->pngPtr()), 1);
            return;
        }
        buffer.setStatus(ImageFrame::FramePartial);
        buffer.setHasAlpha(false);
        buffer.setColorProfile(m_colorProfile);

        // For PNGs, the frame always fills the entire image.
        buffer.setOriginalFrameRect(IntRect(IntPoint(), size()));

        if (png_get_interlace_type(m_reader->pngPtr(), m_reader->infoPtr()) != PNG_INTERLACE_NONE)
            m_reader->createInterlaceBuffer((m_reader->hasAlpha() ? 4 : 3) * size().width() * size().height());
    }

    if (!rowBuffer)
        return;

    // libpng comments (pasted in here to explain what follows)
    /*
     * this function is called for every row in the image.  If the
     * image is interlacing, and you turned on the interlace handler,
     * this function will be called for every row in every pass.
     * Some of these rows will not be changed from the previous pass.
     * When the row is not changed, the new_row variable will be NULL.
     * The rows and passes are called in order, so you don't really
     * need the row_num and pass, but I'm supplying them because it
     * may make your life easier.
     *
     * For the non-NULL rows of interlaced images, you must call
     * png_progressive_combine_row() passing in the row and the
     * old row.  You can call this function for NULL rows (it will
     * just return) and for non-interlaced images (it just does the
     * memcpy for you) if it will make the code easier.  Thus, you
     * can just do this for all cases:
     *
     *    png_progressive_combine_row(png_ptr, old_row, new_row);
     *
     * where old_row is what was displayed for previous rows.  Note
     * that the first pass (pass == 0 really) will completely cover
     * the old row, so the rows do not have to be initialized.  After
     * the first pass (and only for interlaced images), you will have
     * to pass the current row, and the function will combine the
     * old row and the new row.
     */

    png_structp png = m_reader->pngPtr();
    bool hasAlpha = m_reader->hasAlpha();
    unsigned colorChannels = hasAlpha ? 4 : 3;
    png_bytep row;
    png_bytep interlaceBuffer = m_reader->interlaceBuffer();
    if (interlaceBuffer) {
        row = interlaceBuffer + (rowIndex * colorChannels * size().width());
        png_progressive_combine_row(png, row, rowBuffer);
    } else
        row = rowBuffer;

    // Copy the data into our buffer.
    int width = scaledSize().width();
    int destY = scaledY(rowIndex);

    // Check that the row is within the image bounds. LibPNG may supply an extra row.
    if (destY < 0 || destY >= scaledSize().height())
        return;
    bool nonTrivialAlpha = false;
    for (int x = 0; x < width; ++x) {
        png_bytep pixel = row + (m_scaled ? m_scaledColumns[x] : x) * colorChannels;
        unsigned alpha = hasAlpha ? pixel[3] : 255;
        buffer.setRGBA(x, destY, pixel[0], pixel[1], pixel[2], alpha);
        nonTrivialAlpha |= alpha < 255;
    }
    if (nonTrivialAlpha && !buffer.hasAlpha())
        buffer.setHasAlpha(nonTrivialAlpha);
}
Esempio n. 24
0
int ImageFilter_PNG::ident(FileObject &file, IMAGE &img)
{
#ifdef HAVE_PNG
	try {
		const char *address=file.map(0,256);
		file.seek(0);
		if (address==NULL) return 0;

		if (png_sig_cmp((png_byte*)address, 0, 8)!=0) { // Ist es ein PNG-File?
			return 0;
		}
		png_structp png_ptr = png_create_read_struct
				(PNG_LIBPNG_VER_STRING, NULL ,NULL, NULL);
		if (!png_ptr) return 0;

		png_infop info_ptr = png_create_info_struct(png_ptr);
		if (!info_ptr) {
			png_destroy_read_struct(&png_ptr,(png_infopp)NULL, (png_infopp)NULL);
			return 0;
		}
		png_infop end_info = png_create_info_struct(png_ptr);
		if (!end_info) {
			png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
			return 0;
		}
		png_set_read_fn(png_ptr,&file, (png_rw_ptr) user_read_data);
		//png_set_write_fn(png_structp write_ptr, voidp write_io_ptr, png_rw_ptr write_data_fn,
		//    png_flush_ptr output_flush_fn);
		png_read_info(png_ptr, info_ptr);
		img.width=png_get_image_width(png_ptr, info_ptr);
		img.height=png_get_image_height(png_ptr, info_ptr);
		img.bitdepth=png_get_bit_depth(png_ptr, info_ptr);
		img.colors=0;
		img.pitch=png_get_rowbytes(png_ptr, info_ptr);
		//img->pfp.header_version=0;
		bool supported=true;
		img.format=RGBFormat::unknown;
		if (img.bitdepth!=8) supported=false;		// Nur 8-Bit/Farbwert wird unterstützt

		switch (png_get_color_type(png_ptr, info_ptr)) {
			case PNG_COLOR_TYPE_GRAY:
				img.bitdepth=8;
				img.colors=256;
				img.format=RGBFormat::GREY8;
				break;
			case PNG_COLOR_TYPE_PALETTE:
				img.bitdepth=8;
				img.colors=256;
				img.format=RGBFormat::Palette;
				//supported=false;
				break;
			case PNG_COLOR_TYPE_RGB:
				img.colors=0xffffff;
				img.bitdepth=24;
				img.format=RGBFormat::X8R8G8B8;
				break;
			case PNG_COLOR_TYPE_RGB_ALPHA:
				img.colors=0xffffff;
				img.bitdepth=32;
				img.format=RGBFormat::A8R8G8B8;
				break;
			case PNG_COLOR_TYPE_GRAY_ALPHA:
				img.colors=256;
				img.bitdepth=32;
				img.format=RGBFormat::GREYALPHA32;
				break;
		};

		if (png_get_interlace_type(png_ptr,info_ptr)!=PNG_INTERLACE_NONE) {	// Interlaced wird nicht unterstützt
			supported=false;
		}

		png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
		if (!supported) {
			return 0;
		}
		return 1;
	} catch (...) {
		return 0;
	}
	return 0;
#else
	return 0;
#endif
}
Esempio n. 25
0
void png_reader::read(unsigned x0, unsigned y0,image_data_32& image)
{
    FILE *fp=fopen(fileName_.c_str(),"rb");
    if (!fp) throw image_reader_exception("cannot open image file "+fileName_);

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

    if (!png_ptr)
    {
        fclose(fp);
        throw image_reader_exception("failed to allocate png_ptr");
    }

    // catch errors in a custom way to avoid the need for setjmp
    png_set_error_fn(png_ptr, png_get_error_ptr(png_ptr), user_error_fn, user_warning_fn);

    png_infop info_ptr;
    try
    {
        info_ptr = png_create_info_struct(png_ptr);
        if (!info_ptr)
        {
            png_destroy_read_struct(&png_ptr,0,0);
            fclose(fp);
            throw image_reader_exception("failed to create info_ptr");
        }
    }
    catch (std::exception const& ex)
    {
        png_destroy_read_struct(&png_ptr,0,0);
        fclose(fp);
        throw;
    }

    png_set_read_fn(png_ptr, (png_voidp)fp, png_read_data);
    png_read_info(png_ptr, info_ptr);

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

    // quick hack -- only work in >=libpng 1.2.7
    png_set_add_alpha(png_ptr,0xff,PNG_FILLER_AFTER); //rgba

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

    if (x0 == 0 && y0 == 0 && image.width() >= width_ && image.height() >= height_)
    {

        if (png_get_interlace_type(png_ptr,info_ptr) == PNG_INTERLACE_ADAM7)
        {
            png_set_interlace_handling(png_ptr); // FIXME: libpng bug?
            // according to docs png_read_image
            // "..automatically handles interlacing,
            // so you don't need to call png_set_interlace_handling()"
        }
        png_read_update_info(png_ptr, info_ptr);
        // we can read whole image at once
        // alloc row pointers
        boost::scoped_array<png_byte*> rows(new png_bytep[height_]);
        for (unsigned i=0; i<height_; ++i)
            rows[i] = (png_bytep)image.getRow(i);
        png_read_image(png_ptr, rows.get());
    }
    else
    {
        png_read_update_info(png_ptr, info_ptr);
        unsigned w=std::min(unsigned(image.width()),width_);
        unsigned h=std::min(unsigned(image.height()),height_);
        unsigned rowbytes=png_get_rowbytes(png_ptr, info_ptr);
        boost::scoped_array<png_byte> row(new png_byte[rowbytes]);
        //START read image rows
        for (unsigned i=0;i<height_;++i)
        {
            png_read_row(png_ptr,row.get(),0);
            if (i>=y0 && i<h)
            {
                image.setRow(i-y0,reinterpret_cast<unsigned*>(&row[x0]),w);
            }
        }
        //END
    }

    png_read_end(png_ptr,0);
    png_destroy_read_struct(&png_ptr, &info_ptr,0);
    fclose(fp);
}
Esempio n. 26
0
File: png.c Progetto: rtandy/meh
int png_read(struct image *img){
	unsigned int y;
	png_bytepp row_pointers;
	struct png_t *p = (struct png_t *)img;

	if(setjmp(png_jmpbuf(p->png_ptr))){
		png_destroy_read_struct(&p->png_ptr, &p->info_ptr, &p->end_info);
		return 1;
	}

	{
		int color_type = png_get_color_type(p->png_ptr, p->info_ptr);
		int bit_depth = png_get_bit_depth(p->png_ptr, p->info_ptr);
		if (color_type == PNG_COLOR_TYPE_PALETTE)
			png_set_expand(p->png_ptr);
		if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
			png_set_expand(p->png_ptr);
		if (png_get_valid(p->png_ptr, p->info_ptr, PNG_INFO_tRNS))
			png_set_expand(p->png_ptr);
		if (bit_depth == 16)
			png_set_strip_16(p->png_ptr);
		if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
			png_set_gray_to_rgb(p->png_ptr);
		//png_set_strip_alpha(p->png_ptr);

		png_color_16 my_background = {.red = 0xff, .green = 0xff, .blue = 0xff};
		png_color_16p image_background;

		if(png_get_bKGD(p->png_ptr, p->info_ptr, &image_background))
			png_set_background(p->png_ptr, image_background, PNG_BACKGROUND_GAMMA_FILE, 1, 1.0);
		else
			png_set_background(p->png_ptr, &my_background, PNG_BACKGROUND_GAMMA_SCREEN, 2, 1.0);

		if(png_get_interlace_type(p->png_ptr, p->info_ptr) == PNG_INTERLACE_ADAM7)
			p->numpasses = png_set_interlace_handling(p->png_ptr);
		else
			p->numpasses = 1;
		png_read_update_info(p->png_ptr, p->info_ptr);
	}

	row_pointers = (png_bytepp)malloc(img->bufheight * sizeof(png_bytep));
	for(y = 0; y < img->bufheight; y++)
		row_pointers[y] = img->buf + y * img->bufwidth * 3;

	png_read_image(p->png_ptr, row_pointers);
	free(row_pointers);

	img->state |= LOADED | SLOWLOADED;

	return 0;
}

void png_close(struct image *img){
	struct png_t *p = (struct png_t *)img;
	png_destroy_read_struct(&p->png_ptr, &p->info_ptr, &p->end_info);
	fclose(p->f);
}

struct imageformat libpng = {
	png_open,
	NULL,
	png_read,
	png_close
};
Esempio n. 27
0
TypedImage LoadPng(const std::string& filename)
{
    PANGOLIN_UNUSED(filename);

#ifdef HAVE_PNG
    FILE *in = fopen(filename.c_str(), "rb");

    if( in )  {
        //check the header
        const size_t nBytes = 8;
        png_byte header[nBytes];
        size_t nread = fread(header, 1, nBytes, in);
        int nIsPNG = png_sig_cmp(header, 0, nread);

        if ( nIsPNG != 0 )  {
            throw std::runtime_error( filename + " is not a PNG file" );
        }

        //set up initial png structs
        png_structp png_ptr = png_create_read_struct( PNG_LIBPNG_VER_STRING, (png_voidp)NULL, NULL, &PngWarningsCallback);
        if (!png_ptr) {
            throw std::runtime_error( "PNG Init error 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);
            throw std::runtime_error( "PNG Init error 2" );
        }

        png_infop end_info = png_create_info_struct(png_ptr);
        if (!end_info) {
            png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
            throw std::runtime_error( "PNG Init error 3" );
        }

        png_init_io(png_ptr, in);
        png_set_sig_bytes(png_ptr, nBytes);

        //read the file
        png_read_png(png_ptr, info_ptr, PNG_TRANSFORM_SWAP_ENDIAN, NULL);

        if( png_get_bit_depth(png_ptr, info_ptr) == 1)  {
            //Unpack bools to bytes to ease loading.
            png_set_packing(png_ptr);
        } else if( png_get_bit_depth(png_ptr, info_ptr) < 8) {
            //Expand nonbool colour depths up to 8bpp
            png_set_expand_gray_1_2_4_to_8(png_ptr);
        }

        //Get rid of palette, by transforming it to RGB
        if(png_get_color_type(png_ptr, info_ptr) == PNG_COLOR_TYPE_PALETTE) {
            png_set_palette_to_rgb(png_ptr);
        }

        if( png_get_interlace_type(png_ptr,info_ptr) != PNG_INTERLACE_NONE) {
            throw std::runtime_error( "Interlace not yet supported" );
        }

        const size_t w = png_get_image_width(png_ptr,info_ptr);
        const size_t h = png_get_image_height(png_ptr,info_ptr);
        const size_t pitch = png_get_rowbytes(png_ptr, info_ptr);

        TypedImage img(w, h, PngFormat(png_ptr, info_ptr), pitch);

        png_bytepp rows = png_get_rows(png_ptr, info_ptr);
        for( unsigned int r = 0; r < h; r++) {
            memcpy( img.ptr + pitch*r, rows[r], pitch );
        }
        png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);

        fclose(in);
        return img;
    }

    throw std::runtime_error("Unable to load PNG file, '" + filename + "'");

#else
    throw std::runtime_error("PNG Support not enabled. Please rebuild Pangolin.");
#endif
}
PremultipliedImage decodePNG(const uint8_t* data, size_t size) {
    util::CharArrayBuffer dataBuffer { reinterpret_cast<const char*>(data), size };
    std::istream stream(&dataBuffer);

    png_byte header[8] = { 0 };
    stream.read(reinterpret_cast<char*>(header), 8);
    if (stream.gcount() != 8)
        throw std::runtime_error("PNG reader: Could not read image");

    int is_png = !png_sig_cmp(header, 0, 8);
    if (!is_png)
        throw std::runtime_error("File or stream is not a png");

    png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr);
    if (!png_ptr)
        throw std::runtime_error("failed to allocate png_ptr");

    // catch errors in a custom way to avoid the need for setjmp
    png_set_error_fn(png_ptr, png_get_error_ptr(png_ptr), user_error_fn, user_warning_fn);

    png_infop info_ptr;
    png_struct_guard sguard(&png_ptr, &info_ptr);
    info_ptr = png_create_info_struct(png_ptr);
    if (!info_ptr)
        throw std::runtime_error("failed to create info_ptr");

    png_set_read_fn(png_ptr, &stream, png_read_data);
    png_set_sig_bytes(png_ptr, 8);
    png_read_info(png_ptr, info_ptr);

    png_uint_32 width = 0;
    png_uint_32 height = 0;
    int bit_depth = 0;
    int color_type = 0;
    png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, nullptr, nullptr, nullptr);

    UnassociatedImage image { static_cast<uint16_t>(width), static_cast<uint16_t>(height) };

    if (color_type == PNG_COLOR_TYPE_PALETTE)
        png_set_expand(png_ptr);

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

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

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

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

    png_set_add_alpha(png_ptr, 0xff, PNG_FILLER_AFTER);

    if (png_get_interlace_type(png_ptr,info_ptr) == PNG_INTERLACE_ADAM7) {
        png_set_interlace_handling(png_ptr); // FIXME: libpng bug?
        // according to docs png_read_image
        // "..automatically handles interlacing,
        // so you don't need to call png_set_interlace_handling()"
    }

    png_read_update_info(png_ptr, info_ptr);

    // we can read whole image at once
    // alloc row pointers
    const std::unique_ptr<png_bytep[]> rows(new png_bytep[height]);
    for (unsigned row = 0; row < height; ++row)
        rows[row] = image.data.get() + row * width * 4;
    png_read_image(png_ptr, rows.get());

    png_read_end(png_ptr, nullptr);

    return util::premultiply(std::move(image));
}
Esempio n. 29
0
int begin(char* base_file_name, unsigned char *png_buf, long long png_length) {

  MY_PNG_READ_OFFSET = 0;
  PNG_LENGTH = png_length; 
  ENTIRE_PNG_BUF = png_buf;

  if (png_sig_cmp(ENTIRE_PNG_BUF, 0, 8) != 0) {
    error(-1, "png_sig_cmp", E_INVALID);
    return -1;
  }

  DEBUG_PRINT(("Initial png size is %lld bytes\n", PNG_LENGTH));

  my_png_meta *pm = calloc(1, sizeof(my_png_meta));
  my_init_libpng(pm);

  //If libpng errors, we end up here
  if (setjmp(png_jmpbuf(pm->read_ptr))) {
    DEBUG_PRINT(("libpng called setjmp!\n"));
    my_deinit_libpng(pm);
    free(ENTIRE_PNG_BUF);
    error(-1, "libpng", "libpng encountered an error\n");
    return -1;
  }

  //Normally a file, but instead make it our buffer
  void *read_io_ptr = png_get_io_ptr(pm->read_ptr);
  png_set_read_fn(pm->read_ptr, read_io_ptr, my_png_read_fn);

  //Transform all PNG image types to RGB
  int transforms = 
    PNG_TRANSFORM_GRAY_TO_RGB |
    PNG_TRANSFORM_STRIP_ALPHA | 
    PNG_TRANSFORM_EXPAND;

  png_read_png(pm->read_ptr, pm->info_ptr, transforms, NULL);

  //Now that it was read and transformed, its size will differ
  PNG_LENGTH = 0; 

  //Lets collect our metadata
  struct ihdr_infos_s ihdr_infos;
  ihdr_infos.bit_depth        = png_get_bit_depth(pm->read_ptr, pm->info_ptr);
  ihdr_infos.color_type       = png_get_color_type(pm->read_ptr, pm->info_ptr);
  ihdr_infos.filter_method    = png_get_filter_type(pm->read_ptr, pm->info_ptr);
  ihdr_infos.compression_type = png_get_compression_type(pm->read_ptr, pm->info_ptr);
  ihdr_infos.interlace_type   = png_get_interlace_type(pm->read_ptr, pm->info_ptr);
  ihdr_infos.height           = png_get_image_height(pm->read_ptr, pm->info_ptr);
  ihdr_infos.width            = png_get_image_width(pm->read_ptr, pm->info_ptr);

  if (ihdr_infos.color_type != 2) {
    DEBUG_PRINT((E_INVALID));
    free(ENTIRE_PNG_BUF);
    my_deinit_libpng(pm);
    DEBUG_PRINT(("Looks like libpng could not correctly convert to RGB\n"));
    return -1;
  }

  //Just in case we want to enable alpha, etc
  switch(ihdr_infos.color_type) {
    case 0:  //greyscale
    case 3:  //indexed
      ihdr_infos.bytes_per_pixel = 1;
      break;
    case 4: ihdr_infos.bytes_per_pixel = 2; break; //greyscale w/ alpha 
    case 2: ihdr_infos.bytes_per_pixel = 3; break; //Truecolour (RGB)
    case 6: ihdr_infos.bytes_per_pixel = 4; break; //Truecolour w/ alpha
    default: error_fatal(1, "ihdr_infos", "Unknown image type"); //should never happen
  }

  ihdr_infos.scanline_len = (ihdr_infos.bytes_per_pixel * ihdr_infos.width) + 1;

  DEBUG_PRINT(("HEIGHT: %u\n", ihdr_infos.height));
  DEBUG_PRINT(("WIDTH: %u\n", ihdr_infos.width));
  DEBUG_PRINT(("BIT_DEPTH: %u\n", ihdr_infos.bit_depth));

  // Don't compress, since we are merely copying it to memory,
  // we will be decompressing it again anyway
  png_set_compression_level(pm->write_ptr, Z_NO_COMPRESSION);

  void *write_io_ptr = png_get_io_ptr(pm->write_ptr);
  png_set_write_fn(pm->write_ptr, write_io_ptr, my_png_write_fn, my_png_dummy_flush);

  //Make sure we use all filters
  png_set_filter(pm->write_ptr, 0,
      PNG_FILTER_NONE  | PNG_FILTER_VALUE_NONE |
      PNG_FILTER_SUB   | PNG_FILTER_VALUE_SUB  |
      PNG_FILTER_UP    | PNG_FILTER_VALUE_UP   |
      PNG_FILTER_AVG   | PNG_FILTER_VALUE_AVG  |
      PNG_FILTER_PAETH | PNG_FILTER_VALUE_PAETH);

  //Set our comment
  struct png_text_struct comment_struct;

  comment_struct.compression = -1;
  comment_struct.key = " Glitched by pnglitch.xyz ";
  comment_struct.text = NULL;
  comment_struct.text_length = 0;
  
  png_set_text(pm->write_ptr, pm->info_ptr, &comment_struct, 1);

  //Buffer is Written using callback my_png_write_fn to buffer
  //ENTIRE_PNG_BUF. PNG_LENGTH will be updated automatically by it
  png_write_png(pm->write_ptr, pm->info_ptr, PNG_TRANSFORM_IDENTITY, NULL);

  my_deinit_libpng(pm);

  DEBUG_PRINT(("libpng output buf is %lld bytes\n", PNG_LENGTH));

  //Now that libpng has converted the image
  //and we have it in a buffer, we process it by hand with zlib
  struct z_stream_s inflate_stream;
  my_init_zlib(&inflate_stream);
  inflateInit(&inflate_stream);

  //Pointer to keep track of where we are
  unsigned char *pngp = ENTIRE_PNG_BUF;

  //Skip PNG Signature
  pngp += 8; 

  //Get Header
  unsigned char ihdr_bytes_buf[4+4+13+4]; // size + label + content + crc
  buf_read(ihdr_bytes_buf, &pngp, 4+4+13+4);

  //When we run into non-idat chunks, we will want to preserve them.
  //The spec says there's no chunk that needs to go after IDAT,
  //so we can simply concatenate all of these chunks into a buffer
  //then write them all at once after the IHDR
  
  //ancillary chunks, eg comments
  unsigned char *ancil_chunks_buf = calloc(1,1);
  long long ancil_chunks_len = 0;

  unsigned char *unzip_idats_buf = calloc(1, 1);
  long unzip_buf_len = 1;
  long unzip_buf_offset = 0;

  long long zipped_idats_len = 0; //Length of all idats as we read them

  unsigned long accum_png_len = 8 + (4+4+13+4);

  int chunk_count = 0;

  printf("Uncompressing image data...\n");
  while (1) {
    unsigned char chunk_label[4];
    unsigned char chunk_len_buf[4];

    buf_read(chunk_len_buf, &pngp, 4);

    //first 4 bytes are the length of data section
    long chunk_len = four_bytes_to_int(chunk_len_buf);

    accum_png_len += chunk_len + 4 + 4 + 4; // plus len, crc, label
    DEBUG_PRINT(("at %lu --> %lld\n", accum_png_len, PNG_LENGTH));

    //leave at end of buffer
    if (accum_png_len >= PNG_LENGTH)
      break;

    //read the chunk label (name of this header)
    buf_read(chunk_label, &pngp, 4);

    DEBUG_PRINT(("Reading chunk %d with label '%c%c%c%c', size %ld\n",
          chunk_count, chunk_label[0], chunk_label[1], chunk_label[2],
          chunk_label[3], chunk_len));

    chunk_count += 1;

    if (memcmp(chunk_label, "IDAT", 4) == 0) {

      zipped_idats_len += chunk_len;

      //read the chunk's data section
      unsigned char *raw_chunk_buf = calloc(chunk_len, 1);
      buf_read(raw_chunk_buf, &pngp, chunk_len);

      //Tell inflate to uncompress it
      inflate_stream.next_in = raw_chunk_buf; 
      inflate_stream.avail_in = chunk_len; 

      //Now uncompress it (resizes buffer automatically)
      unsigned char *check_uncompress = uncompress_buffer(&inflate_stream, 
          unzip_idats_buf, &unzip_buf_len, &unzip_buf_offset);

      //Stop if error
      if (check_uncompress == NULL) {
        DEBUG_PRINT((E_GLITCH));
        free(ancil_chunks_buf);
        free(raw_chunk_buf);
        free(unzip_idats_buf);
        free(ENTIRE_PNG_BUF);
        return -1;
      }

      //Moving on
      unzip_idats_buf = check_uncompress;
      free(raw_chunk_buf);
      pngp += 4; // skip CRC

    } else { //This is not an idat

      ancil_chunks_buf = realloc(ancil_chunks_buf, 
          ancil_chunks_len + 4 + 4 + chunk_len + 4); //make room for new data

      //append length and label bytes
      append_bytes(ancil_chunks_buf, chunk_len_buf, &ancil_chunks_len, 4);
      append_bytes(ancil_chunks_buf, chunk_label, &ancil_chunks_len, 4);

      //append chunk data
      unsigned char *raw_chunk_buf = calloc(chunk_len, 1);
      buf_read(raw_chunk_buf, &pngp, chunk_len);
      append_bytes(ancil_chunks_buf, raw_chunk_buf, &ancil_chunks_len, chunk_len );

      //append chunk crc
      unsigned char chunk_crc_buf[4];
      buf_read(chunk_crc_buf, &pngp, 4);
      append_bytes(ancil_chunks_buf, chunk_crc_buf, &ancil_chunks_len, 4);

      free(raw_chunk_buf);

      DEBUG_PRINT(("ancillary chunks length: %lld\n", ancil_chunks_len));

    }
  }

  //buf contains all idats uncompressed, concatenated
  unsigned long unzipped_idats_len = inflate_stream.total_out; 
  unzip_idats_buf = realloc(unzip_idats_buf, unzipped_idats_len);

  //we already have ancillary chunks and idats, don't need the original
  free(ENTIRE_PNG_BUF);
  inflateEnd(&inflate_stream);

  printf("Uncompressed %lld bytes to %ld bytes\n", zipped_idats_len, unzipped_idats_len);

  printf("Glitching image data...\n");

  for (int g=0;g<NUM_OUTPUT_FILES;g++) {

    //do glitches
    switch(g) {
      case 5:
        glitch_random(unzip_idats_buf, unzipped_idats_len,
            ihdr_infos.scanline_len, 0.0005);
        break;
      case 6:
        glitch_random_filter(unzip_idats_buf, unzipped_idats_len,
            ihdr_infos.scanline_len);
        break;
      default:
        glitch_filter(unzip_idats_buf, unzipped_idats_len,
            ihdr_infos.scanline_len, g);
    }

    //recompress so we can write them to file
    long long glitched_idats_len = 0;
    unsigned char *glitched_idats = zip_idats(unzip_idats_buf,
        unzipped_idats_len, &glitched_idats_len);

    if (glitched_idats == NULL) {
      DEBUG_PRINT((E_GLITCH));
      free (unzip_idats_buf);
      free (ancil_chunks_buf);
      return -1;
    }

    char path[MAX_PATH_LENGTH];
    bzero(path, MAX_PATH_LENGTH);

    snprintf(path, MAX_PATH_LENGTH, "%s%s%s-%d.png", OUTPUT_DIRECTORY, DIR_SEP,
        base_file_name, g);

    DEBUG_PRINT(("Output file name is %s\n", path));

    FILE *outfp = fopen(path, "wb");

    write_glitched_image(glitched_idats, glitched_idats_len, ihdr_bytes_buf,
        ancil_chunks_buf, ancil_chunks_len, outfp);

    printf("%s\n", path);
    fflush(stdout);

    fclose(outfp);
    free(glitched_idats);
  }

  free(ancil_chunks_buf);
  free(unzip_idats_buf);
  return 0;
}
Esempio n. 30
0
void png_reader<T>::read(unsigned x0, unsigned y0,image_data_32& image)
{
    stream_.clear();
    stream_.seekg(0, std::ios_base::beg);

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

    if (!png_ptr)
    {
        throw image_reader_exception("failed to allocate png_ptr");
    }

    // catch errors in a custom way to avoid the need for setjmp
    png_set_error_fn(png_ptr, png_get_error_ptr(png_ptr), user_error_fn, user_warning_fn);

    png_infop info_ptr;
    png_struct_guard sguard(&png_ptr,&info_ptr);
    info_ptr = png_create_info_struct(png_ptr);
    if (!info_ptr) throw image_reader_exception("failed to create info_ptr");

    png_set_read_fn(png_ptr, (png_voidp)&stream_, png_read_data);
    png_read_info(png_ptr, info_ptr);

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

    // quick hack -- only work in >=libpng 1.2.7
    png_set_add_alpha(png_ptr,0xff,PNG_FILLER_AFTER); //rgba

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

    if (x0 == 0 && y0 == 0 && image.width() >= width_ && image.height() >= height_)
    {

        if (png_get_interlace_type(png_ptr,info_ptr) == PNG_INTERLACE_ADAM7)
        {
            png_set_interlace_handling(png_ptr); // FIXME: libpng bug?
            // according to docs png_read_image
            // "..automatically handles interlacing,
            // so you don't need to call png_set_interlace_handling()"
        }
        png_read_update_info(png_ptr, info_ptr);
        // we can read whole image at once
        // alloc row pointers
        const std::unique_ptr<png_bytep[]> rows(new png_bytep[height_]);
        for (unsigned i=0; i<height_; ++i)
            rows[i] = (png_bytep)image.getRow(i);
        png_read_image(png_ptr, rows.get());
    }
    else
    {
        png_read_update_info(png_ptr, info_ptr);
        unsigned w=std::min(unsigned(image.width()),width_ - x0);
        unsigned h=std::min(unsigned(image.height()),height_ - y0);
        unsigned rowbytes=png_get_rowbytes(png_ptr, info_ptr);
        const std::unique_ptr<png_byte[]> row(new png_byte[rowbytes]);
        //START read image rows
        for (unsigned i = 0;i < height_; ++i)
        {
            png_read_row(png_ptr,row.get(),0);
            if (i >= y0 && i < (y0 + h))
            {
                image.setRow(i-y0,reinterpret_cast<unsigned*>(&row[x0 * 4]),w);
            }
        }
        //END
    }
    png_read_end(png_ptr,0);
}