PSDTranslator: Add support for monochrome (1bit) and 16bit colors

This commit is contained in:
Gerasim Troeglazov 2013-12-13 08:56:54 +00:00
parent 0ba6a7e263
commit dc17c462e3
3 changed files with 133 additions and 101 deletions

View File

@ -76,7 +76,7 @@ PSDLoader::IsSupported(void)
if (fChannels < 0 || fChannels > 16)
return false;
if (fDepth != 8)
if (fDepth > 16)
return false;
if (_ColorFormat() == PSD_COLOR_FORMAT_UNSUPPORTED)
@ -121,35 +121,38 @@ PSDLoader::_ColorFormat(void)
return format;
switch (fColorFormat) {
case PSD_COLOR_MODE_BITS:
format = PSD_COLOR_FORMAT_BITMAP;
break;
case PSD_COLOR_MODE_RGB:
if (fChannels == 3)
format = PSD_COLOR_FORMAT_RGB_8;
if (fChannels >= 4)
format = PSD_COLOR_FORMAT_RGB_A_8;
format = PSD_COLOR_FORMAT_RGB;
else if (fChannels >= 4)
format = PSD_COLOR_FORMAT_RGB_A;
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;
format = PSD_COLOR_FORMAT_GRAY;
else if (fChannels == 2)
format = PSD_COLOR_FORMAT_GRAY_A;
break;
case PSD_COLOR_MODE_MULTICHANNEL:
if (fChannels == 3)
format = PSD_COLOR_FORMAT_MULTICHANNEL_8;
format = PSD_COLOR_FORMAT_MULTICHANNEL;
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;
format = PSD_COLOR_FORMAT_MULTICHANNEL;
else if (fChannels == 4)
format = PSD_COLOR_FORMAT_CMYK;
else if (fChannels > 4)
format = PSD_COLOR_FORMAT_CMYK_A;
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;
format = PSD_COLOR_FORMAT_LAB;
else if (fChannels > 3)
format = PSD_COLOR_FORMAT_LAB_A;
break;
default:
break;
@ -169,51 +172,64 @@ PSDLoader::Decode(BPositionIO *target)
fStream->Seek(0, SEEK_SET);
fStream->Read(fStreamBuffer, fStreamSize);
int32 depthBytes = fDepth / 8;
int32 rowBytes = (fWidth * fDepth) / 8;
int32 channelBytes = rowBytes * fHeight;
uint8 *imageData[5];
for (int i = 0; i < fChannels; i++)
imageData[i] = new uint8[fWidth * fHeight];
imageData[i] = new uint8[channelBytes];
int pixelCount = fWidth * fHeight;
if (fCompression == PSD_COMPRESSED_RAW) {
for (int channelIdx = 0; channelIdx < fChannels; channelIdx++) {
uint8 *ptr = imageData[channelIdx];
for (int i = 0; i < pixelCount; i++, ptr++)
*ptr = (uint8)fStreamBuffer[fStreamPos++];
switch (fCompression) {
case PSD_COMPRESSED_RAW:
{
for (int channelIdx = 0; channelIdx < fChannels; channelIdx++) {
uint8 *ptr = imageData[channelIdx];
for (int i = 0; i < channelBytes; i++, ptr++)
*ptr = (uint8)fStreamBuffer[fStreamPos++];
}
break;
}
}
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--;
case 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 < channelBytes) {
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--;
}
}
}
}
break;
}
default:
delete fStreamBuffer;
for (int i = 0; i < fChannels; i++)
delete imageData[i];
return B_NO_TRANSLATOR;
}
delete fStreamBuffer;
TranslatorBitmap bitsHeader;
@ -222,9 +238,18 @@ PSDLoader::Decode(BPositionIO *target)
bitsHeader.bounds.top = 0;
bitsHeader.bounds.right = fWidth - 1;
bitsHeader.bounds.bottom = fHeight - 1;
bitsHeader.rowBytes = sizeof(uint32) * fWidth;
bitsHeader.colors = B_RGBA32;
bitsHeader.dataSize = bitsHeader.rowBytes * fHeight;
psd_color_format colorFormat = _ColorFormat();
if (colorFormat == PSD_COLOR_FORMAT_BITMAP) {
bitsHeader.rowBytes = rowBytes;
bitsHeader.dataSize = channelBytes;
bitsHeader.colors = B_GRAY1;
} else {
bitsHeader.rowBytes = sizeof(uint32) * fWidth;
bitsHeader.colors = B_RGBA32;
bitsHeader.dataSize = bitsHeader.rowBytes * fHeight;
}
if (swap_data(B_UINT32_TYPE, &bitsHeader,
sizeof(TranslatorBitmap), B_SWAP_HOST_TO_BENDIAN) != B_OK) {
@ -234,34 +259,40 @@ PSDLoader::Decode(BPositionIO *target)
target->Write(&bitsHeader, sizeof(TranslatorBitmap));
uint8 *lineData = new uint8[fWidth * sizeof(uint32)];
psd_color_format colorFormat = _ColorFormat();
switch (colorFormat) {
case PSD_COLOR_FORMAT_GRAY_8:
case PSD_COLOR_FORMAT_GRAY_A_8:
case PSD_COLOR_FORMAT_BITMAP:
{
int32 rowBytes = (fWidth / 8 ) * fHeight;
for (int32 i = 0; i < rowBytes; i++)
imageData[0][i]^=255;
target->Write(imageData[0], rowBytes);
break;
}
case PSD_COLOR_FORMAT_GRAY:
case PSD_COLOR_FORMAT_GRAY_A:
{
bool isAlpha = colorFormat == PSD_COLOR_FORMAT_GRAY_A_8;
bool isAlpha = colorFormat == PSD_COLOR_FORMAT_GRAY_A;
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++;
uint8 y = *(yCh += depthBytes);
*ptr++ = y;
*ptr++ = y;
*ptr++ = y;
*ptr++ = isAlpha ? *alphaCh++ : 255;
*ptr++ = isAlpha ? *(alphaCh += depthBytes) : 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:
case PSD_COLOR_FORMAT_MULTICHANNEL:
case PSD_COLOR_FORMAT_RGB:
case PSD_COLOR_FORMAT_RGB_A:
{
bool isAlpha = colorFormat == PSD_COLOR_FORMAT_RGB_A_8;
bool isAlpha = colorFormat == PSD_COLOR_FORMAT_RGB_A;
uint8 *rCh = imageData[0];
uint8 *gCh = imageData[1];
uint8 *bCh = imageData[2];
@ -269,19 +300,19 @@ PSDLoader::Decode(BPositionIO *target)
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;
*ptr++ = *(bCh += depthBytes);
*ptr++ = *(gCh += depthBytes);
*ptr++ = *(rCh += depthBytes);
*ptr++ = isAlpha ? *(alphaCh += depthBytes) : 255;
}
target->Write(lineData, fWidth * sizeof(uint32));
}
break;
}
case PSD_COLOR_FORMAT_CMYK_8:
case PSD_COLOR_FORMAT_CMYK_A_8:
case PSD_COLOR_FORMAT_CMYK:
case PSD_COLOR_FORMAT_CMYK_A:
{
bool isAlpha = colorFormat == PSD_COLOR_FORMAT_CMYK_A_8;
bool isAlpha = colorFormat == PSD_COLOR_FORMAT_CMYK_A;
uint8 *cCh = imageData[0];
uint8 *mCh = imageData[1];
uint8 *yCh = imageData[2];
@ -290,23 +321,23 @@ PSDLoader::Decode(BPositionIO *target)
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);
double c = 1.0 - *(cCh += depthBytes) / 255.0;
double m = 1.0 - *(mCh += depthBytes) / 255.0;
double y = 1.0 - *(yCh += depthBytes) / 255.0;
double k = 1.0 - *(kCh += depthBytes) / 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;
*ptr++ = alphaCh ? *(alphaCh += depthBytes) : 255;
}
target->Write(lineData, fWidth * sizeof(uint32));
}
break;
}
case PSD_COLOR_FORMAT_LAB_8:
case PSD_COLOR_FORMAT_LAB_A_8:
case PSD_COLOR_FORMAT_LAB:
case PSD_COLOR_FORMAT_LAB_A:
{
bool isAlpha = colorFormat == PSD_COLOR_FORMAT_LAB_A_8;
bool isAlpha = colorFormat == PSD_COLOR_FORMAT_LAB_A;
uint8 *lCh = imageData[0];
uint8 *aCh = imageData[1];
uint8 *bCh = imageData[2];
@ -314,9 +345,9 @@ PSDLoader::Decode(BPositionIO *target)
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 L = *(lCh += depthBytes) / 255.0 * 100.0;
double a = *(aCh += depthBytes) - 128.0;
double b = *(bCh += depthBytes) - 128.0;
double Y = L * (1.0 / 116.0) + 16.0 / 116.0;
double X = a * (1.0 / 500.0) + Y;
@ -352,7 +383,7 @@ PSDLoader::Decode(BPositionIO *target)
*ptr++ = (uint8)(B * 255.0);
*ptr++ = (uint8)(G * 255.0);
*ptr++ = (uint8)(R * 255.0);
*ptr++ = isAlpha ? *alphaCh++ : 255;
*ptr++ = isAlpha ? *(alphaCh += depthBytes) : 255;
}
target->Write(lineData, fWidth * sizeof(uint32));
}

View File

@ -42,15 +42,16 @@ enum psd_color_mode {
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
PSD_COLOR_FORMAT_BITMAP,
PSD_COLOR_FORMAT_RGB,
PSD_COLOR_FORMAT_RGB_A,
PSD_COLOR_FORMAT_GRAY,
PSD_COLOR_FORMAT_GRAY_A,
PSD_COLOR_FORMAT_MULTICHANNEL,
PSD_COLOR_FORMAT_CMYK,
PSD_COLOR_FORMAT_CMYK_A,
PSD_COLOR_FORMAT_LAB,
PSD_COLOR_FORMAT_LAB_A
};
@ -58,11 +59,11 @@ class PSDLoader {
public:
PSDLoader(BPositionIO *stream);
~PSDLoader();
status_t Decode(BPositionIO *target);
bool IsLoaded(void);
bool IsSupported(void);
BString ColorFormatName(void);
private:
@ -71,14 +72,14 @@ private:
uint8 _GetUInt8FromStream(BPositionIO *in);
int8 _GetInt8FromStream(BPositionIO *in);
void _SkipStreamBlock(BPositionIO *in, size_t count);
psd_color_format _ColorFormat(void);
BPositionIO *fStream;
uint8 *fStreamBuffer;
size_t fStreamSize;
size_t fStreamPos;
int32 fSignature;
int16 fVersion;
int16 fChannels;
@ -87,7 +88,7 @@ private:
int16 fDepth;
int16 fColorFormat;
int16 fCompression;
bool fLoaded;
};

View File

@ -21,7 +21,7 @@
#define DOCUMENT_COUNT "/documentCount"
#define DOCUMENT_INDEX "/documentIndex"
#define PSD_TRANSLATOR_VERSION B_TRANSLATION_MAKE_VERSION(1, 1, 0)
#define PSD_TRANSLATOR_VERSION B_TRANSLATION_MAKE_VERSION(1, 1, 1)
#define PSD_IMAGE_FORMAT 'PSD '
#define PSD_IN_QUALITY 0.5