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
32#include <qimage.h>
33#include <qimagereader.h>
34#include <qlist.h>
35#include <qtransform.h>
36#include <qrandom.h>
37#include <stdio.h>
38
39#include <qpainter.h>
40#include <private/qimage_p.h>
41#include <private/qdrawhelper_p.h>
42
43#ifdef Q_OS_DARWIN
44#include <CoreGraphics/CoreGraphics.h>
45#endif
46
47#if defined(Q_OS_WIN) && !defined(Q_OS_WINRT)
48# include <qt_windows.h>
49#endif
50
51Q_DECLARE_METATYPE(QImage::Format)
52Q_DECLARE_METATYPE(Qt::GlobalColor)
53
54class tst_QImage : public QObject
55{
56 Q_OBJECT
57
58public:
59 tst_QImage();
60
61private slots:
62 void initTestCase();
63 void swap();
64 void create();
65 void createInvalidXPM();
66 void createFromUChar();
67 void formatHandlersInput_data();
68 void formatHandlersInput();
69
70 void setAlphaChannel_data();
71 void setAlphaChannel();
72
73 void alphaChannel();
74
75 void convertToFormat_data();
76 void convertToFormat();
77 void convertToFormatWithColorTable();
78
79 void convertToFormatRgb888ToRGB32();
80
81 void createAlphaMask_data();
82 void createAlphaMask();
83#ifndef QT_NO_IMAGE_HEURISTIC_MASK
84 void createHeuristicMask();
85#endif
86
87 void dotsPerMeterZero();
88 void dotsPerMeterAndDpi();
89
90 void convertToFormatPreserveDotsPrMeter();
91 void convertToFormatPreserveText();
92
93 void rotate_data();
94 void rotate();
95
96 void copy();
97
98 void load();
99 void loadFromData();
100#if !defined(QT_NO_DATASTREAM)
101 void loadFromDataStream();
102#endif
103
104 void setPixel_data();
105 void setPixel();
106 void setPixelWithAlpha_data();
107 void setPixelWithAlpha();
108 void setPixelColorWithAlpha_data();
109 void setPixelColorWithAlpha();
110
111 void defaultColorTable_data();
112 void defaultColorTable();
113 void setColorCount();
114 void setColor();
115
116 void rasterClipping();
117
118 void pointOverloads();
119 void destructor();
120 void cacheKey();
121
122 void smoothScale();
123 void smoothScale2_data();
124 void smoothScale2();
125 void smoothScale3_data();
126 void smoothScale3();
127 void smoothScale4_data();
128 void smoothScale4();
129
130 void smoothScaleBig();
131 void smoothScaleAlpha();
132
133 void transformed_data();
134 void transformed();
135 void transformed2();
136
137 void scaled();
138
139 void paintEngine();
140 void setAlphaChannelWhilePainting();
141
142 void smoothScaledSubImage();
143
144 void nullSize_data();
145 void nullSize();
146
147 void premultipliedAlphaConsistency();
148
149 void compareIndexed();
150
151 void fillColor_data();
152 void fillColor();
153
154 void fillColorWithAlpha_data();
155 void fillColorWithAlpha();
156
157 void fillRGB888();
158
159 void fillPixel_data();
160 void fillPixel();
161
162 void rgbSwapped_data();
163 void rgbSwapped();
164
165 void mirrored_data();
166 void mirrored();
167
168 void inplaceRgbSwapped_data();
169 void inplaceRgbSwapped();
170
171 void inplaceMirrored_data();
172 void inplaceMirrored();
173
174 void inplaceMirroredOdd_data();
175 void inplaceMirroredOdd();
176
177 void inplaceRgbMirrored();
178
179 void genericRgbConversion_data();
180 void genericRgbConversion();
181
182 void inplaceRgbConversion_data();
183 void inplaceRgbConversion();
184
185 void largeGenericRgbConversion_data();
186 void largeGenericRgbConversion();
187
188 void largeInplaceRgbConversion_data();
189 void largeInplaceRgbConversion();
190
191 void deepCopyWhenPaintingActive();
192 void scaled_QTBUG19157();
193
194 void convertOverUnPreMul();
195
196 void scaled_QTBUG35972();
197
198 void convertToPixelFormat();
199 void convertToImageFormat_data();
200 void convertToImageFormat();
201
202 void invertPixelsRGB_data();
203 void invertPixelsRGB();
204
205 void invertPixelsIndexed();
206
207 void exifOrientation_data();
208 void exifOrientation();
209
210 void exif_QTBUG45865();
211 void exifInvalidData_data();
212 void exifInvalidData();
213 void exifReadComments();
214
215 void cleanupFunctions();
216
217 void devicePixelRatio();
218 void rgb30Unpremul();
219 void rgb30Repremul_data();
220 void rgb30Repremul();
221
222 void metadataPassthrough();
223
224 void pixelColor();
225 void pixel();
226
227 void ditherGradient_data();
228 void ditherGradient();
229
230 void reinterpretAsFormat_data();
231 void reinterpretAsFormat();
232
233 void reinterpretAsFormat2();
234
235 void complexTransform8bit();
236
237#ifdef Q_OS_DARWIN
238 void toCGImage_data();
239 void toCGImage();
240#endif
241
242 void hugeQImage();
243
244 void convertColorTable();
245
246 void wideImage();
247
248#if defined(Q_OS_WIN) && !defined(Q_OS_WINRT)
249 void toWinHBITMAP_data();
250 void toWinHBITMAP();
251 void fromMonoHBITMAP();
252#endif // Q_OS_WIN && !Q_OS_WINRT
253
254private:
255 const QString m_prefix;
256};
257
258static QLatin1String formatToString(QImage::Format format)
259{
260 switch (format) {
261 case QImage::Format_Invalid:
262 return QLatin1String("Invalid");
263 case QImage::Format_Mono:
264 return QLatin1String("Mono");
265 case QImage::Format_MonoLSB:
266 return QLatin1String("MonoLSB");
267 case QImage::Format_Indexed8:
268 return QLatin1String("Indexed8");
269 case QImage::Format_RGB32:
270 return QLatin1String("RGB32");
271 case QImage::Format_ARGB32:
272 return QLatin1String("ARGB32");
273 case QImage::Format_ARGB32_Premultiplied:
274 return QLatin1String("ARGB32pm");
275 case QImage::Format_RGB16:
276 return QLatin1String("RGB16");
277 case QImage::Format_ARGB8565_Premultiplied:
278 return QLatin1String("ARGB8565pm");
279 case QImage::Format_RGB666:
280 return QLatin1String("RGB666");
281 case QImage::Format_ARGB6666_Premultiplied:
282 return QLatin1String("ARGB6666pm");
283 case QImage::Format_RGB555:
284 return QLatin1String("RGB555");
285 case QImage::Format_ARGB8555_Premultiplied:
286 return QLatin1String("ARGB8555pm");
287 case QImage::Format_RGB888:
288 return QLatin1String("RGB888");
289 case QImage::Format_RGB444:
290 return QLatin1String("RGB444");
291 case QImage::Format_ARGB4444_Premultiplied:
292 return QLatin1String("ARGB4444pm");
293 case QImage::Format_RGBX8888:
294 return QLatin1String("RGBx88888");
295 case QImage::Format_RGBA8888:
296 return QLatin1String("RGBA88888");
297 case QImage::Format_RGBA8888_Premultiplied:
298 return QLatin1String("RGBA88888pm");
299 case QImage::Format_BGR30:
300 return QLatin1String("BGR30");
301 case QImage::Format_A2BGR30_Premultiplied:
302 return QLatin1String("A2BGR30pm");
303 case QImage::Format_RGB30:
304 return QLatin1String("RGB30");
305 case QImage::Format_A2RGB30_Premultiplied:
306 return QLatin1String("A2RGB30pm");
307 case QImage::Format_Alpha8:
308 return QLatin1String("Alpha8");
309 case QImage::Format_Grayscale8:
310 return QLatin1String("Grayscale8");
311 case QImage::Format_RGBX64:
312 return QLatin1String("RGBx64");
313 case QImage::Format_RGBA64:
314 return QLatin1String("RGBA64");
315 case QImage::Format_RGBA64_Premultiplied:
316 return QLatin1String("RGBA64pm");
317 case QImage::Format_Grayscale16:
318 return QLatin1String("Grayscale16");
319 case QImage::Format_BGR888:
320 return QLatin1String("BGR888");
321 default:
322 break;
323 };
324 Q_UNREACHABLE();
325 qWarning(msg: "Unhandled image format");
326 return QLatin1String("unknown");
327}
328
329tst_QImage::tst_QImage()
330 : m_prefix(QFINDTESTDATA("images/"))
331{
332}
333
334void tst_QImage::initTestCase()
335{
336 QVERIFY(!m_prefix.isEmpty());
337}
338
339void tst_QImage::swap()
340{
341 QImage i1( 16, 16, QImage::Format_RGB32 ), i2( 32, 32, QImage::Format_RGB32 );
342 i1.fill( color: Qt::white );
343 i2.fill( color: Qt::black );
344 const qint64 i1k = i1.cacheKey();
345 const qint64 i2k = i2.cacheKey();
346 i1.swap(other&: i2);
347 QCOMPARE(i1.cacheKey(), i2k);
348 QCOMPARE(i1.size(), QSize(32,32));
349 QCOMPARE(i2.cacheKey(), i1k);
350 QCOMPARE(i2.size(), QSize(16,16));
351}
352
353// Test if QImage (or any functions called from QImage) throws an
354// exception when creating an extremely large image.
355// QImage::create() should return "false" in this case.
356void tst_QImage::create()
357{
358 bool cr = true;
359 QT_TRY {
360 QImage image(700000000, 70000000, QImage::Format_Indexed8);
361 image.setColorCount(256);
362 cr = !image.isNull();
363 } QT_CATCH (...) {
364 }
365 QVERIFY( !cr );
366}
367
368void tst_QImage::createInvalidXPM()
369{
370 QTest::ignoreMessage(type: QtWarningMsg, message: "QImage::QImage(), XPM is not supported");
371 const char *xpm[] = {""};
372 QImage invalidXPM(xpm);
373 QVERIFY(invalidXPM.isNull());
374}
375
376void tst_QImage::createFromUChar()
377{
378 uint data[] = { 0xff010101U,
379 0xff020202U,
380 0xff030303U,
381 0xff040404U };
382
383 // When the data is const, nothing you do to the image will change the source data.
384 QImage i1((const uchar*)data, 2, 2, 8, QImage::Format_RGB32);
385 QCOMPARE(i1.pixel(0,0), 0xFF010101U);
386 QCOMPARE(i1.pixel(1,0), 0xFF020202U);
387 QCOMPARE(i1.pixel(0,1), 0xFF030303U);
388 QCOMPARE(i1.pixel(1,1), 0xFF040404U);
389 {
390 QImage i(i1);
391 i.setPixel(x: 0,y: 0,index_or_rgb: 5);
392 }
393 QCOMPARE(i1.pixel(0,0), 0xFF010101U);
394 QCOMPARE(*(QRgb*)data, 0xFF010101U);
395 *((QRgb*)i1.bits()) = 0xFF070707U;
396 QCOMPARE(i1.pixel(0,0), 0xFF070707U);
397 QCOMPARE(*(QRgb*)data, 0xFF010101U);
398
399 // Changing copies should not change the original image or data.
400 {
401 QImage i(i1);
402 i.setPixel(x: 0,y: 0,index_or_rgb: 5);
403 QCOMPARE(*(QRgb*)data, 0xFF010101U);
404 i1.setPixel(x: 0,y: 0,index_or_rgb: 9);
405 QCOMPARE(i1.pixel(0,0), 0xFF000009U);
406 QCOMPARE(i.pixel(0,0), 0xFF000005U);
407 }
408 QCOMPARE(i1.pixel(0,0), 0xFF000009U);
409
410 // When the data is non-const, nothing you do to copies of the image will change the source data,
411 // but changing the image (here via bits()) will change the source data.
412 QImage i2((uchar*)data, 2, 2, 8, QImage::Format_RGB32);
413 QCOMPARE(i2.pixel(0,0), 0xFF010101U);
414 QCOMPARE(i2.pixel(1,0), 0xFF020202U);
415 QCOMPARE(i2.pixel(0,1), 0xFF030303U);
416 QCOMPARE(i2.pixel(1,1), 0xFF040404U);
417 {
418 QImage i(i2);
419 i.setPixel(x: 0,y: 0,index_or_rgb: 5);
420 }
421 QCOMPARE(i2.pixel(0,0), 0xFF010101U);
422 QCOMPARE(*(QRgb*)data, 0xFF010101U);
423 *((QRgb*)i2.bits()) = 0xFF070707U;
424 QCOMPARE(i2.pixel(0,0), 0xFF070707U);
425 QCOMPARE(*(QRgb*)data, 0xFF070707U);
426
427 // Changing the data will change the image in either case.
428 QImage i3((uchar*)data, 2, 2, 8, QImage::Format_RGB32);
429 QImage i4((const uchar*)data, 2, 2, 8, QImage::Format_RGB32);
430 *(QRgb*)data = 0xFF060606U;
431 QCOMPARE(i3.pixel(0,0), 0xFF060606U);
432 QCOMPARE(i4.pixel(0,0), 0xFF060606U);
433}
434
435void tst_QImage::formatHandlersInput_data()
436{
437 QTest::addColumn<QString>(name: "testFormat");
438 QTest::addColumn<QString>(name: "testFile");
439
440 // add a new line here when a file is added
441 QTest::newRow(dataTag: "ICO") << "ICO" << m_prefix + "image.ico";
442 QTest::newRow(dataTag: "PNG") << "PNG" << m_prefix + "image.png";
443 QTest::newRow(dataTag: "GIF") << "GIF" << m_prefix + "image.gif";
444 QTest::newRow(dataTag: "BMP") << "BMP" << m_prefix + "image.bmp";
445 QTest::newRow(dataTag: "JPEG") << "JPEG" << m_prefix + "image.jpg";
446 QTest::newRow(dataTag: "PBM") << "PBM" << m_prefix + "image.pbm";
447 QTest::newRow(dataTag: "PGM") << "PGM" << m_prefix + "image.pgm";
448 QTest::newRow(dataTag: "PPM") << "PPM" << m_prefix + "image.ppm";
449 QTest::newRow(dataTag: "XBM") << "XBM" << m_prefix + "image.xbm";
450 QTest::newRow(dataTag: "XPM") << "XPM" << m_prefix + "image.xpm";
451}
452
453void tst_QImage::formatHandlersInput()
454{
455 QFETCH(QString, testFormat);
456 QFETCH(QString, testFile);
457 QList<QByteArray> formats = QImageReader::supportedImageFormats();
458 // qDebug("Image input formats : %s", formats.join(" | ").latin1());
459
460 bool formatSupported = false;
461 for (QList<QByteArray>::Iterator it = formats.begin(); it != formats.end(); ++it) {
462 if (*it == testFormat.toLower().toUtf8()) {
463 formatSupported = true;
464 break;
465 }
466 }
467 if (formatSupported) {
468// qDebug(QImage::imageFormat(testFile));
469 QCOMPARE(testFormat.toLatin1().toLower(), QImageReader::imageFormat(testFile));
470 } else {
471 QString msg = "Format not supported : ";
472 QSKIP(QString(msg + testFormat).toLatin1());
473 }
474}
475
476void tst_QImage::setAlphaChannel_data()
477{
478 QTest::addColumn<int>(name: "red");
479 QTest::addColumn<int>(name: "green");
480 QTest::addColumn<int>(name: "blue");
481 QTest::addColumn<int>(name: "alpha");
482 QTest::addColumn<bool>(name: "gray");
483
484 QTest::newRow(dataTag: "red at 0%, gray") << 255 << 0 << 0 << 0 << true;
485 QTest::newRow(dataTag: "red at 25%, gray") << 255 << 0 << 0 << 63 << true;
486 QTest::newRow(dataTag: "red at 50%, gray") << 255 << 0 << 0 << 127 << true;
487 QTest::newRow(dataTag: "red at 100%, gray") << 255 << 0 << 0 << 191 << true;
488 QTest::newRow(dataTag: "red at 0%, 32bit") << 255 << 0 << 0 << 0 << false;
489 QTest::newRow(dataTag: "red at 25%, 32bit") << 255 << 0 << 0 << 63 << false;
490 QTest::newRow(dataTag: "red at 50%, 32bit") << 255 << 0 << 0 << 127 << false;
491 QTest::newRow(dataTag: "red at 100%, 32bit") << 255 << 0 << 0 << 191 << false;
492
493 QTest::newRow(dataTag: "green at 0%, gray") << 0 << 255 << 0 << 0 << true;
494 QTest::newRow(dataTag: "green at 25%, gray") << 0 << 255 << 0 << 63 << true;
495 QTest::newRow(dataTag: "green at 50%, gray") << 0 << 255 << 0 << 127 << true;
496 QTest::newRow(dataTag: "green at 100%, gray") << 0 << 255 << 0 << 191 << true;
497 QTest::newRow(dataTag: "green at 0%, 32bit") << 0 << 255 << 0 << 0 << false;
498 QTest::newRow(dataTag: "green at 25%, 32bit") << 0 << 255 << 0 << 63 << false;
499 QTest::newRow(dataTag: "green at 50%, 32bit") << 0 << 255 << 0 << 127 << false;
500 QTest::newRow(dataTag: "green at 100%, 32bit") << 0 << 255 << 0 << 191 << false;
501
502 QTest::newRow(dataTag: "blue at 0%, gray") << 0 << 0 << 255 << 0 << true;
503 QTest::newRow(dataTag: "blue at 25%, gray") << 0 << 0 << 255 << 63 << true;
504 QTest::newRow(dataTag: "blue at 50%, gray") << 0 << 0 << 255 << 127 << true;
505 QTest::newRow(dataTag: "blue at 100%, gray") << 0 << 0 << 255 << 191 << true;
506 QTest::newRow(dataTag: "blue at 0%, 32bit") << 0 << 0 << 255 << 0 << false;
507 QTest::newRow(dataTag: "blue at 25%, 32bit") << 0 << 0 << 255 << 63 << false;
508 QTest::newRow(dataTag: "blue at 50%, 32bit") << 0 << 0 << 255 << 127 << false;
509 QTest::newRow(dataTag: "blue at 100%, 32bit") << 0 << 0 << 255 << 191 << false;
510}
511
512void tst_QImage::setAlphaChannel()
513{
514 QFETCH(int, red);
515 QFETCH(int, green);
516 QFETCH(int, blue);
517 QFETCH(int, alpha);
518 QFETCH(bool, gray);
519
520 int width = 100;
521 int height = 100;
522
523 QImage image(width, height, QImage::Format_RGB32);
524 image.fill(pixel: qRgb(r: red, g: green, b: blue));
525
526 // Create the alpha channel
527 QImage alphaChannel;
528 if (gray) {
529 alphaChannel = QImage(width, height, QImage::Format_Indexed8);
530 alphaChannel.setColorCount(256);
531 for (int i=0; i<256; ++i)
532 alphaChannel.setColor(i, c: qRgb(r: i, g: i, b: i));
533 alphaChannel.fill(pixel: alpha);
534 } else {
535 alphaChannel = QImage(width, height, QImage::Format_ARGB32);
536 alphaChannel.fill(pixel: qRgb(r: alpha, g: alpha, b: alpha));
537 }
538
539 image.setAlphaChannel(alphaChannel);
540 image = image.convertToFormat(f: QImage::Format_ARGB32);
541 QCOMPARE(image.format(), QImage::Format_ARGB32);
542
543 // alpha of 0 becomes black at a=0 due to premultiplication
544 QRgb pixel = alpha == 0 ? 0 : qRgba(r: red, g: green, b: blue, a: alpha);
545 bool allPixelsOK = true;
546 for (int y=0; y<height; ++y) {
547 for (int x=0; x<width; ++x) {
548 allPixelsOK &= image.pixel(x, y) == pixel;
549 }
550 }
551 QVERIFY(allPixelsOK);
552
553 QImage outAlpha = image.alphaChannel();
554 QCOMPARE(outAlpha.size(), image.size());
555
556 bool allAlphaOk = true;
557 for (int y=0; y<height; ++y) {
558 for (int x=0; x<width; ++x) {
559 allAlphaOk &= outAlpha.pixelIndex(x, y) == alpha;
560 }
561 }
562 QVERIFY(allAlphaOk);
563
564}
565
566void tst_QImage::alphaChannel()
567{
568 QImage img(10, 10, QImage::Format_Mono);
569 img.setColor(i: 0, c: Qt::transparent);
570 img.setColor(i: 1, c: Qt::black);
571 img.fill(pixel: 0);
572
573 QPainter p(&img);
574 p.fillRect(x: 2, y: 2, w: 6, h: 6, c: Qt::black);
575 p.end();
576
577 QCOMPARE(img.alphaChannel(), img.convertToFormat(QImage::Format_ARGB32).alphaChannel());
578}
579
580void tst_QImage::convertToFormat_data()
581{
582 QTest::addColumn<int>(name: "inFormat");
583 QTest::addColumn<uint>(name: "inPixel");
584 QTest::addColumn<int>(name: "resFormat");
585 QTest::addColumn<uint>(name: "resPixel");
586
587 QTest::newRow(dataTag: "red rgb32 -> argb32") << int(QImage::Format_RGB32) << 0xffff0000
588 << int(QImage::Format_ARGB32) << 0xffff0000;
589 QTest::newRow(dataTag: "green rgb32 -> argb32") << int(QImage::Format_RGB32) << 0xff00ff00
590 << int(QImage::Format_ARGB32) << 0xff00ff00;
591 QTest::newRow(dataTag: "blue rgb32 -> argb32") << int(QImage::Format_RGB32) << 0xff0000ff
592 << int(QImage::Format_ARGB32) << 0xff0000ff;
593
594 QTest::newRow(dataTag: "red rgb32 -> rgb16") << int(QImage::Format_RGB32) << 0xffff0000
595 << int(QImage::Format_RGB16) << 0xffff0000;
596 QTest::newRow(dataTag: "green rgb32 -> rgb16") << int(QImage::Format_RGB32) << 0xff00ff00
597 << int(QImage::Format_RGB16) << 0xff00ff00;
598 QTest::newRow(dataTag: "blue rgb32 -> rgb16") << int(QImage::Format_RGB32) << 0xff0000ff
599 << int(QImage::Format_RGB16) << 0xff0000ff;
600 QTest::newRow(dataTag: "funky rgb32 -> rgb16") << int(QImage::Format_RGB32) << 0xfff0c080
601 << int(QImage::Format_RGB16) << 0xfff7c384;
602
603 QTest::newRow(dataTag: "red rgb32 -> argb32_pm") << int(QImage::Format_RGB32) << 0xffff0000
604 << int(QImage::Format_ARGB32_Premultiplied) << 0xffff0000;
605 QTest::newRow(dataTag: "green rgb32 -> argb32_pm") << int(QImage::Format_RGB32) << 0xff00ff00
606 << int(QImage::Format_ARGB32_Premultiplied) <<0xff00ff00;
607 QTest::newRow(dataTag: "blue rgb32 -> argb32_pm") << int(QImage::Format_RGB32) << 0xff0000ff
608 << int(QImage::Format_ARGB32_Premultiplied) << 0xff0000ff;
609
610 QTest::newRow(dataTag: "semired argb32 -> pm") << int(QImage::Format_ARGB32) << 0x7fff0000u
611 << int(QImage::Format_ARGB32_Premultiplied) << 0x7f7f0000u;
612 QTest::newRow(dataTag: "semigreen argb32 -> pm") << int(QImage::Format_ARGB32) << 0x7f00ff00u
613 << int(QImage::Format_ARGB32_Premultiplied) << 0x7f007f00u;
614 QTest::newRow(dataTag: "semiblue argb32 -> pm") << int(QImage::Format_ARGB32) << 0x7f0000ffu
615 << int(QImage::Format_ARGB32_Premultiplied) << 0x7f00007fu;
616 QTest::newRow(dataTag: "semiwhite argb32 -> pm") << int(QImage::Format_ARGB32) << 0x7fffffffu
617 << int(QImage::Format_ARGB32_Premultiplied) << 0x7f7f7f7fu;
618 QTest::newRow(dataTag: "semiblack argb32 -> pm") << int(QImage::Format_ARGB32) << 0x7f000000u
619 << int(QImage::Format_ARGB32_Premultiplied) << 0x7f000000u;
620
621 QTest::newRow(dataTag: "semired pm -> argb32") << int(QImage::Format_ARGB32_Premultiplied) << 0x7f7f0000u
622 << int(QImage::Format_ARGB32) << 0x7fff0000u;
623 QTest::newRow(dataTag: "semigreen pm -> argb32") << int(QImage::Format_ARGB32_Premultiplied) << 0x7f007f00u
624 << int(QImage::Format_ARGB32) << 0x7f00ff00u;
625 QTest::newRow(dataTag: "semiblue pm -> argb32") << int(QImage::Format_ARGB32_Premultiplied) << 0x7f00007fu
626 << int(QImage::Format_ARGB32) << 0x7f0000ffu;
627 QTest::newRow(dataTag: "semiwhite pm -> argb32") << int(QImage::Format_ARGB32_Premultiplied) << 0x7f7f7f7fu
628 << int(QImage::Format_ARGB32) << 0x7fffffffu;
629 QTest::newRow(dataTag: "semiblack pm -> argb32") << int(QImage::Format_ARGB32_Premultiplied) << 0x7f000000u
630 << int(QImage::Format_ARGB32) << 0x7f000000u;
631
632 QTest::newRow(dataTag: "semired pm -> rgb32") << int(QImage::Format_ARGB32_Premultiplied) << 0x7f7f0000u
633 << int(QImage::Format_RGB32) << 0xffff0000u;
634 QTest::newRow(dataTag: "semigreen pm -> rgb32") << int(QImage::Format_ARGB32_Premultiplied) << 0x7f007f00u
635 << int(QImage::Format_RGB32) << 0xff00ff00u;
636 QTest::newRow(dataTag: "semiblue pm -> rgb32") << int(QImage::Format_ARGB32_Premultiplied) << 0x7f00007fu
637 << int(QImage::Format_RGB32) << 0xff0000ffu;
638 QTest::newRow(dataTag: "semiwhite pm -> rgb32") << int(QImage::Format_ARGB32_Premultiplied) << 0x7f7f7f7fu
639 << int(QImage::Format_RGB32) << 0xffffffffu;
640 QTest::newRow(dataTag: "semiblack pm -> rgb32") << int(QImage::Format_ARGB32_Premultiplied) << 0x7f000000u
641 << int(QImage::Format_RGB32) << 0xff000000u;
642
643 QTest::newRow(dataTag: "semired argb32 -> rgb32") << int(QImage::Format_ARGB32) << 0x7fff0000u
644 << int(QImage::Format_RGB32) << 0xffff0000u;
645 QTest::newRow(dataTag: "semigreen argb32 -> rgb32") << int(QImage::Format_ARGB32) << 0x7f00ff00u
646 << int(QImage::Format_RGB32) << 0xff00ff00u;
647 QTest::newRow(dataTag: "semiblue argb32 -> rgb32") << int(QImage::Format_ARGB32) << 0x7f0000ffu
648 << int(QImage::Format_RGB32) << 0xff0000ffu;
649 QTest::newRow(dataTag: "semiwhite argb -> rgb32") << int(QImage::Format_ARGB32) << 0x7fffffffu
650 << int(QImage::Format_RGB32) << 0xffffffffu;
651 QTest::newRow(dataTag: "semiblack argb -> rgb32") << int(QImage::Format_ARGB32) << 0x7f000000u
652 << int(QImage::Format_RGB32) << 0xff000000u;
653
654 QTest::newRow(dataTag: "black mono -> rgb32") << int(QImage::Format_Mono) << 0x00000000u
655 << int(QImage::Format_RGB32) << 0xff000000u;
656
657 QTest::newRow(dataTag: "white mono -> rgb32") << int(QImage::Format_Mono) << 0x00000001u
658 << int(QImage::Format_RGB32) << 0xffffffffu;
659 QTest::newRow(dataTag: "red rgb16 -> argb32") << int(QImage::Format_RGB16) << 0xffff0000
660 << int(QImage::Format_ARGB32) << 0xffff0000;
661 QTest::newRow(dataTag: "green rgb16 -> argb32") << int(QImage::Format_RGB16) << 0xff00ff00
662 << int(QImage::Format_ARGB32) << 0xff00ff00;
663 QTest::newRow(dataTag: "blue rgb16 -> argb32") << int(QImage::Format_RGB16) << 0xff0000ff
664 << int(QImage::Format_ARGB32) << 0xff0000ff;
665 QTest::newRow(dataTag: "red rgb16 -> rgb16") << int(QImage::Format_RGB32) << 0xffff0000
666 << int(QImage::Format_RGB16) << 0xffff0000;
667 QTest::newRow(dataTag: "green rgb16 -> rgb16") << int(QImage::Format_RGB32) << 0xff00ff00
668 << int(QImage::Format_RGB16) << 0xff00ff00;
669 QTest::newRow(dataTag: "blue rgb16 -> rgb16") << int(QImage::Format_RGB32) << 0xff0000ff
670 << int(QImage::Format_RGB16) << 0xff0000ff;
671 QTest::newRow(dataTag: "semired argb32 -> rgb16") << int(QImage::Format_ARGB32) << 0x7fff0000u
672 << int(QImage::Format_RGB16) << 0xffff0000;
673 QTest::newRow(dataTag: "semigreen argb32 -> rgb16") << int(QImage::Format_ARGB32) << 0x7f00ff00u
674 << int(QImage::Format_RGB16) << 0xff00ff00;
675 QTest::newRow(dataTag: "semiblue argb32 -> rgb16") << int(QImage::Format_ARGB32) << 0x7f0000ffu
676 << int(QImage::Format_RGB16) << 0xff0000ff;
677 QTest::newRow(dataTag: "semired pm -> rgb16") << int(QImage::Format_ARGB32_Premultiplied) << 0x7f7f0000u
678 << int(QImage::Format_RGB16) << 0xffff0000u;
679
680 QTest::newRow(dataTag: "semigreen pm -> rgb16") << int(QImage::Format_ARGB32_Premultiplied) << 0x7f007f00u
681 << int(QImage::Format_RGB16) << 0xff00ff00u;
682 QTest::newRow(dataTag: "semiblue pm -> rgb16") << int(QImage::Format_ARGB32_Premultiplied) << 0x7f00007fu
683 << int(QImage::Format_RGB16) << 0xff0000ffu;
684 QTest::newRow(dataTag: "semiwhite pm -> rgb16") << int(QImage::Format_ARGB32_Premultiplied) << 0x7f7f7f7fu
685 << int(QImage::Format_RGB16) << 0xffffffffu;
686 QTest::newRow(dataTag: "semiblack pm -> rgb16") << int(QImage::Format_ARGB32_Premultiplied) << 0x7f000000u
687 << int(QImage::Format_RGB16) << 0xff000000u;
688
689 QTest::newRow(dataTag: "mono -> mono lsb") << int(QImage::Format_Mono) << 1u
690 << int(QImage::Format_MonoLSB) << 0xffffffffu;
691 QTest::newRow(dataTag: "mono lsb -> mono") << int(QImage::Format_MonoLSB) << 1u
692 << int(QImage::Format_Mono) << 0xffffffffu;
693
694 QTest::newRow(dataTag: "red rgb32 -> rgb666") << int(QImage::Format_RGB32) << 0xffff0000
695 << int(QImage::Format_RGB666) << 0xffff0000;
696 QTest::newRow(dataTag: "green rgb32 -> rgb666") << int(QImage::Format_RGB32) << 0xff00ff00
697 << int(QImage::Format_RGB666) << 0xff00ff00;
698 QTest::newRow(dataTag: "blue rgb32 -> rgb666") << int(QImage::Format_RGB32) << 0xff0000ff
699 << int(QImage::Format_RGB666) << 0xff0000ff;
700
701 QTest::newRow(dataTag: "red rgb16 -> rgb666") << int(QImage::Format_RGB16) << 0xffff0000
702 << int(QImage::Format_RGB666) << 0xffff0000;
703 QTest::newRow(dataTag: "green rgb16 -> rgb666") << int(QImage::Format_RGB16) << 0xff00ff00
704 << int(QImage::Format_RGB666) << 0xff00ff00;
705 QTest::newRow(dataTag: "blue rgb16 -> rgb666") << int(QImage::Format_RGB16) << 0xff0000ff
706 << int(QImage::Format_RGB666) << 0xff0000ff;
707
708 QTest::newRow(dataTag: "red rgb32 -> rgb15") << int(QImage::Format_RGB32) << 0xffff0000
709 << int(QImage::Format_RGB555) << 0xffff0000;
710 QTest::newRow(dataTag: "green rgb32 -> rgb15") << int(QImage::Format_RGB32) << 0xff00ff00
711 << int(QImage::Format_RGB555) << 0xff00ff00;
712 QTest::newRow(dataTag: "blue rgb32 -> rgb15") << int(QImage::Format_RGB32) << 0xff0000ff
713 << int(QImage::Format_RGB555) << 0xff0000ff;
714 QTest::newRow(dataTag: "funky rgb32 -> rgb15") << int(QImage::Format_RGB32) << 0xfff0c080
715 << int(QImage::Format_RGB555) << 0xfff7c684;
716
717 QTest::newRow(dataTag: "red rgb16 -> rgb15") << int(QImage::Format_RGB16) << 0xffff0000
718 << int(QImage::Format_RGB555) << 0xffff0000;
719 QTest::newRow(dataTag: "green rgb16 -> rgb15") << int(QImage::Format_RGB16) << 0xff00ff00
720 << int(QImage::Format_RGB555) << 0xff00ff00;
721 QTest::newRow(dataTag: "blue rgb16 -> rgb15") << int(QImage::Format_RGB16) << 0xff0000ff
722 << int(QImage::Format_RGB555) << 0xff0000ff;
723 QTest::newRow(dataTag: "funky rgb16 -> rgb15") << int(QImage::Format_RGB16) << 0xfff0c080
724 << int(QImage::Format_RGB555) << 0xfff7c684;
725
726 QTest::newRow(dataTag: "red rgb32 -> argb8565") << int(QImage::Format_RGB32) << 0xffff0000
727 << int(QImage::Format_ARGB8565_Premultiplied) << 0xffff0000;
728 QTest::newRow(dataTag: "green rgb32 -> argb8565") << int(QImage::Format_RGB32) << 0xff00ff00
729 << int(QImage::Format_ARGB8565_Premultiplied) << 0xff00ff00;
730 QTest::newRow(dataTag: "blue rgb32 -> argb8565") << int(QImage::Format_RGB32) << 0xff0000ff
731 << int(QImage::Format_ARGB8565_Premultiplied) << 0xff0000ff;
732
733 QTest::newRow(dataTag: "red rgb16 -> argb8565") << int(QImage::Format_RGB16) << 0xffff0000
734 << int(QImage::Format_ARGB8565_Premultiplied) << 0xffff0000;
735 QTest::newRow(dataTag: "green rgb16 -> argb8565") << int(QImage::Format_RGB16) << 0xff00ff00
736 << int(QImage::Format_ARGB8565_Premultiplied) << 0xff00ff00;
737 QTest::newRow(dataTag: "blue rgb16 -> argb8565") << int(QImage::Format_RGB16) << 0xff0000ff
738 << int(QImage::Format_ARGB8565_Premultiplied) << 0xff0000ff;
739
740 QTest::newRow(dataTag: "red argb8565 -> argb32") << int(QImage::Format_ARGB8565_Premultiplied) << 0xffff0000
741 << int(QImage::Format_ARGB32) << 0xffff0000;
742 QTest::newRow(dataTag: "green argb8565 -> argb32") << int(QImage::Format_ARGB8565_Premultiplied) << 0xff00ff00
743 << int(QImage::Format_ARGB32) << 0xff00ff00;
744 QTest::newRow(dataTag: "blue argb8565 -> argb32") << int(QImage::Format_ARGB8565_Premultiplied) << 0xff0000ff
745 << int(QImage::Format_ARGB32) << 0xff0000ff;
746
747 QTest::newRow(dataTag: "semired argb32 -> argb8565") << int(QImage::Format_ARGB32) << 0x7fff0000u
748 << int(QImage::Format_ARGB8565_Premultiplied) << 0x7f7b0000u;
749 QTest::newRow(dataTag: "semigreen argb32 -> argb8565") << int(QImage::Format_ARGB32) << 0x7f00ff00u
750 << int(QImage::Format_ARGB8565_Premultiplied) << 0x7f007d00u;
751 QTest::newRow(dataTag: "semiblue argb32 -> argb8565") << int(QImage::Format_ARGB32) << 0x7f0000ffu
752 << int(QImage::Format_ARGB8565_Premultiplied) << 0x7f00007bu;
753
754 QTest::newRow(dataTag: "semired pm -> argb8565") << int(QImage::Format_ARGB32_Premultiplied) << 0x7f7f0000u
755 << int(QImage::Format_ARGB8565_Premultiplied) << 0x7f7b0000u;
756 QTest::newRow(dataTag: "semigreen pm -> argb8565") << int(QImage::Format_ARGB32_Premultiplied) << 0x7f007f00u
757 << int(QImage::Format_ARGB8565_Premultiplied) << 0x7f007d00u;
758 QTest::newRow(dataTag: "semiblue pm -> argb8565") << int(QImage::Format_ARGB32_Premultiplied) << 0x7f00007fu
759 << int(QImage::Format_ARGB8565_Premultiplied) << 0x7f00007bu;
760 QTest::newRow(dataTag: "semiwhite pm -> argb8565") << int(QImage::Format_ARGB32_Premultiplied) << 0x7f7f7f7fu
761 << int(QImage::Format_ARGB8565_Premultiplied) << 0x7f7b7d7bu;
762 QTest::newRow(dataTag: "semiblack pm -> argb8565") << int(QImage::Format_ARGB32_Premultiplied) << 0x7f000000u
763 << int(QImage::Format_ARGB8565_Premultiplied) << 0x7f000000u;
764
765 QTest::newRow(dataTag: "red rgb666 -> argb32") << int(QImage::Format_RGB666) << 0xffff0000
766 << int(QImage::Format_ARGB32) << 0xffff0000;
767 QTest::newRow(dataTag: "green rgb666 -> argb32") << int(QImage::Format_RGB666) << 0xff00ff00
768 << int(QImage::Format_ARGB32) << 0xff00ff00;
769 QTest::newRow(dataTag: "blue rgb666 -> argb32") << int(QImage::Format_RGB666) << 0xff0000ff
770 << int(QImage::Format_ARGB32) << 0xff0000ff;
771
772 QTest::newRow(dataTag: "semired argb32 -> rgb666") << int(QImage::Format_ARGB32) << 0x7fff0000u
773 << int(QImage::Format_RGB666) << 0xffff0000;
774 QTest::newRow(dataTag: "semigreen argb32 -> rgb666") << int(QImage::Format_ARGB32) << 0x7f00ff00u
775 << int(QImage::Format_RGB666) << 0xff00ff00;
776 QTest::newRow(dataTag: "semiblue argb32 -> rgb666") << int(QImage::Format_ARGB32) << 0x7f0000ffu
777 << int(QImage::Format_RGB666) << 0xff0000ff;
778
779 QTest::newRow(dataTag: "semired pm -> rgb666") << int(QImage::Format_ARGB32_Premultiplied) << 0x7f7f0000u
780 << int(QImage::Format_RGB666) << 0xffff0000u;
781 QTest::newRow(dataTag: "semigreen pm -> rgb666") << int(QImage::Format_ARGB32_Premultiplied) << 0x7f007f00u
782 << int(QImage::Format_RGB666) << 0xff00ff00u;
783 QTest::newRow(dataTag: "semiblue pm -> rgb666") << int(QImage::Format_ARGB32_Premultiplied) << 0x7f00007fu
784 << int(QImage::Format_RGB666) << 0xff0000ffu;
785 QTest::newRow(dataTag: "semiwhite pm -> rgb666") << int(QImage::Format_ARGB32_Premultiplied) << 0x7f7f7f7fu
786 << int(QImage::Format_RGB666) << 0xffffffffu;
787 QTest::newRow(dataTag: "semiblack pm -> rgb666") << int(QImage::Format_ARGB32_Premultiplied) << 0x7f000000u
788 << int(QImage::Format_RGB666) << 0xff000000u;
789
790 QTest::newRow(dataTag: "red rgb15 -> argb32") << int(QImage::Format_RGB555) << 0xffff0000
791 << int(QImage::Format_ARGB32) << 0xffff0000;
792 QTest::newRow(dataTag: "green rgb15 -> argb32") << int(QImage::Format_RGB555) << 0xff00ff00
793 << int(QImage::Format_ARGB32) << 0xff00ff00;
794 QTest::newRow(dataTag: "blue rgb15 -> argb32") << int(QImage::Format_RGB555) << 0xff0000ff
795 << int(QImage::Format_ARGB32) << 0xff0000ff;
796
797 QTest::newRow(dataTag: "semired argb32 -> rgb15") << int(QImage::Format_ARGB32) << 0x7fff0000u
798 << int(QImage::Format_RGB555) << 0xffff0000;
799 QTest::newRow(dataTag: "semigreen argb32 -> rgb15") << int(QImage::Format_ARGB32) << 0x7f00ff00u
800 << int(QImage::Format_RGB555) << 0xff00ff00;
801 QTest::newRow(dataTag: "semiblue argb32 -> rgb15") << int(QImage::Format_ARGB32) << 0x7f0000ffu
802 << int(QImage::Format_RGB555) << 0xff0000ff;
803
804 QTest::newRow(dataTag: "semired pm -> rgb15") << int(QImage::Format_ARGB32_Premultiplied) << 0x7f7f0000u
805 << int(QImage::Format_RGB555) << 0xffff0000u;
806 QTest::newRow(dataTag: "semigreen pm -> rgb15") << int(QImage::Format_ARGB32_Premultiplied) << 0x7f007f00u
807 << int(QImage::Format_RGB555) << 0xff00ff00u;
808 QTest::newRow(dataTag: "semiblue pm -> rgb15") << int(QImage::Format_ARGB32_Premultiplied) << 0x7f00007fu
809 << int(QImage::Format_RGB555) << 0xff0000ffu;
810 QTest::newRow(dataTag: "semiwhite pm -> rgb15") << int(QImage::Format_ARGB32_Premultiplied) << 0x7f7f7f7fu
811 << int(QImage::Format_RGB555) << 0xffffffffu;
812 QTest::newRow(dataTag: "semiblack pm -> rgb15") << int(QImage::Format_ARGB32_Premultiplied) << 0x7f000000u
813 << int(QImage::Format_RGB555) << 0xff000000u;
814
815
816 QTest::newRow(dataTag: "red rgb32 -> argb8555") << int(QImage::Format_RGB32) << 0xffff0000
817 << int(QImage::Format_ARGB8555_Premultiplied) << 0xffff0000;
818 QTest::newRow(dataTag: "green rgb32 -> argb8555") << int(QImage::Format_RGB32) << 0xff00ff00
819 << int(QImage::Format_ARGB8555_Premultiplied) << 0xff00ff00;
820 QTest::newRow(dataTag: "blue rgb32 -> argb8555") << int(QImage::Format_RGB32) << 0xff0000ff
821 << int(QImage::Format_ARGB8555_Premultiplied) << 0xff0000ff;
822
823 QTest::newRow(dataTag: "red rgb16 -> argb8555") << int(QImage::Format_RGB16) << 0xffff0000
824 << int(QImage::Format_ARGB8555_Premultiplied) << 0xffff0000;
825 QTest::newRow(dataTag: "green rgb16 -> argb8555") << int(QImage::Format_RGB16) << 0xff00ff00
826 << int(QImage::Format_ARGB8555_Premultiplied) << 0xff00ff00;
827 QTest::newRow(dataTag: "blue rgb16 -> argb8555") << int(QImage::Format_RGB16) << 0xff0000ff
828 << int(QImage::Format_ARGB8555_Premultiplied) << 0xff0000ff;
829
830 QTest::newRow(dataTag: "red argb8555 -> argb32") << int(QImage::Format_ARGB8555_Premultiplied) << 0xffff0000
831 << int(QImage::Format_ARGB32) << 0xffff0000;
832 QTest::newRow(dataTag: "green argb8555 -> argb32") << int(QImage::Format_ARGB8555_Premultiplied) << 0xff00ff00
833 << int(QImage::Format_ARGB32) << 0xff00ff00;
834 QTest::newRow(dataTag: "blue argb8555 -> argb32") << int(QImage::Format_ARGB8555_Premultiplied) << 0xff0000ff
835 << int(QImage::Format_ARGB32) << 0xff0000ff;
836
837 QTest::newRow(dataTag: "semired argb32 -> argb8555") << int(QImage::Format_ARGB32) << 0x7fff0000u
838 << int(QImage::Format_ARGB8555_Premultiplied) << 0x7f7b0000u;
839 QTest::newRow(dataTag: "semigreen argb32 -> argb8555") << int(QImage::Format_ARGB32) << 0x7f00ff00u
840 << int(QImage::Format_ARGB8555_Premultiplied) << 0x7f007b00u;
841 QTest::newRow(dataTag: "semiblue argb32 -> argb8555") << int(QImage::Format_ARGB32) << 0x7f0000ffu
842 << int(QImage::Format_ARGB8555_Premultiplied) << 0x7f00007bu;
843
844 QTest::newRow(dataTag: "semired pm -> argb8555") << int(QImage::Format_ARGB32_Premultiplied) << 0x7f7f0000u
845 << int(QImage::Format_ARGB8555_Premultiplied) << 0x7f7b0000u;
846 QTest::newRow(dataTag: "semigreen pm -> argb8555") << int(QImage::Format_ARGB32_Premultiplied) << 0x7f007f00u
847 << int(QImage::Format_ARGB8555_Premultiplied) << 0x7f007b00u;
848 QTest::newRow(dataTag: "semiblue pm -> argb8555") << int(QImage::Format_ARGB32_Premultiplied) << 0x7f00007fu
849 << int(QImage::Format_ARGB8555_Premultiplied) << 0x7f00007bu;
850 QTest::newRow(dataTag: "semiwhite pm -> argb8555") << int(QImage::Format_ARGB32_Premultiplied) << 0x7f7f7f7fu
851 << int(QImage::Format_ARGB8555_Premultiplied) << 0x7f7b7b7bu;
852 QTest::newRow(dataTag: "semiblack pm -> argb8555") << int(QImage::Format_ARGB32_Premultiplied) << 0x7f000000u
853 << int(QImage::Format_ARGB8555_Premultiplied) << 0x7f000000u;
854
855 QTest::newRow(dataTag: "red rgb32 -> rgb888") << int(QImage::Format_RGB32) << 0xffff0000
856 << int(QImage::Format_RGB888) << 0xffff0000;
857 QTest::newRow(dataTag: "green rgb32 -> rgb888") << int(QImage::Format_RGB32) << 0xff00ff00
858 << int(QImage::Format_RGB888) << 0xff00ff00;
859 QTest::newRow(dataTag: "blue rgb32 -> rgb888") << int(QImage::Format_RGB32) << 0xff0000ff
860 << int(QImage::Format_RGB888) << 0xff0000ff;
861
862 QTest::newRow(dataTag: "red rgb32 -> bgr888") << int(QImage::Format_RGB32) << 0xffff0000
863 << int(QImage::Format_BGR888) << 0xffff0000;
864 QTest::newRow(dataTag: "green rgb32 -> bgr888") << int(QImage::Format_RGB32) << 0xff00ff00
865 << int(QImage::Format_BGR888) << 0xff00ff00;
866 QTest::newRow(dataTag: "blue rgb32 -> bgr888") << int(QImage::Format_RGB32) << 0xff0000ff
867 << int(QImage::Format_BGR888) << 0xff0000ff;
868
869 QTest::newRow(dataTag: "red rgb16 -> rgb888") << int(QImage::Format_RGB16) << 0xffff0000
870 << int(QImage::Format_RGB888) << 0xffff0000;
871 QTest::newRow(dataTag: "green rgb16 -> rgb888") << int(QImage::Format_RGB16) << 0xff00ff00
872 << int(QImage::Format_RGB888) << 0xff00ff00;
873 QTest::newRow(dataTag: "blue rgb16 -> rgb888") << int(QImage::Format_RGB16) << 0xff0000ff
874 << int(QImage::Format_RGB888) << 0xff0000ff;
875
876 QTest::newRow(dataTag: "red rgb888 -> argb32") << int(QImage::Format_RGB888) << 0xffff0000
877 << int(QImage::Format_ARGB32) << 0xffff0000;
878 QTest::newRow(dataTag: "green rgb888 -> argb32") << int(QImage::Format_RGB888) << 0xff00ff00
879 << int(QImage::Format_ARGB32) << 0xff00ff00;
880 QTest::newRow(dataTag: "blue rgb888 -> argb32") << int(QImage::Format_RGB888) << 0xff0000ff
881 << int(QImage::Format_ARGB32) << 0xff0000ff;
882
883 QTest::newRow(dataTag: "red bgr888 -> argb32") << int(QImage::Format_RGB888) << 0xffff0000
884 << int(QImage::Format_ARGB32) << 0xffff0000;
885 QTest::newRow(dataTag: "green bgr888 -> argb32") << int(QImage::Format_RGB888) << 0xff00ff00
886 << int(QImage::Format_ARGB32) << 0xff00ff00;
887 QTest::newRow(dataTag: "blue bgr888 -> argb32") << int(QImage::Format_RGB888) << 0xff0000ff
888 << int(QImage::Format_ARGB32) << 0xff0000ff;
889
890 QTest::newRow(dataTag: "red rgb888 -> rgbx8888") << int(QImage::Format_RGB888) << 0xffff0000
891 << int(QImage::Format_RGBX8888) << 0xffff0000;
892 QTest::newRow(dataTag: "green rgb888 -> rgbx8888") << int(QImage::Format_RGB888) << 0xff00ff00
893 << int(QImage::Format_RGBX8888) << 0xff00ff00;
894 QTest::newRow(dataTag: "blue rgb888 -> rgbx8888") << int(QImage::Format_RGB888) << 0xff0000ff
895 << int(QImage::Format_RGBX8888) << 0xff0000ff;
896
897 QTest::newRow(dataTag: "semired argb32 -> rgb888") << int(QImage::Format_ARGB32) << 0x7fff0000u
898 << int(QImage::Format_RGB888) << 0xffff0000;
899 QTest::newRow(dataTag: "semigreen argb32 -> rgb888") << int(QImage::Format_ARGB32) << 0x7f00ff00u
900 << int(QImage::Format_RGB888) << 0xff00ff00;
901 QTest::newRow(dataTag: "semiblue argb32 -> rgb888") << int(QImage::Format_ARGB32) << 0x7f0000ffu
902 << int(QImage::Format_RGB888) << 0xff0000ff;
903
904 QTest::newRow(dataTag: "semired pm -> rgb888") << int(QImage::Format_ARGB32_Premultiplied) << 0x7f7f0000u
905 << int(QImage::Format_RGB888) << 0xffff0000u;
906 QTest::newRow(dataTag: "semigreen pm -> rgb888") << int(QImage::Format_ARGB32_Premultiplied) << 0x7f007f00u
907 << int(QImage::Format_RGB888) << 0xff00ff00u;
908 QTest::newRow(dataTag: "semiblue pm -> rgb888") << int(QImage::Format_ARGB32_Premultiplied) << 0x7f00007fu
909 << int(QImage::Format_RGB888) << 0xff0000ffu;
910 QTest::newRow(dataTag: "semiwhite pm -> rgb888") << int(QImage::Format_ARGB32_Premultiplied) << 0x7f7f7f7fu
911 << int(QImage::Format_RGB888) << 0xffffffffu;
912 QTest::newRow(dataTag: "semiblack pm -> rgb888") << int(QImage::Format_ARGB32_Premultiplied) << 0x7f000000u
913 << int(QImage::Format_RGB888) << 0xff000000u;
914
915 QTest::newRow(dataTag: "red rgba8888 -> argb32") << int(QImage::Format_RGBA8888) << 0xffff0000
916 << int(QImage::Format_ARGB32) << 0xffff0000;
917 QTest::newRow(dataTag: "green rgba8888 -> argb32") << int(QImage::Format_RGBA8888) << 0xff00ff00
918 << int(QImage::Format_ARGB32) << 0xff00ff00;
919 QTest::newRow(dataTag: "blue rgba8888 -> argb32") << int(QImage::Format_RGBA8888) << 0xff0000ff
920 << int(QImage::Format_ARGB32) << 0xff0000ff;
921
922 QTest::newRow(dataTag: "semired rgba8888 -> argb pm") << int(QImage::Format_RGBA8888) << 0x7fff0000u
923 << int(QImage::Format_ARGB32_Premultiplied) << 0x7f7f0000u;
924 QTest::newRow(dataTag: "semigreen rgba8888 -> argb pm") << int(QImage::Format_RGBA8888) << 0x7f00ff00u
925 << int(QImage::Format_ARGB32_Premultiplied) << 0x7f007f00u;
926 QTest::newRow(dataTag: "semiblue rgba8888 -> argb pm") << int(QImage::Format_RGBA8888) << 0x7f0000ffu
927 << int(QImage::Format_ARGB32_Premultiplied) << 0x7f00007fu;
928 QTest::newRow(dataTag: "semiwhite rgba8888 -> argb pm") << int(QImage::Format_RGBA8888) << 0x7fffffffu
929 << int(QImage::Format_ARGB32_Premultiplied) << 0x7f7f7f7fu;
930 QTest::newRow(dataTag: "semiblack rgba8888 -> argb pm") << int(QImage::Format_RGBA8888) << 0x7f000000u
931 << int(QImage::Format_ARGB32_Premultiplied) << 0x7f000000u;
932
933 QTest::newRow(dataTag: "red rgb30 -> argb32") << int(QImage::Format_RGB30) << 0xffff0000
934 << int(QImage::Format_ARGB32) << 0xffff0000;
935 QTest::newRow(dataTag: "green rgb30 -> argb32") << int(QImage::Format_RGB30) << 0xff00ff00
936 << int(QImage::Format_ARGB32) << 0xff00ff00;
937 QTest::newRow(dataTag: "blue rgb30 -> argb32") << int(QImage::Format_RGB30) << 0xff0000ff
938 << int(QImage::Format_ARGB32) << 0xff0000ff;
939
940 QTest::newRow(dataTag: "semigray argb32 -> a2rgb30 pm") << int(QImage::Format_ARGB32) << 0x4c646565u
941 << int(QImage::Format_A2RGB30_Premultiplied) << 0x55212222u;
942
943 QTest::newRow(dataTag: "white gray8 -> argb pm") << int(QImage::Format_Grayscale8) << 0xfffffeffu
944 << int(QImage::Format_ARGB32_Premultiplied) << 0xfffefefeu;
945 QTest::newRow(dataTag: "gray gray8 -> argb pm") << int(QImage::Format_Grayscale8) << 0xff565557u
946 << int(QImage::Format_ARGB32_Premultiplied) << 0xff555555u;
947 QTest::newRow(dataTag: "black gray8 -> argb pm") << int(QImage::Format_Grayscale8) << 0xff000100u
948 << int(QImage::Format_ARGB32_Premultiplied) << 0xff000000u;
949}
950
951
952void tst_QImage::convertToFormat()
953{
954 QFETCH(int, inFormat);
955 QFETCH(uint, inPixel);
956 QFETCH(int, resFormat);
957 QFETCH(uint, resPixel);
958
959 QImage src(32, 32, QImage::Format(inFormat));
960
961 if (inFormat == QImage::Format_Mono) {
962 src.setColor(i: 0, c: qRgba(r: 0,g: 0,b: 0,a: 0xff));
963 src.setColor(i: 1, c: qRgba(r: 255,g: 255,b: 255,a: 0xff));
964 }
965
966 for (int y=0; y<src.height(); ++y)
967 for (int x=0; x<src.width(); ++x)
968 src.setPixel(x, y, index_or_rgb: inPixel);
969
970 QImage result = src.convertToFormat(f: QImage::Format(resFormat));
971
972 QCOMPARE(src.width(), result.width());
973 QCOMPARE(src.height(), result.height());
974
975 bool same = true;
976 for (int y=0; y<result.height(); ++y) {
977 for (int x=0; x<result.width(); ++x) {
978 QRgb pixel = result.pixel(x, y);
979 same &= (pixel == resPixel);
980 if (!same) {
981 printf(format: "expect=%08x, result=%08x\n", resPixel, pixel);
982 y = 100000;
983 break;
984 }
985
986 }
987 }
988 QVERIFY(same);
989
990 // repeat tests converting from an image with nonstandard stride
991
992 int dp = (src.depth() < 8 || result.depth() < 8) ? 8 : 1;
993 QImage src2(src.bits() + (dp*src.depth())/8,
994 src.width() - dp*2,
995 src.height() - 1, src.bytesPerLine(),
996 src.format());
997 if (src.depth() < 8)
998 src2.setColorTable(src.colorTable());
999
1000 const QImage result2 = src2.convertToFormat(f: QImage::Format(resFormat));
1001
1002 QCOMPARE(src2.width(), result2.width());
1003 QCOMPARE(src2.height(), result2.height());
1004
1005 QImage expected2(result.bits() + (dp*result.depth())/8,
1006 result.width() - dp*2,
1007 result.height() - 1, result.bytesPerLine(),
1008 result.format());
1009 if (result.depth() < 8)
1010 expected2.setColorTable(result.colorTable());
1011
1012 result2.save(fileName: "result2.xpm", format: "XPM");
1013 expected2.save(fileName: "expected2.xpm", format: "XPM");
1014
1015 QCOMPARE(result2, expected2);
1016 QFile::remove(fileName: QLatin1String("result2.xpm"));
1017 QFile::remove(fileName: QLatin1String("expected2.xpm"));
1018}
1019
1020void tst_QImage::convertToFormatWithColorTable()
1021{
1022 QVector<QRgb> colors(2);
1023 colors[0] = 0xFF000000;
1024 colors[1] = 0xFFFFFFFF;
1025 for (int format = QImage::Format_RGB32; format < QImage::Format_Alpha8; ++format) {
1026 QImage fromImage(10, 10, (QImage::Format)format);
1027 QImage bitmap = fromImage.convertToFormat(f: QImage::Format_Mono, colorTable: colors);
1028 QVERIFY(!bitmap.isNull());
1029 }
1030}
1031
1032void tst_QImage::convertToFormatRgb888ToRGB32()
1033{
1034 // 545 so width % 4 != 0. This ensure there is padding at the end of the scanlines
1035 const int height = 545;
1036 const int width = 545;
1037 QImage source(width, height, QImage::Format_RGB888);
1038 for (int y = 0; y < height; ++y) {
1039 uchar *srcPixels = source.scanLine(y);
1040 for (int x = 0; x < width * 3; ++x)
1041 srcPixels[x] = x;
1042 }
1043
1044 QImage rgb32Image = source.convertToFormat(f: QImage::Format_RGB888);
1045 QCOMPARE(rgb32Image.format(), QImage::Format_RGB888);
1046 for (int x = 0; x < width; ++x) {
1047 for (int y = 0; y < height; ++y)
1048 QCOMPARE(rgb32Image.pixel(x, y), source.pixel(x, y));
1049 }
1050}
1051
1052void tst_QImage::createAlphaMask_data()
1053{
1054 QTest::addColumn<int>(name: "x");
1055 QTest::addColumn<int>(name: "y");
1056 QTest::addColumn<int>(name: "alpha1");
1057 QTest::addColumn<int>(name: "alpha2");
1058
1059 int alphas[] = { 0, 127, 255 };
1060
1061 for (unsigned a1 = 0; a1 < sizeof(alphas) / sizeof(int); ++a1) {
1062 const QByteArray a1B = QByteArray::number(alphas[a1]);
1063 for (unsigned a2 = 0; a2 < sizeof(alphas) / sizeof(int); ++a2) {
1064 if (a1 == a2)
1065 continue;
1066 const QByteArray a2B = QByteArray::number(alphas[a2]);
1067 for (int x=10; x<18; x+=3) {
1068 const QByteArray xB = QByteArray::number(x);
1069 for (int y=100; y<108; y+=3) {
1070 const QByteArray testName = "x=" + xB + ", y=" + QByteArray::number(y)
1071 + ", a1=" + a1B + ", a2=" + a2B;
1072 QTest::newRow(dataTag: testName.constData()) << x << y << alphas[a1] << alphas[a2];
1073 }
1074 }
1075 }
1076 }
1077}
1078
1079void tst_QImage::createAlphaMask()
1080{
1081 QFETCH(int, x);
1082 QFETCH(int, y);
1083 QFETCH(int, alpha1);
1084 QFETCH(int, alpha2);
1085
1086 QSize size(255, 255);
1087 int pixelsInLines = size.width() + size.height() - 1;
1088 int pixelsOutofLines = size.width() * size.height() - pixelsInLines;
1089
1090 // Generate an white image with two lines, horizontal at y and vertical at x.
1091 // Lines have alpha of alpha2, rest has alpha of alpha1
1092 QImage image(size, QImage::Format_ARGB32);
1093 for (int cy=0; cy<image.height(); ++cy) {
1094 for (int cx=0; cx<image.width(); ++cx) {
1095 int alpha = (y == cy || x == cx) ? alpha2 : alpha1;
1096 image.setPixel(x: cx, y: cy, index_or_rgb: qRgba(r: 255, g: 255, b: 255, a: alpha));
1097 }
1098 }
1099
1100 QImage mask = image.createAlphaMask(flags: Qt::OrderedAlphaDither);
1101
1102 // Sanity check...
1103 QCOMPARE(mask.width(), image.width());
1104 QCOMPARE(mask.height(), image.height());
1105
1106 // Sum up the number of pixels set for both lines and other area
1107 int sumAlpha1 = 0;
1108 int sumAlpha2 = 0;
1109 for (int cy=0; cy<image.height(); ++cy) {
1110 for (int cx=0; cx<image.width(); ++cx) {
1111 int *alpha = (y == cy || x == cx) ? &sumAlpha2 : &sumAlpha1;
1112 *alpha += mask.pixelIndex(x: cx, y: cy);
1113 }
1114 }
1115
1116 // Compare the set bits to whats expected for that alpha.
1117 const int threshold = 5;
1118 QVERIFY(qAbs(sumAlpha1 * 255 / pixelsOutofLines - alpha1) < threshold);
1119 QVERIFY(qAbs(sumAlpha2 * 255 / pixelsInLines - alpha2) < threshold);
1120}
1121
1122void tst_QImage::dotsPerMeterZero()
1123{
1124 QImage img(100, 100, QImage::Format_RGB32);
1125 QVERIFY(!img.isNull());
1126
1127 int defaultDpmX = img.dotsPerMeterX();
1128 int defaultDpmY = img.dotsPerMeterY();
1129 QVERIFY(defaultDpmX != 0);
1130 QVERIFY(defaultDpmY != 0);
1131
1132 img.setDotsPerMeterX(0);
1133 img.setDotsPerMeterY(0);
1134
1135 QCOMPARE(img.dotsPerMeterX(), defaultDpmX);
1136 QCOMPARE(img.dotsPerMeterY(), defaultDpmY);
1137
1138}
1139
1140// verify that setting dotsPerMeter has an effect on the dpi.
1141void tst_QImage::dotsPerMeterAndDpi()
1142{
1143 QImage img(100, 100, QImage::Format_RGB32);
1144 QVERIFY(!img.isNull());
1145
1146 QPoint defaultLogicalDpi(img.logicalDpiX(), img.logicalDpiY());
1147 QPoint defaultPhysicalDpi(img.physicalDpiX(), img.physicalDpiY());
1148
1149 img.setDotsPerMeterX(100); // set x
1150 QCOMPARE(img.logicalDpiY(), defaultLogicalDpi.y()); // no effect on y
1151 QCOMPARE(img.physicalDpiY(), defaultPhysicalDpi.y());
1152 QVERIFY(img.logicalDpiX() != defaultLogicalDpi.x()); // x changed
1153 QVERIFY(img.physicalDpiX() != defaultPhysicalDpi.x());
1154
1155 img.setDotsPerMeterY(200); // set y
1156 QVERIFY(img.logicalDpiY() != defaultLogicalDpi.y()); // y changed
1157 QVERIFY(img.physicalDpiY() != defaultPhysicalDpi.y());
1158}
1159
1160void tst_QImage::rotate_data()
1161{
1162 QTest::addColumn<QImage::Format>(name: "format");
1163 QTest::addColumn<int>(name: "degrees");
1164
1165 QVector<int> degrees;
1166 degrees << 0 << 90 << 180 << 270;
1167
1168 foreach (int d, degrees) {
1169 const QString dB = QString::number(d);
1170 for (int i = QImage::Format_Indexed8; i < QImage::NImageFormats; i++) {
1171 QImage::Format format = static_cast<QImage::Format>(i);
1172 QTest::newRow(qPrintable(dB + " " + formatToString(format))) << format << d;
1173 }
1174 }
1175}
1176
1177void tst_QImage::rotate()
1178{
1179 QFETCH(QImage::Format, format);
1180 QFETCH(int, degrees);
1181
1182 // test if rotate90 is lossless
1183 int w = 54;
1184 int h = 13;
1185 QImage original(w, h, format);
1186 original.fill(pixel: qRgb(r: 255,g: 255,b: 255));
1187
1188 if (format == QImage::Format_Indexed8) {
1189 original.setColorCount(256);
1190 for (int i = 0; i < 255; ++i)
1191 original.setColor(i, c: qRgb(r: 0, g: i, b: i));
1192 }
1193
1194 if (original.colorTable().isEmpty()) {
1195 for (int x = 0; x < w; ++x) {
1196 original.setPixel(x,y: 0, index_or_rgb: qRgb(r: x,g: 0,b: 128));
1197 original.setPixel(x,y: h - 1, index_or_rgb: qRgb(r: 0,g: 255 - x,b: 128));
1198 }
1199 for (int y = 0; y < h; ++y) {
1200 original.setPixel(x: 0, y, index_or_rgb: qRgb(r: y,g: 0,b: 255));
1201 original.setPixel(x: w - 1, y, index_or_rgb: qRgb(r: 0,g: 255 - y,b: 255));
1202 }
1203 } else {
1204 const int n = original.colorTable().size();
1205 for (int x = 0; x < w; ++x) {
1206 original.setPixel(x, y: 0, index_or_rgb: x % n);
1207 original.setPixel(x, y: h - 1, index_or_rgb: n - (x % n) - 1);
1208 }
1209 for (int y = 0; y < h; ++y) {
1210 original.setPixel(x: 0, y, index_or_rgb: y % n);
1211 original.setPixel(x: w - 1, y, index_or_rgb: n - (y % n) - 1);
1212 }
1213 }
1214
1215 // original.save("rotated90_original.png", "png");
1216
1217 // Initialize the matrix manually (do not use rotate) to avoid rounding errors
1218 QTransform matRotate90;
1219 matRotate90.rotate(a: degrees);
1220 QImage dest = original;
1221 // And rotate it 4 times, then the image should be identical to the original
1222 for (int i = 0; i < 4 ; ++i) {
1223 dest = dest.transformed(matrix: matRotate90);
1224 }
1225
1226 // Make sure they are similar in format before we compare them.
1227 dest = dest.convertToFormat(f: format);
1228
1229 // dest.save("rotated90_result.png","png");
1230 QCOMPARE(original, dest);
1231
1232 // Test with QTransform::rotate 90 also, since we trust that now
1233 matRotate90.rotate(a: degrees);
1234 dest = original;
1235 // And rotate it 4 times, then the image should be identical to the original
1236 for (int i = 0; i < 4 ; ++i) {
1237 dest = dest.transformed(matrix: matRotate90);
1238 }
1239
1240 // Make sure they are similar in format before we compare them.
1241 dest = dest.convertToFormat(f: format);
1242
1243 QCOMPARE(original, dest);
1244}
1245
1246void tst_QImage::copy()
1247{
1248 // Task 99250
1249 {
1250 QImage img(16,16,QImage::Format_ARGB32);
1251 img.copy(rect: QRect(1000,1,1,1));
1252 }
1253}
1254
1255void tst_QImage::load()
1256{
1257 const QString filePath = m_prefix + QLatin1String("image.jpg");
1258
1259 QImage dest(filePath);
1260 QVERIFY(!dest.isNull());
1261 QVERIFY(!dest.load("image_that_does_not_exist.png"));
1262 QVERIFY(dest.isNull());
1263 QVERIFY(dest.load(filePath));
1264 QVERIFY(!dest.isNull());
1265}
1266
1267void tst_QImage::loadFromData()
1268{
1269 const QString filePath = m_prefix + QLatin1String("image.jpg");
1270
1271 QImage original(filePath);
1272 QVERIFY(!original.isNull());
1273
1274 QByteArray ba;
1275 {
1276 QBuffer buf(&ba);
1277 QVERIFY(buf.open(QIODevice::WriteOnly));
1278 QVERIFY(original.save(&buf, "BMP"));
1279 }
1280 QVERIFY(!ba.isEmpty());
1281
1282 QImage dest;
1283 QVERIFY(dest.loadFromData(ba, "BMP"));
1284 QVERIFY(!dest.isNull());
1285
1286 QCOMPARE(original, dest);
1287
1288 QVERIFY(!dest.loadFromData(QByteArray()));
1289 QVERIFY(dest.isNull());
1290}
1291
1292#if !defined(QT_NO_DATASTREAM)
1293void tst_QImage::loadFromDataStream()
1294{
1295 const QString filePath = m_prefix + QLatin1String("image.jpg");
1296
1297 QImage original(filePath);
1298 QVERIFY(!original.isNull());
1299
1300 QByteArray ba;
1301 {
1302 QDataStream s(&ba, QIODevice::WriteOnly);
1303 s << original;
1304 }
1305 QVERIFY(!ba.isEmpty());
1306
1307 QImage dest;
1308 {
1309 QDataStream s(&ba, QIODevice::ReadOnly);
1310 s >> dest;
1311 }
1312 QVERIFY(!dest.isNull());
1313
1314 QCOMPARE(original, dest);
1315
1316 {
1317 ba.clear();
1318 QDataStream s(&ba, QIODevice::ReadOnly);
1319 s >> dest;
1320 }
1321 QVERIFY(dest.isNull());
1322}
1323#endif // QT_NO_DATASTREAM
1324
1325void tst_QImage::setPixel_data()
1326{
1327 QTest::addColumn<int>(name: "format");
1328 QTest::addColumn<uint>(name: "value");
1329 QTest::addColumn<uint>(name: "expected");
1330
1331 QTest::newRow(dataTag: "ARGB32 red") << int(QImage::Format_ARGB32)
1332 << 0xffff0000 << 0xffff0000;
1333 QTest::newRow(dataTag: "ARGB32 green") << int(QImage::Format_ARGB32)
1334 << 0xff00ff00 << 0xff00ff00;
1335 QTest::newRow(dataTag: "ARGB32 blue") << int(QImage::Format_ARGB32)
1336 << 0xff0000ff << 0xff0000ff;
1337 QTest::newRow(dataTag: "RGB16 red") << int(QImage::Format_RGB16)
1338 << 0xffff0000 << 0xf800u;
1339 QTest::newRow(dataTag: "RGB16 green") << int(QImage::Format_RGB16)
1340 << 0xff00ff00 << 0x07e0u;
1341 QTest::newRow(dataTag: "RGB16 blue") << int(QImage::Format_RGB16)
1342 << 0xff0000ff << 0x001fu;
1343 QTest::newRow(dataTag: "ARGB8565_Premultiplied red") << int(QImage::Format_ARGB8565_Premultiplied)
1344 << 0xffff0000 << 0xf800ffu;
1345 QTest::newRow(dataTag: "ARGB8565_Premultiplied green") << int(QImage::Format_ARGB8565_Premultiplied)
1346 << 0xff00ff00 << 0x07e0ffu;
1347 QTest::newRow(dataTag: "ARGB8565_Premultiplied blue") << int(QImage::Format_ARGB8565_Premultiplied)
1348 << 0xff0000ff << 0x001fffu;
1349 QTest::newRow(dataTag: "RGB666 red") << int(QImage::Format_RGB666)
1350 << 0xffff0000 << 0x03f000u;
1351 QTest::newRow(dataTag: "RGB666 green") << int(QImage::Format_RGB666)
1352 << 0xff00ff00 << 0x000fc0u;
1353 QTest::newRow(dataTag: "RGB666 blue") << int(QImage::Format_RGB666)
1354 << 0xff0000ff << 0x00003fu;
1355 QTest::newRow(dataTag: "RGB555 red") << int(QImage::Format_RGB555)
1356 << 0xffff0000 << 0x7c00u;
1357 QTest::newRow(dataTag: "RGB555 green") << int(QImage::Format_RGB555)
1358 << 0xff00ff00 << 0x03e0u;
1359 QTest::newRow(dataTag: "RGB555 blue") << int(QImage::Format_RGB555)
1360 << 0xff0000ff << 0x001fu;
1361 QTest::newRow(dataTag: "ARGB8555_Premultiplied red") << int(QImage::Format_ARGB8555_Premultiplied)
1362 << 0xffff0000 << 0x7c00ffu;
1363 QTest::newRow(dataTag: "ARGB8555_Premultiplied green") << int(QImage::Format_ARGB8555_Premultiplied)
1364 << 0xff00ff00 << 0x03e0ffu;
1365 QTest::newRow(dataTag: "ARGB8555_Premultiplied blue") << int(QImage::Format_ARGB8555_Premultiplied)
1366 << 0xff0000ff << 0x001fffu;
1367 QTest::newRow(dataTag: "RGB888 red") << int(QImage::Format_RGB888)
1368 << 0xffff0000 << 0xff0000u;
1369 QTest::newRow(dataTag: "RGB888 green") << int(QImage::Format_RGB888)
1370 << 0xff00ff00 << 0x00ff00u;
1371 QTest::newRow(dataTag: "RGB888 blue") << int(QImage::Format_RGB888)
1372 << 0xff0000ff << 0x0000ffu;
1373 QTest::newRow(dataTag: "BGR888 red") << int(QImage::Format_BGR888)
1374 << 0xffff0000 << 0x0000ffu;
1375 QTest::newRow(dataTag: "BGR888 green") << int(QImage::Format_BGR888)
1376 << 0xff00ff00 << 0x00ff00u;
1377 QTest::newRow(dataTag: "BGR888 blue") << int(QImage::Format_BGR888)
1378 << 0xff0000ff << 0xff0000u;
1379#if Q_BYTE_ORDER == Q_BIG_ENDIAN
1380 QTest::newRow("RGBA8888 red") << int(QImage::Format_RGBA8888)
1381 << 0xffff0000u << 0xff0000ffu;
1382 QTest::newRow("RGBA8888 green") << int(QImage::Format_RGBA8888)
1383 << 0xff00ff00u << 0x00ff00ffu;
1384 QTest::newRow("RGBA8888 blue") << int(QImage::Format_RGBA8888)
1385 << 0xff0000ffu << 0x0000ffffu;
1386#else
1387 QTest::newRow(dataTag: "RGBA8888 red") << int(QImage::Format_RGBA8888)
1388 << 0xffff0000u << 0xff0000ffu;
1389 QTest::newRow(dataTag: "RGBA8888 green") << int(QImage::Format_RGBA8888)
1390 << 0xff00ff00u << 0xff00ff00u;
1391 QTest::newRow(dataTag: "RGBA8888 blue") << int(QImage::Format_RGBA8888)
1392 << 0xff0000ffu << 0xffff0000u;
1393#endif
1394 QTest::newRow(dataTag: "A2BGR30_Premultiplied red") << int(QImage::Format_A2BGR30_Premultiplied)
1395 << 0xffff0000u << 0xc00003ffu;
1396 QTest::newRow(dataTag: "A2BGR30_Premultiplied green") << int(QImage::Format_A2BGR30_Premultiplied)
1397 << 0xff00ff00u << 0xc00ffc00u;
1398 QTest::newRow(dataTag: "A2BGR30_Premultiplied blue") << int(QImage::Format_A2BGR30_Premultiplied)
1399 << 0xff0000ffu << 0xfff00000u;
1400 QTest::newRow(dataTag: "RGB30 red") << int(QImage::Format_RGB30)
1401 << 0xffff0000u << 0xfff00000u;
1402 QTest::newRow(dataTag: "RGB30 green") << int(QImage::Format_RGB30)
1403 << 0xff00ff00u << 0xc00ffc00u;
1404 QTest::newRow(dataTag: "RGB30 blue") << int(QImage::Format_RGB30)
1405 << 0xff0000ffu << 0xc00003ffu;
1406}
1407
1408void tst_QImage::setPixel()
1409{
1410 QFETCH(int, format);
1411 QFETCH(uint, value);
1412 QFETCH(uint, expected);
1413
1414 const int w = 13;
1415 const int h = 15;
1416
1417 QImage img(w, h, QImage::Format(format));
1418
1419 // fill image
1420 for (int y = 0; y < h; ++y)
1421 for (int x = 0; x < w; ++x)
1422 img.setPixel(x, y, index_or_rgb: value);
1423
1424 // check pixel values
1425 switch (format) {
1426 case int(QImage::Format_RGB32):
1427 case int(QImage::Format_ARGB32):
1428 case int(QImage::Format_ARGB32_Premultiplied):
1429 case int(QImage::Format_RGBX8888):
1430 case int(QImage::Format_RGBA8888):
1431 case int(QImage::Format_RGBA8888_Premultiplied):
1432 case int(QImage::Format_A2BGR30_Premultiplied):
1433 case int(QImage::Format_RGB30):
1434 {
1435 for (int y = 0; y < h; ++y) {
1436 const quint32 *row = (const quint32*)(img.scanLine(y));
1437 for (int x = 0; x < w; ++x) {
1438 quint32 result = row[x];
1439 if (result != expected)
1440 printf(format: "[x,y]: %d,%d, expected=%08x, result=%08x\n",
1441 x, y, expected, result);
1442 QCOMPARE(uint(result), expected);
1443 }
1444 }
1445 break;
1446 }
1447 case int(QImage::Format_RGB555):
1448 case int(QImage::Format_RGB16):
1449 {
1450 for (int y = 0; y < h; ++y) {
1451 const quint16 *row = (const quint16*)(img.scanLine(y));
1452 for (int x = 0; x < w; ++x) {
1453 quint16 result = row[x];
1454 if (result != expected)
1455 printf(format: "[x,y]: %d,%d, expected=%04x, result=%04x\n",
1456 x, y, expected, result);
1457 QCOMPARE(uint(result), expected);
1458 }
1459 }
1460 break;
1461 }
1462 case int(QImage::Format_RGB666):
1463 case int(QImage::Format_ARGB8565_Premultiplied):
1464 case int(QImage::Format_ARGB8555_Premultiplied):
1465 case int(QImage::Format_RGB888):
1466 case int(QImage::Format_BGR888):
1467 {
1468 for (int y = 0; y < h; ++y) {
1469 const quint24 *row = (const quint24*)(img.scanLine(y));
1470 for (int x = 0; x < w; ++x) {
1471 quint32 result = row[x];
1472 if (result != expected)
1473 printf(format: "[x,y]: %d,%d, expected=%04x, result=%04x\n",
1474 x, y, expected, result);
1475 QCOMPARE(result, expected);
1476 }
1477 }
1478 break;
1479 }
1480 default:
1481 qFatal(msg: "Test not implemented for format %d", format);
1482 }
1483}
1484
1485void tst_QImage::setPixelWithAlpha_data()
1486{
1487 QTest::addColumn<QImage::Format>(name: "format");
1488
1489 for (int c = QImage::Format_RGB32; c < QImage::NImageFormats; ++c) {
1490 if (c == QImage::Format_Grayscale8)
1491 continue;
1492 if (c == QImage::Format_Grayscale16)
1493 continue;
1494 if (c == QImage::Format_Alpha8)
1495 continue;
1496 QTest::newRow(qPrintable(formatToString(QImage::Format(c)))) << QImage::Format(c);
1497 }
1498}
1499
1500void tst_QImage::setPixelWithAlpha()
1501{
1502 QFETCH(QImage::Format, format);
1503 QImage image(1, 1, format);
1504 QRgb referenceColor = qRgba(r: 0, g: 170, b: 85, a: 170);
1505 image.setPixel(x: 0, y: 0, index_or_rgb: referenceColor);
1506
1507 if (!image.hasAlphaChannel())
1508 referenceColor = 0xff000000 | referenceColor;
1509
1510 QRgb color = image.pixel(x: 0, y: 0);
1511 QCOMPARE(qRed(color) & 0xf0, qRed(referenceColor) & 0xf0);
1512 QCOMPARE(qGreen(color) & 0xf0, qGreen(referenceColor) & 0xf0);
1513 QCOMPARE(qBlue(color) & 0xf0, qBlue(referenceColor) & 0xf0);
1514 QCOMPARE(qAlpha(color) & 0xf0, qAlpha(referenceColor) & 0xf0);
1515}
1516
1517void tst_QImage::setPixelColorWithAlpha_data()
1518{
1519 setPixelWithAlpha_data();
1520}
1521
1522void tst_QImage::setPixelColorWithAlpha()
1523{
1524 QFETCH(QImage::Format, format);
1525 QImage image(1, 1, format);
1526 image.setPixelColor(x: 0, y: 0, c: QColor(170, 85, 255, 170));
1527 QRgb referenceColor = qRgba(r: 170, g: 85, b: 255, a: 170);
1528
1529 if (!image.hasAlphaChannel())
1530 referenceColor = 0xff000000 | referenceColor;
1531 else if (image.pixelFormat().premultiplied() == QPixelFormat::Premultiplied)
1532 referenceColor = qPremultiply(x: referenceColor);
1533
1534 QRgb color = image.pixel(x: 0, y: 0);
1535 QCOMPARE(qRed(color) & 0xf0, qRed(referenceColor) & 0xf0);
1536 QCOMPARE(qGreen(color) & 0xf0, qGreen(referenceColor) & 0xf0);
1537 QCOMPARE(qBlue(color) & 0xf0, qBlue(referenceColor) & 0xf0);
1538 QCOMPARE(qAlpha(color) & 0xf0, qAlpha(referenceColor) & 0xf0);
1539}
1540
1541void tst_QImage::convertToFormatPreserveDotsPrMeter()
1542{
1543 QImage img(100, 100, QImage::Format_ARGB32_Premultiplied);
1544
1545 int dpmx = 123;
1546 int dpmy = 234;
1547 img.setDotsPerMeterX(dpmx);
1548 img.setDotsPerMeterY(dpmy);
1549 img.fill(pixel: 0x12345678);
1550
1551 img = img.convertToFormat(f: QImage::Format_RGB32);
1552
1553 QCOMPARE(img.dotsPerMeterX(), dpmx);
1554 QCOMPARE(img.dotsPerMeterY(), dpmy);
1555}
1556
1557void tst_QImage::convertToFormatPreserveText()
1558{
1559 QImage img(100, 100, QImage::Format_ARGB32_Premultiplied);
1560
1561 img.setText(key: "foo", value: "bar");
1562 img.setText(key: "foo2", value: "bar2");
1563 img.fill(pixel: 0x12345678);
1564
1565 QStringList listResult;
1566 listResult << "foo" << "foo2";
1567 QString result = "foo: bar\n\nfoo2: bar2";
1568
1569 QImage imgResult1 = img.convertToFormat(f: QImage::Format_RGB32);
1570 QCOMPARE(imgResult1.text(), result);
1571 QCOMPARE(imgResult1.textKeys(), listResult);
1572
1573 QVector<QRgb> colorTable(4);
1574 for (int i = 0; i < 4; ++i)
1575 colorTable[i] = QRgb(42);
1576 QImage imgResult2 = img.convertToFormat(f: QImage::Format_MonoLSB,
1577 colorTable);
1578 QCOMPARE(imgResult2.text(), result);
1579 QCOMPARE(imgResult2.textKeys(), listResult);
1580}
1581
1582void tst_QImage::defaultColorTable_data()
1583{
1584 QTest::addColumn<QImage::Format>(name: "format");
1585 QTest::addColumn<int>(name: "createdDataCount");
1586 QTest::addColumn<int>(name: "externalDataCount");
1587
1588 // For historical reasons, internally created mono images get a default colormap.
1589 // Externally created and Indexed8 images do not.
1590 QTest::newRow(dataTag: "Mono") << QImage::Format_Mono << 2 << 0;
1591 QTest::newRow(dataTag: "MonoLSB") << QImage::Format_MonoLSB << 2 << 0;
1592 QTest::newRow(dataTag: "Indexed8") << QImage::Format_Indexed8 << 0 << 0;
1593 QTest::newRow(dataTag: "ARGB32_PM") << QImage::Format_A2BGR30_Premultiplied << 0 << 0;
1594}
1595
1596void tst_QImage::defaultColorTable()
1597{
1598 QFETCH(QImage::Format, format);
1599 QFETCH(int, createdDataCount);
1600 QFETCH(int, externalDataCount);
1601
1602 QImage img1(1, 1, format);
1603 QCOMPARE(img1.colorCount(), createdDataCount);
1604 QCOMPARE(img1.colorTable().size(), createdDataCount);
1605
1606 quint32 buf;
1607 QImage img2(reinterpret_cast<uchar *>(&buf), 1, 1, format);
1608 QCOMPARE(img2.colorCount(), externalDataCount);
1609
1610 QImage nullImg(0, 0, format);
1611 QCOMPARE(nullImg.colorCount(), 0);
1612}
1613
1614void tst_QImage::setColorCount()
1615{
1616 QImage img(0, 0, QImage::Format_Indexed8);
1617 QTest::ignoreMessage(type: QtWarningMsg, message: "QImage::setColorCount: null image");
1618 img.setColorCount(256);
1619 QCOMPARE(img.colorCount(), 0);
1620}
1621
1622void tst_QImage::setColor()
1623{
1624 QImage img(0, 0, QImage::Format_Indexed8);
1625 img.setColor(i: 0, c: qRgba(r: 18, g: 219, b: 108, a: 128));
1626 QCOMPARE(img.colorCount(), 0);
1627
1628 QImage img2(1, 1, QImage::Format_Indexed8);
1629 img2.setColor(i: 0, c: qRgba(r: 18, g: 219, b: 108, a: 128));
1630 QCOMPARE(img2.colorCount(), 1);
1631}
1632
1633/* Just some sanity checking that we don't draw outside the buffer of
1634 * the image. Hopefully this will create crashes or at least some
1635 * random test fails when broken.
1636 */
1637void tst_QImage::rasterClipping()
1638{
1639 QImage image(10, 10, QImage::Format_RGB32);
1640 image.fill(pixel: 0xffffffff);
1641
1642 QPainter p(&image);
1643
1644 p.drawLine(x1: -1000, y1: 5, x2: 5, y2: 5);
1645 p.drawLine(x1: -1000, y1: 5, x2: 1000, y2: 5);
1646 p.drawLine(x1: 5, y1: 5, x2: 1000, y2: 5);
1647
1648 p.drawLine(x1: 5, y1: -1000, x2: 5, y2: 5);
1649 p.drawLine(x1: 5, y1: -1000, x2: 5, y2: 1000);
1650 p.drawLine(x1: 5, y1: 5, x2: 5, y2: 1000);
1651
1652 p.setBrush(Qt::red);
1653
1654 p.drawEllipse(x: 3, y: 3, w: 4, h: 4);
1655 p.drawEllipse(x: -100, y: -100, w: 210, h: 210);
1656
1657 p.drawEllipse(x: -1000, y: 0, w: 2010, h: 2010);
1658 p.drawEllipse(x: 0, y: -1000, w: 2010, h: 2010);
1659 p.drawEllipse(x: -2010, y: -1000, w: 2010, h: 2010);
1660 p.drawEllipse(x: -1000, y: -2010, w: 2010, h: 2010);
1661 QVERIFY(true);
1662}
1663
1664// Tests the new QPoint overloads in QImage in Qt 4.2
1665void tst_QImage::pointOverloads()
1666{
1667 QImage image(100, 100, QImage::Format_RGB32);
1668 image.fill(pixel: 0xff00ff00);
1669
1670 // IsValid
1671 QVERIFY(image.valid(QPoint(0, 0)));
1672 QVERIFY(image.valid(QPoint(99, 0)));
1673 QVERIFY(image.valid(QPoint(0, 99)));
1674 QVERIFY(image.valid(QPoint(99, 99)));
1675
1676 QVERIFY(!image.valid(QPoint(50, -1))); // outside on the top
1677 QVERIFY(!image.valid(QPoint(50, 100))); // outside on the bottom
1678 QVERIFY(!image.valid(QPoint(-1, 50))); // outside on the left
1679 QVERIFY(!image.valid(QPoint(100, 50))); // outside on the right
1680
1681 // Test the pixel setter
1682 image.setPixel(pt: QPoint(10, 10), index_or_rgb: 0xff0000ff);
1683 QCOMPARE(image.pixel(10, 10), 0xff0000ff);
1684
1685 // pixel getter
1686 QCOMPARE(image.pixel(QPoint(10, 10)), 0xff0000ff);
1687
1688 // pixelIndex()
1689 QImage indexed = image.convertToFormat(f: QImage::Format_Indexed8);
1690 QCOMPARE(indexed.pixelIndex(10, 10), indexed.pixelIndex(QPoint(10, 10)));
1691}
1692
1693void tst_QImage::destructor()
1694{
1695 QPolygon poly(6);
1696 poly.setPoint(index: 0,x: -1455, y: 1435);
1697
1698 QImage image(100, 100, QImage::Format_RGB32);
1699 QPainter ptPix(&image);
1700 ptPix.setPen(Qt::black);
1701 ptPix.setBrush(Qt::black);
1702 ptPix.drawPolygon(polygon: poly, fillRule: Qt::WindingFill);
1703 ptPix.end();
1704
1705}
1706
1707
1708/* XPM */
1709static const char *monoPixmap[] = {
1710/* width height ncolors chars_per_pixel */
1711"4 4 2 1",
1712"x c #000000",
1713". c #ffffff",
1714/* pixels */
1715"xxxx",
1716"x..x",
1717"x..x",
1718"xxxx"
1719};
1720
1721
1722#ifndef QT_NO_IMAGE_HEURISTIC_MASK
1723void tst_QImage::createHeuristicMask()
1724{
1725 QImage img(monoPixmap);
1726 img = img.convertToFormat(f: QImage::Format_MonoLSB);
1727 QImage mask = img.createHeuristicMask();
1728 QImage newMask = mask.convertToFormat(f: QImage::Format_ARGB32_Premultiplied);
1729
1730 // line 2
1731 QVERIFY(newMask.pixel(0,1) != newMask.pixel(1,1));
1732 QCOMPARE(newMask.pixel(1,1), newMask.pixel(2,1));
1733 QVERIFY(newMask.pixel(2,1) != newMask.pixel(3,1));
1734
1735 // line 3
1736 QVERIFY(newMask.pixel(0,2) != newMask.pixel(1,2));
1737 QCOMPARE(newMask.pixel(1,2), newMask.pixel(2,2));
1738 QVERIFY(newMask.pixel(2,2) != newMask.pixel(3,2));
1739}
1740#endif
1741
1742void tst_QImage::cacheKey()
1743{
1744 QImage image1(2, 2, QImage::Format_RGB32);
1745 qint64 image1_key = image1.cacheKey();
1746 QImage image2 = image1;
1747
1748 QCOMPARE(image2.cacheKey(), image1.cacheKey());
1749 image2.detach();
1750 QVERIFY(image2.cacheKey() != image1.cacheKey());
1751 QCOMPARE(image1.cacheKey(), image1_key);
1752}
1753
1754void tst_QImage::smoothScale()
1755{
1756 unsigned int data[2] = { qRgba(r: 0, g: 0, b: 0, a: 0), qRgba(r: 128, g: 128, b: 128, a: 128) };
1757
1758 QImage imgX((unsigned char *)data, 2, 1, QImage::Format_ARGB32_Premultiplied);
1759 QImage imgY((unsigned char *)data, 1, 2, QImage::Format_ARGB32_Premultiplied);
1760
1761 QImage scaledX = imgX.scaled(s: QSize(4, 1), aspectMode: Qt::IgnoreAspectRatio, mode: Qt::SmoothTransformation);
1762 QImage scaledY = imgY.scaled(s: QSize(1, 4), aspectMode: Qt::IgnoreAspectRatio, mode: Qt::SmoothTransformation);
1763
1764 uint *scaled[2] = {
1765 (unsigned int *)scaledX.bits(),
1766 (unsigned int *)scaledY.bits()
1767 };
1768
1769 int expected[4] = { 0, 32, 96, 128 };
1770 for (int image = 0; image < 2; ++image) {
1771 for (int index = 0; index < 4; ++index) {
1772 for (int component = 0; component < 4; ++component) {
1773 int pixel = scaled[image][index];
1774 int val = (pixel >> (component * 8)) & 0xff;
1775
1776 QCOMPARE(val, expected[index]);
1777 }
1778 }
1779 }
1780}
1781
1782// test area sampling
1783void tst_QImage::smoothScale2_data()
1784{
1785 QTest::addColumn<QImage::Format>(name: "format");
1786 QTest::addColumn<int>(name: "size");
1787
1788 int sizes[] = { 2, 3, 4, 6, 7, 8, 10, 16, 20, 32, 40, 64, 100, 101, 128, 0 };
1789 QImage::Format formats[] = { QImage::Format_RGB32, QImage::Format_ARGB32_Premultiplied, QImage::Format_RGBX64, QImage::Format_RGBA64_Premultiplied, QImage::Format_Invalid };
1790 for (int j = 0; formats[j] != QImage::Format_Invalid; ++j) {
1791 QString formatstr = formatToString(format: formats[j]);
1792 for (int i = 0; sizes[i] != 0; ++i) {
1793 const QByteArray sizeB = QByteArray::number(sizes[i]);
1794 QTest::newRow(dataTag: QString("%1 %2x%2").arg(a: formatstr).arg(a: sizes[i]).toUtf8()) << formats[j] << sizes[i];
1795 }
1796 }
1797}
1798
1799void tst_QImage::smoothScale2()
1800{
1801 QFETCH(QImage::Format, format);
1802 QFETCH(int, size);
1803
1804 bool opaque = (format == QImage::Format_RGB32 || format == QImage::Format_RGBX64);
1805
1806 QRgb expected = opaque ? qRgb(r: 63, g: 127, b: 255) : qRgba(r: 31, g: 63, b: 127, a: 127);
1807
1808 QImage img(size, size, format);
1809 img.fill(pixel: expected);
1810
1811 // scale x down, y down
1812 QImage scaled = img.scaled(s: QSize(1, 1), aspectMode: Qt::IgnoreAspectRatio, mode: Qt::SmoothTransformation);
1813 QRgb pixel = scaled.pixel(x: 0, y: 0);
1814 QCOMPARE(qAlpha(pixel), qAlpha(expected));
1815 QCOMPARE(qRed(pixel), qRed(expected));
1816 QCOMPARE(qGreen(pixel), qGreen(expected));
1817 QCOMPARE(qBlue(pixel), qBlue(expected));
1818
1819 // scale x down, y up
1820 scaled = img.scaled(s: QSize(1, size * 2), aspectMode: Qt::IgnoreAspectRatio, mode: Qt::SmoothTransformation);
1821 for (int y = 0; y < scaled.height(); ++y) {
1822 pixel = scaled.pixel(x: 0, y);
1823 QCOMPARE(qAlpha(pixel), qAlpha(expected));
1824 QCOMPARE(qRed(pixel), qRed(expected));
1825 QCOMPARE(qGreen(pixel), qGreen(expected));
1826 QCOMPARE(qBlue(pixel), qBlue(expected));
1827 }
1828
1829 // scale x up, y down
1830 scaled = img.scaled(s: QSize(size * 2, 1), aspectMode: Qt::IgnoreAspectRatio, mode: Qt::SmoothTransformation);
1831 for (int x = 0; x < scaled.width(); ++x) {
1832 pixel = scaled.pixel(x, y: 0);
1833 QCOMPARE(qAlpha(pixel), qAlpha(expected));
1834 QCOMPARE(qRed(pixel), qRed(expected));
1835 QCOMPARE(qGreen(pixel), qGreen(expected));
1836 QCOMPARE(qBlue(pixel), qBlue(expected));
1837 }
1838
1839 // scale x up
1840 scaled = img.scaled(s: QSize(size, size * 2), aspectMode: Qt::IgnoreAspectRatio, mode: Qt::SmoothTransformation);
1841 for (int y = 0; y < scaled.height(); ++y) {
1842 for (int x = 0; x < scaled.width(); ++x) {
1843 pixel = scaled.pixel(x, y);
1844 QCOMPARE(qAlpha(pixel), qAlpha(expected));
1845 QCOMPARE(qRed(pixel), qRed(expected));
1846 QCOMPARE(qGreen(pixel), qGreen(expected));
1847 QCOMPARE(qBlue(pixel), qBlue(expected));
1848 }
1849 }
1850
1851 // scale y up
1852 scaled = img.scaled(s: QSize(size * 2, size), aspectMode: Qt::IgnoreAspectRatio, mode: Qt::SmoothTransformation);
1853 for (int y = 0; y < scaled.height(); ++y) {
1854 for (int x = 0; x < scaled.width(); ++x) {
1855 pixel = scaled.pixel(x, y);
1856 QCOMPARE(qAlpha(pixel), qAlpha(expected));
1857 QCOMPARE(qRed(pixel), qRed(expected));
1858 QCOMPARE(qGreen(pixel), qGreen(expected));
1859 QCOMPARE(qBlue(pixel), qBlue(expected));
1860 }
1861 }
1862
1863 // scale x up, y up
1864 scaled = img.scaled(s: QSize(size * 2, size * 2), aspectMode: Qt::IgnoreAspectRatio, mode: Qt::SmoothTransformation);
1865 for (int y = 0; y < scaled.height(); ++y) {
1866 for (int x = 0; x < scaled.width(); ++x) {
1867 pixel = scaled.pixel(x, y);
1868 QCOMPARE(qAlpha(pixel), qAlpha(expected));
1869 QCOMPARE(qRed(pixel), qRed(expected));
1870 QCOMPARE(qGreen(pixel), qGreen(expected));
1871 QCOMPARE(qBlue(pixel), qBlue(expected));
1872 }
1873 }
1874}
1875
1876static inline int rand8()
1877{
1878 return QRandomGenerator::global()->bounded(highest: 256);
1879}
1880
1881void tst_QImage::smoothScale3_data()
1882{
1883 QTest::addColumn<QImage>(name: "img");
1884 QTest::addColumn<qreal>(name: "scale_x");
1885 QTest::addColumn<qreal>(name: "scale_y");
1886
1887 QImage img(128, 128, QImage::Format_RGB32);
1888 for (int y = 0; y < img.height(); ++y) {
1889 for (int x = 0; x < img.width(); ++x) {
1890 const int red = rand8();
1891 const int green = rand8();
1892 const int blue = rand8();
1893 const int alpha = 255;
1894
1895 img.setPixel(x, y, index_or_rgb: qRgba(r: red, g: green, b: blue, a: alpha));
1896 }
1897 }
1898
1899 QTest::newRow(dataTag: "(0.5, 0.5)") << img << qreal(0.5) << qreal(0.5);
1900 QTest::newRow(dataTag: "(0.5, 1.0)") << img << qreal(0.5) << qreal(1.0);
1901 QTest::newRow(dataTag: "(1.0, 0.5)") << img << qreal(1.0) << qreal(0.5);
1902 QTest::newRow(dataTag: "(0.5, 2.0)") << img << qreal(0.5) << qreal(2.0);
1903 QTest::newRow(dataTag: "(1.0, 2.0)") << img << qreal(1.0) << qreal(2.0);
1904 QTest::newRow(dataTag: "(2.0, 0.5)") << img << qreal(2.0) << qreal(0.5);
1905 QTest::newRow(dataTag: "(2.0, 1.0)") << img << qreal(2.0) << qreal(1.0);
1906 QTest::newRow(dataTag: "(2.0, 2.0)") << img << qreal(2) << qreal(2);
1907}
1908// compares img.scale against the bilinear filtering used by QPainter
1909void tst_QImage::smoothScale3()
1910{
1911 QFETCH(QImage, img);
1912 QFETCH(qreal, scale_x);
1913 QFETCH(qreal, scale_y);
1914
1915 QImage a = img.scaled(w: img.width() * scale_x, h: img.height() * scale_y, aspectMode: Qt::IgnoreAspectRatio, mode: Qt::SmoothTransformation);
1916 QImage b(a.size(), a.format());
1917 b.fill(pixel: 0x0);
1918
1919 QPainter p(&b);
1920 p.setRenderHint(hint: QPainter::SmoothPixmapTransform);
1921 p.scale(sx: scale_x, sy: scale_y);
1922 p.drawImage(x: 0, y: 0, image: img);
1923 p.end();
1924 int err = 0;
1925
1926 for (int y = 0; y < a.height(); ++y) {
1927 for (int x = 0; x < a.width(); ++x) {
1928 QRgb ca = a.pixel(x, y);
1929 QRgb cb = b.pixel(x, y);
1930
1931 // tolerate a little bit of rounding errors
1932 int tolerance = 3;
1933 bool r = true;
1934 r &= qAbs(t: qRed(rgb: ca) - qRed(rgb: cb)) <= tolerance;
1935 r &= qAbs(t: qGreen(rgb: ca) - qGreen(rgb: cb)) <= tolerance;
1936 r &= qAbs(t: qBlue(rgb: ca) - qBlue(rgb: cb)) <= tolerance;
1937 if (!r)
1938 err++;
1939 }
1940 }
1941 QCOMPARE(err, 0);
1942}
1943
1944// Tests smooth upscale is smooth
1945void tst_QImage::smoothScale4_data()
1946{
1947 QTest::addColumn<QImage::Format>(name: "format");
1948
1949 QTest::newRow(dataTag: "RGB32") << QImage::Format_RGB32;
1950#if QT_CONFIG(raster_64bit)
1951 QTest::newRow(dataTag: "RGBx64") << QImage::Format_RGBX64;
1952#endif
1953}
1954
1955void tst_QImage::smoothScale4()
1956{
1957 QFETCH(QImage::Format, format);
1958 QImage img(4, 4, format);
1959 for (int y = 0; y < 4; ++y) {
1960 for (int x = 0; x < 4; ++x) {
1961 img.setPixel(x, y, index_or_rgb: qRgb(r: x * 255 / 3, g: y * 255 / 3, b: 0));
1962 }
1963 }
1964 QImage scaled = img.scaled(w: 37, h: 23, aspectMode: Qt::IgnoreAspectRatio, mode: Qt::SmoothTransformation);
1965 QCOMPARE(scaled.format(), format);
1966 for (int y = 0; y < scaled.height(); ++y) {
1967 for (int x = 0; x < scaled.width(); ++x) {
1968 if (x > 0)
1969 QVERIFY(scaled.pixelColor(x, y).redF() >= scaled.pixelColor(x - 1, y).redF());
1970 if (y > 0)
1971 QVERIFY(scaled.pixelColor(x, y).greenF() >= scaled.pixelColor(x, y - 1).greenF());
1972 }
1973 }
1974}
1975
1976void tst_QImage::smoothScaleBig()
1977{
1978 int bigValue = 200000;
1979 QImage tall(4, bigValue, QImage::Format_ARGB32);
1980 tall.fill(pixel: 0x0);
1981
1982 QImage wide(bigValue, 4, QImage::Format_ARGB32);
1983 wide.fill(pixel: 0x0);
1984
1985 QImage tallScaled = tall.scaled(w: 4, h: tall.height() / 4, aspectMode: Qt::IgnoreAspectRatio, mode: Qt::SmoothTransformation);
1986 QImage wideScaled = wide.scaled(w: wide.width() / 4, h: 4, aspectMode: Qt::IgnoreAspectRatio, mode: Qt::SmoothTransformation);
1987
1988 QCOMPARE(tallScaled.pixel(0, 0), QRgb(0x0));
1989 QCOMPARE(wideScaled.pixel(0, 0), QRgb(0x0));
1990}
1991
1992void tst_QImage::smoothScaleAlpha()
1993{
1994 QImage src(128, 128, QImage::Format_ARGB32_Premultiplied);
1995 src.fill(pixel: 0x0);
1996
1997 QPainter srcPainter(&src);
1998 srcPainter.setPen(Qt::NoPen);
1999 srcPainter.setBrush(Qt::white);
2000 srcPainter.drawEllipse(r: QRect(QPoint(), src.size()));
2001 srcPainter.end();
2002
2003 QImage dst(32, 32, QImage::Format_ARGB32_Premultiplied);
2004 dst.fill(pixel: 0xffffffff);
2005 QImage expected = dst;
2006
2007 QPainter dstPainter(&dst);
2008 dstPainter.drawImage(x: 0, y: 0, image: src.scaled(s: dst.size(), aspectMode: Qt::IgnoreAspectRatio, mode: Qt::SmoothTransformation));
2009 dstPainter.end();
2010
2011 QCOMPARE(dst, expected);
2012}
2013
2014static int count(const QImage &img, int x, int y, int dx, int dy, QRgb pixel)
2015{
2016 int i = 0;
2017 while (x >= 0 && x < img.width() && y >= 0 && y < img.height()) {
2018 i += (img.pixel(x, y) == pixel);
2019 x += dx;
2020 y += dy;
2021 }
2022 return i;
2023}
2024
2025const int transformed_image_width = 128;
2026const int transformed_image_height = 128;
2027
2028void tst_QImage::transformed_data()
2029{
2030 QTest::addColumn<QTransform>(name: "transform");
2031
2032 {
2033 QTransform transform;
2034 transform.translate(dx: 10.4, dy: 10.4);
2035 QTest::newRow(dataTag: "Translate") << transform;
2036 }
2037 {
2038 QTransform transform;
2039 transform.scale(sx: 1.5, sy: 1.5);
2040 QTest::newRow(dataTag: "Scale") << transform;
2041 }
2042 {
2043 QTransform transform;
2044 transform.rotate(a: 30);
2045 QTest::newRow(dataTag: "Rotate 30") << transform;
2046 }
2047 {
2048 QTransform transform;
2049 transform.rotate(a: 90);
2050 QTest::newRow(dataTag: "Rotate 90") << transform;
2051 }
2052 {
2053 QTransform transform;
2054 transform.rotate(a: 180);
2055 QTest::newRow(dataTag: "Rotate 180") << transform;
2056 }
2057 {
2058 QTransform transform;
2059 transform.rotate(a: 270);
2060 QTest::newRow(dataTag: "Rotate 270") << transform;
2061 }
2062 {
2063 QTransform transform;
2064 transform.translate(dx: transformed_image_width/2, dy: transformed_image_height/2);
2065 transform.rotate(a: 155, axis: Qt::XAxis);
2066 transform.translate(dx: -transformed_image_width/2, dy: -transformed_image_height/2);
2067 QTest::newRow(dataTag: "Perspective 1") << transform;
2068 }
2069 {
2070 QTransform transform;
2071 transform.rotate(a: 155, axis: Qt::XAxis);
2072 transform.translate(dx: -transformed_image_width/2, dy: -transformed_image_height/2);
2073 QTest::newRow(dataTag: "Perspective 2") << transform;
2074 }
2075}
2076
2077void tst_QImage::transformed()
2078{
2079 QFETCH(QTransform, transform);
2080
2081 QImage img(transformed_image_width, transformed_image_height, QImage::Format_ARGB32_Premultiplied);
2082 QPainter p(&img);
2083 p.fillRect(x: 0, y: 0, w: img.width(), h: img.height(), c: Qt::red);
2084 p.drawRect(x: 0, y: 0, w: img.width()-1, h: img.height()-1);
2085 p.end();
2086
2087 QImage transformed = img.transformed(matrix: transform, mode: Qt::SmoothTransformation);
2088
2089 // all borders should have touched pixels
2090
2091 QVERIFY(count(transformed, 0, 0, 1, 0, 0x0) < transformed.width());
2092 QVERIFY(count(transformed, 0, 0, 0, 1, 0x0) < transformed.height());
2093
2094 QVERIFY(count(transformed, 0, img.height() - 1, 1, 0, 0x0) < transformed.width());
2095 QVERIFY(count(transformed, img.width() - 1, 0, 0, 1, 0x0) < transformed.height());
2096
2097 QImage transformedPadded(transformed.width() + 2, transformed.height() + 2, img.format());
2098 transformedPadded.fill(pixel: 0x0);
2099
2100 p.begin(&transformedPadded);
2101 p.setRenderHint(hint: QPainter::SmoothPixmapTransform);
2102 p.setRenderHint(hint: QPainter::Antialiasing);
2103 p.setTransform(transform: transformed.trueMatrix(transform, w: img.width(), h: img.height()) * QTransform().translate(dx: 1, dy: 1));
2104 p.drawImage(x: 0, y: 0, image: img);
2105 p.end();
2106
2107 // no borders should have touched pixels since we have a one-pixel padding
2108
2109 QCOMPARE(count(transformedPadded, 0, 0, 1, 0, 0x0), transformedPadded.width());
2110 QCOMPARE(count(transformedPadded, 0, 0, 0, 1, 0x0), transformedPadded.height());
2111
2112 QCOMPARE(count(transformedPadded, 0, transformedPadded.height() - 1, 1, 0, 0x0), transformedPadded.width());
2113 QCOMPARE(count(transformedPadded, transformedPadded.width() - 1, 0, 0, 1, 0x0), transformedPadded.height());
2114}
2115
2116void tst_QImage::transformed2()
2117{
2118 QImage img(3, 3, QImage::Format_Mono);
2119 QPainter p(&img);
2120 p.fillRect(x: 0, y: 0, w: 3, h: 3, c: Qt::white);
2121 p.fillRect(x: 0, y: 0, w: 3, h: 3, style: Qt::Dense4Pattern);
2122 p.end();
2123
2124 QTransform transform;
2125 transform.scale(sx: 3, sy: 3);
2126
2127 QImage expected(9, 9, QImage::Format_Mono);
2128 p.begin(&expected);
2129 p.fillRect(x: 0, y: 0, w: 9, h: 9, c: Qt::white);
2130 p.setBrush(Qt::black);
2131 p.setPen(Qt::NoPen);
2132 p.drawRect(x: 3, y: 0, w: 3, h: 3);
2133 p.drawRect(x: 0, y: 3, w: 3, h: 3);
2134 p.drawRect(x: 6, y: 3, w: 3, h: 3);
2135 p.drawRect(x: 3, y: 6, w: 3, h: 3);
2136 p.end();
2137
2138 {
2139 QImage actual = img.transformed(matrix: transform);
2140
2141 QCOMPARE(actual.format(), expected.format());
2142 QCOMPARE(actual.size(), expected.size());
2143 QCOMPARE(actual, expected);
2144 }
2145
2146 {
2147 transform.rotate(a: -90);
2148 QImage actual = img.transformed(matrix: transform);
2149
2150 QCOMPARE(actual.convertToFormat(QImage::Format_ARGB32_Premultiplied),
2151 expected.convertToFormat(QImage::Format_ARGB32_Premultiplied));
2152 }
2153}
2154
2155void tst_QImage::scaled()
2156{
2157 QImage img(102, 3, QImage::Format_Mono);
2158 QPainter p(&img);
2159 p.fillRect(x: 0, y: 0, w: img.width(), h: img.height(), c: Qt::white);
2160 p.end();
2161
2162 QImage scaled = img.scaled(w: 1994, h: 10);
2163
2164 QImage expected(1994, 10, QImage::Format_Mono);
2165 p.begin(&expected);
2166 p.fillRect(x: 0, y: 0, w: expected.width(), h: expected.height(), c: Qt::white);
2167 p.end();
2168
2169 QCOMPARE(scaled, expected);
2170}
2171
2172void tst_QImage::paintEngine()
2173{
2174 QImage img;
2175
2176 QPaintEngine *engine;
2177 {
2178 QImage temp(100, 100, QImage::Format_RGB32);
2179 temp.fill(pixel: 0xff000000);
2180
2181 QPainter p(&temp);
2182 p.fillRect(x: 80,y: 80,w: 10,h: 10,c: Qt::blue);
2183 p.end();
2184
2185 img = temp;
2186
2187 engine = temp.paintEngine();
2188 }
2189
2190 {
2191 QPainter p(&img);
2192
2193 p.fillRect(x: 80,y: 10,w: 10,h: 10,c: Qt::yellow);
2194 p.end();
2195 }
2196
2197 QImage expected(100, 100, QImage::Format_RGB32);
2198 expected.fill(pixel: 0xff000000);
2199
2200 QPainter p(&expected);
2201 p.fillRect(x: 80,y: 80,w: 10,h: 10,c: Qt::blue);
2202 p.fillRect(x: 80,y: 10,w: 10,h: 10,c: Qt::yellow);
2203 p.end();
2204
2205 QCOMPARE(engine, img.paintEngine());
2206 QCOMPARE(img, expected);
2207
2208 {
2209 QImage img1(16, 16, QImage::Format_ARGB32);
2210 QImage img2 = img1;
2211 QVERIFY(img2.paintEngine());
2212 }
2213}
2214
2215void tst_QImage::setAlphaChannelWhilePainting()
2216{
2217 QImage image(100, 100, QImage::Format_ARGB32);
2218 image.fill(color: Qt::black);
2219 QPainter p(&image);
2220
2221 image.setAlphaChannel(image.createMaskFromColor(color: QColor(Qt::black).rgb(), mode: Qt::MaskInColor));
2222}
2223
2224
2225// See task 240047 for details
2226void tst_QImage::smoothScaledSubImage()
2227{
2228 QImage original(128, 128, QImage::Format_RGB32);
2229 QPainter p(&original);
2230 p.fillRect(x: 0, y: 0, w: 64, h: 128, c: Qt::black);
2231 p.fillRect(x: 64, y: 0, w: 64, h: 128, c: Qt::white);
2232 p.end();
2233
2234 QImage subimage(((const QImage &) original).bits(), 32, 32, original.bytesPerLine(), QImage::Format_RGB32); // only in the black part of the source...
2235
2236 QImage scaled = subimage.scaled(w: 8, h: 8, aspectMode: Qt::IgnoreAspectRatio, mode: Qt::SmoothTransformation);
2237
2238 for (int y=0; y<scaled.height(); ++y)
2239 for (int x=0; x<scaled.width(); ++x)
2240 QCOMPARE(scaled.pixel(x, y), 0xff000000);
2241}
2242
2243void tst_QImage::nullSize_data()
2244{
2245 QTest::addColumn<QImage>(name: "image");
2246 QTest::newRow(dataTag: "null image") << QImage();
2247 QTest::newRow(dataTag: "zero-size image") << QImage(0, 0, QImage::Format_RGB32);
2248}
2249
2250void tst_QImage::nullSize()
2251{
2252 QFETCH(QImage, image);
2253 QCOMPARE(image.isNull(), true);
2254 QCOMPARE(image.width(), image.size().width());
2255 QCOMPARE(image.height(), image.size().height());
2256}
2257
2258void tst_QImage::premultipliedAlphaConsistency()
2259{
2260 QImage img(256, 1, QImage::Format_ARGB32);
2261 for (int x = 0; x < 256; ++x)
2262 img.setPixel(x, y: 0, index_or_rgb: (x << 24) | 0xffffff);
2263
2264 QImage converted = img.convertToFormat(f: QImage::Format_ARGB8565_Premultiplied);
2265 QImage pm32 = converted.convertToFormat(f: QImage::Format_ARGB32_Premultiplied);
2266
2267 for (int i = 0; i < pm32.width(); ++i) {
2268 QRgb pixel = pm32.pixel(x: i, y: 0);
2269 QVERIFY(qRed(pixel) <= qAlpha(pixel));
2270 QVERIFY(qGreen(pixel) <= qAlpha(pixel));
2271 QVERIFY(qBlue(pixel) <= qAlpha(pixel));
2272 }
2273}
2274
2275void tst_QImage::compareIndexed()
2276{
2277 QImage img(256, 1, QImage::Format_Indexed8);
2278
2279 QVector<QRgb> colorTable(256);
2280 for (int i = 0; i < 256; ++i)
2281 colorTable[i] = qRgb(r: i, g: i, b: i);
2282 img.setColorTable(colorTable);
2283
2284 for (int i = 0; i < 256; ++i) {
2285 img.setPixel(x: i, y: 0, index_or_rgb: i);
2286 }
2287
2288 QImage imgInverted(256, 1, QImage::Format_Indexed8);
2289 QVector<QRgb> invertedColorTable(256);
2290 for (int i = 0; i < 256; ++i)
2291 invertedColorTable[255-i] = qRgb(r: i, g: i, b: i);
2292 imgInverted.setColorTable(invertedColorTable);
2293
2294 for (int i = 0; i < 256; ++i) {
2295 imgInverted.setPixel(x: i, y: 0, index_or_rgb: (255-i));
2296 }
2297
2298 QCOMPARE(img, imgInverted);
2299}
2300
2301void tst_QImage::fillColor_data()
2302{
2303 QTest::addColumn<QImage::Format>(name: "format");
2304 QTest::addColumn<Qt::GlobalColor>(name: "color");
2305 QTest::addColumn<uint>(name: "pixelValue");
2306
2307 QTest::newRow(dataTag: "Mono, color0") << QImage::Format_Mono << Qt::color0 << 0u;
2308 QTest::newRow(dataTag: "Mono, color1") << QImage::Format_Mono << Qt::color1 << 1u;
2309
2310 QTest::newRow(dataTag: "MonoLSB, color0") << QImage::Format_MonoLSB << Qt::color0 << 0u;
2311 QTest::newRow(dataTag: "MonoLSB, color1") << QImage::Format_MonoLSB << Qt::color1 << 1u;
2312
2313 const char *names[] = {
2314 "Indexed8",
2315 "RGB32",
2316 "ARGB32",
2317 "ARGB32pm",
2318 "RGB16",
2319 "ARGB8565pm",
2320 "RGB666",
2321 "ARGB6666pm",
2322 "RGB555",
2323 "ARGB8555pm",
2324 "RGB888",
2325 "RGB444",
2326 "ARGB4444pm",
2327 "RGBx8888",
2328 "RGBA8888pm",
2329 "BGR30",
2330 "A2RGB30pm",
2331 0
2332 };
2333
2334 QImage::Format formats[] = {
2335 QImage::Format_Indexed8,
2336 QImage::Format_RGB32,
2337 QImage::Format_ARGB32,
2338 QImage::Format_ARGB32_Premultiplied,
2339 QImage::Format_RGB16,
2340 QImage::Format_ARGB8565_Premultiplied,
2341 QImage::Format_RGB666,
2342 QImage::Format_ARGB6666_Premultiplied,
2343 QImage::Format_RGB555,
2344 QImage::Format_ARGB8555_Premultiplied,
2345 QImage::Format_RGB888,
2346 QImage::Format_RGB444,
2347 QImage::Format_ARGB4444_Premultiplied,
2348 QImage::Format_RGBX8888,
2349 QImage::Format_RGBA8888_Premultiplied,
2350 QImage::Format_BGR30,
2351 QImage::Format_A2RGB30_Premultiplied,
2352 };
2353
2354 for (int i=0; names[i] != 0; ++i) {
2355 QByteArray name;
2356 name.append(s: names[i]).append(s: ", ");
2357
2358 QTest::newRow(dataTag: QByteArray(name).append(s: "black").constData()) << formats[i] << Qt::black << 0xff000000;
2359 QTest::newRow(dataTag: QByteArray(name).append(s: "white").constData()) << formats[i] << Qt::white << 0xffffffff;
2360 QTest::newRow(dataTag: QByteArray(name).append(s: "red").constData()) << formats[i] << Qt::red << 0xffff0000;
2361 QTest::newRow(dataTag: QByteArray(name).append(s: "green").constData()) << formats[i] << Qt::green << 0xff00ff00;
2362 QTest::newRow(dataTag: QByteArray(name).append(s: "blue").constData()) << formats[i] << Qt::blue << 0xff0000ff;
2363 }
2364
2365 QTest::newRow(dataTag: "RGB16, transparent") << QImage::Format_RGB16 << Qt::transparent << 0xff000000;
2366 QTest::newRow(dataTag: "RGB32, transparent") << QImage::Format_RGB32 << Qt::transparent << 0xff000000;
2367 QTest::newRow(dataTag: "ARGB32, transparent") << QImage::Format_ARGB32 << Qt::transparent << 0x00000000u;
2368 QTest::newRow(dataTag: "ARGB32pm, transparent") << QImage::Format_ARGB32_Premultiplied << Qt::transparent << 0x00000000u;
2369 QTest::newRow(dataTag: "RGBA8888pm, transparent") << QImage::Format_RGBA8888_Premultiplied << Qt::transparent << 0x00000000u;
2370 QTest::newRow(dataTag: "A2RGB30pm, transparent") << QImage::Format_A2RGB30_Premultiplied << Qt::transparent << 0x00000000u;
2371}
2372
2373void tst_QImage::fillColor()
2374{
2375 QFETCH(QImage::Format, format);
2376 QFETCH(Qt::GlobalColor, color);
2377 QFETCH(uint, pixelValue);
2378
2379 QImage image(1, 1, format);
2380
2381 if (image.depth() == 8) {
2382 QVector<QRgb> table;
2383 table << 0xff000000;
2384 table << 0xffffffff;
2385 table << 0xffff0000;
2386 table << 0xff00ff00;
2387 table << 0xff0000ff;
2388 image.setColorTable(table);
2389 }
2390
2391 image.fill(color);
2392 if (image.depth() == 1) {
2393 QCOMPARE(image.pixelIndex(0, 0), (int) pixelValue);
2394 } else {
2395 QCOMPARE(image.pixel(0, 0), pixelValue);
2396 }
2397
2398 image.fill(color: QColor(color));
2399 if (image.depth() == 1) {
2400 QCOMPARE(image.pixelIndex(0, 0), (int) pixelValue);
2401 } else {
2402 QCOMPARE(image.pixel(0, 0), pixelValue);
2403 }
2404}
2405
2406void tst_QImage::fillColorWithAlpha_data()
2407{
2408 setPixelWithAlpha_data();
2409}
2410
2411void tst_QImage::fillColorWithAlpha()
2412{
2413 QFETCH(QImage::Format, format);
2414 QImage image(1, 1, format);
2415 image.fill(color: QColor(255, 170, 85, 170));
2416 QRgb referenceColor = qRgba(r: 255, g: 170, b: 85, a: 170);
2417
2418 if (!image.hasAlphaChannel())
2419 referenceColor = 0xff000000 | referenceColor;
2420 else if (image.pixelFormat().premultiplied() == QPixelFormat::Premultiplied)
2421 referenceColor = qPremultiply(x: referenceColor);
2422
2423 QRgb color = image.pixel(x: 0, y: 0);
2424 QCOMPARE(qRed(color) & 0xf0, qRed(referenceColor) & 0xf0);
2425 QCOMPARE(qGreen(color) & 0xf0, qGreen(referenceColor) & 0xf0);
2426 QCOMPARE(qBlue(color) & 0xf0, qBlue(referenceColor) & 0xf0);
2427 QCOMPARE(qAlpha(color) & 0xf0, qAlpha(referenceColor) & 0xf0);
2428}
2429
2430void tst_QImage::fillRGB888()
2431{
2432 QImage expected(1, 1, QImage::Format_RGB888);
2433 QImage actual(1, 1, QImage::Format_RGB888);
2434
2435 for (int c = Qt::black; c < Qt::transparent; ++c) {
2436 QColor color = QColor(Qt::GlobalColor(c));
2437
2438 expected.fill(color);
2439 actual.fill(pixel: color.rgba());
2440
2441 QCOMPARE(actual.pixel(0, 0), expected.pixel(0, 0));
2442 }
2443}
2444
2445void tst_QImage::fillPixel_data()
2446{
2447 QTest::addColumn<QImage::Format>(name: "format");
2448 QTest::addColumn<uint>(name: "color");
2449 QTest::addColumn<uint>(name: "pixelValue");
2450
2451 QTest::newRow(dataTag: "RGB16, transparent") << QImage::Format_RGB16 << 0x0u << 0xff000000u;
2452 QTest::newRow(dataTag: "RGB32, transparent") << QImage::Format_RGB32 << 0x0u << 0xff000000u;
2453 QTest::newRow(dataTag: "RGB444, transparent") << QImage::Format_RGB444 << 0x0u << 0xff000000u;
2454 QTest::newRow(dataTag: "RGB666, transparent") << QImage::Format_RGB666 << 0x0u << 0xff000000u;
2455 QTest::newRow(dataTag: "RGBx8888, transparent") << QImage::Format_RGBX8888 << 0x0u << 0xff000000u;
2456 QTest::newRow(dataTag: "ARGB32, transparent") << QImage::Format_ARGB32 << 0x0u << 0x00000000u;
2457 QTest::newRow(dataTag: "ARGB32pm, transparent") << QImage::Format_ARGB32_Premultiplied << 0x0u << 0x00000000u;
2458 QTest::newRow(dataTag: "RGBA8888pm, transparent") << QImage::Format_RGBA8888_Premultiplied << 0x0u << 0x00000000u;
2459 QTest::newRow(dataTag: "Grayscale8, transparent") << QImage::Format_Grayscale8 << 0x0u << 0xff000000u;
2460 QTest::newRow(dataTag: "Alpha8, transparent") << QImage::Format_Alpha8 << 0x0u << 0x00000000u;
2461
2462 QTest::newRow(dataTag: "RGB16, red") << QImage::Format_RGB16 << (uint)qConvertRgb32To16(c: 0xffff0000) << 0xffff0000u;
2463 QTest::newRow(dataTag: "RGB32, red") << QImage::Format_RGB32 << 0xffff0000u << 0xffff0000u;
2464 QTest::newRow(dataTag: "ARGB32, red") << QImage::Format_ARGB32 << 0xffff0000u << 0xffff0000u;
2465 QTest::newRow(dataTag: "RGBA8888, red") << QImage::Format_RGBA8888 << 0xff0000ffu << 0xffff0000u;
2466
2467 QTest::newRow(dataTag: "Grayscale8, grey") << QImage::Format_Grayscale8 << 0x80u << 0xff808080u;
2468
2469 QTest::newRow(dataTag: "RGB32, semi-red") << QImage::Format_RGB32 << 0x80ff0000u << 0xffff0000u;
2470 QTest::newRow(dataTag: "ARGB32, semi-red") << QImage::Format_ARGB32 << 0x80ff0000u << 0x80ff0000u;
2471 QTest::newRow(dataTag: "ARGB32pm, semi-red") << QImage::Format_ARGB32 << 0x80800000u << 0x80800000u;
2472 QTest::newRow(dataTag: "RGBA8888pm, semi-red") << QImage::Format_RGBA8888_Premultiplied << 0x80000080u << 0x80800000u;
2473
2474 QTest::newRow(dataTag: "Alpha8, semi-transparent") << QImage::Format_Alpha8 << 0x80u << 0x80000000u;
2475}
2476
2477void tst_QImage::fillPixel()
2478{
2479 QFETCH(QImage::Format, format);
2480 QFETCH(uint, color);
2481 QFETCH(uint, pixelValue);
2482
2483 QImage image(1, 1, format);
2484
2485 image.fill(pixel: color);
2486 QCOMPARE(image.pixel(0, 0), pixelValue);
2487 if (image.depth() == 8)
2488 QCOMPARE(*(const uchar *)image.constBits(), color);
2489}
2490
2491void tst_QImage::rgbSwapped_data()
2492{
2493 QTest::addColumn<QImage::Format>(name: "format");
2494
2495 for (int i = QImage::Format_Indexed8; i < QImage::NImageFormats; ++i) {
2496 if (i == QImage::Format_Alpha8
2497 || i == QImage::Format_Grayscale8
2498 || i == QImage::Format_Grayscale16) {
2499 continue;
2500 }
2501 QTest::addRow(format: "%s", formatToString(format: QImage::Format(i)).data()) << QImage::Format(i);
2502 }
2503}
2504
2505void tst_QImage::rgbSwapped()
2506{
2507 QFETCH(QImage::Format, format);
2508
2509 QImage image(100, 1, format);
2510 image.fill(pixel: 0);
2511
2512 QVector<QColor> testColor(image.width());
2513
2514 for (int i = 0; i < image.width(); ++i)
2515 testColor[i] = QColor(i, 10 + i, 20 + i * 2, 30 + i);
2516
2517 if (format != QImage::Format_Indexed8) {
2518 QPainter p(&image);
2519 p.setCompositionMode(QPainter::CompositionMode_Source);
2520 for (int i = 0; i < image.width(); ++i)
2521 p.fillRect(QRect(i, 0, 1, 1), color: testColor[i].rgb());
2522 } else {
2523 image.setColorCount(image.width());
2524 for (int i = 0; i < image.width(); ++i) {
2525 image.setColor(i: 0, c: testColor[i].rgba());
2526 image.setPixel(x: i, y: 0, index_or_rgb: i);
2527 }
2528 }
2529
2530 QImage imageSwapped = image.rgbSwapped();
2531
2532 for (int i = 0; i < image.width(); ++i) {
2533 QColor referenceColor = QColor(image.pixel(x: i, y: 0));
2534 QColor swappedColor = QColor(imageSwapped.pixel(x: i, y: 0));
2535
2536 QCOMPARE(swappedColor.alpha(), referenceColor.alpha());
2537 QCOMPARE(swappedColor.red(), referenceColor.blue());
2538 QCOMPARE(swappedColor.green(), referenceColor.green());
2539 QCOMPARE(swappedColor.blue(), referenceColor.red());
2540 }
2541
2542 QImage imageSwappedTwice = imageSwapped.rgbSwapped();
2543
2544 QCOMPARE(image, imageSwappedTwice);
2545
2546 QCOMPARE(memcmp(image.constBits(), imageSwappedTwice.constBits(), image.sizeInBytes()), 0);
2547}
2548
2549void tst_QImage::mirrored_data()
2550{
2551 QTest::addColumn<QImage::Format>(name: "format");
2552 QTest::addColumn<bool>(name: "swap_vertical");
2553 QTest::addColumn<bool>(name: "swap_horizontal");
2554 QTest::addColumn<int>(name: "width");
2555 QTest::addColumn<int>(name: "height");
2556
2557 QTest::newRow(dataTag: "Format_RGB32, vertical") << QImage::Format_RGB32 << true << false << 16 << 16;
2558 QTest::newRow(dataTag: "Format_ARGB32, vertical") << QImage::Format_ARGB32 << true << false << 16 << 16;
2559 QTest::newRow(dataTag: "Format_ARGB32_Premultiplied, vertical") << QImage::Format_ARGB32_Premultiplied << true << false << 16 << 16;
2560 QTest::newRow(dataTag: "Format_RGB16, vertical") << QImage::Format_RGB16 << true << false << 16 << 16;
2561 QTest::newRow(dataTag: "Format_ARGB8565_Premultiplied, vertical") << QImage::Format_ARGB8565_Premultiplied << true << false << 16 << 16;
2562 QTest::newRow(dataTag: "Format_ARGB6666_Premultiplied, vertical") << QImage::Format_ARGB6666_Premultiplied << true << false << 16 << 16;
2563 QTest::newRow(dataTag: "Format_ARGB4444_Premultiplied, vertical") << QImage::Format_ARGB4444_Premultiplied << true << false << 16 << 16;
2564 QTest::newRow(dataTag: "Format_RGB666, vertical") << QImage::Format_RGB666 << true << false << 16 << 16;
2565 QTest::newRow(dataTag: "Format_RGB555, vertical") << QImage::Format_RGB555 << true << false << 16 << 16;
2566 QTest::newRow(dataTag: "Format_ARGB8555_Premultiplied, vertical") << QImage::Format_ARGB8555_Premultiplied << true << false << 16 << 16;
2567 QTest::newRow(dataTag: "Format_RGB888, vertical") << QImage::Format_RGB888 << true << false << 16 << 16;
2568 QTest::newRow(dataTag: "Format_BGR888, vertical") << QImage::Format_BGR888 << true << false << 16 << 16;
2569 QTest::newRow(dataTag: "Format_RGB444, vertical") << QImage::Format_RGB444 << true << false << 16 << 16;
2570 QTest::newRow(dataTag: "Format_RGBX8888, vertical") << QImage::Format_RGBX8888 << true << false << 16 << 16;
2571 QTest::newRow(dataTag: "Format_RGBA8888_Premultiplied, vertical") << QImage::Format_RGBA8888_Premultiplied << true << false << 16 << 16;
2572 QTest::newRow(dataTag: "Format_A2BGR30_Premultiplied, vertical") << QImage::Format_A2BGR30_Premultiplied << true << false << 16 << 16;
2573 QTest::newRow(dataTag: "Format_RGB30, vertical") << QImage::Format_RGB30 << true << false << 16 << 16;
2574 QTest::newRow(dataTag: "Format_Indexed8, vertical") << QImage::Format_Indexed8 << true << false << 16 << 16;
2575 QTest::newRow(dataTag: "Format_Mono, vertical") << QImage::Format_Mono << true << false << 16 << 16;
2576 QTest::newRow(dataTag: "Format_MonoLSB, vertical") << QImage::Format_MonoLSB << true << false << 16 << 16;
2577
2578 QTest::newRow(dataTag: "Format_ARGB32_Premultiplied, horizontal") << QImage::Format_ARGB32_Premultiplied << false << true << 16 << 16;
2579 QTest::newRow(dataTag: "Format_RGB888, horizontal") << QImage::Format_RGB888 << false << true << 16 << 16;
2580 QTest::newRow(dataTag: "Format_RGB16, horizontal") << QImage::Format_RGB16 << false << true << 16 << 16;
2581 QTest::newRow(dataTag: "Format_Indexed8, horizontal") << QImage::Format_Indexed8 << false << true << 16 << 16;
2582 QTest::newRow(dataTag: "Format_Mono, horizontal") << QImage::Format_Mono << false << true << 16 << 16;
2583 QTest::newRow(dataTag: "Format_MonoLSB, horizontal") << QImage::Format_MonoLSB << false << true << 16 << 16;
2584
2585 QTest::newRow(dataTag: "Format_ARGB32_Premultiplied, horizontal+vertical") << QImage::Format_ARGB32_Premultiplied << true << true << 16 << 16;
2586 QTest::newRow(dataTag: "Format_RGB888, horizontal+vertical") << QImage::Format_RGB888 << true << true << 16 << 16;
2587 QTest::newRow(dataTag: "Format_RGB16, horizontal+vertical") << QImage::Format_RGB16 << true << true << 16 << 16;
2588 QTest::newRow(dataTag: "Format_Indexed8, horizontal+vertical") << QImage::Format_Indexed8 << true << true << 16 << 16;
2589 QTest::newRow(dataTag: "Format_Mono, horizontal+vertical") << QImage::Format_Mono << true << true << 16 << 16;
2590 QTest::newRow(dataTag: "Format_MonoLSB, horizontal+vertical") << QImage::Format_MonoLSB << true << true << 16 << 16;
2591
2592 QTest::newRow(dataTag: "Format_RGB32, vertical") << QImage::Format_RGB32 << true << false << 8 << 16;
2593 QTest::newRow(dataTag: "Format_ARGB32, vertical") << QImage::Format_ARGB32 << true << false << 16 << 8;
2594 QTest::newRow(dataTag: "Format_Mono, vertical, non-aligned") << QImage::Format_Mono << true << false << 19 << 25;
2595 QTest::newRow(dataTag: "Format_MonoLSB, vertical, non-aligned") << QImage::Format_MonoLSB << true << false << 19 << 25;
2596
2597 // Non-aligned horizontal 1-bit needs special handling so test this.
2598 QTest::newRow(dataTag: "Format_Mono, horizontal, non-aligned") << QImage::Format_Mono << false << true << 13 << 17;
2599 QTest::newRow(dataTag: "Format_Mono, horizontal, non-aligned") << QImage::Format_Mono << false << true << 19 << 25;
2600 QTest::newRow(dataTag: "Format_Mono, horizontal+vertical, non-aligned") << QImage::Format_Mono << true << true << 25 << 47;
2601 QTest::newRow(dataTag: "Format_Mono, horizontal+vertical, non-aligned") << QImage::Format_Mono << true << true << 21 << 16;
2602
2603 QTest::newRow(dataTag: "Format_MonoLSB, horizontal, non-aligned") << QImage::Format_MonoLSB << false << true << 13 << 17;
2604 QTest::newRow(dataTag: "Format_MonoLSB, horizontal, non-aligned") << QImage::Format_MonoLSB << false << true << 19 << 25;
2605 QTest::newRow(dataTag: "Format_MonoLSB, horizontal+vertical, non-aligned") << QImage::Format_MonoLSB << true << true << 25 << 47;
2606 QTest::newRow(dataTag: "Format_MonoLSB, horizontal+vertical, non-aligned") << QImage::Format_MonoLSB << true << true << 21 << 16;
2607}
2608
2609void tst_QImage::mirrored()
2610{
2611 QFETCH(QImage::Format, format);
2612 QFETCH(bool, swap_vertical);
2613 QFETCH(bool, swap_horizontal);
2614 QFETCH(int, width);
2615 QFETCH(int, height);
2616
2617 QImage image(width, height, format);
2618
2619 switch (format) {
2620 case QImage::Format_Mono:
2621 case QImage::Format_MonoLSB:
2622 for (int i = 0; i < image.height(); ++i) {
2623 ushort* scanLine = (ushort*)image.scanLine(i);
2624 *scanLine = (i % 2) ? 0x5555U : 0xCCCCU;
2625 }
2626 break;
2627 case QImage::Format_Indexed8:
2628 for (int i = 0; i < image.height(); ++i) {
2629 for (int j = 0; j < image.width(); ++j) {
2630 image.setColor(i: i*16+j, c: qRgb(r: j*16, g: i*16, b: 0));
2631 image.setPixel(x: j, y: i, index_or_rgb: i*16+j);
2632 }
2633 }
2634 break;
2635 default:
2636 for (int i = 0; i < image.height(); ++i)
2637 for (int j = 0; j < image.width(); ++j)
2638 image.setPixel(x: j, y: i, index_or_rgb: qRgb(r: j*16, g: i*16, b: 0));
2639 break;
2640 }
2641
2642 QImage imageMirrored = image.mirrored(horizontally: swap_horizontal, vertically: swap_vertical);
2643
2644 for (int i = 0; i < image.height(); ++i) {
2645 int mirroredI = swap_vertical ? (image.height() - i - 1) : i;
2646 for (int j = 0; j < image.width(); ++j) {
2647 QRgb referenceColor = image.pixel(x: j, y: i);
2648 int mirroredJ = swap_horizontal ? (image.width() - j - 1) : j;
2649 QRgb mirroredColor = imageMirrored.pixel(x: mirroredJ, y: mirroredI);
2650 QCOMPARE(mirroredColor, referenceColor);
2651 }
2652 }
2653
2654 QImage imageMirroredTwice = imageMirrored.mirrored(horizontally: swap_horizontal, vertically: swap_vertical);
2655
2656 QCOMPARE(image, imageMirroredTwice);
2657
2658 if (format != QImage::Format_Mono && format != QImage::Format_MonoLSB)
2659 QCOMPARE(memcmp(image.constBits(), imageMirroredTwice.constBits(), image.sizeInBytes()), 0);
2660 else {
2661 for (int i = 0; i < image.height(); ++i)
2662 for (int j = 0; j < image.width(); ++j)
2663 QCOMPARE(image.pixel(j,i), imageMirroredTwice.pixel(j,i));
2664 }
2665}
2666
2667void tst_QImage::inplaceRgbSwapped_data()
2668{
2669 rgbSwapped_data();
2670}
2671
2672void tst_QImage::inplaceRgbSwapped()
2673{
2674#if defined(Q_COMPILER_REF_QUALIFIERS)
2675 QFETCH(QImage::Format, format);
2676
2677 QImage image(64, 1, format);
2678 image.fill(pixel: 0);
2679
2680 QVector<QRgb> testColor(image.width());
2681 for (int i = 0; i < image.width(); ++i)
2682 testColor[i] = qRgb(r: i * 2, g: i * 3, b: 255 - i * 4);
2683
2684 if (format == QImage::Format_Indexed8) {
2685 for (int i = 0; i < image.width(); ++i) {
2686 image.setColor(i, c: testColor[i]);
2687 image.setPixel(x: i, y: 0, index_or_rgb: i);
2688 }
2689 } else {
2690 for (int i = 0; i < image.width(); ++i)
2691 image.setPixel(x: i, y: 0, index_or_rgb: testColor[i]);
2692 }
2693
2694 const uchar* orginalPtr = image.constScanLine(0);
2695 QImage imageSwapped = std::move(image).rgbSwapped();
2696
2697 for (int i = 0; i < imageSwapped.width(); ++i) {
2698 QRgb referenceColor = testColor[i];
2699 QRgb swappedColor = imageSwapped.pixel(x: i, y: 0);
2700 QCOMPARE(qRed(swappedColor) & 0xf0, qBlue(referenceColor) & 0xf0);
2701 QCOMPARE(qGreen(swappedColor) & 0xf0, qGreen(referenceColor) & 0xf0);
2702 QCOMPARE(qBlue(swappedColor) & 0xf0, qRed(referenceColor) & 0xf0);
2703 }
2704
2705 QCOMPARE(imageSwapped.constScanLine(0), orginalPtr);
2706
2707 for (int rw = 0; rw <= 1; rw++) {
2708 // Test attempted inplace conversion of images created on existing buffer
2709 uchar *volatileData = 0;
2710 QImage orig = imageSwapped;
2711 QImage dataSwapped;
2712 {
2713 QVERIFY(!orig.isNull());
2714 volatileData = new uchar[orig.sizeInBytes()];
2715 memcpy(dest: volatileData, src: orig.constBits(), n: orig.sizeInBytes());
2716
2717 QImage dataImage;
2718 if (rw)
2719 dataImage = QImage(volatileData, orig.width(), orig.height(), orig.format());
2720 else
2721 dataImage = QImage((const uchar *)volatileData, orig.width(), orig.height(), orig.format());
2722
2723 if (orig.colorCount())
2724 dataImage.setColorTable(orig.colorTable());
2725
2726 dataSwapped = std::move(dataImage).rgbSwapped();
2727 QVERIFY(!dataSwapped.isNull());
2728 delete[] volatileData;
2729 }
2730
2731 QVERIFY2(dataSwapped.constBits() != volatileData, rw ? "non-const" : "const");
2732 QCOMPARE(dataSwapped, orig.rgbSwapped());
2733 }
2734
2735#endif
2736}
2737
2738
2739void tst_QImage::inplaceMirrored_data()
2740{
2741 QTest::addColumn<QImage::Format>(name: "format");
2742 QTest::addColumn<bool>(name: "swap_vertical");
2743 QTest::addColumn<bool>(name: "swap_horizontal");
2744
2745 for (int i = QImage::Format_Mono; i < QImage::NImageFormats; ++i) {
2746 if (i == QImage::Format_Alpha8
2747 || i == QImage::Format_Grayscale8
2748 || i == QImage::Format_Grayscale16) {
2749 continue;
2750 }
2751 if (i == QImage::Format_RGB444 || i == QImage::Format_ARGB4444_Premultiplied)
2752 continue;
2753 const auto fmt = formatToString(format: QImage::Format(i));
2754 QTest::addRow(format: "%s, vertical", fmt.data())
2755 << QImage::Format(i) << true << false;
2756 QTest::addRow(format: "%s, horizontal", fmt.data())
2757 << QImage::Format(i) << false << true;
2758 QTest::addRow(format: "%s, horizontal+vertical", fmt.data())
2759 << QImage::Format(i) << true << true;
2760 }
2761}
2762
2763void tst_QImage::inplaceMirrored()
2764{
2765#if defined(Q_COMPILER_REF_QUALIFIERS)
2766 QFETCH(QImage::Format, format);
2767 QFETCH(bool, swap_vertical);
2768 QFETCH(bool, swap_horizontal);
2769
2770 QImage image(16, 16, format);
2771
2772 switch (format) {
2773 case QImage::Format_Mono:
2774 case QImage::Format_MonoLSB:
2775 for (int i = 0; i < image.height(); ++i) {
2776 ushort* scanLine = (ushort*)image.scanLine(i);
2777 *scanLine = (i % 2) ? 0x0fffU : 0xf000U;
2778 }
2779 break;
2780 case QImage::Format_Indexed8:
2781 for (int i = 0; i < image.height(); ++i) {
2782 for (int j = 0; j < image.width(); ++j) {
2783 image.setColor(i: i*16+j, c: qRgb(r: j*16, g: i*16, b: 0));
2784 image.setPixel(x: j, y: i, index_or_rgb: i*16+j);
2785 }
2786 }
2787 break;
2788 default:
2789 for (int i = 0; i < image.height(); ++i)
2790 for (int j = 0; j < image.width(); ++j)
2791 image.setPixel(x: j, y: i, index_or_rgb: qRgb(r: j*16, g: i*16, b: 0));
2792 }
2793
2794 const uchar* originalPtr = image.constScanLine(0);
2795
2796 QImage imageMirrored = std::move(image).mirrored(horizontally: swap_horizontal, vertically: swap_vertical);
2797 if (format != QImage::Format_Mono && format != QImage::Format_MonoLSB) {
2798 for (int i = 0; i < imageMirrored.height(); ++i) {
2799 int mirroredI = swap_vertical ? (imageMirrored.height() - i - 1) : i;
2800 for (int j = 0; j < imageMirrored.width(); ++j) {
2801 int mirroredJ = swap_horizontal ? (imageMirrored.width() - j - 1) : j;
2802 QRgb mirroredColor = imageMirrored.pixel(x: mirroredJ, y: mirroredI);
2803 QCOMPARE(qRed(mirroredColor) & 0xF8, j * 16);
2804 QCOMPARE(qGreen(mirroredColor) & 0xF8, i * 16);
2805 }
2806 }
2807 } else {
2808 for (int i = 0; i < imageMirrored.height(); ++i) {
2809 ushort* scanLine = (ushort*)imageMirrored.scanLine(i);
2810 ushort expect;
2811 if (swap_vertical && swap_horizontal)
2812 expect = (i % 2) ? 0x000fU : 0xfff0U;
2813 else if (swap_vertical)
2814 expect = (i % 2) ? 0xf000U : 0x0fffU;
2815 else
2816 expect = (i % 2) ? 0xfff0U : 0x000fU;
2817 QCOMPARE(*scanLine, expect);
2818 }
2819 }
2820 QCOMPARE(imageMirrored.constScanLine(0), originalPtr);
2821
2822 for (int rw = 0; rw <= 1; rw++) {
2823 // Test attempted inplace conversion of images created on existing buffer
2824 uchar *volatileData = 0;
2825 QImage orig = imageMirrored;
2826 QImage dataSwapped;
2827 {
2828 QVERIFY(!orig.isNull());
2829 volatileData = new uchar[orig.sizeInBytes()];
2830 memcpy(dest: volatileData, src: orig.constBits(), n: orig.sizeInBytes());
2831
2832 QImage dataImage;
2833 if (rw)
2834 dataImage = QImage(volatileData, orig.width(), orig.height(), orig.format());
2835 else
2836 dataImage = QImage((const uchar *)volatileData, orig.width(), orig.height(), orig.format());
2837
2838 if (orig.colorCount())
2839 dataImage.setColorTable(orig.colorTable());
2840
2841 dataSwapped = std::move(dataImage).mirrored(horizontally: swap_horizontal, vertically: swap_vertical);
2842 QVERIFY(!dataSwapped.isNull());
2843 delete[] volatileData;
2844 }
2845
2846 QVERIFY2(dataSwapped.constBits() != volatileData, rw ? "non-const" : "const");
2847 QCOMPARE(dataSwapped, orig.mirrored(swap_horizontal, swap_vertical));
2848 }
2849
2850#endif
2851}
2852
2853void tst_QImage::inplaceMirroredOdd_data()
2854{
2855 QTest::addColumn<QImage::Format>(name: "format");
2856 QTest::addColumn<bool>(name: "swap_vertical");
2857 QTest::addColumn<bool>(name: "swap_horizontal");
2858
2859 QTest::newRow(dataTag: "Format_ARGB32, vertical") << QImage::Format_ARGB32 << true << false;
2860 QTest::newRow(dataTag: "Format_RGB888, vertical") << QImage::Format_RGB888 << true << false;
2861 QTest::newRow(dataTag: "Format_RGB16, vertical") << QImage::Format_RGB16 << true << false;
2862
2863 QTest::newRow(dataTag: "Format_ARGB32, horizontal") << QImage::Format_ARGB32 << false << true;
2864 QTest::newRow(dataTag: "Format_RGB888, horizontal") << QImage::Format_RGB888 << false << true;
2865 QTest::newRow(dataTag: "Format_RGB16, horizontal") << QImage::Format_RGB16 << false << true;
2866
2867 QTest::newRow(dataTag: "Format_ARGB32, horizontal+vertical") << QImage::Format_ARGB32 << true << true;
2868 QTest::newRow(dataTag: "Format_RGB888, horizontal+vertical") << QImage::Format_RGB888 << true << true;
2869 QTest::newRow(dataTag: "Format_RGB16, horizontal+vertical") << QImage::Format_RGB16 << true << true;
2870}
2871
2872void tst_QImage::inplaceMirroredOdd()
2873{
2874#if defined(Q_COMPILER_REF_QUALIFIERS)
2875 QFETCH(QImage::Format, format);
2876 QFETCH(bool, swap_vertical);
2877 QFETCH(bool, swap_horizontal);
2878
2879 QImage image(15, 15, format);
2880
2881 for (int i = 0; i < image.height(); ++i)
2882 for (int j = 0; j < image.width(); ++j)
2883 image.setPixel(x: j, y: i, index_or_rgb: qRgb(r: j*16, g: i*16, b: 0));
2884
2885 const uchar* originalPtr = image.constScanLine(0);
2886
2887 QImage imageMirrored = std::move(image).mirrored(horizontally: swap_horizontal, vertically: swap_vertical);
2888 for (int i = 0; i < imageMirrored.height(); ++i) {
2889 int mirroredI = swap_vertical ? (imageMirrored.height() - i - 1) : i;
2890 for (int j = 0; j < imageMirrored.width(); ++j) {
2891 int mirroredJ = swap_horizontal ? (imageMirrored.width() - j - 1) : j;
2892 QRgb mirroredColor = imageMirrored.pixel(x: mirroredJ, y: mirroredI);
2893 QCOMPARE(qRed(mirroredColor) & 0xF8, j * 16);
2894 QCOMPARE(qGreen(mirroredColor) & 0xF8, i * 16);
2895 }
2896 }
2897 QCOMPARE(imageMirrored.constScanLine(0), originalPtr);
2898#endif
2899}
2900
2901void tst_QImage::inplaceRgbMirrored()
2902{
2903#if defined(Q_COMPILER_REF_QUALIFIERS)
2904 QImage image1(32, 32, QImage::Format_ARGB32);
2905 QImage image2(32, 32, QImage::Format_ARGB32);
2906 image1.fill(pixel: 0);
2907 image2.fill(pixel: 0);
2908 const uchar* originalPtr1 = image1.constScanLine(0);
2909 const uchar* originalPtr2 = image2.constScanLine(0);
2910
2911 QCOMPARE(std::move(image1).rgbSwapped().mirrored().constScanLine(0), originalPtr1);
2912 QCOMPARE(std::move(image2).mirrored().rgbSwapped().constScanLine(0), originalPtr2);
2913#endif
2914}
2915
2916void tst_QImage::genericRgbConversion_data()
2917{
2918 QTest::addColumn<QImage::Format>(name: "format");
2919 QTest::addColumn<QImage::Format>(name: "dest_format");
2920
2921 for (int i = QImage::Format_RGB32; i < QImage::NImageFormats; ++i) {
2922 if (i == QImage::Format_Alpha8)
2923 continue;
2924 const QLatin1String formatI = formatToString(format: QImage::Format(i));
2925 for (int j = QImage::Format_RGB32; j < QImage::NImageFormats; ++j) {
2926 if (j == QImage::Format_Alpha8)
2927 continue;
2928 if (i == j)
2929 continue;
2930 QTest::addRow(format: "%s -> %s", formatI.data(), formatToString(format: QImage::Format(j)).data())
2931 << QImage::Format(i) << QImage::Format(j);
2932 }
2933 }
2934}
2935
2936void tst_QImage::genericRgbConversion()
2937{
2938 // Test that all RGB conversions work and maintain at least 4bit of color accuracy.
2939 QFETCH(QImage::Format, format);
2940 QFETCH(QImage::Format, dest_format);
2941
2942 bool srcGrayscale = format == QImage::Format_Grayscale8 || format == QImage::Format_Grayscale16;
2943 bool dstGrayscale = dest_format == QImage::Format_Grayscale8 || dest_format == QImage::Format_Grayscale16;
2944
2945 QImage image(16, 16, format);
2946
2947 for (int i = 0; i < image.height(); ++i)
2948 for (int j = 0; j < image.width(); ++j)
2949 image.setPixel(x: j, y: i, index_or_rgb: qRgb(r: j*16, g: i*16, b: 0));
2950
2951 QImage imageConverted = image.convertToFormat(f: dest_format);
2952 QCOMPARE(imageConverted.format(), dest_format);
2953 for (int i = 0; i < imageConverted.height(); ++i) {
2954 for (int j = 0; j < imageConverted.width(); ++j) {
2955 QRgb convertedColor = imageConverted.pixel(x: j,y: i);
2956 if (srcGrayscale || dstGrayscale) {
2957 QVERIFY(qAbs(qGray(convertedColor) - qGray(qRgb(j*16, i*16, 0))) < 15);
2958 } else {
2959 QCOMPARE(qRed(convertedColor) & 0xF0, j * 16);
2960 QCOMPARE(qGreen(convertedColor) & 0xF0, i * 16);
2961 }
2962 }
2963 }
2964}
2965
2966void tst_QImage::inplaceRgbConversion_data()
2967{
2968 QTest::addColumn<QImage::Format>(name: "format");
2969 QTest::addColumn<QImage::Format>(name: "dest_format");
2970
2971 for (int i = QImage::Format_RGB32; i < QImage::NImageFormats; ++i) {
2972 if (i == QImage::Format_Alpha8
2973 || i == QImage::Format_Grayscale8
2974 || i == QImage::Format_Grayscale16) {
2975 continue;
2976 }
2977 for (int j = QImage::Format_RGB32; j < QImage::NImageFormats; ++j) {
2978 if (j == QImage::Format_Alpha8
2979 || j == QImage::Format_Grayscale8
2980 || j == QImage::Format_Grayscale16) {
2981 continue;
2982 }
2983 if (i == j)
2984 continue;
2985 if (qt_depthForFormat(format: QImage::Format(i)) >= qt_depthForFormat(format: QImage::Format(j)))
2986 QTest::addRow(format: "%s -> %s", formatToString(format: QImage::Format(i)).data(), formatToString(format: QImage::Format(j)).data())
2987 << QImage::Format(i) << QImage::Format(j);
2988 }
2989 }
2990}
2991
2992void tst_QImage::inplaceRgbConversion()
2993{
2994 QFETCH(QImage::Format, format);
2995 QFETCH(QImage::Format, dest_format);
2996
2997 QImage image(16, 16, format);
2998
2999 for (int i = 0; i < image.height(); ++i)
3000 for (int j = 0; j < image.width(); ++j)
3001 image.setPixel(x: j, y: i, index_or_rgb: qRgb(r: j*16, g: i*16, b: 0));
3002
3003 const uchar* originalPtr = image.constScanLine(0);
3004
3005 QImage imageConverted = std::move(image).convertToFormat(f: dest_format);
3006 QCOMPARE(imageConverted.format(), dest_format);
3007 for (int i = 0; i < imageConverted.height(); ++i) {
3008 for (int j = 0; j < imageConverted.width(); ++j) {
3009 QRgb convertedColor = imageConverted.pixel(x: j,y: i);
3010 QCOMPARE(qRed(convertedColor) & 0xF0, j * 16);
3011 QCOMPARE(qGreen(convertedColor) & 0xF0, i * 16);
3012 }
3013 }
3014 if (qt_depthForFormat(format) == qt_depthForFormat(format: dest_format))
3015 QCOMPARE(imageConverted.constScanLine(0), originalPtr);
3016
3017 if (qt_depthForFormat(format) <= 32) {
3018 // Test attempted inplace conversion of images created on existing buffer
3019 static const quint32 readOnlyData[] = { 0xff0102ffU, 0xff0506ffU, 0xff0910ffU, 0xff1314ffU };
3020 quint32 readWriteData[] = { 0xff0102ffU, 0xff0506ffU, 0xff0910ffU, 0xff1314ffU };
3021
3022 QImage roInplaceConverted;
3023 QImage rwInplaceConverted;
3024
3025 {
3026 QImage roImage((const uchar *)readOnlyData, 2, 2, format);
3027 roInplaceConverted = std::move(roImage).convertToFormat(f: dest_format);
3028
3029 QImage rwImage((uchar *)readWriteData, 2, 2, format);
3030 rwInplaceConverted = std::move(rwImage).convertToFormat(f: dest_format);
3031 }
3032
3033 QImage roImage2((const uchar *)readOnlyData, 2, 2, format);
3034 QImage normalConverted = roImage2.convertToFormat(f: dest_format);
3035
3036 QVERIFY(roInplaceConverted.constBits() != (const uchar *)readOnlyData);
3037 QCOMPARE(normalConverted, roInplaceConverted);
3038
3039 QVERIFY(rwInplaceConverted.constBits() != (const uchar *)readWriteData);
3040 QCOMPARE(normalConverted, rwInplaceConverted);
3041 }
3042}
3043
3044void tst_QImage::largeGenericRgbConversion_data()
3045{
3046 QTest::addColumn<QImage::Format>(name: "format");
3047 QTest::addColumn<QImage::Format>(name: "dest_format");
3048
3049 QImage::Format formats[] = {
3050 QImage::Format_RGB32,
3051 QImage::Format_ARGB32,
3052 QImage::Format_ARGB32_Premultiplied,
3053 QImage::Format_RGB16,
3054 QImage::Format_RGB888,
3055 QImage::Format_RGBA8888,
3056 QImage::Format_BGR30,
3057 QImage::Format_A2RGB30_Premultiplied,
3058 QImage::Format_RGBA64_Premultiplied,
3059 };
3060
3061 for (QImage::Format src_format : formats) {
3062 for (QImage::Format dst_format : formats) {
3063 if (src_format == dst_format)
3064 continue;
3065
3066 QTest::addRow(format: "%s -> %s", formatToString(format: src_format).data(), formatToString(format: dst_format).data())
3067 << src_format << dst_format;
3068 }
3069 }
3070}
3071
3072void tst_QImage::largeGenericRgbConversion()
3073{
3074 // Also test a larger conversion for a few formats (here the tested precision is also higher)
3075 QFETCH(QImage::Format, format);
3076 QFETCH(QImage::Format, dest_format);
3077
3078 // Must have more than 64k pixels to trigger threaded codepath:
3079 QImage image(512, 216, format);
3080
3081 for (int i = 0; i < image.height(); ++i)
3082 for (int j = 0; j < image.width(); ++j)
3083 image.setPixel(x: j, y: i, index_or_rgb: qRgb(r: j % 256, g: i, b: 0));
3084
3085 const bool precision_8bit = (format != QImage::Format_RGB16) && (dest_format != QImage::Format_RGB16);
3086
3087 QImage imageConverted = image.convertToFormat(f: dest_format);
3088 QCOMPARE(imageConverted.format(), dest_format);
3089 for (int i = 0; i < imageConverted.height(); ++i) {
3090 for (int j = 0; j < imageConverted.width(); ++j) {
3091 if (precision_8bit) {
3092 QCOMPARE(imageConverted.pixel(j, i), image.pixel(j, i));
3093 } else {
3094 QRgb convertedColor = imageConverted.pixel(x: j,y: i);
3095 QCOMPARE(qRed(convertedColor) & 0xF8, (j % 256) & 0xF8);
3096 QCOMPARE(qGreen(convertedColor) & 0xFC, i & 0xFC);
3097 }
3098 }
3099 }
3100}
3101
3102void tst_QImage::largeInplaceRgbConversion_data()
3103{
3104 QTest::addColumn<QImage::Format>(name: "format");
3105 QTest::addColumn<QImage::Format>(name: "dest_format");
3106
3107 QImage::Format formats[] = {
3108 QImage::Format_RGB32,
3109 QImage::Format_ARGB32,
3110 QImage::Format_ARGB32_Premultiplied,
3111 QImage::Format_RGB16,
3112 QImage::Format_RGB888,
3113 QImage::Format_RGBA8888,
3114 QImage::Format_BGR30,
3115 QImage::Format_A2RGB30_Premultiplied,
3116 QImage::Format_RGBA64_Premultiplied,
3117 };
3118
3119 for (QImage::Format src_format : formats) {
3120 for (QImage::Format dst_format : formats) {
3121 if (src_format == dst_format)
3122 continue;
3123 if (qt_depthForFormat(format: src_format) < qt_depthForFormat(format: dst_format))
3124 continue;
3125 QTest::addRow(format: "%s -> %s", formatToString(format: src_format).data(), formatToString(format: dst_format).data())
3126 << src_format << dst_format;
3127 }
3128 }
3129}
3130
3131void tst_QImage::largeInplaceRgbConversion()
3132{
3133 // Also test a larger conversion for a few formats
3134 QFETCH(QImage::Format, format);
3135 QFETCH(QImage::Format, dest_format);
3136
3137 // Must have more than 64k pixels to trigger threaded codepath:
3138 QImage image(512, 216, format);
3139
3140 for (int i = 0; i < image.height(); ++i)
3141 for (int j = 0; j < image.width(); ++j)
3142 image.setPixel(x: j, y: i, index_or_rgb: qRgb(r: j % 256, g: i, b: 0));
3143
3144 const bool precision_8bit = (format != QImage::Format_RGB16) && (dest_format != QImage::Format_RGB16);
3145
3146 image.convertTo(f: dest_format);
3147 QCOMPARE(image.format(), dest_format);
3148 for (int i = 0; i < image.height(); ++i) {
3149 for (int j = 0; j < image.width(); ++j) {
3150 if (precision_8bit) {
3151 QCOMPARE(image.pixel(j,i), qRgb(j % 256, i, 0));
3152 } else {
3153 QRgb convertedColor = image.pixel(x: j,y: i);
3154 QCOMPARE(qRed(convertedColor) & 0xF8, (j % 256) & 0xF8);
3155 QCOMPARE(qGreen(convertedColor) & 0xFC, i & 0xFC);
3156 }
3157 }
3158 }
3159}
3160
3161void tst_QImage::deepCopyWhenPaintingActive()
3162{
3163 QImage image(64, 64, QImage::Format_ARGB32_Premultiplied);
3164 image.fill(pixel: 0);
3165
3166 QPainter painter(&image);
3167 QImage copy = image;
3168
3169 painter.setBrush(Qt::black);
3170 painter.drawEllipse(r: image.rect());
3171
3172 QVERIFY(copy != image);
3173}
3174
3175void tst_QImage::scaled_QTBUG19157()
3176{
3177 QImage foo(5000, 1, QImage::Format_RGB32);
3178 foo = foo.scaled(w: 1024, h: 1024, aspectMode: Qt::KeepAspectRatio);
3179 QVERIFY(!foo.isNull());
3180}
3181
3182void tst_QImage::convertOverUnPreMul()
3183{
3184 QImage image(256, 256, QImage::Format_ARGB32_Premultiplied);
3185
3186 for (int j = 0; j < 256; j++) {
3187 for (int i = 0; i <= j; i++) {
3188 image.setPixel(x: i, y: j, index_or_rgb: qRgba(r: i, g: i, b: i, a: j));
3189 }
3190 }
3191
3192 QImage image2 = image.convertToFormat(f: QImage::Format_ARGB32).convertToFormat(f: QImage::Format_ARGB32_Premultiplied);
3193
3194 for (int j = 0; j < 256; j++) {
3195 for (int i = 0; i <= j; i++) {
3196 QCOMPARE(qAlpha(image2.pixel(i, j)), qAlpha(image.pixel(i, j)));
3197 QCOMPARE(qGray(image2.pixel(i, j)), qGray(image.pixel(i, j)));
3198 }
3199 }
3200}
3201
3202void tst_QImage::scaled_QTBUG35972()
3203{
3204 QImage src(532,519,QImage::Format_ARGB32_Premultiplied);
3205 src.fill(color: QColor(Qt::white));
3206 QImage dest(1000,1000,QImage::Format_ARGB32_Premultiplied);
3207 dest.fill(color: QColor(Qt::white));
3208 QPainter painter1(&dest);
3209 const QTransform trf(1.25, 0,
3210 0, 1.25,
3211 /*dx */ 15.900000000000034, /* dy */ 72.749999999999986);
3212 painter1.setTransform(transform: trf);
3213 painter1.drawImage(targetRect: QRectF(-2.6, -2.6, 425.6, 415.20000000000005), image: src, sourceRect: QRectF(0,0,532,519));
3214
3215 const quint32 *pixels = reinterpret_cast<const quint32 *>(dest.constBits());
3216 int size = dest.width()*dest.height();
3217 for (int i = 0; i < size; ++i)
3218 QCOMPARE(pixels[i], 0xffffffff);
3219}
3220
3221void tst_QImage::convertToPixelFormat()
3222{
3223 QPixelFormat rgb565 = qPixelFormatRgba(red: 5,green: 6,blue: 5,alfa: 0,usage: QPixelFormat::IgnoresAlpha, position: QPixelFormat::AtBeginning, pmul: QPixelFormat::NotPremultiplied, typeInt: QPixelFormat::UnsignedShort);
3224 QPixelFormat rgb565ImageFormat = QImage::toPixelFormat(format: QImage::Format_RGB16);
3225 QCOMPARE(rgb565, rgb565ImageFormat);
3226}
3227
3228void tst_QImage::convertToImageFormat_data()
3229{
3230 QTest::addColumn<QImage::Format>(name: "image_format");
3231 QTest::newRow(dataTag: "Convert Format_Invalid") << QImage::Format_Invalid;
3232 QTest::newRow(dataTag: "Convert Format_Mono") << QImage::Format_Mono;
3233 //This ends up being a QImage::Format_Mono since we cant specify LSB in QPixelFormat
3234 //QTest::newRow("Convert Format_MonoLSB") << QImage::Format_MonoLSB;
3235 QTest::newRow(dataTag: "Convert Format_Indexed8") << QImage::Format_Indexed8;
3236 QTest::newRow(dataTag: "Convert Format_RGB32") << QImage::Format_RGB32;
3237 QTest::newRow(dataTag: "Convert Format_ARGB32") << QImage::Format_ARGB32;
3238 QTest::newRow(dataTag: "Convert Format_ARGB32_Premultiplied") << QImage::Format_ARGB32_Premultiplied;
3239 QTest::newRow(dataTag: "Convert Format_RGB16") << QImage::Format_RGB16;
3240 QTest::newRow(dataTag: "Convert Format_ARGB8565_Premultiplied") << QImage::Format_ARGB8565_Premultiplied;
3241 QTest::newRow(dataTag: "Convert Format_RGB666") << QImage::Format_RGB666;
3242 QTest::newRow(dataTag: "Convert Format_ARGB6666_Premultiplied") << QImage::Format_ARGB6666_Premultiplied;
3243 QTest::newRow(dataTag: "Convert Format_RGB555") << QImage::Format_RGB555;
3244 QTest::newRow(dataTag: "Convert Format_ARGB8555_Premultiplied") << QImage::Format_ARGB8555_Premultiplied;
3245 QTest::newRow(dataTag: "Convert Format_RGB888") << QImage::Format_RGB888;
3246 QTest::newRow(dataTag: "Convert Format_RGB444") << QImage::Format_RGB444;
3247 QTest::newRow(dataTag: "Convert Format_ARGB4444_Premultiplied") << QImage::Format_ARGB4444_Premultiplied;
3248 QTest::newRow(dataTag: "Convert Format_RGBX8888") << QImage::Format_RGBX8888;
3249 QTest::newRow(dataTag: "Convert Format_RGBA8888") << QImage::Format_RGBA8888;
3250 QTest::newRow(dataTag: "Convert Format_RGBA8888_Premultiplied") << QImage::Format_RGBA8888_Premultiplied;
3251}
3252
3253void tst_QImage::convertToImageFormat()
3254{
3255 QFETCH(QImage::Format, image_format);
3256
3257 QPixelFormat pixel_format = QImage::toPixelFormat(format: image_format);
3258 QImage::Format format = QImage::toImageFormat(format: pixel_format);
3259 QCOMPARE(format, image_format);
3260}
3261
3262void tst_QImage::invertPixelsRGB_data()
3263{
3264 QTest::addColumn<QImage::Format>(name: "image_format");
3265
3266 for (int i = QImage::Format_RGB32; i < QImage::NImageFormats; ++i) {
3267 if (i == QImage::Format_Alpha8
3268 || i == QImage::Format_Grayscale8
3269 || i == QImage::Format_Grayscale16) {
3270 continue;
3271 }
3272 QTest::addRow(format: "%s", formatToString(format: QImage::Format(i)).data()) << QImage::Format(i);
3273 }
3274}
3275
3276void tst_QImage::invertPixelsRGB()
3277{
3278 QFETCH(QImage::Format, image_format);
3279
3280 QImage image(1, 1, image_format);
3281 image.fill(color: QColor::fromRgb(r: 32, g: 64, b: 96));
3282 image.invertPixels();
3283
3284 QCOMPARE(image.format(), image_format);
3285
3286 uint pixel = image.pixel(x: 0, y: 0);
3287 QCOMPARE(qRed(pixel) >> 4, (255 - 32) >> 4);
3288 QCOMPARE(qGreen(pixel) >> 4, (255 - 64) >> 4);
3289 QCOMPARE(qBlue(pixel) >> 4, (255 - 96) >> 4);
3290}
3291
3292void tst_QImage::invertPixelsIndexed()
3293{
3294 {
3295 QImage image(1, 1, QImage::Format_Mono);
3296 image.fill(color: Qt::color1);
3297 image.invertPixels();
3298 QCOMPARE(image.pixelIndex(0, 0), 0);
3299 }
3300 {
3301 QImage image(1, 1, QImage::Format_MonoLSB);
3302 image.fill(color: Qt::color0);
3303 image.invertPixels();
3304 QCOMPARE(image.pixelIndex(0, 0), 1);
3305 }
3306 {
3307 QImage image(1, 1, QImage::Format_Indexed8);
3308 image.setColorTable({0xff000000, 0xffffffff});
3309 image.fill(color: Qt::black);
3310 image.invertPixels();
3311 QCOMPARE(image.pixelIndex(0, 0), 255);
3312 }
3313 {
3314 QImage image(1, 1, QImage::Format_Indexed8);
3315 image.setColorTable({0xff000000, 0xffffffff, 0x80000000, 0x80ffffff, 0x00000000});
3316 image.fill(color: Qt::white);
3317 image.invertPixels();
3318 QCOMPARE(image.pixelIndex(0, 0), 254);
3319 }
3320}
3321
3322void tst_QImage::exifOrientation_data()
3323{
3324 QTest::addColumn<QString>(name: "fileName");
3325 QTest::addColumn<int>(name: "orientation");
3326 QTest::addColumn<int>(name: "dpmx");
3327 QTest::addColumn<int>(name: "dpmy");
3328 QTest::newRow(dataTag: "Orientation 1, Intel format") << m_prefix + "jpeg_exif_orientation_value_1.jpg" << (int)QImageIOHandler::TransformationNone << 39 << 39;
3329 QTest::newRow(dataTag: "Orientation 2, Intel format") << m_prefix + "jpeg_exif_orientation_value_2.jpg" << (int)QImageIOHandler::TransformationMirror << 39 << 39;
3330 QTest::newRow(dataTag: "Orientation 3, Intel format") << m_prefix + "jpeg_exif_orientation_value_3.jpg" << (int)QImageIOHandler::TransformationRotate180 << 39 << 39;
3331 QTest::newRow(dataTag: "Orientation 4, Intel format") << m_prefix + "jpeg_exif_orientation_value_4.jpg" << (int)QImageIOHandler::TransformationFlip << 39 << 39;
3332 QTest::newRow(dataTag: "Orientation 5, Intel format") << m_prefix + "jpeg_exif_orientation_value_5.jpg" << (int)QImageIOHandler::TransformationFlipAndRotate90 << 39 << 39;
3333 QTest::newRow(dataTag: "Orientation 6, Intel format") << m_prefix + "jpeg_exif_orientation_value_6.jpg" << (int)QImageIOHandler::TransformationRotate90 << 39 << 39;
3334 QTest::newRow(dataTag: "Orientation 6, Motorola format") << m_prefix + "jpeg_exif_orientation_value_6_motorola.jpg" << (int)QImageIOHandler::TransformationRotate90 << 39 << 39;
3335 QTest::newRow(dataTag: "Orientation 7, Intel format") << m_prefix + "jpeg_exif_orientation_value_7.jpg" << (int)QImageIOHandler::TransformationMirrorAndRotate90 << 39 << 39;
3336 QTest::newRow(dataTag: "Orientation 8, Intel format") << m_prefix + "jpeg_exif_orientation_value_8.jpg" << (int)QImageIOHandler::TransformationRotate270 << 39 << 39;
3337}
3338
3339QT_BEGIN_NAMESPACE
3340extern void qt_imageTransform(QImage &src, QImageIOHandler::Transformations orient);
3341QT_END_NAMESPACE
3342QT_USE_NAMESPACE
3343
3344void tst_QImage::exifOrientation()
3345{
3346 QFETCH(QString, fileName);
3347 QFETCH(int, orientation);
3348 QFETCH(int, dpmx);
3349 QFETCH(int, dpmy);
3350
3351 QImageReader imageReader(fileName);
3352 imageReader.setAutoTransform(true);
3353 QCOMPARE(imageReader.transformation(), orientation);
3354 QImage img = imageReader.read();
3355 QCOMPARE(img.dotsPerMeterX(), dpmx);
3356 QCOMPARE(img.dotsPerMeterY(), dpmy);
3357 QRgb px;
3358 QVERIFY(!img.isNull());
3359 px = img.pixel(x: 0, y: 0);
3360 QVERIFY(qRed(px) > 250 && qGreen(px) < 5 && qBlue(px) < 5);
3361
3362 px = img.pixel(x: img.width() - 1, y: 0);
3363 QVERIFY(qRed(px) < 5 && qGreen(px) < 5 && qBlue(px) > 250);
3364
3365 QImageReader imageReader2(fileName);
3366 QCOMPARE(imageReader2.autoTransform(), false);
3367 QCOMPARE(imageReader2.transformation(), orientation);
3368 QImage img2 = imageReader2.read();
3369 qt_imageTransform(src&: img2, orient: imageReader2.transformation());
3370 QCOMPARE(img, img2);
3371}
3372
3373void tst_QImage::exif_QTBUG45865()
3374{
3375 QFile file(m_prefix + "jpeg_exif_QTBUG-45865.jpg");
3376 QVERIFY(file.open(QIODevice::ReadOnly));
3377 QByteArray byteArray = file.readAll();
3378 QImage image = QImage::fromData(data: byteArray);
3379 QCOMPARE(image.size(), QSize(5, 8));
3380}
3381
3382void tst_QImage::exifInvalidData_data()
3383{
3384 QTest::addColumn<bool>(name: "$never used");
3385 QTest::newRow(dataTag: "QTBUG-46870");
3386 QTest::newRow(dataTag: "back_pointers");
3387 QTest::newRow(dataTag: "past_end");
3388 QTest::newRow(dataTag: "too_many_ifds");
3389 QTest::newRow(dataTag: "too_many_tags");
3390}
3391
3392void tst_QImage::exifInvalidData()
3393{
3394 QImage image;
3395 QVERIFY(image.load(m_prefix + "jpeg_exif_invalid_data_" + QTest::currentDataTag() + ".jpg"));
3396 QVERIFY(!image.isNull());
3397}
3398
3399void tst_QImage::exifReadComments()
3400{
3401 QImage image;
3402 QVERIFY(image.load(m_prefix + "jpeg_exif_utf8_comment.jpg"));
3403 QVERIFY(!image.isNull());
3404 QCOMPARE(image.textKeys().size(), 1);
3405 QCOMPARE(image.textKeys().first(), "Description");
3406 // check if exif comment is read as utf-8
3407 QCOMPARE(image.text("Description"), QString::fromUtf8("some unicode chars: ÖÄÜ€@"));
3408
3409 QByteArray ba;
3410 {
3411 QBuffer buf(&ba);
3412 QVERIFY(buf.open(QIODevice::WriteOnly));
3413 QVERIFY(image.save(&buf, "JPG"));
3414 }
3415 QVERIFY(!ba.isEmpty());
3416 image = QImage();
3417 QCOMPARE(image.textKeys().size(), 0);
3418 {
3419 QBuffer buf(&ba);
3420 QVERIFY(buf.open(QIODevice::ReadOnly));
3421 QVERIFY(image.load(&buf, "JPG"));
3422 }
3423 // compare written (and reread) description text
3424 QCOMPARE(image.text("Description"), QString::fromUtf8("some unicode chars: ÖÄÜ€@"));
3425}
3426
3427static void cleanupFunction(void* info)
3428{
3429 bool *called = static_cast<bool*>(info);
3430 *called = true;
3431}
3432
3433void tst_QImage::cleanupFunctions()
3434{
3435 QImage bufferImage(64, 64, QImage::Format_ARGB32);
3436 bufferImage.fill(pixel: 0);
3437
3438 bool called;
3439
3440 {
3441 called = false;
3442 {
3443 QImage image(bufferImage.bits(), bufferImage.width(), bufferImage.height(), bufferImage.format(), cleanupFunction, &called);
3444 }
3445 QVERIFY(called);
3446 }
3447
3448 {
3449 called = false;
3450 QImage *copy = 0;
3451 {
3452 QImage image(bufferImage.bits(), bufferImage.width(), bufferImage.height(), bufferImage.format(), cleanupFunction, &called);
3453 copy = new QImage(image);
3454 }
3455 QVERIFY(!called);
3456 delete copy;
3457 QVERIFY(called);
3458 }
3459
3460}
3461
3462// test image devicePixelRatio setting and detaching
3463void tst_QImage::devicePixelRatio()
3464{
3465 // create image
3466 QImage a(64, 64, QImage::Format_ARGB32);
3467 a.fill(color: Qt::white);
3468 QCOMPARE(a.devicePixelRatio(), qreal(1.0));
3469 QCOMPARE(a.isDetached(), true);
3470
3471 // copy image
3472 QImage b = a;
3473 QCOMPARE(b.devicePixelRatio(), qreal(1.0));
3474 QCOMPARE(a.isDetached(), false);
3475 QCOMPARE(b.isDetached(), false);
3476
3477 // set devicePixelRatio to the current value: does not detach
3478 a.setDevicePixelRatio(qreal(1.0));
3479 QCOMPARE(a.isDetached(), false);
3480 QCOMPARE(b.isDetached(), false);
3481
3482 // set devicePixelRatio to a new value: may detach (currently
3483 // does, but we may want to avoid the data copy the future)
3484 a.setDevicePixelRatio(qreal(2.0));
3485 QCOMPARE(a.devicePixelRatio(), qreal(2.0));
3486 QCOMPARE(b.devicePixelRatio(), qreal(1.0));
3487}
3488
3489void tst_QImage::rgb30Unpremul()
3490{
3491 QImage a(3, 1, QImage::Format_A2RGB30_Premultiplied);
3492 ((uint*)a.bits())[0] = (3U << 30) | (128 << 20) | (256 << 10) | 512;
3493 ((uint*)a.bits())[1] = (2U << 30) | (131 << 20) | (259 << 10) | 515;
3494 ((uint*)a.bits())[2] = (1U << 30) | ( 67 << 20) | (131 << 10) | 259;
3495
3496 QImage b = a.convertToFormat(f: QImage::Format_RGB30);
3497 const uint* bbits = (const uint*)b.bits();
3498 QCOMPARE(bbits[0], (3U << 30) | (128 << 20) | (256 << 10) | 512);
3499 QCOMPARE(bbits[1], (3U << 30) | (196 << 20) | (388 << 10) | 772);
3500 QCOMPARE(bbits[2], (3U << 30) | (201 << 20) | (393 << 10) | 777);
3501}
3502
3503void tst_QImage::rgb30Repremul_data()
3504{
3505 QTest::addColumn<uint>(name: "color");
3506 for (int i = 255; i > 0; i -= 15) {
3507 QTest::addRow(format: "100%% red=%d", i) << qRgba(r: i, g: 0, b: 0, a: 0xff);
3508 QTest::addRow(format: "75%% red=%d", i) << qRgba(r: i, g: 0, b: 0, a: 0xc0);
3509 QTest::addRow(format: "50%% red=%d", i) << qRgba(r: i, g: 0, b: 0, a: 0x80);
3510 QTest::addRow(format: "37.5%% red=%d", i) << qRgba(r: i, g: 0, b: 0, a: 0x60);
3511 }
3512}
3513
3514void tst_QImage::rgb30Repremul()
3515{
3516 QFETCH(uint, color);
3517
3518 QImage a(1, 1, QImage::Format_ARGB32);
3519 a.setPixel(x: 0, y: 0, index_or_rgb: color);
3520
3521 QImage b = a.convertToFormat(f: QImage::Format_A2BGR30_Premultiplied);
3522 b = b.convertToFormat(f: QImage::Format_ARGB32);
3523 uint expectedColor = qUnpremultiply(p: qPremultiply(x: color));
3524 uint newColor = b.pixel(x: 0, y: 0);
3525 QVERIFY(qAbs(qRed(newColor) - qRed(expectedColor)) <= 1);
3526}
3527
3528void tst_QImage::metadataPassthrough()
3529{
3530 QImage a(64, 64, QImage::Format_ARGB32);
3531 a.fill(color: Qt::white);
3532 a.setText(QStringLiteral("Test"), QStringLiteral("Text"));
3533 a.setDotsPerMeterX(100);
3534 a.setDotsPerMeterY(80);
3535 a.setDevicePixelRatio(2.0);
3536
3537 QImage scaled = a.scaled(s: QSize(32, 32), aspectMode: Qt::IgnoreAspectRatio, mode: Qt::SmoothTransformation);
3538 QCOMPARE(scaled.text(QStringLiteral("Test")), a.text(QStringLiteral("Test")));
3539 QCOMPARE(scaled.dotsPerMeterX(), a.dotsPerMeterX());
3540 QCOMPARE(scaled.dotsPerMeterY(), a.dotsPerMeterY());
3541 QCOMPARE(scaled.devicePixelRatio(), a.devicePixelRatio());
3542
3543 scaled = a.scaled(s: QSize(128, 128), aspectMode: Qt::IgnoreAspectRatio, mode: Qt::FastTransformation);
3544 QCOMPARE(scaled.text(QStringLiteral("Test")), a.text(QStringLiteral("Test")));
3545 QCOMPARE(scaled.dotsPerMeterX(), a.dotsPerMeterX());
3546 QCOMPARE(scaled.dotsPerMeterY(), a.dotsPerMeterY());
3547 QCOMPARE(scaled.devicePixelRatio(), a.devicePixelRatio());
3548
3549 QImage mirrored = a.mirrored();
3550 QCOMPARE(mirrored.text(QStringLiteral("Test")), a.text(QStringLiteral("Test")));
3551 QCOMPARE(mirrored.dotsPerMeterX(), a.dotsPerMeterX());
3552 QCOMPARE(mirrored.dotsPerMeterY(), a.dotsPerMeterY());
3553 QCOMPARE(mirrored.devicePixelRatio(), a.devicePixelRatio());
3554
3555 QTransform t;
3556 t.rotate(a: 90);
3557 QImage rotated = a.transformed(matrix: t);
3558 QCOMPARE(rotated.text(QStringLiteral("Test")), a.text(QStringLiteral("Test")));
3559 QCOMPARE(rotated.dotsPerMeterX(), a.dotsPerMeterX());
3560 QCOMPARE(rotated.dotsPerMeterY(), a.dotsPerMeterY());
3561 QCOMPARE(rotated.devicePixelRatio(), a.devicePixelRatio());
3562
3563 QImage swapped = a.rgbSwapped();
3564 QCOMPARE(swapped.text(QStringLiteral("Test")), a.text(QStringLiteral("Test")));
3565 QCOMPARE(swapped.dotsPerMeterX(), a.dotsPerMeterX());
3566 QCOMPARE(swapped.dotsPerMeterY(), a.dotsPerMeterY());
3567 QCOMPARE(swapped.devicePixelRatio(), a.devicePixelRatio());
3568
3569 QImage converted = a.convertToFormat(f: QImage::Format_RGB32);
3570 QCOMPARE(converted.text(QStringLiteral("Test")), a.text(QStringLiteral("Test")));
3571 QCOMPARE(converted.dotsPerMeterX(), a.dotsPerMeterX());
3572 QCOMPARE(converted.dotsPerMeterY(), a.dotsPerMeterY());
3573 QCOMPARE(converted.devicePixelRatio(), a.devicePixelRatio());
3574
3575 QVector<QRgb> clut({ 0xFFFF0000, 0xFF00FF00, 0xFF0000FF });
3576 QImage convertedWithClut = a.convertToFormat(f: QImage::Format_Indexed8, colorTable: clut);
3577 QCOMPARE(convertedWithClut.text(QStringLiteral("Test")), a.text(QStringLiteral("Test")));
3578 QCOMPARE(convertedWithClut.dotsPerMeterX(), a.dotsPerMeterX());
3579 QCOMPARE(convertedWithClut.dotsPerMeterY(), a.dotsPerMeterY());
3580 QCOMPARE(convertedWithClut.devicePixelRatio(), a.devicePixelRatio());
3581
3582 QImage copied = a.copy(x: 0, y: 0, w: a.width() / 2, h: a.height() / 2);
3583 QCOMPARE(copied.text(QStringLiteral("Test")), a.text(QStringLiteral("Test")));
3584 QCOMPARE(copied.dotsPerMeterX(), a.dotsPerMeterX());
3585 QCOMPARE(copied.dotsPerMeterY(), a.dotsPerMeterY());
3586 QCOMPARE(copied.devicePixelRatio(), a.devicePixelRatio());
3587
3588 QImage alphaMask = a.createAlphaMask();
3589 QCOMPARE(alphaMask.dotsPerMeterX(), a.dotsPerMeterX());
3590 QCOMPARE(alphaMask.dotsPerMeterY(), a.dotsPerMeterY());
3591 QCOMPARE(alphaMask.devicePixelRatio(), a.devicePixelRatio());
3592
3593 QImage heuristicMask = a.createHeuristicMask();
3594 QCOMPARE(heuristicMask.dotsPerMeterX(), a.dotsPerMeterX());
3595 QCOMPARE(heuristicMask.dotsPerMeterY(), a.dotsPerMeterY());
3596 QCOMPARE(heuristicMask.devicePixelRatio(), a.devicePixelRatio());
3597
3598 QImage maskFromColor = a.createMaskFromColor(color: qRgb(r: 0, g: 0, b: 0));
3599 QCOMPARE(maskFromColor.dotsPerMeterX(), a.dotsPerMeterX());
3600 QCOMPARE(maskFromColor.dotsPerMeterY(), a.dotsPerMeterY());
3601 QCOMPARE(maskFromColor.devicePixelRatio(), a.devicePixelRatio());
3602}
3603
3604void tst_QImage::pixelColor()
3605{
3606 QImage argb32(1, 1, QImage::Format_ARGB32);
3607 QImage argb32pm(1, 1, QImage::Format_ARGB32_Premultiplied);
3608
3609 QColor c(Qt::red);
3610 c.setAlpha(128);
3611 argb32.setPixelColor(pt: QPoint(0, 0), c);
3612 argb32pm.setPixelColor(pt: QPoint(0, 0), c);
3613 QCOMPARE(argb32.pixelColor(QPoint(0, 0)), c);
3614 QCOMPARE(argb32pm.pixelColor(QPoint(0, 0)), c);
3615
3616 QImage t = argb32.convertToFormat(f: QImage::Format_ARGB32_Premultiplied);
3617 QCOMPARE(t.pixel(0,0), argb32pm.pixel(0,0));
3618
3619 // Try specifying an invalid position.
3620 QTest::ignoreMessage(type: QtWarningMsg, message: "QImage::setPixelColor: coordinate (-1,-1) out of range");
3621 argb32.setPixelColor(x: -1, y: -1, c: QColor(Qt::red));
3622
3623 // Try setting an invalid color.
3624 QTest::ignoreMessage(type: QtWarningMsg, message: "QImage::setPixelColor: color is invalid");
3625 argb32.setPixelColor(x: 0, y: 0, c: QColor());
3626
3627 // Test correct premultiplied handling of RGBA64 as well
3628 QImage rgba64(1, 1, QImage::Format_RGBA64);
3629 QImage rgba64pm(1, 1, QImage::Format_RGBA64_Premultiplied);
3630 rgba64.setPixelColor(pt: QPoint(0, 0), c);
3631 rgba64pm.setPixelColor(pt: QPoint(0, 0), c);
3632 QCOMPARE(rgba64.pixelColor(QPoint(0, 0)), c);
3633 QCOMPARE(rgba64pm.pixelColor(QPoint(0, 0)), c);
3634}
3635
3636void tst_QImage::pixel()
3637{
3638 {
3639 QImage mono(1, 1, QImage::Format_Mono);
3640 QImage monolsb(1, 1, QImage::Format_MonoLSB);
3641 QImage indexed(1, 1, QImage::Format_Indexed8);
3642
3643 mono.fill(pixel: 0);
3644 monolsb.fill(pixel: 0);
3645 indexed.fill(pixel: 0);
3646
3647 QCOMPARE(QColor(mono.pixel(0, 0)), QColor(Qt::black));
3648 QCOMPARE(QColor(monolsb.pixel(0, 0)), QColor(Qt::black));
3649 indexed.pixel(x: 0, y: 0); // Don't crash
3650 }
3651
3652 {
3653 uchar a = 0;
3654 QImage mono(&a, 1, 1, QImage::Format_Mono);
3655 QImage monolsb(&a, 1, 1, QImage::Format_MonoLSB);
3656 QImage indexed(&a, 1, 1, QImage::Format_Indexed8);
3657
3658 mono.pixel(x: 0, y: 0); // Don't crash
3659 monolsb.pixel(x: 0, y: 0); // Don't crash
3660 indexed.pixel(x: 0, y: 0); // Don't crash
3661 }
3662}
3663
3664void tst_QImage::ditherGradient_data()
3665{
3666 QTest::addColumn<QImage>(name: "image");
3667 QTest::addColumn<QImage::Format>(name: "format");
3668 QTest::addColumn<int>(name: "flags");
3669 QTest::addColumn<int>(name: "minimumExpectedGradient");
3670
3671 QImage rgb32(256, 16, QImage::Format_RGB32);
3672 QLinearGradient gradient(QRectF(rgb32.rect()).topLeft(), QRectF(rgb32.rect()).topRight());
3673 gradient.setColorAt(pos: 0.0, color: QColor(0, 0, 0));
3674 gradient.setColorAt(pos: 1.0, color: QColor(255, 255, 255));
3675 QPainter p;
3676 p.begin(&rgb32);
3677 p.fillRect(rgb32.rect(), gradient);
3678 p.end();
3679
3680 QTest::newRow(dataTag: "rgb32 -> rgb444 (no dither)") << rgb32 << QImage::Format_RGB444 << 0 << 16;
3681 QTest::newRow(dataTag: "rgb32 -> rgb444 (dithering)") << rgb32 << QImage::Format_RGB444 << int(Qt::PreferDither | Qt::OrderedDither) << 33;
3682 QTest::newRow(dataTag: "rgb32 -> argb4444pm (dithering)") << rgb32 << QImage::Format_ARGB4444_Premultiplied << int(Qt::PreferDither | Qt::OrderedDither) << 33;
3683 QTest::newRow(dataTag: "rgb32 -> rgb16 (no dither)") << rgb32 << QImage::Format_RGB16 << 0 << 32;
3684 QTest::newRow(dataTag: "rgb32 -> rgb16 (dithering)") << rgb32 << QImage::Format_RGB16 << int(Qt::PreferDither | Qt::OrderedDither) << 65;
3685 QTest::newRow(dataTag: "rgb32 -> rgb666 (no dither)") << rgb32 << QImage::Format_RGB666 << 0 << 64;
3686 QTest::newRow(dataTag: "rgb32 -> rgb666 (dithering)") << rgb32 << QImage::Format_RGB666 << int(Qt::PreferDither | Qt::OrderedDither) << 129;
3687
3688 // Test we get the same results for opaque input in the ARGBPM implementation.
3689 rgb32 = std::move(rgb32).convertToFormat(f: QImage::Format_ARGB32_Premultiplied);
3690 QTest::newRow(dataTag: "argb32pm -> argb4444pm (no dither)") << rgb32 << QImage::Format_ARGB4444_Premultiplied << 0 << 16;
3691 QTest::newRow(dataTag: "argb32pm -> rgb444 (dithering)") << rgb32 << QImage::Format_RGB444 << int(Qt::PreferDither | Qt::OrderedDither) << 33;
3692 QTest::newRow(dataTag: "argb32pm -> argb4444pm (dithering)") << rgb32 << QImage::Format_ARGB4444_Premultiplied << int(Qt::PreferDither | Qt::OrderedDither) << 33;
3693 QTest::newRow(dataTag: "argb32pm -> argb8565pm (no dither)") << rgb32 << QImage::Format_ARGB8565_Premultiplied << 0 << 32;
3694 QTest::newRow(dataTag: "argb32pm -> argb8565pm (dithering)") << rgb32 << QImage::Format_ARGB8565_Premultiplied << int(Qt::PreferDither | Qt::OrderedDither) << 65;
3695 QTest::newRow(dataTag: "argb32pm -> argb6666pm (no dither)") << rgb32 << QImage::Format_ARGB6666_Premultiplied << 0 << 64;
3696 QTest::newRow(dataTag: "argb32pm -> argb6666pm (dithering)") << rgb32 << QImage::Format_ARGB6666_Premultiplied << int(Qt::PreferDither | Qt::OrderedDither) << 129;
3697
3698#if QT_CONFIG(raster_64bit)
3699 QImage rgb30(1024, 16, QImage::Format_RGB30);
3700 QLinearGradient gradient30(QRectF(rgb30.rect()).topLeft(), QRectF(rgb30.rect()).topRight());
3701 gradient30.setColorAt(pos: 0.0, color: QColor(0, 0, 0));
3702 gradient30.setColorAt(pos: 1.0, color: QColor(255, 255, 255));
3703 p.begin(&rgb30);
3704 p.fillRect(rgb30.rect(), gradient30);
3705 p.end();
3706
3707 QTest::newRow(dataTag: "rgb30 -> rgb32 (no dither)") << rgb30 << QImage::Format_RGB32 << 0 << 256;
3708 QTest::newRow(dataTag: "rgb30 -> rgb32 (dithering)") << rgb30 << QImage::Format_RGB32 << int(Qt::PreferDither | Qt::OrderedDither) << 513;
3709 QTest::newRow(dataTag: "rgb30 -> rgb888 (no dither)") << rgb30 << QImage::Format_RGB888 << 0 << 256;
3710 QTest::newRow(dataTag: "rgb30 -> rgb888 (dithering)") << rgb30 << QImage::Format_RGB888 << int(Qt::PreferDither | Qt::OrderedDither) << 513;
3711#endif
3712}
3713
3714void tst_QImage::ditherGradient()
3715{
3716 QFETCH(QImage, image);
3717 QFETCH(QImage::Format, format);
3718 QFETCH(int, flags);
3719 QFETCH(int, minimumExpectedGradient);
3720
3721 QImage converted = image.convertToFormat(f: format, flags: (Qt::ImageConversionFlags)flags);
3722 int observedGradientSteps = 0;
3723 int lastTotal = -1;
3724 for (int i = 0; i < converted.width(); ++i) {
3725 int total = 0;
3726 for (int j = 0; j < converted.height(); ++j) {
3727 uint c = converted.pixel(x: i, y: j);
3728 QCOMPARE(qAlpha(c), 255);
3729 total += qRed(rgb: c);
3730 }
3731 if (total > lastTotal) {
3732 observedGradientSteps++;
3733 lastTotal = total;
3734 }
3735 }
3736 QVERIFY(observedGradientSteps >= minimumExpectedGradient);
3737}
3738
3739void tst_QImage::reinterpretAsFormat_data()
3740{
3741 QTest::addColumn<QImage::Format>(name: "in_format");
3742 QTest::addColumn<QImage::Format>(name: "out_format");
3743 QTest::addColumn<QColor>(name: "in_color");
3744 QTest::addColumn<QColor>(name: "out_color");
3745
3746#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
3747 QTest::newRow(dataTag: "rgb32 -> rgbx8888") << QImage::Format_RGB32 << QImage::Format_RGBX8888 << QColor(Qt::red) << QColor(Qt::blue);
3748 QTest::newRow(dataTag: "rgba8888 -> argb32") << QImage::Format_RGBA8888 << QImage::Format_ARGB32 << QColor(Qt::red) << QColor(Qt::blue);
3749 QTest::newRow(dataTag: "argb32pm -> rgba8888pm") << QImage::Format_RGBA8888_Premultiplied << QImage::Format_ARGB32_Premultiplied << QColor(Qt::green) << QColor(Qt::green);
3750#endif
3751 QTest::newRow(dataTag: "rgb32 -> argb32") << QImage::Format_RGB32 << QImage::Format_ARGB32 << QColor(Qt::cyan) << QColor(Qt::cyan);
3752 QTest::newRow(dataTag: "argb32pm -> rgb32") << QImage::Format_ARGB32_Premultiplied << QImage::Format_RGB32 << QColor(Qt::transparent) << QColor(Qt::black);
3753 QTest::newRow(dataTag: "argb32 -> rgb32") << QImage::Format_ARGB32 << QImage::Format_RGB32 << QColor(255, 0, 0, 127) << QColor(255, 0, 0);
3754 QTest::newRow(dataTag: "argb32pm -> rgb32") << QImage::Format_ARGB32_Premultiplied << QImage::Format_RGB32 << QColor(255, 0, 0, 127) << QColor(127, 0, 0);
3755}
3756
3757void tst_QImage::reinterpretAsFormat()
3758{
3759 QFETCH(QImage::Format, in_format);
3760 QFETCH(QImage::Format, out_format);
3761 QFETCH(QColor, in_color);
3762 QFETCH(QColor, out_color);
3763
3764 QImage image(1, 1, in_format);
3765 image.setPixelColor(x: 0, y: 0, c: in_color);
3766 QVERIFY(image.reinterpretAsFormat(out_format));
3767 QCOMPARE(image.pixelColor(0, 0), out_color);
3768}
3769
3770void tst_QImage::reinterpretAsFormat2()
3771{
3772 const uint imageData[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
3773
3774 {
3775 QImage image(reinterpret_cast<const uchar*>(imageData), 4, 2, QImage::Format_RGB32);
3776 QCOMPARE(image.pixelColor(0, 0), QColor(Qt::black));
3777 QVERIFY(image.isDetached());
3778 QVERIFY(image.reinterpretAsFormat(QImage::Format_ARGB32_Premultiplied));
3779 QCOMPARE(image.constBits(), reinterpret_cast<const uchar*>(imageData));
3780 QCOMPARE(image.pixelColor(0, 0), QColor(Qt::transparent));
3781
3782 QVERIFY(!image.reinterpretAsFormat(QImage::Format_Grayscale8));
3783 }
3784 {
3785 QImage image(reinterpret_cast<const uchar*>(imageData), 8, 4, QImage::Format_Indexed8);
3786 image.setColor(i: 0, c: qRgb(r: 255, g: 255, b: 255));
3787 QCOMPARE(image.pixelColor(0, 0), QColor(Qt::white));
3788 QVERIFY(image.reinterpretAsFormat(QImage::Format_Grayscale8));
3789 QCOMPARE(image.pixelColor(0, 0), QColor(Qt::black));
3790 QVERIFY(image.reinterpretAsFormat(QImage::Format_Alpha8));
3791 QCOMPARE(image.pixelColor(0, 0), QColor(Qt::transparent));
3792
3793 QVERIFY(!image.reinterpretAsFormat(QImage::Format_RGB16));
3794 }
3795}
3796
3797void tst_QImage::complexTransform8bit()
3798{
3799 QImage img1(100, 100, QImage::Format_RGB32);
3800 img1.fill(color: Qt::green);
3801 img1 = img1.convertToFormat(f: QImage::Format_Indexed8);
3802 QImage img2 = img1.transformed(matrix: QTransform().rotate(a: 45), mode: Qt::SmoothTransformation);
3803 // Currently the format is always QImage::Format_ARGB32_Premultiplied, but it
3804 // doesn't have to be, and if it becomes indexed this test is no longer be valid.
3805 QVERIFY(img2.format() > QImage::Format_Indexed8);
3806 QCOMPARE(img2.colorCount(), 0);
3807}
3808
3809#ifdef Q_OS_DARWIN
3810
3811void tst_QImage::toCGImage_data()
3812{
3813 QTest::addColumn<QImage::Format>("format");
3814 QTest::addColumn<bool>("supported");
3815
3816 // Populate test data with supported status for all QImage formats.
3817 QSet<QImage::Format> supported =
3818 { QImage::Format_ARGB32, QImage::Format_RGB32, QImage::Format_RGBA8888_Premultiplied,
3819 QImage::Format_RGBA8888, QImage::Format_RGBX8888, QImage::Format_ARGB32_Premultiplied };
3820
3821 for (int i = QImage::Format_Invalid; i < QImage::Format_Grayscale8; ++i) {
3822 QTest::addRow("%s", formatToString(QImage::Format(i)).data())
3823 << QImage::Format(i) << supported.contains(QImage::Format(i));
3824 }
3825}
3826
3827// Verify that toCGImage() returns a valid CGImageRef for supported image formats.
3828void tst_QImage::toCGImage()
3829{
3830 QFETCH(QImage::Format, format);
3831 QFETCH(bool, supported);
3832
3833 QImage qimage(64, 64, format);
3834 qimage.fill(Qt::red);
3835
3836 CGImageRef cgimage = qimage.toCGImage();
3837 QCOMPARE(cgimage != nullptr, supported);
3838
3839 CGImageRelease(cgimage);
3840}
3841
3842#endif
3843
3844void tst_QImage::hugeQImage()
3845{
3846#if Q_PROCESSOR_WORDSIZE < 8
3847 QSKIP("Test only makes sense on 64-bit machines");
3848#else
3849 QImage image(25000, 25000, QImage::Format_RGB32);
3850
3851 QVERIFY(!image.isNull());
3852 QCOMPARE(image.height(), 25000);
3853 QCOMPARE(image.width(), 25000);
3854 QCOMPARE(image.sizeInBytes(), qsizetype(25000)*25000*4);
3855 QCOMPARE(image.bytesPerLine(), 25000 * 4);
3856
3857 QCOMPARE(image.constScanLine(24990), image.constBits() + qsizetype(25000)*24990*4);
3858
3859 image.setPixel(x: 20000, y: 24990, index_or_rgb: 0xffaabbcc);
3860 QCOMPARE(image.pixel(20000, 24990), 0xffaabbcc);
3861 QCOMPARE((reinterpret_cast<const unsigned int *>(image.constScanLine(24990)))[20000], 0xffaabbcc);
3862
3863 QImage canvas(100, 100, QImage::Format_RGB32);
3864 QPainter painter(&canvas);
3865 painter.drawImage(x: 0,y: 0, image, sx: 19950, sy: 24900, sw: 100, sh: 100);
3866 painter.end();
3867 QCOMPARE(reinterpret_cast<const unsigned int *>(canvas.constScanLine(90))[50], 0xffaabbcc);
3868#endif
3869}
3870
3871void tst_QImage::convertColorTable()
3872{
3873 QImage image(10, 10, QImage::Format_Indexed8);
3874 image.setColor(i: 0, c: 0x80ffffff);
3875 image.fill(pixel: 0);
3876 QImage argb32 = image.convertToFormat(f: QImage::Format_ARGB32);
3877 QCOMPARE(argb32.pixel(0,0), 0x80ffffff);
3878 QImage argb32pm = image.convertToFormat(f: QImage::Format_ARGB32_Premultiplied);
3879 QCOMPARE(argb32pm.pixel(0,0), 0x80808080);
3880 QImage rgb32 = image.convertToFormat(f: QImage::Format_RGB32);
3881 QCOMPARE(rgb32.pixel(0,0), 0xffffffff);
3882}
3883
3884void tst_QImage::wideImage()
3885{
3886 // QTBUG-73731 and QTBUG-73732
3887 QImage i(538994187, 2, QImage::Format_ARGB32);
3888 QImage i2(32, 32, QImage::Format_ARGB32);
3889 i2.fill(color: Qt::white);
3890
3891 // Test that it doesn't crash:
3892 QPainter painter(&i);
3893 // With the composition mode is SourceOver out it's an invalid write
3894 // With the composition mode is Source it's an invalid read
3895 painter.drawImage(x: 0, y: 0, image: i2);
3896 painter.setCompositionMode(QPainter::CompositionMode_Source);
3897 painter.drawImage(x: 0, y: 0, image: i2);
3898
3899 // Qt6: Test that it actually works on 64bit architectures.
3900}
3901
3902#if defined(Q_OS_WIN) && !defined(Q_OS_WINRT)
3903QT_BEGIN_NAMESPACE
3904Q_GUI_EXPORT HBITMAP qt_imageToWinHBITMAP(const QImage &p, int hbitmapFormat = 0);
3905Q_GUI_EXPORT QImage qt_imageFromWinHBITMAP(HBITMAP bitmap, int hbitmapFormat = 0);
3906QT_END_NAMESPACE
3907
3908static inline QColor COLORREFToQColor(COLORREF cr)
3909{
3910 return QColor(GetRValue(cr), GetGValue(cr), GetBValue(cr));
3911}
3912
3913void tst_QImage::toWinHBITMAP_data()
3914{
3915 QTest::addColumn<QImage::Format>("format");
3916 QTest::addColumn<QColor>("color");
3917 QTest::addColumn<QColor>("bottomRightColor");
3918
3919 const QColor red(Qt::red);
3920 const QColor green(Qt::green);
3921 const QColor blue(Qt::blue);
3922 const QColor gray(Qt::gray);
3923 const QColor gray555(0x5a, 0x5a, 0x5a); // Note: Interpolation 8<->5 bit occurs.
3924 const QColor white(Qt::white);
3925 const QColor black(Qt::black);
3926
3927 QTest::newRow("argb32p-red") << QImage::Format_ARGB32_Premultiplied << red << gray;
3928 QTest::newRow("argb32p-green") << QImage::Format_ARGB32_Premultiplied << green << gray;
3929 QTest::newRow("argb32p-blue") << QImage::Format_ARGB32_Premultiplied << blue << gray;
3930 QTest::newRow("rgb888-red") << QImage::Format_RGB888 << red << gray;
3931 QTest::newRow("rgb888-green") << QImage::Format_RGB888 << green << gray;
3932 QTest::newRow("rgb888-blue") << QImage::Format_RGB888 << blue << gray;
3933 QTest::newRow("indexed8-red") << QImage::Format_Indexed8 << red << gray;
3934 QTest::newRow("indexed8-green") << QImage::Format_Indexed8 << green << gray;
3935 QTest::newRow("indexed8-blue") << QImage::Format_Indexed8 << blue << gray;
3936 QTest::newRow("rgb555-red") << QImage::Format_RGB555 << red << gray555;
3937 QTest::newRow("rgb555-green") << QImage::Format_RGB555 << green << gray555;
3938 QTest::newRow("rgb555-blue") << QImage::Format_RGB555 << blue << gray555;
3939 QTest::newRow("mono") << QImage::Format_Mono << white << black;
3940}
3941
3942// Test image filled with color, black pixel at botttom right corner.
3943static inline QImage createTestImage(QImage::Format format, int width, int height,
3944 const QColor &fillColor, const QColor &bottomRightColor)
3945{
3946 QImage image(QSize(width, height), format);
3947 image.fill(fillColor);
3948 QPainter painter(&image);
3949 QPen pen = painter.pen();
3950 pen.setColor(bottomRightColor);
3951 painter.setPen(pen);
3952 painter.drawPoint(width -1, height - 1);
3953 return image;
3954}
3955
3956void tst_QImage::toWinHBITMAP()
3957{
3958 static const int width = 73;
3959 static const int height = 57;
3960
3961 QFETCH(QImage::Format, format);
3962 QFETCH(QColor, color);
3963 QFETCH(QColor, bottomRightColor);
3964
3965 // Cannot paint on indexed/mono images.
3966 const QImage image = format == QImage::Format_Indexed8 || format == QImage::Format_Mono
3967 ? createTestImage(QImage::Format_RGB32, width, height, color, bottomRightColor).convertToFormat(format)
3968 : createTestImage(format, width, height, color, bottomRightColor);
3969
3970 const HBITMAP bitmap = qt_imageToWinHBITMAP(image);
3971
3972 QVERIFY(bitmap != 0);
3973
3974 // Verify size
3975 BITMAP bitmapInfo;
3976 memset(&bitmapInfo, 0, sizeof(BITMAP));
3977
3978 const int res = GetObject(bitmap, sizeof(BITMAP), &bitmapInfo);
3979 QVERIFY(res);
3980 QCOMPARE(width, int(bitmapInfo.bmWidth));
3981 QCOMPARE(height, int(bitmapInfo.bmHeight));
3982
3983 const HDC displayDc = GetDC(0);
3984 const HDC bitmapDc = CreateCompatibleDC(displayDc);
3985
3986 const HBITMAP nullBitmap = static_cast<HBITMAP>(SelectObject(bitmapDc, bitmap));
3987
3988 QCOMPARE(COLORREFToQColor(GetPixel(bitmapDc, 0, 0)), color);
3989 QCOMPARE(COLORREFToQColor(GetPixel(bitmapDc, width - 1, 3)), color);
3990 QCOMPARE(COLORREFToQColor(GetPixel(bitmapDc, 3, height - 1)), color);
3991 QCOMPARE(COLORREFToQColor(GetPixel(bitmapDc, width - 1, height - 1)), bottomRightColor);
3992
3993 const QImage convertedBack = qt_imageFromWinHBITMAP(bitmap);
3994 QCOMPARE(convertedBack.convertToFormat(QImage::Format_ARGB32_Premultiplied),
3995 image.convertToFormat(QImage::Format_ARGB32_Premultiplied));
3996
3997 // Clean up
3998 SelectObject(bitmapDc, nullBitmap);
3999 DeleteObject(bitmap);
4000 DeleteDC(bitmapDc);
4001 ReleaseDC(0, displayDc);
4002}
4003
4004void tst_QImage::fromMonoHBITMAP() // QTBUG-72343, corruption for mono bitmaps
4005{
4006 enum : int { width = 32, height = 32, size = width * height / 8 }; // 32x32 mono bitmap
4007 char bitmapData[size];
4008 memset(bitmapData, 0, size);
4009 const HBITMAP hbitmap = CreateBitmap(width, height, /* planes */ 1, /* bitcount */ 1, bitmapData);
4010 const QImage image = qt_imageFromWinHBITMAP(hbitmap);
4011 QCOMPARE(image.size(), QSize(width, height));
4012 QCOMPARE(image.scanLine(0)[0], 0u);
4013 DeleteObject(hbitmap);
4014}
4015
4016#endif // Q_OS_WIN && !Q_OS_WINRT
4017
4018QTEST_GUILESS_MAIN(tst_QImage)
4019#include "tst_qimage.moc"
4020

source code of qtbase/tests/auto/gui/image/qimage/tst_qimage.cpp