summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGiuseppe D'Angelo <giuseppe.dangelo@kdab.com>2024-03-09 14:34:50 +0100
committerGiuseppe D'Angelo <giuseppe.dangelo@kdab.com>2024-03-10 11:59:32 +0100
commit003cef9d40f2e840f2690bd465994deaab5c2b95 (patch)
tree98ec3ec9882c5dea77f2cab6f356e891122e8e91
parent0804109d686e0a99ab0de0f1c70e3422183c6e98 (diff)
PNG: preserve ICC profiles that QColorSpace does not handle
QColorSpace::isValid() returns true if QColorSpace can handle the profile. When called on a QColorSpace obtained via QColorSpace::fromIccProfile, this doesn't necessarily mean that the ICC profile itself was invalid; it could be that the ICC data was valid, but QColorSpace didn't know how to use it. This is especially true on Qt <= 6.7, where only XYZ/RGB matrix profiles were supported. We don't fully parse ICC v4, and we're lacking an API to differentiate between "ICC data was valid but QColorSpace doesn't handle it" vs "ICC data was invalid". Still, an invalid QColorSpace will still the original ICC data, so it can be saved again without loss of information. So: 1) when loading a PNG with embedded ICC data, keep the loaded profile even if it's "invalid"; 2) when writing a PNG, check if we have ICC data to save, and unconditionally write it if it's the case. This avoids data loss in the two directions. This work has been kindly sponsored by the QGIS project (https://qgis.org/). Pick-to: 6.7 6.6 6.5 Change-Id: I1f27f603acbca1590c820e80f52f3b994f5ea5c7 Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
-rw-r--r--src/gui/image/qpnghandler.cpp20
1 files changed, 10 insertions, 10 deletions
diff --git a/src/gui/image/qpnghandler.cpp b/src/gui/image/qpnghandler.cpp
index c9b12c15f8..615a36fa36 100644
--- a/src/gui/image/qpnghandler.cpp
+++ b/src/gui/image/qpnghandler.cpp
@@ -554,10 +554,10 @@ bool QPngHandlerPrivate::readPngHeader()
#endif
png_uint_32 profLen;
png_get_iCCP(png_ptr, info_ptr, &name, &compressionType, &profileData, &profLen);
- colorSpace = QColorSpace::fromIccProfile(QByteArray((const char *)profileData, profLen));
- if (!colorSpace.isValid()) {
- qCDebug(lcImageIo) << "QPngHandler: Failed to parse ICC profile";
- } else {
+ Q_UNUSED(name);
+ Q_UNUSED(compressionType);
+ if (profLen > 0) {
+ colorSpace = QColorSpace::fromIccProfile(QByteArray((const char *)profileData, profLen));
QColorSpacePrivate *csD = QColorSpacePrivate::get(colorSpace);
if (csD->description.isEmpty())
csD->description = QString::fromLatin1((const char *)name);
@@ -926,15 +926,15 @@ bool QPNGImageWriter::writeImage(const QImage& image, int compression_in, const
color_type, 0, 0, 0); // sets #channels
#ifdef PNG_iCCP_SUPPORTED
- if (image.colorSpace().isValid()) {
- QColorSpace cs = image.colorSpace();
- // Support the old gamma making it override transferfunction.
- if (gamma != 0.0 && !qFuzzyCompare(cs.gamma(), 1.0f / gamma))
- cs = cs.withTransferFunction(QColorSpace::TransferFunction::Gamma, 1.0f / gamma);
+ QColorSpace cs = image.colorSpace();
+ // Support the old gamma making it override transferfunction (if possible)
+ if (cs.isValid() && gamma != 0.0 && !qFuzzyCompare(cs.gamma(), 1.0f / gamma))
+ cs = cs.withTransferFunction(QColorSpace::TransferFunction::Gamma, 1.0f / gamma);
+ QByteArray iccProfile = cs.iccProfile();
+ if (!iccProfile.isEmpty()) {
QByteArray iccProfileName = cs.description().toLatin1();
if (iccProfileName.isEmpty())
iccProfileName = QByteArrayLiteral("Custom");
- QByteArray iccProfile = cs.iccProfile();
png_set_iCCP(png_ptr, info_ptr,
#if PNG_LIBPNG_VER < 10500
iccProfileName.data(), PNG_COMPRESSION_TYPE_BASE, iccProfile.data(),