44 return qFromBigEndian((quint16)
value);
50 return qFromBigEndian((quint32)
value);
62 return qFromBigEndian((quint16)
value);
68 return qFromBigEndian((quint32)
value);
80 return qFromBigEndian((quint16)
value);
86 return qFromBigEndian((quint32)
value);
98 return qFromBigEndian((quint16)
value);
104 return qFromBigEndian((quint32)
value);
116 return qFromBigEndian((quint16)
value);
122 return qFromBigEndian((quint32)
value);
125template<
class Traits>
143 return static_cast<quint8
>(
value * 255U);
146template<
class Traits, psd_
byte_order
byteOrder = psd_
byte_order::psdBigEndian>
149 using channels_type =
typename Traits::channels_type;
151 const channels_type data =
reinterpret_cast<const channels_type *
>(channelBytes.first().constData())[col];
153 *dstPtr = truncateToOpacity<Traits>(convertByteOrder<Traits>(data));
155 *dstPtr = truncateToOpacity<Traits>(data);
159template<
class Traits, psd_
byte_order
byteOrder = psd_
byte_order::psdBigEndian>
160inline typename Traits::channels_type
161readChannelValue(
const QMap<quint16, QByteArray> &channelBytes, quint16 channelId,
int col,
typename Traits::channels_type defaultValue)
163 using channels_type =
typename Traits::channels_type;
165 if (channelBytes.contains(channelId)) {
166 const QByteArray &bytes = channelBytes[channelId];
167 if (col < bytes.size()) {
168 const channels_type data =
reinterpret_cast<const channels_type *
>(bytes.constData())[col];
170 return convertByteOrder<Traits>(data);
176 dbgFile <<
"col index out of range channelId: " << channelId <<
" col:" << col;
182template<
class Traits, psd_
byte_order
byteOrder = psd_
byte_order::psdBigEndian>
183void readGrayPixel(
const QMap<quint16, QByteArray> &channelBytes,
int col, quint8 *dstPtr)
185 using Pixel =
typename Traits::Pixel;
186 using channels_type =
typename Traits::channels_type;
189 Pixel *pixelPtr =
reinterpret_cast<Pixel *
>(dstPtr);
191 pixelPtr->gray = readChannelValue<Traits, byteOrder>(channelBytes, 0, col, unitValue);
192 pixelPtr->alpha = readChannelValue<Traits, byteOrder>(channelBytes, -1, col, unitValue);
195template<
class Traits, psd_
byte_order
byteOrder = psd_
byte_order::psdBigEndian>
196void readRgbPixel(
const QMap<quint16, QByteArray> &channelBytes,
int col, quint8 *dstPtr)
198 using Pixel =
typename Traits::Pixel;
199 using channels_type =
typename Traits::channels_type;
202 Pixel *pixelPtr =
reinterpret_cast<Pixel *
>(dstPtr);
204 pixelPtr->blue = readChannelValue<Traits, byteOrder>(channelBytes, 2, col, unitValue);
205 pixelPtr->green = readChannelValue<Traits, byteOrder>(channelBytes, 1, col, unitValue);
206 pixelPtr->red = readChannelValue<Traits, byteOrder>(channelBytes, 0, col, unitValue);
207 pixelPtr->alpha = readChannelValue<Traits, byteOrder>(channelBytes, -1, col, unitValue);
210template<
class Traits, psd_
byte_order
byteOrder = psd_
byte_order::psdBigEndian>
211void readCmykPixel(
const QMap<quint16, QByteArray> &channelBytes,
int col, quint8 *dstPtr)
213 using Pixel =
typename Traits::Pixel;
214 using channels_type =
typename Traits::channels_type;
217 Pixel *pixelPtr =
reinterpret_cast<Pixel *
>(dstPtr);
219 pixelPtr->cyan = unitValue - readChannelValue<Traits, byteOrder>(channelBytes, 0, col, unitValue);
220 pixelPtr->magenta = unitValue - readChannelValue<Traits, byteOrder>(channelBytes, 1, col, unitValue);
221 pixelPtr->yellow = unitValue - readChannelValue<Traits, byteOrder>(channelBytes, 2, col, unitValue);
222 pixelPtr->black = unitValue - readChannelValue<Traits, byteOrder>(channelBytes, 3, col, unitValue);
223 pixelPtr->alpha = readChannelValue<Traits, byteOrder>(channelBytes, -1, col, unitValue);
226template<
class Traits, psd_
byte_order
byteOrder = psd_
byte_order::psdBigEndian>
227void readLabPixel(
const QMap<quint16, QByteArray> &channelBytes,
int col, quint8 *dstPtr)
229 using Pixel =
typename Traits::Pixel;
230 using channels_type =
typename Traits::channels_type;
233 Pixel *pixelPtr =
reinterpret_cast<Pixel *
>(dstPtr);
235 pixelPtr->L = readChannelValue<Traits, byteOrder>(channelBytes, 0, col, unitValue);
236 pixelPtr->a = readChannelValue<Traits, byteOrder>(channelBytes, 1, col, unitValue);
237 pixelPtr->b = readChannelValue<Traits, byteOrder>(channelBytes, 2, col, unitValue);
238 pixelPtr->alpha = readChannelValue<Traits, byteOrder>(channelBytes, -1, col, unitValue);
241template<psd_
byte_order
byteOrder>
242void readRgbPixelCommon(
int channelSize,
const QMap<quint16, QByteArray> &channelBytes,
int col, quint8 *dstPtr)
244 if (channelSize == 1) {
245 readRgbPixel<KoBgrU8Traits, byteOrder>(channelBytes, col, dstPtr);
246 }
else if (channelSize == 2) {
247 readRgbPixel<KoBgrU16Traits, byteOrder>(channelBytes, col, dstPtr);
248 }
else if (channelSize == 4) {
249 readRgbPixel<KoBgrU16Traits, byteOrder>(channelBytes, col, dstPtr);
253template<psd_
byte_order
byteOrder>
254void readGrayPixelCommon(
int channelSize,
const QMap<quint16, QByteArray> &channelBytes,
int col, quint8 *dstPtr)
256 if (channelSize == 1) {
257 readGrayPixel<KoGrayU8Traits, byteOrder>(channelBytes, col, dstPtr);
258 }
else if (channelSize == 2) {
259 readGrayPixel<KoGrayU16Traits, byteOrder>(channelBytes, col, dstPtr);
260 }
else if (channelSize == 4) {
261 readGrayPixel<KoGrayU32Traits, byteOrder>(channelBytes, col, dstPtr);
265template<psd_
byte_order
byteOrder>
266void readCmykPixelCommon(
int channelSize,
const QMap<quint16, QByteArray> &channelBytes,
int col, quint8 *dstPtr)
268 if (channelSize == 1) {
269 readCmykPixel<KoCmykU8Traits, byteOrder>(channelBytes, col, dstPtr);
270 }
else if (channelSize == 2) {
271 readCmykPixel<KoCmykU16Traits, byteOrder>(channelBytes, col, dstPtr);
272 }
else if (channelSize == 4) {
273 readCmykPixel<KoCmykF32Traits, byteOrder>(channelBytes, col, dstPtr);
277template<psd_
byte_order
byteOrder>
278void readLabPixelCommon(
int channelSize,
const QMap<quint16, QByteArray> &channelBytes,
int col, quint8 *dstPtr)
280 if (channelSize == 1) {
281 readLabPixel<KoLabU8Traits, byteOrder>(channelBytes, col, dstPtr);
282 }
else if (channelSize == 2) {
283 readLabPixel<KoLabU16Traits, byteOrder>(channelBytes, col, dstPtr);
284 }
else if (channelSize == 4) {
285 readLabPixel<KoLabF32Traits, byteOrder>(channelBytes, col, dstPtr);
289template<psd_
byte_order
byteOrder>
292 if (channelSize == 1) {
293 readAlphaMaskPixel<AlphaU8Traits, byteOrder>(channelBytes, col, dstPtr);
294 }
else if (channelSize == 2) {
295 readAlphaMaskPixel<AlphaU16Traits, byteOrder>(channelBytes, col, dstPtr);
296 }
else if (channelSize == 4) {
297 readAlphaMaskPixel<AlphaF32Traits, byteOrder>(channelBytes, col, dstPtr);
303 const int uncompressedLength = width * channelSize;
305 QMap<quint16, QByteArray> channelBytes;
307 Q_FOREACH (
ChannelInfo *channelInfo, channelInfoRecords) {
309 if (!processMasks && channelInfo->
channelId < -1)
315 channelBytes[channelInfo->
channelId] = io.read(uncompressedLength);
319 QByteArray compressedBytes = io.read(rleLength);
321 channelBytes.insert(channelInfo->
channelId, uncompressedBytes);
324 QString error = QString(
"Unsupported Compression mode: %1")
326 dbgFile <<
"ERROR: fetchChannelsBytes:" << error;
334using PixelFunc = std::function<
void(
int,
const QMap<quint16, QByteArray> &,
int, quint8 *)>;
338 const QRect &layerRect,
346 if (layerRect.isEmpty()) {
352 const int numPixels = channelSize * layerRect.width() * layerRect.height();
354 QMap<quint16, QByteArray> channelBytes;
359 QByteArray uncompressedBytes;
361 uncompressedBytes =
Compression::uncompress(numPixels, compressedBytes, infoRecords.first()->compressionType, layerRect.width(), channelSize * 8);
363 if (uncompressedBytes.size() != numPixels) {
364 QString error = QString(
"Failed to unzip channel data: id = %1, compression = %2")
375 channelBytes.insert(info->
channelId, uncompressedBytes);
381 pixelFunc(channelSize, channelBytes, col, it.
rawData());
387 for (
int i = 0; i < layerRect.height(); i++) {
388 QMap<quint16, QByteArray> channelBytes;
390 channelBytes =
fetchChannelsBytes(io, infoRecords, i, layerRect.width(), channelSize, processMasks);
392 for (
int col = 0; col < layerRect.width(); col++) {
393 pixelFunc(channelSize, channelBytes, col, it->rawData());
399 if (i < layerRect.height() - 1) {
406template<psd_
byte_order
byteOrder>
411 const QRect &layerRect,
416 readCommon(device, io, layerRect, infoRecords, channelSize, &readGrayPixelCommon<byteOrder>,
false);
419 readCommon(device, io, layerRect, infoRecords, channelSize, &readRgbPixelCommon<byteOrder>,
false);
422 readCommon(device, io, layerRect, infoRecords, channelSize, &readCmykPixelCommon<byteOrder>,
false);
425 readCommon(device, io, layerRect, infoRecords, channelSize, &readLabPixelCommon<byteOrder>,
false);
433 QString error = QString(
"Unsupported color mode: %1").arg(colorMode);
442 const QRect &layerRect,
448 return readChannelsImpl<psd_byte_order::psdLittleEndian>(io, device, colorMode, channelSize, layerRect, infoRecords);
450 return readChannelsImpl<psd_byte_order::psdBigEndian>(io, device, colorMode, channelSize, layerRect, infoRecords);
454template<psd_
byte_order
byteOrder>
458 readCommon(device, io, layerRect, infoRecords, channelSize, &readAlphaMaskPixelCommon<byteOrder>,
true);
464 const QRect &layerRect,
470 return readAlphaMaskChannelsImpl<psd_byte_order::psdLittleEndian>(io, device, channelSize, layerRect, infoRecords);
472 return readAlphaMaskChannelsImpl<psd_byte_order::psdBigEndian>(io, device, channelSize, layerRect, infoRecords);
476template<psd_
byte_order
byteOrder = psd_
byte_order::psdBigEndian>
479 const int channelSize,
481 const qint64 sizeFieldOffset,
482 const qint64 rleBlockOffset,
483 const bool writeCompressionType)
486 QScopedPointer<Pusher> channelBlockSizeExternalTag;
487 if (sizeFieldOffset >= 0) {
488 channelBlockSizeExternalTag.reset(
new Pusher(io, 0, sizeFieldOffset));
491 if (writeCompressionType) {
495 const bool externalRleBlock = rleBlockOffset >= 0;
498 const qint64 channelRLESizePos = externalRleBlock ? rleBlockOffset : io.pos();
501 QScopedPointer<KisOffsetKeeper> rleOffsetKeeper;
503 if (externalRleBlock) {
505 io.seek(rleBlockOffset);
509 for (
int i = 0; i < rc.height(); ++i) {
511 const quint16 fakeRLEBLockSize = 0;
516 const int stride = channelSize * rc.width();
517 for (qint32 row = 0; row < rc.height(); ++row) {
518 QByteArray uncompressed = QByteArray::fromRawData((
const char *)plane + row * stride, stride);
523 if (io.write(compressed) != compressed.size()) {
529template<psd_
byte_order
byteOrder = psd_
byte_order::psdBigEndian>
532 const int channelSize,
534 const qint64 sizeFieldOffset,
535 const bool writeCompressionType)
538 QScopedPointer<Pusher> channelBlockSizeExternalTag;
539 if (sizeFieldOffset >= 0) {
540 channelBlockSizeExternalTag.reset(
new Pusher(io, 0, sizeFieldOffset));
543 if (writeCompressionType) {
547 QByteArray uncompressed(
reinterpret_cast<const char *
>(plane), rc.width() * rc.height() * channelSize);
550 if (compressed.size() == 0 || io.write(compressed) != compressed.size()) {
557 const int channelSize,
559 const qint64 sizeFieldOffset,
560 const qint64 rleBlockOffset,
561 const bool writeCompressionType,
566 return writeChannelDataRLEImpl<psd_byte_order::psdLittleEndian>(io, plane, channelSize, rc, sizeFieldOffset, rleBlockOffset, writeCompressionType);
568 return writeChannelDataRLEImpl(io, plane, channelSize, rc, sizeFieldOffset, rleBlockOffset, writeCompressionType);
572template<psd_
byte_order
byteOrder = psd_
byte_order::psdBigEndian>
577 if (channelSize == 1) {
578 if (channelId >= 0 && (colorMode ==
CMYK || colorMode ==
CMYK64)) {
579 for (
int i = 0; i < numPixels; ++i) {
580 dataPlane[i] = 255 - dataPlane[i];
583 }
else if (channelSize == 2) {
585 for (
int i = 0; i < numPixels; ++i) {
586 quint16 *pixelPtr =
reinterpret_cast<quint16 *
>(dataPlane) + i;
590 val = qFromBigEndian(val);
591 if (channelId >= 0 && (colorMode ==
CMYK || colorMode ==
CMYK64)) {
596 }
else if (channelSize == 4) {
598 for (
int i = 0; i < numPixels; ++i) {
599 quint32 *pixelPtr =
reinterpret_cast<quint32 *
>(dataPlane) + i;
603 val = qFromBigEndian(val);
604 if (channelId >= 0 && (colorMode ==
CMYK || colorMode ==
CMYK64)) {
605 val = std::numeric_limits<quint32>::max() - val;
612template<psd_
byte_order
byteOrder = psd_
byte_order::psdBigEndian>
619 const bool writeCompressionType,
633 quint8 *alphaPlanePtr = 0;
640 std::swap(holder,
tmp[channelIndex]);
643 std::swap(holder, alphaPlanePtr);
645 planes.append(holder);
651 planes.insert(0, alphaPlanePtr);
654 planes.append(alphaPlanePtr);
655 KIS_ASSERT_RECOVER_NOOP((writingInfoList.size() == planes.size() - 1) || (writingInfoList.last().channelId == -1));
665 const int numPixels = rc.width() * rc.height();
670 for (
int i = 0; i < writingInfoList.size(); i++) {
676 preparePixelForWrite<psd_byte_order::psdBigEndian>(planes[i], numPixels, channelSize, info.
channelId, colorMode);
678 dbgFile <<
"\t\tchannel start" <<
ppVar(io.pos()) <<
", compression type" << compressionType;
680 switch (compressionType) {
683 writeChannelDataZIPImpl<byteOrder>(io, planes[i], channelSize, rc, info.
sizeFieldOffset, writeCompressionType);
695 Q_FOREACH (quint8 *plane, planes) {
703 Q_FOREACH (quint8 *plane, planes) {
715 const bool writeCompressionType,
722 return writePixelDataCommonImpl<psd_byte_order::psdLittleEndian>(io,
728 writeCompressionType,
732 return writePixelDataCommonImpl(io, dev, rc, colorMode, channelSize, alphaFirst, writeCompressionType, writingInfoList, compressionType);
float value(const T *src, size_t ch)
static QByteArray uncompress(int unpacked_len, QByteArray bytes, psd_compression_type compressionType, int row_size=0, int color_depth=0)
static QByteArray compress(QByteArray bytes, psd_compression_type compressionType, int row_size=0, int color_depth=0)
QVector< quint8 * > readPlanarBytes(qint32 x, qint32 y, qint32 w, qint32 h) const
KisHLineIteratorSP createHLineIteratorNG(qint32 x, qint32 y, qint32 w)
const KoColorSpace * colorSpace() const
ALWAYS_INLINE quint8 * rawData()
@ ALPHA
The channel represents the opacity of a pixel.
enumChannelType channelType() const
static int displayPositionToChannelIndex(int displayPosition, const QList< KoChannelInfo * > &channels)
static QList< KoChannelInfo * > displayOrderSorted(const QList< KoChannelInfo * > &channels)
qint32 displayPosition() const
QList< KoChannelInfo * > channels
#define SAFE_WRITE_EX(byteOrder, device, varname)
#define KIS_SAFE_ASSERT_RECOVER_RETURN(cond)
#define KIS_ASSERT_RECOVER_RETURN(cond)
#define KIS_ASSERT_RECOVER_NOOP(cond)
#define PREPEND_METHOD(msg)
const quint16 quint16_MAX
typedef void(QOPENGLF_APIENTRYP PFNGLINVALIDATEBUFFERDATAPROC)(GLuint buffer)
void readCmykPixelCommon(int channelSize, const QMap< quint16, QByteArray > &channelBytes, int col, quint8 *dstPtr)
void readRgbPixelCommon(int channelSize, const QMap< quint16, QByteArray > &channelBytes, int col, quint8 *dstPtr)
Traits::channels_type convertByteOrder(typename Traits::channels_type value)
void writePixelDataCommon(QIODevice &io, KisPaintDeviceSP dev, const QRect &rc, psd_color_mode colorMode, int channelSize, bool alphaFirst, const bool writeCompressionType, QVector< ChannelWritingInfo > &writingInfoList, psd_compression_type compressionType, psd_byte_order byteOrder)
void readCommon(KisPaintDeviceSP dev, QIODevice &io, const QRect &layerRect, QVector< ChannelInfo * > infoRecords, int channelSize, PixelFunc pixelFunc, bool processMasks)
void preparePixelForWrite(quint8 *dataPlane, int numPixels, int channelSize, int channelId, psd_color_mode colorMode)
void readLabPixelCommon(int channelSize, const QMap< quint16, QByteArray > &channelBytes, int col, quint8 *dstPtr)
void readChannels(QIODevice &io, KisPaintDeviceSP device, psd_color_mode colorMode, int channelSize, const QRect &layerRect, QVector< ChannelInfo * > infoRecords, psd_byte_order byteOrder)
quint16 convertByteOrder< KoBgrU16Traits >(quint16 value)
quint16 convertByteOrder< KoCmykU16Traits >(quint16 value)
quint8 truncateToOpacity(typename Traits::channels_type value)
quint8 convertByteOrder< KoCmykU8Traits >(quint8 value)
void writePixelDataCommonImpl(QIODevice &io, KisPaintDeviceSP dev, const QRect &rc, psd_color_mode colorMode, int channelSize, bool alphaFirst, const bool writeCompressionType, QVector< ChannelWritingInfo > &writingInfoList, psd_compression_type compressionType)
void writeChannelDataRLE(QIODevice &io, const quint8 *plane, const int channelSize, const QRect &rc, const qint64 sizeFieldOffset, const qint64 rleBlockOffset, const bool writeCompressionType, psd_byte_order byteOrder)
void readAlphaMaskChannels(QIODevice &io, KisPaintDeviceSP device, int channelSize, const QRect &layerRect, QVector< ChannelInfo * > infoRecords, psd_byte_order byteOrder)
std::function< void(int, const QMap< quint16, QByteArray > &, int, quint8 *)> PixelFunc
void readAlphaMaskPixel(const QMap< quint16, QByteArray > &channelBytes, int col, quint8 *dstPtr)
void readAlphaMaskPixelCommon(int channelSize, const QMap< quint16, QByteArray > &channelBytes, int col, quint8 *dstPtr)
void writeChannelDataRLEImpl(QIODevice &io, const quint8 *plane, const int channelSize, const QRect &rc, const qint64 sizeFieldOffset, const qint64 rleBlockOffset, const bool writeCompressionType)
quint32 convertByteOrder< KoGrayU32Traits >(quint32 value)
void writeChannelDataZIPImpl(QIODevice &io, const quint8 *plane, const int channelSize, const QRect &rc, const qint64 sizeFieldOffset, const bool writeCompressionType)
float convertByteOrder< AlphaF32Traits >(float value)
quint8 convertByteOrder< AlphaU8Traits >(quint8 value)
QMap< quint16, QByteArray > fetchChannelsBytes(QIODevice &io, QVector< ChannelInfo * > channelInfoRecords, int row, int width, int channelSize, bool processMasks)
quint8 convertByteOrder< KoGrayU8Traits >(quint8 value)
void readGrayPixel(const QMap< quint16, QByteArray > &channelBytes, int col, quint8 *dstPtr)
void readAlphaMaskChannelsImpl(QIODevice &io, KisPaintDeviceSP device, int channelSize, const QRect &layerRect, QVector< ChannelInfo * > infoRecords)
quint16 convertByteOrder< KoGrayU16Traits >(quint16 value)
void readLabPixel(const QMap< quint16, QByteArray > &channelBytes, int col, quint8 *dstPtr)
quint8 truncateToOpacity< AlphaU8Traits >(typename AlphaU8Traits::channels_type value)
void readRgbPixel(const QMap< quint16, QByteArray > &channelBytes, int col, quint8 *dstPtr)
Traits::channels_type readChannelValue(const QMap< quint16, QByteArray > &channelBytes, quint16 channelId, int col, typename Traits::channels_type defaultValue)
quint16 convertByteOrder< AlphaU16Traits >(quint16 value)
float convertByteOrder< KoCmykF32Traits >(float value)
quint8 convertByteOrder< KoBgrU8Traits >(quint8 value)
void readChannelsImpl(QIODevice &io, KisPaintDeviceSP device, psd_color_mode colorMode, int channelSize, const QRect &layerRect, QVector< ChannelInfo * > infoRecords)
void readGrayPixelCommon(int channelSize, const QMap< quint16, QByteArray > &channelBytes, int col, quint8 *dstPtr)
quint32 convertByteOrder< KoBgrU32Traits >(quint32 value)
quint8 convertByteOrder< KoLabU8Traits >(quint8 value)
quint8 truncateToOpacity< AlphaU16Traits >(typename AlphaU16Traits::channels_type value)
quint8 truncateToOpacity< AlphaF32Traits >(typename AlphaF32Traits::channels_type value)
float convertByteOrder< KoLabF32Traits >(float value)
void readCmykPixel(const QMap< quint16, QByteArray > &channelBytes, int col, quint8 *dstPtr)
quint16 convertByteOrder< KoLabU16Traits >(quint16 value)
QVector< quint32 > rleRowLengths
psd_compression_type compressionType
quint64 channelDataLength
_channels_type_ channels_type
the type of the value of the channels of this color space