19#include <qpa/qplatformintegration.h>
20#include <private/qguiapplication_p.h>
24#include <qpa/qplatformpixmap.h>
26#include <private/qcolorspace_p.h>
27#include <private/qcolortransform_p.h>
28#include <private/qmemrotate_p.h>
29#include <private/qimagescale_p.h>
30#include <private/qpixellayout_p.h>
31#include <private/qsimd_p.h>
35#include <private/qpaintengine_raster_p.h>
37#include <private/qimage_p.h>
38#include <private/qfont_p.h>
40#if QT_CONFIG(qtgui_threadpool)
41#include <private/qlatch_p.h>
42#include <qthreadpool.h>
43#include <private/qthreadpool_p.h>
46#include <qtgui_tracepoints_p.h>
50#define QT_XFORM_TYPE_MSBFIRST 0
51#define QT_XFORM_TYPE_LSBFIRST 1
56using namespace Qt::StringLiterals;
61QT_WARNING_DISABLE_MSVC(4723)
63#if defined(Q_CC_DEC) && defined(__alpha) && (__DECCXX_VER-0
>= 50190001
)
64#pragma message disable narrowptr
68#define QIMAGE_SANITYCHECK_MEMORY(image)
69 if ((image).isNull()) {
70 qWarning("QImage: out of memory, returning null image");
75 "#include <qimagereader.h>"
79"ENUM { } QImage::Format;" \
80"FLAGS { } Qt::ImageConversionFlags;"
83Q_TRACE_PARAM_REPLACE(Qt::AspectRatioMode,
int);
84Q_TRACE_PARAM_REPLACE(Qt::TransformationMode,
int);
86static QImage
rotated90(
const QImage &src);
92 Q_CONSTINIT
static QBasicAtomicInt serial = Q_BASIC_ATOMIC_INITIALIZER(0);
93 return 1 + serial.fetchAndAddRelaxed(1);
96QImageData::QImageData()
97 : ref(0), width(0), height(0), depth(0), nbytes(0), devicePixelRatio(1.0), data(
nullptr),
98 format(QImage::Format_ARGB32), bytes_per_line(0),
99 ser_no(next_qimage_serial_number()),
101 offset(0, 0), own_data(
true), ro_data(
false), has_alpha_clut(
false),
102 is_cached(
false), cleanupFunction(
nullptr), cleanupInfo(
nullptr),
105 QPoint dpis = qt_defaultDpis();
106 dpmx = dpis.x() * 100 / qreal(2.54);
107 dpmy = dpis.y() * 100 / qreal(2.54);
111
112
113
114
115
116
117QImageData * Q_TRACE_INSTRUMENT(qtgui) QImageData::create(
const QSize &size, QImage::Format format)
119 if (size.isEmpty() || format <= QImage::Format_Invalid || format >= QImage::NImageFormats)
122 Q_TRACE_SCOPE(QImageData_create, size, format);
124 int width = size.width();
125 int height = size.height();
126 int depth = qt_depthForFormat(format);
127 auto params = calculateImageParameters(width, height, depth);
128 if (!params.isValid())
131 auto d = std::make_unique<QImageData>();
134 case QImage::Format_Mono:
135 case QImage::Format_MonoLSB:
136 d->colortable.resize(2);
137 d->colortable[0] = QColor(Qt::black).rgba();
138 d->colortable[1] = QColor(Qt::white).rgba();
148 d->has_alpha_clut =
false;
149 d->is_cached =
false;
151 d->bytes_per_line = params.bytesPerLine;
152 d->nbytes = params.totalSize;
153 d->data = (uchar *)malloc(d->nbytes);
162QImageData::~QImageData()
165 cleanupFunction(cleanupInfo);
167 QImagePixmapCleanupHooks::executeImageHooks((((qint64) ser_no) << 32) | ((qint64) detach_no));
169 if (data && own_data)
170 QtPrivate::sizedFree(data, nbytes);
174#if defined(_M_ARM) && defined(_MSC_VER)
175#pragma optimize("", off)
178bool QImageData::checkForAlphaPixels()
const
180 bool has_alpha_pixels =
false;
184 case QImage::Format_Mono:
185 case QImage::Format_MonoLSB:
186 case QImage::Format_Indexed8:
187 has_alpha_pixels = has_alpha_clut;
189 case QImage::Format_Alpha8:
190 has_alpha_pixels =
true;
192 case QImage::Format_ARGB32:
193 case QImage::Format_ARGB32_Premultiplied: {
194 const uchar *bits = data;
195 for (
int y=0; y<height && !has_alpha_pixels; ++y) {
196 uint alphaAnd = 0xff000000;
197 for (
int x=0; x<width; ++x)
198 alphaAnd &=
reinterpret_cast<
const uint*>(bits)[x];
199 has_alpha_pixels = (alphaAnd != 0xff000000);
200 bits += bytes_per_line;
204 case QImage::Format_RGBA8888:
205 case QImage::Format_RGBA8888_Premultiplied: {
206 const uchar *bits = data;
207 for (
int y=0; y<height && !has_alpha_pixels; ++y) {
208 uchar alphaAnd = 0xff;
209 for (
int x=0; x<width; ++x)
210 alphaAnd &= bits[x * 4+ 3];
211 has_alpha_pixels = (alphaAnd != 0xff);
212 bits += bytes_per_line;
216 case QImage::Format_A2BGR30_Premultiplied:
217 case QImage::Format_A2RGB30_Premultiplied: {
218 const uchar *bits = data;
219 for (
int y=0; y<height && !has_alpha_pixels; ++y) {
220 uint alphaAnd = 0xc0000000;
221 for (
int x=0; x<width; ++x)
222 alphaAnd &=
reinterpret_cast<
const uint*>(bits)[x];
223 has_alpha_pixels = (alphaAnd != 0xc0000000);
224 bits += bytes_per_line;
228 case QImage::Format_ARGB8555_Premultiplied:
229 case QImage::Format_ARGB8565_Premultiplied: {
230 const uchar *bits = data;
231 const uchar *end_bits = data + bytes_per_line;
233 for (
int y=0; y<height && !has_alpha_pixels; ++y) {
234 uchar alphaAnd = 0xff;
235 while (bits < end_bits) {
239 has_alpha_pixels = (alphaAnd != 0xff);
241 end_bits += bytes_per_line;
245 case QImage::Format_ARGB6666_Premultiplied: {
246 const uchar *bits = data;
247 const uchar *end_bits = data + bytes_per_line;
249 for (
int y=0; y<height && !has_alpha_pixels; ++y) {
250 uchar alphaAnd = 0xfc;
251 while (bits < end_bits) {
255 has_alpha_pixels = (alphaAnd != 0xfc);
257 end_bits += bytes_per_line;
261 case QImage::Format_ARGB4444_Premultiplied: {
262 const uchar *bits = data;
263 for (
int y=0; y<height && !has_alpha_pixels; ++y) {
264 ushort alphaAnd = 0xf000;
265 for (
int x=0; x<width; ++x)
266 alphaAnd &=
reinterpret_cast<
const ushort*>(bits)[x];
267 has_alpha_pixels = (alphaAnd != 0xf000);
268 bits += bytes_per_line;
271 case QImage::Format_RGBA64:
272 case QImage::Format_RGBA64_Premultiplied: {
274 for (
int y=0; y<height && !has_alpha_pixels; ++y) {
275 for (
int x=0; x<width; ++x) {
276 has_alpha_pixels |= !(((QRgba64 *)bits)[x].isOpaque());
278 bits += bytes_per_line;
281 case QImage::Format_RGBA16FPx4:
282 case QImage::Format_RGBA16FPx4_Premultiplied: {
284 for (
int y = 0; y < height && !has_alpha_pixels; ++y) {
285 for (
int x = 0; x < width; ++x)
286 has_alpha_pixels |= ((qfloat16 *)bits)[x * 4 + 3] < 1.0f;
287 bits += bytes_per_line;
290 case QImage::Format_RGBA32FPx4:
291 case QImage::Format_RGBA32FPx4_Premultiplied: {
293 for (
int y = 0; y < height && !has_alpha_pixels; ++y) {
294 for (
int x = 0; x < width; ++x)
295 has_alpha_pixels |= ((
float *)bits)[x * 4 + 3] < 1.0f;
296 bits += bytes_per_line;
300 case QImage::Format_RGB32:
301 case QImage::Format_RGB16:
302 case QImage::Format_RGB444:
303 case QImage::Format_RGB555:
304 case QImage::Format_RGB666:
305 case QImage::Format_RGB888:
306 case QImage::Format_BGR888:
307 case QImage::Format_RGBX8888:
308 case QImage::Format_BGR30:
309 case QImage::Format_RGB30:
310 case QImage::Format_Grayscale8:
311 case QImage::Format_Grayscale16:
312 case QImage::Format_RGBX64:
313 case QImage::Format_RGBX16FPx4:
314 case QImage::Format_RGBX32FPx4:
315 case QImage::Format_CMYK8888:
317 case QImage::Format_Invalid:
318 case QImage::NImageFormats:
323 return has_alpha_pixels;
325#if defined(_M_ARM) && defined(_MSC_VER)
326#pragma optimize("", on)
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
633
634
635
636
637
638
639
642
643
644
645
646
647
651
652
653
654
655
656
657
658
659
660
663
664
665
666
667
668
669
670
671
672
673
674
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
791
792
795
796
797
798
800QImage::QImage()
noexcept
807
808
809
810
811
812
813
814
815
816QImage::QImage(
int width,
int height, Format format)
817 : QImage(QSize(width, height), format)
822
823
824
825
826
827
828
829
830QImage::QImage(
const QSize &size, Format format)
833 d = QImageData::create(size, format);
838QImageData *QImageData::create(uchar *data,
int width,
int height, qsizetype bpl, QImage::Format format,
bool readOnly, QImageCleanupFunction cleanupFunction,
void *cleanupInfo)
840 if (width <= 0 || height <= 0 || !data || format <= QImage::Format_Invalid || format >= QImage::NImageFormats)
843 const int depth = qt_depthForFormat(format);
844 auto params = calculateImageParameters(width, height, depth);
845 if (!params.isValid())
850 const qsizetype min_bytes_per_line = (qsizetype(width) * depth + 7)/8;
851 if (bpl < min_bytes_per_line)
855 params.bytesPerLine = bpl;
856 if (qMulOverflow<qsizetype>(bpl, height, ¶ms.totalSize))
860 QImageData *d =
new QImageData;
864 d->ro_data = readOnly;
871 d->bytes_per_line = params.bytesPerLine;
872 d->nbytes = params.totalSize;
874 d->cleanupFunction = cleanupFunction;
875 d->cleanupInfo = cleanupInfo;
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897QImage::QImage(uchar* data,
int width,
int height, Format format, QImageCleanupFunction cleanupFunction,
void *cleanupInfo)
900 d = QImageData::create(data, width, height, 0, format,
false, cleanupFunction, cleanupInfo);
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928QImage::QImage(
const uchar* data,
int width,
int height, Format format, QImageCleanupFunction cleanupFunction,
void *cleanupInfo)
931 d = QImageData::create(
const_cast<uchar*>(data), width, height, 0, format,
true, cleanupFunction, cleanupInfo);
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
952QImage::QImage(uchar *data,
int width,
int height, qsizetype bytesPerLine, Format format, QImageCleanupFunction cleanupFunction,
void *cleanupInfo)
955 d = QImageData::create(data, width, height, bytesPerLine, format,
false, cleanupFunction, cleanupInfo);
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
983QImage::QImage(
const uchar *data,
int width,
int height, qsizetype bytesPerLine, Format format, QImageCleanupFunction cleanupFunction,
void *cleanupInfo)
986 d = QImageData::create(
const_cast<uchar*>(data), width, height, bytesPerLine, format,
true, cleanupFunction, cleanupInfo);
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1009QImage::QImage(
const QString &fileName,
const char *format)
1013 load(fileName, format);
1016#ifndef QT_NO_IMAGEFORMAT_XPM
1017extern bool qt_read_xpm_image_or_array(QIODevice *device,
const char *
const *source, QImage &image);
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1035QImage::QImage(
const char *
const xpm[])
1041 if (!qt_read_xpm_image_or_array(
nullptr, xpm, *
this))
1043 qWarning(
"QImage::QImage(), XPM is not supported");
1048
1049
1050
1051
1052
1053
1054
1056QImage::QImage(
const QImage &image)
1059 if (image.paintingActive()) {
1061 image.copy().swap(*
this);
1070
1071
1075 if (d && !d->ref.deref())
1080
1081
1082
1083
1084
1085
1086
1087
1089QImage &QImage::operator=(
const QImage &image)
1091 if (image.paintingActive()) {
1092 operator=(image.copy());
1096 if (d && !d->ref.deref())
1104
1105
1106
1109
1110
1111int QImage::devType()
const
1113 return QInternal::Image;
1117
1118
1119QImage::operator QVariant()
const
1121 return QVariant::fromValue(*
this);
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135void QImage::detach()
1138 if (d->is_cached && d->ref.loadRelaxed() == 1)
1139 QImagePixmapCleanupHooks::executeImageHooks(cacheKey());
1141 if (d->ref.loadRelaxed() != 1 || d->ro_data)
1151
1152
1153
1154
1155
1156
1157
1158void QImage::detachMetadata(
bool invalidateCache)
1161 if (d->is_cached && d->ref.loadRelaxed() == 1)
1162 QImagePixmapCleanupHooks::executeImageHooks(cacheKey());
1164 if (d->ref.loadRelaxed() != 1)
1167 if (d && invalidateCache)
1174 dst->dpmx = src->dpmx;
1175 dst->dpmy = src->dpmy;
1176 dst->devicePixelRatio = src->devicePixelRatio;
1183 dst->text = src->text;
1184 dst->offset = src->offset;
1185 dst->colorSpace = src->colorSpace;
1190 dst->setDotsPerMeterX(src.dotsPerMeterX());
1191 dst->setDotsPerMeterY(src.dotsPerMeterY());
1192 dst->setDevicePixelRatio(src.devicePixelRatio());
1193 const auto textKeys = src.textKeys();
1194 for (
const auto &key: textKeys)
1195 dst->setText(key, src.text(key));
1200
1201
1202
1203
1204
1205
1206
1207
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229QImage Q_TRACE_INSTRUMENT(qtgui) QImage::copy(
const QRect& r)
const
1231 Q_TRACE_SCOPE(QImage_copy, r);
1236 QImage image(d->width, d->height, d->format);
1242 if (image.d->nbytes != d->nbytes) {
1243 qsizetype bpl = qMin(bytesPerLine(), image.bytesPerLine());
1244 for (
int i = 0; i < height(); i++)
1245 memcpy(image.scanLine(i), scanLine(i), bpl);
1247 memcpy(image.bits(), bits(), d->nbytes);
1248 image.d->colortable = d->colortable;
1249 image.d->has_alpha_clut = d->has_alpha_clut;
1250 copyMetadata(image.d, d);
1261 if (w <= 0 || h <= 0)
1264 QImage image(w, h, d->format);
1268 if (x < 0 || y < 0 || x + w > d->width || y + h > d->height) {
1281 image.d->colortable = d->colortable;
1283 int pixels_to_copy = qMax(w - dx, 0);
1286 else if (pixels_to_copy > d->width - x)
1287 pixels_to_copy = d->width - x;
1288 int lines_to_copy = qMax(h - dy, 0);
1291 else if (lines_to_copy > d->height - y)
1292 lines_to_copy = d->height - y;
1294 bool byteAligned =
true;
1295 if (d->format == Format_Mono || d->format == Format_MonoLSB)
1296 byteAligned = !(dx & 7) && !(x & 7) && !(pixels_to_copy & 7);
1299 const uchar *src = d->data + ((x * d->depth) >> 3) + y * d->bytes_per_line;
1300 uchar *dest = image.d->data + ((dx * d->depth) >> 3) + dy * image.d->bytes_per_line;
1301 const qsizetype bytes_to_copy = (qsizetype(pixels_to_copy) * d->depth) >> 3;
1302 for (
int i = 0; i < lines_to_copy; ++i) {
1303 memcpy(dest, src, bytes_to_copy);
1304 src += d->bytes_per_line;
1305 dest += image.d->bytes_per_line;
1307 }
else if (d->format == Format_Mono) {
1308 const uchar *src = d->data + y * d->bytes_per_line;
1309 uchar *dest = image.d->data + dy * image.d->bytes_per_line;
1310 for (
int i = 0; i < lines_to_copy; ++i) {
1311 for (
int j = 0; j < pixels_to_copy; ++j) {
1312 if (src[(x + j) >> 3] & (0x80 >> ((x + j) & 7)))
1313 dest[(dx + j) >> 3] |= (0x80 >> ((dx + j) & 7));
1315 dest[(dx + j) >> 3] &= ~(0x80 >> ((dx + j) & 7));
1317 src += d->bytes_per_line;
1318 dest += image.d->bytes_per_line;
1321 Q_ASSERT(d->format == Format_MonoLSB);
1322 const uchar *src = d->data + y * d->bytes_per_line;
1323 uchar *dest = image.d->data + dy * image.d->bytes_per_line;
1324 for (
int i = 0; i < lines_to_copy; ++i) {
1325 for (
int j = 0; j < pixels_to_copy; ++j) {
1326 if (src[(x + j) >> 3] & (0x1 << ((x + j) & 7)))
1327 dest[(dx + j) >> 3] |= (0x1 << ((dx + j) & 7));
1329 dest[(dx + j) >> 3] &= ~(0x1 << ((dx + j) & 7));
1331 src += d->bytes_per_line;
1332 dest += image.d->bytes_per_line;
1336 copyMetadata(image.d, d);
1337 image.d->has_alpha_clut = d->has_alpha_clut;
1344
1345
1346
1347
1348
1349bool QImage::isNull()
const
1355
1356
1357
1358
1359
1360
1361int QImage::width()
const
1363 return d ? d->width : 0;
1367
1368
1369
1370
1371
1372
1373int QImage::height()
const
1375 return d ? d->height : 0;
1379
1380
1381
1382
1383
1384
1385QSize QImage::size()
const
1387 return d ? QSize(d->width, d->height) : QSize(0, 0);
1391
1392
1393
1394
1395
1396
1397
1398QRect QImage::rect()
const
1400 return d ? QRect(0, 0, d->width, d->height) : QRect();
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415int QImage::depth()
const
1417 return d ? d->depth : 0;
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431int QImage::colorCount()
const
1433 return d ? d->colortable.size() : 0;
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447void QImage::setColorTable(
const QList<QRgb> &colors)
1451 detachMetadata(
true);
1457 d->colortable = colors;
1458 d->has_alpha_clut =
false;
1459 for (
int i = 0; i < d->colortable.size(); ++i) {
1460 if (qAlpha(d->colortable.at(i)) != 255) {
1461 d->has_alpha_clut =
true;
1468
1469
1470
1471
1472
1473QList<QRgb> QImage::colorTable()
const
1475 return d ? d->colortable : QList<QRgb>();
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489qreal QImage::devicePixelRatio()
const
1493 return d->devicePixelRatio;
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517void QImage::setDevicePixelRatio(qreal scaleFactor)
1522 if (scaleFactor == d->devicePixelRatio)
1527 d->devicePixelRatio = scaleFactor;
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540QSizeF QImage::deviceIndependentSize()
const
1543 return QSizeF(0, 0);
1544 return QSizeF(d->width, d->height) / d->devicePixelRatio;
1549
1550
1551
1552
1553
1554
1555qsizetype QImage::sizeInBytes()
const
1557 return d ? d->nbytes : 0;
1561
1562
1563
1564
1565
1566
1567qsizetype QImage::bytesPerLine()
const
1569 return d ? d->bytes_per_line : 0;
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584QRgb QImage::color(
int i)
const
1586 Q_ASSERT(i < colorCount());
1587 return d ? d->colortable.at(i) : QRgb(uint(-1));
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602void QImage::setColor(
int i, QRgb c)
1606 if (i < 0 || d->depth > 8 || i >= 1<<d->depth) {
1607 qWarning(
"QImage::setColor: Index out of bound %d", i);
1610 detachMetadata(
true);
1616 if (i >= d->colortable.size())
1618 d->colortable[i] = c;
1619 d->has_alpha_clut |= (qAlpha(c) != 255);
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644uchar *QImage::scanLine(
int i)
1655 return d->data + i * d->bytes_per_line;
1659
1660
1661const uchar *QImage::scanLine(
int i)
const
1666 Q_ASSERT(i >= 0 && i < height());
1667 return d->data + i * d->bytes_per_line;
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685const uchar *QImage::constScanLine(
int i)
const
1690 Q_ASSERT(i >= 0 && i < height());
1691 return d->data + i * d->bytes_per_line;
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705uchar *QImage::bits()
1719
1720
1721
1722
1723
1724
1725const uchar *QImage::bits()
const
1727 return d ? d->data :
nullptr;
1732
1733
1734
1735
1736
1737
1738
1739
1740const uchar *QImage::constBits()
const
1742 return d ? d->data :
nullptr;
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1765void QImage::fill(uint pixel)
1776 if (d->depth == 1 || d->depth == 8) {
1778 if (d->depth == 1) {
1787 qt_rectfill<quint8>(d->data, pixel, 0, 0,
1788 w, d->height, d->bytes_per_line);
1790 }
else if (d->depth == 16) {
1791 if (d->format == Format_RGB444)
1793 qt_rectfill<quint16>(
reinterpret_cast<quint16*>(d->data), pixel,
1794 0, 0, d->width, d->height, d->bytes_per_line);
1796 }
else if (d->depth == 24) {
1797 if (d->format == Format_RGB666)
1799 qt_rectfill<quint24>(
reinterpret_cast<quint24*>(d->data), pixel,
1800 0, 0, d->width, d->height, d->bytes_per_line);
1802 }
else if (d->format >= QImage::Format_RGBX64 && d->format <= QImage::Format_RGBA64_Premultiplied) {
1803 qt_rectfill<quint64>(
reinterpret_cast<quint64*>(d->data), QRgba64::fromArgb32(pixel),
1804 0, 0, d->width, d->height, d->bytes_per_line);
1806 }
else if (d->format >= QImage::Format_RGBX16FPx4 && d->format <= QImage::Format_RGBA16FPx4_Premultiplied) {
1808 QRgbaFloat16 cf = QRgbaFloat16::fromArgb32(pixel);
1809 ::memcpy(&cu, &cf,
sizeof(quint64));
1810 qt_rectfill<quint64>(
reinterpret_cast<quint64*>(d->data), cu,
1811 0, 0, d->width, d->height, d->bytes_per_line);
1813 }
else if (d->format >= QImage::Format_RGBX32FPx4 && d->format <= QImage::Format_RGBA32FPx4_Premultiplied) {
1814 QRgbaFloat32 cf = QRgbaFloat32::fromArgb32(pixel);
1815 uchar *data = d->data;
1816 for (
int y = 0; y < d->height; ++y) {
1817 QRgbaFloat32 *line =
reinterpret_cast<QRgbaFloat32 *>(data);
1818 for (
int x = 0; x < d->width; ++x)
1820 data += d->bytes_per_line;
1824 Q_ASSERT(d->depth == 32);
1826 if (d->format == Format_RGB32)
1827 pixel |= 0xff000000;
1828 if (d->format == Format_RGBX8888)
1829#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
1830 pixel |= 0xff000000;
1832 pixel |= 0x000000ff;
1834 if (d->format == Format_BGR30 || d->format == Format_RGB30)
1835 pixel |= 0xc0000000;
1837 qt_rectfill<uint>(
reinterpret_cast<uint*>(d->data), pixel,
1838 0, 0, d->width, d->height, d->bytes_per_line);
1843
1844
1845
1846
1847
1848
1850void QImage::fill(Qt::GlobalColor color)
1852 fill(QColor(color));
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1872void QImage::fill(
const QColor &color)
1882 QRgba64 opaque = color.rgba64();
1883 opaque.setAlpha(65535);
1884 switch (d->format) {
1885 case QImage::Format_RGB32:
1886 case QImage::Format_ARGB32:
1889 case QImage::Format_ARGB32_Premultiplied:
1890 fill(qPremultiply(color.rgba()));
1892 case QImage::Format_RGBX8888:
1893 fill(ARGB2RGBA(color.rgba() | 0xff000000));
1895 case QImage::Format_RGBA8888:
1896 fill(ARGB2RGBA(color.rgba()));
1898 case QImage::Format_RGBA8888_Premultiplied:
1899 fill(ARGB2RGBA(qPremultiply(color.rgba())));
1901 case QImage::Format_BGR30:
1902 fill(qConvertRgb64ToRgb30<PixelOrderBGR>(opaque));
1904 case QImage::Format_RGB30:
1905 fill(qConvertRgb64ToRgb30<PixelOrderRGB>(opaque));
1907 case QImage::Format_RGB16:
1908 fill((uint) qConvertRgb32To16(color.rgba()));
1910 case QImage::Format_Indexed8: {
1912 for (
int i=0; i<d->colortable.size(); ++i) {
1913 if (color.rgba() == d->colortable.at(i)) {
1921 case QImage::Format_Mono:
1922 case QImage::Format_MonoLSB:
1923 if (color == Qt::color1)
1928 case QImage::Format_RGBX64:
1929 qt_rectfill<quint64>(
reinterpret_cast<quint64*>(d->data), opaque,
1930 0, 0, d->width, d->height, d->bytes_per_line);
1932 case QImage::Format_RGBA64:
1933 qt_rectfill<quint64>(
reinterpret_cast<quint64*>(d->data), color.rgba64(),
1934 0, 0, d->width, d->height, d->bytes_per_line);
1936 case QImage::Format_RGBA64_Premultiplied:
1937 qt_rectfill<quint64>(
reinterpret_cast<quint64 *>(d->data), color.rgba64().premultiplied(),
1938 0, 0, d->width, d->height, d->bytes_per_line);
1940 case QImage::Format_RGBX16FPx4:
1941 case QImage::Format_RGBA16FPx4:
1942 case QImage::Format_RGBA16FPx4_Premultiplied:
1943 case QImage::Format_RGBX32FPx4:
1944 case QImage::Format_RGBA32FPx4:
1945 case QImage::Format_RGBA32FPx4_Premultiplied:{
1947 color.getRgbF(&r, &g, &b, &a);
1948 if (!hasAlphaChannel())
1950 if (depth() == 64) {
1951 QRgbaFloat16 c16{qfloat16(r), qfloat16(g), qfloat16(b), qfloat16(a)};
1952 if (d->format == Format_RGBA16FPx4_Premultiplied)
1953 c16 = c16.premultiplied();
1954 qt_rectfill<QRgbaFloat16>(
reinterpret_cast<QRgbaFloat16 *>(d->data), c16,
1955 0, 0, d->width, d->height, d->bytes_per_line);
1957 QRgbaFloat32 c32{r, g, b, a};
1958 if (d->format == Format_RGBA32FPx4_Premultiplied)
1959 c32 = c32.premultiplied();
1960 qt_rectfill<QRgbaFloat32>(
reinterpret_cast<QRgbaFloat32 *>(d->data), c32,
1961 0, 0, d->width, d->height, d->bytes_per_line);
1967 p.setCompositionMode(QPainter::CompositionMode_Source);
1968 p.fillRect(rect(), color);
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
1994void QImage::invertPixels(InvertMode mode)
2005 QImage::Format originalFormat = d->format;
2007 if (hasAlphaChannel() && qPixelLayouts[d->format].premultiplied) {
2008 if (d->format == QImage::Format_RGBA16FPx4_Premultiplied) {
2009 if (!d->convertInPlace(QImage::Format_RGBA16FPx4, { }))
2010 *
this = convertToFormat(QImage::Format_RGBA16FPx4);
2011 }
else if (d->format == QImage::Format_RGBA32FPx4_Premultiplied) {
2012 if (!d->convertInPlace(QImage::Format_RGBA32FPx4, { }))
2013 *
this = convertToFormat(QImage::Format_RGBA32FPx4);
2014 }
else if (depth() > 32) {
2015 if (!d->convertInPlace(QImage::Format_RGBA64, { }))
2016 *
this = convertToFormat(QImage::Format_RGBA64);
2018 if (!d->convertInPlace(QImage::Format_ARGB32, { }))
2019 *
this = convertToFormat(QImage::Format_ARGB32);
2025 qsizetype bpl = (qsizetype(d->width) * d->depth + 7) / 8;
2026 int pad = d->bytes_per_line - bpl;
2027 uchar *sl = d->data;
2028 for (
int y=0; y<d->height; ++y) {
2029 for (qsizetype x=0; x<bpl; ++x)
2033 }
else if (format() >= QImage::Format_RGBX16FPx4 && format() <= QImage::Format_RGBA16FPx4_Premultiplied) {
2034 qfloat16 *p =
reinterpret_cast<qfloat16 *>(d->data);
2035 qfloat16 *end =
reinterpret_cast<qfloat16 *>(d->data + d->nbytes);
2037 p[0] = qfloat16(1) - p[0];
2038 p[1] = qfloat16(1) - p[1];
2039 p[2] = qfloat16(1) - p[2];
2040 if (mode == InvertRgba)
2041 p[3] = qfloat16(1) - p[3];
2044 }
else if (format() >= QImage::Format_RGBX32FPx4 && format() <= QImage::Format_RGBA32FPx4_Premultiplied) {
2045 uchar *data = d->data;
2046 for (
int y = 0; y < d->height; ++y) {
2047 float *p =
reinterpret_cast<
float *>(data);
2048 for (
int x = 0; x < d->width; ++x) {
2052 if (mode == InvertRgba)
2056 data += d->bytes_per_line;
2058 }
else if (depth() == 64) {
2059 quint16 *p = (quint16*)d->data;
2060 quint16 *end = (quint16*)(d->data + d->nbytes);
2061 quint16 xorbits = 0xffff;
2066 if (mode == InvertRgba)
2072 quint32 *p = (quint32*)d->data;
2073 quint32 *end = (quint32*)(d->data + d->nbytes);
2074 quint32 xorbits = 0xffffffff;
2075 switch (d->format) {
2076 case QImage::Format_RGBA8888:
2077 if (mode == InvertRgba)
2080 case QImage::Format_RGBX8888:
2081#if Q_BYTE_ORDER == Q_BIG_ENDIAN
2082 xorbits = 0xffffff00;
2085 xorbits = 0x00ffffff;
2088 case QImage::Format_ARGB32:
2089 if (mode == InvertRgba)
2092 case QImage::Format_RGB32:
2093 xorbits = 0x00ffffff;
2095 case QImage::Format_BGR30:
2096 case QImage::Format_RGB30:
2097 xorbits = 0x3fffffff;
2108 if (originalFormat != d->format) {
2109 if (!d->convertInPlace(originalFormat, { }))
2110 *
this = convertToFormat(originalFormat);
2126
2127
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137
2139void QImage::setColorCount(
int colorCount)
2142 qWarning(
"QImage::setColorCount: null image");
2146 detachMetadata(
true);
2152 if (colorCount == d->colortable.size())
2154 if (colorCount <= 0) {
2155 d->colortable.clear();
2158 int nc = d->colortable.size();
2159 d->colortable.resize(colorCount);
2160 for (
int i = nc; i < colorCount; ++i)
2161 d->colortable[i] = 0;
2165
2166
2167
2168
2169QImage::Format QImage::format()
const
2173 Q_ASSERT(d->format < NImageFormats);
2174 Q_ASSERT(d->format > Format_Invalid);
2176 return d ? d->format : Format_Invalid;
2180
2181
2182
2183
2184
2185
2186
2187
2188
2189
2192
2193
2194
2195
2196
2197
2198
2199
2200
2201
2202
2205
2206
2207QImage QImage::convertToFormat_helper(Format format, Qt::ImageConversionFlags flags)
const
2209 if (!d || d->format == format)
2212 if (d->format == Format_Invalid || format <= Format_Invalid || format >= NImageFormats)
2215 const QPixelLayout *destLayout = &qPixelLayouts[format];
2216 Image_Converter converter = qimage_converter_map[d->format][format];
2217 if (!converter && format > QImage::Format_Indexed8 && d->format > QImage::Format_Indexed8) {
2218 if (qt_highColorPrecision(d->format, !destLayout->hasAlphaChannel)
2219 && qt_highColorPrecision(format, !hasAlphaChannel())) {
2220#if QT_CONFIG(raster_fp)
2221 if (qt_fpColorPrecision(d->format) && qt_fpColorPrecision(format))
2222 converter = convert_generic_over_rgba32f;
2225 converter = convert_generic_over_rgb64;
2227 converter = convert_generic;
2230 QImage image(d->width, d->height, format);
2234 copyMetadata(image.d, d);
2236 converter(image.d, d, flags);
2241 Q_ASSERT(format != QImage::Format_ARGB32 && format != QImage::Format_RGB32);
2242 Q_ASSERT(d->format != QImage::Format_ARGB32 && d->format != QImage::Format_RGB32);
2244 if (!hasAlphaChannel())
2245 return convertToFormat(Format_RGB32, flags).convertToFormat(format, flags);
2247 return convertToFormat(Format_ARGB32, flags).convertToFormat(format, flags);
2251
2252
2253bool QImage::convertToFormat_inplace(Format format, Qt::ImageConversionFlags flags)
2255 return d && d->convertInPlace(format, flags);
2258static inline int pixel_distance(QRgb p1, QRgb p2) {
2260 int g1 = qGreen(p1);
2262 int a1 = qAlpha(p1);
2265 int g2 = qGreen(p2);
2267 int a2 = qAlpha(p2);
2269 return abs(r1 - r2) + abs(g1 - g2) + abs(b1 - b2) + abs(a1 - a2);
2272static inline int closestMatch(QRgb pixel,
const QList<QRgb> &clut) {
2274 int current_distance = INT_MAX;
2275 for (
int i=0; i<clut.size(); ++i) {
2276 int dist = pixel_distance(pixel, clut.at(i));
2277 if (dist < current_distance) {
2278 current_distance = dist;
2285static QImage convertWithPalette(
const QImage &src, QImage::Format format,
2286 const QList<QRgb> &clut) {
2287 QImage dest(src.size(), format);
2288 dest.setColorTable(clut);
2290 copyMetadata(QImageData::get(dest), QImageData::get(src));
2292 int h = src.height();
2293 int w = src.width();
2295 QHash<QRgb,
int> cache;
2297 if (format == QImage::Format_Indexed8) {
2298 for (
int y=0; y<h; ++y) {
2299 const QRgb *src_pixels = (
const QRgb *) src.scanLine(y);
2300 uchar *dest_pixels = (uchar *) dest.scanLine(y);
2301 for (
int x=0; x<w; ++x) {
2302 int src_pixel = src_pixels[x];
2303 int value = cache.value(src_pixel, -1);
2305 value = closestMatch(src_pixel, clut);
2306 cache.insert(src_pixel, value);
2308 dest_pixels[x] = (uchar) value;
2312 QList<QRgb> table = clut;
2314 for (
int y=0; y<h; ++y) {
2315 const QRgb *src_pixels = (
const QRgb *) src.scanLine(y);
2316 for (
int x=0; x<w; ++x) {
2317 int src_pixel = src_pixels[x];
2318 int value = cache.value(src_pixel, -1);
2320 value = closestMatch(src_pixel, table);
2321 cache.insert(src_pixel, value);
2323 dest.setPixel(x, y, value);
2332
2333
2334
2335
2336
2337
2338
2339
2340
2341QImage QImage::convertToFormat(Format format,
const QList<QRgb> &colorTable, Qt::ImageConversionFlags flags)
const
2343 if (!d || d->format == format)
2346 if (format <= QImage::Format_Invalid || format >= QImage::NImageFormats)
2348 if (format <= QImage::Format_Indexed8)
2349 return convertWithPalette(convertToFormat(QImage::Format_ARGB32, flags), format, colorTable);
2351 return convertToFormat(format, flags);
2355
2356
2357
2358
2359
2360
2361
2362
2363
2364
2365
2366
2367
2368
2369
2370
2371
2372
2373
2374
2375
2377bool QImage::reinterpretAsFormat(Format format)
2379 if (format <= Format_Invalid || format >= NImageFormats)
2383 if (d->format == format)
2385 if (qt_depthForFormat(format) != qt_depthForFormat(d->format))
2387 if (!isDetached()) {
2388 QImageData *oldD = d;
2403
2404
2405
2406
2407
2408
2409
2410
2411
2413void QImage::convertTo(Format format, Qt::ImageConversionFlags flags)
2415 if (!d || format <= QImage::Format_Invalid || format >= QImage::NImageFormats)
2418 if (d->format == format)
2422 if (convertToFormat_inplace(format, flags))
2425 *
this = convertToFormat_helper(format, flags);
2429
2430
2431
2432
2433
2434
2435
2438
2439
2440
2441
2442
2443bool QImage::valid(
int x,
int y)
const
2446 && x >= 0 && x < d->width
2447 && y >= 0 && y < d->height;
2451
2452
2453
2454
2455
2456
2457
2458
2459
2462
2463
2464
2465
2466int QImage::pixelIndex(
int x,
int y)
const
2468 if (!d || x < 0 || x >= d->width || y < 0 || y >= height()) {
2469 qWarning(
"QImage::pixelIndex: coordinate (%d,%d) out of range", x, y);
2472 const uchar * s = scanLine(y);
2475 return (*(s + (x >> 3)) >> (7- (x & 7))) & 1;
2476 case Format_MonoLSB:
2477 return (*(s + (x >> 3)) >> (x & 7)) & 1;
2478 case Format_Indexed8:
2481 qWarning(
"QImage::pixelIndex: Not applicable for %d-bpp images (no palette)", d->depth);
2488
2489
2490
2491
2492
2493
2494
2495
2496
2497
2498
2499
2500
2503
2504
2505
2506
2507QRgb QImage::pixel(
int x,
int y)
const
2509 if (!d || x < 0 || x >= d->width || y < 0 || y >= d->height) {
2510 qWarning(
"QImage::pixel: coordinate (%d,%d) out of range", x, y);
2514 const uchar *s = d->data + y * d->bytes_per_line;
2517 switch (d->format) {
2519 index = (*(s + (x >> 3)) >> (~x & 7)) & 1;
2521 case Format_MonoLSB:
2522 index = (*(s + (x >> 3)) >> (x & 7)) & 1;
2524 case Format_Indexed8:
2531 if (index >= d->colortable.size()) {
2532 qWarning(
"QImage::pixel: color table index %d out of range.", index);
2535 return d->colortable.at(index);
2537 std::optional<QRgb> out;
2538 switch (d->format) {
2541 case Format_ARGB32_Premultiplied:
2542 out =
reinterpret_cast<
const QRgb *>(s)[x];
2544 case Format_RGBX8888:
2545 case Format_RGBA8888:
2546 case Format_RGBA8888_Premultiplied:
2547 out = RGBA2ARGB(
reinterpret_cast<
const quint32 *>(s)[x]);
2550 case Format_A2BGR30_Premultiplied:
2551 out = qConvertA2rgb30ToArgb32<PixelOrderBGR>(
reinterpret_cast<
const quint32 *>(s)[x]);
2554 case Format_A2RGB30_Premultiplied:
2555 out = qConvertA2rgb30ToArgb32<PixelOrderRGB>(
reinterpret_cast<
const quint32 *>(s)[x]);
2558 return qConvertRgb16To32(
reinterpret_cast<
const quint16 *>(s)[x]);
2561 case Format_RGBA64_Premultiplied:
2562 out =
reinterpret_cast<
const QRgba64 *>(s)[x].toArgb32();
2564 case Format_RGBX16FPx4:
2565 case Format_RGBA16FPx4:
2566 case Format_RGBA16FPx4_Premultiplied:
2567 out =
reinterpret_cast<
const QRgbaFloat16 *>(s)[x].toArgb32();
2569 case Format_RGBX32FPx4:
2570 case Format_RGBA32FPx4:
2571 case Format_RGBA32FPx4_Premultiplied:
2572 out =
reinterpret_cast<
const QRgbaFloat32 *>(s)[x].toArgb32();
2576 const QPixelLayout *layout = &qPixelLayouts[d->format];
2579 if (!layout->hasAlphaChannel)
2584 return *layout->fetchToARGB32PM(&result, s, x, 1,
nullptr,
nullptr);
2588
2589
2590
2591
2592
2593
2594
2595
2596
2597
2598
2599
2600
2601
2602
2603
2604
2605
2606
2609
2610
2611
2612
2613void QImage::setPixel(
int x,
int y, uint index_or_rgb)
2615 if (!d || x < 0 || x >= width() || y < 0 || y >= height()) {
2616 qWarning(
"QImage::setPixel: coordinate (%d,%d) out of range", x, y);
2620 uchar * s = scanLine(y);
2623 case Format_MonoLSB:
2624 if (index_or_rgb > 1) {
2625 qWarning(
"QImage::setPixel: Index %d out of range", index_or_rgb);
2626 }
else if (format() == Format_MonoLSB) {
2627 if (index_or_rgb==0)
2628 *(s + (x >> 3)) &= ~(1 << (x & 7));
2630 *(s + (x >> 3)) |= (1 << (x & 7));
2632 if (index_or_rgb==0)
2633 *(s + (x >> 3)) &= ~(1 << (7-(x & 7)));
2635 *(s + (x >> 3)) |= (1 << (7-(x & 7)));
2638 case Format_Indexed8:
2639 if (index_or_rgb >= (uint)d->colortable.size()) {
2640 qWarning(
"QImage::setPixel: Index %d out of range", index_or_rgb);
2643 s[x] = index_or_rgb;
2648 ((uint *)s)[x] = 0xff000000 | index_or_rgb;
2651 case Format_ARGB32_Premultiplied:
2652 ((uint *)s)[x] = index_or_rgb;
2655 ((quint16 *)s)[x] = qConvertRgb32To16(index_or_rgb);
2657 case Format_RGBX8888:
2658 ((uint *)s)[x] = ARGB2RGBA(0xff000000 | index_or_rgb);
2660 case Format_RGBA8888:
2661 case Format_RGBA8888_Premultiplied:
2662 ((uint *)s)[x] = ARGB2RGBA(index_or_rgb);
2665 ((uint *)s)[x] = qConvertRgb32ToRgb30<PixelOrderBGR>(index_or_rgb);
2667 case Format_A2BGR30_Premultiplied:
2668 ((uint *)s)[x] = qConvertArgb32ToA2rgb30<PixelOrderBGR>(index_or_rgb);
2671 ((uint *)s)[x] = qConvertRgb32ToRgb30<PixelOrderRGB>(index_or_rgb);
2673 case Format_A2RGB30_Premultiplied:
2674 ((uint *)s)[x] = qConvertArgb32ToA2rgb30<PixelOrderRGB>(index_or_rgb);
2677 ((QRgba64 *)s)[x] = QRgba64::fromArgb32(index_or_rgb | 0xff000000);
2680 case Format_RGBA64_Premultiplied:
2681 ((QRgba64 *)s)[x] = QRgba64::fromArgb32(index_or_rgb);
2683 case Format_RGBX16FPx4:
2684 ((QRgbaFloat16 *)s)[x] = QRgbaFloat16::fromArgb32(index_or_rgb | 0xff000000);
2686 case Format_RGBA16FPx4:
2687 case Format_RGBA16FPx4_Premultiplied:
2688 ((QRgbaFloat16 *)s)[x] = QRgbaFloat16::fromArgb32(index_or_rgb);
2690 case Format_RGBX32FPx4:
2691 ((QRgbaFloat32 *)s)[x] = QRgbaFloat32::fromArgb32(index_or_rgb | 0xff000000);
2693 case Format_RGBA32FPx4:
2694 case Format_RGBA32FPx4_Premultiplied:
2695 ((QRgbaFloat32 *)s)[x] = QRgbaFloat32::fromArgb32(index_or_rgb);
2697 case Format_Invalid:
2705 const QPixelLayout *layout = &qPixelLayouts[d->format];
2706 if (!hasAlphaChannel())
2707 layout->storeFromRGB32(s, &index_or_rgb, x, 1,
nullptr,
nullptr);
2709 layout->storeFromARGB32PM(s, &index_or_rgb, x, 1,
nullptr,
nullptr);
2713
2714
2715
2716
2717
2718
2719
2720
2721
2722
2723
2724
2725
2726
2729
2730
2731
2732
2733
2734QColor QImage::pixelColor(
int x,
int y)
const
2736 if (!d || x < 0 || x >= d->width || y < 0 || y >= height()) {
2737 qWarning(
"QImage::pixelColor: coordinate (%d,%d) out of range", x, y);
2742 const uchar * s = constScanLine(y);
2743 switch (d->format) {
2745 case Format_A2BGR30_Premultiplied:
2746 c = qConvertA2rgb30ToRgb64<PixelOrderBGR>(
reinterpret_cast<
const quint32 *>(s)[x]);
2749 case Format_A2RGB30_Premultiplied:
2750 c = qConvertA2rgb30ToRgb64<PixelOrderRGB>(
reinterpret_cast<
const quint32 *>(s)[x]);
2754 case Format_RGBA64_Premultiplied:
2755 c =
reinterpret_cast<
const QRgba64 *>(s)[x];
2757 case Format_Grayscale16: {
2758 quint16 v =
reinterpret_cast<
const quint16 *>(s)[x];
2759 return QColor(qRgba64(v, v, v, 0xffff));
2761 case Format_RGBX16FPx4:
2762 case Format_RGBA16FPx4:
2763 case Format_RGBA16FPx4_Premultiplied: {
2764 QRgbaFloat16 p =
reinterpret_cast<
const QRgbaFloat16 *>(s)[x];
2765 if (d->format == Format_RGBA16FPx4_Premultiplied)
2766 p = p.unpremultiplied();
2767 else if (d->format == Format_RGBX16FPx4)
2770 color.setRgbF(p.red(), p.green(), p.blue(), p.alpha());
2773 case Format_RGBX32FPx4:
2774 case Format_RGBA32FPx4:
2775 case Format_RGBA32FPx4_Premultiplied: {
2776 QRgbaFloat32 p =
reinterpret_cast<
const QRgbaFloat32 *>(s)[x];
2777 if (d->format == Format_RGBA32FPx4_Premultiplied)
2778 p = p.unpremultiplied();
2779 else if (d->format == Format_RGBX32FPx4)
2782 color.setRgbF(p.red(), p.green(), p.blue(), p.alpha());
2786 c = QRgba64::fromArgb32(pixel(x, y));
2790 switch (d->format) {
2800 if (hasAlphaChannel() && qPixelLayouts[d->format].premultiplied)
2801 c = c.unpremultiplied();
2806
2807
2808
2809
2810
2811
2812
2813
2814
2815
2816
2817
2818
2819
2822
2823
2824
2825
2826
2827void QImage::setPixelColor(
int x,
int y,
const QColor &color)
2829 if (!d || x < 0 || x >= width() || y < 0 || y >= height()) {
2830 qWarning(
"QImage::setPixelColor: coordinate (%d,%d) out of range", x, y);
2834 if (!color.isValid()) {
2835 qWarning(
"QImage::setPixelColor: color is invalid");
2840 QRgba64 c = color.rgba64();
2841 if (!hasAlphaChannel())
2843 else if (qPixelLayouts[d->format].premultiplied)
2844 c = c.premultiplied();
2846 uchar * s = scanLine(y);
2847 switch (d->format) {
2849 case Format_MonoLSB:
2850 case Format_Indexed8:
2851 qWarning(
"QImage::setPixelColor: called on monochrome or indexed format");
2854 ((uint *)s)[x] = qConvertRgb64ToRgb30<PixelOrderBGR>(c) | 0xc0000000;
2856 case Format_A2BGR30_Premultiplied:
2857 ((uint *)s)[x] = qConvertRgb64ToRgb30<PixelOrderBGR>(c);
2860 ((uint *)s)[x] = qConvertRgb64ToRgb30<PixelOrderRGB>(c) | 0xc0000000;
2862 case Format_A2RGB30_Premultiplied:
2863 ((uint *)s)[x] = qConvertRgb64ToRgb30<PixelOrderRGB>(c);
2867 case Format_RGBA64_Premultiplied:
2868 ((QRgba64 *)s)[x] = c;
2870 case Format_RGBX16FPx4:
2871 case Format_RGBA16FPx4:
2872 case Format_RGBA16FPx4_Premultiplied: {
2874 color.getRgbF(&r, &g, &b, &a);
2875 if (d->format == Format_RGBX16FPx4)
2877 QRgbaFloat16 c16f{qfloat16(r), qfloat16(g), qfloat16(b), qfloat16(a)};
2878 if (d->format == Format_RGBA16FPx4_Premultiplied)
2879 c16f = c16f.premultiplied();
2880 ((QRgbaFloat16 *)s)[x] = c16f;
2883 case Format_RGBX32FPx4:
2884 case Format_RGBA32FPx4:
2885 case Format_RGBA32FPx4_Premultiplied: {
2887 color.getRgbF(&r, &g, &b, &a);
2888 if (d->format == Format_RGBX32FPx4)
2890 QRgbaFloat32 c32f{r, g, b, a};
2891 if (d->format == Format_RGBA32FPx4_Premultiplied)
2892 c32f = c32f.premultiplied();
2893 ((QRgbaFloat32 *)s)[x] = c32f;
2897 setPixel(x, y, c.toArgb32());
2903
2904
2905
2906
2907
2908
2909
2910
2911bool QImage::allGray()
const
2916 switch (d->format) {
2918 case Format_MonoLSB:
2919 case Format_Indexed8:
2920 for (
int i = 0; i < d->colortable.size(); ++i) {
2921 if (!qIsGray(d->colortable.at(i)))
2927 case Format_Grayscale8:
2928 case Format_Grayscale16:
2932 case Format_ARGB32_Premultiplied:
2933#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
2934 case Format_RGBX8888:
2935 case Format_RGBA8888:
2936 case Format_RGBA8888_Premultiplied:
2938 for (
int j = 0; j < d->height; ++j) {
2939 const QRgb *b = (
const QRgb *)constScanLine(j);
2940 for (
int i = 0; i < d->width; ++i) {
2947 for (
int j = 0; j < d->height; ++j) {
2948 const quint16 *b = (
const quint16 *)constScanLine(j);
2949 for (
int i = 0; i < d->width; ++i) {
2950 if (!qIsGray(qConvertRgb16To32(b[i])))
2959 Q_DECL_UNINITIALIZED uint buffer[BufferSize];
2960 const QPixelLayout *layout = &qPixelLayouts[d->format];
2961 const auto fetch = layout->fetchToARGB32PM;
2962 for (
int j = 0; j < d->height; ++j) {
2963 const uchar *b = constScanLine(j);
2965 while (x < d->width) {
2966 int l = qMin(d->width - x, BufferSize);
2967 const uint *ptr = fetch(buffer, b, x, l,
nullptr,
nullptr);
2968 for (
int i = 0; i < l; ++i) {
2969 if (!qIsGray(ptr[i]))
2979
2980
2981
2982
2983
2984
2985
2986
2987bool QImage::isGrayscale()
const
2992 if (d->format == QImage::Format_Alpha8)
2995 if (d->format == QImage::Format_Grayscale8 || d->format == QImage::Format_Grayscale16)
3004 Q_ASSERT(d->format == QImage::Format_Indexed8);
3005 for (
int i = 0; i < colorCount(); i++)
3006 if (d->colortable.at(i) != qRgb(i,i,i))
3015
3016
3017
3018
3019
3020
3021
3022
3023
3024
3025
3028
3029
3030
3031
3032
3033
3034
3035
3036
3037
3038
3039
3040
3041
3042
3043
3044
3045
3046
3047
3048
3049
3050
3051
3052
3053QImage Q_TRACE_INSTRUMENT(qtgui) QImage::scaled(
const QSize& s, Qt::AspectRatioMode aspectMode, Qt::TransformationMode mode)
const
3056 qWarning(
"QImage::scaled: Image is a null image");
3062 QSize newSize = size();
3063 newSize.scale(s, aspectMode);
3064 newSize.rwidth() = qMax(newSize.width(), 1);
3065 newSize.rheight() = qMax(newSize.height(), 1);
3066 if (newSize == size())
3069 Q_TRACE_SCOPE(QImage_scaled, s, aspectMode, mode);
3071 QTransform wm = QTransform::fromScale((qreal)newSize.width() / width(), (qreal)newSize.height() / height());
3072 QImage img = transformed(wm, mode);
3078
3079
3080
3081
3082
3083
3084
3085
3086
3087
3088
3089
3090QImage Q_TRACE_INSTRUMENT(qtgui) QImage::scaledToWidth(
int w, Qt::TransformationMode mode)
const
3093 qWarning(
"QImage::scaleWidth: Image is a null image");
3099 Q_TRACE_SCOPE(QImage_scaledToWidth, w, mode);
3101 qreal factor = (qreal) w / width();
3102 QTransform wm = QTransform::fromScale(factor, factor);
3103 return transformed(wm, mode);
3107
3108
3109
3110
3111
3112
3113
3114
3115
3116
3117
3118
3119
3120QImage Q_TRACE_INSTRUMENT(qtgui) QImage::scaledToHeight(
int h, Qt::TransformationMode mode)
const
3123 qWarning(
"QImage::scaleHeight: Image is a null image");
3129 Q_TRACE_SCOPE(QImage_scaledToHeight, h, mode);
3131 qreal factor = (qreal) h / height();
3132 QTransform wm = QTransform::fromScale(factor, factor);
3133 return transformed(wm, mode);
3137
3138
3139
3140
3141
3142
3143
3144
3145
3146
3147
3148
3149
3150
3151
3152
3153QImage Q_TRACE_INSTRUMENT(qtgui) QImage::createAlphaMask(Qt::ImageConversionFlags flags)
const
3155 if (!d || d->format == QImage::Format_RGB32)
3158 if (d->depth == 1) {
3161 return convertToFormat(Format_Indexed8, flags).createAlphaMask(flags);
3164 QImage mask(d->width, d->height, Format_MonoLSB);
3165 if (!mask.isNull()) {
3166 dither_to_Mono(mask.d, d, flags,
true);
3167 copyPhysicalMetadata(mask.d, d);
3172#ifndef QT_NO_IMAGE_HEURISTIC_MASK
3174
3175
3176
3177
3178
3179
3180
3181
3182
3183
3184
3185
3186
3187
3188
3189
3190
3191
3192
3193
3194
3195
3197QImage QImage::createHeuristicMask(
bool clipTight)
const
3202 if (d->depth != 32) {
3203 QImage img32 = convertToFormat(Format_RGB32);
3204 return img32.createHeuristicMask(clipTight);
3207#define PIX(x,y) (*((const QRgb*)scanLine(y)+x) & 0x00ffffff
)
3211 QImage m(w, h, Format_MonoLSB);
3214 m.setColor(0, QColor(Qt::color0).rgba());
3215 m.setColor(1, QColor(Qt::color1).rgba());
3218 QRgb background =
PIX(0,0);
3219 if (background !=
PIX(w-1,0) &&
3220 background !=
PIX(0,h-1) &&
3221 background !=
PIX(w-1,h-1)) {
3222 background =
PIX(w-1,0);
3223 if (background !=
PIX(w-1,h-1) &&
3224 background !=
PIX(0,h-1) &&
3225 PIX(0,h-1) ==
PIX(w-1,h-1)) {
3226 background =
PIX(w-1,h-1);
3232 uchar *ypp, *ypc, *ypn;
3235 ypn = m.scanLine(0);
3237 for (y = 0; y < h; y++) {
3240 ypn = (y == h-1) ?
nullptr : m.scanLine(y+1);
3241 const QRgb *p = (
const QRgb *)scanLine(y);
3242 for (x = 0; x < w; x++) {
3245 if ((x == 0 || y == 0 || x == w-1 || y == h-1 ||
3246 !(*(ypc + ((x-1) >> 3)) & (1 << ((x-1) & 7))) ||
3247 !(*(ypc + ((x+1) >> 3)) & (1 << ((x+1) & 7))) ||
3248 !(*(ypp + (x >> 3)) & (1 << (x & 7))) ||
3249 !(*(ypn + (x >> 3)) & (1 << (x & 7)))) &&
3250 ( (*(ypc + (x >> 3)) & (1 << (x & 7)))) &&
3251 ((*p & 0x00ffffff) == background)) {
3253 *(ypc + (x >> 3)) &= ~(1 << (x & 7));
3261 ypn = m.scanLine(0);
3263 for (y = 0; y < h; y++) {
3266 ypn = (y == h-1) ?
nullptr : m.scanLine(y+1);
3267 const QRgb *p = (
const QRgb *)scanLine(y);
3268 for (x = 0; x < w; x++) {
3269 if ((*p & 0x00ffffff) != background) {
3271 *(ypc + ((x-1) >> 3)) |= (1 << ((x-1) & 7));
3273 *(ypc + ((x+1) >> 3)) |= (1 << ((x+1) & 7));
3275 *(ypp + (x >> 3)) |= (1 << (x & 7));
3277 *(ypn + (x >> 3)) |= (1 << (x & 7));
3286 copyPhysicalMetadata(m.d, d);
3292
3293
3294
3295
3296
3297
3298
3299
3301QImage QImage::createMaskFromColor(QRgb color, Qt::MaskMode mode)
const
3305 QImage maskImage(size(), QImage::Format_MonoLSB);
3308 uchar *s = maskImage.bits();
3312 if (depth() == 32) {
3313 for (
int h = 0; h < d->height; h++) {
3314 const uint *sl = (
const uint *) scanLine(h);
3315 for (
int w = 0; w < d->width; w++) {
3317 *(s + (w >> 3)) |= (1 << (w & 7));
3319 s += maskImage.bytesPerLine();
3322 for (
int h = 0; h < d->height; h++) {
3323 for (
int w = 0; w < d->width; w++) {
3324 if ((uint) pixel(w, h) == color)
3325 *(s + (w >> 3)) |= (1 << (w & 7));
3327 s += maskImage.bytesPerLine();
3330 if (mode == Qt::MaskOutColor)
3331 maskImage.invertPixels();
3333 copyPhysicalMetadata(maskImage.d, d);
3338
3339
3340
3341
3342
3343
3344
3345
3346
3347
3348
3349
3352
3353
3354
3355
3356
3357
3358
3359
3360
3363
3364
3365
3366
3367
3368
3369
3370
3371
3372
3373
3376
3377
3378
3379
3380
3381
3382
3383
3385template<
class T>
inline void do_mirror_data(QImageData *dst, QImageData *src,
3386 int dstX0,
int dstY0,
3387 int dstXIncr,
int dstYIncr,
3393 const int srcXEnd = (dstX0 && !dstY0) ? w / 2 : w;
3394 const int srcYEnd = dstY0 ? h / 2 : h;
3395 for (
int srcY = 0, dstY = dstY0; srcY < srcYEnd; ++srcY, dstY += dstYIncr) {
3396 T *srcPtr = (T *) (src->data + srcY * src->bytes_per_line);
3397 T *dstPtr = (T *) (dst->data + dstY * dst->bytes_per_line);
3398 for (
int srcX = 0, dstX = dstX0; srcX < srcXEnd; ++srcX, dstX += dstXIncr)
3399 std::swap(srcPtr[srcX], dstPtr[dstX]);
3402 if (dstX0 && dstY0 && (h & 1)) {
3404 int srcXEnd2 = w / 2;
3405 T *srcPtr = (T *) (src->data + srcY * src->bytes_per_line);
3406 for (
int srcX = 0, dstX = dstX0; srcX < srcXEnd2; ++srcX, dstX += dstXIncr)
3407 std::swap(srcPtr[srcX], srcPtr[dstX]);
3410 for (
int srcY = 0, dstY = dstY0; srcY < h; ++srcY, dstY += dstYIncr) {
3411 T *srcPtr = (T *) (src->data + srcY * src->bytes_per_line);
3412 T *dstPtr = (T *) (dst->data + dstY * dst->bytes_per_line);
3413 for (
int srcX = 0, dstX = dstX0; srcX < w; ++srcX, dstX += dstXIncr)
3414 dstPtr[dstX] = srcPtr[srcX];
3419inline void do_flip(QImageData *dst, QImageData *src,
int w,
int h,
int depth)
3421 const int data_bytes_per_line = w * (depth / 8);
3423 uint *srcPtr =
reinterpret_cast<uint *>(src->data);
3424 uint *dstPtr =
reinterpret_cast<uint *>(dst->data + (h - 1) * dst->bytes_per_line);
3426 const int uint_per_line = (data_bytes_per_line + 3) >> 2;
3427 for (
int y = 0; y < h; ++y) {
3429 for (
int x = 0; x < uint_per_line; x++) {
3430 const uint d = dstPtr[x];
3431 const uint s = srcPtr[x];
3435 srcPtr += src->bytes_per_line >> 2;
3436 dstPtr -= dst->bytes_per_line >> 2;
3440 const uchar *srcPtr = src->data;
3441 uchar *dstPtr = dst->data + (h - 1) * dst->bytes_per_line;
3442 for (
int y = 0; y < h; ++y) {
3443 memcpy(dstPtr, srcPtr, data_bytes_per_line);
3444 srcPtr += src->bytes_per_line;
3445 dstPtr -= dst->bytes_per_line;
3450inline void do_mirror(QImageData *dst, QImageData *src,
bool horizontal,
bool vertical)
3452 Q_ASSERT(src->width == dst->width && src->height == dst->height && src->depth == dst->depth);
3454 int h = src->height;
3455 int depth = src->depth;
3457 if (src->depth == 1) {
3462 if (vertical && !horizontal) {
3464 do_flip(dst, src, w, h, depth);
3468 int dstX0 = 0, dstXIncr = 1;
3469 int dstY0 = 0, dstYIncr = 1;
3483 do_mirror_data<QRgbaFloat32>(dst, src, dstX0, dstY0, dstXIncr, dstYIncr, w, h);
3486 do_mirror_data<quint64>(dst, src, dstX0, dstY0, dstXIncr, dstYIncr, w, h);
3489 do_mirror_data<quint32>(dst, src, dstX0, dstY0, dstXIncr, dstYIncr, w, h);
3492 do_mirror_data<quint24>(dst, src, dstX0, dstY0, dstXIncr, dstYIncr, w, h);
3495 do_mirror_data<quint16>(dst, src, dstX0, dstY0, dstXIncr, dstYIncr, w, h);
3498 do_mirror_data<quint8>(dst, src, dstX0, dstY0, dstXIncr, dstYIncr, w, h);
3507 if (horizontal && dst->depth == 1) {
3508 Q_ASSERT(dst->format == QImage::Format_Mono || dst->format == QImage::Format_MonoLSB);
3509 const int shift = 8 - (dst->width % 8);
3510 const uchar *bitflip = qt_get_bitflip_array();
3511 for (
int y = 0; y < h; ++y) {
3512 uchar *begin = dst->data + y * dst->bytes_per_line;
3513 uchar *end = begin + dst->bytes_per_line;
3514 for (uchar *p = begin; p < end; ++p) {
3518 if (shift != 8 && p != begin) {
3519 if (dst->format == QImage::Format_Mono) {
3520 for (
int i = 0; i < shift; ++i) {
3522 p[-1] |= (*p & (128 >> i)) >> (7 - i);
3525 for (
int i = 0; i < shift; ++i) {
3527 p[-1] |= (*p & (1 << i)) << (7 - i);
3533 if (dst->format == QImage::Format_Mono)
3543
3544
3545QImage QImage::mirrored_helper(
bool horizontal,
bool vertical)
const
3550 if ((d->width <= 1 && d->height <= 1) || (!horizontal && !vertical))
3554 QImage result(d->width, d->height, d->format);
3561 result.d->colortable = d->colortable;
3562 result.d->has_alpha_clut = d->has_alpha_clut;
3563 copyMetadata(result.d, d);
3565 do_mirror(result.d, d, horizontal, vertical);
3571
3572
3573void QImage::mirrored_inplace(
bool horizontal,
bool vertical)
3575 if (!d || (d->width <= 1 && d->height <= 1) || (!horizontal && !vertical))
3584 do_mirror(d, d, horizontal, vertical);
3588
3589
3590
3591
3592
3593
3594
3595
3596
3597
3598
3601
3602
3603
3604
3605
3606
3607
3608
3610static inline void rgbSwapped_generic(
int width,
int height,
const QImage *src, QImage *dst,
const QPixelLayout* layout)
3612 const RbSwapFunc func = layout->rbSwap;
3614 qWarning(
"Trying to rb-swap an image format where it doesn't make sense");
3620 for (
int i = 0; i < height; ++i) {
3621 uchar *q = dst->scanLine(i);
3622 const uchar *p = src->constScanLine(i);
3628
3629
3630QImage Q_TRACE_INSTRUMENT(qtgui) QImage::rgbSwapped_helper()
const
3635 Q_TRACE_SCOPE(QImage_rgbSwapped_helper);
3639 switch (d->format) {
3640 case Format_Invalid:
3645 case Format_Grayscale8:
3646 case Format_Grayscale16:
3649 case Format_MonoLSB:
3650 case Format_Indexed8:
3652 for (
int i = 0; i < res.d->colortable.size(); i++) {
3653 QRgb c = res.d->colortable.at(i);
3654 res.d->colortable[i] = QRgb(((c << 16) & 0xff0000) | ((c >> 16) & 0xff) | (c & 0xff00ff00));
3657 case Format_RGBX8888:
3658 case Format_RGBA8888:
3659 case Format_RGBA8888_Premultiplied:
3660#if Q_BYTE_ORDER == Q_BIG_ENDIAN
3661 res = QImage(d->width, d->height, d->format);
3663 for (
int i = 0; i < d->height; i++) {
3664 uint *q = (uint*)res.scanLine(i);
3665 const uint *p = (
const uint*)constScanLine(i);
3666 const uint *end = p + d->width;
3669 *q = ((c << 16) & 0xff000000) | ((c >> 16) & 0xff00) | (c & 0x00ff00ff);
3681 case Format_ARGB32_Premultiplied:
3682 res = QImage(d->width, d->height, d->format);
3684 for (
int i = 0; i < d->height; i++) {
3685 uint *q = (uint*)res.scanLine(i);
3686 const uint *p = (
const uint*)constScanLine(i);
3687 const uint *end = p + d->width;
3690 *q = ((c << 16) & 0xff0000) | ((c >> 16) & 0xff) | (c & 0xff00ff00);
3697 res = QImage(d->width, d->height, d->format);
3699 for (
int i = 0; i < d->height; i++) {
3700 ushort *q = (ushort*)res.scanLine(i);
3701 const ushort *p = (
const ushort*)constScanLine(i);
3702 const ushort *end = p + d->width;
3705 *q = ((c << 11) & 0xf800) | ((c >> 11) & 0x1f) | (c & 0x07e0);
3712 res = QImage(d->width, d->height, d->format);
3714 rgbSwapped_generic(d->width, d->height,
this, &res, &qPixelLayouts[d->format]);
3717 copyMetadata(res.d, d);
3722
3723
3724void QImage::rgbSwapped_inplace()
3735 switch (d->format) {
3736 case Format_Invalid:
3741 case Format_Grayscale8:
3742 case Format_Grayscale16:
3745 case Format_MonoLSB:
3746 case Format_Indexed8:
3747 for (
int i = 0; i < d->colortable.size(); i++) {
3748 QRgb c = d->colortable.at(i);
3749 d->colortable[i] = QRgb(((c << 16) & 0xff0000) | ((c >> 16) & 0xff) | (c & 0xff00ff00));
3752 case Format_RGBX8888:
3753 case Format_RGBA8888:
3754 case Format_RGBA8888_Premultiplied:
3755#if Q_BYTE_ORDER == Q_BIG_ENDIAN
3756 for (
int i = 0; i < d->height; i++) {
3757 uint *p = (uint*)scanLine(i);
3758 uint *end = p + d->width;
3761 *p = ((c << 16) & 0xff000000) | ((c >> 16) & 0xff00) | (c & 0x00ff00ff);
3772 case Format_ARGB32_Premultiplied:
3773 for (
int i = 0; i < d->height; i++) {
3774 uint *p = (uint*)scanLine(i);
3775 uint *end = p + d->width;
3778 *p = ((c << 16) & 0xff0000) | ((c >> 16) & 0xff) | (c & 0xff00ff00);
3784 for (
int i = 0; i < d->height; i++) {
3785 ushort *p = (ushort*)scanLine(i);
3786 ushort *end = p + d->width;
3789 *p = ((c << 11) & 0xf800) | ((c >> 11) & 0x1f) | (c & 0x07e0);
3795 case Format_A2BGR30_Premultiplied:
3797 case Format_A2RGB30_Premultiplied:
3798 for (
int i = 0; i < d->height; i++) {
3799 uint *p = (uint*)scanLine(i);
3800 uint *end = p + d->width;
3802 *p = qRgbSwapRgb30(*p);
3808 rgbSwapped_generic(d->width, d->height,
this,
this, &qPixelLayouts[d->format]);
3814
3815
3816
3817
3818
3819
3820
3821
3822
3823
3824
3825
3826
3827
3828
3829
3830
3832bool QImage::load(
const QString &fileName,
const char* format)
3834 *
this = QImageReader(fileName, format).read();
3839
3840
3841
3842
3843
3845bool QImage::load(QIODevice* device,
const char* format)
3847 *
this = QImageReader(device, format).read();
3852
3853
3854
3855
3856
3857
3858
3859
3860
3861
3862
3864bool QImage::loadFromData(QByteArrayView data,
const char *format)
3866 *
this = fromData(data, format);
3871
3872
3873
3874
3875
3876
3878bool QImage::loadFromData(
const uchar *buf,
int len,
const char *format)
3880 return loadFromData(QByteArrayView(buf, len), format);
3884
3885
3886
3887
3888
3889
3892
3893
3894
3895
3896
3897
3898
3899
3900
3901
3902
3903
3904
3906QImage QImage::fromData(QByteArrayView data,
const char *format)
3908 QByteArray a = QByteArray::fromRawData(data.constData(), data.size());
3911 b.open(QIODevice::ReadOnly);
3912 return QImageReader(&b, format).read();
3916
3917
3918
3919
3920
3921
3923QImage QImage::fromData(
const uchar *data,
int size,
const char *format)
3925 return fromData(QByteArrayView(data, size), format);
3929
3930
3931
3932
3933
3934
3935
3938
3939
3940
3941
3942
3943
3944
3945
3946
3947
3948
3949
3950
3951
3952
3953bool QImage::save(
const QString &fileName,
const char *format,
int quality)
const
3957 QImageWriter writer(fileName, format);
3958 return d->doImageIO(
this, &writer, quality);
3962
3963
3964
3965
3966
3967
3968
3969
3970
3972bool QImage::save(QIODevice* device,
const char* format,
int quality)
const
3976 QImageWriter writer(device, format);
3977 return d->doImageIO(
this, &writer, quality);
3981
3983bool QImageData::doImageIO(
const QImage *image, QImageWriter *writer,
int quality)
const
3985 if (quality > 100 || quality < -1)
3986 qWarning(
"QImage::save: Quality out of range [-1, 100]");
3988 writer->setQuality(qMin(quality,100));
3989 const bool result = writer->write(*image);
3992 qWarning(
"QImage::save: failed to write image - %s", qPrintable(writer->errorString()));
3998
3999
4000#if !defined(QT_NO_DATASTREAM)
4002
4003
4004
4005
4006
4007
4008
4009
4010
4012QDataStream &operator<<(QDataStream &s,
const QImage &image)
4014 if (s.version() >= 5) {
4015 if (image.isNull()) {
4023 QImageWriter writer(s.device(), s.version() == 1 ?
"bmp" :
"png");
4024 writer.write(image);
4029
4030
4031
4032
4033
4034
4035
4036
4038QDataStream &operator>>(QDataStream &s, QImage &image)
4040 if (s.version() >= 5) {
4048 image = QImageReader(s.device(), s.version() == 1 ?
"bmp" :
"png").read();
4049 if (image.isNull() && s.version() >= 5)
4050 s.setStatus(QDataStream::ReadPastEnd);
4058
4059
4060
4061
4062
4063
4064
4065
4066
4067
4068
4070bool QImage::operator==(
const QImage & i)
const
4079 if (i.d->height != d->height || i.d->width != d->width || i.d->format != d->format || i.d->colorSpace != d->colorSpace)
4082 if (d->format != Format_RGB32) {
4083 if (d->format >= Format_ARGB32) {
4084 const int n = d->width * d->depth / 8;
4085 if (n == d->bytes_per_line && n == i.d->bytes_per_line) {
4086 if (memcmp(bits(), i.bits(), d->nbytes))
4089 for (
int y = 0; y < d->height; ++y) {
4090 if (memcmp(scanLine(y), i.scanLine(y), n))
4095 const int w = width();
4096 const int h = height();
4097 const QList<QRgb> &colortable = d->colortable;
4098 const QList<QRgb> &icolortable = i.d->colortable;
4099 for (
int y=0; y<h; ++y) {
4100 for (
int x=0; x<w; ++x) {
4101 if (colortable[pixelIndex(x, y)] != icolortable[i.pixelIndex(x, y)])
4108 for(
int l = 0; l < d->height; l++) {
4110 const uint *p1 =
reinterpret_cast<
const uint*>(scanLine(l));
4111 const uint *p2 =
reinterpret_cast<
const uint*>(i.scanLine(l));
4113 if ((*p1++ & 0x00ffffff) != (*p2++ & 0x00ffffff))
4123
4124
4125
4126
4127
4128
4129
4130
4131
4132
4133
4135bool QImage::operator!=(
const QImage & i)
const
4137 return !(*
this == i);
4144
4145
4146
4147
4148
4149
4150
4151int QImage::dotsPerMeterX()
const
4153 return d ? qRound(d->dpmx) : 0;
4157
4158
4159
4160
4161
4162
4163
4164int QImage::dotsPerMeterY()
const
4166 return d ? qRound(d->dpmy) : 0;
4170
4171
4172
4173
4174
4175
4176
4177
4178
4179
4180
4181void QImage::setDotsPerMeterX(
int x)
4183 if (!d || !x || d->dpmx == x)
4192
4193
4194
4195
4196
4197
4198
4199
4200
4201
4202
4203void QImage::setDotsPerMeterY(
int y)
4205 if (!d || !y || d->dpmy == y)
4214
4215
4216
4217
4218
4219
4220
4221QPoint QImage::offset()
const
4223 return d ? d->offset : QPoint();
4228
4229
4230
4231
4232
4233
4234
4235void QImage::setOffset(
const QPoint& p)
4237 if (!d || d->offset == p)
4246
4247
4248
4249
4250
4251
4252
4253QStringList QImage::textKeys()
const
4255 return d ? QStringList(d->text.keys()) : QStringList();
4259
4260
4261
4262
4263
4264
4265QString QImage::text(
const QString &key)
const
4271 return d->text.value(key);
4274 for (
auto it = d->text.begin(), end = d->text.end(); it != end; ++it)
4275 tmp += it.key() +
": "_L1 + it.value().simplified() +
"\n\n"_L1;
4282
4283
4284
4285
4286
4287
4288
4289
4290
4291
4292
4293
4294
4295
4296
4297
4298
4299
4300
4301
4302
4303
4304
4305void QImage::setText(
const QString &key,
const QString &value)
4312 d->text.insert(key, value);
4316
4317
4318
4319
4320QPaintEngine *QImage::paintEngine()
const
4325 if (!d->paintEngine) {
4326 QPaintDevice *paintDevice =
const_cast<QImage *>(
this);
4327 QPlatformIntegration *platformIntegration = QGuiApplicationPrivate::platformIntegration();
4328 if (platformIntegration)
4329 d->paintEngine = platformIntegration->createImagePaintEngine(paintDevice);
4330 if (!d->paintEngine)
4331 d->paintEngine =
new QRasterPaintEngine(paintDevice);
4334 return d->paintEngine;
4339
4340
4341
4342
4343int QImage::metric(PaintDeviceMetric metric)
const
4356 return qRound(d->width * 1000 / d->dpmx);
4359 return qRound(d->height * 1000 / d->dpmy);
4362 return d->colortable.size();
4368 return qRound(d->dpmx * 0.0254);
4372 return qRound(d->dpmy * 0.0254);
4375 case PdmPhysicalDpiX:
4376 return qRound(d->dpmx * 0.0254);
4379 case PdmPhysicalDpiY:
4380 return qRound(d->dpmy * 0.0254);
4383 case PdmDevicePixelRatio:
4384 return d->devicePixelRatio;
4387 case PdmDevicePixelRatioScaled:
4388 return d->devicePixelRatio * QPaintDevice::devicePixelRatioFScale();
4391 case PdmDevicePixelRatioF_EncodedA:
4393 case PdmDevicePixelRatioF_EncodedB:
4394 return QPaintDevice::encodeMetricF(metric, d->devicePixelRatio);
4398 qWarning(
"QImage::metric(): Unhandled metric type %d", metric);
4407
4408
4410
4411
4412
4413
4414
4415
4416
4417
4418
4419
4420
4421
4422
4423
4424
4425
4426
4427
4430#define IWX_MSB(b) if (trigx < maxws && trigy < maxhs) {
4431 if (*(sptr+sbpl*(trigy>>12
)+(trigx>>15
)) &
4432 (1
<< (7
-((trigx>>12
)&7
))))
4439#define IWX_LSB(b) if (trigx < maxws && trigy < maxhs) {
4440 if (*(sptr+sbpl*(trigy>>12
)+(trigx>>15
)) &
4441 (1
<< ((trigx>>12
)&7
)))
4448#define IWX_PIX(b) if (trigx < maxws && trigy < maxhs) {
4449 if ((*(sptr+sbpl*(trigy>>12
)+(trigx>>15
)) &
4450 (1
<< (7
-((trigx>>12
)&7
)))) == 0
)
4457bool qt_xForm_helper(
const QTransform &trueMat,
int xoffset,
int type,
int depth,
4458 uchar *dptr, qsizetype dbpl,
int p_inc,
int dHeight,
4459 const uchar *sptr, qsizetype sbpl,
int sWidth,
int sHeight)
4461 int m11 =
int(trueMat.m11()*4096.0);
4462 int m12 =
int(trueMat.m12()*4096.0);
4463 int m21 =
int(trueMat.m21()*4096.0);
4464 int m22 =
int(trueMat.m22()*4096.0);
4465 int dx = qRound(trueMat.dx()*4096.0);
4466 int dy = qRound(trueMat.dy()*4096.0);
4468 int m21ydx = dx + (xoffset<<16) + (m11 + m21) / 2;
4469 int m22ydy = dy + (m12 + m22) / 2;
4472 uint maxws = sWidth<<12;
4473 uint maxhs = sHeight<<12;
4475 for (
int y=0; y<dHeight; y++) {
4478 uchar *maxp = dptr + dbpl;
4482 while (dptr < maxp) {
4483 if (trigx < maxws && trigy < maxhs)
4484 *dptr = *(sptr+sbpl*(trigy>>12)+(trigx>>12));
4492 while (dptr < maxp) {
4493 if (trigx < maxws && trigy < maxhs)
4494 *((ushort*)dptr) = *((
const ushort *)(sptr+sbpl*(trigy>>12) +
4504 while (dptr < maxp) {
4505 if (trigx < maxws && trigy < maxhs) {
4506 const uchar *p2 = sptr+sbpl*(trigy>>12) + ((trigx>>12)*3);
4518 while (dptr < maxp) {
4519 if (trigx < maxws && trigy < maxhs)
4520 *((uint*)dptr) = *((
const uint *)(sptr+sbpl*(trigy>>12) +
4535 while (dptr < maxp) {
4548 while (dptr < maxp) {
4573
4574
4575
4576
4577
4578
4579qint64 QImage::cacheKey()
const
4584 return (((qint64) d->ser_no) << 32) | ((qint64) d->detach_no);
4588
4589
4590
4591
4592
4593
4595bool QImage::isDetached()
const
4597 return d && d->ref.loadRelaxed() == 1;
4602
4603
4604
4605
4606
4607
4608
4609
4610
4611
4612
4613
4614
4615
4616
4617
4618
4620void QImage::setAlphaChannel(
const QImage &alphaChannel)
4622 if (!d || alphaChannel.isNull())
4625 if (d->paintEngine && d->paintEngine->isActive()) {
4626 qWarning(
"QImage::setAlphaChannel: "
4627 "Unable to set alpha channel while image is being painted on");
4631 const Format alphaFormat = qt_alphaVersionForPainting(d->format);
4632 if (d->format == alphaFormat)
4635 convertTo(alphaFormat);
4641 if (alphaChannel.format() == QImage::Format_Alpha8 || (alphaChannel.d->depth == 8 && alphaChannel.isGrayscale()))
4642 sourceImage = alphaChannel;
4644 sourceImage = alphaChannel.convertToFormat(QImage::Format_Grayscale8);
4645 if (!sourceImage.reinterpretAsFormat(QImage::Format_Alpha8))
4648 QPainter painter(
this);
4649 if (sourceImage.size() != size())
4650 painter.setRenderHint(QPainter::SmoothPixmapTransform);
4651 painter.setCompositionMode(QPainter::CompositionMode_DestinationIn);
4652 painter.drawImage(rect(), sourceImage);
4656
4657
4658
4659
4660
4661bool QImage::hasAlphaChannel()
const
4665 const QPixelFormat format = pixelFormat();
4666 if (format.alphaUsage() == QPixelFormat::UsesAlpha)
4668 if (format.colorModel() == QPixelFormat::Indexed)
4669 return d->has_alpha_clut;
4674
4675
4676
4677
4678
4679
4680
4681
4682
4683int QImage::bitPlaneCount()
const
4688 switch (d->format) {
4689 case QImage::Format_Invalid:
4691 case QImage::Format_BGR30:
4692 case QImage::Format_RGB30:
4695 case QImage::Format_RGB32:
4696 case QImage::Format_RGBX8888:
4699 case QImage::Format_RGB666:
4702 case QImage::Format_RGB555:
4705 case QImage::Format_ARGB8555_Premultiplied:
4708 case QImage::Format_RGB444:
4711 case QImage::Format_RGBX64:
4712 case QImage::Format_RGBX16FPx4:
4715 case QImage::Format_RGBX32FPx4:
4719 bpc = qt_depthForFormat(d->format);
4726
4727
4728
4729
4730
4731
4732
4733
4734
4735
4736QImage QImage::smoothScaled(
int w,
int h)
const
4739 switch (src.format()) {
4740 case QImage::Format_RGB32:
4741 case QImage::Format_ARGB32_Premultiplied:
4742#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
4743 case QImage::Format_RGBX8888:
4745 case QImage::Format_RGBA8888_Premultiplied:
4746#if QT_CONFIG(raster_64bit)
4747 case QImage::Format_RGBX64:
4748 case QImage::Format_RGBA64_Premultiplied:
4750 case QImage::Format_RGBA64:
4751 case QImage::Format_Grayscale16:
4752 src.convertTo(QImage::Format_RGBA64_Premultiplied);
4755#if QT_CONFIG(raster_fp)
4756 case QImage::Format_RGBX32FPx4:
4757 case QImage::Format_RGBA32FPx4_Premultiplied:
4759 case QImage::Format_RGBX16FPx4:
4760 src.convertTo(QImage::Format_RGBX32FPx4);
4762 case QImage::Format_RGBA16FPx4:
4763 case QImage::Format_RGBA16FPx4_Premultiplied:
4764 case QImage::Format_RGBA32FPx4:
4765 src.convertTo(QImage::Format_RGBA32FPx4_Premultiplied);
4768 case QImage::Format_CMYK8888:
4771 if (src.hasAlphaChannel())
4772 src.convertTo(QImage::Format_ARGB32_Premultiplied);
4774 src.convertTo(QImage::Format_RGB32);
4776 src = qSmoothScaleImage(src, w, h);
4778 copyMetadata(src.d, d);
4782static QImage rotated90(
const QImage &image)
4784 QImage out(image.height(), image.width(), image.format());
4787 copyMetadata(QImageData::get(out), QImageData::get(image));
4788 if (image.colorCount() > 0)
4789 out.setColorTable(image.colorTable());
4790 int w = image.width();
4791 int h = image.height();
4792 const MemRotateFunc memrotate = qMemRotateFunctions[qPixelLayouts[image.format()].bpp][2];
4794 memrotate(image.constBits(), w, h, image.bytesPerLine(), out.bits(), out.bytesPerLine());
4796 for (
int y=0; y<h; ++y) {
4797 if (image.colorCount())
4798 for (
int x=0; x<w; ++x)
4799 out.setPixel(h-y-1, x, image.pixelIndex(x, y));
4801 for (
int x=0; x<w; ++x)
4802 out.setPixel(h-y-1, x, image.pixel(x, y));
4808static QImage rotated180(
const QImage &image)
4810 const MemRotateFunc memrotate = qMemRotateFunctions[qPixelLayouts[image.format()].bpp][1];
4812 return image.flipped(Qt::Horizontal | Qt::Vertical);
4814 QImage out(image.width(), image.height(), image.format());
4817 copyMetadata(QImageData::get(out), QImageData::get(image));
4818 if (image.colorCount() > 0)
4819 out.setColorTable(image.colorTable());
4820 int w = image.width();
4821 int h = image.height();
4822 memrotate(image.constBits(), w, h, image.bytesPerLine(), out.bits(), out.bytesPerLine());
4826static QImage rotated270(
const QImage &image)
4828 QImage out(image.height(), image.width(), image.format());
4831 copyMetadata(QImageData::get(out), QImageData::get(image));
4832 if (image.colorCount() > 0)
4833 out.setColorTable(image.colorTable());
4834 int w = image.width();
4835 int h = image.height();
4836 const MemRotateFunc memrotate = qMemRotateFunctions[qPixelLayouts[image.format()].bpp][0];
4838 memrotate(image.constBits(), w, h, image.bytesPerLine(), out.bits(), out.bytesPerLine());
4840 for (
int y=0; y<h; ++y) {
4841 if (image.colorCount())
4842 for (
int x=0; x<w; ++x)
4843 out.setPixel(y, w-x-1, image.pixelIndex(x, y));
4845 for (
int x=0; x<w; ++x)
4846 out.setPixel(y, w-x-1, image.pixel(x, y));
4853
4854
4855
4856
4857
4858
4859
4860
4861
4862
4863
4864
4865
4866
4867
4868
4869
4870
4871
4872
4873
4874
4876QImage Q_TRACE_INSTRUMENT(qtgui) QImage::transformed(
const QTransform &matrix, Qt::TransformationMode mode )
const
4881 Q_TRACE_PARAM_REPLACE(
const QTransform &,
double[9]);
4882 Q_TRACE_SCOPE(QImage_transformed, QList<
double>({matrix.m11(), matrix.m12(), matrix.m13(),
4883 matrix.m21(), matrix.m22(), matrix.m23(),
4884 matrix.m31(), matrix.m32(), matrix.m33()}).data(), mode);
4887 const int ws = width();
4888 const int hs = height();
4895 QTransform mat = trueMatrix(matrix, ws, hs);
4896 bool complex_xform =
false;
4897 bool scale_xform =
false;
4898 bool nonpaintable_scale_xform =
false;
4899 if (mat.type() <= QTransform::TxScale) {
4900 if (mat.type() == QTransform::TxNone)
4902 else if (mat.m11() == -1. && mat.m22() == -1.)
4903 return rotated180(*
this);
4905 hd = qRound(qAbs(mat.m22()) * hs);
4906 wd = qRound(qAbs(mat.m11()) * ws);
4910 if (hd * 2 < hs || wd * 2 < ws)
4911 nonpaintable_scale_xform =
true;
4913 if (format() == QImage::Format_CMYK8888)
4914 nonpaintable_scale_xform =
true;
4916 if (mat.type() <= QTransform::TxRotate && mat.m11() == 0 && mat.m22() == 0) {
4917 if (mat.m12() == 1. && mat.m21() == -1.)
4918 return rotated90(*
this);
4919 else if (mat.m12() == -1. && mat.m21() == 1.)
4920 return rotated270(*
this);
4923 QPolygonF a(QRectF(0, 0, ws, hs));
4925 QRect r = a.boundingRect().toAlignedRect();
4928 complex_xform =
true;
4931 if (wd == 0 || hd == 0)
4934 if (scale_xform && mode == Qt::SmoothTransformation) {
4936 case QImage::Format_RGB32:
4937 case QImage::Format_ARGB32_Premultiplied:
4938#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
4939 case QImage::Format_RGBX8888:
4941 case QImage::Format_RGBA8888_Premultiplied:
4942#if QT_CONFIG(raster_64bit)
4943 case QImage::Format_RGBX64:
4944 case QImage::Format_RGBA64_Premultiplied:
4946 case QImage::Format_CMYK8888:
4948 if (mat.m11() > 0.0F && mat.m22() > 0.0F)
4949 return smoothScaled(wd, hd);
4955 if (nonpaintable_scale_xform
4956#if QT_CONFIG(qtgui_threadpool)
4957 || (ws * hs) >= (1<<20)
4961 if (mat.m11() < 0.0F && mat.m22() < 0.0F) {
4962 scaledImage = smoothScaled(wd, hd).flipped(Qt::Horizontal | Qt::Vertical);
4963 }
else if (mat.m11() < 0.0F) {
4964 scaledImage = smoothScaled(wd, hd).flipped(Qt::Horizontal);
4965 }
else if (mat.m22() < 0.0F) {
4966 scaledImage = smoothScaled(wd, hd).flipped(Qt::Vertical);
4968 scaledImage = smoothScaled(wd, hd);
4972 case QImage::Format_Mono:
4973 case QImage::Format_MonoLSB:
4974 case QImage::Format_Indexed8:
4977 return scaledImage.convertToFormat(format());
4984 qsizetype sbpl = bytesPerLine();
4985 const uchar *sptr = bits();
4987 QImage::Format target_format = d->format;
4989 if (complex_xform || mode == Qt::SmoothTransformation) {
4990 if (d->format < QImage::Format_RGB32 || (!hasAlphaChannel() && complex_xform)) {
4991 target_format = qt_alphaVersion(d->format);
4995 QImage dImage(wd, hd, target_format);
4998 if (target_format == QImage::Format_MonoLSB
4999 || target_format == QImage::Format_Mono
5000 || target_format == QImage::Format_Indexed8) {
5001 dImage.d->colortable = d->colortable;
5002 dImage.d->has_alpha_clut = d->has_alpha_clut | complex_xform;
5006 if (target_format == QImage::Format_Indexed8) {
5007 if (dImage.d->colortable.size() < 256) {
5009 dImage.d->colortable.append(0x0);
5010 memset(dImage.bits(), dImage.d->colortable.size() - 1, dImage.d->nbytes);
5012 memset(dImage.bits(), 0, dImage.d->nbytes);
5015 memset(dImage.bits(), 0x00, dImage.d->nbytes);
5017 if (target_format >= QImage::Format_RGB32 && target_format != QImage::Format_CMYK8888) {
5019 QImage sImage = (devicePixelRatio() != 1) ? QImage(constBits(), width(), height(), format()) : *
this;
5021 && (d->format == QImage::Format_MonoLSB
5022 || d->format == QImage::Format_Mono
5023 || d->format == QImage::Format_Indexed8)) {
5024 sImage.d->colortable = d->colortable;
5025 sImage.d->has_alpha_clut = d->has_alpha_clut;
5028 Q_ASSERT(sImage.devicePixelRatio() == 1);
5029 Q_ASSERT(sImage.devicePixelRatio() == dImage.devicePixelRatio());
5031 QPainter p(&dImage);
5032 if (mode == Qt::SmoothTransformation) {
5033 p.setRenderHint(QPainter::Antialiasing);
5034 p.setRenderHint(QPainter::SmoothPixmapTransform);
5036 p.setTransform(mat);
5037 p.drawImage(QPoint(0, 0), sImage);
5040 mat = mat.inverted(&invertible);
5046 qsizetype dbpl = dImage.bytesPerLine();
5047 qt_xForm_helper(mat, 0, type, bpp, dImage.bits(), dbpl, 0, hd, sptr, sbpl, ws, hs);
5049 copyMetadata(dImage.d, d);
5056
5057
5058
5059
5060
5061
5062
5063
5064
5065
5066
5067
5068
5069
5070
5071
5072
5073
5075QTransform QImage::trueMatrix(
const QTransform &matrix,
int w,
int h)
5077 const QRectF rect(0, 0, w, h);
5078 const QRect mapped = matrix.mapRect(rect).toAlignedRect();
5079 const QPoint delta = mapped.topLeft();
5080 return matrix * QTransform().translate(-delta.x(), -delta.y());
5084
5085
5086
5087
5088
5089
5090void QImage::setColorSpace(
const QColorSpace &colorSpace)
5094 if (d->colorSpace == colorSpace)
5096 if (colorSpace.isValid() && !qt_compatibleColorModelSource(pixelFormat().colorModel(), colorSpace.colorModel()))
5099 detachMetadata(
false);
5101 d->colorSpace = colorSpace;
5105
5106
5107
5108
5109
5110
5111
5112
5113
5114
5115
5116void QImage::convertToColorSpace(
const QColorSpace &colorSpace)
5118 if (!d || !d->colorSpace.isValid())
5120 if (!colorSpace.isValidTarget()) {
5121 qWarning() <<
"QImage::convertToColorSpace: Output colorspace is not valid";
5124 if (d->colorSpace == colorSpace)
5126 if (!qt_compatibleColorModelTarget(pixelFormat().colorModel(),
5127 colorSpace.colorModel(), colorSpace.transformModel())) {
5128 *
this = convertedToColorSpace(colorSpace);
5131 applyColorTransform(d->colorSpace.transformationToColorSpace(colorSpace));
5132 if (d->ref.loadRelaxed() != 1)
5133 detachMetadata(
false);
5134 d->colorSpace = colorSpace;
5138
5139
5140
5141
5142
5143
5144
5145
5146
5147
5148
5149
5150void QImage::convertToColorSpace(
const QColorSpace &colorSpace, QImage::Format format, Qt::ImageConversionFlags flags)
5152 if (!d || !d->colorSpace.isValid())
5154 if (!colorSpace.isValidTarget()) {
5155 qWarning() <<
"QImage::convertToColorSpace: Output colorspace is not valid";
5158 if (!qt_compatibleColorModelTarget(toPixelFormat(format).colorModel(),
5159 colorSpace.colorModel(), colorSpace.transformModel())) {
5160 qWarning() <<
"QImage::convertToColorSpace: Color space is not compatible with format";
5164 if (d->colorSpace == colorSpace)
5165 return convertTo(format, flags);
5166 applyColorTransform(d->colorSpace.transformationToColorSpace(colorSpace), format, flags);
5167 d->colorSpace = colorSpace;
5171
5172
5173
5174
5175
5176
5177
5178
5179
5180
5181
5182
5183
5184QImage QImage::convertedToColorSpace(
const QColorSpace &colorSpace)
const
5186 if (!d || !d->colorSpace.isValid())
5188 if (!colorSpace.isValidTarget()) {
5189 qWarning() <<
"QImage::convertedToColorSpace: Output colorspace is not valid";
5192 if (d->colorSpace == colorSpace)
5194 QImage image = colorTransformed(d->colorSpace.transformationToColorSpace(colorSpace));
5195 image.setColorSpace(colorSpace);
5200
5201
5202
5203
5204
5205
5206
5207
5208
5209
5210
5211
5212
5213QImage QImage::convertedToColorSpace(
const QColorSpace &colorSpace, QImage::Format format, Qt::ImageConversionFlags flags)
const &
5215 if (!d || !d->colorSpace.isValid())
5217 if (!colorSpace.isValidTarget()) {
5218 qWarning() <<
"QImage::convertedToColorSpace: Output colorspace is not valid";
5221 if (!qt_compatibleColorModelTarget(toPixelFormat(format).colorModel(),
5222 colorSpace.colorModel(), colorSpace.transformModel())) {
5223 qWarning() <<
"QImage::convertedToColorSpace: Color space is not compatible with format";
5226 if (d->colorSpace == colorSpace)
5227 return convertedTo(format, flags);
5228 QImage image = colorTransformed(d->colorSpace.transformationToColorSpace(colorSpace), format, flags);
5229 image.setColorSpace(colorSpace);
5233QImage QImage::convertedToColorSpace(
const QColorSpace &colorSpace, QImage::Format format, Qt::ImageConversionFlags flags) &&
5235 if (!d || !d->colorSpace.isValid())
5237 if (!colorSpace.isValidTarget()) {
5238 qWarning() <<
"QImage::convertedToColorSpace: Output colorspace is not valid";
5241 if (!qt_compatibleColorModelTarget(toPixelFormat(format).colorModel(),
5242 colorSpace.colorModel(), colorSpace.transformModel())) {
5243 qWarning() <<
"QImage::convertedToColorSpace: Color space is not compatible with format";
5246 if (d->colorSpace == colorSpace)
5247 return convertedTo(format, flags);
5248 applyColorTransform(d->colorSpace.transformationToColorSpace(colorSpace), format, flags);
5249 return std::move(*
this);
5253
5254
5255
5256
5257QColorSpace QImage::colorSpace()
const
5260 return QColorSpace();
5261 return d->colorSpace;
5265
5266
5267
5268
5269void QImage::applyColorTransform(
const QColorTransform &transform)
5271 if (transform.isIdentity())
5274 if (!qt_compatibleColorModelSource(pixelFormat().colorModel(), QColorTransformPrivate::get(transform)->colorSpaceIn->colorModel) ||
5275 !qt_compatibleColorModelTarget(pixelFormat().colorModel(), QColorTransformPrivate::get(transform)->colorSpaceOut->colorModel,
5276 QColorTransformPrivate::get(transform)->colorSpaceOut->transformModel)) {
5277 qWarning() <<
"QImage::applyColorTransform can not apply format switching transform without switching format";
5284 if (pixelFormat().colorModel() == QPixelFormat::Indexed) {
5285 for (
int i = 0; i < d->colortable.size(); ++i)
5286 d->colortable[i] = transform.map(d->colortable[i]);
5289 QImage::Format oldFormat = format();
5290 if (qt_fpColorPrecision(oldFormat)) {
5291 if (oldFormat != QImage::Format_RGBX32FPx4 && oldFormat != QImage::Format_RGBA32FPx4
5292 && oldFormat != QImage::Format_RGBA32FPx4_Premultiplied)
5293 convertTo(QImage::Format_RGBA32FPx4);
5294 }
else if (depth() > 32) {
5295 if (oldFormat != QImage::Format_RGBX64 && oldFormat != QImage::Format_RGBA64
5296 && oldFormat != QImage::Format_RGBA64_Premultiplied)
5297 convertTo(QImage::Format_RGBA64);
5298 }
else if (oldFormat != QImage::Format_ARGB32 && oldFormat != QImage::Format_RGB32
5299 && oldFormat != QImage::Format_ARGB32_Premultiplied && oldFormat != QImage::Format_CMYK8888
5300 && oldFormat != QImage::Format_Grayscale8 && oldFormat != QImage::Format_Grayscale16) {
5301 if (hasAlphaChannel())
5302 convertTo(QImage::Format_ARGB32);
5304 convertTo(QImage::Format_RGB32);
5307 QColorTransformPrivate::TransformFlags flags = QColorTransformPrivate::Unpremultiplied;
5309 case Format_ARGB32_Premultiplied:
5310 case Format_RGBA64_Premultiplied:
5311 case Format_RGBA32FPx4_Premultiplied:
5312 flags = QColorTransformPrivate::Premultiplied;
5314 case Format_Grayscale8:
5315 case Format_Grayscale16:
5317 case Format_CMYK8888:
5319 case Format_RGBX32FPx4:
5320 flags = QColorTransformPrivate::InputOpaque;
5324 case Format_RGBA32FPx4:
5330 std::function<
void(
int,
int)> transformSegment;
5332 if (format() == Format_Grayscale8) {
5333 transformSegment = [&](
int yStart,
int yEnd) {
5334 for (
int y = yStart; y < yEnd; ++y) {
5335 uint8_t *scanline =
reinterpret_cast<uint8_t *>(d->data + y * d->bytes_per_line);
5336 QColorTransformPrivate::get(transform)->apply(scanline, scanline, width(), flags);
5339 }
else if (format() == Format_Grayscale16) {
5340 transformSegment = [&](
int yStart,
int yEnd) {
5341 for (
int y = yStart; y < yEnd; ++y) {
5342 uint16_t *scanline =
reinterpret_cast<uint16_t *>(d->data + y * d->bytes_per_line);
5343 QColorTransformPrivate::get(transform)->apply(scanline, scanline, width(), flags);
5346 }
else if (qt_fpColorPrecision(format())) {
5347 transformSegment = [&](
int yStart,
int yEnd) {
5348 for (
int y = yStart; y < yEnd; ++y) {
5349 QRgbaFloat32 *scanline =
reinterpret_cast<QRgbaFloat32 *>(d->data + y * d->bytes_per_line);
5350 QColorTransformPrivate::get(transform)->apply(scanline, scanline, width(), flags);
5353 }
else if (depth() > 32) {
5354 transformSegment = [&](
int yStart,
int yEnd) {
5355 for (
int y = yStart; y < yEnd; ++y) {
5356 QRgba64 *scanline =
reinterpret_cast<QRgba64 *>(d->data + y * d->bytes_per_line);
5357 QColorTransformPrivate::get(transform)->apply(scanline, scanline, width(), flags);
5360 }
else if (oldFormat == QImage::Format_CMYK8888) {
5361 transformSegment = [&](
int yStart,
int yEnd) {
5362 for (
int y = yStart; y < yEnd; ++y) {
5363 QCmyk32 *scanline =
reinterpret_cast<QCmyk32 *>(d->data + y * d->bytes_per_line);
5364 QColorTransformPrivate::get(transform)->apply(scanline, scanline, width(), flags);
5368 transformSegment = [&](
int yStart,
int yEnd) {
5369 for (
int y = yStart; y < yEnd; ++y) {
5370 QRgb *scanline =
reinterpret_cast<QRgb *>(d->data + y * d->bytes_per_line);
5371 QColorTransformPrivate::get(transform)->apply(scanline, scanline, width(), flags);
5376#if QT_CONFIG(qtgui_threadpool)
5377 int segments = (qsizetype(width()) * height()) >> 16;
5378 segments = std::min(segments, height());
5379 QThreadPool *threadPool = QGuiApplicationPrivate::qtGuiThreadPool();
5380 if (segments > 1 && threadPool && !threadPool->contains(QThread::currentThread())) {
5381 QLatch latch(segments);
5383 for (
int i = 0; i < segments; ++i) {
5384 int yn = (height() - y) / (segments - i);
5385 threadPool->start([&, y, yn]() {
5386 transformSegment(y, y + yn);
5394 transformSegment(0, height());
5396 if (oldFormat != format())
5397 *
this = std::move(*
this).convertToFormat(oldFormat);
5401
5402
5403
5404
5405
5406
5407
5408void QImage::applyColorTransform(
const QColorTransform &transform, QImage::Format toFormat, Qt::ImageConversionFlags flags)
5412 if (transform.isIdentity())
5413 return convertTo(toFormat, flags);
5415 *
this = colorTransformed(transform, toFormat, flags);
5419
5420
5421
5422
5423
5424
5425
5426
5427
5428
5429
5430QImage QImage::colorTransformed(
const QColorTransform &transform)
const &
5434 if (transform.isIdentity())
5437 const QColorSpacePrivate *inColorSpace = QColorTransformPrivate::get(transform)->colorSpaceIn.constData();
5438 const QColorSpacePrivate *outColorSpace = QColorTransformPrivate::get(transform)->colorSpaceOut.constData();
5439 if (!qt_compatibleColorModelSource(pixelFormat().colorModel(), inColorSpace->colorModel)) {
5440 qWarning() <<
"QImage::colorTransformed: Invalid input color space for transform";
5443 if (!qt_compatibleColorModelTarget(pixelFormat().colorModel(), outColorSpace->colorModel, outColorSpace->transformModel)) {
5445 switch (outColorSpace->colorModel) {
5446 case QColorSpace::ColorModel::Rgb:
5447 return colorTransformed(transform, qt_highColorPrecision(format(),
true) ? QImage::Format_RGBX64 : QImage::Format_RGB32);
5448 case QColorSpace::ColorModel::Gray:
5449 return colorTransformed(transform, qt_highColorPrecision(format(),
true) ? QImage::Format_Grayscale16 : QImage::Format_Grayscale8);
5450 case QColorSpace::ColorModel::Cmyk:
5451 return colorTransformed(transform, QImage::Format_CMYK8888);
5452 case QColorSpace::ColorModel::Undefined:
5458 QImage image = copy();
5459 image.applyColorTransform(transform);
5463static bool isRgb32Data(QImage::Format f)
5466 case QImage::Format_RGB32:
5467 case QImage::Format_ARGB32:
5468 case QImage::Format_ARGB32_Premultiplied:
5476static bool isRgb64Data(QImage::Format f)
5479 case QImage::Format_RGBX64:
5480 case QImage::Format_RGBA64:
5481 case QImage::Format_RGBA64_Premultiplied:
5489static bool isRgb32fpx4Data(QImage::Format f)
5492 case QImage::Format_RGBX32FPx4:
5493 case QImage::Format_RGBA32FPx4:
5494 case QImage::Format_RGBA32FPx4_Premultiplied:
5503
5504
5505
5506
5507
5508
5509
5510
5511
5512
5513
5514
5515QImage QImage::colorTransformed(
const QColorTransform &transform, QImage::Format toFormat, Qt::ImageConversionFlags flags)
const &
5519 if (toFormat == QImage::Format_Invalid)
5520 toFormat = format();
5521 if (transform.isIdentity())
5522 return convertedTo(toFormat, flags);
5524 const QColorSpacePrivate *inColorSpace = QColorTransformPrivate::get(transform)->colorSpaceIn.constData();
5525 const QColorSpacePrivate *outColorSpace = QColorTransformPrivate::get(transform)->colorSpaceOut.constData();
5526 if (!qt_compatibleColorModelSource(pixelFormat().colorModel(), inColorSpace->colorModel)) {
5527 qWarning() <<
"QImage::colorTransformed: Invalid input color space for transform";
5530 if (!qt_compatibleColorModelTarget(toPixelFormat(toFormat).colorModel(), outColorSpace->colorModel, outColorSpace->transformModel)) {
5531 qWarning() <<
"QImage::colorTransformed: Invalid output color space for transform";
5535 QImage fromImage = *
this;
5537 QImage::Format tmpFormat = toFormat;
5539 case QImage::Format_RGB32:
5540 case QImage::Format_ARGB32:
5541 case QImage::Format_ARGB32_Premultiplied:
5542 case QImage::Format_RGBX32FPx4:
5543 case QImage::Format_RGBA32FPx4:
5544 case QImage::Format_RGBA32FPx4_Premultiplied:
5545 case QImage::Format_RGBX64:
5546 case QImage::Format_RGBA64:
5547 case QImage::Format_RGBA64_Premultiplied:
5548 case QImage::Format_Grayscale8:
5549 case QImage::Format_Grayscale16:
5550 case QImage::Format_CMYK8888:
5553 case QImage::Format_RGB16:
5554 case QImage::Format_RGB444:
5555 case QImage::Format_RGB555:
5556 case QImage::Format_RGB666:
5557 case QImage::Format_RGB888:
5558 case QImage::Format_BGR888:
5559 case QImage::Format_RGBX8888:
5560 tmpFormat = QImage::Format_RGB32;
5562 case QImage::Format_Mono:
5563 case QImage::Format_MonoLSB:
5564 case QImage::Format_Indexed8:
5565 case QImage::Format_ARGB8565_Premultiplied:
5566 case QImage::Format_ARGB6666_Premultiplied:
5567 case QImage::Format_ARGB8555_Premultiplied:
5568 case QImage::Format_ARGB4444_Premultiplied:
5569 case QImage::Format_RGBA8888:
5570 case QImage::Format_RGBA8888_Premultiplied:
5571 tmpFormat = QImage::Format_ARGB32;
5573 case QImage::Format_BGR30:
5574 case QImage::Format_RGB30:
5575 tmpFormat = QImage::Format_RGBX64;
5577 case QImage::Format_A2BGR30_Premultiplied:
5578 case QImage::Format_A2RGB30_Premultiplied:
5579 tmpFormat = QImage::Format_RGBA64;
5581 case QImage::Format_RGBX16FPx4:
5582 case QImage::Format_RGBA16FPx4:
5583 case QImage::Format_RGBA16FPx4_Premultiplied:
5584 tmpFormat = QImage::Format_RGBA32FPx4;
5586 case QImage::Format_Alpha8:
5587 return convertedTo(QImage::Format_Alpha8);
5588 case QImage::Format_Invalid:
5589 case QImage::NImageFormats:
5593 QColorSpace::ColorModel inColorData = qt_csColorData(pixelFormat().colorModel());
5594 QColorSpace::ColorModel outColorData = qt_csColorData(toPixelFormat(toFormat).colorModel());
5596 if (inColorData != outColorData) {
5597 if (fromImage.format() == QImage::Format_Grayscale8 && outColorData == QColorSpace::ColorModel::Rgb)
5598 tmpFormat = QImage::Format_RGB32;
5599 else if (tmpFormat == QImage::Format_Grayscale8 && qt_highColorPrecision(fromImage.format()))
5600 tmpFormat = QImage::Format_Grayscale16;
5601 else if (fromImage.format() == QImage::Format_Grayscale16 && outColorData == QColorSpace::ColorModel::Rgb)
5602 tmpFormat = QImage::Format_RGBX64;
5604 if (tmpFormat == QImage::Format_Grayscale8 && fromImage.format() == QImage::Format_Grayscale16)
5605 tmpFormat = QImage::Format_Grayscale16;
5606 else if (qt_fpColorPrecision(fromImage.format()) && !qt_fpColorPrecision(tmpFormat))
5607 tmpFormat = QImage::Format_RGBA32FPx4;
5608 else if (isRgb32Data(tmpFormat) && qt_highColorPrecision(fromImage.format(),
true))
5609 tmpFormat = QImage::Format_RGBA64;
5612 QImage toImage(size(), tmpFormat);
5613 copyMetadata(&toImage, *
this);
5615 std::function<
void(
int,
int)> transformSegment;
5616 QColorTransformPrivate::TransformFlags transFlags = QColorTransformPrivate::Unpremultiplied;
5618 if (inColorData != outColorData) {
5620 if (inColorData == QColorSpace::ColorModel::Gray && outColorData == QColorSpace::ColorModel::Rgb) {
5622 if (format() == QImage::Format_Grayscale8) {
5623 transformSegment = [&](
int yStart,
int yEnd) {
5624 for (
int y = yStart; y < yEnd; ++y) {
5625 const quint8 *in_scanline =
reinterpret_cast<
const quint8 *>(d->data + y * d->bytes_per_line);
5626 QRgb *out_scanline =
reinterpret_cast<QRgb *>(toImage.d->data + y * toImage.bytesPerLine());
5627 QColorTransformPrivate::get(transform)->apply(out_scanline, in_scanline, width(), QColorTransformPrivate::InputOpaque);
5631 transformSegment = [&](
int yStart,
int yEnd) {
5632 for (
int y = yStart; y < yEnd; ++y) {
5633 const quint16 *in_scanline =
reinterpret_cast<
const quint16 *>(d->data + y * d->bytes_per_line);
5634 QRgba64 *out_scanline =
reinterpret_cast<QRgba64 *>(toImage.d->data + y * toImage.bytesPerLine());
5635 QColorTransformPrivate::get(transform)->apply(out_scanline, in_scanline, width(), QColorTransformPrivate::InputOpaque);
5639 }
else if (inColorData == QColorSpace::ColorModel::Gray && outColorData == QColorSpace::ColorModel::Cmyk) {
5641 if (format() == QImage::Format_Grayscale8) {
5642 transformSegment = [&](
int yStart,
int yEnd) {
5643 for (
int y = yStart; y < yEnd; ++y) {
5644 const quint8 *in_scanline =
reinterpret_cast<
const quint8 *>(d->data + y * d->bytes_per_line);
5645 QCmyk32 *out_scanline =
reinterpret_cast<QCmyk32 *>(toImage.d->data + y * toImage.bytesPerLine());
5646 QColorTransformPrivate::get(transform)->apply(out_scanline, in_scanline, width(), QColorTransformPrivate::InputOpaque);
5650 transformSegment = [&](
int yStart,
int yEnd) {
5651 for (
int y = yStart; y < yEnd; ++y) {
5652 const quint16 *in_scanline =
reinterpret_cast<
const quint16 *>(d->data + y * d->bytes_per_line);
5653 QCmyk32 *out_scanline =
reinterpret_cast<QCmyk32 *>(toImage.d->data + y * toImage.bytesPerLine());
5654 QColorTransformPrivate::get(transform)->apply(out_scanline, in_scanline, width(), QColorTransformPrivate::InputOpaque);
5658 }
else if (inColorData == QColorSpace::ColorModel::Rgb && outColorData == QColorSpace::ColorModel::Gray) {
5660 if (tmpFormat == QImage::Format_Grayscale8) {
5661 fromImage.convertTo(QImage::Format_RGB32);
5662 transformSegment = [&](
int yStart,
int yEnd) {
5663 for (
int y = yStart; y < yEnd; ++y) {
5664 const QRgb *in_scanline =
reinterpret_cast<
const QRgb *>(fromImage.constBits() + y * fromImage.bytesPerLine());
5665 quint8 *out_scanline =
reinterpret_cast<quint8 *>(toImage.d->data + y * toImage.bytesPerLine());
5666 QColorTransformPrivate::get(transform)->apply(out_scanline, in_scanline, width(), QColorTransformPrivate::InputOpaque);
5670 fromImage.convertTo(QImage::Format_RGBX64);
5671 transformSegment = [&](
int yStart,
int yEnd) {
5672 for (
int y = yStart; y < yEnd; ++y) {
5673 const QRgba64 *in_scanline =
reinterpret_cast<
const QRgba64 *>(fromImage.constBits() + y * fromImage.bytesPerLine());
5674 quint16 *out_scanline =
reinterpret_cast<quint16 *>(toImage.d->data + y * toImage.bytesPerLine());
5675 QColorTransformPrivate::get(transform)->apply(out_scanline, in_scanline, width(), QColorTransformPrivate::InputOpaque);
5679 }
else if (inColorData == QColorSpace::ColorModel::Cmyk && outColorData == QColorSpace::ColorModel::Gray) {
5681 if (tmpFormat == QImage::Format_Grayscale8) {
5682 transformSegment = [&](
int yStart,
int yEnd) {
5683 for (
int y = yStart; y < yEnd; ++y) {
5684 const QCmyk32 *in_scanline =
reinterpret_cast<
const QCmyk32 *>(fromImage.constBits() + y * fromImage.bytesPerLine());
5685 quint8 *out_scanline =
reinterpret_cast<quint8 *>(toImage.d->data + y * toImage.bytesPerLine());
5686 QColorTransformPrivate::get(transform)->apply(out_scanline, in_scanline, width(), QColorTransformPrivate::InputOpaque);
5690 transformSegment = [&](
int yStart,
int yEnd) {
5691 for (
int y = yStart; y < yEnd; ++y) {
5692 const QCmyk32 *in_scanline =
reinterpret_cast<
const QCmyk32 *>(fromImage.constBits() + y * fromImage.bytesPerLine());
5693 quint16 *out_scanline =
reinterpret_cast<quint16 *>(toImage.d->data + y * toImage.bytesPerLine());
5694 QColorTransformPrivate::get(transform)->apply(out_scanline, in_scanline, width(), QColorTransformPrivate::InputOpaque);
5698 }
else if (inColorData == QColorSpace::ColorModel::Cmyk && outColorData == QColorSpace::ColorModel::Rgb) {
5700 if (isRgb32Data(tmpFormat) ) {
5701 transformSegment = [&](
int yStart,
int yEnd) {
5702 for (
int y = yStart; y < yEnd; ++y) {
5703 const QCmyk32 *in_scanline =
reinterpret_cast<
const QCmyk32 *>(fromImage.constBits() + y * fromImage.bytesPerLine());
5704 QRgb *out_scanline =
reinterpret_cast<QRgb *>(toImage.d->data + y * toImage.bytesPerLine());
5705 QColorTransformPrivate::get(transform)->apply(out_scanline, in_scanline, width(), QColorTransformPrivate::InputOpaque);
5708 }
else if (isRgb64Data(tmpFormat)) {
5709 transformSegment = [&](
int yStart,
int yEnd) {
5710 for (
int y = yStart; y < yEnd; ++y) {
5711 const QCmyk32 *in_scanline =
reinterpret_cast<
const QCmyk32 *>(fromImage.constBits() + y * fromImage.bytesPerLine());
5712 QRgba64 *out_scanline =
reinterpret_cast<QRgba64 *>(toImage.d->data + y * toImage.bytesPerLine());
5713 QColorTransformPrivate::get(transform)->apply(out_scanline, in_scanline, width(), QColorTransformPrivate::InputOpaque);
5717 Q_ASSERT(isRgb32fpx4Data(tmpFormat));
5718 transformSegment = [&](
int yStart,
int yEnd) {
5719 for (
int y = yStart; y < yEnd; ++y) {
5720 const QCmyk32 *in_scanline =
reinterpret_cast<
const QCmyk32 *>(fromImage.constBits() + y * fromImage.bytesPerLine());
5721 QRgbaFloat32 *out_scanline =
reinterpret_cast<QRgbaFloat32 *>(toImage.d->data + y * toImage.bytesPerLine());
5722 QColorTransformPrivate::get(transform)->apply(out_scanline, in_scanline, width(), QColorTransformPrivate::InputOpaque);
5726 }
else if (inColorData == QColorSpace::ColorModel::Rgb && outColorData == QColorSpace::ColorModel::Cmyk) {
5728 if (!fromImage.hasAlphaChannel())
5729 transFlags = QColorTransformPrivate::InputOpaque;
5730 else if (qPixelLayouts[fromImage.format()].premultiplied)
5731 transFlags = QColorTransformPrivate::Premultiplied;
5732 if (isRgb32Data(fromImage.format()) ) {
5733 transformSegment = [&](
int yStart,
int yEnd) {
5734 for (
int y = yStart; y < yEnd; ++y) {
5735 const QRgb *in_scanline =
reinterpret_cast<
const QRgb *>(fromImage.constBits() + y * fromImage.bytesPerLine());
5736 QCmyk32 *out_scanline =
reinterpret_cast<QCmyk32 *>(toImage.d->data + y * toImage.bytesPerLine());
5737 QColorTransformPrivate::get(transform)->apply(out_scanline, in_scanline, width(), transFlags);
5740 }
else if (isRgb64Data(fromImage.format())) {
5741 transformSegment = [&](
int yStart,
int yEnd) {
5742 for (
int y = yStart; y < yEnd; ++y) {
5743 const QRgba64 *in_scanline =
reinterpret_cast<
const QRgba64 *>(fromImage.constBits() + y * fromImage.bytesPerLine());
5744 QCmyk32 *out_scanline =
reinterpret_cast<QCmyk32 *>(toImage.d->data + y * toImage.bytesPerLine());
5745 QColorTransformPrivate::get(transform)->apply(out_scanline, in_scanline, width(), transFlags);
5749 Q_ASSERT(isRgb32fpx4Data(fromImage.format()));
5750 transformSegment = [&](
int yStart,
int yEnd) {
5751 for (
int y = yStart; y < yEnd; ++y) {
5752 const QRgbaFloat32 *in_scanline =
reinterpret_cast<
const QRgbaFloat32 *>(fromImage.constBits() + y * fromImage.bytesPerLine());
5753 QCmyk32 *out_scanline =
reinterpret_cast<QCmyk32 *>(toImage.d->data + y * toImage.bytesPerLine());
5754 QColorTransformPrivate::get(transform)->apply(out_scanline, in_scanline, width(), transFlags);
5763 if (pixelFormat().colorModel() == QPixelFormat::Indexed) {
5764 for (
int i = 0; i < d->colortable.size(); ++i)
5765 fromImage.d->colortable[i] = transform.map(d->colortable[i]);
5766 return fromImage.convertedTo(toFormat, flags);
5769 QImage::Format oldFormat = format();
5770 if (qt_fpColorPrecision(oldFormat)) {
5771 if (oldFormat != QImage::Format_RGBX32FPx4 && oldFormat != QImage::Format_RGBA32FPx4
5772 && oldFormat != QImage::Format_RGBA32FPx4_Premultiplied)
5773 fromImage.convertTo(QImage::Format_RGBA32FPx4);
5774 }
else if (qt_highColorPrecision(oldFormat,
true)) {
5775 if (oldFormat != QImage::Format_RGBX64 && oldFormat != QImage::Format_RGBA64
5776 && oldFormat != QImage::Format_RGBA64_Premultiplied && oldFormat != QImage::Format_Grayscale16)
5777 fromImage.convertTo(QImage::Format_RGBA64);
5778 }
else if (oldFormat != QImage::Format_ARGB32 && oldFormat != QImage::Format_RGB32
5779 && oldFormat != QImage::Format_ARGB32_Premultiplied && oldFormat != QImage::Format_CMYK8888
5780 && oldFormat != QImage::Format_Grayscale8 && oldFormat != QImage::Format_Grayscale16) {
5781 if (hasAlphaChannel())
5782 fromImage.convertTo(QImage::Format_ARGB32);
5784 fromImage.convertTo(QImage::Format_RGB32);
5787 if (!fromImage.hasAlphaChannel())
5788 transFlags = QColorTransformPrivate::InputOpaque;
5789 else if (qPixelLayouts[fromImage.format()].premultiplied)
5790 transFlags = QColorTransformPrivate::Premultiplied;
5792 if (fromImage.format() == Format_Grayscale8) {
5793 transformSegment = [&](
int yStart,
int yEnd) {
5794 for (
int y = yStart; y < yEnd; ++y) {
5795 const quint8 *in_scanline =
reinterpret_cast<
const quint8 *>(fromImage.constBits() + y * fromImage.bytesPerLine());
5796 if (tmpFormat == Format_Grayscale8) {
5797 quint8 *out_scanline =
reinterpret_cast<quint8 *>(toImage.d->data + y * toImage.bytesPerLine());
5798 QColorTransformPrivate::get(transform)->apply(out_scanline, in_scanline, width(), transFlags);
5800 Q_ASSERT(tmpFormat == Format_Grayscale16);
5801 quint16 *out_scanline =
reinterpret_cast<quint16 *>(toImage.d->data + y * toImage.bytesPerLine());
5802 QColorTransformPrivate::get(transform)->apply(out_scanline, in_scanline, width(), transFlags);
5806 }
else if (fromImage.format() == Format_Grayscale16) {
5807 transformSegment = [&](
int yStart,
int yEnd) {
5808 for (
int y = yStart; y < yEnd; ++y) {
5809 const quint16 *in_scanline =
reinterpret_cast<
const quint16 *>(fromImage.constBits() + y * fromImage.bytesPerLine());
5810 quint16 *out_scanline =
reinterpret_cast<quint16 *>(toImage.d->data + y * toImage.bytesPerLine());
5811 QColorTransformPrivate::get(transform)->apply(out_scanline, in_scanline, width(), transFlags);
5814 }
else if (fromImage.format() == Format_CMYK8888) {
5815 Q_ASSERT(tmpFormat == Format_CMYK8888);
5816 transformSegment = [&](
int yStart,
int yEnd) {
5817 for (
int y = yStart; y < yEnd; ++y) {
5818 const QCmyk32 *in_scanline =
reinterpret_cast<
const QCmyk32 *>(fromImage.constBits() + y * fromImage.bytesPerLine());
5819 QCmyk32 *out_scanline =
reinterpret_cast<QCmyk32 *>(toImage.d->data + y * toImage.bytesPerLine());
5820 QColorTransformPrivate::get(transform)->apply(out_scanline, in_scanline, width(), transFlags);
5823 }
else if (isRgb32fpx4Data(fromImage.format())) {
5824 Q_ASSERT(isRgb32fpx4Data(tmpFormat));
5825 transformSegment = [&](
int yStart,
int yEnd) {
5826 for (
int y = yStart; y < yEnd; ++y) {
5827 const QRgbaFloat32 *in_scanline =
reinterpret_cast<
const QRgbaFloat32 *>(fromImage.constBits() + y * fromImage.bytesPerLine());
5828 QRgbaFloat32 *out_scanline =
reinterpret_cast<QRgbaFloat32 *>(toImage.d->data + y * toImage.bytesPerLine());
5829 QColorTransformPrivate::get(transform)->apply(out_scanline, in_scanline, width(), transFlags);
5832 }
else if (isRgb64Data(fromImage.format())) {
5833 transformSegment = [&](
int yStart,
int yEnd) {
5834 for (
int y = yStart; y < yEnd; ++y) {
5835 const QRgba64 *in_scanline =
reinterpret_cast<
const QRgba64 *>(fromImage.constBits() + y * fromImage.bytesPerLine());
5836 if (isRgb32fpx4Data(tmpFormat)) {
5837 QRgbaFloat32 *out_scanline =
reinterpret_cast<QRgbaFloat32 *>(toImage.d->data + y * toImage.bytesPerLine());
5838 QColorTransformPrivate::get(transform)->apply(out_scanline, in_scanline, width(), transFlags);
5840 Q_ASSERT(isRgb64Data(tmpFormat));
5841 QRgba64 *out_scanline =
reinterpret_cast<QRgba64 *>(toImage.d->data + y * toImage.bytesPerLine());
5842 QColorTransformPrivate::get(transform)->apply(out_scanline, in_scanline, width(), transFlags);
5847 transformSegment = [&](
int yStart,
int yEnd) {
5848 for (
int y = yStart; y < yEnd; ++y) {
5849 const QRgb *in_scanline =
reinterpret_cast<
const QRgb *>(fromImage.constBits() + y * fromImage.bytesPerLine());
5850 if (isRgb32fpx4Data(tmpFormat)) {
5851 QRgbaFloat32 *out_scanline =
reinterpret_cast<QRgbaFloat32 *>(toImage.d->data + y * toImage.bytesPerLine());
5852 QColorTransformPrivate::get(transform)->apply(out_scanline, in_scanline, width(), transFlags);
5853 }
else if (isRgb64Data(tmpFormat)) {
5854 QRgba64 *out_scanline =
reinterpret_cast<QRgba64 *>(toImage.d->data + y * toImage.bytesPerLine());
5855 QColorTransformPrivate::get(transform)->apply(out_scanline, in_scanline, width(), transFlags);
5857 Q_ASSERT(isRgb32Data(tmpFormat));
5858 QRgb *out_scanline =
reinterpret_cast<QRgb *>(toImage.d->data + y * toImage.bytesPerLine());
5859 QColorTransformPrivate::get(transform)->apply(out_scanline, in_scanline, width(), transFlags);
5866#if QT_CONFIG(qtgui_threadpool)
5867 int segments = (qsizetype(width()) * height()) >> 16;
5868 segments = std::min(segments, height());
5869 QThreadPool *threadPool = QGuiApplicationPrivate::qtGuiThreadPool();
5870 if (segments > 1 && threadPool && !threadPool->contains(QThread::currentThread())) {
5871 QLatch latch(segments);
5873 for (
int i = 0; i < segments; ++i) {
5874 int yn = (height() - y) / (segments - i);
5875 threadPool->start([&, y, yn]() {
5876 transformSegment(y, y + yn);
5884 transformSegment(0, height());
5886 if (tmpFormat != toFormat)
5887 toImage.convertTo(toFormat);
5893
5894
5895
5896
5897
5898
5899
5900QImage QImage::colorTransformed(
const QColorTransform &transform) &&
5905 const QColorSpacePrivate *inColorSpace = QColorTransformPrivate::get(transform)->colorSpaceIn.constData();
5906 const QColorSpacePrivate *outColorSpace = QColorTransformPrivate::get(transform)->colorSpaceOut.constData();
5907 if (!qt_compatibleColorModelSource(pixelFormat().colorModel(), inColorSpace->colorModel)) {
5908 qWarning() <<
"QImage::colorTransformed: Invalid input color space for transform";
5911 if (!qt_compatibleColorModelTarget(pixelFormat().colorModel(), outColorSpace->colorModel, outColorSpace->transformModel)) {
5913 switch (outColorSpace->colorModel) {
5914 case QColorSpace::ColorModel::Rgb:
5915 return colorTransformed(transform, qt_highColorPrecision(format(),
true) ? QImage::Format_RGBX64 : QImage::Format_RGB32);
5916 case QColorSpace::ColorModel::Gray:
5917 return colorTransformed(transform, qt_highColorPrecision(format(),
true) ? QImage::Format_Grayscale16 : QImage::Format_Grayscale8);
5918 case QColorSpace::ColorModel::Cmyk:
5919 return colorTransformed(transform, QImage::Format_CMYK8888);
5920 case QColorSpace::ColorModel::Undefined:
5926 applyColorTransform(transform);
5927 return std::move(*
this);
5931
5932
5933
5934
5935
5936
5937
5938QImage QImage::colorTransformed(
const QColorTransform &transform, QImage::Format format, Qt::ImageConversionFlags flags) &&
5941 return colorTransformed(transform, format, flags);
5944bool QImageData::convertInPlace(QImage::Format newFormat, Qt::ImageConversionFlags flags)
5946 if (format == newFormat)
5950 if (ref.loadRelaxed() > 1 || !own_data)
5953 InPlace_Image_Converter converter = qimage_inplace_converter_map[format][newFormat];
5955 return converter(
this, flags);
5956 if (format > QImage::Format_Indexed8 && newFormat > QImage::Format_Indexed8 && !qimage_converter_map[format][newFormat]) {
5959 if (qt_highColorPrecision(newFormat, !qPixelLayouts[newFormat].hasAlphaChannel)
5960 && qt_highColorPrecision(format, !qPixelLayouts[format].hasAlphaChannel)) {
5961#if QT_CONFIG(raster_fp)
5962 if (qt_fpColorPrecision(format) && qt_fpColorPrecision(newFormat))
5963 return convert_generic_inplace_over_rgba32f(
this, newFormat, flags);
5965 return convert_generic_inplace_over_rgb64(
this, newFormat, flags);
5967 return convert_generic_inplace(
this, newFormat, flags);
5973
5974
5975
5978
5979
5980
5982#ifndef QT_NO_DEBUG_STREAM
5983QDebug operator<<(QDebug dbg,
const QImage &i)
5985 QDebugStateSaver saver(dbg);
5992 dbg << i.size() <<
",format=" << i.format() <<
",depth=" << i.depth();
5994 dbg <<
",colorCount=" << i.colorCount();
5995 const int bytesPerLine = i.bytesPerLine();
5996 dbg <<
",devicePixelRatio=" << i.devicePixelRatio()
5997 <<
",bytesPerLine=" << bytesPerLine <<
",sizeInBytes=" << i.sizeInBytes();
5998 if (dbg.verbosity() > 2 && i.height() > 0) {
5999 const int outputLength = qMin(bytesPerLine, 24);
6001 << QByteArray(
reinterpret_cast<
const char *>(i.scanLine(0)), outputLength).toHex()
6010static constexpr QPixelFormat pixelformats[] = {
6014 QPixelFormat(QPixelFormat::Indexed,
6021 QPixelFormat::IgnoresAlpha,
6022 QPixelFormat::AtBeginning,
6023 QPixelFormat::NotPremultiplied,
6024 QPixelFormat::UnsignedByte,
6025 QPixelFormat::BigEndian),
6027 QPixelFormat(QPixelFormat::Indexed,
6034 QPixelFormat::IgnoresAlpha,
6035 QPixelFormat::AtBeginning,
6036 QPixelFormat::NotPremultiplied,
6037 QPixelFormat::UnsignedByte,
6038 QPixelFormat::BigEndian),
6040 QPixelFormat(QPixelFormat::Indexed,
6047 QPixelFormat::IgnoresAlpha,
6048 QPixelFormat::AtBeginning,
6049 QPixelFormat::NotPremultiplied,
6050 QPixelFormat::UnsignedByte,
6051 QPixelFormat::BigEndian),
6053 QPixelFormat(QPixelFormat::RGB,
6060 QPixelFormat::IgnoresAlpha,
6061 QPixelFormat::AtBeginning,
6062 QPixelFormat::NotPremultiplied,
6063 QPixelFormat::UnsignedInteger,
6064 QPixelFormat::CurrentSystemEndian),
6066 QPixelFormat(QPixelFormat::RGB,
6073 QPixelFormat::UsesAlpha,
6074 QPixelFormat::AtBeginning,
6075 QPixelFormat::NotPremultiplied,
6076 QPixelFormat::UnsignedInteger,
6077 QPixelFormat::CurrentSystemEndian),
6079 QPixelFormat(QPixelFormat::RGB,
6086 QPixelFormat::UsesAlpha,
6087 QPixelFormat::AtBeginning,
6088 QPixelFormat::Premultiplied,
6089 QPixelFormat::UnsignedInteger,
6090 QPixelFormat::CurrentSystemEndian),
6092 QPixelFormat(QPixelFormat::RGB,
6099 QPixelFormat::IgnoresAlpha,
6100 QPixelFormat::AtBeginning,
6101 QPixelFormat::NotPremultiplied,
6102 QPixelFormat::UnsignedShort,
6103 QPixelFormat::CurrentSystemEndian),
6105 QPixelFormat(QPixelFormat::RGB,
6112 QPixelFormat::UsesAlpha,
6113 QPixelFormat::AtBeginning,
6114 QPixelFormat::Premultiplied,
6115 QPixelFormat::UnsignedInteger,
6116 QPixelFormat::CurrentSystemEndian),
6118 QPixelFormat(QPixelFormat::RGB,
6125 QPixelFormat::IgnoresAlpha,
6126 QPixelFormat::AtBeginning,
6127 QPixelFormat::NotPremultiplied,
6128 QPixelFormat::UnsignedInteger,
6129 QPixelFormat::CurrentSystemEndian),
6131 QPixelFormat(QPixelFormat::RGB,
6138 QPixelFormat::UsesAlpha,
6139 QPixelFormat::AtEnd,
6140 QPixelFormat::Premultiplied,
6141 QPixelFormat::UnsignedInteger,
6142 QPixelFormat::CurrentSystemEndian),
6144 QPixelFormat(QPixelFormat::RGB,
6151 QPixelFormat::IgnoresAlpha,
6152 QPixelFormat::AtBeginning,
6153 QPixelFormat::NotPremultiplied,
6154 QPixelFormat::UnsignedShort,
6155 QPixelFormat::CurrentSystemEndian),
6157 QPixelFormat(QPixelFormat::RGB,
6164 QPixelFormat::UsesAlpha,
6165 QPixelFormat::AtBeginning,
6166 QPixelFormat::Premultiplied,
6167 QPixelFormat::UnsignedInteger,
6168 QPixelFormat::CurrentSystemEndian),
6170 QPixelFormat(QPixelFormat::RGB,
6177 QPixelFormat::IgnoresAlpha,
6178 QPixelFormat::AtBeginning,
6179 QPixelFormat::NotPremultiplied,
6180 QPixelFormat::UnsignedByte,
6181 QPixelFormat::BigEndian),
6183 QPixelFormat(QPixelFormat::RGB,
6190 QPixelFormat::IgnoresAlpha,
6191 QPixelFormat::AtBeginning,
6192 QPixelFormat::NotPremultiplied,
6193 QPixelFormat::UnsignedShort,
6194 QPixelFormat::CurrentSystemEndian),
6196 QPixelFormat(QPixelFormat::RGB,
6203 QPixelFormat::UsesAlpha,
6204 QPixelFormat::AtBeginning,
6205 QPixelFormat::Premultiplied,
6206 QPixelFormat::UnsignedShort,
6207 QPixelFormat::CurrentSystemEndian),
6209 QPixelFormat(QPixelFormat::RGB,
6216 QPixelFormat::IgnoresAlpha,
6217 QPixelFormat::AtEnd,
6218 QPixelFormat::NotPremultiplied,
6219 QPixelFormat::UnsignedByte,
6220 QPixelFormat::BigEndian),
6222 QPixelFormat(QPixelFormat::RGB,
6229 QPixelFormat::UsesAlpha,
6230 QPixelFormat::AtEnd,
6231 QPixelFormat::NotPremultiplied,
6232 QPixelFormat::UnsignedByte,
6233 QPixelFormat::BigEndian),
6235 QPixelFormat(QPixelFormat::RGB,
6242 QPixelFormat::UsesAlpha,
6243 QPixelFormat::AtEnd,
6244 QPixelFormat::Premultiplied,
6245 QPixelFormat::UnsignedByte,
6246 QPixelFormat::BigEndian),
6248 QPixelFormat(QPixelFormat::BGR,
6255 QPixelFormat::IgnoresAlpha,
6256 QPixelFormat::AtBeginning,
6257 QPixelFormat::NotPremultiplied,
6258 QPixelFormat::UnsignedInteger,
6259 QPixelFormat::CurrentSystemEndian),
6261 QPixelFormat(QPixelFormat::BGR,
6268 QPixelFormat::UsesAlpha,
6269 QPixelFormat::AtBeginning,
6270 QPixelFormat::Premultiplied,
6271 QPixelFormat::UnsignedInteger,
6272 QPixelFormat::CurrentSystemEndian),
6274 QPixelFormat(QPixelFormat::RGB,
6281 QPixelFormat::IgnoresAlpha,
6282 QPixelFormat::AtBeginning,
6283 QPixelFormat::NotPremultiplied,
6284 QPixelFormat::UnsignedInteger,
6285 QPixelFormat::CurrentSystemEndian),
6287 QPixelFormat(QPixelFormat::RGB,
6294 QPixelFormat::UsesAlpha,
6295 QPixelFormat::AtBeginning,
6296 QPixelFormat::Premultiplied,
6297 QPixelFormat::UnsignedInteger,
6298 QPixelFormat::CurrentSystemEndian),
6300 QPixelFormat(QPixelFormat::Alpha,
6307 QPixelFormat::UsesAlpha,
6308 QPixelFormat::AtBeginning,
6309 QPixelFormat::Premultiplied,
6310 QPixelFormat::UnsignedByte,
6311 QPixelFormat::BigEndian),
6313 QPixelFormat(QPixelFormat::Grayscale,
6320 QPixelFormat::IgnoresAlpha,
6321 QPixelFormat::AtBeginning,
6322 QPixelFormat::NotPremultiplied,
6323 QPixelFormat::UnsignedByte,
6324 QPixelFormat::BigEndian),
6326 QPixelFormat(QPixelFormat::RGB,
6333 QPixelFormat::IgnoresAlpha,
6334 QPixelFormat::AtEnd,
6335 QPixelFormat::NotPremultiplied,
6336 QPixelFormat::UnsignedShort,
6337 QPixelFormat::CurrentSystemEndian),
6339 QPixelFormat(QPixelFormat::RGB,
6346 QPixelFormat::UsesAlpha,
6347 QPixelFormat::AtEnd,
6348 QPixelFormat::NotPremultiplied,
6349 QPixelFormat::UnsignedShort,
6350 QPixelFormat::CurrentSystemEndian),
6352 QPixelFormat(QPixelFormat::RGB,
6359 QPixelFormat::UsesAlpha,
6360 QPixelFormat::AtEnd,
6361 QPixelFormat::Premultiplied,
6362 QPixelFormat::UnsignedShort,
6363 QPixelFormat::CurrentSystemEndian),
6365 QPixelFormat(QPixelFormat::Grayscale,
6372 QPixelFormat::IgnoresAlpha,
6373 QPixelFormat::AtBeginning,
6374 QPixelFormat::NotPremultiplied,
6375 QPixelFormat::UnsignedShort,
6376 QPixelFormat::CurrentSystemEndian),
6378 QPixelFormat(QPixelFormat::BGR,
6385 QPixelFormat::IgnoresAlpha,
6386 QPixelFormat::AtBeginning,
6387 QPixelFormat::NotPremultiplied,
6388 QPixelFormat::UnsignedByte,
6389 QPixelFormat::BigEndian),
6391 QPixelFormat(QPixelFormat::RGB,
6398 QPixelFormat::IgnoresAlpha,
6399 QPixelFormat::AtEnd,
6400 QPixelFormat::NotPremultiplied,
6401 QPixelFormat::FloatingPoint,
6402 QPixelFormat::CurrentSystemEndian),
6404 QPixelFormat(QPixelFormat::RGB,
6411 QPixelFormat::UsesAlpha,
6412 QPixelFormat::AtEnd,
6413 QPixelFormat::NotPremultiplied,
6414 QPixelFormat::FloatingPoint,
6415 QPixelFormat::CurrentSystemEndian),
6417 QPixelFormat(QPixelFormat::RGB,
6424 QPixelFormat::UsesAlpha,
6425 QPixelFormat::AtEnd,
6426 QPixelFormat::Premultiplied,
6427 QPixelFormat::FloatingPoint,
6428 QPixelFormat::CurrentSystemEndian),
6430 QPixelFormat(QPixelFormat::RGB,
6437 QPixelFormat::IgnoresAlpha,
6438 QPixelFormat::AtEnd,
6439 QPixelFormat::NotPremultiplied,
6440 QPixelFormat::FloatingPoint,
6441 QPixelFormat::CurrentSystemEndian),
6443 QPixelFormat(QPixelFormat::RGB,
6450 QPixelFormat::UsesAlpha,
6451 QPixelFormat::AtEnd,
6452 QPixelFormat::NotPremultiplied,
6453 QPixelFormat::FloatingPoint,
6454 QPixelFormat::CurrentSystemEndian),
6456 QPixelFormat(QPixelFormat::RGB,
6463 QPixelFormat::UsesAlpha,
6464 QPixelFormat::AtEnd,
6465 QPixelFormat::Premultiplied,
6466 QPixelFormat::FloatingPoint,
6467 QPixelFormat::CurrentSystemEndian),
6469 QPixelFormat(QPixelFormat::CMYK,
6476 QPixelFormat::IgnoresAlpha,
6477 QPixelFormat::AtBeginning,
6478 QPixelFormat::NotPremultiplied,
6479 QPixelFormat::UnsignedInteger,
6480 QPixelFormat::CurrentSystemEndian),
6482static_assert(
sizeof(pixelformats) /
sizeof(*pixelformats) == QImage::NImageFormats);
6485
6486
6487QPixelFormat QImage::pixelFormat()
const noexcept
6489 return toPixelFormat(format());
6493
6494
6495QPixelFormat QImage::toPixelFormat(QImage::Format format)
noexcept
6497 Q_ASSERT(
static_cast<
int>(format) < NImageFormats &&
static_cast<
int>(format) >= 0);
6498 return pixelformats[format];
6502
6503
6504QImage::Format QImage::toImageFormat(QPixelFormat format)
noexcept
6506 for (
int i = 0; i < NImageFormats; i++) {
6507 if (format == pixelformats[i])
6510 return Format_Invalid;
6515 Qt::Orientations orients = {};
6516 if (orient.testFlag(QImageIOHandler::TransformationMirror))
6517 orients |= Qt::Horizontal;
6518 if (orient.testFlag(QImageIOHandler::TransformationFlip))
6519 orients |= Qt::Vertical;
6525 if (orient == QImageIOHandler::TransformationNone)
6527 if (orient == QImageIOHandler::TransformationRotate270) {
6528 src = rotated270(src);
6530 src.flip(toOrientations(orient));
6531 if (orient & QImageIOHandler::TransformationRotate90)
6532 src = rotated90(src);
6538 QMap<QString, QString> text = qt_getImageTextFromDescription(description);
6539 const auto textKeys = image.textKeys();
6540 for (
const QString &key : textKeys) {
6541 if (!key.isEmpty() && !text.contains(key))
6542 text.insert(key, image.text(key));
6549 QMap<QString, QString> text;
6550 for (
const auto &pair : QStringView{description}.tokenize(u"\n\n")) {
6551 int index = pair.indexOf(u':');
6552 if (index >= 0 && pair.indexOf(u' ') < index) {
6553 if (!pair.trimmed().isEmpty())
6554 text.insert(
"Description"_L1, pair.toString().simplified());
6556 const auto key = pair.left(index);
6557 if (!key.trimmed().isEmpty())
6558 text.insert(key.toString(), pair.mid(index + 2).toString().simplified());
6566#include "moc_qimage.cpp"
Combined button and popup list for selecting options.
Q_TRACE_METADATA(qtcore, "ENUM { AUTO, RANGE User ... MaxUser } QEvent::Type;")
static QImage rotated90(const QImage &src)
static void copyMetadata(QImage *dst, const QImage &src)
#define QT_XFORM_TYPE_LSBFIRST
static void copyMetadata(QImageData *dst, const QImageData *src)
#define QT_XFORM_TYPE_MSBFIRST
static int next_qimage_serial_number()
#define QIMAGE_SANITYCHECK_MEMORY(image)
static void copyPhysicalMetadata(QImageData *dst, const QImageData *src)
static QImage rotated270(const QImage &src)
QMap< QString, QString > qt_getImageText(const QImage &image, const QString &description)
Q_GUI_EXPORT void qt_imageTransform(QImage &src, QImageIOHandler::Transformations orient)
static QImage rotated180(const QImage &src)
static Qt::Orientations toOrientations(QImageIOHandler::Transformations orient)
QMap< QString, QString > qt_getImageTextFromDescription(const QString &description)