[Scummvm-cvs-logs] SF.net SVN: scummvm:[55723] scummvm/trunk

thebluegr at users.sourceforge.net thebluegr at users.sourceforge.net
Wed Feb 2 16:43:45 CET 2011


Revision: 55723
          http://scummvm.svn.sourceforge.net/scummvm/?rev=55723&view=rev
Author:   thebluegr
Date:     2011-02-02 15:43:45 +0000 (Wed, 02 Feb 2011)

Log Message:
-----------
GRAPHICS: Implemented a PNG decoder, and set it as default for the sword25 engine

libpng is still needed for PNG encoding (for thumbnails in saved games of sword25), but
since we'll probably drop support for the original saved games anyway, the PNG encoding
code will ultimately be removed

Modified Paths:
--------------
    scummvm/trunk/engines/sword25/gfx/image/pngloader.cpp
    scummvm/trunk/graphics/module.mk

Added Paths:
-----------
    scummvm/trunk/graphics/png.cpp
    scummvm/trunk/graphics/png.h

Modified: scummvm/trunk/engines/sword25/gfx/image/pngloader.cpp
===================================================================
--- scummvm/trunk/engines/sword25/gfx/image/pngloader.cpp	2011-02-02 15:35:05 UTC (rev 55722)
+++ scummvm/trunk/engines/sword25/gfx/image/pngloader.cpp	2011-02-02 15:43:45 UTC (rev 55723)
@@ -32,13 +32,23 @@
  *
  */
 
+// Define to use ScummVM's PNG decoder, instead of libpng
+#define USE_INTERNAL_PNG_DECODER
+
+#ifndef USE_INTERNAL_PNG_DECODER
 // Disable symbol overrides so that we can use png.h
 #define FORBIDDEN_SYMBOL_ALLOW_ALL
+#endif
 
 #include "common/memstream.h"
 #include "sword25/gfx/image/image.h"
 #include "sword25/gfx/image/pngloader.h"
+#ifndef USE_INTERNAL_PNG_DECODER
 #include <png.h>
+#else
+#include "graphics/pixelformat.h"
+#include "graphics/png.h"
+#endif
 
 namespace Sword25 {
 
@@ -87,6 +97,7 @@
 	return static_cast<uint>(stream.pos() + compressedGamedataSize);
 }
 
+#ifndef USE_INTERNAL_PNG_DECODER
 static void png_user_read_data(png_structp png_ptr, png_bytep data, png_size_t length) {
 	const byte **ref = (const byte **)png_get_io_ptr(png_ptr);
 	memcpy(data, *ref, length);
@@ -96,9 +107,10 @@
 static bool doIsCorrectImageFormat(const byte *fileDataPtr, uint fileSize) {
 	return (fileSize > 8) && png_check_sig(const_cast<byte *>(fileDataPtr), 8);
 }
+#endif
 
-
 bool PNGLoader::doDecodeImage(const byte *fileDataPtr, uint fileSize, byte *&uncompressedDataPtr, int &width, int &height, int &pitch) {
+#ifndef USE_INTERNAL_PNG_DECODER
 	png_structp png_ptr = NULL;
 	png_infop   info_ptr = NULL;
 
@@ -202,7 +214,25 @@
 
 	// Destroy libpng structures
 	png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
+#else
+	Common::MemoryReadStream *fileStr = new Common::MemoryReadStream(fileDataPtr, fileSize, DisposeAfterUse::NO);
+	Graphics::PNG *png = new Graphics::PNG();
+	if (!png->read(fileStr))	// the fileStr pointer, and thus pFileData will be deleted after this is done
+		error("Error while reading PNG image");	
 
+	Graphics::PixelFormat format = Graphics::PixelFormat(4, 8, 8, 8, 8, 16, 8, 0, 24);
+	Graphics::Surface *pngSurface = png->getSurface(format);
+
+	width = pngSurface->w;
+	height = pngSurface->h;
+	uncompressedDataPtr = new byte[pngSurface->pitch * pngSurface->h];
+	memcpy(uncompressedDataPtr, (byte *)pngSurface->pixels, pngSurface->pitch * pngSurface->h);
+	pngSurface->free();
+
+	delete pngSurface;
+	delete png;
+
+#endif
 	// Signal success
 	return true;
 }
@@ -213,6 +243,7 @@
 }
 
 bool PNGLoader::doImageProperties(const byte *fileDataPtr, uint fileSize, int &width, int &height) {
+#ifndef USE_INTERNAL_PNG_DECODER
 	// Check for valid PNG signature
 	if (!doIsCorrectImageFormat(fileDataPtr, fileSize))
 		return false;
@@ -249,7 +280,9 @@
 
 	// Die Strukturen freigeben
 	png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
-
+#else
+	// We don't need to read the image properties here...
+#endif
 	return true;
 
 }

Modified: scummvm/trunk/graphics/module.mk
===================================================================
--- scummvm/trunk/graphics/module.mk	2011-02-02 15:35:05 UTC (rev 55722)
+++ scummvm/trunk/graphics/module.mk	2011-02-02 15:43:45 UTC (rev 55723)
@@ -15,6 +15,7 @@
 	imagedec.o \
 	jpeg.o \
 	pict.o \
+	png.o \
 	primitives.o \
 	scaler.o \
 	scaler/thumbnail_intern.o \

Added: scummvm/trunk/graphics/png.cpp
===================================================================
--- scummvm/trunk/graphics/png.cpp	                        (rev 0)
+++ scummvm/trunk/graphics/png.cpp	2011-02-02 15:43:45 UTC (rev 55723)
@@ -0,0 +1,449 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "graphics/conversion.h"
+#include "graphics/png.h"
+#include "graphics/pixelformat.h"
+
+#include "common/endian.h"
+#include "common/memstream.h"
+#include "common/stream.h"
+#include "common/util.h"
+#include "common/zlib.h"
+
+namespace Graphics {
+
+enum PNGChunks {
+	// == Critical chunks =====================================================
+	kChunkIHDR = MKID_BE('IHDR'),	// Image header
+	kChunkIDAT = MKID_BE('IDAT'),	// Image data
+	kChunkPLTE = MKID_BE('PLTE'),	// Palette
+	kChunkIEND = MKID_BE('IEND'),	// Image trailer
+	// == Ancillary chunks ====================================================
+	kChunktRNS = MKID_BE('tRNS')	// Transparency
+	// All of the other ancillary chunks are ignored. They're added here for
+	// reference only.
+	// cHRM - Primary chromacities and white point
+	// gAMA - Image gamma
+	// iCCP - Embedded ICC profile
+	// sBIT - Significant bits
+	// sRGB - Standard RGB color space
+	// tEXT - Textual data
+	// sTXt - Compressed textual data
+	// iTXt - International textual data
+	// bKGD - Background color
+	// hIST - Image histogram
+	// pHYs - Physical pixel dimensions
+	// sPLT - Suggested palette
+	// tIME - Image last-modification time
+};
+
+// Refer to http://www.w3.org/TR/PNG/#9Filters
+enum PNGFilters {
+	kFilterNone    = 0,
+	kFilterSub     = 1,
+	kFilterUp      = 2,
+	kFilterAverage = 3,
+	kFilterPaeth   = 4
+};
+
+#define PNG_HEADER(a, b, c, d) CONSTANT_LE_32(d | (c << 8) | (b << 16) | (a << 24))
+
+PNG::PNG() : _compressedBuffer(0), _compressedBufferSize(0), 
+			_unfilteredSurface(0), _transparentColorSpecified(false) {
+}
+
+PNG::~PNG() {
+	if (_unfilteredSurface) {
+		_unfilteredSurface->free();
+		delete _unfilteredSurface;
+	}
+}
+
+Graphics::Surface *PNG::getSurface(const PixelFormat &format) {
+	Graphics::Surface *output = new Graphics::Surface();
+	output->create(_unfilteredSurface->w, _unfilteredSurface->h, format.bytesPerPixel);
+	byte *src = (byte *)_unfilteredSurface->pixels;
+	byte a = 0xFF;
+
+	if (_header.colorType != kIndexed) {
+		if (_header.colorType == kTrueColor || _header.colorType == kTrueColorWithAlpha) {
+			if (_unfilteredSurface->bytesPerPixel != 3 && _unfilteredSurface->bytesPerPixel != 4)
+				error("Unsupported truecolor PNG format");
+		} else if (_header.colorType == kGrayScale || _header.colorType == kGrayScaleWithAlpha) {
+			if (_unfilteredSurface->bytesPerPixel != 1 && _unfilteredSurface->bytesPerPixel != 2)
+				error("Unsupported grayscale PNG format");
+		}
+
+		for (uint16 i = 0; i < output->h; i++) {
+			for (uint16 j = 0; j < output->w; j++) {
+				if (format.bytesPerPixel == 2) {
+					if (_unfilteredSurface->bytesPerPixel == 1) {		// Grayscale
+						if (_transparentColorSpecified)
+							a = (src[0] == _transparentColor[0]) ? 0 : 0xFF;
+						*((uint16 *)output->getBasePtr(j, i)) = format.ARGBToColor(    a, src[0], src[0], src[0]);
+					} else if (_unfilteredSurface->bytesPerPixel == 2) {	// Grayscale + alpha
+						*((uint16 *)output->getBasePtr(j, i)) = format.ARGBToColor(src[1], src[0], src[0], src[0]);
+					} else if (_unfilteredSurface->bytesPerPixel == 3) {	// RGB
+						if (_transparentColorSpecified) {
+							bool isTransparentColor = (src[0] == _transparentColor[0] &&
+													   src[1] == _transparentColor[1] &&
+													   src[2] == _transparentColor[2]);
+							a = isTransparentColor ? 0 : 0xFF;
+						}
+						*((uint16 *)output->getBasePtr(j, i)) = format.ARGBToColor(     a, src[0], src[1], src[2]);
+					} else if (_unfilteredSurface->bytesPerPixel == 4) {	// RGBA
+						*((uint16 *)output->getBasePtr(j, i)) = format.ARGBToColor(src[3], src[0], src[1], src[2]);
+					}
+				} else {
+					if (_unfilteredSurface->bytesPerPixel == 1) {		// Grayscale
+						if (_transparentColorSpecified)
+							a = (src[0] == _transparentColor[0]) ? 0 : 0xFF;
+						*((uint32 *)output->getBasePtr(j, i)) = format.ARGBToColor(     a, src[0], src[0], src[0]);
+					} else if (_unfilteredSurface->bytesPerPixel == 2) {	// Grayscale + alpha
+						*((uint32 *)output->getBasePtr(j, i)) = format.ARGBToColor(src[1], src[0], src[0], src[0]);
+					} else if (_unfilteredSurface->bytesPerPixel == 3) {	// RGB
+						if (_transparentColorSpecified) {
+							bool isTransparentColor = (src[0] == _transparentColor[0] &&
+													   src[1] == _transparentColor[1] &&
+													   src[2] == _transparentColor[2]);
+							a = isTransparentColor ? 0 : 0xFF;
+						}
+						*((uint32 *)output->getBasePtr(j, i)) = format.ARGBToColor(     a, src[0], src[1], src[2]);
+					} else if (_unfilteredSurface->bytesPerPixel == 4) {	// RGBA
+						*((uint32 *)output->getBasePtr(j, i)) = format.ARGBToColor(src[3], src[0], src[1], src[2]);
+					}
+				}
+
+				src += _unfilteredSurface->bytesPerPixel;
+			}
+		}
+	} else {
+		byte index, r, g, b;
+
+		// Convert the indexed surface to the target pixel format
+		for (uint16 i = 0; i < output->h; i++) {
+			for (uint16 j = 0; j < output->w; j++) {
+				index = *src;
+				r = _palette[index * 4 + 0];
+				g = _palette[index * 4 + 1];
+				b = _palette[index * 4 + 2];
+				a = _palette[index * 4 + 3];
+
+				if (format.bytesPerPixel == 2)
+					*((uint16 *)output->getBasePtr(j, i)) = format.ARGBToColor(a, r, g, b);
+				else
+					*((uint32 *)output->getBasePtr(j, i)) = format.ARGBToColor(a, r, g, b);
+
+				src++;
+			}
+		}
+	}
+
+	return output;
+}
+
+bool PNG::read(Common::SeekableReadStream *str) {
+	uint32 chunkLength = 0, chunkType = 0;
+	_stream = str;
+
+	// First, check the PNG signature
+	if (_stream->readUint32BE() != PNG_HEADER(0x89, 0x50, 0x4e, 0x47)) {
+		delete _stream;
+		return false;
+	}
+	if (_stream->readUint32BE() != PNG_HEADER(0x0d, 0x0a, 0x1a, 0x0a)) {
+		delete _stream;
+		return false;
+	}
+
+	// Start reading chunks till we reach an IEND chunk
+	while (chunkType != kChunkIEND) {
+		// The chunk length does not include the type or CRC bytes
+		chunkLength = _stream->readUint32BE();
+		chunkType = _stream->readUint32BE();
+
+		switch (chunkType) {
+		case kChunkIHDR:
+			readHeaderChunk();
+			break;
+		case kChunkIDAT:
+			if (_compressedBufferSize == 0) {
+				_compressedBufferSize += chunkLength;
+				_compressedBuffer = new byte[_compressedBufferSize];
+				_stream->read(_compressedBuffer, chunkLength);
+			} else {
+				// Expand the buffer
+				uint32 prevSize = _compressedBufferSize;
+				_compressedBufferSize += chunkLength;
+				byte *tmp = new byte[prevSize];
+				memcpy(tmp, _compressedBuffer, prevSize);
+				delete[] _compressedBuffer;
+				_compressedBuffer = new byte[_compressedBufferSize];
+				memcpy(_compressedBuffer, tmp, prevSize);
+				delete[] tmp;
+				_stream->read(_compressedBuffer + prevSize, chunkLength);
+			}
+			break;
+		case kChunkPLTE:	// only available in indexed PNGs
+			if (_header.colorType != kIndexed)
+				error("A palette chunk has been found in a non-indexed PNG file");
+			if (chunkLength % 3 != 0)
+				error("Palette chunk not divisible by 3");
+			_paletteEntries = chunkLength / 3;
+			readPaletteChunk();
+			break;
+		case kChunkIEND:
+			// End of stream
+			break;
+		case kChunktRNS:
+			readTransparencyChunk(chunkLength);
+			break;
+		default:
+			// Skip the chunk content
+			_stream->skip(chunkLength);
+			break;
+		}
+
+		if (chunkType != kChunkIEND)
+			_stream->skip(4);	// skip the chunk CRC checksum
+	}
+
+	// We no longer need the file stream, thus close it here
+	delete _stream;
+	_stream = 0;
+
+	// Unpack the compressed buffer
+	Common::MemoryReadStream *compData = new Common::MemoryReadStream(_compressedBuffer, _compressedBufferSize, DisposeAfterUse::YES);
+	_imageData = Common::wrapCompressedReadStream(compData);
+	
+	// Construct the final image
+	constructImage();
+
+	// Close the uncompressed stream, which will also delete the memory stream,
+	// and thus the original compressed buffer
+	delete _imageData;
+
+	return true;
+}
+
+/**
+ * Paeth predictor, used by PNG filter type 4
+ * The parameters are of signed 16-bit integers, but should come
+ * from unsigned chars. The integers  are only needed to make
+ * the paeth calculation correct.
+ *
+ * Taken from lodePNG, with a slight patch:
+ * http://www.atalasoft.com/cs/blogs/stevehawley/archive/2010/02/23/libpng-you-re-doing-it-wrong.aspx
+ */
+byte PNG::paethPredictor(int16 a, int16 b, int16 c) {
+  int16 pa = ABS<int16>(b - c);
+  int16 pb = ABS<int16>(a - c);
+  int16 pc = ABS<int16>(a + b - c - c);
+    
+  if (pa <= MIN<int16>(pb, pc))
+	  return (byte)a;
+  else if (pb <= pc)
+	  return (byte)b;
+  else
+	  return (byte)c;
+}
+
+/**
+ * Unfilters a filtered PNG scan line.
+ * PNG filters are defined in: http://www.w3.org/TR/PNG/#9Filters
+ * Note that filters are always applied to bytes
+ *
+ * Taken from lodePNG
+ */
+void PNG::unfilterScanLine(byte *dest, const byte *scanLine, const byte *prevLine, uint16 byteWidth, byte filterType, uint16 length) {
+	uint16 i;
+
+	switch (filterType) {
+	case kFilterNone:		// no change
+		for (i = 0; i < length; i++)
+			dest[i] = scanLine[i];
+		break;
+	case kFilterSub:		// add the bytes to the left
+		for (i = 0; i < byteWidth; i++)
+			dest[i] = scanLine[i];
+		for (i = byteWidth; i < length; i++)
+			dest[i] = scanLine[i] + dest[i - byteWidth];
+		break;
+	case kFilterUp:			// add the bytes of the above scanline
+		if (prevLine) {
+			for (i = 0; i < length; i++)
+				dest[i] = scanLine[i] + prevLine[i];
+		} else {
+			for (i = 0; i < length; i++)
+				dest[i] = scanLine[i];
+		}
+		break;
+	case kFilterAverage:	// average value of the left and top left
+		if (prevLine) {
+			for (i = 0; i < byteWidth; i++)
+				dest[i] = scanLine[i] + prevLine[i] / 2;
+			for (i = byteWidth; i < length; i++)
+				dest[i] = scanLine[i] + ((dest[i - byteWidth] + prevLine[i]) / 2);
+		} else {
+			for (i = 0; i < byteWidth; i++)
+				dest[i] = scanLine[i];
+			for (i = byteWidth; i < length; i++)
+				dest[i] = scanLine[i] + dest[i - byteWidth] / 2;
+		}
+		break;
+	case kFilterPaeth:		// Paeth filter: http://www.w3.org/TR/PNG/#9Filter-type-4-Paeth
+		if (prevLine) {
+			for(i = 0; i < byteWidth; i++)
+				dest[i] = (scanLine[i] + prevLine[i]); // paethPredictor(0, prevLine[i], 0) is always prevLine[i]
+			for(i = byteWidth; i < length; i++)
+				dest[i] = (scanLine[i] + paethPredictor(dest[i - byteWidth], prevLine[i], prevLine[i - byteWidth]));
+		} else {
+			for(i = 0; i < byteWidth; i++)
+				dest[i] = scanLine[i];
+			for(i = byteWidth; i < length; i++)
+				dest[i] = (scanLine[i] + dest[i - byteWidth]); // paethPredictor(dest[i - byteWidth], 0, 0) is always dest[i - byteWidth]
+		}
+		break;
+	default:
+		error("Unknown line filter");
+	}
+
+}
+
+void PNG::constructImage() {
+	assert (_header.bitDepth != 0);
+
+	byte *dest;
+	byte *scanLine;
+	byte *prevLine = 0;
+	byte filterType;
+	uint16 scanLineWidth = (_header.width * getNumColorChannels() * _header.bitDepth + 7) / 8;
+
+	if (_unfilteredSurface) {
+		_unfilteredSurface->free();
+		delete _unfilteredSurface;
+	}
+	_unfilteredSurface = new Graphics::Surface();
+	_unfilteredSurface->create(_header.width, _header.height, (getNumColorChannels() * _header.bitDepth + 7) / 8);
+	scanLine = new byte[_unfilteredSurface->pitch];
+	dest = (byte *)_unfilteredSurface->getBasePtr(0, 0);
+
+	switch(_header.interlaceType) {
+	case kNonInterlaced:
+		for (uint16 y = 0; y < _unfilteredSurface->h; y++) {
+			filterType = _imageData->readByte();
+			_imageData->read(scanLine, scanLineWidth);
+			unfilterScanLine(dest, scanLine, prevLine, _unfilteredSurface->bytesPerPixel, filterType, scanLineWidth);
+			prevLine = dest;
+			dest += _unfilteredSurface->pitch;
+		}
+		break;
+	case kInterlaced:
+		// Theoretically, this shouldn't be needed, as interlacing is only
+		// useful for web images. Interlaced PNG images require more complex
+		// handling, so unless having support for such images is needed, there
+		// is no reason to add support for them.
+		error("TODO: Support for interlaced PNG images");
+		break;
+	}
+
+	delete[] scanLine;
+}
+
+void PNG::readHeaderChunk() {
+	_header.width = _stream->readUint32BE();
+	_header.height = _stream->readUint32BE();
+	_header.bitDepth = _stream->readByte();
+	if (_header.bitDepth > 8)
+		error("Only PNGs with a bit depth of 1-8 bits are supported (i.e. PNG24)");
+	_header.colorType = (PNGColorType)_stream->readByte();
+	_header.compressionMethod = _stream->readByte();
+	// Compression methods: http://www.w3.org/TR/PNG/#10Compression
+	// Only compression method 0 (deflate) is documented and supported
+	if (_header.compressionMethod != 0)
+		error("Unknown PNG compression method: %d", _header.compressionMethod);
+	_header.filterMethod = _stream->readByte();
+	// Filter methods: http://www.w3.org/TR/PNG/#9Filters
+	// Only filter method 0 is documented and supported
+	if (_header.filterMethod != 0)
+		error("Unknown PNG filter method: %d", _header.filterMethod);
+	_header.interlaceType = (PNGInterlaceType)_stream->readByte();
+}
+
+byte PNG::getNumColorChannels() {
+	switch (_header.colorType) {
+	case kGrayScale:
+		return 1; // Gray
+	case kTrueColor:
+		return 3; // RGB
+	case kIndexed:
+		return 1; // Indexed
+	case kGrayScaleWithAlpha:
+		return 2; // Gray + Alpha
+	case kTrueColorWithAlpha:
+		return 4; // RGBA
+	default:
+		error("Unknown color type");
+	}
+}
+
+void PNG::readPaletteChunk() {
+	for (byte i = 0; i < _paletteEntries; i++) {
+		_palette[i * 4 + 0] = _stream->readByte();	// R
+		_palette[i * 4 + 1] = _stream->readByte();	// G
+		_palette[i * 4 + 2] = _stream->readByte();	// B
+		_palette[i * 4 + 3] = 0xFF;	// Alpha, set in the tRNS chunk
+	}
+}
+
+void PNG::readTransparencyChunk(uint32 chunkLength) {
+	_transparentColorSpecified = true;
+
+	switch(_header.colorType) {
+	case kGrayScale:
+		_transparentColor[0] = _stream->readUint16BE();
+		_transparentColor[1] = _transparentColor[0];
+		_transparentColor[2] = _transparentColor[0];
+		break;
+	case kTrueColor:
+		_transparentColor[0] = _stream->readUint16BE();
+		_transparentColor[1] = _stream->readUint16BE();
+		_transparentColor[2] = _stream->readUint16BE();
+		break;
+	case kIndexed:
+		for (uint32 i = 0; i < chunkLength; i++)
+			_palette[i * 4 + 3] = _stream->readByte();
+		// A transparency chunk may have less entries
+		// than the palette entries. The remaining ones
+		// are unmodified (set to 255). Check here:
+		// http://www.w3.org/TR/PNG/#11tRNS
+		break;
+	default:
+		error("Transparency chunk found in a PNG that has a separate transparency channel");
+	}
+}
+
+} // End of Graphics namespace


Property changes on: scummvm/trunk/graphics/png.cpp
___________________________________________________________________
Added: svn:mime-type
   + text/plain
Added: svn:keywords
   + Date Rev Author URL Id
Added: svn:eol-style
   + native

Added: scummvm/trunk/graphics/png.h
===================================================================
--- scummvm/trunk/graphics/png.h	                        (rev 0)
+++ scummvm/trunk/graphics/png.h	2011-02-02 15:43:45 UTC (rev 55723)
@@ -0,0 +1,162 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+/*
+ * PNG decoder used in engines:
+ *  - sword25
+ */
+
+#ifndef GRAPHICS_PNG_H
+#define GRAPHICS_PNG_H
+
+#include "graphics/surface.h"
+
+// PNG decoder, based on the W3C specs:
+// http://www.w3.org/TR/PNG/
+// and lodePNG:
+// http://members.gamedev.net/lode/projects/LodePNG/
+// and the ysflight PNG decoder:
+// http://homepage3.nifty.com/ysflight/pngdecoder/pngdecodere.html
+
+// All the numbers are BE: http://www.w3.org/TR/PNG/#7Integers-and-byte-order
+
+// Note: At the moment, this decoder only supports non-interlaced images, and
+// does not support truecolor/grayscale images with 16bit depth.
+//
+// Theoretically, interlaced images shouldn't be needed for games, as
+// interlacing is only useful for images in websites.
+//
+// PNG images with 16bit depth (i.e. 48bit images) are quite rare, and can
+// theoretically contain more than 16.7 millions of colors (the so-called "deep
+// color" representation). In essence, each of the R, G, B and A components in
+// them is specified with 2 bytes, instead of 1. However, the PNG specification
+// always refers to color components with 1 byte each, so this part of the spec
+// is a bit unclear. For now, these won't be supported, until a suitable sample
+// is found.
+
+namespace Common {
+class SeekableReadStream;
+}
+
+namespace Graphics {
+
+enum PNGColorType {
+	kGrayScale          = 0,	// bit depths: 1, 2, 4, 8, 16
+	kTrueColor          = 2,	// bit depths: 8, 16
+	kIndexed            = 3,	// bit depths: 1, 2, 4, 8
+	kGrayScaleWithAlpha = 4,	// bit depths: 8, 16
+	kTrueColorWithAlpha = 6		// bit depths: 8, 16
+};
+
+enum PNGInterlaceType {
+	kNonInterlaced      = 0,
+	kInterlaced         = 1
+};
+
+struct PNGHeader {
+	uint32 width;
+	uint32 height;
+	byte bitDepth;
+	PNGColorType colorType;
+	byte compressionMethod;
+	byte filterMethod;
+	PNGInterlaceType interlaceType;
+};
+
+struct PixelFormat;
+
+class PNG {
+public:
+	PNG();
+	~PNG();
+
+	/**
+	 * Reads a PNG image from the specified stream
+	 */
+	bool read(Common::SeekableReadStream *str);
+
+	/**
+	 * Returns the information obtained from the PNG header.
+	 */
+	PNGHeader getHeader() const { return _header; }
+
+	/**
+	 * Returns the PNG image, formatted for the specified pixel format.
+	 */
+	Graphics::Surface *getSurface(const PixelFormat &format);
+
+	/**
+	 * Returns the indexed PNG8 image. Used for PNGs with an indexed 256 color
+	 * palette, when they're shown on an 8-bit color screen, as no translation
+	 * is taking place.
+	 */
+	Graphics::Surface *getIndexedSurface() {
+		if (_header.colorType != kIndexed)
+			error("Indexed surface requested for a non-indexed PNG");
+		return _unfilteredSurface;
+	}
+
+	/**
+	 * Returns the palette of the specified PNG8 image
+	 */
+	void getPalette(byte *palette, byte &entries) {
+		if (_header.colorType != kIndexed)
+			error("Palette requested for a non-indexed PNG");
+		palette = _palette;
+		entries = _paletteEntries;
+	}
+
+private:
+	void readHeaderChunk();
+	byte getNumColorChannels();
+
+	void readPaletteChunk();
+	void readTransparencyChunk(uint32 chunkLength);
+
+	void constructImage();
+	void unfilterScanLine(byte *dest, const byte *scanLine, const byte *prevLine, uint16 byteWidth, byte filterType, uint16 length);
+	byte paethPredictor(int16 a, int16 b, int16 c);
+
+	// The original file stream
+	Common::SeekableReadStream *_stream;
+	// The unzipped image data stream
+	Common::SeekableReadStream *_imageData;
+
+	PNGHeader _header;
+
+	byte _palette[256 * 4];	// RGBA
+	byte _paletteEntries;
+	uint16 _transparentColor[3];
+	bool _transparentColorSpecified;
+
+	byte *_compressedBuffer;
+	uint32 _compressedBufferSize;
+
+	Graphics::Surface *_unfilteredSurface;
+};
+
+} // End of Graphics namespace
+
+#endif // GRAPHICS_PNG_H


Property changes on: scummvm/trunk/graphics/png.h
___________________________________________________________________
Added: svn:mime-type
   + text/plain
Added: svn:keywords
   + Date Rev Author URL Id
Added: svn:eol-style
   + native


This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.




More information about the Scummvm-git-logs mailing list