summaryrefslogtreecommitdiffstats
path: root/src/gui/image
diff options
context:
space:
mode:
Diffstat (limited to 'src/gui/image')
-rw-r--r--src/gui/image/qbitmap.h2
-rw-r--r--src/gui/image/qicon.cpp2
-rw-r--r--src/gui/image/qicon.h8
-rw-r--r--src/gui/image/qimage.cpp148
-rw-r--r--src/gui/image/qimage.h28
-rw-r--r--src/gui/image/qimage_conversions.cpp4
-rw-r--r--src/gui/image/qimage_p.h6
-rw-r--r--src/gui/image/qpicture.h4
-rw-r--r--src/gui/image/qpixmap.h4
-rw-r--r--src/gui/image/qpixmapcache.cpp2
-rw-r--r--src/gui/image/qpixmapcache.h8
-rw-r--r--src/gui/image/qpixmapcache_p.h2
-rw-r--r--src/gui/image/qpnghandler.cpp72
-rw-r--r--src/gui/image/qppmhandler_p.h2
14 files changed, 248 insertions, 44 deletions
diff --git a/src/gui/image/qbitmap.h b/src/gui/image/qbitmap.h
index f7895bb1e0..3cc360f670 100644
--- a/src/gui/image/qbitmap.h
+++ b/src/gui/image/qbitmap.h
@@ -61,7 +61,7 @@ public:
QBitmap(const QBitmap &other) : QPixmap(other) {}
// QBitmap(QBitmap &&other) : QPixmap(std::move(other)) {} // QPixmap doesn't, yet, have a move ctor
QBitmap &operator=(const QBitmap &other) { QPixmap::operator=(other); return *this; }
- QBitmap &operator=(QBitmap &&other) Q_DECL_NOTHROW { QPixmap::operator=(std::move(other)); return *this; }
+ QBitmap &operator=(QBitmap &&other) noexcept { QPixmap::operator=(std::move(other)); return *this; }
~QBitmap();
#endif
diff --git a/src/gui/image/qicon.cpp b/src/gui/image/qicon.cpp
index c3c4b24678..892a686c89 100644
--- a/src/gui/image/qicon.cpp
+++ b/src/gui/image/qicon.cpp
@@ -663,7 +663,7 @@ QFactoryLoader *qt_iconEngineFactoryLoader()
/*!
Constructs a null icon.
*/
-QIcon::QIcon() Q_DECL_NOEXCEPT
+QIcon::QIcon() noexcept
: d(0)
{
}
diff --git a/src/gui/image/qicon.h b/src/gui/image/qicon.h
index 8870950982..0f834fc2cb 100644
--- a/src/gui/image/qicon.h
+++ b/src/gui/image/qicon.h
@@ -58,11 +58,11 @@ public:
enum Mode { Normal, Disabled, Active, Selected };
enum State { On, Off };
- QIcon() Q_DECL_NOEXCEPT;
+ QIcon() noexcept;
QIcon(const QPixmap &pixmap);
QIcon(const QIcon &other);
#ifdef Q_COMPILER_RVALUE_REFS
- QIcon(QIcon &&other) Q_DECL_NOEXCEPT
+ QIcon(QIcon &&other) noexcept
: d(other.d)
{ other.d = nullptr; }
#endif
@@ -71,10 +71,10 @@ public:
~QIcon();
QIcon &operator=(const QIcon &other);
#ifdef Q_COMPILER_RVALUE_REFS
- inline QIcon &operator=(QIcon &&other) Q_DECL_NOEXCEPT
+ inline QIcon &operator=(QIcon &&other) noexcept
{ swap(other); return *this; }
#endif
- inline void swap(QIcon &other) Q_DECL_NOEXCEPT
+ inline void swap(QIcon &other) noexcept
{ qSwap(d, other.d); }
operator QVariant() const;
diff --git a/src/gui/image/qimage.cpp b/src/gui/image/qimage.cpp
index ebd9037e44..917dde3b0f 100644
--- a/src/gui/image/qimage.cpp
+++ b/src/gui/image/qimage.cpp
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2018 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtGui module of the Qt Toolkit.
@@ -38,8 +38,10 @@
****************************************************************************/
#include "qimage.h"
-#include "qdatastream.h"
+
#include "qbuffer.h"
+#include "qdatastream.h"
+#include "qcolortransform.h"
#include "qmap.h"
#include "qmatrix.h"
#include "qtransform.h"
@@ -54,6 +56,7 @@
#include <stdlib.h>
#include <limits.h>
#include <qpa/qplatformpixmap.h>
+#include <private/qcolortransform_p.h>
#include <private/qdrawhelper_p.h>
#include <private/qmemrotate_p.h>
#include <private/qimagescale_p.h>
@@ -738,7 +741,7 @@ bool QImageData::checkForAlphaPixels() const
\sa isNull()
*/
-QImage::QImage() Q_DECL_NOEXCEPT
+QImage::QImage() noexcept
: QPaintDevice()
{
d = 0;
@@ -1103,6 +1106,7 @@ static void copyMetadata(QImageData *dst, const QImageData *src)
// Doesn't copy colortable and alpha_clut, or offset.
copyPhysicalMetadata(dst, src);
dst->text = src->text;
+ dst->colorSpace = src->colorSpace;
}
static void copyMetadata(QImage *dst, const QImage &src)
@@ -1392,7 +1396,7 @@ void QImage::setColorTable(const QVector<QRgb> colors)
#if QT_VERSION >= QT_VERSION_CHECK(6,0,0)
d->colortable = colors;
#else
- d->colortable = qMove(const_cast<QVector<QRgb>&>(colors));
+ d->colortable = std::move(const_cast<QVector<QRgb>&>(colors));
#endif
d->has_alpha_clut = false;
for (int i = 0; i < d->colortable.size(); ++i) {
@@ -4686,12 +4690,14 @@ QImage QImage::smoothScaled(int w, int h) const {
case QImage::Format_RGBX8888:
#endif
case QImage::Format_RGBA8888_Premultiplied:
+#if QT_CONFIG(raster_64bit)
case QImage::Format_RGBX64:
case QImage::Format_RGBA64_Premultiplied:
break;
case QImage::Format_RGBA64:
src = src.convertToFormat(QImage::Format_RGBA64_Premultiplied);
break;
+#endif
default:
if (src.hasAlphaChannel())
src = src.convertToFormat(QImage::Format_ARGB32_Premultiplied);
@@ -4949,6 +4955,132 @@ QTransform QImage::trueMatrix(const QTransform &matrix, int w, int h)
return matrix * QTransform().translate(-delta.x(), -delta.y());
}
+/*!
+ \since 5.14
+
+ Sets the image color space to \a colorSpace without performing any conversions on image data.
+
+ \sa colorSpace()
+*/
+void QImage::setColorSpace(const QColorSpace &colorSpace)
+{
+ if (!d)
+ return;
+ if (d->colorSpace == colorSpace)
+ return;
+ if (!isDetached()) // Detach only if shared, not for read-only data.
+ detach();
+ d->colorSpace = colorSpace;
+}
+
+/*!
+ \since 5.14
+
+ Converts the image to \a colorSpace.
+
+ If the image has no valid color space, the method does nothing.
+
+ \sa convertedToColorSpace(), setColorSpace()
+*/
+void QImage::convertToColorSpace(const QColorSpace &colorSpace)
+{
+ if (!d)
+ return;
+ if (!d->colorSpace.isValid())
+ return;
+ if (!colorSpace.isValid()) {
+ qWarning() << "QImage::convertToColorSpace: Output colorspace is not valid";
+ return;
+ }
+ detach();
+ applyColorTransform(d->colorSpace.transformationToColorSpace(colorSpace));
+ d->colorSpace = colorSpace;
+}
+
+/*!
+ \since 5.14
+
+ Returns the image converted to \a colorSpace.
+
+ If the image has no valid color space, a null QImage is returned.
+
+ \sa convertToColorSpace()
+*/
+QImage QImage::convertedToColorSpace(const QColorSpace &colorSpace) const
+{
+ if (!d || !d->colorSpace.isValid() || !colorSpace.isValid())
+ return QImage();
+ QImage image = copy();
+ image.convertToColorSpace(colorSpace);
+ return image;
+}
+
+/*!
+ \since 5.14
+
+ Returns the color space of the image if a color space is defined.
+*/
+QColorSpace QImage::colorSpace() const
+{
+ if (!d)
+ return QColorSpace::Undefined;
+ return d->colorSpace;
+}
+
+/*!
+ \since 5.14
+
+ Applies the color transformation \a transform to all pixels in the image.
+*/
+void QImage::applyColorTransform(const QColorTransform &transform)
+{
+ QImage::Format oldFormat = format();
+ if (depth() > 32) {
+ if (format() != QImage::Format_RGBX64 && format() != QImage::Format_RGBA64
+ && format() != QImage::Format_RGBA64_Premultiplied)
+ *this = std::move(*this).convertToFormat(QImage::Format_RGBA64);
+ } else if (format() != QImage::Format_ARGB32 && format() != QImage::Format_RGB32
+ && format() != QImage::Format_ARGB32_Premultiplied) {
+ if (hasAlphaChannel())
+ *this = std::move(*this).convertToFormat(QImage::Format_ARGB32);
+ else
+ *this = std::move(*this).convertToFormat(QImage::Format_RGB32);
+ }
+
+ QColorTransformPrivate::TransformFlags flags = QColorTransformPrivate::Unpremultiplied;
+ switch (format()) {
+ case Format_ARGB32_Premultiplied:
+ case Format_RGBA64_Premultiplied:
+ flags = QColorTransformPrivate::Premultiplied;
+ break;
+ case Format_RGB32:
+ case Format_RGBX64:
+ flags = QColorTransformPrivate::InputOpaque;
+ break;
+ case Format_ARGB32:
+ case Format_RGBA64:
+ break;
+ default:
+ Q_UNREACHABLE();
+ }
+
+ if (depth() > 32) {
+ for (int i = 0; i < height(); ++i) {
+ QRgba64 *scanline = reinterpret_cast<QRgba64 *>(scanLine(i));
+ transform.d_func()->apply(scanline, scanline, width(), flags);
+ }
+ } else {
+ for (int i = 0; i < height(); ++i) {
+ QRgb *scanline = reinterpret_cast<QRgb *>(scanLine(i));
+ transform.d_func()->apply(scanline, scanline, width(), flags);
+ }
+ }
+
+ if (oldFormat != format())
+ *this = std::move(*this).convertToFormat(oldFormat);
+}
+
+
bool QImageData::convertInPlace(QImage::Format newFormat, Qt::ImageConversionFlags flags)
{
if (format == newFormat)
@@ -5424,7 +5556,7 @@ Q_STATIC_ASSERT(sizeof(pixelformats) / sizeof(*pixelformats) == QImage::NImageFo
/*!
Returns the QImage::Format as a QPixelFormat
*/
-QPixelFormat QImage::pixelFormat() const Q_DECL_NOTHROW
+QPixelFormat QImage::pixelFormat() const noexcept
{
return toPixelFormat(format());
}
@@ -5432,7 +5564,7 @@ QPixelFormat QImage::pixelFormat() const Q_DECL_NOTHROW
/*!
Converts \a format into a QPixelFormat
*/
-QPixelFormat QImage::toPixelFormat(QImage::Format format) Q_DECL_NOTHROW
+QPixelFormat QImage::toPixelFormat(QImage::Format format) noexcept
{
Q_ASSERT(static_cast<int>(format) < NImageFormats);
return pixelformats[format];
@@ -5441,7 +5573,7 @@ QPixelFormat QImage::toPixelFormat(QImage::Format format) Q_DECL_NOTHROW
/*!
Converts \a format into a QImage::Format
*/
-QImage::Format QImage::toImageFormat(QPixelFormat format) Q_DECL_NOTHROW
+QImage::Format QImage::toImageFormat(QPixelFormat format) noexcept
{
for (int i = 0; i < NImageFormats; i++) {
if (format == pixelformats[i])
@@ -5457,7 +5589,7 @@ Q_GUI_EXPORT void qt_imageTransform(QImage &src, QImageIOHandler::Transformation
if (orient == QImageIOHandler::TransformationRotate270) {
src = rotated270(src);
} else {
- src = qMove(src).mirrored(orient & QImageIOHandler::TransformationMirror,
+ src = std::move(src).mirrored(orient & QImageIOHandler::TransformationMirror,
orient & QImageIOHandler::TransformationFlip);
if (orient & QImageIOHandler::TransformationRotate90)
src = rotated90(src);
diff --git a/src/gui/image/qimage.h b/src/gui/image/qimage.h
index 8335e117f2..9d177142d9 100644
--- a/src/gui/image/qimage.h
+++ b/src/gui/image/qimage.h
@@ -61,9 +61,11 @@ Q_FORWARD_DECLARE_MUTABLE_CG_TYPE(CGImage);
QT_BEGIN_NAMESPACE
+class QColorSpace;
+class QColorTransform;
class QIODevice;
-class QStringList;
class QMatrix;
+class QStringList;
class QTransform;
class QVariant;
template <class T> class QList;
@@ -135,7 +137,7 @@ public:
};
Q_ENUM(Format)
- QImage() Q_DECL_NOEXCEPT;
+ QImage() noexcept;
QImage(const QSize &size, Format format);
QImage(int width, int height, Format format);
QImage(uchar *data, int width, int height, Format format, QImageCleanupFunction cleanupFunction = nullptr, void *cleanupInfo = nullptr);
@@ -150,7 +152,7 @@ public:
QImage(const QImage &);
#ifdef Q_COMPILER_RVALUE_REFS
- inline QImage(QImage &&other) Q_DECL_NOEXCEPT
+ inline QImage(QImage &&other) noexcept
: QPaintDevice(), d(nullptr)
{ qSwap(d, other.d); }
#endif
@@ -158,10 +160,10 @@ public:
QImage &operator=(const QImage &);
#ifdef Q_COMPILER_RVALUE_REFS
- inline QImage &operator=(QImage &&other) Q_DECL_NOEXCEPT
+ inline QImage &operator=(QImage &&other) noexcept
{ qSwap(d, other.d); return *this; }
#endif
- inline void swap(QImage &other) Q_DECL_NOEXCEPT
+ inline void swap(QImage &other) noexcept
{ qSwap(d, other.d); }
bool isNull() const;
@@ -289,17 +291,23 @@ public:
QImage mirrored(bool horizontally = false, bool vertically = true) const &
{ return mirrored_helper(horizontally, vertically); }
QImage &&mirrored(bool horizontally = false, bool vertically = true) &&
- { mirrored_inplace(horizontally, vertically); return qMove(*this); }
+ { mirrored_inplace(horizontally, vertically); return std::move(*this); }
QImage rgbSwapped() const &
{ return rgbSwapped_helper(); }
QImage &&rgbSwapped() &&
- { rgbSwapped_inplace(); return qMove(*this); }
+ { rgbSwapped_inplace(); return std::move(*this); }
#else
QImage mirrored(bool horizontally = false, bool vertically = true) const;
QImage rgbSwapped() const;
#endif
void invertPixels(InvertMode = InvertRgb);
+ QColorSpace colorSpace() const;
+ QImage convertedToColorSpace(const QColorSpace &) const;
+ void convertToColorSpace(const QColorSpace &);
+ void setColorSpace(const QColorSpace &);
+
+ void applyColorTransform(const QColorTransform &transform);
bool load(QIODevice *device, const char* format);
bool load(const QString &fileName, const char *format = nullptr);
@@ -333,9 +341,9 @@ public:
QString text(const QString &key = QString()) const;
void setText(const QString &key, const QString &value);
- QPixelFormat pixelFormat() const Q_DECL_NOTHROW;
- static QPixelFormat toPixelFormat(QImage::Format format) Q_DECL_NOTHROW;
- static QImage::Format toImageFormat(QPixelFormat format) Q_DECL_NOTHROW;
+ QPixelFormat pixelFormat() const noexcept;
+ static QPixelFormat toPixelFormat(QImage::Format format) noexcept;
+ static QImage::Format toImageFormat(QPixelFormat format) noexcept;
// Platform specific conversion functions
#if defined(Q_OS_DARWIN) || defined(Q_QDOC)
diff --git a/src/gui/image/qimage_conversions.cpp b/src/gui/image/qimage_conversions.cpp
index 82ffb8af8b..837ac88470 100644
--- a/src/gui/image/qimage_conversions.cpp
+++ b/src/gui/image/qimage_conversions.cpp
@@ -39,7 +39,7 @@
#include <private/qdrawhelper_p.h>
#include <private/qguiapplication_p.h>
-#include <private/qcolorprofile_p.h>
+#include <private/qcolortrclut_p.h>
#include <private/qendian_p.h>
#include <private/qsimd_p.h>
#include <private/qimage_p.h>
@@ -100,7 +100,7 @@ const uchar *qt_get_bitflip_array()
void qGamma_correct_back_to_linear_cs(QImage *image)
{
- const QColorProfile *cp = QGuiApplicationPrivate::instance()->colorProfileForA32Text();
+ const QColorTrcLut *cp = QGuiApplicationPrivate::instance()->colorProfileForA32Text();
if (!cp)
return;
// gamma correct the pixels back to linear color space...
diff --git a/src/gui/image/qimage_p.h b/src/gui/image/qimage_p.h
index d88ad2d1d2..9da6acd0a7 100644
--- a/src/gui/image/qimage_p.h
+++ b/src/gui/image/qimage_p.h
@@ -51,7 +51,9 @@
// We mean it.
//
+#include <QtGui/qcolorspace.h>
#include <QtGui/private/qtguiglobal_p.h>
+#include <QtGui/qimage.h>
#include <QtCore/private/qnumeric_p.h>
#include <QMap>
@@ -65,7 +67,7 @@ struct Q_GUI_EXPORT QImageData { // internal image data
QImageData();
~QImageData();
static QImageData *create(const QSize &size, QImage::Format format);
- static QImageData *create(uchar *data, int w, int h, int bpl, QImage::Format format, bool readOnly, QImageCleanupFunction cleanupFunction = 0, void *cleanupInfo = 0);
+ static QImageData *create(uchar *data, int w, int h, int bpl, QImage::Format format, bool readOnly, QImageCleanupFunction cleanupFunction = nullptr, void *cleanupInfo = nullptr);
QAtomicInt ref;
@@ -106,6 +108,8 @@ struct Q_GUI_EXPORT QImageData { // internal image data
QPaintEngine *paintEngine;
+ QColorSpace colorSpace;
+
struct ImageSizeParameters {
qsizetype bytesPerLine;
qsizetype totalSize;
diff --git a/src/gui/image/qpicture.h b/src/gui/image/qpicture.h
index ec7b4bd7e3..cac2ef5dfc 100644
--- a/src/gui/image/qpicture.h
+++ b/src/gui/image/qpicture.h
@@ -79,10 +79,10 @@ public:
QPicture& operator=(const QPicture &p);
#ifdef Q_COMPILER_RVALUE_REFS
- inline QPicture &operator=(QPicture &&other) Q_DECL_NOEXCEPT
+ inline QPicture &operator=(QPicture &&other) noexcept
{ qSwap(d_ptr, other.d_ptr); return *this; }
#endif
- inline void swap(QPicture &other) Q_DECL_NOEXCEPT
+ inline void swap(QPicture &other) noexcept
{ d_ptr.swap(other.d_ptr); }
void detach();
bool isDetached() const;
diff --git a/src/gui/image/qpixmap.h b/src/gui/image/qpixmap.h
index 13c81f18d0..2103fcc58c 100644
--- a/src/gui/image/qpixmap.h
+++ b/src/gui/image/qpixmap.h
@@ -74,10 +74,10 @@ public:
QPixmap &operator=(const QPixmap &);
#ifdef Q_COMPILER_RVALUE_REFS
- inline QPixmap &operator=(QPixmap &&other) Q_DECL_NOEXCEPT
+ inline QPixmap &operator=(QPixmap &&other) noexcept
{ qSwap(data, other.data); return *this; }
#endif
- inline void swap(QPixmap &other) Q_DECL_NOEXCEPT
+ inline void swap(QPixmap &other) noexcept
{ qSwap(data, other.data); }
operator QVariant() const;
diff --git a/src/gui/image/qpixmapcache.cpp b/src/gui/image/qpixmapcache.cpp
index 66907bebd7..a41ec8f35c 100644
--- a/src/gui/image/qpixmapcache.cpp
+++ b/src/gui/image/qpixmapcache.cpp
@@ -176,7 +176,7 @@ bool QPixmapCache::Key::operator ==(const Key &key) const
Otherwise, if pixmap was flushed, the key is no longer valid.
\since 5.7
*/
-bool QPixmapCache::Key::isValid() const Q_DECL_NOTHROW
+bool QPixmapCache::Key::isValid() const noexcept
{
return d && d->isValid;
}
diff --git a/src/gui/image/qpixmapcache.h b/src/gui/image/qpixmapcache.h
index 12d05b00f3..c5bedb27ab 100644
--- a/src/gui/image/qpixmapcache.h
+++ b/src/gui/image/qpixmapcache.h
@@ -56,8 +56,8 @@ public:
Key();
Key(const Key &other);
#ifdef Q_COMPILER_RVALUE_REFS
- Key(Key &&other) Q_DECL_NOTHROW : d(other.d) { other.d = nullptr; }
- Key &operator =(Key &&other) Q_DECL_NOTHROW { swap(other); return *this; }
+ Key(Key &&other) noexcept : d(other.d) { other.d = nullptr; }
+ Key &operator =(Key &&other) noexcept { swap(other); return *this; }
#endif
~Key();
bool operator ==(const Key &key) const;
@@ -65,8 +65,8 @@ public:
{ return !operator==(key); }
Key &operator =(const Key &other);
- void swap(Key &other) Q_DECL_NOTHROW { qSwap(d, other.d); }
- bool isValid() const Q_DECL_NOTHROW;
+ void swap(Key &other) noexcept { qSwap(d, other.d); }
+ bool isValid() const noexcept;
private:
KeyData *d;
diff --git a/src/gui/image/qpixmapcache_p.h b/src/gui/image/qpixmapcache_p.h
index 3c57367514..ab8e2b7558 100644
--- a/src/gui/image/qpixmapcache_p.h
+++ b/src/gui/image/qpixmapcache_p.h
@@ -87,7 +87,7 @@ public:
&& !d->image.d->paintEngine->isActive())
{
delete d->image.d->paintEngine;
- d->image.d->paintEngine = 0;
+ d->image.d->paintEngine = nullptr;
}
}
}
diff --git a/src/gui/image/qpnghandler.cpp b/src/gui/image/qpnghandler.cpp
index 1c269213e2..39d0807606 100644
--- a/src/gui/image/qpnghandler.cpp
+++ b/src/gui/image/qpnghandler.cpp
@@ -42,6 +42,7 @@
#ifndef QT_NO_IMAGEFORMAT_PNG
#include <qcoreapplication.h>
+#include <qdebug.h>
#include <qiodevice.h>
#include <qimage.h>
#include <qlist.h>
@@ -50,6 +51,10 @@
#include <private/qimage_p.h> // for qt_getImageText
+#include <qcolorspace.h>
+#include <private/qcolorspace_p.h>
+#include <private/qicc_p.h>
+
#include <png.h>
#include <pngconf.h>
@@ -96,9 +101,16 @@ public:
ReadingEnd,
Error
};
+ // Defines the order of how the various ways of setting colorspace overrides eachother:
+ enum ColorSpaceState {
+ Undefined = 0,
+ GammaChrm = 1, // gAMA+cHRM chunks
+ Srgb = 2, // sRGB chunk
+ Icc = 3 // iCCP chunk
+ };
QPngHandlerPrivate(QPngHandler *qq)
- : gamma(0.0), fileGamma(0.0), quality(50), compression(50), png_ptr(0), info_ptr(0), end_info(0), state(Ready), q(qq)
+ : gamma(0.0), fileGamma(0.0), quality(50), compression(50), colorSpaceState(Undefined), png_ptr(0), info_ptr(0), end_info(0), state(Ready), q(qq)
{ }
float gamma;
@@ -108,6 +120,8 @@ public:
QString description;
QSize scaledSize;
QStringList readTexts;
+ QColorSpace colorSpace;
+ ColorSpaceState colorSpaceState;
png_struct *png_ptr;
png_info *info_ptr;
@@ -226,11 +240,8 @@ void qpiw_flush_fn(png_structp /* png_ptr */)
}
static
-void setup_qt(QImage& image, png_structp png_ptr, png_infop info_ptr, QSize scaledSize, bool *doScaledRead, float screen_gamma=0.0, float file_gamma=0.0)
+void setup_qt(QImage& image, png_structp png_ptr, png_infop info_ptr, QSize scaledSize, bool *doScaledRead)
{
- if (screen_gamma != 0.0 && file_gamma != 0.0)
- png_set_gamma(png_ptr, 1.0f / screen_gamma, file_gamma);
-
png_uint_32 width = 0;
png_uint_32 height = 0;
int bit_depth = 0;
@@ -585,10 +596,45 @@ bool QPngHandlerPrivate::readPngHeader()
readPngTexts(info_ptr);
+#ifdef PNG_iCCP_SUPPORTED
+ if (png_get_valid(png_ptr, info_ptr, PNG_INFO_iCCP)) {
+ png_charp name = nullptr;
+ int compressionType = 0;
+#if (PNG_LIBPNG_VER < 10500)
+ png_charp profileData = nullptr;
+#else
+ png_bytep profileData = nullptr;
+#endif
+ png_uint_32 profLen;
+ png_get_iCCP(png_ptr, info_ptr, &name, &compressionType, &profileData, &profLen);
+ if (!QIcc::fromIccProfile(QByteArray::fromRawData((const char *)profileData, profLen), &colorSpace)) {
+ qWarning() << "QPngHandler: Failed to parse ICC profile";
+ } else {
+ colorSpaceState = Icc;
+ }
+ }
+#endif
+ if (png_get_valid(png_ptr, info_ptr, PNG_INFO_sRGB)) {
+ int rendering_intent = -1;
+ png_get_sRGB(png_ptr, info_ptr, &rendering_intent);
+ // We don't actually care about the rendering_intent, just that it is valid
+ if (rendering_intent >= 0 && rendering_intent <= 3 && colorSpaceState <= Srgb) {
+ colorSpace = QColorSpace::SRgb;
+ colorSpaceState = Srgb;
+ }
+ }
if (png_get_valid(png_ptr, info_ptr, PNG_INFO_gAMA)) {
double file_gamma = 0.0;
png_get_gAMA(png_ptr, info_ptr, &file_gamma);
fileGamma = file_gamma;
+ if (fileGamma > 0.0f && colorSpaceState <= GammaChrm) {
+ QColorSpacePrivate *csPrivate = colorSpace.d_func();
+ csPrivate->gamut = QColorSpace::Gamut::SRgb;
+ csPrivate->transferFunction = QColorSpace::TransferFunction::Gamma;
+ csPrivate->gamma = fileGamma;
+ csPrivate->initialize();
+ colorSpaceState = GammaChrm;
+ }
}
state = ReadHeader;
@@ -613,8 +659,19 @@ bool QPngHandlerPrivate::readPngImage(QImage *outImage)
return false;
}
+ if (gamma != 0.0 && fileGamma != 0.0) {
+ // This configuration forces gamma correction and
+ // thus changes the output colorspace
+ png_set_gamma(png_ptr, 1.0f / gamma, fileGamma);
+ QColorSpacePrivate *csPrivate = colorSpace.d_func();
+ csPrivate->transferFunction = QColorSpace::TransferFunction::Gamma;
+ csPrivate->gamma = gamma;
+ csPrivate->initialize();
+ colorSpaceState = GammaChrm;
+ }
+
bool doScaledRead = false;
- setup_qt(*outImage, png_ptr, info_ptr, scaledSize, &doScaledRead, gamma, fileGamma);
+ setup_qt(*outImage, png_ptr, info_ptr, scaledSize, &doScaledRead);
if (outImage->isNull()) {
png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
@@ -683,6 +740,9 @@ bool QPngHandlerPrivate::readPngImage(QImage *outImage)
if (scaledSize.isValid() && outImage->size() != scaledSize)
*outImage = outImage->scaled(scaledSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
+ if (colorSpaceState > Undefined && colorSpace.isValid())
+ outImage->setColorSpace(colorSpace);
+
return true;
}
diff --git a/src/gui/image/qppmhandler_p.h b/src/gui/image/qppmhandler_p.h
index f3c9d0f139..2f3811b759 100644
--- a/src/gui/image/qppmhandler_p.h
+++ b/src/gui/image/qppmhandler_p.h
@@ -71,7 +71,7 @@ public:
QByteArray name() const override;
#endif
- static bool canRead(QIODevice *device, QByteArray *subType = 0);
+ static bool canRead(QIODevice *device, QByteArray *subType = nullptr);
QVariant option(ImageOption option) const override;
void setOption(ImageOption option, const QVariant &value) override;