1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the test suite of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:GPL-EXCEPT$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU
19** General Public License version 3 as published by the Free Software
20** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
21** included in the packaging of this file. Please review the following
22** information to ensure the GNU General Public License requirements will
23** be met: https://www.gnu.org/licenses/gpl-3.0.html.
24**
25** $QT_END_LICENSE$
26**
27****************************************************************************/
28
29
30#include <QtTest/QtTest>
31#include <qpixmap.h>
32#include <qbitmap.h>
33#include <qimage.h>
34#include <qimagereader.h>
35#ifndef QT_NO_WIDGETS
36#include <qdesktopwidget.h>
37#include <qsplashscreen.h>
38#endif
39#include <qpaintengine.h>
40
41#include <qpa/qplatformpixmap.h>
42#include <qpa/qplatformintegration.h>
43#include <private/qguiapplication_p.h>
44#include <private/qdrawhelper_p.h>
45
46#include <QSet>
47
48#ifdef Q_OS_WIN
49#include <windows.h>
50#endif
51
52
53Q_DECLARE_METATYPE(QImage::Format)
54
55class tst_QPixmap : public QObject
56{
57 Q_OBJECT
58
59public:
60 tst_QPixmap();
61
62public slots:
63 void initTestCase();
64 void cleanupTestCase();
65
66private slots:
67 void swap();
68
69 void fromImage_data();
70 void fromImage();
71
72 void fromUninitializedImage_data();
73 void fromUninitializedImage();
74
75 void convertFromImage_data();
76 void convertFromImage();
77 void convertFromImageShouldDetach();
78
79 void testMetrics();
80
81 void scroll_data();
82 void scroll();
83
84 void fill_data();
85 void fill();
86 void fill_transparent();
87
88 void createMaskFromColor();
89
90 void mask();
91 void bitmapMask();
92 void bitmapFromImageRvalue();
93 void setGetMask_data();
94 void setGetMask();
95 void cacheKey();
96 void drawBitmap();
97 void isNull();
98 void task_246446();
99 void task_51271();
100
101 void convertFromImageNoDetach();
102 void convertFromImageNoDetach2();
103 void convertFromImageDetach();
104 void convertFromImageCacheKey();
105
106#if defined(Q_OS_WIN) && !defined(Q_OS_WINRT)
107 void toWinHBITMAP_data();
108 void toWinHBITMAP();
109 void fromWinHBITMAP_data();
110 void fromWinHBITMAP();
111
112 void toWinHICON_data();
113 void toWinHICON();
114 void fromWinHICON_data();
115 void fromWinHICON();
116#endif
117
118 void onlyNullPixmapsOutsideGuiThread();
119 void refUnref();
120
121 void copy();
122 void deepCopyPreservesDpr();
123 void fillPreservesDpr();
124 void dprPassthrough();
125 void depthOfNullObjects();
126
127 void transformed();
128 void transformed2();
129
130 void fromImage_crash();
131
132 void load();
133 void loadFromData();
134#if !defined(QT_NO_DATASTREAM)
135 void loadFromDataStream();
136#endif
137
138 void fromData();
139 void loadFromDataNullValues();
140
141 void loadFromDataImage_data();
142 void loadFromDataImage();
143
144 void fromImageReader_data();
145 void fromImageReader();
146
147 void fromImageReaderAnimatedGif_data();
148 void fromImageReaderAnimatedGif();
149
150 void preserveDepth();
151#ifndef QT_NO_WIDGETS
152 void splash_crash();
153#endif
154
155 void toImageDeepCopy();
156
157 void loadAsBitmapOrPixmap();
158
159 void scaled_QTBUG19157();
160 void detachOnLoad_QTBUG29639();
161
162 void copyOnNonAlignedBoundary();
163 void devicePixelRatio();
164
165private:
166 const QString m_prefix;
167 const QString m_convertFromImage;
168 const QString m_loadFromData;
169 const QTemporaryDir m_tempDir;
170};
171
172static bool lenientCompare(const QPixmap &actual, const QPixmap &expected)
173{
174 QImage expectedImage = expected.toImage().convertToFormat(f: QImage::Format_RGB32);
175 QImage actualImage = actual.toImage().convertToFormat(f: QImage::Format_RGB32);
176
177 if (expectedImage.size() != actualImage.size()) {
178 qWarning(msg: "Image size comparison failed: expected: %dx%d, got %dx%d",
179 expectedImage.size().width(), expectedImage.size().height(),
180 actualImage.size().width(), actualImage.size().height());
181 return false;
182 }
183
184 const int size = actual.width() * actual.height();
185 const int threshold = QPixmap::defaultDepth() == 16 ? 10 : 2;
186
187 QRgb *a = (QRgb *)actualImage.bits();
188 QRgb *e = (QRgb *)expectedImage.bits();
189 for (int i = 0; i < size; ++i) {
190 const QColor ca(a[i]);
191 const QColor ce(e[i]);
192 if (qAbs(t: ca.red() - ce.red()) > threshold
193 || qAbs(t: ca.green() - ce.green()) > threshold
194 || qAbs(t: ca.blue() - ce.blue()) > threshold) {
195 qWarning(msg: "Color mismatch at pixel #%d: Expected: %d,%d,%d, got %d,%d,%d",
196 i, ce.red(), ce.green(), ce.blue(), ca.red(), ca.green(), ca.blue());
197 return false;
198 }
199 }
200
201 return true;
202}
203
204
205tst_QPixmap::tst_QPixmap()
206 : m_prefix(QFINDTESTDATA("images/"))
207 , m_convertFromImage(QFINDTESTDATA("convertFromImage"))
208 , m_loadFromData(QFINDTESTDATA("loadFromData"))
209{
210}
211
212void tst_QPixmap::initTestCase()
213{
214 QVERIFY(!m_prefix.isEmpty());
215 QVERIFY(!m_convertFromImage.isEmpty());
216 QVERIFY(!m_loadFromData.isEmpty());
217 QVERIFY2(m_tempDir.isValid(), qPrintable(m_tempDir.errorString()));
218}
219
220void tst_QPixmap::cleanupTestCase()
221{
222}
223
224void tst_QPixmap::swap()
225{
226 QPixmap p1( 16, 16 ), p2( 32, 32 );
227 p1.fill( fillColor: Qt::white );
228 p2.fill( fillColor: Qt::black );
229 const qint64 p1k = p1.cacheKey();
230 const qint64 p2k = p2.cacheKey();
231 p1.swap(other&: p2);
232 QCOMPARE(p1.cacheKey(), p2k);
233 QCOMPARE(p1.size(), QSize(32,32));
234 QCOMPARE(p2.cacheKey(), p1k);
235 QCOMPARE(p2.size(), QSize(16,16));
236}
237
238void tst_QPixmap::fromImage_data()
239{
240 bool is16bit = false;
241 if (QPixmap::defaultDepth() == 16)
242 is16bit = true;
243
244 QTest::addColumn<QImage::Format>(name: "format");
245
246 QTest::newRow(dataTag: "Format_Mono") << QImage::Format_Mono;
247 QTest::newRow(dataTag: "Format_MonoLSB") << QImage::Format_MonoLSB;
248// QTest::newRow("Format_Indexed8") << QImage::Format_Indexed8;
249 if (!is16bit)
250 QTest::newRow(dataTag: "Format_RGB32") << QImage::Format_RGB32;
251 QTest::newRow(dataTag: "Format_ARGB32") << QImage::Format_ARGB32;
252 QTest::newRow(dataTag: "Format_ARGB32_Premultiplied") << QImage::Format_ARGB32_Premultiplied;
253 if (!is16bit)
254 QTest::newRow(dataTag: "Format_RGB16") << QImage::Format_RGB16;
255}
256
257void tst_QPixmap::fromImage()
258{
259 QFETCH(QImage::Format, format);
260
261 QImage image(37, 16, format);
262
263 if (image.colorCount() == 2) {
264 image.setColor(i: 0, c: QColor(Qt::color0).rgba());
265 image.setColor(i: 1, c: QColor(Qt::color1).rgba());
266 }
267 image.fill(pixel: 0x7f7f7f7f);
268
269 const QPixmap pixmap = QPixmap::fromImage(image);
270 const QImage result = pixmap.toImage();
271 image = image.convertToFormat(f: result.format());
272 QCOMPARE(result, image);
273}
274
275
276void tst_QPixmap::fromUninitializedImage_data()
277{
278 QTest::addColumn<QImage::Format>(name: "format");
279
280 QTest::newRow(dataTag: "Format_Mono") << QImage::Format_Mono;
281 QTest::newRow(dataTag: "Format_MonoLSB") << QImage::Format_MonoLSB;
282 QTest::newRow(dataTag: "Format_Indexed8") << QImage::Format_Indexed8;
283 QTest::newRow(dataTag: "Format_RGB32") << QImage::Format_RGB32;
284 QTest::newRow(dataTag: "Format_ARGB32") << QImage::Format_ARGB32;
285 QTest::newRow(dataTag: "Format_ARGB32_Premultiplied") << QImage::Format_ARGB32_Premultiplied;
286 QTest::newRow(dataTag: "Format_RGB16") << QImage::Format_RGB16;
287}
288
289void tst_QPixmap::fromUninitializedImage()
290{
291 QFETCH(QImage::Format, format);
292
293 QImage image(100, 100, format);
294 QPixmap pix = QPixmap::fromImage(image);
295
296 // it simply shouldn't crash...
297 QVERIFY(true);
298
299}
300
301void tst_QPixmap::convertFromImage_data()
302{
303 QTest::addColumn<QImage>(name: "img1");
304 QTest::addColumn<QImage>(name: "img2");
305
306 {
307 QImage img1;
308 QImage img2;
309 QVERIFY(img1.load(m_convertFromImage + "/task31722_0/img1.png"));
310 QVERIFY(img2.load(m_convertFromImage + "/task31722_0/img2.png"));
311 QVERIFY(img1.load(m_convertFromImage + "/task31722_0/img1.png"));
312 QVERIFY(img2.load(m_convertFromImage + "/task31722_0/img2.png"));
313 QTest::newRow(dataTag: "Task 31722 0") << img1 << img2;
314 }
315 {
316 QImage img1;
317 QImage img2;
318 QVERIFY(img1.load(m_convertFromImage + "/task31722_1/img1.png"));
319 QVERIFY(img2.load(m_convertFromImage + "/task31722_1/img2.png"));
320 QTest::newRow(dataTag: "Task 31722 1") << img1 << img2;
321 }
322}
323
324void tst_QPixmap::convertFromImage()
325{
326 QFETCH(QImage, img1);
327 QFETCH(QImage, img2);
328
329 QPixmap pix = QPixmap::fromImage(image: img1);
330 pix = QPixmap::fromImage(image: img2);
331
332 QPixmap res = QPixmap::fromImage(image: img2);
333 QCOMPARE(pix, res);
334}
335
336void tst_QPixmap::convertFromImageShouldDetach()
337{
338 QImage img1;
339 QImage img2;
340 QVERIFY(img1.load(m_convertFromImage + "/task31722_0/img1.png"));
341 QVERIFY(img2.load(m_convertFromImage + "/task31722_0/img2.png"));
342 QPixmap pix = QPixmap::fromImage(image: img1);
343 QPixmap pix1 = pix;
344 pix.convertFromImage(img: img2);
345 QCOMPARE(pix, QPixmap::fromImage(img2));
346 QCOMPARE(pix1, QPixmap::fromImage(img1)); // unchanged
347}
348
349void tst_QPixmap::scroll_data()
350{
351 QTest::addColumn<QImage>(name: "input");
352 QTest::addColumn<int>(name: "dx");
353 QTest::addColumn<int>(name: "dy");
354 QTest::addColumn<QRect>(name: "rect");
355 QTest::addColumn<QRegion>(name: "exposed");
356 QTest::addColumn<bool>(name: "newPix");
357
358 QImage input(":/images/designer.png");
359
360 // Noop tests
361 QTest::newRow(dataTag: "null") << QImage() << 0 << 0 << QRect() << QRegion() << false;
362 QTest::newRow(dataTag: "dx_0_dy_0_null") << input << 0 << 0 << QRect() << QRegion() << false;
363 QTest::newRow(dataTag: "dx_1_dy_0_null") << input << 1 << 0 << QRect() << QRegion() << false;
364 QTest::newRow(dataTag: "dx_0_dy_1_null") << input << 0 << 1 << QRect() << QRegion() << false;
365 QTest::newRow(dataTag: "dx_0_dy_0_x_y_w_h") << input << 0 << 0 << input.rect() << QRegion() << false;
366
367 QRegion r;
368 // Scroll whole pixmap
369 r = QRegion(); r += QRect(0, 0, 128, 10);
370 QTest::newRow(dataTag: "dx_0_dy_10_x_y_w_h") << input << 0 << 10 << input.rect() << r << true;
371 r = QRegion(); r += QRect(0, 0, 10, 128);
372 QTest::newRow(dataTag: "dx_10_dy_0_x_y_w_h") << input << 10 << 0 << input.rect() << r << true;
373 r = QRegion(); r += QRect(0, 0, 128, 10); r += QRect(0, 10, 10, 118);
374 QTest::newRow(dataTag: "dx_10_dy_10_x_y_w_h") << input << 10 << 10 << input.rect() << r << true;
375 r = QRegion(); r += QRect(118, 0, 10, 128);
376 QTest::newRow(dataTag: "dx_-10_dy_0_x_y_w_h") << input << -10 << 0 << input.rect() << r << true;
377 r = QRegion(); r += QRect(0, 118, 128, 10);
378 QTest::newRow(dataTag: "dx_0_dy_-10_x_y_w_h") << input << 0 << -10 << input.rect() << r << true;
379 r = QRegion(); r += QRect(118, 0, 10, 118); r += QRect(0, 118, 128, 10);
380 QTest::newRow(dataTag: "dx_-10_dy_-10_x_y_w_h") << input << -10 << -10 << input.rect() << r << true;
381
382 // Scroll part of pixmap
383 QTest::newRow(dataTag: "dx_0_dy_0_50_50_100_100") << input << 0 << 0 << QRect(50, 50, 100, 100) << QRegion() << false;
384 r = QRegion(); r += QRect(50, 50, 10, 78);
385 QTest::newRow(dataTag: "dx_10_dy_0_50_50_100_100") << input << 10 << 0 << QRect(50, 50, 100, 100) << r << true;
386 r = QRegion(); r += QRect(50, 50, 78, 10);
387 QTest::newRow(dataTag: "dx_0_dy_10_50_50_100_100") << input << 0 << 10 << QRect(50, 50, 100, 100) << r << true;
388 r = QRegion(); r += QRect(50, 50, 78, 10); r += QRect(50, 60, 10, 68);
389 QTest::newRow(dataTag: "dx_10_dy_10_50_50_100_100") << input << 10 << 10 << QRect(50, 50, 100, 100) << r << true;
390 r = QRegion(); r += QRect(118, 50, 10, 78);
391 QTest::newRow(dataTag: "dx_-10_dy_0_50_50_100_100") << input << -10 << 0 << QRect(50, 50, 100, 100) << r << true;
392 r = QRegion(); r += QRect(50, 118, 78, 10);
393 QTest::newRow(dataTag: "dx_0_dy_-10_50_50_100_100") << input << 0 << -10 << QRect(50, 50, 100, 100) << r << true;
394 r = QRegion(); r += QRect(118, 50, 10, 68); r += QRect(50, 118, 78, 10);
395 QTest::newRow(dataTag: "dx_-10_dy_-10_50_50_100_100") << input << -10 << -10 << QRect(50, 50, 100, 100) << r << true;
396
397 // Scroll away the whole pixmap
398 r = input.rect();
399 QTest::newRow(dataTag: "dx_128_dy_0_x_y_w_h") << input << 128 << 0 << input.rect() << r << false;
400 QTest::newRow(dataTag: "dx_0_dy_128_x_y_w_h") << input << 0 << 128 << input.rect() << r << false;
401 QTest::newRow(dataTag: "dx_128_dy_128_x_y_w_h") << input << 128 << 128 << input.rect() << r << false;
402 QTest::newRow(dataTag: "dx_-128_dy_0_x_y_w_h") << input << -128 << 0 << input.rect() << r << false;
403 QTest::newRow(dataTag: "dx_0_dy_-128_x_y_w_h") << input << 0 << -128 << input.rect() << r << false;
404 QTest::newRow(dataTag: "dx_-128_dy_-128_x_y_w_h") << input << -128 << -128 << input.rect() << r << false;
405
406 // Scroll away part of the pixmap
407 r = QRegion(); r += QRect(64, 64, 64, 64);
408 QTest::newRow(dataTag: "dx_128_dy_128_64_64_128_128") << input << 128 << 128 << QRect(64, 64, 128, 128) << r << false;
409}
410
411void tst_QPixmap::scroll()
412{
413 QFETCH(QImage, input);
414 QFETCH(int, dx);
415 QFETCH(int, dy);
416 QFETCH(QRect, rect);
417 QFETCH(QRegion, exposed);
418 QFETCH(bool, newPix);
419
420 QPixmap pixmap = QPixmap::fromImage(image: input);
421 QRegion exp;
422 qint64 oldKey = pixmap.cacheKey();
423 pixmap.scroll(dx, dy, rect, exposed: &exp);
424 if (!newPix)
425 QCOMPARE(pixmap.cacheKey(), oldKey);
426 else
427 QVERIFY(pixmap.cacheKey() != oldKey);
428
429 const QString fileName = QLatin1String(":/images/") + QLatin1String(QTest::currentDataTag())
430 + QLatin1String(".png");
431 QPixmap output(fileName);
432 QCOMPARE(input.isNull(), output.isNull());
433 QVERIFY(lenientCompare(pixmap, output));
434 QCOMPARE(exp, exposed);
435}
436
437void tst_QPixmap::fill_data()
438{
439 QTest::addColumn<uint>(name: "pixel");
440 QTest::addColumn<bool>(name: "syscolor");
441 QTest::addColumn<bool>(name: "bitmap");
442 for (int color = Qt::black; color < Qt::darkYellow; ++color)
443 QTest::newRow(dataTag: ("syscolor_" + QByteArray::number(color)).constData())
444 << uint(color) << true << false;
445
446 QPixmap pixmap(1, 1);
447 QTest::newRow(dataTag: "alpha_7f_red") << 0x7fff0000u << false << false;
448 QTest::newRow(dataTag: "alpha_3f_blue") << 0x3f0000ffu << false << false;
449 QTest::newRow(dataTag: "alpha_b7_green") << 0xbf00ff00u << false << false;
450 QTest::newRow(dataTag: "alpha_7f_white") << 0x7fffffffu << false << false;
451 QTest::newRow(dataTag: "alpha_3f_white") << 0x3fffffffu << false << false;
452 QTest::newRow(dataTag: "alpha_b7_white") << 0xb7ffffffu << false << false;
453 QTest::newRow(dataTag: "alpha_7f_black") << 0x7f000000u << false << false;
454 QTest::newRow(dataTag: "alpha_3f_black") << 0x3f000000u << false << false;
455 QTest::newRow(dataTag: "alpha_b7_black") << 0xbf000000u << false << false;
456
457 QTest::newRow(dataTag: "bitmap_color0") << uint(Qt::color0) << true << true;
458 QTest::newRow(dataTag: "bitmap_color1") << uint(Qt::color1) << true << true;
459}
460
461void tst_QPixmap::fill()
462{
463 QFETCH(uint, pixel);
464 QFETCH(bool, syscolor);
465 QFETCH(bool, bitmap);
466
467 QColor color;
468
469 if (syscolor)
470 color = QColor(Qt::GlobalColor(pixel));
471 else
472 color = QColor(qRed(rgb: pixel), qGreen(rgb: pixel), qBlue(rgb: pixel), qAlpha(rgb: pixel));
473
474 QColor compareColor = color;
475 if (bitmap && syscolor) {
476 // special case color0 and color1 for bitmaps.
477 if (pixel == Qt::color0)
478 compareColor.setRgb(r: 255, g: 255, b: 255);
479 else
480 compareColor.setRgb(r: 0, g: 0, b: 0);
481 }
482
483 QPixmap pm;
484
485 if (bitmap)
486 pm = QBitmap(400, 400);
487 else
488 pm = QPixmap(400, 400);
489
490 pm.fill(fillColor: color);
491 if (syscolor && !bitmap && pm.depth() < 24) {
492 QSKIP("Test does not work on displays without true color");
493 }
494
495 QImage image = pm.toImage();
496 if (bitmap && syscolor) {
497 int pixelindex = (pixel == Qt::color0) ? 0 : 1;
498 QCOMPARE(image.pixelIndex(0,0), pixelindex);
499 }
500 QImage::Format format = compareColor.alpha() != 255
501 ? QImage::Format_ARGB32
502 : QImage::Format_RGB32;
503 image = image.convertToFormat(f: format);
504
505
506 QImage shouldBe(400, 400, format);
507 shouldBe.fill(pixel: compareColor.rgba());
508
509 QCOMPARE(image, shouldBe);
510}
511
512void tst_QPixmap::fill_transparent()
513{
514 QPixmap pixmap(10, 10);
515 pixmap.fill(fillColor: Qt::transparent);
516 QVERIFY(pixmap.hasAlphaChannel());
517}
518
519void tst_QPixmap::mask()
520{
521 QPixmap pm(100, 100);
522 QBitmap bm(100, 100);
523
524 pm.fill();
525 bm.fill();
526
527 QVERIFY(!pm.isNull());
528 QVERIFY(!bm.isNull());
529 if (!pm.hasAlphaChannel()) {
530 // This would fail if the default pixmap format is
531 // argb32_premultiplied. The mask will be all 1's.
532 // Therefore this is skipped when the alpha channel is present.
533 QVERIFY(pm.mask().isNull());
534 }
535
536 QImage img = bm.toImage();
537 QVERIFY(img.format() == QImage::Format_MonoLSB
538 || img.format() == QImage::Format_Mono);
539
540 pm.setMask(bm);
541 QVERIFY(!pm.mask().isNull());
542
543 bm = QBitmap();
544 // Invalid format here, since isNull() == true
545 QVERIFY(bm.toImage().isNull());
546 QCOMPARE(bm.toImage().format(), QImage::Format_Invalid);
547 pm.setMask(bm);
548 QVERIFY(pm.mask().isNull());
549
550 bm = QBitmap(100, 100);
551 bm.fill();
552 pm.setMask(bm);
553 QVERIFY(!pm.mask().isNull());
554}
555
556void tst_QPixmap::bitmapMask()
557{
558 QImage image(3, 3, QImage::Format_Mono);
559 image.setColor(i: 0, c: Qt::color0);
560 image.setColor(i: 1, c: Qt::color1);
561 image.fill(color: Qt::color0);
562 image.setPixel(x: 1, y: 1, index_or_rgb: Qt::color1);
563 image.setPixel(x: 0, y: 0, index_or_rgb: Qt::color1);
564
565 QImage image_mask(3, 3, QImage::Format_Mono);
566 image_mask.setColor(i: 0, c: Qt::color0);
567 image_mask.setColor(i: 1, c: Qt::color1);
568 image_mask.fill(color: Qt::color0);
569 image_mask.setPixel(x: 1, y: 1, index_or_rgb: Qt::color1);
570 image_mask.setPixel(x: 2, y: 0, index_or_rgb: Qt::color1);
571
572 QBitmap pm = QBitmap::fromImage(image);
573 QBitmap pm_mask = QBitmap::fromImage(image: image_mask);
574 pm.setMask(pm_mask);
575
576 image = pm.toImage();
577 image.setColor(i: 0, c: Qt::color0);
578 image.setColor(i: 1, c: Qt::color1);
579 image_mask = pm_mask.toImage();
580 image_mask.setColor(i: 0, c: Qt::color0);
581 image_mask.setColor(i: 1, c: Qt::color1);
582
583 QVERIFY(!image.pixel(0, 0));
584 QVERIFY(!image.pixel(2, 0));
585 QVERIFY(image.pixel(1, 1));
586}
587
588void tst_QPixmap::bitmapFromImageRvalue()
589{
590 auto makeImage = [](){
591 QImage image(3, 3, QImage::Format_MonoLSB);
592 image.setColor(i: 0, c: Qt::color0);
593 image.setColor(i: 1, c: Qt::color1);
594 image.fill(color: Qt::color0);
595 image.setPixel(x: 1, y: 1, index_or_rgb: Qt::color1);
596 image.setPixel(x: 0, y: 0, index_or_rgb: Qt::color1);
597 return image;
598 };
599
600 auto image1 = makeImage();
601 auto image2 = makeImage();
602 auto bitmap1 = QBitmap::fromImage(image: image1);
603 auto bitmap2 = QBitmap::fromImage(image: std::move(image2));
604 QCOMPARE(bitmap1.toImage(), bitmap2.toImage());
605 QVERIFY(!image1.isNull());
606 QVERIFY(image2.isNull());
607}
608
609void tst_QPixmap::setGetMask_data()
610{
611 QTest::addColumn<QPixmap>(name: "pixmap");
612 QTest::addColumn<QBitmap>(name: "mask");
613 QTest::addColumn<QBitmap>(name: "expected");
614
615 QPixmap pixmap(10, 10);
616 QBitmap mask(10, 10);
617 QPainter p;
618
619 p.begin(&pixmap);
620 p.fillRect(x: 0, y: 0, w: 10, h: 10, b: QColor(Qt::black));
621 p.end();
622
623 QTest::newRow(dataTag: "nullmask 0") << QPixmap() << QBitmap() << QBitmap();
624 QTest::newRow(dataTag: "nullmask 1") << pixmap << QBitmap() << QBitmap();
625 mask.clear();
626 QTest::newRow(dataTag: "nullmask 2") << pixmap << mask << mask;
627 QTest::newRow(dataTag: "nullmask 3") << QPixmap(QBitmap()) << QBitmap() << QBitmap();
628
629 p.begin(&mask);
630 p.fillRect(x: 1, y: 1, w: 5, h: 5, b: QColor(Qt::color1));
631 p.end();
632 QTest::newRow(dataTag: "simple mask 0") << pixmap << mask << mask;
633}
634
635void tst_QPixmap::setGetMask()
636{
637 QFETCH(QPixmap, pixmap);
638 QFETCH(QBitmap, mask);
639 QFETCH(QBitmap, expected);
640
641 pixmap.setMask(mask);
642 QBitmap result = pixmap.mask();
643
644 QImage resultImage = result.toImage();
645 QImage expectedImage = expected.toImage();
646 QCOMPARE(resultImage.convertToFormat(expectedImage.format()),
647 expectedImage);
648}
649
650void tst_QPixmap::testMetrics()
651{
652 QPixmap pixmap(100, 100);
653
654 QCOMPARE(pixmap.width(), 100);
655 QCOMPARE(pixmap.height(), 100);
656 QVERIFY(pixmap.depth() >= QPixmap::defaultDepth());
657
658 QBitmap bitmap(100, 100);
659
660 QCOMPARE(bitmap.width(), 100);
661 QCOMPARE(bitmap.height(), 100);
662 QCOMPARE(bitmap.depth(), 1);
663
664 QPixmap null;
665
666 QCOMPARE(null.size().width(), null.width());
667 QCOMPARE(null.size().height(), null.height());
668}
669
670void tst_QPixmap::createMaskFromColor()
671{
672 QImage image(3, 3, QImage::Format_Indexed8);
673 image.setColorCount(10);
674 image.setColor(i: 0, c: 0xffffffff);
675 image.setColor(i: 1, c: 0xff000000);
676 image.setColor(i: 2, c: 0xffff0000);
677 image.setColor(i: 3, c: 0xff0000ff);
678 image.fill(pixel: 0);
679 image.setPixel(x: 1, y: 0, index_or_rgb: 1);
680 image.setPixel(x: 0, y: 1, index_or_rgb: 2);
681 image.setPixel(x: 1, y: 1, index_or_rgb: 3);
682
683 QImage im_mask = image.createMaskFromColor(color: 0xffff0000);
684 QCOMPARE((uint) im_mask.pixel(0, 1), QColor(Qt::color0).rgba());
685 QCOMPARE((uint) im_mask.pixel(0, 1), QColor(Qt::color0).rgba());
686
687 QPixmap pixmap = QPixmap::fromImage(image);
688 QBitmap mask = pixmap.createMaskFromColor(maskColor: Qt::red);
689 QBitmap inv_mask = pixmap.createMaskFromColor(maskColor: Qt::red, mode: Qt::MaskOutColor);
690 QCOMPARE((uint) mask.toImage().pixel(0, 1), QColor(Qt::color0).rgba());
691 QCOMPARE((uint) inv_mask.toImage().pixel(0, 1), QColor(Qt::color1).rgba());
692}
693
694
695void tst_QPixmap::cacheKey()
696{
697 QPixmap pixmap1(1, 1);
698 QPixmap pixmap2(1, 1);
699 qint64 pixmap1_key = pixmap1.cacheKey();
700
701 QVERIFY(pixmap1.cacheKey() != pixmap2.cacheKey());
702
703 pixmap2 = pixmap1;
704 QCOMPARE(pixmap2.cacheKey(), pixmap1.cacheKey());
705
706 pixmap2.detach();
707 QVERIFY(pixmap2.cacheKey() != pixmap1.cacheKey());
708 QCOMPARE(pixmap1.cacheKey(), pixmap1_key);
709}
710
711// Test drawing a bitmap on a pixmap.
712void tst_QPixmap::drawBitmap()
713{
714 QBitmap bitmap(10,10);
715 bitmap.fill(fillColor: Qt::color1);
716
717 QPixmap pixmap(10,10);
718 QPainter painter2(&pixmap);
719 painter2.fillRect(x: 0,y: 0,w: 10,h: 10, b: QBrush(Qt::green));
720 painter2.setPen(Qt::red);
721 painter2.drawPixmap(x: 0,y: 0,w: 10,h: 10, pm: bitmap);
722 painter2.end();
723
724 QPixmap expected(10, 10);
725 expected.fill(fillColor: Qt::red);
726
727 QVERIFY(lenientCompare(pixmap, expected));
728}
729
730void tst_QPixmap::isNull()
731{
732 {
733 QPixmap pixmap(1,1);
734 QVERIFY(!pixmap.isNull());
735 }
736 {
737 QPixmap pixmap(0,0);
738 QVERIFY(pixmap.isNull());
739 }
740
741 {
742 QPixmap pixmap(0,1);
743 QVERIFY(pixmap.isNull());
744 }
745 {
746 QPixmap pixmap(1,0);
747 QVERIFY(pixmap.isNull());
748 }
749 {
750 QPixmap pixmap(-1,-1);
751 QVERIFY(pixmap.isNull());
752 }
753 {
754 QPixmap pixmap(-1,5);
755 QVERIFY(pixmap.isNull());
756 }
757}
758
759void tst_QPixmap::convertFromImageNoDetach()
760{
761 QPixmap randomPixmap(10, 10);
762 if (randomPixmap.handle()->classId() != QPlatformPixmap::RasterClass)
763 QSKIP("Test only valid for raster pixmaps");
764
765 //first get the screen format
766 QImage::Format screenFormat = randomPixmap.toImage().format();
767 QVERIFY(screenFormat != QImage::Format_Invalid);
768
769 QImage orig(100,100, screenFormat);
770
771 QPixmap pix = QPixmap::fromImage(image: orig);
772 QImage copy = pix.toImage();
773
774 QCOMPARE(copy.format(), screenFormat);
775
776 const QImage constOrig = orig;
777 const QImage constCopy = copy;
778 QCOMPARE(constOrig.bits(), constCopy.bits());
779}
780
781void tst_QPixmap::convertFromImageNoDetach2()
782{
783 QPixmap randomPixmap(10, 10);
784 if (randomPixmap.handle()->classId() != QPlatformPixmap::RasterClass)
785 QSKIP("Test only valid for raster pixmaps");
786
787 //first get the screen format
788 QImage::Format screenFormat = randomPixmap.toImage().format();
789 QVERIFY(screenFormat != QImage::Format_Invalid);
790 if (screenFormat != QImage::Format_RGB32 &&
791 screenFormat != QImage::Format_ARGB32_Premultiplied)
792 QSKIP("Test only valid for platforms with RGB32 pixmaps");
793
794 QImage orig(100,100, QImage::Format_ARGB32_Premultiplied);
795 orig.fill(color: Qt::white);
796
797 const uchar *origBits = orig.constBits();
798
799 QPixmap pix = QPixmap::fromImage(image: std::move(orig));
800 QImage copy = pix.toImage();
801
802 QVERIFY(!copy.hasAlphaChannel());
803 QCOMPARE(copy.format(), QImage::Format_RGB32);
804
805 QCOMPARE(origBits, copy.constBits());
806}
807
808void tst_QPixmap::convertFromImageDetach()
809{
810 QImage img(10,10, QImage::Format_RGB32);
811 img.fill(pixel: 0);
812 QVERIFY(!img.isNull());
813 QPixmap p = QPixmap::fromImage(image: img);
814 QVERIFY(p.isDetached());
815 QPixmap copy = p;
816 QVERIFY(!copy.isDetached());
817 QVERIFY(!p.isDetached());
818 img.fill(pixel: 1);
819 p = QPixmap::fromImage(image: img);
820 QVERIFY(copy.isDetached());
821}
822
823void tst_QPixmap::convertFromImageCacheKey()
824{
825 QPixmap randomPixmap(10, 10);
826 if (randomPixmap.handle()->classId() != QPlatformPixmap::RasterClass)
827 QSKIP("Test only valid for raster pixmaps");
828
829 //first get the screen format
830 QImage::Format screenFormat = randomPixmap.toImage().format();
831 QVERIFY(screenFormat != QImage::Format_Invalid);
832
833 QImage orig(100,100, screenFormat);
834 orig.fill(pixel: 0);
835
836 QPixmap pix = QPixmap::fromImage(image: orig);
837 QImage copy = pix.toImage();
838
839 QCOMPARE(copy.format(), screenFormat);
840
841 QCOMPARE(orig.cacheKey(), pix.cacheKey());
842 QCOMPARE(copy.cacheKey(), pix.cacheKey());
843}
844
845#if defined(Q_OS_WIN) && !defined(Q_OS_WINRT)
846
847QT_BEGIN_NAMESPACE
848Q_GUI_EXPORT HBITMAP qt_createIconMask(const QBitmap &bitmap);
849Q_GUI_EXPORT HBITMAP qt_pixmapToWinHBITMAP(const QPixmap &p, int hbitmapFormat = 0);
850Q_GUI_EXPORT QPixmap qt_pixmapFromWinHBITMAP(HBITMAP bitmap, int hbitmapFormat = 0);
851Q_GUI_EXPORT HICON qt_pixmapToWinHICON(const QPixmap &p);
852Q_GUI_EXPORT QImage qt_imageFromWinHBITMAP(HDC hdc, HBITMAP bitmap, int w, int h);
853Q_GUI_EXPORT QPixmap qt_pixmapFromWinHICON(HICON icon);
854QT_END_NAMESPACE
855
856void tst_QPixmap::toWinHBITMAP_data()
857{
858 QTest::addColumn<int>("red");
859 QTest::addColumn<int>("green");
860 QTest::addColumn<int>("blue");
861
862 QTest::newRow("red") << 255 << 0 << 0;
863 QTest::newRow("green") << 0 << 255 << 0;
864 QTest::newRow("blue") << 0 << 0 << 255;
865}
866
867void tst_QPixmap::toWinHBITMAP()
868{
869 QFETCH(int, red);
870 QFETCH(int, green);
871 QFETCH(int, blue);
872
873 QPixmap pm(100, 100);
874 pm.fill(QColor(red, green, blue));
875
876 HBITMAP bitmap = qt_pixmapToWinHBITMAP(pm);
877
878 QVERIFY(bitmap != 0);
879
880 // Verify size
881 BITMAP bitmap_info;
882 memset(&bitmap_info, 0, sizeof(BITMAP));
883
884 int res = GetObject(bitmap, sizeof(BITMAP), &bitmap_info);
885 QVERIFY(res);
886
887 QCOMPARE(100, (int) bitmap_info.bmWidth);
888 QCOMPARE(100, (int) bitmap_info.bmHeight);
889
890 HDC display_dc = GetDC(0);
891 HDC bitmap_dc = CreateCompatibleDC(display_dc);
892
893 HBITMAP null_bitmap = (HBITMAP) SelectObject(bitmap_dc, bitmap);
894
895 COLORREF pixel = GetPixel(bitmap_dc, 0, 0);
896 QCOMPARE((int)GetRValue(pixel), red);
897 QCOMPARE((int)GetGValue(pixel), green);
898 QCOMPARE((int)GetBValue(pixel), blue);
899
900 // Clean up
901 SelectObject(bitmap_dc, null_bitmap);
902 DeleteObject(bitmap);
903 DeleteDC(bitmap_dc);
904 ReleaseDC(0, display_dc);
905
906}
907
908void tst_QPixmap::fromWinHBITMAP_data()
909{
910 toWinHBITMAP_data();
911}
912
913void tst_QPixmap::fromWinHBITMAP()
914{
915 QFETCH(int, red);
916 QFETCH(int, green);
917 QFETCH(int, blue);
918
919 HDC display_dc = GetDC(0);
920 HDC bitmap_dc = CreateCompatibleDC(display_dc);
921 HBITMAP bitmap = CreateCompatibleBitmap(display_dc, 100, 100);
922 SelectObject(bitmap_dc, bitmap);
923
924 SelectObject(bitmap_dc, GetStockObject(NULL_PEN));
925 HGDIOBJ old_brush = SelectObject(bitmap_dc, CreateSolidBrush(RGB(red, green, blue)));
926 Rectangle(bitmap_dc, 0, 0, 100, 100);
927
928 QPixmap pixmap = qt_pixmapFromWinHBITMAP(bitmap);
929 QCOMPARE(pixmap.width(), 100);
930 QCOMPARE(pixmap.height(), 100);
931
932 QImage image = pixmap.toImage();
933 QRgb pixel = image.pixel(0, 0);
934 QCOMPARE(qRed(pixel), red);
935 QCOMPARE(qGreen(pixel), green);
936 QCOMPARE(qBlue(pixel), blue);
937
938 DeleteObject(SelectObject(bitmap_dc, old_brush));
939 DeleteObject(SelectObject(bitmap_dc, bitmap));
940 DeleteDC(bitmap_dc);
941 ReleaseDC(0, display_dc);
942}
943
944static bool compareImages(const QImage &actualImage, const QImage &expectedImage)
945{
946 if (actualImage.width() != expectedImage.width()
947 || actualImage.height() != expectedImage.height()) {
948 qWarning("Image size comparison failed: expected: %dx%d, got %dx%d",
949 expectedImage.size().width(), expectedImage.size().height(),
950 actualImage.size().width(), actualImage.size().height());
951 return false;
952 }
953 if (actualImage.format() != expectedImage.format()) {
954 qWarning("Image format comparison failed: expected: %d, got %d",
955 expectedImage.format(), actualImage.format());
956 return false;
957 }
958
959 static const int fuzz = 1;
960
961 for (int y = 0; y < actualImage.height(); ++y) {
962 for (int x = 0; x < expectedImage.width(); ++x) {
963 const QRgb p1 = actualImage.pixel(x, y);
964 const QRgb p2 = expectedImage.pixel(x, y);
965
966 if (qAbs(qRed(p1) - qRed(p2)) > fuzz
967 || qAbs(qGreen(p1) - qGreen(p2)) > fuzz
968 || qAbs(qBlue(p1) - qBlue(p2)) > fuzz
969 || qAbs(qAlpha(p1) - qAlpha(p2)) > fuzz) {
970 qWarning("Color mismatch at pixel %d,%d: Expected: 0x%x. got 0x%x",
971 x, y, p2, p1);
972 return false;
973 }
974 }
975 }
976 return true;
977}
978
979void tst_QPixmap::toWinHICON_data()
980{
981 QTest::addColumn<QString>("image");
982 QTest::addColumn<int>("width");
983 QTest::addColumn<int>("height");
984
985 const QString prefix = QFINDTESTDATA("convertFromToHICON");
986
987 QTest::newRow("32bpp_16x16") << prefix + QLatin1String("/icon_32bpp") << 16 << 16;
988 QTest::newRow("32bpp_32x32") << prefix + QLatin1String("/icon_32bpp") << 32 << 32;
989 QTest::newRow("32bpp_48x48") << prefix + QLatin1String("/icon_32bpp") << 48 << 48;
990 QTest::newRow("32bpp_256x256") << prefix + QLatin1String("/icon_32bpp") << 256 << 256;
991
992 QTest::newRow("8bpp_16x16") << prefix + QLatin1String("/icon_8bpp") << 16 << 16;
993 QTest::newRow("8bpp_32x32") << prefix + QLatin1String("/icon_8bpp") << 32 << 32;
994 QTest::newRow("8bpp_48x48") << prefix + QLatin1String("/icon_8bpp") << 48 << 48;
995}
996
997void tst_QPixmap::toWinHICON()
998{
999 enum { Alpha = 2 };
1000
1001 QFETCH(int, width);
1002 QFETCH(int, height);
1003 QFETCH(QString, image);
1004
1005 QPixmap empty(width, height);
1006 empty.fill(Qt::transparent);
1007
1008 HDC display_dc = GetDC(0);
1009 HDC bitmap_dc = CreateCompatibleDC(display_dc);
1010 HBITMAP bitmap = qt_pixmapToWinHBITMAP(empty, Alpha);
1011 SelectObject(bitmap_dc, bitmap);
1012
1013 const QString fileName = image + QLatin1Char('_') + QString::number(width) + QLatin1Char('x')
1014 + QString::number(height) + QLatin1String(".png");
1015 QImage imageFromFile(fileName);
1016 imageFromFile = imageFromFile.convertToFormat(QImage::Format_ARGB32_Premultiplied);
1017
1018 HICON icon = qt_pixmapToWinHICON(QPixmap::fromImage(imageFromFile));
1019
1020 DrawIconEx(bitmap_dc, 0, 0, icon, width, height, 0, 0, DI_NORMAL);
1021
1022 DestroyIcon(icon);
1023 DeleteDC(bitmap_dc);
1024
1025 QImage imageFromHICON = qt_pixmapFromWinHBITMAP(bitmap, Alpha).toImage();
1026
1027 ReleaseDC(0, display_dc);
1028
1029 // fuzzy comparison must be used, as the pixel values change slightly during conversion
1030 // between QImage::Format_ARGB32 and QImage::Format_ARGB32_Premultiplied, or elsewhere
1031
1032 QVERIFY(compareImages(imageFromHICON, imageFromFile));
1033}
1034
1035void tst_QPixmap::fromWinHICON_data()
1036{
1037 toWinHICON_data();
1038}
1039
1040void tst_QPixmap::fromWinHICON()
1041{
1042 QFETCH(int, width);
1043 QFETCH(int, height);
1044 QFETCH(QString, image);
1045
1046 HICON icon = (HICON)LoadImage(0, (wchar_t*)(image + QLatin1String(".ico")).utf16(), IMAGE_ICON, width, height, LR_LOADFROMFILE);
1047 QImage imageFromHICON = qt_pixmapFromWinHICON(icon).toImage();
1048 DestroyIcon(icon);
1049
1050 const QString fileName = image + QLatin1Char('_') + QString::number(width) + QLatin1Char('x')
1051 + QString::number(height) + QLatin1String(".png");
1052 QImage imageFromFile(fileName);
1053 imageFromFile = imageFromFile.convertToFormat(QImage::Format_ARGB32_Premultiplied);
1054
1055 // fuzzy comparison must be used, as the pixel values change slightly during conversion
1056 // between QImage::Format_ARGB32 and QImage::Format_ARGB32_Premultiplied, or elsewhere
1057
1058 QVERIFY(compareImages(imageFromHICON, imageFromFile));
1059}
1060
1061#endif // Q_OS_WIN && !Q_OS_WINRT
1062
1063void tst_QPixmap::onlyNullPixmapsOutsideGuiThread()
1064{
1065 class Thread : public QThread
1066 {
1067 public:
1068 void run()
1069 {
1070 QTest::ignoreMessage(type: QtWarningMsg,
1071 message: "QPixmap: It is not safe to use pixmaps outside the GUI thread");
1072 QPixmap pixmap;
1073 QVERIFY(pixmap.isNull());
1074
1075 QTest::ignoreMessage(type: QtWarningMsg,
1076 message: "QPixmap: It is not safe to use pixmaps outside the GUI thread");
1077 QPixmap pixmap1(100, 100);
1078 QVERIFY(pixmap1.isNull());
1079
1080 QTest::ignoreMessage(type: QtWarningMsg,
1081 message: "QPixmap: It is not safe to use pixmaps outside the GUI thread");
1082 QPixmap pixmap2(pixmap1);
1083 QVERIFY(pixmap2.isNull());
1084 }
1085 };
1086 if (QGuiApplicationPrivate::platform_integration->hasCapability(cap: QPlatformIntegration::ThreadedPixmaps))
1087 QSKIP("This platform supports threaded pixmaps.");
1088
1089 Thread thread;
1090 thread.start();
1091 thread.wait();
1092}
1093
1094void tst_QPixmap::refUnref()
1095{
1096 // Simple ref/unref
1097 {
1098 QPixmap p;
1099 }
1100 {
1101 QBitmap b;
1102 }
1103
1104 // Get a copy of a pixmap that goes out of scope
1105 {
1106 QPixmap b;
1107 {
1108 QPixmap a(10, 10);
1109 a.fill(fillColor: Qt::color0);
1110 b = a;
1111 }
1112 }
1113 {
1114 QBitmap mask;
1115 {
1116 QBitmap bitmap(10, 10);
1117 bitmap.fill(fillColor: Qt::color1);
1118 mask = bitmap.mask();
1119 }
1120 mask.fill(fillColor: Qt::color0);
1121 }
1122
1123}
1124
1125void tst_QPixmap::copy()
1126{
1127 QPixmap src(32, 32);
1128 {
1129 QPainter p(&src);
1130 p.fillRect(x: 0, y: 0, w: 32, h: 32, c: Qt::red);
1131 p.fillRect(x: 10, y: 10, w: 10, h: 10, c: Qt::blue);
1132 }
1133
1134 QPixmap dest = src.copy(ax: 10, ay: 10, awidth: 10, aheight: 10);
1135
1136 QPixmap expected(10, 10);
1137 expected.fill(fillColor: Qt::blue);
1138 QVERIFY(lenientCompare(dest, expected));
1139
1140 QPixmap trans;
1141 trans.fill(fillColor: Qt::transparent);
1142
1143 QPixmap transCopy = trans.copy();
1144 QCOMPARE(trans, transCopy);
1145}
1146
1147// QTBUG-58653: Force a deep copy of a pixmap by
1148// having a QPainter and check whether DevicePixelRatio is preserved
1149void tst_QPixmap::deepCopyPreservesDpr()
1150{
1151 const qreal dpr = 2;
1152 QPixmap src(32, 32);
1153 src.setDevicePixelRatio(dpr);
1154 src.fill(fillColor: Qt::red);
1155 QPainter painter(&src);
1156 const QPixmap dest = src.copy();
1157 QCOMPARE(dest.devicePixelRatio(), dpr);
1158}
1159
1160// Check that the DPR is preserved after doing a fill after an
1161// assigned copy of the QPixmap
1162void tst_QPixmap::fillPreservesDpr()
1163{
1164 const qreal dpr = 2;
1165 QPixmap src(32, 32);
1166 src.setDevicePixelRatio(dpr);
1167 src.fill(fillColor: Qt::red);
1168 QPixmap dest = src;
1169 dest.fill(fillColor: Qt::blue);
1170 QCOMPARE(dest.devicePixelRatio(), dpr);
1171}
1172
1173void tst_QPixmap::dprPassthrough()
1174{
1175 const qreal dpr = 2;
1176 QPixmap src(32, 32);
1177 src.setDevicePixelRatio(dpr);
1178 src.fill(fillColor: Qt::transparent);
1179 QCOMPARE(src.devicePixelRatio(), dpr);
1180
1181 QImage img = src.toImage();
1182 QCOMPARE(img.devicePixelRatio(), dpr);
1183
1184 QPixmap pm(1, 1);
1185 pm.convertFromImage(img);
1186 QCOMPARE(pm.devicePixelRatio(), dpr);
1187
1188 QBitmap heuristicMask = src.createHeuristicMask();
1189 QCOMPARE(heuristicMask.devicePixelRatio(), dpr);
1190
1191 QBitmap maskFromColor = src.createMaskFromColor(maskColor: Qt::white);
1192 QCOMPARE(maskFromColor.devicePixelRatio(), dpr);
1193
1194 QBitmap mask = src.mask();
1195 QCOMPARE(mask.devicePixelRatio(), dpr);
1196
1197 QPixmap scaled = src.scaled(w: 16, h: 16);
1198 QCOMPARE(scaled.devicePixelRatio(), dpr);
1199
1200 QTransform t;
1201 t.rotate(a: 90);
1202 QPixmap transformed = src.transformed(t);
1203 QCOMPARE(transformed.devicePixelRatio(), dpr);
1204}
1205
1206void tst_QPixmap::depthOfNullObjects()
1207{
1208 QBitmap b1;
1209 QCOMPARE(b1.depth(), 0);
1210 QPixmap p4;
1211 QCOMPARE(p4.depth(), 0);
1212}
1213
1214void tst_QPixmap::transformed()
1215{
1216 QPixmap p1(20, 10);
1217 p1.fill(fillColor: Qt::red);
1218 {
1219 QPainter p(&p1);
1220 p.drawRect(x: 0, y: 0, w: p1.width() - 1, h: p1.height() - 1);
1221 }
1222
1223 QPixmap p2(10, 20);
1224 {
1225 QPainter p(&p2);
1226 p.rotate(a: 90);
1227 p.drawPixmap(x: 0, y: -p1.height(), pm: p1);
1228 }
1229
1230 QPixmap p3(20, 10);
1231 {
1232 QPainter p(&p3);
1233 p.rotate(a: 180);
1234 p.drawPixmap(x: -p1.width(), y: -p1.height(), pm: p1);
1235 }
1236
1237 QPixmap p4(10, 20);
1238 {
1239 QPainter p(&p4);
1240 p.rotate(a: 270);
1241 p.drawPixmap(x: -p1.width(), y: 0, pm: p1);
1242 }
1243
1244 QPixmap p1_90 = p1.transformed(QTransform().rotate(a: 90));
1245 QPixmap p1_180 = p1.transformed(QTransform().rotate(a: 180));
1246 QPixmap p1_270 = p1.transformed(QTransform().rotate(a: 270));
1247
1248 QVERIFY(lenientCompare(p1_90, p2));
1249 QVERIFY(lenientCompare(p1_180, p3));
1250 QVERIFY(lenientCompare(p1_270, p4));
1251}
1252
1253void tst_QPixmap::transformed2()
1254{
1255 QPixmap pm(3, 3);
1256 pm.fill(fillColor: Qt::red);
1257 QPainter p(&pm);
1258 p.fillRect(x: 0, y: 0, w: 3, h: 3, b: QBrush(Qt::Dense4Pattern));
1259 p.end();
1260
1261 QTransform transform;
1262 transform.rotate(a: -90);
1263 transform.scale(sx: 3, sy: 3);
1264
1265 QPixmap actual = pm.transformed(transform);
1266
1267 QPixmap expected(9, 9);
1268 expected.fill(fillColor: Qt::red);
1269 p.begin(&expected);
1270 p.setBrush(Qt::black);
1271 p.setPen(Qt::NoPen);
1272 p.drawRect(x: 3, y: 0, w: 3, h: 3);
1273 p.drawRect(x: 0, y: 3, w: 3, h: 3);
1274 p.drawRect(x: 6, y: 3, w: 3, h: 3);
1275 p.drawRect(x: 3, y: 6, w: 3, h: 3);
1276 p.end();
1277
1278 QVERIFY(lenientCompare(actual, expected));
1279}
1280
1281void tst_QPixmap::load()
1282{
1283 const QString filePath = m_prefix + QLatin1String("designer.png");
1284
1285 QPixmap dest(filePath);
1286 QVERIFY(!dest.isNull());
1287 QVERIFY(!dest.load("image_that_does_not_exist.png"));
1288 QVERIFY(dest.isNull());
1289 QVERIFY(dest.load(filePath));
1290 QVERIFY(!dest.isNull());
1291}
1292
1293void tst_QPixmap::loadFromData()
1294{
1295 const QString filePath = m_prefix + QLatin1String("designer.png");
1296
1297 QPixmap original(filePath);
1298 QVERIFY(!original.isNull());
1299
1300 QByteArray ba;
1301 {
1302 QBuffer buf(&ba);
1303 QVERIFY(buf.open(QIODevice::WriteOnly));
1304 QVERIFY(original.save(&buf, "BMP"));
1305 }
1306 QVERIFY(!ba.isEmpty());
1307
1308 QPixmap dest;
1309 QVERIFY(dest.loadFromData(ba, "BMP"));
1310 QVERIFY(!dest.isNull());
1311
1312 QCOMPARE(original, dest);
1313
1314 QVERIFY(!dest.loadFromData(QByteArray()));
1315 QVERIFY(dest.isNull());
1316}
1317
1318#if !defined(QT_NO_DATASTREAM)
1319void tst_QPixmap::loadFromDataStream()
1320{
1321 const QString filePath = m_prefix + QLatin1String("designer.png");
1322
1323 QPixmap original(filePath);
1324 QVERIFY(!original.isNull());
1325
1326 QByteArray ba;
1327 {
1328 QDataStream s(&ba, QIODevice::WriteOnly);
1329 s << original;
1330 }
1331 QVERIFY(!ba.isEmpty());
1332
1333 QPixmap dest;
1334 {
1335 QDataStream s(&ba, QIODevice::ReadOnly);
1336 s >> dest;
1337 }
1338 QVERIFY(!dest.isNull());
1339
1340 QCOMPARE(original, dest);
1341
1342 {
1343 ba.clear();
1344 QDataStream s(&ba, QIODevice::ReadOnly);
1345 s >> dest;
1346 }
1347 QVERIFY(dest.isNull());
1348}
1349#endif // QT_NO_DATASTREAM
1350
1351void tst_QPixmap::fromImage_crash()
1352{
1353 QImage *img = new QImage(64, 64, QImage::Format_ARGB32_Premultiplied);
1354
1355 QPixmap pm = QPixmap::fromImage(image: *img);
1356 QPainter painter(&pm);
1357
1358 delete img;
1359}
1360
1361#ifndef QT_NO_WIDGETS
1362//This is testing QPlatformPixmap::createCompatiblePlatformPixmap - see QTBUG-5977
1363void tst_QPixmap::splash_crash()
1364{
1365 QPixmap pix;
1366 pix = QPixmap(":/images/designer.png");
1367 QSplashScreen splash(pix);
1368 splash.show();
1369 QCoreApplication::processEvents();
1370 splash.close();
1371}
1372#endif
1373
1374void tst_QPixmap::fromData()
1375{
1376 unsigned char bits[] = { 0xaa, 0x55 };
1377
1378 QBitmap bm = QBitmap::fromData(size: QSize(8, 2), bits);
1379 QImage img = bm.toImage();
1380
1381 QSet<QRgb> colors;
1382 for (int y = 0; y < img.height(); ++y)
1383 for (int x = 0; x < img.width(); ++x)
1384 colors << img.pixel(x, y);
1385
1386 QCOMPARE(colors.size(), 2);
1387
1388 QCOMPARE(img.pixel(0, 0), QRgb(0xffffffff));
1389 QCOMPARE(img.pixel(0, 1), QRgb(0xff000000));
1390}
1391
1392void tst_QPixmap::loadFromDataNullValues()
1393{
1394 {
1395 QPixmap pixmap;
1396 pixmap.loadFromData(buf: QByteArray());
1397 QVERIFY(pixmap.isNull());
1398 }
1399 {
1400 QPixmap pixmap;
1401 pixmap.loadFromData(buf: 0, len: 123);
1402 QVERIFY(pixmap.isNull());
1403 }
1404 {
1405 QPixmap pixmap;
1406 const uchar bla[] = "bla";
1407 pixmap.loadFromData(buf: bla, len: 0);
1408 QVERIFY(pixmap.isNull());
1409 }
1410}
1411
1412void tst_QPixmap::loadFromDataImage_data()
1413{
1414 QTest::addColumn<QString>(name: "imagePath");
1415
1416 QTest::newRow(dataTag: "designer_argb32.png") << m_loadFromData + "/designer_argb32.png";
1417 // When no extension is provided we try all extensions that has been registered by image providers
1418 QTest::newRow(dataTag: "designer_argb32") << m_loadFromData + "/designer_argb32.png";
1419 QTest::newRow(dataTag: "designer_indexed8_no_alpha.png") << m_loadFromData + "/designer_indexed8_no_alpha.png";
1420 QTest::newRow(dataTag: "designer_indexed8_with_alpha.png") << m_loadFromData + "/designer_indexed8_with_alpha.png";
1421 QTest::newRow(dataTag: "designer_rgb32.png") << m_loadFromData + "/designer_rgb32.png";
1422 QTest::newRow(dataTag: "designer_indexed8_no_alpha.gif") << m_loadFromData + "/designer_indexed8_no_alpha.gif";
1423 QTest::newRow(dataTag: "designer_indexed8_with_alpha.gif") << m_loadFromData + "/designer_indexed8_with_alpha.gif";
1424 QTest::newRow(dataTag: "designer_rgb32.jpg") << m_loadFromData + "/designer_rgb32.jpg";
1425}
1426
1427void tst_QPixmap::loadFromDataImage()
1428{
1429 QFETCH(QString, imagePath);
1430
1431 QImage imageRef(imagePath);
1432 QPixmap pixmapWithCopy = QPixmap::fromImage(image: imageRef);
1433
1434 QFile file(imagePath);
1435 file.open(flags: QIODevice::ReadOnly);
1436 QByteArray rawData = file.readAll();
1437
1438 QPixmap directLoadingPixmap;
1439 directLoadingPixmap.loadFromData(buf: rawData);
1440
1441 QCOMPARE(pixmapWithCopy, directLoadingPixmap);
1442}
1443
1444void tst_QPixmap::fromImageReader_data()
1445{
1446 QTest::addColumn<QString>(name: "imagePath");
1447
1448 QTest::newRow(dataTag: "designer_argb32.png") << m_loadFromData + "/designer_argb32.png";
1449 QTest::newRow(dataTag: "designer_indexed8_no_alpha.png") << m_loadFromData + "/designer_indexed8_no_alpha.png";
1450 QTest::newRow(dataTag: "designer_indexed8_with_alpha.png") << m_loadFromData + "/designer_indexed8_with_alpha.png";
1451 QTest::newRow(dataTag: "designer_rgb32.png") << m_loadFromData + "/designer_rgb32.png";
1452 QTest::newRow(dataTag: "designer_indexed8_no_alpha.gif") << m_loadFromData + "/designer_indexed8_no_alpha.gif";
1453 QTest::newRow(dataTag: "designer_indexed8_with_alpha.gif") << m_loadFromData + "/designer_indexed8_with_alpha.gif";
1454 QTest::newRow(dataTag: "designer_rgb32.jpg") << m_loadFromData + "/designer_rgb32.jpg";
1455 QTest::newRow(dataTag: "designer_indexed8_with_alpha_animated") << m_loadFromData + "/designer_indexed8_with_alpha_animated.gif";
1456 QTest::newRow(dataTag: "designer_indexed8_no_alpha_animated") << m_loadFromData + "/designer_indexed8_no_alpha_animated.gif";
1457}
1458
1459void tst_QPixmap::fromImageReader()
1460{
1461 QFETCH(QString, imagePath);
1462
1463 QImage imageRef(imagePath);
1464 QPixmap pixmapWithCopy = QPixmap::fromImage(image: imageRef);
1465
1466 QImageReader imageReader(imagePath);
1467
1468 QPixmap directLoadingPixmap = QPixmap::fromImageReader(imageReader: &imageReader);
1469
1470 QCOMPARE(pixmapWithCopy, directLoadingPixmap);
1471}
1472
1473void tst_QPixmap::fromImageReaderAnimatedGif_data()
1474{
1475 QTest::addColumn<QString>(name: "imagePath");
1476 QTest::newRow(dataTag: "gif with alpha") << QString::fromLatin1(str: "/designer_indexed8_with_alpha_animated.gif");
1477 QTest::newRow(dataTag: "gif without alpha") << QString::fromLatin1(str: "/designer_indexed8_no_alpha_animated.gif");
1478}
1479
1480void tst_QPixmap::fromImageReaderAnimatedGif()
1481{
1482 QFETCH(QString, imagePath);
1483
1484 const QString path = m_loadFromData + imagePath;
1485
1486 QImageReader referenceReader(path);
1487 QImageReader pixmapReader(path);
1488
1489 QVERIFY(referenceReader.canRead());
1490 QVERIFY(referenceReader.imageCount() > 1);
1491
1492 for (int i = 0; i < referenceReader.imageCount(); ++i) {
1493 QImage refImage = referenceReader.read();
1494 QPixmap refPixmap = QPixmap::fromImage(image: refImage);
1495
1496 QPixmap directLoadingPixmap = QPixmap::fromImageReader(imageReader: &pixmapReader);
1497 QCOMPARE(refPixmap, directLoadingPixmap);
1498 }
1499}
1500
1501void tst_QPixmap::task_246446()
1502{
1503 // This crashed without the bugfix in 246446
1504 QPixmap pm(10, 10);
1505 pm.fill(fillColor: Qt::transparent); // force 32-bit depth
1506 QBitmap bm;
1507 pm.setMask(bm);
1508 {
1509 QPixmap pm2(pm);
1510 }
1511 QCOMPARE(pm.width(), 10);
1512 QVERIFY(pm.mask().isNull());
1513}
1514
1515void tst_QPixmap::task_51271()
1516{
1517 QPixmap pm;
1518 QBitmap bm;
1519 QVERIFY(!pm.isQBitmap()); // Should not crash !
1520 QVERIFY(bm.isQBitmap());
1521}
1522
1523void tst_QPixmap::preserveDepth()
1524{
1525 QPixmap target(64, 64);
1526 target.fill(fillColor: Qt::transparent);
1527
1528 QPixmap source(64, 64);
1529 source.fill(fillColor: Qt::white);
1530
1531 int depth = source.depth();
1532
1533 QPainter painter(&target);
1534 painter.setBrush(source);
1535 painter.drawRect(r: target.rect());
1536 painter.end();
1537
1538 QCOMPARE(depth, source.depth());
1539}
1540
1541void tst_QPixmap::loadAsBitmapOrPixmap()
1542{
1543 QImage tmp(10, 10, QImage::Format_RGB32);
1544 tmp.save(fileName: m_tempDir.path() + "/temp_image.png");
1545
1546 bool ok;
1547
1548 // Check that we can load the pixmap as a pixmap and that it then turns into a pixmap
1549 QPixmap pixmap(m_tempDir.path() + "/temp_image.png");
1550 QVERIFY(!pixmap.isNull());
1551 QVERIFY(pixmap.depth() > 1);
1552 QVERIFY(!pixmap.isQBitmap());
1553
1554 pixmap = QPixmap();
1555 ok = pixmap.load(fileName: m_tempDir.path() + "/temp_image.png");
1556 QVERIFY(ok);
1557 QVERIFY(!pixmap.isNull());
1558 QVERIFY(pixmap.depth() > 1);
1559 QVERIFY(!pixmap.isQBitmap());
1560
1561 //now we can try to load it without an extension
1562 pixmap = QPixmap();
1563 ok = pixmap.load(fileName: m_tempDir.path() + "/temp_image");
1564 QVERIFY(ok);
1565 QVERIFY(!pixmap.isNull());
1566 QVERIFY(pixmap.depth() > 1);
1567 QVERIFY(!pixmap.isQBitmap());
1568
1569 // The do the same check for bitmaps..
1570 QBitmap bitmap(m_tempDir.path() + "/temp_image.png");
1571 QVERIFY(!bitmap.isNull());
1572 QCOMPARE(bitmap.depth(), 1);
1573 QVERIFY(bitmap.isQBitmap());
1574
1575 bitmap = QBitmap();
1576 ok = bitmap.load(fileName: m_tempDir.path() + "/temp_image.png");
1577 QVERIFY(ok);
1578 QVERIFY(!bitmap.isNull());
1579 QCOMPARE(bitmap.depth(), 1);
1580 QVERIFY(bitmap.isQBitmap());
1581
1582 // check that a QBitmap stays a QBitmap even when loading fails:
1583 ok = bitmap.load(fileName: QString());
1584 QVERIFY(!ok);
1585 QVERIFY(bitmap.isNull());
1586 QVERIFY(bitmap.isQBitmap());
1587
1588 ok = bitmap.load(fileName: "does not exist");
1589 QVERIFY(!ok);
1590 QVERIFY(bitmap.isNull());
1591 QVERIFY(bitmap.isQBitmap());
1592
1593 ok = bitmap.load(fileName: "does not exist.png");
1594 QVERIFY(!ok);
1595 QVERIFY(bitmap.isNull());
1596 QVERIFY(bitmap.isQBitmap());
1597
1598 QTemporaryFile garbage;
1599 QVERIFY(garbage.open());
1600 const QString garbagePath = garbage.fileName();
1601 garbage.write(data: reinterpret_cast<const char *>(&garbage), len: sizeof garbage);
1602 garbage.close();
1603
1604 ok = bitmap.load(fileName: garbagePath);
1605 QVERIFY(!ok);
1606 QVERIFY(bitmap.isNull());
1607 QVERIFY(bitmap.isQBitmap());
1608}
1609
1610void tst_QPixmap::toImageDeepCopy()
1611{
1612 QPixmap pixmap(64, 64);
1613 pixmap.fill(fillColor: Qt::white);
1614
1615 QPainter painter(&pixmap);
1616 QImage first = pixmap.toImage();
1617
1618 painter.setBrush(Qt::black);
1619 painter.drawEllipse(r: pixmap.rect());
1620
1621 QImage second = pixmap.toImage();
1622
1623 QVERIFY(first != second);
1624}
1625
1626void tst_QPixmap::scaled_QTBUG19157()
1627{
1628 QPixmap foo(5000, 1);
1629 foo = foo.scaled(w: 1024, h: 1024, aspectMode: Qt::KeepAspectRatio);
1630 QVERIFY(!foo.isNull());
1631}
1632
1633void tst_QPixmap::detachOnLoad_QTBUG29639()
1634{
1635 QPixmap a;
1636 a.load(fileName: m_convertFromImage + "/task31722_0/img1.png");
1637 a.load(fileName: m_convertFromImage + "/task31722_0/img2.png");
1638
1639 QPixmap b;
1640 b.load(fileName: m_convertFromImage + "/task31722_0/img1.png");
1641
1642 QVERIFY(a.toImage() != b.toImage());
1643}
1644
1645void tst_QPixmap::copyOnNonAlignedBoundary()
1646{
1647 QImage img(8, 2, QImage::Format_RGB16);
1648
1649 QPixmap pm1 = QPixmap::fromImage(image: img, flags: Qt::NoFormatConversion);
1650 QPixmap pm2 = pm1.copy(rect: QRect(5, 0, 3, 2)); // When copying second line: 2 bytes too many are read which might cause an access violation.
1651}
1652
1653// test pixmap devicePixelRatio setting and detaching
1654void tst_QPixmap::devicePixelRatio()
1655{
1656 // create pixmap
1657 QPixmap a(64, 64);
1658 a.fill(fillColor: Qt::white);
1659 QCOMPARE(a.devicePixelRatio(), qreal(1.0));
1660 QCOMPARE(a.isDetached(), true);
1661
1662 // copy pixmap
1663 QPixmap b = a;
1664 QCOMPARE(b.devicePixelRatio(), qreal(1.0));
1665 QCOMPARE(a.isDetached(), false);
1666 QCOMPARE(b.isDetached(), false);
1667
1668 // set devicePixelRatio to the current value: does not detach
1669 a.setDevicePixelRatio(qreal(1.0));
1670 QCOMPARE(a.isDetached(), false);
1671 QCOMPARE(b.isDetached(), false);
1672
1673 // set devicePixelRatio to a new value: may detach (currently
1674 // does, but we may want to avoid the data copy the future)
1675 a.setDevicePixelRatio(qreal(2.0));
1676 QCOMPARE(a.devicePixelRatio(), qreal(2.0));
1677 QCOMPARE(b.devicePixelRatio(), qreal(1.0));
1678}
1679
1680QTEST_MAIN(tst_QPixmap)
1681#include "tst_qpixmap.moc"
1682

source code of qtbase/tests/auto/gui/image/qpixmap/tst_qpixmap.cpp