[prev in list] [next in list] [prev in thread] [next in thread]
List: kde-commits
Subject: [calligra/calligra/2.9] krita/plugins/formats/psd: Make PSD pixel data saving code be shared between
From: Dmitry Kazakov <dimula73 () gmail ! com>
Date: 2015-08-13 17:15:20
Message-ID: E1ZPw64-0001eb-AD () scm ! kde ! org
[Download RAW message or body]
Git commit f3e3cb3596c2970e424b57430a53eb4ca0320d04 by Dmitry Kazakov.
Committed on 13/08/2015 at 15:46.
Pushed by dkazakov into branch 'calligra/2.9'.
Make PSD pixel data saving code be shared between KisImageData and KisLayerRecord
It also fixes a set of loading/saving bugs we had
M +23 -83 krita/plugins/formats/psd/psd_image_data.cpp
M +1 -1 krita/plugins/formats/psd/psd_image_data.h
M +26 -117 krita/plugins/formats/psd/psd_layer_record.cpp
M +2 -5 krita/plugins/formats/psd/psd_layer_record.h
M +173 -0 krita/plugins/formats/psd/psd_pixel_utils.cpp
M +28 -0 krita/plugins/formats/psd/psd_pixel_utils.h
M +8 -5 krita/plugins/formats/psd/psd_saver.cpp
http://commits.kde.org/calligra/f3e3cb3596c2970e424b57430a53eb4ca0320d04
diff --git a/krita/plugins/formats/psd/psd_image_data.cpp \
b/krita/plugins/formats/psd/psd_image_data.cpp index f609110..693f143 100644
--- a/krita/plugins/formats/psd/psd_image_data.cpp
+++ b/krita/plugins/formats/psd/psd_image_data.cpp
@@ -149,7 +149,7 @@ bool PSDImageData::read(QIODevice *io, KisPaintDeviceSP dev ) {
return true;
}
-bool PSDImageData::write(QIODevice *io, KisPaintDeviceSP dev)
+bool PSDImageData::write(QIODevice *io, KisPaintDeviceSP dev, bool hasAlpha)
{
// XXX: make the compression settting configurable. For now, always use RLE.
psdwrite(io, (quint16)Compression::RLE);
@@ -157,93 +157,33 @@ bool PSDImageData::write(QIODevice *io, KisPaintDeviceSP dev)
// now write all the channels in display order
// fill in the channel chooser, in the display order, but store the pixel index as well.
QRect rc(0, 0, m_header->width, m_header->height);
- QVector<quint8* > tmp = dev->readPlanarBytes(0, 0, rc.width(), rc.height());
- // then reorder the planes to fit the psd model -- alpha first, then display order
- QVector<quint8* > planes;
- QList<KoChannelInfo*> origChannels = dev->colorSpace()->channels();
-
- quint8* alphaPlane = 0;
- foreach(KoChannelInfo *ch, KoChannelInfo::displayOrderSorted(origChannels)) {
- int channelIndex = KoChannelInfo::displayPositionToChannelIndex(ch->displayPosition(), \
origChannels);
- //qDebug() << ppVar(ch->name()) << ppVar(ch->pos()) << ppVar(ch->displayPosition()) << \
ppVar(channelIndex);
- if (ch->channelType() == KoChannelInfo::ALPHA) {
- alphaPlane = tmp[channelIndex];
- } else {
- planes.append(tmp[channelIndex]);
- }
- }
- planes.append(alphaPlane); // alpha is last, in contrast with layers, where it's first.
- // now planes are holding pointers to quint8 arrays
- tmp.clear();
-
- // Now fix up the cmyk channels, we need to invert them
- if (m_header->colormode == CMYK || m_header->colormode == CMYK64) {
- for (int i = 0; i < 4; ++i) {
- if (m_header->channelDepth == 8) {
- for (int j = 0; j < rc.width() * rc.height(); ++j) {
- planes[i][j] = 255 - planes[i][j];
- }
- }
- else if (m_header->channelDepth == 16) {
- quint16 val;
- for (int j = 0; j < rc.width() * rc.height(); ++j) {
- val = reinterpret_cast<quint16*>(planes[i])[j];
- val = quint16_MAX - ntohs(val);
- reinterpret_cast<quint16*>(planes[i])[j] = val;
- }
- }
- }
- }
- quint64 channelLengthPos = io->pos();
- // write zero's for the channel lengths section
- for (uint i = 0; i < dev->colorSpace()->channelCount() * rc.height(); ++i) {
- psdwrite(io, (quint16)0);
- }
- // here the actual channel data starts
- quint64 channelStartPos = io->pos();
-
- for (int channelInfoIndex = 0; channelInfoIndex < planes.size(); ++channelInfoIndex) {
- quint8 *plane = planes[channelInfoIndex];
-
- quint32 stride = (m_header->channelDepth / 8) * rc.width();
- for (qint32 row = 0; row < rc.height(); ++row) {
-
- QByteArray uncompressed = QByteArray::fromRawData((const char*)plane + row * \
stride, stride);
- if (m_header->channelDepth == 8) {
- } else if (m_header->channelDepth == 16) {
- quint16 *dataPtr = reinterpret_cast<quint16 *>(uncompressed.data());
- for (int i = 0; i < rc.width(); i++) {
- quint16 val = htons(*dataPtr);
- *dataPtr = val;
- ++dataPtr;
- }
- } else if (m_header->channelDepth == 32) {
- quint32 *dataPtr = reinterpret_cast<quint32 *>(uncompressed.data());
- for (int i = 0; i < rc.width(); i++) {
- quint32 val = htonl(*dataPtr);
- *dataPtr = val;
- ++dataPtr;
- }
- }
- QByteArray compressed = Compression::compress(uncompressed, Compression::RLE);
+ const int channelSize = m_header->channelDepth / 8;
+ const psd_color_mode colorMode = m_header->colormode;
- io->seek(channelLengthPos);
- psdwrite(io, (quint16)compressed.size());
- channelLengthPos +=2;
- io->seek(channelStartPos);
+ QVector<PsdPixelUtils::ChannelWritingInfo> writingInfoList;
- if (io->write(compressed) != compressed.size()) {
- error = "Could not write image data";
- return false;
- }
+ bool writeAlpha = hasAlpha &&
+ dev->colorSpace()->channelCount() != dev->colorSpace()->colorChannelCount();
- channelStartPos += compressed.size();
- }
- }
+ const int numChannels =
+ writeAlpha ?
+ dev->colorSpace()->channelCount() :
+ dev->colorSpace()->colorChannelCount();
- qDeleteAll(planes);
- planes.clear();
+ for (int i = 0; i < numChannels; i++) {
+ const int rleOffset = io->pos();
+
+ int channelId = writeAlpha && i == numChannels - 1 ? -1 : i;
+
+ writingInfoList <<
+ PsdPixelUtils::ChannelWritingInfo(channelId, -1, rleOffset);
+
+ io->seek(io->pos() + rc.height() * sizeof(quint16));
+ }
+ PsdPixelUtils::writePixelDataCommon(io, dev, rc,
+ colorMode, channelSize,
+ false, false, writingInfoList);
return true;
}
diff --git a/krita/plugins/formats/psd/psd_image_data.h \
b/krita/plugins/formats/psd/psd_image_data.h index 8d7c294..61529bc 100644
--- a/krita/plugins/formats/psd/psd_image_data.h
+++ b/krita/plugins/formats/psd/psd_image_data.h
@@ -38,7 +38,7 @@ public:
virtual ~PSDImageData();
bool read(QIODevice *io, KisPaintDeviceSP dev);
- bool write(QIODevice *io, KisPaintDeviceSP dev);
+ bool write(QIODevice *io, KisPaintDeviceSP dev, bool hasAlpha);
QString error;
diff --git a/krita/plugins/formats/psd/psd_layer_record.cpp \
b/krita/plugins/formats/psd/psd_layer_record.cpp index b7b391c..c572147 100644
--- a/krita/plugins/formats/psd/psd_layer_record.cpp
+++ b/krita/plugins/formats/psd/psd_layer_record.cpp
@@ -587,36 +587,6 @@ void PSDLayerRecord::write(QIODevice* io,
}
}
-void writeChannelDataRLE(QIODevice *io, const quint8 *plane, const int channelSize, const \
QRect &rc, const qint64 sizeFieldOffset)
-{
- KisAslWriterUtils::OffsetStreamPusher<quint32> channelBlockSizeExternalTag(io, 0, \
sizeFieldOffset);
-
- SAFE_WRITE_EX(io, (quint16)Compression::RLE);
-
- // the start of RLE sizes block
- const qint64 channelRLESizePos = io->pos();
-
- // write zero's for the channel lengths block
- for(int i = 0; i < rc.height(); ++i) {
- // XXX: choose size for PSB!
- const quint16 fakeRLEBLockSize = 0;
- SAFE_WRITE_EX(io, fakeRLEBLockSize);
- }
-
- quint32 stride = channelSize * rc.width();
- for (qint32 row = 0; row < rc.height(); ++row) {
-
- QByteArray uncompressed = QByteArray::fromRawData((const char*)plane + row * stride, \
stride);
- QByteArray compressed = Compression::compress(uncompressed, Compression::RLE);
-
- KisAslWriterUtils::OffsetStreamPusher<quint16> rleExternalTag(io, 0, channelRLESizePos \
+ row * sizeof(quint16));
-
- if (io->write(compressed) != compressed.size()) {
- throw KisAslWriterUtils::ASLWriteException("Failed to write image data");
- }
- }
-}
-
void PSDLayerRecord::writeTransparencyMaskPixelData(QIODevice *io)
{
if (m_onlyTransparencyMask) {
@@ -626,116 +596,55 @@ void PSDLayerRecord::writeTransparencyMaskPixelData(QIODevice *io)
QByteArray buffer(m_onlyTransparencyMaskRect.width() * \
m_onlyTransparencyMaskRect.height(), 0);
device->readBytes((quint8*)buffer.data(), m_onlyTransparencyMaskRect);
- writeChannelDataRLE(io, (quint8*)buffer.data(), 1, m_onlyTransparencyMaskRect, \
m_transparencyMaskSizeOffset); + PsdPixelUtils::writeChannelDataRLE(io, \
(quint8*)buffer.data(), 1, m_onlyTransparencyMaskRect, m_transparencyMaskSizeOffset, -1, true); \
} }
void PSDLayerRecord::writePixelData(QIODevice *io)
{
+ try {
+ writePixelDataImpl(io);
+ } catch (KisAslWriterUtils::ASLWriteException &e) {
+ throw KisAslWriterUtils::ASLWriteException(PREPEND_METHOD(e.what()));
+ }
+}
+
+void PSDLayerRecord::writePixelDataImpl(QIODevice *io)
+{
dbgFile << "writing pixel data for layer" << layerName << "at" << io->pos();
KisPaintDeviceSP dev = m_layerContentDevice;
const QRect rc(left, top, right - left, bottom - top);
if (rc.isEmpty()) {
- try {
- dbgFile << "Layer is empty! Writing placeholder information.";
+ dbgFile << "Layer is empty! Writing placeholder information.";
- for (int i = 0; i < nChannels; i++) {
- const ChannelInfo *channelInfo = channelInfoRecords[i];
- KisAslWriterUtils::OffsetStreamPusher<quint32> channelBlockSizeExternalTag(io, \
0, channelInfo->channelInfoPosition);
- SAFE_WRITE_EX(io, (quint16)Compression::Uncompressed);
- }
-
- writeTransparencyMaskPixelData(io);
-
- } catch (KisAslWriterUtils::ASLWriteException &e) {
- throw KisAslWriterUtils::ASLWriteException(PREPEND_METHOD(e.what()));
+ for (int i = 0; i < nChannels; i++) {
+ const ChannelInfo *channelInfo = channelInfoRecords[i];
+ KisAslWriterUtils::OffsetStreamPusher<quint32> channelBlockSizeExternalTag(io, 0, \
channelInfo->channelInfoPosition); + SAFE_WRITE_EX(io, \
(quint16)Compression::Uncompressed); }
+ writeTransparencyMaskPixelData(io);
+
return;
}
// now write all the channels in display order
dbgFile << "layer" << layerName;
- QVector<quint8* > tmp = dev->readPlanarBytes(rc.x() - dev->x(), rc.y() - dev->y(), \
rc.width(), rc.height());
-
- // then reorder the planes to fit the psd model -- alpha first, then display order
- QVector<quint8*> planes;
- QList<KoChannelInfo*> origChannels = dev->colorSpace()->channels();
-
- foreach(KoChannelInfo *ch, KoChannelInfo::displayOrderSorted(origChannels)) {
- int channelIndex = KoChannelInfo::displayPositionToChannelIndex(ch->displayPosition(), \
origChannels);
- quint8 *holder = tmp[channelIndex];
- tmp[channelIndex] = 0;
-
- if (ch->channelType() == KoChannelInfo::ALPHA) {
- planes.insert(0, holder);
- } else {
- planes.append(holder);
- }
- }
-
- // now planes are holding pointers to quint8 arrays
- tmp.clear();
-
- try {
- // here's where we save the total size of the channel data
- for (int channelInfoIndex = 0; channelInfoIndex < nChannels; ++channelInfoIndex) {
-
- const ChannelInfo *channelInfo = channelInfoRecords[channelInfoIndex];
-
- dbgFile << "\tWriting channel" << channelInfoIndex << "psd channel id" << \
channelInfo->channelId;
-
- // if the bitdepth > 8, place the bytes in the right order
- // if cmyk, invert the pixel value
- if (m_header.channelDepth == 8) {
- if (channelInfo->channelId >= 0 && (m_header.colormode == CMYK || \
m_header.colormode == CMYK64)) {
- for (int i = 0; i < rc.width() * rc.height(); ++i) {
- planes[channelInfoIndex][i] = 255 - planes[channelInfoIndex][i];
- }
- }
- }
- else if (m_header.channelDepth == 16) {
- quint16 val;
- for (int i = 0; i < rc.width() * rc.height(); ++i) {
- val = reinterpret_cast<quint16*>(planes[channelInfoIndex])[i];
- val = ntohs(val);
- if (channelInfo->channelId >= 0 && (m_header.colormode == CMYK || \
m_header.colormode == CMYK64)) {
- val = quint16_MAX - val;
- }
- reinterpret_cast<quint16*>(planes[channelInfoIndex])[i] = val;
- }
- }
- else if (m_header.channelDepth == 32) {
- quint32 val;
- for (int i = 0; i < rc.width() * rc.height(); ++i) {
- val = reinterpret_cast<quint32*>(planes[channelInfoIndex])[i];
- val = ntohl(val);
- if (channelInfo->channelId >= 0 && (m_header.colormode == CMYK || \
m_header.colormode == CMYK64)) {
- val = quint16_MAX - val;
- }
- reinterpret_cast<quint32*>(planes[channelInfoIndex])[i] = val;
- }
- }
-
- dbgFile << "\t\tchannel start" << ppVar(io->pos());
-
- writeChannelDataRLE(io, planes[channelInfoIndex], m_header.channelDepth / 8, rc, \
channelInfo->channelInfoPosition);
- }
-
- writeTransparencyMaskPixelData(io);
-
- } catch (KisAslWriterUtils::ASLWriteException &e) {
- qDeleteAll(planes);
- planes.clear();
+ const int channelSize = m_header.channelDepth / 8;
+ const psd_color_mode colorMode = m_header.colormode;
- throw KisAslWriterUtils::ASLWriteException(PREPEND_METHOD(e.what()));
+ QVector<PsdPixelUtils::ChannelWritingInfo> writingInfoList;
+ foreach (const ChannelInfo *channelInfo, channelInfoRecords) {
+ writingInfoList <<
+ PsdPixelUtils::ChannelWritingInfo(channelInfo->channelId,
+ channelInfo->channelInfoPosition);
}
- qDeleteAll(planes);
- planes.clear();
+ PsdPixelUtils::writePixelDataCommon(io, dev, rc, colorMode, channelSize, true, true, \
writingInfoList); + writeTransparencyMaskPixelData(io);
}
bool PSDLayerRecord::valid()
diff --git a/krita/plugins/formats/psd/psd_layer_record.h \
b/krita/plugins/formats/psd/psd_layer_record.h index a58a3e83..3270eca 100644
--- a/krita/plugins/formats/psd/psd_layer_record.h
+++ b/krita/plugins/formats/psd/psd_layer_record.h
@@ -158,12 +158,9 @@ public:
private:
void writeTransparencyMaskPixelData(QIODevice *io);
-private:
+ void writePixelDataImpl(QIODevice *io);
- bool readRGB(KisPaintDeviceSP dev ,QIODevice *io);
- bool readCMYK(KisPaintDeviceSP dev ,QIODevice *io);
- bool readLAB(KisPaintDeviceSP dev ,QIODevice *io);
- bool readGray(KisPaintDeviceSP dev ,QIODevice *io);
+private:
KisPaintDeviceSP m_layerContentDevice;
KisNodeSP m_onlyTransparencyMask;
diff --git a/krita/plugins/formats/psd/psd_pixel_utils.cpp \
b/krita/plugins/formats/psd/psd_pixel_utils.cpp index 50be4b9..a9b4884 100644
--- a/krita/plugins/formats/psd/psd_pixel_utils.cpp
+++ b/krita/plugins/formats/psd/psd_pixel_utils.cpp
@@ -30,6 +30,7 @@
#include <netinet/in.h> // htonl
+#include <asl/kis_asl_writer_utils.h>
#include <asl/kis_asl_reader_utils.h>
#include "psd_layer_record.h"
@@ -349,4 +350,176 @@ void readChannels(QIODevice *io,
throw KisAslReaderUtils::ASLParseException(error);
}
}
+
+void writeChannelDataRLE(QIODevice *io, const quint8 *plane, const int channelSize, const \
QRect &rc, const qint64 sizeFieldOffset, const qint64 rleBlockOffset, const bool \
writeCompressionType) +{
+ typedef KisAslWriterUtils::OffsetStreamPusher<quint32> Pusher;
+ QScopedPointer<Pusher> channelBlockSizeExternalTag;
+ if (sizeFieldOffset >= 0) {
+ channelBlockSizeExternalTag.reset(new Pusher(io, 0, sizeFieldOffset));
+ }
+
+ if (writeCompressionType) {
+ SAFE_WRITE_EX(io, (quint16)Compression::RLE);
+ }
+
+ const bool externalRleBlock = rleBlockOffset >= 0;
+
+ // the start of RLE sizes block
+ const qint64 channelRLESizePos = externalRleBlock ? rleBlockOffset : io->pos();
+
+ {
+ QScopedPointer<KisOffsetKeeper> rleOffsetKeeper;
+
+ if (externalRleBlock) {
+ rleOffsetKeeper.reset(new KisOffsetKeeper(io));
+ io->seek(rleBlockOffset);
+ }
+
+ // write zero's for the channel lengths block
+ for(int i = 0; i < rc.height(); ++i) {
+ // XXX: choose size for PSB!
+ const quint16 fakeRLEBLockSize = 0;
+ SAFE_WRITE_EX(io, fakeRLEBLockSize);
+ }
+ }
+
+ quint32 stride = channelSize * rc.width();
+ for (qint32 row = 0; row < rc.height(); ++row) {
+
+ QByteArray uncompressed = QByteArray::fromRawData((const char*)plane + row * stride, \
stride); + QByteArray compressed = Compression::compress(uncompressed, \
Compression::RLE); +
+ KisAslWriterUtils::OffsetStreamPusher<quint16> rleExternalTag(io, 0, channelRLESizePos \
+ row * sizeof(quint16)); +
+ if (io->write(compressed) != compressed.size()) {
+ throw KisAslWriterUtils::ASLWriteException("Failed to write image data");
+ }
+ }
+}
+
+inline void preparePixelForWrite(quint8 *dataPlane,
+ int numPixels,
+ int channelSize,
+ int channelId,
+ psd_color_mode colorMode)
+{
+ // if the bitdepth > 8, place the bytes in the right order
+ // if cmyk, invert the pixel value
+ if (channelSize == 1) {
+ if (channelId >= 0 && (colorMode == CMYK || colorMode == CMYK64)) {
+ for (int i = 0; i < numPixels; ++i) {
+ dataPlane[i] = 255 - dataPlane[i];
+ }
+ }
+ }
+ else if (channelSize == 2) {
+ quint16 val;
+ for (int i = 0; i < numPixels; ++i) {
+ quint16 *pixelPtr = reinterpret_cast<quint16*>(dataPlane) + i;
+
+ val = *pixelPtr;
+ val = ntohs(val);
+ if (channelId >= 0 && (colorMode == CMYK || colorMode == CMYK64)) {
+ val = quint16_MAX - val;
+ }
+ *pixelPtr = val;
+ }
+ }
+ else if (channelSize == 4) {
+ quint32 val;
+ for (int i = 0; i < numPixels; ++i) {
+ quint32 *pixelPtr = reinterpret_cast<quint32*>(dataPlane) + i;
+
+ val = *pixelPtr;
+ val = ntohl(val);
+ if (channelId >= 0 && (colorMode == CMYK || colorMode == CMYK64)) {
+ val = quint16_MAX - val;
+ }
+ *pixelPtr = val;
+ }
+ }
+}
+
+void writePixelDataCommon(QIODevice *io,
+ KisPaintDeviceSP dev,
+ const QRect &rc,
+ psd_color_mode colorMode,
+ int channelSize,
+ bool alphaFirst,
+ const bool writeCompressionType,
+ QVector<ChannelWritingInfo> &writingInfoList)
+{
+ // Empty rects must be processed separately on a higher level!
+ KIS_ASSERT_RECOVER_RETURN(!rc.isEmpty());
+
+ QVector<quint8* > tmp = dev->readPlanarBytes(rc.x() - dev->x(), rc.y() - dev->y(), \
rc.width(), rc.height()); + const KoColorSpace *colorSpace = dev->colorSpace();
+
+ QVector<quint8*> planes;
+
+ { // prepare 'planes' array
+
+ quint8 *alphaPlanePtr = 0;
+
+ QList<KoChannelInfo*> origChannels = colorSpace->channels();
+ foreach(KoChannelInfo *ch, KoChannelInfo::displayOrderSorted(origChannels)) {
+ int channelIndex = \
KoChannelInfo::displayPositionToChannelIndex(ch->displayPosition(), origChannels); +
+ quint8 *holder = 0;
+ qSwap(holder, tmp[channelIndex]);
+
+ if (ch->channelType() == KoChannelInfo::ALPHA) {
+ qSwap(holder, alphaPlanePtr);
+ } else {
+ planes.append(holder);
+ }
+ }
+
+ if (alphaPlanePtr) {
+ if (alphaFirst) {
+ planes.insert(0, alphaPlanePtr);
+ KIS_ASSERT_RECOVER_NOOP(writingInfoList.first().channelId == -1);
+ } else {
+ planes.append(alphaPlanePtr);
+ KIS_ASSERT_RECOVER_NOOP(
+ (writingInfoList.size() == planes.size() - 1) ||
+ (writingInfoList.last().channelId == -1));
+ }
+ }
+
+ // now planes are holding pointers to quint8 arrays
+ tmp.clear();
+ }
+
+ KIS_ASSERT_RECOVER_RETURN(planes.size() >= writingInfoList.size());
+
+ const int numPixels = rc.width() * rc.height();
+
+ // write down the planes
+
+ try {
+ for (int i = 0; i < writingInfoList.size(); i++) {
+ const ChannelWritingInfo &info = writingInfoList[i];
+
+ dbgFile << "\tWriting channel" << i << "psd channel id" << info.channelId;
+
+ preparePixelForWrite(planes[i], numPixels, channelSize, info.channelId, \
colorMode); +
+ dbgFile << "\t\tchannel start" << ppVar(io->pos());
+
+ writeChannelDataRLE(io, planes[i], channelSize, rc, info.sizeFieldOffset, \
info.rleBlockOffset, writeCompressionType); + }
+
+ } catch (KisAslWriterUtils::ASLWriteException &e) {
+ qDeleteAll(planes);
+ planes.clear();
+
+ throw KisAslWriterUtils::ASLWriteException(PREPEND_METHOD(e.what()));
+ }
+
+ qDeleteAll(planes);
+ planes.clear();
+}
+
}
diff --git a/krita/plugins/formats/psd/psd_pixel_utils.h \
b/krita/plugins/formats/psd/psd_pixel_utils.h index 4af352f..a1c93b6 100644
--- a/krita/plugins/formats/psd/psd_pixel_utils.h
+++ b/krita/plugins/formats/psd/psd_pixel_utils.h
@@ -27,10 +27,21 @@
class QIODevice;
struct ChannelInfo;
+struct ChannelWritingInfo;
namespace PsdPixelUtils
{
+ struct ChannelWritingInfo {
+ ChannelWritingInfo() : channelId(0), sizeFieldOffset(-1), rleBlockOffset(-1) {}
+ ChannelWritingInfo(qint16 _channelId, int _sizeFieldOffset) : channelId(_channelId), \
sizeFieldOffset(_sizeFieldOffset), rleBlockOffset(-1) {} + ChannelWritingInfo(qint16 \
_channelId, int _sizeFieldOffset, int _rleBlockOffset) : channelId(_channelId), \
sizeFieldOffset(_sizeFieldOffset), rleBlockOffset(_rleBlockOffset) {} +
+ qint16 channelId;
+ int sizeFieldOffset;
+ int rleBlockOffset;
+ };
+
void readChannels(QIODevice *io,
KisPaintDeviceSP device,
psd_color_mode colorMode,
@@ -38,6 +49,23 @@ namespace PsdPixelUtils
const QRect &layerRect,
QVector<ChannelInfo*> infoRecords);
+ void writeChannelDataRLE(QIODevice *io,
+ const quint8 *plane,
+ const int channelSize,
+ const QRect &rc,
+ const qint64 sizeFieldOffset,
+ const qint64 rleBlockOffset,
+ const bool writeCompressionType);
+
+ void writePixelDataCommon(QIODevice *io,
+ KisPaintDeviceSP dev,
+ const QRect &rc,
+ psd_color_mode colorMode,
+ int channelSize,
+ bool alphaFirst,
+ const bool writeCompressionType,
+ QVector<ChannelWritingInfo> &writingInfoList);
+
}
#endif /* __PSD_PIXEL_UTILS_H */
diff --git a/krita/plugins/formats/psd/psd_saver.cpp b/krita/plugins/formats/psd/psd_saver.cpp
index 9098f67..f9b44c0 100644
--- a/krita/plugins/formats/psd/psd_saver.cpp
+++ b/krita/plugins/formats/psd/psd_saver.cpp
@@ -142,11 +142,17 @@ KisImageBuilder_Result PSDSaver::buildFile(const KUrl& uri)
return KisImageBuilder_RESULT_NOT_LOCAL;
}
+ const bool haveLayers = m_image->rootLayer()->childCount() > 1 ||
+ checkIfHasTransparency(m_image->rootLayer()->firstChild()->projection());
+
// HEADER
PSDHeader header;
header.signature = "8BPS";
header.version = 1;
- header.nChannels = m_image->colorSpace()->channelCount();
+ header.nChannels = haveLayers ?
+ m_image->colorSpace()->channelCount() :
+ m_image->colorSpace()->colorChannelCount();
+
header.width = m_image->width();
header.height = m_image->height();
@@ -240,9 +246,6 @@ KisImageBuilder_Result PSDSaver::buildFile(const KUrl& uri)
// Only save layers and masks if there is more than one layer
dbgFile << "m_image->rootLayer->childCount" << m_image->rootLayer()->childCount() << \
f.pos();
- bool haveLayers = m_image->rootLayer()->childCount() > 1 ||
- checkIfHasTransparency(m_image->rootLayer()->firstChild()->projection());
-
if (haveLayers) {
PSDLayerMaskSection layerSection(header);
@@ -262,7 +265,7 @@ KisImageBuilder_Result PSDSaver::buildFile(const KUrl& uri)
// IMAGE DATA
dbgFile << "Saving composited image" << f.pos();
PSDImageData imagedata(&header);
- if (!imagedata.write(&f, m_image->projection())) {
+ if (!imagedata.write(&f, m_image->projection(), haveLayers)) {
dbgFile << "Failed to write image data. Error:" << imagedata.error;
return KisImageBuilder_RESULT_FAILURE;
}
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic