qt5base-lts/tests/auto/gui/image/qpixmap/tst_qpixmap.cpp

1693 lines
48 KiB
C++
Raw Normal View History

/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the test suite of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:GPL-EXCEPT$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include <QSet>
#include <QTemporaryFile>
#include <QBuffer>
#include <QTest>
#include <QPixmap>
#include <QBitmap>
#include <QImage>
#include <QImageReader>
#include <QPaintEngine>
#ifndef QT_NO_WIDGETS
#include <QSplashScreen>
#endif
Expose QPA API under qpa/* The main reasons for doing this are: 1. _qpa.h end up in the master QtGui include file. QtGui is meant for userland applications. qpa code is neither binary nor source compatible. Inadvertant use of QPA api makes the user code binary-incompatible. 2. syncqt creates forwarding headers for non-private header files. This gives people the impression that this is public API. As discussed on the mailing list, even though QPA api is internal and subject to change, it needs to treated differently from private headers since they will be used by in-qtbase and out-of-qtbase plugins. This commit does the following: 1. The _qpa in QPA header files is dropped. 2. syncqt now treats any file with qplatform prefix as a special file and moves it to qpa/ directory. The recommended way of using QPA API in plugins is: #include <qpa/qplatformfoo.h>. This allows the user include QPA API from multiple modules (for example, qplatformfoo might be in QtPrintSupport) 3. The user needs to explicitly add QT += <module>-private to get access to the qpa api. 4. Creates compat headers for the olden style qplatformfoo_qpa.h and QPlatformFoo includes. This commit does not change the cpp filenames. This requires a more careful merging of existing non qpa cpp files and existing cpp files on a case by case basis. This can be done at anytime. The following files are not renamed as part of this changed but will be fixed as part of a future change: src/gui/kernel/qgenericpluginfactory_qpa.h src/gui/kernel/qgenericplugin_qpa.h src/gui/kernel/qwindowsysteminterface_qpa.h files were renamed using for x in `find . -name "qplatform*_qpa.h"`; do git mv $x "${x/_qpa.h/.h}"; done for x in `find . -name "qplatform*_qpa_p.h"`; do git mv $x "${x/_qpa_p.h/_p.h}"; done includes were renamed using script for file in `find . -name "*.h" -or -name "*.cpp" -or -name "*.mm"`; do sed -i -e 's,.*#.*include.*<\(Qt.*/\)\?\(QPlatform.*\)>,#include <qpa/\L\2.h>,g' \ -e 's,.*#.*include.*"\(Qt.*/\)\?\(QPlatform.*\)",#include <qpa/\L\2.h>,g' \ -e 's,.*#.*include.* "\(qplatform.*\)_qpa.h",#include <qpa/\L\1.h>,g' \ -e 's,.*#.*include.*"\(qplatform.*\)_qpa_p.h",#include <qpa/\L\1_p.h>,g' \ -e 's,.*#.*include.*<\(Qt.*/\|Qt.*/private/\|private/\)\?\(qplatform.*\)_qpa\(.*\)>,#include <qpa/\2\3>,g' \ -e 's,.*#.*include.*"\(Qt.*/\|Qt.*/private/\|private/\)\?\(qplatform.*\)_qpa\(.*\)",#include <qpa/\2\3>,g' \ $file done Change-Id: I04a350314a45746e3911f54b3b21ad03315afb67 Reviewed-by: Morten Johan Sørvig <morten.sorvig@nokia.com> Reviewed-by: Samuel Rødal <samuel.rodal@nokia.com> Reviewed-by: Friedemann Kleint <Friedemann.Kleint@nokia.com> Reviewed-by: Sean Harmer <sean.harmer@kdab.com> Reviewed-by: Lars Knoll <lars.knoll@nokia.com> Reviewed-by: Gunnar Sletta <gunnar.sletta@nokia.com>
2012-04-26 23:33:35 +00:00
#include <qpa/qplatformpixmap.h>
#include <qpa/qplatformintegration.h>
#include <private/qguiapplication_p.h>
#include <private/qdrawhelper_p.h>
#ifdef Q_OS_WIN
#include <windows.h>
#endif
Q_DECLARE_METATYPE(QImage::Format)
class tst_QPixmap : public QObject
{
Q_OBJECT
public:
tst_QPixmap();
public slots:
void initTestCase();
void cleanupTestCase();
private slots:
void swap();
void fromImage_data();
void fromImage();
void fromUninitializedImage_data();
void fromUninitializedImage();
void convertFromImage_data();
void convertFromImage();
void convertFromImageShouldDetach();
void testMetrics();
void scroll_data();
void scroll();
void fill_data();
void fill();
void fill_transparent();
void createMaskFromColor();
void mask();
void bitmapMask();
void bitmapFromImageRvalue();
void setGetMask_data();
void setGetMask();
void cacheKey();
void drawBitmap();
void isNull();
void task_246446();
void task_51271();
void convertFromImageNoDetach();
void convertFromImageNoDetach2();
void convertFromImageDetach();
void convertFromImageCacheKey();
#if defined(Q_OS_WIN)
void toWinHBITMAP_data();
void toWinHBITMAP();
void fromWinHBITMAP_data();
void fromWinHBITMAP();
void toWinHICON_data();
void toWinHICON();
void fromWinHICON_data();
void fromWinHICON();
#endif
void onlyNullPixmapsOutsideGuiThread();
void refUnref();
void copy();
void move();
void deepCopyPreservesDpr();
void dprPassthrough();
void depthOfNullObjects();
void transformed();
void transformed2();
void fromImage_crash();
void load();
void loadFromData();
#if !defined(QT_NO_DATASTREAM)
void loadFromDataStream();
#endif
void fromData();
void loadFromDataNullValues();
void loadFromDataImage_data();
void loadFromDataImage();
void fromImageReader_data();
void fromImageReader();
void fromImageReaderAnimatedGif_data();
void fromImageReaderAnimatedGif();
void preserveDepth();
#ifndef QT_NO_WIDGETS
void splash_crash();
#endif
void toImageDeepCopy();
void loadAsBitmapOrPixmap();
void scaled_QTBUG19157();
void detachOnLoad_QTBUG29639();
void copyOnNonAlignedBoundary();
void devicePixelRatio();
void deviceIndependentSize();
private:
const QString m_prefix;
const QString m_convertFromImage;
const QString m_loadFromData;
const QTemporaryDir m_tempDir;
};
static bool lenientCompare(const QPixmap &actual, const QPixmap &expected)
{
QImage expectedImage = expected.toImage().convertToFormat(QImage::Format_RGB32);
QImage actualImage = actual.toImage().convertToFormat(QImage::Format_RGB32);
if (expectedImage.size() != actualImage.size()) {
qWarning("Image size comparison failed: expected: %dx%d, got %dx%d",
expectedImage.size().width(), expectedImage.size().height(),
actualImage.size().width(), actualImage.size().height());
return false;
}
const int size = actual.width() * actual.height();
const int threshold = QPixmap::defaultDepth() == 16 ? 10 : 2;
QRgb *a = (QRgb *)actualImage.bits();
QRgb *e = (QRgb *)expectedImage.bits();
for (int i = 0; i < size; ++i) {
const QColor ca(a[i]);
const QColor ce(e[i]);
if (qAbs(ca.red() - ce.red()) > threshold
|| qAbs(ca.green() - ce.green()) > threshold
|| qAbs(ca.blue() - ce.blue()) > threshold) {
qWarning("Color mismatch at pixel #%d: Expected: %d,%d,%d, got %d,%d,%d",
i, ce.red(), ce.green(), ce.blue(), ca.red(), ca.green(), ca.blue());
return false;
}
}
return true;
}
tst_QPixmap::tst_QPixmap()
: m_prefix(QFINDTESTDATA("images/"))
, m_convertFromImage(QFINDTESTDATA("convertFromImage"))
, m_loadFromData(QFINDTESTDATA("loadFromData"))
{
}
void tst_QPixmap::initTestCase()
{
QVERIFY(!m_prefix.isEmpty());
QVERIFY(!m_convertFromImage.isEmpty());
QVERIFY(!m_loadFromData.isEmpty());
QVERIFY2(m_tempDir.isValid(), qPrintable(m_tempDir.errorString()));
}
void tst_QPixmap::cleanupTestCase()
{
}
void tst_QPixmap::swap()
{
QPixmap p1( 16, 16 ), p2( 32, 32 );
p1.fill( Qt::white );
p2.fill( Qt::black );
const qint64 p1k = p1.cacheKey();
const qint64 p2k = p2.cacheKey();
p1.swap(p2);
QCOMPARE(p1.cacheKey(), p2k);
QCOMPARE(p1.size(), QSize(32,32));
QCOMPARE(p2.cacheKey(), p1k);
QCOMPARE(p2.size(), QSize(16,16));
}
void tst_QPixmap::fromImage_data()
{
bool is16bit = false;
if (QPixmap::defaultDepth() == 16)
is16bit = true;
QTest::addColumn<QImage::Format>("format");
QTest::newRow("Format_Mono") << QImage::Format_Mono;
QTest::newRow("Format_MonoLSB") << QImage::Format_MonoLSB;
// QTest::newRow("Format_Indexed8") << QImage::Format_Indexed8;
if (!is16bit)
QTest::newRow("Format_RGB32") << QImage::Format_RGB32;
QTest::newRow("Format_ARGB32") << QImage::Format_ARGB32;
QTest::newRow("Format_ARGB32_Premultiplied") << QImage::Format_ARGB32_Premultiplied;
if (!is16bit)
QTest::newRow("Format_RGB16") << QImage::Format_RGB16;
}
void tst_QPixmap::fromImage()
{
QFETCH(QImage::Format, format);
QImage image(37, 16, format);
if (image.colorCount() == 2) {
image.setColor(0, QColor(Qt::color0).rgba());
image.setColor(1, QColor(Qt::color1).rgba());
}
image.fill(0x7f7f7f7f);
const QPixmap pixmap = QPixmap::fromImage(image);
const QImage result = pixmap.toImage();
image = image.convertToFormat(result.format());
QCOMPARE(result, image);
}
void tst_QPixmap::fromUninitializedImage_data()
{
QTest::addColumn<QImage::Format>("format");
QTest::newRow("Format_Mono") << QImage::Format_Mono;
QTest::newRow("Format_MonoLSB") << QImage::Format_MonoLSB;
QTest::newRow("Format_Indexed8") << QImage::Format_Indexed8;
QTest::newRow("Format_RGB32") << QImage::Format_RGB32;
QTest::newRow("Format_ARGB32") << QImage::Format_ARGB32;
QTest::newRow("Format_ARGB32_Premultiplied") << QImage::Format_ARGB32_Premultiplied;
QTest::newRow("Format_RGB16") << QImage::Format_RGB16;
}
void tst_QPixmap::fromUninitializedImage()
{
QFETCH(QImage::Format, format);
QImage image(100, 100, format);
QPixmap pix = QPixmap::fromImage(image);
// it simply shouldn't crash...
QVERIFY(true);
}
void tst_QPixmap::convertFromImage_data()
{
QTest::addColumn<QImage>("img1");
QTest::addColumn<QImage>("img2");
{
QImage img1;
QImage img2;
QVERIFY(img1.load(m_convertFromImage + "/task31722_0/img1.png"));
QVERIFY(img2.load(m_convertFromImage + "/task31722_0/img2.png"));
QVERIFY(img1.load(m_convertFromImage + "/task31722_0/img1.png"));
QVERIFY(img2.load(m_convertFromImage + "/task31722_0/img2.png"));
QTest::newRow("Task 31722 0") << img1 << img2;
}
{
QImage img1;
QImage img2;
QVERIFY(img1.load(m_convertFromImage + "/task31722_1/img1.png"));
QVERIFY(img2.load(m_convertFromImage + "/task31722_1/img2.png"));
QTest::newRow("Task 31722 1") << img1 << img2;
}
}
void tst_QPixmap::convertFromImage()
{
QFETCH(QImage, img1);
QFETCH(QImage, img2);
QPixmap pix = QPixmap::fromImage(img1);
pix = QPixmap::fromImage(img2);
QPixmap res = QPixmap::fromImage(img2);
QCOMPARE(pix, res);
}
void tst_QPixmap::convertFromImageShouldDetach()
{
QImage img1;
QImage img2;
QVERIFY(img1.load(m_convertFromImage + "/task31722_0/img1.png"));
QVERIFY(img2.load(m_convertFromImage + "/task31722_0/img2.png"));
QPixmap pix = QPixmap::fromImage(img1);
QPixmap pix1 = pix;
pix.convertFromImage(img2);
QCOMPARE(pix, QPixmap::fromImage(img2));
QCOMPARE(pix1, QPixmap::fromImage(img1)); // unchanged
}
void tst_QPixmap::scroll_data()
{
QTest::addColumn<QImage>("input");
QTest::addColumn<int>("dx");
QTest::addColumn<int>("dy");
QTest::addColumn<QRect>("rect");
QTest::addColumn<QRegion>("exposed");
QTest::addColumn<bool>("newPix");
QImage input(":/images/designer.png");
// Noop tests
QTest::newRow("null") << QImage() << 0 << 0 << QRect() << QRegion() << false;
QTest::newRow("dx_0_dy_0_null") << input << 0 << 0 << QRect() << QRegion() << false;
QTest::newRow("dx_1_dy_0_null") << input << 1 << 0 << QRect() << QRegion() << false;
QTest::newRow("dx_0_dy_1_null") << input << 0 << 1 << QRect() << QRegion() << false;
QTest::newRow("dx_0_dy_0_x_y_w_h") << input << 0 << 0 << input.rect() << QRegion() << false;
QRegion r;
// Scroll whole pixmap
r = QRegion(); r += QRect(0, 0, 128, 10);
QTest::newRow("dx_0_dy_10_x_y_w_h") << input << 0 << 10 << input.rect() << r << true;
r = QRegion(); r += QRect(0, 0, 10, 128);
QTest::newRow("dx_10_dy_0_x_y_w_h") << input << 10 << 0 << input.rect() << r << true;
r = QRegion(); r += QRect(0, 0, 128, 10); r += QRect(0, 10, 10, 118);
QTest::newRow("dx_10_dy_10_x_y_w_h") << input << 10 << 10 << input.rect() << r << true;
r = QRegion(); r += QRect(118, 0, 10, 128);
QTest::newRow("dx_-10_dy_0_x_y_w_h") << input << -10 << 0 << input.rect() << r << true;
r = QRegion(); r += QRect(0, 118, 128, 10);
QTest::newRow("dx_0_dy_-10_x_y_w_h") << input << 0 << -10 << input.rect() << r << true;
r = QRegion(); r += QRect(118, 0, 10, 118); r += QRect(0, 118, 128, 10);
QTest::newRow("dx_-10_dy_-10_x_y_w_h") << input << -10 << -10 << input.rect() << r << true;
// Scroll part of pixmap
QTest::newRow("dx_0_dy_0_50_50_100_100") << input << 0 << 0 << QRect(50, 50, 100, 100) << QRegion() << false;
r = QRegion(); r += QRect(50, 50, 10, 78);
QTest::newRow("dx_10_dy_0_50_50_100_100") << input << 10 << 0 << QRect(50, 50, 100, 100) << r << true;
r = QRegion(); r += QRect(50, 50, 78, 10);
QTest::newRow("dx_0_dy_10_50_50_100_100") << input << 0 << 10 << QRect(50, 50, 100, 100) << r << true;
r = QRegion(); r += QRect(50, 50, 78, 10); r += QRect(50, 60, 10, 68);
QTest::newRow("dx_10_dy_10_50_50_100_100") << input << 10 << 10 << QRect(50, 50, 100, 100) << r << true;
r = QRegion(); r += QRect(118, 50, 10, 78);
QTest::newRow("dx_-10_dy_0_50_50_100_100") << input << -10 << 0 << QRect(50, 50, 100, 100) << r << true;
r = QRegion(); r += QRect(50, 118, 78, 10);
QTest::newRow("dx_0_dy_-10_50_50_100_100") << input << 0 << -10 << QRect(50, 50, 100, 100) << r << true;
r = QRegion(); r += QRect(118, 50, 10, 68); r += QRect(50, 118, 78, 10);
QTest::newRow("dx_-10_dy_-10_50_50_100_100") << input << -10 << -10 << QRect(50, 50, 100, 100) << r << true;
// Scroll away the whole pixmap
r = input.rect();
QTest::newRow("dx_128_dy_0_x_y_w_h") << input << 128 << 0 << input.rect() << r << false;
QTest::newRow("dx_0_dy_128_x_y_w_h") << input << 0 << 128 << input.rect() << r << false;
QTest::newRow("dx_128_dy_128_x_y_w_h") << input << 128 << 128 << input.rect() << r << false;
QTest::newRow("dx_-128_dy_0_x_y_w_h") << input << -128 << 0 << input.rect() << r << false;
QTest::newRow("dx_0_dy_-128_x_y_w_h") << input << 0 << -128 << input.rect() << r << false;
QTest::newRow("dx_-128_dy_-128_x_y_w_h") << input << -128 << -128 << input.rect() << r << false;
// Scroll away part of the pixmap
r = QRegion(); r += QRect(64, 64, 64, 64);
QTest::newRow("dx_128_dy_128_64_64_128_128") << input << 128 << 128 << QRect(64, 64, 128, 128) << r << false;
}
void tst_QPixmap::scroll()
{
QFETCH(QImage, input);
QFETCH(int, dx);
QFETCH(int, dy);
QFETCH(QRect, rect);
QFETCH(QRegion, exposed);
QFETCH(bool, newPix);
QPixmap pixmap = QPixmap::fromImage(input);
QRegion exp;
qint64 oldKey = pixmap.cacheKey();
pixmap.scroll(dx, dy, rect, &exp);
if (!newPix)
QCOMPARE(pixmap.cacheKey(), oldKey);
else
QVERIFY(pixmap.cacheKey() != oldKey);
const QString fileName = QLatin1String(":/images/") + QLatin1String(QTest::currentDataTag())
+ QLatin1String(".png");
QPixmap output(fileName);
QCOMPARE(input.isNull(), output.isNull());
QVERIFY(lenientCompare(pixmap, output));
QCOMPARE(exp, exposed);
}
void tst_QPixmap::fill_data()
{
QTest::addColumn<uint>("pixel");
QTest::addColumn<bool>("syscolor");
QTest::addColumn<bool>("bitmap");
for (int color = Qt::black; color < Qt::darkYellow; ++color)
QTest::newRow(("syscolor_" + QByteArray::number(color)).constData())
<< uint(color) << true << false;
QPixmap pixmap(1, 1);
QTest::newRow("alpha_7f_red") << 0x7fff0000u << false << false;
QTest::newRow("alpha_3f_blue") << 0x3f0000ffu << false << false;
QTest::newRow("alpha_b7_green") << 0xbf00ff00u << false << false;
QTest::newRow("alpha_7f_white") << 0x7fffffffu << false << false;
QTest::newRow("alpha_3f_white") << 0x3fffffffu << false << false;
QTest::newRow("alpha_b7_white") << 0xb7ffffffu << false << false;
QTest::newRow("alpha_7f_black") << 0x7f000000u << false << false;
QTest::newRow("alpha_3f_black") << 0x3f000000u << false << false;
QTest::newRow("alpha_b7_black") << 0xbf000000u << false << false;
QTest::newRow("bitmap_color0") << uint(Qt::color0) << true << true;
QTest::newRow("bitmap_color1") << uint(Qt::color1) << true << true;
}
void tst_QPixmap::fill()
{
QFETCH(uint, pixel);
QFETCH(bool, syscolor);
QFETCH(bool, bitmap);
QColor color;
if (syscolor)
color = QColor(Qt::GlobalColor(pixel));
else
color = QColor(qRed(pixel), qGreen(pixel), qBlue(pixel), qAlpha(pixel));
QColor compareColor = color;
if (bitmap && syscolor) {
// special case color0 and color1 for bitmaps.
if (pixel == Qt::color0)
compareColor.setRgb(255, 255, 255);
else
compareColor.setRgb(0, 0, 0);
}
QPixmap pm;
if (bitmap)
pm = QBitmap(400, 400);
else
pm = QPixmap(400, 400);
pm.fill(color);
if (syscolor && !bitmap && pm.depth() < 24) {
QSKIP("Test does not work on displays without true color");
}
QImage image = pm.toImage();
if (bitmap && syscolor) {
int pixelindex = (pixel == Qt::color0) ? 0 : 1;
QCOMPARE(image.pixelIndex(0,0), pixelindex);
}
QImage::Format format = compareColor.alpha() != 255
? QImage::Format_ARGB32
: QImage::Format_RGB32;
image = image.convertToFormat(format);
QImage shouldBe(400, 400, format);
shouldBe.fill(compareColor.rgba());
QCOMPARE(image, shouldBe);
}
void tst_QPixmap::fill_transparent()
{
QPixmap pixmap(10, 10);
pixmap.fill(Qt::transparent);
QVERIFY(pixmap.hasAlphaChannel());
}
void tst_QPixmap::mask()
{
QPixmap pm(100, 100);
QBitmap bm(100, 100);
pm.fill();
bm.fill();
QVERIFY(!pm.isNull());
QVERIFY(!bm.isNull());
if (!pm.hasAlphaChannel()) {
// This would fail if the default pixmap format is
// argb32_premultiplied. The mask will be all 1's.
// Therefore this is skipped when the alpha channel is present.
QVERIFY(pm.mask().isNull());
}
QImage img = bm.toImage();
QVERIFY(img.format() == QImage::Format_MonoLSB
|| img.format() == QImage::Format_Mono);
pm.setMask(bm);
QVERIFY(!pm.mask().isNull());
bm = QBitmap();
// Invalid format here, since isNull() == true
QVERIFY(bm.toImage().isNull());
QCOMPARE(bm.toImage().format(), QImage::Format_Invalid);
pm.setMask(bm);
QVERIFY(pm.mask().isNull());
bm = QBitmap(100, 100);
bm.fill();
pm.setMask(bm);
QVERIFY(!pm.mask().isNull());
}
void tst_QPixmap::bitmapMask()
{
QImage image(3, 3, QImage::Format_Mono);
image.setColor(0, Qt::color0);
image.setColor(1, Qt::color1);
image.fill(Qt::color0);
image.setPixel(1, 1, Qt::color1);
image.setPixel(0, 0, Qt::color1);
QImage image_mask(3, 3, QImage::Format_Mono);
image_mask.setColor(0, Qt::color0);
image_mask.setColor(1, Qt::color1);
image_mask.fill(Qt::color0);
image_mask.setPixel(1, 1, Qt::color1);
image_mask.setPixel(2, 0, Qt::color1);
QBitmap pm = QBitmap::fromImage(image);
QBitmap pm_mask = QBitmap::fromImage(image_mask);
pm.setMask(pm_mask);
image = pm.toImage();
image.setColor(0, Qt::color0);
image.setColor(1, Qt::color1);
image_mask = pm_mask.toImage();
image_mask.setColor(0, Qt::color0);
image_mask.setColor(1, Qt::color1);
QVERIFY(!image.pixel(0, 0));
QVERIFY(!image.pixel(2, 0));
QVERIFY(image.pixel(1, 1));
}
void tst_QPixmap::bitmapFromImageRvalue()
{
auto makeImage = [](){
QImage image(3, 3, QImage::Format_MonoLSB);
image.setColor(0, Qt::color0);
image.setColor(1, Qt::color1);
image.fill(Qt::color0);
image.setPixel(1, 1, Qt::color1);
image.setPixel(0, 0, Qt::color1);
return image;
};
auto image1 = makeImage();
auto image2 = makeImage();
auto bitmap1 = QBitmap::fromImage(image1);
auto bitmap2 = QBitmap::fromImage(std::move(image2));
QCOMPARE(bitmap1.toImage(), bitmap2.toImage());
QVERIFY(!image1.isNull());
QVERIFY(image2.isNull());
}
void tst_QPixmap::setGetMask_data()
{
QTest::addColumn<QPixmap>("pixmap");
QTest::addColumn<QBitmap>("mask");
QTest::addColumn<QBitmap>("expected");
QPixmap pixmap(10, 10);
QBitmap mask(10, 10);
QPainter p;
p.begin(&pixmap);
p.fillRect(0, 0, 10, 10, QColor(Qt::black));
p.end();
QTest::newRow("nullmask 0") << QPixmap() << QBitmap() << QBitmap();
QTest::newRow("nullmask 1") << pixmap << QBitmap() << QBitmap();
mask.clear();
QTest::newRow("nullmask 2") << pixmap << mask << mask;
QTest::newRow("nullmask 3") << QPixmap(QBitmap()) << QBitmap() << QBitmap();
p.begin(&mask);
p.fillRect(1, 1, 5, 5, QColor(Qt::color1));
p.end();
QTest::newRow("simple mask 0") << pixmap << mask << mask;
}
void tst_QPixmap::setGetMask()
{
QFETCH(QPixmap, pixmap);
QFETCH(QBitmap, mask);
QFETCH(QBitmap, expected);
pixmap.setMask(mask);
QBitmap result = pixmap.mask();
QImage resultImage = result.toImage();
QImage expectedImage = expected.toImage();
QCOMPARE(resultImage.convertToFormat(expectedImage.format()),
expectedImage);
}
void tst_QPixmap::testMetrics()
{
QPixmap pixmap(100, 100);
QCOMPARE(pixmap.width(), 100);
QCOMPARE(pixmap.height(), 100);
QVERIFY(pixmap.depth() >= QPixmap::defaultDepth());
QBitmap bitmap(100, 100);
QCOMPARE(bitmap.width(), 100);
QCOMPARE(bitmap.height(), 100);
QCOMPARE(bitmap.depth(), 1);
QPixmap null;
QCOMPARE(null.size().width(), null.width());
QCOMPARE(null.size().height(), null.height());
}
void tst_QPixmap::createMaskFromColor()
{
QImage image(3, 3, QImage::Format_Indexed8);
image.setColorCount(10);
image.setColor(0, 0xffffffff);
image.setColor(1, 0xff000000);
image.setColor(2, 0xffff0000);
image.setColor(3, 0xff0000ff);
image.fill(0);
image.setPixel(1, 0, 1);
image.setPixel(0, 1, 2);
image.setPixel(1, 1, 3);
QImage im_mask = image.createMaskFromColor(0xffff0000);
QCOMPARE((uint) im_mask.pixel(0, 1), QColor(Qt::color0).rgba());
QCOMPARE((uint) im_mask.pixel(0, 1), QColor(Qt::color0).rgba());
QPixmap pixmap = QPixmap::fromImage(image);
QBitmap mask = pixmap.createMaskFromColor(Qt::red);
QBitmap inv_mask = pixmap.createMaskFromColor(Qt::red, Qt::MaskOutColor);
QCOMPARE((uint) mask.toImage().pixel(0, 1), QColor(Qt::color0).rgba());
QCOMPARE((uint) inv_mask.toImage().pixel(0, 1), QColor(Qt::color1).rgba());
}
void tst_QPixmap::cacheKey()
{
QPixmap pixmap1(1, 1);
QPixmap pixmap2(1, 1);
qint64 pixmap1_key = pixmap1.cacheKey();
QVERIFY(pixmap1.cacheKey() != pixmap2.cacheKey());
pixmap2 = pixmap1;
QCOMPARE(pixmap2.cacheKey(), pixmap1.cacheKey());
pixmap2.detach();
QVERIFY(pixmap2.cacheKey() != pixmap1.cacheKey());
QCOMPARE(pixmap1.cacheKey(), pixmap1_key);
}
// Test drawing a bitmap on a pixmap.
void tst_QPixmap::drawBitmap()
{
QBitmap bitmap(10,10);
bitmap.fill(Qt::color1);
QPixmap pixmap(10,10);
QPainter painter2(&pixmap);
painter2.fillRect(0,0,10,10, QBrush(Qt::green));
painter2.setPen(Qt::red);
painter2.drawPixmap(0,0,10,10, bitmap);
painter2.end();
QPixmap expected(10, 10);
expected.fill(Qt::red);
QVERIFY(lenientCompare(pixmap, expected));
}
void tst_QPixmap::isNull()
{
{
QPixmap pixmap(1,1);
QVERIFY(!pixmap.isNull());
}
{
QPixmap pixmap(0,0);
QVERIFY(pixmap.isNull());
}
{
QPixmap pixmap(0,1);
QVERIFY(pixmap.isNull());
}
{
QPixmap pixmap(1,0);
QVERIFY(pixmap.isNull());
}
{
QPixmap pixmap(-1,-1);
QVERIFY(pixmap.isNull());
}
{
QPixmap pixmap(-1,5);
QVERIFY(pixmap.isNull());
}
}
void tst_QPixmap::convertFromImageNoDetach()
{
QPixmap randomPixmap(10, 10);
if (randomPixmap.handle()->classId() != QPlatformPixmap::RasterClass)
QSKIP("Test only valid for raster pixmaps");
//first get the screen format
QImage::Format screenFormat = randomPixmap.toImage().format();
QVERIFY(screenFormat != QImage::Format_Invalid);
QImage orig(100,100, screenFormat);
QPixmap pix = QPixmap::fromImage(orig);
QImage copy = pix.toImage();
QCOMPARE(copy.format(), screenFormat);
const QImage constOrig = orig;
const QImage constCopy = copy;
QCOMPARE(constOrig.bits(), constCopy.bits());
}
void tst_QPixmap::convertFromImageNoDetach2()
{
QPixmap randomPixmap(10, 10);
if (randomPixmap.handle()->classId() != QPlatformPixmap::RasterClass)
QSKIP("Test only valid for raster pixmaps");
//first get the screen format
QImage::Format screenFormat = randomPixmap.toImage().format();
QVERIFY(screenFormat != QImage::Format_Invalid);
if (screenFormat != QImage::Format_RGB32 &&
screenFormat != QImage::Format_ARGB32_Premultiplied)
QSKIP("Test only valid for platforms with RGB32 pixmaps");
QImage orig(100,100, QImage::Format_ARGB32_Premultiplied);
orig.fill(Qt::white);
const uchar *origBits = orig.constBits();
QPixmap pix = QPixmap::fromImage(std::move(orig));
QImage copy = pix.toImage();
QVERIFY(!copy.hasAlphaChannel());
QCOMPARE(copy.format(), QImage::Format_RGB32);
QCOMPARE(origBits, copy.constBits());
}
void tst_QPixmap::convertFromImageDetach()
{
QImage img(10,10, QImage::Format_RGB32);
img.fill(0);
QVERIFY(!img.isNull());
QPixmap p = QPixmap::fromImage(img);
QVERIFY(p.isDetached());
QPixmap copy = p;
QVERIFY(!copy.isDetached());
QVERIFY(!p.isDetached());
img.fill(1);
p = QPixmap::fromImage(img);
QVERIFY(copy.isDetached());
}
void tst_QPixmap::convertFromImageCacheKey()
{
QPixmap randomPixmap(10, 10);
if (randomPixmap.handle()->classId() != QPlatformPixmap::RasterClass)
QSKIP("Test only valid for raster pixmaps");
//first get the screen format
QImage::Format screenFormat = randomPixmap.toImage().format();
QVERIFY(screenFormat != QImage::Format_Invalid);
QImage orig(100,100, screenFormat);
orig.fill(0);
QPixmap pix = QPixmap::fromImage(orig);
QImage copy = pix.toImage();
QCOMPARE(copy.format(), screenFormat);
QCOMPARE(orig.cacheKey(), pix.cacheKey());
QCOMPARE(copy.cacheKey(), pix.cacheKey());
}
#if defined(Q_OS_WIN)
QT_BEGIN_NAMESPACE
Q_GUI_EXPORT HBITMAP qt_createIconMask(const QBitmap &bitmap);
Q_GUI_EXPORT HBITMAP qt_pixmapToWinHBITMAP(const QPixmap &p, int hbitmapFormat = 0);
Q_GUI_EXPORT QPixmap qt_pixmapFromWinHBITMAP(HBITMAP bitmap, int hbitmapFormat = 0);
Q_GUI_EXPORT HICON qt_pixmapToWinHICON(const QPixmap &p);
Q_GUI_EXPORT QImage qt_imageFromWinHBITMAP(HDC hdc, HBITMAP bitmap, int w, int h);
Q_GUI_EXPORT QPixmap qt_pixmapFromWinHICON(HICON icon);
QT_END_NAMESPACE
void tst_QPixmap::toWinHBITMAP_data()
{
QTest::addColumn<int>("red");
QTest::addColumn<int>("green");
QTest::addColumn<int>("blue");
QTest::newRow("red") << 255 << 0 << 0;
QTest::newRow("green") << 0 << 255 << 0;
QTest::newRow("blue") << 0 << 0 << 255;
}
void tst_QPixmap::toWinHBITMAP()
{
QFETCH(int, red);
QFETCH(int, green);
QFETCH(int, blue);
QPixmap pm(100, 100);
pm.fill(QColor(red, green, blue));
HBITMAP bitmap = qt_pixmapToWinHBITMAP(pm);
QVERIFY(bitmap != 0);
// Verify size
BITMAP bitmap_info;
memset(&bitmap_info, 0, sizeof(BITMAP));
int res = GetObject(bitmap, sizeof(BITMAP), &bitmap_info);
QVERIFY(res);
QCOMPARE(100, (int) bitmap_info.bmWidth);
QCOMPARE(100, (int) bitmap_info.bmHeight);
HDC display_dc = GetDC(0);
HDC bitmap_dc = CreateCompatibleDC(display_dc);
HBITMAP null_bitmap = (HBITMAP) SelectObject(bitmap_dc, bitmap);
COLORREF pixel = GetPixel(bitmap_dc, 0, 0);
QCOMPARE((int)GetRValue(pixel), red);
QCOMPARE((int)GetGValue(pixel), green);
QCOMPARE((int)GetBValue(pixel), blue);
// Clean up
SelectObject(bitmap_dc, null_bitmap);
DeleteObject(bitmap);
DeleteDC(bitmap_dc);
ReleaseDC(0, display_dc);
}
void tst_QPixmap::fromWinHBITMAP_data()
{
toWinHBITMAP_data();
}
void tst_QPixmap::fromWinHBITMAP()
{
QFETCH(int, red);
QFETCH(int, green);
QFETCH(int, blue);
HDC display_dc = GetDC(0);
HDC bitmap_dc = CreateCompatibleDC(display_dc);
HBITMAP bitmap = CreateCompatibleBitmap(display_dc, 100, 100);
SelectObject(bitmap_dc, bitmap);
SelectObject(bitmap_dc, GetStockObject(NULL_PEN));
HGDIOBJ old_brush = SelectObject(bitmap_dc, CreateSolidBrush(RGB(red, green, blue)));
Rectangle(bitmap_dc, 0, 0, 100, 100);
QPixmap pixmap = qt_pixmapFromWinHBITMAP(bitmap);
QCOMPARE(pixmap.width(), 100);
QCOMPARE(pixmap.height(), 100);
QImage image = pixmap.toImage();
QRgb pixel = image.pixel(0, 0);
QCOMPARE(qRed(pixel), red);
QCOMPARE(qGreen(pixel), green);
QCOMPARE(qBlue(pixel), blue);
DeleteObject(SelectObject(bitmap_dc, old_brush));
DeleteObject(SelectObject(bitmap_dc, bitmap));
DeleteDC(bitmap_dc);
ReleaseDC(0, display_dc);
}
static bool compareImages(const QImage &actualImage, const QImage &expectedImage)
{
if (actualImage.width() != expectedImage.width()
|| actualImage.height() != expectedImage.height()) {
qWarning("Image size comparison failed: expected: %dx%d, got %dx%d",
expectedImage.size().width(), expectedImage.size().height(),
actualImage.size().width(), actualImage.size().height());
return false;
}
if (actualImage.format() != expectedImage.format()) {
qWarning("Image format comparison failed: expected: %d, got %d",
expectedImage.format(), actualImage.format());
return false;
}
static const int fuzz = 1;
for (int y = 0; y < actualImage.height(); ++y) {
for (int x = 0; x < expectedImage.width(); ++x) {
const QRgb p1 = actualImage.pixel(x, y);
const QRgb p2 = expectedImage.pixel(x, y);
if (qAbs(qRed(p1) - qRed(p2)) > fuzz
|| qAbs(qGreen(p1) - qGreen(p2)) > fuzz
|| qAbs(qBlue(p1) - qBlue(p2)) > fuzz
|| qAbs(qAlpha(p1) - qAlpha(p2)) > fuzz) {
qWarning("Color mismatch at pixel %d,%d: Expected: 0x%x. got 0x%x",
x, y, p2, p1);
return false;
}
}
}
return true;
}
void tst_QPixmap::toWinHICON_data()
{
QTest::addColumn<QString>("image");
QTest::addColumn<int>("width");
QTest::addColumn<int>("height");
const QString prefix = QFINDTESTDATA("convertFromToHICON");
QTest::newRow("32bpp_16x16") << prefix + QLatin1String("/icon_32bpp") << 16 << 16;
QTest::newRow("32bpp_32x32") << prefix + QLatin1String("/icon_32bpp") << 32 << 32;
QTest::newRow("32bpp_48x48") << prefix + QLatin1String("/icon_32bpp") << 48 << 48;
QTest::newRow("32bpp_256x256") << prefix + QLatin1String("/icon_32bpp") << 256 << 256;
QTest::newRow("8bpp_16x16") << prefix + QLatin1String("/icon_8bpp") << 16 << 16;
QTest::newRow("8bpp_32x32") << prefix + QLatin1String("/icon_8bpp") << 32 << 32;
QTest::newRow("8bpp_48x48") << prefix + QLatin1String("/icon_8bpp") << 48 << 48;
}
void tst_QPixmap::toWinHICON()
{
enum { Alpha = 2 };
QFETCH(int, width);
QFETCH(int, height);
QFETCH(QString, image);
QPixmap empty(width, height);
empty.fill(Qt::transparent);
HDC display_dc = GetDC(0);
HDC bitmap_dc = CreateCompatibleDC(display_dc);
HBITMAP bitmap = qt_pixmapToWinHBITMAP(empty, Alpha);
SelectObject(bitmap_dc, bitmap);
const QString fileName = image + QLatin1Char('_') + QString::number(width) + QLatin1Char('x')
+ QString::number(height) + QLatin1String(".png");
QImage imageFromFile(fileName);
imageFromFile = imageFromFile.convertToFormat(QImage::Format_ARGB32_Premultiplied);
HICON icon = qt_pixmapToWinHICON(QPixmap::fromImage(imageFromFile));
DrawIconEx(bitmap_dc, 0, 0, icon, width, height, 0, 0, DI_NORMAL);
DestroyIcon(icon);
DeleteDC(bitmap_dc);
QImage imageFromHICON = qt_pixmapFromWinHBITMAP(bitmap, Alpha).toImage();
ReleaseDC(0, display_dc);
// fuzzy comparison must be used, as the pixel values change slightly during conversion
// between QImage::Format_ARGB32 and QImage::Format_ARGB32_Premultiplied, or elsewhere
QVERIFY(compareImages(imageFromHICON, imageFromFile));
}
void tst_QPixmap::fromWinHICON_data()
{
toWinHICON_data();
}
void tst_QPixmap::fromWinHICON()
{
QFETCH(int, width);
QFETCH(int, height);
QFETCH(QString, image);
HICON icon = (HICON)LoadImage(0, (wchar_t*)(image + QLatin1String(".ico")).utf16(), IMAGE_ICON, width, height, LR_LOADFROMFILE);
QImage imageFromHICON = qt_pixmapFromWinHICON(icon).toImage();
DestroyIcon(icon);
const QString fileName = image + QLatin1Char('_') + QString::number(width) + QLatin1Char('x')
+ QString::number(height) + QLatin1String(".png");
QImage imageFromFile(fileName);
imageFromFile = imageFromFile.convertToFormat(QImage::Format_ARGB32_Premultiplied);
// fuzzy comparison must be used, as the pixel values change slightly during conversion
// between QImage::Format_ARGB32 and QImage::Format_ARGB32_Premultiplied, or elsewhere
QVERIFY(compareImages(imageFromHICON, imageFromFile));
}
#endif // Q_OS_WIN
void tst_QPixmap::onlyNullPixmapsOutsideGuiThread()
{
class Thread : public QThread
{
public:
void run() override
{
QTest::ignoreMessage(QtWarningMsg,
"QPixmap: It is not safe to use pixmaps outside the GUI thread");
QPixmap pixmap;
QVERIFY(pixmap.isNull());
QTest::ignoreMessage(QtWarningMsg,
"QPixmap: It is not safe to use pixmaps outside the GUI thread");
QPixmap pixmap1(100, 100);
QVERIFY(pixmap1.isNull());
QTest::ignoreMessage(QtWarningMsg,
"QPixmap: It is not safe to use pixmaps outside the GUI thread");
QPixmap pixmap2(pixmap1);
QVERIFY(pixmap2.isNull());
}
};
if (QGuiApplicationPrivate::platform_integration->hasCapability(QPlatformIntegration::ThreadedPixmaps))
QSKIP("This platform supports threaded pixmaps.");
Thread thread;
thread.start();
thread.wait();
}
void tst_QPixmap::refUnref()
{
// Simple ref/unref
{
QPixmap p;
}
{
QBitmap b;
}
// Get a copy of a pixmap that goes out of scope
{
QPixmap b;
{
QPixmap a(10, 10);
a.fill(Qt::color0);
b = a;
}
}
{
QBitmap mask;
{
QBitmap bitmap(10, 10);
bitmap.fill(Qt::color1);
mask = bitmap.mask();
}
mask.fill(Qt::color0);
}
}
void tst_QPixmap::copy()
{
QPixmap src(32, 32);
{
QPainter p(&src);
p.fillRect(0, 0, 32, 32, Qt::red);
p.fillRect(10, 10, 10, 10, Qt::blue);
}
QPixmap dest = src.copy(10, 10, 10, 10);
QPixmap expected(10, 10);
expected.fill(Qt::blue);
QVERIFY(lenientCompare(dest, expected));
QPixmap trans;
trans.fill(Qt::transparent);
QPixmap transCopy = trans.copy();
QCOMPARE(trans, transCopy);
}
void tst_QPixmap::move()
{
QPixmap moveFrom(32, 32);
QPixmap moveAssigned;
moveAssigned = std::move(moveFrom);
QVERIFY(!moveAssigned.isNull());
QVERIFY(moveFrom.isNull());
QPixmap moveConstructed(std::move(moveAssigned));
QVERIFY(moveAssigned.isNull());
QVERIFY(!moveConstructed.isNull());
}
// QTBUG-58653: Force a deep copy of a pixmap by
// having a QPainter and check whether DevicePixelRatio is preserved
void tst_QPixmap::deepCopyPreservesDpr()
{
const qreal dpr = 2;
QPixmap src(32, 32);
src.setDevicePixelRatio(dpr);
src.fill(Qt::red);
QPainter painter(&src);
const QPixmap dest = src.copy();
QCOMPARE(dest.devicePixelRatio(), dpr);
}
void tst_QPixmap::dprPassthrough()
{
const qreal dpr = 2;
QPixmap src(32, 32);
src.setDevicePixelRatio(dpr);
src.fill(Qt::transparent);
QCOMPARE(src.devicePixelRatio(), dpr);
QImage img = src.toImage();
QCOMPARE(img.devicePixelRatio(), dpr);
QPixmap pm(1, 1);
pm.convertFromImage(img);
QCOMPARE(pm.devicePixelRatio(), dpr);
QBitmap heuristicMask = src.createHeuristicMask();
QCOMPARE(heuristicMask.devicePixelRatio(), dpr);
QBitmap maskFromColor = src.createMaskFromColor(Qt::white);
QCOMPARE(maskFromColor.devicePixelRatio(), dpr);
QBitmap mask = src.mask();
QCOMPARE(mask.devicePixelRatio(), dpr);
QPixmap scaled = src.scaled(16, 16);
QCOMPARE(scaled.devicePixelRatio(), dpr);
QTransform t;
t.rotate(90);
QPixmap transformed = src.transformed(t);
QCOMPARE(transformed.devicePixelRatio(), dpr);
}
void tst_QPixmap::depthOfNullObjects()
{
QBitmap b1;
QCOMPARE(b1.depth(), 0);
QPixmap p4;
QCOMPARE(p4.depth(), 0);
}
void tst_QPixmap::transformed()
{
QPixmap p1(20, 10);
p1.fill(Qt::red);
{
QPainter p(&p1);
p.drawRect(0, 0, p1.width() - 1, p1.height() - 1);
}
QPixmap p2(10, 20);
{
QPainter p(&p2);
p.rotate(90);
p.drawPixmap(0, -p1.height(), p1);
}
QPixmap p3(20, 10);
{
QPainter p(&p3);
p.rotate(180);
p.drawPixmap(-p1.width(), -p1.height(), p1);
}
QPixmap p4(10, 20);
{
QPainter p(&p4);
p.rotate(270);
p.drawPixmap(-p1.width(), 0, p1);
}
QPixmap p1_90 = p1.transformed(QTransform().rotate(90));
QPixmap p1_180 = p1.transformed(QTransform().rotate(180));
QPixmap p1_270 = p1.transformed(QTransform().rotate(270));
QVERIFY(lenientCompare(p1_90, p2));
QVERIFY(lenientCompare(p1_180, p3));
QVERIFY(lenientCompare(p1_270, p4));
}
void tst_QPixmap::transformed2()
{
QPixmap pm(3, 3);
pm.fill(Qt::red);
QPainter p(&pm);
p.fillRect(0, 0, 3, 3, QBrush(Qt::Dense4Pattern));
p.end();
QTransform transform;
transform.rotate(-90);
transform.scale(3, 3);
QPixmap actual = pm.transformed(transform);
QPixmap expected(9, 9);
expected.fill(Qt::red);
p.begin(&expected);
p.setBrush(Qt::black);
p.setPen(Qt::NoPen);
p.drawRect(3, 0, 3, 3);
p.drawRect(0, 3, 3, 3);
p.drawRect(6, 3, 3, 3);
p.drawRect(3, 6, 3, 3);
p.end();
QVERIFY(lenientCompare(actual, expected));
}
void tst_QPixmap::load()
{
const QString filePath = m_prefix + QLatin1String("designer.png");
QPixmap dest(filePath);
QVERIFY(!dest.isNull());
QVERIFY(!dest.load("image_that_does_not_exist.png"));
QVERIFY(dest.isNull());
QVERIFY(dest.load(filePath));
QVERIFY(!dest.isNull());
}
void tst_QPixmap::loadFromData()
{
const QString filePath = m_prefix + QLatin1String("designer.png");
QPixmap original(filePath);
QVERIFY(!original.isNull());
QByteArray ba;
{
QBuffer buf(&ba);
QVERIFY(buf.open(QIODevice::WriteOnly));
QVERIFY(original.save(&buf, "BMP"));
}
QVERIFY(!ba.isEmpty());
QPixmap dest;
QVERIFY(dest.loadFromData(ba, "BMP"));
QVERIFY(!dest.isNull());
QCOMPARE(original, dest);
QVERIFY(!dest.loadFromData(QByteArray()));
QVERIFY(dest.isNull());
}
#if !defined(QT_NO_DATASTREAM)
void tst_QPixmap::loadFromDataStream()
{
const QString filePath = m_prefix + QLatin1String("designer.png");
QPixmap original(filePath);
QVERIFY(!original.isNull());
QByteArray ba;
{
QDataStream s(&ba, QIODevice::WriteOnly);
s << original;
}
QVERIFY(!ba.isEmpty());
QPixmap dest;
{
QDataStream s(&ba, QIODevice::ReadOnly);
s >> dest;
}
QVERIFY(!dest.isNull());
QCOMPARE(original, dest);
{
ba.clear();
QDataStream s(&ba, QIODevice::ReadOnly);
s >> dest;
}
QVERIFY(dest.isNull());
}
#endif // QT_NO_DATASTREAM
void tst_QPixmap::fromImage_crash()
{
QImage *img = new QImage(64, 64, QImage::Format_ARGB32_Premultiplied);
QPixmap pm = QPixmap::fromImage(*img);
QPainter painter(&pm);
delete img;
}
#ifndef QT_NO_WIDGETS
//This is testing QPlatformPixmap::createCompatiblePlatformPixmap - see QTBUG-5977
void tst_QPixmap::splash_crash()
{
QPixmap pix;
pix = QPixmap(":/images/designer.png");
QSplashScreen splash(pix);
splash.show();
QCoreApplication::processEvents();
splash.close();
}
#endif
void tst_QPixmap::fromData()
{
unsigned char bits[] = { 0xaa, 0x55 };
QBitmap bm = QBitmap::fromData(QSize(8, 2), bits);
QImage img = bm.toImage();
QSet<QRgb> colors;
for (int y = 0; y < img.height(); ++y)
for (int x = 0; x < img.width(); ++x)
colors << img.pixel(x, y);
QCOMPARE(colors.size(), 2);
QCOMPARE(img.pixel(0, 0), QRgb(0xffffffff));
QCOMPARE(img.pixel(0, 1), QRgb(0xff000000));
}
void tst_QPixmap::loadFromDataNullValues()
{
{
QPixmap pixmap;
pixmap.loadFromData(QByteArray());
QVERIFY(pixmap.isNull());
}
{
QPixmap pixmap;
pixmap.loadFromData(0, 123);
QVERIFY(pixmap.isNull());
}
{
QPixmap pixmap;
const uchar bla[] = "bla";
pixmap.loadFromData(bla, 0);
QVERIFY(pixmap.isNull());
}
}
void tst_QPixmap::loadFromDataImage_data()
{
QTest::addColumn<QString>("imagePath");
QTest::newRow("designer_argb32.png") << m_loadFromData + "/designer_argb32.png";
// When no extension is provided we try all extensions that has been registered by image providers
QTest::newRow("designer_argb32") << m_loadFromData + "/designer_argb32.png";
QTest::newRow("designer_indexed8_no_alpha.png") << m_loadFromData + "/designer_indexed8_no_alpha.png";
QTest::newRow("designer_indexed8_with_alpha.png") << m_loadFromData + "/designer_indexed8_with_alpha.png";
QTest::newRow("designer_rgb32.png") << m_loadFromData + "/designer_rgb32.png";
QTest::newRow("designer_indexed8_no_alpha.gif") << m_loadFromData + "/designer_indexed8_no_alpha.gif";
QTest::newRow("designer_indexed8_with_alpha.gif") << m_loadFromData + "/designer_indexed8_with_alpha.gif";
QTest::newRow("designer_rgb32.jpg") << m_loadFromData + "/designer_rgb32.jpg";
}
void tst_QPixmap::loadFromDataImage()
{
QFETCH(QString, imagePath);
QImage imageRef(imagePath);
QPixmap pixmapWithCopy = QPixmap::fromImage(imageRef);
QFile file(imagePath);
file.open(QIODevice::ReadOnly);
QByteArray rawData = file.readAll();
QPixmap directLoadingPixmap;
directLoadingPixmap.loadFromData(rawData);
QCOMPARE(pixmapWithCopy, directLoadingPixmap);
}
void tst_QPixmap::fromImageReader_data()
{
QTest::addColumn<QString>("imagePath");
QTest::newRow("designer_argb32.png") << m_loadFromData + "/designer_argb32.png";
QTest::newRow("designer_indexed8_no_alpha.png") << m_loadFromData + "/designer_indexed8_no_alpha.png";
QTest::newRow("designer_indexed8_with_alpha.png") << m_loadFromData + "/designer_indexed8_with_alpha.png";
QTest::newRow("designer_rgb32.png") << m_loadFromData + "/designer_rgb32.png";
QTest::newRow("designer_indexed8_no_alpha.gif") << m_loadFromData + "/designer_indexed8_no_alpha.gif";
QTest::newRow("designer_indexed8_with_alpha.gif") << m_loadFromData + "/designer_indexed8_with_alpha.gif";
QTest::newRow("designer_rgb32.jpg") << m_loadFromData + "/designer_rgb32.jpg";
QTest::newRow("designer_indexed8_with_alpha_animated") << m_loadFromData + "/designer_indexed8_with_alpha_animated.gif";
QTest::newRow("designer_indexed8_no_alpha_animated") << m_loadFromData + "/designer_indexed8_no_alpha_animated.gif";
}
void tst_QPixmap::fromImageReader()
{
QFETCH(QString, imagePath);
QImage imageRef(imagePath);
QPixmap pixmapWithCopy = QPixmap::fromImage(imageRef);
QImageReader imageReader(imagePath);
QPixmap directLoadingPixmap = QPixmap::fromImageReader(&imageReader);
QCOMPARE(pixmapWithCopy, directLoadingPixmap);
}
void tst_QPixmap::fromImageReaderAnimatedGif_data()
{
QTest::addColumn<QString>("imagePath");
QTest::newRow("gif with alpha") << QString::fromLatin1("/designer_indexed8_with_alpha_animated.gif");
QTest::newRow("gif without alpha") << QString::fromLatin1("/designer_indexed8_no_alpha_animated.gif");
}
void tst_QPixmap::fromImageReaderAnimatedGif()
{
QFETCH(QString, imagePath);
const QString path = m_loadFromData + imagePath;
QImageReader referenceReader(path);
QImageReader pixmapReader(path);
QVERIFY(referenceReader.canRead());
QVERIFY(referenceReader.imageCount() > 1);
for (int i = 0; i < referenceReader.imageCount(); ++i) {
QImage refImage = referenceReader.read();
QPixmap refPixmap = QPixmap::fromImage(refImage);
QPixmap directLoadingPixmap = QPixmap::fromImageReader(&pixmapReader);
QCOMPARE(refPixmap, directLoadingPixmap);
}
}
void tst_QPixmap::task_246446()
{
// This crashed without the bugfix in 246446
QPixmap pm(10, 10);
pm.fill(Qt::transparent); // force 32-bit depth
QBitmap bm;
pm.setMask(bm);
{
QPixmap pm2(pm);
}
QCOMPARE(pm.width(), 10);
QVERIFY(pm.mask().isNull());
}
void tst_QPixmap::task_51271()
{
QPixmap pm;
QBitmap bm;
QVERIFY(!pm.isQBitmap()); // Should not crash !
QVERIFY(bm.isQBitmap());
}
void tst_QPixmap::preserveDepth()
{
QPixmap target(64, 64);
target.fill(Qt::transparent);
QPixmap source(64, 64);
source.fill(Qt::white);
int depth = source.depth();
QPainter painter(&target);
painter.setBrush(source);
painter.drawRect(target.rect());
painter.end();
QCOMPARE(depth, source.depth());
}
void tst_QPixmap::loadAsBitmapOrPixmap()
{
QImage tmp(10, 10, QImage::Format_RGB32);
tmp.save(m_tempDir.path() + "/temp_image.png");
bool ok;
// Check that we can load the pixmap as a pixmap and that it then turns into a pixmap
QPixmap pixmap(m_tempDir.path() + "/temp_image.png");
QVERIFY(!pixmap.isNull());
QVERIFY(pixmap.depth() > 1);
QVERIFY(!pixmap.isQBitmap());
pixmap = QPixmap();
ok = pixmap.load(m_tempDir.path() + "/temp_image.png");
QVERIFY(ok);
QVERIFY(!pixmap.isNull());
QVERIFY(pixmap.depth() > 1);
QVERIFY(!pixmap.isQBitmap());
//now we can try to load it without an extension
pixmap = QPixmap();
ok = pixmap.load(m_tempDir.path() + "/temp_image");
QVERIFY(ok);
QVERIFY(!pixmap.isNull());
QVERIFY(pixmap.depth() > 1);
QVERIFY(!pixmap.isQBitmap());
// The do the same check for bitmaps..
QBitmap bitmap(m_tempDir.path() + "/temp_image.png");
QVERIFY(!bitmap.isNull());
QCOMPARE(bitmap.depth(), 1);
QVERIFY(bitmap.isQBitmap());
bitmap = QBitmap();
ok = bitmap.load(m_tempDir.path() + "/temp_image.png");
QVERIFY(ok);
QVERIFY(!bitmap.isNull());
QCOMPARE(bitmap.depth(), 1);
QVERIFY(bitmap.isQBitmap());
// check that a QBitmap stays a QBitmap even when loading fails:
ok = bitmap.load(QString());
QVERIFY(!ok);
QVERIFY(bitmap.isNull());
QVERIFY(bitmap.isQBitmap());
ok = bitmap.load("does not exist");
QVERIFY(!ok);
QVERIFY(bitmap.isNull());
QVERIFY(bitmap.isQBitmap());
ok = bitmap.load("does not exist.png");
QVERIFY(!ok);
QVERIFY(bitmap.isNull());
QVERIFY(bitmap.isQBitmap());
QTemporaryFile garbage;
QVERIFY(garbage.open());
const QString garbagePath = garbage.fileName();
garbage.write(reinterpret_cast<const char *>(&garbage), sizeof garbage);
garbage.close();
ok = bitmap.load(garbagePath);
QVERIFY(!ok);
QVERIFY(bitmap.isNull());
QVERIFY(bitmap.isQBitmap());
}
void tst_QPixmap::toImageDeepCopy()
{
QPixmap pixmap(64, 64);
pixmap.fill(Qt::white);
QPainter painter(&pixmap);
QImage first = pixmap.toImage();
painter.setBrush(Qt::black);
painter.drawEllipse(pixmap.rect());
QImage second = pixmap.toImage();
QVERIFY(first != second);
}
void tst_QPixmap::scaled_QTBUG19157()
{
QPixmap foo(5000, 1);
foo = foo.scaled(1024, 1024, Qt::KeepAspectRatio);
QVERIFY(!foo.isNull());
}
void tst_QPixmap::detachOnLoad_QTBUG29639()
{
QPixmap a;
a.load(m_convertFromImage + "/task31722_0/img1.png");
a.load(m_convertFromImage + "/task31722_0/img2.png");
QPixmap b;
b.load(m_convertFromImage + "/task31722_0/img1.png");
QVERIFY(a.toImage() != b.toImage());
}
void tst_QPixmap::copyOnNonAlignedBoundary()
{
QImage img(8, 2, QImage::Format_RGB16);
QPixmap pm1 = QPixmap::fromImage(img, Qt::NoFormatConversion);
QPixmap pm2 = pm1.copy(QRect(5, 0, 3, 2)); // When copying second line: 2 bytes too many are read which might cause an access violation.
}
// test pixmap devicePixelRatio setting and detaching
void tst_QPixmap::devicePixelRatio()
{
// create pixmap
QPixmap a(64, 64);
a.fill(Qt::white);
QCOMPARE(a.devicePixelRatio(), qreal(1.0));
QCOMPARE(a.isDetached(), true);
// copy pixmap
QPixmap b = a;
QCOMPARE(b.devicePixelRatio(), qreal(1.0));
QCOMPARE(a.isDetached(), false);
QCOMPARE(b.isDetached(), false);
// set devicePixelRatio to the current value: does not detach
a.setDevicePixelRatio(qreal(1.0));
QCOMPARE(a.isDetached(), false);
QCOMPARE(b.isDetached(), false);
// set devicePixelRatio to a new value: may detach (currently
// does, but we may want to avoid the data copy the future)
a.setDevicePixelRatio(qreal(2.0));
QCOMPARE(a.devicePixelRatio(), qreal(2.0));
QCOMPARE(b.devicePixelRatio(), qreal(1.0));
}
void tst_QPixmap::deviceIndependentSize() {
QPixmap a(64, 64);
a.fill(Qt::white);
a.setDevicePixelRatio(1.0);
QCOMPARE(a.deviceIndependentSize(), QSizeF(64, 64));
a.setDevicePixelRatio(2.0);
QCOMPARE(a.deviceIndependentSize(), QSizeF(32, 32));
}
QTEST_MAIN(tst_QPixmap)
#include "tst_qpixmap.moc"