PSDTranslator: Add RLE compression method for export
This commit is contained in:
@@ -142,6 +142,7 @@ PSDTranslator::DerivedTranslate(BPositionIO *source,
|
|||||||
{
|
{
|
||||||
if (outType == PSD_IMAGE_FORMAT) {
|
if (outType == PSD_IMAGE_FORMAT) {
|
||||||
PSDWriter psdFile(source);
|
PSDWriter psdFile(source);
|
||||||
|
psdFile.SetCompression(PSD_COMPRESSED_RLE);
|
||||||
return psdFile.Encode(target);
|
return psdFile.Encode(target);
|
||||||
}
|
}
|
||||||
return B_NO_TRANSLATOR;
|
return B_NO_TRANSLATOR;
|
||||||
|
|||||||
@@ -74,16 +74,45 @@ PSDWriter::Encode(BPositionIO *target)
|
|||||||
fStream->Seek(fBitmapDataPos, SEEK_SET);
|
fStream->Seek(fBitmapDataPos, SEEK_SET);
|
||||||
|
|
||||||
BDataArray psdChannel[4];
|
BDataArray psdChannel[4];
|
||||||
|
BDataArray psdByteCounts[4];
|
||||||
for (int i = 0; i < channelSize; i++) {
|
|
||||||
uint8 rgba[4];
|
if (fCompression == PSD_COMPRESSED_RAW) {
|
||||||
fStream->Read(rgba, sizeof(uint32));
|
for (int i = 0; i < channelSize; i++) {
|
||||||
psdChannel[0].Append((uint8)rgba[2]); // Red channel
|
uint8 rgba[4];
|
||||||
psdChannel[1].Append((uint8)rgba[1]); // Green channel
|
fStream->Read(rgba, sizeof(uint32));
|
||||||
psdChannel[2].Append((uint8)rgba[0]); // Blue channel
|
psdChannel[0].Append((uint8)rgba[2]); // Red channel
|
||||||
if (fChannels == 4)
|
psdChannel[1].Append((uint8)rgba[1]); // Green channel
|
||||||
psdChannel[3].Append((uint8)rgba[3]); // Alpha 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
|
// PSD header
|
||||||
BDataArray psdHeader(64);
|
BDataArray psdHeader(64);
|
||||||
@@ -126,13 +155,25 @@ PSDWriter::Encode(BPositionIO *target)
|
|||||||
psdLayersSection << (uint32)fWidth;
|
psdLayersSection << (uint32)fWidth;
|
||||||
psdLayersSection << (uint16)fChannels;
|
psdLayersSection << (uint16)fChannels;
|
||||||
|
|
||||||
for (int dataChannel = 0; dataChannel < 3; dataChannel++) {
|
for (int channelIdx = 0; channelIdx < 3; channelIdx++) {
|
||||||
psdLayersSection << (int16)dataChannel; // Channel num
|
psdLayersSection << (int16)channelIdx; // Channel num
|
||||||
psdLayersSection << (uint32)(psdChannel[dataChannel].Length() + 2);
|
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) {
|
if (fChannels == 4) {
|
||||||
psdLayersSection << (int16)-1; // Alpha channel id (-1)
|
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 << "8BIM";
|
||||||
psdLayersSection << "norm"; // Blend mode = norm
|
psdLayersSection << "norm"; // Blend mode = norm
|
||||||
@@ -148,12 +189,27 @@ PSDWriter::Encode(BPositionIO *target)
|
|||||||
uint8 layerName[16] = {"Layer #1 "};
|
uint8 layerName[16] = {"Layer #1 "};
|
||||||
psdLayersSection.Append(layerName, 15); // Layer name
|
psdLayersSection.Append(layerName, 15); // Layer name
|
||||||
|
|
||||||
for (int dataChannel = 0; dataChannel < fChannels; dataChannel++) {
|
if (fCompression == PSD_COMPRESSED_RAW) {
|
||||||
psdLayersSection << fCompression; // Compression mode
|
for (int channelIdx = 0; channelIdx < fChannels; channelIdx++) {
|
||||||
psdLayersSection.Append(psdChannel[dataChannel].Buffer(),
|
psdLayersSection << fCompression; // Compression mode
|
||||||
psdChannel[dataChannel].Length()); // Layer image data
|
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);
|
psdHeader.WriteToStream(target);
|
||||||
|
|
||||||
psdColorModeSection.WriteToStream(target);
|
psdColorModeSection.WriteToStream(target);
|
||||||
@@ -161,19 +217,70 @@ PSDWriter::Encode(BPositionIO *target)
|
|||||||
_WriteUInt32ToStream(target, psdImageResourceSection.Length());
|
_WriteUInt32ToStream(target, psdImageResourceSection.Length());
|
||||||
psdImageResourceSection.WriteToStream(target);
|
psdImageResourceSection.WriteToStream(target);
|
||||||
|
|
||||||
_WriteUInt32ToStream(target, psdLayersSection.Length() + 4);
|
_WriteUInt32ToStream(target, psdLayersSection.Length() + sizeof(int32));
|
||||||
_WriteUInt32ToStream(target, psdLayersSection.Length());
|
_WriteUInt32ToStream(target, psdLayersSection.Length());
|
||||||
psdLayersSection.WriteToStream(target);
|
psdLayersSection.WriteToStream(target);
|
||||||
|
|
||||||
// Merged layer
|
// Merged layer
|
||||||
_WriteUInt16ToStream(target, fCompression); // Compression mode
|
_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;
|
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
|
void
|
||||||
PSDWriter::_WriteInt32ToStream(BPositionIO *stream, int32 val)
|
PSDWriter::_WriteInt32ToStream(BPositionIO *stream, int32 val)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -23,6 +23,7 @@
|
|||||||
#include <List.h>
|
#include <List.h>
|
||||||
|
|
||||||
#include "PSDLoader.h"
|
#include "PSDLoader.h"
|
||||||
|
#include "DataArray.h"
|
||||||
|
|
||||||
class PSDWriter {
|
class PSDWriter {
|
||||||
public:
|
public:
|
||||||
@@ -44,6 +45,8 @@ private:
|
|||||||
uint8 val, size_t count);
|
uint8 val, size_t count);
|
||||||
void _WriteBlockToStream(BPositionIO *stream,
|
void _WriteBlockToStream(BPositionIO *stream,
|
||||||
uint8 *block, size_t count);
|
uint8 *block, size_t count);
|
||||||
|
|
||||||
|
BDataArray* PackBits(uint8 *buff, int32 len);
|
||||||
|
|
||||||
BPositionIO *fStream;
|
BPositionIO *fStream;
|
||||||
size_t fBitmapDataPos;
|
size_t fBitmapDataPos;
|
||||||
|
|||||||
Reference in New Issue
Block a user