From 7983058de34e9b8bf7345f2001a39242a83cf1f9 Mon Sep 17 00:00:00 2001 From: Gerasim Troeglazov <3dEyes@gmail.com> Date: Thu, 19 Dec 2013 10:37:09 +0000 Subject: [PATCH] PSDTranslator: Rework export module --- src/add-ons/translators/psd/PSDTranslator.cpp | 50 +--- src/add-ons/translators/psd/PSDTranslator.h | 5 +- .../translators/psd/PSDTranslator.rdef | 6 +- src/add-ons/translators/psd/PSDWriter.cpp | 216 +++++++++++------- src/add-ons/translators/psd/PSDWriter.h | 17 +- 5 files changed, 153 insertions(+), 141 deletions(-) diff --git a/src/add-ons/translators/psd/PSDTranslator.cpp b/src/add-ons/translators/psd/PSDTranslator.cpp index 33247399f1..a4bdbd9a12 100644 --- a/src/add-ons/translators/psd/PSDTranslator.cpp +++ b/src/add-ons/translators/psd/PSDTranslator.cpp @@ -140,8 +140,10 @@ PSDTranslator::DerivedTranslate(BPositionIO *source, } case 1: { - if (outType == PSD_IMAGE_FORMAT) - return _TranslateFromBits(source, ioExtension, outType, target); + if (outType == PSD_IMAGE_FORMAT) { + PSDWriter psdFile(source); + return psdFile.Encode(target); + } return B_NO_TRANSLATOR; } default: @@ -150,50 +152,6 @@ PSDTranslator::DerivedTranslate(BPositionIO *source, } -status_t -PSDTranslator::_TranslateFromBits(BPositionIO* stream, - BMessage* ioExtension, uint32 outType, - BPositionIO* target) -{ - TranslatorBitmap bitsHeader; - status_t result; - result = identify_bits_header(stream, NULL, &bitsHeader); - if (result != B_OK) - return result; - - if (bitsHeader.colors != B_RGB32 - && bitsHeader.colors != B_RGBA32) { - return B_NO_TRANSLATOR; - } - - uint32 width = bitsHeader.bounds.IntegerWidth() + 1; - uint32 height = bitsHeader.bounds.IntegerHeight() + 1; - - int32 layerSize = height * width; - int32 layersCount = bitsHeader.colors == B_RGB32 ? 3 : 4; - - uint8 *buff = new uint8[layerSize * layersCount]; - - uint8 *ptr = buff; - for (int i = 0; i < layerSize; i++) { - uint8 rgba[4]; - stream->Read(rgba, sizeof(uint32)); - ptr[i] = rgba[2]; - ptr[i+layerSize] = rgba[1]; - ptr[i+layerSize+layerSize] = rgba[0]; - if (layersCount == 4) - ptr[i+layerSize+layerSize+layerSize] = rgba[3]; - } - - PSDWriter psdFile(stream); - psdFile.EncodeFromRGBA(target, buff, layersCount, width, height); - - delete buff; - - return B_OK; -} - - status_t PSDTranslator::DerivedCanHandleImageSize(float width, float height) const { diff --git a/src/add-ons/translators/psd/PSDTranslator.h b/src/add-ons/translators/psd/PSDTranslator.h index a4f211fdc0..eaeb82bd27 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, 2, 0) +#define PSD_TRANSLATOR_VERSION B_TRANSLATION_MAKE_VERSION(1, 2, 1) #define PSD_IMAGE_FORMAT 'PSD ' #define PSD_IN_QUALITY 0.7 @@ -53,9 +53,6 @@ class PSDTranslator : public BaseTranslator { protected: virtual ~PSDTranslator(); - private: - status_t _TranslateFromBits(BPositionIO* stream, - BMessage* settings, uint32 outType, BPositionIO* target); }; extern const char *kDocumentCount; diff --git a/src/add-ons/translators/psd/PSDTranslator.rdef b/src/add-ons/translators/psd/PSDTranslator.rdef index 3b8d4c7ea7..1cdd5a4f1e 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 = 1, - minor = 3, + middle = 2, + minor = 1, variety = 0, internal = 0, - short_info = "1.1.3", + short_info = "1.2.1", long_info = "Haiku PSDTranslator Add-Ons." }; diff --git a/src/add-ons/translators/psd/PSDWriter.cpp b/src/add-ons/translators/psd/PSDWriter.cpp index 6c3184c2d9..dc18ce5907 100644 --- a/src/add-ons/translators/psd/PSDWriter.cpp +++ b/src/add-ons/translators/psd/PSDWriter.cpp @@ -8,11 +8,39 @@ #include "BaseTranslator.h" #include "PSDWriter.h" +#include "DataArray.h" PSDWriter::PSDWriter(BPositionIO *stream) { fStream = stream; + fReady = false; + + TranslatorBitmap header; + stream->Seek(0, SEEK_SET); + status_t err = stream->Read(&header, sizeof(TranslatorBitmap)); + if (err < B_OK) + return; + else if (err < (int)sizeof(TranslatorBitmap)) + return; + + fBitmapDataPos = stream->Position(); + + BRect bounds; + bounds.left = B_BENDIAN_TO_HOST_FLOAT(header.bounds.left); + bounds.top = B_BENDIAN_TO_HOST_FLOAT(header.bounds.top); + bounds.right = B_BENDIAN_TO_HOST_FLOAT(header.bounds.right); + bounds.bottom = B_BENDIAN_TO_HOST_FLOAT(header.bounds.bottom); + fInRowBytes = B_BENDIAN_TO_HOST_INT32(header.rowBytes); + fColorSpace = (color_space)B_BENDIAN_TO_HOST_INT32(header.colors); + fChannels = fColorSpace == B_RGB32 ? 3 : 4; + + fWidth = bounds.IntegerWidth() + 1; + fHeight = bounds.IntegerHeight() + 1; + + fCompression = PSD_COMPRESSED_RAW; + + fReady = true; } @@ -21,108 +49,126 @@ PSDWriter::~PSDWriter() } -status_t -PSDWriter::EncodeFromRGBA(BPositionIO *target, uint8 *buff, - int32 layers, int32 width, int32 height) +bool +PSDWriter::IsReady(void) { - int32 channelSize = width * height; + return fReady; +} - _WriteUInt32ToStream(target, 0x38425053); // 8BPS - _WriteUInt16ToStream(target, 1); // Version = 1 - _WriteFillBlockToStream(target, 0, 6); // reserved - _WriteInt16ToStream(target, layers); // Channels - _WriteInt32ToStream(target, height); // Height - _WriteInt32ToStream(target, width); // Width - _WriteInt16ToStream(target, 8); // Depth = 8 - _WriteInt16ToStream(target, PSD_COLOR_MODE_RGB); // ColorMode - _WriteUInt32ToStream(target, 0); // ColorModeBlockSize = 0 - size_t sizePos = target->Position(); - _WriteUInt32ToStream(target, 0); // ImageResourceBlockSize = 0 for now - _WriteUInt32ToStream(target, 0x3842494D); // 8BIM - _WriteUInt16ToStream(target, 1005); - _WriteUInt16ToStream(target, 0); - _WriteUInt32ToStream(target, 16); - uint8 resBlock[16] = {0x00, 0x48, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, - 0x00, 0x48, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01}; - _WriteBlockToStream(target, resBlock, 16); +void +PSDWriter::SetCompression(int16 compression) +{ + fCompression = compression; +} - // current layer info - _WriteUInt32ToStream(target, 0x3842494D); // 8BIM - _WriteUInt16ToStream(target, 1024); - _WriteUInt16ToStream(target, 0); - _WriteUInt32ToStream(target, 2); - _WriteUInt16ToStream(target, 0); // Set current layer to 0 - int32 resBlockSize = target->Position() - sizePos; - size_t lastPos = target->Position(); - target->Seek(sizePos, SEEK_SET); - _WriteUInt32ToStream(target, resBlockSize - sizeof(uint32)); - target->Seek(lastPos, SEEK_SET); +status_t +PSDWriter::Encode(BPositionIO *target) +{ + if (!fReady) + return B_NO_TRANSLATOR; - sizePos = target->Position(); - _WriteUInt32ToStream(target, 0); // Layer & mask block size = 0 - _WriteUInt32ToStream(target, 0); // Layer info block size = 0 + int32 channelSize = fWidth * fHeight; - _WriteUInt16ToStream(target, 1); // Layers count + fStream->Seek(fBitmapDataPos, SEEK_SET); - _WriteUInt32ToStream(target, 0); // Layer rect - _WriteUInt32ToStream(target, 0); - _WriteUInt32ToStream(target, height); - _WriteUInt32ToStream(target, width); - - _WriteInt16ToStream(target, layers); // Layer Channels - - for (int channels = 0; channels < 3; channels++) { - _WriteInt16ToStream(target, channels); // Channel num - _WriteUInt32ToStream(target, channelSize + 2); // Channel size + BDataArray psdChannel[4]; + + for (int i = 0; i < channelSize; i++) { + uint8 rgba[4]; + fStream->Read(rgba, sizeof(uint32)); + psdChannel[0].Append((uint8)rgba[2]); // Red channel + psdChannel[1].Append((uint8)rgba[1]); // Green channel + psdChannel[2].Append((uint8)rgba[0]); // Blue channel + if (fChannels == 4) + psdChannel[3].Append((uint8)rgba[3]); // Alpha channel } - if (layers == 4) { - _WriteInt16ToStream(target, -1); - _WriteUInt32ToStream(target, channelSize + 2); // Alpha channel size + // PSD header + BDataArray psdHeader(64); + psdHeader << "8BPS"; // Signature + psdHeader << (uint16)1; // Version = 1 + psdHeader.Repeat(0, 6); // Reserved + psdHeader << fChannels; // Channels + psdHeader << fHeight << fWidth; // Image size + psdHeader << (int16)8; // Depth + psdHeader << (int16)PSD_COLOR_MODE_RGB; // ColorMode + + // Color mode section + BDataArray psdColorModeSection(16); + psdColorModeSection << (uint32)0; + + // Image resource section + BDataArray psdImageResourceSection(64); + psdImageResourceSection << "8BIM"; // Block signature + psdImageResourceSection << (uint16)1005; + psdImageResourceSection << (uint16)0; + psdImageResourceSection << (uint32)16; + uint8 resBlock[16] = {0x00, 0x48, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x01, + 0x00, 0x48, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x01}; + psdImageResourceSection.Append(resBlock, 16); + // Current layer info + psdImageResourceSection << "8BIM"; // Block signature + psdImageResourceSection << (uint16)1024; + psdImageResourceSection << (uint16)0; + psdImageResourceSection << (uint32)2; + psdImageResourceSection << (uint16)0; // Set current layer to 0 + + // Layer & mask section + BDataArray psdLayersSection; + psdLayersSection << (uint16)1; // Layers count + psdLayersSection << (uint32)0; // Layer rect + psdLayersSection << (uint32)0; + psdLayersSection << (uint32)fHeight; + psdLayersSection << (uint32)fWidth; + psdLayersSection << (uint16)fChannels; + + for (int dataChannel = 0; dataChannel < 3; dataChannel++) { + psdLayersSection << (int16)dataChannel; // Channel num + psdLayersSection << (uint32)(psdChannel[dataChannel].Length() + 2); } + if (fChannels == 4) { + psdLayersSection << (int16)-1; // Alpha channel id (-1) + psdLayersSection << (uint32)(psdChannel[4].Length() + 2); + } + psdLayersSection << "8BIM"; + psdLayersSection << "norm"; // Blend mode = norm + psdLayersSection << (uint8)255; // Opacity + psdLayersSection << (uint8)0; // Clipping + psdLayersSection << (uint8)1; // Flags + psdLayersSection << (uint8)0; // Flags + psdLayersSection << (uint32)24; // Extra data length + psdLayersSection << (uint32)0; // Mask info + psdLayersSection << (uint32)0; - _WriteUInt32ToStream(target, 0x3842494D); // 8BIM - - uint8 blendModeKey[4] = {'n','o','r','m'}; - _WriteBlockToStream(target, blendModeKey, 4); // Blend mode norm - - _WriteUInt8ToStream(target, 255); // Alpha - - _WriteUInt8ToStream(target, 0); // Clipping - _WriteUInt8ToStream(target, 1); // Flags - _WriteUInt8ToStream(target, 0); // Flags - - _WriteUInt32ToStream(target, 24); // Extra data length - _WriteUInt32ToStream(target, 0); // Mask info - _WriteUInt32ToStream(target, 0); - - _WriteUInt8ToStream(target, 15); // Layer name length + psdLayersSection << (uint8)15; // Layer name length uint8 layerName[16] = {"Layer #1 "}; - _WriteBlockToStream(target, layerName, 15); // Layer name + psdLayersSection.Append(layerName, 15); // Layer name - for (int dataChannel = 0; dataChannel < layers; dataChannel++) { - _WriteInt16ToStream(target, PSD_COMPRESSED_RAW); // Compression mode - _WriteBlockToStream(target, buff + dataChannel * channelSize, - channelSize); // Layer image data + for (int dataChannel = 0; dataChannel < fChannels; dataChannel++) { + psdLayersSection << fCompression; // Compression mode + psdLayersSection.Append(psdChannel[dataChannel].Buffer(), + psdChannel[dataChannel].Length()); // Layer image data } + + psdHeader.WriteToStream(target); + + psdColorModeSection.WriteToStream(target); + + _WriteUInt32ToStream(target, psdImageResourceSection.Length()); + psdImageResourceSection.WriteToStream(target); - uint32 layerBlockSize = target->Position() - sizePos; + _WriteUInt32ToStream(target, psdLayersSection.Length() + 4); + _WriteUInt32ToStream(target, psdLayersSection.Length()); + psdLayersSection.WriteToStream(target); -/* if (layerBlockSize % 2 != 0) { - _WriteUInt8ToStream(target, 0); - layerBlockSize++; - }*/ - - lastPos = target->Position(); - target->Seek(sizePos, SEEK_SET); - _WriteUInt32ToStream(target, layerBlockSize - 4); - _WriteUInt32ToStream(target, layerBlockSize - 8); - target->Seek(lastPos, SEEK_SET); - - _WriteUInt16ToStream(target, PSD_COMPRESSED_RAW); // Compression mode - _WriteBlockToStream(target, buff, channelSize * layers); + // Merged layer + _WriteUInt16ToStream(target, fCompression); // Compression mode + for (int dataChannel = 0; dataChannel < fChannels; dataChannel++) + psdChannel[dataChannel].WriteToStream(target); return B_OK; } diff --git a/src/add-ons/translators/psd/PSDWriter.h b/src/add-ons/translators/psd/PSDWriter.h index 5f428c7745..9703d9281d 100644 --- a/src/add-ons/translators/psd/PSDWriter.h +++ b/src/add-ons/translators/psd/PSDWriter.h @@ -29,8 +29,9 @@ public: PSDWriter(BPositionIO *stream); ~PSDWriter(); - status_t EncodeFromRGBA(BPositionIO *target, uint8 *buff, - int32 layers, int32 width, int32 height); + bool IsReady(void); + void SetCompression(int16 compression); + status_t Encode(BPositionIO *target); private: void _WriteInt32ToStream(BPositionIO *stream, int32); @@ -44,7 +45,17 @@ private: void _WriteBlockToStream(BPositionIO *stream, uint8 *block, size_t count); - BPositionIO *fStream; + BPositionIO *fStream; + size_t fBitmapDataPos; + + color_space fColorSpace; + int32 fInRowBytes; + int16 fChannels; + int32 fWidth; + int32 fHeight; + int16 fCompression; + + bool fReady; };