File indexing completed on 2024-05-19 04:27:28

0001 /*
0002  *  SPDX-FileCopyrightText: 2009 Boudewijn Rempt <boud@valdyas.org>
0003  *  SPDX-FileCopyrightText: 2021 L. E. Segovia <amy@amyspark.me>
0004  *
0005  *  SPDX-License-Identifier: GPL-2.0-or-later
0006  */
0007 #include "psd_layer_record.h"
0008 
0009 #include <QtEndian>
0010 
0011 #include <KoColor.h>
0012 #include <QBuffer>
0013 #include <QDataStream>
0014 #include <QIODevice>
0015 #include <QStringList>
0016 
0017 #include "kis_iterator_ng.h"
0018 #include <algorithm>
0019 #include <kis_debug.h>
0020 #include <kis_node.h>
0021 #include <kis_paint_layer.h>
0022 
0023 #include "compression.h"
0024 #include "psd.h"
0025 #include "psd_header.h"
0026 #include "psd_utils.h"
0027 
0028 #include <KoColorSpace.h>
0029 #include <KoColorSpaceMaths.h>
0030 #include <KoColorSpaceRegistry.h>
0031 #include <KoColorSpaceTraits.h>
0032 
0033 #include <asl/kis_asl_reader_utils.h>
0034 #include <asl/kis_asl_writer_utils.h>
0035 #include <asl/kis_offset_keeper.h>
0036 
0037 #include "psd_pixel_utils.h"
0038 #include <kundo2command.h>
0039 
0040 // Just for pretty debug messages
0041 QString channelIdToChannelType(int channelId, psd_color_mode colormode)
0042 {
0043     switch (channelId) {
0044     case -3:
0045         return "Real User Supplied Layer Mask (when both a user mask and a vector mask are present";
0046     case -2:
0047         return "User Supplied Layer Mask";
0048     case -1:
0049         return "Transparency mask";
0050     case 0:
0051         switch (colormode) {
0052         case Bitmap:
0053         case Indexed:
0054             return QString("bitmap or indexed: %1").arg(channelId);
0055         case Grayscale:
0056         case Gray16:
0057             return "gray";
0058         case RGB:
0059         case RGB48:
0060             return "red";
0061         case Lab:
0062         case Lab48:
0063             return "L";
0064         case CMYK:
0065         case CMYK64:
0066             return "cyan";
0067         case MultiChannel:
0068         case DeepMultichannel:
0069             return QString("multichannel channel %1").arg(channelId);
0070         case DuoTone:
0071         case Duotone16:
0072             return QString("duotone channel %1").arg(channelId);
0073         default:
0074             return QString("unknown: %1").arg(channelId);
0075         };
0076     case 1:
0077         switch (colormode) {
0078         case Bitmap:
0079         case Indexed:
0080             return QString("WARNING bitmap or indexed: %1").arg(channelId);
0081         case Grayscale:
0082         case Gray16:
0083             return QString("WARNING: %1").arg(channelId);
0084         case RGB:
0085         case RGB48:
0086             return "green";
0087         case Lab:
0088         case Lab48:
0089             return "a";
0090         case CMYK:
0091         case CMYK64:
0092             return "Magenta";
0093         case MultiChannel:
0094         case DeepMultichannel:
0095             return QString("multichannel channel %1").arg(channelId);
0096         case DuoTone:
0097         case Duotone16:
0098             return QString("duotone channel %1").arg(channelId);
0099         default:
0100             return QString("unknown: %1").arg(channelId);
0101         };
0102     case 2:
0103         switch (colormode) {
0104         case Bitmap:
0105         case Indexed:
0106             return QString("WARNING bitmap or indexed: %1").arg(channelId);
0107         case Grayscale:
0108         case Gray16:
0109             return QString("WARNING: %1").arg(channelId);
0110         case RGB:
0111         case RGB48:
0112             return "blue";
0113         case Lab:
0114         case Lab48:
0115             return "b";
0116         case CMYK:
0117         case CMYK64:
0118             return "yellow";
0119         case MultiChannel:
0120         case DeepMultichannel:
0121             return QString("multichannel channel %1").arg(channelId);
0122         case DuoTone:
0123         case Duotone16:
0124             return QString("duotone channel %1").arg(channelId);
0125         default:
0126             return QString("unknown: %1").arg(channelId);
0127         };
0128     case 3:
0129         switch (colormode) {
0130         case Bitmap:
0131         case Indexed:
0132             return QString("WARNING bitmap or indexed: %1").arg(channelId);
0133         case Grayscale:
0134         case Gray16:
0135             return QString("WARNING: %1").arg(channelId);
0136         case RGB:
0137         case RGB48:
0138             return QString("alpha: %1").arg(channelId);
0139         case Lab:
0140         case Lab48:
0141             return QString("alpha: %1").arg(channelId);
0142         case CMYK:
0143         case CMYK64:
0144             return "Key";
0145         case MultiChannel:
0146         case DeepMultichannel:
0147             return QString("multichannel channel %1").arg(channelId);
0148         case DuoTone:
0149         case Duotone16:
0150             return QString("duotone channel %1").arg(channelId);
0151         default:
0152             return QString("unknown: %1").arg(channelId);
0153         };
0154     default:
0155         return QString("unknown: %1").arg(channelId);
0156     };
0157 }
0158 
0159 PSDLayerRecord::PSDLayerRecord(const PSDHeader &header)
0160     : infoBlocks(header)
0161     , m_header(header)
0162 {
0163 }
0164 
0165 bool PSDLayerRecord::read(QIODevice &io)
0166 {
0167     switch (m_header.byteOrder) {
0168     case psd_byte_order::psdLittleEndian:
0169         return readImpl<psd_byte_order::psdLittleEndian>(io);
0170     default:
0171         return readImpl(io);
0172     }
0173 }
0174 
0175 template<psd_byte_order byteOrder>
0176 bool PSDLayerRecord::readImpl(QIODevice &io)
0177 {
0178     dbgFile << "Going to read layer record. Pos:" << io.pos();
0179 
0180     if (!psdread<byteOrder>(io, top) || !psdread<byteOrder>(io, left) || !psdread<byteOrder>(io, bottom) || !psdread<byteOrder>(io, right)
0181         || !psdread<byteOrder>(io, nChannels)) {
0182         error = "could not read layer record";
0183         return false;
0184     }
0185 
0186     dbgFile << "\ttop" << top << "left" << left << "bottom" << bottom << "right" << right << "number of channels" << nChannels;
0187 
0188     Q_ASSERT(top <= bottom);
0189     Q_ASSERT(left <= right);
0190     Q_ASSERT(nChannels > 0);
0191 
0192     if (nChannels < 1) {
0193         error = QString("Not enough channels. Got: %1").arg(nChannels);
0194         return false;
0195     }
0196 
0197     if (nChannels > MAX_CHANNELS) {
0198         error = QString("Too many channels. Got: %1").arg(nChannels);
0199         return false;
0200     }
0201 
0202     for (int i = 0; i < nChannels; ++i) {
0203         if (io.atEnd()) {
0204             error = "Could not read enough data for channels";
0205             return false;
0206         }
0207 
0208         ChannelInfo *info = new ChannelInfo;
0209 
0210         if (!psdread<byteOrder>(io, info->channelId)) {
0211             error = "could not read channel id";
0212             delete info;
0213             return false;
0214         }
0215         bool r;
0216         if (m_header.version == 1) {
0217             quint32 channelDataLength;
0218             r = psdread<byteOrder>(io, channelDataLength);
0219             info->channelDataLength = (quint64)channelDataLength;
0220         } else {
0221             r = psdread<byteOrder>(io, info->channelDataLength);
0222         }
0223         if (!r) {
0224             error = "Could not read length for channel data";
0225             delete info;
0226             return false;
0227         }
0228 
0229         dbgFile << "\tchannel" << i << "id" << channelIdToChannelType(info->channelId, m_header.colormode) << "length" << info->channelDataLength << "start"
0230                 << info->channelDataStart << "offset" << info->channelOffset << "channelInfoPosition" << info->channelInfoPosition;
0231 
0232         channelInfoRecords << info;
0233     }
0234 
0235     if (!psd_read_blendmode<byteOrder>(io, blendModeKey)) {
0236         error = QString("Could not read blend mode key. Got: %1").arg(blendModeKey);
0237         return false;
0238     }
0239 
0240     dbgFile << "\tBlend mode" << blendModeKey << "pos" << io.pos();
0241 
0242     if (!psdread<byteOrder>(io, opacity)) {
0243         error = "Could not read opacity";
0244         return false;
0245     }
0246 
0247     dbgFile << "\tOpacity" << opacity << io.pos();
0248 
0249     if (!psdread<byteOrder>(io, clipping)) {
0250         error = "Could not read clipping";
0251         return false;
0252     }
0253 
0254     dbgFile << "\tclipping" << clipping << io.pos();
0255 
0256     quint8 flags;
0257     if (!psdread<byteOrder>(io, flags)) {
0258         error = "Could not read flags";
0259         return false;
0260     }
0261     dbgFile << "\tflags" << flags << io.pos();
0262 
0263     transparencyProtected = flags & 1 ? true : false;
0264 
0265     dbgFile << "\ttransparency protected" << transparencyProtected;
0266 
0267     visible = flags & 2 ? false : true;
0268 
0269     dbgFile << "\tvisible" << visible;
0270 
0271     if (flags & 8) {
0272         irrelevant = flags & 16 ? true : false;
0273     } else {
0274         irrelevant = false;
0275     }
0276 
0277     dbgFile << "\tirrelevant" << irrelevant;
0278 
0279     dbgFile << "\tfiller at " << io.pos();
0280 
0281     quint8 filler;
0282     if (!psdread<byteOrder>(io, filler) || filler != 0) {
0283         error = "Could not read padding";
0284         return false;
0285     }
0286 
0287     dbgFile << "\tGoing to read extra data length" << io.pos();
0288 
0289     quint32 extraDataLength;
0290     if (!psdread<byteOrder>(io, extraDataLength) || io.bytesAvailable() < extraDataLength) {
0291         error = QString("Could not read extra layer data: %1 at pos %2").arg(extraDataLength).arg(io.pos());
0292         return false;
0293     }
0294 
0295     dbgFile << "\tExtra data length" << extraDataLength;
0296 
0297     if (extraDataLength > 0) {
0298         dbgFile << "Going to read extra data field. Bytes available: " << io.bytesAvailable() << "pos" << io.pos();
0299 
0300         // See https://www.adobe.com/devnet-apps/photoshop/fileformatashtml/#50577409_22582
0301         quint32 layerMaskLength = 1; // invalid...
0302         if (!psdread<byteOrder>(io, layerMaskLength) || io.bytesAvailable() < layerMaskLength) {
0303             error = QString("Could not read layer mask length: %1").arg(layerMaskLength);
0304             return false;
0305         }
0306 
0307         layerMask = {};
0308 
0309         if (layerMaskLength == 0) {
0310             dbgFile << "\tNo layer mask/adjustment layer data. pos" << io.pos();
0311         } else {
0312             dbgFile << "\tReading layer mask/adjustment layer data. Length of block:" << layerMaskLength << "pos"
0313                     << io.pos();
0314 
0315             if (!psdread<byteOrder>(io, layerMask.top) || !psdread<byteOrder>(io, layerMask.left)
0316                 || !psdread<byteOrder>(io, layerMask.bottom) || !psdread<byteOrder>(io, layerMask.right)
0317                 || !psdread<byteOrder>(io, layerMask.defaultColor) || !psdread<byteOrder>(io, flags)) {
0318                 error = "could not read common records of layer mask";
0319                 return false;
0320             }
0321 
0322             layerMask.positionedRelativeToLayer = (flags & 1) != 0;
0323             layerMask.disabled = (flags & 2) != 0;
0324             layerMask.invertLayerMaskWhenBlending = (flags & 4) != 0;
0325             const bool hasMaskParameters = (flags & 8) != 0;
0326 
0327             dbgFile << "\tLayer mask info (original): position relative" << layerMask.positionedRelativeToLayer
0328                     << ", disabled" << layerMask.disabled << ", invert" << layerMask.invertLayerMaskWhenBlending
0329                     << ", needs to read mask parameters" << hasMaskParameters;
0330 
0331             if (layerMaskLength == 20) {
0332                 quint16 padding = 0;
0333                 if (!psdread<byteOrder>(io, padding)) {
0334                     error = "Could not read layer mask padding";
0335                     return false;
0336                 }
0337             } else {
0338                 quint32 remainingBlockLength = layerMaskLength - 18;
0339 
0340                 dbgFile << "\tReading selective records from layer mask info. Remaining block length"
0341                         << remainingBlockLength;
0342 
0343                 if (hasMaskParameters) {
0344                     if (!psdread<byteOrder>(io, flags)) {
0345                         error = "could not read mask parameters";
0346                         return false;
0347                     }
0348 
0349                     remainingBlockLength -= 1;
0350 
0351                     dbgFile << "\t\tMask parameters" << QString::number(flags, 2) << ". Remaining block length"
0352                             << remainingBlockLength;
0353 
0354                     if (flags & 1) {
0355                         quint8 dummy = 0;
0356                         if (!psdread<byteOrder>(io, dummy)) {
0357                             error = "could not read user mask density";
0358                             return false;
0359                         }
0360                         remainingBlockLength -= sizeof(dummy);
0361                     }
0362 
0363                     if (flags & 2) {
0364                         double dummy = 0;
0365                         if (!psdread<byteOrder>(io, dummy)) {
0366                             error = "could not read user mask feather";
0367                             return false;
0368                         }
0369                         remainingBlockLength -= sizeof(dummy);
0370                     }
0371 
0372                     if (flags & 4) {
0373                         quint8 dummy = 0;
0374                         if (!psdread<byteOrder>(io, dummy)) {
0375                             error = "could not read vector mask density";
0376                             return false;
0377                         }
0378                         remainingBlockLength -= sizeof(dummy);
0379                     }
0380 
0381                     if (flags & 8) {
0382                         double dummy = 0;
0383                         if (!psdread<byteOrder>(io, dummy)) {
0384                             error = "could not read vector mask feather";
0385                             return false;
0386                         }
0387                         remainingBlockLength -= sizeof(dummy);
0388                     }
0389                 }
0390 
0391                 if (remainingBlockLength >= 1) {
0392                     if (!psdread<byteOrder>(io, flags)) {
0393                         error = "could not read 'real' mask record";
0394                         return false;
0395                     }
0396 
0397                     layerMask.positionedRelativeToLayer = (flags & 1) != 0;
0398                     layerMask.disabled = (flags & 2) != 0;
0399                     layerMask.invertLayerMaskWhenBlending = (flags & 4) != 0;
0400                     const bool hasMaskParameters = (flags & 8) != 0;
0401 
0402                     dbgFile << "\t\tLayer mask info (real): position relative" << layerMask.positionedRelativeToLayer
0403                             << ", disabled" << layerMask.disabled << ", invert" << layerMask.invertLayerMaskWhenBlending
0404                             << ", needs to read mask parameters" << hasMaskParameters;
0405 
0406                     remainingBlockLength -= 1;
0407 
0408                     dbgFile << "\t\tRemaining block length" << remainingBlockLength;
0409                 }
0410 
0411                 if (remainingBlockLength >= 1) {
0412                     if (!psdread<byteOrder>(io, layerMask.defaultColor)) {
0413                         error = "could not read 'real' default color";
0414                         return false;
0415                     }
0416                     remainingBlockLength -= 1;
0417                     dbgFile << "\t\tRead 'real' default color. Remaining block length" << remainingBlockLength;
0418                 }
0419 
0420                 if (remainingBlockLength >= 16) {
0421                     if (!psdread<byteOrder>(io, layerMask.top) || !psdread<byteOrder>(io, layerMask.left)
0422                         || !psdread<byteOrder>(io, layerMask.bottom) || !psdread<byteOrder>(io, layerMask.right)) {
0423                         error = "could not read 'real' mask rectangle";
0424                         return false;
0425                     }
0426                     remainingBlockLength -= 16;
0427                     dbgFile << "\t\tRead 'real' mask rectangle. Remaining block length" << remainingBlockLength;
0428                 }
0429             }
0430         }
0431 
0432         // layer blending thingies
0433         quint32 blendingDataLength = 0;
0434         if (!psdread<byteOrder>(io, blendingDataLength) || io.bytesAvailable() < blendingDataLength) {
0435             error = "Could not read extra blending data.";
0436             return false;
0437         }
0438 
0439         quint32 blendingNchannels = blendingDataLength > 0 ? (blendingDataLength - 8) / 4 / 2 : 0;
0440 
0441         dbgFile << "\tNumber of blending channels:" << blendingNchannels;
0442 
0443         if (blendingDataLength > 0) {
0444             if (blendingDataLength > 0) {
0445                 if (!psdread<byteOrder>(io, blendingRanges.compositeGrayRange.first.blackValues[0])
0446                     || !psdread<byteOrder>(io, blendingRanges.compositeGrayRange.first.blackValues[1])
0447                     || !psdread<byteOrder>(io, blendingRanges.compositeGrayRange.first.whiteValues[0])
0448                     || !psdread<byteOrder>(io, blendingRanges.compositeGrayRange.first.whiteValues[1])) {
0449                     error = "Could not read blending black/white values";
0450                     return false;
0451                 }
0452             }
0453             blendingDataLength -= 4;
0454 
0455             if (blendingDataLength > 0) {
0456                 if (!psdread<byteOrder>(io, blendingRanges.compositeGrayRange.second.blackValues[0])
0457                     || !psdread<byteOrder>(io, blendingRanges.compositeGrayRange.second.blackValues[1])
0458                     || !psdread<byteOrder>(io, blendingRanges.compositeGrayRange.second.whiteValues[0])
0459                     || !psdread<byteOrder>(io, blendingRanges.compositeGrayRange.second.whiteValues[1])) {
0460                     error = "Could not read blending black/white values";
0461                     return false;
0462                 }
0463             }
0464             blendingDataLength -= 4;
0465 
0466             dbgFile << "\tBlending ranges:";
0467             dbgFile << "\t\tcomposite gray (source) :" << blendingRanges.compositeGrayRange.first;
0468             dbgFile << "\t\tcomposite gray (dest):" << blendingRanges.compositeGrayRange.second;
0469 
0470             for (quint32 i = 0; i < blendingNchannels; ++i) {
0471                 LayerBlendingRanges::LayerBlendingRange src{};
0472                 LayerBlendingRanges::LayerBlendingRange dst{};
0473                 if (!psdread<byteOrder>(io, src.blackValues[0]) || !psdread<byteOrder>(io, src.blackValues[1]) || !psdread<byteOrder>(io, src.whiteValues[0])
0474                     || !psdread<byteOrder>(io, src.whiteValues[1]) || !psdread<byteOrder>(io, dst.blackValues[0]) || !psdread<byteOrder>(io, dst.blackValues[1])
0475                     || !psdread<byteOrder>(io, dst.whiteValues[0]) || !psdread<byteOrder>(io, dst.whiteValues[1])) {
0476                     error = QString("could not read src/dst range for channel %1").arg(i);
0477                     return false;
0478                 }
0479                 dbgFile << "\t\tread range " << src << "to" << dst << "for channel" << i;
0480                 blendingRanges.sourceDestinationRanges << qMakePair(src, dst);
0481             }
0482         }
0483 
0484         dbgFile << "\tGoing to read layer name at" << io.pos();
0485         quint8 layerNameLength;
0486         if (!psdread<byteOrder>(io, layerNameLength)) {
0487             error = "Could not read layer name length";
0488             return false;
0489         }
0490 
0491         dbgFile << "\tlayer name length unpadded" << layerNameLength << "pos" << io.pos();
0492         layerNameLength = ((layerNameLength + 1 + 3) & ~0x03) - 1;
0493 
0494         dbgFile << "\tlayer name length padded" << layerNameLength << "pos" << io.pos();
0495         // XXX: This should use psdread_pascalstring
0496         layerName = io.read(layerNameLength);
0497         dbgFile << "\tlayer name" << layerName << io.pos();
0498 
0499         dbgFile << "\tAbout to read additional info blocks at" << io.pos();
0500 
0501         if (!infoBlocks.read(io)) {
0502             error = infoBlocks.error;
0503             return false;
0504         }
0505 
0506         if (infoBlocks.keys.contains("luni") && !infoBlocks.unicodeLayerName.isEmpty()) {
0507             layerName = infoBlocks.unicodeLayerName;
0508         }
0509 
0510         labelColor = kritaColorLabelIndex(infoBlocks.labelColor);
0511     }
0512 
0513     return valid();
0514 }
0515 
0516 void PSDLayerRecord::write(QIODevice &io,
0517                            KisPaintDeviceSP layerContentDevice,
0518                            KisNodeSP onlyTransparencyMask,
0519                            const QRect &maskRect,
0520                            psd_section_type sectionType,
0521                            const QDomDocument &stylesXmlDoc,
0522                            bool useLfxsLayerStyleFormat)
0523 {
0524     switch (m_header.byteOrder) {
0525     case psd_byte_order::psdLittleEndian:
0526         return writeImpl<psd_byte_order::psdLittleEndian>(io,
0527                                                           layerContentDevice,
0528                                                           onlyTransparencyMask,
0529                                                           maskRect,
0530                                                           sectionType,
0531                                                           stylesXmlDoc,
0532                                                           useLfxsLayerStyleFormat);
0533     default:
0534         return writeImpl(io, layerContentDevice, onlyTransparencyMask, maskRect, sectionType, stylesXmlDoc, useLfxsLayerStyleFormat);
0535     }
0536 }
0537 
0538 template<psd_byte_order byteOrder>
0539 void PSDLayerRecord::writeImpl(QIODevice &io,
0540                                KisPaintDeviceSP layerContentDevice,
0541                                KisNodeSP onlyTransparencyMask,
0542                                const QRect &maskRect,
0543                                psd_section_type sectionType,
0544                                const QDomDocument &stylesXmlDoc,
0545                                bool useLfxsLayerStyleFormat)
0546 {
0547     dbgFile << "writing layer info record"
0548             << "at" << io.pos();
0549 
0550     m_layerContentDevice = layerContentDevice;
0551     m_onlyTransparencyMask = onlyTransparencyMask;
0552     m_onlyTransparencyMaskRect = maskRect;
0553 
0554     dbgFile << "saving layer record for " << layerName << "at pos" << io.pos();
0555     dbgFile << "\ttop" << top << "left" << left << "bottom" << bottom << "right" << right << "number of channels" << nChannels;
0556     Q_ASSERT(left <= right);
0557     Q_ASSERT(top <= bottom);
0558     Q_ASSERT(nChannels > 0);
0559 
0560     try {
0561         {
0562             const QRect layerRect(left, top, right - left, bottom - top);
0563             KisAslWriterUtils::writeRect<byteOrder>(layerRect, io);
0564         }
0565 
0566         {
0567             quint16 realNumberOfChannels = nChannels + bool(m_onlyTransparencyMask);
0568             SAFE_WRITE_EX(byteOrder, io, realNumberOfChannels);
0569         }
0570 
0571         Q_FOREACH (ChannelInfo *channel, channelInfoRecords) {
0572             SAFE_WRITE_EX(byteOrder, io, (quint16)channel->channelId);
0573 
0574             channel->channelInfoPosition = static_cast<int>(io.pos());
0575 
0576             // to be filled in when we know how big channel block is
0577             const quint32 fakeChannelSize = 0;
0578             SAFE_WRITE_EX(byteOrder, io, fakeChannelSize);
0579         }
0580 
0581         if (m_onlyTransparencyMask) {
0582             const quint16 userSuppliedMaskChannelId = -2;
0583             SAFE_WRITE_EX(byteOrder, io, userSuppliedMaskChannelId);
0584 
0585             m_transparencyMaskSizeOffset = io.pos();
0586 
0587             const quint32 fakeTransparencyMaskSize = 0;
0588             SAFE_WRITE_EX(byteOrder, io, fakeTransparencyMaskSize);
0589         }
0590 
0591         // blend mode
0592         dbgFile << ppVar(blendModeKey) << ppVar(io.pos());
0593 
0594         KisAslWriterUtils::writeFixedString<byteOrder>("8BIM", io);
0595         KisAslWriterUtils::writeFixedString<byteOrder>(blendModeKey, io);
0596 
0597         SAFE_WRITE_EX(byteOrder, io, opacity);
0598         SAFE_WRITE_EX(byteOrder, io, clipping); // unused
0599 
0600         // visibility and protection
0601         quint8 flags = 0;
0602         if (transparencyProtected)
0603             flags |= 1;
0604         if (!visible)
0605             flags |= 2;
0606         flags |= (1 << 3);
0607         if (irrelevant) {
0608             flags |= (1 << 4);
0609         }
0610 
0611         SAFE_WRITE_EX(byteOrder, io, flags);
0612 
0613         {
0614             quint8 padding = 0;
0615             SAFE_WRITE_EX(byteOrder, io, padding);
0616         }
0617 
0618         {
0619             // extra fields with their own length tag
0620             KisAslWriterUtils::OffsetStreamPusher<quint32, byteOrder> extraDataSizeTag(io);
0621 
0622             if (m_onlyTransparencyMask) {
0623                 {
0624                     const quint32 layerMaskDataSize = 20; // support simple case only
0625                     SAFE_WRITE_EX(byteOrder, io, layerMaskDataSize);
0626                 }
0627 
0628                 KisAslWriterUtils::writeRect<byteOrder>(m_onlyTransparencyMaskRect, io);
0629 
0630                 {
0631                     // NOTE: in PSD the default color of the mask is stored in 1 byte value!
0632                     //       Even when the mask is actually 16/32 bit! I have no idea how it is
0633                     //       actually treated in this case.
0634                     KIS_ASSERT_RECOVER_NOOP(m_onlyTransparencyMask->paintDevice()->pixelSize() == 1);
0635                     const quint8 defaultPixel = *m_onlyTransparencyMask->paintDevice()->defaultPixel().data();
0636                     SAFE_WRITE_EX(byteOrder, io, defaultPixel);
0637                 }
0638 
0639                 {
0640                     const quint8 maskFlags = 0; // nothing serious
0641                     SAFE_WRITE_EX(byteOrder, io, maskFlags);
0642 
0643                     const quint16 padding = 0; // 2-byte padding
0644                     SAFE_WRITE_EX(byteOrder, io, padding);
0645                 }
0646             } else {
0647                 const quint32 nullLayerMaskDataSize = 0;
0648                 SAFE_WRITE_EX(byteOrder, io, nullLayerMaskDataSize);
0649             }
0650 
0651             {
0652                 // blending ranges are not implemented yet
0653                 const quint32 nullBlendingRangesSize = 0;
0654                 SAFE_WRITE_EX(byteOrder, io, nullBlendingRangesSize);
0655             }
0656 
0657             // layer name: Pascal string, padded to a multiple of 4 bytes.
0658             psdwrite_pascalstring<byteOrder>(io, layerName, 4);
0659 
0660             PsdAdditionalLayerInfoBlock additionalInfoBlock(m_header);
0661 
0662             // write 'luni' data block
0663             additionalInfoBlock.writeLuniBlockEx(io, layerName);
0664 
0665             additionalInfoBlock.writeLclrBlockEx(io, psdLabelColor(labelColor));
0666 
0667             // write 'lsct' data block
0668             if (sectionType != psd_other) {
0669                 additionalInfoBlock.writeLsctBlockEx(io, sectionType, isPassThrough, blendModeKey);
0670             }
0671 
0672             // write 'lfx2' data block
0673             if (!stylesXmlDoc.isNull()) {
0674                 additionalInfoBlock.writeLfx2BlockEx(io, stylesXmlDoc, useLfxsLayerStyleFormat);
0675             }
0676 
0677             // write SoCo, GdFl, PtFl data blocks.
0678             if (!fillConfig.isNull()) {
0679                 additionalInfoBlock.writeFillLayerBlockEx(io, fillConfig, fillType);
0680             }
0681 
0682         }
0683     } catch (KisAslWriterUtils::ASLWriteException &e) {
0684         throw KisAslWriterUtils::ASLWriteException(PREPEND_METHOD(e.what()));
0685     }
0686 }
0687 
0688 KisPaintDeviceSP PSDLayerRecord::convertMaskDeviceIfNeeded(KisPaintDeviceSP dev)
0689 {
0690     KisPaintDeviceSP result = dev;
0691 
0692     if (m_header.channelDepth == 16) {
0693         result = new KisPaintDevice(*dev);
0694         result->convertTo(KoColorSpaceRegistry::instance()->alpha16());
0695     } else if (m_header.channelDepth == 32) {
0696         result = new KisPaintDevice(*dev);
0697         result->convertTo(KoColorSpaceRegistry::instance()->alpha32f());
0698     }
0699     return result;
0700 }
0701 
0702 quint16 PSDLayerRecord::psdLabelColor(int colorLabelIndex)
0703 {
0704     quint16 color = 0;
0705     switch (colorLabelIndex) {
0706     case 0: // none
0707         color = 0;
0708         break;
0709     case 1: // Blue
0710         color = 5;
0711         break;
0712     case 2: // Green
0713         color = 4;
0714         break;
0715     case 3: // Yellow
0716         color = 3;
0717         break;
0718     case 4: // Orange
0719         color = 2;
0720         break;
0721     case 5: // Brown, don't save.
0722         color = 0;
0723         break;
0724     case 6: // Red
0725         color = 1;
0726         break;
0727     case 7: // Purple
0728         color = 6;
0729         break;
0730     case 8: // Grey
0731         color = 7;
0732         break;
0733     default:
0734         color = 0;
0735     }
0736     return color;
0737 }
0738 
0739 int PSDLayerRecord::kritaColorLabelIndex(quint16 labelColor)
0740 {
0741     int color = 0;
0742     switch (labelColor) {
0743     case 0:
0744         color = 0;
0745         break;
0746     case 1: // red
0747         color = 6;
0748         break;
0749     case 2: // Orange
0750         color = 4;
0751         break;
0752     case 3: // Yellow
0753         color = 3;
0754         break;
0755     case 4: // Green
0756         color = 2;
0757         break;
0758     case 5: // Blue
0759         color = 1;
0760         break;
0761     case 6: // Purple
0762         color = 7;
0763         break;
0764     case 7: // Grey
0765         color = 8;
0766         break;
0767     default:
0768         color = 0;
0769     }
0770     return color;
0771 }
0772 
0773 template<psd_byte_order byteOrder>
0774 void PSDLayerRecord::writeTransparencyMaskPixelData(QIODevice &io)
0775 {
0776     if (m_onlyTransparencyMask) {
0777         KisPaintDeviceSP device = convertMaskDeviceIfNeeded(m_onlyTransparencyMask->paintDevice());
0778 
0779         QByteArray buffer(static_cast<int>(device->pixelSize()) * m_onlyTransparencyMaskRect.width() * m_onlyTransparencyMaskRect.height(), 0);
0780         device->readBytes((quint8 *)buffer.data(), m_onlyTransparencyMaskRect);
0781 
0782         PsdPixelUtils::writeChannelDataRLE(io,
0783                                            (quint8 *)buffer.data(),
0784                                            static_cast<int>(device->pixelSize()),
0785                                            m_onlyTransparencyMaskRect,
0786                                            m_transparencyMaskSizeOffset,
0787                                            -1,
0788                                            true,
0789                                            byteOrder);
0790     }
0791 }
0792 
0793 void PSDLayerRecord::writePixelData(QIODevice &io, psd_compression_type compressionType)
0794 {
0795     try {
0796         switch (m_header.byteOrder) {
0797         case psd_byte_order::psdLittleEndian:
0798             writePixelDataImpl<psd_byte_order::psdLittleEndian>(io, compressionType);
0799             break;
0800         default:
0801             writePixelDataImpl(io, compressionType);
0802             break;
0803         }
0804     } catch (KisAslWriterUtils::ASLWriteException &e) {
0805         throw KisAslWriterUtils::ASLWriteException(PREPEND_METHOD(e.what()));
0806     }
0807 }
0808 
0809 template<psd_byte_order byteOrder>
0810 void PSDLayerRecord::writePixelDataImpl(QIODevice &io, psd_compression_type compressionType)
0811 {
0812     dbgFile << "writing pixel data for layer" << layerName << "at" << io.pos();
0813 
0814     KisPaintDeviceSP dev = m_layerContentDevice;
0815     const QRect rc(left, top, right - left, bottom - top);
0816 
0817     if (rc.isEmpty()) {
0818         dbgFile << "Layer is empty! Writing placeholder information.";
0819 
0820         for (int i = 0; i < nChannels; i++) {
0821             const ChannelInfo *channelInfo = channelInfoRecords[i];
0822             KisAslWriterUtils::OffsetStreamPusher<quint32, byteOrder> channelBlockSizeExternalTag(io, 0, channelInfo->channelInfoPosition);
0823             SAFE_WRITE_EX(byteOrder, io, static_cast<quint16>(psd_compression_type::Uncompressed));
0824         }
0825 
0826         writeTransparencyMaskPixelData<byteOrder>(io);
0827 
0828         return;
0829     }
0830 
0831     // now write all the channels in display order
0832     dbgFile << "layer" << layerName;
0833 
0834     const int channelSize = m_header.channelDepth / 8;
0835     const psd_color_mode colorMode = m_header.colormode;
0836 
0837     QVector<PsdPixelUtils::ChannelWritingInfo> writingInfoList;
0838     Q_FOREACH (const ChannelInfo *channelInfo, channelInfoRecords) {
0839         writingInfoList << PsdPixelUtils::ChannelWritingInfo(channelInfo->channelId, channelInfo->channelInfoPosition);
0840     }
0841 
0842     PsdPixelUtils::writePixelDataCommon(io, dev, rc, colorMode, channelSize, true, true, writingInfoList, compressionType, byteOrder);
0843     writeTransparencyMaskPixelData<byteOrder>(io);
0844 }
0845 
0846 bool PSDLayerRecord::valid()
0847 {
0848     // XXX: check validity!
0849     return true;
0850 }
0851 
0852 bool PSDLayerRecord::readPixelData(QIODevice &io, KisPaintDeviceSP device)
0853 {
0854     dbgFile << "Reading pixel data for layer" << layerName << "pos" << io.pos();
0855 
0856     const int channelSize = m_header.channelDepth / 8;
0857     const QRect layerRect = QRect(left, top, right - left, bottom - top);
0858 
0859     try {
0860         // WARNING: Pixel data is ALWAYS in big endian!!!
0861         PsdPixelUtils::readChannels(io, device, m_header.colormode, channelSize, layerRect, channelInfoRecords, psd_byte_order::psdBigEndian);
0862     } catch (KisAslReaderUtils::ASLParseException &e) {
0863         device->clear();
0864         error = e.what();
0865         return false;
0866     }
0867 
0868     return true;
0869 }
0870 
0871 QRect PSDLayerRecord::channelRect(ChannelInfo *channel) const
0872 {
0873     QRect result;
0874 
0875     if (channel->channelId < -1) {
0876         result = QRect(layerMask.left, layerMask.top, layerMask.right - layerMask.left, layerMask.bottom - layerMask.top);
0877     } else {
0878         result = QRect(left, top, right - left, bottom - top);
0879     }
0880 
0881     return result;
0882 }
0883 
0884 bool PSDLayerRecord::readMask(QIODevice &io, KisPaintDeviceSP dev, ChannelInfo *channelInfo)
0885 {
0886     KIS_ASSERT_RECOVER(channelInfo->channelId < -1)
0887     {
0888         return false;
0889     }
0890 
0891     dbgFile << "Going to read" << channelIdToChannelType(channelInfo->channelId, m_header.colormode) << "mask";
0892 
0893     QRect maskRect = channelRect(channelInfo);
0894     if (maskRect.isEmpty()) {
0895         dbgFile << "Empty Channel";
0896         return true;
0897     }
0898 
0899     // the device must be a pixel selection
0900     KIS_ASSERT_RECOVER(dev->pixelSize() == 1)
0901     {
0902         return false;
0903     }
0904 
0905     dev->setDefaultPixel(KoColor(&layerMask.defaultColor, dev->colorSpace()));
0906 
0907     const int pixelSize = m_header.channelDepth == 16 ? 2 : m_header.channelDepth == 32 ? 4 : 1;
0908 
0909     QVector<ChannelInfo *> infoRecords;
0910     infoRecords << channelInfo;
0911     PsdPixelUtils::readAlphaMaskChannels(io, dev, pixelSize, maskRect, infoRecords);
0912 
0913     return true;
0914 }
0915 
0916 QDebug operator<<(QDebug dbg, const PSDLayerRecord &layer)
0917 {
0918 #ifndef NODEBUG
0919     dbg.nospace() << "valid: " << const_cast<PSDLayerRecord *>(&layer)->valid();
0920     dbg.nospace() << ", name: " << layer.layerName;
0921     dbg.nospace() << ", top: " << layer.top;
0922     dbg.nospace() << ", left:" << layer.left;
0923     dbg.nospace() << ", bottom: " << layer.bottom;
0924     dbg.nospace() << ", right: " << layer.right;
0925     dbg.nospace() << ", number of channels: " << layer.nChannels;
0926     dbg.nospace() << ", blendModeKey: " << layer.blendModeKey;
0927     dbg.nospace() << ", opacity: " << layer.opacity;
0928     dbg.nospace() << ", clipping: " << layer.clipping;
0929     dbg.nospace() << ", transparency protected: " << layer.transparencyProtected;
0930     dbg.nospace() << ", visible: " << layer.visible;
0931     dbg.nospace() << ", irrelevant: " << layer.irrelevant << "\n";
0932     Q_FOREACH (const ChannelInfo *channel, layer.channelInfoRecords) {
0933         dbg.space() << channel;
0934     }
0935 #endif
0936     return dbg.nospace();
0937 }
0938 
0939 QDebug operator<<(QDebug dbg, const ChannelInfo &channel)
0940 {
0941 #ifndef NODEBUG
0942     dbg.nospace() << "\tChannel type" << channel.channelId << "size: " << channel.channelDataLength << "compression type" << channel.compressionType << "\n";
0943 #endif
0944     return dbg.nospace();
0945 }