/**************************************************************************** ** ** 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 #include #include #include #include #include #include class tst_QPixmap : public QObject { Q_OBJECT public: tst_QPixmap() : m_dataDirectory(QFINDTESTDATA("data")) {} private slots: void initTestCase(); void toHBITMAP_data(); void toHBITMAP(); void fromHBITMAP_data(); void fromHBITMAP(); void toHICON_data(); void toHICON(); void fromHICON_data(); void fromHICON(); void imageConversion(); private: const QString m_dataDirectory; }; void tst_QPixmap::initTestCase() { QVERIFY(!m_dataDirectory.isEmpty()); } void tst_QPixmap::toHBITMAP_data() { QTest::addColumn("red"); QTest::addColumn("green"); QTest::addColumn("blue"); QTest::newRow("red") << 255 << 0 << 0; QTest::newRow("green") << 0 << 255 << 0; QTest::newRow("blue") << 0 << 0 << 255; } void tst_QPixmap::toHBITMAP() { QFETCH(int, red); QFETCH(int, green); QFETCH(int, blue); QPixmap pm(100, 100); pm.fill(QColor(red, green, blue)); const HBITMAP bitmap = QtWin::toHBITMAP(pm); QVERIFY(bitmap != nullptr); // Verify size BITMAP bitmapInfo; memset(&bitmapInfo, 0, sizeof(BITMAP)); QVERIFY(GetObject(bitmap, sizeof(BITMAP), &bitmapInfo)); QCOMPARE(LONG(100), bitmapInfo.bmWidth); QCOMPARE(LONG(100), bitmapInfo.bmHeight); const HDC displayDc = GetDC(nullptr); const HDC bitmapDc = CreateCompatibleDC(displayDc); const auto nullBitmap = static_cast(SelectObject(bitmapDc, bitmap)); const COLORREF pixel = GetPixel(bitmapDc, 0, 0); QCOMPARE(int(GetRValue(pixel)), red); QCOMPARE(int(GetGValue(pixel)), green); QCOMPARE(int(GetBValue(pixel)), blue); // Clean up SelectObject(bitmapDc, nullBitmap); DeleteObject(bitmap); DeleteDC(bitmapDc); ReleaseDC(nullptr, displayDc); } void tst_QPixmap::fromHBITMAP_data() { toHBITMAP_data(); } void tst_QPixmap::fromHBITMAP() { QFETCH(int, red); QFETCH(int, green); QFETCH(int, blue); const HDC displayDc = GetDC(nullptr); const HDC bitmapDc = CreateCompatibleDC(displayDc); const HBITMAP bitmap = CreateCompatibleBitmap(displayDc, 100, 100); SelectObject(bitmapDc, bitmap); SelectObject(bitmapDc, GetStockObject(NULL_PEN)); const HGDIOBJ oldBrush = SelectObject(bitmapDc, CreateSolidBrush(RGB(red, green, blue))); Rectangle(bitmapDc, 0, 0, 100, 100); const QPixmap pixmap = QtWin::fromHBITMAP(bitmap); QCOMPARE(pixmap.width(), 100); QCOMPARE(pixmap.height(), 100); const QImage image = pixmap.toImage(); const QRgb pixel = image.pixel(0, 0); QCOMPARE(qRed(pixel), red); QCOMPARE(qGreen(pixel), green); QCOMPARE(qBlue(pixel), blue); DeleteObject(SelectObject(bitmapDc, oldBrush)); DeleteObject(SelectObject(bitmapDc, bitmap)); DeleteDC(bitmapDc); ReleaseDC(nullptr, displayDc); } static bool compareImages(const QImage &actual, const QImage &expected, QByteArray *errorMessage) { if (actual.size() != expected.size()) { QString s; QDebug(&s) << "Size mismatch, actual: " << actual.size() << " expected: " << expected.size(); *errorMessage = s.toLocal8Bit(); return false; } if (actual.format() != expected.format()) { *errorMessage = QByteArrayLiteral("Format mismatch, actual: ") + QByteArray::number(actual.format()) + QByteArrayLiteral(", expected: ") + QByteArray::number(expected.format()); return false; } static const int fuzz = 1; for (int y = 0; y < actual.height(); ++y) { for (int x = 0; x < expected.width(); ++x) { const QRgb actualRgb = actual.pixel(x, y); const QRgb expectedRgb = expected.pixel(x, y); const bool pixelMatches = qAbs(qRed(actualRgb) - qRed(expectedRgb)) <= fuzz && qAbs(qGreen(actualRgb) - qGreen(expectedRgb)) <= fuzz && qAbs(qBlue(actualRgb) - qBlue(expectedRgb)) <= fuzz && qAbs(qAlpha(actualRgb) - qAlpha(expectedRgb)) <= fuzz; if (!pixelMatches) { QString s; QDebug(&s) << "Pixmal mismatch at " << x << ',' << y << " actual: " << QColor(actualRgb) << " expected: " << QColor(expectedRgb); *errorMessage = s.toLocal8Bit(); return false; } } } return true; } static inline QString pngFileName(const QString &image, int width, int height) { return image + u'_' + QString::number(width) + u'x' + QString::number(height) + QStringLiteral(".png"); } void tst_QPixmap::toHICON_data() { QTest::addColumn("image"); QTest::addColumn("width"); QTest::addColumn("height"); QTest::newRow("32bpp_16x16") << m_dataDirectory + QStringLiteral("/icon_32bpp") << 16 << 16; QTest::newRow("32bpp_32x32") << m_dataDirectory + QStringLiteral("/icon_32bpp") << 32 << 32; QTest::newRow("32bpp_48x48") << m_dataDirectory + QStringLiteral("/icon_32bpp") << 48 << 48; QTest::newRow("32bpp_256x256") << m_dataDirectory + QStringLiteral("/icon_32bpp") << 256 << 256; QTest::newRow("8bpp_16x16") << m_dataDirectory + QStringLiteral("/icon_8bpp") << 16 << 16; QTest::newRow("8bpp_32x32") << m_dataDirectory + QStringLiteral("/icon_8bpp") << 32 << 32; QTest::newRow("8bpp_48x48") << m_dataDirectory + QStringLiteral("/icon_8bpp") << 48 << 48; } void tst_QPixmap::toHICON() { QFETCH(int, width); QFETCH(int, height); QFETCH(QString, image); QPixmap empty(width, height); empty.fill(Qt::transparent); const HDC displayDc = GetDC(nullptr); const HDC bitmapDc = CreateCompatibleDC(displayDc); const HBITMAP bitmap = QtWin::toHBITMAP(empty, QtWin::HBitmapAlpha); SelectObject(bitmapDc, bitmap); const QString imageFileName = pngFileName(image, width, height); QVERIFY2(QFileInfo::exists(imageFileName), qPrintable(imageFileName)); const QImage imageFromFile = QImage(imageFileName).convertToFormat(QImage::Format_ARGB32_Premultiplied); QVERIFY(!imageFromFile.isNull()); const HICON icon = QtWin::toHICON(QPixmap::fromImage(imageFromFile)); DrawIconEx(bitmapDc, 0, 0, icon, width, height, 0, nullptr, DI_NORMAL); DestroyIcon(icon); DeleteDC(bitmapDc); const QImage imageFromHICON = QtWin::fromHBITMAP(bitmap, QtWin::HBitmapAlpha).toImage(); QVERIFY(!imageFromHICON.isNull()); ReleaseDC(nullptr, displayDc); // fuzzy comparison must be used, as the pixel values change slightly during conversion // between QImage::Format_ARGB32 and QImage::Format_ARGB32_Premultiplied, or elsewhere QByteArray errorMessage; QVERIFY2(compareImages(imageFromHICON, imageFromFile, &errorMessage), errorMessage.constData()); } void tst_QPixmap::fromHICON_data() { toHICON_data(); } void tst_QPixmap::fromHICON() { QFETCH(int, width); QFETCH(int, height); QFETCH(QString, image); const QString iconFileName = image + QStringLiteral(".ico"); QVERIFY2(QFileInfo::exists(iconFileName), qPrintable(iconFileName)); const auto icon = static_cast(LoadImage(nullptr, reinterpret_cast(iconFileName.utf16()), IMAGE_ICON, width, height, LR_LOADFROMFILE)); const QImage imageFromHICON = QtWin::fromHICON(icon).toImage(); DestroyIcon(icon); const QString imageFileName = pngFileName(image, width, height); QVERIFY2(QFileInfo::exists(imageFileName), qPrintable(imageFileName)); const QImage imageFromFile = QImage(imageFileName).convertToFormat(QImage::Format_ARGB32_Premultiplied); QVERIFY(!imageFromFile.isNull()); // fuzzy comparison must be used, as the pixel values change slightly during conversion // between QImage::Format_ARGB32 and QImage::Format_ARGB32_Premultiplied, or elsewhere QByteArray errorMessage; QVERIFY2(compareImages(imageFromHICON, imageFromFile, &errorMessage), errorMessage.constData()); } void tst_QPixmap::imageConversion() { // Extensive testing of all formats is done in QtGui; this merely tests // the exports/linkage. QImage image(73, 57, QImage::Format_ARGB32_Premultiplied); image.fill(Qt::red); QPainter painter(&image); painter.drawLine(0, 0, image.width(), image.height()); const HBITMAP hBitMap = QtWin::imageToHBITMAP(image); QVERIFY(hBitMap); const QImage fromHBitMap = QtWin::imageFromHBITMAP(hBitMap, QtWin::HBitmapPremultipliedAlpha); QCOMPARE(fromHBitMap, image); DeleteObject(hBitMap); } QTEST_MAIN(tst_QPixmap) #include "tst_qpixmap.moc"