aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/src/others/irrlicht-1.8.1/source/Irrlicht/CImageLoaderPSD.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/others/irrlicht-1.8.1/source/Irrlicht/CImageLoaderPSD.cpp')
-rw-r--r--src/others/irrlicht-1.8.1/source/Irrlicht/CImageLoaderPSD.cpp375
1 files changed, 375 insertions, 0 deletions
diff --git a/src/others/irrlicht-1.8.1/source/Irrlicht/CImageLoaderPSD.cpp b/src/others/irrlicht-1.8.1/source/Irrlicht/CImageLoaderPSD.cpp
new file mode 100644
index 0000000..3eb5c3b
--- /dev/null
+++ b/src/others/irrlicht-1.8.1/source/Irrlicht/CImageLoaderPSD.cpp
@@ -0,0 +1,375 @@
1// Copyright (C) 2002-2012 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
15namespace irr
16{
17namespace video
18{
19
20
21//! constructor
22CImageLoaderPSD::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")
32bool 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
40bool 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
53IImage* 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
166bool 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
201bool 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
343s16 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
365IImageLoader* createImageLoaderPSD()
366{
367 return new CImageLoaderPSD();
368}
369
370
371} // end namespace video
372} // end namespace irr
373
374#endif
375