PSDTranslator: Add Photoshop Big (PSB) format support

This commit is contained in:
Gerasim Troeglazov
2013-12-20 09:30:03 +00:00
parent a47ae0d08e
commit 6d7acad27d
9 changed files with 152 additions and 51 deletions
+33 -9
View File
@@ -22,18 +22,31 @@ ConfigView::ConfigView(TranslatorSettings *settings)
{ {
fSettings = settings; fSettings = settings;
BPopUpMenu* popupMenu = new BPopUpMenu("popup_compression"); BPopUpMenu* compressionPopupMenu = new BPopUpMenu("popup_compression");
uint32 currentCompression = uint32 currentCompression =
fSettings->SetGetInt32(PSD_SETTING_COMPRESSION); fSettings->SetGetInt32(PSD_SETTING_COMPRESSION);
_AddItemToMenu(popupMenu, "Uncompressed", _AddItemToMenu(compressionPopupMenu, "Uncompressed",
PSD_COMPRESSED_RAW, currentCompression); MSG_COMPRESSION_CHANGED, PSD_COMPRESSED_RAW, currentCompression);
_AddItemToMenu(popupMenu, "RLE", _AddItemToMenu(compressionPopupMenu, "RLE",
PSD_COMPRESSED_RLE, currentCompression); MSG_COMPRESSION_CHANGED, PSD_COMPRESSED_RLE, currentCompression);
fCompressionField = new BMenuField("compression", fCompressionField = new BMenuField("compression",
"Compression: ", popupMenu); "Compression: ", compressionPopupMenu);
BPopUpMenu* versionPopupMenu = new BPopUpMenu("popup_version");
uint32 currentVersion =
fSettings->SetGetInt32(PSD_SETTING_VERSION);
_AddItemToMenu(versionPopupMenu, "Photoshop Document (PSD File)",
MSG_VERSION_CHANGED, PSD_FILE, currentVersion);
_AddItemToMenu(versionPopupMenu, "Photoshop Big Document (PSB File)",
MSG_VERSION_CHANGED, PSB_FILE, currentVersion);
fVersionField = new BMenuField("version",
"Format: ", versionPopupMenu);
BAlignment leftAlignment(B_ALIGN_LEFT, B_ALIGN_VERTICAL_UNSET); BAlignment leftAlignment(B_ALIGN_LEFT, B_ALIGN_VERTICAL_UNSET);
@@ -66,6 +79,8 @@ ConfigView::ConfigView(TranslatorSettings *settings)
stringView->SetExplicitAlignment(leftAlignment); stringView->SetExplicitAlignment(leftAlignment);
AddChild(stringView); AddChild(stringView);
AddChild(fVersionField);
AddChild(fCompressionField); AddChild(fCompressionField);
AddChild(BSpaceLayoutItem::CreateGlue()); AddChild(BSpaceLayoutItem::CreateGlue());
@@ -86,6 +101,7 @@ void
ConfigView::AllAttached() ConfigView::AllAttached()
{ {
fCompressionField->Menu()->SetTargetForItems(this); fCompressionField->Menu()->SetTargetForItems(this);
fVersionField->Menu()->SetTargetForItems(this);
} }
@@ -101,6 +117,14 @@ ConfigView::MessageReceived(BMessage* message)
} }
break; break;
} }
case MSG_VERSION_CHANGED: {
int32 value;
if (message->FindInt32("value", &value) >= B_OK) {
fSettings->SetGetInt32(PSD_SETTING_VERSION, &value);
fSettings->SaveSettings();
}
break;
}
default: default:
BView::MessageReceived(message); BView::MessageReceived(message);
} }
@@ -109,9 +133,9 @@ ConfigView::MessageReceived(BMessage* message)
void void
ConfigView::_AddItemToMenu(BMenu* menu, const char* label, ConfigView::_AddItemToMenu(BMenu* menu, const char* label,
uint32 value, uint32 current_value) uint32 mess, uint32 value, uint32 current_value)
{ {
BMessage* message = new BMessage(MSG_COMPRESSION_CHANGED); BMessage* message = new BMessage(mess);
message->AddInt32("value", value); message->AddInt32("value", value);
BMenuItem* item = new BMenuItem(label, message); BMenuItem* item = new BMenuItem(label, message);
item->SetMarked(value == current_value); item->SetMarked(value == current_value);
+3 -1
View File
@@ -16,6 +16,7 @@
#include <MenuField.h> #include <MenuField.h>
#define MSG_COMPRESSION_CHANGED 'cchg' #define MSG_COMPRESSION_CHANGED 'cchg'
#define MSG_VERSION_CHANGED 'vchg'
class ConfigView : public BGroupView { class ConfigView : public BGroupView {
public: public:
@@ -27,10 +28,11 @@ class ConfigView : public BGroupView {
private: private:
void _AddItemToMenu(BMenu* menu, const char* label, void _AddItemToMenu(BMenu* menu, const char* label,
uint32 value, uint32 current_value); uint32 mess, uint32 value, uint32 current_value);
BTextView* fCopyrightView; BTextView* fCopyrightView;
BMenuField* fCompressionField; BMenuField* fCompressionField;
BMenuField* fVersionField;
TranslatorSettings *fSettings; TranslatorSettings *fSettings;
}; };
+25 -4
View File
@@ -46,7 +46,12 @@ PSDLoader::PSDLoader(BPositionIO *src)
_SkipStreamBlock(fStream, fImageResourceSectionSize); _SkipStreamBlock(fStream, fImageResourceSectionSize);
// Skip [layer and mask] block // Skip [layer and mask] block
_SkipStreamBlock(fStream, _GetInt32FromStream(fStream)); if (fVersion == PSD_FILE)
_SkipStreamBlock(fStream, _GetInt32FromStream(fStream));
else if (fVersion == PSB_FILE)
_SkipStreamBlock(fStream, _GetInt64FromStream(fStream));
else
return;
fCompression = _GetInt16FromStream(fStream); fCompression = _GetInt16FromStream(fStream);
@@ -74,8 +79,10 @@ PSDLoader::IsSupported(void)
if (!fLoaded) if (!fLoaded)
return false; return false;
if (fVersion != 1) if (fVersion != PSD_FILE
&& fVersion != PSB_FILE) {
return false; return false;
}
if (fChannels < 0 || fChannels > PSD_MAX_CHANNELS) if (fChannels < 0 || fChannels > PSD_MAX_CHANNELS)
return false; return false;
@@ -87,8 +94,9 @@ PSDLoader::IsSupported(void)
return false; return false;
if (fCompression != PSD_COMPRESSED_RAW if (fCompression != PSD_COMPRESSED_RAW
&& fCompression != PSD_COMPRESSED_RLE) && fCompression != PSD_COMPRESSED_RLE) {
return false; return false;
}
return true; return true;
} }
@@ -207,7 +215,11 @@ PSDLoader::Decode(BPositionIO *target)
} }
case PSD_COMPRESSED_RLE: case PSD_COMPRESSED_RLE:
{ {
fStreamPos += fHeight * fChannels * 2; if (fVersion == PSD_FILE)
fStreamPos += fHeight * fChannels * 2;
else if (fVersion == PSB_FILE)
fStreamPos += fHeight * fChannels * 4;
for (int channelIdx = 0; channelIdx < fChannels; channelIdx++) { for (int channelIdx = 0; channelIdx < fChannels; channelIdx++) {
uint8 *ptr = imageData[channelIdx]; uint8 *ptr = imageData[channelIdx];
// Read the RLE data. // Read the RLE data.
@@ -448,6 +460,15 @@ PSDLoader::Decode(BPositionIO *target)
} }
int64
PSDLoader::_GetInt64FromStream(BPositionIO *in)
{
int64 ret;
in->Read(&ret, sizeof(int64));
return B_BENDIAN_TO_HOST_INT64(ret);
}
int32 int32
PSDLoader::_GetInt32FromStream(BPositionIO *in) PSDLoader::_GetInt32FromStream(BPositionIO *in)
{ {
+7
View File
@@ -25,6 +25,12 @@
#define PSD_MAX_CHANNELS 16 #define PSD_MAX_CHANNELS 16
enum psd_version {
PSD_FILE = 1,
PSB_FILE = 2
};
enum psd_compressed_type { enum psd_compressed_type {
PSD_COMPRESSED_RAW = 0, PSD_COMPRESSED_RAW = 0,
PSD_COMPRESSED_RLE = 1 PSD_COMPRESSED_RLE = 1
@@ -72,6 +78,7 @@ public:
BString ColorFormatName(void); BString ColorFormatName(void);
private: private:
int64 _GetInt64FromStream(BPositionIO *in);
int32 _GetInt32FromStream(BPositionIO *in); int32 _GetInt32FromStream(BPositionIO *in);
int16 _GetInt16FromStream(BPositionIO *in); int16 _GetInt16FromStream(BPositionIO *in);
uint8 _GetUInt8FromStream(BPositionIO *in); uint8 _GetUInt8FromStream(BPositionIO *in);
@@ -61,7 +61,8 @@ static const translation_format sOutputFormats[] = {
static const TranSetting sDefaultSettings[] = { static const TranSetting sDefaultSettings[] = {
{B_TRANSLATOR_EXT_HEADER_ONLY, TRAN_SETTING_BOOL, false}, {B_TRANSLATOR_EXT_HEADER_ONLY, TRAN_SETTING_BOOL, false},
{B_TRANSLATOR_EXT_DATA_ONLY, TRAN_SETTING_BOOL, false}, {B_TRANSLATOR_EXT_DATA_ONLY, TRAN_SETTING_BOOL, false},
{PSD_SETTING_COMPRESSION, TRAN_SETTING_INT32, PSD_COMPRESSED_RLE} {PSD_SETTING_COMPRESSION, TRAN_SETTING_INT32, PSD_COMPRESSED_RLE},
{PSD_SETTING_VERSION, TRAN_SETTING_INT32, PSD_FILE}
}; };
const uint32 kNumInputFormats = sizeof(sInputFormats) const uint32 kNumInputFormats = sizeof(sInputFormats)
@@ -141,11 +142,17 @@ PSDTranslator::DerivedTranslate(BPositionIO *source,
} }
case 1: case 1:
{ {
if (outType == PSD_IMAGE_FORMAT) { if (outType == PSD_IMAGE_FORMAT) {
PSDWriter psdFile(source); PSDWriter psdFile(source);
uint32 compression = uint32 compression =
fSettings->SetGetInt32(PSD_SETTING_COMPRESSION); fSettings->SetGetInt32(PSD_SETTING_COMPRESSION);
uint32 version =
fSettings->SetGetInt32(PSD_SETTING_VERSION);
psdFile.SetCompression(compression); psdFile.SetCompression(compression);
psdFile.SetVersion(version);
if (psdFile.IsReady()) if (psdFile.IsReady())
return psdFile.Encode(target); return psdFile.Encode(target);
} }
+2 -1
View File
@@ -22,8 +22,9 @@
#define DOCUMENT_INDEX "/documentIndex" #define DOCUMENT_INDEX "/documentIndex"
#define PSD_SETTING_COMPRESSION "psd /compression" #define PSD_SETTING_COMPRESSION "psd /compression"
#define PSD_SETTING_VERSION "psd /psdversion"
#define PSD_TRANSLATOR_VERSION B_TRANSLATION_MAKE_VERSION(1, 2, 1) #define PSD_TRANSLATOR_VERSION B_TRANSLATION_MAKE_VERSION(1, 3, 0)
#define PSD_IMAGE_FORMAT 'PSD ' #define PSD_IMAGE_FORMAT 'PSD '
#define PSD_IN_QUALITY 0.7 #define PSD_IN_QUALITY 0.7
@@ -6,10 +6,10 @@ resource app_signature "application/x-vnd.Haiku-PSDTranslator";
resource app_version { resource app_version {
major = 1, major = 1,
middle = 2, middle = 3,
minor = 1, minor = 0,
variety = 0, variety = 0,
internal = 0, internal = 0,
short_info = "1.2.1", short_info = "1.3.0",
long_info = "Haiku PSDTranslator Add-Ons." long_info = "Haiku PSDTranslator Add-Ons."
}; };
+65 -30
View File
@@ -33,11 +33,14 @@ PSDWriter::PSDWriter(BPositionIO *stream)
bounds.bottom = B_BENDIAN_TO_HOST_FLOAT(header.bounds.bottom); bounds.bottom = B_BENDIAN_TO_HOST_FLOAT(header.bounds.bottom);
fInRowBytes = B_BENDIAN_TO_HOST_INT32(header.rowBytes); fInRowBytes = B_BENDIAN_TO_HOST_INT32(header.rowBytes);
fColorSpace = (color_space)B_BENDIAN_TO_HOST_INT32(header.colors); fColorSpace = (color_space)B_BENDIAN_TO_HOST_INT32(header.colors);
if (fColorSpace != B_RGB32 && fColorSpace != B_RGBA32)
return;
fChannels = fColorSpace == B_RGB32 ? 3 : 4; fChannels = fColorSpace == B_RGB32 ? 3 : 4;
fWidth = bounds.IntegerWidth() + 1; fWidth = bounds.IntegerWidth() + 1;
fHeight = bounds.IntegerHeight() + 1; fHeight = bounds.IntegerHeight() + 1;
fVersion = PSD_FILE;
fCompression = PSD_COMPRESSED_RAW; fCompression = PSD_COMPRESSED_RAW;
fReady = true; fReady = true;
@@ -63,6 +66,13 @@ PSDWriter::SetCompression(int16 compression)
} }
void
PSDWriter::SetVersion(int16 ver)
{
fVersion = ver;
}
status_t status_t
PSDWriter::Encode(BPositionIO *target) PSDWriter::Encode(BPositionIO *target)
{ {
@@ -98,16 +108,18 @@ PSDWriter::Encode(BPositionIO *target)
lineData[2].Append((uint8)rgba[0]); // Blue channel lineData[2].Append((uint8)rgba[0]); // Blue channel
if (fChannels == 4) if (fChannels == 4)
lineData[3].Append((uint8)rgba[3]); // Alpha channel lineData[3].Append((uint8)rgba[3]); // Alpha channel
else
lineData[3].Append((uint8)255);
} }
for (int channelIdx = 0; channelIdx < fChannels; channelIdx++) { for (int channelIdx = 0; channelIdx < fChannels; channelIdx++) {
BDataArray *packedLine = PackBits(lineData[channelIdx].Buffer(), BDataArray *packedLine = PackBits(lineData[channelIdx].Buffer(),
lineData[channelIdx].Length()); lineData[channelIdx].Length());
psdByteCounts[channelIdx].Append((uint16)packedLine->Length());
psdChannel[channelIdx].Append(packedLine->Buffer(), if (fVersion == PSD_FILE)
packedLine->Length()); psdByteCounts[channelIdx].Append((uint16)packedLine->Length());
else
psdByteCounts[channelIdx].Append((uint32)packedLine->Length());
psdChannel[channelIdx].Append(*packedLine);
delete packedLine; delete packedLine;
} }
} }
@@ -117,7 +129,7 @@ PSDWriter::Encode(BPositionIO *target)
// PSD header // PSD header
BDataArray psdHeader(64); BDataArray psdHeader(64);
psdHeader << "8BPS"; // Signature psdHeader << "8BPS"; // Signature
psdHeader << (uint16)1; // Version = 1 psdHeader << (uint16)fVersion; // Version
psdHeader.Repeat(0, 6); // Reserved psdHeader.Repeat(0, 6); // Reserved
psdHeader << fChannels; // Channels psdHeader << fChannels; // Channels
psdHeader << fHeight << fWidth; // Image size psdHeader << fHeight << fWidth; // Image size
@@ -155,26 +167,31 @@ PSDWriter::Encode(BPositionIO *target)
psdLayersSection << (uint32)fWidth; psdLayersSection << (uint32)fWidth;
psdLayersSection << (uint16)fChannels; psdLayersSection << (uint16)fChannels;
for (int channelIdx = 0; channelIdx < 3; channelIdx++) { for (int channelIdx = 0; channelIdx < fChannels; channelIdx++) {
psdLayersSection << (int16)channelIdx; // Channel num if (channelIdx == 3)
psdLayersSection << (int16)-1; // Alpha channel id (-1)
else
psdLayersSection << (int16)channelIdx; // Channel num
if (fCompression == PSD_COMPRESSED_RAW) { if (fCompression == PSD_COMPRESSED_RAW) {
psdLayersSection << (uint32)(psdChannel[channelIdx].Length() if (fVersion == PSD_FILE) {
+ sizeof(int16)); psdLayersSection << (uint32)(psdChannel[channelIdx].Length()
+ sizeof(int16));
} else {
psdLayersSection << (uint64)(psdChannel[channelIdx].Length()
+ sizeof(int16));
}
} else { } else {
psdLayersSection << (uint32)(psdChannel[channelIdx].Length() if (fVersion == PSD_FILE) {
+ psdByteCounts[channelIdx].Length() + sizeof(int16)); psdLayersSection << (uint32)(psdChannel[channelIdx].Length()
} + psdByteCounts[channelIdx].Length() + sizeof(int16));
} } else {
if (fChannels == 4) { psdLayersSection << (uint64)(psdChannel[channelIdx].Length()
psdLayersSection << (int16)-1; // Alpha channel id (-1) + psdByteCounts[channelIdx].Length() + sizeof(int16));
if (fCompression == PSD_COMPRESSED_RAW) { }
psdLayersSection << (uint32)(psdChannel[3].Length()
+ sizeof(int16));
} else {
psdLayersSection << (uint32)(psdChannel[3].Length()
+ psdByteCounts[3].Length() + sizeof(int16));
} }
} }
psdLayersSection << "8BIM"; psdLayersSection << "8BIM";
psdLayersSection << "norm"; // Blend mode = norm psdLayersSection << "norm"; // Blend mode = norm
psdLayersSection << (uint8)255; // Opacity psdLayersSection << (uint8)255; // Opacity
@@ -192,16 +209,13 @@ PSDWriter::Encode(BPositionIO *target)
if (fCompression == PSD_COMPRESSED_RAW) { if (fCompression == PSD_COMPRESSED_RAW) {
for (int channelIdx = 0; channelIdx < fChannels; channelIdx++) { for (int channelIdx = 0; channelIdx < fChannels; channelIdx++) {
psdLayersSection << fCompression; // Compression mode psdLayersSection << fCompression; // Compression mode
psdLayersSection.Append(psdChannel[channelIdx].Buffer(), psdLayersSection.Append(psdChannel[channelIdx]); // Channel data
psdChannel[channelIdx].Length()); // Layer image data
} }
} else { } else {
for (int channelIdx = 0; channelIdx < fChannels; channelIdx++) { for (int channelIdx = 0; channelIdx < fChannels; channelIdx++) {
psdLayersSection << fCompression; // Compression mode psdLayersSection << fCompression; // Compression mode
psdLayersSection.Append(psdByteCounts[channelIdx].Buffer(), psdLayersSection.Append(psdByteCounts[channelIdx]); // Bytes count
psdByteCounts[channelIdx].Length()); // Bytes count psdLayersSection.Append(psdChannel[channelIdx]); // Channel data
psdLayersSection.Append(psdChannel[channelIdx].Buffer(),
psdChannel[channelIdx].Length()); // Layer image data
} }
} }
@@ -217,8 +231,13 @@ PSDWriter::Encode(BPositionIO *target)
_WriteUInt32ToStream(target, psdImageResourceSection.Length()); _WriteUInt32ToStream(target, psdImageResourceSection.Length());
psdImageResourceSection.WriteToStream(target); psdImageResourceSection.WriteToStream(target);
_WriteUInt32ToStream(target, psdLayersSection.Length() + sizeof(int32)); if (fVersion == PSD_FILE) {
_WriteUInt32ToStream(target, psdLayersSection.Length()); _WriteUInt32ToStream(target, psdLayersSection.Length() + sizeof(int32));
_WriteUInt32ToStream(target, psdLayersSection.Length());
} else {
_WriteUInt64ToStream(target, psdLayersSection.Length() + sizeof(int64));
_WriteUInt64ToStream(target, psdLayersSection.Length());
}
psdLayersSection.WriteToStream(target); psdLayersSection.WriteToStream(target);
// Merged layer // Merged layer
@@ -281,6 +300,22 @@ PSDWriter::PackBits(uint8 *buff, int32 len)
} }
void
PSDWriter::_WriteInt64ToStream(BPositionIO *stream, int64 val)
{
val = B_HOST_TO_BENDIAN_INT64(val);
stream->Write(&val, sizeof(int32));
}
void
PSDWriter::_WriteUInt64ToStream(BPositionIO *stream, uint64 val)
{
val = B_HOST_TO_BENDIAN_INT64(val);
stream->Write(&val, sizeof(uint64));
}
void void
PSDWriter::_WriteInt32ToStream(BPositionIO *stream, int32 val) PSDWriter::_WriteInt32ToStream(BPositionIO *stream, int32 val)
{ {
+5 -1
View File
@@ -30,11 +30,14 @@ public:
PSDWriter(BPositionIO *stream); PSDWriter(BPositionIO *stream);
~PSDWriter(); ~PSDWriter();
bool IsReady(void); bool IsReady(void);
void SetCompression(int16 compression); void SetCompression(int16 compression);
void SetVersion(int16 version);
status_t Encode(BPositionIO *target); status_t Encode(BPositionIO *target);
private: private:
void _WriteInt64ToStream(BPositionIO *stream, int64);
void _WriteUInt64ToStream(BPositionIO *stream, uint64);
void _WriteInt32ToStream(BPositionIO *stream, int32); void _WriteInt32ToStream(BPositionIO *stream, int32);
void _WriteUInt32ToStream(BPositionIO *stream, uint32); void _WriteUInt32ToStream(BPositionIO *stream, uint32);
void _WriteInt16ToStream(BPositionIO *stream, int16); void _WriteInt16ToStream(BPositionIO *stream, int16);
@@ -57,6 +60,7 @@ private:
int32 fWidth; int32 fWidth;
int32 fHeight; int32 fHeight;
int16 fCompression; int16 fCompression;
int16 fVersion;
bool fReady; bool fReady;
}; };