hrev46529 adds 1 changeset to branch 'master' old head: 46f5821ad15158023327cad1f90a05dbe43f1aa7 new head: 85a9ab3f0418a4481841ac423d4bebb69575273f overview: http://cgit.haiku-os.org/haiku/log/?qt=range&q=85a9ab3+%5E46f5821 ---------------------------------------------------------------------------- 85a9ab3: PSDTranslator: Add support for Grayscale, CMYK and Lab color modes [ Gerasim Troeglazov <3dEyes@xxxxxxxxx> ] ---------------------------------------------------------------------------- Revision: hrev46529 Commit: 85a9ab3f0418a4481841ac423d4bebb69575273f URL: http://cgit.haiku-os.org/haiku/commit/?id=85a9ab3 Author: Gerasim Troeglazov <3dEyes@xxxxxxxxx> Date: Thu Dec 12 11:25:38 2013 UTC ---------------------------------------------------------------------------- 5 files changed, 321 insertions(+), 100 deletions(-) src/add-ons/translators/psd/PSDLoader.cpp | 359 ++++++++++++++++----- src/add-ons/translators/psd/PSDLoader.h | 48 ++- src/add-ons/translators/psd/PSDTranslator.cpp | 8 +- src/add-ons/translators/psd/PSDTranslator.h | 2 +- src/add-ons/translators/psd/PSDTranslator.rdef | 4 +- ---------------------------------------------------------------------------- diff --git a/src/add-ons/translators/psd/PSDLoader.cpp b/src/add-ons/translators/psd/PSDLoader.cpp index ee0c265..d183022 100644 --- a/src/add-ons/translators/psd/PSDLoader.cpp +++ b/src/add-ons/translators/psd/PSDLoader.cpp @@ -22,32 +22,32 @@ PSDLoader::PSDLoader(BPositionIO *src) fStream->Seek(0, SEEK_SET); - fSignature = GetInt32FromStream(fStream); + fSignature = _GetInt32FromStream(fStream); if (fSignature != 0x38425053) return; - fVersion = GetInt16FromStream(fStream); + fVersion = _GetInt16FromStream(fStream); - //Skip reserved data - SkipStreamBlock(fStream, 6); + // Skip reserved data + _SkipStreamBlock(fStream, 6); - fChannels = GetInt16FromStream(fStream); - fHeight = GetInt32FromStream(fStream); - fWidth = GetInt32FromStream(fStream); - fDepth = GetInt16FromStream(fStream); - fColorFormat = GetInt16FromStream(fStream); + fChannels = _GetInt16FromStream(fStream); + fHeight = _GetInt32FromStream(fStream); + fWidth = _GetInt32FromStream(fStream); + fDepth = _GetInt16FromStream(fStream); + fColorFormat = _GetInt16FromStream(fStream); - //Skip mode data - SkipStreamBlock(fStream, GetInt32FromStream(fStream)); - //Skip image resources - SkipStreamBlock(fStream, GetInt32FromStream(fStream)); - //Skip reserved data - SkipStreamBlock(fStream, GetInt32FromStream(fStream)); + // Skip mode data + _SkipStreamBlock(fStream, _GetInt32FromStream(fStream)); + // Skip image resources + _SkipStreamBlock(fStream, _GetInt32FromStream(fStream)); + // Skip reserved data + _SkipStreamBlock(fStream, _GetInt32FromStream(fStream)); - fCompression = GetInt16FromStream(fStream); + fCompression = _GetInt16FromStream(fStream); fStreamPos = fStream->Position(); - + fLoaded = true; } @@ -73,92 +73,148 @@ PSDLoader::IsSupported(void) if (fVersion != 1) return false; - if (fChannels < 0 || fChannels > 16) - return false; + if (fChannels < 0 || fChannels > 16) + return false; if (fDepth != 8) return false; - if (fColorFormat != 3) + if (_ColorFormat() == PSD_COLOR_FORMAT_UNSUPPORTED) return false; - if (fCompression != PSD_COMPRESSED_RAW && - fCompression != PSD_COMPRESSED_RLE) + if (fCompression != PSD_COMPRESSED_RAW + && fCompression != PSD_COMPRESSED_RLE) return false; return true; } +BString +PSDLoader::ColorFormatName(void) +{ + switch (fColorFormat) { + case PSD_COLOR_MODE_BITS: + return "Bitmap"; + case PSD_COLOR_MODE_GRAYSCALE: + return "Grayscale"; + case PSD_COLOR_MODE_INDEXED: + return "Indexed"; + case PSD_COLOR_MODE_RGB: + return fChannels > 3 ? "RGBA" : "RGB"; + case PSD_COLOR_MODE_CMYK: + return "CMYK"; + case PSD_COLOR_MODE_MULTICHANNEL: + return "Multichannel"; + case PSD_COLOR_MODE_LAB: + return "Lab"; + } + return ""; +} + + +int32 +PSDLoader::_ColorFormat(void) +{ + int32 format = PSD_COLOR_FORMAT_UNSUPPORTED; + if (!fLoaded) + return format; + + switch (fColorFormat) { + case PSD_COLOR_MODE_RGB: + if (fChannels == 3) + format = PSD_COLOR_FORMAT_RGB_8; + if (fChannels >= 4) + format = PSD_COLOR_FORMAT_RGB_A_8; + break; + case PSD_COLOR_MODE_GRAYSCALE: + if (fChannels == 1) + format = PSD_COLOR_FORMAT_GRAY_8; + if (fChannels == 2) + format = PSD_COLOR_FORMAT_GRAY_A_8; + break; + case PSD_COLOR_MODE_MULTICHANNEL: + if (fChannels == 3) + format = PSD_COLOR_FORMAT_MULTICHANNEL_8; + break; + case PSD_COLOR_MODE_CMYK: + if (fChannels == 3) + format = PSD_COLOR_FORMAT_MULTICHANNEL_8; + if (fChannels == 4) + format = PSD_COLOR_FORMAT_CMYK_8; + if (fChannels > 4) + format = PSD_COLOR_FORMAT_CMYK_A_8; + break; + case PSD_COLOR_MODE_LAB: + if (fChannels == 3) + format = PSD_COLOR_FORMAT_LAB_8; + if (fChannels > 3) + format = PSD_COLOR_FORMAT_LAB_A_8; + break; + default: + break; + }; + + return format; +} + + int PSDLoader::Decode(BPositionIO *target) { - if(!IsSupported()) + if (!IsSupported()) return B_NO_TRANSLATOR; fStreamBuffer = new uint8[fStreamSize]; fStream->Seek(0, SEEK_SET); fStream->Read(fStreamBuffer, fStreamSize); - uint8 *imageData = new uint8[fWidth * fHeight * sizeof(uint32)]; + uint8 *imageData[5]; + for (int i = 0; i < fChannels; i++) + imageData[i] = new uint8[fWidth * fHeight]; int pixelCount = fWidth * fHeight; - - //RGBA to BRGA order mapping table - int channelMap[4] = {2, 1, 0, 3}; if (fCompression == PSD_COMPRESSED_RAW) { - for (int channelIdx = 0; channelIdx < 4; channelIdx++) { - uint8 *ptr = imageData + channelMap[channelIdx]; - if (channelIdx > fChannels) { - for (int i = 0; i < pixelCount; i++, ptr += 4) - *ptr = (channelIdx == 3) ? 255 : 0; - } else { - for (int i = 0; i < pixelCount; i++, ptr += 4) - *ptr = (uint8)fStreamBuffer[fStreamPos++]; - } - } - } - - if (fCompression == PSD_COMPRESSED_RLE) { - fStreamPos += fHeight * fChannels * 2; - - for (int channelIdx = 0; channelIdx < 4; channelIdx++) { - uint8 *ptr = imageData + channelMap[channelIdx]; - - if (channelIdx >= fChannels) { - for (int i = 0; i < pixelCount; i++, ptr += 4) - *ptr = (channelIdx == 3 ? 255 : 0); - } else { - // Read the RLE data. - int count = 0; - while (count < pixelCount) { - uint8 len = (uint8)fStreamBuffer[fStreamPos++]; - if (len == 128) { - continue; - } else if (len < 128) { - len++; - count += len; - while (len) { - *ptr = (int8)fStreamBuffer[fStreamPos++]; - ptr += 4; - len--; - } - } else if (len > 128) { - int8 val = (int8)fStreamBuffer[fStreamPos++]; - len ^= 255; - len += 2; - count += len; - while (len) { - *ptr = val; - ptr += 4; - len--; - } - } - } - } - } - } + for (int channelIdx = 0; channelIdx < fChannels; channelIdx++) { + uint8 *ptr = imageData[channelIdx]; + for (int i = 0; i < pixelCount; i++, ptr++) + *ptr = (uint8)fStreamBuffer[fStreamPos++]; + } + } + + if (fCompression == PSD_COMPRESSED_RLE) { + fStreamPos += fHeight * fChannels * 2; + for (int channelIdx = 0; channelIdx < fChannels; channelIdx++) { + uint8 *ptr = imageData[channelIdx]; + // Read the RLE data. + int count = 0; + while (count < pixelCount) { + uint8 len = (uint8)fStreamBuffer[fStreamPos++]; + if (len == 128) { + continue; + } else if (len < 128) { + len++; + count += len; + while (len) { + *ptr++ = (int8)fStreamBuffer[fStreamPos++]; + len--; + } + } else if (len > 128) { + int8 val = (int8)fStreamBuffer[fStreamPos++]; + len ^= 255; + len += 2; + count += len; + while (len) { + *ptr++ = val; + len--; + } + } + } + } + } + + delete fStreamBuffer; TranslatorBitmap bitsHeader; bitsHeader.magic = B_TRANSLATOR_BITMAP; @@ -176,17 +232,146 @@ PSDLoader::Decode(BPositionIO *target) } target->Write(&bitsHeader, sizeof(TranslatorBitmap)); - target->Write(imageData, fHeight * fWidth * sizeof(uint32)); - - delete imageData; - delete fStreamBuffer; + + uint8 *lineData = new uint8[fWidth * sizeof(uint32)]; + + int32 colorFormat = _ColorFormat(); + + switch (colorFormat) { + case PSD_COLOR_FORMAT_GRAY_8: + case PSD_COLOR_FORMAT_GRAY_A_8: + { + bool isAlpha = colorFormat == PSD_COLOR_FORMAT_GRAY_A_8; + uint8 *yCh = imageData[0]; + uint8 *alphaCh = isAlpha ? imageData[1] : NULL; + for (int h = 0; h < fHeight; h++) { + uint8 *ptr = lineData; + for (int w = 0; w < fWidth; w++) { + uint8 y = *yCh++; + *ptr++ = y; + *ptr++ = y; + *ptr++ = y; + *ptr++ = isAlpha ? *alphaCh++ : 255; + } + target->Write(lineData, fWidth * sizeof(uint32)); + } + break; + } + case PSD_COLOR_FORMAT_MULTICHANNEL_8: + case PSD_COLOR_FORMAT_RGB_8: + case PSD_COLOR_FORMAT_RGB_A_8: + { + bool isAlpha = colorFormat == PSD_COLOR_FORMAT_RGB_A_8; + uint8 *rCh = imageData[0]; + uint8 *gCh = imageData[1]; + uint8 *bCh = imageData[2]; + uint8 *alphaCh = isAlpha ? imageData[3] : NULL; + for (int h = 0; h < fHeight; h++) { + uint8 *ptr = lineData; + for (int w = 0; w < fWidth; w++) { + *ptr++ = *bCh++; + *ptr++ = *gCh++; + *ptr++ = *rCh++; + *ptr++ = isAlpha ? *alphaCh++ : 255; + } + target->Write(lineData, fWidth * sizeof(uint32)); + } + break; + } + case PSD_COLOR_FORMAT_CMYK_8: + case PSD_COLOR_FORMAT_CMYK_A_8: + { + bool isAlpha = colorFormat == PSD_COLOR_FORMAT_CMYK_A_8; + uint8 *cCh = imageData[0]; + uint8 *mCh = imageData[1]; + uint8 *yCh = imageData[2]; + uint8 *kCh = imageData[3]; + uint8 *alphaCh = isAlpha ? imageData[4] : NULL; + for (int h = 0; h < fHeight; h++) { + uint8 *ptr = lineData; + for (int w = 0; w < fWidth; w++) { + double c = 1.0 - (*cCh++ / 255.0); + double m = 1.0 - (*mCh++ / 255.0); + double y = 1.0 - (*yCh++ / 255.0); + double k = 1.0 - (*kCh++ / 255.0); + *ptr++ = (uint8)((1.0 - (y * (1.0 - k) + k)) * 255.0); + *ptr++ = (uint8)((1.0 - (m * (1.0 - k) + k)) * 255.0); + *ptr++ = (uint8)((1.0 - (c * (1.0 - k) + k)) * 255.0); + *ptr++ = alphaCh ? *alphaCh++ : 255; + } + target->Write(lineData, fWidth * sizeof(uint32)); + } + break; + } + case PSD_COLOR_FORMAT_LAB_8: + case PSD_COLOR_FORMAT_LAB_A_8: + { + bool isAlpha = colorFormat == PSD_COLOR_FORMAT_LAB_A_8; + uint8 *lCh = imageData[0]; + uint8 *aCh = imageData[1]; + uint8 *bCh = imageData[2]; + uint8 *alphaCh = isAlpha ? imageData[3] : NULL; + for (int h = 0; h < fHeight; h++) { + uint8 *ptr = lineData; + for (int w = 0; w < fWidth; w++) { + double L = ((*lCh++) / 255.0) * 100.0; + double a = (*aCh++) - 128.0; + double b = (*bCh++) - 128.0; + + double Y = L * (1.0 / 116.0) + 16.0 / 116.0; + double X = a * (1.0 / 500.0) + Y; + double Z = b * (-1.0 / 200.0) + Y; + + X = X > 6.0 / 29.0 ? X * X * X : X * (108.0 / 841.0) + - (432.0 / 24389.0); + Y = L > 8.0 ? Y * Y * Y : L * (27.0 / 24389.0); + Z = Z > 6.0 / 29.0 ? Z * Z * Z : Z * (108.0 / 841.0) + - (432.0 / 24389.0); + + double R = X * (1219569.0 / 395920.0) + + Y * (-608687.0 / 395920.0) + + Z * (-107481.0 / 197960.0); + double G = X * (-80960619.0 / 87888100.0) + + Y * (82435961.0 / 43944050.0) + + Z * (3976797.0 / 87888100.0); + double B = X * (93813.0 / 1774030.0) + + Y * (-180961.0 / 887015.0) + + Z * (107481.0 / 93370.0); + + R = R > 0.0031308 ? pow(R, 1.0 / 2.4) * 1.055 - 0.055 + : R * 12.92; + G = G > 0.0031308 ? pow(G, 1.0 / 2.4) * 1.055 - 0.055 + : G * 12.92; + B = B > 0.0031308 ? pow(B, 1.0 / 2.4) * 1.055 - 0.055 + : B * 12.92; + + R = (R < 0) ? 0 : ((R > 1) ? 1 : R); + G = (G < 0) ? 0 : ((G > 1) ? 1 : G); + B = (B < 0) ? 0 : ((B > 1) ? 1 : B); + + *ptr++ = (uint8)(B * 255.0); + *ptr++ = (uint8)(G * 255.0); + *ptr++ = (uint8)(R * 255.0); + *ptr++ = isAlpha ? *alphaCh++ : 255; + } + target->Write(lineData, fWidth * sizeof(uint32)); + } + break; + } + default: + break; + }; + + delete lineData; + for (int i = 0; i < fChannels; i++) + delete imageData[i]; return B_OK; } int32 -PSDLoader::GetInt32FromStream(BPositionIO *in) +PSDLoader::_GetInt32FromStream(BPositionIO *in) { int32 ret; in->Read(&ret, sizeof(int32)); @@ -195,7 +380,7 @@ PSDLoader::GetInt32FromStream(BPositionIO *in) int16 -PSDLoader::GetInt16FromStream(BPositionIO *in) +PSDLoader::_GetInt16FromStream(BPositionIO *in) { int16 ret; in->Read(&ret, sizeof(int16)); @@ -204,7 +389,7 @@ PSDLoader::GetInt16FromStream(BPositionIO *in) int8 -PSDLoader::GetInt8FromStream(BPositionIO *in) +PSDLoader::_GetInt8FromStream(BPositionIO *in) { int8 ret; in->Read(&ret, sizeof(int8)); @@ -213,7 +398,7 @@ PSDLoader::GetInt8FromStream(BPositionIO *in) uint8 -PSDLoader::GetUInt8FromStream(BPositionIO *in) +PSDLoader::_GetUInt8FromStream(BPositionIO *in) { uint8 ret; in->Read(&ret, sizeof(uint8)); @@ -222,7 +407,7 @@ PSDLoader::GetUInt8FromStream(BPositionIO *in) void -PSDLoader::SkipStreamBlock(BPositionIO *in, size_t count) +PSDLoader::_SkipStreamBlock(BPositionIO *in, size_t count) { in->Seek(count, SEEK_CUR); } diff --git a/src/add-ons/translators/psd/PSDLoader.h b/src/add-ons/translators/psd/PSDLoader.h index 5207e22..01bcdb2 100644 --- a/src/add-ons/translators/psd/PSDLoader.h +++ b/src/add-ons/translators/psd/PSDLoader.h @@ -16,13 +16,43 @@ #include <TranslationDefs.h> #include <GraphicsDefs.h> #include <InterfaceDefs.h> +#include <String.h> #include <DataIO.h> #include <File.h> #include <ByteOrder.h> #include <List.h> -#define PSD_COMPRESSED_RAW 0 -#define PSD_COMPRESSED_RLE 1 + +enum psd_compressed_type { + PSD_COMPRESSED_RAW = 0, + PSD_COMPRESSED_RLE = 1 +}; + + +enum psd_color_mode { + PSD_COLOR_MODE_BITS = 0, + PSD_COLOR_MODE_GRAYSCALE = 1, + PSD_COLOR_MODE_INDEXED = 2, + PSD_COLOR_MODE_RGB = 3, + PSD_COLOR_MODE_CMYK = 4, + PSD_COLOR_MODE_MULTICHANNEL = 7, + PSD_COLOR_MODE_LAB = 9 +}; + + +enum psd_color_format { + PSD_COLOR_FORMAT_UNSUPPORTED, + PSD_COLOR_FORMAT_RGB_8, + PSD_COLOR_FORMAT_RGB_A_8, + PSD_COLOR_FORMAT_GRAY_8, + PSD_COLOR_FORMAT_GRAY_A_8, + PSD_COLOR_FORMAT_MULTICHANNEL_8, + PSD_COLOR_FORMAT_CMYK_8, + PSD_COLOR_FORMAT_CMYK_A_8, + PSD_COLOR_FORMAT_LAB_8, + PSD_COLOR_FORMAT_LAB_A_8 +}; + class PSDLoader { public: @@ -32,13 +62,17 @@ public: int Decode(BPositionIO *target); bool IsLoaded(void); bool IsSupported(void); + + BString ColorFormatName(void); private: - int32 GetInt32FromStream(BPositionIO *in); - int16 GetInt16FromStream(BPositionIO *in); - uint8 GetUInt8FromStream(BPositionIO *in); - int8 GetInt8FromStream(BPositionIO *in); - void SkipStreamBlock(BPositionIO *in, size_t count); + int32 _GetInt32FromStream(BPositionIO *in); + int16 _GetInt16FromStream(BPositionIO *in); + uint8 _GetUInt8FromStream(BPositionIO *in); + int8 _GetInt8FromStream(BPositionIO *in); + void _SkipStreamBlock(BPositionIO *in, size_t count); + + int32 _ColorFormat(void); BPositionIO *fStream; uint8 *fStreamBuffer; diff --git a/src/add-ons/translators/psd/PSDTranslator.cpp b/src/add-ons/translators/psd/PSDTranslator.cpp index 2a89abd..4f9f79a 100644 --- a/src/add-ons/translators/psd/PSDTranslator.cpp +++ b/src/add-ons/translators/psd/PSDTranslator.cpp @@ -88,7 +88,9 @@ PSDTranslator::DerivedIdentify(BPositionIO *stream, info->group = B_TRANSLATOR_BITMAP; info->quality = PSD_IN_QUALITY; info->capability = PSD_IN_CAPABILITY; - strcpy(info->name, kPSDName); + BString name(kPSDName); + name << " (" << psdFile.ColorFormatName() << ")"; + strcpy(info->name, name.String()); strcpy(info->MIME, kPSDMimeType); return B_OK; @@ -112,8 +114,8 @@ PSDTranslator::DerivedTranslate(BPositionIO *source, PSDLoader psdFile(source); if (!psdFile.IsLoaded()) return B_NO_TRANSLATOR; - - return psdFile.Decode(target); + + return psdFile.Decode(target); } default: diff --git a/src/add-ons/translators/psd/PSDTranslator.h b/src/add-ons/translators/psd/PSDTranslator.h index 2134bee..5b00972 100644 --- a/src/add-ons/translators/psd/PSDTranslator.h +++ b/src/add-ons/translators/psd/PSDTranslator.h @@ -21,7 +21,7 @@ #define DOCUMENT_COUNT "/documentCount" #define DOCUMENT_INDEX "/documentIndex" -#define PSD_TRANSLATOR_VERSION B_TRANSLATION_MAKE_VERSION(1, 0, 0) +#define PSD_TRANSLATOR_VERSION B_TRANSLATION_MAKE_VERSION(1, 1, 0) #define PSD_IMAGE_FORMAT 'PSD ' #define PSD_IN_QUALITY 0.5 diff --git a/src/add-ons/translators/psd/PSDTranslator.rdef b/src/add-ons/translators/psd/PSDTranslator.rdef index 32de175..8aefc0f 100644 --- a/src/add-ons/translators/psd/PSDTranslator.rdef +++ b/src/add-ons/translators/psd/PSDTranslator.rdef @@ -6,10 +6,10 @@ resource app_signature "application/x-vnd.Haiku-PSDTranslator"; resource app_version { major = 1, - middle = 0, + middle = 1, minor = 0, variety = 0, internal = 0, - short_info = "1.0.0", + short_info = "1.1.0", long_info = "Haiku PSDTranslator Add-Ons." };