Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package kimageformats for openSUSE:Factory 
checked in at 2022-05-16 18:06:58
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/kimageformats (Old)
 and      /work/SRC/openSUSE:Factory/.kimageformats.new.1538 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "kimageformats"

Mon May 16 18:06:58 2022 rev:106 rq:977178 version:5.94.0

Changes:
--------
--- /work/SRC/openSUSE:Factory/kimageformats/kimageformats.changes      
2022-04-11 23:48:35.951512248 +0200
+++ /work/SRC/openSUSE:Factory/.kimageformats.new.1538/kimageformats.changes    
2022-05-16 18:08:47.797289923 +0200
@@ -1,0 +2,23 @@
+Tue May 10 08:17:59 UTC 2022 - Christophe Giboudeaux <[email protected]>
+
+- Update to 5.94.0
+  * New feature release
+  * For more details please see:
+  * https://kde.org/announcements/frameworks/5/5.94.0
+- Changes since 5.93.0:
+  * avif: prepare for breaking change in libavif
+  * XCF: Support to QImageIOHandler::Size option
+  * Support to QImageIOHandler::Size option
+  * QByteArray resize removal
+  * psd: Fix crash on broken files
+  * psd: duotone read
+  * psd: Don't crash with broken images
+  * psd: Header depth has to be 8 for CM_INDEXED color_mode
+  * psd: Protect against broken images
+  * psd: Don't abort on broken images
+  * avif: lossless support
+  * psd: Don't assert on broken files
+  * Add windows CI
+  * PSD: Performance improvements and support to missing common formats
+
+-------------------------------------------------------------------

Old:
----
  kimageformats-5.93.0.tar.xz
  kimageformats-5.93.0.tar.xz.sig

New:
----
  kimageformats-5.94.0.tar.xz
  kimageformats-5.94.0.tar.xz.sig

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ kimageformats.spec ++++++
--- /var/tmp/diff_new_pack.WsRoLz/_old  2022-05-16 18:08:48.397290491 +0200
+++ /var/tmp/diff_new_pack.WsRoLz/_new  2022-05-16 18:08:48.401290494 +0200
@@ -22,7 +22,7 @@
 %if 0%{?suse_version} > 1500 || (0%{?is_opensuse} && 0%{?sle_version} >= 
150300)
 %define with_heif 1
 %endif
-%define _tar_path 5.93
+%define _tar_path 5.94
 # Full KF5 version (e.g. 5.33.0)
 %{!?_kf5_version: %global _kf5_version %{version}}
 # Last major and minor KF5 version (e.g. 5.33)
@@ -30,7 +30,7 @@
 # Only needed for the package signature condition
 %bcond_without released
 Name:           kimageformats
-Version:        5.93.0
+Version:        5.94.0
 Release:        0
 Summary:        Image format plugins for Qt
 License:        LGPL-2.1-or-later


++++++ kimageformats-5.93.0.tar.xz -> kimageformats-5.94.0.tar.xz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/kimageformats-5.93.0/.gitlab-ci.yml 
new/kimageformats-5.94.0/.gitlab-ci.yml
--- old/kimageformats-5.93.0/.gitlab-ci.yml     2022-04-02 12:00:12.000000000 
+0200
+++ new/kimageformats-5.94.0/.gitlab-ci.yml     2022-05-02 11:46:37.000000000 
+0200
@@ -7,3 +7,4 @@
   - 
https://invent.kde.org/sysadmin/ci-utilities/raw/master/gitlab-templates/freebsd.yml
   - 
https://invent.kde.org/sysadmin/ci-utilities/raw/master/gitlab-templates/linux-qt6.yml
   - 
https://invent.kde.org/sysadmin/ci-utilities/raw/master/gitlab-templates/android-qt6.yml
+  - 
https://invent.kde.org/sysadmin/ci-utilities/raw/master/gitlab-templates/windows.yml
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/kimageformats-5.93.0/README.md 
new/kimageformats-5.94.0/README.md
--- old/kimageformats-5.93.0/README.md  2022-04-02 12:00:12.000000000 +0200
+++ new/kimageformats-5.94.0/README.md  2022-05-02 11:46:37.000000000 +0200
@@ -16,7 +16,7 @@
 - Animated Windows cursors (ani)
 - Gimp (xcf)
 - OpenEXR (exr)
-- Photoshop documents (psd)
+- Photoshop documents (psd, psb, pdd, psdt)
 - Sun Raster (ras)
 
 The following image formats have read and write support:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/kimageformats-5.93.0/autotests/CMakeLists.txt 
new/kimageformats-5.94.0/autotests/CMakeLists.txt
--- old/kimageformats-5.93.0/autotests/CMakeLists.txt   2022-04-02 
12:00:12.000000000 +0200
+++ new/kimageformats-5.94.0/autotests/CMakeLists.txt   2022-05-02 
11:46:37.000000000 +0200
@@ -86,8 +86,7 @@
     kimageformats_read_tests(
         avif
     )
-    # because the plug-ins use RGB->YUV conversion which sometimes results in 
1 value difference.
-    kimageformats_write_tests(FUZZ 1
+    kimageformats_write_tests(
         avif-nodatacheck-lossless
     )
 endif()
Binary files old/kimageformats-5.93.0/autotests/read/psd/16bit_grayscale.png 
and new/kimageformats-5.94.0/autotests/read/psd/16bit_grayscale.png differ
Binary files old/kimageformats-5.93.0/autotests/read/psd/16bit_grayscale.psd 
and new/kimageformats-5.94.0/autotests/read/psd/16bit_grayscale.psd differ
Binary files old/kimageformats-5.93.0/autotests/read/psd/16bit_photoshop.png 
and new/kimageformats-5.94.0/autotests/read/psd/16bit_photoshop.png differ
Binary files old/kimageformats-5.93.0/autotests/read/psd/16bit_photoshop.psb 
and new/kimageformats-5.94.0/autotests/read/psd/16bit_photoshop.psb differ
Binary files old/kimageformats-5.93.0/autotests/read/psd/32bit-rgb.png and 
new/kimageformats-5.94.0/autotests/read/psd/32bit-rgb.png differ
Binary files old/kimageformats-5.93.0/autotests/read/psd/32bit-rgb.psd and 
new/kimageformats-5.94.0/autotests/read/psd/32bit-rgb.psd differ
Binary files old/kimageformats-5.93.0/autotests/read/psd/32bit_grayscale.png 
and new/kimageformats-5.94.0/autotests/read/psd/32bit_grayscale.png differ
Binary files old/kimageformats-5.93.0/autotests/read/psd/32bit_grayscale.psd 
and new/kimageformats-5.94.0/autotests/read/psd/32bit_grayscale.psd differ
Binary files old/kimageformats-5.93.0/autotests/read/psd/8bit-grayscale.png and 
new/kimageformats-5.94.0/autotests/read/psd/8bit-grayscale.png differ
Binary files old/kimageformats-5.93.0/autotests/read/psd/8bit-grayscale.psd and 
new/kimageformats-5.94.0/autotests/read/psd/8bit-grayscale.psd differ
Binary files old/kimageformats-5.93.0/autotests/read/psd/8bit-photoshop.png and 
new/kimageformats-5.94.0/autotests/read/psd/8bit-photoshop.png differ
Binary files old/kimageformats-5.93.0/autotests/read/psd/8bit-photoshop.psb and 
new/kimageformats-5.94.0/autotests/read/psd/8bit-photoshop.psb differ
Binary files old/kimageformats-5.93.0/autotests/read/psd/adobehq-2_5.png and 
new/kimageformats-5.94.0/autotests/read/psd/adobehq-2_5.png differ
Binary files old/kimageformats-5.93.0/autotests/read/psd/adobehq-2_5.psd and 
new/kimageformats-5.94.0/autotests/read/psd/adobehq-2_5.psd differ
Binary files old/kimageformats-5.93.0/autotests/read/psd/birthday.pdd and 
new/kimageformats-5.94.0/autotests/read/psd/birthday.pdd differ
Binary files old/kimageformats-5.93.0/autotests/read/psd/birthday.png and 
new/kimageformats-5.94.0/autotests/read/psd/birthday.png differ
Binary files old/kimageformats-5.93.0/autotests/read/psd/bitmap.png and 
new/kimageformats-5.94.0/autotests/read/psd/bitmap.png differ
Binary files old/kimageformats-5.93.0/autotests/read/psd/bitmap.psd and 
new/kimageformats-5.94.0/autotests/read/psd/bitmap.psd differ
Binary files old/kimageformats-5.93.0/autotests/read/psd/duotone.png and 
new/kimageformats-5.94.0/autotests/read/psd/duotone.png differ
Binary files old/kimageformats-5.93.0/autotests/read/psd/duotone.psb and 
new/kimageformats-5.94.0/autotests/read/psd/duotone.psb differ
Binary files old/kimageformats-5.93.0/autotests/read/psd/indexed.png and 
new/kimageformats-5.94.0/autotests/read/psd/indexed.png differ
Binary files old/kimageformats-5.93.0/autotests/read/psd/indexed.psd and 
new/kimageformats-5.94.0/autotests/read/psd/indexed.psd differ
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/kimageformats-5.93.0/src/imageformats/avif.cpp 
new/kimageformats-5.94.0/src/imageformats/avif.cpp
--- old/kimageformats-5.93.0/src/imageformats/avif.cpp  2022-04-02 
12:00:12.000000000 +0200
+++ new/kimageformats-5.94.0/src/imageformats/avif.cpp  2022-05-02 
11:46:37.000000000 +0200
@@ -452,8 +452,13 @@
         return false;
     }
 
-    if (m_quality >= 100 && !avifCodecName(AVIF_CODEC_CHOICE_AOM, 
AVIF_CODEC_FLAG_CAN_ENCODE)) {
-        qWarning("You are using %s encoder. It is recommended to enable libAOM 
encoder in libavif for better near-lossless compression.", encoder_name);
+    bool lossless = false;
+    if (m_quality >= 100) {
+        if (avifCodecName(AVIF_CODEC_CHOICE_AOM, AVIF_CODEC_FLAG_CAN_ENCODE)) {
+            lossless = true;
+        } else {
+            qWarning("You are using %s encoder. It is recommended to enable 
libAOM encoder in libavif to use lossless compression.", encoder_name);
+        }
     }
 
     int maxQuantizer = AVIF_QUANTIZER_WORST_QUALITY * (100 - qBound(0, 
m_quality, 100)) / 100;
@@ -648,43 +653,47 @@
 
             // in case primaries or trc were not identified
             if ((primaries_to_save == 2) || (transfer_to_save == 2)) {
-                // upgrade image to higher bit depth
-                if (save_depth == 8) {
-                    save_depth = 10;
-                    if (tmpcolorimage.hasAlphaChannel()) {
-                        tmpcolorimage = 
tmpcolorimage.convertToFormat(QImage::Format_RGBA64);
-                    } else {
-                        tmpcolorimage = 
tmpcolorimage.convertToFormat(QImage::Format_RGBX64);
+                if (lossless) {
+                    iccprofile = tmpcolorimage.colorSpace().iccProfile();
+                } else {
+                    // upgrade image to higher bit depth
+                    if (save_depth == 8) {
+                        save_depth = 10;
+                        if (tmpcolorimage.hasAlphaChannel()) {
+                            tmpcolorimage = 
tmpcolorimage.convertToFormat(QImage::Format_RGBA64);
+                        } else {
+                            tmpcolorimage = 
tmpcolorimage.convertToFormat(QImage::Format_RGBX64);
+                        }
                     }
-                }
 
-                if ((primaries_to_save == 2) && (transfer_to_save != 2)) { // 
other primaries but known trc
-                    primaries_to_save = (avifColorPrimaries)1; // 
AVIF_COLOR_PRIMARIES_BT709
-                    matrix_to_save = (avifMatrixCoefficients)1; // 
AVIF_MATRIX_COEFFICIENTS_BT709
-
-                    switch (transfer_to_save) {
-                    case 8: // AVIF_TRANSFER_CHARACTERISTICS_LINEAR
-                        
tmpcolorimage.convertToColorSpace(QColorSpace(QColorSpace::Primaries::SRgb, 
QColorSpace::TransferFunction::Linear));
-                        break;
-                    case 4: // AVIF_TRANSFER_CHARACTERISTICS_BT470M
-                        
tmpcolorimage.convertToColorSpace(QColorSpace(QColorSpace::Primaries::SRgb, 
2.2f));
-                        break;
-                    case 5: // AVIF_TRANSFER_CHARACTERISTICS_BT470BG
-                        
tmpcolorimage.convertToColorSpace(QColorSpace(QColorSpace::Primaries::SRgb, 
2.8f));
-                        break;
-                    default: // AVIF_TRANSFER_CHARACTERISTICS_SRGB + any other
-                        
tmpcolorimage.convertToColorSpace(QColorSpace(QColorSpace::Primaries::SRgb, 
QColorSpace::TransferFunction::SRgb));
+                    if ((primaries_to_save == 2) && (transfer_to_save != 2)) { 
// other primaries but known trc
+                        primaries_to_save = (avifColorPrimaries)1; // 
AVIF_COLOR_PRIMARIES_BT709
+                        matrix_to_save = (avifMatrixCoefficients)1; // 
AVIF_MATRIX_COEFFICIENTS_BT709
+
+                        switch (transfer_to_save) {
+                        case 8: // AVIF_TRANSFER_CHARACTERISTICS_LINEAR
+                            
tmpcolorimage.convertToColorSpace(QColorSpace(QColorSpace::Primaries::SRgb, 
QColorSpace::TransferFunction::Linear));
+                            break;
+                        case 4: // AVIF_TRANSFER_CHARACTERISTICS_BT470M
+                            
tmpcolorimage.convertToColorSpace(QColorSpace(QColorSpace::Primaries::SRgb, 
2.2f));
+                            break;
+                        case 5: // AVIF_TRANSFER_CHARACTERISTICS_BT470BG
+                            
tmpcolorimage.convertToColorSpace(QColorSpace(QColorSpace::Primaries::SRgb, 
2.8f));
+                            break;
+                        default: // AVIF_TRANSFER_CHARACTERISTICS_SRGB + any 
other
+                            
tmpcolorimage.convertToColorSpace(QColorSpace(QColorSpace::Primaries::SRgb, 
QColorSpace::TransferFunction::SRgb));
+                            transfer_to_save = (avifTransferCharacteristics)13;
+                            break;
+                        }
+                    } else if ((primaries_to_save != 2) && (transfer_to_save 
== 2)) { // recognized primaries but other trc
                         transfer_to_save = (avifTransferCharacteristics)13;
-                        break;
+                        
tmpcolorimage.convertToColorSpace(tmpcolorimage.colorSpace().withTransferFunction(QColorSpace::TransferFunction::SRgb));
+                    } else { // unrecognized profile
+                        primaries_to_save = (avifColorPrimaries)1; // 
AVIF_COLOR_PRIMARIES_BT709
+                        transfer_to_save = (avifTransferCharacteristics)13;
+                        matrix_to_save = (avifMatrixCoefficients)1; // 
AVIF_MATRIX_COEFFICIENTS_BT709
+                        
tmpcolorimage.convertToColorSpace(QColorSpace(QColorSpace::Primaries::SRgb, 
QColorSpace::TransferFunction::SRgb));
                     }
-                } else if ((primaries_to_save != 2) && (transfer_to_save == 
2)) { // recognized primaries but other trc
-                    transfer_to_save = (avifTransferCharacteristics)13;
-                    
tmpcolorimage.convertToColorSpace(tmpcolorimage.colorSpace().withTransferFunction(QColorSpace::TransferFunction::SRgb));
-                } else { // unrecognized profile
-                    primaries_to_save = (avifColorPrimaries)1; // 
AVIF_COLOR_PRIMARIES_BT709
-                    transfer_to_save = (avifTransferCharacteristics)13;
-                    matrix_to_save = (avifMatrixCoefficients)1; // 
AVIF_MATRIX_COEFFICIENTS_BT709
-                    
tmpcolorimage.convertToColorSpace(QColorSpace(QColorSpace::Primaries::SRgb, 
QColorSpace::TransferFunction::SRgb));
                 }
             }
         } else { // profile is unsupported by Qt
@@ -694,6 +703,9 @@
             }
         }
 
+        if (lossless && pixel_format == AVIF_PIXEL_FORMAT_YUV444) {
+            matrix_to_save = (avifMatrixCoefficients)0;
+        }
         avif = avifImageCreate(tmpcolorimage.width(), tmpcolorimage.height(), 
save_depth, pixel_format);
         avif->matrixCoefficients = matrix_to_save;
 
@@ -712,9 +724,7 @@
         if (save_depth > 8) { // 10bit depth
             rgb.depth = 16;
 
-            if (tmpcolorimage.hasAlphaChannel()) {
-                avif->alphaRange = AVIF_RANGE_FULL;
-            } else {
+            if (!tmpcolorimage.hasAlphaChannel()) {
                 rgb.ignoreAlpha = AVIF_TRUE;
             }
 
@@ -724,7 +734,6 @@
 
             if (tmpcolorimage.hasAlphaChannel()) {
                 rgb.format = AVIF_RGB_FORMAT_RGBA;
-                avif->alphaRange = AVIF_RANGE_FULL;
             } else {
                 rgb.format = AVIF_RGB_FORMAT_RGB;
             }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/kimageformats-5.93.0/src/imageformats/psd.cpp 
new/kimageformats-5.94.0/src/imageformats/psd.cpp
--- old/kimageformats-5.93.0/src/imageformats/psd.cpp   2022-04-02 
12:00:12.000000000 +0200
+++ new/kimageformats-5.94.0/src/imageformats/psd.cpp   2022-05-02 
11:46:37.000000000 +0200
@@ -3,6 +3,7 @@
 
     SPDX-FileCopyrightText: 2003 Ignacio Casta??o <[email protected]>
     SPDX-FileCopyrightText: 2015 Alex Merry <[email protected]>
+    SPDX-FileCopyrightText: 2022 Mirco Miranda 
<[email protected]>
 
     SPDX-License-Identifier: LGPL-2.0-or-later
 */
@@ -17,13 +18,27 @@
  * http://www.adobe.com/devnet-apps/photoshop/fileformatashtml/
  */
 
+/*
+ * Limitations of the current code:
+ * - 32-bit float image are converted to 16-bit integer image.
+ *   NOTE: Qt 6.2 allow 32-bit float images (RGB only)
+ * - Other color spaces cannot be read due to lack of QImage support for
+ *   color spaces other than RGB (and Grayscale): a conversion to
+ *   RGB must be done.
+ *   - The best way to convert between different color spaces is to use a
+ *     color management engine (e.g. LittleCMS).
+ *   - An approximate way is to ignore the color information and use
+ *     literature formulas (possible but not recommended).
+ */
+
 #include "psd_p.h"
 
-#include "rle_p.h"
+#include "util_p.h"
 
 #include <QDataStream>
 #include <QDebug>
 #include <QImage>
+#include <QColorSpace>
 
 typedef quint32 uint;
 typedef quint16 ushort;
@@ -42,6 +57,14 @@
     CM_LABCOLOR = 9,
 };
 
+enum ImageResourceId : quint16 {
+    IRI_RESOLUTIONINFO = 0x03ED,
+    IRI_ICCPROFILE = 0x040F,
+    IRI_TRANSPARENCYINDEX = 0x0417,
+    IRI_VERSIONINFO = 0x0421,
+    IRI_XMPMETADATA = 0x0424
+};
+
 struct PSDHeader {
     uint signature;
     ushort version;
@@ -53,6 +76,339 @@
     ushort color_mode;
 };
 
+struct PSDImageResourceBlock {
+    QString name;
+    QByteArray data;
+};
+
+/*!
+ * \brief The PSDDuotoneOptions struct
+ * \note You can decode the duotone data using the "Duotone Options"
+ * file format found in the "Photoshop File Format" specs.
+ */
+struct PSDDuotoneOptions {
+    QByteArray data;
+};
+
+/*!
+ * \brief The PSDColorModeDataSection struct
+ * Only indexed color and duotone have color mode data.
+ */
+struct PSDColorModeDataSection {
+    PSDDuotoneOptions duotone;
+    QVector<QRgb> palette;
+};
+
+using PSDImageResourceSection = QHash<quint16, PSDImageResourceBlock>;
+
+/*!
+ * \brief fixedPointToDouble
+ * Converts a fixed point number to floating point one.
+ */
+static double fixedPointToDouble(qint32 fixedPoint)
+{
+    auto i = double(fixedPoint >> 16);
+    auto d = double((fixedPoint & 0x0000FFFF) / 65536.0);
+    return (i+d);
+}
+
+/*!
+ * \brief readPascalString
+ * Reads the Pascal string as defined in the PSD specification.
+ * \param s The stream.
+ * \param alignBytes Alignment of the string.
+ * \param size Number of stream bytes used.
+ * \return The string read.
+ */
+static QString readPascalString(QDataStream &s, qint32 alignBytes = 1, qint32 
*size = nullptr)
+{
+    qint32 tmp = 0;
+    if (size == nullptr)
+        size = &tmp;
+
+    quint8 stringSize;
+    s >> stringSize;
+    *size = sizeof(stringSize);
+
+    QString str;
+    if (stringSize > 0) {
+        QByteArray ba;
+        ba.resize(stringSize);
+        auto read = s.readRawData(ba.data(), ba.size());
+        if (read > 0) {
+            *size += read;
+            str = QString::fromLatin1(ba);
+        }
+    }
+
+    // align
+    if (alignBytes > 1)
+        if (auto pad = *size % alignBytes)
+            *size += s.skipRawData(alignBytes - pad);
+
+    return str;
+}
+
+/*!
+ * \brief readImageResourceSection
+ * Reads the image resource section.
+ * \param s The stream.
+ * \param ok Pointer to the operation result variable.
+ * \return The image resource section raw data.
+ */
+static PSDImageResourceSection readImageResourceSection(QDataStream &s, bool 
*ok = nullptr)
+{
+    PSDImageResourceSection irs;
+
+    bool tmp = true;
+    if (ok == nullptr)
+        ok = &tmp;
+    *ok = true;
+
+    // Section size
+    qint32 sectioSize;
+    s >> sectioSize;
+
+#ifdef QT_DEBUG
+    auto pos = qint64();
+    if (auto dev = s.device())
+        pos = dev->pos();
+#endif
+
+    // Reading Image resource block
+    for (auto size = sectioSize; size > 0;) {
+        // Length      Description
+        // -------------------------------------------------------------------
+        // 4           Signature: '8BIM'
+        // 2           Unique identifier for the resource. Image resource IDs
+        //             contains a list of resource IDs used by Photoshop.
+        // Variable    Name: Pascal string, padded to make the size even
+        //             (a null name consists of two bytes of 0)
+        // 4           Actual size of resource data that follows
+        // Variable    The resource data, described in the sections on the
+        //             individual resource types. It is padded to make the size
+        //             even.
+
+        quint32 signature;
+        s >> signature;
+        size -= sizeof(signature);
+        // NOTE: MeSa signature is not documented but found in some old PSD 
take from Photoshop 7.0 CD.
+        if (signature != 0x3842494D && signature != 0x4D655361) { // 8BIM and 
MeSa
+            qDebug() << "Invalid Image Resource Block Signature!";
+            *ok = false;
+            break;
+        }
+
+        // id
+        quint16 id;
+        s >> id;
+        size -= sizeof(id);
+
+        // getting data
+        PSDImageResourceBlock irb;
+
+        // name
+        qint32 bytes = 0;
+        irb.name = readPascalString(s, 2, &bytes);
+        size -= bytes;
+
+        // data read
+        quint32 dataSize;
+        s >> dataSize;
+        size -= sizeof(dataSize);
+        // NOTE: Qt device::read() and QDataStream::readRawData() could read 
less data than specified.
+        //       The read code should be improved.
+        if(auto dev = s.device())
+            irb.data = dev->read(dataSize);
+        auto read = irb.data.size();
+        if (read > 0)
+            size -= read;
+        if (read != dataSize) {
+            qDebug() << "Image Resource Block Read Error!";
+            *ok = false;
+            break;
+        }
+
+        if (auto pad = dataSize % 2) {
+            auto skipped = s.skipRawData(pad);
+            if (skipped > 0)
+                size -= skipped;
+        }
+
+        // insert IRB
+        irs.insert(id, irb);
+    }
+
+#ifdef QT_DEBUG
+    if (auto dev = s.device()) {
+        if ((dev->pos() - pos) != sectioSize) {
+            *ok = false;
+        }
+    }
+#endif
+
+    return irs;
+}
+
+/*!
+ * \brief readColorModeDataSection
+ * Read the color mode section
+ * \param s The stream.
+ * \param ok Pointer to the operation result variable.
+ * \return The color mode section.
+ */
+PSDColorModeDataSection readColorModeDataSection(QDataStream &s, bool *ok = 
nullptr)
+{
+    PSDColorModeDataSection cms;
+
+    bool tmp = false;
+    if (ok == nullptr)
+        ok = &tmp;
+    *ok = true;
+
+    qint32 size;
+    s >> size;
+    if (size != 768) {  // read the duotone data (524 bytes)
+        // NOTE: A RGB/Gray float image has a 112 bytes ColorModeData that 
could be
+        //       the "32-bit Toning Options" of Photoshop (starts with 'hdrt').
+        //       Official Adobe specification tells "Only indexed color and 
duotone
+        //       (see the mode field in the File header section) have color 
mode data.".
+        //       See test case images 32bit_grayscale.psd and 32bit-rgb.psd
+        cms.duotone.data = s.device()->read(size);
+        if (cms.duotone.data.size() != size)
+            *ok = false;
+    }
+    else {              // read the palette (768 bytes)
+        auto&& palette = cms.palette;
+        QVector<quint8> vect(size);
+        for (auto&& v : vect)
+            s >> v;
+        for (qsizetype i = 0, n = vect.size()/3; i < n; ++i)
+            palette.append(qRgb(vect.at(i), vect.at(n+i), vect.at(n+n+i)));
+    }
+
+    return cms;
+}
+
+/*!
+ * \brief setColorSpace
+ * Set the color space to the image.
+ * \param img The image.
+ * \param irs The image resource section.
+ * \return True on success, otherwise false.
+ */
+static bool setColorSpace(QImage& img, const PSDImageResourceSection& irs)
+{
+    if (!irs.contains(IRI_ICCPROFILE))
+        return false;
+    auto irb = irs.value(IRI_ICCPROFILE);
+    auto cs = QColorSpace::fromIccProfile(irb.data);
+    if (!cs.isValid())
+        return false;
+    img.setColorSpace(cs);
+    return true;
+}
+
+/*!
+ * \brief setXmpData
+ * Adds XMP metadata to QImage.
+ * \param img The image.
+ * \param irs The image resource section.
+ * \return True on success, otherwise false.
+ */
+static bool setXmpData(QImage& img, const PSDImageResourceSection& irs)
+{
+    if (!irs.contains(IRI_XMPMETADATA))
+        return false;
+    auto irb = irs.value(IRI_XMPMETADATA);
+    auto xmp = QString::fromUtf8(irb.data);
+    if (xmp.isEmpty())
+        return false;
+    // NOTE: "XML:com.adobe.xmp" is the meta set by Qt reader when an
+    //       XMP packet is found (e.g. when reading a PNG saved by Photoshop).
+    //       I'm reusing the same key because a programs could search for it.
+    img.setText(QStringLiteral("XML:com.adobe.xmp"), xmp);
+    return true;
+}
+
+/*!
+ * \brief hasMergedData
+ * Checks if merged image data are available.
+ * \param irs The image resource section.
+ * \return True on success or if the block does not exist, otherwise false.
+ */
+static bool hasMergedData(const PSDImageResourceSection& irs)
+{
+    if (!irs.contains(IRI_VERSIONINFO))
+        return true;
+    auto irb = irs.value(IRI_VERSIONINFO);
+    if (irb.data.size() > 4)
+        return irb.data.at(4) != 0;
+    return false;
+}
+
+/*!
+ * \brief setResolution
+ * Set the image resolution.
+ * \param img The image.
+ * \param irs The image resource section.
+ * \return True on success, otherwise false.
+ */
+static bool setResolution(QImage& img, const PSDImageResourceSection& irs)
+{
+    if (!irs.contains(IRI_RESOLUTIONINFO))
+        return false;
+    auto irb = irs.value(IRI_RESOLUTIONINFO);
+
+    QDataStream s(irb.data);
+    s.setByteOrder(QDataStream::BigEndian);
+
+    qint32 i32;
+    s >> i32;                               // Horizontal resolution in pixels 
per inch.
+    if (i32 <= 0)
+        return false;
+    auto hres = fixedPointToDouble(i32);
+
+    s.skipRawData(4);                       // Display data (not used here)
+
+    s >> i32;                               // Vertial resolution in pixels 
per inch.
+    if (i32 <= 0)
+        return false;
+    auto vres = fixedPointToDouble(i32);
+
+    img.setDotsPerMeterX(hres * 1000 / 25.4);
+    img.setDotsPerMeterY(vres * 1000 / 25.4);
+    return true;
+}
+
+/*!
+ * \brief setTransparencyIndex
+ * Search for transparency index block and, if found, changes the alpha of the 
value at the given index.
+ * \param img The image.
+ * \param irs The image resource section.
+ * \return True on success, otherwise false.
+ */
+static bool setTransparencyIndex(QImage& img, const PSDImageResourceSection& 
irs)
+{
+    if (!irs.contains(IRI_TRANSPARENCYINDEX))
+        return false;
+    auto irb = irs.value(IRI_TRANSPARENCYINDEX);
+    QDataStream s(irb.data);
+    s.setByteOrder(QDataStream::BigEndian);
+    quint16 idx;
+    s >> idx;
+
+    auto palette = img.colorTable();
+    if (idx < palette.size()) {
+        auto&& v = palette[idx];
+        v = QRgb(v & ~0xFF000000);
+        img.setColorTable(palette);
+        return true;
+    }
+
+    return false;
+}
+
 static QDataStream &operator>>(QDataStream &s, PSDHeader &header)
 {
     s >> header.signature;
@@ -80,66 +436,227 @@
 // Check that the header is supported.
 static bool IsSupported(const PSDHeader &header)
 {
-    if (header.version != 1) {
-        return false;
-    }
-    if (header.channel_count > 16) {
+    if (header.version != 1 && header.version != 2) {
         return false;
     }
-    if (header.depth != 8 && header.depth != 16) {
+    if (header.depth != 8 &&
+        header.depth != 16 &&
+        header.depth != 32 &&
+        header.depth != 1) {
         return false;
     }
-    if (header.color_mode != CM_RGB) {
+    if (header.color_mode != CM_RGB &&
+        header.color_mode != CM_GRAYSCALE &&
+        header.color_mode != CM_INDEXED &&
+        header.color_mode != CM_DUOTONE &&
+        header.color_mode != CM_BITMAP) {
         return false;
     }
     return true;
 }
 
-static void skip_section(QDataStream &s)
+static bool skip_section(QDataStream &s, bool psb = false)
 {
-    quint32 section_length;
+    qint64 section_length;
+    if (!psb) {
+        quint32 tmp;
+        s >> tmp;
+        section_length = tmp;
+    }
+    else {
+        s >> section_length;
+    }
+
     // Skip mode data.
-    s >> section_length;
-    s.skipRawData(section_length);
+    for (qint32 i32 = 0; section_length; section_length -= i32) {
+        i32 = std::min(section_length, 
qint64(std::numeric_limits<qint32>::max()));
+        i32 = s.skipRawData(i32);
+        if (i32 < 1)
+            return false;
+    }
+    return true;
 }
 
-template<class Trait>
-static Trait readPixel(QDataStream &stream)
+/*!
+ * \brief decompress
+ * Fast PackBits decompression.
+ * \param input The compressed input buffer.
+ * \param ilen The input buffer size.
+ * \param output The uncompressed target buffer.
+ * \param olen The target buffer size.
+ * \return The number of valid bytes in the target buffer.
+ */
+qint64 decompress(const char *input, qint64 ilen, char *output, qint64 olen)
 {
-    Trait pixel;
-    stream >> pixel;
-    return pixel;
+    qint64  j = 0;
+    for (qint64 ip = 0, rr = 0, available = olen; j < olen && ip < ilen; 
available = olen - j) {
+        char n = input[ip++];
+        if (static_cast<signed char>(n) == -128)
+            continue;
+
+        if (static_cast<signed char>(n) >= 0) {
+            rr = qint64(n) + 1;
+            if (available < rr) {
+                ip--;
+                break;
+            }
+
+            if (ip + rr > ilen)
+                return -1;
+            memcpy(output + j, input + ip, size_t(rr));
+            ip += rr;
+        }
+        else if (ip < ilen) {
+            rr = qint64(1-n);
+            if (available < rr) {
+                ip--;
+                break;
+            }
+            memset(output + j, input[ip++], size_t(rr));
+        }
+
+        j += rr;
+    }
+    return j;
 }
 
-static QRgb updateRed(QRgb oldPixel, quint8 redPixel)
+/*!
+ * \brief imageFormat
+ * \param header The PSD header.
+ * \return The Qt image format.
+ */
+static QImage::Format imageFormat(const PSDHeader &header)
+{
+    if (header.channel_count == 0) {
+        return QImage::Format_Invalid;
+    }
+
+    auto format = QImage::Format_Invalid;
+    switch(header.color_mode) {
+    case CM_RGB:
+        if (header.depth == 16 || header.depth == 32)
+            format = header.channel_count < 4 ? QImage::Format_RGBX64 : 
QImage::Format_RGBA64;
+        else
+            format = header.channel_count < 4 ? QImage::Format_RGB888 : 
QImage::Format_RGBA8888;
+        break;
+    case CM_GRAYSCALE:
+    case CM_DUOTONE:
+        format = header.depth == 8 ? QImage::Format_Grayscale8 : 
QImage::Format_Grayscale16;
+        break;
+    case CM_INDEXED:
+        format = header.depth == 8 ? QImage::Format_Indexed8 : 
QImage::Format_Invalid;
+        break;
+    case CM_BITMAP:
+        format = header.depth == 1 ? QImage::Format_Mono : 
QImage::Format_Invalid;
+        break;
+    }
+    return format;
+}
+
+/*!
+ * \brief imageChannels
+ * \param format The Qt image format.
+ * \return The number of channels of the image format.
+ */
+static qint32 imageChannels(const QImage::Format& format)
 {
-    return qRgba(redPixel, qGreen(oldPixel), qBlue(oldPixel), 
qAlpha(oldPixel));
+    qint32 c = 4;
+    switch(format) {
+    case QImage::Format_RGB888:
+        c = 3;
+        break;
+    case QImage::Format_Grayscale8:
+    case QImage::Format_Grayscale16:
+    case QImage::Format_Indexed8:
+    case QImage::Format_Mono:
+        c = 1;
+        break;
+    default:
+        break;
+    }
+    return c;
+}
+
+inline quint8 xchg(quint8 v) {
+    return v;
 }
-static QRgb updateGreen(QRgb oldPixel, quint8 greenPixel)
+
+inline quint16 xchg(quint16 v) {
+#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
+    return quint16( (v>>8) | (v<<8) );
+#else
+    return v;   // never tested
+#endif
+}
+
+inline quint32 xchg(quint32 v) {
+#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
+    return quint32( (v>>24) | ((v & 0x00FF0000)>>8) | ((v & 0x0000FF00)<<8) | 
(v<<24) );
+#else
+    return v;  // never tested
+#endif
+}
+
+template<class T>
+inline void planarToChunchy(uchar *target, const char* source, qint32 width, 
qint32 c, qint32 cn)
 {
-    return qRgba(qRed(oldPixel), greenPixel, qBlue(oldPixel), 
qAlpha(oldPixel));
+    auto s = reinterpret_cast<const T*>(source);
+    auto t = reinterpret_cast<T*>(target);
+    for (qint32 x = 0; x < width; ++x)
+        t[x*cn+c] = xchg(s[x]);
 }
-static QRgb updateBlue(QRgb oldPixel, quint8 bluePixel)
+
+template<class T>
+inline void planarToChunchyFloat(uchar *target, const char* source, qint32 
width, qint32 c, qint32 cn)
 {
-    return qRgba(qRed(oldPixel), qGreen(oldPixel), bluePixel, 
qAlpha(oldPixel));
+    auto s = reinterpret_cast<const T*>(source);
+    auto t = reinterpret_cast<quint16*>(target);
+    for (qint32 x = 0; x < width; ++x) {
+        auto tmp = xchg(s[x]);
+        t[x*cn+c] = std::min(quint16(*reinterpret_cast<float*>(&tmp) * 
std::numeric_limits<quint16>::max() + 0.5),
+                             std::numeric_limits<quint16>::max());
+    }
 }
-static QRgb updateAlpha(QRgb oldPixel, quint8 alphaPixel)
+
+inline void monoInvert(uchar *target, const char* source, qint32 bytes)
 {
-    return qRgba(qRed(oldPixel), qGreen(oldPixel), qBlue(oldPixel), 
alphaPixel);
+    auto s = reinterpret_cast<const quint8*>(source);
+    auto t = reinterpret_cast<quint8*>(target);
+    for (qint32 x = 0; x < bytes; ++x)
+        t[x] = ~s[x];
 }
-typedef QRgb (*channelUpdater)(QRgb, quint8);
 
 // Load the PSD image.
 static bool LoadPSD(QDataStream &stream, const PSDHeader &header, QImage &img)
 {
-    // Mode data
-    skip_section(stream);
+    // Checking for PSB
+    auto isPsb = header.version == 2;
+    bool ok = false;
 
-    // Image resources
-    skip_section(stream);
+    // Color Mode Data section
+    auto cmds = readColorModeDataSection(stream, &ok);
+    if (!ok) {
+        qDebug() << "Error while skipping Color Mode Data section";
+        return false;
+    }
+
+    // Image Resources Section
+    auto irs = readImageResourceSection(stream, &ok);
+    if (!ok) {
+        qDebug() << "Error while reading Image Resources Section";
+        return false;
+    }
+    // Checking for merged image (Photoshop compatibility data)
+    if (!hasMergedData(irs)) {
+        qDebug() << "No merged data found";
+        return false;
+    }
 
-    // Reserved data
-    skip_section(stream);
+    // Layer and Mask section
+    if (!skip_section(stream, isPsb)) {
+        qDebug() << "Error while skipping Layer and Mask section";
+        return false;
+    }
 
     // Find out if the data is compressed.
     // Known values:
@@ -147,103 +664,114 @@
     //   1: RLE compressed
     quint16 compression;
     stream >> compression;
-
     if (compression > 1) {
         qDebug() << "Unknown compression type";
         return false;
     }
 
-    quint32 channel_num = header.channel_count;
-
-    QImage::Format fmt = header.depth == 8 ? QImage::Format_RGB32 : 
QImage::Format_RGBX64;
-    // Clear the image.
-    if (channel_num >= 4) {
-        // Enable alpha.
-        fmt = header.depth == 8 ? QImage::Format_ARGB32 : 
QImage::Format_RGBA64;
-
-        // Ignore the other channels.
-        channel_num = 4;
+    const QImage::Format format = imageFormat(header);
+    if (format == QImage::Format_Invalid) {
+        qWarning() << "Unsupported image format. color_mode:" << 
header.color_mode << "depth:" << header.depth << "channel_count:" << 
header.channel_count;
+        return false;
     }
 
-    img = QImage(header.width, header.height, fmt);
+    img = QImage(header.width, header.height, format);
     if (img.isNull()) {
         qWarning() << "Failed to allocate image, invalid dimensions?" << 
QSize(header.width, header.height);
         return false;
     }
     img.fill(qRgb(0, 0, 0));
-
-    const quint32 pixel_count = header.height * header.width;
-    const quint32 channel_size = pixel_count * header.depth / 8;
-
-    // Verify this, as this is used to write into the memory of the QImage
-    if (pixel_count > img.sizeInBytes() / (header.depth == 8 ? sizeof(QRgb) : 
sizeof(QRgba64))) {
-        qWarning() << "Invalid pixel count!" << pixel_count << "bytes 
available:" << img.sizeInBytes();
-        return false;
+    if (!cmds.palette.isEmpty()) {
+        img.setColorTable(cmds.palette);
+        setTransparencyIndex(img, irs);
     }
 
-    QRgb *image_data = reinterpret_cast<QRgb *>(img.bits());
+    auto imgChannels = imageChannels(img.format());
+    auto channel_num = std::min(qint32(header.channel_count), imgChannels);
+    auto raw_count = qsizetype(header.width * header.depth + 7) / 8;
 
-    if (!image_data) {
+    if (header.height > kMaxQVectorSize / header.channel_count / 
sizeof(quint32)) {
+        qWarning() << "LoadPSD() header height/channel_count too big" << 
header.height << header.channel_count;
         return false;
     }
 
-    static const channelUpdater updaters[4] = {updateRed, updateGreen, 
updateBlue, updateAlpha};
-
-    typedef QRgba64 (*channelUpdater16)(QRgba64, quint16);
-    static const channelUpdater16 updaters64[4] = {[](QRgba64 oldPixel, 
quint16 redPixel) {
-                                                       return 
qRgba64((oldPixel & ~(0xFFFFull << 0)) | (quint64(redPixel) << 0));
-                                                   },
-                                                   [](QRgba64 oldPixel, 
quint16 greenPixel) {
-                                                       return 
qRgba64((oldPixel & ~(0xFFFFull << 16)) | (quint64(greenPixel) << 16));
-                                                   },
-                                                   [](QRgba64 oldPixel, 
quint16 bluePixel) {
-                                                       return 
qRgba64((oldPixel & ~(0xFFFFull << 32)) | (quint64(bluePixel) << 32));
-                                                   },
-                                                   [](QRgba64 oldPixel, 
quint16 alphaPixel) {
-                                                       return 
qRgba64((oldPixel & ~(0xFFFFull << 48)) | (quint64(alphaPixel) << 48));
-                                                   }};
-
-    if (compression) {
-        // Skip row lengths.
-        int skip_count = header.height * header.channel_count * 
sizeof(quint16);
-        if (stream.skipRawData(skip_count) != skip_count) {
-            return false;
-        }
-
-        for (unsigned short channel = 0; channel < channel_num; channel++) {
-            bool success = false;
-            if (header.depth == 8) {
-                success = decodeRLEData(RLEVariant::PackBits, stream, 
image_data, channel_size, &readPixel<quint8>, updaters[channel]);
-            } else if (header.depth == 16) {
-                QRgba64 *image_data = reinterpret_cast<QRgba64 *>(img.bits());
-                success = decodeRLEData(RLEVariant::PackBits16, stream, 
image_data, channel_size, &readPixel<quint8>, updaters64[channel]);
-            }
-
-            if (!success) {
-                qDebug() << "decodeRLEData on channel" << channel << "failed";
-                return false;
+    QVector<quint32> strides(header.height * header.channel_count, raw_count);
+    // Read the compressed stride sizes
+    if (compression)
+        for (auto&& v : strides) {
+            if (isPsb) {
+                stream >> v;
+                continue;
             }
+            quint16 tmp;
+            stream >> tmp;
+            v = tmp;
         }
-    } else {
-        for (unsigned short channel = 0; channel < channel_num; channel++) {
-            if (header.depth == 8) {
-                for (unsigned i = 0; i < pixel_count; ++i) {
-                    image_data[i] = updaters[channel](image_data[i], 
readPixel<quint8>(stream));
+
+    // Read the image
+    QByteArray rawStride;
+    rawStride.resize(raw_count);
+    for (qint32 c = 0; c < channel_num; ++c) {
+        for(qint32 y = 0, h = header.height; y < h; ++y) {
+            auto&& strideSize = strides.at(c*qsizetype(h)+y);
+            if (compression) {
+                QByteArray tmp;
+                tmp.resize(strideSize);
+                if (stream.readRawData(tmp.data(), tmp.size()) != tmp.size()) {
+                    qDebug() << "Error while reading the stream of channel" << 
c << "line" << y;
+                    return false;
                 }
-            } else if (header.depth == 16) {
-                QRgba64 *image_data = reinterpret_cast<QRgba64 *>(img.bits());
-                for (unsigned i = 0; i < pixel_count; ++i) {
-                    image_data[i] = updaters64[channel](image_data[i], 
readPixel<quint16>(stream));
+                if (decompress(tmp.data(), tmp.size(), rawStride.data(), 
rawStride.size()) < 0) {
+                    qDebug() << "Error while decompressing the channel" << c 
<< "line" << y;
+                    return false;
                 }
             }
-            // make sure we didn't try to read past the end of the stream
+            else {
+                if (stream.readRawData(rawStride.data(), rawStride.size()) != 
rawStride.size()) {
+                    qDebug() << "Error while reading the stream of channel" << 
c << "line" << y;
+                    return false;
+                }
+            }
+
             if (stream.status() != QDataStream::Ok) {
-                qDebug() << "DataStream status was" << stream.status();
+                qDebug() << "Stream read error" << stream.status();
                 return false;
             }
+
+            auto scanLine = img.scanLine(y);
+            if (header.depth == 1)          // Bitmap
+                monoInvert(scanLine, rawStride.data(), 
std::min(rawStride.size(), img.bytesPerLine()));
+            else if (header.depth == 8)     // 8-bits images: Indexed, 
Grayscale, RGB/RGBA
+                planarToChunchy<quint8>(scanLine, rawStride.data(), 
header.width, c, imgChannels);
+            else if (header.depth == 16)    // 16-bits integer images: 
Grayscale, RGB/RGBA
+                planarToChunchy<quint16>(scanLine, rawStride.data(), 
header.width, c, imgChannels);
+            else if (header.depth == 32)    // 32-bits float images: 
Grayscale, RGB/RGBA (coverted to equivalent integer 16-bits)
+                planarToChunchyFloat<quint32>(scanLine, rawStride.data(), 
header.width, c, imgChannels);
         }
     }
 
+    // Resolution info
+    if (!setResolution(img, irs)) {
+        // qDebug() << "No resolution info found!";
+    }
+
+    // ICC profile
+    if (!setColorSpace(img, irs)) {
+        // qDebug() << "No colorspace info set!";
+    }
+
+    // XMP data
+    if (!setXmpData(img, irs)) {
+        // qDebug() << "No XMP data found!";
+    }
+
+    // Duotone images: color data contains the duotone specification (not 
documented).
+    // Other applications that read Photoshop files can treat a duotone image 
as a gray image,
+    // and just preserve the contents of the duotone information when reading 
and writing the file.
+    if (!cmds.duotone.data.isEmpty()) {
+        img.setText(QStringLiteral("PSDDuotoneOptions"), 
QString::fromUtf8(cmds.duotone.data.toHex()));
+    }
+
     return true;
 }
 
@@ -292,6 +820,38 @@
     return true;
 }
 
+bool PSDHandler::supportsOption(ImageOption option) const
+{
+    if (option == QImageIOHandler::Size)
+        return true;
+    return false;
+}
+
+QVariant PSDHandler::option(ImageOption option) const
+{
+    QVariant v;
+
+    if (option == QImageIOHandler::Size) {
+        if (auto d = device()) {
+            // transactions works on both random and sequential devices
+            d->startTransaction();
+            auto ba = d->read(sizeof(PSDHeader));
+            d->rollbackTransaction();
+
+            QDataStream s(ba);
+            s.setByteOrder(QDataStream::BigEndian);
+
+            PSDHeader header;
+            s >> header;
+
+            if (s.status() == QDataStream::Ok && IsValid(header))
+                v = QVariant::fromValue(QSize(header.width, header.height));
+        }
+    }
+
+    return v;
+}
+
 bool PSDHandler::canRead(QIODevice *device)
 {
     if (!device) {
@@ -332,7 +892,7 @@
 
 QImageIOPlugin::Capabilities PSDPlugin::capabilities(QIODevice *device, const 
QByteArray &format) const
 {
-    if (format == "psd") {
+    if (format == "psd" || format == "psb" || format == "pdd" || format == 
"psdt") {
         return Capabilities(CanRead);
     }
     if (!format.isEmpty()) {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/kimageformats-5.93.0/src/imageformats/psd.json 
new/kimageformats-5.94.0/src/imageformats/psd.json
--- old/kimageformats-5.93.0/src/imageformats/psd.json  2022-04-02 
12:00:12.000000000 +0200
+++ new/kimageformats-5.94.0/src/imageformats/psd.json  2022-05-02 
11:46:37.000000000 +0200
@@ -1,4 +1,4 @@
 {
-    "Keys": [ "psd" ],
-    "MimeTypes": [ "image/vnd.adobe.photoshop" ]
+    "Keys": [ "psd", "psb", "pdd", "psdt" ],
+    "MimeTypes": [ "image/vnd.adobe.photoshop", "image/vnd.adobe.photoshop", 
"image/vnd.adobe.photoshop", "image/vnd.adobe.photoshop" ]
 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/kimageformats-5.93.0/src/imageformats/psd_p.h 
new/kimageformats-5.94.0/src/imageformats/psd_p.h
--- old/kimageformats-5.93.0/src/imageformats/psd_p.h   2022-04-02 
12:00:12.000000000 +0200
+++ new/kimageformats-5.94.0/src/imageformats/psd_p.h   2022-05-02 
11:46:37.000000000 +0200
@@ -18,6 +18,9 @@
     bool canRead() const override;
     bool read(QImage *image) override;
 
+    bool supportsOption(QImageIOHandler::ImageOption option) const override;
+    QVariant option(QImageIOHandler::ImageOption option) const override;
+
     static bool canRead(QIODevice *device);
 };
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/kimageformats-5.93.0/src/imageformats/ras.cpp 
new/kimageformats-5.94.0/src/imageformats/ras.cpp
--- old/kimageformats-5.93.0/src/imageformats/ras.cpp   2022-04-02 
12:00:12.000000000 +0200
+++ new/kimageformats-5.94.0/src/imageformats/ras.cpp   2022-05-02 
11:46:37.000000000 +0200
@@ -9,6 +9,8 @@
 
 #include "ras_p.h"
 
+#include "util_p.h"
+
 #include <QDataStream>
 #include <QDebug>
 #include <QImage>
@@ -102,8 +104,7 @@
 {
     s.device()->seek(RasHeader::SIZE);
 
-    // QVector uses some extra space for stuff, hence the 32 here suggested by 
thiago
-    if (ras.ColorMapLength > std::numeric_limits<int>::max() - 32) {
+    if (ras.ColorMapLength > kMaxQVectorSize) {
         qWarning() << "LoadRAS() unsupported image color map length in file 
header" << ras.ColorMapLength;
         return false;
     }
@@ -127,8 +128,7 @@
         qWarning() << "LoadRAS() mistmatch between height and width" << 
ras.Width << ras.Height << ras.Length << ras.Depth;
         return false;
     }
-    // QVector uses some extra space for stuff, hence the 32 here suggested by 
thiago
-    if (ras.Length > std::numeric_limits<int>::max() - 32) {
+    if (ras.Length > kMaxQVectorSize) {
         qWarning() << "LoadRAS() unsupported image length in file header" << 
ras.Length;
         return false;
     }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/kimageformats-5.93.0/src/imageformats/util_p.h 
new/kimageformats-5.94.0/src/imageformats/util_p.h
--- old/kimageformats-5.93.0/src/imageformats/util_p.h  1970-01-01 
01:00:00.000000000 +0100
+++ new/kimageformats-5.94.0/src/imageformats/util_p.h  2022-05-02 
11:46:37.000000000 +0200
@@ -0,0 +1,10 @@
+/*
+    SPDX-FileCopyrightText: 2022 Albert Astals Cid <[email protected]>
+
+    SPDX-License-Identifier: LGPL-2.0-or-later
+*/
+
+#include <limits>
+
+// QVector uses some extra space for stuff, hence the 32 here suggested by 
Thiago Macieira
+static constexpr int kMaxQVectorSize = std::numeric_limits<int>::max() - 32;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/kimageformats-5.93.0/src/imageformats/xcf.cpp 
new/kimageformats-5.94.0/src/imageformats/xcf.cpp
--- old/kimageformats-5.93.0/src/imageformats/xcf.cpp   2022-04-02 
12:00:12.000000000 +0200
+++ new/kimageformats-5.94.0/src/imageformats/xcf.cpp   2022-05-02 
11:46:37.000000000 +0200
@@ -3270,6 +3270,52 @@
     return false;
 }
 
+bool XCFHandler::supportsOption(ImageOption option) const
+{
+    if (option == QImageIOHandler::Size)
+        return true;
+    return false;
+}
+
+QVariant XCFHandler::option(ImageOption option) const
+{
+    QVariant v;
+
+    if (option == QImageIOHandler::Size) {
+        /*
+         * The image structure always starts at offset 0 in the XCF file.
+         * byte[9]     "gimp xcf " File type identification
+         * byte[4]     version     XCF version
+         *                          "file": version 0
+         *                          "v001": version 1
+         *                          "v002": version 2
+         *                          "v003": version 3
+         * byte        0            Zero marks the end of the version tag.
+         * uint32      width        Width of canvas
+         * uint32      height       Height of canvas
+         */
+        if (auto d = device()) {
+            // transactions works on both random and sequential devices
+            d->startTransaction();
+            auto ba9 = d->read(9);      // "gimp xcf "
+            auto ba5 = d->read(4+1);    // version + null terminator
+            auto ba = d->read(8);       // width and height
+            d->rollbackTransaction();
+            if (ba9 == QByteArray("gimp xcf ") && ba5.size() == 5) {
+                QDataStream ds(ba);
+                quint32 width;
+                ds >> width;
+                quint32 height;
+                ds >> height;
+                if (ds.status() == QDataStream::Ok)
+                    v = QVariant::fromValue(QSize(width, height));
+            }
+        }
+    }
+
+    return v;
+}
+
 bool XCFHandler::canRead(QIODevice *device)
 {
     if (!device) {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/kimageformats-5.93.0/src/imageformats/xcf_p.h 
new/kimageformats-5.94.0/src/imageformats/xcf_p.h
--- old/kimageformats-5.93.0/src/imageformats/xcf_p.h   2022-04-02 
12:00:12.000000000 +0200
+++ new/kimageformats-5.94.0/src/imageformats/xcf_p.h   2022-05-02 
11:46:37.000000000 +0200
@@ -20,6 +20,9 @@
     bool read(QImage *image) override;
     bool write(const QImage &image) override;
 
+    bool supportsOption(QImageIOHandler::ImageOption option) const override;
+    QVariant option(QImageIOHandler::ImageOption option) const override;
+
     static bool canRead(QIODevice *device);
 };
 

Reply via email to