16#include <qtransform.h>
22Q_CONSTINIT QBasicMutex QColorSpacePrivate::s_lutWriteLock;
24Q_CONSTINIT
static QAtomicPointer<QColorSpacePrivate> s_predefinedColorspacePrivates[QColorSpace::Bt2100Hlg] = {};
27 for (QAtomicPointer<QColorSpacePrivate> &ptr : s_predefinedColorspacePrivates) {
28 QColorSpacePrivate *prv = ptr.fetchAndStoreAcquire(
nullptr);
29 if (prv && !prv->ref.deref())
34Q_DESTRUCTOR_FUNCTION(cleanupPredefinedColorspaces)
36QColorSpace::PrimaryPoints QColorSpace::PrimaryPoints::fromPrimaries(Primaries primaries)
41 out.redPoint = QPointF(0.640, 0.330);
42 out.greenPoint = QPointF(0.300, 0.600);
43 out.bluePoint = QPointF(0.150, 0.060);
44 out.whitePoint = QColorVector::D65Chromaticity();
46 case Primaries::DciP3D65:
47 out.redPoint = QPointF(0.680, 0.320);
48 out.greenPoint = QPointF(0.265, 0.690);
49 out.bluePoint = QPointF(0.150, 0.060);
50 out.whitePoint = QColorVector::D65Chromaticity();
52 case Primaries::AdobeRgb:
53 out.redPoint = QPointF(0.640, 0.330);
54 out.greenPoint = QPointF(0.210, 0.710);
55 out.bluePoint = QPointF(0.150, 0.060);
56 out.whitePoint = QColorVector::D65Chromaticity();
58 case Primaries::ProPhotoRgb:
59 out.redPoint = QPointF(0.7347, 0.2653);
60 out.greenPoint = QPointF(0.1596, 0.8404);
61 out.bluePoint = QPointF(0.0366, 0.0001);
62 out.whitePoint = QColorVector::D50Chromaticity();
64 case Primaries::Bt2020:
65 out.redPoint = QPointF(0.708, 0.292);
66 out.greenPoint = QPointF(0.170, 0.797);
67 out.bluePoint = QPointF(0.131, 0.046);
68 out.whitePoint = QColorVector::D65Chromaticity();
76bool QColorSpace::PrimaryPoints::isValid()
const noexcept
78 if (!QColorVector::isValidChromaticity(redPoint))
80 if (!QColorVector::isValidChromaticity(greenPoint))
82 if (!QColorVector::isValidChromaticity(bluePoint))
84 if (!QColorVector::isValidChromaticity(whitePoint))
93 QColorVector::fromXYChromaticity(primaries.redPoint),
94 QColorVector::fromXYChromaticity(primaries.greenPoint),
95 QColorVector::fromXYChromaticity(primaries.bluePoint)
101 const auto wXyz = QColorVector::fromXYChromaticity(primaries.whitePoint);
118 switch (namedColorSpace) {
119 case QColorSpace::SRgb:
120 primaries = QColorSpace::Primaries::SRgb;
121 transferFunction = QColorSpace::TransferFunction::SRgb;
122 description = QStringLiteral(
"sRGB");
124 case QColorSpace::SRgbLinear:
125 primaries = QColorSpace::Primaries::SRgb;
126 transferFunction = QColorSpace::TransferFunction::Linear;
127 description = QStringLiteral(
"Linear sRGB");
129 case QColorSpace::AdobeRgb:
130 primaries = QColorSpace::Primaries::AdobeRgb;
131 transferFunction = QColorSpace::TransferFunction::Gamma;
133 description = QStringLiteral(
"Adobe RGB");
135 case QColorSpace::DisplayP3:
136 primaries = QColorSpace::Primaries::DciP3D65;
137 transferFunction = QColorSpace::TransferFunction::SRgb;
138 description = QStringLiteral(
"Display P3");
140 case QColorSpace::ProPhotoRgb:
141 primaries = QColorSpace::Primaries::ProPhotoRgb;
142 transferFunction = QColorSpace::TransferFunction::ProPhotoRgb;
143 description = QStringLiteral(
"ProPhoto RGB");
145 case QColorSpace::Bt2020:
146 primaries = QColorSpace::Primaries::Bt2020;
147 transferFunction = QColorSpace::TransferFunction::Bt2020;
148 description = QStringLiteral(
"BT.2020");
150 case QColorSpace::Bt2100Pq:
151 primaries = QColorSpace::Primaries::Bt2020;
152 transferFunction = QColorSpace::TransferFunction::St2084;
153 description = QStringLiteral(
"BT.2100(PQ)");
155 case QColorSpace::Bt2100Hlg:
156 primaries = QColorSpace::Primaries::Bt2020;
157 transferFunction = QColorSpace::TransferFunction::Hlg;
158 description = QStringLiteral(
"BT.2100(HLG)");
177 QColorSpace::TransferFunction transferFunction,
185 Q_ASSERT(primaries.isValid());
186 toXyz = qColorSpacePrimaryPointsToXyzMatrix(primaries);
187 chad = QColorMatrix::chromaticAdaptation(whitePoint);
188 toXyz = chad * toXyz;
195 QColorSpace::TransferFunction transferFunction,
203 chad = QColorMatrix::chromaticAdaptation(
this->whitePoint);
215 chad = QColorMatrix::chromaticAdaptation(
this->whitePoint);
217 setTransferFunctionTable(transferFunctionTable);
227 setTransferFunctionTable(transferFunctionTable);
239 Q_ASSERT(primaries.isValid());
240 toXyz = qColorSpacePrimaryPointsToXyzMatrix(primaries);
241 chad = QColorMatrix::chromaticAdaptation(whitePoint);
242 toXyz = chad * toXyz;
243 setTransferFunctionTable(transferFunctionTable);
249 const QList<uint16_t> &redTransferFunctionTable,
250 const QList<uint16_t> &greenTransferFunctionTable,
251 const QList<uint16_t> &blueTransferFunctionTable)
257 Q_ASSERT(primaries.isValid());
258 toXyz = qColorSpacePrimaryPointsToXyzMatrix(primaries);
259 whitePoint = QColorVector::fromXYChromaticity(primaries.whitePoint);
260 chad = QColorMatrix::chromaticAdaptation(whitePoint);
261 toXyz = chad * toXyz;
262 setTransferFunctionTables(redTransferFunctionTable,
263 greenTransferFunctionTable,
264 blueTransferFunctionTable);
271 case QColorSpace::Primaries::SRgb:
272 if (transferFunction == QColorSpace::TransferFunction::SRgb) {
273 namedColorSpace = QColorSpace::SRgb;
274 if (description.isEmpty())
275 description = QStringLiteral(
"sRGB");
278 if (transferFunction == QColorSpace::TransferFunction::Linear) {
279 namedColorSpace = QColorSpace::SRgbLinear;
280 if (description.isEmpty())
281 description = QStringLiteral(
"Linear sRGB");
285 case QColorSpace::Primaries::AdobeRgb:
286 if (transferFunction == QColorSpace::TransferFunction::Gamma) {
287 if (qAbs(
gamma - 2.19921875f) < (1/1024.0f)) {
288 namedColorSpace = QColorSpace::AdobeRgb;
289 if (description.isEmpty())
290 description = QStringLiteral(
"Adobe RGB");
295 case QColorSpace::Primaries::DciP3D65:
296 if (transferFunction == QColorSpace::TransferFunction::SRgb) {
297 namedColorSpace = QColorSpace::DisplayP3;
298 if (description.isEmpty())
299 description = QStringLiteral(
"Display P3");
303 case QColorSpace::Primaries::ProPhotoRgb:
304 if (transferFunction == QColorSpace::TransferFunction::ProPhotoRgb) {
305 namedColorSpace = QColorSpace::ProPhotoRgb;
306 if (description.isEmpty())
307 description = QStringLiteral(
"ProPhoto RGB");
310 if (transferFunction == QColorSpace::TransferFunction::Gamma) {
312 if (qAbs(
gamma - 1.8f) < (1/1024.0f)) {
313 namedColorSpace = QColorSpace::ProPhotoRgb;
314 if (description.isEmpty())
315 description = QStringLiteral(
"ProPhoto RGB");
320 case QColorSpace::Primaries::Bt2020:
321 if (transferFunction == QColorSpace::TransferFunction::Bt2020) {
322 namedColorSpace = QColorSpace::Bt2020;
323 if (description.isEmpty())
324 description = QStringLiteral(
"BT.2020");
327 if (transferFunction == QColorSpace::TransferFunction::St2084) {
328 namedColorSpace = QColorSpace::Bt2100Pq;
329 if (description.isEmpty())
330 description = QStringLiteral(
"BT.2100(PQ)");
333 if (transferFunction == QColorSpace::TransferFunction::Hlg) {
334 namedColorSpace = QColorSpace::Bt2100Hlg;
335 if (description.isEmpty())
336 description = QStringLiteral(
"BT.2100(HLG)");
344 namedColorSpace = Unknown;
355 if (primaries == QColorSpace::Primaries::Custom) {
356 toXyz = QColorMatrix();
357 whitePoint = QColorVector::D50();
360 auto colorSpacePrimaries = QColorSpace::PrimaryPoints::fromPrimaries(primaries);
361 toXyz = qColorSpacePrimaryPointsToXyzMatrix(colorSpacePrimaries);
362 whitePoint = QColorVector::fromXYChromaticity(colorSpacePrimaries.whitePoint);
363 chad = QColorMatrix::chromaticAdaptation(whitePoint);
364 toXyz = chad * toXyz;
369 QColorTransferTable table(transferFunctionTable.size(), transferFunctionTable);
370 if (!table.isEmpty() && !table.checkValidity()) {
371 qWarning() <<
"Invalid transfer function table given to QColorSpace";
372 trc[0].m_type = QColorTrc::Type::Uninitialized;
375 transferFunction = QColorSpace::TransferFunction::Custom;
377 if (table.asColorTransferFunction(&curve)) {
380 transferFunction = QColorSpace::TransferFunction::Linear;
383 transferFunction = QColorSpace::TransferFunction::SRgb;
385 trc[0].m_type = QColorTrc::Type::ParameterizedFunction;
386 trc[0].m_fun = curve;
388 trc[0].m_type = QColorTrc::Type::Table;
389 trc[0].m_table = table;
394 const QList<uint16_t> &greenTransferFunctionTable,
395 const QList<uint16_t> &blueTransferFunctionTable)
397 QColorTransferTable redTable(redTransferFunctionTable.size(), redTransferFunctionTable);
398 QColorTransferTable greenTable(greenTransferFunctionTable.size(), greenTransferFunctionTable);
399 QColorTransferTable blueTable(blueTransferFunctionTable.size(), blueTransferFunctionTable);
400 if (!redTable.isEmpty() && !greenTable.isEmpty() && !blueTable.isEmpty() &&
401 !redTable.checkValidity() && !greenTable.checkValidity() && !blueTable.checkValidity()) {
402 qWarning() <<
"Invalid transfer function table given to QColorSpace";
403 trc[0].m_type = QColorTrc::Type::Uninitialized;
404 trc[1].m_type = QColorTrc::Type::Uninitialized;
405 trc[2].m_type = QColorTrc::Type::Uninitialized;
408 transferFunction = QColorSpace::TransferFunction::Custom;
410 if (redTable.asColorTransferFunction(&curve)) {
411 trc[0].m_type = QColorTrc::Type::ParameterizedFunction;
412 trc[0].m_fun = curve;
414 trc[0].m_type = QColorTrc::Type::Table;
415 trc[0].m_table = redTable;
417 if (greenTable.asColorTransferFunction(&curve)) {
418 trc[1].m_type = QColorTrc::Type::ParameterizedFunction;
419 trc[1].m_fun = curve;
421 trc[1].m_type = QColorTrc::Type::Table;
422 trc[1].m_table = greenTable;
424 if (blueTable.asColorTransferFunction(&curve)) {
425 trc[2].m_type = QColorTrc::Type::ParameterizedFunction;
426 trc[2].m_fun = curve;
428 trc[2].m_type = QColorTrc::Type::Table;
429 trc[2].m_table = blueTable;
431 lut.generated.storeRelease(0);
436 switch (transferFunction) {
437 case QColorSpace::TransferFunction::Linear:
438 trc[0] = QColorTransferFunction();
439 if (qFuzzyIsNull(
gamma))
442 case QColorSpace::TransferFunction::Gamma:
443 trc[0] = QColorTransferFunction::fromGamma(gamma);
445 case QColorSpace::TransferFunction::SRgb:
446 trc[0] = QColorTransferFunction::fromSRgb();
447 if (qFuzzyIsNull(
gamma))
450 case QColorSpace::TransferFunction::ProPhotoRgb:
451 trc[0] = QColorTransferFunction::fromProPhotoRgb();
452 if (qFuzzyIsNull(
gamma))
455 case QColorSpace::TransferFunction::Bt2020:
456 trc[0] = QColorTransferFunction::fromBt2020();
457 if (qFuzzyIsNull(
gamma))
460 case QColorSpace::TransferFunction::St2084:
461 trc[0] = QColorTransferGenericFunction::pq();
463 case QColorSpace::TransferFunction::Hlg:
464 trc[0] = QColorTransferGenericFunction::hlg();
466 case QColorSpace::TransferFunction::Custom:
474 lut.generated.storeRelease(0);
483 ptr->colorSpaceIn =
this;
484 ptr->colorSpaceOut = out;
486 ptr->colorMatrix = toXyz;
490 ptr->colorMatrix = out->toXyz.inverted() * ptr->colorMatrix;
492 return QColorTransform();
501 ptr->colorSpaceIn =
this;
502 ptr->colorSpaceOut =
this;
504 ptr->colorMatrix = toXyz;
509 ptr->colorMatrix = chad.inverted() * ptr->colorMatrix;
515 return transformModel == QColorSpace::TransformModel::ThreeComponentMatrix;
520 Q_ASSERT(transformModel == QColorSpace::TransformModel::ElementListProcessing);
521 Q_ASSERT(primaries == QColorSpace::Primaries::Custom);
522 Q_ASSERT(transferFunction == QColorSpace::TransferFunction::Custom);
524 transformModel = QColorSpace::TransformModel::ThreeComponentMatrix;
525 colorModel = QColorSpace::ColorModel::Rgb;
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
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
593
594
595
596
597
598
599
600
601
602
603
606
607
608
609
610
611
612
613
614
615
616
617
618
619
622
623
624
625
626
627
628
629
630
631
632
633
634
635
638
639
640
641
642
643
644
645
646
647
648
651
652
653
654
655
656
657
658
659
662
663
664
665
668
669
670
671
674
675
676
677
680
681
682QColorSpace::QColorSpace(NamedColorSpace namedColorSpace)
684 if (namedColorSpace < QColorSpace::SRgb || namedColorSpace > QColorSpace::Bt2100Hlg) {
685 qWarning() <<
"QColorSpace attempted constructed from invalid QColorSpace::NamedColorSpace: " <<
int(namedColorSpace);
689 auto &atomicRef = s_predefinedColorspacePrivates[
static_cast<
int>(namedColorSpace) - 1];
690 QColorSpacePrivate *cspriv = atomicRef.loadAcquire();
692 auto *tmp =
new QColorSpacePrivate(namedColorSpace);
694 if (atomicRef.testAndSetOrdered(
nullptr, tmp, cspriv))
704
705
706
707QColorSpace::QColorSpace(QColorSpace::Primaries primaries, QColorSpace::TransferFunction transferFunction,
float gamma)
708 : d_ptr(
new QColorSpacePrivate(primaries, transferFunction, gamma))
713
714
715
716QColorSpace::QColorSpace(QColorSpace::Primaries primaries,
float gamma)
717 : d_ptr(
new QColorSpacePrivate(primaries, TransferFunction::Gamma, gamma))
722
723
724
725
726
727
728
729
730QColorSpace::QColorSpace(QColorSpace::Primaries gamut,
const QList<uint16_t> &transferFunctionTable)
731 : d_ptr(
new QColorSpacePrivate(gamut, transferFunctionTable))
736
737
738
739
740
741QColorSpace::QColorSpace(QPointF whitePoint, TransferFunction transferFunction,
float gamma)
742 : d_ptr(
new QColorSpacePrivate(whitePoint, transferFunction, gamma))
747
748
749
750
751
752QColorSpace::QColorSpace(QPointF whitePoint,
const QList<uint16_t> &transferFunctionTable)
753 : d_ptr(
new QColorSpacePrivate(whitePoint, transferFunctionTable))
758
759
760
761QColorSpace::QColorSpace(
const QPointF &whitePoint,
const QPointF &redPoint,
762 const QPointF &greenPoint,
const QPointF &bluePoint,
763 QColorSpace::TransferFunction transferFunction,
float gamma)
764 : QColorSpace({whitePoint, redPoint, greenPoint, bluePoint}, transferFunction, gamma)
769
770
771
772
773
774QColorSpace::QColorSpace(
const PrimaryPoints &primaryPoints, TransferFunction transferFunction,
float gamma)
776 if (!primaryPoints.isValid()) {
777 qWarning() <<
"QColorSpace attempted constructed from invalid primaries:"
778 << primaryPoints.whitePoint << primaryPoints.redPoint << primaryPoints.greenPoint << primaryPoints.bluePoint;
781 d_ptr =
new QColorSpacePrivate(primaryPoints, transferFunction, gamma);
785
786
787
788
789
790
791QColorSpace::QColorSpace(
const QPointF &whitePoint,
const QPointF &redPoint,
792 const QPointF &greenPoint,
const QPointF &bluePoint,
793 const QList<uint16_t> &transferFunctionTable)
794 : d_ptr(
new QColorSpacePrivate({whitePoint, redPoint, greenPoint, bluePoint}, transferFunctionTable))
799
800
801
802
803
804
805QColorSpace::QColorSpace(
const QPointF &whitePoint,
const QPointF &redPoint,
806 const QPointF &greenPoint,
const QPointF &bluePoint,
807 const QList<uint16_t> &redTransferFunctionTable,
808 const QList<uint16_t> &greenTransferFunctionTable,
809 const QList<uint16_t> &blueTransferFunctionTable)
810 : d_ptr(
new QColorSpacePrivate({whitePoint, redPoint, greenPoint, bluePoint},
811 redTransferFunctionTable,
812 greenTransferFunctionTable,
813 blueTransferFunctionTable))
817QColorSpace::~QColorSpace() =
default;
819QT_DEFINE_QESDP_SPECIALIZATION_DTOR(QColorSpacePrivate)
821QColorSpace::QColorSpace(
const QColorSpace &colorSpace)
noexcept =
default;
824
825
828
829
830
831QColorSpace::Primaries QColorSpace::primaries()
const noexcept
833 if (Q_UNLIKELY(!d_ptr))
834 return QColorSpace::Primaries::Custom;
835 return d_ptr->primaries;
839
840
841
842
843
844QColorSpace::TransferFunction QColorSpace::transferFunction()
const noexcept
846 if (Q_UNLIKELY(!d_ptr))
847 return QColorSpace::TransferFunction::Custom;
848 return d_ptr->transferFunction;
852
853
854
855
856
857
858float QColorSpace::gamma()
const noexcept
860 if (Q_UNLIKELY(!d_ptr))
866
867
868
869
870void QColorSpace::setTransferFunction(QColorSpace::TransferFunction transferFunction,
float gamma)
872 if (transferFunction == TransferFunction::Custom)
875 d_ptr =
new QColorSpacePrivate(Primaries::Custom, transferFunction, gamma);
878 if (d_ptr->transferFunction == transferFunction && d_ptr->gamma == gamma)
881 if (d_ptr->transformModel == TransformModel::ElementListProcessing)
882 d_ptr->clearElementListProcessingForEdit();
883 d_ptr->iccProfile = {};
884 d_ptr->description = QString();
885 d_ptr->transferFunction = transferFunction;
886 d_ptr->gamma = gamma;
887 d_ptr->identifyColorSpace();
888 d_ptr->setTransferFunction();
892
893
894
895
896
897void QColorSpace::setTransferFunction(
const QList<uint16_t> &transferFunctionTable)
900 d_ptr =
new QColorSpacePrivate(Primaries::Custom, transferFunctionTable);
905 if (d_ptr->transformModel == TransformModel::ElementListProcessing)
906 d_ptr->clearElementListProcessingForEdit();
907 d_ptr->iccProfile = {};
908 d_ptr->description = QString();
909 d_ptr->setTransferFunctionTable(transferFunctionTable);
911 d_ptr->identifyColorSpace();
912 d_ptr->setTransferFunction();
916
917
918
919
920
921
922void QColorSpace::setTransferFunctions(
const QList<uint16_t> &redTransferFunctionTable,
923 const QList<uint16_t> &greenTransferFunctionTable,
924 const QList<uint16_t> &blueTransferFunctionTable)
927 d_ptr =
new QColorSpacePrivate();
928 d_ptr->setTransferFunctionTables(redTransferFunctionTable,
929 greenTransferFunctionTable,
930 blueTransferFunctionTable);
935 if (d_ptr->transformModel == TransformModel::ElementListProcessing)
936 d_ptr->clearElementListProcessingForEdit();
937 d_ptr->iccProfile = {};
938 d_ptr->description = QString();
939 d_ptr->setTransferFunctionTables(redTransferFunctionTable,
940 greenTransferFunctionTable,
941 blueTransferFunctionTable);
943 d_ptr->identifyColorSpace();
947
948
949
950
951
952QColorSpace QColorSpace::withTransferFunction(QColorSpace::TransferFunction transferFunction,
float gamma)
const
954 if (!isValid() || transferFunction == TransferFunction::Custom)
956 if (d_ptr->transferFunction == transferFunction && d_ptr->gamma == gamma)
958 QColorSpace out(*
this);
959 out.setTransferFunction(transferFunction, gamma);
964
965
966
967
968
969
970QColorSpace QColorSpace::withTransferFunction(
const QList<uint16_t> &transferFunctionTable)
const
974 QColorSpace out(*
this);
975 out.setTransferFunction(transferFunctionTable);
980
981
982
983
984
985
986
987QColorSpace QColorSpace::withTransferFunctions(
const QList<uint16_t> &redTransferFunctionTable,
988 const QList<uint16_t> &greenTransferFunctionTable,
989 const QList<uint16_t> &blueTransferFunctionTable)
const
993 QColorSpace out(*
this);
994 out.setTransferFunctions(redTransferFunctionTable, greenTransferFunctionTable, blueTransferFunctionTable);
999
1000
1001
1002
1003void QColorSpace::setPrimaries(QColorSpace::Primaries primariesId)
1005 if (primariesId == Primaries::Custom)
1008 d_ptr =
new QColorSpacePrivate(primariesId, TransferFunction::Custom, 0.0f);
1011 if (d_ptr->primaries == primariesId)
1014 if (d_ptr->transformModel == TransformModel::ElementListProcessing)
1015 d_ptr->clearElementListProcessingForEdit();
1016 d_ptr->iccProfile = {};
1017 d_ptr->description = QString();
1018 d_ptr->primaries = primariesId;
1019 d_ptr->colorModel = QColorSpace::ColorModel::Rgb;
1020 d_ptr->identifyColorSpace();
1021 d_ptr->setToXyzMatrix();
1025
1026
1027
1028
1029
1030void QColorSpace::setPrimaries(
const QPointF &whitePoint,
const QPointF &redPoint,
1031 const QPointF &greenPoint,
const QPointF &bluePoint)
1033 setPrimaryPoints({whitePoint, redPoint, greenPoint, bluePoint});
1037
1038
1039
1040
1041
1042void QColorSpace::setPrimaryPoints(
const QColorSpace::PrimaryPoints &primaryPoints)
1044 if (!primaryPoints.isValid())
1047 d_ptr =
new QColorSpacePrivate(primaryPoints, TransferFunction::Custom, 0.0f);
1050 QColorMatrix toXyz = qColorSpacePrimaryPointsToXyzMatrix(primaryPoints);
1051 QColorMatrix chad = QColorMatrix::chromaticAdaptation(QColorVector::fromXYChromaticity(primaryPoints.whitePoint));
1052 toXyz = chad * toXyz;
1053 if (QColorVector::fromXYChromaticity(primaryPoints.whitePoint) == d_ptr->whitePoint
1054 && toXyz == d_ptr->toXyz && chad == d_ptr->chad)
1057 if (d_ptr->transformModel == TransformModel::ElementListProcessing)
1058 d_ptr->clearElementListProcessingForEdit();
1059 d_ptr->iccProfile = {};
1060 d_ptr->description = QString();
1061 d_ptr->primaries = QColorSpace::Primaries::Custom;
1062 d_ptr->colorModel = QColorSpace::ColorModel::Rgb;
1063 d_ptr->toXyz = toXyz;
1065 d_ptr->whitePoint = QColorVector::fromXYChromaticity(primaryPoints.whitePoint);
1066 d_ptr->identifyColorSpace();
1070
1071
1072
1073
1074
1075QColorSpace::PrimaryPoints QColorSpace::primaryPoints()
const
1077 if (Q_UNLIKELY(!d_ptr))
1079 QColorMatrix rawToXyz = d_ptr->chad.inverted() * d_ptr->toXyz;
1080 return PrimaryPoints{rawToXyz.r.toChromaticity(),
1081 rawToXyz.g.toChromaticity(),
1082 rawToXyz.b.toChromaticity(),
1083 d_ptr->whitePoint.toChromaticity()};
1087
1088
1089
1090
1091QPointF QColorSpace::whitePoint()
const
1093 if (Q_UNLIKELY(!d_ptr))
1095 return d_ptr->whitePoint.toChromaticity();
1099
1100
1101
1102
1103void QColorSpace::setWhitePoint(QPointF whitePoint)
1105 if (Q_UNLIKELY(!d_ptr)) {
1106 d_ptr =
new QColorSpacePrivate(whitePoint, TransferFunction::Custom, 0.0f);
1109 if (QColorVector::fromXYChromaticity(whitePoint) == d_ptr->whitePoint)
1112 if (d_ptr->transformModel == TransformModel::ElementListProcessing)
1113 d_ptr->clearElementListProcessingForEdit();
1114 d_ptr->iccProfile = {};
1115 d_ptr->description = QString();
1116 d_ptr->primaries = QColorSpace::Primaries::Custom;
1118 if (d_ptr->colorModel == QColorSpace::ColorModel::Undefined)
1119 d_ptr->colorModel = QColorSpace::ColorModel::Gray;
1120 QColorVector wXyz(QColorVector::fromXYChromaticity(whitePoint));
1121 if (d_ptr->transformModel == QColorSpace::TransformModel::ThreeComponentMatrix) {
1122 if (d_ptr->colorModel == QColorSpace::ColorModel::Rgb) {
1124 QColorMatrix rawToXyz = d_ptr->chad.inverted() * d_ptr->toXyz;
1125 QColorVector whiteScale = rawToXyz.inverted().map(wXyz);
1126 rawToXyz = rawToXyz * QColorMatrix::fromScale(whiteScale);
1127 d_ptr->chad = QColorMatrix::chromaticAdaptation(wXyz);
1128 d_ptr->toXyz = d_ptr->chad * rawToXyz;
1129 }
else if (d_ptr->colorModel == QColorSpace::ColorModel::Gray) {
1130 d_ptr->chad = d_ptr->toXyz = QColorMatrix::chromaticAdaptation(wXyz);
1133 d_ptr->whitePoint = wXyz;
1134 d_ptr->identifyColorSpace();
1138
1139
1140
1141
1142QColorSpace::TransformModel QColorSpace::transformModel()
const noexcept
1144 if (Q_UNLIKELY(!d_ptr))
1145 return QColorSpace::TransformModel::ThreeComponentMatrix;
1146 return d_ptr->transformModel;
1150
1151
1152
1153
1154QColorSpace::ColorModel QColorSpace::colorModel()
const noexcept
1156 if (Q_UNLIKELY(!d_ptr))
1157 return QColorSpace::ColorModel::Undefined;
1158 return d_ptr->colorModel;
1162
1163
1164void QColorSpace::detach()
1169 d_ptr =
new QColorSpacePrivate;
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184QByteArray QColorSpace::iccProfile()
const
1186 if (Q_UNLIKELY(!d_ptr))
1187 return QByteArray();
1188 if (!d_ptr->iccProfile.isEmpty())
1189 return d_ptr->iccProfile;
1191 return QByteArray();
1192 return QIcc::toIccProfile(*
this);
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206QColorSpace QColorSpace::fromIccProfile(
const QByteArray &iccProfile)
1208 QColorSpace colorSpace;
1209 if (QIcc::fromIccProfile(iccProfile, &colorSpace))
1211 colorSpace.detach();
1212 colorSpace.d_ptr->iccProfile = iccProfile;
1217
1218
1219
1220
1221
1222
1223
1224bool QColorSpace::isValid()
const noexcept
1228 return d_ptr->isValid();
1232
1233
1234
1235
1236bool QColorSpace::isValidTarget()
const noexcept
1240 if (!d_ptr->isThreeComponentMatrix())
1241 return !d_ptr->mBA.isEmpty();
1242 return d_ptr->isValid();
1246
1247
1250 if (!isThreeComponentMatrix())
1251 return !mAB.isEmpty();
1252 if (!toXyz.isValid())
1254 if (colorModel == QColorSpace::ColorModel::Gray) {
1255 if (!trc[0].isValid())
1257 }
else if (colorModel == QColorSpace::ColorModel::Rgb){
1258 if (!trc[0].isValid() || !trc[1].isValid() || !trc[2].isValid())
1267
1268
1269
1270
1271
1274
1275
1276
1277
1278
1283 return element.trc[0] == other.trc[0]
1284 && element.trc[1] == other.trc[1]
1285 && element.trc[2] == other.trc[2]
1286 && element.trc[3] == other.trc[3];
1292 return element == other;
1296 const QColorVector &other)
1298 return element == other;
1304 if (element.gridPointsX != other.gridPointsX)
1306 if (element.gridPointsY != other.gridPointsY)
1308 if (element.gridPointsZ != other.gridPointsZ)
1310 if (element.gridPointsW != other.gridPointsW)
1312 if (element.table.size() != other.table.size())
1314 for (qsizetype i = 0; i < element.table.size(); ++i) {
1315 if (element.table[i] != other.table[i])
1324 return compareElement(element,
std::get<T>(other));
1328
1329
1330bool QColorSpace::equals(
const QColorSpace &other)
const
1332 if (d_ptr == other.d_ptr)
1336 return d_ptr->equals(other.d_ptr.constData());
1340
1341
1347 if (namedColorSpace && other->namedColorSpace)
1348 return namedColorSpace == other->namedColorSpace;
1352 if (valid1 != valid2)
1354 if (!valid1 && !valid2) {
1355 if (!iccProfile.isEmpty() || !other->iccProfile.isEmpty())
1356 return iccProfile == other->iccProfile;
1362 if (transformModel != other->transformModel)
1368 if (colorModel != other->colorModel)
1370 if (mAB.count() != other->mAB.count())
1372 if (mBA.count() != other->mBA.count())
1376 for (qsizetype i = 0; i < mAB.count(); ++i) {
1377 if (mAB[i].index() != other->mAB[i].index())
1380 for (qsizetype i = 0; i < mBA.count(); ++i) {
1381 if (mBA[i].index() != other->mBA[i].index())
1386 for (qsizetype i = 0; i < mAB.count(); ++i) {
1387 if (!std::visit([&](
auto &&elm) {
return compareElements(elm, other->mAB[i]); }, mAB[i]))
1390 for (qsizetype i = 0; i < mBA.count(); ++i) {
1391 if (!std::visit([&](
auto &&elm) {
return compareElements(elm, other->mBA[i]); }, mBA[i]))
1398 if (primaries != QColorSpace::Primaries::Custom && other->primaries != QColorSpace::Primaries::Custom) {
1399 if (primaries != other->primaries)
1402 if (toXyz != other->toXyz)
1406 if (transferFunction != QColorSpace::TransferFunction::Custom && other->transferFunction != QColorSpace::TransferFunction::Custom) {
1407 if (transferFunction != other->transferFunction)
1409 if (transferFunction == QColorSpace::TransferFunction::Gamma)
1410 return (qAbs(
gamma - other
->gamma) <= (1.0f / 512.0f));
1414 if (trc[0] != other->trc[0] ||
1415 trc[1] != other->trc[1] ||
1416 trc[2] != other->trc[2])
1423
1424
1425
1426QColorTransform QColorSpace::transformationToColorSpace(
const QColorSpace &colorspace)
const
1429 return QColorTransform();
1431 if (*
this == colorspace)
1432 return QColorTransform();
1433 if (!colorspace.isValidTarget()) {
1434 qWarning() <<
"QColorSpace::transformationToColorSpace: colorspace not a valid target";
1435 return QColorTransform();
1438 return d_ptr->transformationToColorSpace(colorspace.d_ptr.get());
1442
1443
1444
1445QColorSpace::operator QVariant()
const
1447 return QVariant::fromValue(*
this);
1451
1452
1453
1454
1455
1456
1457
1458QString QColorSpace::description()
const noexcept
1461 return d_ptr->userDescription.isEmpty() ? d_ptr->description : d_ptr->userDescription;
1466
1467
1468
1469
1470
1471
1472
1473void QColorSpace::setDescription(
const QString &description)
1476 d_ptr->iccProfile = {};
1477 d_ptr->userDescription = description;
1481
1482
1483#if !defined(QT_NO_DATASTREAM)
1485
1486
1487
1488
1489
1490
1491
1495 s << image.iccProfile();
1500
1501
1502
1503
1504
1505
1506
1507
1511 QByteArray iccProfile;
1513 colorSpace = QColorSpace::fromIccProfile(iccProfile);
1518#ifndef QT_NO_DEBUG_STREAM
1521 return dbg <<
":Transfer";
1525 return dbg <<
":Matrix";
1529 return dbg <<
":Offset";
1533 return dbg <<
":CLUT";
1537 for (
auto &&element : elements)
1538 std::visit([&](
auto &&elm) { dbg << elm; }, element);
1543 QDebugStateSaver saver(dbg);
1545 dbg <<
"QColorSpace(";
1546 if (colorSpace.d_ptr) {
1547 if (colorSpace.d_ptr->namedColorSpace)
1548 dbg << colorSpace.d_ptr->namedColorSpace <<
", ";
1550 dbg << colorSpace.colorModel() <<
", ";
1551 if (!colorSpace.isValid()) {
1553 if (!colorSpace.d_ptr->iccProfile.isEmpty())
1554 dbg <<
" with profile data";
1555 }
else if (colorSpace.d_ptr->isThreeComponentMatrix()) {
1556 dbg << colorSpace.primaries() <<
", " << colorSpace.transferFunction();
1557 if (colorSpace.transferFunction() == QColorSpace::TransferFunction::Gamma)
1558 dbg <<
"=" << colorSpace.gamma();
1560 if (colorSpace.d_ptr->isPcsLab)
1564 dbg <<
"A2B" << colorSpace.d_ptr->mAB;
1565 if (!colorSpace.d_ptr->mBA.isEmpty())
1566 dbg <<
", B2A" << colorSpace.d_ptr->mBA;
1576#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)