diff --git a/src/gui/image/qimage.cpp b/src/gui/image/qimage.cpp index b1dcf6a9f8..9870e19cec 100644 --- a/src/gui/image/qimage.cpp +++ b/src/gui/image/qimage.cpp @@ -2120,6 +2120,44 @@ QImage QImage::convertToFormat(Format format, const QVector &colorTable, Q return image; } +/*! + \since 5.9 + + Changes the format of the image without changing the data. Only + works between formats of the same depth. + + Returns \c true if successful. + + This function can be used to change images with alpha-channels to + their corresponding opaque formats if the data is known to be opaque-only, + or to change the format of a given image buffer before overwriting + it with new data. + + \warning The function does not check if the image data is valid in the + new format and will still return \c true if the depths are compatible. + Operations on an image with invalid data are undefined. + + \warning If the image is not detached, this will cause the data to be + copied. + + \sa isDetached(), hasAlphaChannel(), convertToFormat() +*/ + +bool QImage::reinterpretAsFormat(Format format) +{ + if (!d) + return false; + if (d->format == format) + return true; + if (qt_depthForFormat(format) != qt_depthForFormat(d->format)) + return false; + if (!isDetached()) // Detach only if shared, not for read-only data. + detach(); + + d->format = format; + return true; +} + /*! \fn bool QImage::valid(const QPoint &pos) const diff --git a/src/gui/image/qimage.h b/src/gui/image/qimage.h index fd2298561e..204e7a54b2 100644 --- a/src/gui/image/qimage.h +++ b/src/gui/image/qimage.h @@ -192,6 +192,7 @@ public: QImage convertToFormat(Format f, Qt::ImageConversionFlags flags = Qt::AutoColor) const Q_REQUIRED_RESULT; #endif QImage convertToFormat(Format f, const QVector &colorTable, Qt::ImageConversionFlags flags = Qt::AutoColor) const Q_REQUIRED_RESULT; + bool reinterpretAsFormat(Format f); int width() const; int height() const; diff --git a/tests/auto/gui/image/qimage/tst_qimage.cpp b/tests/auto/gui/image/qimage/tst_qimage.cpp index 65ee4a2188..21481e374d 100644 --- a/tests/auto/gui/image/qimage/tst_qimage.cpp +++ b/tests/auto/gui/image/qimage/tst_qimage.cpp @@ -206,6 +206,11 @@ private slots: void ditherGradient_data(); void ditherGradient(); + void reinterpretAsFormat_data(); + void reinterpretAsFormat(); + + void reinterpretAsFormat2(); + #ifdef Q_OS_DARWIN void toCGImage_data(); void toCGImage(); @@ -3303,6 +3308,64 @@ void tst_QImage::ditherGradient() QVERIFY(observedGradientSteps >= minimumExpectedGradient); } +void tst_QImage::reinterpretAsFormat_data() +{ + QTest::addColumn("in_format"); + QTest::addColumn("out_format"); + QTest::addColumn("in_color"); + QTest::addColumn("out_color"); + +#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN + QTest::newRow("rgb32 -> rgbx8888") << QImage::Format_RGB32 << QImage::Format_RGBX8888 << QColor(Qt::red) << QColor(Qt::blue); + QTest::newRow("rgba8888 -> argb32") << QImage::Format_RGBA8888 << QImage::Format_ARGB32 << QColor(Qt::red) << QColor(Qt::blue); + QTest::newRow("argb32pm -> rgba8888pm") << QImage::Format_RGBA8888_Premultiplied << QImage::Format_ARGB32_Premultiplied << QColor(Qt::green) << QColor(Qt::green); +#endif + QTest::newRow("rgb32 -> argb32") << QImage::Format_RGB32 << QImage::Format_ARGB32 << QColor(Qt::cyan) << QColor(Qt::cyan); + QTest::newRow("argb32pm -> rgb32") << QImage::Format_ARGB32_Premultiplied << QImage::Format_RGB32 << QColor(Qt::transparent) << QColor(Qt::black); + QTest::newRow("argb32 -> rgb32") << QImage::Format_ARGB32 << QImage::Format_RGB32 << QColor(255, 0, 0, 127) << QColor(255, 0, 0); + QTest::newRow("argb32pm -> rgb32") << QImage::Format_ARGB32_Premultiplied << QImage::Format_RGB32 << QColor(255, 0, 0, 127) << QColor(127, 0, 0); +} + +void tst_QImage::reinterpretAsFormat() +{ + QFETCH(QImage::Format, in_format); + QFETCH(QImage::Format, out_format); + QFETCH(QColor, in_color); + QFETCH(QColor, out_color); + + QImage image(1, 1, in_format); + image.setPixelColor(0, 0, in_color); + QVERIFY(image.reinterpretAsFormat(out_format)); + QCOMPARE(image.pixelColor(0, 0), out_color); +} + +void tst_QImage::reinterpretAsFormat2() +{ + const uint imageData[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; + + { + QImage image(reinterpret_cast(imageData), 4, 2, QImage::Format_RGB32); + QCOMPARE(image.pixelColor(0, 0), QColor(Qt::black)); + QVERIFY(image.isDetached()); + QVERIFY(image.reinterpretAsFormat(QImage::Format_ARGB32_Premultiplied)); + QCOMPARE(image.constBits(), reinterpret_cast(imageData)); + QCOMPARE(image.pixelColor(0, 0), QColor(Qt::transparent)); + + QVERIFY(!image.reinterpretAsFormat(QImage::Format_Grayscale8)); + } + { + QImage image(reinterpret_cast(imageData), 8, 4, QImage::Format_Indexed8); + image.setColor(0, qRgb(255, 255, 255)); + QCOMPARE(image.pixelColor(0, 0), QColor(Qt::white)); + QVERIFY(image.reinterpretAsFormat(QImage::Format_Grayscale8)); + QCOMPARE(image.pixelColor(0, 0), QColor(Qt::black)); + QVERIFY(image.reinterpretAsFormat(QImage::Format_Alpha8)); + QCOMPARE(image.pixelColor(0, 0), QColor(Qt::transparent)); + + QVERIFY(!image.reinterpretAsFormat(QImage::Format_RGB16)); + } +} + #ifdef Q_OS_DARWIN void tst_QImage::toCGImage_data()