2 * Copyright 2013, Gerasim Troeglazov, 3dEyes@gmail.com. All rights reserved.
3 * Distributed under the terms of the MIT License.
11 #include "BaseTranslator.h"
13 #undef B_TRANSLATION_CONTEXT
14 #define B_TRANSLATION_CONTEXT "PSDLoader"
17 PSDLoader::PSDLoader(BPositionIO
*src
)
22 fStream
->Seek(0, SEEK_END
);
23 fStreamSize
= fStream
->Position();
24 fStream
->Seek(0, SEEK_SET
);
29 fStream
->Seek(0, SEEK_SET
);
31 fSignature
= _GetInt32FromStream(fStream
);
32 if (fSignature
!= 0x38425053) // 8BPS
35 fVersion
= _GetInt16FromStream(fStream
);
38 _SkipStreamBlock(fStream
, 6);
40 fChannels
= _GetInt16FromStream(fStream
);
41 fHeight
= _GetInt32FromStream(fStream
);
42 fWidth
= _GetInt32FromStream(fStream
);
43 fDepth
= _GetInt16FromStream(fStream
);
44 fColorFormat
= _GetInt16FromStream(fStream
);
46 fColorModeDataSize
= _GetInt32FromStream(fStream
);
47 fColorModeDataPos
= fStream
->Position();
48 _SkipStreamBlock(fStream
, fColorModeDataSize
);
50 fImageResourceSectionSize
= _GetInt32FromStream(fStream
);
51 fImageResourceSectionPos
= fStream
->Position();
52 _SkipStreamBlock(fStream
, fImageResourceSectionSize
);
54 // Skip [layer and mask] block
55 if (fVersion
== PSD_FILE
)
56 _SkipStreamBlock(fStream
, _GetInt32FromStream(fStream
));
57 else if (fVersion
== PSB_FILE
)
58 _SkipStreamBlock(fStream
, _GetInt64FromStream(fStream
));
62 fCompression
= _GetInt16FromStream(fStream
);
64 fStreamPos
= fStream
->Position();
70 PSDLoader::~PSDLoader()
76 PSDLoader::IsLoaded(void)
83 PSDLoader::IsSupported(void)
88 if (fVersion
!= PSD_FILE
89 && fVersion
!= PSB_FILE
) {
93 if (fChannels
< 0 || fChannels
> PSD_MAX_CHANNELS
)
99 if (_ColorFormat() == PSD_COLOR_FORMAT_UNSUPPORTED
)
102 if (fCompression
!= PSD_COMPRESSED_RAW
103 && fCompression
!= PSD_COMPRESSED_RLE
) {
112 PSDLoader::ColorFormatName(void)
114 switch (fColorFormat
) {
115 case PSD_COLOR_MODE_BITS
:
116 return B_TRANSLATE("Bitmap");
117 case PSD_COLOR_MODE_GRAYSCALE
:
118 return B_TRANSLATE("Grayscale");
119 case PSD_COLOR_MODE_INDEXED
:
120 return B_TRANSLATE("Indexed");
121 case PSD_COLOR_MODE_RGB
:
122 return fChannels
> 3 ? B_TRANSLATE("RGBA") : B_TRANSLATE("RGB");
123 case PSD_COLOR_MODE_CMYK
:
124 return B_TRANSLATE("CMYK");
125 case PSD_COLOR_MODE_MULTICHANNEL
:
126 return B_TRANSLATE("Multichannel");
127 case PSD_COLOR_MODE_LAB
:
128 return B_TRANSLATE("Lab");
129 case PSD_COLOR_MODE_DUOTONE
:
130 return B_TRANSLATE("Duotone");
137 PSDLoader::_ColorFormat(void)
139 psd_color_format format
= PSD_COLOR_FORMAT_UNSUPPORTED
;
143 switch (fColorFormat
) {
144 case PSD_COLOR_MODE_BITS
:
145 format
= PSD_COLOR_FORMAT_BITMAP
;
147 case PSD_COLOR_MODE_RGB
:
149 format
= PSD_COLOR_FORMAT_RGB
;
150 else if (fChannels
>= 4)
151 format
= PSD_COLOR_FORMAT_RGB_A
;
153 case PSD_COLOR_MODE_GRAYSCALE
:
155 format
= PSD_COLOR_FORMAT_GRAY
;
156 else if (fChannels
== 2)
157 format
= PSD_COLOR_FORMAT_GRAY_A
;
159 case PSD_COLOR_MODE_MULTICHANNEL
:
161 format
= PSD_COLOR_FORMAT_MULTICHANNEL
;
163 case PSD_COLOR_MODE_CMYK
:
165 format
= PSD_COLOR_FORMAT_MULTICHANNEL
;
166 else if (fChannels
== 4)
167 format
= PSD_COLOR_FORMAT_CMYK
;
168 else if (fChannels
> 4)
169 format
= PSD_COLOR_FORMAT_CMYK_A
;
171 case PSD_COLOR_MODE_LAB
:
173 format
= PSD_COLOR_FORMAT_LAB
;
174 else if (fChannels
> 3)
175 format
= PSD_COLOR_FORMAT_LAB_A
;
177 case PSD_COLOR_MODE_DUOTONE
:
179 format
= PSD_COLOR_FORMAT_DUOTONE
;
181 case PSD_COLOR_MODE_INDEXED
:
182 if (fChannels
>= 1 && fColorModeDataSize
>= 3)
183 format
= PSD_COLOR_FORMAT_INDEXED
;
194 PSDLoader::Decode(BPositionIO
*target
)
197 return B_NO_TRANSLATOR
;
199 fStreamBuffer
= new uint8
[fStreamSize
];
200 fStream
->Seek(0, SEEK_SET
);
201 fStream
->Read(fStreamBuffer
, fStreamSize
);
203 int32 depthBytes
= fDepth
/ 8;
204 int32 rowBytes
= (fWidth
* fDepth
) / 8;
205 int32 channelBytes
= rowBytes
* fHeight
;
207 uint8
*imageData
[PSD_MAX_CHANNELS
];
208 for (int i
= 0; i
< fChannels
; i
++)
209 imageData
[i
] = new uint8
[channelBytes
];
212 switch (fCompression
) {
213 case PSD_COMPRESSED_RAW
:
215 for (int channelIdx
= 0; channelIdx
< fChannels
; channelIdx
++) {
216 uint8
*ptr
= imageData
[channelIdx
];
217 for (int i
= 0; i
< channelBytes
; i
++, ptr
++)
218 *ptr
= (uint8
)fStreamBuffer
[fStreamPos
++];
222 case PSD_COMPRESSED_RLE
:
224 if (fVersion
== PSD_FILE
)
225 fStreamPos
+= fHeight
* fChannels
* 2;
226 else if (fVersion
== PSB_FILE
)
227 fStreamPos
+= fHeight
* fChannels
* 4;
229 for (int channelIdx
= 0; channelIdx
< fChannels
; channelIdx
++) {
230 uint8
*ptr
= imageData
[channelIdx
];
231 // Read the RLE data.
233 while (count
< channelBytes
) {
234 uint8 len
= (uint8
)fStreamBuffer
[fStreamPos
++];
237 } else if (len
< 128) {
241 *ptr
++ = (int8
)fStreamBuffer
[fStreamPos
++];
244 } else if (len
> 128) {
245 int8 val
= (int8
)fStreamBuffer
[fStreamPos
++];
259 delete[] fStreamBuffer
;
260 for (int i
= 0; i
< fChannels
; i
++)
261 delete[] imageData
[i
];
262 return B_NO_TRANSLATOR
;
265 delete[] fStreamBuffer
;
267 TranslatorBitmap bitsHeader
;
268 bitsHeader
.magic
= B_TRANSLATOR_BITMAP
;
269 bitsHeader
.bounds
.left
= 0;
270 bitsHeader
.bounds
.top
= 0;
271 bitsHeader
.bounds
.right
= fWidth
- 1;
272 bitsHeader
.bounds
.bottom
= fHeight
- 1;
274 psd_color_format colorFormat
= _ColorFormat();
276 if (colorFormat
== PSD_COLOR_FORMAT_BITMAP
) {
277 bitsHeader
.rowBytes
= rowBytes
;
278 bitsHeader
.dataSize
= channelBytes
;
279 bitsHeader
.colors
= B_GRAY1
;
281 bitsHeader
.rowBytes
= sizeof(uint32
) * fWidth
;
282 bitsHeader
.colors
= B_RGBA32
;
283 bitsHeader
.dataSize
= bitsHeader
.rowBytes
* fHeight
;
286 if (swap_data(B_UINT32_TYPE
, &bitsHeader
,
287 sizeof(TranslatorBitmap
), B_SWAP_HOST_TO_BENDIAN
) != B_OK
) {
288 return B_NO_TRANSLATOR
;
291 target
->Write(&bitsHeader
, sizeof(TranslatorBitmap
));
293 uint8
*lineData
= new uint8
[fWidth
* sizeof(uint32
)];
295 switch (colorFormat
) {
296 case PSD_COLOR_FORMAT_BITMAP
:
298 int32 rowBytes
= (fWidth
/ 8 ) * fHeight
;
299 for (int32 i
= 0; i
< rowBytes
; i
++)
300 imageData
[0][i
]^=255;
301 target
->Write(imageData
[0], rowBytes
);
304 case PSD_COLOR_FORMAT_INDEXED
:
306 int32 paletteSize
= fColorModeDataSize
/ 3;
308 uint8
*colorData
= new uint8
[fColorModeDataSize
];
309 fStream
->Seek(fColorModeDataPos
, SEEK_SET
);
310 fStream
->Read(colorData
, fColorModeDataSize
);
312 if (_ParseImageResources() != B_OK
)
313 fTransparentIndex
= 256;
315 uint8
*redPalette
= colorData
;
316 uint8
*greenPalette
= colorData
+ paletteSize
;
317 uint8
*bluePalette
= colorData
+ paletteSize
* 2;
319 for (int h
= 0; h
< fHeight
; h
++) {
320 uint8
*ptr
= lineData
;
321 for (int w
= 0; w
< fWidth
; w
++) {
322 uint8 colorIndex
= imageData
[0][index
];
323 ptr
[0] = bluePalette
[colorIndex
];
324 ptr
[1] = greenPalette
[colorIndex
];
325 ptr
[2] = redPalette
[colorIndex
];
326 ptr
[3] = colorIndex
== fTransparentIndex
? 0 : 255;
328 ptr
+= sizeof(uint32
);
331 target
->Write(lineData
, fWidth
* sizeof(uint32
));
336 case PSD_COLOR_FORMAT_DUOTONE
:
337 case PSD_COLOR_FORMAT_GRAY
:
338 case PSD_COLOR_FORMAT_GRAY_A
:
340 bool isAlpha
= colorFormat
== PSD_COLOR_FORMAT_GRAY_A
;
342 for (int h
= 0; h
< fHeight
; h
++) {
343 uint8
*ptr
= lineData
;
344 for (int w
= 0; w
< fWidth
; w
++) {
345 ptr
[0] = imageData
[0][index
];
346 ptr
[1] = imageData
[0][index
];
347 ptr
[2] = imageData
[0][index
];
348 ptr
[3] = isAlpha
? imageData
[1][index
] : 255;
350 ptr
+= sizeof(uint32
);
353 target
->Write(lineData
, fWidth
* sizeof(uint32
));
357 case PSD_COLOR_FORMAT_MULTICHANNEL
:
358 case PSD_COLOR_FORMAT_RGB
:
359 case PSD_COLOR_FORMAT_RGB_A
:
361 bool isAlpha
= colorFormat
== PSD_COLOR_FORMAT_RGB_A
;
363 for (int h
= 0; h
< fHeight
; h
++) {
364 uint8
*ptr
= lineData
;
365 for (int w
= 0; w
< fWidth
; w
++) {
366 ptr
[0] = imageData
[2][index
];
367 ptr
[1] = imageData
[1][index
];
368 ptr
[2] = imageData
[0][index
];
369 ptr
[3] = isAlpha
? imageData
[3][index
] : 255;
371 ptr
+= sizeof(uint32
);
374 target
->Write(lineData
, fWidth
* sizeof(uint32
));
378 case PSD_COLOR_FORMAT_CMYK
:
379 case PSD_COLOR_FORMAT_CMYK_A
:
381 bool isAlpha
= colorFormat
== PSD_COLOR_FORMAT_CMYK_A
;
383 for (int h
= 0; h
< fHeight
; h
++) {
384 uint8
*ptr
= lineData
;
385 for (int w
= 0; w
< fWidth
; w
++) {
386 double c
= 1.0 - imageData
[0][index
] / 255.0;
387 double m
= 1.0 - imageData
[1][index
] / 255.0;
388 double y
= 1.0 - imageData
[2][index
] / 255.0;
389 double k
= 1.0 - imageData
[3][index
] / 255.0;
390 ptr
[0] = (uint8
)((1.0 - (y
* (1.0 - k
) + k
)) * 255.0);
391 ptr
[1] = (uint8
)((1.0 - (m
* (1.0 - k
) + k
)) * 255.0);
392 ptr
[2] = (uint8
)((1.0 - (c
* (1.0 - k
) + k
)) * 255.0);
393 ptr
[3] = isAlpha
? imageData
[4][index
] : 255;
395 ptr
+= sizeof(uint32
);
398 target
->Write(lineData
, fWidth
* sizeof(uint32
));
402 case PSD_COLOR_FORMAT_LAB
:
403 case PSD_COLOR_FORMAT_LAB_A
:
405 bool isAlpha
= colorFormat
== PSD_COLOR_FORMAT_LAB_A
;
407 for (int h
= 0; h
< fHeight
; h
++) {
408 uint8
*ptr
= lineData
;
409 for (int w
= 0; w
< fWidth
; w
++) {
410 double L
= imageData
[0][index
] / 255.0 * 100.0;
411 double a
= imageData
[1][index
] - 128.0;
412 double b
= imageData
[2][index
] - 128.0;
414 double Y
= L
* (1.0 / 116.0) + 16.0 / 116.0;
415 double X
= a
* (1.0 / 500.0) + Y
;
416 double Z
= b
* (-1.0 / 200.0) + Y
;
418 X
= X
> 6.0 / 29.0 ? X
* X
* X
: X
* (108.0 / 841.0)
420 Y
= L
> 8.0 ? Y
* Y
* Y
: L
* (27.0 / 24389.0);
421 Z
= Z
> 6.0 / 29.0 ? Z
* Z
* Z
: Z
* (108.0 / 841.0)
424 double R
= X
* (1219569.0 / 395920.0)
425 + Y
* (-608687.0 / 395920.0)
426 + Z
* (-107481.0 / 197960.0);
427 double G
= X
* (-80960619.0 / 87888100.0)
428 + Y
* (82435961.0 / 43944050.0)
429 + Z
* (3976797.0 / 87888100.0);
430 double B
= X
* (93813.0 / 1774030.0)
431 + Y
* (-180961.0 / 887015.0)
432 + Z
* (107481.0 / 93370.0);
434 R
= R
> 0.0031308 ? pow(R
, 1.0 / 2.4) * 1.055 - 0.055
436 G
= G
> 0.0031308 ? pow(G
, 1.0 / 2.4) * 1.055 - 0.055
438 B
= B
> 0.0031308 ? pow(B
, 1.0 / 2.4) * 1.055 - 0.055
441 R
= (R
< 0) ? 0 : ((R
> 1) ? 1 : R
);
442 G
= (G
< 0) ? 0 : ((G
> 1) ? 1 : G
);
443 B
= (B
< 0) ? 0 : ((B
> 1) ? 1 : B
);
445 ptr
[0] = (uint8
)(B
* 255.0);
446 ptr
[1] = (uint8
)(G
* 255.0);
447 ptr
[2] = (uint8
)(R
* 255.0);
448 ptr
[3] = isAlpha
? imageData
[3][index
] : 255;
450 ptr
+= sizeof(uint32
);
453 target
->Write(lineData
, fWidth
* sizeof(uint32
));
462 for (int i
= 0; i
< fChannels
; i
++)
463 delete[] imageData
[i
];
470 PSDLoader::_GetInt64FromStream(BPositionIO
*in
)
473 in
->Read(&ret
, sizeof(int64
));
474 return B_BENDIAN_TO_HOST_INT64(ret
);
479 PSDLoader::_GetInt32FromStream(BPositionIO
*in
)
482 in
->Read(&ret
, sizeof(int32
));
483 return B_BENDIAN_TO_HOST_INT32(ret
);
488 PSDLoader::_GetInt16FromStream(BPositionIO
*in
)
491 in
->Read(&ret
, sizeof(int16
));
492 return B_BENDIAN_TO_HOST_INT16(ret
);
497 PSDLoader::_GetInt8FromStream(BPositionIO
*in
)
500 in
->Read(&ret
, sizeof(int8
));
506 PSDLoader::_GetUInt8FromStream(BPositionIO
*in
)
509 in
->Read(&ret
, sizeof(uint8
));
515 PSDLoader::_SkipStreamBlock(BPositionIO
*in
, size_t count
)
517 in
->Seek(count
, SEEK_CUR
);
522 PSDLoader::_ParseImageResources(void)
524 if (!fLoaded
&& fImageResourceSectionSize
== 0)
527 size_t currentPos
= fStream
->Position();
528 fStream
->Seek(fImageResourceSectionPos
, SEEK_SET
);
530 while (fStream
->Position() < currentPos
+ fImageResourceSectionSize
) {
531 int32 resBlockSignature
= _GetInt32FromStream(fStream
);
532 if (resBlockSignature
!= 0x3842494D) // 8BIM
535 uint16 resID
= _GetInt16FromStream(fStream
);
537 BString resName
, name
;
540 int charData
= _GetUInt8FromStream(fStream
);
543 if (nameLength
% 2 == 1) {
544 _GetUInt8FromStream(fStream
);
553 uint32 resSize
= _GetInt32FromStream(fStream
);
555 if (resSize
% 2 == 1)
560 fTransparentIndex
= _GetInt16FromStream(fStream
);
563 _SkipStreamBlock(fStream
, resSize
);
567 fStream
->Seek(currentPos
, SEEK_SET
);