~baltix/+junk/irrlicht-test

« back to all changes in this revision

Viewing changes to source/Irrlicht/CImageLoaderPSD.cpp

  • Committer: Mantas Kriaučiūnas
  • Date: 2011-07-18 13:06:25 UTC
  • Revision ID: mantas@akl.lt-20110718130625-c5pvifp61e7kj1ol
Included whole irrlicht SVN libraries to work around launchpad recipe issue with quilt, see https://answers.launchpad.net/launchpad/+question/165193

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// Copyright (C) 2002-2011 Nikolaus Gebhardt
 
2
// This file is part of the "Irrlicht Engine".
 
3
// For conditions of distribution and use, see copyright notice in irrlicht.h
 
4
 
 
5
#include "CImageLoaderPSD.h"
 
6
 
 
7
#ifdef _IRR_COMPILE_WITH_PSD_LOADER_
 
8
 
 
9
#include "IReadFile.h"
 
10
#include "os.h"
 
11
#include "CImage.h"
 
12
#include "irrString.h"
 
13
 
 
14
 
 
15
namespace irr
 
16
{
 
17
namespace video
 
18
{
 
19
 
 
20
 
 
21
//! constructor
 
22
CImageLoaderPSD::CImageLoaderPSD()
 
23
{
 
24
        #ifdef _DEBUG
 
25
        setDebugName("CImageLoaderPSD");
 
26
        #endif
 
27
}
 
28
 
 
29
 
 
30
//! returns true if the file maybe is able to be loaded by this class
 
31
//! based on the file extension (e.g. ".tga")
 
32
bool CImageLoaderPSD::isALoadableFileExtension(const io::path& filename) const
 
33
{
 
34
        return core::hasFileExtension ( filename, "psd" );
 
35
}
 
36
 
 
37
 
 
38
 
 
39
//! returns true if the file maybe is able to be loaded by this class
 
40
bool CImageLoaderPSD::isALoadableFileFormat(io::IReadFile* file) const
 
41
{
 
42
        if (!file)
 
43
                return false;
 
44
 
 
45
        u8 type[3];
 
46
        file->read(&type, sizeof(u8)*3);
 
47
        return (type[2]==2); // we currently only handle tgas of type 2.
 
48
}
 
49
 
 
50
 
 
51
 
 
52
//! creates a surface from the file
 
53
IImage* CImageLoaderPSD::loadImage(io::IReadFile* file) const
 
54
{
 
55
        u32* imageData = 0;
 
56
 
 
57
        PsdHeader header;
 
58
        file->read(&header, sizeof(PsdHeader));
 
59
 
 
60
#ifndef __BIG_ENDIAN__
 
61
        header.version = os::Byteswap::byteswap(header.version);
 
62
        header.channels = os::Byteswap::byteswap(header.channels);
 
63
        header.height = os::Byteswap::byteswap(header.height);
 
64
        header.width = os::Byteswap::byteswap(header.width);
 
65
        header.depth = os::Byteswap::byteswap(header.depth);
 
66
        header.mode = os::Byteswap::byteswap(header.mode);
 
67
#endif
 
68
 
 
69
        if (header.signature[0] != '8' ||
 
70
                header.signature[1] != 'B' ||
 
71
                header.signature[2] != 'P' ||
 
72
                header.signature[3] != 'S')
 
73
                return 0;
 
74
 
 
75
        if (header.version != 1)
 
76
        {
 
77
                os::Printer::log("Unsupported PSD file version", file->getFileName(), ELL_ERROR);
 
78
                return 0;
 
79
        }
 
80
 
 
81
        if (header.mode != 3 || header.depth != 8)
 
82
        {
 
83
                os::Printer::log("Unsupported PSD color mode or depth.\n", file->getFileName(), ELL_ERROR);
 
84
                return 0;
 
85
        }
 
86
 
 
87
        // skip color mode data
 
88
 
 
89
        u32 l;
 
90
        file->read(&l, sizeof(u32));
 
91
#ifndef __BIG_ENDIAN__
 
92
        l = os::Byteswap::byteswap(l);
 
93
#endif
 
94
        if (!file->seek(l, true))
 
95
        {
 
96
                os::Printer::log("Error seeking file pos to image resources.\n", file->getFileName(), ELL_ERROR);
 
97
                return 0;
 
98
        }
 
99
 
 
100
        // skip image resources
 
101
 
 
102
        file->read(&l, sizeof(u32));
 
103
#ifndef __BIG_ENDIAN__
 
104
        l = os::Byteswap::byteswap(l);
 
105
#endif
 
106
        if (!file->seek(l, true))
 
107
        {
 
108
                os::Printer::log("Error seeking file pos to layer and mask.\n", file->getFileName(), ELL_ERROR);
 
109
                return 0;
 
110
        }
 
111
 
 
112
        // skip layer & mask
 
113
 
 
114
        file->read(&l, sizeof(u32));
 
115
#ifndef __BIG_ENDIAN__
 
116
        l = os::Byteswap::byteswap(l);
 
117
#endif
 
118
        if (!file->seek(l, true))
 
119
        {
 
120
                os::Printer::log("Error seeking file pos to image data section.\n", file->getFileName(), ELL_ERROR);
 
121
                return 0;
 
122
        }
 
123
 
 
124
        // read image data
 
125
 
 
126
        u16 compressionType;
 
127
        file->read(&compressionType, sizeof(u16));
 
128
#ifndef __BIG_ENDIAN__
 
129
        compressionType = os::Byteswap::byteswap(compressionType);
 
130
#endif
 
131
 
 
132
        if (compressionType != 1 && compressionType != 0)
 
133
        {
 
134
                os::Printer::log("Unsupported psd compression mode.\n", file->getFileName(), ELL_ERROR);
 
135
                return 0;
 
136
        }
 
137
 
 
138
        // create image data block
 
139
 
 
140
        imageData = new u32[header.width * header.height];
 
141
 
 
142
        bool res = false;
 
143
 
 
144
        if (compressionType == 0)
 
145
                res = readRawImageData(file, header, imageData); // RAW image data
 
146
        else
 
147
                res = readRLEImageData(file, header, imageData); // RLE compressed data
 
148
 
 
149
        video::IImage* image = 0;
 
150
 
 
151
        if (res)
 
152
        {
 
153
                // create surface
 
154
                image = new CImage(ECF_A8R8G8B8,
 
155
                        core::dimension2d<u32>(header.width, header.height), imageData);
 
156
        }
 
157
 
 
158
        if (!image)
 
159
                delete [] imageData;
 
160
        imageData = 0;
 
161
 
 
162
        return image;
 
163
}
 
164
 
 
165
 
 
166
bool CImageLoaderPSD::readRawImageData(io::IReadFile* file, const PsdHeader& header, u32* imageData) const
 
167
{
 
168
        u8* tmpData = new u8[header.width * header.height];
 
169
 
 
170
        for (s32 channel=0; channel<header.channels && channel < 3; ++channel)
 
171
        {
 
172
                if (!file->read(tmpData, sizeof(c8) * header.width * header.height))
 
173
                {
 
174
                        os::Printer::log("Error reading color channel\n", file->getFileName(), ELL_ERROR);
 
175
                        break;
 
176
                }
 
177
 
 
178
                s16 shift = getShiftFromChannel((c8)channel, header);
 
179
                if (shift != -1)
 
180
                {
 
181
                        u32 mask = 0xff << shift;
 
182
 
 
183
                        for (u32 x=0; x<header.width; ++x)
 
184
                        {
 
185
                                for (u32 y=0; y<header.height; ++y)
 
186
                                {
 
187
                                        s32 index = x + y*header.width;
 
188
                                        imageData[index] = ~(~imageData[index] | mask);
 
189
                                        imageData[index] |= tmpData[index] << shift;
 
190
                                }
 
191
                        }
 
192
                }
 
193
 
 
194
        }
 
195
 
 
196
        delete [] tmpData;
 
197
        return true;
 
198
}
 
199
 
 
200
 
 
201
bool CImageLoaderPSD::readRLEImageData(io::IReadFile* file, const PsdHeader& header, u32* imageData) const
 
202
{
 
203
        /*      If the compression code is 1, the image data
 
204
                starts with the byte counts for all the scan lines in the channel
 
205
                (LayerBottom LayerTop), with each count stored as a two
 
206
                byte value. The RLE compressed data follows, with each scan line
 
207
                compressed separately. The RLE compression is the same compres-sion
 
208
                algorithm used by the Macintosh ROM routine PackBits, and
 
209
                the TIFF standard.
 
210
                If the Layer's Size, and therefore the data, is odd, a pad byte will
 
211
                be inserted at the end of the row.
 
212
        */
 
213
 
 
214
        /*
 
215
        A pseudo code fragment to unpack might look like this:
 
216
 
 
217
        Loop until you get the number of unpacked bytes you are expecting:
 
218
                Read the next source byte into n.
 
219
                If n is between 0 and 127 inclusive, copy the next n+1 bytes literally.
 
220
                Else if n is between -127 and -1 inclusive, copy the next byte -n+1
 
221
                times.
 
222
                Else if n is -128, noop.
 
223
        Endloop
 
224
 
 
225
        In the inverse routine, it is best to encode a 2-byte repeat run as a replicate run
 
226
        except when preceded and followed by a literal run. In that case, it is best to merge
 
227
        the three runs into one literal run. Always encode 3-byte repeats as replicate runs.
 
228
        That is the essence of the algorithm. Here are some additional rules:
 
229
        - Pack each row separately. Do not compress across row boundaries.
 
230
        - The number of uncompressed bytes per row is defined to be (ImageWidth + 7)
 
231
        / 8. If the uncompressed bitmap is required to have an even number of bytes per
 
232
        row, decompress into word-aligned buffers.
 
233
        - If a run is larger than 128 bytes, encode the remainder of the run as one or more
 
234
        additional replicate runs.
 
235
        When PackBits data is decompressed, the result should be interpreted as per com-pression
 
236
        type 1 (no compression).
 
237
        */
 
238
 
 
239
        u8* tmpData = new u8[header.width * header.height];
 
240
        u16 *rleCount= new u16 [header.height * header.channels];
 
241
 
 
242
        s32 size=0;
 
243
 
 
244
        for (u32 y=0; y<header.height * header.channels; ++y)
 
245
        {
 
246
                if (!file->read(&rleCount[y], sizeof(u16)))
 
247
                {
 
248
                        delete [] tmpData;
 
249
                        delete [] rleCount;
 
250
                        os::Printer::log("Error reading rle rows\n", file->getFileName(), ELL_ERROR);
 
251
                        return false;
 
252
                }
 
253
 
 
254
#ifndef __BIG_ENDIAN__
 
255
                rleCount[y] = os::Byteswap::byteswap(rleCount[y]);
 
256
#endif
 
257
                size += rleCount[y];
 
258
        }
 
259
 
 
260
        s8 *buf = new s8[size];
 
261
        if (!file->read(buf, size))
 
262
        {
 
263
                delete [] rleCount;
 
264
                delete [] buf;
 
265
                delete [] tmpData;
 
266
                os::Printer::log("Error reading rle rows\n", file->getFileName(), ELL_ERROR);
 
267
                return false;
 
268
        }
 
269
 
 
270
        u16 *rcount=rleCount;
 
271
 
 
272
        s8 rh;
 
273
        u16 bytesRead;
 
274
        u8 *dest;
 
275
        s8 *pBuf = buf;
 
276
 
 
277
        // decompress packbit rle
 
278
 
 
279
        for (s32 channel=0; channel<header.channels; channel++)
 
280
        {
 
281
                for (u32 y=0; y<header.height; ++y, ++rcount)
 
282
                {
 
283
                        bytesRead=0;
 
284
                        dest = &tmpData[y*header.width];
 
285
 
 
286
                        while (bytesRead < *rcount)
 
287
                        {
 
288
                                rh = *pBuf++;
 
289
                                ++bytesRead;
 
290
 
 
291
                                if (rh >= 0)
 
292
                                {
 
293
                                        ++rh;
 
294
 
 
295
                                        while (rh--)
 
296
                                        {
 
297
                                                *dest = *pBuf++;
 
298
                                                ++bytesRead;
 
299
                                                ++dest;
 
300
                                        }
 
301
                                }
 
302
                                else
 
303
                                if (rh > -128)
 
304
                                {
 
305
                                        rh = -rh +1;
 
306
 
 
307
                                        while (rh--)
 
308
                                        {
 
309
                                                *dest = *pBuf;
 
310
                                                ++dest;
 
311
                                        }
 
312
 
 
313
                                        ++pBuf;
 
314
                                        ++bytesRead;
 
315
                                }
 
316
                        }
 
317
                }
 
318
 
 
319
                s16 shift = getShiftFromChannel((c8)channel, header);
 
320
 
 
321
                if (shift != -1)
 
322
                {
 
323
                        u32 mask = 0xff << shift;
 
324
 
 
325
                        for (u32 x=0; x<header.width; ++x)
 
326
                                for (u32 y=0; y<header.height; ++y)
 
327
                                {
 
328
                                        s32 index = x + y*header.width;
 
329
                                        imageData[index] = ~(~imageData[index] | mask);
 
330
                                        imageData[index] |= tmpData[index] << shift;
 
331
                                }
 
332
                }
 
333
        }
 
334
 
 
335
        delete [] rleCount;
 
336
        delete [] buf;
 
337
        delete [] tmpData;
 
338
 
 
339
        return true;
 
340
}
 
341
 
 
342
 
 
343
s16 CImageLoaderPSD::getShiftFromChannel(c8 channelNr, const PsdHeader& header) const
 
344
{
 
345
        switch(channelNr)
 
346
        {
 
347
        case 0:
 
348
                return 16;  // red
 
349
        case 1:
 
350
                return 8;   // green
 
351
        case 2:
 
352
                return 0;   // blue
 
353
        case 3:
 
354
                return header.channels == 4 ? 24 : -1;  // ?
 
355
        case 4:
 
356
                return 24;  // alpha
 
357
        default:
 
358
                return -1;
 
359
        }
 
360
}
 
361
 
 
362
 
 
363
 
 
364
//! creates a loader which is able to load tgas
 
365
IImageLoader* createImageLoaderPSD()
 
366
{
 
367
        return new CImageLoaderPSD();
 
368
}
 
369
 
 
370
 
 
371
} // end namespace video
 
372
} // end namespace irr
 
373
 
 
374
#endif
 
375