PageRenderTime 17ms CodeModel.GetById 1ms app.highlight 13ms RepoModel.GetById 1ms app.codeStats 1ms

/xbmc/screensavers/rsxs-0.9/src/pngimage.cc

http://github.com/xbmc/xbmc
C++ | 206 lines | 162 code | 22 blank | 22 comment | 27 complexity | 0ffa13c8acccd80ff9d80b6dfd4e5a0f MD5 | raw file
  1/*
  2 * Really Slick XScreenSavers
  3 * Copyright (C) 2002-2006  Michael Chapman
  4 *
  5 * This program is free software; you can redistribute it and/or modify
  6 * it under the terms of the GNU General Public License version 2 as
  7 * published by the Free Software Foundation.
  8 *
  9 * This program is distributed in the hope that it will be useful,
 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 12 * GNU General Public License for more details.
 13 *
 14 * You should have received a copy of the GNU General Public License
 15 * along with this program; if not, write to the Free Software
 16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 17 *
 18 *****************************************************************************
 19 *
 20 * This is a Linux port of the Really Slick Screensavers,
 21 * Copyright (C) 2002 Terence M. Welsh, available from www.reallyslick.com
 22 */
 23#include <common.hh>
 24
 25#if HAVE_PNG_H
 26	#include <png.h>
 27#endif
 28
 29#if HAVE_SETJMP_H
 30	#include <setjmp.h>
 31#endif
 32
 33#include <cerrno>
 34#include <color.hh>
 35#include <pngimage.hh>
 36#include <cstring>
 37
 38void PNG::load(FILE* in, bool fullColor) {
 39	png_byte sig[8];
 40	int sigBytes = fread(sig, 1, 8, in);
 41
 42	if (png_sig_cmp(sig, 0, sigBytes))
 43		throw Exception("Not a PNG file");
 44
 45	png_structp png = png_create_read_struct(PNG_LIBPNG_VER_STRING,
 46		NULL, NULL, NULL);
 47	if (!png)
 48		throw Exception("Could not create PNG read structure");
 49	png_infop pngInfo = png_create_info_struct(png);
 50	if (!pngInfo)
 51		throw Exception("Could not create PNG info structure");
 52
 53	try {
 54		if (setjmp(png_jmpbuf(png)))
 55			throw Exception("PNG could not be decoded");
 56
 57		png_init_io(png, in);
 58		png_set_sig_bytes(png, sigBytes);
 59
 60		png_read_info(png, pngInfo);
 61
 62		if (png_get_color_type(png, pngInfo) == PNG_COLOR_TYPE_PALETTE)
 63			png_set_palette_to_rgb(png);
 64		if (
 65			(png_get_color_type(png, pngInfo) == PNG_COLOR_TYPE_GRAY) &&
 66			png_get_bit_depth(png, pngInfo) < 8
 67		)
 68			png_set_expand_gray_1_2_4_to_8(png);
 69		if (png_get_valid(png, pngInfo, PNG_INFO_tRNS))
 70			png_set_tRNS_to_alpha(png);
 71		if (fullColor)
 72			png_set_gray_to_rgb(png);
 73		if (png_get_bit_depth(png, pngInfo) < 8)
 74			png_set_packing(png);
 75		png_read_update_info(png, pngInfo);
 76
 77		_width = png_get_image_width(png, pngInfo);
 78		_height = png_get_image_height(png, pngInfo);
 79
 80		switch (png_get_color_type(png, pngInfo)) {
 81		case PNG_COLOR_TYPE_GRAY:
 82			_format = GL_LUMINANCE;
 83			_bytesPerPixel = 1;
 84			_hasAlphaChannel = false;
 85			break;
 86		case PNG_COLOR_TYPE_RGB:
 87			_format = GL_RGB;
 88			_bytesPerPixel = 3;
 89			_hasAlphaChannel = false;
 90			break;
 91		case PNG_COLOR_TYPE_RGBA:
 92			_format = GL_RGBA;
 93			_bytesPerPixel = 4;
 94			_hasAlphaChannel = true;
 95			break;
 96		case PNG_COLOR_TYPE_GA:
 97			_format = GL_LUMINANCE_ALPHA;
 98			_bytesPerPixel = 2;
 99			_hasAlphaChannel = true;
100			break;
101		default:
102			throw Exception("Unhandled image type");
103		}
104		switch (png_get_bit_depth(png, pngInfo)) {
105		case 8:
106			_type = GL_UNSIGNED_BYTE;
107			break;
108		case 16:
109			_type = GL_UNSIGNED_SHORT;
110			_bytesPerPixel *= 2;
111			break;
112		default:
113			throw Exception("Unhandled image depth");
114		}
115		_numComponents = png_get_channels(png, pngInfo);
116
117		GLint alignment;
118 		glGetIntegerv(GL_UNPACK_ALIGNMENT, &alignment);
119		_rowLength =
120			((_width * _bytesPerPixel + alignment - 1) / alignment) * alignment;
121		_data = new uint8_t[_height * _rowLength];
122		png_bytep* rows = new png_bytep[_height];
123		for (GLsizei i = 0; i < _height; ++i)
124			rows[i] = _data + _rowLength * i;
125		png_read_image(png, rows);
126		delete[] rows;
127
128		png_read_end(png, NULL);
129		png_destroy_read_struct(&png, &pngInfo, NULL);
130	} catch (...) {
131		png_destroy_read_struct(&png, &pngInfo, NULL);
132		throw;
133	}
134}
135
136PNG::PNG(const std::string& filename, bool fullColor) {
137	if (filename.empty())
138		throw Exception("Empty filename");
139
140	FILE* in = NULL;
141	if (filename[0] != '/')
142		in = std::fopen((Common::resourceDir + '/' + filename).c_str(), "rb");
143
144	if (!in)
145		in = std::fopen(filename.c_str(), "rb");
146
147	if (!in)
148		throw Exception(stdx::oss() << filename << ": " << std::strerror(errno));
149
150	try {
151		load(in, fullColor);
152	} catch (Exception e) {
153		throw Exception(stdx::oss() << filename << ": " << e);
154	}
155	std::fclose(in);
156}
157
158PNG::~PNG() {
159	if (_data) delete[] _data;
160}
161
162const RGBColor PNG::operator()(GLsizei x, GLsizei y) const {
163	if (x >= _width || y >= _height)
164		return RGBColor();
165
166	uint8_t* pos = _data + _rowLength * y + _bytesPerPixel * x;
167	if (_type == GL_UNSIGNED_BYTE) {
168		switch (_format) {
169		case GL_LUMINANCE:
170		case GL_LUMINANCE_ALPHA:
171			{
172				float l = float(*pos) / 255.0f;
173				return RGBColor(l, l, l);
174			}
175		case GL_RGB:
176		case GL_RGBA:
177			{
178				float r = float(pos[0]) / 255.0f;
179				float g = float(pos[1]) / 255.0f;
180				float b = float(pos[2]) / 255.0f;
181				return RGBColor(r, g, b);
182			}
183		default:
184			return RGBColor();
185		}
186	} else {
187		switch (_format) {
188		case GL_LUMINANCE:
189		case GL_LUMINANCE_ALPHA:
190			{
191				float l = float((unsigned int)(pos[0]) * 255 + pos[1]) / 65535.0f;
192				return RGBColor(l, l, l);
193			}
194		case GL_RGB:
195		case GL_RGBA:
196			{
197				float r = float((unsigned int)(pos[0]) * 255 + pos[1]) / 65535.0f;
198				float g = float((unsigned int)(pos[2]) * 255 + pos[3]) / 65535.0f;
199				float b = float((unsigned int)(pos[4]) * 255 + pos[5]) / 65535.0f;
200				return RGBColor(r, g, b);
201			}
202		default:
203			return RGBColor();
204		}
205	}
206}