Compare commits

...

5 Commits

Author SHA1 Message Date
ae6b724824 GIT_SILENT Upgrade ECM and KF version requirements for 5.93.0 release. 2022-04-02 10:00:12 +00:00
3e751dd80d 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
2022-03-23 23:34:33 +00:00
e69dff73e6 avif: encoder speed 7->6 2022-03-10 09:44:50 +01:00
64cfe52bee avif: fix jumpToImage 2022-03-10 09:39:53 +01:00
8732fc8487 avif: warn about non-recommended libavif configuration 2022-03-10 09:35:08 +01:00
5 changed files with 98 additions and 9 deletions

View File

@ -3,7 +3,7 @@ cmake_minimum_required(VERSION 3.16)
project(KImageFormats)
include(FeatureSummary)
find_package(ECM 5.92.0 NO_MODULE)
find_package(ECM 5.93.0 NO_MODULE)
set_package_properties(ECM PROPERTIES TYPE REQUIRED DESCRIPTION "Extra CMake Modules." URL "https://commits.kde.org/extra-cmake-modules")
feature_summary(WHAT REQUIRED_PACKAGES_NOT_FOUND FATAL_ON_MISSING_REQUIRED_PACKAGES)

Binary file not shown.

After

Width:  |  Height:  |  Size: 115 KiB

Binary file not shown.

View File

@ -446,6 +446,16 @@ bool QAVIFHandler::write(const QImage &image)
return false;
}
const char *encoder_name = avifCodecName(AVIF_CODEC_CHOICE_AUTO, AVIF_CODEC_FLAG_CAN_ENCODE);
if (!encoder_name) {
qWarning("Cannot save AVIF images because libavif was built without AV1 encoders!");
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);
}
int maxQuantizer = AVIF_QUANTIZER_WORST_QUALITY * (100 - qBound(0, m_quality, 100)) / 100;
int minQuantizer = 0;
int maxQuantizerAlpha = 0;
@ -738,7 +748,7 @@ bool QAVIFHandler::write(const QImage &image)
encoder->maxQuantizerAlpha = maxQuantizerAlpha;
}
encoder->speed = 7;
encoder->speed = 6;
res = avifEncoderWrite(encoder, avif, &raw);
avifEncoderDestroy(encoder);
@ -891,7 +901,8 @@ bool QAVIFHandler::jumpToImage(int imageNumber)
return false;
}
if (imageNumber == m_decoder->imageCount) { // we are here already
if (imageNumber == m_decoder->imageIndex) { // we are here already
m_must_jump_to_next_image = false;
return true;
}

View File

@ -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.