Exemplo n.º 1
0
    void set_add_alpha(uint_32 filler, filler_type type) const
    {
        TRACE_IO_TRANSFORM("png_set_add_alpha: filler=%08x, type=%d\n",
                           filler, type);

        png_set_add_alpha(m_png, filler, type);
    }
Exemplo n.º 2
0
bool PNGImageReader::decode() {
    try {
        // From http://trac.mapnik.org/browser/trunk/src/png_reader.cpp
        if (color == PNG_COLOR_TYPE_PALETTE)
            png_set_expand(png);
        if (color == PNG_COLOR_TYPE_GRAY)
            png_set_expand(png);
        if (png_get_valid(png, info, PNG_INFO_tRNS))
            png_set_expand(png);
        if (depth == 16)
            png_set_strip_16(png);
        if (depth < 8)
            png_set_packing(png);
        if (color == PNG_COLOR_TYPE_GRAY ||
                color == PNG_COLOR_TYPE_GRAY_ALPHA)
            png_set_gray_to_rgb(png);

        if (interlace == PNG_INTERLACE_ADAM7)
            png_set_interlace_handling(png);

        // Always add an alpha channel.
        if (!this->alpha) {
            png_set_add_alpha(png, 0xFF, PNG_FILLER_AFTER);
        }

        double gamma;
        if (png_get_gAMA(png, info, &gamma))
            png_set_gamma(png, 2.2, gamma);

        png_read_update_info(png, info);

        unsigned int rowbytes = png_get_rowbytes(png, info);
        assert(width * 4 == rowbytes);

        surface = (unsigned int*)malloc(width * height * 4);
        assert(surface);

        png_bytep row_pointers[height];
        for (unsigned i = 0; i < height; i++) {
            row_pointers[i] = (unsigned char *)surface + (i * rowbytes);
        }

        // Read image data
        png_read_image(png, row_pointers);

        png_read_end(png, NULL);

        return true;
    } catch (std::exception& e) {
        png_destroy_read_struct(&png, &info, NULL);
        width = 0;
        height = 0;
        if (surface) free(surface);
        surface = NULL;

        return false;
    }
}
Exemplo n.º 3
0
//
// Load a texture from a png image
//
bool PngLoader::loadImageIntoBuffer() {
	DEBUG_ENTER_FUNC();

	if (!basicImageLoad()) {
		png_destroy_read_struct(&_pngPtr, &_infoPtr, png_infopp_NULL);
		return false;
	}
	png_set_strip_16(_pngPtr);		// Strip off 16 bit channels in case they occur

	if (_paletteSize) {
		// Copy the palette
		png_colorp srcPal = _infoPtr->palette;
		for (int i = 0; i < _infoPtr->num_palette; i++) {
			unsigned char alphaVal = (i < _infoPtr->num_trans) ? _infoPtr->trans[i] : 0xFF;	// Load alpha if it's there
			_palette->setSingleColorRGBA(i, srcPal->red, srcPal->green, srcPal->blue, alphaVal);
			srcPal++;
		}
	} else {	// Not a palettized image
		if (_colorType == PNG_COLOR_TYPE_GRAY && _bitDepth < 8)
			png_set_gray_1_2_4_to_8(_pngPtr);	// Round up grayscale images
		if (png_get_valid(_pngPtr, _infoPtr, PNG_INFO_tRNS))
			png_set_tRNS_to_alpha(_pngPtr);		// Convert trans channel to alpha for 32 bits

		png_set_add_alpha(_pngPtr, 0xff, PNG_FILLER_AFTER);		// Filler for alpha if none exists
	}

	uint32 rowBytes = png_get_rowbytes(_pngPtr, _infoPtr);

	// there seems to be a bug in libpng where it doesn't increase the rowbytes or the
	// channel even after we add the alpha channel
	if (_channels == 3 && (rowBytes / _width) == 3) {
		_channels = 4;
		rowBytes = _width * _channels;
	}

	PSP_DEBUG_PRINT("rowBytes[%d], channels[%d]\n", rowBytes, _channels);

	unsigned char *line = (unsigned char*) malloc(rowBytes);
	if (!line) {
		png_destroy_read_struct(&_pngPtr, png_infopp_NULL, png_infopp_NULL);
		PSP_ERROR("Couldn't allocate line\n");
		return false;
	}

	for (size_t y = 0; y < _height; y++) {
		png_read_row(_pngPtr, line, png_bytep_NULL);
		_buffer->copyFromRect(line, rowBytes, 0, y, _width, 1);	// Copy into buffer
	}
	free(line);
	png_read_end(_pngPtr, _infoPtr);
	png_destroy_read_struct(&_pngPtr, &_infoPtr, png_infopp_NULL);

	return true;
}
Exemplo n.º 4
0
/*
 * @brief process IHDR data
 * @note not called until the IDAT chunk starts processing
 */
void apng_ani::info_callback()
{
	png_set_expand(_pngp);
	png_set_strip_16(_pngp);
	png_set_gray_to_rgb(_pngp); // what about 'non-colour' headanis?
	png_set_add_alpha(_pngp, 0xff, PNG_FILLER_AFTER); // doesn't affect images that already have alpha channel
	png_set_interlace_handling(_pngp);
	png_set_bgr(_pngp);

	png_read_update_info(_pngp, _infop);
}
Exemplo n.º 5
0
static PngInfo read_and_update_info(const png_structp png_ptr, const png_infop info_ptr)
{
	png_uint_32 width, height;
	int bit_depth, color_type;

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

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

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

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

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

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

	png_read_update_info(png_ptr, info_ptr);

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

	return (PngInfo) {width, height, color_type};
}
Exemplo n.º 6
0
void setformat_rgba8(
    png_structp png, png_infop info,
    int bitdepth, int colortype )
{
    double gamma;
    if( png_get_gAMA( png, info, &gamma ) )
    {
        png_set_gamma( png, 2.2, gamma );
    }
    else
    {
        png_set_gamma( png, 2.2, 0.45455 );
    }
    if( colortype == PNG_COLOR_TYPE_PALETTE )
    {
        png_set_palette_to_rgb( png );
    }
    if( colortype == PNG_COLOR_TYPE_GRAY && bitdepth < 8 )
    {
        png_set_expand_gray_1_2_4_to_8( png );
    }
    if( png_get_valid( png, info, PNG_INFO_tRNS ) )
    {
        png_set_tRNS_to_alpha( png );
    }
    else
    {
        int channels = png_get_channels( png, info );
        if( channels == 1 || channels == 3 )
        {
            png_set_add_alpha( png, 255, PNG_FILLER_AFTER );
        }
    }
    if( colortype == PNG_COLOR_TYPE_GRAY ||
            colortype == PNG_COLOR_TYPE_GRAY_ALPHA )
    {
        png_set_gray_to_rgb( png );
    }
    if( bitdepth == 16 )
    {
        png_set_scale_16( png );
    }
}
Exemplo n.º 7
0
bool loadParallax (unsigned short v, unsigned short fracX, unsigned short fracY) {
	setResourceForFatal (v);
	if (! openFileFromNum (v)) return fatal ("Can't open parallax image");

	parallaxLayer * nP = new parallaxLayer;
	if (! checkNew (nP)) return false;

	nP -> next = parallaxStuff;
	parallaxStuff = nP;
	if (nP -> next) {
		nP -> next -> prev = nP;
	}
	nP -> prev = NULL;

	int picWidth;
	int picHeight;

	long file_pointer = ftell (bigDataFile);

	png_structp png_ptr;
	png_infop info_ptr, end_info;


	int fileIsPNG = true;

	// Is this a PNG file?

	char tmp[10];
	size_t bytes_read = fread(tmp, 1, 8, bigDataFile);
	if (bytes_read != 8 && ferror (bigDataFile)) {
		debugOut("Reading error in loadParallax.\n");
	}
    if (png_sig_cmp((png_byte *) tmp, 0, 8)) {
		// No, it's old-school HSI
		fileIsPNG = false;
		fseek(bigDataFile, file_pointer, SEEK_SET);

		picWidth = nP -> width = get2bytes (bigDataFile);
		picHeight = nP -> height = get2bytes (bigDataFile);
	} else {
		// Read the PNG header

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

		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;
		}

		end_info = png_create_info_struct(png_ptr);
		if (!end_info) {
			png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
			return false;
		}
		png_init_io(png_ptr, bigDataFile);		// 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);

		picWidth = nP -> width = width;
		picHeight = nP -> height = height;

		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);

	}

	if (! NPOT_textures) {
		picWidth = getNextPOT(picWidth);
		picHeight = getNextPOT(picHeight);
	}

	nP -> fileNum = v;
	nP -> fractionX = fracX;
	nP -> fractionY = fracY;

	if (fracX == 65535) {
		nP -> wrapS = false;
		if (nP -> width < winWidth) {
			fatal ("For AUTOFIT parallax backgrounds, the image must be at least as wide as the game window/screen.");
			return false;
		}
	} else {
		nP -> wrapS = true;
	}

	if (fracY == 65535) {
		nP -> wrapT = false;
		if (nP -> height < winHeight) {
			fatal ("For AUTOFIT parallax backgrounds, the image must be at least as tall as the game window/screen.");
			return false;
		}
	} else {
		nP -> wrapT = true;
	}

	nP -> texture = new GLubyte [picHeight * picWidth * 4];
	if (! checkNew (nP -> texture)) return false;

	if (fileIsPNG) {
		unsigned char * row_pointers[nP -> height];
		for (int i = 0; i < nP -> height; i++)
			row_pointers[i] = nP -> texture + 4*i*picWidth;

		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);
	} else {

		int t1, t2, n;
		unsigned short c;
		GLubyte * target;

		for (t2 = 0; t2 < nP -> height; t2 ++) {
			t1 = 0;
			while (t1 < nP -> width) {
				c = (unsigned short) get2bytes (bigDataFile);
				if (c & 32) {
					n = fgetc (bigDataFile) + 1;
					c -= 32;
				} else {
					n = 1;
				}
				while (n--) {
					target = nP -> texture + 4*picWidth*t2 + t1*4;
					if (c == 63519 || c == 2015) {
						target[0] = (GLubyte) 0;
						target[1] = (GLubyte) 0;
						target[2] = (GLubyte) 0;
						target[3] = (GLubyte) 0;
					} else {
						target[0] = (GLubyte) redValue(c);
						target[1] = (GLubyte) greenValue(c);
						target[2] = (GLubyte) blueValue(c);
						target[3] = (GLubyte) 255;
					}
					t1 ++;
				}
			}
		}
	}

	glGenTextures (1, &nP->textureName);
	glBindTexture (GL_TEXTURE_2D, nP->textureName);
	if (nP -> wrapS)
		glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
	else
		glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
	if (nP -> wrapT)
		glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
	else
		glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

	if (gameSettings.antiAlias < 0) {
		glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
		glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
	} else {
		glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
		glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
	}

	texImage2D (GL_TEXTURE_2D, 0, GL_RGBA, picWidth, picHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, nP->texture, nP->textureName);

	finishAccess ();
	setResourceForFatal (-1);
	return true;
}
Exemplo n.º 8
0
bool loadLightMap (int v) {
	int newPicWidth, newPicHeight;

	setResourceForFatal (v);
	if (! openFileFromNum (v)) return fatal ("Can't open light map.");

	long file_pointer = ftell (bigDataFile);

	png_structp png_ptr;
	png_infop info_ptr, end_info;


	int fileIsPNG = true;

	// Is this a PNG file?

	char tmp[10];
	size_t bytes_read = fread(tmp, 1, 8, bigDataFile);
	if (bytes_read != 8 && ferror (bigDataFile)) {
		debugOut("Reading error in loadLightMap.\n");
	}

    if (png_sig_cmp((png_byte *) tmp, 0, 8)) {
		// No, it's old-school HSI
		fileIsPNG = false;
		fseek(bigDataFile, file_pointer, SEEK_SET);

		newPicWidth = lightMap.w = get2bytes (bigDataFile);
		newPicHeight = lightMap.h = get2bytes (bigDataFile);
	} else {
		// Read the PNG header

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

		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;
		}

		end_info = png_create_info_struct(png_ptr);
		if (!end_info) {
			png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
			return false;
		}
		png_init_io(png_ptr, bigDataFile);		// 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);

		newPicWidth = lightMap.w = width;
		newPicHeight = lightMap.h = height;

		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);

	}

	if (lightMapMode == LIGHTMAPMODE_HOTSPOT) {
		if (lightMap.w != sceneWidth || lightMap.h != sceneHeight) {
			return fatal ("Light map width and height don't match scene width and height. That is required for lightmaps in HOTSPOT mode.");
		}
	}

	if (! NPOT_textures) {
		newPicWidth = getNextPOT(lightMap.w);
		newPicHeight = getNextPOT(lightMap.h);
		lightMap.texW = (double) lightMap.w / newPicWidth;
		lightMap.texH = (double) lightMap.h / newPicHeight;
	} else {
		lightMap.texW = 1.0;
		lightMap.texH = 1.0;
	}

	killLightMap ();
	lightMapNumber = v;

	glPixelStorei (GL_UNPACK_ALIGNMENT, 1);

	if (lightMap.data) delete [] lightMap.data;

	lightMap.data = new GLubyte [newPicWidth*newPicHeight*4];
	if (! lightMap.data) {
		return fatal ("Out of memory loading light map.");
	}

	int t1, t2, n;
	unsigned short c;
	GLubyte * target;

	if (fileIsPNG) {
		unsigned char * row_pointers[lightMap.h];
		for (int i = 0; i<lightMap.h; i++)
			row_pointers[i] = lightMap.data + 4*i*newPicWidth;

		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);
	} else {

		for (t2 = 0; t2 < lightMap.h; t2 ++) {
			t1 = 0;
			while (t1 < lightMap.w) {
				c = (unsigned short) get2bytes (bigDataFile);
				if (c & 32) {
					n = fgetc (bigDataFile) + 1;
					c -= 32;
				} else {
					n = 1;
				}
				while (n --) {
					target = lightMap.data + 4*newPicWidth*t2 + t1*4;
					target[0] = (GLubyte) redValue(c);
					target[1] = (GLubyte) greenValue(c);
					target[2] = (GLubyte) blueValue(c);
					target[3] = (GLubyte) 255;
					t1++;
				}
			}
		}
	}

	if (! lightMap.name) glGenTextures (1, &lightMap.name);
	glBindTexture(GL_TEXTURE_2D, lightMap.name);
	glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
	glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
	glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
	glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
	texImage2D (GL_TEXTURE_2D, 0, GL_RGBA, newPicWidth, newPicHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, lightMap.data, lightMap.name);

	finishAccess ();
	setResourceForFatal (-1);

	return true;
}
Exemplo n.º 9
0
bool MCImageDecodePNG(IO_handle p_stream, MCImageBitmap *&r_bitmap)
{
	bool t_success = true;

	MCImageBitmap *t_bitmap = nil;

	png_structp t_png = nil;
	png_infop t_info = nil;
	png_infop t_end_info = nil;

	t_success = nil != (t_png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL));

	if (t_success)
		t_success = nil != (t_info = png_create_info_struct(t_png));

	if (t_success)
		t_success = nil != (t_end_info = png_create_info_struct(t_png));

	if (setjmp(png_jmpbuf(t_png)))
	{
		t_success = false;
	}

	if (t_success)
	{
		png_set_read_fn(t_png, p_stream, stream_read);
		png_read_info(t_png, t_info);
	}

	png_uint_32 t_width, t_height;
	int t_bit_depth, t_color_type;
	int t_interlace_method, t_compression_method, t_filter_method;
	int t_interlace_passes;

	if (t_success)
	{
		png_get_IHDR(t_png, t_info, &t_width, &t_height,
			&t_bit_depth, &t_color_type,
			&t_interlace_method, &t_compression_method, &t_filter_method);
	}

	if (t_success)
		t_success = MCImageBitmapCreate(t_width, t_height, t_bitmap);
	
	if (t_success)
	{
		bool t_need_alpha = false;

		t_interlace_passes = png_set_interlace_handling(t_png);

		if (t_color_type == PNG_COLOR_TYPE_PALETTE)
			png_set_palette_to_rgb(t_png);
		if (t_color_type == PNG_COLOR_TYPE_GRAY || t_color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
			png_set_gray_to_rgb(t_png);

		if (png_get_valid(t_png, t_info, PNG_INFO_tRNS))
		{
			png_set_tRNS_to_alpha(t_png);
			t_need_alpha = true;
			/* OVERHAUL - REVISIT - assume image has transparent pixels if tRNS is present */
			t_bitmap->has_transparency = true;
		}

		if (t_color_type & PNG_COLOR_MASK_ALPHA)
		{
			t_need_alpha = true;
			/* OVERHAUL - REVISIT - assume image has alpha if color type allows it */
			t_bitmap->has_alpha = t_bitmap->has_transparency = true;
		}
		else if (!t_need_alpha)
			png_set_add_alpha(t_png, 0xFF, MCswapbytes ? PNG_FILLER_AFTER : PNG_FILLER_BEFORE);

		if (t_bit_depth == 16)
			png_set_strip_16(t_png);

		if (MCswapbytes)
			png_set_bgr(t_png);
		else
			png_set_swap_alpha(t_png);
	}

	// MW-2009-12-10: Support for color profiles
	MCColorTransformRef t_color_xform;
	t_color_xform = nil;

	// Try to get an embedded ICC profile...
	if (t_success && t_color_xform == nil && png_get_valid(t_png, t_info, PNG_INFO_iCCP))
	{
		png_charp t_ccp_name;
		png_bytep t_ccp_profile;
		int t_ccp_compression_type;
		png_uint_32 t_ccp_profile_length;
		png_get_iCCP(t_png, t_info, &t_ccp_name, &t_ccp_compression_type, &t_ccp_profile, &t_ccp_profile_length);
		
		MCColorSpaceInfo t_csinfo;
		t_csinfo . type = kMCColorSpaceEmbedded;
		t_csinfo . embedded . data = t_ccp_profile;
		t_csinfo . embedded . data_size = t_ccp_profile_length;
		t_color_xform = MCscreen -> createcolortransform(t_csinfo);
	}

	// Next try an sRGB style profile...
	if (t_success && t_color_xform == nil && png_get_valid(t_png, t_info, PNG_INFO_sRGB))
	{
		int t_intent;
		png_get_sRGB(t_png, t_info, &t_intent);

		MCColorSpaceInfo t_csinfo;
		t_csinfo . type = kMCColorSpaceStandardRGB;
		t_csinfo . standard . intent = (MCColorSpaceIntent)t_intent;
		t_color_xform = MCscreen -> createcolortransform(t_csinfo);
	}

	// Finally try for cHRM + gAMA...
	if (t_success && t_color_xform == nil && png_get_valid(t_png, t_info, PNG_INFO_cHRM) &&
		png_get_valid(t_png, t_info, PNG_INFO_gAMA))
	{
		MCColorSpaceInfo t_csinfo;
		t_csinfo . type = kMCColorSpaceCalibratedRGB;
		png_get_cHRM(t_png, t_info,
				&t_csinfo . calibrated . white_x, &t_csinfo . calibrated . white_y,
				&t_csinfo . calibrated . red_x, &t_csinfo . calibrated . red_y,
				&t_csinfo . calibrated . green_x, &t_csinfo . calibrated . green_y,
				&t_csinfo . calibrated . blue_x, &t_csinfo . calibrated . blue_y);
		png_get_gAMA(t_png, t_info, &t_csinfo . calibrated . gamma);
		t_color_xform = MCscreen -> createcolortransform(t_csinfo);
	}

	// Could not create any kind, so fallback to gamma transform.
	if (t_success && t_color_xform == nil)
	{
		double image_gamma;
		if (png_get_gAMA(t_png, t_info, &image_gamma))
			png_set_gamma(t_png, MCgamma, image_gamma);
		else
			png_set_gamma(t_png, MCgamma, 0.45);
	}
	
	if (t_success)
	{
		for (uindex_t t_pass = 0; t_pass < t_interlace_passes; t_pass++)
		{
			png_bytep t_data_ptr = (png_bytep)t_bitmap->data;
			for (uindex_t i = 0; i < t_height; i++)
			{
				png_read_row(t_png, t_data_ptr, nil);
				t_data_ptr += t_bitmap->stride;
			}
		}
	}

	if (t_success)
		png_read_end(t_png, t_end_info);

	if (t_png != nil)
		png_destroy_read_struct(&t_png, &t_info, &t_end_info);

	// transform colours using extracted colour profile
	if (t_success && t_color_xform != nil)
		MCImageBitmapApplyColorTransform(t_bitmap,  t_color_xform);

	if (t_color_xform != nil)
		MCscreen -> destroycolortransform(t_color_xform);

	if (t_success)
		r_bitmap = t_bitmap;
	else
	{
		if (t_bitmap != nil)
			MCImageFreeBitmap(t_bitmap);
	}

	return t_success;
}
Exemplo n.º 10
0
/*
=================
image_png_load
=================
*/
GNUC_NONNULL static erbool image_png_load (const char *name, image_t *im)
{
    fs_file_t   f;
    int         size, r, width, height, inc;
    png_byte   *image = NULL, *p = NULL;
    png_structp pngst;
    png_infop   info = NULL;
    png_byte    depth, color_type;

    if (NULL == (f = fs_open(name, FS_RDONLY, &size, false)))
        return false;

    if (NULL == (pngst = png_create_read_struct(PNG_LIBPNG_VER_STRING,
                                                NULL,
                                                &epng_error,
                                                &epng_warn)))
    {
        sys_printf("failed to create png read struct\n");
        fs_close(f);
        return false;
    }

    if (NULL == (info = png_create_info_struct(pngst)))
    {
        sys_printf("failed to create png info struct\n");
        goto error;
    }

    if (setjmp(png_jmpbuf(pngst)))
        goto error;

    png_set_user_limits(pngst, IMAGE_MAX_WIDTH, IMAGE_MAX_HEIGHT);
    png_set_read_fn(pngst, f, &epng_read);
    png_read_info(pngst, info);

    width  = png_get_image_width(pngst, info);
    height = png_get_image_height(pngst, info);
    depth  = png_get_bit_depth(pngst, info);

    if (16 == depth)
    {
        /* 16 -> 8 */
        png_set_strip_16(pngst);
        depth = 8;
    }

    color_type = png_get_color_type(pngst, info);

    /* 1/2/4 gray -> 8 gray */
    if (PNG_COLOR_TYPE_GRAY == color_type && depth < 8)
        png_set_expand_gray_1_2_4_to_8(pngst);

    /* gray/palette -> rgb */
    if (PNG_COLOR_TYPE_GRAY == color_type || PNG_COLOR_TYPE_GRAY_ALPHA == color_type)
        png_set_gray_to_rgb(pngst);
    else if (PNG_COLOR_TYPE_PALETTE)
        png_set_palette_to_rgb(pngst);

    /* transparency -> alpha */
    if (png_get_valid(pngst, info, PNG_INFO_tRNS))
    {
        png_set_tRNS_to_alpha(pngst);
    }
    else
    {
        /* to rgba */
        if (PNG_COLOR_TYPE_RGB_ALPHA != color_type &&
            PNG_COLOR_TYPE_GRAY_ALPHA != color_type)
            png_set_add_alpha(pngst, 0xff, PNG_FILLER_AFTER);
    }

    /* deinterlace */
    png_set_interlace_handling(pngst);

    /* read */
    inc = width * 4;

    p = image = mem_alloc(image_mempool, height * inc);

    for (r = 0; r < height ;r++, p += inc)
        png_read_row(pngst, p, NULL);

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

    fs_close(f);

    im->width  = width;
    im->height = height;
    im->data   = image;

    return true;

error:
    if (NULL != f)
        fs_close(f);

    png_destroy_read_struct(&pngst, NULL != info ? &info : NULL, NULL);

    if (NULL != image)
        mem_free(image);

    return false;
}
Exemplo n.º 11
0
static int VS_CC read_png(img_hnd_t *ih, int n)
{
    FILE *fp = imgr_fopen(ih->src[n].name);
    if (!fp) {
        return -1;
    }

    png_structp p_str =
        png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
    if (!p_str) {
        fclose(fp);
        return -1;
    }

    png_infop p_info = png_create_info_struct(p_str);
    if (!p_info) {
        fclose(fp);
        png_destroy_read_struct(&p_str, NULL, NULL);
        return -1;
    }

    png_init_io(p_str, fp);
    png_read_info(p_str, p_info);

    png_uint_32 width, height;
    int color_type, bit_depth;
    png_get_IHDR(p_str, p_info, &width, &height, &bit_depth, &color_type,
                 NULL, NULL, NULL);
    if (color_type & PNG_COLOR_TYPE_PALETTE) {
        png_set_palette_to_rgb(p_str);
    }
    if (bit_depth < 8) {
        png_set_packing(p_str);
    }
    if (bit_depth > 8) {
        png_set_swap(p_str);
    }
    if (ih->enable_alpha == 0) {
        if (color_type & PNG_COLOR_MASK_ALPHA) {
            png_set_strip_alpha(p_str);
        }
    } else if ((color_type & PNG_COLOR_MASK_ALPHA) == 0) {
        png_set_add_alpha(p_str, 0x00, PNG_FILLER_AFTER);
    }
    png_read_update_info(p_str, p_info);
    png_read_image(p_str, ih->png_row_index);

    fclose(fp);
    png_destroy_read_struct(&p_str, &p_info, NULL);

    ih->misc = IMG_ORDER_RGB;
    ih->row_adjust = 1;

    switch ((ih->src[n].format->id << 1) | ih->enable_alpha) {
    case (pfRGB24 << 1 | 0):
        ih->write_frame = func_write_rgb24;
        break;
    case (pfRGB24 << 1 | 1):
        ih->write_frame = func_write_rgb32;
        break;
    case (pfRGB48 << 1 | 0):
        ih->write_frame = func_write_rgb48;
        break;
    case (pfRGB48 << 1 | 1):
        ih->write_frame = func_write_rgb64;
        break;
    case (pfGray8 << 1 | 0):
    case (pfGray16 << 1 | 0):
        ih->write_frame = func_write_planar;
        break;
    case (pfGray8 << 1 | 1):
        ih->write_frame = func_write_gray8_a;
        break;
    case (pfGray16 << 1 | 1):
        ih->write_frame = func_write_gray16_a;
        break;
    default:
        break;
    }

    return 0;
}
Exemplo n.º 12
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;
}
Exemplo n.º 13
0
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;
}
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;
}
SDL_Surface* LoadPng(const char* Filename){ // Loads to a software image
	//Prepare the guards - prepare here so all are called by lngjmp
	FileGuard guardfin;
	PngGuard guardPng;
	SurfaceGuard guardRetVal;

	//Open the file
	FILE *fin;
	if(!GLOBAL_ZipFile.IsOpen()){
		fin = fopen(Filename, "rb");
		guardfin.GuardFile(fin);
		if (!fin)
			return 0;
	}
	//Verify the header
	{
		png_byte Header[8];
		if(GLOBAL_ZipFile.IsOpen()){
			if(GLOBAL_ZipFile.ReadSomeStart(Filename,Header,8) != 8)
				return 0;
		}
		else
			fread(Header,1,8,fin);
		if(png_sig_cmp(Header,0,8) != 0)
			return 0; // File closing handled by guard.
	}
	//Initialize structures
	png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
	guardPng.GuardPngStruct(png_ptr);
	if (!png_ptr)
		return 0; // File closing handled by guard
	png_infop info_ptr = png_create_info_struct(png_ptr);
	guardPng.GuardStartInfo(info_ptr);
	if (!info_ptr)
		return 0; // File and png closing handled by guards
	png_infop end_info = png_create_info_struct(png_ptr);
	guardPng.GuardEndInfo(end_info);
	if (!end_info)
		return 0; // File and png closing handled by guards
	if (setjmp(png_jmpbuf(png_ptr)))
		return 0; // If there's an error, jump here.  File and png closing still handled by guards

	// Read the png header
	if(GLOBAL_ZipFile.IsOpen()){
		png_set_read_fn(png_ptr, NULL, PngZipRead); // Using global zipfile, so leave io ptr as null
	}else
		png_init_io(png_ptr,fin);
	png_set_sig_bytes(png_ptr,8);

	png_read_info(png_ptr,info_ptr);
	unsigned int width = png_get_image_width(png_ptr, info_ptr);
	unsigned int height = png_get_image_height(png_ptr, info_ptr);
	int bit_depth = png_get_bit_depth(png_ptr, info_ptr);
	int color_type = png_get_color_type(png_ptr, info_ptr);

	// Modify so pixel data is RGBA
	if (color_type == PNG_COLOR_TYPE_PALETTE){ // palette -> rgb
		png_set_palette_to_rgb(png_ptr);
#if SDL_BYTEORDER == SDL_LIL_ENDIAN
		png_set_add_alpha(png_ptr, 255, PNG_FILLER_BEFORE);
#else
		png_set_add_alpha(png_ptr, 255, PNG_FILLER_AFTER);
#endif
	}
	if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) // grayscale 2,4 -> rgba
		png_set_tRNS_to_alpha(png_ptr);
	else if (color_type == PNG_COLOR_TYPE_RGB ||	color_type == PNG_COLOR_TYPE_GRAY)
#if SDL_BYTEORDER == SDL_LIL_ENDIAN
		png_set_add_alpha(png_ptr, 255, PNG_FILLER_BEFORE);
#else
		png_set_add_alpha(png_ptr, 255, PNG_FILLER_AFTER);
#endif
	else
Exemplo n.º 16
0
void *png_read_file(const char *name, png_uint_32 *_w, png_uint_32 *_h,
 check_w_h_constraint_t constraint, rgba_surface_allocator_t allocator)
{
  png_uint_32 i, w, h, stride;
  png_byte header[8];
  png_structp png_ptr = NULL;
  png_infop info_ptr = NULL;
  png_bytep * volatile row_ptrs = NULL;
  void * volatile s = NULL;
  void *pixels;
  int type;
  int bpp;
  FILE *f;

  f = fopen_unsafe(name, "rb");
  if(!f)
    goto exit_out;

  if(fread(header, 1, 8, f) < 8)
    goto exit_close;

  if(png_sig_cmp(header, 0, 8))
    goto exit_close;

  png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
  if(!png_ptr)
    goto exit_close;

  info_ptr = png_create_info_struct(png_ptr);
  if(!info_ptr)
    goto exit_free_close;

  if(setjmp(png_jmpbuf(png_ptr)))
    goto exit_free_close;

  png_init_io(png_ptr, f);
  png_set_sig_bytes(png_ptr, 8);
  png_read_info(png_ptr, info_ptr);
  png_get_IHDR(png_ptr, info_ptr, &w, &h, &bpp, &type, NULL, NULL, NULL);

  if(!constraint(w, h))
  {
    warn("Requested image '%s' failed dimension checks.\n", name);
    goto exit_free_close;
  }

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

  else if(type == PNG_COLOR_TYPE_GRAY_ALPHA || !(type & PNG_COLOR_MASK_COLOR))
    png_set_gray_to_rgb(png_ptr);

  else if(!(type & PNG_COLOR_MASK_COLOR) && bpp < 8)
    png_set_expand_gray_1_2_4_to_8(png_ptr);

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

  else if(bpp < 8)
    png_set_packing(png_ptr);

  if(png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
    png_set_tRNS_to_alpha(png_ptr);
  else if(!(type & PNG_COLOR_MASK_ALPHA))
    png_set_add_alpha(png_ptr, 0xff, PNG_FILLER_AFTER);

  // FIXME: Are these necessary?
  png_read_update_info(png_ptr, info_ptr);
  png_get_IHDR(png_ptr, info_ptr, &w, &h, &bpp, &type, NULL, NULL, NULL);

  row_ptrs = cmalloc(sizeof(png_bytep) * h);
  if(!row_ptrs)
    goto exit_free_close;

  s = allocator(w, h, &stride, &pixels);
  if(!s)
    goto exit_free_close;

  for(i = 0; i < h; i++)
    row_ptrs[i] = (png_bytep)(unsigned char *)pixels + i * stride;

  png_read_image(png_ptr, row_ptrs);

  if(_w)
    *_w = w;
  if(_h)
    *_h = h;

exit_free_close:
  png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
  free(row_ptrs);
exit_close:
  fclose(f);
exit_out:
  return s;
}
Exemplo n.º 17
0
	int Read ( byte **data, int *width, int *height )
	{
		// Setup the pointers
		*data = NULL;
		*width = 0;
		*height = 0;

		// Make sure we're actually reading PNG data.
		const int SIGNATURE_LEN = 8;

		byte ident[SIGNATURE_LEN];
		memcpy (ident, buf, SIGNATURE_LEN);

		if ( !png_check_sig (ident, SIGNATURE_LEN) )
		{
			ri.Printf (PRINT_ERROR, "PNG signature not found in given image.");
			return 0;
		}

		png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL, png_print_error, png_print_warning);
		if ( png_ptr == NULL )
		{
			ri.Printf (PRINT_ERROR, "Could not allocate enough memory to load the image.");
			return 0;
		}

		info_ptr = png_create_info_struct (png_ptr);
		if ( setjmp (png_jmpbuf (png_ptr)) )
		{
			return 0;
		}

		// We've read the signature
		offset += SIGNATURE_LEN;

		// Setup reading information, and read header
		png_set_read_fn (png_ptr, (png_voidp)this, &user_read_data);
#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED
		// This generic "ignore all, except required chunks" requires 1.6.0 or newer"
		png_set_keep_unknown_chunks (png_ptr, PNG_HANDLE_CHUNK_NEVER, NULL, -1);
#endif
		png_set_sig_bytes (png_ptr, SIGNATURE_LEN);
		png_read_info (png_ptr, info_ptr);

		png_uint_32 width_;
		png_uint_32 height_;
		int depth;
		int colortype;

		png_get_IHDR (png_ptr, info_ptr, &width_, &height_, &depth, &colortype, NULL, NULL, NULL);

		// While modern OpenGL can handle non-PoT textures, it's faster to handle only PoT
		// so that the graphics driver doesn't have to fiddle about with the texture when uploading.
		if ( !IsPowerOfTwo (width_) || !IsPowerOfTwo (height_) )
		{
			ri.Printf (PRINT_ERROR, "Width or height is not a power-of-two.\n");
			return 0;
		}

		// This function is equivalent to using what used to be LoadPNG32. LoadPNG8 also existed,
		// but this only seemed to be used by the RMG system which does not work in JKA. If this
		// does need to be re-implemented, then colortype should be PNG_COLOR_TYPE_PALETTE or
		// PNG_COLOR_TYPE_GRAY.
		if ( colortype != PNG_COLOR_TYPE_RGB && colortype != PNG_COLOR_TYPE_RGBA )
		{
			ri.Printf (PRINT_ERROR, "Image is not 24-bit or 32-bit.");
			return 0;
		}

		// Read the png data
		if ( colortype == PNG_COLOR_TYPE_RGB )
		{
			// Expand RGB -> RGBA
			png_set_add_alpha (png_ptr, 0xff, PNG_FILLER_AFTER);
		}

		png_read_update_info (png_ptr, info_ptr);

		// We always assume there are 4 channels. RGB channels are expanded to RGBA when read.
		byte *tempData = (byte *)ri.Z_Malloc (width_ * height_ * 4, TAG_TEMP_PNG, qfalse, 4);
		if ( !tempData )
		{
			ri.Printf (PRINT_ERROR, "Could not allocate enough memory to load the image.");
			return 0;
		}

		// Dynamic array of row pointers, with 'height' elements, initialized to NULL.
		byte **row_pointers = (byte **)ri.Z_Malloc (sizeof (byte *) * height_, TAG_TEMP_PNG, qfalse, 4);
		if ( !row_pointers )
		{
			ri.Printf (PRINT_ERROR, "Could not allocate enough memory to load the image.");

			ri.Z_Free (tempData);
			
			return 0;
		}

		// Re-set the jmp so that these new memory allocations can be reclaimed
		if ( setjmp (png_jmpbuf (png_ptr)) )
		{
			ri.Z_Free (row_pointers);
			ri.Z_Free (tempData);
			return 0;
		}

		for ( unsigned int i = 0, j = 0; i < height_; i++, j += 4 )
		{
			row_pointers[i] = tempData + j * width_;
		}

		png_read_image (png_ptr, row_pointers);

		// Finish reading
		png_read_end (png_ptr, NULL);

		ri.Z_Free (row_pointers);

		// Finally assign all the parameters
		*data = tempData;
		*width = width_;
		*height = height_;

		return 1;
	}
Exemplo n.º 18
0
bool loadHSI (FILE * fp, int x, int y, bool reserve) {

	int t1, t2, n;
	unsigned short c;
	GLubyte * target;
	int32_t transCol = reserve ? -1 : 63519;
	int picWidth;
	int picHeight;
	int realPicWidth, realPicHeight;
	long file_pointer = ftell (fp);

	png_structp png_ptr;
	png_infop info_ptr, end_info;


	int fileIsPNG = true;

	// Is this a PNG file?

	char tmp[10];
	size_t bytes_read = fread(tmp, 1, 8, fp);
	if (bytes_read != 8 && ferror (fp)) {
		debugOut("Reading error in loadHSI.\n");
	}
    if (png_sig_cmp((png_byte *) tmp, 0, 8)) {
		// No, it's old-school HSI
		fileIsPNG = false;
		fseek(fp, file_pointer, SEEK_SET);

		picWidth = realPicWidth = get2bytes (fp);
		picHeight = realPicHeight = get2bytes (fp);
	} else {
		// Read the PNG header

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

		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;
		}

		end_info = png_create_info_struct(png_ptr);
		if (!end_info) {
			png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
			return false;
		}
		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);

		picWidth = realPicWidth = width;
		picHeight = realPicHeight = height;

		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);

	}


	GLfloat texCoordW = 1.0;
	GLfloat texCoordH = 1.0;
	if (! NPOT_textures) {
		picWidth = getNextPOT(picWidth);
		picHeight = getNextPOT(picHeight);
		texCoordW = ((double)realPicWidth) / picWidth;
		texCoordH = ((double)realPicHeight) / picHeight;
	}

	if (reserve) {
		if (! resizeBackdrop (realPicWidth, realPicHeight)) return false;
	}

	if (x == IN_THE_CENTRE) x = (sceneWidth - realPicWidth) >> 1;
	if (y == IN_THE_CENTRE) y = (sceneHeight - realPicHeight) >> 1;
	if (x < 0 || x + realPicWidth > sceneWidth || y < 0 || y + realPicHeight > sceneHeight) return false;

	if (fileIsPNG) {
		unsigned char * row_pointers[realPicHeight];
		for (int i = 0; i<realPicHeight; i++)
			row_pointers[i] = backdropTexture + 4*i*picWidth;

		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);
	} else {
		for (t2 = 0; t2 < realPicHeight; t2 ++) {
			t1 = 0;
			while (t1 < realPicWidth) {
				c = (unsigned short) get2bytes (fp);
				if (c & 32) {
					n = fgetc (fp) + 1;
					c -= 32;
				} else {
					n = 1;
				}
				while (n --) {
					target = backdropTexture + 4*picWidth*t2 + t1*4;
					if (c == transCol || c == 2015) {
						target[0] = (GLubyte) 0;
						target[1] = (GLubyte) 0;
						target[2] = (GLubyte) 0;
						target[3] = (GLubyte) 0;
					} else {
						target[0] = (GLubyte) redValue(c);
						target[1] = (GLubyte) greenValue(c);
						target[2] = (GLubyte) blueValue(c);
						target[3] = (GLubyte) 255;
					}
					t1++;
				}
			}
		}
	}

	GLuint tmpTex;

	glGenTextures (1, &tmpTex);
	glBindTexture(GL_TEXTURE_2D, tmpTex);
	glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
	glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
	if (gameSettings.antiAlias < 0) {
		glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
		glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
	} else {
		glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
		glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
	}
	texImage2D (GL_TEXTURE_2D, 0, GL_RGBA, picWidth, picHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, backdropTexture, tmpTex);


	//glTexEnvf (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);


	float btx1;
	float btx2;
	float bty1;
	float bty2;
	if (! NPOT_textures) {
		btx1 = backdropTexW * x / sceneWidth;
		btx2 = backdropTexW * (x+realPicWidth) / sceneWidth;
		bty1 = backdropTexH * y / sceneHeight;
		bty2 = backdropTexH * (y+realPicHeight) / sceneHeight;
	} else {
		btx1 = (float) x / sceneWidth;
		btx2 = (float) (x+realPicWidth) / sceneWidth;
		bty1 = (float) y / sceneHeight;
		bty2 = (float) (y+realPicHeight) / sceneHeight;
	}

	const GLfloat btexCoords[] = { 
		btx1, bty1,
		btx2, bty1,
		btx1, bty2,
		btx2, bty2 
	}; 

	setPixelCoords (true);

	int xoffset = 0;
	while (xoffset < realPicWidth) {
		int w = (realPicWidth-xoffset < viewportWidth) ? realPicWidth-xoffset : viewportWidth;

		int yoffset = 0;
		while (yoffset < realPicHeight) {
			int h = (realPicHeight-yoffset < viewportHeight) ? realPicHeight-yoffset : viewportHeight;

			glClear(GL_COLOR_BUFFER_BIT);	// Clear The Screen

			const GLfloat vertices[] = { 
				(GLfloat)-xoffset, (GLfloat)-yoffset, 0., 
				(GLfloat)realPicWidth-xoffset, (GLfloat)-yoffset, 0., 
				(GLfloat)-xoffset, (GLfloat)-yoffset+realPicHeight, 0.,
				(GLfloat)realPicWidth-xoffset, (GLfloat)-yoffset+realPicHeight, 0.
			};

			const GLfloat texCoords[] = { 
				0.0f, 0.0f,
				texCoordW, 0.0f,
				0.0f, texCoordH,
				texCoordW, texCoordH
			}; 

			if (backdropExists) {
				// Render the sprite to the backdrop
				// (using mulitexturing, so the old backdrop is seen where alpha < 1.0)
				glActiveTexture(GL_TEXTURE2);
				glBindTexture (GL_TEXTURE_2D, backdropTextureName);
				glActiveTexture(GL_TEXTURE0);

				glUseProgram(shader.paste);
				GLint uniform = glGetUniformLocation(shader.paste, "useLightTexture");
				if (uniform >= 0) glUniform1i(uniform, 0); // No lighting

				setPMVMatrix(shader.paste);

				setPrimaryColor(1.0, 1.0, 1.0, 1.0);
				glBindTexture(GL_TEXTURE_2D, tmpTex);
				//glTexEnvf (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);

				drawQuad(shader.paste, vertices, 3, texCoords, NULL, btexCoords);

				glUseProgram(0);

			} else {
				// It's all new - nothing special to be done.

				glUseProgram(shader.texture);
				setPMVMatrix(shader.texture);

				glBindTexture(GL_TEXTURE_2D, tmpTex);

				setPrimaryColor(1.0, 0.0, 0.0, 0.0);

				drawQuad(shader.texture, vertices, 1, texCoords);

				glUseProgram(0);
			}

			// Copy Our ViewPort To The Texture
			copyTexSubImage2D(GL_TEXTURE_2D, 0, x+xoffset, y+yoffset, viewportOffsetX, viewportOffsetY, w, h, backdropTextureName);

			yoffset += viewportHeight;
		}

		xoffset += viewportWidth;
	}
	deleteTextures(1, &tmpTex);

	setPixelCoords (false);

	backdropExists = true;
	return true;
}
Exemplo n.º 19
0
static const char * VS_CC
check_png(img_hnd_t *ih, int n, FILE *fp, vs_args_t *va)
{
    uint8_t signature[PNG_SIG_LENGTH];
    if (fread(signature, 1, PNG_SIG_LENGTH, fp) != PNG_SIG_LENGTH ||
        png_sig_cmp(signature, 0, PNG_SIG_LENGTH)) {
        return "unsupported format";
    }

    png_structp p_str = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL,
                                               NULL, NULL);
    if (!p_str) {
        return "failed to create png_read_struct";
    }

    png_infop p_info = png_create_info_struct(p_str);
    if (!p_info) {
        png_destroy_read_struct(&p_str, NULL, NULL);
        return "failed to create png_info_struct";
    }

    png_init_io(p_str, fp);
    png_set_sig_bytes(p_str, PNG_SIG_LENGTH);
    png_read_info(p_str, p_info);

    png_uint_32 width, height;
    int color_type, bit_depth;
    png_get_IHDR(p_str, p_info, &width, &height, &bit_depth, &color_type,
                 NULL, NULL, NULL);
    if (color_type & PNG_COLOR_TYPE_PALETTE) {
        png_set_palette_to_rgb(p_str);
    }
    if (bit_depth < 8) {
        png_set_packing(p_str);
    }
    if (ih->enable_alpha == 0) {
        if (color_type & PNG_COLOR_MASK_ALPHA) {
            png_set_strip_alpha(p_str);
        }
    } else if ((color_type & PNG_COLOR_MASK_ALPHA) == 0) {
        png_set_add_alpha(p_str, 0x00, PNG_FILLER_AFTER);
    }

    png_read_update_info(p_str, p_info);
    png_get_IHDR(p_str, p_info, &width, &height, &bit_depth, &color_type,
                 NULL, NULL, NULL);
    uint32_t row_size = png_get_rowbytes(p_str, p_info);

    png_destroy_read_struct(&p_str, &p_info, NULL);

    ih->src[n].width = width;

    ih->src[n].height = height;

    VSPresetFormat pf = get_dst_format(color_type, bit_depth);
    if (pf == pfNone) {
        return "unsupported png color type";
    }
    ih->src[n].format = va->vsapi->getFormatPreset(pf, va->core);

    ih->src[n].read = read_png;

    ih->src[n].flip = 0;

    if (row_size > va->max_row_size) {
        va->max_row_size = row_size;
    }

    return NULL;
}
Exemplo n.º 20
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);
}
Exemplo n.º 21
0
ImageReaderPNG::ImageType ImageReaderPNG::readData(const std::string& filePath, PNGInfra& infra, bool wantAlpha)
{
	if (filePath.empty())
		return eInvalid;

	infra.pFile = fopen(filePath.c_str(), "rb");
	if (!infra.pFile)
	{
		fprintf(stderr, "Error opening file: %s\n", filePath.c_str());
		return eInvalid;
	}

	unsigned char sig[8];

	// check the signature
	fread(sig, 1, 8, infra.pFile);
	if (!png_check_sig(sig, 8))
	{
		fprintf(stderr, "Cannot open file: %s - not a valid PNG file.\n", filePath.c_str());
		fclose(infra.pFile);
		return eInvalid;
	}

	infra.pPNG = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
	if (!infra.pPNG)
	{
		fclose(infra.pFile);
		return eInvalid;
	}

	infra.pInfo = png_create_info_struct(infra.pPNG);
	if (!infra.pInfo)
	{
		png_destroy_read_struct(&infra.pPNG, NULL, NULL);
		fclose(infra.pFile);
		return eInvalid;
	}

	if (setjmp(png_jmpbuf(infra.pPNG)))
	{
		png_destroy_read_struct(&infra.pPNG, &infra.pInfo, NULL);
		fclose(infra.pFile);
		return eInvalid;
	}

	png_init_io(infra.pPNG, infra.pFile);
	png_set_sig_bytes(infra.pPNG, 8);
	png_read_info(infra.pPNG, infra.pInfo);

	int colorType;
	int bitDepth, interlaceType, compressionType;

	png_get_IHDR(infra.pPNG, infra.pInfo, &infra.width, &infra.height, &bitDepth, &colorType, &interlaceType, &compressionType, NULL);

	if (colorType == PNG_COLOR_TYPE_PALETTE)
		png_set_palette_to_rgb(infra.pPNG);

	if (png_get_valid(infra.pPNG, infra.pInfo, PNG_INFO_tRNS))
	{
		png_set_tRNS_to_alpha(infra.pPNG);
	}

	if (bitDepth == 16)
		png_set_strip_16(infra.pPNG);

	ImageType type = eInvalid;

	if (!wantAlpha)
	{
		// add black Alpha
		if ((colorType & PNG_COLOR_MASK_ALPHA) == 0)
			png_set_add_alpha(infra.pPNG, 0xFF, PNG_FILLER_AFTER);

		if (colorType == PNG_COLOR_TYPE_GRAY || colorType == PNG_COLOR_TYPE_GRAY_ALPHA)
			png_set_gray_to_rgb(infra.pPNG);
		else if (colorType != PNG_COLOR_TYPE_RGB && colorType != PNG_COLOR_TYPE_RGB_ALPHA)
			return eInvalid;

		type = eRGBA;
	}
	else
	{
		if (colorType == PNG_COLOR_TYPE_RGB_ALPHA)
			type = eRGBA;
		else if (colorType == PNG_COLOR_TYPE_GRAY || colorType == PNG_COLOR_TYPE_GRAY_ALPHA)
			type = eA;
		else
			return eInvalid;
	}

	png_read_update_info(infra.pPNG, infra.pInfo);

	infra.pRows = new png_bytep[infra.height * png_sizeof(png_bytep)];

	png_set_rows(infra.pPNG, infra.pInfo, infra.pRows);

	for (unsigned int i = 0; i < infra.height; i++)
	{
		infra.pRows[i] = new png_byte[png_get_rowbytes(infra.pPNG, infra.pInfo)];
	}

	png_read_image(infra.pPNG, infra.pRows);
	png_read_end(infra.pPNG, infra.pInfo);

	return type;
}
Exemplo n.º 22
0
bool isis::codecs::png::DecoderImpl::init()
{
	// checking PNG signature
	png_byte pngsig[8];
	int bytes_read = source_->read(pngsig, 8);
	if (8 != bytes_read)
		return false;
	bool is_png = 0 == png_sig_cmp(pngsig, 0, 8);
	if (!is_png)
		return false;

	// creating png read struct
	png_ = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, report_error, report_warning);
	if (!png_)
		return false;

	// creating png info struct
	info_ = png_create_info_struct(png_);
	if (!info_)
		return false;

	// overriding read function
	png_set_read_fn(png_, reinterpret_cast<png_voidp>(source_.get()), read_png);

	// error handler
	if (setjmp(png_jmpbuf(png_)))
	{
		ISIS_LOG_COMMENT_LOCATION
		log_error("Reading error.");
		return false;
	}

	// reading info
	png_set_sig_bytes(png_, 8);
	png_read_info(png_, info_);

	// getting info
//    png_byte channels = png_get_channels( png, info );
	png_uint_32 image_width = png_get_image_width(png_, info_);
	png_uint_32 image_height = png_get_image_height(png_, info_);
	png_byte bit_depth = png_get_bit_depth(png_, info_);
	png_byte colour_type = png_get_color_type(png_, info_);
//    png_byte filter_type = png_get_filter_type( png, info );
//    png_byte interlace_type = png_get_interlace_type( png, info );
//    png_byte compression_type = png_get_compression_type( png, info );

// converting any format to A8R8G8B8
	switch (colour_type & ~PNG_COLOR_MASK_ALPHA)
	{
	case PNG_COLOR_TYPE_GRAY:
		if (bit_depth < 8)
			png_set_expand_gray_1_2_4_to_8(png_);
		png_set_gray_to_rgb(png_);
		break;

	case PNG_COLOR_TYPE_RGB:
		// do nothing
		break;

	case PNG_COLOR_TYPE_PALETTE:
		png_set_palette_to_rgb(png_);
		break;
	}
	// narrow 16bit channels
	if (bit_depth == 16)
		png_set_strip_16(png_);
	// add alpha channel if none
	if (!(colour_type & PNG_COLOR_MASK_ALPHA))
	{
		// use tRNS if present, otherwise just add 0xFF alpha
		if (png_get_valid(png_, info_, PNG_INFO_tRNS))
			png_set_tRNS_to_alpha(png_);
		else
			png_set_add_alpha(png_, 0xFF, PNG_FILLER_AFTER);
	}
	// BGR -> RGB
	png_set_bgr(png_);

	size_ = {(int)image_width, (int)image_height};
	bit_depth_ = 32; // all images are converted to A8R8G8B8
	return true;
}
Exemplo n.º 23
0
    void PngReader::read(unsigned x0, unsigned y0,ImageData32& image) 
    {
	FILE *fp=fopen(fileName_.c_str(),"r");
	if (!fp) throw ImageReaderException("cannot open image file "+fileName_);
	
        png_structp png_ptr = png_create_read_struct
	    (PNG_LIBPNG_VER_STRING,0,0,0);
	
	if (!png_ptr) 
	{
	    fclose(fp);
	    throw ImageReaderException("failed to allocate png_ptr");
	}
	
	png_infop info_ptr = png_create_info_struct(png_ptr);
	if (!info_ptr)
	{
	    png_destroy_read_struct(&png_ptr,0,0);
	    fclose(fp);
	    throw ImageReaderException("failed to create info_ptr");
	}

	png_init_io(png_ptr, fp);
	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,1,1);
 
	double gamma;
	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);
	
	//START read image rows
	unsigned w=std::min((unsigned)image.width(),width_);
	unsigned h=std::min((unsigned)image.height(),height_);
	
	unsigned rowbytes=png_get_rowbytes(png_ptr, info_ptr);
	unsigned char* row= new unsigned char[rowbytes];
	for (unsigned i=0;i<height_;++i)
	{
	    png_read_row(png_ptr,row,0);
	    if (i>=y0 && i<h) 
	    {
		image.setRow(i-y0,(unsigned*) &row[x0],w);
	    } 
	}
	//END
	delete [] row;
	png_read_end(png_ptr,0);
	png_destroy_read_struct(&png_ptr, &info_ptr,0);
	fclose(fp);
    }
Exemplo n.º 24
0
	int Read ( const char *filename, byte **data, int *width, int *height )
	{
		// Setup the pointers
		*data = NULL;
		*width = 0;
		*height = 0;

		// Check and make sure the filename is valid (because you can never be too careful...)
		if( !filename || !filename[0] )
		{
			ri->Printf( PRINT_ERROR, "PNG read called with invalid filename.\n" );
			return 0;
		}

		// Copy the filename to the global variable
		Q_strncpyz( currentPNGFile, filename, sizeof(currentPNGFile) );

		// Make sure we're actually reading PNG data.
		const int SIGNATURE_LEN = 8;

		byte ident[SIGNATURE_LEN];
		memcpy (ident, buf, SIGNATURE_LEN);

		if ( !png_check_sig (ident, SIGNATURE_LEN) )
		{
			ri->Printf (PRINT_ERROR, "PNG signature not found in %s.\n", currentPNGFile );
			return 0;
		}

		png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL, png_print_error, png_print_warning);
		if ( png_ptr == NULL )
		{
			ri->Printf (PRINT_ERROR, "PNG: Could not allocate enough memory to load %s\n", currentPNGFile );
			return 0;
		}

		info_ptr = png_create_info_struct (png_ptr);
		if ( setjmp (png_jmpbuf (png_ptr)) )
		{
			return 0;
		}

		// We've read the signature
		offset += SIGNATURE_LEN;

		// Setup reading information, and read header
		png_set_read_fn (png_ptr, (png_voidp)this, &user_read_data);
		png_set_sig_bytes (png_ptr, SIGNATURE_LEN);
		png_read_info (png_ptr, info_ptr);

		png_uint_32 width_;
		png_uint_32 height_;
		int depth;
		int colortype;

		png_get_IHDR (png_ptr, info_ptr, &width_, &height_, &depth, &colortype, NULL, NULL, NULL);

		// While modern OpenGL can handle non-PoT textures, it's faster to handle only PoT
		// so that the graphics driver doesn't have to fiddle about with the texture when uploading.
		if ( !IsPowerOfTwo (width_) || !IsPowerOfTwo (height_) )
		{
			ri->Printf (PRINT_ERROR, "PNG: Width or height of %s is not a power-of-two.\n", currentPNGFile );
			return 0;
		}

		// This function is equivalent to using what used to be LoadPNG32. LoadPNG8 also existed,
		// but this only seemed to be used by the RMG system which does not work in JKA. If this
		// does need to be re-implemented, then colortype should be PNG_COLOR_TYPE_PALETTE or
		// PNG_COLOR_TYPE_GRAY.
		if ( colortype != PNG_COLOR_TYPE_RGB && colortype != PNG_COLOR_TYPE_RGBA )
		{
			ri->Printf (PRINT_ERROR, "PNG: %s is not 24-bit or 32-bit.\n", currentPNGFile );
			return 0;
		}

		// Read the png data
		if ( colortype == PNG_COLOR_TYPE_RGB )
		{
			// Expand RGB -> RGBA
			png_set_add_alpha (png_ptr, 0xff, PNG_FILLER_AFTER);
		}

		png_read_update_info (png_ptr, info_ptr);

		// We always assume there are 4 channels. RGB channels are expanded to RGBA when read.
		byte *tempData = (byte *)ri->Z_Malloc (width_ * height_ * 4, TAG_TEMP_PNG, qfalse, 4);
		if ( !tempData )
		{
			ri->Printf (PRINT_ERROR, "Could not allocate enough memory to load %s.\n", currentPNGFile );
			return 0;
		}

		// Dynamic array of row pointers, with 'height' elements, initialized to NULL.
		byte **row_pointers = (byte **)ri->Hunk_AllocateTempMemory (sizeof (byte *) * height_);
		if ( !row_pointers )
		{
			ri->Printf (PRINT_ERROR, "Could not allocate enough memory to load %s.\n", currentPNGFile );

			ri->Z_Free (tempData);
			
			return 0;
		}

		// Re-set the jmp so that these new memory allocations can be reclaimed
		if ( setjmp (png_jmpbuf (png_ptr)) )
		{
			ri->Hunk_FreeTempMemory (row_pointers);
			ri->Z_Free (tempData);
			return 0;
		}

		for ( unsigned int i = 0, j = 0; i < height_; i++, j += 4 )
		{
			row_pointers[i] = tempData + j * width_;
		}

		png_read_image (png_ptr, row_pointers);

		// Finish reading
		png_read_end (png_ptr, NULL);

		ri->Hunk_FreeTempMemory (row_pointers);

		// Finally assign all the parameters
		*data = tempData;
		*width = width_;
		*height = height_;

		return 1;
	}
Exemplo n.º 25
0
s32 pngDecodeData(PPUThread& ppu, PHandle handle, PStream stream, vm::ptr<u8> data, PDataControlParam data_control_param, PDataOutInfo data_out_info, PCbControlDisp cb_control_disp = vm::null, PDispParam disp_param = vm::null)
{
	if (cb_control_disp || disp_param)
	{
		throw EXCEPTION("Partial image decoding is not supported");
	}

	// Indicate, that the PNG decoding is stopped/failed. This is incase, we return an error code in the middle of decoding
	data_out_info->status = CELL_PNGDEC_DEC_STATUS_STOP;

	// Possibilities for decoding in different sizes aren't tested, so if anyone finds any of these cases, we'll know about it.
	if (stream->info.imageWidth != stream->out_param.outputWidth)
	{
		throw EXCEPTION("Image width doesn't match output width! (%d/%d)", stream->out_param.outputWidth, stream->info.imageWidth);
	}

	if (stream->info.imageHeight != stream->out_param.outputHeight)
	{
		throw EXCEPTION("Image width doesn't match output height! (%d/%d)", stream->out_param.outputHeight, stream->info.imageHeight);
	}

	// Get the amount of output bytes per line
	const u32 bytes_per_line = data_control_param->outputBytesPerLine;

	// Whether to recaculate bytes per row
	bool recalculate_bytes_per_row = false;

	// Check if the game is expecting the number of bytes per line to be lower, than the actual bytes per line on the image. (Arkedo Pixel for example)
	// In such case we strip the bit depth to be lower.
	if ((bytes_per_line < stream->out_param.outputWidthByte) && stream->out_param.outputBitDepth != 8)
	{
		// Check if the packing is really 1 byte per 1 pixel
		if (stream->packing != CELL_PNGDEC_1BYTE_PER_1PIXEL)
		{
			throw EXCEPTION("Unexpected packing value! (%d)", stream->packing);
		}

		// Scale 16 bit depth down to 8 bit depth. PS3 uses png_set_strip_16, since png_set_scale_16 wasn't available back then.
		png_set_strip_16(stream->png_ptr);
		recalculate_bytes_per_row = true;
	}
	// Check if the outputWidthByte is smaller than the intended output length of a line. For example an image might be in RGB, but we need to output 4 components, so we need to perform alpha padding.
	else if (stream->out_param.outputWidthByte < (stream->out_param.outputWidth * stream->out_param.outputComponents))
	{
		// If fixed alpha is not specified in such a case, the default value for the alpha is 0xFF (255)
		if (!stream->fixed_alpha)
		{
			stream->fixed_alpha_colour = 0xFF;
		}

		// We need to fill alpha (before or after, depending on the output colour format) using the fixed alpha value passed by the game.
		png_set_add_alpha(stream->png_ptr, stream->fixed_alpha_colour, stream->out_param.outputColorSpace == CELL_PNGDEC_RGBA ? PNG_FILLER_AFTER : PNG_FILLER_BEFORE);
		recalculate_bytes_per_row = true;
	}
	// We decode as RGBA, so we need to swap the alpha
	else if (stream->out_param.outputColorSpace == CELL_PNGDEC_ARGB)
	{
		// Swap the alpha channel for the ARGB output format, if the padding isn't needed
		png_set_swap_alpha(stream->png_ptr);
	}
	// Sometimes games pass in a RBG/RGBA image and want it as grayscale
	else if ((stream->out_param.outputColorSpace == CELL_PNGDEC_GRAYSCALE_ALPHA || stream->out_param.outputColorSpace == CELL_PNGDEC_GRAYSCALE)
		  && (stream->info.colorSpace == CELL_PNGDEC_RGB || stream->info.colorSpace == CELL_PNGDEC_RGBA))
	{
		// Tell libpng to convert it to grayscale
		png_set_rgb_to_gray(stream->png_ptr, PNG_ERROR_ACTION_NONE, PNG_RGB_TO_GRAY_DEFAULT, PNG_RGB_TO_GRAY_DEFAULT);
		recalculate_bytes_per_row = true;
	}

	if (recalculate_bytes_per_row)
	{
		// Update the info structure
		png_read_update_info(stream->png_ptr, stream->info_ptr);

		// Recalculate the bytes per row
		stream->out_param.outputWidthByte = png_get_rowbytes(stream->png_ptr, stream->info_ptr);
	}

	// Calculate the image size
	u32 image_size = stream->out_param.outputWidthByte * stream->out_param.outputHeight;

	// Buffer for storing the image
	std::vector<u8> png(image_size);
	
	// Make an unique pointer for the row pointers
	std::vector<u8*> row_pointers(stream->out_param.outputHeight);

	// Allocate memory for rows
	for (u32 y = 0; y < stream->out_param.outputHeight; y++)
	{
		row_pointers[y] = &png[y * stream->out_param.outputWidthByte];
	}

	// Decode the image
	png_read_image(stream->png_ptr, row_pointers.data());

	// Check if the image needs to be flipped
	const bool flip = stream->out_param.outputMode == CELL_PNGDEC_BOTTOM_TO_TOP;

	// Copy the result to the output buffer
	switch (stream->out_param.outputColorSpace)
	{
	case CELL_PNGDEC_RGB:
	case CELL_PNGDEC_RGBA:
	case CELL_PNGDEC_ARGB:
	case CELL_PNGDEC_GRAYSCALE_ALPHA:
	{
		// Check if we need to flip the image or need to leave empty bytes at the end of a line
		if ((bytes_per_line > stream->out_param.outputWidthByte) || flip)
		{
			// Get how many bytes per line we need to output - bytesPerLine is total amount of bytes per line, rest is unused and the game can do as it pleases.
			const u32 line_size = std::min(bytes_per_line, stream->out_param.outputWidth * 4);

			// If the game wants more bytes per line to be output, than the image has, then we simply copy what we have for each line,
			// and continue on the next line, thus leaving empty bytes at the end of the line.
			for (u32 i = 0; i < stream->out_param.outputHeight; i++)
			{
				const u32 dst = i * bytes_per_line;
				const u32 src = stream->out_param.outputWidth * 4 * (flip ? stream->out_param.outputHeight - i - 1 : i);
				memcpy(&data[dst], &png[src], line_size);
			}
		}
		else
		{
			// We can simply copy the output to the data pointer specified by the game, since we already do alpha channel transformations in libpng, if needed
			memcpy(data.get_ptr(), png.data(), image_size);
		}
		break;
	}

	default: throw EXCEPTION("Unsupported color space (%d)", stream->out_param.outputColorSpace);
	}

	// Get the number of iTXt, tEXt and zTXt chunks
	s32 text_chunks = 0;
	png_get_text(stream->png_ptr, stream->info_ptr, nullptr, &text_chunks);

	// Set the chunk information and the previously obtained number of text chunks
	data_out_info->numText = (u32)text_chunks;
	data_out_info->chunkInformation = pngDecGetChunkInformation(stream, true);
	data_out_info->numUnknownChunk = 0; // TODO: Get this somehow. Does anything even use or need this?

	// Indicate that the decoding succeeded
	data_out_info->status = CELL_PNGDEC_DEC_STATUS_FINISH;

	return CELL_OK;
}
Exemplo n.º 26
0
void FPngImageWrapper::UncompressPNGData( const ERGBFormat::Type InFormat, const int32 InBitDepth )
{
	// thread safety
	FScopeLock PNGLock(&GPNGSection);

	check( CompressedData.Num() );
	check( Width > 0 );
	check( Height > 0 );

	// Note that PNGs on PC tend to be BGR
	check( InFormat == ERGBFormat::BGRA || InFormat == ERGBFormat::RGBA || InFormat == ERGBFormat::Gray )	// Other formats unsupported at present
	check( InBitDepth == 8 || InBitDepth == 16 )	// Other formats unsupported at present

	// Reset to the beginning of file so we can use png_read_png(), which expects to start at the beginning.
	ReadOffset = 0;
		
	png_structp png_ptr	= png_create_read_struct_2( PNG_LIBPNG_VER_STRING, this, FPngImageWrapper::user_error_fn, FPngImageWrapper::user_warning_fn, NULL, FPngImageWrapper::user_malloc, FPngImageWrapper::user_free);
	check( png_ptr );

	png_infop info_ptr	= png_create_info_struct( png_ptr );
	check( info_ptr );
	PNGReadGuard PNGGuard( &png_ptr, &info_ptr );
	{
		if (ColorType == PNG_COLOR_TYPE_PALETTE)
		{
			png_set_palette_to_rgb(png_ptr);
		}

		if ((ColorType & PNG_COLOR_MASK_COLOR) == 0 && BitDepth < 8)
		{
			png_set_expand_gray_1_2_4_to_8(png_ptr);
		}

		// Insert alpha channel with full opacity for RGB images without alpha
		if ((ColorType & PNG_COLOR_MASK_ALPHA) == 0 && (InFormat == ERGBFormat::BGRA || InFormat == ERGBFormat::RGBA))
		{
			// png images don't set PNG_COLOR_MASK_ALPHA if they have alpha from a tRNS chunk, but png_set_add_alpha seems to be safe regardless
			if ((ColorType & PNG_COLOR_MASK_COLOR) == 0)
			{
				png_set_tRNS_to_alpha(png_ptr);
			}
			else if (ColorType == PNG_COLOR_TYPE_PALETTE)
			{
				png_set_tRNS_to_alpha(png_ptr);
			}
			if (InBitDepth == 8)
			{
				png_set_add_alpha(png_ptr, 0xff , PNG_FILLER_AFTER);
			}
			else if (InBitDepth == 16)
			{
				png_set_add_alpha(png_ptr, 0xffff , PNG_FILLER_AFTER);
			}
		}

		// Calculate Pixel Depth
		const uint32 PixelChannels = (InFormat == ERGBFormat::Gray) ? 1 : 4;
		const uint32 BytesPerPixel = (InBitDepth * PixelChannels) / 8;
		const uint32 BytesPerRow = BytesPerPixel * Width;
		RawData.Empty(Height * BytesPerRow);
		RawData.AddUninitialized(Height * BytesPerRow);

		png_set_read_fn( png_ptr, this, FPngImageWrapper::user_read_compressed );

		png_bytep* row_pointers = (png_bytep*) png_malloc( png_ptr, Height*sizeof(png_bytep) );
		PNGGuard.SetRowPointers(&row_pointers);
		for (int32 i = 0; i < Height; i++)
		{
			row_pointers[i]= &RawData[i * BytesPerRow];
		}
		png_set_rows(png_ptr, info_ptr, row_pointers);

		uint32 Transform = (InFormat == ERGBFormat::BGRA) ? PNG_TRANSFORM_BGR : PNG_TRANSFORM_IDENTITY;
			
		// PNG files store 16-bit pixels in network byte order (big-endian, ie. most significant bits first).
#if PLATFORM_LITTLE_ENDIAN
		// We're little endian so we need to swap
		if (BitDepth == 16)
		{
			Transform |= PNG_TRANSFORM_SWAP_ENDIAN;
		}
#endif

		// Convert grayscale png to RGB if requested
		if ((ColorType & PNG_COLOR_MASK_COLOR) == 0 &&
			(InFormat == ERGBFormat::RGBA || InFormat == ERGBFormat::BGRA))
		{
			Transform |= PNG_TRANSFORM_GRAY_TO_RGB;
		}

		// Convert RGB png to grayscale if requested
		if ((ColorType & PNG_COLOR_MASK_COLOR) != 0 && InFormat == ERGBFormat::Gray)
		{
			png_set_rgb_to_gray_fixed(png_ptr, 2 /* warn if image is in color */, -1, -1);
		}

		// Strip alpha channel if requested output is grayscale
		if (InFormat == ERGBFormat::Gray)
		{
			// this is not necessarily the best option, instead perhaps:
			// png_color background = {0,0,0};
			// png_set_background(png_ptr, &background, PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0);
			Transform |= PNG_TRANSFORM_STRIP_ALPHA;
		}

		// Reduce 16-bit to 8-bit if requested
		if (BitDepth == 16 && InBitDepth == 8)
		{
#if PNG_LIBPNG_VER >= 10504
			check(0); // Needs testing
			Transform |= PNG_TRANSFORM_SCALE_16;
#else
			Transform |= PNG_TRANSFORM_STRIP_16;
#endif
		}

		// Increase 8-bit to 16-bit if requested
		if (BitDepth <= 8 && InBitDepth == 16)
		{
#if PNG_LIBPNG_VER >= 10504
			check(0); // Needs testing
			Transform |= PNG_TRANSFORM_EXPAND_16
#else
			// Expanding 8-bit images to 16-bit via transform needs a libpng update
			check(0);
#endif
		}

		png_read_png(png_ptr, info_ptr, Transform, NULL);
	}

	RawFormat = InFormat;
	RawBitDepth = InBitDepth;
}
Exemplo n.º 27
0
static GstFlowReturn
gst_pngdec_caps_create_and_set (GstPngDec * pngdec)
{
  GstFlowReturn ret = GST_FLOW_OK;
  gint bpc = 0, color_type;
  png_uint_32 width, height;
  GstVideoFormat format = GST_VIDEO_FORMAT_UNKNOWN;

  g_return_val_if_fail (GST_IS_PNGDEC (pngdec), GST_FLOW_ERROR);

  /* Get bits per channel */
  bpc = png_get_bit_depth (pngdec->png, pngdec->info);

  /* Get Color type */
  color_type = png_get_color_type (pngdec->png, pngdec->info);

  /* Add alpha channel if 16-bit depth, but not for GRAY images */
  if ((bpc > 8) && (color_type != PNG_COLOR_TYPE_GRAY)) {
    png_set_add_alpha (pngdec->png, 0xffff, PNG_FILLER_BEFORE);
    png_set_swap (pngdec->png);
  }
#if 0
  /* We used to have this HACK to reverse the outgoing bytes, but the problem
   * that originally required the hack seems to have been in videoconvert's
   * RGBA descriptions. It doesn't seem needed now that's fixed, but might
   * still be needed on big-endian systems, I'm not sure. J.S. 6/7/2007 */
  if (color_type == PNG_COLOR_TYPE_RGB_ALPHA)
    png_set_bgr (pngdec->png);
#endif

  /* Gray scale with alpha channel converted to RGB */
  if (color_type == PNG_COLOR_TYPE_GRAY_ALPHA) {
    GST_LOG_OBJECT (pngdec,
        "converting grayscale png with alpha channel to RGB");
    png_set_gray_to_rgb (pngdec->png);
  }

  /* Gray scale converted to upscaled to 8 bits */
  if ((color_type == PNG_COLOR_TYPE_GRAY_ALPHA) ||
      (color_type == PNG_COLOR_TYPE_GRAY)) {
    if (bpc < 8) {              /* Convert to 8 bits */
      GST_LOG_OBJECT (pngdec, "converting grayscale image to 8 bits");
#if PNG_LIBPNG_VER < 10400
      png_set_gray_1_2_4_to_8 (pngdec->png);
#else
      png_set_expand_gray_1_2_4_to_8 (pngdec->png);
#endif
    }
  }

  /* Palette converted to RGB */
  if (color_type == PNG_COLOR_TYPE_PALETTE) {
    GST_LOG_OBJECT (pngdec, "converting palette png to RGB");
    png_set_palette_to_rgb (pngdec->png);
  }

  png_set_interlace_handling (pngdec->png);

  /* Update the info structure */
  png_read_update_info (pngdec->png, pngdec->info);

  /* Get IHDR header again after transformation settings */
  png_get_IHDR (pngdec->png, pngdec->info, &width, &height,
      &bpc, &pngdec->color_type, NULL, NULL, NULL);

  GST_LOG_OBJECT (pngdec, "this is a %dx%d PNG image", (gint) width,
      (gint) height);

  switch (pngdec->color_type) {
    case PNG_COLOR_TYPE_RGB:
      GST_LOG_OBJECT (pngdec, "we have no alpha channel, depth is 24 bits");
      if (bpc == 8)
        format = GST_VIDEO_FORMAT_RGB;
      break;
    case PNG_COLOR_TYPE_RGB_ALPHA:
      GST_LOG_OBJECT (pngdec,
          "we have an alpha channel, depth is 32 or 64 bits");
      if (bpc == 8)
        format = GST_VIDEO_FORMAT_RGBA;
      else if (bpc == 16)
        format = GST_VIDEO_FORMAT_ARGB64;
      break;
    case PNG_COLOR_TYPE_GRAY:
      GST_LOG_OBJECT (pngdec,
          "We have an gray image, depth is 8 or 16 (be) bits");
      if (bpc == 8)
        format = GST_VIDEO_FORMAT_GRAY8;
      else if (bpc == 16)
        format = GST_VIDEO_FORMAT_GRAY16_BE;
      break;
    default:
      break;
  }

  if (format == GST_VIDEO_FORMAT_UNKNOWN) {
    GST_ELEMENT_ERROR (pngdec, STREAM, NOT_IMPLEMENTED, (NULL),
        ("pngdec does not support this color type"));
    ret = GST_FLOW_NOT_SUPPORTED;
    goto beach;
  }

  /* Check if output state changed */
  if (pngdec->output_state) {
    GstVideoInfo *info = &pngdec->output_state->info;

    if (width == GST_VIDEO_INFO_WIDTH (info) &&
        height == GST_VIDEO_INFO_HEIGHT (info) &&
        GST_VIDEO_INFO_FORMAT (info) == format) {
      goto beach;
    }
    gst_video_codec_state_unref (pngdec->output_state);
  }

  pngdec->output_state =
      gst_video_decoder_set_output_state (GST_VIDEO_DECODER (pngdec), format,
      width, height, pngdec->input_state);
  gst_video_decoder_negotiate (GST_VIDEO_DECODER (pngdec));
  GST_DEBUG ("Final %d %d", GST_VIDEO_INFO_WIDTH (&pngdec->output_state->info),
      GST_VIDEO_INFO_HEIGHT (&pngdec->output_state->info));

beach:
  return ret;
}
Exemplo n.º 28
0
/* TODO: I wonder why this function ALWAYS returns 0 */
int loadPNG(ePtr<gPixmap> &result, const char *filename, int accel)
{
	CFile fp(filename, "rb");

	if (!fp)
	{
		eDebug("[ePNG] couldn't open %s", filename );
		return 0;
	}
	{
		__u8 header[8];
		if (!fread(header, 8, 1, fp))
		{
			eDebug("[ePNG] failed to get png header");
			return 0;
		}
		if (png_sig_cmp(header, 0, 8))
		{
			eDebug("[ePNG] header size mismatch");
			return 0;
		}
	}
	png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
	if (!png_ptr)
	{
		eDebug("[ePNG] failed to create read struct");
		return 0;
	}
	png_infop info_ptr = png_create_info_struct(png_ptr);
	if (!info_ptr)
	{
		eDebug("[ePNG] failed to create info struct");
		png_destroy_read_struct(&png_ptr, (png_infopp)0, (png_infopp)0);
		return 0;
	}
	png_infop end_info = png_create_info_struct(png_ptr);
	if (!end_info)
	{
		eDebug("[ePNG] failed to create end info struct");
		png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
		return 0;
	}
	if (setjmp(png_jmpbuf(png_ptr)))
	{
		eDebug("[ePNG] png setjump failed or activated");
		png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
		result = 0;
		return 0;
	}
	png_init_io(png_ptr, fp);
	png_set_sig_bytes(png_ptr, 8);
	png_read_info(png_ptr, info_ptr);

	png_uint_32 width, height;
	int bit_depth;
	int color_type;
	int interlace_type;
	int channels;
	int trns;

	png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, 0, 0);
	channels = png_get_channels(png_ptr, info_ptr);
	trns = png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS);
	//eDebug("[ePNG] %s: before %dx%dx%dbpcx%dchan coltyp=%d", filename, (int)width, (int)height, bit_depth, channels, color_type);

	/*
	 * gPixmaps use 8 bits per channel. rgb pixmaps are stored as abgr.
	 * So convert 1,2 and 4 bpc to 8bpc images that enigma can blit
	 * so add 'empty' alpha channel
	 * Expand G+tRNS to GA, RGB+tRNS to RGBA
	 */
	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 && bit_depth < 8)
		png_set_expand_gray_1_2_4_to_8(png_ptr);
	if (color_type == PNG_COLOR_TYPE_GRAY && trns)
		png_set_tRNS_to_alpha(png_ptr);
	if ((color_type == PNG_COLOR_TYPE_GRAY && trns) || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) {
		png_set_gray_to_rgb(png_ptr);
		png_set_bgr(png_ptr);
	}

	if (color_type == PNG_COLOR_TYPE_RGB) {
		if (trns)
			png_set_tRNS_to_alpha(png_ptr);
		else
			png_set_add_alpha(png_ptr, 255, PNG_FILLER_AFTER);
	}

	if (color_type == PNG_COLOR_TYPE_RGB || color_type == PNG_COLOR_TYPE_RGB_ALPHA)
		png_set_bgr(png_ptr);

	// Update the info structures after the transformations take effect
	if (interlace_type != PNG_INTERLACE_NONE)
		png_set_interlace_handling(png_ptr);  // needed before read_update_info()
	png_read_update_info (png_ptr, info_ptr);
	png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, 0, 0, 0);
	channels = png_get_channels(png_ptr, info_ptr);

	result = new gPixmap(eSize(width, height), bit_depth * channels, accel);
	gUnmanagedSurface *surface = result->surface;

	png_bytep *rowptr = new png_bytep[height];
	for (unsigned int i = 0; i < height; i++)
		rowptr[i] = ((png_byte*)(surface->data)) + i * surface->stride;
	png_read_image(png_ptr, rowptr);

	delete [] rowptr;

	int num_palette = -1, num_trans = -1;
	if (color_type == PNG_COLOR_TYPE_PALETTE) {
		if (png_get_valid(png_ptr, info_ptr, PNG_INFO_PLTE)) {
			png_color *palette;
			png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette);
			if (num_palette)
				surface->clut.data = new gRGB[num_palette];
			else
				surface->clut.data = 0;
			surface->clut.colors = num_palette;

			for (int i = 0; i < num_palette; i++) {
				surface->clut.data[i].a = 0;
				surface->clut.data[i].r = palette[i].red;
				surface->clut.data[i].g = palette[i].green;
				surface->clut.data[i].b = palette[i].blue;
			}
			if (trns) {
				png_byte *trans;
				png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, 0);
				for (int i = 0; i < num_trans; i++)
					surface->clut.data[i].a = 255 - trans[i];
				for (int i = num_trans; i < num_palette; i++)
					surface->clut.data[i].a = 0;
			}
		}
		else {
			surface->clut.data = 0;
			surface->clut.colors = 0;
		}
		surface->clut.start = 0;
	}
	//eDebug("[ePNG] %s: after  %dx%dx%dbpcx%dchan coltyp=%d cols=%d trans=%d", filename, (int)width, (int)height, bit_depth, channels, color_type, num_palette, num_trans);

	png_read_end(png_ptr, end_info);
	png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
	return 0;
}
Exemplo n.º 29
0
// Pull a texture off the graphics card
// Load a PNG file, and send it to upload_texture
SPTexture* SPTexture_frompng(const char* path) {
	SPTexture* texture = NULL;
	spTexID texid = spTexID_Bad;
	FILE* pngf = fopen(path, "rb");
	
	uint32_t width = 0;
	uint32_t height = 0;
	ubyte* pixmap = NULL;
	png_byte** row_heads = NULL;
	const size_t SIG_LENGTH = 8;
	
	png_structp png_state = NULL;
	png_infop png_info = NULL;

	if(pngf == NULL) {
		return texture;
	}
	
	// Ensure that the given path really is a PNG file
	{
		ubyte signature[8];
		size_t bytes_read = fread(signature, sizeof(byte), SIG_LENGTH, pngf);
		if(bytes_read < 8) {
			fclose(pngf);
			printf("Error\n");
			return texture;
		}
		
		if(png_sig_cmp(signature, 0, SIG_LENGTH)) {
			fclose(pngf);
			return texture;
		}
	}
	
	// Read the PNG file
	png_state = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
	png_info = png_create_info_struct(png_state);
	
	png_init_io(png_state, pngf);
	png_set_sig_bytes(png_state, SIG_LENGTH);
	
	if(setjmp(png_jmpbuf(png_state))) {	
		// Something went wrong while reading the PNG data
		png_destroy_read_struct(&png_state, &png_info, NULL);

		if(pixmap) {
			free(pixmap);
		}
		if(row_heads) {
			free(row_heads);
		}
		fclose(pngf);
		return spTexID_Bad;
	}
	
	// Prep work for reading the PNG 
	{
		png_read_info(png_state, png_info);
		width = png_get_image_width(png_state, png_info);
		height = png_get_image_height(png_state, png_info);
		
		// We use signed integers to correspond with glTexImage2D, but PNG uses uint32_t
		if(width >= INT_MAX || height >= INT_MAX) {
			return spTexID_Bad;
		}
		
		png_byte bit_depth = png_get_bit_depth(png_state, png_info);
		png_byte color_type = png_get_color_type(png_state, png_info);
		png_size_t stride = 0;

		// Ensure RGBA color
		if(color_type == PNG_COLOR_TYPE_PALETTE) {
			png_set_palette_to_rgb(png_state);
		}
		if(color_type == PNG_COLOR_TYPE_RGB) {
			png_set_add_alpha(png_state, 0xFF, PNG_FILLER_AFTER);
		}

		// Ensure exactly 8 bits of color
		if(bit_depth > 8) {
			png_set_strip_16(png_state);
		}
		else if(bit_depth < 8) {
			png_set_packing(png_state);
		}
		
		png_read_update_info(png_state, png_info);

		// Create blank, safe-ish row pointers that point inside a dense pixmap
		stride = png_get_rowbytes(png_state, png_info);
		pixmap = malloc(stride * height);
		row_heads = calloc(sizeof(byte*), height);
		for(uint32_t row=0; row<height; row++) {
			// I've read that OpenGL expects rows in the opposite order, but
			// this works fine
			row_heads[row] = pixmap + row*stride;
//			row_heads[row] = &(pixmap[(height-row-1)*stride]);
		}
		
		// Read in the PNG data
		png_read_image(png_state, row_heads);
		texid = upload_texture(spTextureFmt_RGBA, (GLsizei)width, (GLsizei)height, pixmap);
		
		// Goodness gracious, Spaceman!  What a mess to clean!
		png_destroy_read_struct(&png_state, &png_info, NULL);
		free(row_heads);
		free(pixmap);
	}
	
	fclose(pngf);

	texture = SPTexture_new(width, height, texid);

	return texture;
}
Exemplo n.º 30
0
APNGDATA * loadPng(IPngReader *pSrc)
{
	png_bytep  dataFrame;
	png_uint_32 bytesPerRow;
	png_uint_32 bytesPerFrame;
    png_bytepp rowPointers;
	png_byte   sig[8];
	
	png_structp png_ptr_read;
	png_infop info_ptr_read;
	
    pSrc->read(sig,8);
    if(!png_check_sig(sig,8))
    {
        return NULL;
    }
    
    png_ptr_read = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);

    info_ptr_read = png_create_info_struct(png_ptr_read);
    
	if (setjmp(png_jmpbuf(png_ptr_read)))
    {
        png_destroy_read_struct(&png_ptr_read, &info_ptr_read, NULL);
        return NULL;
    }
        
    png_set_read_fn(png_ptr_read,pSrc,mypng_read_data);
    png_set_sig_bytes(png_ptr_read, 8);
 
    if ((png_ptr_read->bit_depth < 8) ||
        (png_ptr_read->color_type == PNG_COLOR_TYPE_PALETTE) ||
        (info_ptr_read->valid & PNG_INFO_tRNS))
        png_set_expand(png_ptr_read);

    png_set_add_alpha(png_ptr_read, 0xff, PNG_FILLER_AFTER);
    png_set_interlace_handling(png_ptr_read);
    png_set_gray_to_rgb(png_ptr_read);
    png_set_strip_16(png_ptr_read);
   
	png_read_info(png_ptr_read, info_ptr_read);
    png_read_update_info(png_ptr_read, info_ptr_read);
    
    bytesPerRow = png_ptr_read->width * 4;
    bytesPerFrame = bytesPerRow * png_ptr_read->height;
    
    APNGDATA * apng = (APNGDATA*) malloc(sizeof(APNGDATA));
    memset(apng,0,sizeof(APNGDATA));
    apng->nWid  = png_ptr_read->width;
    apng->nHei = png_ptr_read->height;
    
    //图像帧数据
    dataFrame = (png_bytep)malloc(bytesPerRow * apng->nHei);
    memset(dataFrame,0,bytesPerFrame);
    //获得扫描行指针
    rowPointers = (png_bytepp)malloc(sizeof(png_bytep)* apng->nHei);
    for(int i=0;i<apng->nHei;i++)
        rowPointers[i] = dataFrame + bytesPerRow * i;

	if (!png_get_valid(png_ptr_read, info_ptr_read, PNG_INFO_acTL))
	{//load png doesn't has this trunk.
        
        png_read_image(png_ptr_read,rowPointers);
                
        apng->pdata =dataFrame;
        apng->nFrames =1;
	}else
	{//load apng
        apng->nFrames  = png_get_num_frames(png_ptr_read, info_ptr_read);//获取总帧数

        png_bytep data = (png_bytep)malloc( bytesPerFrame * apng->nFrames);//为每一帧分配内存
        png_bytep curFrame = (png_bytep)malloc(bytesPerFrame);
        memset(curFrame,0,bytesPerFrame);
               
        apng->nLoops = png_get_num_plays(png_ptr_read, info_ptr_read);
        apng->pDelay = (unsigned short*)malloc(sizeof(unsigned short)*apng->nFrames);
        
        for(int iFrame = 0;iFrame<apng->nFrames;iFrame++)
        {
            //读帧信息头
            png_read_frame_head(png_ptr_read, info_ptr_read);
            
            //计算出帧延时信息
            if (png_get_valid(png_ptr_read, info_ptr_read, PNG_INFO_fcTL))
            {
                png_uint_16 delay_num = info_ptr_read->next_frame_delay_num,
                            delay_den = info_ptr_read->next_frame_delay_den;
            
                if (delay_den==0 || delay_den==100)
                    apng->pDelay[iFrame] = delay_num;
                else
                    if (delay_den==10)
                        apng->pDelay[iFrame] = delay_num*10;
                    else
                        if (delay_den==1000)
                            apng->pDelay[iFrame] = delay_num/10;
                        else
                            apng->pDelay[iFrame] = delay_num*100/delay_den;
            }else
            {
                apng->pDelay[iFrame] = 0;
            }
            //读取PNG帧到dataFrame中,不含偏移数据
            png_read_image(png_ptr_read, rowPointers);
            {//将当前帧数据绘制到当前显示帧中:1)获得绘制的背景;2)计算出绘制位置; 3)使用指定的绘制方式与背景混合


                //1)计算出绘制位置
                png_bytep lineDst=curFrame+info_ptr_read->next_frame_y_offset*bytesPerRow + 4 * info_ptr_read->next_frame_x_offset;
                png_bytep lineSour=dataFrame;
                //2)使用指定的绘制方式与背景混合
                switch(info_ptr_read->next_frame_blend_op)
                {
                case PNG_BLEND_OP_OVER:
                    {
                        for(unsigned int y=0;y<info_ptr_read->next_frame_height;y++)
                        {
                            png_bytep lineDst1=lineDst;
                            png_bytep lineSour1=lineSour;
                            for(unsigned int x=0;x<info_ptr_read->next_frame_width;x++)
                            {
                                png_byte alpha = lineSour1[3];
                                *lineDst1++ = ((*lineDst1)*(255-alpha)+(*lineSour1++)*alpha)>>8;
                                *lineDst1++ = ((*lineDst1)*(255-alpha)+(*lineSour1++)*alpha)>>8;
                                *lineDst1++ = ((*lineDst1)*(255-alpha)+(*lineSour1++)*alpha)>>8;
                                *lineDst1++ = ((*lineDst1)*(255-alpha)+(*lineSour1++)*alpha)>>8;
                            }
                            lineDst += bytesPerRow;
                            lineSour+= bytesPerRow;
                        }
                    }
                    break;
                case PNG_BLEND_OP_SOURCE:
                    {
                        for(unsigned int  y=0;y<info_ptr_read->next_frame_height;y++)
                        {
                            memcpy(lineDst,lineSour,info_ptr_read->next_frame_width*4);
                            lineDst += bytesPerRow;
                            lineSour+= bytesPerRow;
                        }
                    }
                    break;
                default:
                    SASSERT(FALSE);
                    break;
                }
                
                png_bytep targetFrame = data + bytesPerFrame * iFrame;
                memcpy(targetFrame,curFrame,bytesPerFrame);

                lineDst=curFrame+info_ptr_read->next_frame_y_offset*bytesPerRow + 4 * info_ptr_read->next_frame_x_offset;

                //3)处理当前帧绘制区域
                switch(info_ptr_read->next_frame_dispose_op)
                {
                case PNG_DISPOSE_OP_BACKGROUND://clear background
                    {
                        for(unsigned int y=0;y<info_ptr_read->next_frame_height;y++)
                        {
                            memset(lineDst,0,info_ptr_read->next_frame_width*4);
                            lineDst += bytesPerRow;
                        }

                    }
                    break;
                case PNG_DISPOSE_OP_PREVIOUS://copy previous frame
                    if(iFrame>0)
                    {
                        memcpy(curFrame,targetFrame-bytesPerFrame,bytesPerFrame);
                    }
                    break;
                case PNG_DISPOSE_OP_NONE://using current frame, doing nothing
                    break;
                default:
                    SASSERT(0);
                    break;
                }
            }

        }
        free(curFrame);
        free(dataFrame);
        apng->pdata =data;
	}
    free(rowPointers);

	png_read_end(png_ptr_read,info_ptr_read);
	
    png_destroy_read_struct(&png_ptr_read, &info_ptr_read, NULL);
    return apng;    
}