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