1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | #include "PSDLoader.h" |
8 | #include "BaseTranslator.h" |
9 | |
10 | |
11 | PSDLoader::PSDLoader(BPositionIO *src) |
12 | { |
13 | fLoaded = false; |
14 | fStream = src; |
15 | |
16 | fStream->Seek(0, SEEK_END2); |
17 | fStreamSize = fStream->Position(); |
18 | fStream->Seek(0, SEEK_SET0); |
19 | |
20 | if (fStreamSize <= 0) |
21 | return; |
22 | |
23 | fStream->Seek(0, SEEK_SET0); |
24 | |
25 | fSignature = _GetInt32FromStream(fStream); |
26 | if (fSignature != 0x38425053) |
27 | return; |
28 | |
29 | fVersion = _GetInt16FromStream(fStream); |
30 | |
31 | |
32 | _SkipStreamBlock(fStream, 6); |
33 | |
34 | fChannels = _GetInt16FromStream(fStream); |
35 | fHeight = _GetInt32FromStream(fStream); |
36 | fWidth = _GetInt32FromStream(fStream); |
37 | fDepth = _GetInt16FromStream(fStream); |
38 | fColorFormat = _GetInt16FromStream(fStream); |
39 | |
40 | fColorModeDataSize = _GetInt32FromStream(fStream); |
41 | fColorModeDataPos = fStream->Position(); |
42 | _SkipStreamBlock(fStream, fColorModeDataSize); |
43 | |
44 | fImageResourceSectionSize = _GetInt32FromStream(fStream); |
45 | fImageResourceSectionPos = fStream->Position(); |
46 | _SkipStreamBlock(fStream, fImageResourceSectionSize); |
47 | |
48 | |
49 | if (fVersion == PSD_FILE) |
50 | _SkipStreamBlock(fStream, _GetInt32FromStream(fStream)); |
51 | else if (fVersion == PSB_FILE) |
52 | _SkipStreamBlock(fStream, _GetInt64FromStream(fStream)); |
53 | else |
54 | return; |
55 | |
56 | fCompression = _GetInt16FromStream(fStream); |
57 | |
58 | fStreamPos = fStream->Position(); |
59 | |
60 | fLoaded = true; |
61 | } |
62 | |
63 | |
64 | PSDLoader::~PSDLoader() |
65 | { |
66 | } |
67 | |
68 | |
69 | bool |
70 | PSDLoader::IsLoaded(void) |
71 | { |
72 | return fLoaded; |
73 | } |
74 | |
75 | |
76 | bool |
77 | PSDLoader::IsSupported(void) |
78 | { |
79 | if (!fLoaded) |
80 | return false; |
81 | |
82 | if (fVersion != PSD_FILE |
83 | && fVersion != PSB_FILE) { |
84 | return false; |
85 | } |
86 | |
87 | if (fChannels < 0 || fChannels > PSD_MAX_CHANNELS16) |
88 | return false; |
89 | |
90 | if (fDepth > 16) |
91 | return false; |
92 | |
93 | if (_ColorFormat() == PSD_COLOR_FORMAT_UNSUPPORTED) |
94 | return false; |
95 | |
96 | if (fCompression != PSD_COMPRESSED_RAW |
97 | && fCompression != PSD_COMPRESSED_RLE) { |
98 | return false; |
99 | } |
100 | |
101 | return true; |
102 | } |
103 | |
104 | |
105 | BString |
106 | PSDLoader::ColorFormatName(void) |
107 | { |
108 | switch (fColorFormat) { |
109 | case PSD_COLOR_MODE_BITS: |
110 | return "Bitmap"; |
111 | case PSD_COLOR_MODE_GRAYSCALE: |
112 | return "Grayscale"; |
113 | case PSD_COLOR_MODE_INDEXED: |
114 | return "Indexed"; |
115 | case PSD_COLOR_MODE_RGB: |
116 | return fChannels > 3 ? "RGBA" : "RGB"; |
117 | case PSD_COLOR_MODE_CMYK: |
118 | return "CMYK"; |
119 | case PSD_COLOR_MODE_MULTICHANNEL: |
120 | return "Multichannel"; |
121 | case PSD_COLOR_MODE_LAB: |
122 | return "Lab"; |
123 | case PSD_COLOR_MODE_DUOTONE: |
124 | return "Duotone"; |
125 | } |
126 | return ""; |
127 | } |
128 | |
129 | |
130 | psd_color_format |
131 | PSDLoader::_ColorFormat(void) |
132 | { |
133 | psd_color_format format = PSD_COLOR_FORMAT_UNSUPPORTED; |
134 | if (!fLoaded) |
135 | return format; |
136 | |
137 | switch (fColorFormat) { |
138 | case PSD_COLOR_MODE_BITS: |
139 | format = PSD_COLOR_FORMAT_BITMAP; |
140 | break; |
141 | case PSD_COLOR_MODE_RGB: |
142 | if (fChannels == 3) |
143 | format = PSD_COLOR_FORMAT_RGB; |
144 | else if (fChannels >= 4) |
145 | format = PSD_COLOR_FORMAT_RGB_A; |
146 | break; |
147 | case PSD_COLOR_MODE_GRAYSCALE: |
148 | if (fChannels == 1) |
149 | format = PSD_COLOR_FORMAT_GRAY; |
150 | else if (fChannels == 2) |
151 | format = PSD_COLOR_FORMAT_GRAY_A; |
152 | break; |
153 | case PSD_COLOR_MODE_MULTICHANNEL: |
154 | if (fChannels == 3) |
155 | format = PSD_COLOR_FORMAT_MULTICHANNEL; |
156 | break; |
157 | case PSD_COLOR_MODE_CMYK: |
158 | if (fChannels == 3) |
159 | format = PSD_COLOR_FORMAT_MULTICHANNEL; |
160 | else if (fChannels == 4) |
161 | format = PSD_COLOR_FORMAT_CMYK; |
162 | else if (fChannels > 4) |
163 | format = PSD_COLOR_FORMAT_CMYK_A; |
164 | break; |
165 | case PSD_COLOR_MODE_LAB: |
166 | if (fChannels == 3) |
167 | format = PSD_COLOR_FORMAT_LAB; |
168 | else if (fChannels > 3) |
169 | format = PSD_COLOR_FORMAT_LAB_A; |
170 | break; |
171 | case PSD_COLOR_MODE_DUOTONE: |
172 | if (fChannels >= 1) |
173 | format = PSD_COLOR_FORMAT_DUOTONE; |
174 | break; |
175 | case PSD_COLOR_MODE_INDEXED: |
176 | if (fChannels >= 1 && fColorModeDataSize >= 3) |
177 | format = PSD_COLOR_FORMAT_INDEXED; |
178 | break; |
179 | default: |
180 | break; |
181 | }; |
182 | |
183 | return format; |
184 | } |
185 | |
186 | |
187 | status_t |
188 | PSDLoader::Decode(BPositionIO *target) |
189 | { |
190 | if (!IsSupported()) |
| |
191 | return B_NO_TRANSLATOR(((-2147483647 - 1) + 0x4800) + 1); |
192 | |
193 | fStreamBuffer = new uint8[fStreamSize]; |
| |
194 | fStream->Seek(0, SEEK_SET0); |
195 | fStream->Read(fStreamBuffer, fStreamSize); |
196 | |
197 | int32 depthBytes = fDepth / 8; |
198 | int32 rowBytes = (fWidth * fDepth) / 8; |
199 | int32 channelBytes = rowBytes * fHeight; |
200 | |
201 | uint8 *imageData[PSD_MAX_CHANNELS16]; |
202 | for (int i = 0; i < fChannels; i++) |
| 3 | | Loop condition is true. Entering loop body | |
|
| 4 | | Loop condition is false. Execution continues on line 206 | |
|
203 | imageData[i] = new uint8[channelBytes]; |
204 | |
205 | |
206 | switch (fCompression) { |
| 5 | | Control jumps to 'case PSD_COMPRESSED_RAW:' at line 207 | |
|
207 | case PSD_COMPRESSED_RAW: |
208 | { |
209 | for (int channelIdx = 0; channelIdx < fChannels; channelIdx++) { |
| 6 | | Loop condition is true. Entering loop body | |
|
| 9 | | Loop condition is false. Execution continues on line 214 | |
|
210 | uint8 *ptr = imageData[channelIdx]; |
211 | for (int i = 0; i < channelBytes; i++, ptr++) |
| 7 | | Assuming 'i' is >= 'channelBytes' | |
|
| 8 | | Loop condition is false. Execution continues on line 209 | |
|
212 | *ptr = (uint8)fStreamBuffer[fStreamPos++]; |
213 | } |
214 | break; |
| 10 | | Execution continues on line 259 | |
|
215 | } |
216 | case PSD_COMPRESSED_RLE: |
217 | { |
218 | if (fVersion == PSD_FILE) |
219 | fStreamPos += fHeight * fChannels * 2; |
220 | else if (fVersion == PSB_FILE) |
221 | fStreamPos += fHeight * fChannels * 4; |
222 | |
223 | for (int channelIdx = 0; channelIdx < fChannels; channelIdx++) { |
224 | uint8 *ptr = imageData[channelIdx]; |
225 | |
226 | int count = 0; |
227 | while (count < channelBytes) { |
228 | uint8 len = (uint8)fStreamBuffer[fStreamPos++]; |
229 | if (len == 128) { |
230 | continue; |
231 | } else if (len < 128) { |
232 | len++; |
233 | count += len; |
234 | while (len) { |
235 | *ptr++ = (int8)fStreamBuffer[fStreamPos++]; |
236 | len--; |
237 | } |
238 | } else if (len > 128) { |
239 | int8 val = (int8)fStreamBuffer[fStreamPos++]; |
240 | len ^= 255; |
241 | len += 2; |
242 | count += len; |
243 | while (len) { |
244 | *ptr++ = val; |
245 | len--; |
246 | } |
247 | } |
248 | } |
249 | } |
250 | break; |
251 | } |
252 | default: |
253 | delete fStreamBuffer; |
254 | for (int i = 0; i < fChannels; i++) |
255 | delete imageData[i]; |
256 | return B_NO_TRANSLATOR(((-2147483647 - 1) + 0x4800) + 1); |
257 | } |
258 | |
259 | delete fStreamBuffer; |
| 11 | | Memory allocated by 'new[]' should be deallocated by 'delete[]', not 'delete' |
|
260 | |
261 | TranslatorBitmap bitsHeader; |
262 | bitsHeader.magic = B_TRANSLATOR_BITMAP; |
263 | bitsHeader.bounds.left = 0; |
264 | bitsHeader.bounds.top = 0; |
265 | bitsHeader.bounds.right = fWidth - 1; |
266 | bitsHeader.bounds.bottom = fHeight - 1; |
267 | |
268 | psd_color_format colorFormat = _ColorFormat(); |
269 | |
270 | if (colorFormat == PSD_COLOR_FORMAT_BITMAP) { |
271 | bitsHeader.rowBytes = rowBytes; |
272 | bitsHeader.dataSize = channelBytes; |
273 | bitsHeader.colors = B_GRAY1; |
274 | } else { |
275 | bitsHeader.rowBytes = sizeof(uint32) * fWidth; |
276 | bitsHeader.colors = B_RGBA32; |
277 | bitsHeader.dataSize = bitsHeader.rowBytes * fHeight; |
278 | } |
279 | |
280 | if (swap_data(B_UINT32_TYPE, &bitsHeader, |
281 | sizeof(TranslatorBitmap), B_SWAP_HOST_TO_BENDIAN) != B_OK((int)0)) { |
282 | return B_NO_TRANSLATOR(((-2147483647 - 1) + 0x4800) + 1); |
283 | } |
284 | |
285 | target->Write(&bitsHeader, sizeof(TranslatorBitmap)); |
286 | |
287 | uint8 *lineData = new uint8[fWidth * sizeof(uint32)]; |
288 | |
289 | switch (colorFormat) { |
290 | case PSD_COLOR_FORMAT_BITMAP: |
291 | { |
292 | int32 rowBytes = (fWidth / 8 ) * fHeight; |
293 | for (int32 i = 0; i < rowBytes; i++) |
294 | imageData[0][i]^=255; |
295 | target->Write(imageData[0], rowBytes); |
296 | break; |
297 | } |
298 | case PSD_COLOR_FORMAT_INDEXED: |
299 | { |
300 | int32 paletteSize = fColorModeDataSize / 3; |
301 | |
302 | uint8 *colorData = new uint8[fColorModeDataSize]; |
303 | fStream->Seek(fColorModeDataPos, SEEK_SET0); |
304 | fStream->Read(colorData, fColorModeDataSize); |
305 | |
306 | if (_ParseImageResources() != B_OK((int)0)) |
307 | fTransparentIndex = 256; |
308 | |
309 | uint8 *redPalette = colorData; |
310 | uint8 *greenPalette = colorData + paletteSize; |
311 | uint8 *bluePalette = colorData + paletteSize * 2; |
312 | int32 index = 0; |
313 | for (int h = 0; h < fHeight; h++) { |
314 | uint8 *ptr = lineData; |
315 | for (int w = 0; w < fWidth; w++) { |
316 | uint8 colorIndex = imageData[0][index]; |
317 | ptr[0] = bluePalette[colorIndex]; |
318 | ptr[1] = greenPalette[colorIndex]; |
319 | ptr[2] = redPalette[colorIndex]; |
320 | ptr[3] = colorIndex == fTransparentIndex ? 0 : 255; |
321 | |
322 | ptr += sizeof(uint32); |
323 | index++; |
324 | } |
325 | target->Write(lineData, fWidth * sizeof(uint32)); |
326 | } |
327 | delete colorData; |
328 | break; |
329 | } |
330 | case PSD_COLOR_FORMAT_DUOTONE: |
331 | case PSD_COLOR_FORMAT_GRAY: |
332 | case PSD_COLOR_FORMAT_GRAY_A: |
333 | { |
334 | bool isAlpha = colorFormat == PSD_COLOR_FORMAT_GRAY_A; |
335 | int32 index = 0; |
336 | for (int h = 0; h < fHeight; h++) { |
337 | uint8 *ptr = lineData; |
338 | for (int w = 0; w < fWidth; w++) { |
339 | ptr[0] = imageData[0][index]; |
340 | ptr[1] = imageData[0][index]; |
341 | ptr[2] = imageData[0][index]; |
342 | ptr[3] = isAlpha ? imageData[1][index] : 255; |
343 | |
344 | ptr += sizeof(uint32); |
345 | index += depthBytes; |
346 | } |
347 | target->Write(lineData, fWidth * sizeof(uint32)); |
348 | } |
349 | break; |
350 | } |
351 | case PSD_COLOR_FORMAT_MULTICHANNEL: |
352 | case PSD_COLOR_FORMAT_RGB: |
353 | case PSD_COLOR_FORMAT_RGB_A: |
354 | { |
355 | bool isAlpha = colorFormat == PSD_COLOR_FORMAT_RGB_A; |
356 | int32 index = 0; |
357 | for (int h = 0; h < fHeight; h++) { |
358 | uint8 *ptr = lineData; |
359 | for (int w = 0; w < fWidth; w++) { |
360 | ptr[0] = imageData[2][index]; |
361 | ptr[1] = imageData[1][index]; |
362 | ptr[2] = imageData[0][index]; |
363 | ptr[3] = isAlpha ? imageData[3][index] : 255; |
364 | |
365 | ptr += sizeof(uint32); |
366 | index += depthBytes; |
367 | } |
368 | target->Write(lineData, fWidth * sizeof(uint32)); |
369 | } |
370 | break; |
371 | } |
372 | case PSD_COLOR_FORMAT_CMYK: |
373 | case PSD_COLOR_FORMAT_CMYK_A: |
374 | { |
375 | bool isAlpha = colorFormat == PSD_COLOR_FORMAT_CMYK_A; |
376 | int32 index = 0; |
377 | for (int h = 0; h < fHeight; h++) { |
378 | uint8 *ptr = lineData; |
379 | for (int w = 0; w < fWidth; w++) { |
380 | double c = 1.0 - imageData[0][index] / 255.0; |
381 | double m = 1.0 - imageData[1][index] / 255.0; |
382 | double y = 1.0 - imageData[2][index] / 255.0; |
383 | double k = 1.0 - imageData[3][index] / 255.0; |
384 | ptr[0] = (uint8)((1.0 - (y * (1.0 - k) + k)) * 255.0); |
385 | ptr[1] = (uint8)((1.0 - (m * (1.0 - k) + k)) * 255.0); |
386 | ptr[2] = (uint8)((1.0 - (c * (1.0 - k) + k)) * 255.0); |
387 | ptr[3] = isAlpha ? imageData[4][index] : 255; |
388 | |
389 | ptr += sizeof(uint32); |
390 | index += depthBytes; |
391 | } |
392 | target->Write(lineData, fWidth * sizeof(uint32)); |
393 | } |
394 | break; |
395 | } |
396 | case PSD_COLOR_FORMAT_LAB: |
397 | case PSD_COLOR_FORMAT_LAB_A: |
398 | { |
399 | bool isAlpha = colorFormat == PSD_COLOR_FORMAT_LAB_A; |
400 | int32 index = 0; |
401 | for (int h = 0; h < fHeight; h++) { |
402 | uint8 *ptr = lineData; |
403 | for (int w = 0; w < fWidth; w++) { |
404 | double L = imageData[0][index] / 255.0 * 100.0; |
405 | double a = imageData[1][index] - 128.0; |
406 | double b = imageData[2][index] - 128.0; |
407 | |
408 | double Y = L * (1.0 / 116.0) + 16.0 / 116.0; |
409 | double X = a * (1.0 / 500.0) + Y; |
410 | double Z = b * (-1.0 / 200.0) + Y; |
411 | |
412 | X = X > 6.0 / 29.0 ? X * X * X : X * (108.0 / 841.0) |
413 | - (432.0 / 24389.0); |
414 | Y = L > 8.0 ? Y * Y * Y : L * (27.0 / 24389.0); |
415 | Z = Z > 6.0 / 29.0 ? Z * Z * Z : Z * (108.0 / 841.0) |
416 | - (432.0 / 24389.0); |
417 | |
418 | double R = X * (1219569.0 / 395920.0) |
419 | + Y * (-608687.0 / 395920.0) |
420 | + Z * (-107481.0 / 197960.0); |
421 | double G = X * (-80960619.0 / 87888100.0) |
422 | + Y * (82435961.0 / 43944050.0) |
423 | + Z * (3976797.0 / 87888100.0); |
424 | double B = X * (93813.0 / 1774030.0) |
425 | + Y * (-180961.0 / 887015.0) |
426 | + Z * (107481.0 / 93370.0); |
427 | |
428 | R = R > 0.0031308 ? pow(R, 1.0 / 2.4) * 1.055 - 0.055 |
429 | : R * 12.92; |
430 | G = G > 0.0031308 ? pow(G, 1.0 / 2.4) * 1.055 - 0.055 |
431 | : G * 12.92; |
432 | B = B > 0.0031308 ? pow(B, 1.0 / 2.4) * 1.055 - 0.055 |
433 | : B * 12.92; |
434 | |
435 | R = (R < 0) ? 0 : ((R > 1) ? 1 : R); |
436 | G = (G < 0) ? 0 : ((G > 1) ? 1 : G); |
437 | B = (B < 0) ? 0 : ((B > 1) ? 1 : B); |
438 | |
439 | ptr[0] = (uint8)(B * 255.0); |
440 | ptr[1] = (uint8)(G * 255.0); |
441 | ptr[2] = (uint8)(R * 255.0); |
442 | ptr[3] = isAlpha ? imageData[3][index] : 255; |
443 | |
444 | ptr += sizeof(uint32); |
445 | index += depthBytes; |
446 | } |
447 | target->Write(lineData, fWidth * sizeof(uint32)); |
448 | } |
449 | break; |
450 | } |
451 | default: |
452 | break; |
453 | }; |
454 | |
455 | delete lineData; |
456 | for (int i = 0; i < fChannels; i++) |
457 | delete imageData[i]; |
458 | |
459 | return B_OK((int)0); |
460 | } |
461 | |
462 | |
463 | int64 |
464 | PSDLoader::_GetInt64FromStream(BPositionIO *in) |
465 | { |
466 | int64 ret; |
467 | in->Read(&ret, sizeof(int64)); |
468 | return B_BENDIAN_TO_HOST_INT64(ret)__swap_int64(ret); |
469 | } |
470 | |
471 | |
472 | int32 |
473 | PSDLoader::_GetInt32FromStream(BPositionIO *in) |
474 | { |
475 | int32 ret; |
476 | in->Read(&ret, sizeof(int32)); |
477 | return B_BENDIAN_TO_HOST_INT32(ret)__swap_int32(ret); |
478 | } |
479 | |
480 | |
481 | int16 |
482 | PSDLoader::_GetInt16FromStream(BPositionIO *in) |
483 | { |
484 | int16 ret; |
485 | in->Read(&ret, sizeof(int16)); |
486 | return B_BENDIAN_TO_HOST_INT16(ret)__swap_int16(ret); |
487 | } |
488 | |
489 | |
490 | int8 |
491 | PSDLoader::_GetInt8FromStream(BPositionIO *in) |
492 | { |
493 | int8 ret; |
494 | in->Read(&ret, sizeof(int8)); |
495 | return ret; |
496 | } |
497 | |
498 | |
499 | uint8 |
500 | PSDLoader::_GetUInt8FromStream(BPositionIO *in) |
501 | { |
502 | uint8 ret; |
503 | in->Read(&ret, sizeof(uint8)); |
504 | return ret; |
505 | } |
506 | |
507 | |
508 | void |
509 | PSDLoader::_SkipStreamBlock(BPositionIO *in, size_t count) |
510 | { |
511 | in->Seek(count, SEEK_CUR1); |
512 | } |
513 | |
514 | |
515 | status_t |
516 | PSDLoader::_ParseImageResources(void) |
517 | { |
518 | if (!fLoaded && fImageResourceSectionSize == 0) |
519 | return B_ERROR(-1); |
520 | |
521 | size_t currentPos = fStream->Position(); |
522 | fStream->Seek(fImageResourceSectionPos, SEEK_SET0); |
523 | |
524 | while (fStream->Position() < currentPos + fImageResourceSectionSize) { |
525 | int32 resBlockSignature = _GetInt32FromStream(fStream); |
526 | if (resBlockSignature != 0x3842494D) |
527 | return B_ERROR(-1); |
528 | |
529 | uint16 resID = _GetInt16FromStream(fStream); |
530 | |
531 | BString resName, name; |
532 | int nameLength = 0; |
533 | while (true) { |
534 | int charData = _GetUInt8FromStream(fStream); |
535 | nameLength++; |
536 | if (charData == 0) { |
537 | if (nameLength % 2 == 1) { |
538 | _GetUInt8FromStream(fStream); |
539 | nameLength++; |
540 | } |
541 | break; |
542 | } else |
543 | name += charData; |
544 | resName = name; |
545 | } |
546 | |
547 | uint32 resSize = _GetInt32FromStream(fStream); |
548 | |
549 | if (resSize % 2 == 1) |
550 | resSize++; |
551 | |
552 | switch (resID) { |
553 | case 0x0417: |
554 | fTransparentIndex = _GetInt16FromStream(fStream); |
555 | break; |
556 | default: |
557 | _SkipStreamBlock(fStream, resSize); |
558 | } |
559 | } |
560 | |
561 | fStream->Seek(currentPos, SEEK_SET0); |
562 | |
563 | return B_OK((int)0); |
564 | } |