hrev46565 adds 3 changesets to branch 'master' old head: bd50e8aedbea52e02a35cd1070eff0e597126ced new head: 5a65c29781873d0e3b18ec9bc15f30623d8a6f08 overview: http://cgit.haiku-os.org/haiku/log/?qt=range&q=5a65c29+%5Ebd50e8a ---------------------------------------------------------------------------- e3ec312: PSDTranslator: Implemented DataArray class for export improvements 7983058: PSDTranslator: Rework export module 5a65c29: PSDTranslator: Add RLE compression method for export [ Gerasim Troeglazov <3dEyes@xxxxxxxxx> ] ---------------------------------------------------------------------------- 8 files changed, 549 insertions(+), 147 deletions(-) src/add-ons/translators/psd/DataArray.cpp | 216 +++++++++++++ src/add-ons/translators/psd/DataArray.h | 61 ++++ src/add-ons/translators/psd/Jamfile | 2 + src/add-ons/translators/psd/PSDTranslator.cpp | 51 +--- src/add-ons/translators/psd/PSDTranslator.h | 5 +- src/add-ons/translators/psd/PSDTranslator.rdef | 6 +- src/add-ons/translators/psd/PSDWriter.cpp | 335 +++++++++++++++------ src/add-ons/translators/psd/PSDWriter.h | 20 +- ############################################################################ Commit: e3ec312ebf6ad6343d7477963cf5e3edd4b41deb URL: http://cgit.haiku-os.org/haiku/commit/?id=e3ec312 Author: Gerasim Troeglazov <3dEyes@xxxxxxxxx> Date: Thu Dec 19 09:11:26 2013 UTC PSDTranslator: Implemented DataArray class for export improvements ---------------------------------------------------------------------------- diff --git a/src/add-ons/translators/psd/DataArray.cpp b/src/add-ons/translators/psd/DataArray.cpp new file mode 100644 index 0000000..e3dd21b --- /dev/null +++ b/src/add-ons/translators/psd/DataArray.cpp @@ -0,0 +1,216 @@ +/* + * Copyright 2013, Gerasim Troeglazov, 3dEyes@xxxxxxxxx. All rights reserved. + * Distributed under the terms of the MIT License. + */ + +#include "DataArray.h" + + +BDataArray::BDataArray(int32 blockSize) +{ + fBlockSize = blockSize; + fData = (uint8*)malloc(blockSize); + fAllocatedDataSize = blockSize; + fDataSize = 0; +} + + +BDataArray::~BDataArray() +{ + free(fData); +} + + +status_t +BDataArray::_ReallocArrayFor(int32 size) +{ + if (fDataSize + size > fAllocatedDataSize) { + int32 blocks = ((fDataSize + size) / fBlockSize) + 1; + uint8 *newData = (uint8*)realloc(fData, blocks * fBlockSize); + if (newData != NULL) { + fData = newData; + fAllocatedDataSize = blocks * fBlockSize; + } + } + return fData == NULL ? B_NO_MEMORY : B_OK; +} + + +uint8* +BDataArray::Buffer(void) +{ + return fData; +} + + +int32 +BDataArray::Length(void) +{ + return fDataSize; +} + + +ssize_t +BDataArray::WriteToStream(BPositionIO *stream) +{ + return stream->Write(fData, fDataSize); +} + + +status_t +BDataArray::Append(uint8 val) +{ + status_t status = _ReallocArrayFor(sizeof(val)); + if (status != B_OK) + return status; + fData[fDataSize] = val; + fDataSize++; + return B_OK; +} + + +status_t +BDataArray::Append(int8 val) +{ + return Append((uint8)val); +} + + +status_t +BDataArray::Append(uint16 val) +{ + status_t status = _ReallocArrayFor(sizeof(val)); + if (status != B_OK) + return status; + val = B_HOST_TO_BENDIAN_INT16(val); + memcpy(fData + fDataSize, &val, sizeof(val)); + fDataSize += sizeof(val); + return B_OK; +} + + +status_t +BDataArray::Append(int16 val) +{ + return Append((uint16)val); +} + + +status_t +BDataArray::Append(uint32 val) +{ + status_t status = _ReallocArrayFor(sizeof(val)); + if (status != B_OK) + return status; + val = B_HOST_TO_BENDIAN_INT32(val); + memcpy(fData + fDataSize, &val, sizeof(val)); + fDataSize += sizeof(val); + return B_OK; +} + + +status_t +BDataArray::Append(int32 val) +{ + return Append((uint32)val); +} + + +status_t +BDataArray::Append(const char *str) +{ + int32 len = strlen(str); + status_t status = _ReallocArrayFor(len); + if (status != B_OK) + return status; + memcpy(fData + fDataSize, str, len); + fDataSize += len; + return B_OK; +} + + +status_t +BDataArray::Append(BString str) +{ + return Append(str.String()); +} + + +status_t +BDataArray::Append(uint8 *ptr, int32 len) +{ + status_t status = _ReallocArrayFor(len); + if (status != B_OK) + return status; + memcpy(fData + fDataSize, ptr, len); + fDataSize += len; + return B_OK; +} + + +status_t +BDataArray::Repeat(uint8 byte, int32 count) +{ + status_t status = _ReallocArrayFor(count); + if (status != B_OK) + return status; + memset(fData + fDataSize, byte, count); + fDataSize += count; + return B_OK; +} + + +BDataArray& +BDataArray::operator<<(int8 val) +{ + Append(val); + return *this; +} + + +BDataArray& +BDataArray::operator<<(uint8 val) +{ + Append(val); + return *this; +} + + +BDataArray& +BDataArray::operator<<(int16 val) +{ + Append(val); + return *this; +} + + +BDataArray& +BDataArray::operator<<(uint16 val) +{ + Append(val); + return *this; +} + + +BDataArray& +BDataArray::operator<<(int32 val) +{ + Append(val); + return *this; +} + + +BDataArray& +BDataArray::operator<<(uint32 val) +{ + Append(val); + return *this; +} + + +BDataArray& +BDataArray::operator<<(const char* str) +{ + Append(str); + return *this; +} diff --git a/src/add-ons/translators/psd/DataArray.h b/src/add-ons/translators/psd/DataArray.h new file mode 100644 index 0000000..33d97cf --- /dev/null +++ b/src/add-ons/translators/psd/DataArray.h @@ -0,0 +1,61 @@ +/* + * Copyright 2013, Gerasim Troeglazov, 3dEyes@xxxxxxxxx. All rights reserved. + * Distributed under the terms of the MIT License. + */ + + +#ifndef PSD_DATA_ARRAY_H +#define PSD_DATA_ARRAY_H + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include <String.h> +#include <DataIO.h> +#include <File.h> +#include <ByteOrder.h> + +#define DATAARRAY_BLOCK_SIZE 1024 + +class BDataArray { +public: + BDataArray(int32 blockSize = DATAARRAY_BLOCK_SIZE); + ~BDataArray(); + + status_t Append(int8 val); + status_t Append(uint8 val); + status_t Append(int16 val); + status_t Append(uint16 val); + status_t Append(int32 val); + status_t Append(uint32 val); + status_t Append(const char *str); + status_t Append(BString str); + status_t Append(uint8 *ptr, int32 len); + + status_t Repeat(uint8 byte, int32 count); + + BDataArray& operator<<(int8); + BDataArray& operator<<(uint8); + BDataArray& operator<<(int16); + BDataArray& operator<<(uint16); + BDataArray& operator<<(int32); + BDataArray& operator<<(uint32); + BDataArray& operator<<(const char*); + + uint8 *Buffer(void); + int32 Length(void); + + ssize_t WriteToStream(BPositionIO *stream); + +private: + inline status_t _ReallocArrayFor(int32 size); + + uint8 *fData; + int32 fDataSize; + int32 fAllocatedDataSize; + int32 fBlockSize; +}; + + +#endif /* PSD_DATA_ARRAY_H */ diff --git a/src/add-ons/translators/psd/Jamfile b/src/add-ons/translators/psd/Jamfile index 20dbc71..bbf7c3c 100644 --- a/src/add-ons/translators/psd/Jamfile +++ b/src/add-ons/translators/psd/Jamfile @@ -14,6 +14,7 @@ for architectureObject in [ MultiArchSubDirSetup ] { PSDTranslator.cpp PSDLoader.cpp PSDWriter.cpp + DataArray.cpp ConfigView.cpp : be translation [ MultiArchDefaultGristFiles libtranslatorsutils.a ] @@ -30,5 +31,6 @@ DoCatalogs PSDTranslator : PSDTranslator.cpp PSDLoader.cpp PSDWriter.cpp + DataArray.cpp ConfigView.cpp ; ############################################################################ Commit: 7983058de34e9b8bf7345f2001a39242a83cf1f9 URL: http://cgit.haiku-os.org/haiku/commit/?id=7983058 Author: Gerasim Troeglazov <3dEyes@xxxxxxxxx> Date: Thu Dec 19 10:37:09 2013 UTC PSDTranslator: Rework export module ---------------------------------------------------------------------------- diff --git a/src/add-ons/translators/psd/PSDTranslator.cpp b/src/add-ons/translators/psd/PSDTranslator.cpp index 3324739..a4bdbd9 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: @@ -151,50 +153,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 { return B_OK; diff --git a/src/add-ons/translators/psd/PSDTranslator.h b/src/add-ons/translators/psd/PSDTranslator.h index a4f211f..eaeb82b 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 3b8d4c7..1cdd5a4 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 6c3184c..dc18ce5 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; - - _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); - - // 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); - - sizePos = target->Position(); - _WriteUInt32ToStream(target, 0); // Layer & mask block size = 0 - _WriteUInt32ToStream(target, 0); // Layer info block size = 0 - - _WriteUInt16ToStream(target, 1); // Layers count - - _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 - } - - if (layers == 4) { - _WriteInt16ToStream(target, -1); - _WriteUInt32ToStream(target, channelSize + 2); // Alpha channel size - } - - _WriteUInt32ToStream(target, 0x3842494D); // 8BIM + return fReady; +} - uint8 blendModeKey[4] = {'n','o','r','m'}; - _WriteBlockToStream(target, blendModeKey, 4); // Blend mode norm - _WriteUInt8ToStream(target, 255); // Alpha +void +PSDWriter::SetCompression(int16 compression) +{ + fCompression = compression; +} - _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); +status_t +PSDWriter::Encode(BPositionIO *target) +{ + if (!fReady) + return B_NO_TRANSLATOR; + + int32 channelSize = fWidth * fHeight; + + fStream->Seek(fBitmapDataPos, SEEK_SET); + + 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 + } - _WriteUInt8ToStream(target, 15); // Layer name length + // 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; + + 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 } - - uint32 layerBlockSize = target->Position() - sizePos; - -/* 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); + + psdHeader.WriteToStream(target); + + psdColorModeSection.WriteToStream(target); + + _WriteUInt32ToStream(target, psdImageResourceSection.Length()); + psdImageResourceSection.WriteToStream(target); + + _WriteUInt32ToStream(target, psdLayersSection.Length() + 4); + _WriteUInt32ToStream(target, psdLayersSection.Length()); + psdLayersSection.WriteToStream(target); + + // 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 5f428c7..9703d92 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; }; ############################################################################ Revision: hrev46565 Commit: 5a65c29781873d0e3b18ec9bc15f30623d8a6f08 URL: http://cgit.haiku-os.org/haiku/commit/?id=5a65c29 Author: Gerasim Troeglazov <3dEyes@xxxxxxxxx> Date: Thu Dec 19 12:20:14 2013 UTC PSDTranslator: Add RLE compression method for export ---------------------------------------------------------------------------- diff --git a/src/add-ons/translators/psd/PSDTranslator.cpp b/src/add-ons/translators/psd/PSDTranslator.cpp index a4bdbd9..466bad8 100644 --- a/src/add-ons/translators/psd/PSDTranslator.cpp +++ b/src/add-ons/translators/psd/PSDTranslator.cpp @@ -142,6 +142,7 @@ PSDTranslator::DerivedTranslate(BPositionIO *source, { if (outType == PSD_IMAGE_FORMAT) { PSDWriter psdFile(source); + psdFile.SetCompression(PSD_COMPRESSED_RLE); return psdFile.Encode(target); } return B_NO_TRANSLATOR; diff --git a/src/add-ons/translators/psd/PSDWriter.cpp b/src/add-ons/translators/psd/PSDWriter.cpp index dc18ce5..11f68ed 100644 --- a/src/add-ons/translators/psd/PSDWriter.cpp +++ b/src/add-ons/translators/psd/PSDWriter.cpp @@ -74,16 +74,45 @@ PSDWriter::Encode(BPositionIO *target) fStream->Seek(fBitmapDataPos, SEEK_SET); 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 - } + BDataArray psdByteCounts[4]; + + if (fCompression == PSD_COMPRESSED_RAW) { + 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 + } + } else if (fCompression == PSD_COMPRESSED_RLE) { + for (int32 h = 0; h < fHeight; h++) { + BDataArray lineData[4]; + + for (int32 w = 0; w < fWidth; w++) { + uint8 rgba[4]; + fStream->Read(rgba, sizeof(uint32)); + lineData[0].Append((uint8)rgba[2]); // Red channel + lineData[1].Append((uint8)rgba[1]); // Green channel + lineData[2].Append((uint8)rgba[0]); // Blue channel + if (fChannels == 4) + lineData[3].Append((uint8)rgba[3]); // Alpha channel + else + lineData[3].Append((uint8)255); + } + + for (int channelIdx = 0; channelIdx < fChannels; channelIdx++) { + BDataArray *packedLine = PackBits(lineData[channelIdx].Buffer(), + lineData[channelIdx].Length()); + psdByteCounts[channelIdx].Append((uint16)packedLine->Length()); + psdChannel[channelIdx].Append(packedLine->Buffer(), + packedLine->Length()); + delete packedLine; + } + } + } else + return B_NO_TRANSLATOR; // PSD header BDataArray psdHeader(64); @@ -126,13 +155,25 @@ PSDWriter::Encode(BPositionIO *target) psdLayersSection << (uint32)fWidth; psdLayersSection << (uint16)fChannels; - for (int dataChannel = 0; dataChannel < 3; dataChannel++) { - psdLayersSection << (int16)dataChannel; // Channel num - psdLayersSection << (uint32)(psdChannel[dataChannel].Length() + 2); + for (int channelIdx = 0; channelIdx < 3; channelIdx++) { + psdLayersSection << (int16)channelIdx; // Channel num + if (fCompression == PSD_COMPRESSED_RAW) { + psdLayersSection << (uint32)(psdChannel[channelIdx].Length() + + sizeof(int16)); + } else { + psdLayersSection << (uint32)(psdChannel[channelIdx].Length() + + psdByteCounts[channelIdx].Length() + sizeof(int16)); + } } if (fChannels == 4) { psdLayersSection << (int16)-1; // Alpha channel id (-1) - psdLayersSection << (uint32)(psdChannel[4].Length() + 2); + if (fCompression == PSD_COMPRESSED_RAW) { + psdLayersSection << (uint32)(psdChannel[4].Length() + + sizeof(int16)); + } else { + psdLayersSection << (uint32)(psdChannel[4].Length() + + psdByteCounts[4].Length() + sizeof(int16)); + } } psdLayersSection << "8BIM"; psdLayersSection << "norm"; // Blend mode = norm @@ -148,12 +189,27 @@ PSDWriter::Encode(BPositionIO *target) uint8 layerName[16] = {"Layer #1 "}; psdLayersSection.Append(layerName, 15); // Layer name - for (int dataChannel = 0; dataChannel < fChannels; dataChannel++) { - psdLayersSection << fCompression; // Compression mode - psdLayersSection.Append(psdChannel[dataChannel].Buffer(), - psdChannel[dataChannel].Length()); // Layer image data + if (fCompression == PSD_COMPRESSED_RAW) { + for (int channelIdx = 0; channelIdx < fChannels; channelIdx++) { + psdLayersSection << fCompression; // Compression mode + psdLayersSection.Append(psdChannel[channelIdx].Buffer(), + psdChannel[channelIdx].Length()); // Layer image data + } + } else { + for (int channelIdx = 0; channelIdx < fChannels; channelIdx++) { + psdLayersSection << fCompression; // Compression mode + psdLayersSection.Append(psdByteCounts[channelIdx].Buffer(), + psdByteCounts[channelIdx].Length()); // Bytes count + psdLayersSection.Append(psdChannel[channelIdx].Buffer(), + psdChannel[channelIdx].Length()); // Layer image data + } } - + + if (fCompression == PSD_COMPRESSED_RLE + && psdLayersSection.Length() % 2 != 0) { + psdLayersSection << (uint8)0; + } + psdHeader.WriteToStream(target); psdColorModeSection.WriteToStream(target); @@ -161,19 +217,70 @@ PSDWriter::Encode(BPositionIO *target) _WriteUInt32ToStream(target, psdImageResourceSection.Length()); psdImageResourceSection.WriteToStream(target); - _WriteUInt32ToStream(target, psdLayersSection.Length() + 4); + _WriteUInt32ToStream(target, psdLayersSection.Length() + sizeof(int32)); _WriteUInt32ToStream(target, psdLayersSection.Length()); psdLayersSection.WriteToStream(target); // Merged layer _WriteUInt16ToStream(target, fCompression); // Compression mode - for (int dataChannel = 0; dataChannel < fChannels; dataChannel++) - psdChannel[dataChannel].WriteToStream(target); + + if (fCompression == PSD_COMPRESSED_RLE) { + for (int channelIdx = 0; channelIdx < fChannels; channelIdx++) + psdByteCounts[channelIdx].WriteToStream(target); + } + + for (int channelIdx = 0; channelIdx < fChannels; channelIdx++) + psdChannel[channelIdx].WriteToStream(target); return B_OK; } +BDataArray* +PSDWriter::PackBits(uint8 *buff, int32 len) +{ + BDataArray *packedBits = new BDataArray(); + + int32 count = len; + len = 0; + + while (count > 0) { + int i; + for (i = 0; (i < 128) && (buff[0] == buff[i]) && (count - i > 0); i++); + if (i < 2) { + for (i = 0; i < 128; i++) { + bool b1 = buff[i] != buff[i + 1]; + bool b3 = buff[i] != buff[i + 2]; + bool b2 = count - (i + 2) < 1; + if (count - (i + 1) <= 0) + break; + if (!(b1 || b2 || b3)) + break; + } + + if (count == 1) + i = 1; + + if (i > 0) { + packedBits->Append((uint8)(i - 1)); + for (int j = 0; j < i; j++) + packedBits->Append((uint8)buff[j]); + buff += i; + count -= i; + len += (i + 1); + } + } else { + packedBits->Append((uint8)(-(i - 1))); + packedBits->Append((uint8)(*buff)); + buff += i; + count -= i; + len += 2; + } + } + return packedBits; +} + + void PSDWriter::_WriteInt32ToStream(BPositionIO *stream, int32 val) { diff --git a/src/add-ons/translators/psd/PSDWriter.h b/src/add-ons/translators/psd/PSDWriter.h index 9703d92..739add7 100644 --- a/src/add-ons/translators/psd/PSDWriter.h +++ b/src/add-ons/translators/psd/PSDWriter.h @@ -23,6 +23,7 @@ #include <List.h> #include "PSDLoader.h" +#include "DataArray.h" class PSDWriter { public: @@ -44,6 +45,8 @@ private: uint8 val, size_t count); void _WriteBlockToStream(BPositionIO *stream, uint8 *block, size_t count); + + BDataArray* PackBits(uint8 *buff, int32 len); BPositionIO *fStream; size_t fBitmapDataPos;