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 #include "BaseTranslator.h" 9 10 11 PSDLoader::PSDLoader(BPositionIO *src) 12 { 13 fLoaded = false; 14 fStream = src; 15 16 fStream->Seek(0, SEEK_END); 17 fStreamSize = fStream->Position(); 18 fStream->Seek(0, SEEK_SET); 19 20 if (fStreamSize <= 0) 21 return; 22 23 fStream->Seek(0, SEEK_SET); 24 25 fSignature = _GetInt32FromStream(fStream); 26 if (fSignature != 0x38425053) // 8BPS 27 return; 28 29 fVersion = _GetInt16FromStream(fStream); 30 31 // Skip reserved data 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 // Skip [layer and mask] block 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_CHANNELS) 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; 192 193 fStreamBuffer = new uint8[fStreamSize]; 194 fStream->Seek(0, SEEK_SET); 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_CHANNELS]; 202 for (int i = 0; i < fChannels; i++) 203 imageData[i] = new uint8[channelBytes]; 204 205 206 switch (fCompression) { 207 case PSD_COMPRESSED_RAW: 208 { 209 for (int channelIdx = 0; channelIdx < fChannels; channelIdx++) { 210 uint8 *ptr = imageData[channelIdx]; 211 for (int i = 0; i < channelBytes; i++, ptr++) 212 *ptr = (uint8)fStreamBuffer[fStreamPos++]; 213 } 214 break; 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 // Read the RLE data. 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; 257 } 258 259 delete[] fStreamBuffer; 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) { 282 return B_NO_TRANSLATOR; 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_SET); 304 fStream->Read(colorData, fColorModeDataSize); 305 306 if (_ParseImageResources() != B_OK) 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; 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); 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); 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); 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_CUR); 512 } 513 514 515 status_t 516 PSDLoader::_ParseImageResources(void) 517 { 518 if (!fLoaded && fImageResourceSectionSize == 0) 519 return B_ERROR; 520 521 size_t currentPos = fStream->Position(); 522 fStream->Seek(fImageResourceSectionPos, SEEK_SET); 523 524 while (fStream->Position() < currentPos + fImageResourceSectionSize) { 525 int32 resBlockSignature = _GetInt32FromStream(fStream); 526 if (resBlockSignature != 0x3842494D) // 8BIM 527 return B_ERROR; 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_SET); 562 563 return B_OK; 564 } 565