00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042 #include "OSGConfig.h"
00043 #include "OSGBaseFunctions.h"
00044
00045 #include "OSGPSDImageFileType.h"
00046
00047 #include <OSGLog.h>
00048
00049
00050 OSG_USING_NAMESPACE
00051
00052
00065 static UInt32 parseUInt32(char *&ptr)
00066 {
00067 UInt32 result =
00068 (static_cast<UInt32>(static_cast<UInt8>(ptr[0])) << 24) |
00069 (static_cast<UInt32>(static_cast<UInt8>(ptr[1])) << 16) |
00070 (static_cast<UInt32>(static_cast<UInt8>(ptr[2])) << 8) |
00071 (static_cast<UInt32>(static_cast<UInt8>(ptr[3])) << 0);
00072 ptr += 4;
00073 return result;
00074 }
00075
00076 static UInt16 parseUInt16(char *&ptr)
00077 {
00078 UInt16 result =
00079 (static_cast<UInt32>(static_cast<UInt8>(ptr[0])) << 8) |
00080 (static_cast<UInt32>(static_cast<UInt8>(ptr[1])) << 0);
00081 ptr +=2;
00082 return result;
00083 }
00084
00085 typedef struct
00086 {
00087 Int8 signature[4];
00088 UInt16 version;
00089 Int8 reserved[6];
00090 UInt16 channels;
00091 UInt32 rows;
00092 UInt32 columns;
00093 UInt16 depth;
00094 UInt16 mode;
00095 }
00096 PSDHeader;
00097
00098 static bool readHeader(std::istream &is, PSDHeader &header)
00099 {
00100
00101 char buffer[26];
00102 is.read(buffer, 26);
00103 if (is.gcount() != 26)
00104 return false;
00105
00106
00107 char *ptr = buffer;
00108 memcpy(header.signature, ptr, 4);
00109 ptr += 4;
00110 header.version = parseUInt16(ptr);
00111 memcpy(header.reserved, ptr, 6);
00112 ptr += 6;
00113 header.channels = parseUInt16(ptr);
00114 header.rows = parseUInt32(ptr);
00115 header.columns = parseUInt32(ptr);
00116 header.depth = parseUInt16(ptr);
00117 header.mode = parseUInt16(ptr);
00118
00119
00120 if (memcmp(header.signature, "8BPS", 4) != 0)
00121 return false;
00122 if (header.version != 1)
00123 return false;
00124
00125 return true;
00126 }
00127
00128 static bool readColorModeData(std::istream &is, const PSDHeader &header, char *colormap)
00129 {
00130
00131 char buffer[4];
00132 is.read(buffer, 4);
00133 if (is.gcount() != 4)
00134 return false;
00135
00136
00137 char *ptr = buffer;
00138 UInt32 length = parseUInt32(ptr);
00139
00140
00141 if (header.mode == 2)
00142 {
00143 if (length != 768)
00144 return false;
00145 length = 0;
00146 is.read(colormap, 768);
00147 if (static_cast<UInt32>(is.gcount()) != 768)
00148 return false;
00149 }
00150
00151
00152 is.ignore(length);
00153 if (static_cast<UInt32>(is.gcount()) != length)
00154 return false;
00155
00156 return true;
00157 }
00158
00159 static bool readResource(std::istream &is, UInt32 &length, Int16 &transparentIndex)
00160 {
00161
00162 if (length < 8)
00163 return false;
00164 char buffer[8];
00165 is.read(buffer, 6);
00166 if (is.gcount() != 6)
00167 return false;
00168 length -= 6;
00169 char *ptr = buffer + 4;
00170 UInt16 id = parseUInt16(ptr);
00171 int c = is.get();
00172 if (c == EOF)
00173 return false;
00174 length -= 1;
00175 if ((c & 1) == 0)
00176 ++c;
00177 if (static_cast<UInt32>(c) > length)
00178 return false;
00179 is.ignore(c);
00180 if (is.gcount() != c)
00181 return false;
00182 length -= c;
00183 ptr = buffer + 4;
00184 is.read(ptr, 4);
00185 if (is.gcount() != 4)
00186 return false;
00187 length -= 4;
00188 UInt32 size = parseUInt32(ptr);
00189 if (size > length)
00190 return false;
00191
00192 if (memcmp(buffer, "8BIM", 4) == 0)
00193 {
00194 switch (id)
00195 {
00196 case 0x417:
00197 if (size == 2)
00198 {
00199 ptr = buffer + 4;
00200 is.read(ptr, 2);
00201 if (is.gcount() != 2)
00202 return false;
00203 size = 0;
00204 length -= 2;
00205 transparentIndex = parseUInt16(ptr);
00206 }
00207 break;
00208 }
00209 }
00210
00211 if ((size & 1) != 0)
00212 ++size;
00213 is.ignore(size);
00214 if (static_cast<UInt32>(is.gcount()) != size)
00215 return false;
00216 length -= size;
00217
00218 return true;
00219 }
00220
00221 static bool readImageResources(std::istream &is, Int16 &transparentIndex)
00222 {
00223
00224 char buffer[4];
00225 is.read(buffer, 4);
00226 if (is.gcount() != 4)
00227 return false;
00228
00229
00230 char *ptr = buffer;
00231 UInt32 length = parseUInt32(ptr);
00232
00233
00234 while (length > 0)
00235 if (readResource(is, length, transparentIndex) == false)
00236 return false;
00237
00238 return true;
00239 }
00240
00241 static bool readLayerAndMaskInformation(std::istream &is)
00242 {
00243
00244 char buffer[4];
00245 is.read(buffer, 4);
00246 if (is.gcount() != 4)
00247 return false;
00248
00249
00250 char *ptr = buffer;
00251 UInt32 length = parseUInt32(ptr);
00252
00253
00254 is.ignore(length);
00255 if (static_cast<UInt32>(is.gcount()) != length)
00256 return false;
00257
00258 return true;
00259 }
00260
00261 static bool readImageData(std::istream &is, const PSDHeader &header, UInt16 relevantChannels, char *colormap, Int16 &transparentIndex, UInt8 *data)
00262 {
00263
00264 std::vector<char> buffer;
00265 buffer.resize(2);
00266 char *ptr = &(buffer.front());
00267 is.read(ptr, 2);
00268 if (is.gcount() != 2)
00269 return false;
00270
00271
00272 UInt16 compression = parseUInt16(ptr);
00273 if (compression > 1)
00274 return false;
00275
00276
00277 UInt32 bpl = (header.columns * header.depth + 7) / 8;
00278 UInt32 dstBpl;
00279 if (header.mode == 2)
00280 dstBpl = header.columns * (transparentIndex != -1 ? 4 : 3);
00281 else
00282 dstBpl = header.columns * relevantChannels;
00283
00284
00285
00286 std::vector<UInt16> lineLength;
00287 if (compression == 1)
00288 {
00289 UInt32 numLines = header.rows * header.channels;
00290 lineLength.resize(numLines);
00291 UInt32 size = numLines * 2;
00292 buffer.resize(size);
00293 ptr = &(buffer.front());
00294 is.read(ptr, size);
00295 if (static_cast<UInt32>(is.gcount()) != size)
00296 return false;
00297 UInt16 maxLength = 0;
00298 for (UInt32 i = 0; i < numLines; ++i)
00299 {
00300 UInt16 length = parseUInt16(ptr);
00301 lineLength[i] = length;
00302 if (length > maxLength)
00303 maxLength = length;
00304 }
00305 buffer.resize(maxLength);
00306 }
00307 else
00308 buffer.resize(bpl);
00309
00310 UInt32 lineNumber = 0;
00311 std::vector<char> line(bpl);
00312 UInt8 *dstPtr;
00313 for (UInt16 c = 0; c < header.channels; ++c)
00314 {
00315 dstPtr = data + c + dstBpl * (header.rows - 1);
00316 for (UInt32 y = 0; y < header.rows; ++y)
00317 {
00318
00319 UInt32 size;
00320 if (compression == 1)
00321 {
00322 ptr = &(buffer.front());
00323 size = lineLength[lineNumber];
00324 }
00325 else
00326 {
00327 ptr = &(line.front());
00328 size = bpl;
00329 }
00330 is.read(ptr, size);
00331 if (static_cast<UInt32>(is.gcount()) != size)
00332 return false;
00333
00334 if (c < relevantChannels)
00335 {
00336
00337 if (compression == 1)
00338 {
00339 UInt32 src = 0, dst = 0;
00340 while (src < size)
00341 {
00342 UInt8 runCount = buffer[src++];
00343 if (runCount & 0x80)
00344 {
00345 runCount = -runCount + 1;
00346 if (dst + runCount > bpl)
00347 return false;
00348 for (; runCount > 0; --runCount)
00349 line[dst++] = buffer[src];
00350 ++src;
00351 }
00352 else
00353 {
00354 ++runCount;
00355 if (dst + runCount > bpl)
00356 return false;
00357 for (; runCount > 0; --runCount)
00358 line[dst++] = buffer[src++];
00359 }
00360 }
00361 if (dst != bpl)
00362 return false;
00363 }
00364
00365
00366 UInt8 *lineDstPtr = dstPtr;
00367 switch (header.depth)
00368 {
00369 case 1:
00370 for (UInt32 x = 0; x < header.columns; ++x)
00371 {
00372 UInt8 v = line[x / 8] & (1 << (7 - (x & 7)));
00373 *lineDstPtr = v != 0 ? 0 : 255;
00374 lineDstPtr += relevantChannels;
00375 }
00376 break;
00377 case 8:
00378 if (header.mode == 2)
00379 for (UInt32 x = 0; x < header.columns; ++x)
00380 {
00381 UInt8 index = line[x];
00382 *lineDstPtr++ = colormap[index];
00383 *lineDstPtr++ = colormap[index + 256];
00384 *lineDstPtr++ = colormap[index + 512];
00385 if (transparentIndex != -1)
00386 *lineDstPtr++ = index == transparentIndex ? 0 : 255;
00387 }
00388 else
00389 for (UInt32 x = 0; x < header.columns; ++x)
00390 {
00391 *lineDstPtr = line[x];
00392 lineDstPtr += relevantChannels;
00393 }
00394 break;
00395 case 16:
00396 for (UInt32 x = 0; x < header.columns; ++x)
00397 {
00398 *lineDstPtr = line[x * 2];
00399 lineDstPtr += relevantChannels;
00400 }
00401 break;
00402 }
00403 }
00404 dstPtr -= dstBpl;
00405
00406 ++lineNumber;
00407 }
00408 }
00409
00410 return true;
00411 }
00412
00413
00414
00415 static const Char8 *suffixArray[] = {
00416 "psd"
00417 };
00418
00419 PSDImageFileType PSDImageFileType::_the("image/x-photoshop",
00420 suffixArray, sizeof(suffixArray),
00421 OSG_READ_SUPPORTED);
00422
00423
00427 PSDImageFileType& PSDImageFileType::the (void)
00428 {
00429 return _the;
00430 }
00431
00432
00437 bool PSDImageFileType::read(ImagePtr &image, std::istream &is,
00438 const std::string &mimetype)
00439 {
00440 PSDHeader header;
00441 if (readHeader(is, header) == false)
00442 {
00443 FWARNING(("PSD file is corrupt!\n"));
00444 return false;
00445 }
00446
00447 char colormap[768];
00448 if (readColorModeData(is, header, colormap) == false)
00449 {
00450 FWARNING(("PSD file is corrupt!\n"));
00451 return false;
00452 }
00453
00454 Int16 transparentIndex = -1;
00455 if (readImageResources(is, transparentIndex) == false)
00456 {
00457 FWARNING(("PSD file is corrupt!\n"));
00458 return false;
00459 }
00460
00461 if (readLayerAndMaskInformation(is) == false)
00462 {
00463 FWARNING(("PSD file is corrupt!\n"));
00464 return false;
00465 }
00466
00467 Image::PixelFormat format = Image::OSG_INVALID_PF;
00468 UInt16 relevantChannels = header.channels;
00469 switch (header.mode)
00470 {
00471 case 0:
00472 if ((header.channels != 1) || (header.depth != 1))
00473 break;
00474 format = Image::OSG_L_PF;
00475 break;
00476 case 1:
00477 if ((header.depth != 8) && (header.depth != 16))
00478 break;
00479 switch (header.channels)
00480 {
00481 case 1:
00482 format = Image::OSG_L_PF;
00483 break;
00484 case 2:
00485 format = Image::OSG_LA_PF;
00486 break;
00487 default:
00488 break;
00489 }
00490 break;
00491 case 2:
00492 if ((header.channels != 1) || (header.depth != 8))
00493 break;
00494 format = transparentIndex != -1 ? Image::OSG_RGBA_PF : Image::OSG_RGB_PF;
00495 break;
00496 case 3:
00497 if ((header.depth != 8) && (header.depth != 16))
00498 break;
00499 if (header.channels < 3)
00500 break;
00501 if (header.channels == 3)
00502 format = Image::OSG_RGB_PF;
00503 else
00504 {
00505 format = Image::OSG_RGBA_PF;
00506 relevantChannels = 4;
00507 }
00508 break;
00509 case 4:
00510 if ((header.depth != 8) && (header.depth != 16))
00511 break;
00512
00513 break;
00514 case 7:
00515
00516 break;
00517 case 8:
00518 if (header.depth != 8)
00519 break;
00520 switch (header.channels)
00521 {
00522 case 1:
00523 format = Image::OSG_L_PF;
00524 break;
00525 case 2:
00526 format = Image::OSG_LA_PF;
00527 break;
00528 default:
00529 break;
00530 }
00531 break;
00532 case 9:
00533 if ((header.depth != 8) && (header.depth != 16))
00534 break;
00535
00536 break;
00537 default:
00538 break;
00539 }
00540
00541 if (format == Image::OSG_INVALID_PF)
00542 {
00543 FWARNING(("Unsupported image type for PSD file!\n"));
00544 return false;
00545 }
00546
00547 image->set(format, header.columns, header.rows);
00548 UChar8 *data = image->getData();
00549
00550 if (readImageData(is, header, relevantChannels, colormap, transparentIndex, data) == false)
00551 {
00552 FWARNING(("PSD file is corrupt!\n"));
00553 return false;
00554 }
00555
00556 return true;
00557 }
00558
00559
00565 std::string PSDImageFileType::determineMimetypeFromStream(std::istream &is)
00566 {
00567 char filecode[4];
00568 is.read(filecode, 4);
00569 is.seekg(-4, std::ios::cur);
00570 return strncmp(filecode, "8BPS", 4) == 0 ?
00571 std::string(getMimeType()) : std::string();
00572 }
00573
00574
00578 PSDImageFileType::PSDImageFileType(const Char8 *mimeType,
00579 const Char8 *suffixArray[],
00580 UInt16 suffixByteCount,
00581 UInt32 flags) :
00582 ImageFileType(mimeType,suffixArray, suffixByteCount, flags)
00583 {}
00584
00585
00589 PSDImageFileType::~PSDImageFileType(void) {}