summaryrefslogtreecommitdiffstats
path: root/src/gui/image
diff options
context:
space:
mode:
Diffstat (limited to 'src/gui/image')
-rw-r--r--src/gui/image/qbitmap.cpp2
-rw-r--r--src/gui/image/qbitmap.h5
-rw-r--r--src/gui/image/qbmphandler.cpp4
-rw-r--r--src/gui/image/qbmphandler_p.h3
-rw-r--r--src/gui/image/qicon.cpp14
-rw-r--r--src/gui/image/qicon.h9
-rw-r--r--src/gui/image/qiconengine.h1
-rw-r--r--src/gui/image/qiconloader.cpp11
-rw-r--r--src/gui/image/qimage.cpp337
-rw-r--r--src/gui/image/qimage.h37
-rw-r--r--src/gui/image/qimage_conversions.cpp398
-rw-r--r--src/gui/image/qimage_darwin.mm29
-rw-r--r--src/gui/image/qimage_neon.cpp66
-rw-r--r--src/gui/image/qimage_p.h46
-rw-r--r--src/gui/image/qimageiohandler.cpp4
-rw-r--r--src/gui/image/qimageiohandler.h3
-rw-r--r--src/gui/image/qimagereader.cpp22
-rw-r--r--src/gui/image/qimagewriter.cpp16
-rw-r--r--src/gui/image/qimagewriter.h5
-rw-r--r--src/gui/image/qmovie.cpp6
-rw-r--r--src/gui/image/qpaintengine_pic_p.h2
-rw-r--r--src/gui/image/qpicture.cpp35
-rw-r--r--src/gui/image/qpicture.h4
-rw-r--r--src/gui/image/qpixmap.cpp54
-rw-r--r--src/gui/image/qpixmap.h20
-rw-r--r--src/gui/image/qpixmap_raster.cpp3
-rw-r--r--src/gui/image/qpixmap_win.cpp9
-rw-r--r--src/gui/image/qpixmapcache.cpp14
-rw-r--r--src/gui/image/qpixmapcache.h12
-rw-r--r--src/gui/image/qpixmapcache_p.h2
-rw-r--r--src/gui/image/qplatformpixmap.cpp1
-rw-r--r--src/gui/image/qpnghandler.cpp157
-rw-r--r--src/gui/image/qpnghandler_p.h2
-rw-r--r--src/gui/image/qppmhandler.cpp2
-rw-r--r--src/gui/image/qppmhandler_p.h4
-rw-r--r--src/gui/image/qxbmhandler.cpp6
-rw-r--r--src/gui/image/qxbmhandler_p.h2
-rw-r--r--src/gui/image/qxpmhandler.cpp2
-rw-r--r--src/gui/image/qxpmhandler_p.h2
39 files changed, 886 insertions, 465 deletions
diff --git a/src/gui/image/qbitmap.cpp b/src/gui/image/qbitmap.cpp
index 2453242fa8..455045eb57 100644
--- a/src/gui/image/qbitmap.cpp
+++ b/src/gui/image/qbitmap.cpp
@@ -310,6 +310,7 @@ QBitmap QBitmap::transformed(const QTransform &matrix) const
return bm;
}
+#if QT_DEPRECATED_SINCE(5, 13)
/*!
\overload
\obsolete
@@ -321,5 +322,6 @@ QBitmap QBitmap::transformed(const QMatrix &matrix) const
{
return transformed(QTransform(matrix));
}
+#endif
QT_END_NAMESPACE
diff --git a/src/gui/image/qbitmap.h b/src/gui/image/qbitmap.h
index 188064fccf..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
@@ -76,7 +76,10 @@ public:
static QBitmap fromData(const QSize &size, const uchar *bits,
QImage::Format monoFormat = QImage::Format_MonoLSB);
+#if QT_DEPRECATED_SINCE(5, 13)
+ QT_DEPRECATED_X("Use QBitmap::transformed(QTransform) instead")
QBitmap transformed(const QMatrix &) const;
+#endif
QBitmap transformed(const QTransform &matrix) const;
typedef QExplicitlySharedDataPointer<QPlatformPixmap> DataPtr;
diff --git a/src/gui/image/qbmphandler.cpp b/src/gui/image/qbmphandler.cpp
index 5dff4ab0ac..7f8e072322 100644
--- a/src/gui/image/qbmphandler.cpp
+++ b/src/gui/image/qbmphandler.cpp
@@ -188,7 +188,7 @@ static bool read_dib_infoheader(QDataStream &s, BMP_INFOHDR &bi)
if (!(comp == BMP_RGB || (nbits == 4 && comp == BMP_RLE4) ||
(nbits == 8 && comp == BMP_RLE8) || ((nbits == 16 || nbits == 32) && comp == BMP_BITFIELDS)))
return false; // weird compression type
- if (bi.biWidth < 0 || quint64(bi.biWidth) * qAbs(bi.biHeight) > 16384 * 16384)
+ if (bi.biWidth <= 0 || !bi.biHeight || quint64(bi.biWidth) * qAbs(bi.biHeight) > 16384 * 16384)
return false;
return true;
@@ -866,10 +866,12 @@ void QBmpHandler::setOption(ImageOption option, const QVariant &value)
Q_UNUSED(value);
}
+#if QT_DEPRECATED_SINCE(5, 13)
QByteArray QBmpHandler::name() const
{
return formatName();
}
+#endif
QT_END_NAMESPACE
diff --git a/src/gui/image/qbmphandler_p.h b/src/gui/image/qbmphandler_p.h
index 56b39dd0f0..33b5b9c501 100644
--- a/src/gui/image/qbmphandler_p.h
+++ b/src/gui/image/qbmphandler_p.h
@@ -113,8 +113,9 @@ public:
bool read(QImage *image) override;
bool write(const QImage &image) override;
+#if QT_DEPRECATED_SINCE(5, 13)
QByteArray name() const override;
-
+#endif
static bool canRead(QIODevice *device);
QVariant option(ImageOption option) const override;
diff --git a/src/gui/image/qicon.cpp b/src/gui/image/qicon.cpp
index 5907d69f87..892a686c89 100644
--- a/src/gui/image/qicon.cpp
+++ b/src/gui/image/qicon.cpp
@@ -47,8 +47,10 @@
#include "private/qiconloader_p.h"
#include "qpainter.h"
#include "qfileinfo.h"
+#if QT_CONFIG(mimetype)
#include <qmimedatabase.h>
#include <qmimetype.h>
+#endif
#include "qpixmapcache.h"
#include "qvariant.h"
#include "qcache.h"
@@ -313,9 +315,9 @@ QPixmap QPixmapIconEngine::pixmap(const QSize &size, QIcon::Mode mode, QIcon::St
% HexString<uint>(actualSize.height());
if (mode == QIcon::Active) {
- if (QPixmapCache::find(key % HexString<uint>(mode), pm))
+ if (QPixmapCache::find(key % HexString<uint>(mode), &pm))
return pm; // horray
- if (QPixmapCache::find(key % HexString<uint>(QIcon::Normal), pm)) {
+ if (QPixmapCache::find(key % HexString<uint>(QIcon::Normal), &pm)) {
QPixmap active = pm;
if (QGuiApplication *guiApp = qobject_cast<QGuiApplication *>(qApp))
active = static_cast<QGuiApplicationPrivate*>(QObjectPrivate::get(guiApp))->applyQIconStyleHelper(QIcon::Active, pm);
@@ -324,7 +326,7 @@ QPixmap QPixmapIconEngine::pixmap(const QSize &size, QIcon::Mode mode, QIcon::St
}
}
- if (!QPixmapCache::find(key % HexString<uint>(mode), pm)) {
+ if (!QPixmapCache::find(key % HexString<uint>(mode), &pm)) {
if (pm.size() != actualSize)
pm = pm.scaled(actualSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
if (pe->mode != mode && mode != QIcon::Normal) {
@@ -661,7 +663,7 @@ QFactoryLoader *qt_iconEngineFactoryLoader()
/*!
Constructs a null icon.
*/
-QIcon::QIcon() Q_DECL_NOEXCEPT
+QIcon::QIcon() noexcept
: d(0)
{
}
@@ -1079,10 +1081,10 @@ void QIcon::addFile(const QString &fileName, const QSize &size, Mode mode, State
QFileInfo info(fileName);
QString suffix = info.suffix();
-#ifndef QT_NO_MIMETYPE
+#if QT_CONFIG(mimetype)
if (suffix.isEmpty())
suffix = QMimeDatabase().mimeTypeForFile(info).preferredSuffix(); // determination from contents
-#endif // !QT_NO_MIMETYPE
+#endif // mimetype
QIconEngine *engine = iconEngineFromSuffix(fileName, suffix);
d = new QIconPrivate(engine ? engine : new QPixmapIconEngine);
}
diff --git a/src/gui/image/qicon.h b/src/gui/image/qicon.h
index 6a4fc8927a..0f834fc2cb 100644
--- a/src/gui/image/qicon.h
+++ b/src/gui/image/qicon.h
@@ -50,6 +50,7 @@ QT_BEGIN_NAMESPACE
class QIconPrivate;
class QIconEngine;
+class QPainter;
class Q_GUI_EXPORT QIcon
{
@@ -57,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
@@ -70,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/qiconengine.h b/src/gui/image/qiconengine.h
index 0c67ef2686..0c5b51dc71 100644
--- a/src/gui/image/qiconengine.h
+++ b/src/gui/image/qiconengine.h
@@ -90,6 +90,7 @@ public:
QPixmap pixmap;
};
+ // ### Qt6: move content to proper virtual functions
virtual void virtual_hook(int id, void *data);
private:
diff --git a/src/gui/image/qiconloader.cpp b/src/gui/image/qiconloader.cpp
index 228de3adc3..1d0c93f26f 100644
--- a/src/gui/image/qiconloader.cpp
+++ b/src/gui/image/qiconloader.cpp
@@ -50,7 +50,9 @@
#include <QtCore/qmath.h>
#include <QtCore/QList>
#include <QtCore/QDir>
+#if QT_CONFIG(settings)
#include <QtCore/QSettings>
+#endif
#include <QtGui/QPainter>
#include <private/qhexstring_p.h>
@@ -348,7 +350,7 @@ QIconTheme::QIconTheme(const QString &themeName)
m_valid = true;
}
}
-#ifndef QT_NO_SETTINGS
+#if QT_CONFIG(settings)
if (themeIndex.exists()) {
const QSettings indexReader(themeIndex.fileName(), QSettings::IniFormat);
const QStringList keys = indexReader.allKeys();
@@ -407,7 +409,7 @@ QIconTheme::QIconTheme(const QString &themeName)
if (!m_parents.contains(QLatin1String("hicolor")))
m_parents.append(QLatin1String("hicolor"));
}
-#endif //QT_NO_SETTINGS
+#endif // settings
}
QThemeIconInfo QIconLoader::findIconHelper(const QString &themeName,
@@ -627,7 +629,10 @@ void QIconLoaderEngine::ensureLoaded()
void QIconLoaderEngine::paint(QPainter *painter, const QRect &rect,
QIcon::Mode mode, QIcon::State state)
{
- QSize pixmapSize = rect.size();
+ const qreal dpr = !qApp->testAttribute(Qt::AA_UseHighDpiPixmaps) ?
+ qreal(1.0) : painter->device()->devicePixelRatioF();
+
+ QSize pixmapSize = rect.size() * dpr;
painter->drawPixmap(rect, pixmap(pixmapSize, mode, state));
}
diff --git a/src/gui/image/qimage.cpp b/src/gui/image/qimage.cpp
index 636cacfb9c..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>
@@ -113,26 +116,19 @@ QImageData::QImageData()
\internal
Creates a new image data.
- Returns 0 if invalid parameters are give or anything else failed.
+ Returns \nullptr if invalid parameters are give or anything else failed.
*/
QImageData * QImageData::create(const QSize &size, QImage::Format format)
{
- if (!size.isValid() || format == QImage::Format_Invalid)
- return 0; // invalid parameter(s)
+ if (size.isEmpty() || format == QImage::Format_Invalid)
+ return nullptr; // invalid parameter(s)
- uint width = size.width();
- uint height = size.height();
- uint depth = qt_depthForFormat(format);
-
- const int bytes_per_line = ((width * depth + 31) >> 5) << 2; // bytes per scanline (must be multiple of 4)
-
- // sanity check for potential overflows
- if (std::numeric_limits<int>::max()/depth < width
- || bytes_per_line <= 0
- || height <= 0
- || std::numeric_limits<qsizetype>::max()/uint(bytes_per_line) < height
- || std::numeric_limits<int>::max()/sizeof(uchar *) < uint(height))
- return 0;
+ int width = size.width();
+ int height = size.height();
+ int depth = qt_depthForFormat(format);
+ auto params = calculateImageParameters(width, height, depth);
+ if (!params.isValid())
+ return nullptr;
QScopedPointer<QImageData> d(new QImageData);
@@ -154,18 +150,15 @@ QImageData * QImageData::create(const QSize &size, QImage::Format format)
d->has_alpha_clut = false;
d->is_cached = false;
- d->bytes_per_line = bytes_per_line;
-
- d->nbytes = d->bytes_per_line*height;
+ d->bytes_per_line = params.bytesPerLine;
+ d->nbytes = params.totalSize;
d->data = (uchar *)malloc(d->nbytes);
- if (!d->data) {
- return 0;
- }
+ if (!d->data)
+ return nullptr;
d->ref.ref();
return d.take();
-
}
QImageData::~QImageData()
@@ -298,6 +291,7 @@ bool QImageData::checkForAlphaPixels() const
case QImage::Format_BGR30:
case QImage::Format_RGB30:
case QImage::Format_Grayscale8:
+ case QImage::Format_Grayscale16:
case QImage::Format_RGBX64:
break;
case QImage::Format_Invalid:
@@ -720,6 +714,7 @@ bool QImageData::checkForAlphaPixels() const
\value Format_A2RGB30_Premultiplied The image is stored using a 32-bit premultiplied ARGB format (2-10-10-10). (added in Qt 5.4)
\value Format_Alpha8 The image is stored using an 8-bit alpha only format. (added in Qt 5.5)
\value Format_Grayscale8 The image is stored using an 8-bit grayscale format. (added in Qt 5.5)
+ \value Format_Grayscale16 The image is stored using an 16-bit grayscale format. (added in Qt 5.13)
\value Format_RGBX64 The image is stored using a 64-bit halfword-ordered RGB(x) format (16-16-16-16).
This is the same as the Format_RGBX64 except alpha must always be 65535. (added in Qt 5.12)
\value Format_RGBA64 The image is stored using a 64-bit halfword-ordered RGBA format (16-16-16-16). (added in Qt 5.12)
@@ -746,7 +741,7 @@ bool QImageData::checkForAlphaPixels() const
\sa isNull()
*/
-QImage::QImage() Q_DECL_NOEXCEPT
+QImage::QImage() noexcept
: QPaintDevice()
{
d = 0;
@@ -786,27 +781,27 @@ QImage::QImage(const QSize &size, Format format)
QImageData *QImageData::create(uchar *data, int width, int height, int bpl, QImage::Format format, bool readOnly, QImageCleanupFunction cleanupFunction, void *cleanupInfo)
{
- QImageData *d = 0;
-
- if (format == QImage::Format_Invalid)
- return d;
+ if (width <= 0 || height <= 0 || !data || format == QImage::Format_Invalid)
+ return nullptr;
const int depth = qt_depthForFormat(format);
- const int calc_bytes_per_line = ((width * depth + 31)/32) * 4;
- const int min_bytes_per_line = (width * depth + 7)/8;
-
- if (bpl <= 0)
- bpl = calc_bytes_per_line;
-
- if (width <= 0 || height <= 0 || !data
- || INT_MAX/sizeof(uchar *) < uint(height)
- || INT_MAX/uint(depth) < uint(width)
- || bpl <= 0
- || bpl < min_bytes_per_line
- || INT_MAX/uint(bpl) < uint(height))
- return d; // invalid parameter(s)
+ auto params = calculateImageParameters(width, height, depth);
+ if (!params.isValid())
+ return nullptr;
+
+ if (bpl > 0) {
+ // can't overflow, because has calculateImageParameters already done this multiplication
+ const int min_bytes_per_line = (width * depth + 7)/8;
+ if (bpl < min_bytes_per_line)
+ return nullptr;
+
+ // recalculate the total with this value
+ params.bytesPerLine = bpl;
+ if (mul_overflow<qsizetype>(bpl, height, &params.totalSize))
+ return nullptr;
+ }
- d = new QImageData;
+ QImageData *d = new QImageData;
d->ref.ref();
d->own_data = false;
@@ -817,8 +812,8 @@ QImageData *QImageData::create(uchar *data, int width, int height, int bpl, QIm
d->depth = depth;
d->format = format;
- d->bytes_per_line = bpl;
- d->nbytes = d->bytes_per_line * height;
+ d->bytes_per_line = params.bytesPerLine;
+ d->nbytes = params.totalSize;
d->cleanupFunction = cleanupFunction;
d->cleanupInfo = cleanupInfo;
@@ -1099,13 +1094,30 @@ void QImage::detach()
}
-static void copyMetadata(QImageData *dst, const QImageData *src)
+static void copyPhysicalMetadata(QImageData *dst, const QImageData *src)
{
- // Doesn't copy colortable and alpha_clut, or offset.
dst->dpmx = src->dpmx;
dst->dpmy = src->dpmy;
dst->devicePixelRatio = src->devicePixelRatio;
+}
+
+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)
+{
+ dst->setDotsPerMeterX(src.dotsPerMeterX());
+ dst->setDotsPerMeterY(src.dotsPerMeterY());
+ dst->setDevicePixelRatio(src.devicePixelRatio());
+ const auto textKeys = src.textKeys();
+ for (const auto &key: textKeys)
+ dst->setText(key, src.text(key));
+
}
/*!
@@ -1319,7 +1331,7 @@ QRect QImage::rect() const
The image depth is the number of bits used to store a single
pixel, also called bits per pixel (bpp).
- The supported depths are 1, 8, 16, 24 and 32.
+ The supported depths are 1, 8, 16, 24, 32 and 64.
\sa bitPlaneCount(), convertToFormat(), {QImage#Image Formats}{Image Formats},
{QImage#Image Information}{Image Information}
@@ -1384,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) {
@@ -1458,6 +1470,7 @@ void QImage::setDevicePixelRatio(qreal scaleFactor)
d->devicePixelRatio = scaleFactor;
}
+#if QT_DEPRECATED_SINCE(5, 10)
/*!
\since 4.6
\obsolete
@@ -1474,6 +1487,7 @@ int QImage::byteCount() const
Q_ASSERT(!d || d->nbytes < std::numeric_limits<int>::max());
return d ? int(d->nbytes) : 0;
}
+#endif
/*!
\since 5.10
@@ -1494,10 +1508,17 @@ qsizetype QImage::sizeInBytes() const
\sa scanLine()
*/
+#if QT_VERSION >= QT_VERSION_CHECK(6,0,0)
+qsizetype QImage::bytesPerLine() const
+{
+ return d ? d->bytes_per_line : 0;
+}
+#else
int QImage::bytesPerLine() const
{
return d ? d->bytes_per_line : 0;
}
+#endif
/*!
@@ -1553,7 +1574,9 @@ void QImage::setColor(int i, QRgb c)
Returns a pointer to the pixel data at the scanline with index \a
i. The first scanline is at index 0.
- The scanline data is aligned on a 32-bit boundary.
+ The scanline data is as minimum 32-bit aligned. For 64-bit formats
+ it follows the native alignment of 64-bit integers (64-bit for most
+ platforms, but notably 32-bit on i386).
\warning If you are accessing 32-bpp image data, cast the returned
pointer to \c{QRgb*} (QRgb has a 32-bit size) and use it to
@@ -2048,6 +2071,7 @@ static bool highColorPrecision(QImage::Format format)
case QImage::Format_RGBX64:
case QImage::Format_RGBA64:
case QImage::Format_RGBA64_Premultiplied:
+ case QImage::Format_Grayscale16:
return true;
default:
break;
@@ -2069,13 +2093,7 @@ QImage QImage::convertToFormat_helper(Format format, Qt::ImageConversionFlags fl
Image_Converter converter = qimage_converter_map[d->format][format];
if (!converter && format > QImage::Format_Indexed8 && d->format > QImage::Format_Indexed8) {
if (highColorPrecision(format) && highColorPrecision(d->format)) {
- // Convert over RGBA64_Premultiplied
- if (format == QImage::Format_RGBA64_Premultiplied)
- converter = convert_generic_to_rgb64;
- else {
- Q_ASSERT(d->format != QImage::Format_RGBA64_Premultiplied);
- return convertToFormat(Format_RGBA64_Premultiplied, flags).convertToFormat(format, flags);
- }
+ converter = convert_generic_to_rgb64;
} else
converter = convert_generic;
}
@@ -2256,6 +2274,29 @@ bool QImage::reinterpretAsFormat(Format format)
}
/*!
+ \since 5.13
+
+ Detach and convert the image to the given \a format in place.
+
+ The specified image conversion \a flags control how the image data
+ is handled during the conversion process.
+
+ \sa convertToFormat()
+*/
+
+void QImage::convertTo(Format format, Qt::ImageConversionFlags flags)
+{
+ if (!d || format == QImage::Format_Invalid)
+ return;
+
+ detach();
+ if (convertToFormat_inplace(format, flags))
+ return;
+
+ *this = convertToFormat_helper(format, flags);
+}
+
+/*!
\fn bool QImage::valid(const QPoint &pos) const
Returns \c true if \a pos is a valid coordinate pair within the
@@ -2541,6 +2582,10 @@ QColor QImage::pixelColor(int x, int y) const
case Format_RGBA64_Premultiplied:
c = reinterpret_cast<const QRgba64 *>(s)[x];
break;
+ case Format_Grayscale16: {
+ quint16 v = reinterpret_cast<const quint16 *>(s)[x];
+ return QColor(qRgba64(v, v, v, 0xffff));
+ }
default:
c = QRgba64::fromArgb32(pixel(x, y));
break;
@@ -2651,6 +2696,7 @@ bool QImage::allGray() const
case Format_Alpha8:
return false;
case Format_Grayscale8:
+ case Format_Grayscale16:
return true;
case Format_RGB32:
case Format_ARGB32:
@@ -2717,7 +2763,7 @@ bool QImage::isGrayscale() const
if (d->format == QImage::Format_Alpha8)
return false;
- if (d->format == QImage::Format_Grayscale8)
+ if (d->format == QImage::Format_Grayscale8 || d->format == QImage::Format_Grayscale16)
return true;
switch (depth()) {
@@ -2927,8 +2973,10 @@ QImage QImage::createAlphaMask(Qt::ImageConversionFlags flags) const
}
QImage mask(d->width, d->height, Format_MonoLSB);
- if (!mask.isNull())
+ if (!mask.isNull()) {
dither_to_Mono(mask.d, d, flags, true);
+ copyPhysicalMetadata(mask.d, d);
+ }
return mask;
}
@@ -3046,6 +3094,7 @@ QImage QImage::createHeuristicMask(bool clipTight) const
#undef PIX
+ copyPhysicalMetadata(m.d, d);
return m;
}
#endif //QT_NO_IMAGE_HEURISTIC_MASK
@@ -3089,6 +3138,8 @@ QImage QImage::createMaskFromColor(QRgb color, Qt::MaskMode mode) const
}
if (mode == Qt::MaskOutColor)
maskImage.invertPixels();
+
+ copyPhysicalMetadata(maskImage.d, d);
return maskImage;
}
@@ -3351,6 +3402,7 @@ QImage QImage::rgbSwapped_helper() const
break;
case Format_Alpha8:
case Format_Grayscale8:
+ case Format_Grayscale16:
return *this;
case Format_Mono:
case Format_MonoLSB:
@@ -3462,6 +3514,7 @@ void QImage::rgbSwapped_inplace()
break;
case Format_Alpha8:
case Format_Grayscale8:
+ case Format_Grayscale16:
return;
case Format_Mono:
case Format_MonoLSB:
@@ -3553,7 +3606,7 @@ void QImage::rgbSwapped_inplace()
The loader attempts to read the image using the specified \a format, e.g.,
PNG or JPG. If \a format is not specified (which is the default), it is
auto-detected based on the file's suffix and header. For details, see
- {QImageReader::setAutoDetectImageFormat()}{QImageReader}.
+ QImageReader::setAutoDetectImageFormat().
The file name can either refer to an actual file on disk or to one
of the application's embedded resources. See the
@@ -3750,7 +3803,9 @@ QDataStream &operator>>(QDataStream &s, QImage &image)
return s;
}
}
- image = QImageReader(s.device(), 0).read();
+ image = QImageReader(s.device(), s.version() == 1 ? "bmp" : "png").read();
+ if (image.isNull() && s.version() >= 5)
+ s.setStatus(QDataStream::ReadPastEnd);
return s;
}
#endif // QT_NO_DATASTREAM
@@ -4635,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);
@@ -4656,8 +4713,7 @@ QImage QImage::smoothScaled(int w, int h) const {
static QImage rotated90(const QImage &image)
{
QImage out(image.height(), image.width(), image.format());
- out.setDotsPerMeterX(image.dotsPerMeterY());
- out.setDotsPerMeterY(image.dotsPerMeterX());
+ copyMetadata(&out, image);
if (image.colorCount() > 0)
out.setColorTable(image.colorTable());
int w = image.width();
@@ -4685,8 +4741,7 @@ static QImage rotated180(const QImage &image)
return image.mirrored(true, true);
QImage out(image.width(), image.height(), image.format());
- out.setDotsPerMeterX(image.dotsPerMeterY());
- out.setDotsPerMeterY(image.dotsPerMeterX());
+ copyMetadata(&out, image);
if (image.colorCount() > 0)
out.setColorTable(image.colorTable());
int w = image.width();
@@ -4698,8 +4753,7 @@ static QImage rotated180(const QImage &image)
static QImage rotated270(const QImage &image)
{
QImage out(image.height(), image.width(), image.format());
- out.setDotsPerMeterX(image.dotsPerMeterY());
- out.setDotsPerMeterY(image.dotsPerMeterX());
+ copyMetadata(&out, image);
if (image.colorCount() > 0)
out.setColorTable(image.colorTable());
int w = image.width();
@@ -4901,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)
@@ -5357,13 +5537,26 @@ static Q_CONSTEXPR QPixelFormat pixelformats[] = {
/*PREMULTIPLIED*/ QPixelFormat::Premultiplied,
/*INTERPRETATION*/ QPixelFormat::UnsignedShort,
/*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
+ //QImage::Format_Grayscale16:
+ QPixelFormat(QPixelFormat::Grayscale,
+ /*GRAY*/ 16,
+ /*SECOND*/ 0,
+ /*THIRD*/ 0,
+ /*FOURTH*/ 0,
+ /*FIFTH*/ 0,
+ /*ALPHA*/ 0,
+ /*ALPHA USAGE*/ QPixelFormat::IgnoresAlpha,
+ /*ALPHA POSITION*/ QPixelFormat::AtBeginning,
+ /*PREMULTIPLIED*/ QPixelFormat::NotPremultiplied,
+ /*INTERPRETATION*/ QPixelFormat::UnsignedShort,
+ /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
};
Q_STATIC_ASSERT(sizeof(pixelformats) / sizeof(*pixelformats) == QImage::NImageFormats);
/*!
Returns the QImage::Format as a QPixelFormat
*/
-QPixelFormat QImage::pixelFormat() const Q_DECL_NOTHROW
+QPixelFormat QImage::pixelFormat() const noexcept
{
return toPixelFormat(format());
}
@@ -5371,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];
@@ -5380,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])
@@ -5396,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 4b7a3b1ead..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;
@@ -128,17 +130,14 @@ public:
Format_RGBX64,
Format_RGBA64,
Format_RGBA64_Premultiplied,
-#if 0
- // reserved for future use
Format_Grayscale16,
-#endif
#ifndef Q_QDOC
NImageFormats
#endif
};
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);
@@ -153,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
@@ -161,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;
@@ -199,6 +198,8 @@ public:
Q_REQUIRED_RESULT QImage convertToFormat(Format f, const QVector<QRgb> &colorTable, Qt::ImageConversionFlags flags = Qt::AutoColor) const;
bool reinterpretAsFormat(Format f);
+ void convertTo(Format f, Qt::ImageConversionFlags flags = Qt::AutoColor);
+
int width() const;
int height() const;
QSize size() const;
@@ -227,7 +228,11 @@ public:
uchar *scanLine(int);
const uchar *scanLine(int) const;
const uchar *constScanLine(int) const;
+#if QT_VERSION >= QT_VERSION_CHECK(6,0,0)
+ qsizetype bytesPerLine() const;
+#else
int bytesPerLine() const;
+#endif
bool valid(int x, int y) const;
bool valid(const QPoint &pt) const;
@@ -286,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);
@@ -330,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 964dc0d5c6..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...
@@ -223,18 +223,29 @@ void convert_generic(QImageData *dest, const QImageData *src, Qt::ImageConversio
void convert_generic_to_rgb64(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags)
{
- Q_ASSERT(dest->format == QImage::Format_RGBA64_Premultiplied);
+ Q_ASSERT(dest->format > QImage::Format_Indexed8);
Q_ASSERT(src->format > QImage::Format_Indexed8);
+ QRgba64 buf[BufferSize];
+ QRgba64 *buffer = buf;
const QPixelLayout *srcLayout = &qPixelLayouts[src->format];
+ const QPixelLayout *destLayout = &qPixelLayouts[dest->format];
const uchar *srcData = src->data;
uchar *destData = dest->data;
const FetchAndConvertPixelsFunc64 fetch = srcLayout->fetchToRGBA64PM;
+ const ConvertAndStorePixelsFunc64 store = qStoreFromRGBA64PM[dest->format];
for (int y = 0; y < src->height; ++y) {
- const QRgba64 *ptr = fetch((QRgba64*)destData, srcData, 0, src->width, nullptr, nullptr);
- if (ptr != (const QRgba64*)destData) {
- memcpy(destData, ptr, dest->bytes_per_line);
+ int x = 0;
+ while (x < src->width) {
+ int l = src->width - x;
+ if (destLayout->bpp == QPixelLayout::BPP64)
+ buffer = reinterpret_cast<QRgba64 *>(destData) + x;
+ else
+ l = qMin(l, BufferSize);
+ const QRgba64 *ptr = fetch(buffer, srcData, x, l, nullptr, nullptr);
+ store(destData, ptr, x, l, nullptr, nullptr);
+ x += l;
}
srcData += src->bytes_per_line;
destData += dest->bytes_per_line;
@@ -817,10 +828,10 @@ static bool convert_indexed8_to_ARGB_PM_inplace(QImageData *data, Qt::ImageConve
Q_ASSERT(data->own_data);
const int depth = 32;
-
- const qsizetype dst_bytes_per_line = ((data->width * depth + 31) >> 5) << 2;
- const qsizetype nbytes = dst_bytes_per_line * data->height;
- uchar *const newData = (uchar *)realloc(data->data, nbytes);
+ auto params = QImageData::calculateImageParameters(data->width, data->height, depth);
+ if (params.bytesPerLine < 0)
+ return false;
+ uchar *const newData = (uchar *)realloc(data->data, params.totalSize);
if (!newData)
return false;
@@ -828,10 +839,10 @@ static bool convert_indexed8_to_ARGB_PM_inplace(QImageData *data, Qt::ImageConve
// start converting from the end because the end image is bigger than the source
uchar *src_data = newData + data->nbytes; // end of src
- quint32 *dest_data = (quint32 *) (newData + nbytes); // end of dest > end of src
+ quint32 *dest_data = (quint32 *) (newData + params.totalSize); // end of dest > end of src
const int width = data->width;
const int src_pad = data->bytes_per_line - width;
- const int dest_pad = (dst_bytes_per_line >> 2) - width;
+ const int dest_pad = (params.bytesPerLine >> 2) - width;
if (data->colortable.size() == 0) {
data->colortable.resize(256);
for (int i = 0; i < 256; ++i)
@@ -858,9 +869,9 @@ static bool convert_indexed8_to_ARGB_PM_inplace(QImageData *data, Qt::ImageConve
data->colortable = QVector<QRgb>();
data->format = QImage::Format_ARGB32_Premultiplied;
- data->bytes_per_line = dst_bytes_per_line;
+ data->bytes_per_line = params.bytesPerLine;
data->depth = depth;
- data->nbytes = nbytes;
+ data->nbytes = params.totalSize;
return true;
}
@@ -871,10 +882,10 @@ static bool convert_indexed8_to_ARGB_inplace(QImageData *data, Qt::ImageConversi
Q_ASSERT(data->own_data);
const int depth = 32;
-
- const qsizetype dst_bytes_per_line = ((data->width * depth + 31) >> 5) << 2;
- const qsizetype nbytes = dst_bytes_per_line * data->height;
- uchar *const newData = (uchar *)realloc(data->data, nbytes);
+ auto params = QImageData::calculateImageParameters(data->width, data->height, depth);
+ if (params.bytesPerLine < 0)
+ return false;
+ uchar *const newData = (uchar *)realloc(data->data, params.totalSize);
if (!newData)
return false;
@@ -882,10 +893,10 @@ static bool convert_indexed8_to_ARGB_inplace(QImageData *data, Qt::ImageConversi
// start converting from the end because the end image is bigger than the source
uchar *src_data = newData + data->nbytes;
- quint32 *dest_data = (quint32 *) (newData + nbytes);
+ quint32 *dest_data = (quint32 *) (newData + params.totalSize);
const int width = data->width;
const int src_pad = data->bytes_per_line - width;
- const int dest_pad = (dst_bytes_per_line >> 2) - width;
+ const int dest_pad = (params.bytesPerLine >> 2) - width;
if (data->colortable.size() == 0) {
data->colortable.resize(256);
for (int i = 0; i < 256; ++i)
@@ -909,9 +920,9 @@ static bool convert_indexed8_to_ARGB_inplace(QImageData *data, Qt::ImageConversi
data->colortable = QVector<QRgb>();
data->format = QImage::Format_ARGB32;
- data->bytes_per_line = dst_bytes_per_line;
+ data->bytes_per_line = params.bytesPerLine;
data->depth = depth;
- data->nbytes = nbytes;
+ data->nbytes = params.totalSize;
return true;
}
@@ -939,10 +950,10 @@ static bool convert_indexed8_to_RGB16_inplace(QImageData *data, Qt::ImageConvers
Q_ASSERT(data->own_data);
const int depth = 16;
-
- const qsizetype dst_bytes_per_line = ((data->width * depth + 31) >> 5) << 2;
- const qsizetype nbytes = dst_bytes_per_line * data->height;
- uchar *const newData = (uchar *)realloc(data->data, nbytes);
+ auto params = QImageData::calculateImageParameters(data->width, data->height, depth);
+ if (params.bytesPerLine < 0)
+ return false;
+ uchar *const newData = (uchar *)realloc(data->data, params.totalSize);
if (!newData)
return false;
@@ -950,10 +961,10 @@ static bool convert_indexed8_to_RGB16_inplace(QImageData *data, Qt::ImageConvers
// start converting from the end because the end image is bigger than the source
uchar *src_data = newData + data->nbytes;
- quint16 *dest_data = (quint16 *) (newData + nbytes);
+ quint16 *dest_data = (quint16 *) (newData + params.totalSize);
const int width = data->width;
const int src_pad = data->bytes_per_line - width;
- const int dest_pad = (dst_bytes_per_line >> 1) - width;
+ const int dest_pad = (params.bytesPerLine >> 1) - width;
quint16 colorTableRGB16[256];
const int tableSize = data->colortable.size();
@@ -983,9 +994,9 @@ static bool convert_indexed8_to_RGB16_inplace(QImageData *data, Qt::ImageConvers
}
data->format = QImage::Format_RGB16;
- data->bytes_per_line = dst_bytes_per_line;
+ data->bytes_per_line = params.bytesPerLine;
data->depth = depth;
- data->nbytes = nbytes;
+ data->nbytes = params.totalSize;
return true;
}
@@ -997,6 +1008,7 @@ static bool convert_RGB_to_RGB16_inplace(QImageData *data, Qt::ImageConversionFl
const int depth = 16;
+ // cannot overflow, since we're shrinking the buffer
const qsizetype dst_bytes_per_line = ((data->width * depth + 31) >> 5) << 2;
const qsizetype src_bytes_per_line = data->bytes_per_line;
quint32 *src_data = (quint32 *) data->data;
@@ -1013,12 +1025,11 @@ static bool convert_RGB_to_RGB16_inplace(QImageData *data, Qt::ImageConversionFl
data->depth = depth;
data->nbytes = dst_bytes_per_line * data->height;
uchar *const newData = (uchar *)realloc(data->data, data->nbytes);
- if (newData) {
+ if (newData)
data->data = newData;
- return true;
- } else {
- return false;
- }
+
+ // can't fail, since we're shrinking
+ return true;
}
static void convert_ARGB_PM_to_ARGB(QImageData *dest, const QImageData *src)
@@ -1205,33 +1216,6 @@ static void convert_RGBA64_to_ARGB32(QImageData *dest, const QImageData *src, Qt
}
template<bool RGBA>
-static void convert_RGBA64PM_to_ARGB32(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags)
-{
- Q_ASSERT(src->format == QImage::Format_RGBA64_Premultiplied);
- Q_ASSERT(RGBA || dest->format == QImage::Format_ARGB32);
- Q_ASSERT(!RGBA || dest->format == QImage::Format_RGBA8888);
- Q_ASSERT(src->width == dest->width);
- Q_ASSERT(src->height == dest->height);
-
- const int src_pad = (src->bytes_per_line >> 3) - src->width;
- const int dest_pad = (dest->bytes_per_line >> 2) - dest->width;
- const QRgba64 *src_data = reinterpret_cast<const QRgba64 *>(src->data);
- uint *dest_data = reinterpret_cast<uint *>(dest->data);
-
- for (int i = 0; i < src->height; ++i) {
- const QRgba64 *end = src_data + src->width;
- while (src_data < end) {
- QRgba64 s = src_data->unpremultiplied();
- *dest_data = RGBA ? ARGB2RGBA(s.toArgb32()) : s.toArgb32();
- ++src_data;
- ++dest_data;
- }
- src_data += src_pad;
- dest_data += dest_pad;
- }
-}
-
-template<bool RGBA>
static void convert_ARGB32_to_RGBA64(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags)
{
Q_ASSERT(RGBA || src->format == QImage::Format_ARGB32);
@@ -1240,74 +1224,14 @@ static void convert_ARGB32_to_RGBA64(QImageData *dest, const QImageData *src, Qt
Q_ASSERT(src->width == dest->width);
Q_ASSERT(src->height == dest->height);
- const int src_pad = (src->bytes_per_line >> 2) - src->width;
- const int dest_pad = (dest->bytes_per_line >> 3) - dest->width;
- const uint *src_data = reinterpret_cast<const uint *>(src->data);
- QRgba64 *dest_data = reinterpret_cast<QRgba64 *>(dest->data);
-
- for (int i = 0; i < src->height; ++i) {
- const uint *end = src_data + src->width;
- while (src_data < end) {
- if (RGBA)
- *dest_data = QRgba64::fromArgb32(RGBA2ARGB(*src_data));
- else
- *dest_data = QRgba64::fromArgb32(*src_data);
- ++src_data;
- ++dest_data;
- }
- src_data += src_pad;
- dest_data += dest_pad;
- }
-}
-
-template<QtPixelOrder PixelOrder>
-static void convert_RGBA64PM_to_RGB30(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags)
-{
- Q_ASSERT(src->format == QImage::Format_RGBA64_Premultiplied);
- Q_ASSERT(dest->format == QImage::Format_RGB30 || dest->format == QImage::Format_BGR30);
- Q_ASSERT(src->width == dest->width);
- Q_ASSERT(src->height == dest->height);
-
- const int src_pad = (src->bytes_per_line >> 3) - src->width;
- const int dest_pad = (dest->bytes_per_line >> 2) - dest->width;
- const QRgba64 *src_data = reinterpret_cast<const QRgba64 *>(src->data);
- uint *dest_data = reinterpret_cast<uint *>(dest->data);
-
- for (int i = 0; i < src->height; ++i) {
- const QRgba64 *end = src_data + src->width;
- while (src_data < end) {
- *dest_data = 0xc0000000 | qConvertRgb64ToRgb30<PixelOrder>(src_data->unpremultiplied());
- ++src_data;
- ++dest_data;
- }
- src_data += src_pad;
- dest_data += dest_pad;
- }
-}
-
-template<QtPixelOrder PixelOrder>
-static void convert_RGBA64PM_to_A2RGB30(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags)
-{
- Q_ASSERT(src->format == QImage::Format_RGBA64_Premultiplied);
- Q_ASSERT(dest->format == QImage::Format_A2RGB30_Premultiplied
- || dest->format == QImage::Format_A2BGR30_Premultiplied);
- Q_ASSERT(src->width == dest->width);
- Q_ASSERT(src->height == dest->height);
-
- const int src_pad = (src->bytes_per_line >> 3) - src->width;
- const int dest_pad = (dest->bytes_per_line >> 2) - dest->width;
- const QRgba64 *src_data = reinterpret_cast<const QRgba64 *>(src->data);
- uint *dest_data = reinterpret_cast<uint *>(dest->data);
+ const uchar *src_data = src->data;
+ uchar *dest_data = dest->data;
+ const FetchAndConvertPixelsFunc64 fetch = qPixelLayouts[src->format + 1].fetchToRGBA64PM;
for (int i = 0; i < src->height; ++i) {
- const QRgba64 *end = src_data + src->width;
- while (src_data < end) {
- *dest_data = qConvertRgb64ToRgb30<PixelOrder>(*src_data);
- ++src_data;
- ++dest_data;
- }
- src_data += src_pad;
- dest_data += dest_pad;
+ fetch(reinterpret_cast<QRgba64 *>(dest_data), src_data, 0, src->width, nullptr, nullptr);
+ src_data += src->bytes_per_line;;
+ dest_data += dest->bytes_per_line;
}
}
@@ -1447,6 +1371,56 @@ static bool convert_RGBA64PM_to_RGBA64_inplace(QImageData *data, Qt::ImageConver
return true;
}
+static void convert_gray16_to_RGBA64(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags)
+{
+ Q_ASSERT(src->format == QImage::Format_Grayscale16);
+ Q_ASSERT(dest->format == QImage::Format_RGBA64 || dest->format == QImage::Format_RGBX64 ||
+ dest->format == QImage::Format_RGBA64_Premultiplied);
+ Q_ASSERT(src->width == dest->width);
+ Q_ASSERT(src->height == dest->height);
+
+ const qsizetype sbpl = src->bytes_per_line;
+ const qsizetype dbpl = dest->bytes_per_line;
+ const uchar *src_data = src->data;
+ uchar *dest_data = dest->data;
+
+ for (int i = 0; i < src->height; ++i) {
+ const quint16 *src_line = reinterpret_cast<const quint16 *>(src_data);
+ QRgba64 *dest_line = reinterpret_cast<QRgba64 *>(dest_data);
+ for (int j = 0; j < src->width; ++j) {
+ quint16 s = src_line[j];
+ dest_line[j] = qRgba64(s, s, s, 0xFFFF);
+ }
+ src_data += sbpl;
+ dest_data += dbpl;
+ }
+}
+
+static void convert_RGBA64_to_gray16(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags)
+{
+ Q_ASSERT(dest->format == QImage::Format_Grayscale16);
+ Q_ASSERT(src->format == QImage::Format_RGBX64 ||
+ src->format == QImage::Format_RGBA64_Premultiplied);
+ Q_ASSERT(src->width == dest->width);
+ Q_ASSERT(src->height == dest->height);
+
+ const qsizetype sbpl = src->bytes_per_line;
+ const qsizetype dbpl = dest->bytes_per_line;
+ const uchar *src_data = src->data;
+ uchar *dest_data = dest->data;
+
+ for (int i = 0; i < src->height; ++i) {
+ const QRgba64 *src_line = reinterpret_cast<const QRgba64 *>(src_data);
+ quint16 *dest_line = reinterpret_cast<quint16 *>(dest_data);
+ for (int j = 0; j < src->width; ++j) {
+ QRgba64 s = src_line[j].unpremultiplied();
+ dest_line[j] = qGray(s.red(), s.green(), s.blue());
+ }
+ src_data += sbpl;
+ dest_data += dbpl;
+ }
+}
+
static QVector<QRgb> fix_color_table(const QVector<QRgb> &ctbl, QImage::Format format)
{
QVector<QRgb> colorTable = ctbl;
@@ -2291,7 +2265,7 @@ static bool convert_Grayscale8_to_Indexed8_inplace(QImageData *data, Qt::ImageCo
Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormats] =
{
{
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
},
{
0,
@@ -2312,7 +2286,7 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat
0,
0,
0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
}, // Format_Mono
{
@@ -2334,7 +2308,7 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat
0,
0,
0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
}, // Format_MonoLSB
{
@@ -2359,7 +2333,7 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat
0, 0, 0, 0, 0,
convert_Indexed8_to_Alpha8,
convert_Indexed8_to_Grayscale8,
- 0, 0, 0
+ 0, 0, 0, 0
}, // Format_Indexed8
{
@@ -2387,7 +2361,7 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat
convert_RGB_to_RGB30<PixelOrderRGB, false>,
0,
0, 0,
- 0, 0, 0
+ 0, 0, 0, 0
}, // Format_RGB32
{
@@ -2417,7 +2391,7 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat
0, 0,
0,
convert_ARGB32_to_RGBA64<false>,
- 0
+ 0, 0
}, // Format_ARGB32
{
@@ -2442,7 +2416,7 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat
convert_ARGB_to_RGBA,
0, 0, 0, 0,
0, 0,
- 0, 0, 0
+ 0, 0, 0, 0
}, // Format_ARGB32_Premultiplied
{
@@ -2464,7 +2438,7 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat
0,
0,
0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
}, // Format_RGB16
{
@@ -2486,7 +2460,7 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat
0,
0,
0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
}, // Format_ARGB8565_Premultiplied
{
@@ -2508,7 +2482,7 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat
0,
0,
0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
}, // Format_RGB666
{
@@ -2530,7 +2504,7 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat
0,
0,
0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
}, // Format_ARGB6666_Premultiplied
{
@@ -2552,7 +2526,7 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat
0,
0,
0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
}, // Format_RGB555
{
@@ -2574,7 +2548,7 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat
0,
0,
0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
}, // Format_ARGB8555_Premultiplied
{
@@ -2597,7 +2571,7 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat
convert_RGB888_to_RGB<true>,
convert_RGB888_to_RGB<true>,
convert_RGB888_to_RGB<true>,
- 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
}, // Format_RGB888
{
@@ -2619,7 +2593,7 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat
0,
0,
0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
}, // Format_RGB444
{
@@ -2640,7 +2614,7 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat
0,
0,
0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
}, // Format_ARGB4444_Premultiplied
{
0,
@@ -2667,7 +2641,7 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat
convert_RGB_to_RGB30<PixelOrderRGB, true>,
0,
0, 0,
- 0, 0, 0
+ 0, 0, 0, 0
}, // Format_RGBX8888
{
0,
@@ -2696,7 +2670,7 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat
0, 0,
0,
convert_ARGB32_to_RGBA64<true>,
- 0
+ 0, 0
}, // Format_RGBA8888
{
@@ -2718,7 +2692,7 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat
0,
0,
0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
}, // Format_RGBA8888_Premultiplied
{
@@ -2746,7 +2720,7 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat
convert_BGR30_to_RGB30,
convert_BGR30_to_RGB30,
0, 0,
- 0, 0, 0
+ 0, 0, 0, 0
}, // Format_BGR30
{
0,
@@ -2773,8 +2747,8 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat
convert_A2RGB30_PM_to_RGB30<true>,
convert_BGR30_to_RGB30,
0, 0,
- 0, 0, 0
- }, // Format_BGR30A2_Premultiplied
+ 0, 0, 0, 0
+ }, // Format_A2BGR30_Premultiplied
{
0,
0,
@@ -2799,7 +2773,7 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat
convert_BGR30_to_RGB30,
0,
convert_passthrough,
- 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0
}, // Format_RGB30
{
0,
@@ -2826,8 +2800,8 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat
convert_A2RGB30_PM_to_RGB30<false>,
0,
0, 0,
- 0, 0, 0
- }, // Format_RGB30A2_Premultiplied
+ 0, 0, 0, 0
+ }, // Format_A2RGB30_Premultiplied
{
0,
0,
@@ -2846,7 +2820,7 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat
0,
0,
0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
}, // Format_Alpha8
{
0,
@@ -2872,7 +2846,8 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, // self
convert_passthrough,
- convert_passthrough
+ convert_passthrough,
+ convert_RGBA64_to_gray16
}, // Format_RGBX64
{
0,
@@ -2898,7 +2873,8 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat
0, 0,
convert_RGBA64_to_RGBx64,
0, // self
- convert_RGBA64_to_RGBA64PM
+ convert_RGBA64_to_RGBA64PM,
+ 0
}, // Format_RGBA64
{
0,
@@ -2906,7 +2882,6 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat
0,
0,
0,
- convert_RGBA64PM_to_ARGB32<false>,
0,
0,
0,
@@ -2918,29 +2893,58 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat
0,
0,
0,
- convert_RGBA64PM_to_ARGB32<true>,
0,
- convert_RGBA64PM_to_RGB30<PixelOrderBGR>,
- convert_RGBA64PM_to_A2RGB30<PixelOrderBGR>,
- convert_RGBA64PM_to_RGB30<PixelOrderRGB>,
- convert_RGBA64PM_to_A2RGB30<PixelOrderRGB>,
+ 0,
+ 0,
+ 0, 0, 0, 0,
0, 0,
convert_RGBA64PM_to_RGBA64<true>,
convert_RGBA64PM_to_RGBA64<false>,
- 0 // self
- } // Format_RGBA64_Premultiplied
+ 0, // self
+ convert_RGBA64_to_gray16
+ }, // Format_RGBA64_Premultiplied
+ {
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0, 0,
+ convert_gray16_to_RGBA64,
+ convert_gray16_to_RGBA64,
+ convert_gray16_to_RGBA64,
+ 0 // self
+ }, // Format_Grayscale16
};
InPlace_Image_Converter qimage_inplace_converter_map[QImage::NImageFormats][QImage::NImageFormats] =
{
{
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
},
{
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
}, // Format_Mono
{
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
}, // Format_MonoLSB
{
0,
@@ -2964,7 +2968,7 @@ InPlace_Image_Converter qimage_inplace_converter_map[QImage::NImageFormats][QIma
0, 0, 0, 0, 0,
convert_Indexed8_to_Alpha8_inplace,
convert_Indexed8_to_Grayscale8_inplace,
- 0, 0, 0
+ 0, 0, 0, 0
}, // Format_Indexed8
{
0,
@@ -2991,7 +2995,7 @@ InPlace_Image_Converter qimage_inplace_converter_map[QImage::NImageFormats][QIma
convert_RGB_to_RGB30_inplace<PixelOrderRGB, false>,
0,
0, 0,
- 0, 0, 0
+ 0, 0, 0, 0
}, // Format_RGB32
{
0,
@@ -3018,7 +3022,7 @@ InPlace_Image_Converter qimage_inplace_converter_map[QImage::NImageFormats][QIma
convert_RGB_to_RGB30_inplace<PixelOrderRGB, false>,
0,
0, 0,
- 0, 0, 0
+ 0, 0, 0, 0
}, // Format_ARGB32
{
0,
@@ -3042,34 +3046,34 @@ InPlace_Image_Converter qimage_inplace_converter_map[QImage::NImageFormats][QIma
convert_ARGB_to_RGBA_inplace<QImage::Format_RGBA8888_Premultiplied>,
0, 0, 0, 0,
0, 0,
- 0, 0, 0
+ 0, 0, 0, 0
}, // Format_ARGB32_Premultiplied
{
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
}, // Format_RGB16
{
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
}, // Format_ARGB8565_Premultiplied
{
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
}, // Format_RGB666
{
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
}, // Format_ARGB6666_Premultiplied
{
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
}, // Format_RGB555
{
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
}, // Format_ARGB8555_Premultiplied
{
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
}, // Format_RGB888
{
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
}, // Format_RGB444
{
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
}, // Format_ARGB4444_Premultiplied
{
0,
@@ -3096,7 +3100,7 @@ InPlace_Image_Converter qimage_inplace_converter_map[QImage::NImageFormats][QIma
convert_RGB_to_RGB30_inplace<PixelOrderRGB, true>,
0,
0, 0,
- 0, 0, 0
+ 0, 0, 0, 0
}, // Format_RGBX8888
{
0,
@@ -3123,7 +3127,7 @@ InPlace_Image_Converter qimage_inplace_converter_map[QImage::NImageFormats][QIma
convert_RGB_to_RGB30_inplace<PixelOrderRGB, true>,
0,
0, 0,
- 0, 0, 0
+ 0, 0, 0, 0
}, // Format_RGBA8888
{
0,
@@ -3145,7 +3149,7 @@ InPlace_Image_Converter qimage_inplace_converter_map[QImage::NImageFormats][QIma
0,
0,
0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
}, // Format_RGBA8888_Premultiplied
{
0,
@@ -3172,7 +3176,7 @@ InPlace_Image_Converter qimage_inplace_converter_map[QImage::NImageFormats][QIma
convert_BGR30_to_RGB30_inplace,
convert_BGR30_to_A2RGB30_inplace,
0, 0,
- 0, 0, 0
+ 0, 0, 0, 0
}, // Format_BGR30
{
0,
@@ -3198,8 +3202,8 @@ InPlace_Image_Converter qimage_inplace_converter_map[QImage::NImageFormats][QIma
0, // self
convert_A2RGB30_PM_to_RGB30_inplace<true>,
convert_BGR30_to_RGB30_inplace,
- 0, 0, 0, 0, 0
- }, // Format_BGR30A2_Premultiplied
+ 0, 0, 0, 0, 0, 0
+ }, // Format_A2BGR30_Premultiplied
{
0,
0,
@@ -3224,7 +3228,7 @@ InPlace_Image_Converter qimage_inplace_converter_map[QImage::NImageFormats][QIma
convert_BGR30_to_A2RGB30_inplace,
0, // self
convert_passthrough_inplace<QImage::Format_A2RGB30_Premultiplied>,
- 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0
}, // Format_RGB30
{
0,
@@ -3251,8 +3255,8 @@ InPlace_Image_Converter qimage_inplace_converter_map[QImage::NImageFormats][QIma
convert_A2RGB30_PM_to_RGB30_inplace<false>,
0, // self
0, 0,
- 0, 0, 0
- }, // Format_RGB30A2_Premultiplied
+ 0, 0, 0, 0
+ }, // Format_A2RGB30_Premultiplied
{
0,
0,
@@ -3276,7 +3280,7 @@ InPlace_Image_Converter qimage_inplace_converter_map[QImage::NImageFormats][QIma
0, 0, 0, 0,
0, // self
0,
- 0, 0, 0
+ 0, 0, 0, 0
}, // Format_Alpha8
{
0,
@@ -3301,26 +3305,32 @@ InPlace_Image_Converter qimage_inplace_converter_map[QImage::NImageFormats][QIma
0, 0, 0, 0,
0,
0, // self
- 0, 0, 0
+ 0, 0, 0, 0
}, // Format_Grayscale8
{
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, // self
convert_passthrough_inplace<QImage::Format_RGBA64>,
convert_passthrough_inplace<QImage::Format_RGBA64_Premultiplied>,
+ 0
}, // Format_RGBX64
{
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
convert_RGBA64_to_RGBx64_inplace,
0, // self
- convert_RGBA64_to_RGBA64PM_inplace
+ convert_RGBA64_to_RGBA64PM_inplace,
+ 0
}, // Format_RGBA64
{
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
convert_RGBA64PM_to_RGBA64_inplace<true>,
convert_RGBA64PM_to_RGBA64_inplace<false>,
- 0 // self
- } // Format_RGBA64_Premultiplied
+ 0, // self
+ 0
+ }, // Format_RGBA64_Premultiplied
+ {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ }, // Format_Grayscale16
};
static void qInitImageConversions()
diff --git a/src/gui/image/qimage_darwin.mm b/src/gui/image/qimage_darwin.mm
index a5c391ad21..7ca1a0869a 100644
--- a/src/gui/image/qimage_darwin.mm
+++ b/src/gui/image/qimage_darwin.mm
@@ -40,6 +40,7 @@
#include "qimage.h"
#include <private/qcore_mac_p.h>
+#include <private/qcoregraphics_p.h>
#import <Foundation/Foundation.h>
#import <CoreGraphics/CoreGraphics.h>
@@ -98,32 +99,10 @@ CGImageRef QImage::toCGImage() const
if (isNull())
return nil;
- // Determine the target native format
- uint cgflags = kCGImageAlphaNone;
- switch (format()) {
- case QImage::Format_ARGB32:
- cgflags = kCGImageAlphaFirst | kCGBitmapByteOrder32Host;
- break;
- case QImage::Format_RGB32:
- cgflags = kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Host;
- break;
- case QImage::Format_RGBA8888_Premultiplied:
- cgflags = kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big;
- break;
- case QImage::Format_RGBA8888:
- cgflags = kCGImageAlphaLast | kCGBitmapByteOrder32Big;
- break;
- case QImage::Format_RGBX8888:
- cgflags = kCGImageAlphaNoneSkipLast | kCGBitmapByteOrder32Big;
- break;
- case QImage::Format_ARGB32_Premultiplied:
- cgflags = kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host;
- break;
- default: break;
- }
+ CGBitmapInfo bitmapInfo = qt_mac_bitmapInfoForImage(*this);
// Format not supported: return nil CGImageRef
- if (cgflags == kCGImageAlphaNone)
+ if (bitmapInfo == kCGImageAlphaNone)
return nil;
// Create a data provider that owns a copy of the QImage and references the image data.
@@ -140,7 +119,7 @@ CGImageRef QImage::toCGImage() const
const bool shouldInterpolate = false;
return CGImageCreate(width(), height(), bitsPerComponent, bitsPerPixel,
- this->bytesPerLine(), colorSpace, cgflags, dataProvider,
+ this->bytesPerLine(), colorSpace, bitmapInfo, dataProvider,
decode, shouldInterpolate, kCGRenderingIntentDefault);
}
diff --git a/src/gui/image/qimage_neon.cpp b/src/gui/image/qimage_neon.cpp
index 57a24edeca..9dbcb11db5 100644
--- a/src/gui/image/qimage_neon.cpp
+++ b/src/gui/image/qimage_neon.cpp
@@ -52,65 +52,41 @@ Q_GUI_EXPORT void QT_FASTCALL qt_convert_rgb888_to_rgb32_neon(quint32 *dst, cons
const quint32 *const end = dst + len;
- // align dst on 64 bits
- const int offsetToAlignOn8Bytes = (reinterpret_cast<quintptr>(dst) >> 2) & 0x1;
- for (int i = 0; i < offsetToAlignOn8Bytes; ++i) {
+ // align dst on 128 bits
+ const int offsetToAlignOn16Bytes = (reinterpret_cast<quintptr>(dst) >> 2) & 0x3;
+ for (int i = 0; i < offsetToAlignOn16Bytes; ++i) {
*dst++ = qRgb(src[0], src[1], src[2]);
src += 3;
}
- if ((len - offsetToAlignOn8Bytes) >= 8) {
- const quint32 *const simdEnd = end - 7;
-#if !defined(Q_PROCESSOR_ARM_64)
- register uint8x8_t fullVector asm ("d3") = vdup_n_u8(0xff);
- do {
+ if ((len - offsetToAlignOn16Bytes) >= 16) {
+ const quint32 *const simdEnd = end - 15;
+ uint8x16x4_t dstVector;
#if Q_BYTE_ORDER == Q_BIG_ENDIAN
- asm volatile (
- "vld3.8 { d4, d5, d6 }, [%[SRC]] !\n\t"
- "vst4.8 { d3, d4, d5, d6 }, [%[DST],:64] !\n\t"
- : [DST]"+r" (dst), [SRC]"+r" (src)
- : "w"(fullVector)
- : "memory", "d4", "d5", "d6"
- );
+ dstVector.val[0] = vdupq_n_u8(0xff);
#else
- asm volatile (
- "vld3.8 { d0, d1, d2 }, [%[SRC]] !\n\t"
- "vswp d0, d2\n\t"
- "vst4.8 { d0, d1, d2, d3 }, [%[DST],:64] !\n\t"
- : [DST]"+r" (dst), [SRC]"+r" (src)
- : "w"(fullVector)
- : "memory", "d0", "d1", "d2"
- );
+ dstVector.val[3] = vdupq_n_u8(0xff);
#endif
- } while (dst < simdEnd);
-#else
- register uint8x8_t fullVector asm ("v3") = vdup_n_u8(0xff);
do {
+ uint8x16x3_t srcVector = vld3q_u8(src);
+ src += 3 * 16;
#if Q_BYTE_ORDER == Q_BIG_ENDIAN
- asm volatile (
- "ld3 { v4.8b, v5.8b, v6.8b }, [%[SRC]], #24 \n\t"
- "st4 { v3.8b, v4.8b, v5.8b, v6.8b }, [%[DST]], #32 \n\t"
- : [DST]"+r" (dst), [SRC]"+r" (src)
- : "w"(fullVector)
- : "memory", "v4", "v5", "v6"
- );
+ dstVector.val[1] = srcVector.val[0];
+ dstVector.val[2] = srcVector.val[1];
+ dstVector.val[3] = srcVector.val[2];
#else
- asm volatile (
- "ld3 { v0.8b, v1.8b, v2.8b }, [%[SRC]], #24 \n\t"
- "mov v4.8b, v2.8b\n\t"
- "mov v2.8b, v0.8b\n\t"
- "mov v0.8b, v4.8b\n\t"
- "st4 { v0.8b, v1.8b, v2.8b, v3.8b }, [%[DST]], #32 \n\t"
- : [DST]"+r" (dst), [SRC]"+r" (src)
- : "w"(fullVector)
- : "memory", "v0", "v1", "v2", "v4"
- );
+ dstVector.val[0] = srcVector.val[2];
+ dstVector.val[1] = srcVector.val[1];
+ dstVector.val[2] = srcVector.val[0];
#endif
+ vst4q_u8(reinterpret_cast<uint8_t*>(dst), dstVector);
+ dst += 16;
} while (dst < simdEnd);
-#endif
}
- while (dst != end) {
+ int i = 0;
+ int length = end - dst;
+ SIMD_EPILOGUE(i, length, 15) {
*dst++ = qRgb(src[0], src[1], src[2]);
src += 3;
}
diff --git a/src/gui/image/qimage_p.h b/src/gui/image/qimage_p.h
index 2fe29a88d3..9da6acd0a7 100644
--- a/src/gui/image/qimage_p.h
+++ b/src/gui/image/qimage_p.h
@@ -51,7 +51,10 @@
// 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>
#include <QVector>
@@ -64,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;
@@ -104,8 +107,48 @@ struct Q_GUI_EXPORT QImageData { // internal image data
bool doImageIO(const QImage *image, QImageWriter* io, int quality) const;
QPaintEngine *paintEngine;
+
+ QColorSpace colorSpace;
+
+ struct ImageSizeParameters {
+ qsizetype bytesPerLine;
+ qsizetype totalSize;
+ bool isValid() const { return bytesPerLine > 0 && totalSize > 0; }
+ };
+ static ImageSizeParameters calculateImageParameters(qsizetype width, qsizetype height, qsizetype depth);
};
+inline QImageData::ImageSizeParameters
+QImageData::calculateImageParameters(qsizetype width, qsizetype height, qsizetype depth)
+{
+ ImageSizeParameters invalid = { -1, -1 };
+ if (height <= 0)
+ return invalid;
+
+ // calculate the size, taking care of overflows
+ qsizetype bytes_per_line;
+ if (mul_overflow(width, depth, &bytes_per_line))
+ return invalid;
+ if (add_overflow(bytes_per_line, qsizetype(31), &bytes_per_line))
+ return invalid;
+ // bytes per scanline (must be multiple of 4)
+ bytes_per_line = (bytes_per_line >> 5) << 2; // can't overflow
+
+ qsizetype total_size;
+ if (mul_overflow(height, bytes_per_line, &total_size))
+ return invalid;
+ qsizetype dummy;
+ if (mul_overflow(height, qsizetype(sizeof(uchar *)), &dummy))
+ return invalid; // why is this here?
+#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
+ // Disallow images where width * depth calculations might overflow
+ if (width > (INT_MAX - 31) / depth)
+ return invalid;
+#endif
+
+ return { bytes_per_line, total_size };
+}
+
typedef void (*Image_Converter)(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags);
typedef bool (*InPlace_Image_Converter)(QImageData *data, Qt::ImageConversionFlags);
@@ -156,6 +199,7 @@ inline int qt_depthForFormat(QImage::Format format)
case QImage::Format_RGB16:
case QImage::Format_RGB444:
case QImage::Format_ARGB4444_Premultiplied:
+ case QImage::Format_Grayscale16:
depth = 16;
break;
case QImage::Format_RGB666:
diff --git a/src/gui/image/qimageiohandler.cpp b/src/gui/image/qimageiohandler.cpp
index 5d1f8fa91f..0e7b541cf2 100644
--- a/src/gui/image/qimageiohandler.cpp
+++ b/src/gui/image/qimageiohandler.cpp
@@ -340,7 +340,7 @@ void QImageIOHandler::setDevice(QIODevice *device)
/*!
Returns the device currently assigned to the QImageIOHandler. If
- not device has been assigned, 0 is returned.
+ not device has been assigned, \nullptr is returned.
*/
QIODevice *QImageIOHandler::device() const
{
@@ -416,6 +416,7 @@ QByteArray QImageIOHandler::format() const
\sa read(), QIODevice::peek()
*/
+#if QT_DEPRECATED_SINCE(5, 13)
/*!
\obsolete
@@ -426,6 +427,7 @@ QByteArray QImageIOHandler::name() const
{
return format();
}
+#endif
/*!
Writes the image \a image to the assigned device. Returns \c true on
diff --git a/src/gui/image/qimageiohandler.h b/src/gui/image/qimageiohandler.h
index 990df96534..c20b84afbb 100644
--- a/src/gui/image/qimageiohandler.h
+++ b/src/gui/image/qimageiohandler.h
@@ -69,7 +69,10 @@ public:
void setFormat(const QByteArray &format) const;
QByteArray format() const;
+#if QT_DEPRECATED_SINCE(5, 13)
+ QT_DEPRECATED_X("Use QImageIOHandler::format() instead")
virtual QByteArray name() const;
+#endif
virtual bool canRead() const = 0;
virtual bool read(QImage *image) = 0;
diff --git a/src/gui/image/qimagereader.cpp b/src/gui/image/qimagereader.cpp
index 6d358984d6..61f20e0c65 100644
--- a/src/gui/image/qimagereader.cpp
+++ b/src/gui/image/qimagereader.cpp
@@ -165,6 +165,7 @@
#endif
#include <private/qimagereaderwriterhelpers_p.h>
+#include <qtgui_tracepoints_p.h>
#include <algorithm>
@@ -525,7 +526,7 @@ bool QImageReaderPrivate::initHandler()
// Try the most probable extension first
int currentFormatIndex = extensions.indexOf(format.toLower());
if (currentFormatIndex > 0)
- extensions.swap(0, currentFormatIndex);
+ extensions.swapItemsAt(0, currentFormatIndex);
}
int currentExtension = 0;
@@ -755,13 +756,13 @@ void QImageReader::setDevice(QIODevice *device)
d->device = device;
d->deleteDevice = false;
delete d->handler;
- d->handler = 0;
+ d->handler = nullptr;
d->text.clear();
}
/*!
- Returns the device currently assigned to QImageReader, or 0 if no
- device has been assigned.
+ Returns the device currently assigned to QImageReader, or \nullptr
+ if no device has been assigned.
*/
QIODevice *QImageReader::device() const
{
@@ -1250,7 +1251,18 @@ bool QImageReader::read(QImage *image)
d->handler->setOption(QImageIOHandler::Quality, d->quality);
// read the image
- if (!d->handler->read(image)) {
+ if (Q_TRACE_ENABLED(QImageReader_read_before_reading)) {
+ QString fileName = QStringLiteral("unknown");
+ if (QFile *file = qobject_cast<QFile *>(d->device))
+ fileName = file->fileName();
+ Q_TRACE(QImageReader_read_before_reading, this, fileName);
+ }
+
+ const bool result = d->handler->read(image);
+
+ Q_TRACE(QImageReader_read_after_reading, this, result);
+
+ if (!result) {
d->imageReaderError = InvalidDataError;
d->errorString = QImageReader::tr("Unable to read image data");
return false;
diff --git a/src/gui/image/qimagewriter.cpp b/src/gui/image/qimagewriter.cpp
index 5ce7e309bb..ec66588ddf 100644
--- a/src/gui/image/qimagewriter.cpp
+++ b/src/gui/image/qimagewriter.cpp
@@ -71,6 +71,16 @@
formats, in addition to any image format plugins that support
writing.
+ \note QImageWriter assumes exclusive control over the file or
+ device that is assigned. Any attempts to modify the assigned file
+ or device during the lifetime of the QImageWriter object will
+ yield undefined results. If immediate access to a resource is
+ desired, the use of a scope is the recommended method.
+
+ For example:
+
+ \snippet qimagewriter/main.cpp 0
+
\sa QImageReader, QImageIOHandler, QImageIOPlugin
*/
@@ -397,8 +407,8 @@ void QImageWriter::setDevice(QIODevice *device)
}
/*!
- Returns the device currently assigned to QImageWriter, or 0 if no
- device has been assigned.
+ Returns the device currently assigned to QImageWriter, or \nullptr
+ if no device has been assigned.
*/
QIODevice *QImageWriter::device() const
{
@@ -638,6 +648,7 @@ QImageIOHandler::Transformations QImageWriter::transformation() const
return d->transformation;
}
+#if QT_DEPRECATED_SINCE(5, 13)
/*!
\obsolete
@@ -669,6 +680,7 @@ QString QImageWriter::description() const
{
return d->description;
}
+#endif
/*!
\since 4.1
diff --git a/src/gui/image/qimagewriter.h b/src/gui/image/qimagewriter.h
index 29c06ccdd2..ef84a59b7c 100644
--- a/src/gui/image/qimagewriter.h
+++ b/src/gui/image/qimagewriter.h
@@ -100,9 +100,12 @@ public:
QImageIOHandler::Transformations transformation() const;
void setTransformation(QImageIOHandler::Transformations orientation);
- // Obsolete as of 4.1
+#if QT_DEPRECATED_SINCE(5, 13)
+ QT_DEPRECATED_X("Use QImageWriter::setText() instead")
void setDescription(const QString &description);
+ QT_DEPRECATED_X("Use QImageReader::text() instead")
QString description() const;
+#endif
void setText(const QString &key, const QString &text);
diff --git a/src/gui/image/qmovie.cpp b/src/gui/image/qmovie.cpp
index 010760de4c..79203c7b98 100644
--- a/src/gui/image/qmovie.cpp
+++ b/src/gui/image/qmovie.cpp
@@ -379,7 +379,7 @@ QFrameInfo QMoviePrivate::infoForFrame(int frameNumber)
}
if (frameNumber > greatestFrameNumber)
greatestFrameNumber = frameNumber;
- QPixmap aPixmap = QPixmap::fromImage(anImage);
+ QPixmap aPixmap = QPixmap::fromImage(std::move(anImage));
int aDelay = reader->nextImageDelay();
return QFrameInfo(aPixmap, aDelay);
} else if (frameNumber != 0) {
@@ -405,7 +405,7 @@ QFrameInfo QMoviePrivate::infoForFrame(int frameNumber)
return QFrameInfo(); // Invalid
}
greatestFrameNumber = i;
- QPixmap aPixmap = QPixmap::fromImage(anImage);
+ QPixmap aPixmap = QPixmap::fromImage(std::move(anImage));
int aDelay = reader->nextImageDelay();
QFrameInfo info(aPixmap, aDelay);
// Cache it!
@@ -659,7 +659,7 @@ void QMovie::setDevice(QIODevice *device)
/*!
Returns the device QMovie reads image data from. If no device has
- currently been assigned, 0 is returned.
+ currently been assigned, \nullptr is returned.
\sa setDevice(), fileName()
*/
diff --git a/src/gui/image/qpaintengine_pic_p.h b/src/gui/image/qpaintengine_pic_p.h
index c3044796ad..c9e4b43197 100644
--- a/src/gui/image/qpaintengine_pic_p.h
+++ b/src/gui/image/qpaintengine_pic_p.h
@@ -103,7 +103,7 @@ protected:
QPicturePaintEngine(QPaintEnginePrivate &dptr);
private:
- Q_DISABLE_COPY(QPicturePaintEngine)
+ Q_DISABLE_COPY_MOVE(QPicturePaintEngine)
void writeCmdLength(int pos, const QRectF &r, bool corr);
};
diff --git a/src/gui/image/qpicture.cpp b/src/gui/image/qpicture.cpp
index 7aa221948e..56b82abcfa 100644
--- a/src/gui/image/qpicture.cpp
+++ b/src/gui/image/qpicture.cpp
@@ -636,7 +636,7 @@ bool QPicture::exec(QPainter *painter, QDataStream &s, int nrecords)
if (d->formatMajor <= 5) {
s >> ia >> i_8;
painter->drawPolygon(ia, i_8 ? Qt::WindingFill : Qt::OddEvenFill);
- a.clear();
+ ia.clear();
} else {
s >> a >> i_8;
painter->drawPolygon(a, i_8 ? Qt::WindingFill : Qt::OddEvenFill);
@@ -647,10 +647,10 @@ bool QPicture::exec(QPainter *painter, QDataStream &s, int nrecords)
s >> ia;
QPainterPath path;
Q_ASSERT(ia.size() == 4);
- path.moveTo(ia.at(0));
- path.cubicTo(ia.at(1), ia.at(2), ia.at(3));
+ path.moveTo(ia.value(0));
+ path.cubicTo(ia.value(1), ia.value(2), ia.value(3));
painter->strokePath(path, painter->pen());
- a.clear();
+ ia.clear();
}
break;
case QPicturePrivate::PdcDrawText:
@@ -730,7 +730,7 @@ bool QPicture::exec(QPainter *painter, QDataStream &s, int nrecords)
int index;
s >> r >> index >> sr;
Q_ASSERT(index < d->pixmap_list.size());
- pixmap = d->pixmap_list.at(index);
+ pixmap = d->pixmap_list.value(index);
} else {
s >> r >> pixmap >> sr;
}
@@ -744,7 +744,7 @@ bool QPicture::exec(QPainter *painter, QDataStream &s, int nrecords)
int index;
s >> r >> index >> p;
Q_ASSERT(index < d->pixmap_list.size());
- pixmap = d->pixmap_list.at(index);
+ pixmap = d->pixmap_list.value(index);
} else {
s >> r >> pixmap >> p;
}
@@ -765,7 +765,7 @@ bool QPicture::exec(QPainter *painter, QDataStream &s, int nrecords)
int index;
s >> r >> index >> sr >> ul;
Q_ASSERT(index < d->image_list.size());
- image = d->image_list.at(index);
+ image = d->image_list.value(index);
} else {
s >> r >> image >> sr >> ul;
}
@@ -817,7 +817,7 @@ bool QPicture::exec(QPainter *painter, QDataStream &s, int nrecords)
int index;
s >> index;
Q_ASSERT(index < d->pen_list.size());
- pen = d->pen_list.at(index);
+ pen = d->pen_list.value(index);
} else {
s >> pen;
}
@@ -828,7 +828,7 @@ bool QPicture::exec(QPainter *painter, QDataStream &s, int nrecords)
int index;
s >> index;
Q_ASSERT(index < d->brush_list.size());
- brush = d->brush_list.at(index);
+ brush = d->brush_list.value(index);
} else {
s >> brush;
}
@@ -858,7 +858,7 @@ bool QPicture::exec(QPainter *painter, QDataStream &s, int nrecords)
break;
case QPicturePrivate::PdcSetWXform:
s >> i_8;
- painter->setMatrixEnabled(i_8);
+ painter->setWorldMatrixEnabled(i_8);
break;
case QPicturePrivate::PdcSetWMatrix:
if (d->formatMajor >= 8) {
@@ -910,7 +910,7 @@ bool QPicture::exec(QPainter *painter, QDataStream &s, int nrecords)
break;
default:
qWarning("QPicture::play: Invalid command %d", c);
- if (len) // skip unknown command
+ if (len > 0) // skip unknown command
s.device()->seek(s.device()->pos()+len);
}
#if defined(QT_DEBUG)
@@ -1075,7 +1075,8 @@ bool QPicturePrivate::checkFormat()
char mf_id[4]; // picture header tag
s.readRawData(mf_id, 4); // read actual tag
- if (memcmp(mf_id, qt_mfhdr_tag, 4) != 0) { // wrong header id
+ int bufSize = pictb.buffer().size();
+ if (memcmp(mf_id, qt_mfhdr_tag, 4) != 0 || bufSize < 12) { // wrong header id or size
qWarning("QPicturePaintEngine::checkFormat: Incorrect header");
pictb.close();
return false;
@@ -1199,8 +1200,8 @@ QT_END_INCLUDE_NAMESPACE
\obsolete
Returns a string that specifies the picture format of the file \a
- fileName, or 0 if the file cannot be read or if the format is not
- recognized.
+ fileName, or \nullptr if the file cannot be read or if the format
+ is not recognized.
\sa load(), save()
*/
@@ -1542,7 +1543,7 @@ const QPicture &QPictureIO::picture() const { return d->pi; }
int QPictureIO::status() const { return d->iostat; }
/*!
- Returns the picture format string or 0 if no format has been
+ Returns the picture format string or \nullptr if no format has been
explicitly set.
*/
const char *QPictureIO::format() const { return d->frmt; }
@@ -1865,7 +1866,7 @@ QList<QByteArray> QPictureIO::outputFormats()
bool QPictureIO::read()
{
QFile file;
- const char *picture_format;
+ QByteArray picture_format;
QPictureHandler *h;
if (d->iodev) { // read from io device
@@ -1881,7 +1882,7 @@ bool QPictureIO::read()
if (d->frmt.isEmpty()) {
// Try to guess format
picture_format = pictureFormat(d->iodev); // get picture format
- if (!picture_format) {
+ if (picture_format.isEmpty()) {
if (file.isOpen()) { // unknown format
file.close();
d->iodev = 0;
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.cpp b/src/gui/image/qpixmap.cpp
index 4b2334ae52..5b4d218603 100644
--- a/src/gui/image/qpixmap.cpp
+++ b/src/gui/image/qpixmap.cpp
@@ -714,8 +714,8 @@ QBitmap QPixmap::createMaskFromColor(const QColor &maskColor, Qt::MaskMode mode)
control the conversion.
Note that QPixmaps are automatically added to the QPixmapCache
- when loaded from a file; the key used is internal and can not
- be acquired.
+ when loaded from a file in main thread; the key used is internal
+ and cannot be acquired.
\sa loadFromData(), {QPixmap#Reading and Writing Image
Files}{Reading and Writing Image Files}
@@ -729,6 +729,7 @@ bool QPixmap::load(const QString &fileName, const char *format, Qt::ImageConvers
// Note: If no extension is provided, we try to match the
// file against known plugin extensions
if (info.completeSuffix().isEmpty() || info.exists()) {
+ const bool inGuiThread = qApp->thread() == QThread::currentThread();
QString key = QLatin1String("qt_pixmap")
% info.absoluteFilePath()
@@ -736,13 +737,14 @@ bool QPixmap::load(const QString &fileName, const char *format, Qt::ImageConvers
% HexString<quint64>(info.size())
% HexString<uint>(data ? data->pixelType() : QPlatformPixmap::PixmapType);
- if (QPixmapCache::find(key, this))
+ if (inGuiThread && QPixmapCache::find(key, this))
return true;
data = QPlatformPixmap::create(0, 0, data ? data->pixelType() : QPlatformPixmap::PixmapType);
if (data->fromFile(fileName, format, flags)) {
- QPixmapCache::insert(key, *this);
+ if (inGuiThread)
+ QPixmapCache::insert(key, *this);
return true;
}
}
@@ -856,6 +858,7 @@ bool QPixmap::doImageIO(QImageWriter *writer, int quality) const
}
+#if QT_DEPRECATED_SINCE(5, 13)
/*!
\obsolete
@@ -876,6 +879,14 @@ void QPixmap::fill(const QPaintDevice *device, const QPoint &p)
Use QPainter or the fill(QColor) overload instead.
*/
+void QPixmap::fill(const QPaintDevice *device, int xofs, int yofs)
+{
+ Q_UNUSED(device)
+ Q_UNUSED(xofs)
+ Q_UNUSED(yofs)
+ qWarning("this function is deprecated, ignored");
+}
+#endif
/*!
@@ -959,6 +970,7 @@ static void sendResizeEvents(QWidget *target)
}
#endif
+#if QT_DEPRECATED_SINCE(5, 13)
/*!
\obsolete
@@ -982,6 +994,14 @@ QPixmap QPixmap::grabWidget(QObject *widget, const QRect &rectangle)
Use QWidget::grab() instead.
*/
+QPixmap QPixmap::grabWidget(QObject *widget, int x, int y, int w, int h)
+{
+QT_WARNING_PUSH
+QT_WARNING_DISABLE_DEPRECATED
+ return grabWidget(widget, QRect(x, y, w, h));
+QT_WARNING_POP
+}
+#endif
/*****************************************************************************
QPixmap stream functions
@@ -1356,12 +1376,6 @@ QPixmap QPixmap::transformed(const QMatrix &matrix, Qt::TransformationMode mode)
The cacheKey() function returns a number that uniquely
identifies the contents of the QPixmap object.
- The x11Info() function returns information about the configuration
- of the X display used by the screen to which the pixmap currently
- belongs. The x11PictureHandle() function returns the X11 Picture
- handle of the pixmap for XRender support. Note that the two latter
- functions are only available on x11.
-
\endtable
\section1 Pixmap Conversion
@@ -1392,9 +1406,6 @@ QPixmap QPixmap::transformed(const QMatrix &matrix, Qt::TransformationMode mode)
function returns the actual matrix used for transforming the
pixmap.
- \note When using the native X11 graphics system, the pixmap
- becomes invalid when the QApplication instance is destroyed.
-
\sa QBitmap, QImage, QImageReader, QImageWriter
*/
@@ -1541,6 +1552,11 @@ QPixmap QPixmap::fromImage(const QImage &image, Qt::ImageConversionFlags flags)
if (image.isNull())
return QPixmap();
+ if (Q_UNLIKELY(!qobject_cast<QGuiApplication *>(QCoreApplication::instance()))) {
+ qWarning("QPixmap::fromImage: QPixmap cannot be created without a QGuiApplication");
+ return QPixmap();
+ }
+
QScopedPointer<QPlatformPixmap> data(QGuiApplicationPrivate::platformIntegration()->createPlatformPixmap(QPlatformPixmap::PixmapType));
data->fromImage(image, flags);
return QPixmap(data.take());
@@ -1563,6 +1579,11 @@ QPixmap QPixmap::fromImageInPlace(QImage &image, Qt::ImageConversionFlags flags)
if (image.isNull())
return QPixmap();
+ if (Q_UNLIKELY(!qobject_cast<QGuiApplication *>(QCoreApplication::instance()))) {
+ qWarning("QPixmap::fromImageInPlace: QPixmap cannot be created without a QGuiApplication");
+ return QPixmap();
+ }
+
QScopedPointer<QPlatformPixmap> data(QGuiApplicationPrivate::platformIntegration()->createPlatformPixmap(QPlatformPixmap::PixmapType));
data->fromImageInPlace(image, flags);
return QPixmap(data.take());
@@ -1582,11 +1603,17 @@ QPixmap QPixmap::fromImageInPlace(QImage &image, Qt::ImageConversionFlags flags)
*/
QPixmap QPixmap::fromImageReader(QImageReader *imageReader, Qt::ImageConversionFlags flags)
{
+ if (Q_UNLIKELY(!qobject_cast<QGuiApplication *>(QCoreApplication::instance()))) {
+ qWarning("QPixmap::fromImageReader: QPixmap cannot be created without a QGuiApplication");
+ return QPixmap();
+ }
+
QScopedPointer<QPlatformPixmap> data(QGuiApplicationPrivate::platformIntegration()->createPlatformPixmap(QPlatformPixmap::PixmapType));
data->fromImageReader(imageReader, flags);
return QPixmap(data.take());
}
+#if QT_DEPRECATED_SINCE(5, 13)
/*!
\fn QPixmap QPixmap::grabWindow(WId window, int x, int y, int
width, int height)
@@ -1640,6 +1667,7 @@ QPixmap QPixmap::grabWindow(WId window, int x, int y, int w, int h)
" Defaulting to primary screen.");
return QGuiApplication::primaryScreen()->grabWindow(window, x, y, w, h);
}
+#endif
/*!
\internal
diff --git a/src/gui/image/qpixmap.h b/src/gui/image/qpixmap.h
index 55cca7a766..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;
@@ -94,8 +94,12 @@ public:
static int defaultDepth();
void fill(const QColor &fillColor = Qt::white);
+#if QT_DEPRECATED_SINCE(5, 13)
+ QT_DEPRECATED_X("Use QPainter or fill(QColor)")
void fill(const QPaintDevice *device, const QPoint &ofs);
- inline void fill(const QPaintDevice *device, int xofs, int yofs) { fill(device, QPoint(xofs, yofs)); }
+ QT_DEPRECATED_X("Use QPainter or fill(QColor)")
+ void fill(const QPaintDevice *device, int xofs, int yofs);
+#endif
QBitmap mask() const;
void setMask(const QBitmap &);
@@ -111,10 +115,14 @@ public:
#endif
QBitmap createMaskFromColor(const QColor &maskColor, Qt::MaskMode mode = Qt::MaskInColor) const;
- static QPixmap grabWindow(WId, int x=0, int y=0, int w=-1, int h=-1);
+#if QT_DEPRECATED_SINCE(5, 13)
+ QT_DEPRECATED_X("Use QScreen::grabWindow() instead")
+ static QPixmap grabWindow(WId, int x = 0, int y = 0, int w = -1, int h = -1);
+ QT_DEPRECATED_X("Use QWidget::grab() instead")
static QPixmap grabWidget(QObject *widget, const QRect &rect);
- static inline QPixmap grabWidget(QObject *widget, int x=0, int y=0, int w=-1, int h=-1)
- { return grabWidget(widget, QRect(x, y, w, h)); }
+ QT_DEPRECATED_X("Use QWidget::grab() instead")
+ static QPixmap grabWidget(QObject *widget, int x = 0, int y = 0, int w = -1, int h = -1);
+#endif
inline QPixmap scaled(int w, int h, Qt::AspectRatioMode aspectMode = Qt::IgnoreAspectRatio,
Qt::TransformationMode mode = Qt::FastTransformation) const
diff --git a/src/gui/image/qpixmap_raster.cpp b/src/gui/image/qpixmap_raster.cpp
index 13c1c29d5b..2732bbd197 100644
--- a/src/gui/image/qpixmap_raster.cpp
+++ b/src/gui/image/qpixmap_raster.cpp
@@ -203,6 +203,9 @@ void QRasterPlatformPixmap::fill(const QColor &color)
pixel = qAlpha(color.rgba());
} else if (image.format() == QImage::Format_Grayscale8) {
pixel = qGray(color.rgba());
+ } else if (image.format() == QImage::Format_Grayscale16) {
+ QRgba64 c = color.rgba64();
+ pixel = qGray(c.red(), c.green(), c.blue());
} else
{
pixel = 0;
diff --git a/src/gui/image/qpixmap_win.cpp b/src/gui/image/qpixmap_win.cpp
index b8d13ac092..3a2db74098 100644
--- a/src/gui/image/qpixmap_win.cpp
+++ b/src/gui/image/qpixmap_win.cpp
@@ -210,7 +210,7 @@ static QImage copyImageData(const BITMAPINFOHEADER &header, const RGBQUAD *color
class DisplayHdc
{
- Q_DISABLE_COPY(DisplayHdc)
+ Q_DISABLE_COPY_MOVE(DisplayHdc)
public:
DisplayHdc() : m_displayDc(GetDC(nullptr)) {}
~DisplayHdc() { ReleaseDC(nullptr, m_displayDc); }
@@ -422,8 +422,11 @@ static QImage imageFromWinHBITMAP_GetDiBits(HBITMAP bitmap, bool forceQuads, int
if (info.bmiHeader.biHeight > 0) // Force top-down
info.bmiHeader.biHeight = -info.bmiHeader.biHeight;
info.bmiHeader.biCompression = BI_RGB; // Extract using no compression (can be BI_BITFIELD)
- if (forceQuads)
+ size_t allocSize = info.bmiHeader.biSizeImage;
+ if (forceQuads) {
info.bmiHeader.biBitCount = 32;
+ allocSize = info.bmiHeader.biWidth * qAbs(info.bmiHeader.biHeight) * 4;
+ }
const QImage::Format imageFormat = imageFromWinHBITMAP_Format(info.bmiHeader, hbitmapFormat);
if (imageFormat == QImage::Format_Invalid) {
@@ -431,7 +434,7 @@ static QImage imageFromWinHBITMAP_GetDiBits(HBITMAP bitmap, bool forceQuads, int
return QImage();
}
- QScopedPointer<uchar> data(new uchar[info.bmiHeader.biSizeImage]);
+ QScopedArrayPointer<uchar> data(new uchar[allocSize]);
if (!GetDIBits(displayDc, bitmap, 0, qAbs(info.bmiHeader.biHeight), data.data(), &info, DIB_RGB_COLORS)) {
qErrnoWarning("%s: GetDIBits() failed to get data.", __FUNCTION__);
return QImage();
diff --git a/src/gui/image/qpixmapcache.cpp b/src/gui/image/qpixmapcache.cpp
index 3d1652f68b..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;
}
@@ -469,10 +469,13 @@ QPixmapCacheEntry::~QPixmapCacheEntry()
pm_cache()->releaseKey(key);
}
+#if QT_DEPRECATED_SINCE(5, 13)
/*!
\obsolete
\overload
+ Use bool find(const QString &, QPixmap *) instead.
+
Returns the pixmap associated with the \a key in the cache, or
null if there is no such pixmap.
@@ -494,13 +497,14 @@ QPixmap *QPixmapCache::find(const QString &key)
/*!
\obsolete
- Use bool find(const QString&, QPixmap*) instead.
+ Use bool find(const QString &, QPixmap *) instead.
*/
-bool QPixmapCache::find(const QString &key, QPixmap& pixmap)
+bool QPixmapCache::find(const QString &key, QPixmap &pixmap)
{
return find(key, &pixmap);
}
+#endif
/*!
Looks for a cached pixmap associated with the given \a key in the cache.
@@ -513,7 +517,7 @@ bool QPixmapCache::find(const QString &key, QPixmap& pixmap)
\snippet code/src_gui_image_qpixmapcache.cpp 1
*/
-bool QPixmapCache::find(const QString &key, QPixmap* pixmap)
+bool QPixmapCache::find(const QString &key, QPixmap *pixmap)
{
QPixmap *ptr = pm_cache()->object(key);
if (ptr && pixmap)
@@ -530,7 +534,7 @@ bool QPixmapCache::find(const QString &key, QPixmap* pixmap)
\since 4.6
*/
-bool QPixmapCache::find(const Key &key, QPixmap* pixmap)
+bool QPixmapCache::find(const Key &key, QPixmap *pixmap)
{
//The key is not valid anymore, a flush happened before probably
if (!key.d || !key.d->isValid)
diff --git a/src/gui/image/qpixmapcache.h b/src/gui/image/qpixmapcache.h
index ea10ab1b76..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;
@@ -76,8 +76,12 @@ public:
static int cacheLimit();
static void setCacheLimit(int);
+#if QT_DEPRECATED_SINCE(5, 13)
+ QT_DEPRECATED_X("Use bool find(const QString &, QPixmap *) instead")
static QPixmap *find(const QString &key);
+ QT_DEPRECATED_X("Use bool find(const QString &, QPixmap *) instead")
static bool find(const QString &key, QPixmap &pixmap);
+#endif
static bool find(const QString &key, QPixmap *pixmap);
static bool find(const Key &key, QPixmap *pixmap);
static bool insert(const QString &key, const QPixmap &pixmap);
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/qplatformpixmap.cpp b/src/gui/image/qplatformpixmap.cpp
index 2209c3de4d..a2e01147c4 100644
--- a/src/gui/image/qplatformpixmap.cpp
+++ b/src/gui/image/qplatformpixmap.cpp
@@ -178,6 +178,7 @@ QBitmap QPlatformPixmap::mask() const
if (mask.isNull()) // allocation failed
return QBitmap();
+ mask.setDevicePixelRatio(devicePixelRatio());
mask.setColorCount(2);
mask.setColor(0, QColor(Qt::color0).rgba());
mask.setColor(1, QColor(Qt::color1).rgba());
diff --git a/src/gui/image/qpnghandler.cpp b/src/gui/image/qpnghandler.cpp
index 242d8cd63b..39d0807606 100644
--- a/src/gui/image/qpnghandler.cpp
+++ b/src/gui/image/qpnghandler.cpp
@@ -42,15 +42,19 @@
#ifndef QT_NO_IMAGEFORMAT_PNG
#include <qcoreapplication.h>
+#include <qdebug.h>
#include <qiodevice.h>
#include <qimage.h>
#include <qlist.h>
-#include <qtextcodec.h>
#include <qvariant.h>
#include <qvector.h>
#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>
@@ -97,17 +101,27 @@ 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(2), 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;
float fileGamma;
- int quality;
+ int quality; // quality is used for backward compatibility, maps to compression
+ int compression;
QString description;
QSize scaledSize;
QStringList readTexts;
+ QColorSpace colorSpace;
+ ColorSpaceState colorSpaceState;
png_struct *png_ptr;
png_info *info_ptr;
@@ -161,11 +175,11 @@ public:
void setGamma(float);
bool writeImage(const QImage& img, int x, int y);
- bool writeImage(const QImage& img, volatile int quality, const QString &description, int x, int y);
+ bool writeImage(const QImage& img, volatile int compression_in, const QString &description, int x, int y);
bool writeImage(const QImage& img)
{ return writeImage(img, 0, 0); }
- bool writeImage(const QImage& img, int quality, const QString &description)
- { return writeImage(img, quality, description, 0, 0); }
+ bool writeImage(const QImage& img, int compression, const QString &description)
+ { return writeImage(img, compression, description, 0, 0); }
QIODevice* device() { return dev; }
@@ -226,21 +240,18 @@ 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;
- png_uint_32 height;
- int bit_depth;
- int color_type;
+ png_uint_32 width = 0;
+ png_uint_32 height = 0;
+ int bit_depth = 0;
+ int color_type = 0;
png_bytep trans_alpha = 0;
png_color_16p trans_color_p = 0;
int num_trans;
png_colorp palette = 0;
int num_palette;
- int interlace_method;
+ int interlace_method = PNG_INTERLACE_LAST;
png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_method, 0, 0);
png_set_interlace_handling(png_ptr);
@@ -266,6 +277,18 @@ void setup_qt(QImage& image, png_structp png_ptr, png_infop info_ptr, QSize scal
else if (g == 1)
image.setColor(0, qRgba(255, 255, 255, 0));
}
+ } else if (bit_depth == 16
+ && png_get_channels(png_ptr, info_ptr) == 1
+ && !png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
+ if (image.size() != QSize(width, height) || image.format() != QImage::Format_Grayscale16) {
+ image = QImage(width, height, QImage::Format_Grayscale16);
+ if (image.isNull())
+ return;
+ }
+
+ png_read_update_info(png_ptr, info_ptr);
+ if (QSysInfo::ByteOrder == QSysInfo::LittleEndian)
+ png_set_swap(png_ptr);
} else if (bit_depth == 16) {
bool hasMask = png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS);
if (!hasMask)
@@ -573,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;
@@ -601,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);
@@ -671,14 +740,17 @@ 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;
}
QImage::Format QPngHandlerPrivate::readImageFormat()
{
QImage::Format format = QImage::Format_Invalid;
- png_uint_32 width, height;
- int bit_depth, color_type;
+ png_uint_32 width = 0, height = 0;
+ int bit_depth = 0, color_type = 0;
png_colorp palette;
int num_palette;
png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, 0, 0, 0);
@@ -687,7 +759,7 @@ QImage::Format QPngHandlerPrivate::readImageFormat()
if (bit_depth == 1 && png_get_channels(png_ptr, info_ptr) == 1) {
format = QImage::Format_Mono;
} else if (bit_depth == 16) {
- format = png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS) ? QImage::Format_RGBA64 : QImage::Format_RGBX64;
+ format = png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS) ? QImage::Format_RGBA64 : QImage::Format_Grayscale16;
} else if (bit_depth == 8 && !png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
format = QImage::Format_Grayscale8;
} else {
@@ -814,7 +886,7 @@ bool QPNGImageWriter::writeImage(const QImage& image, int off_x, int off_y)
return writeImage(image, -1, QString(), off_x, off_y);
}
-bool QPNGImageWriter::writeImage(const QImage& image, volatile int quality_in, const QString &description,
+bool QPNGImageWriter::writeImage(const QImage& image, volatile int compression_in, const QString &description,
int off_x_in, int off_y_in)
{
QPoint offset = image.offset();
@@ -842,13 +914,13 @@ bool QPNGImageWriter::writeImage(const QImage& image, volatile int quality_in, c
return false;
}
- int quality = quality_in;
- if (quality >= 0) {
- if (quality > 9) {
- qWarning("PNG: Quality %d out of range", quality);
- quality = 9;
+ int compression = compression_in;
+ if (compression >= 0) {
+ if (compression > 9) {
+ qWarning("PNG: Compression %d out of range", compression);
+ compression = 9;
}
- png_set_compression_level(png_ptr, quality);
+ png_set_compression_level(png_ptr, compression);
}
png_set_write_fn(png_ptr, (void*)this, qpiw_write_fn, qpiw_flush_fn);
@@ -861,7 +933,8 @@ bool QPNGImageWriter::writeImage(const QImage& image, volatile int quality_in, c
else
color_type = PNG_COLOR_TYPE_PALETTE;
}
- else if (image.format() == QImage::Format_Grayscale8)
+ else if (image.format() == QImage::Format_Grayscale8
+ || image.format() == QImage::Format_Grayscale16)
color_type = PNG_COLOR_TYPE_GRAY;
else if (image.hasAlphaChannel())
color_type = PNG_COLOR_TYPE_RGB_ALPHA;
@@ -877,6 +950,7 @@ bool QPNGImageWriter::writeImage(const QImage& image, volatile int quality_in, c
case QImage::Format_RGBX64:
case QImage::Format_RGBA64:
case QImage::Format_RGBA64_Premultiplied:
+ case QImage::Format_Grayscale16:
bpc = 16;
break;
default:
@@ -988,6 +1062,7 @@ bool QPNGImageWriter::writeImage(const QImage& image, volatile int quality_in, c
case QImage::Format_RGBX64:
case QImage::Format_RGBA64:
case QImage::Format_RGBA64_Premultiplied:
+ case QImage::Format_Grayscale16:
png_set_swap(png_ptr);
break;
default:
@@ -1018,6 +1093,7 @@ bool QPNGImageWriter::writeImage(const QImage& image, volatile int quality_in, c
case QImage::Format_MonoLSB:
case QImage::Format_Indexed8:
case QImage::Format_Grayscale8:
+ case QImage::Format_Grayscale16:
case QImage::Format_RGB32:
case QImage::Format_ARGB32:
case QImage::Format_RGB888:
@@ -1067,15 +1143,21 @@ bool QPNGImageWriter::writeImage(const QImage& image, volatile int quality_in, c
}
static bool write_png_image(const QImage &image, QIODevice *device,
- int quality, float gamma, const QString &description)
+ int compression, int quality, float gamma, const QString &description)
{
+ // quality is used for backward compatibility, maps to compression
+
QPNGImageWriter writer(device);
- if (quality >= 0) {
- quality = qMin(quality, 100);
- quality = (100-quality) * 9 / 91; // map [0,100] -> [9,0]
- }
+ if (compression >= 0)
+ compression = qMin(compression, 100);
+ else if (quality >= 0)
+ compression = 100 - qMin(quality, 100);
+
+ if (compression >= 0)
+ compression = (compression * 9) / 91; // map [0,100] -> [0,9]
+
writer.setGamma(gamma);
- return writer.writeImage(image, quality, description);
+ return writer.writeImage(image, compression, description);
}
QPngHandler::QPngHandler()
@@ -1122,7 +1204,7 @@ bool QPngHandler::read(QImage *image)
bool QPngHandler::write(const QImage &image)
{
- return write_png_image(image, device(), d->quality, d->gamma, d->description);
+ return write_png_image(image, device(), d->compression, d->quality, d->gamma, d->description);
}
bool QPngHandler::supportsOption(ImageOption option) const
@@ -1131,6 +1213,7 @@ bool QPngHandler::supportsOption(ImageOption option) const
|| option == Description
|| option == ImageFormat
|| option == Quality
+ || option == CompressionRatio
|| option == Size
|| option == ScaledSize;
}
@@ -1146,6 +1229,8 @@ QVariant QPngHandler::option(ImageOption option) const
return d->gamma == 0.0 ? d->fileGamma : d->gamma;
else if (option == Quality)
return d->quality;
+ else if (option == CompressionRatio)
+ return d->compression;
else if (option == Description)
return d->description;
else if (option == Size)
@@ -1164,16 +1249,20 @@ void QPngHandler::setOption(ImageOption option, const QVariant &value)
d->gamma = value.toFloat();
else if (option == Quality)
d->quality = value.toInt();
+ else if (option == CompressionRatio)
+ d->compression = value.toInt();
else if (option == Description)
d->description = value.toString();
else if (option == ScaledSize)
d->scaledSize = value.toSize();
}
+#if QT_DEPRECATED_SINCE(5, 13)
QByteArray QPngHandler::name() const
{
return "png";
}
+#endif
QT_END_NAMESPACE
diff --git a/src/gui/image/qpnghandler_p.h b/src/gui/image/qpnghandler_p.h
index 4ca716e7c2..5d4da97395 100644
--- a/src/gui/image/qpnghandler_p.h
+++ b/src/gui/image/qpnghandler_p.h
@@ -69,7 +69,9 @@ public:
bool read(QImage *image) override;
bool write(const QImage &image) override;
+#if QT_DEPRECATED_SINCE(5, 13)
QByteArray name() const override;
+#endif
QVariant option(ImageOption option) const override;
void setOption(ImageOption option, const QVariant &value) override;
diff --git a/src/gui/image/qppmhandler.cpp b/src/gui/image/qppmhandler.cpp
index bfde0aa76e..13ee2eadd2 100644
--- a/src/gui/image/qppmhandler.cpp
+++ b/src/gui/image/qppmhandler.cpp
@@ -576,10 +576,12 @@ void QPpmHandler::setOption(ImageOption option, const QVariant &value)
subType = value.toByteArray().toLower();
}
+#if QT_DEPRECATED_SINCE(5, 13)
QByteArray QPpmHandler::name() const
{
return subType.isEmpty() ? QByteArray("ppm") : subType;
}
+#endif
QT_END_NAMESPACE
diff --git a/src/gui/image/qppmhandler_p.h b/src/gui/image/qppmhandler_p.h
index 1c6fbd6869..2f3811b759 100644
--- a/src/gui/image/qppmhandler_p.h
+++ b/src/gui/image/qppmhandler_p.h
@@ -67,9 +67,11 @@ public:
bool read(QImage *image) override;
bool write(const QImage &image) override;
+#if QT_DEPRECATED_SINCE(5, 13)
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;
diff --git a/src/gui/image/qxbmhandler.cpp b/src/gui/image/qxbmhandler.cpp
index 24d86e116d..65a5b63bc7 100644
--- a/src/gui/image/qxbmhandler.cpp
+++ b/src/gui/image/qxbmhandler.cpp
@@ -97,6 +97,8 @@ static bool read_xbm_header(QIODevice *device, int& w, int& h)
if (r1.indexIn(sbuf) == 0 &&
r2.indexIn(sbuf, r1.matchedLength()) == r1.matchedLength())
w = QByteArray(&buf[r1.matchedLength()]).trimmed().toInt();
+ else
+ return false;
// "#define .._height <num>"
readBytes = device->readLine(buf, buflen);
@@ -109,6 +111,8 @@ static bool read_xbm_header(QIODevice *device, int& w, int& h)
if (r1.indexIn(sbuf) == 0 &&
r2.indexIn(sbuf, r1.matchedLength()) == r1.matchedLength())
h = QByteArray(&buf[r1.matchedLength()]).trimmed().toInt();
+ else
+ return false;
// format error
if (w <= 0 || w > 32767 || h <= 0 || h > 32767)
@@ -352,10 +356,12 @@ void QXbmHandler::setOption(ImageOption option, const QVariant &value)
fileName = value.toString();
}
+#if QT_DEPRECATED_SINCE(5, 13)
QByteArray QXbmHandler::name() const
{
return "xbm";
}
+#endif
QT_END_NAMESPACE
diff --git a/src/gui/image/qxbmhandler_p.h b/src/gui/image/qxbmhandler_p.h
index 26439af527..ae590a1944 100644
--- a/src/gui/image/qxbmhandler_p.h
+++ b/src/gui/image/qxbmhandler_p.h
@@ -66,7 +66,9 @@ public:
bool read(QImage *image) override;
bool write(const QImage &image) override;
+#if QT_DEPRECATED_SINCE(5, 13)
QByteArray name() const override;
+#endif
static bool canRead(QIODevice *device);
diff --git a/src/gui/image/qxpmhandler.cpp b/src/gui/image/qxpmhandler.cpp
index 17272ffe69..a32dfda96d 100644
--- a/src/gui/image/qxpmhandler.cpp
+++ b/src/gui/image/qxpmhandler.cpp
@@ -1287,10 +1287,12 @@ void QXpmHandler::setOption(ImageOption option, const QVariant &value)
fileName = value.toString();
}
+#if QT_DEPRECATED_SINCE(5, 13)
QByteArray QXpmHandler::name() const
{
return "xpm";
}
+#endif
QT_END_NAMESPACE
diff --git a/src/gui/image/qxpmhandler_p.h b/src/gui/image/qxpmhandler_p.h
index f118bf2309..a4dd88cd17 100644
--- a/src/gui/image/qxpmhandler_p.h
+++ b/src/gui/image/qxpmhandler_p.h
@@ -68,7 +68,9 @@ public:
static bool canRead(QIODevice *device);
+#if QT_DEPRECATED_SINCE(5, 13)
QByteArray name() const override;
+#endif
QVariant option(ImageOption option) const override;
void setOption(ImageOption option, const QVariant &value) override;