1 /* 2 * Copyright 2013, Gerasim Troeglazov, 3dEyes@gmail.com. All rights reserved. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 7 #include "PSDLoader.h" 8 9 #include <Catalog.h> 10 11 #include "BaseTranslator.h" 12 13 #undef B_TRANSLATION_CONTEXT 14 #define B_TRANSLATION_CONTEXT "PSDLoader" 15 16 17 PSDLoader::PSDLoader(BPositionIO *src) 18 { 19 fLoaded = false; 20 fStream = src; 21 22 fStream->Seek(0, SEEK_END); 23 fStreamSize = fStream->Position(); 24 fStream->Seek(0, SEEK_SET); 25 26 if (fStreamSize <= 0) 27 return; 28 29 fStream->Seek(0, SEEK_SET); 30 31 fSignature = _GetInt32FromStream(fStream); 32 if (fSignature != 0x38425053) // 8BPS 33 return; 34 35 fVersion = _GetInt16FromStream(fStream); 36 37 // Skip reserved data 38 _SkipStreamBlock(fStream, 6); 39 40 fChannels = _GetInt16FromStream(fStream); 41 fHeight = _GetInt32FromStream(fStream); 42 fWidth = _GetInt32FromStream(fStream); 43 fDepth = _GetInt16FromStream(fStream); 44 fColorFormat = _GetInt16FromStream(fStream); 45 46 fColorModeDataSize = _GetInt32FromStream(fStream); 47 fColorModeDataPos = fStream->Position(); 48 _SkipStreamBlock(fStream, fColorModeDataSize); 49 50 fImageResourceSectionSize = _GetInt32FromStream(fStream); 51 fImageResourceSectionPos = fStream->Position(); 52 _SkipStreamBlock(fStream, fImageResourceSectionSize); 53 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)); 59 else 60 return; 61 62 fCompression = _GetInt16FromStream(fStream); 63 64 fStreamPos = fStream->Position(); 65 66 fLoaded = true; 67 } 68 69 70 PSDLoader::~PSDLoader() 71 { 72 } 73 74 75 bool 76 PSDLoader::IsLoaded(void) 77 { 78 return fLoaded; 79 } 80 81 82 bool 83 PSDLoader::IsSupported(void) 84 { 85 if (!fLoaded) 86 return false; 87 88 if (fVersion != PSD_FILE 89 && fVersion != PSB_FILE) { 90 return false; 91 } 92 93 if (fChannels < 0 || fChannels > PSD_MAX_CHANNELS) 94 return false; 95 96 if (fDepth > 16) 97 return false; 98 99 if (_ColorFormat() == PSD_COLOR_FORMAT_UNSUPPORTED) 100 return false; 101 102 if (fCompression != PSD_COMPRESSED_RAW 103 && fCompression != PSD_COMPRESSED_RLE) { 104 return false; 105 } 106 107 return true; 108 } 109 110 111 BString 112 PSDLoader::ColorFormatName(void) 113 { 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"); 131 } 132 return ""; 133 } 134 135 136 psd_color_format 137 PSDLoader::_ColorFormat(void) 138 { 139 psd_color_format format = PSD_COLOR_FORMAT_UNSUPPORTED; 140 if (!fLoaded) 141 return format; 142 143 switch (fColorFormat) { 144 case PSD_COLOR_MODE_BITS: 145 format = PSD_COLOR_FORMAT_BITMAP; 146 break; 147 case PSD_COLOR_MODE_RGB: 148 if (fChannels == 3) 149 format = PSD_COLOR_FORMAT_RGB; 150 else if (fChannels >= 4) 151 format = PSD_COLOR_FORMAT_RGB_A; 152 break; 153 case PSD_COLOR_MODE_GRAYSCALE: 154 if (fChannels == 1) 155 format = PSD_COLOR_FORMAT_GRAY; 156 else if (fChannels == 2) 157 format = PSD_COLOR_FORMAT_GRAY_A; 158 break; 159 case PSD_COLOR_MODE_MULTICHANNEL: 160 if (fChannels == 3) 161 format = PSD_COLOR_FORMAT_MULTICHANNEL; 162 break; 163 case PSD_COLOR_MODE_CMYK: 164 if (fChannels == 3) 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; 170 break; 171 case PSD_COLOR_MODE_LAB: 172 if (fChannels == 3) 173 format = PSD_COLOR_FORMAT_LAB; 174 else if (fChannels > 3) 175 format = PSD_COLOR_FORMAT_LAB_A; 176 break; 177 case PSD_COLOR_MODE_DUOTONE: 178 if (fChannels >= 1) 179 format = PSD_COLOR_FORMAT_DUOTONE; 180 break; 181 case PSD_COLOR_MODE_INDEXED: 182 if (fChannels >= 1 && fColorModeDataSize >= 3) 183 format = PSD_COLOR_FORMAT_INDEXED; 184 break; 185 default: 186 break; 187 }; 188 189 return format; 190 } 191 192 193 status_t 194 PSDLoader::Decode(BPositionIO *target) 195 { 196 if (!IsSupported()) 197 return B_NO_TRANSLATOR; 198 199 fStreamBuffer = new uint8[fStreamSize]; 200 fStream->Seek(0, SEEK_SET); 201 fStream->Read(fStreamBuffer, fStreamSize); 202 203 int32 depthBytes = fDepth / 8; 204 int32 rowBytes = (fWidth * fDepth) / 8; 205 int32 channelBytes = rowBytes * fHeight; 206 207 uint8 *imageData[PSD_MAX_CHANNELS]; 208 for (int i = 0; i < fChannels; i++) 209 imageData[i] = new uint8[channelBytes]; 210 211 212 switch (fCompression) { 213 case PSD_COMPRESSED_RAW: 214 { 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++]; 219 } 220 break; 221 } 222 case PSD_COMPRESSED_RLE: 223 { 224 if (fVersion == PSD_FILE) 225 fStreamPos += fHeight * fChannels * 2; 226 else if (fVersion == PSB_FILE) 227 fStreamPos += fHeight * fChannels * 4; 228 229 for (int channelIdx = 0; channelIdx < fChannels; channelIdx++) { 230 uint8 *ptr = imageData[channelIdx]; 231 // Read the RLE data. 232 int count = 0; 233 while (count < channelBytes) { 234 uint8 len = (uint8)fStreamBuffer[fStreamPos++]; 235 if (len == 128) { 236 continue; 237 } else if (len < 128) { 238 len++; 239 count += len; 240 while (len) { 241 *ptr++ = (int8)fStreamBuffer[fStreamPos++]; 242 len--; 243 } 244 } else if (len > 128) { 245 int8 val = (int8)fStreamBuffer[fStreamPos++]; 246 len ^= 255; 247 len += 2; 248 count += len; 249 while (len) { 250 *ptr++ = val; 251 len--; 252 } 253 } 254 } 255 } 256 break; 257 } 258 default: 259 delete[] fStreamBuffer; 260 for (int i = 0; i < fChannels; i++) 261 delete[] imageData[i]; 262 return B_NO_TRANSLATOR; 263 } 264 265 delete[] fStreamBuffer; 266 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; 273 274 psd_color_format colorFormat = _ColorFormat(); 275 276 if (colorFormat == PSD_COLOR_FORMAT_BITMAP) { 277 bitsHeader.rowBytes = rowBytes; 278 bitsHeader.dataSize = channelBytes; 279 bitsHeader.colors = B_GRAY1; 280 } else { 281 bitsHeader.rowBytes = sizeof(uint32) * fWidth; 282 bitsHeader.colors = B_RGBA32; 283 bitsHeader.dataSize = bitsHeader.rowBytes * fHeight; 284 } 285 286 if (swap_data(B_UINT32_TYPE, &bitsHeader, 287 sizeof(TranslatorBitmap), B_SWAP_HOST_TO_BENDIAN) != B_OK) { 288 return B_NO_TRANSLATOR; 289 } 290 291 target->Write(&bitsHeader, sizeof(TranslatorBitmap)); 292 293 uint8 *lineData = new uint8[fWidth * sizeof(uint32)]; 294 295 switch (colorFormat) { 296 case PSD_COLOR_FORMAT_BITMAP: 297 { 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); 302 break; 303 } 304 case PSD_COLOR_FORMAT_INDEXED: 305 { 306 int32 paletteSize = fColorModeDataSize / 3; 307 308 uint8 *colorData = new uint8[fColorModeDataSize]; 309 fStream->Seek(fColorModeDataPos, SEEK_SET); 310 fStream->Read(colorData, fColorModeDataSize); 311 312 if (_ParseImageResources() != B_OK) 313 fTransparentIndex = 256; 314 315 uint8 *redPalette = colorData; 316 uint8 *greenPalette = colorData + paletteSize; 317 uint8 *bluePalette = colorData + paletteSize * 2; 318 int32 index = 0; 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; 327 328 ptr += sizeof(uint32); 329 index++; 330 } 331 target->Write(lineData, fWidth * sizeof(uint32)); 332 } 333 delete[] colorData; 334 break; 335 } 336 case PSD_COLOR_FORMAT_DUOTONE: 337 case PSD_COLOR_FORMAT_GRAY: 338 case PSD_COLOR_FORMAT_GRAY_A: 339 { 340 bool isAlpha = colorFormat == PSD_COLOR_FORMAT_GRAY_A; 341 int32 index = 0; 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; 349 350 ptr += sizeof(uint32); 351 index += depthBytes; 352 } 353 target->Write(lineData, fWidth * sizeof(uint32)); 354 } 355 break; 356 } 357 case PSD_COLOR_FORMAT_MULTICHANNEL: 358 case PSD_COLOR_FORMAT_RGB: 359 case PSD_COLOR_FORMAT_RGB_A: 360 { 361 bool isAlpha = colorFormat == PSD_COLOR_FORMAT_RGB_A; 362 int32 index = 0; 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; 370 371 ptr += sizeof(uint32); 372 index += depthBytes; 373 } 374 target->Write(lineData, fWidth * sizeof(uint32)); 375 } 376 break; 377 } 378 case PSD_COLOR_FORMAT_CMYK: 379 case PSD_COLOR_FORMAT_CMYK_A: 380 { 381 bool isAlpha = colorFormat == PSD_COLOR_FORMAT_CMYK_A; 382 int32 index = 0; 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; 394 395 ptr += sizeof(uint32); 396 index += depthBytes; 397 } 398 target->Write(lineData, fWidth * sizeof(uint32)); 399 } 400 break; 401 } 402 case PSD_COLOR_FORMAT_LAB: 403 case PSD_COLOR_FORMAT_LAB_A: 404 { 405 bool isAlpha = colorFormat == PSD_COLOR_FORMAT_LAB_A; 406 int32 index = 0; 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; 413 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; 417 418 X = X > 6.0 / 29.0 ? X * X * X : X * (108.0 / 841.0) 419 - (432.0 / 24389.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) 422 - (432.0 / 24389.0); 423 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); 433 434 R = R > 0.0031308 ? pow(R, 1.0 / 2.4) * 1.055 - 0.055 435 : R * 12.92; 436 G = G > 0.0031308 ? pow(G, 1.0 / 2.4) * 1.055 - 0.055 437 : G * 12.92; 438 B = B > 0.0031308 ? pow(B, 1.0 / 2.4) * 1.055 - 0.055 439 : B * 12.92; 440 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); 444 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; 449 450 ptr += sizeof(uint32); 451 index += depthBytes; 452 } 453 target->Write(lineData, fWidth * sizeof(uint32)); 454 } 455 break; 456 } 457 default: 458 break; 459 }; 460 461 delete[] lineData; 462 for (int i = 0; i < fChannels; i++) 463 delete[] imageData[i]; 464 465 return B_OK; 466 } 467 468 469 int64 470 PSDLoader::_GetInt64FromStream(BPositionIO *in) 471 { 472 int64 ret; 473 in->Read(&ret, sizeof(int64)); 474 return B_BENDIAN_TO_HOST_INT64(ret); 475 } 476 477 478 int32 479 PSDLoader::_GetInt32FromStream(BPositionIO *in) 480 { 481 int32 ret; 482 in->Read(&ret, sizeof(int32)); 483 return B_BENDIAN_TO_HOST_INT32(ret); 484 } 485 486 487 int16 488 PSDLoader::_GetInt16FromStream(BPositionIO *in) 489 { 490 int16 ret; 491 in->Read(&ret, sizeof(int16)); 492 return B_BENDIAN_TO_HOST_INT16(ret); 493 } 494 495 496 int8 497 PSDLoader::_GetInt8FromStream(BPositionIO *in) 498 { 499 int8 ret; 500 in->Read(&ret, sizeof(int8)); 501 return ret; 502 } 503 504 505 uint8 506 PSDLoader::_GetUInt8FromStream(BPositionIO *in) 507 { 508 uint8 ret; 509 in->Read(&ret, sizeof(uint8)); 510 return ret; 511 } 512 513 514 void 515 PSDLoader::_SkipStreamBlock(BPositionIO *in, size_t count) 516 { 517 in->Seek(count, SEEK_CUR); 518 } 519 520 521 status_t 522 PSDLoader::_ParseImageResources(void) 523 { 524 if (!fLoaded && fImageResourceSectionSize == 0) 525 return B_ERROR; 526 527 size_t currentPos = fStream->Position(); 528 fStream->Seek(fImageResourceSectionPos, SEEK_SET); 529 530 while (fStream->Position() < currentPos + fImageResourceSectionSize) { 531 int32 resBlockSignature = _GetInt32FromStream(fStream); 532 if (resBlockSignature != 0x3842494D) // 8BIM 533 return B_ERROR; 534 535 uint16 resID = _GetInt16FromStream(fStream); 536 537 BString resName, name; 538 int nameLength = 0; 539 while (true) { 540 int charData = _GetUInt8FromStream(fStream); 541 nameLength++; 542 if (charData == 0) { 543 if (nameLength % 2 == 1) { 544 _GetUInt8FromStream(fStream); 545 nameLength++; 546 } 547 break; 548 } else 549 name += charData; 550 resName = name; 551 } 552 553 uint32 resSize = _GetInt32FromStream(fStream); 554 555 if (resSize % 2 == 1) 556 resSize++; 557 558 switch (resID) { 559 case 0x0417: 560 fTransparentIndex = _GetInt16FromStream(fStream); 561 break; 562 default: 563 _SkipStreamBlock(fStream, resSize); 564 } 565 } 566 567 fStream->Seek(currentPos, SEEK_SET); 568 569 return B_OK; 570 } 571