~ubuntu-branches/ubuntu/raring/scummvm/raring

« back to all changes in this revision

Viewing changes to engines/sword25/gfx/image/pngloader.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Moritz Muehlenhoff
  • Date: 2011-05-25 19:02:23 UTC
  • mto: (21.1.2 sid)
  • mto: This revision was merged to the branch mainline in revision 24.
  • Revision ID: james.westby@ubuntu.com-20110525190223-fiqm0oaec714xk31
Tags: upstream-1.3.0
ImportĀ upstreamĀ versionĀ 1.3.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* ScummVM - Graphic Adventure Engine
 
2
 *
 
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.
 
6
 *
 
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.
 
11
 
 
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.
 
16
 
 
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.
 
20
 *
 
21
 * $URL$
 
22
 * $Id$
 
23
 *
 
24
 */
 
25
 
 
26
/*
 
27
 * This code is based on Broken Sword 2.5 engine
 
28
 *
 
29
 * Copyright (c) Malte Thiesen, Daniel Queteschiner and Michael Elsdoerfer
 
30
 *
 
31
 * Licensed under GNU GPL v2
 
32
 *
 
33
 */
 
34
 
 
35
// Define to use ScummVM's PNG decoder, instead of libpng
 
36
#define USE_INTERNAL_PNG_DECODER
 
37
 
 
38
#ifndef USE_INTERNAL_PNG_DECODER
 
39
// Disable symbol overrides so that we can use png.h
 
40
#define FORBIDDEN_SYMBOL_ALLOW_ALL
 
41
#endif
 
42
 
 
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
 
47
#include <png.h>
 
48
#else
 
49
#include "graphics/pixelformat.h"
 
50
#include "graphics/png.h"
 
51
#endif
 
52
 
 
53
namespace Sword25 {
 
54
 
 
55
/**
 
56
 * Load a NULL-terminated string from the given stream.
 
57
 */
 
58
static Common::String loadString(Common::ReadStream &in, uint maxSize = 999) {
 
59
        Common::String result;
 
60
 
 
61
        while (!in.eos() && (result.size() < maxSize)) {
 
62
                char ch = (char)in.readByte();
 
63
                if (ch == '\0')
 
64
                        break;
 
65
 
 
66
                result += ch;
 
67
        }
 
68
 
 
69
        return result;
 
70
}
 
71
 
 
72
/**
 
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
 
76
 */
 
77
static uint findEmbeddedPNG(const byte *fileDataPtr, uint fileSize) {
 
78
        if (fileSize < 100)
 
79
                return 0;
 
80
        if (memcmp(fileDataPtr, "BS25SAVEGAME", 12))
 
81
                return 0;
 
82
 
 
83
        // Read in the header
 
84
        Common::MemoryReadStream stream(fileDataPtr, fileSize);
 
85
        stream.seek(0, SEEK_SET);
 
86
 
 
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());
 
94
        loadString(stream);
 
95
 
 
96
        // Return the offset of where the thumbnail starts
 
97
        return static_cast<uint>(stream.pos() + compressedGamedataSize);
 
98
}
 
99
 
 
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);
 
104
        *ref += length;
 
105
}
 
106
 
 
107
static bool doIsCorrectImageFormat(const byte *fileDataPtr, uint fileSize) {
 
108
        return (fileSize > 8) && png_check_sig(const_cast<byte *>(fileDataPtr), 8);
 
109
}
 
110
#endif
 
111
 
 
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;
 
116
 
 
117
        int         bitDepth;
 
118
        int         colorType;
 
119
        int         interlaceType;
 
120
        int         i;
 
121
 
 
122
        // Check for valid PNG signature
 
123
        if (!doIsCorrectImageFormat(fileDataPtr, fileSize)) {
 
124
                error("png_check_sig failed");
 
125
        }
 
126
 
 
127
        // Create both PNG structures
 
128
        png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
 
129
        if (!png_ptr) {
 
130
                error("Could not create libpng read struct.");
 
131
        }
 
132
 
 
133
        info_ptr = png_create_info_struct(png_ptr);
 
134
        if (!info_ptr) {
 
135
                error("Could not create libpng info struct.");
 
136
        }
 
137
 
 
138
        // Use alternative reading function
 
139
        const byte **ref = &fileDataPtr;
 
140
        png_set_read_fn(png_ptr, (void *)ref, png_user_read_data);
 
141
 
 
142
        // Read PNG header
 
143
        png_read_info(png_ptr, info_ptr);
 
144
 
 
145
        // Read out PNG informations
 
146
 
 
147
        png_uint_32 w, h;
 
148
        png_get_IHDR(png_ptr, info_ptr, &w, &h, &bitDepth, &colorType, &interlaceType, NULL, NULL);
 
149
        width = w;
 
150
        height = h;
 
151
 
 
152
        // Calculate pitch of output image
 
153
        pitch = GraphicEngine::calcPitch(GraphicEngine::CF_ARGB32, width);
 
154
 
 
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.");
 
160
        }
 
161
 
 
162
        // Images of all color formates will be transformed into ARGB images
 
163
        if (bitDepth == 16)
 
164
                png_set_strip_16(png_ptr);
 
165
        if (colorType == PNG_COLOR_TYPE_PALETTE)
 
166
                png_set_expand(png_ptr);
 
167
        if (bitDepth < 8)
 
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);
 
174
 
 
175
        png_set_bgr(png_ptr);
 
176
 
 
177
        if (colorType != PNG_COLOR_TYPE_RGB_ALPHA)
 
178
                png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER);
 
179
 
 
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);
 
183
        width = w;
 
184
        height = h;
 
185
 
 
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);
 
190
                }
 
191
        } else {
 
192
                // PNGs with interlacing require us to allocate an auxillary
 
193
                // buffer with pointers to all row starts.
 
194
 
 
195
                // Allocate row pointer buffer
 
196
                png_bytep *pRowPtr = new png_bytep[height];
 
197
                if (!pRowPtr) {
 
198
                        error("Could not allocate memory for row pointers.");
 
199
                }
 
200
 
 
201
                // Initialize row pointers
 
202
                for (i = 0; i < height; i++)
 
203
                        pRowPtr[i] = uncompressedDataPtr + i * pitch;
 
204
 
 
205
                // Read image data
 
206
                png_read_image(png_ptr, pRowPtr);
 
207
 
 
208
                // Free row pointer buffer
 
209
                delete[] pRowPtr;
 
210
        }
 
211
 
 
212
        // Read additional data at the end.
 
213
        png_read_end(png_ptr, NULL);
 
214
 
 
215
        // Destroy libpng structures
 
216
        png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
 
217
#else
 
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");
 
222
 
 
223
        Graphics::PixelFormat format = Graphics::PixelFormat(4, 8, 8, 8, 8, 16, 8, 0, 24);
 
224
        Graphics::Surface *pngSurface = png->getSurface(format);
 
225
 
 
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);
 
230
        pngSurface->free();
 
231
 
 
232
        delete pngSurface;
 
233
        delete png;
 
234
 
 
235
#endif
 
236
        // Signal success
 
237
        return true;
 
238
}
 
239
 
 
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);
 
243
}
 
244
 
 
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))
 
249
                return false;
 
250
 
 
251
        png_structp png_ptr = NULL;
 
252
        png_infop info_ptr = NULL;
 
253
 
 
254
        // Create both PNG structures
 
255
        png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
 
256
        if (!png_ptr) {
 
257
                error("Could not create libpng read struct.");
 
258
        }
 
259
 
 
260
        info_ptr = png_create_info_struct(png_ptr);
 
261
        if (!info_ptr) {
 
262
                error("Could not create libpng info struct.");
 
263
        }
 
264
 
 
265
        // Use alternative reading function
 
266
        const byte **ref = &fileDataPtr;
 
267
        png_set_read_fn(png_ptr, (void *)ref, png_user_read_data);
 
268
 
 
269
        // Read PNG Header
 
270
        png_read_info(png_ptr, info_ptr);
 
271
 
 
272
        // Read out PNG informations
 
273
        int bitDepth;
 
274
        int colorType;
 
275
        png_uint_32 w, h;
 
276
        png_get_IHDR(png_ptr, info_ptr, &w, &h, &bitDepth, &colorType, NULL, NULL, NULL);
 
277
 
 
278
        width = w;
 
279
        height = h;
 
280
 
 
281
        // Destroy libpng structures
 
282
        png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
 
283
#else
 
284
        // We don't need to read the image properties here...
 
285
#endif
 
286
        return true;
 
287
 
 
288
}
 
289
 
 
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);
 
293
}
 
294
 
 
295
 
 
296
} // End of namespace Sword25