1
/* ScummVM - Graphic Adventure Engine
3
* ScummVM is the legal property of its developers, whose names
4
* are too numerous to list here. Please refer to the COPYRIGHT
5
* file distributed with this source distribution.
7
* This program is free software; you can redistribute it and/or
8
* modify it under the terms of the GNU General Public License
9
* as published by the Free Software Foundation; either version 2
10
* of the License, or (at your option) any later version.
12
* This program is distributed in the hope that it will be useful,
13
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
* GNU General Public License for more details.
17
* You should have received a copy of the GNU General Public License
18
* along with this program; if not, write to the Free Software
19
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
27
* This code is based on Broken Sword 2.5 engine
29
* Copyright (c) Malte Thiesen, Daniel Queteschiner and Michael Elsdoerfer
31
* Licensed under GNU GPL v2
35
// Define to use ScummVM's PNG decoder, instead of libpng
36
#define USE_INTERNAL_PNG_DECODER
38
#ifndef USE_INTERNAL_PNG_DECODER
39
// Disable symbol overrides so that we can use png.h
40
#define FORBIDDEN_SYMBOL_ALLOW_ALL
43
#include "common/memstream.h"
44
#include "sword25/gfx/image/image.h"
45
#include "sword25/gfx/image/pngloader.h"
46
#ifndef USE_INTERNAL_PNG_DECODER
49
#include "graphics/pixelformat.h"
50
#include "graphics/png.h"
56
* Load a NULL-terminated string from the given stream.
58
static Common::String loadString(Common::ReadStream &in, uint maxSize = 999) {
59
Common::String result;
61
while (!in.eos() && (result.size() < maxSize)) {
62
char ch = (char)in.readByte();
73
* Check if the given data is a savegame, and if so, locate the
74
* offset to the image data.
75
* @return offset to image data if fileDataPtr contains a savegame; 0 otherwise
77
static uint findEmbeddedPNG(const byte *fileDataPtr, uint fileSize) {
80
if (memcmp(fileDataPtr, "BS25SAVEGAME", 12))
84
Common::MemoryReadStream stream(fileDataPtr, fileSize);
85
stream.seek(0, SEEK_SET);
87
// Read header information of savegame
88
uint compressedGamedataSize;
89
loadString(stream); // Marker
90
loadString(stream); // Version
91
loadString(stream); // Description
92
Common::String gameSize = loadString(stream);
93
compressedGamedataSize = atoi(gameSize.c_str());
96
// Return the offset of where the thumbnail starts
97
return static_cast<uint>(stream.pos() + compressedGamedataSize);
100
#ifndef USE_INTERNAL_PNG_DECODER
101
static void png_user_read_data(png_structp png_ptr, png_bytep data, png_size_t length) {
102
const byte **ref = (const byte **)png_get_io_ptr(png_ptr);
103
memcpy(data, *ref, length);
107
static bool doIsCorrectImageFormat(const byte *fileDataPtr, uint fileSize) {
108
return (fileSize > 8) && png_check_sig(const_cast<byte *>(fileDataPtr), 8);
112
bool PNGLoader::doDecodeImage(const byte *fileDataPtr, uint fileSize, byte *&uncompressedDataPtr, int &width, int &height, int &pitch) {
113
#ifndef USE_INTERNAL_PNG_DECODER
114
png_structp png_ptr = NULL;
115
png_infop info_ptr = NULL;
122
// Check for valid PNG signature
123
if (!doIsCorrectImageFormat(fileDataPtr, fileSize)) {
124
error("png_check_sig failed");
127
// Create both PNG structures
128
png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
130
error("Could not create libpng read struct.");
133
info_ptr = png_create_info_struct(png_ptr);
135
error("Could not create libpng info struct.");
138
// Use alternative reading function
139
const byte **ref = &fileDataPtr;
140
png_set_read_fn(png_ptr, (void *)ref, png_user_read_data);
143
png_read_info(png_ptr, info_ptr);
145
// Read out PNG informations
148
png_get_IHDR(png_ptr, info_ptr, &w, &h, &bitDepth, &colorType, &interlaceType, NULL, NULL);
152
// Calculate pitch of output image
153
pitch = GraphicEngine::calcPitch(GraphicEngine::CF_ARGB32, width);
155
// Allocate memory for the final image data.
156
// To keep memory framentation low this happens before allocating memory for temporary image data.
157
uncompressedDataPtr = new byte[pitch * height];
158
if (!uncompressedDataPtr) {
159
error("Could not allocate memory for output image.");
162
// Images of all color formates will be transformed into ARGB images
164
png_set_strip_16(png_ptr);
165
if (colorType == PNG_COLOR_TYPE_PALETTE)
166
png_set_expand(png_ptr);
168
png_set_expand(png_ptr);
169
if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
170
png_set_expand(png_ptr);
171
if (colorType == PNG_COLOR_TYPE_GRAY ||
172
colorType == PNG_COLOR_TYPE_GRAY_ALPHA)
173
png_set_gray_to_rgb(png_ptr);
175
png_set_bgr(png_ptr);
177
if (colorType != PNG_COLOR_TYPE_RGB_ALPHA)
178
png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER);
180
// After the transformations have been registered, the image data is read again.
181
png_read_update_info(png_ptr, info_ptr);
182
png_get_IHDR(png_ptr, info_ptr, &w, &h, &bitDepth, &colorType, NULL, NULL, NULL);
186
if (interlaceType == PNG_INTERLACE_NONE) {
187
// PNGs without interlacing can simply be read row by row.
188
for (i = 0; i < height; i++) {
189
png_read_row(png_ptr, uncompressedDataPtr + i * pitch, NULL);
192
// PNGs with interlacing require us to allocate an auxillary
193
// buffer with pointers to all row starts.
195
// Allocate row pointer buffer
196
png_bytep *pRowPtr = new png_bytep[height];
198
error("Could not allocate memory for row pointers.");
201
// Initialize row pointers
202
for (i = 0; i < height; i++)
203
pRowPtr[i] = uncompressedDataPtr + i * pitch;
206
png_read_image(png_ptr, pRowPtr);
208
// Free row pointer buffer
212
// Read additional data at the end.
213
png_read_end(png_ptr, NULL);
215
// Destroy libpng structures
216
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
218
Common::MemoryReadStream *fileStr = new Common::MemoryReadStream(fileDataPtr, fileSize, DisposeAfterUse::NO);
219
Graphics::PNG *png = new Graphics::PNG();
220
if (!png->read(fileStr)) // the fileStr pointer, and thus pFileData will be deleted after this is done
221
error("Error while reading PNG image");
223
Graphics::PixelFormat format = Graphics::PixelFormat(4, 8, 8, 8, 8, 16, 8, 0, 24);
224
Graphics::Surface *pngSurface = png->getSurface(format);
226
width = pngSurface->w;
227
height = pngSurface->h;
228
uncompressedDataPtr = new byte[pngSurface->pitch * pngSurface->h];
229
memcpy(uncompressedDataPtr, (byte *)pngSurface->pixels, pngSurface->pitch * pngSurface->h);
240
bool PNGLoader::decodeImage(const byte *fileDataPtr, uint fileSize, byte *&uncompressedDataPtr, int &width, int &height, int &pitch) {
241
uint pngOffset = findEmbeddedPNG(fileDataPtr, fileSize);
242
return doDecodeImage(fileDataPtr + pngOffset, fileSize - pngOffset, uncompressedDataPtr, width, height, pitch);
245
bool PNGLoader::doImageProperties(const byte *fileDataPtr, uint fileSize, int &width, int &height) {
246
#ifndef USE_INTERNAL_PNG_DECODER
247
// Check for valid PNG signature
248
if (!doIsCorrectImageFormat(fileDataPtr, fileSize))
251
png_structp png_ptr = NULL;
252
png_infop info_ptr = NULL;
254
// Create both PNG structures
255
png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
257
error("Could not create libpng read struct.");
260
info_ptr = png_create_info_struct(png_ptr);
262
error("Could not create libpng info struct.");
265
// Use alternative reading function
266
const byte **ref = &fileDataPtr;
267
png_set_read_fn(png_ptr, (void *)ref, png_user_read_data);
270
png_read_info(png_ptr, info_ptr);
272
// Read out PNG informations
276
png_get_IHDR(png_ptr, info_ptr, &w, &h, &bitDepth, &colorType, NULL, NULL, NULL);
281
// Destroy libpng structures
282
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
284
// We don't need to read the image properties here...
290
bool PNGLoader::imageProperties(const byte *fileDataPtr, uint fileSize, int &width, int &height) {
291
uint pngOffset = findEmbeddedPNG(fileDataPtr, fileSize);
292
return doImageProperties(fileDataPtr + pngOffset, fileSize - pngOffset, width, height);
296
} // End of namespace Sword25