17#include <qtransform.h>
23Q_CONSTINIT QBasicMutex QColorSpacePrivate::s_lutWriteLock;
25Q_CONSTINIT
static QAtomicPointer<QColorSpacePrivate> s_predefinedColorspacePrivates[QColorSpace::Bt2100Hlg] = {};
28 for (QAtomicPointer<QColorSpacePrivate> &ptr : s_predefinedColorspacePrivates) {
29 QColorSpacePrivate *prv = ptr.fetchAndStoreAcquire(
nullptr);
30 if (prv && !prv->ref.deref())
35Q_DESTRUCTOR_FUNCTION(cleanupPredefinedColorspaces)
37QColorSpace::PrimaryPoints QColorSpace::PrimaryPoints::fromPrimaries(Primaries primaries)
42 out.redPoint = QPointF(0.640, 0.330);
43 out.greenPoint = QPointF(0.300, 0.600);
44 out.bluePoint = QPointF(0.150, 0.060);
45 out.whitePoint = QColorVector::D65Chromaticity();
47 case Primaries::DciP3D65:
48 out.redPoint = QPointF(0.680, 0.320);
49 out.greenPoint = QPointF(0.265, 0.690);
50 out.bluePoint = QPointF(0.150, 0.060);
51 out.whitePoint = QColorVector::D65Chromaticity();
53 case Primaries::AdobeRgb:
54 out.redPoint = QPointF(0.640, 0.330);
55 out.greenPoint = QPointF(0.210, 0.710);
56 out.bluePoint = QPointF(0.150, 0.060);
57 out.whitePoint = QColorVector::D65Chromaticity();
59 case Primaries::ProPhotoRgb:
60 out.redPoint = QPointF(0.7347, 0.2653);
61 out.greenPoint = QPointF(0.1596, 0.8404);
62 out.bluePoint = QPointF(0.0366, 0.0001);
63 out.whitePoint = QColorVector::D50Chromaticity();
65 case Primaries::Bt2020:
66 out.redPoint = QPointF(0.708, 0.292);
67 out.greenPoint = QPointF(0.170, 0.797);
68 out.bluePoint = QPointF(0.131, 0.046);
69 out.whitePoint = QColorVector::D65Chromaticity();
77bool QColorSpace::PrimaryPoints::isValid()
const noexcept
79 if (!QColorVector::isValidChromaticity(redPoint))
81 if (!QColorVector::isValidChromaticity(greenPoint))
83 if (!QColorVector::isValidChromaticity(bluePoint))
85 if (!QColorVector::isValidChromaticity(whitePoint))
94 QColorVector::fromXYChromaticity(primaries.redPoint),
95 QColorVector::fromXYChromaticity(primaries.greenPoint),
96 QColorVector::fromXYChromaticity(primaries.bluePoint)
102 const auto wXyz = QColorVector::fromXYChromaticity(primaries.whitePoint);
119 switch (namedColorSpace) {
120 case QColorSpace::SRgb:
121 primaries = QColorSpace::Primaries::SRgb;
122 transferFunction = QColorSpace::TransferFunction::SRgb;
123 description = QStringLiteral(
"sRGB");
125 case QColorSpace::SRgbLinear:
126 primaries = QColorSpace::Primaries::SRgb;
127 transferFunction = QColorSpace::TransferFunction::Linear;
128 description = QStringLiteral(
"Linear sRGB");
130 case QColorSpace::AdobeRgb:
131 primaries = QColorSpace::Primaries::AdobeRgb;
132 transferFunction = QColorSpace::TransferFunction::Gamma;
134 description = QStringLiteral(
"Adobe RGB");
136 case QColorSpace::DisplayP3:
137 primaries = QColorSpace::Primaries::DciP3D65;
138 transferFunction = QColorSpace::TransferFunction::SRgb;
139 description = QStringLiteral(
"Display P3");
141 case QColorSpace::ProPhotoRgb:
142 primaries = QColorSpace::Primaries::ProPhotoRgb;
143 transferFunction = QColorSpace::TransferFunction::ProPhotoRgb;
144 description = QStringLiteral(
"ProPhoto RGB");
146 case QColorSpace::Bt2020:
147 primaries = QColorSpace::Primaries::Bt2020;
148 transferFunction = QColorSpace::TransferFunction::Bt2020;
149 description = QStringLiteral(
"BT.2020");
151 case QColorSpace::Bt2100Pq:
152 primaries = QColorSpace::Primaries::Bt2020;
153 transferFunction = QColorSpace::TransferFunction::St2084;
154 description = QStringLiteral(
"BT.2100(PQ)");
156 case QColorSpace::Bt2100Hlg:
157 primaries = QColorSpace::Primaries::Bt2020;
158 transferFunction = QColorSpace::TransferFunction::Hlg;
159 description = QStringLiteral(
"BT.2100(HLG)");
178 QColorSpace::TransferFunction transferFunction,
186 Q_ASSERT(primaries.isValid());
187 toXyz = qColorSpacePrimaryPointsToXyzMatrix(primaries);
188 chad = QColorMatrix::chromaticAdaptation(whitePoint);
189 toXyz = chad * toXyz;
196 QColorSpace::TransferFunction transferFunction,
204 chad = QColorMatrix::chromaticAdaptation(
this->whitePoint);
216 chad = QColorMatrix::chromaticAdaptation(
this->whitePoint);
218 setTransferFunctionTable(transferFunctionTable);
228 setTransferFunctionTable(transferFunctionTable);
240 Q_ASSERT(primaries.isValid());
241 toXyz = qColorSpacePrimaryPointsToXyzMatrix(primaries);
242 chad = QColorMatrix::chromaticAdaptation(whitePoint);
243 toXyz = chad * toXyz;
244 setTransferFunctionTable(transferFunctionTable);
250 const QList<uint16_t> &redTransferFunctionTable,
251 const QList<uint16_t> &greenTransferFunctionTable,
252 const QList<uint16_t> &blueTransferFunctionTable)
258 Q_ASSERT(primaries.isValid());
259 toXyz = qColorSpacePrimaryPointsToXyzMatrix(primaries);
260 whitePoint = QColorVector::fromXYChromaticity(primaries.whitePoint);
261 chad = QColorMatrix::chromaticAdaptation(whitePoint);
262 toXyz = chad * toXyz;
263 setTransferFunctionTables(redTransferFunctionTable,
264 greenTransferFunctionTable,
265 blueTransferFunctionTable);
272 case QColorSpace::Primaries::SRgb:
273 if (transferFunction == QColorSpace::TransferFunction::SRgb) {
274 namedColorSpace = QColorSpace::SRgb;
275 if (description.isEmpty())
276 description = QStringLiteral(
"sRGB");
279 if (transferFunction == QColorSpace::TransferFunction::Linear) {
280 namedColorSpace = QColorSpace::SRgbLinear;
281 if (description.isEmpty())
282 description = QStringLiteral(
"Linear sRGB");
286 case QColorSpace::Primaries::AdobeRgb:
287 if (transferFunction == QColorSpace::TransferFunction::Gamma) {
288 if (qAbs(
gamma - 2.19921875f) < (1/1024.0f)) {
289 namedColorSpace = QColorSpace::AdobeRgb;
290 if (description.isEmpty())
291 description = QStringLiteral(
"Adobe RGB");
296 case QColorSpace::Primaries::DciP3D65:
297 if (transferFunction == QColorSpace::TransferFunction::SRgb) {
298 namedColorSpace = QColorSpace::DisplayP3;
299 if (description.isEmpty())
300 description = QStringLiteral(
"Display P3");
304 case QColorSpace::Primaries::ProPhotoRgb:
305 if (transferFunction == QColorSpace::TransferFunction::ProPhotoRgb) {
306 namedColorSpace = QColorSpace::ProPhotoRgb;
307 if (description.isEmpty())
308 description = QStringLiteral(
"ProPhoto RGB");
311 if (transferFunction == QColorSpace::TransferFunction::Gamma) {
313 if (qAbs(
gamma - 1.8f) < (1/1024.0f)) {
314 namedColorSpace = QColorSpace::ProPhotoRgb;
315 if (description.isEmpty())
316 description = QStringLiteral(
"ProPhoto RGB");
321 case QColorSpace::Primaries::Bt2020:
322 if (transferFunction == QColorSpace::TransferFunction::Bt2020) {
323 namedColorSpace = QColorSpace::Bt2020;
324 if (description.isEmpty())
325 description = QStringLiteral(
"BT.2020");
328 if (transferFunction == QColorSpace::TransferFunction::St2084) {
329 namedColorSpace = QColorSpace::Bt2100Pq;
330 if (description.isEmpty())
331 description = QStringLiteral(
"BT.2100(PQ)");
334 if (transferFunction == QColorSpace::TransferFunction::Hlg) {
335 namedColorSpace = QColorSpace::Bt2100Hlg;
336 if (description.isEmpty())
337 description = QStringLiteral(
"BT.2100(HLG)");
345 namedColorSpace = Unknown;
356 if (primaries == QColorSpace::Primaries::Custom) {
357 toXyz = QColorMatrix();
358 whitePoint = QColorVector::D50();
361 auto colorSpacePrimaries = QColorSpace::PrimaryPoints::fromPrimaries(primaries);
362 toXyz = qColorSpacePrimaryPointsToXyzMatrix(colorSpacePrimaries);
363 whitePoint = QColorVector::fromXYChromaticity(colorSpacePrimaries.whitePoint);
364 chad = QColorMatrix::chromaticAdaptation(whitePoint);
365 toXyz = chad * toXyz;
370 QColorTransferTable table(transferFunctionTable.size(), transferFunctionTable);
371 if (!table.isEmpty() && !table.checkValidity()) {
372 qWarning() <<
"Invalid transfer function table given to QColorSpace";
373 trc[0].m_type = QColorTrc::Type::Uninitialized;
376 transferFunction = QColorSpace::TransferFunction::Custom;
378 if (table.asColorTransferFunction(&curve)) {
381 transferFunction = QColorSpace::TransferFunction::Linear;
384 transferFunction = QColorSpace::TransferFunction::SRgb;
386 trc[0].m_type = QColorTrc::Type::ParameterizedFunction;
387 trc[0].m_fun = curve;
389 trc[0].m_type = QColorTrc::Type::Table;
390 trc[0].m_table = table;
395 const QList<uint16_t> &greenTransferFunctionTable,
396 const QList<uint16_t> &blueTransferFunctionTable)
398 QColorTransferTable redTable(redTransferFunctionTable.size(), redTransferFunctionTable);
399 QColorTransferTable greenTable(greenTransferFunctionTable.size(), greenTransferFunctionTable);
400 QColorTransferTable blueTable(blueTransferFunctionTable.size(), blueTransferFunctionTable);
401 if (!redTable.isEmpty() && !greenTable.isEmpty() && !blueTable.isEmpty() &&
402 !redTable.checkValidity() && !greenTable.checkValidity() && !blueTable.checkValidity()) {
403 qWarning() <<
"Invalid transfer function table given to QColorSpace";
404 trc[0].m_type = QColorTrc::Type::Uninitialized;
405 trc[1].m_type = QColorTrc::Type::Uninitialized;
406 trc[2].m_type = QColorTrc::Type::Uninitialized;
409 transferFunction = QColorSpace::TransferFunction::Custom;
411 if (redTable.asColorTransferFunction(&curve)) {
412 trc[0].m_type = QColorTrc::Type::ParameterizedFunction;
413 trc[0].m_fun = curve;
415 trc[0].m_type = QColorTrc::Type::Table;
416 trc[0].m_table = redTable;
418 if (greenTable.asColorTransferFunction(&curve)) {
419 trc[1].m_type = QColorTrc::Type::ParameterizedFunction;
420 trc[1].m_fun = curve;
422 trc[1].m_type = QColorTrc::Type::Table;
423 trc[1].m_table = greenTable;
425 if (blueTable.asColorTransferFunction(&curve)) {
426 trc[2].m_type = QColorTrc::Type::ParameterizedFunction;
427 trc[2].m_fun = curve;
429 trc[2].m_type = QColorTrc::Type::Table;
430 trc[2].m_table = blueTable;
432 lut.generated.storeRelease(0);
437 switch (transferFunction) {
438 case QColorSpace::TransferFunction::Linear:
439 trc[0] = QColorTransferFunction();
440 if (qFuzzyIsNull(
gamma))
443 case QColorSpace::TransferFunction::Gamma:
444 trc[0] = QColorTransferFunction::fromGamma(gamma);
446 case QColorSpace::TransferFunction::SRgb:
447 trc[0] = QColorTransferFunction::fromSRgb();
448 if (qFuzzyIsNull(
gamma))
451 case QColorSpace::TransferFunction::ProPhotoRgb:
452 trc[0] = QColorTransferFunction::fromProPhotoRgb();
453 if (qFuzzyIsNull(
gamma))
456 case QColorSpace::TransferFunction::Bt2020:
457 trc[0] = QColorTransferFunction::fromBt2020();
458 if (qFuzzyIsNull(
gamma))
461 case QColorSpace::TransferFunction::St2084:
462 trc[0] = QColorTransferGenericFunction::pq();
464 case QColorSpace::TransferFunction::Hlg:
465 trc[0] = QColorTransferGenericFunction::hlg();
467 case QColorSpace::TransferFunction::Custom:
475 lut.generated.storeRelease(0);
484 ptr->colorSpaceIn =
this;
485 ptr->colorSpaceOut = out;
487 ptr->colorMatrix = toXyz;
491 ptr->colorMatrix = out->toXyz.inverted() * ptr->colorMatrix;
493 return QColorTransform();
502 ptr->colorSpaceIn =
this;
503 ptr->colorSpaceOut =
this;
505 ptr->colorMatrix = toXyz;
510 ptr->colorMatrix = chad.inverted() * ptr->colorMatrix;
516 return transformModel == QColorSpace::TransformModel::ThreeComponentMatrix;
521 Q_ASSERT(transformModel == QColorSpace::TransformModel::ElementListProcessing);
522 Q_ASSERT(primaries == QColorSpace::Primaries::Custom);
523 Q_ASSERT(transferFunction == QColorSpace::TransferFunction::Custom);
525 transformModel = QColorSpace::TransformModel::ThreeComponentMatrix;
526 colorModel = QColorSpace::ColorModel::Rgb;
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
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
594
595
596
597
598
599
600
601
602
603
604
607
608
609
610
611
612
613
614
615
616
617
618
619
620
623
624
625
626
627
628
629
630
631
632
633
634
635
636
639
640
641
642
643
644
645
646
647
648
649
652
653
654
655
656
657
658
659
660
663
664
665
666
669
670
671
672
675
676
677
678
681
682
683QColorSpace::QColorSpace(NamedColorSpace namedColorSpace)
685 if (namedColorSpace < QColorSpace::SRgb || namedColorSpace > QColorSpace::Bt2100Hlg) {
686 qWarning() <<
"QColorSpace attempted constructed from invalid QColorSpace::NamedColorSpace: " <<
int(namedColorSpace);
690 auto &atomicRef = s_predefinedColorspacePrivates[
static_cast<
int>(namedColorSpace) - 1];
691 QColorSpacePrivate *cspriv = atomicRef.loadAcquire();
693 auto *tmp =
new QColorSpacePrivate(namedColorSpace);
695 if (atomicRef.testAndSetOrdered(
nullptr, tmp, cspriv))
705
706
707
708QColorSpace::QColorSpace(QColorSpace::Primaries primaries, QColorSpace::TransferFunction transferFunction,
float gamma)
709 : d_ptr(
new QColorSpacePrivate(primaries, transferFunction, gamma))
714
715
716
717QColorSpace::QColorSpace(QColorSpace::Primaries primaries,
float gamma)
718 : d_ptr(
new QColorSpacePrivate(primaries, TransferFunction::Gamma, gamma))
723
724
725
726
727
728
729
730
731QColorSpace::QColorSpace(QColorSpace::Primaries gamut,
const QList<uint16_t> &transferFunctionTable)
732 : d_ptr(
new QColorSpacePrivate(gamut, transferFunctionTable))
737
738
739
740
741
742QColorSpace::QColorSpace(QPointF whitePoint, TransferFunction transferFunction,
float gamma)
743 : d_ptr(
new QColorSpacePrivate(whitePoint, transferFunction, gamma))
748
749
750
751
752
753QColorSpace::QColorSpace(QPointF whitePoint,
const QList<uint16_t> &transferFunctionTable)
754 : d_ptr(
new QColorSpacePrivate(whitePoint, transferFunctionTable))
759
760
761
762QColorSpace::QColorSpace(
const QPointF &whitePoint,
const QPointF &redPoint,
763 const QPointF &greenPoint,
const QPointF &bluePoint,
764 QColorSpace::TransferFunction transferFunction,
float gamma)
765 : QColorSpace({whitePoint, redPoint, greenPoint, bluePoint}, transferFunction, gamma)
770
771
772
773
774
775QColorSpace::QColorSpace(
const PrimaryPoints &primaryPoints, TransferFunction transferFunction,
float gamma)
777 if (!primaryPoints.isValid()) {
778 qWarning() <<
"QColorSpace attempted constructed from invalid primaries:"
779 << primaryPoints.whitePoint << primaryPoints.redPoint << primaryPoints.greenPoint << primaryPoints.bluePoint;
782 d_ptr =
new QColorSpacePrivate(primaryPoints, transferFunction, gamma);
786
787
788
789
790
791
792QColorSpace::QColorSpace(
const QPointF &whitePoint,
const QPointF &redPoint,
793 const QPointF &greenPoint,
const QPointF &bluePoint,
794 const QList<uint16_t> &transferFunctionTable)
795 : d_ptr(
new QColorSpacePrivate({whitePoint, redPoint, greenPoint, bluePoint}, transferFunctionTable))
800
801
802
803
804
805
806QColorSpace::QColorSpace(
const QPointF &whitePoint,
const QPointF &redPoint,
807 const QPointF &greenPoint,
const QPointF &bluePoint,
808 const QList<uint16_t> &redTransferFunctionTable,
809 const QList<uint16_t> &greenTransferFunctionTable,
810 const QList<uint16_t> &blueTransferFunctionTable)
811 : d_ptr(
new QColorSpacePrivate({whitePoint, redPoint, greenPoint, bluePoint},
812 redTransferFunctionTable,
813 greenTransferFunctionTable,
814 blueTransferFunctionTable))
818QColorSpace::~QColorSpace() =
default;
820QT_DEFINE_QESDP_SPECIALIZATION_DTOR(QColorSpacePrivate)
822QColorSpace::QColorSpace(
const QColorSpace &colorSpace)
noexcept =
default;
825
826
829
830
831
832QColorSpace::Primaries QColorSpace::primaries()
const noexcept
834 if (Q_UNLIKELY(!d_ptr))
835 return QColorSpace::Primaries::Custom;
836 return d_ptr->primaries;
840
841
842
843
844
845QColorSpace::TransferFunction QColorSpace::transferFunction()
const noexcept
847 if (Q_UNLIKELY(!d_ptr))
848 return QColorSpace::TransferFunction::Custom;
849 return d_ptr->transferFunction;
853
854
855
856
857
858
859float QColorSpace::gamma()
const noexcept
861 if (Q_UNLIKELY(!d_ptr))
867
868
869
870
871void QColorSpace::setTransferFunction(QColorSpace::TransferFunction transferFunction,
float gamma)
873 if (transferFunction == TransferFunction::Custom)
876 d_ptr =
new QColorSpacePrivate(Primaries::Custom, transferFunction, gamma);
879 if (d_ptr->transferFunction == transferFunction && d_ptr->gamma == gamma)
882 if (d_ptr->transformModel == TransformModel::ElementListProcessing)
883 d_ptr->clearElementListProcessingForEdit();
884 d_ptr->iccProfile = {};
885 d_ptr->description = QString();
886 d_ptr->transferFunction = transferFunction;
887 d_ptr->gamma = gamma;
888 d_ptr->identifyColorSpace();
889 d_ptr->setTransferFunction();
893
894
895
896
897
898void QColorSpace::setTransferFunction(
const QList<uint16_t> &transferFunctionTable)
901 d_ptr =
new QColorSpacePrivate(Primaries::Custom, transferFunctionTable);
906 if (d_ptr->transformModel == TransformModel::ElementListProcessing)
907 d_ptr->clearElementListProcessingForEdit();
908 d_ptr->iccProfile = {};
909 d_ptr->description = QString();
910 d_ptr->setTransferFunctionTable(transferFunctionTable);
912 d_ptr->identifyColorSpace();
913 d_ptr->setTransferFunction();
917
918
919
920
921
922
923void QColorSpace::setTransferFunctions(
const QList<uint16_t> &redTransferFunctionTable,
924 const QList<uint16_t> &greenTransferFunctionTable,
925 const QList<uint16_t> &blueTransferFunctionTable)
928 d_ptr =
new QColorSpacePrivate();
929 d_ptr->setTransferFunctionTables(redTransferFunctionTable,
930 greenTransferFunctionTable,
931 blueTransferFunctionTable);
936 if (d_ptr->transformModel == TransformModel::ElementListProcessing)
937 d_ptr->clearElementListProcessingForEdit();
938 d_ptr->iccProfile = {};
939 d_ptr->description = QString();
940 d_ptr->setTransferFunctionTables(redTransferFunctionTable,
941 greenTransferFunctionTable,
942 blueTransferFunctionTable);
944 d_ptr->identifyColorSpace();
948
949
950
951
952
953QColorSpace QColorSpace::withTransferFunction(QColorSpace::TransferFunction transferFunction,
float gamma)
const
955 if (!isValid() || transferFunction == TransferFunction::Custom)
957 if (d_ptr->transferFunction == transferFunction && d_ptr->gamma == gamma)
959 QColorSpace out(*
this);
960 out.setTransferFunction(transferFunction, gamma);
965
966
967
968
969
970
971QColorSpace QColorSpace::withTransferFunction(
const QList<uint16_t> &transferFunctionTable)
const
975 QColorSpace out(*
this);
976 out.setTransferFunction(transferFunctionTable);
981
982
983
984
985
986
987
988QColorSpace QColorSpace::withTransferFunctions(
const QList<uint16_t> &redTransferFunctionTable,
989 const QList<uint16_t> &greenTransferFunctionTable,
990 const QList<uint16_t> &blueTransferFunctionTable)
const
994 QColorSpace out(*
this);
995 out.setTransferFunctions(redTransferFunctionTable, greenTransferFunctionTable, blueTransferFunctionTable);
1000
1001
1002
1003
1004void QColorSpace::setPrimaries(QColorSpace::Primaries primariesId)
1006 if (primariesId == Primaries::Custom)
1009 d_ptr =
new QColorSpacePrivate(primariesId, TransferFunction::Custom, 0.0f);
1012 if (d_ptr->primaries == primariesId)
1015 if (d_ptr->transformModel == TransformModel::ElementListProcessing)
1016 d_ptr->clearElementListProcessingForEdit();
1017 d_ptr->iccProfile = {};
1018 d_ptr->description = QString();
1019 d_ptr->primaries = primariesId;
1020 d_ptr->colorModel = QColorSpace::ColorModel::Rgb;
1021 d_ptr->identifyColorSpace();
1022 d_ptr->setToXyzMatrix();
1026
1027
1028
1029
1030
1031void QColorSpace::setPrimaries(
const QPointF &whitePoint,
const QPointF &redPoint,
1032 const QPointF &greenPoint,
const QPointF &bluePoint)
1034 setPrimaryPoints({whitePoint, redPoint, greenPoint, bluePoint});
1038
1039
1040
1041
1042
1043void QColorSpace::setPrimaryPoints(
const QColorSpace::PrimaryPoints &primaryPoints)
1045 if (!primaryPoints.isValid())
1048 d_ptr =
new QColorSpacePrivate(primaryPoints, TransferFunction::Custom, 0.0f);
1051 QColorMatrix toXyz = qColorSpacePrimaryPointsToXyzMatrix(primaryPoints);
1052 QColorMatrix chad = QColorMatrix::chromaticAdaptation(QColorVector::fromXYChromaticity(primaryPoints.whitePoint));
1053 toXyz = chad * toXyz;
1054 if (QColorVector::fromXYChromaticity(primaryPoints.whitePoint) == d_ptr->whitePoint
1055 && toXyz == d_ptr->toXyz && chad == d_ptr->chad)
1058 if (d_ptr->transformModel == TransformModel::ElementListProcessing)
1059 d_ptr->clearElementListProcessingForEdit();
1060 d_ptr->iccProfile = {};
1061 d_ptr->description = QString();
1062 d_ptr->primaries = QColorSpace::Primaries::Custom;
1063 d_ptr->colorModel = QColorSpace::ColorModel::Rgb;
1064 d_ptr->toXyz = toXyz;
1066 d_ptr->whitePoint = QColorVector::fromXYChromaticity(primaryPoints.whitePoint);
1067 d_ptr->identifyColorSpace();
1071
1072
1073
1074
1075
1076QColorSpace::PrimaryPoints QColorSpace::primaryPoints()
const
1078 if (Q_UNLIKELY(!d_ptr))
1080 QColorMatrix rawToXyz = d_ptr->chad.inverted() * d_ptr->toXyz;
1081 return PrimaryPoints{rawToXyz.r.toChromaticity(),
1082 rawToXyz.g.toChromaticity(),
1083 rawToXyz.b.toChromaticity(),
1084 d_ptr->whitePoint.toChromaticity()};
1088
1089
1090
1091
1092QPointF QColorSpace::whitePoint()
const
1094 if (Q_UNLIKELY(!d_ptr))
1096 return d_ptr->whitePoint.toChromaticity();
1100
1101
1102
1103
1104void QColorSpace::setWhitePoint(QPointF whitePoint)
1106 if (Q_UNLIKELY(!d_ptr)) {
1107 d_ptr =
new QColorSpacePrivate(whitePoint, TransferFunction::Custom, 0.0f);
1110 if (QColorVector::fromXYChromaticity(whitePoint) == d_ptr->whitePoint)
1113 if (d_ptr->transformModel == TransformModel::ElementListProcessing)
1114 d_ptr->clearElementListProcessingForEdit();
1115 d_ptr->iccProfile = {};
1116 d_ptr->description = QString();
1117 d_ptr->primaries = QColorSpace::Primaries::Custom;
1119 if (d_ptr->colorModel == QColorSpace::ColorModel::Undefined)
1120 d_ptr->colorModel = QColorSpace::ColorModel::Gray;
1121 QColorVector wXyz(QColorVector::fromXYChromaticity(whitePoint));
1122 if (d_ptr->transformModel == QColorSpace::TransformModel::ThreeComponentMatrix) {
1123 if (d_ptr->colorModel == QColorSpace::ColorModel::Rgb) {
1125 QColorMatrix rawToXyz = d_ptr->chad.inverted() * d_ptr->toXyz;
1126 QColorVector whiteScale = rawToXyz.inverted().map(wXyz);
1127 rawToXyz = rawToXyz * QColorMatrix::fromScale(whiteScale);
1128 d_ptr->chad = QColorMatrix::chromaticAdaptation(wXyz);
1129 d_ptr->toXyz = d_ptr->chad * rawToXyz;
1130 }
else if (d_ptr->colorModel == QColorSpace::ColorModel::Gray) {
1131 d_ptr->chad = d_ptr->toXyz = QColorMatrix::chromaticAdaptation(wXyz);
1134 d_ptr->whitePoint = wXyz;
1135 d_ptr->identifyColorSpace();
1139
1140
1141
1142
1143QColorSpace::TransformModel QColorSpace::transformModel()
const noexcept
1145 if (Q_UNLIKELY(!d_ptr))
1146 return QColorSpace::TransformModel::ThreeComponentMatrix;
1147 return d_ptr->transformModel;
1151
1152
1153
1154
1155QColorSpace::ColorModel QColorSpace::colorModel()
const noexcept
1157 if (Q_UNLIKELY(!d_ptr))
1158 return QColorSpace::ColorModel::Undefined;
1159 return d_ptr->colorModel;
1163
1164
1165void QColorSpace::detach()
1170 d_ptr =
new QColorSpacePrivate;
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185QByteArray QColorSpace::iccProfile()
const
1187 if (Q_UNLIKELY(!d_ptr))
1188 return QByteArray();
1189 if (!d_ptr->iccProfile.isEmpty())
1190 return d_ptr->iccProfile;
1192 return QByteArray();
1193 return QIcc::toIccProfile(*
this);
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207QColorSpace QColorSpace::fromIccProfile(
const QByteArray &iccProfile)
1209 QColorSpace colorSpace;
1211 QByteArray ownedIccProfile = iccProfile.nullTerminated();
1212 if (QIcc::fromIccProfile(ownedIccProfile, &colorSpace))
1214 colorSpace.detach();
1215 colorSpace.d_ptr->iccProfile = std::move(ownedIccProfile);
1220
1221
1222
1223
1224
1225
1226
1227bool QColorSpace::isValid()
const noexcept
1231 return d_ptr->isValid();
1235
1236
1237
1238
1239bool QColorSpace::isValidTarget()
const noexcept
1243 if (!d_ptr->isThreeComponentMatrix())
1244 return !d_ptr->mBA.isEmpty();
1245 return d_ptr->isValid();
1249
1250
1253 if (!isThreeComponentMatrix())
1254 return !mAB.isEmpty();
1255 if (!toXyz.isValid())
1257 if (colorModel == QColorSpace::ColorModel::Gray) {
1258 if (!trc[0].isValid())
1260 }
else if (colorModel == QColorSpace::ColorModel::Rgb){
1261 if (!trc[0].isValid() || !trc[1].isValid() || !trc[2].isValid())
1270
1271
1272
1273
1274
1277
1278
1279
1280
1281
1286 return element.trc[0] == other.trc[0]
1287 && element.trc[1] == other.trc[1]
1288 && element.trc[2] == other.trc[2]
1289 && element.trc[3] == other.trc[3];
1295 return element == other;
1299 const QColorVector &other)
1301 return element == other;
1307 if (element.gridPointsX != other.gridPointsX)
1309 if (element.gridPointsY != other.gridPointsY)
1311 if (element.gridPointsZ != other.gridPointsZ)
1313 if (element.gridPointsW != other.gridPointsW)
1315 if (element.table.size() != other.table.size())
1317 for (qsizetype i = 0; i < element.table.size(); ++i) {
1318 if (element.table[i] != other.table[i])
1327 return compareElement(element,
std::get<T>(other));
1331
1332
1333bool QColorSpace::equals(
const QColorSpace &other)
const
1335 if (d_ptr == other.d_ptr)
1339 return d_ptr->equals(other.d_ptr.constData());
1343
1344
1350 if (namedColorSpace && other->namedColorSpace)
1351 return namedColorSpace == other->namedColorSpace;
1355 if (valid1 != valid2)
1357 if (!valid1 && !valid2) {
1358 if (!iccProfile.isEmpty() || !other->iccProfile.isEmpty())
1359 return iccProfile == other->iccProfile;
1365 if (transformModel != other->transformModel)
1371 if (colorModel != other->colorModel)
1373 if (mAB.count() != other->mAB.count())
1375 if (mBA.count() != other->mBA.count())
1379 for (qsizetype i = 0; i < mAB.count(); ++i) {
1380 if (mAB[i].index() != other->mAB[i].index())
1383 for (qsizetype i = 0; i < mBA.count(); ++i) {
1384 if (mBA[i].index() != other->mBA[i].index())
1389 for (qsizetype i = 0; i < mAB.count(); ++i) {
1390 if (!std::visit([&](
auto &&elm) {
return compareElements(elm, other->mAB[i]); }, mAB[i]))
1393 for (qsizetype i = 0; i < mBA.count(); ++i) {
1394 if (!std::visit([&](
auto &&elm) {
return compareElements(elm, other->mBA[i]); }, mBA[i]))
1401 if (primaries != QColorSpace::Primaries::Custom && other->primaries != QColorSpace::Primaries::Custom) {
1402 if (primaries != other->primaries)
1405 if (toXyz != other->toXyz)
1409 if (transferFunction != QColorSpace::TransferFunction::Custom && other->transferFunction != QColorSpace::TransferFunction::Custom) {
1410 if (transferFunction != other->transferFunction)
1412 if (transferFunction == QColorSpace::TransferFunction::Gamma)
1413 return (qAbs(
gamma - other
->gamma) <= (1.0f / 512.0f));
1417 if (trc[0] != other->trc[0] ||
1418 trc[1] != other->trc[1] ||
1419 trc[2] != other->trc[2])
1426
1427
1428
1429QColorTransform QColorSpace::transformationToColorSpace(
const QColorSpace &colorspace)
const
1432 return QColorTransform();
1434 if (*
this == colorspace)
1435 return QColorTransform();
1436 if (!colorspace.isValidTarget()) {
1437 qWarning() <<
"QColorSpace::transformationToColorSpace: colorspace not a valid target";
1438 return QColorTransform();
1441 return d_ptr->transformationToColorSpace(colorspace.d_ptr.get());
1445
1446
1447
1448QColorSpace::operator QVariant()
const
1450 return QVariant::fromValue(*
this);
1454
1455
1456
1457
1458
1459
1460
1461QString QColorSpace::description()
const noexcept
1464 return d_ptr->userDescription.isEmpty() ? d_ptr->description : d_ptr->userDescription;
1469
1470
1471
1472
1473
1474
1475
1476void QColorSpace::setDescription(
const QString &description)
1479 d_ptr->iccProfile = {};
1480 d_ptr->userDescription = description;
1484
1485
1486#if !defined(QT_NO_DATASTREAM)
1488
1489
1490
1491
1492
1493
1494
1498 s << image.iccProfile();
1503
1504
1505
1506
1507
1508
1509
1510
1514 QByteArray iccProfile;
1516 colorSpace = QColorSpace::fromIccProfile(iccProfile);
1521#ifndef QT_NO_DEBUG_STREAM
1524 return dbg <<
":Transfer";
1528 return dbg <<
":Matrix";
1532 return dbg <<
":Offset";
1536 return dbg <<
":CLUT";
1540 for (
auto &&element : elements)
1541 std::visit([&](
auto &&elm) { dbg << elm; }, element);
1546 QDebugStateSaver saver(dbg);
1548 dbg <<
"QColorSpace(";
1549 if (colorSpace.d_ptr) {
1550 if (colorSpace.d_ptr->namedColorSpace)
1551 dbg << colorSpace.d_ptr->namedColorSpace <<
", ";
1553 dbg << colorSpace.colorModel() <<
", ";
1554 if (!colorSpace.isValid()) {
1556 if (!colorSpace.d_ptr->iccProfile.isEmpty())
1557 dbg <<
" with profile data";
1558 }
else if (colorSpace.d_ptr->isThreeComponentMatrix()) {
1559 dbg << colorSpace.primaries() <<
", " << colorSpace.transferFunction();
1560 if (colorSpace.transferFunction() == QColorSpace::TransferFunction::Gamma)
1561 dbg <<
"=" << colorSpace.gamma();
1563 if (colorSpace.d_ptr->isPcsLab)
1567 dbg <<
"A2B" << colorSpace.d_ptr->mAB;
1568 if (!colorSpace.d_ptr->mBA.isEmpty())
1569 dbg <<
", B2A" << colorSpace.d_ptr->mBA;
1579#include "moc_qcolorspace.cpp"
QColorMatrix inverted() const
static QColorMatrix identity()
static QColorMatrix fromScale(QColorVector v)
friend constexpr QColorMatrix operator*(const QColorMatrix &a, const QColorMatrix &o)
QColorVector map(const QColorVector &c) const
void setTransferFunctionTables(const QList< uint16_t > &redTransferFunctionTable, const QList< uint16_t > &greenTransferFunctionTable, const QList< uint16_t > &blueTransferFunctionTable)
QColorSpacePrivate(QPointF whitePoint, const QList< uint16_t > &transferFunctionTable)
QColorSpacePrivate(QPointF whitePoint, QColorSpace::TransferFunction transferFunction, float gamma)
QColorSpacePrivate(const QColorSpace::PrimaryPoints &primaries, const QList< uint16_t > &transferFunctionTable)
QColorTransform transformationToColorSpace(const QColorSpacePrivate *out) const
void clearElementListProcessingForEdit()
void setTransferFunctionTable(const QList< uint16_t > &transferFunctionTable)
QColorTransform transformationToXYZ() const
bool isThreeComponentMatrix() const
QColorSpacePrivate(const QColorSpace::PrimaryPoints &primaries, const QList< uint16_t > &redTransferFunctionTable, const QList< uint16_t > &greenTransferFunctionTable, const QList< uint16_t > &blueRransferFunctionTable)
QColorSpacePrivate(const QColorSpace::PrimaryPoints &primaries, QColorSpace::TransferFunction transferFunction, float gamma)
void setTransferFunction()
void identifyColorSpace()
bool isValid() const noexcept
QColorSpacePrivate(QColorSpace::NamedColorSpace namedColorSpace)
bool equals(const QColorSpacePrivate *other) const
Combined button and popup list for selecting options.
static void cleanupPredefinedColorspaces()
static bool compareElement(const QColorSpacePrivate::TransferElement &element, const QColorSpacePrivate::TransferElement &other)
QDebug operator<<(QDebug dbg, const QColorCLUT &)
QDebug operator<<(QDebug dbg, const QColorSpace &colorSpace)
QDebug operator<<(QDebug dbg, const QColorMatrix &)
static bool compareElement(const QColorMatrix &element, const QColorMatrix &other)
QDataStream & operator>>(QDataStream &s, QColorSpace &colorSpace)
QDataStream & operator<<(QDataStream &s, const QColorSpace &image)
QDebug operator<<(QDebug dbg, const QColorVector &)
QColorMatrix qColorSpacePrimaryPointsToXyzMatrix(const QColorSpace::PrimaryPoints &primaries)
static bool compareElements(const T &element, const QColorSpacePrivate::Element &other)
static bool compareElement(const QColorCLUT &element, const QColorCLUT &other)
static bool compareElement(const QColorVector &element, const QColorVector &other)
QDebug operator<<(QDebug dbg, const QColorSpacePrivate::TransferElement &)
QDebug operator<<(QDebug dbg, const QFileInfo &fi)