Exemple #1
0
RImage *RLoadPNG(RContext *context, const char *file)
{
	char *tmp;
	RImage *image = NULL;
	FILE *f;
	png_structp png;
	png_infop pinfo, einfo;
	png_color_16p bkcolor;
	int alpha;
	int x, y, i;
	double gamma, sgamma;
	png_uint_32 width, height;
	int depth, junk, color_type;
	png_bytep *png_rows;
	unsigned char *ptr;

	f = fopen(file, "rb");
	if (!f) {
		RErrorCode = RERR_OPEN;
		return NULL;
	}
	png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, (png_error_ptr) NULL, (png_error_ptr) NULL);
	if (!png) {
		RErrorCode = RERR_NOMEMORY;
		fclose(f);
		return NULL;
	}

	pinfo = png_create_info_struct(png);
	if (!pinfo) {
		RErrorCode = RERR_NOMEMORY;
		fclose(f);
		png_destroy_read_struct(&png, NULL, NULL);
		return NULL;
	}

	einfo = png_create_info_struct(png);
	if (!einfo) {
		RErrorCode = RERR_NOMEMORY;
		fclose(f);
		png_destroy_read_struct(&png, &pinfo, NULL);
		return NULL;
	}

	RErrorCode = RERR_INTERNAL;
#if PNG_LIBPNG_VER - 0 < 10400
	if (setjmp(png->jmpbuf)) {
#else
	if (setjmp(png_jmpbuf(png))) {
#endif
		fclose(f);
		png_destroy_read_struct(&png, &pinfo, &einfo);
		if (image)
			RReleaseImage(image);
		return NULL;
	}

	png_init_io(png, f);

	png_read_info(png, pinfo);

	png_get_IHDR(png, pinfo, &width, &height, &depth, &color_type, &junk, &junk, &junk);

	/* sanity check */
	if (width < 1 || height < 1) {
		fclose(f);
		png_destroy_read_struct(&png, &pinfo, &einfo);
		RErrorCode = RERR_BADIMAGEFILE;
		return NULL;
	}

	/* check for an alpha channel */
	if (png_get_valid(png, pinfo, PNG_INFO_tRNS))
		alpha = True;
	else
		alpha = (color_type & PNG_COLOR_MASK_ALPHA);

	/* allocate RImage */
	image = RCreateImage(width, height, alpha);
	if (!image) {
		fclose(f);
		png_destroy_read_struct(&png, &pinfo, &einfo);
		return NULL;
	}

	/* normalize to 8bpp with alpha channel */
	if (color_type == PNG_COLOR_TYPE_PALETTE && depth <= 8)
		png_set_expand(png);

	if (color_type == PNG_COLOR_TYPE_GRAY && depth <= 8)
		png_set_expand(png);

	if (png_get_valid(png, pinfo, PNG_INFO_tRNS))
		png_set_expand(png);

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

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

	/* set gamma correction */
	if ((context->attribs->flags & RC_GammaCorrection)
	    && context->depth != 8) {
		sgamma = (context->attribs->rgamma + context->attribs->ggamma + context->attribs->bgamma) / 3;
	} else if ((tmp = getenv("DISPLAY_GAMMA")) != NULL) {
		sgamma = atof(tmp);
		if (sgamma < 1.0E-3)
			sgamma = 1;
	} else {
		/* blah */
		sgamma = 2.2;
	}

	if (png_get_gAMA(png, pinfo, &gamma))
		png_set_gamma(png, sgamma, gamma);
	else
		png_set_gamma(png, sgamma, 0.45);

	/* do the transforms */
	png_read_update_info(png, pinfo);

	/* set background color */
	if (png_get_bKGD(png, pinfo, &bkcolor)) {
		image->background.red = bkcolor->red >> 8;
		image->background.green = bkcolor->green >> 8;
		image->background.blue = bkcolor->blue >> 8;
	}

	png_rows = calloc(height, sizeof(char *));
	if (!png_rows) {
		RErrorCode = RERR_NOMEMORY;
		fclose(f);
		RReleaseImage(image);
		png_destroy_read_struct(&png, &pinfo, &einfo);
		return NULL;
	}
	for (y = 0; y < height; y++) {
		png_rows[y] = malloc(png_get_rowbytes(png, pinfo));
		if (!png_rows[y]) {
			RErrorCode = RERR_NOMEMORY;
			fclose(f);
			RReleaseImage(image);
			png_destroy_read_struct(&png, &pinfo, &einfo);
			while (y-- > 0)
				if (png_rows[y])
					free(png_rows[y]);
			free(png_rows);
			return NULL;
		}
	}
	/* read data */
	png_read_image(png, png_rows);

	png_read_end(png, einfo);

	png_destroy_read_struct(&png, &pinfo, &einfo);

	fclose(f);

	ptr = image->data;

	/* convert to RImage */
	if (alpha) {
		for (y = 0; y < height; y++) {
			for (x = 0, i = width * 4; x < i; x++, ptr++) {
				*ptr = *(png_rows[y] + x);
			}
		}
	} else {
		for (y = 0; y < height; y++) {
			for (x = 0, i = width * 3; x < i; x++, ptr++) {
				*ptr = *(png_rows[y] + x);
			}
		}
	}
	for (y = 0; y < height; y++)
		if (png_rows[y])
			free(png_rows[y]);
	free(png_rows);
	return image;
}
void PNGImageDecoder::headerAvailable()
{
    png_structp png = m_reader->pngPtr();
    png_infop info = m_reader->infoPtr();
    png_uint_32 width = png->width;
    png_uint_32 height = png->height;
    
    // Protect against large images.
    if (png->width > cMaxPNGSize || png->height > cMaxPNGSize) {
        longjmp(JMPBUF(png), 1);
        return;
    }
    
    // We can fill in the size now that the header is available.  Avoid memory
    // corruption issues by neutering setFailed() during this call; if we don't
    // do this, failures will cause |m_reader| to be deleted, and our jmpbuf
    // will cease to exist.  Note that we'll still properly set the failure flag
    // in this case as soon as we longjmp().
    m_doNothingOnFailure = true;
    bool result = setSize(width, height);
    m_doNothingOnFailure = false;
    if (!result) {
        longjmp(JMPBUF(png), 1);
        return;
    }

    int bitDepth, colorType, interlaceType, compressionType, filterType, channels;
    png_get_IHDR(png, info, &width, &height, &bitDepth, &colorType, &interlaceType, &compressionType, &filterType);

    if ((colorType == PNG_COLOR_TYPE_RGB || colorType == PNG_COLOR_TYPE_RGB_ALPHA) && !m_ignoreGammaAndColorProfile) {
        // We currently support color profiles only for RGB and RGBA PNGs.  Supporting
        // color profiles for gray-scale images is slightly tricky, at least using the
        // CoreGraphics ICC library, because we expand gray-scale images to RGB but we
        // don't similarly transform the color profile.  We'd either need to transform
        // the color profile or we'd need to decode into a gray-scale image buffer and
        // hand that to CoreGraphics.
        m_colorProfile = readColorProfile(png, info);
    }

    // The options we set here match what Mozilla does.

    // Expand to ensure we use 24-bit for RGB and 32-bit for RGBA.
    if (colorType == PNG_COLOR_TYPE_PALETTE || (colorType == PNG_COLOR_TYPE_GRAY && bitDepth < 8))
        png_set_expand(png);
    
    png_bytep trns = 0;
    int trnsCount = 0;
    if (png_get_valid(png, info, PNG_INFO_tRNS)) {
        png_get_tRNS(png, info, &trns, &trnsCount, 0);
        png_set_expand(png);
    }

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

    if (colorType == PNG_COLOR_TYPE_GRAY || colorType == PNG_COLOR_TYPE_GRAY_ALPHA)
        png_set_gray_to_rgb(png);

    // Deal with gamma and keep it under our control.
    double gamma;
    if (!m_ignoreGammaAndColorProfile && png_get_gAMA(png, info, &gamma)) {
        if ((gamma <= 0.0) || (gamma > cMaxGamma)) {
            gamma = cInverseGamma;
            png_set_gAMA(png, info, gamma);
        }
        png_set_gamma(png, cDefaultGamma, gamma);
    } else
        png_set_gamma(png, cDefaultGamma, cInverseGamma);

    // Tell libpng to send us rows for interlaced pngs.
    if (interlaceType == PNG_INTERLACE_ADAM7)
        png_set_interlace_handling(png);

    // Update our info now.
    png_read_update_info(png, info);
    channels = png_get_channels(png, info);
    ASSERT(channels == 3 || channels == 4);

    m_reader->setHasAlpha(channels == 4);

    if (m_reader->decodingSizeOnly()) {
        // If we only needed the size, halt the reader.     
        m_reader->setReadOffset(m_reader->currentBufferSize() - png->buffer_size);
        png->buffer_size = 0;
    }
}
Exemple #3
0
void png_info_callback(png_structp png_ptr, png_infop info_ptr)
{
	int bit_depth, color_type, intent;
	double gamma;
	int bytes_per_pixel=3;
	struct cached_image *cimg;

	cimg=global_cimg;

	bit_depth=png_get_bit_depth(png_ptr, info_ptr);
	color_type=png_get_color_type(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); /* Legacy version of
		png_set_tRNS_to_alpha(png_ptr); */
		bytes_per_pixel++;
	}
	if (color_type == PNG_COLOR_TYPE_GRAY ||
		color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
		png_set_gray_to_rgb(png_ptr);
	if (bit_depth==16){
#ifndef REPACK_16
#ifdef C_LITTLE_ENDIAN
		/* We use native endianity only if unsigned short is 2-byte
		 * because otherwise we have to reassemble the buffer so we
		 * will leave in the libpng-native big endian.
		 */
		png_set_swap(png_ptr);
#endif /* #ifdef C_LITTLE_ENDIAN */
#endif /* #ifndef REPACK_16 */
		bytes_per_pixel*=sizeof(unsigned short);
	}
	png_set_interlace_handling(png_ptr);
	if (color_type==PNG_COLOR_TYPE_RGB_ALPHA
		||color_type==PNG_COLOR_TYPE_GRAY_ALPHA){
		if (bytes_per_pixel==3
			||bytes_per_pixel==3*sizeof(unsigned short))
			bytes_per_pixel=4*bytes_per_pixel/3;
	}
	cimg->width=png_get_image_width(png_ptr,info_ptr);
	cimg->height=png_get_image_height(png_ptr,info_ptr);
	cimg->buffer_bytes_per_pixel=bytes_per_pixel;
	if (png_get_sRGB(png_ptr, info_ptr, &intent)){
		gamma=sRGB_gamma;
	}
	else
 	{              
  		if (!png_get_gAMA(png_ptr, info_ptr, &gamma)){
			gamma=sRGB_gamma;
		}
	}
	cimg->red_gamma=gamma;
	cimg->green_gamma=gamma;
	cimg->blue_gamma=gamma;
	png_read_update_info(png_ptr,info_ptr);                 
	cimg->strip_optimized=0;
	header_dimensions_known(cimg);
}
Exemple #4
0
int int_png_load(const char *name, unsigned char **buffer, int* xp, int* yp, int* bpp, bool alpha)
{
	static const png_color_16 my_background = {0, 0, 0, 0, 0};
	png_structp png_ptr;
	png_infop info_ptr;
	png_uint_32 width, height;
	unsigned int i;
	int bit_depth, color_type, interlace_type, number_passes, pass, int_bpp;
	png_byte * fbptr;
	FILE     * fh;

	if(!(fh=fopen(name,"rb")))
		return(FH_ERROR_FILE);
	png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
	if(png_ptr == NULL) {
		fclose(fh);
		return(FH_ERROR_FORMAT);
	}
	info_ptr = png_create_info_struct(png_ptr);
	if(info_ptr == NULL)
	{
		png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL);
		fclose(fh);
		return(FH_ERROR_FORMAT);
	}
#if (PNG_LIBPNG_VER < 10500)
	if (setjmp(png_ptr->jmpbuf))
#else
	if (setjmp(png_jmpbuf(png_ptr)))
#endif
	{
		png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
		fclose(fh);
		return(FH_ERROR_FORMAT);
	}
	png_init_io(png_ptr,fh);
	png_read_info(png_ptr, info_ptr);
	png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, NULL, NULL);
	if (alpha)
	{
		*bpp = png_get_channels(png_ptr, info_ptr);
		if ((*bpp != 4) || !(color_type & PNG_COLOR_MASK_ALPHA))
		{
			png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
			fclose(fh);
			return fh_png_load(name, buffer, xp, yp);
		}
		// 24bit PNGs with alpha-channel
		int_bpp = 4;
//		png_set_swap_alpha(png_ptr);
		if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
			png_set_tRNS_to_alpha(png_ptr);
	}else // All other PNGs
	{
		if (color_type == PNG_COLOR_TYPE_PALETTE)
		{
			png_set_palette_to_rgb(png_ptr);
			png_set_background(png_ptr, (png_color_16*)&my_background, PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0);
			/* other possibility for png_set_background: use png_get_bKGD */
		}
		if (color_type == PNG_COLOR_TYPE_GRAY        ||
		    color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
		{
			png_set_gray_to_rgb(png_ptr);
			png_set_background(png_ptr, (png_color_16*)&my_background, PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0);
		}
		/* this test does not trigger for 8bit-paletted PNGs with newer libpng (1.2.36 at least),
	   	   but the data delivered is with alpha channel anyway, so always strip alpha for now
		 */
#if PNG_LIBPNG_VER_MAJOR == 1 && PNG_LIBPNG_VER_MINOR <= 2 && PNG_LIBPNG_VER_RELEASE < 36
		if (color_type & PNG_COLOR_MASK_ALPHA)
#endif
			png_set_strip_alpha(png_ptr);
		if (bit_depth < 8)
			png_set_packing(png_ptr);
		int_bpp = 3;
	}
	if (bit_depth == 16)
		png_set_strip_16(png_ptr);
	number_passes = png_set_interlace_handling(png_ptr);
	png_read_update_info(png_ptr,info_ptr);
	unsigned long rowbytes = png_get_rowbytes(png_ptr, info_ptr);
	if (width * int_bpp != rowbytes)
	{
		printf("[png.cpp]: Error processing %s - please report (including image).\n", name);
		printf("           width: %lu rowbytes: %lu\n", (unsigned long)width, (unsigned long)rowbytes);
		fclose(fh);
		return(FH_ERROR_FORMAT);
	}
	for (pass = 0; pass < number_passes; pass++)
	{
		fbptr = (png_byte *)(*buffer);
		for (i = 0; i < height; i++, fbptr += width * int_bpp)
			png_read_row(png_ptr, fbptr, NULL);
	}
	png_read_end(png_ptr, info_ptr);
	png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
	fclose(fh);
	return(FH_ERROR_OK);
}
Bool
readPng (const char   *filename,
	 char	      **data,
	 unsigned int *width,
	 unsigned int *height)
{
    static const int PNG_SIG_SIZE = 8;
    unsigned char    png_sig[PNG_SIG_SIZE];
    FILE	     *file;
    int		     sig_bytes;
    png_struct	     *png;
    png_info	     *info;
    png_uint_32	     png_width, png_height;
    int	     depth, color_type, interlace, i;
    unsigned int     pixel_size;
    png_byte	     **row_pointers;

    file = fopen (filename, "r");
    if (!file)
    {
	char *home, *imagedir;

	home = getenv ("HOME");
	if (home)
	{
	    imagedir = malloc (strlen (home) +
			       strlen (HOME_IMAGEDIR) +
			       strlen (filename) + 3);
	    if (imagedir)
	    {
		sprintf (imagedir, "%s/%s/%s", home, HOME_IMAGEDIR, filename);
		file = fopen (imagedir, "r");
		free (imagedir);
	    }
	}

	if (!file)
	{
	    imagedir = malloc (strlen (IMAGEDIR) + strlen (filename) + 2);
	    if (imagedir)
	    {
		sprintf (imagedir, "%s/%s", IMAGEDIR, filename);
		file = fopen (imagedir, "r");
		free (imagedir);
	    }

	    if (!file)
		return FALSE;
	}
    }

    sig_bytes = fread (png_sig, 1, PNG_SIG_SIZE, file);
    if (png_check_sig (png_sig, sig_bytes) == 0)
    {
	fclose (file);
	return FALSE;
    }

    png = png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
    if (!png)
    {
	fclose (file);
	return FALSE;
    }

    info = png_create_info_struct (png);
    if (info == NULL)
    {
	fclose (file);
	png_destroy_read_struct (&png, NULL, NULL);
	return FALSE;
    }

    png_init_io (png, file);
    png_set_sig_bytes (png, sig_bytes);

    png_read_info (png, info);

    png_get_IHDR (png, info,
		  &png_width, &png_height, &depth,
		  &color_type, &interlace, NULL, NULL);
    *width = png_width;
    *height = png_height;

    /* convert palette/gray image to rgb */
    if (color_type == PNG_COLOR_TYPE_PALETTE)
	png_set_palette_to_rgb (png);

    /* expand gray bit depth if needed */
    if (color_type == PNG_COLOR_TYPE_GRAY && depth < 8)
	png_set_gray_1_2_4_to_8 (png);

    /* transform transparency to alpha */
    if (png_get_valid(png, info, PNG_INFO_tRNS))
	png_set_tRNS_to_alpha (png);

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

    if (depth < 8)
	png_set_packing (png);

    /* convert grayscale to RGB */
    if (color_type == PNG_COLOR_TYPE_GRAY ||
	color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
	png_set_gray_to_rgb (png);

    if (interlace != PNG_INTERLACE_NONE)
	png_set_interlace_handling (png);

    png_set_bgr (png);
    png_set_filler (png, 0xff, PNG_FILLER_AFTER);

    png_set_read_user_transform_fn (png, premultiplyData);

    png_read_update_info (png, info);

    pixel_size = 4;
    *data = (char *) malloc (png_width * png_height * pixel_size);
    if (*data == NULL)
    {
	fclose (file);
	return FALSE;
    }

    row_pointers = (png_byte **) malloc (png_height * sizeof (char *));
    for (i=0; i < png_height; i++)
	row_pointers[i] = (png_byte *) (*data + i * png_width * pixel_size);

    png_read_image (png, row_pointers);
    png_read_end (png, info);

    free (row_pointers);
    fclose (file);

    png_destroy_read_struct (&png, &info, NULL);

    return TRUE;
}
bool SkPNGImageDecoder::onDecodeInit(SkStream* sk_stream,
        png_structp *png_ptrp, png_infop *info_ptrp)
{
    /* Create and initialize the png_struct with the desired error handler
    * functions.  If you want to use the default stderr and longjump method,
    * you can supply NULL for the last three parameters.  We also supply the
    * the compiler header file version, so that we know if the application
    * was compiled with a compatible version of the library.  */
    png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,
        NULL, sk_error_fn, NULL);
    //   png_voidp user_error_ptr, user_error_fn, user_warning_fn);
    if (png_ptr == NULL) {
        return false;
    }
    *png_ptrp = png_ptr;

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

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

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

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

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

    /* tell libpng to strip 16 bit/color files down to 8 bits/color */
    if (bit_depth == 16) {
        png_set_strip_16(png_ptr);
    }
    /* Extract multiple pixels with bit depths of 1, 2, and 4 from a single
     * byte into separate bytes (useful for paletted and grayscale images). */
    if (bit_depth < 8) {
        png_set_packing(png_ptr);
    }
    /* Expand grayscale images to the full 8 bits from 1, 2, or 4 bits/pixel */
    if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) {
        png_set_gray_1_2_4_to_8(png_ptr);
    }

    /* Make a grayscale image into RGB. */
    if (color_type == PNG_COLOR_TYPE_GRAY ||
        color_type == PNG_COLOR_TYPE_GRAY_ALPHA) {
        png_set_gray_to_rgb(png_ptr);
    }
    return true;
}
Exemple #7
0
void Image::LoadPNG(FILE *f, char *filename, Texture *tex) {
	png_structp png;
	png_infop pnginfo;
	byte ioBuffer[8192];
	byte *raw;

	int filesize = SystemFileManager::FileLength(f);
	raw = (byte *) malloc(filesize + 1);
	if (raw == NULL) {
		Sys_Error("Out of memory to load PNG: %s\n", filename);
		return;
	}

	fread(raw, 1, filesize, f);
	fclose(f);

	if (!raw) {
		Con_Printf("Bad png file %s\n", filename);
		return;
	}

	if (png_sig_cmp(raw, 0, 4)) {
		free(raw);
		return;
	}

	png = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
	if (!png) {
		free(raw);
		return;
	}

	pnginfo = png_create_info_struct(png);

	if (!pnginfo) {
		free(raw);
		png_destroy_read_struct(&png, &pnginfo, 0);
		return;
	}
	png_set_sig_bytes(png, 0/*sizeof( sig )*/);

	mypng_struct_create(); // creates the my_png struct

	my_png->tmpBuf = (char *) raw; //buf = whole file content
	my_png->tmpi = 0;

	png_set_read_fn(png, ioBuffer, fReadData);

	png_read_info(png, pnginfo);

	png_get_IHDR(png, pnginfo, &my_png->Width, &my_png->Height, &my_png->BitDepth, &my_png->ColorType, &my_png->Interlace, &my_png->Compression, &my_png->Filter);
	// ...removed bgColor code here...

	if (my_png->ColorType == PNG_COLOR_TYPE_PALETTE)
		png_set_palette_to_rgb(png);

	if (my_png->ColorType == PNG_COLOR_TYPE_GRAY && my_png->BitDepth < 8)
		png_set_expand_gray_1_2_4_to_8(png);

	// Add alpha channel if present
	if (png_get_valid(png, pnginfo, PNG_INFO_tRNS))
		png_set_tRNS_to_alpha(png);

	// hax: expand 24bit to 32bit
	if (my_png->BitDepth == 8 && my_png->ColorType == PNG_COLOR_TYPE_RGB)
		png_set_filler(png, 255, PNG_FILLER_AFTER);

	if ((my_png->ColorType == PNG_COLOR_TYPE_GRAY) || (my_png->ColorType == PNG_COLOR_TYPE_GRAY_ALPHA)) {
		png_set_gray_to_rgb(png);
		png_set_add_alpha(png, 255, PNG_FILLER_AFTER);
	}

	if (my_png->BitDepth < 8)
		png_set_expand(png);

	// update the info structure
	png_read_update_info(png, pnginfo);

	my_png->FRowBytes = png_get_rowbytes(png, pnginfo);
	my_png->BytesPerPixel = png_get_channels(png, pnginfo); // DL Added 30/08/2000

	InitializeDemData();
	if ((my_png->Data) && (my_png->FRowPtrs))
		png_read_image(png, (png_bytepp) my_png->FRowPtrs);

	png_read_end(png, pnginfo); // read last information chunks

	png_destroy_read_struct(&png, &pnginfo, 0);

	if (my_png->BitDepth == 8) {
		tex->width = my_png->Width;
		tex->height = my_png->Height;
		tex->bytesPerPixel = my_png->BytesPerPixel;
		tex->setData((byte *) my_png->Data);
	} else {
		Con_Printf("Bad png color depth: %s\n", filename);
		free(my_png->Data);
	}

	free(raw);
	mypng_struct_destroy(true);

	return;
}
void PNGImageDecoder::headerAvailable()
{
    png_structp png = reader()->pngPtr();
    png_infop info = reader()->infoPtr();
    png_uint_32 width = png->width;
    png_uint_32 height = png->height;
    
    // Protect against large images.
    if (png->width > cMaxPNGSize || png->height > cMaxPNGSize) {
        m_failed = true;
        longjmp(png->jmpbuf, 1);
        return;
    }
    
    // We can fill in the size now that the header is available.
    if (!m_sizeAvailable) {
        m_sizeAvailable = true;
        m_size = IntSize(width, height);
    }

    int bitDepth, colorType, interlaceType, compressionType, filterType, channels;
    png_get_IHDR(png, info, &width, &height, &bitDepth, &colorType,
                 &interlaceType, &compressionType, &filterType);

    // The options we set here match what Mozilla does.

    // Expand to ensure we use 24-bit for RGB and 32-bit for RGBA.
    if (colorType == PNG_COLOR_TYPE_PALETTE ||
        (colorType == PNG_COLOR_TYPE_GRAY && bitDepth < 8))
        png_set_expand(png);
    
    png_bytep trns = 0;
    int trnsCount = 0;
    if (png_get_valid(png, info, PNG_INFO_tRNS)) {
        png_get_tRNS(png, info, &trns, &trnsCount, 0);
        png_set_expand(png);
    }

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

    if (colorType == PNG_COLOR_TYPE_GRAY ||
        colorType == PNG_COLOR_TYPE_GRAY_ALPHA)
        png_set_gray_to_rgb(png);

    // Deal with gamma and keep it under our control.
    double gamma;
    if (png_get_gAMA(png, info, &gamma)) {
        if ((gamma <= 0.0) || (gamma > cMaxGamma)) {
            gamma = cInverseGamma;
            png_set_gAMA(png, info, gamma);
        }
        png_set_gamma(png, cDefaultGamma, gamma);
    }
    else
        png_set_gamma(png, cDefaultGamma, cInverseGamma);

    // Tell libpng to send us rows for interlaced pngs.
    if (interlaceType == PNG_INTERLACE_ADAM7)
        png_set_interlace_handling(png);

    // Update our info now
    png_read_update_info(png, info);
    channels = png_get_channels(png, info);
    assert(channels == 3 || channels == 4);

    reader()->setHasAlpha(channels == 4);

    if (reader()->decodingSizeOnly()) {
        // If we only needed the size, halt the reader.     
        reader()->setReadOffset(m_data->size() - png->buffer_size);
        png->buffer_size = 0;
    }
}
int
SplashDecodePng(Splash * splash, png_rw_ptr read_func, void *io_ptr)
{
    int stride;
    ImageFormat srcFormat;
    png_uint_32 i, rowbytes;
    png_bytepp row_pointers = NULL;
    png_bytep image_data = NULL;
    int success = 0;
    double gamma;

    png_structp png_ptr = NULL;
    png_infop info_ptr = NULL;

    png_uint_32 width, height;
    int bit_depth, color_type;

    ImageRect srcRect, dstRect;

    png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
    if (!png_ptr) {
        goto done;
    }

    info_ptr = png_create_info_struct(png_ptr);
    if (!info_ptr) {
        goto done;
    }

    if (setjmp(png_ptr->jmpbuf)) {
        goto done;
    }

    png_ptr->io_ptr = io_ptr;
    png_ptr->read_data_fn = read_func;

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

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

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

    /* expand palette images to RGB, low-bit-depth grayscale images to 8 bits,
     * transparency chunks to full alpha channel; strip 16-bit-per-sample
     * images to 8 bits per sample; and convert grayscale to RGB[A]
     * this may be sub-optimal but this simplifies implementation */

    png_set_expand(png_ptr);
    png_set_tRNS_to_alpha(png_ptr);
    png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER);
    png_set_strip_16(png_ptr);
    png_set_gray_to_rgb(png_ptr);

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

    png_read_update_info(png_ptr, info_ptr);

    rowbytes = png_get_rowbytes(png_ptr, info_ptr);

    if (!SAFE_TO_ALLOC(rowbytes, height)) {
        goto done;
    }

    if ((image_data = (unsigned char *) malloc(rowbytes * height)) == NULL) {
        goto done;
    }

    if (!SAFE_TO_ALLOC(height, sizeof(png_bytep))) {
        goto done;
    }
    if ((row_pointers = (png_bytepp) malloc(height * sizeof(png_bytep)))
            == NULL) {
        goto done;
    }

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

    png_read_image(png_ptr, row_pointers);

    SplashCleanup(splash);

    splash->width = width;
    splash->height = height;

    if (!SAFE_TO_ALLOC(splash->width, splash->imageFormat.depthBytes)) {
        goto done;
    }
    stride = splash->width * splash->imageFormat.depthBytes;

    if (!SAFE_TO_ALLOC(splash->height, stride)) {
        goto done;
    }
    splash->frameCount = 1;
    splash->frames = (SplashImage *)
        malloc(sizeof(SplashImage) * splash->frameCount);

    if (splash->frames == NULL) {
        goto done;
    }

    splash->loopCount = 1;
    splash->frames[0].bitmapBits = malloc(stride * splash->height);
    if (splash->frames[0].bitmapBits == NULL) {
        free(splash->frames);
        goto done;
    }
    splash->frames[0].delay = 0;

    /* FIXME: sort out the real format */
    initFormat(&srcFormat, 0xFF000000, 0x00FF0000, 0x0000FF00, 0x000000FF);
    srcFormat.byteOrder = BYTE_ORDER_MSBFIRST;

    initRect(&srcRect, 0, 0, width, height, 1, rowbytes,
        image_data, &srcFormat);
    initRect(&dstRect, 0, 0, width, height, 1, stride,
        splash->frames[0].bitmapBits, &splash->imageFormat);
    convertRect(&srcRect, &dstRect, CVT_COPY);

    SplashInitFrameShape(splash, 0);

    png_read_end(png_ptr, NULL);
    success = 1;

  done:
    free(row_pointers);
    free(image_data);
    png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
    return success;
}
Exemple #10
0
int png_load_img(img I) {
    unsigned char **p, **q;
    png_structp png_ptr;
    png_infop info_ptr;
    png_uint_32 width, height;
    int i, j, bit_depth, color_type, interlace_type;
    png_bytepp row_pointers;

    img_alloc(I);

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

    if (png_ptr == NULL) {
        I->err = IE_HDRFORMAT;
        return 0;
    }

    info_ptr = png_create_info_struct(png_ptr);

    if (info_ptr == NULL) {
        png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL);
        I->err = IE_HDRFORMAT;
        return 0;
    }
    
    rewind(I->fp);
    png_init_io(png_ptr, I->fp);

    png_read_info(png_ptr, info_ptr);

    /* Get image specific data */
    png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,
        &interlace_type, NULL, NULL);

    /* Convert greyscale images to 8-bit RGB */
    if (color_type == PNG_COLOR_TYPE_GRAY ||
        color_type == PNG_COLOR_TYPE_GRAY_ALPHA) {
        if (bit_depth < 8) {
            png_set_expand_gray_1_2_4_to_8(png_ptr);
        }
        png_set_gray_to_rgb(png_ptr);
    }

    /* Change paletted images to RGB */
    if (color_type == PNG_COLOR_TYPE_PALETTE)
        png_set_expand(png_ptr);

    if (bit_depth < 8)
        png_set_expand(png_ptr);

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

    /* The gdk img widget appears to expect 8-bit RGB followed by a 
     * filler byte. */
    png_set_filler(png_ptr, 0, PNG_FILLER_AFTER);
    
    /* Update the info structure after the transforms */
    png_read_update_info(png_ptr, info_ptr); 
/*    png_set_rows(png_ptr, info_ptr, row_pointers)*/

    /* Allocate space before reading the image */
    row_pointers = png_malloc(png_ptr, height * sizeof(png_bytep));
    for (i = 0; i < height; i++) {
        row_pointers[i] = png_malloc(png_ptr, png_get_rowbytes(png_ptr, info_ptr));
    }
    
    /* Read in the image and copy it to the gdk img structure */
    png_read_image(png_ptr, row_pointers);
    
    p = (unsigned char **)I->data;
    q = (unsigned char **)row_pointers;

    for (i = 0; i < height; i++) {
        for (j = 0; j < png_get_rowbytes(png_ptr, info_ptr); j++) {
           p[i][j] = q[i][j];
        }
    }

    png_read_end(png_ptr, info_ptr);

    /* Clean up */
    png_free(png_ptr, row_pointers);
    png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);

    return 1;
}
static int _png_get_hdr( wprint_image_info_t   *image_info )
{
unsigned char header[8];  
memset(header, 0,sizeof(header));
int bit_depth, pixel_depth, number_of_passes;

   image_info->decoder_data.png_info.png_ptr = NULL;
   image_info->decoder_data.png_info.info_ptr = NULL;

   fseek(image_info->imgfile, 0, SEEK_SET);
   int header_size = fread(header, 1, sizeof(header), image_info->imgfile);
   image_info->wprint_ifc->debug(DBG_VERBOSE, "_png_get_hdr(): header_size: %d", header_size);

   int pngsig = png_sig_cmp(header, 0, sizeof(header));
   if (pngsig)
   {
      image_info->wprint_ifc->debug(DBG_ERROR, "_png_get_hdr(): ERROR: not a PNG file");
      return(ERROR);
   }
   image_info->wprint_ifc->debug(DBG_VERBOSE, "_png_get_hdr(): png_sig_cmp() returned %d", pngsig);

   image_info->wprint_ifc->debug(DBG_VERBOSE, "_png_get_hdr(): PNG_LIBPNG_VER_STRING: %s", PNG_LIBPNG_VER_STRING);
   /* initialize stuff */
   image_info->decoder_data.png_info.png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, 
                                                NULL, NULL, NULL);
   image_info->wprint_ifc->debug(DBG_VERBOSE, "_png_get_hdr(): png_create_read_struct() returned %d", image_info->decoder_data.png_info.png_ptr);

   if (!(image_info->decoder_data.png_info.png_ptr))
   {
      image_info->wprint_ifc->debug(DBG_ERROR, "_png_get_hdr(): ERROR: png_create_read_struct failed");
      return(ERROR);
   }

   image_info->decoder_data.png_info.info_ptr = png_create_info_struct(image_info->decoder_data.png_info.png_ptr);
   image_info->wprint_ifc->debug(DBG_VERBOSE, "_png_get_hdr(): png_create_info_struct() returned %d", image_info->decoder_data.png_info.info_ptr);
   if (!(image_info->decoder_data.png_info.info_ptr))
   {
      image_info->wprint_ifc->debug(DBG_ERROR, "_png_get_hdr(): ERROR: png_create_info_struct failed");
      return(ERROR);
   }

   if (setjmp(png_jmpbuf(image_info->decoder_data.png_info.png_ptr)))
   {
      image_info->wprint_ifc->debug(DBG_ERROR, "_png_get_hdr(): ERROR: invalid or corrupt PNG");
      return(ERROR);
   }

   png_init_io(image_info->decoder_data.png_info.png_ptr, image_info->imgfile);
   png_set_sig_bytes(image_info->decoder_data.png_info.png_ptr, sizeof(header));

   png_read_info(image_info->decoder_data.png_info.png_ptr, image_info->decoder_data.png_info.info_ptr);
   number_of_passes = png_set_interlace_handling(image_info->decoder_data.png_info.png_ptr);
   image_info->wprint_ifc->debug(DBG_VERBOSE, "_png_get_hdr(): png_set_interlace_handling() returned %d", number_of_passes);

   // setup background color as white
   png_color_16 bg_color;
   bg_color.index = 0;
   bg_color.red   = (png_uint_16)-1;
   bg_color.green = (png_uint_16)-1;
   bg_color.blue  = (png_uint_16)-1;
   bg_color.gray  = (png_uint_16)-1;
   // blend alpha using white background color instead of stripping alpha channel
   png_set_background(image_info->decoder_data.png_info.png_ptr, &bg_color, PNG_BACKGROUND_GAMMA_FILE, 0, 1.0);
//   png_set_strip_alpha(image_info->decoder_data.png_info.png_ptr);
   png_set_expand(image_info->decoder_data.png_info.png_ptr);
   png_set_strip_16(image_info->decoder_data.png_info.png_ptr);
   png_set_gray_to_rgb(image_info->decoder_data.png_info.png_ptr);
   png_read_update_info(image_info->decoder_data.png_info.png_ptr, image_info->decoder_data.png_info.info_ptr);

   image_info->width = png_get_image_width(image_info->decoder_data.png_info.png_ptr, 
                                           image_info->decoder_data.png_info.info_ptr);
   image_info->wprint_ifc->debug(DBG_VERBOSE, "_png_get_hdr(): png_get_image_width() returned %d", image_info->width);
   image_info->height = png_get_image_height(image_info->decoder_data.png_info.png_ptr, 
                                             image_info->decoder_data.png_info.info_ptr);
   image_info->wprint_ifc->debug(DBG_VERBOSE, "_png_get_hdr(): png_get_image_height() returned %d", image_info->height);

   bit_depth = png_get_bit_depth(image_info->decoder_data.png_info.png_ptr, 
                                 image_info->decoder_data.png_info.info_ptr);
   image_info->wprint_ifc->debug(DBG_VERBOSE, "_png_get_hdr(): png_get_bit_depth() returned %d", bit_depth);
   pixel_depth = image_info->decoder_data.png_info.info_ptr->pixel_depth;

   if ( (bit_depth == BITS_PER_CHANNEL) && (pixel_depth == BITS_PER_PIXEL) )
   {
      image_info->num_components = pixel_depth/bit_depth;
      image_info->wprint_ifc->debug(DBG_LOG, "_png_get_hdr(): PNG %d x %d (%d components)",
             image_info->width, image_info->height, 
             image_info->num_components);
      return(OK);
   }
   else
   {
      image_info->wprint_ifc->debug(DBG_ERROR, "_png_get_hdr(): ERROR: PNG format not supported. pix = %d, bit = %d",
              pixel_depth, bit_depth);
      return(ERROR);
   }
}  /*  static wprint_png_get_hdr  */
Exemple #12
0
bool Image::load (const std::string &s)
{	
	//
	// The following is based on the libpng manual. http://www.libpng.org/pub/png/libpng-1.2.5-manual.html#section-3.1
	//

	//
	// Check the file header
	//

	// Open the file
	std::ifstream infile;
	infile.open(s.c_str(), std::ifstream::in | std::ifstream::binary);

	// Read the header
	const unsigned int NUM_HEADER_BYTES_TO_READ = 8;
	char header[NUM_HEADER_BYTES_TO_READ];
	
	infile.read(header, NUM_HEADER_BYTES_TO_READ);
    if (png_sig_cmp((png_bytep) header, 0, NUM_HEADER_BYTES_TO_READ)) {
        return false;
	}
	
	//
	// Read the image data
	//
	
	png_bytep *row_pointers = NULL;

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

	png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
    if (!png_ptr) {
        return false;
	}
	
	// Allocate/initialize the memory for image information
    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 false;
    }

	// Set error handling if you are using the setjmp/longjmp method (this is
	// the normal method of doing things with libpng).  REQUIRED unless you
	// set up your own error handlers in the png_create_read_struct() earlier.
	if (setjmp(png_jmpbuf(png_ptr))) {
		png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
		delete row_pointers;	// Gets allocated after here, but don't forget the jump!
        return false;
	}

	// Set custom read routine
	png_set_read_fn(png_ptr, &infile, &png_read_data);
   
	// If we have already read some of the signature
	png_set_sig_bytes(png_ptr, NUM_HEADER_BYTES_TO_READ);
   
	//
	// Read the entire image
	//
	
	// Read PNG header info
	png_read_info(png_ptr, info_ptr);

	int bit_depth, color_type, interlace_type;
	
	// Header info
	png_uint_32 width,height;
	png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, NULL, NULL);
	
	// Strip 16 bit down to 8 bit
	png_set_strip_16(png_ptr);
		
	// Extract components to even bytes
	png_set_packing(png_ptr);

	// Expand grayscale images to 8 bit
	png_set_expand(png_ptr);
	
	// Add a filler byte when missing
	png_set_filler(png_ptr,0xFFFFFFFF,PNG_FILLER_AFTER);

	// Expand grayscale images to rgb
	png_set_gray_to_rgb(png_ptr);
	
	// Update the transformation info within libpng
	png_read_update_info(png_ptr, info_ptr);
		
	// Header info again
	png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, NULL, NULL);
	
	// Allocate target image
	allocate(width, height);

	// Handle Gamma
	png_set_gamma(png_ptr, 0.0, 0.0);
	
	// Setup row pointers
	row_pointers = new png_bytep[_data_height];
	if (!row_pointers) {
		png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
        return false;
	}
	
	for (unsigned int y = 0; y < _data_height; ++y) {
		row_pointers[y] = reinterpret_cast<png_byte*>( &getPixel(0,y) );
	}	
	
	// Read the entire image
	png_read_image(png_ptr, row_pointers);
	
	//
	// Clean up
	//
	
	delete row_pointers;
	png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
	
	return true;
}
Exemple #13
0
/*
    ReadPNG - Reads the contents of a PNG file and stores the contents into
              BMGImageStruct

    Inputs:
        filename    - the name of the file to be opened

    Outputs:
        img         - the BMGImageStruct containing the image data

    Returns:
        BMGError - if the file could not be read or a resource error occurred
        BMG_OK   - if the file was read and the data was stored in img

    Limitations:
        None.

    Comments:
        2-bit images are converted to 4-bit images.
        16-bit images are converted to 8-bit images.
        gray scale images with alpha components are converted to 32-bit images
*/
BMGError ReadPNG( const char *filename,
        struct BMGImageStruct * volatile img )
{
    jmp_buf             err_jmp;
    int                 error;

    FILE * volatile		file = NULL;
	int	bit_depth, color_type, interlace_type, compression_type, filter_type,
		row_bytes;
    unsigned char       signature[8];
    png_structp volatile png_ptr = NULL;
    png_infop   volatile info_ptr = NULL;
    unsigned long       Width, Height;

    unsigned char      *bits;
    unsigned char** volatile rows = NULL;

	BMGError tmp;

    /* error handler */
    error = setjmp( err_jmp );
    if ( error != 0 )
    {
        if (info_ptr != NULL)
            png_destroy_read_struct((png_structp *) &png_ptr, (png_infop *) &info_ptr, NULL);
        else if (png_ptr != NULL)
            png_destroy_read_struct((png_structp *) &png_ptr, NULL, NULL);
        if ( rows )
        {
            if ( rows[0] )
                free( rows[0] );
            free( rows );
        }
		if (img)
			FreeBMGImage( img );
		if (file)
			fclose( file );
        return (BMGError)error;
    }

    if ( img == NULL )
        longjmp ( err_jmp, (int)errInvalidBMGImage );

    file = fopen( filename, "rb" );
    if ( !file || fread( signature, 1, 8, file ) != 8)
        longjmp ( err_jmp, (int)errFileOpen );

    /* check the signature */
    if (png_sig_cmp( signature, 0, 8 ) != 0)
        longjmp( err_jmp, (int)errUnsupportedFileFormat );

    /* create a pointer to the png read structure */
    png_ptr = png_create_read_struct( PNG_LIBPNG_VER_STRING, NULL, NULL, NULL );
    if ( !png_ptr )
        longjmp( err_jmp, (int)errMemoryAllocation );

    /* create a pointer to the png info structure */
    info_ptr = png_create_info_struct( png_ptr );
    if ( !info_ptr )
        longjmp( err_jmp, (int)errMemoryAllocation );

    /* bamboozle the PNG longjmp buffer */
    /*generic PNG error handler*/
    error = setjmp( png_jmpbuf( png_ptr ) );
    if ( error > 0 )
        longjmp( err_jmp, error );

    /* attach file buffer to the png read pointer */
    png_init_io( png_ptr, file );

    /*let the read functions know that we have already read the 1st 8 bytes */
    png_set_sig_bytes( png_ptr, 8 );

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

    /* extract the data we need to form the HBITMAP from the PNG header */
	png_get_IHDR(png_ptr, info_ptr, &Width, &Height, &bit_depth, &color_type,
                    &interlace_type, &compression_type, &filter_type );

    img->width =  (unsigned int) Width;
    img->height = (unsigned int) Height;

    img->bits_per_pixel = (unsigned char)32;
	img->scan_width = Width * 4;

	/* strip if color channel is larger than 8 bits */
	if (bit_depth > 8)
	{
		png_set_strip_16(png_ptr);
		bit_depth = 8;
	}

   /* These are not really required per Rice format spec,
    * but is done just in case someone uses them.
    * convert palette color to rgb color */
	if (color_type == PNG_COLOR_TYPE_PALETTE) {
        png_set_palette_to_rgb(png_ptr);
		color_type = PNG_COLOR_TYPE_RGB;
    }

	/* expand 1,2,4 bit gray scale to 8 bit gray scale */
	if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
		png_set_expand_gray_1_2_4_to_8(png_ptr);

    /* convert gray scale or gray scale + alpha to rgb color */
	if (color_type == PNG_COLOR_TYPE_GRAY ||
		color_type == PNG_COLOR_TYPE_GRAY_ALPHA) {
        png_set_gray_to_rgb(png_ptr);
		color_type = PNG_COLOR_TYPE_RGB;
    }

    /* add alpha channel if any */
	if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
		png_set_tRNS_to_alpha(png_ptr);
		color_type = PNG_COLOR_TYPE_RGB_ALPHA;
	}

	/* convert rgb to rgba */
	if (color_type == PNG_COLOR_TYPE_RGB) {
		png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER);
		color_type = PNG_COLOR_TYPE_RGB_ALPHA;
	}

	/* punt invalid formats */
	if (color_type != PNG_COLOR_TYPE_RGB_ALPHA) {
		longjmp(err_jmp, (int)errIncorrectFormat);
	}

	/* convert rgba to bgra */
    png_set_bgr(png_ptr);

	img->palette_size = (unsigned short)0;
	img->bytes_per_palette_entry = 4U;

	tmp = AllocateBMGImage( img );
    if ( tmp != BMG_OK )
        longjmp( err_jmp, (int)tmp );

	/* Update info structure */
    png_read_update_info( png_ptr, info_ptr );

    /* create buffer to read data to */
    rows = (unsigned char **)malloc(Height*sizeof(unsigned char *));
    if ( !rows )
        longjmp( err_jmp, (int)errMemoryAllocation );

	row_bytes = png_get_rowbytes(png_ptr, info_ptr);

    rows[0] = (unsigned char *)malloc( Height*row_bytes*sizeof(char));

    if ( !rows[0] )
        longjmp( err_jmp, (int)errMemoryAllocation );

    for (int i = 1; i < (int)Height; i++ )
		rows[i] = rows[i - 1] + row_bytes;

    /* read the entire image into rows */
    png_read_image( png_ptr, rows );

    bits = img->bits + (Height - 1) * img->scan_width;
    for (int i = 0; i < (int)Height; i++ )
    {
		memcpy(bits, rows[i], 4*Width);
        bits -= img->scan_width;
    }

	free( rows[0] );
    free( rows );
    png_read_end( png_ptr, info_ptr );
    png_destroy_read_struct((png_structp *) &png_ptr, (png_infop *) &info_ptr, NULL);
    fclose( file );

    return BMG_OK;
}
BOOL png2pnm (FILE *png_file, FILE *pnm_file, FILE *alpha_file, BOOL raw, BOOL alpha)
{
  png_struct    *png_ptr = NULL;
  png_info	*info_ptr = NULL;
  png_byte      buf[8];
  png_byte      *png_pixels = NULL;
  png_byte      **row_pointers = NULL;
  png_byte      *pix_ptr = NULL;
  png_uint_32   row_bytes;

  png_uint_32   width;
  png_uint_32   height;
  int           bit_depth;
  int           channels;
  int           color_type;
  int           alpha_present;
  int           row, col;
  int           ret;
  int           i;
  long          dep_16;

  /* read and check signature in PNG file */
  ret = fread (buf, 1, 8, png_file);
  if (ret != 8)
    return FALSE;

  ret = !png_sig_cmp (buf, 0, 8);
  if (!ret)
    return FALSE;

  /* create png and info structures */

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

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

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

  /* set up the input control for C streams */
  png_init_io (png_ptr, png_file);
  png_set_sig_bytes (png_ptr, 8);  /* we already read the 8 signature bytes */

  /* read the file information */
  png_read_info (png_ptr, info_ptr);

  /* get size and bit-depth of the PNG-image */
  png_get_IHDR (png_ptr, info_ptr,
    &width, &height, &bit_depth, &color_type,
    NULL, NULL, NULL);

  /* set-up the transformations */

  /* transform paletted images into full-color rgb */
  if (color_type == PNG_COLOR_TYPE_PALETTE)
    png_set_expand (png_ptr);
  /* expand images to bit-depth 8 (only applicable for grayscale images) */
  if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
    png_set_expand (png_ptr);
  /* transform transparency maps into full alpha-channel */
  if (png_get_valid (png_ptr, info_ptr, PNG_INFO_tRNS))
    png_set_expand (png_ptr);

#ifdef NJET
  /* downgrade 16-bit images to 8 bit */
  if (bit_depth == 16)
    png_set_strip_16 (png_ptr);
  /* transform grayscale images into full-color */
  if (color_type == PNG_COLOR_TYPE_GRAY ||
    color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
    png_set_gray_to_rgb (png_ptr);
  /* only if file has a file gamma, we do a correction */
  if (png_get_gAMA (png_ptr, info_ptr, &file_gamma))
    png_set_gamma (png_ptr, (double) 2.2, file_gamma);
#endif

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

  png_read_update_info (png_ptr, info_ptr);

  /* get the new color-type and bit-depth (after expansion/stripping) */
  png_get_IHDR (png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,
    NULL, NULL, NULL);

  /* check for 16-bit files */
  if (bit_depth == 16)
  {
    raw = FALSE;
#ifdef __TURBOC__
    pnm_file->flags &= ~((unsigned) _F_BIN);
#endif
  }

  /* calculate new number of channels and store alpha-presence */
  if (color_type == PNG_COLOR_TYPE_GRAY)
    channels = 1;
  else if (color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
    channels = 2;
  else if (color_type == PNG_COLOR_TYPE_RGB)
    channels = 3;
  else if (color_type == PNG_COLOR_TYPE_RGB_ALPHA)
    channels = 4;
  else
    channels = 0; /* should never happen */
  alpha_present = (channels - 1) % 2;

  /* check if alpha is expected to be present in file */
  if (alpha && !alpha_present)
  {
    fprintf (stderr, "PNG2PNM\n");
    fprintf (stderr, "Error:  PNG-file doesn't contain alpha channel\n");
    exit (1);
  }

  /* row_bytes is the width x number of channels x (bit-depth / 8) */
  row_bytes = png_get_rowbytes (png_ptr, info_ptr);

  if ((png_pixels = (png_byte *) malloc (row_bytes * height * sizeof (png_byte))) == NULL) {
    png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
    return FALSE;
  }

  if ((row_pointers = (png_byte **) malloc (height * sizeof (png_bytep))) == NULL)
  {
    png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
    free (png_pixels);
    png_pixels = NULL;
    return FALSE;
  }

  /* set the individual row_pointers to point at the correct offsets */
  for (i = 0; i < (height); i++)
    row_pointers[i] = png_pixels + i * row_bytes;

  /* now we can go ahead and just read the whole image */
  png_read_image (png_ptr, row_pointers);

  /* read rest of file, and get additional chunks in info_ptr - REQUIRED */
  png_read_end (png_ptr, info_ptr);

  /* clean up after the read, and free any memory allocated - REQUIRED */
  png_destroy_read_struct (&png_ptr, &info_ptr, (png_infopp) NULL);

  /* write header of PNM file */

  if ((color_type == PNG_COLOR_TYPE_GRAY) ||
      (color_type == PNG_COLOR_TYPE_GRAY_ALPHA))
  {
    fprintf (pnm_file, "%s\n", (raw) ? "P5" : "P2");
    fprintf (pnm_file, "%d %d\n", (int) width, (int) height);
    fprintf (pnm_file, "%ld\n", ((1L << (int) bit_depth) - 1L));
  }
  else if ((color_type == PNG_COLOR_TYPE_RGB) ||
           (color_type == PNG_COLOR_TYPE_RGB_ALPHA))
  {
    fprintf (pnm_file, "%s\n", (raw) ? "P6" : "P3");
    fprintf (pnm_file, "%d %d\n", (int) width, (int) height);
    fprintf (pnm_file, "%ld\n", ((1L << (int) bit_depth) - 1L));
  }

  /* write header of PGM file with alpha channel */

  if ((alpha) &&
      ((color_type == PNG_COLOR_TYPE_GRAY_ALPHA) ||
       (color_type == PNG_COLOR_TYPE_RGB_ALPHA)))
  {
    fprintf (alpha_file, "%s\n", (raw) ? "P5" : "P2");
    fprintf (alpha_file, "%d %d\n", (int) width, (int) height);
    fprintf (alpha_file, "%ld\n", ((1L << (int) bit_depth) - 1L));
  }

  /* write data to PNM file */
  pix_ptr = png_pixels;

  for (row = 0; row < height; row++)
  {
    for (col = 0; col < width; col++)
    {
      for (i = 0; i < (channels - alpha_present); i++)
      {
        if (raw)
          fputc ((int) *pix_ptr++ , pnm_file);
        else
          if (bit_depth == 16){
	    dep_16 = (long) *pix_ptr++;
            fprintf (pnm_file, "%ld ", (dep_16 << 8) + ((long) *pix_ptr++));
          }
          else
            fprintf (pnm_file, "%ld ", (long) *pix_ptr++);
      }
      if (alpha_present)
      {
        if (!alpha)
        {
          pix_ptr++; /* alpha */
          if (bit_depth == 16)
            pix_ptr++;
        }
        else /* output alpha-channel as pgm file */
        {
          if (raw)
            fputc ((int) *pix_ptr++ , alpha_file);
          else
            if (bit_depth == 16){
	      dep_16 = (long) *pix_ptr++;
              fprintf (alpha_file, "%ld ", (dep_16 << 8) + (long) *pix_ptr++);
	    }  
            else
              fprintf (alpha_file, "%ld ", (long) *pix_ptr++);
        }
      } /* if alpha_present */

      if (!raw)
        if (col % 4 == 3)
          fprintf (pnm_file, "\n");
    } /* end for col */

    if (!raw)
      if (col % 4 != 0)
        fprintf (pnm_file, "\n");
  } /* end for row */

  if (row_pointers != (unsigned char**) NULL)
    free (row_pointers);
  if (png_pixels != (unsigned char*) NULL)
    free (png_pixels);

  return TRUE;

} /* end of source */
Exemple #15
0
MMBitmapRef newMMBitmapFromPNG(const char *path, MMPNGReadError *err)
{
	FILE *fp;
	uint8_t header[8];
	png_struct *png_ptr = NULL;
	png_info *info_ptr = NULL;
	png_byte bit_depth, color_type;
	uint8_t *row, *bitmapData;
	uint8_t bytesPerPixel;
	png_uint_32 width, height, y;
	uint32_t bytewidth;

	if ((fp = fopen(path, "rb")) == NULL) {
		if (err != NULL) *err = kPNGAccessError;
		return NULL;
	}

	/* Initialize error code to generic value. */
	if (err != NULL) *err = kPNGGenericError;

	/* Validate the PNG. */
	if (fread(header, 1, sizeof header, fp) == 0) {
		if (err != NULL) *err = kPNGReadError;
		goto bail;
	} else if (!png_check_sig(header, sizeof(header))) {
		if (err != NULL) *err = kPNGInvalidHeaderError;
		goto bail;
	}

	png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
	if (png_ptr == NULL) goto bail;

	info_ptr = png_create_info_struct(png_ptr);
	if (info_ptr == NULL) goto bail;

	/* Set up error handling. */
	if (setjmp(png_jmpbuf(png_ptr))) {
		goto bail;
	}

	png_init_io(png_ptr, fp);

	/* Skip past the header. */
	png_set_sig_bytes(png_ptr, sizeof header);

	png_read_info(png_ptr, info_ptr);

	/* Convert different image types to common type to be read. */
	bit_depth = png_get_bit_depth(png_ptr, info_ptr);
	color_type = png_get_color_type(png_ptr, info_ptr);

	/* Convert color palettes to RGB. */
	if (color_type == PNG_COLOR_TYPE_PALETTE) {
		png_set_palette_to_rgb(png_ptr);
	}

	/* Convert PNG to bit depth of 8. */
	if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) {
#ifdef PNG_LIBPNG_VER_SONUM
#if PNG_LIBPNG_VER_SONUM  >= 14
		png_set_expand_gray_1_2_4_to_8(png_ptr);
#else
		png_set_gray_1_2_4_to_8(png_ptr);
#endif
#else
		png_set_gray_1_2_4_to_8(png_ptr);
#endif
	} else if (bit_depth == 16) {
		png_set_strip_16(png_ptr);
	}

	/* Convert transparency chunk to alpha channel. */
	if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))  {
		png_set_tRNS_to_alpha(png_ptr);
	}

	/* Convert gray images to RGB. */
	if (color_type == PNG_COLOR_TYPE_GRAY ||
	    color_type == PNG_COLOR_TYPE_GRAY_ALPHA) {
		png_set_gray_to_rgb(png_ptr);
	}

	/* Ignore alpha for now. */
	if (color_type & PNG_COLOR_MASK_ALPHA) {
		png_set_strip_alpha(png_ptr);
	}

	/* Get image attributes. */
	width = png_get_image_width(png_ptr, info_ptr);
	height = png_get_image_height(png_ptr, info_ptr);
	bytesPerPixel = 3; /* All images decompress to this size. */
	bytewidth = ADD_PADDING(width * bytesPerPixel); /* Align width. */

	/* Decompress the PNG row by row. */
	bitmapData = calloc(1, bytewidth * height);
	row = png_malloc(png_ptr, png_get_rowbytes(png_ptr, info_ptr));
	if (bitmapData == NULL || row == NULL) goto bail;
	for (y = 0; y < height; ++y) {
		png_uint_32 x;
		const uint32_t rowOffset = y * bytewidth;
		uint8_t *rowptr = row;
		png_read_row(png_ptr, (png_byte *)row, NULL);

		for (x = 0; x < width; ++x) {
			const uint32_t colOffset = x * bytesPerPixel;
			MMRGBColor *color = (MMRGBColor *)(bitmapData + rowOffset + colOffset);
			color->red = *rowptr++;
			color->green = *rowptr++;
			color->blue = *rowptr++;
		}
	}
	free(row);

	/* Finish reading. */
	png_read_end(png_ptr, NULL);
	png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
	fclose(fp);

	return createMMBitmap(bitmapData, width, height,
	                      bytewidth, bytesPerPixel * 8, bytesPerPixel);

bail:
	png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
	fclose(fp);
	return NULL;
}
Exemple #16
0
bool Image::CreateImage(const char* pszImageFile)
{
	StreamReader* pTextureStream = IFileUtil::GetInstance().LoadFile(pszImageFile);
	if (!pTextureStream || !pTextureStream->IsOK())
	{
		SAFE_RELEASE(pTextureStream);
		return false;
	}

	png_structp pPngStruct = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
	if (!pPngStruct)
	{
		png_destroy_read_struct(&pPngStruct, NULL, NULL);
		// logout
		LOGE("load image file failed: %s", pszImageFile);
		SAFE_DELETE(pTextureStream);
		return false;
	}

	png_infop pPngInfo = png_create_info_struct(pPngStruct);
	if (!pPngInfo)
	{
		png_destroy_read_struct(&pPngStruct, &pPngInfo, NULL);
		// logout
		LOGE("create png info failed: %s", pszImageFile);
		SAFE_DELETE(pTextureStream);
		return false;
	}

	setjmp(png_jmpbuf(pPngStruct));

	// define our own callback function for I/O instead of reading from a file
	png_set_read_fn(pPngStruct, pTextureStream, PngReaderCallback);

	png_read_info(pPngStruct, pPngInfo);
	m_nImageWidth = png_get_image_width(pPngStruct, pPngInfo);
	m_nImageHeight = png_get_image_height(pPngStruct, pPngInfo);
	// can be PNG_COLOR_TYPE_RGB, PNG_COLOR_TYPE_PALETTE, ...
	png_byte nColorType = png_get_color_type(pPngStruct, pPngInfo);
	m_nBPP = png_get_bit_depth(pPngStruct, pPngInfo);

	// convert stuff to appropriate formats!
	if(nColorType == PNG_COLOR_TYPE_PALETTE)
	{
		png_set_packing(pPngStruct);
		// expand data to 24-bit RGB or 32-bit RGBA if alpha available
		png_set_palette_to_rgb(pPngStruct);
	}

	// expand data to 24-bit RGB or 32-bit RGBA if alpha available
	if (nColorType == PNG_COLOR_TYPE_GRAY && m_nBPP < 8) png_set_expand_gray_1_2_4_to_8(pPngStruct);
	if (nColorType == PNG_COLOR_TYPE_GRAY_ALPHA) png_set_gray_to_rgb(pPngStruct);
	if (m_nBPP == 16) png_set_strip_16(pPngStruct);

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

	// read image data into pRowPointers
	uchar** pRowPointers = new uchar*[m_nImageHeight];
	for (int y = 0; y < m_nImageHeight; y++)
	{
		pRowPointers[y] = new uchar[m_nImageWidth * 4]; //each pixel(RGBA) has 4 bytes
	}
	png_read_image(pPngStruct, pRowPointers);

	// free the stream object and png structure
	png_destroy_read_struct(&pPngStruct, &pPngInfo, NULL);
	SAFE_RELEASE(pTextureStream);

	// store image data into our pRGBAData, each pixel(RGBA) has 4 bytes
	m_pPixelData = new uchar[m_nImageWidth * m_nImageHeight * 4];
	//unlike store the pixel data from top-left corner, store them from bottom-left corner for OGLES Texture drawing...
	int nCurrPos = (m_nImageWidth * m_nImageHeight * 4) - (4 * m_nImageWidth);
	for(int row = 0; row < m_nImageHeight; row++)
	{
		for(int col = 0; col < (4 * m_nImageWidth); col += 4)
		{
			m_pPixelData[nCurrPos++] = pRowPointers[row][col + 0];    // red
			m_pPixelData[nCurrPos++] = pRowPointers[row][col + 1];    // green
			m_pPixelData[nCurrPos++] = pRowPointers[row][col + 2];    // blue
			m_pPixelData[nCurrPos++] = pRowPointers[row][col + 3];    // alpha
		}
		nCurrPos = (nCurrPos - (m_nImageWidth * 4) * 2); //move the pointer back two rows
	}

	// free pRowPointers
	for (int y = 0; y < m_nImageHeight; y++)
	{
		SAFE_DELETE_ARRAY(pRowPointers[y]);
	}
	SAFE_DELETE_ARRAY(pRowPointers);

	return true;
}
bool loadSpriteFromPNG (const char * file, struct spriteBank *sprites, int index)
{
	if (sprites->type<2) {
		char * error = joinStrings(file, "\n\nPNG files currently not supported in palette mode. Change to 32-bit mode and try again.");
		errorBox ("Can't open PNG file", error);
		delete error;
		return false;
	}
	
	// Open the file	
	FILE * fp = fopen (file, "rb");
	if (fp == NULL) {
		char * error = joinStrings(file, "\n\nThe file can't be opened. I don't know why.");
		errorBox ("Can't open PNG file", error);
		delete error;
		return false;
	}
	
	char tmp[10];
	size_t bytes_read = fread(tmp, 1, 8, fp);
	if (bytes_read != 8 && ferror (fp)) {
		fprintf(stderr, "Reading error in loadSpriteFromPNG.\n");
	}
    if (png_sig_cmp((png_byte *) tmp, 0, 8)) {
		fclose (fp);
		char * error = joinStrings(file, "\n\nIt doesn't appear to be a valid PNG image.");
		errorBox ("Can't open PNG file", error);
		delete error;
		return false;
    }
	
    png_structp png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
    if (!png_ptr) {
		fclose (fp);
		char * error = joinStrings(file, "\n\nError reading the file.");
		errorBox ("Can't open PNG file", error);
		delete error;
		return false;
	}
	
    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);
		fclose (fp);
		char * error = joinStrings(file, "\n\nError reading the file.");
		errorBox ("Can't open PNG file", error);
		delete error;
		return false;
    }
	
    png_infop end_info = png_create_info_struct(png_ptr);
    if (!end_info) {
        png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
		fclose (fp);
		char * error = joinStrings(file, "\n\nError readin the file");
		return errorBox ("Can't open PNG file", error);
    }
    png_init_io(png_ptr, fp);		// Tell libpng which file to read
    png_set_sig_bytes(png_ptr, 8);	// 8 bytes already read
	
	png_read_info(png_ptr, info_ptr);
	
	png_uint_32 width, height;
	int bit_depth, color_type, interlace_type, compression_type, filter_method;
	png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, &compression_type, &filter_method);
	
    if (bit_depth < 8) png_set_packing(png_ptr);
	png_set_expand(png_ptr);
    if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) png_set_gray_to_rgb(png_ptr);	
	if (bit_depth == 16) png_set_strip_16(png_ptr);

	png_set_add_alpha(png_ptr, 0xff, PNG_FILLER_AFTER);
	
	png_read_update_info(png_ptr, info_ptr);
	png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, &compression_type, &filter_method);
		
	int rowbytes = png_get_rowbytes(png_ptr, info_ptr);
	
	unsigned char * row_pointers[height];
	unsigned char * data = new unsigned char [rowbytes*height];
	for (int i = 0; i<height; i++)
		row_pointers[i] = data + i*rowbytes;
	
	png_read_image(png_ptr, (png_byte **) row_pointers);
	png_read_end(png_ptr, NULL);
	png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);

	fclose (fp);
	if (sprites->sprites[index].data) delete sprites->sprites[index].data;
	
	sprites->sprites[index].data = data;
	sprites->sprites[index].width = width;
	sprites->sprites[index].height = height;
	
	int n, r, g, b;
	for (int x=0; x<width;x++) {
		for (int y=0; y<height; y++) {
			if (! sprites->sprites[index].data[4*width*y + x*4 + 3]) {
				n = r = g = b = 0;
				if (x>0 && sprites->sprites[index].data[4*width*y + (x-1)*4 + 3]) {
					n++;
					r+= sprites->sprites[index].data[4*width*y + (x-1)*4];
					g+= sprites->sprites[index].data[4*width*y + (x-1)*4+1];
					b+= sprites->sprites[index].data[4*width*y + (x-1)*4+2];
				}
				if (x<width-1 && sprites->sprites[index].data[4*width*y + (x+1)*4 + 3]) {
					n++;
					r+= sprites->sprites[index].data[4*width*y + (x+1)*4];
					g+= sprites->sprites[index].data[4*width*y + (x+1)*4+1];
					b+= sprites->sprites[index].data[4*width*y + (x+1)*4+2];
				}
				if (y>0 && sprites->sprites[index].data[4*width*(y-1) + x*4 + 3]) {
					n++;
					r+= sprites->sprites[index].data[4*width*(y-1) + x*4];
					g+= sprites->sprites[index].data[4*width*(y-1) + x*4+1];
					b+= sprites->sprites[index].data[4*width*(y-1) + x*4+2];
				}
				if (y<height-1 && sprites->sprites[index].data[4*width*(y+1) + x*4 + 3]) {
					n++;
					r+= sprites->sprites[index].data[4*width*(y+1) + x*4];
					g+= sprites->sprites[index].data[4*width*(y+1) + x*4+1];
					b+= sprites->sprites[index].data[4*width*(y+1) + x*4+2];
				}
				if (n) {
					r /= n;
					g /= n;
					b /= n;
					sprites->sprites[index].data[4*width*y + x*4]=r;
					sprites->sprites[index].data[4*width*y + x*4+1]=g;
					sprites->sprites[index].data[4*width*y + x*4+2]=b;
				}
			}
		}
	}
	
	loadSpriteTexture (sprites, index);
	return true;
}
Exemple #18
0
int fh_png_load(const char *name,unsigned char *buffer,int x,int y)
{
	static const png_color_16 my_background = {0, 0, 0, 0, 0};

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

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

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

#if (PNG_LIBPNG_VER < 10500)
	if(setjmp(png_ptr->jmpbuf))
#else
	if(setjmp(png_jmpbuf(png_ptr)))
#endif
	{
		png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
		fclose(fh); return(FH_ERROR_FORMAT);
	}

	png_init_io(png_ptr,fh);

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

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

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

	if (color_type & PNG_COLOR_MASK_ALPHA)
		png_set_strip_alpha(png_ptr);

	if (bit_depth < 8)
		png_set_packing(png_ptr);

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

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

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

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

	for(pass = 0; pass < number_passes; pass++)
	{
		fbptr = (png_byte *)buffer;
		for (i = 0; i < height; i++, fbptr += width * 3)
		{
			png_read_row(png_ptr, fbptr, NULL);
		}
	}
	png_read_end(png_ptr, info_ptr);
	png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
	fclose(fh);
	return(FH_ERROR_OK);
}
Exemple #19
0
/**
Configure the decoder so that decoded pixels are compatible with a FREE_IMAGE_TYPE format. 
Set conversion instructions as needed. 
@param png_ptr PNG handle
@param info_ptr PNG info handle
@param flags Decoder flags
@param output_image_type Returned FreeImage converted image type
@return Returns TRUE if successful, returns FALSE otherwise
@see png_read_update_info
*/
static BOOL 
ConfigureDecoder(png_structp png_ptr, png_infop info_ptr, int flags, FREE_IMAGE_TYPE *output_image_type) {
	// get original image info
	const int color_type = png_get_color_type(png_ptr, info_ptr);
	const int bit_depth = png_get_bit_depth(png_ptr, info_ptr);
	const int pixel_depth = bit_depth * png_get_channels(png_ptr, info_ptr);

	FREE_IMAGE_TYPE image_type = FIT_BITMAP;	// assume standard image type

	// check for transparency table or single transparent color
	BOOL bIsTransparent = png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS) == PNG_INFO_tRNS ? TRUE : FALSE;

	// check allowed combinations of colour type and bit depth
	// then get converted FreeImage type

	switch(color_type) {
		case PNG_COLOR_TYPE_GRAY:		// color type '0', bitdepth = 1, 2, 4, 8, 16
			switch(bit_depth) {
				case 1:
				case 2:
				case 4:
				case 8:
					// expand grayscale images to the full 8-bit from 2-bit/pixel
					if (pixel_depth == 2) {
						png_set_expand_gray_1_2_4_to_8(png_ptr);
					}

					// if a tRNS chunk is provided, we must also expand the grayscale data to 8-bits,
					// this allows us to make use of the transparency table with existing FreeImage methods
					if (bIsTransparent && (pixel_depth < 8)) {
						png_set_expand_gray_1_2_4_to_8(png_ptr);
					}
					break;

				case 16:
					image_type = (pixel_depth == 16) ? FIT_UINT16 : FIT_UNKNOWN;

					// 16-bit grayscale images can contain a transparent value (shade)
					// if found, expand the transparent value to a full alpha channel
					if (bIsTransparent && (image_type != FIT_UNKNOWN)) {
						// expand tRNS to a full alpha channel
						png_set_tRNS_to_alpha(png_ptr);
						
						// expand new 16-bit gray + 16-bit alpha to full 64-bit RGBA
						png_set_gray_to_rgb(png_ptr);

						image_type = FIT_RGBA16;
					}
					break;

				default:
					image_type = FIT_UNKNOWN;
					break;
			}
			break;

		case PNG_COLOR_TYPE_RGB:		// color type '2', bitdepth = 8, 16
			switch(bit_depth) {
				case 8:
					image_type = (pixel_depth == 24) ? FIT_BITMAP : FIT_UNKNOWN;
					break;
				case 16:
					image_type = (pixel_depth == 48) ? FIT_RGB16 : FIT_UNKNOWN;
					break;
				default:
					image_type = FIT_UNKNOWN;
					break;
			}
			// sometimes, 24- or 48-bit images may contain transparency information
			// check for this use case and convert to an alpha-compatible format
			if (bIsTransparent && (image_type != FIT_UNKNOWN)) {
				// if the image is 24-bit RGB, mark it as 32-bit; if it is 48-bit, mark it as 64-bit
				image_type = (pixel_depth == 24) ? FIT_BITMAP : (pixel_depth == 48) ? FIT_RGBA16 : FIT_UNKNOWN;
				// expand tRNS chunk to alpha channel
				png_set_tRNS_to_alpha(png_ptr);
			}
			break;

		case PNG_COLOR_TYPE_PALETTE:	// color type '3', bitdepth = 1, 2, 4, 8
			switch(bit_depth) {
				case 1:
				case 2:
				case 4:
				case 8:
					// expand palette images to the full 8 bits from 2 bits/pixel
					if (pixel_depth == 2) {
						png_set_packing(png_ptr);
					}

					// if a tRNS chunk is provided, we must also expand the palletized data to 8-bits,
					// this allows us to make use of the transparency table with existing FreeImage methods
					if (bIsTransparent && (pixel_depth < 8)) {
						png_set_packing(png_ptr);
					}
					break;

				default:
					image_type = FIT_UNKNOWN;
					break;
			}
			break;

		case PNG_COLOR_TYPE_GRAY_ALPHA:	// color type '4', bitdepth = 8, 16
			switch(bit_depth) {
				case 8:
					// 8-bit grayscale + 8-bit alpha => convert to 32-bit RGBA
					image_type = (pixel_depth == 16) ? FIT_BITMAP : FIT_UNKNOWN;
					break;
				case 16:
					// 16-bit grayscale + 16-bit alpha => convert to 64-bit RGBA
					image_type = (pixel_depth == 32) ? FIT_RGBA16 : FIT_UNKNOWN;
					break;
				default:
					image_type = FIT_UNKNOWN;
					break;
			}
			// expand 8-bit greyscale + 8-bit alpha to 32-bit
			// expand 16-bit greyscale + 16-bit alpha to 64-bit
			png_set_gray_to_rgb(png_ptr);
			break;

		case PNG_COLOR_TYPE_RGB_ALPHA:	// color type '6', bitdepth = 8, 16
			switch(bit_depth) {
				case 8:
					break;
				case 16:
					image_type = (pixel_depth == 64) ? FIT_RGBA16 : FIT_UNKNOWN;
					break;
				default:
					image_type = FIT_UNKNOWN;
					break;
			}
			break;
	}

	// check for unknown or invalid formats
	if(image_type == FIT_UNKNOWN) {
		*output_image_type = image_type;
		return FALSE;
	}

#ifndef FREEIMAGE_BIGENDIAN
	if((image_type == FIT_UINT16) || (image_type == FIT_RGB16) || (image_type == FIT_RGBA16)) {
		// turn on 16-bit byte swapping
		png_set_swap(png_ptr);
	}
#endif						

#if FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_BGR
	if((image_type == FIT_BITMAP) && ((color_type == PNG_COLOR_TYPE_RGB) || (color_type == PNG_COLOR_TYPE_RGB_ALPHA))) {
		// flip the RGB pixels to BGR (or RGBA to BGRA)
		png_set_bgr(png_ptr);
	}
#endif

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

	if (png_get_valid(png_ptr, info_ptr, PNG_INFO_gAMA)) {
		double gamma = 0;
		double screen_gamma = 2.2;

		if (png_get_gAMA(png_ptr, info_ptr, &gamma) && ( flags & PNG_IGNOREGAMMA ) != PNG_IGNOREGAMMA) {
			png_set_gamma(png_ptr, screen_gamma, gamma);
		}
	}

	// all transformations have been registered; now update info_ptr data		
	png_read_update_info(png_ptr, info_ptr);

	// return the output image type
	*output_image_type = image_type;

	return TRUE;
}
static unsigned char* 
png_file_load (const char *file, 
	       int        *width, 
	       int        *height)
{
  FILE *fd;
  unsigned char *data;
  unsigned char header[8];
  int  bit_depth, color_type;

  png_uint_32  png_width, png_height, i, rowbytes;
  png_structp png_ptr;
  png_infop info_ptr;
  png_bytep *row_pointers;

  if ((fd = fopen( file, "rb" )) == NULL) return NULL;

  fread( header, 1, 8, fd );
  if ( ! png_check_sig( header, 8 ) ) 
    {
      fclose(fd);
      return NULL;
    }

  png_ptr = png_create_read_struct( PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
  if ( ! png_ptr ) {
    fclose(fd);
    return NULL;
  }

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

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

  png_init_io( png_ptr, fd );
  png_set_sig_bytes( png_ptr, 8);
  png_read_info( png_ptr, info_ptr);
  png_get_IHDR( png_ptr, info_ptr, &png_width, &png_height, &bit_depth, 
		&color_type, NULL, NULL, NULL);
  *width = (int) png_width;
  *height = (int) png_height;

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

  if (bit_depth < 8)
    png_set_packing(png_ptr);

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

  /* Add alpha */
  if (( color_type == PNG_COLOR_TYPE_GRAY ) ||
      ( color_type == PNG_COLOR_TYPE_RGB ))
    png_set_add_alpha(png_ptr, 0xff, PNG_FILLER_AFTER); /* req 1.2.7 */

  if (( color_type == PNG_COLOR_TYPE_PALETTE )||
      ( png_get_valid( png_ptr, info_ptr, PNG_INFO_tRNS )))
    png_set_expand(png_ptr);

  png_read_update_info( png_ptr, info_ptr);

  /* allocate space for data and row pointers */
  rowbytes = png_get_rowbytes( png_ptr, info_ptr);
  data = (unsigned char *) malloc( (rowbytes*(*height + 1)));
  row_pointers = (png_bytep *) malloc( (*height)*sizeof(png_bytep));

  if (( data == NULL )||( row_pointers == NULL )) {
    png_destroy_read_struct( &png_ptr, &info_ptr, NULL);
    free(data);
    free(row_pointers);
    return NULL;
  }

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

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

  free(row_pointers);
  png_destroy_read_struct( &png_ptr, &info_ptr, NULL);
  fclose(fd);

  return data;
}
Exemple #21
0
int fh_png_load(char *name,unsigned char *buffer, unsigned char ** alpha,int x,int y)
{
    png_structp png_ptr;
    png_infop info_ptr;
    png_uint_32 width, height;
    int i;
    int bit_depth, color_type, interlace_type;
    int number_passes,pass, trans = 0;
    char *rp;
    png_bytep rptr[2];
    char *fbptr;
    FILE *fh;

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

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

    png_init_io(png_ptr,fh);

    png_read_info(png_ptr, info_ptr);
    png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,&interlace_type, NULL, NULL);
    if (color_type == PNG_COLOR_TYPE_PALETTE) png_set_expand(png_ptr);
    if (bit_depth < 8) png_set_packing(png_ptr);
    if (color_type == PNG_COLOR_TYPE_GRAY || color_type== PNG_COLOR_TYPE_GRAY_ALPHA) png_set_gray_to_rgb(png_ptr);
    if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
    {
        trans = 1;
        png_set_tRNS_to_alpha(png_ptr);
    }

    if(bit_depth == 16) png_set_strip_16(png_ptr);
    number_passes = png_set_interlace_handling(png_ptr);
    png_read_update_info(png_ptr,info_ptr);

    if (color_type == PNG_COLOR_TYPE_GRAY_ALPHA || color_type == PNG_COLOR_TYPE_RGB_ALPHA || trans)
    {
        unsigned char * alpha_buffer = (unsigned char*) malloc(width * height);
        unsigned char * aptr;

        rp = (char*) malloc(width * 4);
        rptr[0] = (png_bytep) rp;

        *alpha = alpha_buffer;

        for (pass = 0; pass < number_passes; pass++)
        {
            fbptr = buffer;
            aptr = alpha_buffer;

            for(i=0; i<height; i++)
            {
                int n;
                unsigned char *trp = rp;

                png_read_rows(png_ptr, rptr, NULL, 1);

                for(n = 0; n < width; n++, fbptr += 3, trp += 4)
                {
                    memcpy(fbptr, trp, 3);
                    *(aptr++) = trp[3];
                }
            }
        }
        free(rp);
    }
    else
    {
        for (pass = 0; pass < number_passes; pass++)
        {
            fbptr = buffer;
            for(i=0; i<height; i++, fbptr += width*3)
            {
                rptr[0] = (png_bytep) fbptr;
                png_read_rows(png_ptr, rptr, NULL, 1);
            }
        }
    }
    png_read_end(png_ptr, info_ptr);
    png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
    fclose(fh);
    return(FH_ERROR_OK);
}
Exemple #22
0
void ImagePNG::ReadPNG(FILE* stream, const void* buffer, bool transparent,
                       int& width, int& height, void*& pixels) {
    pixels = NULL;

    png_struct *png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
    if (png_ptr == NULL) {
        Output::Error("Couldn't allocate PNG structure");
        return;
    }

    png_info *info_ptr = png_create_info_struct(png_ptr);
    if (info_ptr == NULL) {
        Output::Error("Couldn't allocate PNG info structure");
        return;
    }

    if (stream != NULL)
        png_init_io(png_ptr, stream);
    else
        png_set_read_fn(png_ptr, (png_voidp) &buffer, read_data);

    png_read_info(png_ptr, info_ptr);

    png_uint_32 w, h;
    int bit_depth, color_type;
    png_get_IHDR(png_ptr, info_ptr, &w, &h,
                 &bit_depth, &color_type, NULL, NULL, NULL);

    png_color black = {0,0,0};
    png_colorp palette;
    int num_palette = 0;

    switch (color_type) {
    case PNG_COLOR_TYPE_PALETTE:
        if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
            png_set_tRNS_to_alpha(png_ptr);
        else if (transparent && png_get_valid(png_ptr, info_ptr, PNG_INFO_PLTE))
            png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette);
        png_set_palette_to_rgb(png_ptr);
        png_set_filler(png_ptr, 0xFF, PNG_FILLER_AFTER);
        break;
    case PNG_COLOR_TYPE_GRAY:
        png_set_gray_to_rgb(png_ptr);
        if (bit_depth < 8)
            png_set_expand_gray_1_2_4_to_8(png_ptr);
        png_set_filler(png_ptr, 0xFF, PNG_FILLER_AFTER);
        if (transparent) {
            palette = &black;
            num_palette = 1;
        }
        break;
    case PNG_COLOR_TYPE_GRAY_ALPHA:
        png_set_gray_to_rgb(png_ptr);
        if (bit_depth < 8)
            png_set_expand_gray_1_2_4_to_8(png_ptr);
        break;
    case PNG_COLOR_TYPE_RGB:
        png_set_filler(png_ptr, 0xFF, PNG_FILLER_AFTER);
        break;
    case PNG_COLOR_TYPE_RGB_ALPHA:
        break;
    }

    if (bit_depth < 8)
        png_set_packing(png_ptr);

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

    png_read_update_info(png_ptr, info_ptr);

    width = w;
    height = h;
    pixels = malloc(w * h * 4);

    for (png_uint_32 y = 0; y < h; y++) {
        png_bytep dst = (png_bytep) pixels + y * w * 4;
        png_read_row(png_ptr, dst, NULL);
    }

    if (transparent && num_palette > 0) {
        png_color& ck = palette[0];
        uint8 ck1[4] = {ck.red, ck.green, ck.blue, 255};
        uint8 ck2[4] = {ck.red, ck.green, ck.blue,   0};
        uint32 srckey = *(uint32*)ck1;
        uint32 dstkey = *(uint32*)ck2;
        uint32* p = (uint32*) pixels;
        for (unsigned i = 0; i < w * h; i++, p++)
            if (*p == srckey)
                *p = dstkey;
    }

    png_read_end(png_ptr, NULL);

    png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
}
Exemple #23
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);
}
bool  PngDecoder::readData( Mat& img )
{
    bool result = false;
    AutoBuffer<uchar*> _buffer(m_height);
    uchar** buffer = _buffer;
    int color = img.channels() > 1;
    uchar* data = img.data;
    int step = (int)img.step;

    if( m_png_ptr && m_info_ptr && m_end_info && m_width && m_height )
    {
        png_structp png_ptr = (png_structp)m_png_ptr;
        png_infop info_ptr = (png_infop)m_info_ptr;
        png_infop end_info = (png_infop)m_end_info;

        if( setjmp( png_jmpbuf ( png_ptr ) ) == 0 )
        {
            int y;

            if( img.depth() == CV_8U && m_bit_depth == 16 )
                png_set_strip_16( png_ptr );
            else if( !isBigEndian() )
                png_set_swap( png_ptr );

            if(img.channels() < 4)
            {
                /* observation: png_read_image() writes 400 bytes beyond
                 * end of data when reading a 400x118 color png
                 * "mpplus_sand.png".  OpenCV crashes even with demo
                 * programs.  Looking at the loaded image I'd say we get 4
                 * bytes per pixel instead of 3 bytes per pixel.  Test
                 * indicate that it is a good idea to always ask for
                 * stripping alpha..  18.11.2004 Axel Walthelm
                 */
                 png_set_strip_alpha( png_ptr );
            }

            if( m_color_type == PNG_COLOR_TYPE_PALETTE )
                png_set_palette_to_rgb( png_ptr );

            if( m_color_type == PNG_COLOR_TYPE_GRAY && m_bit_depth < 8 )
#if (PNG_LIBPNG_VER_MAJOR*10000 + PNG_LIBPNG_VER_MINOR*100 + PNG_LIBPNG_VER_RELEASE >= 10209) || \
    (PNG_LIBPNG_VER_MAJOR == 1 && PNG_LIBPNG_VER_MINOR == 0 && PNG_LIBPNG_VER_RELEASE >= 18)
                png_set_expand_gray_1_2_4_to_8( png_ptr );
#else
                png_set_gray_1_2_4_to_8( png_ptr );
#endif

            if( CV_MAT_CN(m_type) > 1 && color )
                png_set_bgr( png_ptr ); // convert RGB to BGR
            else if( color )
                png_set_gray_to_rgb( png_ptr ); // Gray->RGB
            else
                png_set_rgb_to_gray( png_ptr, 1, 0.299, 0.587 ); // RGB->Gray

            png_read_update_info( png_ptr, info_ptr );

            for( y = 0; y < m_height; y++ )
                buffer[y] = data + y*step;

            png_read_image( png_ptr, buffer );
            png_read_end( png_ptr, end_info );

            result = true;
        }
    }

    close();
    return result;
}
Exemple #25
0
    /**
     Our implementation of libPNG callbacks
    */
    void haveInfo()
    {
        int bitDepth, colorType, interlaceType;
    
        png_get_IHDR(pngReadStruct, pngInfoStruct, &width, &height, &bitDepth,
                     &colorType, &interlaceType, 0, 0);
                     
        if (!ImageManager::isAcceptableSize(width, height)) {
            libPngError = true;
            return;
        }
        
        //Ask libPNG to change bit depths we don't support
        if (bitDepth < 8)
#if PNG_LIBPNG_VER < 10400
            png_set_gray_1_2_4_to_8(pngReadStruct);
#else
            png_set_expand_gray_1_2_4_to_8(pngReadStruct);
#endif
        
        if (bitDepth > 8)
            png_set_strip_16       (pngReadStruct);
            
        //Some images (basically, only paletted ones) may have alpha
        //included as part of a tRNS chunk. We want to convert that to regular alpha
        //channel..
        bool haveTRNS = false; 
        if (png_get_valid(pngReadStruct, pngInfoStruct, PNG_INFO_tRNS))
        {
            png_set_tRNS_to_alpha(pngReadStruct);
            haveTRNS = true;
            
            if (colorType == PNG_COLOR_TYPE_RGB)
                colorType =  PNG_COLOR_TYPE_RGB_ALPHA; //Paranoia..
            else if (colorType == PNG_COLOR_TYPE_GRAY)
                colorType = PNG_COLOR_TYPE_GRAY_ALPHA;
        }    
            
        ImageFormat imFrm;    
            
        //Prepare for mapping from colorType to our format descriptors.
        switch (colorType)
        {
            case PNG_COLOR_TYPE_GRAY:
                imFrm.greyscaleSetup();
                break;
            case PNG_COLOR_TYPE_GRAY_ALPHA:
                //We don't natively support 8-bit plus alpha, so ask libPNG to expand it out to RGB
                png_set_gray_to_rgb(pngReadStruct);
                imFrm.type = ImageFormat::Image_ARGB_32;
                break;
            case PNG_COLOR_TYPE_PALETTE:                
                //For now, we handle paletted images as RGB or ARGB
                //### TODO: handle non-alpha paletted images with a sufficiently small palette as 
                //paletted
                imFrm.type = haveTRNS ? ImageFormat::Image_ARGB_32 : ImageFormat::Image_RGB_32;
                png_set_palette_to_rgb(pngReadStruct);
                break;
            case PNG_COLOR_TYPE_RGB:
                imFrm.type = ImageFormat::Image_RGB_32;
                break;
            case PNG_COLOR_TYPE_RGB_ALPHA:
                imFrm.type = ImageFormat::Image_ARGB_32;
                break;
            default:
                //Huh?
                libPngError = true;
                return;
        }
        
        //Configure padding/byte swapping if need be (32-bit images)
        //We want a 32-bit value with ARGB.
        //This means that for little-endian, in memory we should have BGRA,
        //and for big-endian, well, ARGB        
        if (imFrm.type == ImageFormat::Image_RGB_32)
        {
            //Need fillers, plus perhaps BGR swapping for non-alpha
#if Q_BYTE_ORDER == Q_BIG_ENDIAN || defined(__BIG_ENDIAN__)
            png_set_filler(pngReadStruct, 0xff, PNG_FILLER_BEFORE);
#else
            png_set_filler(pngReadStruct, 0xff, PNG_FILLER_AFTER);
            png_set_bgr   (pngReadStruct);
#endif                
        }
        else if (imFrm.type == ImageFormat::Image_ARGB_32)
        {
#if Q_BYTE_ORDER == Q_BIG_ENDIAN || defined(__BIG_ENDIAN__)
            png_set_swap_alpha(pngReadStruct); //ARGB, not RGBA
#else
            png_set_bgr   (pngReadStruct);     //BGRA
#endif
        }
        
        //Remember depth, for our own use
        depth = imFrm.depth();
        
        //handle interlacing        
        if (interlaceType != PNG_INTERLACE_NONE)
        {
            interlaced  = true;
            scanlineBuf = new unsigned char[depth * width];
            png_set_interlace_handling(pngReadStruct);
            
            // Give up on premultiply in this case..
            if (imFrm.type == ImageFormat::Image_ARGB_32)
                imFrm.type = ImageFormat::Image_ARGB_32_DontPremult;
        }
        
        notifySingleFrameImage(width, height, imFrm);
        
        //OK, time to start input
        png_read_update_info(pngReadStruct, pngInfoStruct);
    }
Exemple #26
0
SDL_Surface *TCOD_sys_read_png(const char *filename) {
	png_uint_32 png_width,png_height,y;
	int png_bit_depth,png_color_type,png_interlace_type;
	png_structp png_ptr;
	png_infop info_ptr;
	FILE *fp;
	SDL_Surface *bitmap;
	png_bytep *row_pointers;

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

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

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

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

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

	png_init_io(png_ptr, fp);

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

	/* get info about the image */
	png_read_info(png_ptr,info_ptr);
	png_get_IHDR(png_ptr,info_ptr,&png_width,&png_height,&png_bit_depth,&png_color_type,
		&png_interlace_type,NULL,NULL);

	/* convert the image to a format suitable with libtcod */
	png_set_strip_16(png_ptr); /* 16 bits channels => 8 bits channels */
	png_set_packing(png_ptr); /* 1,2,4 bits depth => 24/32 bits depth */
	if ( png_color_type == PNG_COLOR_TYPE_GRAY ) png_set_expand(png_ptr); /* grayscale => color */
	if ( png_color_type == PNG_COLOR_TYPE_GRAY_ALPHA ) png_set_gray_to_rgb(png_ptr);

	/* update the image information */
	png_read_update_info(png_ptr,info_ptr);
	png_get_IHDR(png_ptr,info_ptr,&png_width,&png_height,&png_bit_depth,&png_color_type,
		&png_interlace_type,NULL,NULL);

	/* create the SDL surface */
	bitmap=TCOD_sys_get_surface(png_width,png_height,info_ptr->channels == 4);

	/* get row data */
	row_pointers=(png_bytep *)malloc(sizeof(png_bytep)*png_height);
	for (y=0; y<  png_height; y++ ) {
		row_pointers[y]=(png_bytep)(Uint8 *)(bitmap->pixels) + y * bitmap->pitch;
	}

	/* read png data directly into the SDL surface */
	png_read_image(png_ptr,row_pointers);

	/* clean up after the read, and free any memory allocated - REQUIRED */
	png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL);
	free(row_pointers);

	/* close the file */
	fclose(fp);
	return bitmap;
}
PNGImage LoadImagePNG(const char *path)
{
	PNGImage loadedImage;
	loadedImage.loadedSuccessfully = GL_FALSE;
	
	FILE *PNG_file = fopen(path, "rb");
    if (PNG_file == NULL)
    {
        printf("Can't open PNG file %s\n", path);
        return loadedImage;
    }
    
    GLubyte PNG_header[PNG_HEADER_SIZE];
    
    fread(PNG_header, 1, PNG_HEADER_SIZE, PNG_file);
    if (png_sig_cmp(PNG_header, 0, PNG_HEADER_SIZE) != 0)
    {
        printf("%s is not a PNG file\n", path);
        return loadedImage;
    }
    
    png_structp PNG_reader
	= png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
    if (PNG_reader == NULL)
    {
        printf("Can't start reading PNG file %s\n", path);
        fclose(PNG_file);
        return loadedImage;
    }
	
    png_infop PNG_info = png_create_info_struct(PNG_reader);
    if (PNG_info == NULL)
    {
        printf("Can't get info for PNG file %s\n", path);
		
        png_destroy_read_struct(&PNG_reader, NULL, NULL);
        fclose(PNG_file);
        return loadedImage;
    }
	
    png_infop PNG_end_info = png_create_info_struct(PNG_reader);
    if (PNG_end_info == NULL)
    {
        printf("Can't get end info for PNG file %s\n", path);
		
        png_destroy_read_struct(&PNG_reader, &PNG_info, NULL);
        fclose(PNG_file);
        return loadedImage;
    }
    
    if (setjmp(png_jmpbuf(PNG_reader)))
    {
        printf("Can't load PNG file %s\n", path);
		
        png_destroy_read_struct(&PNG_reader, &PNG_info, &PNG_end_info);
        fclose(PNG_file);
        return loadedImage;
    }
    
    png_init_io(PNG_reader, PNG_file);
    png_set_sig_bytes(PNG_reader, PNG_HEADER_SIZE);
    
    png_read_info(PNG_reader, PNG_info);
	
	// we have to do a custom transformation to premultiply the alpha of the image
    png_set_read_user_transform_fn(PNG_reader, png_read_premultiply_alpha);
    
	png_uint_32 width, height;
    int bit_depth, color_type;
    
	png_get_IHDR(PNG_reader, PNG_info, &width, &height, &bit_depth, &color_type,NULL, NULL, NULL);
	
    if (color_type == PNG_COLOR_TYPE_PALETTE)
    {
        png_set_palette_to_rgb(PNG_reader);
    }
	
    if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) 
    {
        png_set_expand_gray_1_2_4_to_8(PNG_reader);
    }
    
    if (color_type == PNG_COLOR_TYPE_GRAY ||
        color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
    {
        png_set_gray_to_rgb(PNG_reader);
    }
	
    if (png_get_valid(PNG_reader, PNG_info, PNG_INFO_tRNS))
    {
        png_set_tRNS_to_alpha(PNG_reader);
    }
    else
    {
        png_set_filler(PNG_reader, 0xff, PNG_FILLER_AFTER);
    }
    

    if (bit_depth == 16)
    {
        png_set_strip_16(PNG_reader);
    }
	
    png_read_update_info(PNG_reader, PNG_info);
    
	png_uint_32 widthPow2, heightPow2;
	widthPow2 = pow2(width);
	heightPow2 = pow2(height);
	
    png_byte* PNG_image_buffer = (png_byte*)malloc(4 * widthPow2 * heightPow2);
	memset(PNG_image_buffer,0,4*widthPow2*heightPow2); // clear image buffer
    png_byte** PNG_rows = (png_byte**)malloc(height * sizeof(png_byte*));


	png_uint_32 rowBytes = widthPow2*4;

	// load the image from the bottom up
	/*
	 image texture in mem looks like:
	 --------
	 |       |
	 |xxxx	 |
	 |xxxx	 |
	 --------
	 where 'x's represent actual image data and the lines are the image buffer.
	 so the image is aligned at the (0,0) texel coordinate of the image buffer.
	 */
	unsigned int row;
    for (row = 0; row < height; ++row)
    {
        PNG_rows[height-1-row] = PNG_image_buffer + (row * rowBytes);
    }
    png_read_image(PNG_reader, PNG_rows);
	
    free(PNG_rows);
   
    png_destroy_read_struct(&PNG_reader, &PNG_info, &PNG_end_info);
    fclose(PNG_file);
    
	
	GLuint textureID = 0;
	glGenTextures(1, &textureID);
    glBindTexture(GL_TEXTURE_2D, textureID);
	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
	
	glTexImage2D(
				 GL_TEXTURE_2D,
				 0,
				 GL_RGBA,
				 widthPow2,
				 heightPow2,
				 0,
				 GL_RGBA,
				 GL_UNSIGNED_BYTE,
				 PNG_image_buffer);
    
     free(PNG_image_buffer);
	
	loadedImage.width = width;
	loadedImage.height = height;
	loadedImage.widthPow2 = widthPow2;
	loadedImage.heightPow2 = heightPow2;
	loadedImage.textureId = textureID;
	loadedImage.loadedSuccessfully = GL_TRUE;
	
    return loadedImage;
}
Exemple #28
0
Py::Object
_png_module::read_png(const Py::Tuple& args)
{

    args.verify_length(1);
    png_byte header[8];   // 8 is the maximum size that can be checked
    FILE* fp = NULL;
    bool close_file = false;

    Py::Object py_fileobj = Py::Object(args[0]);
#if PY_MAJOR_VERSION >= 3
    int fd = PyObject_AsFileDescriptor(py_fileobj.ptr());
    PyErr_Clear();
#endif

    if (py_fileobj.isString())
    {
        std::string fileName = Py::String(py_fileobj);
        const char *file_name = fileName.c_str();
        if ((fp = fopen(file_name, "rb")) == NULL)
        {
            throw Py::RuntimeError(
                Printf("Could not open file %s for reading", file_name).str());
        }
        close_file = true;
    }
#if PY_MAJOR_VERSION >= 3
    else if (fd != -1) {
        fp = fdopen(fd, "r");
    }
#else
    else if (PyFile_CheckExact(py_fileobj.ptr()))
    {
        fp = PyFile_AsFile(py_fileobj.ptr());
    }
#endif
    else
    {
        PyObject* read_method = PyObject_GetAttrString(py_fileobj.ptr(), "read");
        if (!(read_method && PyCallable_Check(read_method)))
        {
            Py_XDECREF(read_method);
            throw Py::TypeError("Object does not appear to be a 8-bit string path or a Python file-like object");
        }
        Py_XDECREF(read_method);
    }

    if (fp)
    {
        if (fread(header, 1, 8, fp) != 8)
        {
            throw Py::RuntimeError(
                "_image_module::readpng: error reading PNG header");
        }
    }
    else
    {
        _read_png_data(py_fileobj.ptr(), header, 8);
    }
    if (png_sig_cmp(header, 0, 8))
    {
        throw Py::RuntimeError(
            "_image_module::readpng: file not recognized as a PNG file");
    }

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

    if (!png_ptr)
    {
        throw Py::RuntimeError(
            "_image_module::readpng:  png_create_read_struct failed");
    }

    png_infop info_ptr = png_create_info_struct(png_ptr);
    if (!info_ptr)
    {
        throw Py::RuntimeError(
            "_image_module::readpng:  png_create_info_struct failed");
    }

    if (setjmp(png_jmpbuf(png_ptr)))
    {
        throw Py::RuntimeError(
            "_image_module::readpng:  error during init_io");
    }

    if (fp)
    {
        png_init_io(png_ptr, fp);
    }
    else
    {
        png_set_read_fn(png_ptr, (void*)py_fileobj.ptr(), &read_png_data);
    }
    png_set_sig_bytes(png_ptr, 8);
    png_read_info(png_ptr, info_ptr);

    png_uint_32 width = info_ptr->width;
    png_uint_32 height = info_ptr->height;

    int bit_depth = info_ptr->bit_depth;

    // Unpack 1, 2, and 4-bit images
    if (bit_depth < 8)
        png_set_packing(png_ptr);

    // If sig bits are set, shift data
    png_color_8p sig_bit;
    if ((info_ptr->color_type != PNG_COLOR_TYPE_PALETTE) &&
        png_get_sBIT(png_ptr, info_ptr, &sig_bit))
    {
        png_set_shift(png_ptr, sig_bit);
    }

    // Convert big endian to little
    if (bit_depth == 16)
    {
        png_set_swap(png_ptr);
    }

    // Convert palletes to full RGB
    if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
    {
        png_set_palette_to_rgb(png_ptr);
    }

    // If there's an alpha channel convert gray to RGB
    if (info_ptr->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
    {
        png_set_gray_to_rgb(png_ptr);
    }

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

    /* read file */
    if (setjmp(png_jmpbuf(png_ptr)))
    {
        throw Py::RuntimeError(
            "_image_module::readpng: error during read_image");
    }

    png_bytep *row_pointers = new png_bytep[height];
    png_uint_32 row;

    for (row = 0; row < height; row++)
    {
        row_pointers[row] = new png_byte[png_get_rowbytes(png_ptr,info_ptr)];
    }

    png_read_image(png_ptr, row_pointers);

    npy_intp dimensions[3];
    dimensions[0] = height;  //numrows
    dimensions[1] = width;   //numcols
    if (info_ptr->color_type & PNG_COLOR_MASK_ALPHA)
    {
        dimensions[2] = 4;     //RGBA images
    }
    else if (info_ptr->color_type & PNG_COLOR_MASK_COLOR)
    {
        dimensions[2] = 3;     //RGB images
    }
    else
    {
        dimensions[2] = 1;     //Greyscale images
    }
    //For gray, return an x by y array, not an x by y by 1
    int num_dims  = (info_ptr->color_type & PNG_COLOR_MASK_COLOR) ? 3 : 2;

    double max_value = (1 << ((bit_depth < 8) ? 8 : bit_depth)) - 1;
    PyArrayObject *A = (PyArrayObject *) PyArray_SimpleNew(
        num_dims, dimensions, PyArray_FLOAT);

    if (A == NULL)
    {
        throw Py::MemoryError("Could not allocate image array");
    }

    for (png_uint_32 y = 0; y < height; y++)
    {
        png_byte* row = row_pointers[y];
        for (png_uint_32 x = 0; x < width; x++)
        {
            size_t offset = y * A->strides[0] + x * A->strides[1];
            if (bit_depth == 16)
            {
                png_uint_16* ptr = &reinterpret_cast<png_uint_16*>(row)[x * dimensions[2]];
                for (png_uint_32 p = 0; p < (png_uint_32)dimensions[2]; p++)
                {
                    *(float*)(A->data + offset + p*A->strides[2]) = (float)(ptr[p]) / max_value;
                }
            }
            else
            {
                png_byte* ptr = &(row[x * dimensions[2]]);
                for (png_uint_32 p = 0; p < (png_uint_32)dimensions[2]; p++)
                {
                    *(float*)(A->data + offset + p*A->strides[2]) = (float)(ptr[p]) / max_value;
                }
            }
        }
    }

    //free the png memory
    png_read_end(png_ptr, info_ptr);
#ifndef png_infopp_NULL
    png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
#else
    png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL);
#endif
    if (close_file)
    {
        fclose(fp);
    }
    for (row = 0; row < height; row++)
    {
        delete [] row_pointers[row];
    }
    delete [] row_pointers;
    return Py::asObject((PyObject*)A);
}
/****************************************************************************
 * DecodeBlock: the whole thing
 ****************************************************************************
 * This function must be fed with a complete compressed frame.
 ****************************************************************************/
static picture_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
{
    decoder_sys_t *p_sys = p_dec->p_sys;
    block_t *p_block;
    picture_t *p_pic = 0;

    png_uint_32 i_width, i_height;
    int i_color_type, i_interlace_type, i_compression_type, i_filter_type;
    int i_bit_depth, i;

    png_structp p_png;
    png_infop p_info, p_end_info;
    png_bytep *p_row_pointers = NULL;

    if( !pp_block || !*pp_block ) return NULL;

    p_block = *pp_block;
    p_sys->b_error = false;

    if( p_block->i_flags & BLOCK_FLAG_DISCONTINUITY )
    {
        block_Release( p_block ); *pp_block = NULL;
        return NULL;
    }

    p_png = png_create_read_struct( PNG_LIBPNG_VER_STRING, 0, 0, 0 );
    if( p_png == NULL )
    {
        block_Release( p_block ); *pp_block = NULL;
        return NULL;
    }

    p_info = png_create_info_struct( p_png );
    if( p_info == NULL )
    {
        png_destroy_read_struct( &p_png, NULL, NULL );
        block_Release( p_block ); *pp_block = NULL;
        return NULL;
    }

    p_end_info = png_create_info_struct( p_png );
    if( p_end_info == NULL )
    {
        png_destroy_read_struct( &p_png, &p_info, NULL );
        block_Release( p_block ); *pp_block = NULL;
        return NULL;
    }

    /* libpng longjmp's there in case of error */
    if( setjmp( png_jmpbuf( p_png ) ) )
        goto error;

    png_set_read_fn( p_png, (void *)p_block, user_read );
    png_set_error_fn( p_png, (void *)p_dec, user_error, user_warning );

    png_read_info( p_png, p_info );
    if( p_sys->b_error ) goto error;

    png_get_IHDR( p_png, p_info, &i_width, &i_height,
                  &i_bit_depth, &i_color_type, &i_interlace_type,
                  &i_compression_type, &i_filter_type);
    if( p_sys->b_error ) goto error;

    /* Set output properties */
    p_dec->fmt_out.i_codec = VLC_CODEC_RGBA;
    p_dec->fmt_out.video.i_width = i_width;
    p_dec->fmt_out.video.i_height = i_height;
    p_dec->fmt_out.video.i_sar_num = 1;
    p_dec->fmt_out.video.i_sar_den = 1;
    p_dec->fmt_out.video.i_rmask = 0x000000ff;
    p_dec->fmt_out.video.i_gmask = 0x0000ff00;
    p_dec->fmt_out.video.i_bmask = 0x00ff0000;

    if( i_color_type == PNG_COLOR_TYPE_PALETTE )
        png_set_palette_to_rgb( p_png );

    if( i_color_type == PNG_COLOR_TYPE_GRAY ||
        i_color_type == PNG_COLOR_TYPE_GRAY_ALPHA )
          png_set_gray_to_rgb( p_png );

    /* Strip to 8 bits per channel */
    if( i_bit_depth == 16 ) png_set_strip_16( p_png );

    if( png_get_valid( p_png, p_info, PNG_INFO_tRNS ) )
    {
        png_set_tRNS_to_alpha( p_png );
    }
    else if( !(i_color_type & PNG_COLOR_MASK_ALPHA) )
    {
        p_dec->fmt_out.i_codec = VLC_CODEC_RGB24;
    }

    /* Get a new picture */
    p_pic = decoder_NewPicture( p_dec );
    if( !p_pic ) goto error;

    /* Decode picture */
    p_row_pointers = malloc( sizeof(png_bytep) * i_height );
    if( !p_row_pointers )
        goto error;
    for( i = 0; i < (int)i_height; i++ )
        p_row_pointers[i] = p_pic->p->p_pixels + p_pic->p->i_pitch * i;

    png_read_image( p_png, p_row_pointers );
    if( p_sys->b_error ) goto error;
    png_read_end( p_png, p_end_info );
    if( p_sys->b_error ) goto error;

    png_destroy_read_struct( &p_png, &p_info, &p_end_info );
    free( p_row_pointers );

    p_pic->date = p_block->i_pts > VLC_TS_INVALID ? p_block->i_pts : p_block->i_dts;

    block_Release( p_block ); *pp_block = NULL;
    return p_pic;

 error:

    free( p_row_pointers );
    png_destroy_read_struct( &p_png, &p_info, &p_end_info );
    block_Release( p_block ); *pp_block = NULL;
    return NULL;
}
Exemple #30
0
static gboolean
setup_png_transformations(png_structp png_read_ptr, png_infop png_info_ptr,
                          GError **error,
                          png_uint_32* width_p, png_uint_32* height_p,
                          int* color_type_p)
{
        png_uint_32 width, height;
        int bit_depth, color_type, interlace_type, compression_type, filter_type;
        int channels;
        
        /* Get the image info */

        /* Must check bit depth, since png_get_IHDR generates an 
           FPE on bit_depth 0.
        */
        bit_depth = png_get_bit_depth (png_read_ptr, png_info_ptr);
        if (bit_depth < 1 || bit_depth > 16) {
                g_set_error_literal (error,
                                     GDK_PIXBUF_ERROR,
                                     GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
                                     _("Bits per channel of PNG image is invalid."));
                return FALSE;
        }
        png_get_IHDR (png_read_ptr, png_info_ptr,
                      &width, &height,
                      &bit_depth,
                      &color_type,
                      &interlace_type,
                      &compression_type,
                      &filter_type);

        /* set_expand() basically needs to be called unless
           we are already in RGB/RGBA mode
        */
        if (color_type == PNG_COLOR_TYPE_PALETTE &&
            bit_depth <= 8) {

                /* Convert indexed images to RGB */
                png_set_expand (png_read_ptr);

        } else if (color_type == PNG_COLOR_TYPE_GRAY &&
                   bit_depth < 8) {

                /* Convert grayscale to RGB */
                png_set_expand (png_read_ptr);

        } else if (png_get_valid (png_read_ptr, 
                                  png_info_ptr, PNG_INFO_tRNS)) {

                /* If we have transparency header, convert it to alpha
                   channel */
                png_set_expand(png_read_ptr);
                
        } else if (bit_depth < 8) {

                /* If we have < 8 scale it up to 8 */
                png_set_expand(png_read_ptr);


                /* Conceivably, png_set_packing() is a better idea;
                 * God only knows how libpng works
                 */
        }

        /* If we are 16-bit, convert to 8-bit */
        if (bit_depth == 16) {
                png_set_strip_16(png_read_ptr);
        }

        /* If gray scale, convert to RGB */
        if (color_type == PNG_COLOR_TYPE_GRAY ||
            color_type == PNG_COLOR_TYPE_GRAY_ALPHA) {
                png_set_gray_to_rgb(png_read_ptr);
        }
        
        /* If interlaced, handle that */
        if (interlace_type != PNG_INTERLACE_NONE) {
                png_set_interlace_handling(png_read_ptr);
        }
        
        /* Update the info the reflect our transformations */
        png_read_update_info(png_read_ptr, png_info_ptr);
        
        png_get_IHDR (png_read_ptr, png_info_ptr,
                      &width, &height,
                      &bit_depth,
                      &color_type,
                      &interlace_type,
                      &compression_type,
                      &filter_type);

        *width_p = width;
        *height_p = height;
        *color_type_p = color_type;
        
        /* Check that the new info is what we want */
        
        if (width == 0 || height == 0) {
                g_set_error_literal (error,
                                     GDK_PIXBUF_ERROR,
                                     GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
                                     _("Transformed PNG has zero width or height."));
                return FALSE;
        }

        if (bit_depth != 8) {
                g_set_error_literal (error,
                                     GDK_PIXBUF_ERROR,
                                     GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
                                     _("Bits per channel of transformed PNG is not 8."));
                return FALSE;
        }

        if ( ! (color_type == PNG_COLOR_TYPE_RGB ||
                color_type == PNG_COLOR_TYPE_RGB_ALPHA) ) {
                g_set_error_literal (error,
                                     GDK_PIXBUF_ERROR,
                                     GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
                                     _("Transformed PNG not RGB or RGBA."));
                return FALSE;
        }

        channels = png_get_channels(png_read_ptr, png_info_ptr);
        if ( ! (channels == 3 || channels == 4) ) {
                g_set_error_literal (error,
                                     GDK_PIXBUF_ERROR,
                                     GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
                                     _("Transformed PNG has unsupported number of channels, must be 3 or 4."));
                return FALSE;
        }
        return TRUE;
}