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
1208
1209
1210
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235QImage Q_TRACE_INSTRUMENT(qtgui) QImage::copy(
const QRect& r)
const
1237 Q_TRACE_SCOPE(QImage_copy, r);
1242 QImage image(d->width, d->height, d->format);
1248 if (image.d->nbytes != d->nbytes) {
1249 qsizetype bpl = qMin(bytesPerLine(), image.bytesPerLine());
1250 for (
int i = 0; i < height(); i++)
1251 memcpy(image.scanLine(i), scanLine(i), bpl);
1253 memcpy(image.bits(), bits(), d->nbytes);
1254 image.d->colortable = d->colortable;
1255 image.d->has_alpha_clut = d->has_alpha_clut;
1256 copyMetadata(image.d, d);
1267 if (w <= 0 || h <= 0)
1270 QImage image(w, h, d->format);
1274 if (x < 0 || y < 0 || x + w > d->width || y + h > d->height) {
1287 image.d->colortable = d->colortable;
1289 int pixels_to_copy = qMax(w - dx, 0);
1292 else if (pixels_to_copy > d->width - x)
1293 pixels_to_copy = d->width - x;
1294 int lines_to_copy = qMax(h - dy, 0);
1297 else if (lines_to_copy > d->height - y)
1298 lines_to_copy = d->height - y;
1300 bool byteAligned =
true;
1301 if (d->format == Format_Mono || d->format == Format_MonoLSB)
1302 byteAligned = !(dx & 7) && !(x & 7) && !(pixels_to_copy & 7);
1305 const uchar *src = d->data + ((x * d->depth) >> 3) + y * d->bytes_per_line;
1306 uchar *dest = image.d->data + ((dx * d->depth) >> 3) + dy * image.d->bytes_per_line;
1307 const qsizetype bytes_to_copy = (qsizetype(pixels_to_copy) * d->depth) >> 3;
1308 for (
int i = 0; i < lines_to_copy; ++i) {
1309 memcpy(dest, src, bytes_to_copy);
1310 src += d->bytes_per_line;
1311 dest += image.d->bytes_per_line;
1313 }
else if (d->format == Format_Mono) {
1314 const uchar *src = d->data + y * d->bytes_per_line;
1315 uchar *dest = image.d->data + dy * image.d->bytes_per_line;
1316 for (
int i = 0; i < lines_to_copy; ++i) {
1317 for (
int j = 0; j < pixels_to_copy; ++j) {
1318 if (src[(x + j) >> 3] & (0x80 >> ((x + j) & 7)))
1319 dest[(dx + j) >> 3] |= (0x80 >> ((dx + j) & 7));
1321 dest[(dx + j) >> 3] &= ~(0x80 >> ((dx + j) & 7));
1323 src += d->bytes_per_line;
1324 dest += image.d->bytes_per_line;
1327 Q_ASSERT(d->format == Format_MonoLSB);
1328 const uchar *src = d->data + y * d->bytes_per_line;
1329 uchar *dest = image.d->data + dy * image.d->bytes_per_line;
1330 for (
int i = 0; i < lines_to_copy; ++i) {
1331 for (
int j = 0; j < pixels_to_copy; ++j) {
1332 if (src[(x + j) >> 3] & (0x1 << ((x + j) & 7)))
1333 dest[(dx + j) >> 3] |= (0x1 << ((dx + j) & 7));
1335 dest[(dx + j) >> 3] &= ~(0x1 << ((dx + j) & 7));
1337 src += d->bytes_per_line;
1338 dest += image.d->bytes_per_line;
1342 copyMetadata(image.d, d);
1343 image.d->has_alpha_clut = d->has_alpha_clut;
1350
1351
1352
1353
1354
1355bool QImage::isNull()
const
1361
1362
1363
1364
1365
1366
1367int QImage::width()
const
1369 return d ? d->width : 0;
1373
1374
1375
1376
1377
1378
1379int QImage::height()
const
1381 return d ? d->height : 0;
1385
1386
1387
1388
1389
1390
1391QSize QImage::size()
const
1393 return d ? QSize(d->width, d->height) : QSize(0, 0);
1397
1398
1399
1400
1401
1402
1403
1404QRect QImage::rect()
const
1406 return d ? QRect(0, 0, d->width, d->height) : QRect();
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421int QImage::depth()
const
1423 return d ? d->depth : 0;
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437int QImage::colorCount()
const
1439 return d ? d->colortable.size() : 0;
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453void QImage::setColorTable(
const QList<QRgb> &colors)
1457 detachMetadata(
true);
1463 d->colortable = colors;
1464 d->has_alpha_clut =
false;
1465 for (
int i = 0; i < d->colortable.size(); ++i) {
1466 if (qAlpha(d->colortable.at(i)) != 255) {
1467 d->has_alpha_clut =
true;
1474
1475
1476
1477
1478
1479QList<QRgb> QImage::colorTable()
const
1481 return d ? d->colortable : QList<QRgb>();
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495qreal QImage::devicePixelRatio()
const
1499 return d->devicePixelRatio;
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523void QImage::setDevicePixelRatio(qreal scaleFactor)
1528 if (scaleFactor == d->devicePixelRatio)
1533 d->devicePixelRatio = scaleFactor;
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546QSizeF QImage::deviceIndependentSize()
const
1549 return QSizeF(0, 0);
1550 return QSizeF(d->width, d->height) / d->devicePixelRatio;
1555
1556
1557
1558
1559
1560
1561qsizetype QImage::sizeInBytes()
const
1563 return d ? d->nbytes : 0;
1567
1568
1569
1570
1571
1572
1573qsizetype QImage::bytesPerLine()
const
1575 return d ? d->bytes_per_line : 0;
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590QRgb QImage::color(
int i)
const
1592 Q_ASSERT(i < colorCount());
1593 return d ? d->colortable.at(i) : QRgb(uint(-1));
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608void QImage::setColor(
int i, QRgb c)
1612 if (i < 0 || d->depth > 8 || i >= 1<<d->depth) {
1613 qWarning(
"QImage::setColor: Index out of bound %d", i);
1616 detachMetadata(
true);
1622 if (i >= d->colortable.size())
1624 d->colortable[i] = c;
1625 d->has_alpha_clut |= (qAlpha(c) != 255);
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650uchar *QImage::scanLine(
int i)
1661 return d->data + i * d->bytes_per_line;
1665
1666
1667const uchar *QImage::scanLine(
int i)
const
1672 Q_ASSERT(i >= 0 && i < height());
1673 return d->data + i * d->bytes_per_line;
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691const uchar *QImage::constScanLine(
int i)
const
1696 Q_ASSERT(i >= 0 && i < height());
1697 return d->data + i * d->bytes_per_line;
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711uchar *QImage::bits()
1725
1726
1727
1728
1729
1730
1731const uchar *QImage::bits()
const
1733 return d ? d->data :
nullptr;
1738
1739
1740
1741
1742
1743
1744
1745
1746const uchar *QImage::constBits()
const
1748 return d ? d->data :
nullptr;
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1771void QImage::fill(uint pixel)
1782 if (d->depth == 1 || d->depth == 8) {
1784 if (d->depth == 1) {
1793 qt_rectfill<quint8>(d->data, pixel, 0, 0,
1794 w, d->height, d->bytes_per_line);
1796 }
else if (d->depth == 16) {
1797 if (d->format == Format_RGB444)
1799 qt_rectfill<quint16>(
reinterpret_cast<quint16*>(d->data), pixel,
1800 0, 0, d->width, d->height, d->bytes_per_line);
1802 }
else if (d->depth == 24) {
1803 if (d->format == Format_RGB666)
1805 qt_rectfill<quint24>(
reinterpret_cast<quint24*>(d->data), pixel,
1806 0, 0, d->width, d->height, d->bytes_per_line);
1808 }
else if (d->format >= QImage::Format_RGBX64 && d->format <= QImage::Format_RGBA64_Premultiplied) {
1809 qt_rectfill<quint64>(
reinterpret_cast<quint64*>(d->data), QRgba64::fromArgb32(pixel),
1810 0, 0, d->width, d->height, d->bytes_per_line);
1812 }
else if (d->format >= QImage::Format_RGBX16FPx4 && d->format <= QImage::Format_RGBA16FPx4_Premultiplied) {
1814 QRgbaFloat16 cf = QRgbaFloat16::fromArgb32(pixel);
1815 ::memcpy(&cu, &cf,
sizeof(quint64));
1816 qt_rectfill<quint64>(
reinterpret_cast<quint64*>(d->data), cu,
1817 0, 0, d->width, d->height, d->bytes_per_line);
1819 }
else if (d->format >= QImage::Format_RGBX32FPx4 && d->format <= QImage::Format_RGBA32FPx4_Premultiplied) {
1820 QRgbaFloat32 cf = QRgbaFloat32::fromArgb32(pixel);
1821 uchar *data = d->data;
1822 for (
int y = 0; y < d->height; ++y) {
1823 QRgbaFloat32 *line =
reinterpret_cast<QRgbaFloat32 *>(data);
1824 for (
int x = 0; x < d->width; ++x)
1826 data += d->bytes_per_line;
1830 Q_ASSERT(d->depth == 32);
1832 if (d->format == Format_RGB32)
1833 pixel |= 0xff000000;
1834 if (d->format == Format_RGBX8888)
1835#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
1836 pixel |= 0xff000000;
1838 pixel |= 0x000000ff;
1840 if (d->format == Format_BGR30 || d->format == Format_RGB30)
1841 pixel |= 0xc0000000;
1843 qt_rectfill<uint>(
reinterpret_cast<uint*>(d->data), pixel,
1844 0, 0, d->width, d->height, d->bytes_per_line);
1849
1850
1851
1852
1853
1854
1856void QImage::fill(Qt::GlobalColor color)
1858 fill(QColor(color));
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1878void QImage::fill(
const QColor &color)
1888 QRgba64 opaque = color.rgba64();
1889 opaque.setAlpha(65535);
1890 switch (d->format) {
1891 case QImage::Format_RGB32:
1892 case QImage::Format_ARGB32:
1895 case QImage::Format_ARGB32_Premultiplied:
1896 fill(qPremultiply(color.rgba()));
1898 case QImage::Format_RGBX8888:
1899 fill(ARGB2RGBA(color.rgba() | 0xff000000));
1901 case QImage::Format_RGBA8888:
1902 fill(ARGB2RGBA(color.rgba()));
1904 case QImage::Format_RGBA8888_Premultiplied:
1905 fill(ARGB2RGBA(qPremultiply(color.rgba())));
1907 case QImage::Format_BGR30:
1908 fill(qConvertRgb64ToRgb30<PixelOrderBGR>(opaque));
1910 case QImage::Format_RGB30:
1911 fill(qConvertRgb64ToRgb30<PixelOrderRGB>(opaque));
1913 case QImage::Format_RGB16:
1914 fill((uint) qConvertRgb32To16(color.rgba()));
1916 case QImage::Format_Indexed8: {
1918 for (
int i=0; i<d->colortable.size(); ++i) {
1919 if (color.rgba() == d->colortable.at(i)) {
1927 case QImage::Format_Mono:
1928 case QImage::Format_MonoLSB:
1929 if (color == Qt::color1)
1934 case QImage::Format_RGBX64:
1935 qt_rectfill<quint64>(
reinterpret_cast<quint64*>(d->data), opaque,
1936 0, 0, d->width, d->height, d->bytes_per_line);
1938 case QImage::Format_RGBA64:
1939 qt_rectfill<quint64>(
reinterpret_cast<quint64*>(d->data), color.rgba64(),
1940 0, 0, d->width, d->height, d->bytes_per_line);
1942 case QImage::Format_RGBA64_Premultiplied:
1943 qt_rectfill<quint64>(
reinterpret_cast<quint64 *>(d->data), color.rgba64().premultiplied(),
1944 0, 0, d->width, d->height, d->bytes_per_line);
1946 case QImage::Format_RGBX16FPx4:
1947 case QImage::Format_RGBA16FPx4:
1948 case QImage::Format_RGBA16FPx4_Premultiplied:
1949 case QImage::Format_RGBX32FPx4:
1950 case QImage::Format_RGBA32FPx4:
1951 case QImage::Format_RGBA32FPx4_Premultiplied:{
1953 color.getRgbF(&r, &g, &b, &a);
1954 if (!hasAlphaChannel())
1956 if (depth() == 64) {
1957 QRgbaFloat16 c16{qfloat16(r), qfloat16(g), qfloat16(b), qfloat16(a)};
1958 if (d->format == Format_RGBA16FPx4_Premultiplied)
1959 c16 = c16.premultiplied();
1960 qt_rectfill<QRgbaFloat16>(
reinterpret_cast<QRgbaFloat16 *>(d->data), c16,
1961 0, 0, d->width, d->height, d->bytes_per_line);
1963 QRgbaFloat32 c32{r, g, b, a};
1964 if (d->format == Format_RGBA32FPx4_Premultiplied)
1965 c32 = c32.premultiplied();
1966 qt_rectfill<QRgbaFloat32>(
reinterpret_cast<QRgbaFloat32 *>(d->data), c32,
1967 0, 0, d->width, d->height, d->bytes_per_line);
1973 p.setCompositionMode(QPainter::CompositionMode_Source);
1974 p.fillRect(rect(), color);
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
2000void QImage::invertPixels(InvertMode mode)
2011 QImage::Format originalFormat = d->format;
2013 if (hasAlphaChannel() && qPixelLayouts[d->format].premultiplied) {
2014 if (d->format == QImage::Format_RGBA16FPx4_Premultiplied) {
2015 if (!d->convertInPlace(QImage::Format_RGBA16FPx4, { }))
2016 *
this = convertToFormat(QImage::Format_RGBA16FPx4);
2017 }
else if (d->format == QImage::Format_RGBA32FPx4_Premultiplied) {
2018 if (!d->convertInPlace(QImage::Format_RGBA32FPx4, { }))
2019 *
this = convertToFormat(QImage::Format_RGBA32FPx4);
2020 }
else if (depth() > 32) {
2021 if (!d->convertInPlace(QImage::Format_RGBA64, { }))
2022 *
this = convertToFormat(QImage::Format_RGBA64);
2024 if (!d->convertInPlace(QImage::Format_ARGB32, { }))
2025 *
this = convertToFormat(QImage::Format_ARGB32);
2031 qsizetype bpl = (qsizetype(d->width) * d->depth + 7) / 8;
2032 int pad = d->bytes_per_line - bpl;
2033 uchar *sl = d->data;
2034 for (
int y=0; y<d->height; ++y) {
2035 for (qsizetype x=0; x<bpl; ++x)
2039 }
else if (format() >= QImage::Format_RGBX16FPx4 && format() <= QImage::Format_RGBA16FPx4_Premultiplied) {
2040 qfloat16 *p =
reinterpret_cast<qfloat16 *>(d->data);
2041 qfloat16 *end =
reinterpret_cast<qfloat16 *>(d->data + d->nbytes);
2043 p[0] = qfloat16(1) - p[0];
2044 p[1] = qfloat16(1) - p[1];
2045 p[2] = qfloat16(1) - p[2];
2046 if (mode == InvertRgba)
2047 p[3] = qfloat16(1) - p[3];
2050 }
else if (format() >= QImage::Format_RGBX32FPx4 && format() <= QImage::Format_RGBA32FPx4_Premultiplied) {
2051 uchar *data = d->data;
2052 for (
int y = 0; y < d->height; ++y) {
2053 float *p =
reinterpret_cast<
float *>(data);
2054 for (
int x = 0; x < d->width; ++x) {
2058 if (mode == InvertRgba)
2062 data += d->bytes_per_line;
2064 }
else if (depth() == 64) {
2065 quint16 *p = (quint16*)d->data;
2066 quint16 *end = (quint16*)(d->data + d->nbytes);
2067 quint16 xorbits = 0xffff;
2072 if (mode == InvertRgba)
2078 quint32 *p = (quint32*)d->data;
2079 quint32 *end = (quint32*)(d->data + d->nbytes);
2080 quint32 xorbits = 0xffffffff;
2081 switch (d->format) {
2082 case QImage::Format_RGBA8888:
2083 if (mode == InvertRgba)
2086 case QImage::Format_RGBX8888:
2087#if Q_BYTE_ORDER == Q_BIG_ENDIAN
2088 xorbits = 0xffffff00;
2091 xorbits = 0x00ffffff;
2094 case QImage::Format_ARGB32:
2095 if (mode == InvertRgba)
2098 case QImage::Format_RGB32:
2099 xorbits = 0x00ffffff;
2101 case QImage::Format_BGR30:
2102 case QImage::Format_RGB30:
2103 xorbits = 0x3fffffff;
2114 if (originalFormat != d->format) {
2115 if (!d->convertInPlace(originalFormat, { }))
2116 *
this = convertToFormat(originalFormat);
2132
2133
2134
2135
2136
2137
2138
2139
2140
2141
2142
2143
2145void QImage::setColorCount(
int colorCount)
2148 qWarning(
"QImage::setColorCount: null image");
2152 detachMetadata(
true);
2158 if (colorCount == d->colortable.size())
2160 if (colorCount <= 0) {
2161 d->colortable.clear();
2164 int nc = d->colortable.size();
2165 d->colortable.resize(colorCount);
2166 for (
int i = nc; i < colorCount; ++i)
2167 d->colortable[i] = 0;
2171
2172
2173
2174
2175QImage::Format QImage::format()
const
2179 Q_ASSERT(d->format < NImageFormats);
2180 Q_ASSERT(d->format > Format_Invalid);
2182 return d ? d->format : Format_Invalid;
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2198
2199
2200
2201
2202
2203
2204
2205
2206
2207
2208
2211
2212
2213QImage QImage::convertToFormat_helper(Format format, Qt::ImageConversionFlags flags)
const
2215 if (!d || d->format == format)
2218 if (d->format == Format_Invalid || format <= Format_Invalid || format >= NImageFormats)
2221 const QPixelLayout *destLayout = &qPixelLayouts[format];
2222 Image_Converter converter = qimage_converter_map[d->format][format];
2223 if (!converter && format > QImage::Format_Indexed8 && d->format > QImage::Format_Indexed8) {
2224 if (qt_highColorPrecision(d->format, !destLayout->hasAlphaChannel)
2225 && qt_highColorPrecision(format, !hasAlphaChannel())) {
2226#if QT_CONFIG(raster_fp)
2227 if (qt_fpColorPrecision(d->format) && qt_fpColorPrecision(format))
2228 converter = convert_generic_over_rgba32f;
2231 converter = convert_generic_over_rgb64;
2233 converter = convert_generic;
2236 QImage image(d->width, d->height, format);
2240 copyMetadata(image.d, d);
2242 converter(image.d, d, flags);
2247 Q_ASSERT(format != QImage::Format_ARGB32 && format != QImage::Format_RGB32);
2248 Q_ASSERT(d->format != QImage::Format_ARGB32 && d->format != QImage::Format_RGB32);
2250 if (!hasAlphaChannel())
2251 return convertToFormat(Format_RGB32, flags).convertToFormat(format, flags);
2253 return convertToFormat(Format_ARGB32, flags).convertToFormat(format, flags);
2257
2258
2259bool QImage::convertToFormat_inplace(Format format, Qt::ImageConversionFlags flags)
2261 return d && d->convertInPlace(format, flags);
2264static inline int pixel_distance(QRgb p1, QRgb p2) {
2266 int g1 = qGreen(p1);
2268 int a1 = qAlpha(p1);
2271 int g2 = qGreen(p2);
2273 int a2 = qAlpha(p2);
2275 return abs(r1 - r2) + abs(g1 - g2) + abs(b1 - b2) + abs(a1 - a2);
2278static inline int closestMatch(QRgb pixel,
const QList<QRgb> &clut) {
2280 int current_distance = INT_MAX;
2281 for (
int i=0; i<clut.size(); ++i) {
2282 int dist = pixel_distance(pixel, clut.at(i));
2283 if (dist < current_distance) {
2284 current_distance = dist;
2291static QImage convertWithPalette(
const QImage &src, QImage::Format format,
2292 const QList<QRgb> &clut) {
2293 QImage dest(src.size(), format);
2294 dest.setColorTable(clut);
2296 copyMetadata(QImageData::get(dest), QImageData::get(src));
2298 int h = src.height();
2299 int w = src.width();
2301 QHash<QRgb,
int> cache;
2303 if (format == QImage::Format_Indexed8) {
2304 for (
int y=0; y<h; ++y) {
2305 const QRgb *src_pixels = (
const QRgb *) src.scanLine(y);
2306 uchar *dest_pixels = (uchar *) dest.scanLine(y);
2307 for (
int x=0; x<w; ++x) {
2308 int src_pixel = src_pixels[x];
2309 int value = cache.value(src_pixel, -1);
2311 value = closestMatch(src_pixel, clut);
2312 cache.insert(src_pixel, value);
2314 dest_pixels[x] = (uchar) value;
2318 QList<QRgb> table = clut;
2320 for (
int y=0; y<h; ++y) {
2321 const QRgb *src_pixels = (
const QRgb *) src.scanLine(y);
2322 for (
int x=0; x<w; ++x) {
2323 int src_pixel = src_pixels[x];
2324 int value = cache.value(src_pixel, -1);
2326 value = closestMatch(src_pixel, table);
2327 cache.insert(src_pixel, value);
2329 dest.setPixel(x, y, value);
2338
2339
2340
2341
2342
2343
2344
2345
2346
2347QImage QImage::convertToFormat(Format format,
const QList<QRgb> &colorTable, Qt::ImageConversionFlags flags)
const
2349 if (!d || d->format == format)
2352 if (format <= QImage::Format_Invalid || format >= QImage::NImageFormats)
2354 if (format <= QImage::Format_Indexed8)
2355 return convertWithPalette(convertToFormat(QImage::Format_ARGB32, flags), format, colorTable);
2357 return convertToFormat(format, flags);
2361
2362
2363
2364
2365
2366
2367
2368
2369
2370
2371
2372
2373
2374
2375
2376
2377
2378
2379
2380
2381
2383bool QImage::reinterpretAsFormat(Format format)
2385 if (format <= Format_Invalid || format >= NImageFormats)
2389 if (d->format == format)
2391 if (qt_depthForFormat(format) != qt_depthForFormat(d->format))
2393 if (!isDetached()) {
2394 QImageData *oldD = d;
2409
2410
2411
2412
2413
2414
2415
2416
2417
2419void QImage::convertTo(Format format, Qt::ImageConversionFlags flags)
2421 if (!d || format <= QImage::Format_Invalid || format >= QImage::NImageFormats)
2424 if (d->format == format)
2428 if (convertToFormat_inplace(format, flags))
2431 *
this = convertToFormat_helper(format, flags);
2435
2436
2437
2438
2439
2440
2441
2444
2445
2446
2447
2448
2449bool QImage::valid(
int x,
int y)
const
2452 && x >= 0 && x < d->width
2453 && y >= 0 && y < d->height;
2457
2458
2459
2460
2461
2462
2463
2464
2465
2468
2469
2470
2471
2472int QImage::pixelIndex(
int x,
int y)
const
2474 if (!d || x < 0 || x >= d->width || y < 0 || y >= height()) {
2475 qWarning(
"QImage::pixelIndex: coordinate (%d,%d) out of range", x, y);
2478 const uchar * s = scanLine(y);
2481 return (*(s + (x >> 3)) >> (7- (x & 7))) & 1;
2482 case Format_MonoLSB:
2483 return (*(s + (x >> 3)) >> (x & 7)) & 1;
2484 case Format_Indexed8:
2487 qWarning(
"QImage::pixelIndex: Not applicable for %d-bpp images (no palette)", d->depth);
2494
2495
2496
2497
2498
2499
2500
2501
2502
2503
2504
2505
2506
2509
2510
2511
2512
2513QRgb QImage::pixel(
int x,
int y)
const
2515 if (!d || x < 0 || x >= d->width || y < 0 || y >= d->height) {
2516 qWarning(
"QImage::pixel: coordinate (%d,%d) out of range", x, y);
2520 const uchar *s = d->data + y * d->bytes_per_line;
2523 switch (d->format) {
2525 index = (*(s + (x >> 3)) >> (~x & 7)) & 1;
2527 case Format_MonoLSB:
2528 index = (*(s + (x >> 3)) >> (x & 7)) & 1;
2530 case Format_Indexed8:
2537 if (index >= d->colortable.size()) {
2538 qWarning(
"QImage::pixel: color table index %d out of range.", index);
2541 return d->colortable.at(index);
2543 std::optional<QRgb> out;
2544 switch (d->format) {
2547 case Format_ARGB32_Premultiplied:
2548 out =
reinterpret_cast<
const QRgb *>(s)[x];
2550 case Format_RGBX8888:
2551 case Format_RGBA8888:
2552 case Format_RGBA8888_Premultiplied:
2553 out = RGBA2ARGB(
reinterpret_cast<
const quint32 *>(s)[x]);
2556 case Format_A2BGR30_Premultiplied:
2557 out = qConvertA2rgb30ToArgb32<PixelOrderBGR>(
reinterpret_cast<
const quint32 *>(s)[x]);
2560 case Format_A2RGB30_Premultiplied:
2561 out = qConvertA2rgb30ToArgb32<PixelOrderRGB>(
reinterpret_cast<
const quint32 *>(s)[x]);
2564 return qConvertRgb16To32(
reinterpret_cast<
const quint16 *>(s)[x]);
2567 case Format_RGBA64_Premultiplied:
2568 out =
reinterpret_cast<
const QRgba64 *>(s)[x].toArgb32();
2570 case Format_RGBX16FPx4:
2571 case Format_RGBA16FPx4:
2572 case Format_RGBA16FPx4_Premultiplied:
2573 out =
reinterpret_cast<
const QRgbaFloat16 *>(s)[x].toArgb32();
2575 case Format_RGBX32FPx4:
2576 case Format_RGBA32FPx4:
2577 case Format_RGBA32FPx4_Premultiplied:
2578 out =
reinterpret_cast<
const QRgbaFloat32 *>(s)[x].toArgb32();
2582 const QPixelLayout *layout = &qPixelLayouts[d->format];
2585 if (!layout->hasAlphaChannel)
2590 return *layout->fetchToARGB32PM(&result, s, x, 1,
nullptr,
nullptr);
2594
2595
2596
2597
2598
2599
2600
2601
2602
2603
2604
2605
2606
2607
2608
2609
2610
2611
2612
2615
2616
2617
2618
2619void QImage::setPixel(
int x,
int y, uint index_or_rgb)
2621 if (!d || x < 0 || x >= width() || y < 0 || y >= height()) {
2622 qWarning(
"QImage::setPixel: coordinate (%d,%d) out of range", x, y);
2626 uchar * s = scanLine(y);
2629 case Format_MonoLSB:
2630 if (index_or_rgb > 1) {
2631 qWarning(
"QImage::setPixel: Index %d out of range", index_or_rgb);
2632 }
else if (format() == Format_MonoLSB) {
2633 if (index_or_rgb==0)
2634 *(s + (x >> 3)) &= ~(1 << (x & 7));
2636 *(s + (x >> 3)) |= (1 << (x & 7));
2638 if (index_or_rgb==0)
2639 *(s + (x >> 3)) &= ~(1 << (7-(x & 7)));
2641 *(s + (x >> 3)) |= (1 << (7-(x & 7)));
2644 case Format_Indexed8:
2645 if (index_or_rgb >= (uint)d->colortable.size()) {
2646 qWarning(
"QImage::setPixel: Index %d out of range", index_or_rgb);
2649 s[x] = index_or_rgb;
2654 ((uint *)s)[x] = 0xff000000 | index_or_rgb;
2657 case Format_ARGB32_Premultiplied:
2658 ((uint *)s)[x] = index_or_rgb;
2661 ((quint16 *)s)[x] = qConvertRgb32To16(index_or_rgb);
2663 case Format_RGBX8888:
2664 ((uint *)s)[x] = ARGB2RGBA(0xff000000 | index_or_rgb);
2666 case Format_RGBA8888:
2667 case Format_RGBA8888_Premultiplied:
2668 ((uint *)s)[x] = ARGB2RGBA(index_or_rgb);
2671 ((uint *)s)[x] = qConvertRgb32ToRgb30<PixelOrderBGR>(index_or_rgb);
2673 case Format_A2BGR30_Premultiplied:
2674 ((uint *)s)[x] = qConvertArgb32ToA2rgb30<PixelOrderBGR>(index_or_rgb);
2677 ((uint *)s)[x] = qConvertRgb32ToRgb30<PixelOrderRGB>(index_or_rgb);
2679 case Format_A2RGB30_Premultiplied:
2680 ((uint *)s)[x] = qConvertArgb32ToA2rgb30<PixelOrderRGB>(index_or_rgb);
2683 ((QRgba64 *)s)[x] = QRgba64::fromArgb32(index_or_rgb | 0xff000000);
2686 case Format_RGBA64_Premultiplied:
2687 ((QRgba64 *)s)[x] = QRgba64::fromArgb32(index_or_rgb);
2689 case Format_RGBX16FPx4:
2690 ((QRgbaFloat16 *)s)[x] = QRgbaFloat16::fromArgb32(index_or_rgb | 0xff000000);
2692 case Format_RGBA16FPx4:
2693 case Format_RGBA16FPx4_Premultiplied:
2694 ((QRgbaFloat16 *)s)[x] = QRgbaFloat16::fromArgb32(index_or_rgb);
2696 case Format_RGBX32FPx4:
2697 ((QRgbaFloat32 *)s)[x] = QRgbaFloat32::fromArgb32(index_or_rgb | 0xff000000);
2699 case Format_RGBA32FPx4:
2700 case Format_RGBA32FPx4_Premultiplied:
2701 ((QRgbaFloat32 *)s)[x] = QRgbaFloat32::fromArgb32(index_or_rgb);
2703 case Format_Invalid:
2711 const QPixelLayout *layout = &qPixelLayouts[d->format];
2712 if (!hasAlphaChannel())
2713 layout->storeFromRGB32(s, &index_or_rgb, x, 1,
nullptr,
nullptr);
2715 layout->storeFromARGB32PM(s, &index_or_rgb, x, 1,
nullptr,
nullptr);
2719
2720
2721
2722
2723
2724
2725
2726
2727
2728
2729
2730
2731
2732
2735
2736
2737
2738
2739
2740QColor QImage::pixelColor(
int x,
int y)
const
2742 if (!d || x < 0 || x >= d->width || y < 0 || y >= height()) {
2743 qWarning(
"QImage::pixelColor: coordinate (%d,%d) out of range", x, y);
2748 const uchar * s = constScanLine(y);
2749 switch (d->format) {
2751 case Format_A2BGR30_Premultiplied:
2752 c = qConvertA2rgb30ToRgb64<PixelOrderBGR>(
reinterpret_cast<
const quint32 *>(s)[x]);
2755 case Format_A2RGB30_Premultiplied:
2756 c = qConvertA2rgb30ToRgb64<PixelOrderRGB>(
reinterpret_cast<
const quint32 *>(s)[x]);
2760 case Format_RGBA64_Premultiplied:
2761 c =
reinterpret_cast<
const QRgba64 *>(s)[x];
2763 case Format_Grayscale16: {
2764 quint16 v =
reinterpret_cast<
const quint16 *>(s)[x];
2765 return QColor(qRgba64(v, v, v, 0xffff));
2767 case Format_RGBX16FPx4:
2768 case Format_RGBA16FPx4:
2769 case Format_RGBA16FPx4_Premultiplied: {
2770 QRgbaFloat16 p =
reinterpret_cast<
const QRgbaFloat16 *>(s)[x];
2771 if (d->format == Format_RGBA16FPx4_Premultiplied)
2772 p = p.unpremultiplied();
2773 else if (d->format == Format_RGBX16FPx4)
2776 color.setRgbF(p.red(), p.green(), p.blue(), p.alpha());
2779 case Format_RGBX32FPx4:
2780 case Format_RGBA32FPx4:
2781 case Format_RGBA32FPx4_Premultiplied: {
2782 QRgbaFloat32 p =
reinterpret_cast<
const QRgbaFloat32 *>(s)[x];
2783 if (d->format == Format_RGBA32FPx4_Premultiplied)
2784 p = p.unpremultiplied();
2785 else if (d->format == Format_RGBX32FPx4)
2788 color.setRgbF(p.red(), p.green(), p.blue(), p.alpha());
2792 c = QRgba64::fromArgb32(pixel(x, y));
2796 switch (d->format) {
2806 if (hasAlphaChannel() && qPixelLayouts[d->format].premultiplied)
2807 c = c.unpremultiplied();
2812
2813
2814
2815
2816
2817
2818
2819
2820
2821
2822
2823
2824
2825
2828
2829
2830
2831
2832
2833void QImage::setPixelColor(
int x,
int y,
const QColor &color)
2835 if (!d || x < 0 || x >= width() || y < 0 || y >= height()) {
2836 qWarning(
"QImage::setPixelColor: coordinate (%d,%d) out of range", x, y);
2840 if (!color.isValid()) {
2841 qWarning(
"QImage::setPixelColor: color is invalid");
2846 QRgba64 c = color.rgba64();
2847 if (!hasAlphaChannel())
2849 else if (qPixelLayouts[d->format].premultiplied)
2850 c = c.premultiplied();
2852 uchar * s = scanLine(y);
2853 switch (d->format) {
2855 case Format_MonoLSB:
2856 case Format_Indexed8:
2857 qWarning(
"QImage::setPixelColor: called on monochrome or indexed format");
2860 ((uint *)s)[x] = qConvertRgb64ToRgb30<PixelOrderBGR>(c) | 0xc0000000;
2862 case Format_A2BGR30_Premultiplied:
2863 ((uint *)s)[x] = qConvertRgb64ToRgb30<PixelOrderBGR>(c);
2866 ((uint *)s)[x] = qConvertRgb64ToRgb30<PixelOrderRGB>(c) | 0xc0000000;
2868 case Format_A2RGB30_Premultiplied:
2869 ((uint *)s)[x] = qConvertRgb64ToRgb30<PixelOrderRGB>(c);
2873 case Format_RGBA64_Premultiplied:
2874 ((QRgba64 *)s)[x] = c;
2876 case Format_RGBX16FPx4:
2877 case Format_RGBA16FPx4:
2878 case Format_RGBA16FPx4_Premultiplied: {
2880 color.getRgbF(&r, &g, &b, &a);
2881 if (d->format == Format_RGBX16FPx4)
2883 QRgbaFloat16 c16f{qfloat16(r), qfloat16(g), qfloat16(b), qfloat16(a)};
2884 if (d->format == Format_RGBA16FPx4_Premultiplied)
2885 c16f = c16f.premultiplied();
2886 ((QRgbaFloat16 *)s)[x] = c16f;
2889 case Format_RGBX32FPx4:
2890 case Format_RGBA32FPx4:
2891 case Format_RGBA32FPx4_Premultiplied: {
2893 color.getRgbF(&r, &g, &b, &a);
2894 if (d->format == Format_RGBX32FPx4)
2896 QRgbaFloat32 c32f{r, g, b, a};
2897 if (d->format == Format_RGBA32FPx4_Premultiplied)
2898 c32f = c32f.premultiplied();
2899 ((QRgbaFloat32 *)s)[x] = c32f;
2903 setPixel(x, y, c.toArgb32());
2909
2910
2911
2912
2913
2914
2915
2916
2917bool QImage::allGray()
const
2922 switch (d->format) {
2924 case Format_MonoLSB:
2925 case Format_Indexed8:
2926 for (
int i = 0; i < d->colortable.size(); ++i) {
2927 if (!qIsGray(d->colortable.at(i)))
2933 case Format_Grayscale8:
2934 case Format_Grayscale16:
2938 case Format_ARGB32_Premultiplied:
2939#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
2940 case Format_RGBX8888:
2941 case Format_RGBA8888:
2942 case Format_RGBA8888_Premultiplied:
2944 for (
int j = 0; j < d->height; ++j) {
2945 const QRgb *b = (
const QRgb *)constScanLine(j);
2946 for (
int i = 0; i < d->width; ++i) {
2953 for (
int j = 0; j < d->height; ++j) {
2954 const quint16 *b = (
const quint16 *)constScanLine(j);
2955 for (
int i = 0; i < d->width; ++i) {
2956 if (!qIsGray(qConvertRgb16To32(b[i])))
2965 Q_DECL_UNINITIALIZED uint buffer[BufferSize];
2966 const QPixelLayout *layout = &qPixelLayouts[d->format];
2967 const auto fetch = layout->fetchToARGB32PM;
2968 for (
int j = 0; j < d->height; ++j) {
2969 const uchar *b = constScanLine(j);
2971 while (x < d->width) {
2972 int l = qMin(d->width - x, BufferSize);
2973 const uint *ptr = fetch(buffer, b, x, l,
nullptr,
nullptr);
2974 for (
int i = 0; i < l; ++i) {
2975 if (!qIsGray(ptr[i]))
2985
2986
2987
2988
2989
2990
2991
2992
2993bool QImage::isGrayscale()
const
2998 if (d->format == QImage::Format_Alpha8)
3001 if (d->format == QImage::Format_Grayscale8 || d->format == QImage::Format_Grayscale16)
3010 Q_ASSERT(d->format == QImage::Format_Indexed8);
3011 for (
int i = 0; i < colorCount(); i++)
3012 if (d->colortable.at(i) != qRgb(i,i,i))
3021
3022
3023
3024
3025
3026
3027
3028
3029
3030
3031
3034
3035
3036
3037
3038
3039
3040
3041
3042
3043
3044
3045
3046
3047
3048
3049
3050
3051
3052
3053
3054
3055
3056
3057
3058
3059QImage Q_TRACE_INSTRUMENT(qtgui) QImage::scaled(
const QSize& s, Qt::AspectRatioMode aspectMode, Qt::TransformationMode mode)
const
3062 qWarning(
"QImage::scaled: Image is a null image");
3068 QSize newSize = size();
3069 newSize.scale(s, aspectMode);
3070 newSize.rwidth() = qMax(newSize.width(), 1);
3071 newSize.rheight() = qMax(newSize.height(), 1);
3072 if (newSize == size())
3075 Q_TRACE_SCOPE(QImage_scaled, s, aspectMode, mode);
3077 QTransform wm = QTransform::fromScale((qreal)newSize.width() / width(), (qreal)newSize.height() / height());
3078 QImage img = transformed(wm, mode);
3084
3085
3086
3087
3088
3089
3090
3091
3092
3093
3094
3095
3096QImage Q_TRACE_INSTRUMENT(qtgui) QImage::scaledToWidth(
int w, Qt::TransformationMode mode)
const
3099 qWarning(
"QImage::scaleWidth: Image is a null image");
3105 Q_TRACE_SCOPE(QImage_scaledToWidth, w, mode);
3107 qreal factor = (qreal) w / width();
3108 QTransform wm = QTransform::fromScale(factor, factor);
3109 return transformed(wm, mode);
3113
3114
3115
3116
3117
3118
3119
3120
3121
3122
3123
3124
3125
3126QImage Q_TRACE_INSTRUMENT(qtgui) QImage::scaledToHeight(
int h, Qt::TransformationMode mode)
const
3129 qWarning(
"QImage::scaleHeight: Image is a null image");
3135 Q_TRACE_SCOPE(QImage_scaledToHeight, h, mode);
3137 qreal factor = (qreal) h / height();
3138 QTransform wm = QTransform::fromScale(factor, factor);
3139 return transformed(wm, mode);
3143
3144
3145
3146
3147
3148
3149
3150
3151
3152
3153
3154
3155
3156
3157
3158
3159QImage Q_TRACE_INSTRUMENT(qtgui) QImage::createAlphaMask(Qt::ImageConversionFlags flags)
const
3161 if (!d || d->format == QImage::Format_RGB32)
3164 if (d->depth == 1) {
3167 return convertToFormat(Format_Indexed8, flags).createAlphaMask(flags);
3170 if (d->format != Format_Indexed8 && d->format != Format_ARGB32
3171 && d->format != Format_ARGB32_Premultiplied) {
3173 return convertToFormat(Format_ARGB32_Premultiplied, flags).createAlphaMask(flags);
3176 QImage mask(d->width, d->height, Format_MonoLSB);
3177 if (!mask.isNull()) {
3178 dither_to_Mono(mask.d, d, flags,
true);
3179 copyPhysicalMetadata(mask.d, d);
3184#ifndef QT_NO_IMAGE_HEURISTIC_MASK
3186
3187
3188
3189
3190
3191
3192
3193
3194
3195
3196
3197
3198
3199
3200
3201
3202
3203
3204
3205
3206
3207
3209QImage QImage::createHeuristicMask(
bool clipTight)
const
3214 if (d->depth != 32) {
3215 QImage img32 = convertToFormat(Format_RGB32);
3216 return img32.createHeuristicMask(clipTight);
3219#define PIX(x,y) (*((const QRgb*)scanLine(y)+x) & 0x00ffffff
)
3223 QImage m(w, h, Format_MonoLSB);
3226 m.setColor(0, QColor(Qt::color0).rgba());
3227 m.setColor(1, QColor(Qt::color1).rgba());
3230 QRgb background =
PIX(0,0);
3231 if (background !=
PIX(w-1,0) &&
3232 background !=
PIX(0,h-1) &&
3233 background !=
PIX(w-1,h-1)) {
3234 background =
PIX(w-1,0);
3235 if (background !=
PIX(w-1,h-1) &&
3236 background !=
PIX(0,h-1) &&
3237 PIX(0,h-1) ==
PIX(w-1,h-1)) {
3238 background =
PIX(w-1,h-1);
3244 uchar *ypp, *ypc, *ypn;
3247 ypn = m.scanLine(0);
3249 for (y = 0; y < h; y++) {
3252 ypn = (y == h-1) ?
nullptr : m.scanLine(y+1);
3253 const QRgb *p = (
const QRgb *)scanLine(y);
3254 for (x = 0; x < w; x++) {
3257 if ((x == 0 || y == 0 || x == w-1 || y == h-1 ||
3258 !(*(ypc + ((x-1) >> 3)) & (1 << ((x-1) & 7))) ||
3259 !(*(ypc + ((x+1) >> 3)) & (1 << ((x+1) & 7))) ||
3260 !(*(ypp + (x >> 3)) & (1 << (x & 7))) ||
3261 !(*(ypn + (x >> 3)) & (1 << (x & 7)))) &&
3262 ( (*(ypc + (x >> 3)) & (1 << (x & 7)))) &&
3263 ((*p & 0x00ffffff) == background)) {
3265 *(ypc + (x >> 3)) &= ~(1 << (x & 7));
3273 ypn = m.scanLine(0);
3275 for (y = 0; y < h; y++) {
3278 ypn = (y == h-1) ?
nullptr : m.scanLine(y+1);
3279 const QRgb *p = (
const QRgb *)scanLine(y);
3280 for (x = 0; x < w; x++) {
3281 if ((*p & 0x00ffffff) != background) {
3283 *(ypc + ((x-1) >> 3)) |= (1 << ((x-1) & 7));
3285 *(ypc + ((x+1) >> 3)) |= (1 << ((x+1) & 7));
3287 *(ypp + (x >> 3)) |= (1 << (x & 7));
3289 *(ypn + (x >> 3)) |= (1 << (x & 7));
3298 copyPhysicalMetadata(m.d, d);
3304
3305
3306
3307
3308
3309
3310
3311
3313QImage QImage::createMaskFromColor(QRgb color, Qt::MaskMode mode)
const
3317 QImage maskImage(size(), QImage::Format_MonoLSB);
3320 uchar *s = maskImage.bits();
3324 if (depth() == 32) {
3325 for (
int h = 0; h < d->height; h++) {
3326 const uint *sl = (
const uint *) scanLine(h);
3327 for (
int w = 0; w < d->width; w++) {
3329 *(s + (w >> 3)) |= (1 << (w & 7));
3331 s += maskImage.bytesPerLine();
3334 for (
int h = 0; h < d->height; h++) {
3335 for (
int w = 0; w < d->width; w++) {
3336 if ((uint) pixel(w, h) == color)
3337 *(s + (w >> 3)) |= (1 << (w & 7));
3339 s += maskImage.bytesPerLine();
3342 if (mode == Qt::MaskOutColor)
3343 maskImage.invertPixels();
3345 copyPhysicalMetadata(maskImage.d, d);
3350
3351
3352
3353
3354
3355
3356
3357
3358
3359
3360
3361
3364
3365
3366
3367
3368
3369
3370
3371
3372
3375
3376
3377
3378
3379
3380
3381
3382
3383
3384
3385
3388
3389
3390
3391
3392
3393
3394
3395
3397template<
class T>
inline void do_mirror_data(QImageData *dst, QImageData *src,
3398 int dstX0,
int dstY0,
3399 int dstXIncr,
int dstYIncr,
3405 const int srcXEnd = (dstX0 && !dstY0) ? w / 2 : w;
3406 const int srcYEnd = dstY0 ? h / 2 : h;
3407 for (
int srcY = 0, dstY = dstY0; srcY < srcYEnd; ++srcY, dstY += dstYIncr) {
3408 T *srcPtr = (T *) (src->data + srcY * src->bytes_per_line);
3409 T *dstPtr = (T *) (dst->data + dstY * dst->bytes_per_line);
3410 for (
int srcX = 0, dstX = dstX0; srcX < srcXEnd; ++srcX, dstX += dstXIncr)
3411 std::swap(srcPtr[srcX], dstPtr[dstX]);
3414 if (dstX0 && dstY0 && (h & 1)) {
3416 int srcXEnd2 = w / 2;
3417 T *srcPtr = (T *) (src->data + srcY * src->bytes_per_line);
3418 for (
int srcX = 0, dstX = dstX0; srcX < srcXEnd2; ++srcX, dstX += dstXIncr)
3419 std::swap(srcPtr[srcX], srcPtr[dstX]);
3422 for (
int srcY = 0, dstY = dstY0; srcY < h; ++srcY, dstY += dstYIncr) {
3423 T *srcPtr = (T *) (src->data + srcY * src->bytes_per_line);
3424 T *dstPtr = (T *) (dst->data + dstY * dst->bytes_per_line);
3425 for (
int srcX = 0, dstX = dstX0; srcX < w; ++srcX, dstX += dstXIncr)
3426 dstPtr[dstX] = srcPtr[srcX];
3431inline void do_flip(QImageData *dst, QImageData *src,
int w,
int h,
int depth)
3433 const int data_bytes_per_line = w * (depth / 8);
3435 uint *srcPtr =
reinterpret_cast<uint *>(src->data);
3436 uint *dstPtr =
reinterpret_cast<uint *>(dst->data + (h - 1) * dst->bytes_per_line);
3438 const int uint_per_line = (data_bytes_per_line + 3) >> 2;
3439 for (
int y = 0; y < h; ++y) {
3441 for (
int x = 0; x < uint_per_line; x++) {
3442 const uint d = dstPtr[x];
3443 const uint s = srcPtr[x];
3447 srcPtr += src->bytes_per_line >> 2;
3448 dstPtr -= dst->bytes_per_line >> 2;
3452 const uchar *srcPtr = src->data;
3453 uchar *dstPtr = dst->data + (h - 1) * dst->bytes_per_line;
3454 for (
int y = 0; y < h; ++y) {
3455 memcpy(dstPtr, srcPtr, data_bytes_per_line);
3456 srcPtr += src->bytes_per_line;
3457 dstPtr -= dst->bytes_per_line;
3462inline void do_mirror(QImageData *dst, QImageData *src,
bool horizontal,
bool vertical)
3464 Q_ASSERT(src->width == dst->width && src->height == dst->height && src->depth == dst->depth);
3466 int h = src->height;
3467 int depth = src->depth;
3469 if (src->depth == 1) {
3474 if (vertical && !horizontal) {
3476 do_flip(dst, src, w, h, depth);
3480 int dstX0 = 0, dstXIncr = 1;
3481 int dstY0 = 0, dstYIncr = 1;
3495 do_mirror_data<QRgbaFloat32>(dst, src, dstX0, dstY0, dstXIncr, dstYIncr, w, h);
3498 do_mirror_data<quint64>(dst, src, dstX0, dstY0, dstXIncr, dstYIncr, w, h);
3501 do_mirror_data<quint32>(dst, src, dstX0, dstY0, dstXIncr, dstYIncr, w, h);
3504 do_mirror_data<quint24>(dst, src, dstX0, dstY0, dstXIncr, dstYIncr, w, h);
3507 do_mirror_data<quint16>(dst, src, dstX0, dstY0, dstXIncr, dstYIncr, w, h);
3510 do_mirror_data<quint8>(dst, src, dstX0, dstY0, dstXIncr, dstYIncr, w, h);
3519 if (horizontal && dst->depth == 1) {
3520 Q_ASSERT(dst->format == QImage::Format_Mono || dst->format == QImage::Format_MonoLSB);
3521 const int shift = 8 - (dst->width % 8);
3522 const uchar *bitflip = qt_get_bitflip_array();
3523 for (
int y = 0; y < h; ++y) {
3524 uchar *begin = dst->data + y * dst->bytes_per_line;
3525 uchar *end = begin + dst->bytes_per_line;
3526 for (uchar *p = begin; p < end; ++p) {
3530 if (shift != 8 && p != begin) {
3531 if (dst->format == QImage::Format_Mono) {
3532 for (
int i = 0; i < shift; ++i) {
3534 p[-1] |= (*p & (128 >> i)) >> (7 - i);
3537 for (
int i = 0; i < shift; ++i) {
3539 p[-1] |= (*p & (1 << i)) << (7 - i);
3545 if (dst->format == QImage::Format_Mono)
3555
3556
3557QImage QImage::mirrored_helper(
bool horizontal,
bool vertical)
const
3562 if ((d->width <= 1 && d->height <= 1) || (!horizontal && !vertical))
3566 QImage result(d->width, d->height, d->format);
3573 result.d->colortable = d->colortable;
3574 result.d->has_alpha_clut = d->has_alpha_clut;
3575 copyMetadata(result.d, d);
3577 do_mirror(result.d, d, horizontal, vertical);
3583
3584
3585void QImage::mirrored_inplace(
bool horizontal,
bool vertical)
3587 if (!d || (d->width <= 1 && d->height <= 1) || (!horizontal && !vertical))
3596 do_mirror(d, d, horizontal, vertical);
3600
3601
3602
3603
3604
3605
3606
3607
3608
3609
3610
3613
3614
3615
3616
3617
3618
3619
3620
3622static inline void rgbSwapped_generic(
int width,
int height,
const QImage *src, QImage *dst,
const QPixelLayout* layout)
3624 const RbSwapFunc func = layout->rbSwap;
3626 qWarning(
"Trying to rb-swap an image format where it doesn't make sense");
3632 for (
int i = 0; i < height; ++i) {
3633 uchar *q = dst->scanLine(i);
3634 const uchar *p = src->constScanLine(i);
3640
3641
3642QImage Q_TRACE_INSTRUMENT(qtgui) QImage::rgbSwapped_helper()
const
3647 Q_TRACE_SCOPE(QImage_rgbSwapped_helper);
3651 switch (d->format) {
3652 case Format_Invalid:
3657 case Format_Grayscale8:
3658 case Format_Grayscale16:
3661 case Format_MonoLSB:
3662 case Format_Indexed8:
3664 for (
int i = 0; i < res.d->colortable.size(); i++) {
3665 QRgb c = res.d->colortable.at(i);
3666 res.d->colortable[i] = QRgb(((c << 16) & 0xff0000) | ((c >> 16) & 0xff) | (c & 0xff00ff00));
3669 case Format_RGBX8888:
3670 case Format_RGBA8888:
3671 case Format_RGBA8888_Premultiplied:
3672#if Q_BYTE_ORDER == Q_BIG_ENDIAN
3673 res = QImage(d->width, d->height, d->format);
3675 for (
int i = 0; i < d->height; i++) {
3676 uint *q = (uint*)res.scanLine(i);
3677 const uint *p = (
const uint*)constScanLine(i);
3678 const uint *end = p + d->width;
3681 *q = ((c << 16) & 0xff000000) | ((c >> 16) & 0xff00) | (c & 0x00ff00ff);
3693 case Format_ARGB32_Premultiplied:
3694 res = QImage(d->width, d->height, d->format);
3696 for (
int i = 0; i < d->height; i++) {
3697 uint *q = (uint*)res.scanLine(i);
3698 const uint *p = (
const uint*)constScanLine(i);
3699 const uint *end = p + d->width;
3702 *q = ((c << 16) & 0xff0000) | ((c >> 16) & 0xff) | (c & 0xff00ff00);
3709 res = QImage(d->width, d->height, d->format);
3711 for (
int i = 0; i < d->height; i++) {
3712 ushort *q = (ushort*)res.scanLine(i);
3713 const ushort *p = (
const ushort*)constScanLine(i);
3714 const ushort *end = p + d->width;
3717 *q = ((c << 11) & 0xf800) | ((c >> 11) & 0x1f) | (c & 0x07e0);
3724 res = QImage(d->width, d->height, d->format);
3726 rgbSwapped_generic(d->width, d->height,
this, &res, &qPixelLayouts[d->format]);
3729 copyMetadata(res.d, d);
3734
3735
3736void QImage::rgbSwapped_inplace()
3747 switch (d->format) {
3748 case Format_Invalid:
3753 case Format_Grayscale8:
3754 case Format_Grayscale16:
3757 case Format_MonoLSB:
3758 case Format_Indexed8:
3759 for (
int i = 0; i < d->colortable.size(); i++) {
3760 QRgb c = d->colortable.at(i);
3761 d->colortable[i] = QRgb(((c << 16) & 0xff0000) | ((c >> 16) & 0xff) | (c & 0xff00ff00));
3764 case Format_RGBX8888:
3765 case Format_RGBA8888:
3766 case Format_RGBA8888_Premultiplied:
3767#if Q_BYTE_ORDER == Q_BIG_ENDIAN
3768 for (
int i = 0; i < d->height; i++) {
3769 uint *p = (uint*)scanLine(i);
3770 uint *end = p + d->width;
3773 *p = ((c << 16) & 0xff000000) | ((c >> 16) & 0xff00) | (c & 0x00ff00ff);
3784 case Format_ARGB32_Premultiplied:
3785 for (
int i = 0; i < d->height; i++) {
3786 uint *p = (uint*)scanLine(i);
3787 uint *end = p + d->width;
3790 *p = ((c << 16) & 0xff0000) | ((c >> 16) & 0xff) | (c & 0xff00ff00);
3796 for (
int i = 0; i < d->height; i++) {
3797 ushort *p = (ushort*)scanLine(i);
3798 ushort *end = p + d->width;
3801 *p = ((c << 11) & 0xf800) | ((c >> 11) & 0x1f) | (c & 0x07e0);
3807 case Format_A2BGR30_Premultiplied:
3809 case Format_A2RGB30_Premultiplied:
3810 for (
int i = 0; i < d->height; i++) {
3811 uint *p = (uint*)scanLine(i);
3812 uint *end = p + d->width;
3814 *p = qRgbSwapRgb30(*p);
3820 rgbSwapped_generic(d->width, d->height,
this,
this, &qPixelLayouts[d->format]);
3826
3827
3828
3829
3830
3831
3832
3833
3834
3835
3836
3837
3838
3839
3840
3841
3842
3844bool QImage::load(
const QString &fileName,
const char* format)
3846 *
this = QImageReader(fileName, format).read();
3851
3852
3853
3854
3855
3857bool QImage::load(QIODevice* device,
const char* format)
3859 *
this = QImageReader(device, format).read();
3864
3865
3866
3867
3868
3869
3870
3871
3872
3873
3874
3876bool QImage::loadFromData(QByteArrayView data,
const char *format)
3878 *
this = fromData(data, format);
3883
3884
3885
3886
3887
3888
3890bool QImage::loadFromData(
const uchar *buf,
int len,
const char *format)
3892 return loadFromData(QByteArrayView(buf, len), format);
3896
3897
3898
3899
3900
3901
3904
3905
3906
3907
3908
3909
3910
3911
3912
3913
3914
3915
3916
3918QImage QImage::fromData(QByteArrayView data,
const char *format)
3920 QByteArray a = QByteArray::fromRawData(data.constData(), data.size());
3923 b.open(QIODevice::ReadOnly);
3924 return QImageReader(&b, format).read();
3928
3929
3930
3931
3932
3933
3935QImage QImage::fromData(
const uchar *data,
int size,
const char *format)
3937 return fromData(QByteArrayView(data, size), format);
3941
3942
3943
3944
3945
3946
3947
3950
3951
3952
3953
3954
3955
3956
3957
3958
3959
3960
3961
3962
3963
3964
3965bool QImage::save(
const QString &fileName,
const char *format,
int quality)
const
3969 QImageWriter writer(fileName, format);
3970 return d->doImageIO(
this, &writer, quality);
3974
3975
3976
3977
3978
3979
3980
3981
3982
3984bool QImage::save(QIODevice* device,
const char* format,
int quality)
const
3988 QImageWriter writer(device, format);
3989 return d->doImageIO(
this, &writer, quality);
3993
3995bool QImageData::doImageIO(
const QImage *image, QImageWriter *writer,
int quality)
const
3997 if (quality > 100 || quality < -1)
3998 qWarning(
"QImage::save: Quality out of range [-1, 100]");
4000 writer->setQuality(qMin(quality,100));
4001 const bool result = writer->write(*image);
4004 qWarning(
"QImage::save: failed to write image - %s", qPrintable(writer->errorString()));
4009bool QImageData::isWithinIOAllocationLimit(
int width,
int height, QImage::Format format,
4010 const char *context)
4012 if (
const int mbLimit = QImageReader::allocationLimit()) {
4013 qsizetype depth = qMax(qt_depthForFormat(format), 32);
4014 QImageData::ImageSizeParameters szp =
4015 QImageData::calculateImageParameters(width, height, depth);
4018 const qsizetype mb = szp.totalSize >> 20;
4019 if (mb > mbLimit || (mb == mbLimit && szp.totalSize % (1 << 20))) {
4021 qCWarning(lcImageIo,
"%s: Rejecting image as it exceeds the current "
4022 "allocation limit of %i megabytes", context, mbLimit);
4031
4032
4033#if !defined(QT_NO_DATASTREAM)
4035
4036
4037
4038
4039
4040
4041
4042
4043
4045QDataStream &operator<<(QDataStream &s,
const QImage &image)
4047 if (s.version() >= 5) {
4048 if (image.isNull()) {
4056 QImageWriter writer(s.device(), s.version() == 1 ?
"bmp" :
"png");
4057 writer.write(image);
4062
4063
4064
4065
4066
4067
4068
4069
4071QDataStream &operator>>(QDataStream &s, QImage &image)
4073 if (s.version() >= 5) {
4081 image = QImageReader(s.device(), s.version() == 1 ?
"bmp" :
"png").read();
4082 if (image.isNull() && s.version() >= 5)
4083 s.setStatus(QDataStream::ReadPastEnd);
4091
4092
4093
4094
4095
4096
4097
4098
4099
4100
4101
4103bool QImage::operator==(
const QImage & i)
const
4112 if (i.d->height != d->height || i.d->width != d->width || i.d->format != d->format || i.d->colorSpace != d->colorSpace)
4115 if (d->format != Format_RGB32) {
4116 if (d->format >= Format_ARGB32) {
4117 const int n = d->width * d->depth / 8;
4118 if (n == d->bytes_per_line && n == i.d->bytes_per_line) {
4119 if (memcmp(bits(), i.bits(), d->nbytes))
4122 for (
int y = 0; y < d->height; ++y) {
4123 if (memcmp(scanLine(y), i.scanLine(y), n))
4128 const int w = width();
4129 const int h = height();
4130 const QList<QRgb> &colortable = d->colortable;
4131 const QList<QRgb> &icolortable = i.d->colortable;
4132 for (
int y=0; y<h; ++y) {
4133 for (
int x=0; x<w; ++x) {
4134 if (colortable[pixelIndex(x, y)] != icolortable[i.pixelIndex(x, y)])
4141 for(
int l = 0; l < d->height; l++) {
4143 const uint *p1 =
reinterpret_cast<
const uint*>(scanLine(l));
4144 const uint *p2 =
reinterpret_cast<
const uint*>(i.scanLine(l));
4146 if ((*p1++ & 0x00ffffff) != (*p2++ & 0x00ffffff))
4156
4157
4158
4159
4160
4161
4162
4163
4164
4165
4166
4168bool QImage::operator!=(
const QImage & i)
const
4170 return !(*
this == i);
4177
4178
4179
4180
4181
4182
4183
4184int QImage::dotsPerMeterX()
const
4186 return d ? qRound(d->dpmx) : 0;
4190
4191
4192
4193
4194
4195
4196
4197int QImage::dotsPerMeterY()
const
4199 return d ? qRound(d->dpmy) : 0;
4203
4204
4205
4206
4207
4208
4209
4210
4211
4212
4213
4214void QImage::setDotsPerMeterX(
int x)
4216 if (!d || !x || d->dpmx == x)
4225
4226
4227
4228
4229
4230
4231
4232
4233
4234
4235
4236void QImage::setDotsPerMeterY(
int y)
4238 if (!d || !y || d->dpmy == y)
4247
4248
4249
4250
4251
4252
4253
4254QPoint QImage::offset()
const
4256 return d ? d->offset : QPoint();
4261
4262
4263
4264
4265
4266
4267
4268void QImage::setOffset(
const QPoint& p)
4270 if (!d || d->offset == p)
4279
4280
4281
4282
4283
4284
4285
4286QStringList QImage::textKeys()
const
4288 return d ? QStringList(d->text.keys()) : QStringList();
4292
4293
4294
4295
4296
4297
4298QString QImage::text(
const QString &key)
const
4304 return d->text.value(key);
4307 for (
auto it = d->text.begin(), end = d->text.end(); it != end; ++it)
4308 tmp += it.key() +
": "_L1 + it.value().simplified() +
"\n\n"_L1;
4315
4316
4317
4318
4319
4320
4321
4322
4323
4324
4325
4326
4327
4328
4329
4330
4331
4332
4333
4334
4335
4336
4337
4338void QImage::setText(
const QString &key,
const QString &value)
4345 d->text.insert(key, value);
4349
4350
4351
4352
4353QPaintEngine *QImage::paintEngine()
const
4358 if (!d->paintEngine) {
4359 QPaintDevice *paintDevice =
const_cast<QImage *>(
this);
4360 QPlatformIntegration *platformIntegration = QGuiApplicationPrivate::platformIntegration();
4361 if (platformIntegration)
4362 d->paintEngine = platformIntegration->createImagePaintEngine(paintDevice);
4363 if (!d->paintEngine)
4364 d->paintEngine =
new QRasterPaintEngine(paintDevice);
4367 return d->paintEngine;
4372
4373
4374
4375
4376int QImage::metric(PaintDeviceMetric metric)
const
4389 return qRound(d->width * 1000 / d->dpmx);
4392 return qRound(d->height * 1000 / d->dpmy);
4395 return d->colortable.size();
4401 return qRound(d->dpmx * 0.0254);
4405 return qRound(d->dpmy * 0.0254);
4408 case PdmPhysicalDpiX:
4409 return qRound(d->dpmx * 0.0254);
4412 case PdmPhysicalDpiY:
4413 return qRound(d->dpmy * 0.0254);
4416 case PdmDevicePixelRatio:
4417 return d->devicePixelRatio;
4420 case PdmDevicePixelRatioScaled:
4421 return d->devicePixelRatio * QPaintDevice::devicePixelRatioFScale();
4424 case PdmDevicePixelRatioF_EncodedA:
4426 case PdmDevicePixelRatioF_EncodedB:
4427 return QPaintDevice::encodeMetricF(metric, d->devicePixelRatio);
4431 qWarning(
"QImage::metric(): Unhandled metric type %d", metric);
4440
4441
4443
4444
4445
4446
4447
4448
4449
4450
4451
4452
4453
4454
4455
4456
4457
4458
4459
4460
4463#define IWX_MSB(b) if (trigx < maxws && trigy < maxhs) {
4464 if (*(sptr+sbpl*(trigy>>12
)+(trigx>>15
)) &
4465 (1
<< (7
-((trigx>>12
)&7
))))
4472#define IWX_LSB(b) if (trigx < maxws && trigy < maxhs) {
4473 if (*(sptr+sbpl*(trigy>>12
)+(trigx>>15
)) &
4474 (1
<< ((trigx>>12
)&7
)))
4481#define IWX_PIX(b) if (trigx < maxws && trigy < maxhs) {
4482 if ((*(sptr+sbpl*(trigy>>12
)+(trigx>>15
)) &
4483 (1
<< (7
-((trigx>>12
)&7
)))) == 0
)
4490bool qt_xForm_helper(
const QTransform &trueMat,
int xoffset,
int type,
int depth,
4491 uchar *dptr, qsizetype dbpl,
int p_inc,
int dHeight,
4492 const uchar *sptr, qsizetype sbpl,
int sWidth,
int sHeight)
4494 int m11 =
int(trueMat.m11()*4096.0);
4495 int m12 =
int(trueMat.m12()*4096.0);
4496 int m21 =
int(trueMat.m21()*4096.0);
4497 int m22 =
int(trueMat.m22()*4096.0);
4498 int dx = qRound(trueMat.dx()*4096.0);
4499 int dy = qRound(trueMat.dy()*4096.0);
4501 int m21ydx = dx + (xoffset<<16) + (m11 + m21) / 2;
4502 int m22ydy = dy + (m12 + m22) / 2;
4505 uint maxws = sWidth<<12;
4506 uint maxhs = sHeight<<12;
4508 for (
int y=0; y<dHeight; y++) {
4511 uchar *maxp = dptr + dbpl;
4515 while (dptr < maxp) {
4516 if (trigx < maxws && trigy < maxhs)
4517 *dptr = *(sptr+sbpl*(trigy>>12)+(trigx>>12));
4525 while (dptr < maxp) {
4526 if (trigx < maxws && trigy < maxhs)
4527 *((ushort*)dptr) = *((
const ushort *)(sptr+sbpl*(trigy>>12) +
4537 while (dptr < maxp) {
4538 if (trigx < maxws && trigy < maxhs) {
4539 const uchar *p2 = sptr+sbpl*(trigy>>12) + ((trigx>>12)*3);
4551 while (dptr < maxp) {
4552 if (trigx < maxws && trigy < maxhs)
4553 *((uint*)dptr) = *((
const uint *)(sptr+sbpl*(trigy>>12) +
4568 while (dptr < maxp) {
4581 while (dptr < maxp) {
4606
4607
4608
4609
4610
4611
4612qint64 QImage::cacheKey()
const
4617 return (((qint64) d->ser_no) << 32) | ((qint64) d->detach_no);
4621
4622
4623
4624
4625
4626
4628bool QImage::isDetached()
const
4630 return d && d->ref.loadRelaxed() == 1;
4635
4636
4637
4638
4639
4640
4641
4642
4643
4644
4645
4646
4647
4648
4649
4650
4651
4653void QImage::setAlphaChannel(
const QImage &alphaChannel)
4655 if (!d || alphaChannel.isNull())
4658 if (d->paintEngine && d->paintEngine->isActive()) {
4659 qWarning(
"QImage::setAlphaChannel: "
4660 "Unable to set alpha channel while image is being painted on");
4664 const Format alphaFormat = qt_alphaVersionForPainting(d->format);
4665 if (d->format == alphaFormat)
4668 convertTo(alphaFormat);
4674 if (alphaChannel.format() == QImage::Format_Alpha8 || (alphaChannel.d->depth == 8 && alphaChannel.isGrayscale()))
4675 sourceImage = alphaChannel;
4677 sourceImage = alphaChannel.convertToFormat(QImage::Format_Grayscale8);
4678 if (!sourceImage.reinterpretAsFormat(QImage::Format_Alpha8))
4681 QPainter painter(
this);
4682 if (sourceImage.size() != size())
4683 painter.setRenderHint(QPainter::SmoothPixmapTransform);
4684 painter.setCompositionMode(QPainter::CompositionMode_DestinationIn);
4685 painter.drawImage(rect(), sourceImage);
4689
4690
4691
4692
4693
4694bool QImage::hasAlphaChannel()
const
4698 const QPixelFormat format = pixelFormat();
4699 if (format.alphaUsage() == QPixelFormat::UsesAlpha)
4701 if (format.colorModel() == QPixelFormat::Indexed)
4702 return d->has_alpha_clut;
4707
4708
4709
4710
4711
4712
4713
4714
4715
4716int QImage::bitPlaneCount()
const
4721 switch (d->format) {
4722 case QImage::Format_Invalid:
4724 case QImage::Format_BGR30:
4725 case QImage::Format_RGB30:
4728 case QImage::Format_RGB32:
4729 case QImage::Format_RGBX8888:
4732 case QImage::Format_RGB666:
4735 case QImage::Format_RGB555:
4738 case QImage::Format_ARGB8555_Premultiplied:
4741 case QImage::Format_RGB444:
4744 case QImage::Format_RGBX64:
4745 case QImage::Format_RGBX16FPx4:
4748 case QImage::Format_RGBX32FPx4:
4752 bpc = qt_depthForFormat(d->format);
4759
4760
4761
4762
4763
4764
4765
4766
4767
4768
4769QImage QImage::smoothScaled(
int w,
int h)
const
4772 switch (src.format()) {
4773 case QImage::Format_RGB32:
4774 case QImage::Format_ARGB32_Premultiplied:
4775#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
4776 case QImage::Format_RGBX8888:
4778 case QImage::Format_RGBA8888_Premultiplied:
4779#if QT_CONFIG(raster_64bit)
4780 case QImage::Format_RGBX64:
4781 case QImage::Format_RGBA64_Premultiplied:
4783 case QImage::Format_RGBA64:
4784 case QImage::Format_Grayscale16:
4785 src.convertTo(QImage::Format_RGBA64_Premultiplied);
4788#if QT_CONFIG(raster_fp)
4789 case QImage::Format_RGBX32FPx4:
4790 case QImage::Format_RGBA32FPx4_Premultiplied:
4792 case QImage::Format_RGBX16FPx4:
4793 src.convertTo(QImage::Format_RGBX32FPx4);
4795 case QImage::Format_RGBA16FPx4:
4796 case QImage::Format_RGBA16FPx4_Premultiplied:
4797 case QImage::Format_RGBA32FPx4:
4798 src.convertTo(QImage::Format_RGBA32FPx4_Premultiplied);
4801 case QImage::Format_CMYK8888:
4804 if (src.hasAlphaChannel())
4805 src.convertTo(QImage::Format_ARGB32_Premultiplied);
4807 src.convertTo(QImage::Format_RGB32);
4809 src = qSmoothScaleImage(src, w, h);
4811 copyMetadata(src.d, d);
4815static QImage rotated90(
const QImage &image)
4817 QImage out(image.height(), image.width(), image.format());
4820 copyMetadata(QImageData::get(out), QImageData::get(image));
4821 if (image.colorCount() > 0)
4822 out.setColorTable(image.colorTable());
4823 int w = image.width();
4824 int h = image.height();
4825 const MemRotateFunc memrotate = qMemRotateFunctions[qPixelLayouts[image.format()].bpp][2];
4827 memrotate(image.constBits(), w, h, image.bytesPerLine(), out.bits(), out.bytesPerLine());
4829 for (
int y=0; y<h; ++y) {
4830 if (image.colorCount())
4831 for (
int x=0; x<w; ++x)
4832 out.setPixel(h-y-1, x, image.pixelIndex(x, y));
4834 for (
int x=0; x<w; ++x)
4835 out.setPixel(h-y-1, x, image.pixel(x, y));
4841static QImage rotated180(
const QImage &image)
4843 const MemRotateFunc memrotate = qMemRotateFunctions[qPixelLayouts[image.format()].bpp][1];
4845 return image.flipped(Qt::Horizontal | Qt::Vertical);
4847 QImage out(image.width(), image.height(), image.format());
4850 copyMetadata(QImageData::get(out), QImageData::get(image));
4851 if (image.colorCount() > 0)
4852 out.setColorTable(image.colorTable());
4853 int w = image.width();
4854 int h = image.height();
4855 memrotate(image.constBits(), w, h, image.bytesPerLine(), out.bits(), out.bytesPerLine());
4859static QImage rotated270(
const QImage &image)
4861 QImage out(image.height(), image.width(), image.format());
4864 copyMetadata(QImageData::get(out), QImageData::get(image));
4865 if (image.colorCount() > 0)
4866 out.setColorTable(image.colorTable());
4867 int w = image.width();
4868 int h = image.height();
4869 const MemRotateFunc memrotate = qMemRotateFunctions[qPixelLayouts[image.format()].bpp][0];
4871 memrotate(image.constBits(), w, h, image.bytesPerLine(), out.bits(), out.bytesPerLine());
4873 for (
int y=0; y<h; ++y) {
4874 if (image.colorCount())
4875 for (
int x=0; x<w; ++x)
4876 out.setPixel(y, w-x-1, image.pixelIndex(x, y));
4878 for (
int x=0; x<w; ++x)
4879 out.setPixel(y, w-x-1, image.pixel(x, y));
4886
4887
4888
4889
4890
4891
4892
4893
4894
4895
4896
4897
4898
4899
4900
4901
4902
4903
4904
4905
4906
4907
4909QImage Q_TRACE_INSTRUMENT(qtgui) QImage::transformed(
const QTransform &matrix, Qt::TransformationMode mode )
const
4914 Q_TRACE_PARAM_REPLACE(
const QTransform &,
double[9]);
4915 Q_TRACE_SCOPE(QImage_transformed, QList<
double>({matrix.m11(), matrix.m12(), matrix.m13(),
4916 matrix.m21(), matrix.m22(), matrix.m23(),
4917 matrix.m31(), matrix.m32(), matrix.m33()}).data(), mode);
4920 const int ws = width();
4921 const int hs = height();
4928 QTransform mat = trueMatrix(matrix, ws, hs);
4929 bool complex_xform =
false;
4930 bool scale_xform =
false;
4931 bool nonpaintable_scale_xform =
false;
4932 if (mat.type() <= QTransform::TxScale) {
4933 if (mat.type() == QTransform::TxNone)
4935 else if (mat.m11() == -1. && mat.m22() == -1.)
4936 return rotated180(*
this);
4938 hdf = qAbs(mat.m22()) * hs;
4939 wdf = qAbs(mat.m11()) * ws;
4942 if (mat.type() <= QTransform::TxRotate && mat.m11() == 0 && mat.m22() == 0) {
4943 if (mat.m12() == 1. && mat.m21() == -1.)
4944 return rotated90(*
this);
4945 else if (mat.m12() == -1. && mat.m21() == 1.)
4946 return rotated270(*
this);
4949 QPolygonF a(QRectF(0, 0, ws, hs));
4951 const QRectF r = a.boundingRect();
4952 wdf = std::ceil(r.right()) - std::floor(r.left());
4953 hdf = std::ceil(r.bottom()) - std::floor(r.top());
4954 complex_xform =
true;
4957 if (!(wdf < INT_MAX && hdf < INT_MAX))
4959 const int wd = qRound(wdf);
4960 const int hd = qRound(hdf);
4965 if (qint64(hd) * 2 < hs || qint64(wd) * 2 < ws)
4966 nonpaintable_scale_xform =
true;
4968 if (format() == QImage::Format_CMYK8888)
4969 nonpaintable_scale_xform =
true;
4972 if (wd == 0 || hd == 0)
4975 if (scale_xform && mode == Qt::SmoothTransformation) {
4977 case QImage::Format_RGB32:
4978 case QImage::Format_ARGB32_Premultiplied:
4979#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
4980 case QImage::Format_RGBX8888:
4982 case QImage::Format_RGBA8888_Premultiplied:
4983#if QT_CONFIG(raster_64bit)
4984 case QImage::Format_RGBX64:
4985 case QImage::Format_RGBA64_Premultiplied:
4987 case QImage::Format_CMYK8888:
4989 if (mat.m11() > 0.0F && mat.m22() > 0.0F)
4990 return smoothScaled(wd, hd);
4996 if (nonpaintable_scale_xform
4997#if QT_CONFIG(qtgui_threadpool)
4998 || qint64(ws) * hs >= (1 << 20)
5002 if (mat.m11() < 0.0F && mat.m22() < 0.0F) {
5003 scaledImage = smoothScaled(wd, hd).flipped(Qt::Horizontal | Qt::Vertical);
5004 }
else if (mat.m11() < 0.0F) {
5005 scaledImage = smoothScaled(wd, hd).flipped(Qt::Horizontal);
5006 }
else if (mat.m22() < 0.0F) {
5007 scaledImage = smoothScaled(wd, hd).flipped(Qt::Vertical);
5009 scaledImage = smoothScaled(wd, hd);
5013 case QImage::Format_Mono:
5014 case QImage::Format_MonoLSB:
5015 case QImage::Format_Indexed8:
5018 return scaledImage.convertToFormat(format());
5025 qsizetype sbpl = bytesPerLine();
5026 const uchar *sptr = bits();
5028 QImage::Format target_format = d->format;
5030 if (complex_xform || mode == Qt::SmoothTransformation) {
5031 if (d->format < QImage::Format_RGB32 || (!hasAlphaChannel() && complex_xform)) {
5032 target_format = qt_alphaVersion(d->format);
5036 QImage dImage(wd, hd, target_format);
5039 if (target_format == QImage::Format_MonoLSB
5040 || target_format == QImage::Format_Mono
5041 || target_format == QImage::Format_Indexed8) {
5042 dImage.d->colortable = d->colortable;
5043 dImage.d->has_alpha_clut = d->has_alpha_clut | complex_xform;
5047 if (target_format == QImage::Format_Indexed8) {
5048 if (dImage.d->colortable.size() < 256) {
5050 dImage.d->colortable.append(0x0);
5051 memset(dImage.bits(), dImage.d->colortable.size() - 1, dImage.d->nbytes);
5053 memset(dImage.bits(), 0, dImage.d->nbytes);
5056 memset(dImage.bits(), 0x00, dImage.d->nbytes);
5058 if (target_format >= QImage::Format_RGB32 && target_format != QImage::Format_CMYK8888) {
5060 QImage sImage = (devicePixelRatio() != 1) ? QImage(constBits(), width(), height(), format()) : *
this;
5062 && (d->format == QImage::Format_MonoLSB
5063 || d->format == QImage::Format_Mono
5064 || d->format == QImage::Format_Indexed8)) {
5065 sImage.d->colortable = d->colortable;
5066 sImage.d->has_alpha_clut = d->has_alpha_clut;
5069 Q_ASSERT(sImage.devicePixelRatio() == 1);
5070 Q_ASSERT(sImage.devicePixelRatio() == dImage.devicePixelRatio());
5072 QPainter p(&dImage);
5073 if (mode == Qt::SmoothTransformation) {
5074 p.setRenderHint(QPainter::Antialiasing);
5075 p.setRenderHint(QPainter::SmoothPixmapTransform);
5077 p.setTransform(mat);
5078 p.drawImage(QPoint(0, 0), sImage);
5081 mat = mat.inverted(&invertible);
5087 qsizetype dbpl = dImage.bytesPerLine();
5088 qt_xForm_helper(mat, 0, type, bpp, dImage.bits(), dbpl, 0, hd, sptr, sbpl, ws, hs);
5090 copyMetadata(dImage.d, d);
5097
5098
5099
5100
5101
5102
5103
5104
5105
5106
5107
5108
5109
5110
5111
5112
5113
5114
5116QTransform QImage::trueMatrix(
const QTransform &matrix,
int w,
int h)
5118 const QRectF mapped = matrix.mapRect(QRectF(0, 0, w, h));
5120 return matrix * QTransform().translate(-std::floor(mapped.left()), -std::floor(mapped.top()));
5124
5125
5126
5127
5128
5129
5130void QImage::setColorSpace(
const QColorSpace &colorSpace)
5134 if (d->colorSpace == colorSpace)
5136 if (colorSpace.isValid() && !qt_compatibleColorModelSource(pixelFormat().colorModel(), colorSpace.colorModel()))
5139 detachMetadata(
false);
5141 d->colorSpace = colorSpace;
5145
5146
5147
5148
5149
5150
5151
5152
5153
5154
5155
5156void QImage::convertToColorSpace(
const QColorSpace &colorSpace)
5158 if (!d || !d->colorSpace.isValid())
5160 if (!colorSpace.isValidTarget()) {
5161 qWarning() <<
"QImage::convertToColorSpace: Output colorspace is not valid";
5164 if (d->colorSpace == colorSpace)
5166 if (!qt_compatibleColorModelTarget(pixelFormat().colorModel(),
5167 colorSpace.colorModel(), colorSpace.transformModel())) {
5168 *
this = convertedToColorSpace(colorSpace);
5171 applyColorTransform(d->colorSpace.transformationToColorSpace(colorSpace));
5172 if (d->ref.loadRelaxed() != 1)
5173 detachMetadata(
false);
5174 d->colorSpace = colorSpace;
5178
5179
5180
5181
5182
5183
5184
5185
5186
5187
5188
5189
5190void QImage::convertToColorSpace(
const QColorSpace &colorSpace, QImage::Format format, Qt::ImageConversionFlags flags)
5192 if (!d || !d->colorSpace.isValid())
5194 if (!colorSpace.isValidTarget()) {
5195 qWarning() <<
"QImage::convertToColorSpace: Output colorspace is not valid";
5198 if (!qt_compatibleColorModelTarget(toPixelFormat(format).colorModel(),
5199 colorSpace.colorModel(), colorSpace.transformModel())) {
5200 qWarning() <<
"QImage::convertToColorSpace: Color space is not compatible with format";
5204 if (d->colorSpace == colorSpace)
5205 return convertTo(format, flags);
5206 applyColorTransform(d->colorSpace.transformationToColorSpace(colorSpace), format, flags);
5207 d->colorSpace = colorSpace;
5211
5212
5213
5214
5215
5216
5217
5218
5219
5220
5221
5222
5223
5224QImage QImage::convertedToColorSpace(
const QColorSpace &colorSpace)
const
5226 if (!d || !d->colorSpace.isValid())
5228 if (!colorSpace.isValidTarget()) {
5229 qWarning() <<
"QImage::convertedToColorSpace: Output colorspace is not valid";
5232 if (d->colorSpace == colorSpace)
5234 QImage image = colorTransformed(d->colorSpace.transformationToColorSpace(colorSpace));
5235 image.setColorSpace(colorSpace);
5240
5241
5242
5243
5244
5245
5246
5247
5248
5249
5250
5251
5252
5253QImage QImage::convertedToColorSpace(
const QColorSpace &colorSpace, QImage::Format format, Qt::ImageConversionFlags flags)
const &
5255 if (!d || !d->colorSpace.isValid())
5257 if (!colorSpace.isValidTarget()) {
5258 qWarning() <<
"QImage::convertedToColorSpace: Output colorspace is not valid";
5261 if (!qt_compatibleColorModelTarget(toPixelFormat(format).colorModel(),
5262 colorSpace.colorModel(), colorSpace.transformModel())) {
5263 qWarning() <<
"QImage::convertedToColorSpace: Color space is not compatible with format";
5266 if (d->colorSpace == colorSpace)
5267 return convertedTo(format, flags);
5268 QImage image = colorTransformed(d->colorSpace.transformationToColorSpace(colorSpace), format, flags);
5269 image.setColorSpace(colorSpace);
5273QImage QImage::convertedToColorSpace(
const QColorSpace &colorSpace, QImage::Format format, Qt::ImageConversionFlags flags) &&
5275 if (!d || !d->colorSpace.isValid())
5277 if (!colorSpace.isValidTarget()) {
5278 qWarning() <<
"QImage::convertedToColorSpace: Output colorspace is not valid";
5281 if (!qt_compatibleColorModelTarget(toPixelFormat(format).colorModel(),
5282 colorSpace.colorModel(), colorSpace.transformModel())) {
5283 qWarning() <<
"QImage::convertedToColorSpace: Color space is not compatible with format";
5286 if (d->colorSpace == colorSpace)
5287 return convertedTo(format, flags);
5288 applyColorTransform(d->colorSpace.transformationToColorSpace(colorSpace), format, flags);
5289 return std::move(*
this);
5293
5294
5295
5296
5297QColorSpace QImage::colorSpace()
const
5300 return QColorSpace();
5301 return d->colorSpace;
5305
5306
5307
5308
5309void QImage::applyColorTransform(
const QColorTransform &transform)
5311 if (transform.isIdentity())
5314 if (!qt_compatibleColorModelSource(pixelFormat().colorModel(), QColorTransformPrivate::get(transform)->colorSpaceIn->colorModel) ||
5315 !qt_compatibleColorModelTarget(pixelFormat().colorModel(), QColorTransformPrivate::get(transform)->colorSpaceOut->colorModel,
5316 QColorTransformPrivate::get(transform)->colorSpaceOut->transformModel)) {
5317 qWarning() <<
"QImage::applyColorTransform can not apply format switching transform without switching format";
5324 if (pixelFormat().colorModel() == QPixelFormat::Indexed) {
5325 for (
int i = 0; i < d->colortable.size(); ++i)
5326 d->colortable[i] = transform.map(d->colortable[i]);
5329 QImage::Format oldFormat = format();
5330 if (qt_fpColorPrecision(oldFormat)) {
5331 if (oldFormat != QImage::Format_RGBX32FPx4 && oldFormat != QImage::Format_RGBA32FPx4
5332 && oldFormat != QImage::Format_RGBA32FPx4_Premultiplied)
5333 convertTo(QImage::Format_RGBA32FPx4);
5334 }
else if (depth() > 32) {
5335 if (oldFormat != QImage::Format_RGBX64 && oldFormat != QImage::Format_RGBA64
5336 && oldFormat != QImage::Format_RGBA64_Premultiplied)
5337 convertTo(QImage::Format_RGBA64);
5338 }
else if (oldFormat != QImage::Format_ARGB32 && oldFormat != QImage::Format_RGB32
5339 && oldFormat != QImage::Format_ARGB32_Premultiplied && oldFormat != QImage::Format_CMYK8888
5340 && oldFormat != QImage::Format_Grayscale8 && oldFormat != QImage::Format_Grayscale16) {
5341 if (hasAlphaChannel())
5342 convertTo(QImage::Format_ARGB32);
5344 convertTo(QImage::Format_RGB32);
5347 QColorTransformPrivate::TransformFlags flags = QColorTransformPrivate::Unpremultiplied;
5349 case Format_ARGB32_Premultiplied:
5350 case Format_RGBA64_Premultiplied:
5351 case Format_RGBA32FPx4_Premultiplied:
5352 flags = QColorTransformPrivate::Premultiplied;
5354 case Format_Grayscale8:
5355 case Format_Grayscale16:
5357 case Format_CMYK8888:
5359 case Format_RGBX32FPx4:
5360 flags = QColorTransformPrivate::InputOpaque;
5364 case Format_RGBA32FPx4:
5370 std::function<
void(
int,
int)> transformSegment;
5372 if (format() == Format_Grayscale8) {
5373 transformSegment = [&](
int yStart,
int yEnd) {
5374 for (
int y = yStart; y < yEnd; ++y) {
5375 uint8_t *scanline =
reinterpret_cast<uint8_t *>(d->data + y * d->bytes_per_line);
5376 QColorTransformPrivate::get(transform)->apply(scanline, scanline, width(), flags);
5379 }
else if (format() == Format_Grayscale16) {
5380 transformSegment = [&](
int yStart,
int yEnd) {
5381 for (
int y = yStart; y < yEnd; ++y) {
5382 uint16_t *scanline =
reinterpret_cast<uint16_t *>(d->data + y * d->bytes_per_line);
5383 QColorTransformPrivate::get(transform)->apply(scanline, scanline, width(), flags);
5386 }
else if (qt_fpColorPrecision(format())) {
5387 transformSegment = [&](
int yStart,
int yEnd) {
5388 for (
int y = yStart; y < yEnd; ++y) {
5389 QRgbaFloat32 *scanline =
reinterpret_cast<QRgbaFloat32 *>(d->data + y * d->bytes_per_line);
5390 QColorTransformPrivate::get(transform)->apply(scanline, scanline, width(), flags);
5393 }
else if (depth() > 32) {
5394 transformSegment = [&](
int yStart,
int yEnd) {
5395 for (
int y = yStart; y < yEnd; ++y) {
5396 QRgba64 *scanline =
reinterpret_cast<QRgba64 *>(d->data + y * d->bytes_per_line);
5397 QColorTransformPrivate::get(transform)->apply(scanline, scanline, width(), flags);
5400 }
else if (oldFormat == QImage::Format_CMYK8888) {
5401 transformSegment = [&](
int yStart,
int yEnd) {
5402 for (
int y = yStart; y < yEnd; ++y) {
5403 QCmyk32 *scanline =
reinterpret_cast<QCmyk32 *>(d->data + y * d->bytes_per_line);
5404 QColorTransformPrivate::get(transform)->apply(scanline, scanline, width(), flags);
5408 transformSegment = [&](
int yStart,
int yEnd) {
5409 for (
int y = yStart; y < yEnd; ++y) {
5410 QRgb *scanline =
reinterpret_cast<QRgb *>(d->data + y * d->bytes_per_line);
5411 QColorTransformPrivate::get(transform)->apply(scanline, scanline, width(), flags);
5416#if QT_CONFIG(qtgui_threadpool)
5417 int segments = (qsizetype(width()) * height()) >> 16;
5418 segments = std::min(segments, height());
5419 QThreadPool *threadPool = QGuiApplicationPrivate::qtGuiThreadPool();
5420 if (segments > 1 && threadPool && !threadPool->contains(QThread::currentThread())) {
5421 QLatch latch(segments);
5423 for (
int i = 0; i < segments; ++i) {
5424 int yn = (height() - y) / (segments - i);
5425 threadPool->start([&, y, yn]() {
5426 transformSegment(y, y + yn);
5434 transformSegment(0, height());
5436 if (oldFormat != format())
5437 *
this = std::move(*
this).convertToFormat(oldFormat);
5441
5442
5443
5444
5445
5446
5447
5448void QImage::applyColorTransform(
const QColorTransform &transform, QImage::Format toFormat, Qt::ImageConversionFlags flags)
5452 if (transform.isIdentity())
5453 return convertTo(toFormat, flags);
5455 *
this = colorTransformed(transform, toFormat, flags);
5459
5460
5461
5462
5463
5464
5465
5466
5467
5468
5469
5470QImage QImage::colorTransformed(
const QColorTransform &transform)
const &
5474 if (transform.isIdentity())
5477 const QColorSpacePrivate *inColorSpace = QColorTransformPrivate::get(transform)->colorSpaceIn.constData();
5478 const QColorSpacePrivate *outColorSpace = QColorTransformPrivate::get(transform)->colorSpaceOut.constData();
5479 if (!qt_compatibleColorModelSource(pixelFormat().colorModel(), inColorSpace->colorModel)) {
5480 qWarning() <<
"QImage::colorTransformed: Invalid input color space for transform";
5483 if (!qt_compatibleColorModelTarget(pixelFormat().colorModel(), outColorSpace->colorModel, outColorSpace->transformModel)) {
5485 switch (outColorSpace->colorModel) {
5486 case QColorSpace::ColorModel::Rgb:
5487 return colorTransformed(transform, qt_highColorPrecision(format(),
true) ? QImage::Format_RGBX64 : QImage::Format_RGB32);
5488 case QColorSpace::ColorModel::Gray:
5489 return colorTransformed(transform, qt_highColorPrecision(format(),
true) ? QImage::Format_Grayscale16 : QImage::Format_Grayscale8);
5490 case QColorSpace::ColorModel::Cmyk:
5491 return colorTransformed(transform, QImage::Format_CMYK8888);
5492 case QColorSpace::ColorModel::Undefined:
5498 QImage image = copy();
5499 image.applyColorTransform(transform);
5503static bool isRgb32Data(QImage::Format f)
5506 case QImage::Format_RGB32:
5507 case QImage::Format_ARGB32:
5508 case QImage::Format_ARGB32_Premultiplied:
5516static bool isRgb64Data(QImage::Format f)
5519 case QImage::Format_RGBX64:
5520 case QImage::Format_RGBA64:
5521 case QImage::Format_RGBA64_Premultiplied:
5529static bool isRgb32fpx4Data(QImage::Format f)
5532 case QImage::Format_RGBX32FPx4:
5533 case QImage::Format_RGBA32FPx4:
5534 case QImage::Format_RGBA32FPx4_Premultiplied:
5543
5544
5545
5546
5547
5548
5549
5550
5551
5552
5553
5554
5555QImage QImage::colorTransformed(
const QColorTransform &transform, QImage::Format toFormat, Qt::ImageConversionFlags flags)
const &
5559 if (toFormat == QImage::Format_Invalid)
5560 toFormat = format();
5561 if (transform.isIdentity())
5562 return convertedTo(toFormat, flags);
5564 const QColorSpacePrivate *inColorSpace = QColorTransformPrivate::get(transform)->colorSpaceIn.constData();
5565 const QColorSpacePrivate *outColorSpace = QColorTransformPrivate::get(transform)->colorSpaceOut.constData();
5566 if (!qt_compatibleColorModelSource(pixelFormat().colorModel(), inColorSpace->colorModel)) {
5567 qWarning() <<
"QImage::colorTransformed: Invalid input color space for transform";
5570 if (!qt_compatibleColorModelTarget(toPixelFormat(toFormat).colorModel(), outColorSpace->colorModel, outColorSpace->transformModel)) {
5571 qWarning() <<
"QImage::colorTransformed: Invalid output color space for transform";
5575 QImage fromImage = *
this;
5577 QImage::Format tmpFormat = toFormat;
5579 case QImage::Format_RGB32:
5580 case QImage::Format_ARGB32:
5581 case QImage::Format_ARGB32_Premultiplied:
5582 case QImage::Format_RGBX32FPx4:
5583 case QImage::Format_RGBA32FPx4:
5584 case QImage::Format_RGBA32FPx4_Premultiplied:
5585 case QImage::Format_RGBX64:
5586 case QImage::Format_RGBA64:
5587 case QImage::Format_RGBA64_Premultiplied:
5588 case QImage::Format_Grayscale8:
5589 case QImage::Format_Grayscale16:
5590 case QImage::Format_CMYK8888:
5593 case QImage::Format_RGB16:
5594 case QImage::Format_RGB444:
5595 case QImage::Format_RGB555:
5596 case QImage::Format_RGB666:
5597 case QImage::Format_RGB888:
5598 case QImage::Format_BGR888:
5599 case QImage::Format_RGBX8888:
5600 tmpFormat = QImage::Format_RGB32;
5602 case QImage::Format_Mono:
5603 case QImage::Format_MonoLSB:
5604 case QImage::Format_Indexed8:
5605 case QImage::Format_ARGB8565_Premultiplied:
5606 case QImage::Format_ARGB6666_Premultiplied:
5607 case QImage::Format_ARGB8555_Premultiplied:
5608 case QImage::Format_ARGB4444_Premultiplied:
5609 case QImage::Format_RGBA8888:
5610 case QImage::Format_RGBA8888_Premultiplied:
5611 tmpFormat = QImage::Format_ARGB32;
5613 case QImage::Format_BGR30:
5614 case QImage::Format_RGB30:
5615 tmpFormat = QImage::Format_RGBX64;
5617 case QImage::Format_A2BGR30_Premultiplied:
5618 case QImage::Format_A2RGB30_Premultiplied:
5619 tmpFormat = QImage::Format_RGBA64;
5621 case QImage::Format_RGBX16FPx4:
5622 case QImage::Format_RGBA16FPx4:
5623 case QImage::Format_RGBA16FPx4_Premultiplied:
5624 tmpFormat = QImage::Format_RGBA32FPx4;
5626 case QImage::Format_Alpha8:
5627 return convertedTo(QImage::Format_Alpha8);
5628 case QImage::Format_Invalid:
5629 case QImage::NImageFormats:
5633 QColorSpace::ColorModel inColorData = qt_csColorData(pixelFormat().colorModel());
5634 QColorSpace::ColorModel outColorData = qt_csColorData(toPixelFormat(toFormat).colorModel());
5636 if (inColorData != outColorData) {
5637 if (fromImage.format() == QImage::Format_Grayscale8 && outColorData == QColorSpace::ColorModel::Rgb)
5638 tmpFormat = QImage::Format_RGB32;
5639 else if (tmpFormat == QImage::Format_Grayscale8 && qt_highColorPrecision(fromImage.format()))
5640 tmpFormat = QImage::Format_Grayscale16;
5641 else if (fromImage.format() == QImage::Format_Grayscale16 && outColorData == QColorSpace::ColorModel::Rgb)
5642 tmpFormat = QImage::Format_RGBX64;
5644 if (tmpFormat == QImage::Format_Grayscale8 && fromImage.format() == QImage::Format_Grayscale16)
5645 tmpFormat = QImage::Format_Grayscale16;
5646 else if (qt_fpColorPrecision(fromImage.format()) && !qt_fpColorPrecision(tmpFormat))
5647 tmpFormat = QImage::Format_RGBA32FPx4;
5648 else if (isRgb32Data(tmpFormat) && qt_highColorPrecision(fromImage.format(),
true))
5649 tmpFormat = QImage::Format_RGBA64;
5652 QImage toImage(size(), tmpFormat);
5653 copyMetadata(&toImage, *
this);
5655 std::function<
void(
int,
int)> transformSegment;
5656 QColorTransformPrivate::TransformFlags transFlags = QColorTransformPrivate::Unpremultiplied;
5658 if (inColorData != outColorData) {
5660 if (inColorData == QColorSpace::ColorModel::Gray && outColorData == QColorSpace::ColorModel::Rgb) {
5662 if (format() == QImage::Format_Grayscale8) {
5663 transformSegment = [&](
int yStart,
int yEnd) {
5664 for (
int y = yStart; y < yEnd; ++y) {
5665 const quint8 *in_scanline =
reinterpret_cast<
const quint8 *>(d->data + y * d->bytes_per_line);
5666 QRgb *out_scanline =
reinterpret_cast<QRgb *>(toImage.d->data + y * toImage.bytesPerLine());
5667 QColorTransformPrivate::get(transform)->apply(out_scanline, in_scanline, width(), QColorTransformPrivate::InputOpaque);
5671 transformSegment = [&](
int yStart,
int yEnd) {
5672 for (
int y = yStart; y < yEnd; ++y) {
5673 const quint16 *in_scanline =
reinterpret_cast<
const quint16 *>(d->data + y * d->bytes_per_line);
5674 QRgba64 *out_scanline =
reinterpret_cast<QRgba64 *>(toImage.d->data + y * toImage.bytesPerLine());
5675 QColorTransformPrivate::get(transform)->apply(out_scanline, in_scanline, width(), QColorTransformPrivate::InputOpaque);
5679 }
else if (inColorData == QColorSpace::ColorModel::Gray && outColorData == QColorSpace::ColorModel::Cmyk) {
5681 if (format() == QImage::Format_Grayscale8) {
5682 transformSegment = [&](
int yStart,
int yEnd) {
5683 for (
int y = yStart; y < yEnd; ++y) {
5684 const quint8 *in_scanline =
reinterpret_cast<
const quint8 *>(d->data + y * d->bytes_per_line);
5685 QCmyk32 *out_scanline =
reinterpret_cast<QCmyk32 *>(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 quint16 *in_scanline =
reinterpret_cast<
const quint16 *>(d->data + y * d->bytes_per_line);
5693 QCmyk32 *out_scanline =
reinterpret_cast<QCmyk32 *>(toImage.d->data + y * toImage.bytesPerLine());
5694 QColorTransformPrivate::get(transform)->apply(out_scanline, in_scanline, width(), QColorTransformPrivate::InputOpaque);
5698 }
else if (inColorData == QColorSpace::ColorModel::Rgb && outColorData == QColorSpace::ColorModel::Gray) {
5700 if (tmpFormat == QImage::Format_Grayscale8) {
5701 fromImage.convertTo(QImage::Format_RGB32);
5702 transformSegment = [&](
int yStart,
int yEnd) {
5703 for (
int y = yStart; y < yEnd; ++y) {
5704 const QRgb *in_scanline =
reinterpret_cast<
const QRgb *>(fromImage.constBits() + y * fromImage.bytesPerLine());
5705 quint8 *out_scanline =
reinterpret_cast<quint8 *>(toImage.d->data + y * toImage.bytesPerLine());
5706 QColorTransformPrivate::get(transform)->apply(out_scanline, in_scanline, width(), QColorTransformPrivate::InputOpaque);
5710 fromImage.convertTo(QImage::Format_RGBX64);
5711 transformSegment = [&](
int yStart,
int yEnd) {
5712 for (
int y = yStart; y < yEnd; ++y) {
5713 const QRgba64 *in_scanline =
reinterpret_cast<
const QRgba64 *>(fromImage.constBits() + y * fromImage.bytesPerLine());
5714 quint16 *out_scanline =
reinterpret_cast<quint16 *>(toImage.d->data + y * toImage.bytesPerLine());
5715 QColorTransformPrivate::get(transform)->apply(out_scanline, in_scanline, width(), QColorTransformPrivate::InputOpaque);
5719 }
else if (inColorData == QColorSpace::ColorModel::Cmyk && outColorData == QColorSpace::ColorModel::Gray) {
5721 if (tmpFormat == QImage::Format_Grayscale8) {
5722 transformSegment = [&](
int yStart,
int yEnd) {
5723 for (
int y = yStart; y < yEnd; ++y) {
5724 const QCmyk32 *in_scanline =
reinterpret_cast<
const QCmyk32 *>(fromImage.constBits() + y * fromImage.bytesPerLine());
5725 quint8 *out_scanline =
reinterpret_cast<quint8 *>(toImage.d->data + y * toImage.bytesPerLine());
5726 QColorTransformPrivate::get(transform)->apply(out_scanline, in_scanline, width(), QColorTransformPrivate::InputOpaque);
5730 transformSegment = [&](
int yStart,
int yEnd) {
5731 for (
int y = yStart; y < yEnd; ++y) {
5732 const QCmyk32 *in_scanline =
reinterpret_cast<
const QCmyk32 *>(fromImage.constBits() + y * fromImage.bytesPerLine());
5733 quint16 *out_scanline =
reinterpret_cast<quint16 *>(toImage.d->data + y * toImage.bytesPerLine());
5734 QColorTransformPrivate::get(transform)->apply(out_scanline, in_scanline, width(), QColorTransformPrivate::InputOpaque);
5738 }
else if (inColorData == QColorSpace::ColorModel::Cmyk && outColorData == QColorSpace::ColorModel::Rgb) {
5740 if (isRgb32Data(tmpFormat) ) {
5741 transformSegment = [&](
int yStart,
int yEnd) {
5742 for (
int y = yStart; y < yEnd; ++y) {
5743 const QCmyk32 *in_scanline =
reinterpret_cast<
const QCmyk32 *>(fromImage.constBits() + y * fromImage.bytesPerLine());
5744 QRgb *out_scanline =
reinterpret_cast<QRgb *>(toImage.d->data + y * toImage.bytesPerLine());
5745 QColorTransformPrivate::get(transform)->apply(out_scanline, in_scanline, width(), QColorTransformPrivate::InputOpaque);
5748 }
else if (isRgb64Data(tmpFormat)) {
5749 transformSegment = [&](
int yStart,
int yEnd) {
5750 for (
int y = yStart; y < yEnd; ++y) {
5751 const QCmyk32 *in_scanline =
reinterpret_cast<
const QCmyk32 *>(fromImage.constBits() + y * fromImage.bytesPerLine());
5752 QRgba64 *out_scanline =
reinterpret_cast<QRgba64 *>(toImage.d->data + y * toImage.bytesPerLine());
5753 QColorTransformPrivate::get(transform)->apply(out_scanline, in_scanline, width(), QColorTransformPrivate::InputOpaque);
5757 Q_ASSERT(isRgb32fpx4Data(tmpFormat));
5758 transformSegment = [&](
int yStart,
int yEnd) {
5759 for (
int y = yStart; y < yEnd; ++y) {
5760 const QCmyk32 *in_scanline =
reinterpret_cast<
const QCmyk32 *>(fromImage.constBits() + y * fromImage.bytesPerLine());
5761 QRgbaFloat32 *out_scanline =
reinterpret_cast<QRgbaFloat32 *>(toImage.d->data + y * toImage.bytesPerLine());
5762 QColorTransformPrivate::get(transform)->apply(out_scanline, in_scanline, width(), QColorTransformPrivate::InputOpaque);
5766 }
else if (inColorData == QColorSpace::ColorModel::Rgb && outColorData == QColorSpace::ColorModel::Cmyk) {
5768 if (!fromImage.hasAlphaChannel())
5769 transFlags = QColorTransformPrivate::InputOpaque;
5770 else if (qPixelLayouts[fromImage.format()].premultiplied)
5771 transFlags = QColorTransformPrivate::Premultiplied;
5772 if (isRgb32Data(fromImage.format()) ) {
5773 transformSegment = [&](
int yStart,
int yEnd) {
5774 for (
int y = yStart; y < yEnd; ++y) {
5775 const QRgb *in_scanline =
reinterpret_cast<
const QRgb *>(fromImage.constBits() + y * fromImage.bytesPerLine());
5776 QCmyk32 *out_scanline =
reinterpret_cast<QCmyk32 *>(toImage.d->data + y * toImage.bytesPerLine());
5777 QColorTransformPrivate::get(transform)->apply(out_scanline, in_scanline, width(), transFlags);
5780 }
else if (isRgb64Data(fromImage.format())) {
5781 transformSegment = [&](
int yStart,
int yEnd) {
5782 for (
int y = yStart; y < yEnd; ++y) {
5783 const QRgba64 *in_scanline =
reinterpret_cast<
const QRgba64 *>(fromImage.constBits() + y * fromImage.bytesPerLine());
5784 QCmyk32 *out_scanline =
reinterpret_cast<QCmyk32 *>(toImage.d->data + y * toImage.bytesPerLine());
5785 QColorTransformPrivate::get(transform)->apply(out_scanline, in_scanline, width(), transFlags);
5789 Q_ASSERT(isRgb32fpx4Data(fromImage.format()));
5790 transformSegment = [&](
int yStart,
int yEnd) {
5791 for (
int y = yStart; y < yEnd; ++y) {
5792 const QRgbaFloat32 *in_scanline =
reinterpret_cast<
const QRgbaFloat32 *>(fromImage.constBits() + y * fromImage.bytesPerLine());
5793 QCmyk32 *out_scanline =
reinterpret_cast<QCmyk32 *>(toImage.d->data + y * toImage.bytesPerLine());
5794 QColorTransformPrivate::get(transform)->apply(out_scanline, in_scanline, width(), transFlags);
5803 if (pixelFormat().colorModel() == QPixelFormat::Indexed) {
5804 for (
int i = 0; i < d->colortable.size(); ++i)
5805 fromImage.d->colortable[i] = transform.map(d->colortable[i]);
5806 return fromImage.convertedTo(toFormat, flags);
5809 QImage::Format oldFormat = format();
5810 if (qt_fpColorPrecision(oldFormat)) {
5811 if (oldFormat != QImage::Format_RGBX32FPx4 && oldFormat != QImage::Format_RGBA32FPx4
5812 && oldFormat != QImage::Format_RGBA32FPx4_Premultiplied)
5813 fromImage.convertTo(QImage::Format_RGBA32FPx4);
5814 }
else if (qt_highColorPrecision(oldFormat,
true)) {
5815 if (oldFormat != QImage::Format_RGBX64 && oldFormat != QImage::Format_RGBA64
5816 && oldFormat != QImage::Format_RGBA64_Premultiplied && oldFormat != QImage::Format_Grayscale16)
5817 fromImage.convertTo(QImage::Format_RGBA64);
5818 }
else if (oldFormat != QImage::Format_ARGB32 && oldFormat != QImage::Format_RGB32
5819 && oldFormat != QImage::Format_ARGB32_Premultiplied && oldFormat != QImage::Format_CMYK8888
5820 && oldFormat != QImage::Format_Grayscale8 && oldFormat != QImage::Format_Grayscale16) {
5821 if (hasAlphaChannel())
5822 fromImage.convertTo(QImage::Format_ARGB32);
5824 fromImage.convertTo(QImage::Format_RGB32);
5827 if (!fromImage.hasAlphaChannel())
5828 transFlags = QColorTransformPrivate::InputOpaque;
5829 else if (qPixelLayouts[fromImage.format()].premultiplied)
5830 transFlags = QColorTransformPrivate::Premultiplied;
5832 if (fromImage.format() == Format_Grayscale8) {
5833 transformSegment = [&](
int yStart,
int yEnd) {
5834 for (
int y = yStart; y < yEnd; ++y) {
5835 const quint8 *in_scanline =
reinterpret_cast<
const quint8 *>(fromImage.constBits() + y * fromImage.bytesPerLine());
5836 if (tmpFormat == Format_Grayscale8) {
5837 quint8 *out_scanline =
reinterpret_cast<quint8 *>(toImage.d->data + y * toImage.bytesPerLine());
5838 QColorTransformPrivate::get(transform)->apply(out_scanline, in_scanline, width(), transFlags);
5840 Q_ASSERT(tmpFormat == Format_Grayscale16);
5841 quint16 *out_scanline =
reinterpret_cast<quint16 *>(toImage.d->data + y * toImage.bytesPerLine());
5842 QColorTransformPrivate::get(transform)->apply(out_scanline, in_scanline, width(), transFlags);
5846 }
else if (fromImage.format() == Format_Grayscale16) {
5847 transformSegment = [&](
int yStart,
int yEnd) {
5848 for (
int y = yStart; y < yEnd; ++y) {
5849 const quint16 *in_scanline =
reinterpret_cast<
const quint16 *>(fromImage.constBits() + y * fromImage.bytesPerLine());
5850 quint16 *out_scanline =
reinterpret_cast<quint16 *>(toImage.d->data + y * toImage.bytesPerLine());
5851 QColorTransformPrivate::get(transform)->apply(out_scanline, in_scanline, width(), transFlags);
5854 }
else if (fromImage.format() == Format_CMYK8888) {
5855 Q_ASSERT(tmpFormat == Format_CMYK8888);
5856 transformSegment = [&](
int yStart,
int yEnd) {
5857 for (
int y = yStart; y < yEnd; ++y) {
5858 const QCmyk32 *in_scanline =
reinterpret_cast<
const QCmyk32 *>(fromImage.constBits() + y * fromImage.bytesPerLine());
5859 QCmyk32 *out_scanline =
reinterpret_cast<QCmyk32 *>(toImage.d->data + y * toImage.bytesPerLine());
5860 QColorTransformPrivate::get(transform)->apply(out_scanline, in_scanline, width(), transFlags);
5863 }
else if (isRgb32fpx4Data(fromImage.format())) {
5864 Q_ASSERT(isRgb32fpx4Data(tmpFormat));
5865 transformSegment = [&](
int yStart,
int yEnd) {
5866 for (
int y = yStart; y < yEnd; ++y) {
5867 const QRgbaFloat32 *in_scanline =
reinterpret_cast<
const QRgbaFloat32 *>(fromImage.constBits() + y * fromImage.bytesPerLine());
5868 QRgbaFloat32 *out_scanline =
reinterpret_cast<QRgbaFloat32 *>(toImage.d->data + y * toImage.bytesPerLine());
5869 QColorTransformPrivate::get(transform)->apply(out_scanline, in_scanline, width(), transFlags);
5872 }
else if (isRgb64Data(fromImage.format())) {
5873 transformSegment = [&](
int yStart,
int yEnd) {
5874 for (
int y = yStart; y < yEnd; ++y) {
5875 const QRgba64 *in_scanline =
reinterpret_cast<
const QRgba64 *>(fromImage.constBits() + y * fromImage.bytesPerLine());
5876 if (isRgb32fpx4Data(tmpFormat)) {
5877 QRgbaFloat32 *out_scanline =
reinterpret_cast<QRgbaFloat32 *>(toImage.d->data + y * toImage.bytesPerLine());
5878 QColorTransformPrivate::get(transform)->apply(out_scanline, in_scanline, width(), transFlags);
5880 Q_ASSERT(isRgb64Data(tmpFormat));
5881 QRgba64 *out_scanline =
reinterpret_cast<QRgba64 *>(toImage.d->data + y * toImage.bytesPerLine());
5882 QColorTransformPrivate::get(transform)->apply(out_scanline, in_scanline, width(), transFlags);
5887 transformSegment = [&](
int yStart,
int yEnd) {
5888 for (
int y = yStart; y < yEnd; ++y) {
5889 const QRgb *in_scanline =
reinterpret_cast<
const QRgb *>(fromImage.constBits() + y * fromImage.bytesPerLine());
5890 if (isRgb32fpx4Data(tmpFormat)) {
5891 QRgbaFloat32 *out_scanline =
reinterpret_cast<QRgbaFloat32 *>(toImage.d->data + y * toImage.bytesPerLine());
5892 QColorTransformPrivate::get(transform)->apply(out_scanline, in_scanline, width(), transFlags);
5893 }
else if (isRgb64Data(tmpFormat)) {
5894 QRgba64 *out_scanline =
reinterpret_cast<QRgba64 *>(toImage.d->data + y * toImage.bytesPerLine());
5895 QColorTransformPrivate::get(transform)->apply(out_scanline, in_scanline, width(), transFlags);
5897 Q_ASSERT(isRgb32Data(tmpFormat));
5898 QRgb *out_scanline =
reinterpret_cast<QRgb *>(toImage.d->data + y * toImage.bytesPerLine());
5899 QColorTransformPrivate::get(transform)->apply(out_scanline, in_scanline, width(), transFlags);
5906#if QT_CONFIG(qtgui_threadpool)
5907 int segments = (qsizetype(width()) * height()) >> 16;
5908 segments = std::min(segments, height());
5909 QThreadPool *threadPool = QGuiApplicationPrivate::qtGuiThreadPool();
5910 if (segments > 1 && threadPool && !threadPool->contains(QThread::currentThread())) {
5911 QLatch latch(segments);
5913 for (
int i = 0; i < segments; ++i) {
5914 int yn = (height() - y) / (segments - i);
5915 threadPool->start([&, y, yn]() {
5916 transformSegment(y, y + yn);
5924 transformSegment(0, height());
5926 if (tmpFormat != toFormat)
5927 toImage.convertTo(toFormat);
5933
5934
5935
5936
5937
5938
5939
5940QImage QImage::colorTransformed(
const QColorTransform &transform) &&
5945 const QColorSpacePrivate *inColorSpace = QColorTransformPrivate::get(transform)->colorSpaceIn.constData();
5946 const QColorSpacePrivate *outColorSpace = QColorTransformPrivate::get(transform)->colorSpaceOut.constData();
5947 if (!qt_compatibleColorModelSource(pixelFormat().colorModel(), inColorSpace->colorModel)) {
5948 qWarning() <<
"QImage::colorTransformed: Invalid input color space for transform";
5951 if (!qt_compatibleColorModelTarget(pixelFormat().colorModel(), outColorSpace->colorModel, outColorSpace->transformModel)) {
5953 switch (outColorSpace->colorModel) {
5954 case QColorSpace::ColorModel::Rgb:
5955 return colorTransformed(transform, qt_highColorPrecision(format(),
true) ? QImage::Format_RGBX64 : QImage::Format_RGB32);
5956 case QColorSpace::ColorModel::Gray:
5957 return colorTransformed(transform, qt_highColorPrecision(format(),
true) ? QImage::Format_Grayscale16 : QImage::Format_Grayscale8);
5958 case QColorSpace::ColorModel::Cmyk:
5959 return colorTransformed(transform, QImage::Format_CMYK8888);
5960 case QColorSpace::ColorModel::Undefined:
5966 applyColorTransform(transform);
5967 return std::move(*
this);
5971
5972
5973
5974
5975
5976
5977
5978QImage QImage::colorTransformed(
const QColorTransform &transform, QImage::Format format, Qt::ImageConversionFlags flags) &&
5981 return colorTransformed(transform, format, flags);
5984bool QImageData::convertInPlace(QImage::Format newFormat, Qt::ImageConversionFlags flags)
5986 if (format == newFormat)
5990 if (ref.loadRelaxed() > 1 || !own_data)
5993 InPlace_Image_Converter converter = qimage_inplace_converter_map[format][newFormat];
5995 return converter(
this, flags);
5996 if (format > QImage::Format_Indexed8 && newFormat > QImage::Format_Indexed8 && !qimage_converter_map[format][newFormat]) {
5999 if (qt_highColorPrecision(newFormat, !qPixelLayouts[newFormat].hasAlphaChannel)
6000 && qt_highColorPrecision(format, !qPixelLayouts[format].hasAlphaChannel)) {
6001#if QT_CONFIG(raster_fp)
6002 if (qt_fpColorPrecision(format) && qt_fpColorPrecision(newFormat))
6003 return convert_generic_inplace_over_rgba32f(
this, newFormat, flags);
6005 return convert_generic_inplace_over_rgb64(
this, newFormat, flags);
6007 return convert_generic_inplace(
this, newFormat, flags);
6013
6014
6015
6018
6019
6020
6022#ifndef QT_NO_DEBUG_STREAM
6023QDebug operator<<(QDebug dbg,
const QImage &i)
6025 QDebugStateSaver saver(dbg);
6032 dbg << i.size() <<
",format=" << i.format() <<
",depth=" << i.depth();
6034 dbg <<
",colorCount=" << i.colorCount();
6035 const int bytesPerLine = i.bytesPerLine();
6036 dbg <<
",devicePixelRatio=" << i.devicePixelRatio()
6037 <<
",bytesPerLine=" << bytesPerLine <<
",sizeInBytes=" << i.sizeInBytes();
6038 if (dbg.verbosity() > 2 && i.height() > 0) {
6039 const int outputLength = qMin(bytesPerLine, 24);
6041 << QByteArray(
reinterpret_cast<
const char *>(i.scanLine(0)), outputLength).toHex()
6050static constexpr QPixelFormat pixelformats[] = {
6054 QPixelFormat(QPixelFormat::Indexed,
6061 QPixelFormat::IgnoresAlpha,
6062 QPixelFormat::AtBeginning,
6063 QPixelFormat::NotPremultiplied,
6064 QPixelFormat::UnsignedByte,
6065 QPixelFormat::BigEndian),
6067 QPixelFormat(QPixelFormat::Indexed,
6074 QPixelFormat::IgnoresAlpha,
6075 QPixelFormat::AtBeginning,
6076 QPixelFormat::NotPremultiplied,
6077 QPixelFormat::UnsignedByte,
6078 QPixelFormat::BigEndian),
6080 QPixelFormat(QPixelFormat::Indexed,
6087 QPixelFormat::IgnoresAlpha,
6088 QPixelFormat::AtBeginning,
6089 QPixelFormat::NotPremultiplied,
6090 QPixelFormat::UnsignedByte,
6091 QPixelFormat::BigEndian),
6093 QPixelFormat(QPixelFormat::RGB,
6100 QPixelFormat::IgnoresAlpha,
6101 QPixelFormat::AtBeginning,
6102 QPixelFormat::NotPremultiplied,
6103 QPixelFormat::UnsignedInteger,
6104 QPixelFormat::CurrentSystemEndian),
6106 QPixelFormat(QPixelFormat::RGB,
6113 QPixelFormat::UsesAlpha,
6114 QPixelFormat::AtBeginning,
6115 QPixelFormat::NotPremultiplied,
6116 QPixelFormat::UnsignedInteger,
6117 QPixelFormat::CurrentSystemEndian),
6119 QPixelFormat(QPixelFormat::RGB,
6126 QPixelFormat::UsesAlpha,
6127 QPixelFormat::AtBeginning,
6128 QPixelFormat::Premultiplied,
6129 QPixelFormat::UnsignedInteger,
6130 QPixelFormat::CurrentSystemEndian),
6132 QPixelFormat(QPixelFormat::RGB,
6139 QPixelFormat::IgnoresAlpha,
6140 QPixelFormat::AtBeginning,
6141 QPixelFormat::NotPremultiplied,
6142 QPixelFormat::UnsignedShort,
6143 QPixelFormat::CurrentSystemEndian),
6145 QPixelFormat(QPixelFormat::RGB,
6152 QPixelFormat::UsesAlpha,
6153 QPixelFormat::AtBeginning,
6154 QPixelFormat::Premultiplied,
6155 QPixelFormat::UnsignedInteger,
6156 QPixelFormat::CurrentSystemEndian),
6158 QPixelFormat(QPixelFormat::RGB,
6165 QPixelFormat::IgnoresAlpha,
6166 QPixelFormat::AtBeginning,
6167 QPixelFormat::NotPremultiplied,
6168 QPixelFormat::UnsignedInteger,
6169 QPixelFormat::CurrentSystemEndian),
6171 QPixelFormat(QPixelFormat::RGB,
6178 QPixelFormat::UsesAlpha,
6179 QPixelFormat::AtEnd,
6180 QPixelFormat::Premultiplied,
6181 QPixelFormat::UnsignedInteger,
6182 QPixelFormat::CurrentSystemEndian),
6184 QPixelFormat(QPixelFormat::RGB,
6191 QPixelFormat::IgnoresAlpha,
6192 QPixelFormat::AtBeginning,
6193 QPixelFormat::NotPremultiplied,
6194 QPixelFormat::UnsignedShort,
6195 QPixelFormat::CurrentSystemEndian),
6197 QPixelFormat(QPixelFormat::RGB,
6204 QPixelFormat::UsesAlpha,
6205 QPixelFormat::AtBeginning,
6206 QPixelFormat::Premultiplied,
6207 QPixelFormat::UnsignedInteger,
6208 QPixelFormat::CurrentSystemEndian),
6210 QPixelFormat(QPixelFormat::RGB,
6217 QPixelFormat::IgnoresAlpha,
6218 QPixelFormat::AtBeginning,
6219 QPixelFormat::NotPremultiplied,
6220 QPixelFormat::UnsignedByte,
6221 QPixelFormat::BigEndian),
6223 QPixelFormat(QPixelFormat::RGB,
6230 QPixelFormat::IgnoresAlpha,
6231 QPixelFormat::AtBeginning,
6232 QPixelFormat::NotPremultiplied,
6233 QPixelFormat::UnsignedShort,
6234 QPixelFormat::CurrentSystemEndian),
6236 QPixelFormat(QPixelFormat::RGB,
6243 QPixelFormat::UsesAlpha,
6244 QPixelFormat::AtBeginning,
6245 QPixelFormat::Premultiplied,
6246 QPixelFormat::UnsignedShort,
6247 QPixelFormat::CurrentSystemEndian),
6249 QPixelFormat(QPixelFormat::RGB,
6256 QPixelFormat::IgnoresAlpha,
6257 QPixelFormat::AtEnd,
6258 QPixelFormat::NotPremultiplied,
6259 QPixelFormat::UnsignedByte,
6260 QPixelFormat::BigEndian),
6262 QPixelFormat(QPixelFormat::RGB,
6269 QPixelFormat::UsesAlpha,
6270 QPixelFormat::AtEnd,
6271 QPixelFormat::NotPremultiplied,
6272 QPixelFormat::UnsignedByte,
6273 QPixelFormat::BigEndian),
6275 QPixelFormat(QPixelFormat::RGB,
6282 QPixelFormat::UsesAlpha,
6283 QPixelFormat::AtEnd,
6284 QPixelFormat::Premultiplied,
6285 QPixelFormat::UnsignedByte,
6286 QPixelFormat::BigEndian),
6288 QPixelFormat(QPixelFormat::BGR,
6295 QPixelFormat::IgnoresAlpha,
6296 QPixelFormat::AtBeginning,
6297 QPixelFormat::NotPremultiplied,
6298 QPixelFormat::UnsignedInteger,
6299 QPixelFormat::CurrentSystemEndian),
6301 QPixelFormat(QPixelFormat::BGR,
6308 QPixelFormat::UsesAlpha,
6309 QPixelFormat::AtBeginning,
6310 QPixelFormat::Premultiplied,
6311 QPixelFormat::UnsignedInteger,
6312 QPixelFormat::CurrentSystemEndian),
6314 QPixelFormat(QPixelFormat::RGB,
6321 QPixelFormat::IgnoresAlpha,
6322 QPixelFormat::AtBeginning,
6323 QPixelFormat::NotPremultiplied,
6324 QPixelFormat::UnsignedInteger,
6325 QPixelFormat::CurrentSystemEndian),
6327 QPixelFormat(QPixelFormat::RGB,
6334 QPixelFormat::UsesAlpha,
6335 QPixelFormat::AtBeginning,
6336 QPixelFormat::Premultiplied,
6337 QPixelFormat::UnsignedInteger,
6338 QPixelFormat::CurrentSystemEndian),
6340 QPixelFormat(QPixelFormat::Alpha,
6347 QPixelFormat::UsesAlpha,
6348 QPixelFormat::AtBeginning,
6349 QPixelFormat::Premultiplied,
6350 QPixelFormat::UnsignedByte,
6351 QPixelFormat::BigEndian),
6353 QPixelFormat(QPixelFormat::Grayscale,
6360 QPixelFormat::IgnoresAlpha,
6361 QPixelFormat::AtBeginning,
6362 QPixelFormat::NotPremultiplied,
6363 QPixelFormat::UnsignedByte,
6364 QPixelFormat::BigEndian),
6366 QPixelFormat(QPixelFormat::RGB,
6373 QPixelFormat::IgnoresAlpha,
6374 QPixelFormat::AtEnd,
6375 QPixelFormat::NotPremultiplied,
6376 QPixelFormat::UnsignedShort,
6377 QPixelFormat::CurrentSystemEndian),
6379 QPixelFormat(QPixelFormat::RGB,
6386 QPixelFormat::UsesAlpha,
6387 QPixelFormat::AtEnd,
6388 QPixelFormat::NotPremultiplied,
6389 QPixelFormat::UnsignedShort,
6390 QPixelFormat::CurrentSystemEndian),
6392 QPixelFormat(QPixelFormat::RGB,
6399 QPixelFormat::UsesAlpha,
6400 QPixelFormat::AtEnd,
6401 QPixelFormat::Premultiplied,
6402 QPixelFormat::UnsignedShort,
6403 QPixelFormat::CurrentSystemEndian),
6405 QPixelFormat(QPixelFormat::Grayscale,
6412 QPixelFormat::IgnoresAlpha,
6413 QPixelFormat::AtBeginning,
6414 QPixelFormat::NotPremultiplied,
6415 QPixelFormat::UnsignedShort,
6416 QPixelFormat::CurrentSystemEndian),
6418 QPixelFormat(QPixelFormat::BGR,
6425 QPixelFormat::IgnoresAlpha,
6426 QPixelFormat::AtBeginning,
6427 QPixelFormat::NotPremultiplied,
6428 QPixelFormat::UnsignedByte,
6429 QPixelFormat::BigEndian),
6431 QPixelFormat(QPixelFormat::RGB,
6438 QPixelFormat::IgnoresAlpha,
6439 QPixelFormat::AtEnd,
6440 QPixelFormat::NotPremultiplied,
6441 QPixelFormat::FloatingPoint,
6442 QPixelFormat::CurrentSystemEndian),
6444 QPixelFormat(QPixelFormat::RGB,
6451 QPixelFormat::UsesAlpha,
6452 QPixelFormat::AtEnd,
6453 QPixelFormat::NotPremultiplied,
6454 QPixelFormat::FloatingPoint,
6455 QPixelFormat::CurrentSystemEndian),
6457 QPixelFormat(QPixelFormat::RGB,
6464 QPixelFormat::UsesAlpha,
6465 QPixelFormat::AtEnd,
6466 QPixelFormat::Premultiplied,
6467 QPixelFormat::FloatingPoint,
6468 QPixelFormat::CurrentSystemEndian),
6470 QPixelFormat(QPixelFormat::RGB,
6477 QPixelFormat::IgnoresAlpha,
6478 QPixelFormat::AtEnd,
6479 QPixelFormat::NotPremultiplied,
6480 QPixelFormat::FloatingPoint,
6481 QPixelFormat::CurrentSystemEndian),
6483 QPixelFormat(QPixelFormat::RGB,
6490 QPixelFormat::UsesAlpha,
6491 QPixelFormat::AtEnd,
6492 QPixelFormat::NotPremultiplied,
6493 QPixelFormat::FloatingPoint,
6494 QPixelFormat::CurrentSystemEndian),
6496 QPixelFormat(QPixelFormat::RGB,
6503 QPixelFormat::UsesAlpha,
6504 QPixelFormat::AtEnd,
6505 QPixelFormat::Premultiplied,
6506 QPixelFormat::FloatingPoint,
6507 QPixelFormat::CurrentSystemEndian),
6509 QPixelFormat(QPixelFormat::CMYK,
6516 QPixelFormat::IgnoresAlpha,
6517 QPixelFormat::AtBeginning,
6518 QPixelFormat::NotPremultiplied,
6519 QPixelFormat::UnsignedInteger,
6520 QPixelFormat::CurrentSystemEndian),
6522static_assert(
sizeof(pixelformats) /
sizeof(*pixelformats) == QImage::NImageFormats);
6525
6526
6527QPixelFormat QImage::pixelFormat()
const noexcept
6529 return toPixelFormat(format());
6533
6534
6535QPixelFormat QImage::toPixelFormat(QImage::Format format)
noexcept
6537 Q_ASSERT(
static_cast<
int>(format) < NImageFormats &&
static_cast<
int>(format) >= 0);
6538 return pixelformats[format];
6542
6543
6544QImage::Format QImage::toImageFormat(QPixelFormat format)
noexcept
6546 for (
int i = 0; i < NImageFormats; i++) {
6547 if (format == pixelformats[i])
6550 return Format_Invalid;
6555 Qt::Orientations orients = {};
6556 if (orient.testFlag(QImageIOHandler::TransformationMirror))
6557 orients |= Qt::Horizontal;
6558 if (orient.testFlag(QImageIOHandler::TransformationFlip))
6559 orients |= Qt::Vertical;
6565 if (orient == QImageIOHandler::TransformationNone)
6567 if (orient == QImageIOHandler::TransformationRotate270) {
6568 src = rotated270(src);
6570 src.flip(toOrientations(orient));
6571 if (orient & QImageIOHandler::TransformationRotate90)
6572 src = rotated90(src);
6578 QMap<QString, QString> text = qt_getImageTextFromDescription(description);
6579 const auto textKeys = image.textKeys();
6580 for (
const QString &key : textKeys) {
6581 if (!key.isEmpty() && !text.contains(key))
6582 text.insert(key, image.text(key));
6589 QMap<QString, QString> text;
6590 for (
const auto &pair : QStringView{description}.tokenize(u"\n\n")) {
6591 int index = pair.indexOf(u':');
6592 if (index >= 0 && pair.indexOf(u' ') < index) {
6593 if (!pair.trimmed().isEmpty())
6594 text.insert(
"Description"_L1, pair.toString().simplified());
6596 const auto key = pair.left(index);
6597 if (!key.trimmed().isEmpty())
6598 text.insert(key.toString(), pair.mid(index + 2).toString().simplified());
6606#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)