mirror of
https://invent.kde.org/frameworks/kimageformats.git
synced 2026-09-20 06:37:00 -04:00
EXR: support for metadata saved by Photoshop
This commit is contained in:
committed by
Mirco Miranda
parent
43e6efb0e5
commit
6a3c7f2c86
@@ -186,7 +186,7 @@ echo "$HANDLER_TYPES" | while read format; do
|
|||||||
/usr/libexec/moc $SRC/kimageformats/src/imageformats/$format.cpp -o $format.moc
|
/usr/libexec/moc $SRC/kimageformats/src/imageformats/$format.cpp -o $format.moc
|
||||||
header=`ls $SRC/kimageformats/src/imageformats/$format*.h`
|
header=`ls $SRC/kimageformats/src/imageformats/$format*.h`
|
||||||
/usr/libexec/moc $header -o moc_`basename $header .h`.cpp
|
/usr/libexec/moc $header -o moc_`basename $header .h`.cpp
|
||||||
$CXX $CXXFLAGS $LDFLAGS -fPIC -DKIMG_FUZZER_${format}=1 -std=c++17 autotests/ossfuzz/kimgio_fuzzer.cc $SRC/kimageformats/src/imageformats/$format.cpp $SRC/kimageformats/src/imageformats/scanlineconverter.cpp $SRC/kimageformats/src/imageformats/microexif.cpp $SRC/kimageformats/src/imageformats/chunks.cpp -o $OUT/$fuzz_target_name -DJXL_STATIC_DEFINE -DJXL_THREADS_STATIC_DEFINE -DJXL_CMS_STATIC_DEFINE -D__ANSI__ -I $SRC/kimageformats/src/imageformats/ -I $SRC/libavif/include/ -I $SRC/libjxl/build/lib/include/ -I $SRC/libjxl/lib/include/ -I /usr/local/include/OpenEXR/ -I /usr/local/include/KF6/KArchive/ -I /usr/local/include/openjpeg-2.5 -I /usr/local/include/Imath -I $SRC/jxrlib/common/include -I $SRC/jxrlib/jxrgluelib -I $SRC/jxrlib/image/sys -I /usr/include/QtCore/ -I /usr/include/QtGui/ -I . $SRC/libavif/build/libavif.a /usr/local/lib/libheif.a /usr/local/lib/libde265.a /usr/local/lib/libopenh264.a $SRC/aom/build.libavif/libaom.a $SRC/libjxl/build/lib/libjxl_threads.a $SRC/libjxl/build/lib/libjxl.a $SRC/libjxl/build/lib/libjxl_cms.a $SRC/libjxl/build/third_party/highway/libhwy.a $SRC/libjxl/build/third_party/brotli/libbrotlidec.a $SRC/libjxl/build/third_party/brotli/libbrotlienc.a $SRC/libjxl/build/third_party/brotli/libbrotlicommon.a -lQt6Gui -lQt6Core -lQt6BundledLibpng -lQt6BundledHarfbuzz -lm -lQt6BundledPcre2 -ldl -lpthread $LIB_FUZZING_ENGINE /usr/local/lib/libz.a /usr/local/lib/x86_64-linux-gnu/libKF6Archive.a /usr/local/lib/libz.a /usr/local/lib/libraw.a /usr/local/lib/libOpenEXR-3_4.a /usr/local/lib/libIex-3_4.a /usr/local/lib/libImath-3_2.a /usr/local/lib/libIlmThread-3_4.a /usr/local/lib/libOpenEXRCore-3_4.a /usr/local/lib/libOpenEXRUtil-3_4.a /usr/local/lib/libopenjp2.a /usr/local/lib/libzstd.a $SRC/jxrlib/build/libjxrglue.a $SRC/jxrlib/build/libjpegxr.a /usr/local/lib/liblzma.a /usr/local/lib/libbz2.a -lclang_rt.builtins
|
$CXX $CXXFLAGS $LDFLAGS -fPIC -DKIMG_FUZZER_${format}=1 -std=c++17 autotests/ossfuzz/kimgio_fuzzer.cc $SRC/kimageformats/src/imageformats/$format.cpp $SRC/kimageformats/src/imageformats/scanlineconverter.cpp $SRC/kimageformats/src/imageformats/photoshop.cpp $SRC/kimageformats/src/imageformats/microexif.cpp $SRC/kimageformats/src/imageformats/chunks.cpp -o $OUT/$fuzz_target_name -DJXL_STATIC_DEFINE -DJXL_THREADS_STATIC_DEFINE -DJXL_CMS_STATIC_DEFINE -D__ANSI__ -I $SRC/kimageformats/src/imageformats/ -I $SRC/libavif/include/ -I $SRC/libjxl/build/lib/include/ -I $SRC/libjxl/lib/include/ -I /usr/local/include/OpenEXR/ -I /usr/local/include/KF6/KArchive/ -I /usr/local/include/openjpeg-2.5 -I /usr/local/include/Imath -I $SRC/jxrlib/common/include -I $SRC/jxrlib/jxrgluelib -I $SRC/jxrlib/image/sys -I /usr/include/QtCore/ -I /usr/include/QtGui/ -I . $SRC/libavif/build/libavif.a /usr/local/lib/libheif.a /usr/local/lib/libde265.a /usr/local/lib/libopenh264.a $SRC/aom/build.libavif/libaom.a $SRC/libjxl/build/lib/libjxl_threads.a $SRC/libjxl/build/lib/libjxl.a $SRC/libjxl/build/lib/libjxl_cms.a $SRC/libjxl/build/third_party/highway/libhwy.a $SRC/libjxl/build/third_party/brotli/libbrotlidec.a $SRC/libjxl/build/third_party/brotli/libbrotlienc.a $SRC/libjxl/build/third_party/brotli/libbrotlicommon.a -lQt6Gui -lQt6Core -lQt6BundledLibpng -lQt6BundledHarfbuzz -lm -lQt6BundledPcre2 -ldl -lpthread $LIB_FUZZING_ENGINE /usr/local/lib/libz.a /usr/local/lib/x86_64-linux-gnu/libKF6Archive.a /usr/local/lib/libz.a /usr/local/lib/libraw.a /usr/local/lib/libOpenEXR-3_4.a /usr/local/lib/libIex-3_4.a /usr/local/lib/libImath-3_2.a /usr/local/lib/libIlmThread-3_4.a /usr/local/lib/libOpenEXRCore-3_4.a /usr/local/lib/libOpenEXRUtil-3_4.a /usr/local/lib/libopenjp2.a /usr/local/lib/libzstd.a $SRC/jxrlib/build/libjxrglue.a $SRC/jxrlib/build/libjpegxr.a /usr/local/lib/liblzma.a /usr/local/lib/libbz2.a -lclang_rt.builtins
|
||||||
|
|
||||||
# -lclang_rt.builtins in the previous line is a temporary workaround to avoid a linker error "undefined reference to __truncsfhf2". Investigate why this is needed here, but not anywhere else, and possibly remove it.
|
# -lclang_rt.builtins in the previous line is a temporary workaround to avoid a linker error "undefined reference to __truncsfhf2". Investigate why this is needed here, but not anywhere else, and possibly remove it.
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,33 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"fileName" : "alphatest_rgba.tif",
|
||||||
|
"colorSpace" : {
|
||||||
|
"description" : "sRGB build-in (Profilo RGB lineare)",
|
||||||
|
"primaries" : "SRgb",
|
||||||
|
"transferFunction" : "Linear",
|
||||||
|
"gamma" : 1
|
||||||
|
},
|
||||||
|
"metadata" : [
|
||||||
|
{
|
||||||
|
"key" : "ModificationDate",
|
||||||
|
"value" : "2026-09-04T11:45:06"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key" : "Software" ,
|
||||||
|
"value" : "Adobe Photoshop 27.10 (Windows)"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key" : "Author",
|
||||||
|
"value" : "Mirco Miranda"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key" : "Description",
|
||||||
|
"value" : "This test is designed to detect problems with alpha encoding. Specifically, it detects incorrect use of associated values (premultiplied alpha) and unassociated values (normal alpha)."
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"resolution" : {
|
||||||
|
"dotsPerMeterX" : 11811,
|
||||||
|
"dotsPerMeterY" : 11811
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
@@ -7,9 +7,19 @@
|
|||||||
"transferFunction" : "Linear",
|
"transferFunction" : "Linear",
|
||||||
"gamma" : 1
|
"gamma" : 1
|
||||||
},
|
},
|
||||||
|
"metadata" : [
|
||||||
|
{
|
||||||
|
"key" : "ModificationDate",
|
||||||
|
"value" : "2026-04-15T10:48:48"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key" : "Software" ,
|
||||||
|
"value" : "Adobe Photoshop 27.5 (Windows)"
|
||||||
|
}
|
||||||
|
],
|
||||||
"resolution" : {
|
"resolution" : {
|
||||||
"dotsPerMeterX" : 3937,
|
"dotsPerMeterX" : 11811,
|
||||||
"dotsPerMeterY" : 3937
|
"dotsPerMeterY" : 11811
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ endif()
|
|||||||
##################################
|
##################################
|
||||||
|
|
||||||
if(OpenEXR_FOUND)
|
if(OpenEXR_FOUND)
|
||||||
kimageformats_add_plugin(kimg_exr SOURCES exr.cpp scanlineconverter.cpp)
|
kimageformats_add_plugin(kimg_exr SOURCES exr.cpp microexif.cpp photoshop.cpp scanlineconverter.cpp)
|
||||||
if(TARGET OpenEXR::OpenEXR)
|
if(TARGET OpenEXR::OpenEXR)
|
||||||
target_link_libraries(kimg_exr PRIVATE OpenEXR::OpenEXR)
|
target_link_libraries(kimg_exr PRIVATE OpenEXR::OpenEXR)
|
||||||
else()
|
else()
|
||||||
@@ -117,7 +117,7 @@ kimageformats_add_plugin(kimg_pfm SOURCES pfm.cpp)
|
|||||||
|
|
||||||
##################################
|
##################################
|
||||||
|
|
||||||
kimageformats_add_plugin(kimg_psd SOURCES psd.cpp microexif.cpp scanlineconverter.cpp)
|
kimageformats_add_plugin(kimg_psd SOURCES psd.cpp microexif.cpp photoshop.cpp scanlineconverter.cpp)
|
||||||
|
|
||||||
##################################
|
##################################
|
||||||
|
|
||||||
|
|||||||
@@ -8,6 +8,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "exr_p.h"
|
#include "exr_p.h"
|
||||||
|
#include "microexif_p.h"
|
||||||
|
#include "photoshop_p.h"
|
||||||
#include "scanlineconverter_p.h"
|
#include "scanlineconverter_p.h"
|
||||||
#include "util_p.h"
|
#include "util_p.h"
|
||||||
|
|
||||||
@@ -385,6 +387,34 @@ static void readMetadata(const Imf::Header &header, QImage &image)
|
|||||||
if (auto focalLen = header.findTypedAttribute<Imf::FloatAttribute>("effectiveFocalLength")) {
|
if (auto focalLen = header.findTypedAttribute<Imf::FloatAttribute>("effectiveFocalLength")) {
|
||||||
image.setText(QStringLiteral(META_KEY_FOCALLENGTH), QLocale::c().toString(focalLen->value()));
|
image.setText(QStringLiteral(META_KEY_FOCALLENGTH), QLocale::c().toString(focalLen->value()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Photoshop image resource section
|
||||||
|
if (auto adobe = header.findTypedAttribute<Imf::OpaqueAttribute>("adobe_rsrc")) {
|
||||||
|
auto &&data = adobe->data();
|
||||||
|
auto ba = QByteArray(data, data.size());
|
||||||
|
ba.prepend((data.size()) & 0xFF);
|
||||||
|
ba.prepend((data.size() >> 8) & 0xFF);
|
||||||
|
ba.prepend((data.size() >> 16) & 0xFF);
|
||||||
|
ba.prepend((data.size() >> 24) & 0xFF);
|
||||||
|
QDataStream ds(ba);
|
||||||
|
ds.setByteOrder(QDataStream::BigEndian);
|
||||||
|
auto ok = false;
|
||||||
|
auto irs = readImageResourceSection(ds, &ok);
|
||||||
|
if (ok) {
|
||||||
|
if (irs.contains(IRI_EXIFDATA1)) {
|
||||||
|
auto exif = MicroExif::fromByteArray(irs.value(IRI_EXIFDATA1).data);
|
||||||
|
exif.updateImageMetadata(image);
|
||||||
|
exif.updateImageResolution(image);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (irs.contains(IRI_XMPMETADATA)) {
|
||||||
|
auto irb = irs.value(IRI_XMPMETADATA);
|
||||||
|
auto xmp = QString::fromUtf8(irb.data);
|
||||||
|
if (!xmp.isEmpty())
|
||||||
|
image.setText(QStringLiteral(META_KEY_XMP_ADOBE), xmp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
|||||||
@@ -0,0 +1,140 @@
|
|||||||
|
/*
|
||||||
|
This file is part of the KDE project
|
||||||
|
SPDX-FileCopyrightText: 2026 Mirco Miranda <mircomir@outlook.com>
|
||||||
|
|
||||||
|
SPDX-License-Identifier: LGPL-2.1-or-later
|
||||||
|
*/
|
||||||
|
#include "photoshop_p.h"
|
||||||
|
#include "util_p.h"
|
||||||
|
|
||||||
|
#include <QLoggingCategory>
|
||||||
|
|
||||||
|
#ifdef QT_DEBUG
|
||||||
|
Q_LOGGING_CATEGORY(LOG_PSDSHARED, "kf.imageformats.plugins.psdshared", QtDebugMsg)
|
||||||
|
#else
|
||||||
|
Q_LOGGING_CATEGORY(LOG_PSDSHARED, "kf.imageformats.plugins.psdshared", QtWarningMsg)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
QString readPascalString(QDataStream &s, qint32 alignBytes, qint32 *size)
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
PSDImageResourceSection readImageResourceSection(QDataStream &s, bool *ok)
|
||||||
|
{
|
||||||
|
PSDImageResourceSection irs;
|
||||||
|
|
||||||
|
bool tmp = true;
|
||||||
|
if (ok == nullptr)
|
||||||
|
ok = &tmp;
|
||||||
|
*ok = true;
|
||||||
|
|
||||||
|
// Section size
|
||||||
|
quint32 tmpSize;
|
||||||
|
s >> tmpSize;
|
||||||
|
qint64 sectioSize = tmpSize;
|
||||||
|
|
||||||
|
// Reading Image resource block
|
||||||
|
for (auto size = sectioSize; size > 0;) {
|
||||||
|
|
||||||
|
#define DEC_SIZE(value) \
|
||||||
|
if ((size -= qint64(value)) < 0) { \
|
||||||
|
*ok = false; \
|
||||||
|
break; }
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
DEC_SIZE(sizeof(signature))
|
||||||
|
// NOTE: MeSa signature is not documented but found in some old PSD take from Photoshop 7.0 CD.
|
||||||
|
if (signature != S_8BIM && signature != S_MeSa) { // 8BIM and MeSa
|
||||||
|
qCDebug(LOG_PSDSHARED) << "Invalid Image Resource Block Signature!";
|
||||||
|
*ok = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// id
|
||||||
|
quint16 id;
|
||||||
|
s >> id;
|
||||||
|
DEC_SIZE(sizeof(id))
|
||||||
|
|
||||||
|
// getting data
|
||||||
|
PSDImageResourceBlock irb;
|
||||||
|
|
||||||
|
// name
|
||||||
|
qint32 bytes = 0;
|
||||||
|
irb.name = readPascalString(s, 2, &bytes);
|
||||||
|
DEC_SIZE(bytes)
|
||||||
|
|
||||||
|
// data read
|
||||||
|
quint32 dataSize;
|
||||||
|
s >> dataSize;
|
||||||
|
DEC_SIZE(sizeof(dataSize))
|
||||||
|
if (auto dev = s.device()) {
|
||||||
|
if (dataSize > size) {
|
||||||
|
qCDebug(LOG_PSDSHARED) << "Invalid Image Resource Block Data Size!";
|
||||||
|
*ok = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
irb.data = deviceRead(dev, dataSize);
|
||||||
|
}
|
||||||
|
auto read = irb.data.size();
|
||||||
|
if (read > 0) {
|
||||||
|
DEC_SIZE(read)
|
||||||
|
}
|
||||||
|
if (read != qint64(dataSize)) {
|
||||||
|
qCDebug(LOG_PSDSHARED) << "Image Resource Block Read Error!";
|
||||||
|
*ok = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (auto pad = dataSize % 2) {
|
||||||
|
auto skipped = s.skipRawData(pad);
|
||||||
|
if (skipped > 0) {
|
||||||
|
DEC_SIZE(skipped);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// insert IRB
|
||||||
|
irs.insert(ImageResourceId(id), irb);
|
||||||
|
|
||||||
|
#undef DEC_SIZE
|
||||||
|
}
|
||||||
|
|
||||||
|
return irs;
|
||||||
|
}
|
||||||
@@ -0,0 +1,80 @@
|
|||||||
|
/*
|
||||||
|
This file is part of the KDE project
|
||||||
|
SPDX-FileCopyrightText: 2026 Mirco Miranda <mircomir@outlook.com>
|
||||||
|
|
||||||
|
SPDX-License-Identifier: LGPL-2.1-or-later
|
||||||
|
*/
|
||||||
|
#ifndef PHOTOSHOP_P_H
|
||||||
|
#define PHOTOSHOP_P_H
|
||||||
|
|
||||||
|
#include <QDataStream>
|
||||||
|
#include <QHash>
|
||||||
|
#include <QString>
|
||||||
|
|
||||||
|
enum Signature : quint32 {
|
||||||
|
S_8BIM = 0x3842494D, // '8BIM'
|
||||||
|
S_8B64 = 0x38423634, // '8B64'
|
||||||
|
|
||||||
|
S_MeSa = 0x4D655361 // 'MeSa'
|
||||||
|
};
|
||||||
|
|
||||||
|
enum ColorMode : quint16 {
|
||||||
|
CM_BITMAP = 0,
|
||||||
|
CM_GRAYSCALE = 1,
|
||||||
|
CM_INDEXED = 2,
|
||||||
|
CM_RGB = 3,
|
||||||
|
CM_CMYK = 4,
|
||||||
|
CM_MULTICHANNEL = 7,
|
||||||
|
CM_DUOTONE = 8,
|
||||||
|
CM_LABCOLOR = 9,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum ImageResourceId : quint16 {
|
||||||
|
IRI_RESOLUTIONINFO = 0x03ED,
|
||||||
|
IRI_ICCPROFILE = 0x040F,
|
||||||
|
IRI_TRANSPARENCYINDEX = 0x0417,
|
||||||
|
IRI_ALPHAIDENTIFIERS = 0x041D,
|
||||||
|
IRI_VERSIONINFO = 0x0421,
|
||||||
|
IRI_EXIFDATA1 = 0x0422,
|
||||||
|
IRI_EXIFDATA3 = 0x0423, // never seen
|
||||||
|
IRI_XMPMETADATA = 0x0424
|
||||||
|
};
|
||||||
|
|
||||||
|
enum LayerId : quint32 {
|
||||||
|
LI_MT16 = 0x4D743136, // 'Mt16',
|
||||||
|
LI_MT32 = 0x4D743332, // 'Mt32',
|
||||||
|
LI_MTRN = 0x4D74726E // 'Mtrn'
|
||||||
|
};
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief The PSDImageResourceBlock class
|
||||||
|
* Raw data of a PSD image resource block
|
||||||
|
*/
|
||||||
|
struct PSDImageResourceBlock {
|
||||||
|
QString name;
|
||||||
|
QByteArray data;
|
||||||
|
};
|
||||||
|
|
||||||
|
using PSDImageResourceSection = QHash<ImageResourceId, PSDImageResourceBlock>;
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \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.
|
||||||
|
*/
|
||||||
|
QString readPascalString(QDataStream &s, qint32 alignBytes = 1, qint32 *size = nullptr);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \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.
|
||||||
|
*/
|
||||||
|
PSDImageResourceSection readImageResourceSection(QDataStream &s, bool *ok = nullptr);
|
||||||
|
|
||||||
|
#endif // PHOTOSHOP_P_H
|
||||||
+1
-181
@@ -29,12 +29,12 @@
|
|||||||
#include "fastmath_p.h"
|
#include "fastmath_p.h"
|
||||||
#include "microexif_p.h"
|
#include "microexif_p.h"
|
||||||
#include "packbits_p.h"
|
#include "packbits_p.h"
|
||||||
|
#include "photoshop_p.h"
|
||||||
#include "psd_p.h"
|
#include "psd_p.h"
|
||||||
#include "scanlineconverter_p.h"
|
#include "scanlineconverter_p.h"
|
||||||
#include "util_p.h"
|
#include "util_p.h"
|
||||||
|
|
||||||
#include <QColorSpace>
|
#include <QColorSpace>
|
||||||
#include <QDataStream>
|
|
||||||
#include <QImage>
|
#include <QImage>
|
||||||
#include <QLoggingCategory>
|
#include <QLoggingCategory>
|
||||||
|
|
||||||
@@ -99,41 +99,6 @@ namespace // Private.
|
|||||||
|
|
||||||
#define NATIVE_CMYK (CMYK_FORMAT != QImage::Format_Invalid)
|
#define NATIVE_CMYK (CMYK_FORMAT != QImage::Format_Invalid)
|
||||||
|
|
||||||
enum Signature : quint32 {
|
|
||||||
S_8BIM = 0x3842494D, // '8BIM'
|
|
||||||
S_8B64 = 0x38423634, // '8B64'
|
|
||||||
|
|
||||||
S_MeSa = 0x4D655361 // 'MeSa'
|
|
||||||
};
|
|
||||||
|
|
||||||
enum ColorMode : quint16 {
|
|
||||||
CM_BITMAP = 0,
|
|
||||||
CM_GRAYSCALE = 1,
|
|
||||||
CM_INDEXED = 2,
|
|
||||||
CM_RGB = 3,
|
|
||||||
CM_CMYK = 4,
|
|
||||||
CM_MULTICHANNEL = 7,
|
|
||||||
CM_DUOTONE = 8,
|
|
||||||
CM_LABCOLOR = 9,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum ImageResourceId : quint16 {
|
|
||||||
IRI_RESOLUTIONINFO = 0x03ED,
|
|
||||||
IRI_ICCPROFILE = 0x040F,
|
|
||||||
IRI_TRANSPARENCYINDEX = 0x0417,
|
|
||||||
IRI_ALPHAIDENTIFIERS = 0x041D,
|
|
||||||
IRI_VERSIONINFO = 0x0421,
|
|
||||||
IRI_EXIFDATA1 = 0x0422,
|
|
||||||
IRI_EXIFDATA3 = 0x0423, // never seen
|
|
||||||
IRI_XMPMETADATA = 0x0424
|
|
||||||
};
|
|
||||||
|
|
||||||
enum LayerId : quint32 {
|
|
||||||
LI_MT16 = 0x4D743136, // 'Mt16',
|
|
||||||
LI_MT32 = 0x4D743332, // 'Mt32',
|
|
||||||
LI_MTRN = 0x4D74726E // 'Mtrn'
|
|
||||||
};
|
|
||||||
|
|
||||||
struct PSDHeader {
|
struct PSDHeader {
|
||||||
PSDHeader() {
|
PSDHeader() {
|
||||||
memset(this, 0, sizeof(PSDHeader));
|
memset(this, 0, sizeof(PSDHeader));
|
||||||
@@ -149,11 +114,6 @@ struct PSDHeader {
|
|||||||
ushort color_mode;
|
ushort color_mode;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct PSDImageResourceBlock {
|
|
||||||
QString name;
|
|
||||||
QByteArray data;
|
|
||||||
};
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief The PSDDuotoneOptions struct
|
* \brief The PSDDuotoneOptions struct
|
||||||
* \note You can decode the duotone data using the "Duotone Options"
|
* \note You can decode the duotone data using the "Duotone Options"
|
||||||
@@ -172,7 +132,6 @@ struct PSDColorModeDataSection {
|
|||||||
QList<QRgb> palette;
|
QList<QRgb> palette;
|
||||||
};
|
};
|
||||||
|
|
||||||
using PSDImageResourceSection = QHash<quint16, PSDImageResourceBlock>;
|
|
||||||
|
|
||||||
struct PSDLayerInfo {
|
struct PSDLayerInfo {
|
||||||
qint64 size = -1;
|
qint64 size = -1;
|
||||||
@@ -273,145 +232,6 @@ static bool skip_section(QDataStream &s, bool psb = false)
|
|||||||
return skip_data(s, section_length);
|
return skip_data(s, section_length);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
|
||||||
* \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
|
|
||||||
quint32 tmpSize;
|
|
||||||
s >> tmpSize;
|
|
||||||
qint64 sectioSize = tmpSize;
|
|
||||||
|
|
||||||
// Reading Image resource block
|
|
||||||
for (auto size = sectioSize; size > 0;) {
|
|
||||||
|
|
||||||
#define DEC_SIZE(value) \
|
|
||||||
if ((size -= qint64(value)) < 0) { \
|
|
||||||
*ok = false; \
|
|
||||||
break; }
|
|
||||||
|
|
||||||
// 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;
|
|
||||||
DEC_SIZE(sizeof(signature))
|
|
||||||
// NOTE: MeSa signature is not documented but found in some old PSD take from Photoshop 7.0 CD.
|
|
||||||
if (signature != S_8BIM && signature != S_MeSa) { // 8BIM and MeSa
|
|
||||||
qCDebug(LOG_PSDPLUGIN) << "Invalid Image Resource Block Signature!";
|
|
||||||
*ok = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// id
|
|
||||||
quint16 id;
|
|
||||||
s >> id;
|
|
||||||
DEC_SIZE(sizeof(id))
|
|
||||||
|
|
||||||
// getting data
|
|
||||||
PSDImageResourceBlock irb;
|
|
||||||
|
|
||||||
// name
|
|
||||||
qint32 bytes = 0;
|
|
||||||
irb.name = readPascalString(s, 2, &bytes);
|
|
||||||
DEC_SIZE(bytes)
|
|
||||||
|
|
||||||
// data read
|
|
||||||
quint32 dataSize;
|
|
||||||
s >> dataSize;
|
|
||||||
DEC_SIZE(sizeof(dataSize))
|
|
||||||
if (auto dev = s.device()) {
|
|
||||||
if (dataSize > size) {
|
|
||||||
qCDebug(LOG_PSDPLUGIN) << "Invalid Image Resource Block Data Size!";
|
|
||||||
*ok = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
irb.data = deviceRead(dev, dataSize);
|
|
||||||
}
|
|
||||||
auto read = irb.data.size();
|
|
||||||
if (read > 0) {
|
|
||||||
DEC_SIZE(read)
|
|
||||||
}
|
|
||||||
if (read != qint64(dataSize)) {
|
|
||||||
qCDebug(LOG_PSDPLUGIN) << "Image Resource Block Read Error!";
|
|
||||||
*ok = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (auto pad = dataSize % 2) {
|
|
||||||
auto skipped = s.skipRawData(pad);
|
|
||||||
if (skipped > 0) {
|
|
||||||
DEC_SIZE(skipped);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// insert IRB
|
|
||||||
irs.insert(id, irb);
|
|
||||||
|
|
||||||
#undef DEC_SIZE
|
|
||||||
}
|
|
||||||
|
|
||||||
return irs;
|
|
||||||
}
|
|
||||||
|
|
||||||
PSDAdditionalLayerInfo readAdditionalLayer(QDataStream &s, bool *ok = nullptr)
|
PSDAdditionalLayerInfo readAdditionalLayer(QDataStream &s, bool *ok = nullptr)
|
||||||
{
|
{
|
||||||
PSDAdditionalLayerInfo li;
|
PSDAdditionalLayerInfo li;
|
||||||
|
|||||||
Reference in New Issue
Block a user