mirror of
https://invent.kde.org/frameworks/kimageformats.git
synced 2025-05-28 00:30:23 -04:00
Fix XCF parasites metadata in QImage and support to ICC profile
- Fix parasite "gimp-comment" not set due to null QImage - Support to parasite "icc-profile" using Qt 5.14+ API - Added parasite "gimp-image-metadata" as QImage metadata "XML:org.gimp.xml" - Added a XCF with XML metadata and icc prifile embedded in autotest folder (generated by GIMP 2.10.30) - Tested with Qt 5.15.2 and Qt 6.2.3 under Windows and Qt 6.2.3 under macOS
This commit is contained in:
parent
e69dff73e6
commit
3e751dd80d
BIN
autotests/read/xcf/fruktpilot_icc.png
Normal file
BIN
autotests/read/xcf/fruktpilot_icc.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 115 KiB |
BIN
autotests/read/xcf/fruktpilot_icc.xcf
Normal file
BIN
autotests/read/xcf/fruktpilot_icc.xcf
Normal file
Binary file not shown.
@ -16,8 +16,9 @@
|
||||
#include <QStack>
|
||||
#include <QVector>
|
||||
#include <QtEndian>
|
||||
#include <stdlib.h>
|
||||
#include <QColorSpace>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "gimp_p.h"
|
||||
@ -351,6 +352,8 @@ private:
|
||||
bool initialized; //!< Is the QImage initialized?
|
||||
QImage image; //!< final QImage
|
||||
|
||||
QHash<QString,QByteArray> parasites; //!< parasites data
|
||||
|
||||
XCFImage(void)
|
||||
: initialized(false)
|
||||
{
|
||||
@ -405,6 +408,7 @@ private:
|
||||
bool composeTiles(XCFImage &xcf_image);
|
||||
void setGrayPalette(QImage &image);
|
||||
void setPalette(XCFImage &xcf_image, QImage &image);
|
||||
void setImageParasites(const XCFImage &xcf_image, QImage &image);
|
||||
static void assignImageBytes(Layer &layer, uint i, uint j);
|
||||
bool loadHierarchy(QDataStream &xcf_io, Layer &layer);
|
||||
bool loadLevel(QDataStream &xcf_io, Layer &layer, qint32 bpp);
|
||||
@ -665,6 +669,9 @@ bool XCFImageFormat::readXCF(QIODevice *device, QImage *outImage)
|
||||
return false;
|
||||
}
|
||||
|
||||
// The image was created: now I can set metadata and ICC color profile inside it.
|
||||
setImageParasites(xcf_image, xcf_image.image);
|
||||
|
||||
*outImage = xcf_image.image;
|
||||
return true;
|
||||
}
|
||||
@ -715,15 +722,15 @@ bool XCFImageFormat::loadImageProperties(QDataStream &xcf_io, XCFImage &xcf_imag
|
||||
property.readBytes(tag, size);
|
||||
|
||||
quint32 flags;
|
||||
char *data = nullptr;
|
||||
QByteArray data;
|
||||
property >> flags >> data;
|
||||
|
||||
if (tag && strncmp(tag, "gimp-comment", strlen("gimp-comment")) == 0) {
|
||||
xcf_image.image.setText(QStringLiteral("Comment"), QString::fromUtf8(data));
|
||||
}
|
||||
// WARNING: you cannot add metadata to QImage here because it can be null.
|
||||
// Adding a metadata to a QImage when it is null, does nothing (metas are lost).
|
||||
if(tag) // store metadata for future use
|
||||
xcf_image.parasites.insert(QString::fromUtf8(tag), data);
|
||||
|
||||
delete[] tag;
|
||||
delete[] data;
|
||||
}
|
||||
break;
|
||||
|
||||
@ -1234,6 +1241,77 @@ void XCFImageFormat::setPalette(XCFImage &xcf_image, QImage &image)
|
||||
image.setColorTable(xcf_image.palette);
|
||||
}
|
||||
|
||||
/*!
|
||||
* Copy the parasites info to QImage.
|
||||
* \param xcf_image XCF image containing the parasites read from the data stream.
|
||||
* \param image image to apply the parasites data.
|
||||
* \note Some comment taken from https://gitlab.gnome.org/GNOME/gimp/-/blob/master/devel-docs/parasites.txt
|
||||
*/
|
||||
void XCFImageFormat::setImageParasites(const XCFImage &xcf_image, QImage &image)
|
||||
{
|
||||
auto&& p = xcf_image.parasites;
|
||||
auto keys = p.keys();
|
||||
for (auto&& key : qAsConst(keys)) {
|
||||
auto value = p.value(key);
|
||||
if(value.isEmpty())
|
||||
continue;
|
||||
|
||||
// "icc-profile" (IMAGE, PERSISTENT | UNDOABLE)
|
||||
// This contains an ICC profile describing the color space the
|
||||
// image was produced in. TIFF images stored in PhotoShop do
|
||||
// oftentimes contain embedded profiles. An experimental color
|
||||
// manager exists to use this parasite, and it will be used
|
||||
// for interchange between TIFF and PNG (identical profiles)
|
||||
if (key == QStringLiteral("icc-profile")) {
|
||||
auto cs = QColorSpace::fromIccProfile(value);
|
||||
if(cs.isValid())
|
||||
image.setColorSpace(cs);
|
||||
continue;
|
||||
}
|
||||
|
||||
// "gimp-comment" (IMAGE, PERSISTENT)
|
||||
// Standard GIF-style image comments. This parasite should be
|
||||
// human-readable text in UTF-8 encoding. A trailing \0 might
|
||||
// be included and is not part of the comment. Note that image
|
||||
// comments may also be present in the "gimp-metadata" parasite.
|
||||
if (key == QStringLiteral("gimp-comment")) {
|
||||
value.replace('\0', QByteArray());
|
||||
image.setText(QStringLiteral("Comment"), QString::fromUtf8(value));
|
||||
continue;
|
||||
}
|
||||
|
||||
// "gimp-image-metadata"
|
||||
// Saved by GIMP 2.10.30 but it is not mentioned in the specification.
|
||||
// It is an XML block with the properties set using GIMP.
|
||||
if (key == QStringLiteral("gimp-image-metadata")) {
|
||||
// NOTE: I arbitrary defined the metadata "XML:org.gimp.xml" because it seems
|
||||
// a GIMP proprietary XML format (no xmlns defined)
|
||||
value.replace('\0', QByteArray());
|
||||
image.setText(QStringLiteral("XML:org.gimp.xml"), QString::fromUtf8(value));
|
||||
continue;
|
||||
}
|
||||
|
||||
#if 0 // Unable to generate it using latest GIMP version
|
||||
// "gimp-metadata" (IMAGE, PERSISTENT)
|
||||
// The metadata associated with the image, serialized as one XMP
|
||||
// packet. This metadata includes the contents of any XMP, EXIF
|
||||
// and IPTC blocks from the original image, as well as
|
||||
// user-specified values such as image comment, copyright,
|
||||
// license, etc.
|
||||
if (key == QStringLiteral("gimp-metadata")) {
|
||||
// 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 reused the same key because some programs could search for it.
|
||||
value.replace('\0', QByteArray());
|
||||
image.setText(QStringLiteral("XML:com.adobe.xmp"), QString::fromUtf8(value));
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
* Copy the bytes from the tile buffer into the image tile QImage, taking into
|
||||
* account all the myriad different modes.
|
||||
|
Loading…
Reference in New Issue
Block a user