mirror of
https://invent.kde.org/frameworks/kimageformats.git
synced 2026-09-18 06:07:01 -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
|
||||
header=`ls $SRC/kimageformats/src/imageformats/$format*.h`
|
||||
/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.
|
||||
|
||||
|
||||
@@ -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",
|
||||
"gamma" : 1
|
||||
},
|
||||
"metadata" : [
|
||||
{
|
||||
"key" : "ModificationDate",
|
||||
"value" : "2026-04-15T10:48:48"
|
||||
},
|
||||
{
|
||||
"key" : "Software" ,
|
||||
"value" : "Adobe Photoshop 27.5 (Windows)"
|
||||
}
|
||||
],
|
||||
"resolution" : {
|
||||
"dotsPerMeterX" : 3937,
|
||||
"dotsPerMeterY" : 3937
|
||||
"dotsPerMeterX" : 11811,
|
||||
"dotsPerMeterY" : 11811
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
@@ -57,7 +57,7 @@ endif()
|
||||
##################################
|
||||
|
||||
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)
|
||||
target_link_libraries(kimg_exr PRIVATE OpenEXR::OpenEXR)
|
||||
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 "microexif_p.h"
|
||||
#include "photoshop_p.h"
|
||||
#include "scanlineconverter_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")) {
|
||||
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 "microexif_p.h"
|
||||
#include "packbits_p.h"
|
||||
#include "photoshop_p.h"
|
||||
#include "psd_p.h"
|
||||
#include "scanlineconverter_p.h"
|
||||
#include "util_p.h"
|
||||
|
||||
#include <QColorSpace>
|
||||
#include <QDataStream>
|
||||
#include <QImage>
|
||||
#include <QLoggingCategory>
|
||||
|
||||
@@ -99,41 +99,6 @@ namespace // Private.
|
||||
|
||||
#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 {
|
||||
PSDHeader() {
|
||||
memset(this, 0, sizeof(PSDHeader));
|
||||
@@ -149,11 +114,6 @@ struct PSDHeader {
|
||||
ushort color_mode;
|
||||
};
|
||||
|
||||
struct PSDImageResourceBlock {
|
||||
QString name;
|
||||
QByteArray data;
|
||||
};
|
||||
|
||||
/*!
|
||||
* \brief The PSDDuotoneOptions struct
|
||||
* \note You can decode the duotone data using the "Duotone Options"
|
||||
@@ -172,7 +132,6 @@ struct PSDColorModeDataSection {
|
||||
QList<QRgb> palette;
|
||||
};
|
||||
|
||||
using PSDImageResourceSection = QHash<quint16, PSDImageResourceBlock>;
|
||||
|
||||
struct PSDLayerInfo {
|
||||
qint64 size = -1;
|
||||
@@ -273,145 +232,6 @@ static bool skip_section(QDataStream &s, bool psb = false)
|
||||
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 li;
|
||||
|
||||
Reference in New Issue
Block a user