File indexing completed on 2024-04-28 03:54:44

0001 /*
0002     Photoshop File Format support for QImage.
0003 
0004     SPDX-FileCopyrightText: 2003 Ignacio CastaƱo <castano@ludicon.com>
0005     SPDX-FileCopyrightText: 2015 Alex Merry <alex.merry@kde.org>
0006     SPDX-FileCopyrightText: 2022-2023 Mirco Miranda <mircomir@outlook.com>
0007 
0008     SPDX-License-Identifier: LGPL-2.0-or-later
0009 */
0010 
0011 /*
0012  * The early version of this code was based on Thacher Ulrich PSD loading code
0013  * released into the public domain. See: http://tulrich.com/geekstuff/
0014  */
0015 
0016 /*
0017  * Documentation on this file format is available at
0018  * http://www.adobe.com/devnet-apps/photoshop/fileformatashtml/
0019  */
0020 
0021 /*
0022  * Limitations of the current code:
0023  * - Color spaces other than RGB/Grayscale cannot be read due to lack of QImage
0024  *   support. Where possible, a conversion to RGB is done:
0025  *   - CMYK images are converted using an approximated way that ignores the color
0026  *     information (ICC profile).
0027  *   - LAB images are converted to sRGB using literature formulas.
0028  *   - MULICHANNEL images more than 3 channels are converted as CMYK images.
0029  *   - DUOTONE images are considered as Grayscale images.
0030  *
0031  *   NOTE: The best way to convert between different color spaces is to use a
0032  *   color management engine (e.g. LittleCMS).
0033  */
0034 
0035 #include "fastmath_p.h"
0036 #include "psd_p.h"
0037 #include "util_p.h"
0038 
0039 #include <QDataStream>
0040 #include <QDebug>
0041 #include <QImage>
0042 #include <QColorSpace>
0043 
0044 #include <cmath>
0045 #include <cstring>
0046 
0047 typedef quint32 uint;
0048 typedef quint16 ushort;
0049 typedef quint8 uchar;
0050 
0051 /* The fast LAB conversion converts the image to linear sRgb instead to sRgb.
0052  * This should not be a problem because the Qt's QColorSpace supports the linear
0053  * sRgb colorspace.
0054  *
0055  * Using linear conversion, the loading speed is slightly improved. Anyway, if you are using
0056  * an software that discard color info, you should comment it.
0057  *
0058  * At the time I'm writing (07/2022), Gwenview and Krita supports linear sRgb but KDE
0059  * preview creator does not. This is the why, for now, it is disabled.
0060  */
0061 //#define PSD_FAST_LAB_CONVERSION
0062 
0063 namespace // Private.
0064 {
0065 
0066 enum Signature : quint32 {
0067     S_8BIM = 0x3842494D, // '8BIM'
0068     S_8B64 = 0x38423634, // '8B64'
0069 
0070     S_MeSa = 0x4D655361   // 'MeSa'
0071 };
0072 
0073 enum ColorMode : quint16 {
0074     CM_BITMAP = 0,
0075     CM_GRAYSCALE = 1,
0076     CM_INDEXED = 2,
0077     CM_RGB = 3,
0078     CM_CMYK = 4,
0079     CM_MULTICHANNEL = 7,
0080     CM_DUOTONE = 8,
0081     CM_LABCOLOR = 9,
0082 };
0083 
0084 enum ImageResourceId : quint16 {
0085     IRI_RESOLUTIONINFO = 0x03ED,
0086     IRI_ICCPROFILE = 0x040F,
0087     IRI_TRANSPARENCYINDEX = 0x0417,
0088     IRI_VERSIONINFO = 0x0421,
0089     IRI_XMPMETADATA = 0x0424
0090 };
0091 
0092 enum LayerId : quint32 {
0093     LI_MT16 = 0x4D743136,   // 'Mt16',
0094     LI_MT32 = 0x4D743332,   // 'Mt32',
0095     LI_MTRN = 0x4D74726E    // 'Mtrn'
0096 };
0097 
0098 struct PSDHeader {
0099     uint signature;
0100     ushort version;
0101     uchar reserved[6];
0102     ushort channel_count;
0103     uint height;
0104     uint width;
0105     ushort depth;
0106     ushort color_mode;
0107 };
0108 
0109 struct PSDImageResourceBlock {
0110     QString name;
0111     QByteArray data;
0112 };
0113 
0114 /*!
0115  * \brief The PSDDuotoneOptions struct
0116  * \note You can decode the duotone data using the "Duotone Options"
0117  * file format found in the "Photoshop File Format" specs.
0118  */
0119 struct PSDDuotoneOptions {
0120     QByteArray data;
0121 };
0122 
0123 /*!
0124  * \brief The PSDColorModeDataSection struct
0125  * Only indexed color and duotone have color mode data.
0126  */
0127 struct PSDColorModeDataSection {
0128     PSDDuotoneOptions duotone;
0129     QList<QRgb> palette;
0130 };
0131 
0132 using PSDImageResourceSection = QHash<quint16, PSDImageResourceBlock>;
0133 
0134 struct PSDLayerInfo {
0135     qint64 size = -1;
0136     qint16 layerCount = 0;
0137 };
0138 
0139 struct PSDGlobalLayerMaskInfo {
0140     qint64 size = -1;
0141 };
0142 
0143 struct PSDAdditionalLayerInfo {
0144     Signature signature = Signature();
0145     LayerId id = LayerId();
0146     qint64 size = -1;
0147 };
0148 
0149 struct PSDLayerAndMaskSection {
0150     qint64 size = -1;
0151     PSDLayerInfo layerInfo;
0152     PSDGlobalLayerMaskInfo globalLayerMaskInfo;
0153     QHash<LayerId, PSDAdditionalLayerInfo> additionalLayerInfo;
0154 
0155     bool isNull() const {
0156         return (size <= 0);
0157     }
0158 
0159     bool hasAlpha() const {
0160         return layerInfo.layerCount < 0 ||
0161                additionalLayerInfo.contains(LI_MT16) ||
0162                additionalLayerInfo.contains(LI_MT32) ||
0163                additionalLayerInfo.contains(LI_MTRN);
0164     }
0165 
0166     bool atEnd(bool isPsb) const {
0167         qint64 currentSize = 0;
0168         if (layerInfo.size > -1) {
0169             currentSize += layerInfo.size + 4;
0170             if (isPsb)
0171                 currentSize += 4;
0172         }
0173         if (globalLayerMaskInfo.size > -1) {
0174             currentSize += globalLayerMaskInfo.size + 4;
0175         }
0176         auto aliv = additionalLayerInfo.values();
0177         for (auto &&v : aliv) {
0178             currentSize += (12 + v.size);
0179             if (v.signature == S_8B64)
0180                 currentSize += 4;
0181         }
0182         return (size <= currentSize);
0183     }
0184 };
0185 
0186 /*!
0187  * \brief fixedPointToDouble
0188  * Converts a fixed point number to floating point one.
0189  */
0190 static double fixedPointToDouble(qint32 fixedPoint)
0191 {
0192     auto i = double(fixedPoint >> 16);
0193     auto d = double((fixedPoint & 0x0000FFFF) / 65536.0);
0194     return (i+d);
0195 }
0196 
0197 static qint64 readSize(QDataStream &s, bool psb = false)
0198 {
0199     qint64 size = 0;
0200     if (!psb) {
0201         quint32 tmp;
0202         s >> tmp;
0203         size = tmp;
0204     }
0205     else {
0206         s >> size;
0207     }
0208     if (s.status() != QDataStream::Ok) {
0209         size = -1;
0210     }
0211     return size;
0212 }
0213 
0214 static bool skip_data(QDataStream &s, qint64 size)
0215 {
0216     // Skip mode data.
0217     for (qint32 i32 = 0; size; size -= i32) {
0218         i32 = std::min(size, qint64(std::numeric_limits<qint32>::max()));
0219         i32 = s.skipRawData(i32);
0220         if (i32 < 1)
0221             return false;
0222     }
0223     return true;
0224 }
0225 
0226 static bool skip_section(QDataStream &s, bool psb = false)
0227 {
0228     auto section_length = readSize(s, psb);
0229     if (section_length < 0)
0230         return false;
0231     return skip_data(s, section_length);
0232 }
0233 
0234 /*!
0235  * \brief readPascalString
0236  * Reads the Pascal string as defined in the PSD specification.
0237  * \param s The stream.
0238  * \param alignBytes Alignment of the string.
0239  * \param size Number of stream bytes used.
0240  * \return The string read.
0241  */
0242 static QString readPascalString(QDataStream &s, qint32 alignBytes = 1, qint32 *size = nullptr)
0243 {
0244     qint32 tmp = 0;
0245     if (size == nullptr)
0246         size = &tmp;
0247 
0248     quint8 stringSize;
0249     s >> stringSize;
0250     *size = sizeof(stringSize);
0251 
0252     QString str;
0253     if (stringSize > 0) {
0254         QByteArray ba;
0255         ba.resize(stringSize);
0256         auto read = s.readRawData(ba.data(), ba.size());
0257         if (read > 0) {
0258             *size += read;
0259             str = QString::fromLatin1(ba);
0260         }
0261     }
0262 
0263     // align
0264     if (alignBytes > 1)
0265         if (auto pad = *size % alignBytes)
0266             *size += s.skipRawData(alignBytes - pad);
0267 
0268     return str;
0269 }
0270 
0271 /*!
0272  * \brief readImageResourceSection
0273  * Reads the image resource section.
0274  * \param s The stream.
0275  * \param ok Pointer to the operation result variable.
0276  * \return The image resource section raw data.
0277  */
0278 static PSDImageResourceSection readImageResourceSection(QDataStream &s, bool *ok = nullptr)
0279 {
0280     PSDImageResourceSection irs;
0281 
0282     bool tmp = true;
0283     if (ok == nullptr)
0284         ok = &tmp;
0285     *ok = true;
0286 
0287     // Section size
0288     qint32 sectioSize;
0289     s >> sectioSize;
0290 
0291     // Reading Image resource block
0292     for (auto size = sectioSize; size > 0;) {
0293         // Length      Description
0294         // -------------------------------------------------------------------
0295         // 4           Signature: '8BIM'
0296         // 2           Unique identifier for the resource. Image resource IDs
0297         //             contains a list of resource IDs used by Photoshop.
0298         // Variable    Name: Pascal string, padded to make the size even
0299         //             (a null name consists of two bytes of 0)
0300         // 4           Actual size of resource data that follows
0301         // Variable    The resource data, described in the sections on the
0302         //             individual resource types. It is padded to make the size
0303         //             even.
0304 
0305         quint32 signature;
0306         s >> signature;
0307         size -= sizeof(signature);
0308         // NOTE: MeSa signature is not documented but found in some old PSD take from Photoshop 7.0 CD.
0309         if (signature != S_8BIM && signature != S_MeSa) { // 8BIM and MeSa
0310             qDebug() << "Invalid Image Resource Block Signature!";
0311             *ok = false;
0312             break;
0313         }
0314 
0315         // id
0316         quint16 id;
0317         s >> id;
0318         size -= sizeof(id);
0319 
0320         // getting data
0321         PSDImageResourceBlock irb;
0322 
0323         // name
0324         qint32 bytes = 0;
0325         irb.name = readPascalString(s, 2, &bytes);
0326         size -= bytes;
0327 
0328         // data read
0329         quint32 dataSize;
0330         s >> dataSize;
0331         size -= sizeof(dataSize);
0332         // NOTE: Qt device::read() and QDataStream::readRawData() could read less data than specified.
0333         //       The read code should be improved.
0334         if (auto dev = s.device())
0335             irb.data = dev->read(dataSize);
0336         auto read = irb.data.size();
0337         if (read > 0)
0338             size -= read;
0339         if (quint32(read) != dataSize) {
0340             qDebug() << "Image Resource Block Read Error!";
0341             *ok = false;
0342             break;
0343         }
0344 
0345         if (auto pad = dataSize % 2) {
0346             auto skipped = s.skipRawData(pad);
0347             if (skipped > 0)
0348                 size -= skipped;
0349         }
0350 
0351         // insert IRB
0352         irs.insert(id, irb);
0353     }
0354 
0355     return irs;
0356 }
0357 
0358 PSDAdditionalLayerInfo readAdditionalLayer(QDataStream &s, bool *ok = nullptr)
0359 {
0360     PSDAdditionalLayerInfo li;
0361 
0362     bool tmp = true;
0363     if (ok == nullptr)
0364         ok = &tmp;
0365 
0366     s >> li.signature;
0367     *ok = li.signature == S_8BIM || li.signature == S_8B64;
0368     if (!*ok)
0369         return li;
0370 
0371     s >> li.id;
0372     *ok = s.status() == QDataStream::Ok;
0373     if (!*ok)
0374         return li;
0375 
0376     li.size = readSize(s, li.signature == S_8B64);
0377     *ok = li.size >= 0;
0378     if (!*ok)
0379         return li;
0380 
0381     *ok = skip_data(s, li.size);
0382 
0383     return li;
0384 }
0385 
0386 PSDLayerAndMaskSection readLayerAndMaskSection(QDataStream &s, bool isPsb, bool *ok = nullptr)
0387 {
0388     PSDLayerAndMaskSection lms;
0389 
0390     bool tmp = true;
0391     if (ok == nullptr)
0392         ok = &tmp;
0393     *ok = true;
0394 
0395     auto device = s.device();
0396     device->startTransaction();
0397 
0398     lms.size = readSize(s, isPsb);
0399 
0400     // read layer info
0401     if (s.status() == QDataStream::Ok && !lms.atEnd(isPsb)) {
0402         lms.layerInfo.size = readSize(s, isPsb);
0403         if (lms.layerInfo.size > 0) {
0404             s >> lms.layerInfo.layerCount;
0405             skip_data(s, lms.layerInfo.size - sizeof(lms.layerInfo.layerCount));
0406         }
0407     }
0408 
0409     // read global layer mask info
0410     if (s.status() == QDataStream::Ok && !lms.atEnd(isPsb)) {
0411         lms.globalLayerMaskInfo.size = readSize(s, false); // always 32-bits
0412         if (lms.globalLayerMaskInfo.size > 0) {
0413             skip_data(s, lms.globalLayerMaskInfo.size);
0414         }
0415     }
0416 
0417     // read additional layer info
0418     if (s.status() == QDataStream::Ok) {
0419         for (bool ok = true; ok && !lms.atEnd(isPsb);) {
0420             auto al = readAdditionalLayer(s, &ok);
0421             if (ok)
0422                 lms.additionalLayerInfo.insert(al.id, al);
0423         }
0424     }
0425 
0426     device->rollbackTransaction();
0427     *ok = skip_section(s, isPsb);
0428     return lms;
0429 }
0430 
0431 /*!
0432  * \brief readColorModeDataSection
0433  * Read the color mode section
0434  * \param s The stream.
0435  * \param ok Pointer to the operation result variable.
0436  * \return The color mode section.
0437  */
0438 PSDColorModeDataSection readColorModeDataSection(QDataStream &s, bool *ok = nullptr)
0439 {
0440     PSDColorModeDataSection cms;
0441 
0442     bool tmp = false;
0443     if (ok == nullptr)
0444         ok = &tmp;
0445     *ok = true;
0446 
0447     qint32 size;
0448     s >> size;
0449     if (size != 768) {  // read the duotone data (524 bytes)
0450         // NOTE: A RGB/Gray float image has a 112 bytes ColorModeData that could be
0451         //       the "32-bit Toning Options" of Photoshop (starts with 'hdrt').
0452         //       Official Adobe specification tells "Only indexed color and duotone
0453         //       (see the mode field in the File header section) have color mode data.".
0454         //       See test case images 32bit_grayscale.psd and 32bit-rgb.psd
0455         cms.duotone.data = s.device()->read(size);
0456         if (cms.duotone.data.size() != size)
0457             *ok = false;
0458     }
0459     else {              // read the palette (768 bytes)
0460         auto&& palette = cms.palette;
0461         QList<quint8> vect(size);
0462         for (auto&& v : vect)
0463             s >> v;
0464         for (qsizetype i = 0, n = vect.size()/3; i < n; ++i)
0465             palette.append(qRgb(vect.at(i), vect.at(n+i), vect.at(n+n+i)));
0466     }
0467 
0468     return cms;
0469 }
0470 
0471 /*!
0472  * \brief setColorSpace
0473  * Set the color space to the image.
0474  * \param img The image.
0475  * \param irs The image resource section.
0476  * \return True on success, otherwise false.
0477  */
0478 static bool setColorSpace(QImage& img, const PSDImageResourceSection& irs)
0479 {
0480     if (!irs.contains(IRI_ICCPROFILE))
0481         return false;
0482     auto irb = irs.value(IRI_ICCPROFILE);
0483     auto cs = QColorSpace::fromIccProfile(irb.data);
0484     if (!cs.isValid())
0485         return false;
0486     img.setColorSpace(cs);
0487     return true;
0488 }
0489 
0490 /*!
0491  * \brief setXmpData
0492  * Adds XMP metadata to QImage.
0493  * \param img The image.
0494  * \param irs The image resource section.
0495  * \return True on success, otherwise false.
0496  */
0497 static bool setXmpData(QImage& img, const PSDImageResourceSection& irs)
0498 {
0499     if (!irs.contains(IRI_XMPMETADATA))
0500         return false;
0501     auto irb = irs.value(IRI_XMPMETADATA);
0502     auto xmp = QString::fromUtf8(irb.data);
0503     if (xmp.isEmpty())
0504         return false;
0505     // NOTE: "XML:com.adobe.xmp" is the meta set by Qt reader when an
0506     //       XMP packet is found (e.g. when reading a PNG saved by Photoshop).
0507     //       I'm reusing the same key because a programs could search for it.
0508     img.setText(QStringLiteral("XML:com.adobe.xmp"), xmp);
0509     return true;
0510 }
0511 
0512 /*!
0513  * \brief hasMergedData
0514  * Checks if merged image data are available.
0515  * \param irs The image resource section.
0516  * \return True on success or if the block does not exist, otherwise false.
0517  */
0518 static bool hasMergedData(const PSDImageResourceSection& irs)
0519 {
0520     if (!irs.contains(IRI_VERSIONINFO))
0521         return true;
0522     auto irb = irs.value(IRI_VERSIONINFO);
0523     if (irb.data.size() > 4)
0524         return irb.data.at(4) != 0;
0525     return false;
0526 }
0527 
0528 /*!
0529  * \brief setResolution
0530  * Set the image resolution.
0531  * \param img The image.
0532  * \param irs The image resource section.
0533  * \return True on success, otherwise false.
0534  */
0535 static bool setResolution(QImage& img, const PSDImageResourceSection& irs)
0536 {
0537     if (!irs.contains(IRI_RESOLUTIONINFO))
0538         return false;
0539     auto irb = irs.value(IRI_RESOLUTIONINFO);
0540 
0541     QDataStream s(irb.data);
0542     s.setByteOrder(QDataStream::BigEndian);
0543 
0544     qint32 i32;
0545     s >> i32;                               // Horizontal resolution in pixels per inch.
0546     if (i32 <= 0)
0547         return false;
0548     auto hres = fixedPointToDouble(i32);
0549 
0550     s.skipRawData(4);                       // Display data (not used here)
0551 
0552     s >> i32;                               // Vertial resolution in pixels per inch.
0553     if (i32 <= 0)
0554         return false;
0555     auto vres = fixedPointToDouble(i32);
0556 
0557     img.setDotsPerMeterX(hres * 1000 / 25.4);
0558     img.setDotsPerMeterY(vres * 1000 / 25.4);
0559     return true;
0560 }
0561 
0562 /*!
0563  * \brief setTransparencyIndex
0564  * Search for transparency index block and, if found, changes the alpha of the value at the given index.
0565  * \param img The image.
0566  * \param irs The image resource section.
0567  * \return True on success, otherwise false.
0568  */
0569 static bool setTransparencyIndex(QImage& img, const PSDImageResourceSection& irs)
0570 {
0571     if (!irs.contains(IRI_TRANSPARENCYINDEX))
0572         return false;
0573     auto irb = irs.value(IRI_TRANSPARENCYINDEX);
0574     QDataStream s(irb.data);
0575     s.setByteOrder(QDataStream::BigEndian);
0576     quint16 idx;
0577     s >> idx;
0578 
0579     auto palette = img.colorTable();
0580     if (idx < palette.size()) {
0581         auto&& v = palette[idx];
0582         v = QRgb(v & ~0xFF000000);
0583         img.setColorTable(palette);
0584         return true;
0585     }
0586 
0587     return false;
0588 }
0589 
0590 static QDataStream &operator>>(QDataStream &s, PSDHeader &header)
0591 {
0592     s >> header.signature;
0593     s >> header.version;
0594     for (int i = 0; i < 6; i++) {
0595         s >> header.reserved[i];
0596     }
0597     s >> header.channel_count;
0598     s >> header.height;
0599     s >> header.width;
0600     s >> header.depth;
0601     s >> header.color_mode;
0602     return s;
0603 }
0604 
0605 // Check that the header is a valid PSD (as written in the PSD specification).
0606 static bool IsValid(const PSDHeader &header)
0607 {
0608     if (header.signature != 0x38425053) { // '8BPS'
0609         //qDebug() << "PSD header: invalid signature" << header.signature;
0610         return false;
0611     }
0612     if (header.version != 1 && header.version != 2) {
0613         qDebug() << "PSD header: invalid version" << header.version;
0614         return false;
0615     }
0616     if (header.depth != 8 &&
0617         header.depth != 16 &&
0618         header.depth != 32 &&
0619         header.depth != 1) {
0620         qDebug() << "PSD header: invalid depth" << header.depth;
0621         return false;
0622     }
0623     if (header.color_mode != CM_RGB &&
0624         header.color_mode != CM_GRAYSCALE &&
0625         header.color_mode != CM_INDEXED &&
0626         header.color_mode != CM_DUOTONE &&
0627         header.color_mode != CM_CMYK &&
0628         header.color_mode != CM_LABCOLOR &&
0629         header.color_mode != CM_MULTICHANNEL &&
0630         header.color_mode != CM_BITMAP) {
0631         qDebug() << "PSD header: invalid color mode" << header.color_mode;
0632         return false;
0633     }
0634     // Specs tells: "Supported range is 1 to 56" but when the alpha channel is present the limit is 57:
0635     // Photoshop does not make you add more (see also 53alphas.psd test case).
0636     if (header.channel_count < 1 || header.channel_count > 57) {
0637         qDebug() << "PSD header: invalid number of channels" << header.channel_count;
0638         return false;
0639     }
0640     if (header.width > 300000 || header.height > 300000) {
0641         qDebug() << "PSD header: invalid image size" << header.width << "x" << header.height;
0642         return false;
0643     }
0644     return true;
0645 }
0646 
0647 // Check that the header is supported by this plugin.
0648 static bool IsSupported(const PSDHeader &header)
0649 {
0650     if (!IsValid(header)) {
0651         return false;
0652     }
0653     if (header.version != 1 && header.version != 2) {
0654         return false;
0655     }
0656     if (header.depth != 8 &&
0657         header.depth != 16 &&
0658         header.depth != 32 &&
0659         header.depth != 1) {
0660         return false;
0661     }
0662     if (header.color_mode != CM_RGB &&
0663         header.color_mode != CM_GRAYSCALE &&
0664         header.color_mode != CM_INDEXED &&
0665         header.color_mode != CM_DUOTONE &&
0666         header.color_mode != CM_CMYK &&
0667         header.color_mode != CM_MULTICHANNEL &&
0668         header.color_mode != CM_LABCOLOR &&
0669         header.color_mode != CM_BITMAP) {
0670         return false;
0671     }
0672     if (header.color_mode == CM_MULTICHANNEL &&
0673         header.channel_count < 3) {
0674         return false;
0675     }
0676     return true;
0677 }
0678 
0679 /*!
0680  * \brief decompress
0681  * Fast PackBits decompression.
0682  * \param input The compressed input buffer.
0683  * \param ilen The input buffer size.
0684  * \param output The uncompressed target buffer.
0685  * \param olen The target buffer size.
0686  * \return The number of valid bytes in the target buffer.
0687  */
0688 qint64 decompress(const char *input, qint64 ilen, char *output, qint64 olen)
0689 {
0690     qint64  j = 0;
0691     for (qint64 ip = 0, rr = 0, available = olen; j < olen && ip < ilen; available = olen - j) {
0692         signed char n = static_cast<signed char>(input[ip++]);
0693         if (n == -128)
0694             continue;
0695 
0696         if (n >= 0) {
0697             rr = qint64(n) + 1;
0698             if (available < rr) {
0699                 --ip;
0700                 break;
0701             }
0702 
0703             if (ip + rr > ilen)
0704                 return -1;
0705             memcpy(output + j, input + ip, size_t(rr));
0706             ip += rr;
0707         }
0708         else if (ip < ilen) {
0709             rr = qint64(1-n);
0710             if (available < rr) {
0711                 --ip;
0712                 break;
0713             }
0714             memset(output + j, input[ip++], size_t(rr));
0715         }
0716 
0717         j += rr;
0718     }
0719     return j;
0720 }
0721 
0722 /*!
0723  * \brief imageFormat
0724  * \param header The PSD header.
0725  * \return The Qt image format.
0726  */
0727 static QImage::Format imageFormat(const PSDHeader &header, bool alpha)
0728 {
0729     if (header.channel_count == 0) {
0730         return QImage::Format_Invalid;
0731     }
0732 
0733     auto format = QImage::Format_Invalid;
0734     switch(header.color_mode) {
0735     case CM_RGB:
0736         if (header.depth == 32)
0737             format = header.channel_count < 4 || !alpha ? QImage::Format_RGBX32FPx4 : QImage::Format_RGBA32FPx4_Premultiplied;
0738         else if (header.depth == 16)
0739             format = header.channel_count < 4 || !alpha ? QImage::Format_RGBX64 : QImage::Format_RGBA64_Premultiplied;
0740         else
0741             format = header.channel_count < 4 || !alpha ? QImage::Format_RGB888 : QImage::Format_RGBA8888_Premultiplied;
0742         break;
0743     case CM_MULTICHANNEL:       // Treat MCH as CMYK (number of channel check is done in IsSupported())
0744     case CM_CMYK:               // Photoshop supports CMYK/MCH 8-bits and 16-bits only
0745         if (header.depth == 16)
0746             format = header.channel_count < 5 || !alpha ? QImage::Format_RGBX64 : QImage::Format_RGBA64;
0747         else if (header.depth == 8)
0748             format = header.channel_count < 5 || !alpha ? QImage::Format_RGB888 : QImage::Format_RGBA8888;
0749         break;
0750     case CM_LABCOLOR:           // Photoshop supports LAB 8-bits and 16-bits only
0751         if (header.depth == 16)
0752             format = header.channel_count < 4 || !alpha ? QImage::Format_RGBX64 : QImage::Format_RGBA64;
0753         else if (header.depth == 8)
0754             format = header.channel_count < 4 || !alpha ? QImage::Format_RGB888 : QImage::Format_RGBA8888;
0755         break;
0756     case CM_GRAYSCALE:
0757     case CM_DUOTONE:
0758         format = header.depth == 8 ? QImage::Format_Grayscale8 : QImage::Format_Grayscale16;
0759         break;
0760     case CM_INDEXED:
0761         format = header.depth == 8 ? QImage::Format_Indexed8 : QImage::Format_Invalid;
0762         break;
0763     case CM_BITMAP:
0764         format = header.depth == 1 ? QImage::Format_Mono : QImage::Format_Invalid;
0765         break;
0766     }
0767     return format;
0768 }
0769 
0770 /*!
0771  * \brief imageChannels
0772  * \param format The Qt image format.
0773  * \return The number of channels of the image format.
0774  */
0775 static qint32 imageChannels(const QImage::Format& format)
0776 {
0777     qint32 c = 4;
0778     switch(format) {
0779     case QImage::Format_RGB888:
0780         c = 3;
0781         break;
0782     case QImage::Format_Grayscale8:
0783     case QImage::Format_Grayscale16:
0784     case QImage::Format_Indexed8:
0785     case QImage::Format_Mono:
0786         c = 1;
0787         break;
0788     default:
0789         break;
0790     }
0791     return c;
0792 }
0793 
0794 inline quint8 xchg(quint8 v)
0795 {
0796     return v;
0797 }
0798 
0799 inline quint16 xchg(quint16 v)
0800 {
0801 #if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
0802     return quint16( (v>>8) | (v<<8) );
0803 #else
0804     return v;   // never tested
0805 #endif
0806 }
0807 
0808 inline quint32 xchg(quint32 v)
0809 {
0810 #if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
0811     return quint32( (v>>24) | ((v & 0x00FF0000)>>8) | ((v & 0x0000FF00)<<8) | (v<<24) );
0812 #else
0813     return v;  // never tested
0814 #endif
0815 }
0816 
0817 inline float xchg(float v)
0818 {
0819 #if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
0820 #   ifdef Q_CC_MSVC
0821     float *pf = &v;
0822     quint32 f = xchg(*reinterpret_cast<quint32*>(pf));
0823     quint32 *pi = &f;
0824     return *reinterpret_cast<float*>(pi);
0825 #   else
0826     quint32 t;
0827     std::memcpy(&t, &v, sizeof(quint32));
0828     t = xchg(t);
0829     std::memcpy(&v, &t, sizeof(quint32));
0830     return v;
0831 #   endif
0832 #else
0833     return v;  // never tested
0834 #endif
0835 }
0836 
0837 template<class T>
0838 inline void planarToChunchy(uchar *target, const char *source, qint32 width, qint32 c, qint32 cn)
0839 {
0840     auto s = reinterpret_cast<const T*>(source);
0841     auto t = reinterpret_cast<T*>(target);
0842     for (qint32 x = 0; x < width; ++x) {
0843         t[x * cn + c] = xchg(s[x]);
0844     }
0845 }
0846 
0847 template<class T>
0848 inline void planarToChunchyFloatToUInt16(uchar *target, const char *source, qint32 width, qint32 c, qint32 cn)
0849 {
0850     auto s = reinterpret_cast<const T*>(source);
0851     auto t = reinterpret_cast<quint16*>(target);
0852     for (qint32 x = 0; x < width; ++x) {
0853         t[x * cn + c] = quint16(std::min(xchg(s[x]) * std::numeric_limits<quint16>::max() + 0.5, double(std::numeric_limits<quint16>::max())));
0854     }
0855 }
0856 
0857 enum class PremulConversion {
0858     PS2P, // Photoshop premul to qimage premul (required by RGB)
0859     PS2A, // Photoshop premul to unassociated alpha (required by RGB, CMYK and L* components of LAB)
0860     PSLab2A // Photoshop premul to unassociated alpha (required by a* and b* components of LAB)
0861 };
0862 
0863 template<class T>
0864 inline void premulConversion(char *stride, qint32 width, qint32 ac, qint32 cn, const PremulConversion &conv)
0865 {
0866     auto s = reinterpret_cast<T*>(stride);
0867     // NOTE: to avoid overflows, max is casted to qint64: that is possible because max is always an integer (even if T is float)
0868     auto max = qint64(std::numeric_limits<T>::is_integer ? std::numeric_limits<T>::max() : 1);
0869 
0870     for (qint32 c = 0; c < ac; ++c) {
0871         if (conv == PremulConversion::PS2P) {
0872             for (qint32 x = 0; x < width; ++x) {
0873                 auto xcn = x * cn;
0874                 auto alpha = *(s + xcn + ac);
0875                 *(s + xcn + c) = *(s + xcn + c) + alpha - max;
0876             }
0877         }
0878         else if (conv == PremulConversion::PS2A || (conv == PremulConversion::PSLab2A && c == 0)) {
0879             for (qint32 x = 0; x < width; ++x) {
0880                 auto xcn = x * cn;
0881                 auto alpha = *(s + xcn + ac);
0882                 if (alpha > 0)
0883                     *(s + xcn + c) = ((*(s + xcn + c) + alpha - max) * max + alpha / 2) / alpha;
0884             }
0885         }
0886         else if (conv == PremulConversion::PSLab2A) {
0887             for (qint32 x = 0; x < width; ++x) {
0888                 auto xcn = x * cn;
0889                 auto alpha = *(s + xcn + ac);
0890                 if (alpha > 0)
0891                     *(s + xcn + c) = ((*(s + xcn + c) + (alpha - max + 1) / 2) * max + alpha / 2) / alpha;
0892             }
0893         }
0894     }
0895 }
0896 
0897 inline void monoInvert(uchar *target, const char* source, qint32 bytes)
0898 {
0899     auto s = reinterpret_cast<const quint8*>(source);
0900     auto t = reinterpret_cast<quint8*>(target);
0901     for (qint32 x = 0; x < bytes; ++x) {
0902         t[x] = ~s[x];
0903     }
0904 }
0905 
0906 template<class T>
0907 inline void rawChannelsCopy(uchar *target, qint32 targetChannels, const char *source, qint32 sourceChannels, qint32 width)
0908 {
0909     auto s = reinterpret_cast<const T*>(source);
0910     auto t = reinterpret_cast<T*>(target);
0911     for (qint32 c = 0, cs = std::min(targetChannels, sourceChannels); c < cs; ++c) {
0912         for (qint32 x = 0; x < width; ++x) {
0913             t[x * targetChannels + c] = s[x * sourceChannels + c];
0914         }
0915     }
0916 }
0917 
0918 template<class T>
0919 inline void cmykToRgb(uchar *target, qint32 targetChannels, const char *source, qint32 sourceChannels, qint32 width, bool alpha = false)
0920 {
0921     auto s = reinterpret_cast<const T*>(source);
0922     auto t = reinterpret_cast<T*>(target);
0923     auto max = double(std::numeric_limits<T>::max());
0924     auto invmax = 1.0 / max; // speed improvements by ~10%
0925 
0926     if (sourceChannels < 3) {
0927         qDebug() << "cmykToRgb: image is not a valid CMY/CMYK!";
0928         return;
0929     }
0930 
0931     for (qint32 w = 0; w < width; ++w) {
0932         auto ps = s + sourceChannels * w;
0933         auto C = 1 - *(ps + 0) * invmax;
0934         auto M = 1 - *(ps + 1) * invmax;
0935         auto Y = 1 - *(ps + 2) * invmax;
0936         auto K = sourceChannels > 3 ? 1 - *(ps + 3) * invmax : 0.0;
0937 
0938         auto pt = t + targetChannels * w;
0939         *(pt + 0) = T(std::min(max - (C * (1 - K) + K) * max + 0.5, max));
0940         *(pt + 1) = T(std::min(max - (M * (1 - K) + K) * max + 0.5, max));
0941         *(pt + 2) = T(std::min(max - (Y * (1 - K) + K) * max + 0.5, max));
0942         if (targetChannels == 4) {
0943             if (sourceChannels >= 5 && alpha)
0944                 *(pt + 3) = *(ps + 4);
0945             else
0946                 *(pt + 3) = std::numeric_limits<T>::max();
0947         }
0948     }
0949 }
0950 
0951 inline double finv(double v)
0952 {
0953     return (v > 6.0 / 29.0 ? v * v * v : (v - 16.0 / 116.0) / 7.787);
0954 }
0955 
0956 inline double gammaCorrection(double linear)
0957 {
0958 #ifdef PSD_FAST_LAB_CONVERSION
0959     return linear;
0960 #else
0961     // Replacing fastPow with std::pow the conversion time is 2/3 times longer: using fastPow
0962     // there are minimal differences in the conversion that are not visually noticeable.
0963     return (linear > 0.0031308 ? 1.055 * fastPow(linear, 1.0 / 2.4) - 0.055 : 12.92 * linear);
0964 #endif
0965 }
0966 
0967 template<class T>
0968 inline void labToRgb(uchar *target, qint32 targetChannels, const char *source, qint32 sourceChannels, qint32 width, bool alpha = false)
0969 {
0970     auto s = reinterpret_cast<const T*>(source);
0971     auto t = reinterpret_cast<T*>(target);
0972     auto max = double(std::numeric_limits<T>::max());
0973     auto invmax = 1.0 / max;
0974 
0975     if (sourceChannels < 3) {
0976         qDebug() << "labToRgb: image is not a valid LAB!";
0977         return;
0978     }
0979 
0980     for (qint32 w = 0; w < width; ++w) {
0981         auto ps = s + sourceChannels * w;
0982         auto L = (*(ps + 0) * invmax) * 100.0;
0983         auto A = (*(ps + 1) * invmax) * 255.0 - 128.0;
0984         auto B = (*(ps + 2) * invmax) * 255.0 - 128.0;
0985 
0986         // converting LAB to XYZ (D65 illuminant)
0987         auto Y = (L + 16.0) * (1.0 / 116.0);
0988         auto X = A * (1.0 / 500.0) + Y;
0989         auto Z = Y - B * (1.0 / 200.0);
0990 
0991         // NOTE: use the constants of the illuminant of the target RGB color space
0992         X = finv(X) * 0.9504;   // D50: * 0.9642
0993         Y = finv(Y) * 1.0000;   // D50: * 1.0000
0994         Z = finv(Z) * 1.0888;   // D50: * 0.8251
0995 
0996         // converting XYZ to sRGB (sRGB illuminant is D65)
0997         auto r = gammaCorrection(  3.24071   * X - 1.53726  * Y - 0.498571  * Z);
0998         auto g = gammaCorrection(- 0.969258  * X + 1.87599  * Y + 0.0415557 * Z);
0999         auto b = gammaCorrection(  0.0556352 * X - 0.203996 * Y + 1.05707   * Z);
1000 
1001         auto pt = t + targetChannels * w;
1002         *(pt + 0) = T(std::max(std::min(r * max + 0.5, max), 0.0));
1003         *(pt + 1) = T(std::max(std::min(g * max + 0.5, max), 0.0));
1004         *(pt + 2) = T(std::max(std::min(b * max + 0.5, max), 0.0));
1005         if (targetChannels == 4) {
1006             if (sourceChannels >= 4 && alpha)
1007                 *(pt + 3) = *(ps + 3);
1008             else
1009                 *(pt + 3) = std::numeric_limits<T>::max();
1010         }
1011     }
1012 }
1013 
1014 bool readChannel(QByteArray& target, QDataStream &stream, quint32 compressedSize, quint16 compression)
1015 {
1016     if (compression) {
1017         if (compressedSize > kMaxQVectorSize) {
1018             return false;
1019         }
1020         QByteArray tmp;
1021         tmp.resize(compressedSize);
1022         if (stream.readRawData(tmp.data(), tmp.size()) != tmp.size()) {
1023             return false;
1024         }
1025         if (decompress(tmp.data(), tmp.size(), target.data(), target.size()) < 0) {
1026             return false;
1027         }
1028     }
1029     else if (stream.readRawData(target.data(), target.size()) != target.size()) {
1030         return false;
1031     }
1032 
1033     return stream.status() == QDataStream::Ok;
1034 }
1035 
1036 // Load the PSD image.
1037 static bool LoadPSD(QDataStream &stream, const PSDHeader &header, QImage &img)
1038 {
1039     // Checking for PSB
1040     auto isPsb = header.version == 2;
1041     bool ok = false;
1042 
1043     // Color Mode Data section
1044     auto cmds = readColorModeDataSection(stream, &ok);
1045     if (!ok) {
1046         qDebug() << "Error while skipping Color Mode Data section";
1047         return false;
1048     }
1049 
1050     // Image Resources Section
1051     auto irs = readImageResourceSection(stream, &ok);
1052     if (!ok) {
1053         qDebug() << "Error while reading Image Resources Section";
1054         return false;
1055     }
1056     // Checking for merged image (Photoshop compatibility data)
1057     if (!hasMergedData(irs)) {
1058         qDebug() << "No merged data found";
1059         return false;
1060     }
1061 
1062     // Layer and Mask section
1063     auto lms = readLayerAndMaskSection(stream, isPsb, &ok);
1064     if (!ok) {
1065         qDebug() << "Error while skipping Layer and Mask section";
1066         return false;
1067     }
1068 
1069     // Find out if the data is compressed.
1070     // Known values:
1071     //   0: no compression
1072     //   1: RLE compressed
1073     quint16 compression;
1074     stream >> compression;
1075     if (compression > 1) {
1076         qDebug() << "Unknown compression type";
1077         return false;
1078     }
1079 
1080     // Try to identify the nature of spots: note that this is just one of many ways to identify the presence
1081     // of alpha channels: should work in most cases where colorspaces != RGB/Gray
1082     auto alpha = header.color_mode == CM_RGB;
1083     if (!lms.isNull())
1084         alpha = lms.hasAlpha();
1085 
1086     const QImage::Format format = imageFormat(header, alpha);
1087     if (format == QImage::Format_Invalid) {
1088         qWarning() << "Unsupported image format. color_mode:" << header.color_mode << "depth:" << header.depth << "channel_count:" << header.channel_count;
1089         return false;
1090     }
1091 
1092     img = imageAlloc(header.width, header.height, format);
1093     if (img.isNull()) {
1094         qWarning() << "Failed to allocate image, invalid dimensions?" << QSize(header.width, header.height);
1095         return false;
1096     }
1097     img.fill(qRgb(0, 0, 0));
1098     if (!cmds.palette.isEmpty()) {
1099         img.setColorTable(cmds.palette);
1100         setTransparencyIndex(img, irs);
1101     }
1102 
1103     auto imgChannels = imageChannels(img.format());
1104     auto channel_num = std::min(qint32(header.channel_count), imgChannels);
1105     auto raw_count = qsizetype(header.width * header.depth + 7) / 8;
1106 
1107     if (header.height > kMaxQVectorSize / header.channel_count / sizeof(quint32)) {
1108         qWarning() << "LoadPSD() header height/channel_count too big" << header.height << header.channel_count;
1109         return false;
1110     }
1111 
1112     QList<quint32> strides(header.height * header.channel_count, raw_count);
1113     // Read the compressed stride sizes
1114     if (compression) {
1115         for (auto&& v : strides) {
1116             if (isPsb) {
1117                 stream >> v;
1118                 continue;
1119             }
1120             quint16 tmp;
1121             stream >> tmp;
1122             v = tmp;
1123         }
1124     }
1125     // calculate the absolute file positions of each stride (required when a colorspace conversion should be done)
1126     auto device = stream.device();
1127     QList<quint64> stridePositions(strides.size());
1128     if (!stridePositions.isEmpty()) {
1129         stridePositions[0] = device->pos();
1130     }
1131     for (qsizetype i = 1, n = stridePositions.size(); i < n; ++i) {
1132         stridePositions[i] = stridePositions[i-1] + strides.at(i-1);
1133     }
1134 
1135     // Read the image
1136     QByteArray rawStride;
1137     rawStride.resize(raw_count);
1138 
1139     // clang-format off
1140     // checks the need of color conversion (that requires random access to the image)
1141     auto randomAccess = (header.color_mode == CM_CMYK) ||
1142                         (header.color_mode == CM_LABCOLOR) ||
1143                         (header.color_mode == CM_MULTICHANNEL) ||
1144                         (header.color_mode != CM_INDEXED && img.hasAlphaChannel());
1145     // clang-format on
1146 
1147     if (randomAccess) {
1148         // In order to make a colorspace transformation, we need all channels of a scanline
1149         QByteArray psdScanline;
1150         psdScanline.resize(qsizetype(header.width * header.depth * header.channel_count + 7) / 8);
1151         for (qint32 y = 0, h = header.height; y < h; ++y) {
1152             for (qint32 c = 0; c < header.channel_count; ++c) {
1153                 auto strideNumber = c * qsizetype(h) + y;
1154                 if (!device->seek(stridePositions.at(strideNumber))) {
1155                     qDebug() << "Error while seeking the stream of channel" << c << "line" << y;
1156                     return false;
1157                 }
1158                 auto&& strideSize = strides.at(strideNumber);
1159                 if (!readChannel(rawStride, stream, strideSize, compression)) {
1160                     qDebug() << "Error while reading the stream of channel" << c << "line" << y;
1161                     return false;
1162                 }
1163 
1164                 auto scanLine = reinterpret_cast<unsigned char*>(psdScanline.data());
1165                 if (header.depth == 8) {
1166                     planarToChunchy<quint8>(scanLine, rawStride.data(), header.width, c, header.channel_count);
1167                 }
1168                 else if (header.depth == 16) {
1169                     planarToChunchy<quint16>(scanLine, rawStride.data(), header.width, c, header.channel_count);
1170                 }
1171                 else if (header.depth == 32) {
1172                     planarToChunchy<float>(scanLine, rawStride.data(), header.width, c, header.channel_count);
1173                 }
1174             }
1175 
1176             // Convert premultiplied data to unassociated data
1177             if (img.hasAlphaChannel()) {
1178                 auto scanLine = reinterpret_cast<char*>(psdScanline.data());
1179                 if (header.color_mode == CM_CMYK) {
1180                     if (header.depth == 8)
1181                         premulConversion<quint8>(scanLine, header.width, 4, header.channel_count, PremulConversion::PS2A);
1182                     else if (header.depth == 16)
1183                         premulConversion<quint16>(scanLine, header.width, 4, header.channel_count, PremulConversion::PS2A);
1184                 }
1185                 if (header.color_mode == CM_LABCOLOR) {
1186                     if (header.depth == 8)
1187                         premulConversion<quint8>(scanLine, header.width, 3, header.channel_count, PremulConversion::PSLab2A);
1188                     else if (header.depth == 16)
1189                         premulConversion<quint16>(scanLine, header.width, 3, header.channel_count, PremulConversion::PSLab2A);
1190                 }
1191                 if (header.color_mode == CM_RGB) {
1192                     if (header.depth == 8)
1193                         premulConversion<quint8>(scanLine, header.width, 3, header.channel_count, PremulConversion::PS2P);
1194                     else if (header.depth == 16)
1195                         premulConversion<quint16>(scanLine, header.width, 3, header.channel_count, PremulConversion::PS2P);
1196                     else if (header.depth == 32)
1197                         premulConversion<float>(scanLine, header.width, 3, header.channel_count, PremulConversion::PS2P);
1198                 }
1199             }
1200 
1201             // Conversion to RGB
1202             if (header.color_mode == CM_CMYK || header.color_mode == CM_MULTICHANNEL) {
1203                 if (header.depth == 8)
1204                     cmykToRgb<quint8>(img.scanLine(y), imgChannels, psdScanline.data(), header.channel_count, header.width, alpha);
1205                 else if (header.depth == 16)
1206                     cmykToRgb<quint16>(img.scanLine(y), imgChannels, psdScanline.data(), header.channel_count, header.width, alpha);
1207             }
1208             if (header.color_mode == CM_LABCOLOR) {
1209                 if (header.depth == 8)
1210                     labToRgb<quint8>(img.scanLine(y), imgChannels, psdScanline.data(), header.channel_count, header.width, alpha);
1211                 else if (header.depth == 16)
1212                     labToRgb<quint16>(img.scanLine(y), imgChannels, psdScanline.data(), header.channel_count, header.width, alpha);
1213             }
1214             if (header.color_mode == CM_RGB) {
1215                 if (header.depth == 8)
1216                     rawChannelsCopy<quint8>(img.scanLine(y), imgChannels, psdScanline.data(), header.channel_count, header.width);
1217                 else if (header.depth == 16)
1218                     rawChannelsCopy<quint16>(img.scanLine(y), imgChannels, psdScanline.data(), header.channel_count, header.width);
1219                 else if (header.depth == 32)
1220                     rawChannelsCopy<float>(img.scanLine(y), imgChannels, psdScanline.data(), header.channel_count, header.width);
1221             }
1222         }
1223     }
1224     else {
1225         // Linear read (no position jumps): optimized code usable only for the colorspaces supported by QImage
1226         for (qint32 c = 0; c < channel_num; ++c) {
1227             for (qint32 y = 0, h = header.height; y < h; ++y) {
1228                 auto&& strideSize = strides.at(c * qsizetype(h) + y);
1229                 if (!readChannel(rawStride, stream, strideSize, compression)) {
1230                     qDebug() << "Error while reading the stream of channel" << c << "line" << y;
1231                     return false;
1232                 }
1233 
1234                 auto scanLine = img.scanLine(y);
1235                 if (header.depth == 1) { // Bitmap
1236                     monoInvert(scanLine, rawStride.data(), std::min(rawStride.size(), img.bytesPerLine()));
1237                 }
1238                 else if (header.depth == 8) { // 8-bits images: Indexed, Grayscale, RGB/RGBA
1239                     planarToChunchy<quint8>(scanLine, rawStride.data(), header.width, c, imgChannels);
1240                 }
1241                 else if (header.depth == 16) { // 16-bits integer images: Grayscale, RGB/RGBA
1242                     planarToChunchy<quint16>(scanLine, rawStride.data(), header.width, c, imgChannels);
1243                 }
1244                 else if (header.depth == 32 && header.color_mode == CM_RGB) { // 32-bits float images: RGB/RGBA
1245                     planarToChunchy<float>(scanLine, rawStride.data(), header.width, c, imgChannels);
1246                 }
1247                 else if (header.depth == 32 && header.color_mode == CM_GRAYSCALE) { // 32-bits float images: Grayscale (coverted to equivalent integer 16-bits)
1248                     planarToChunchyFloatToUInt16<float>(scanLine, rawStride.data(), header.width, c, imgChannels);
1249                 }
1250             }
1251         }
1252     }
1253 
1254 
1255     // Resolution info
1256     if (!setResolution(img, irs)) {
1257         // qDebug() << "No resolution info found!";
1258     }
1259 
1260     // ICC profile
1261     if (header.color_mode == CM_LABCOLOR) {
1262         // LAB conversion generates a sRGB image
1263 #ifdef PSD_FAST_LAB_CONVERSION
1264         img.setColorSpace(QColorSpace(QColorSpace::SRgbLinear));
1265 #else
1266         img.setColorSpace(QColorSpace(QColorSpace::SRgb));
1267 #endif
1268     }
1269     else if (!setColorSpace(img, irs)) {
1270         // qDebug() << "No colorspace info set!";
1271     }
1272 
1273     // XMP data
1274     if (!setXmpData(img, irs)) {
1275         // qDebug() << "No XMP data found!";
1276     }
1277 
1278     // Duotone images: color data contains the duotone specification (not documented).
1279     // Other applications that read Photoshop files can treat a duotone image as a gray image,
1280     // and just preserve the contents of the duotone information when reading and writing the file.
1281     if (!cmds.duotone.data.isEmpty()) {
1282         img.setText(QStringLiteral("PSDDuotoneOptions"), QString::fromUtf8(cmds.duotone.data.toHex()));
1283     }
1284 
1285     return true;
1286 }
1287 
1288 } // Private
1289 
1290 PSDHandler::PSDHandler()
1291 {
1292 }
1293 
1294 bool PSDHandler::canRead() const
1295 {
1296     if (canRead(device())) {
1297         setFormat("psd");
1298         return true;
1299     }
1300     return false;
1301 }
1302 
1303 bool PSDHandler::read(QImage *image)
1304 {
1305     QDataStream s(device());
1306     s.setByteOrder(QDataStream::BigEndian);
1307 
1308     PSDHeader header;
1309     s >> header;
1310 
1311     // Check image file format.
1312     if (s.atEnd() || !IsValid(header)) {
1313         //         qDebug() << "This PSD file is not valid.";
1314         return false;
1315     }
1316 
1317     // Check if it's a supported format.
1318     if (!IsSupported(header)) {
1319         //         qDebug() << "This PSD file is not supported.";
1320         return false;
1321     }
1322 
1323     QImage img;
1324     if (!LoadPSD(s, header, img)) {
1325         //         qDebug() << "Error loading PSD file.";
1326         return false;
1327     }
1328 
1329     *image = img;
1330     return true;
1331 }
1332 
1333 bool PSDHandler::supportsOption(ImageOption option) const
1334 {
1335     if (option == QImageIOHandler::Size)
1336         return true;
1337     return false;
1338 }
1339 
1340 QVariant PSDHandler::option(ImageOption option) const
1341 {
1342     QVariant v;
1343 
1344     if (option == QImageIOHandler::Size) {
1345         if (auto d = device()) {
1346             // transactions works on both random and sequential devices
1347             d->startTransaction();
1348             auto ba = d->read(sizeof(PSDHeader));
1349             d->rollbackTransaction();
1350 
1351             QDataStream s(ba);
1352             s.setByteOrder(QDataStream::BigEndian);
1353 
1354             PSDHeader header;
1355             s >> header;
1356 
1357             if (s.status() == QDataStream::Ok && IsValid(header))
1358                 v = QVariant::fromValue(QSize(header.width, header.height));
1359         }
1360     }
1361 
1362     return v;
1363 }
1364 
1365 bool PSDHandler::canRead(QIODevice *device)
1366 {
1367     if (!device) {
1368         qWarning("PSDHandler::canRead() called with no device");
1369         return false;
1370     }
1371 
1372     device->startTransaction();
1373 
1374     QDataStream s(device);
1375     s.setByteOrder(QDataStream::BigEndian);
1376 
1377     PSDHeader header;
1378     s >> header;
1379 
1380     device->rollbackTransaction();
1381 
1382     if (s.status() != QDataStream::Ok) {
1383         return false;
1384     }
1385 
1386     if (device->isSequential()) {
1387         if (header.color_mode == CM_CMYK || header.color_mode == CM_LABCOLOR || header.color_mode == CM_MULTICHANNEL) {
1388             return false;
1389         }
1390         if (header.color_mode == CM_RGB && header.channel_count > 3) {
1391             return false; // supposing extra channel as alpha
1392         }
1393     }
1394 
1395     return IsSupported(header);
1396 }
1397 
1398 QImageIOPlugin::Capabilities PSDPlugin::capabilities(QIODevice *device, const QByteArray &format) const
1399 {
1400     if (format == "psd" || format == "psb" || format == "pdd" || format == "psdt") {
1401         return Capabilities(CanRead);
1402     }
1403     if (!format.isEmpty()) {
1404         return {};
1405     }
1406     if (!device->isOpen()) {
1407         return {};
1408     }
1409 
1410     Capabilities cap;
1411     if (device->isReadable() && PSDHandler::canRead(device)) {
1412         cap |= CanRead;
1413     }
1414     return cap;
1415 }
1416 
1417 QImageIOHandler *PSDPlugin::create(QIODevice *device, const QByteArray &format) const
1418 {
1419     QImageIOHandler *handler = new PSDHandler;
1420     handler->setDevice(device);
1421     handler->setFormat(format);
1422     return handler;
1423 }
1424 
1425 #include "moc_psd_p.cpp"