59 return (
a << 24) | (
b << 16) | (
c << 8) |
d;
64 Gray =
IccTag(
'G',
'R',
'A',
'Y'),
267 return int(
x * 65536.0f + 0.5f);
272 return x * (1.0f / 65536.0f);
278 qCWarning(lcIcc,
"Failed ICC signature test");
284 qCWarning(lcIcc,
"Failed tag count sanity");
288 qCWarning(lcIcc,
"Failed basic size sanity");
315 qCWarning(lcIcc,
"Invalid ICC illuminant");
330 if (trc.
m_type == QColorTrc::Type::Function) {
378 if (!spaceDPtr->iccProfile.isEmpty())
379 return spaceDPtr->iccProfile;
380 Q_ASSERT(spaceDPtr->isThreeComponentMatrix());
382 int fixedLengthTagCount = 5;
383 bool writeChad =
false;
384 if (!spaceDPtr->whitePoint.isNull() && spaceDPtr->whitePoint !=
QColorVector::D50()) {
386 fixedLengthTagCount++;
389 const int tagCount = fixedLengthTagCount + 4;
390 const uint profileDataOffset = 128 + 4 + 12 * tagCount;
391 const uint variableTagTableOffsets = 128 + 4 + 12 * fixedLengthTagCount;
392 uint currentOffset = 0;
393 uint rTrcOffset, gTrcOffset, bTrcOffset;
394 uint rTrcSize, gTrcSize, bTrcSize;
395 uint descOffset, descSize;
407 stream << (spaceDPtr->isPcsLab ?
uint(Tag::Lab_) :
uint(Tag::XYZ_));
416 stream <<
IccTag(
'Q',
't', QT_VERSION_MAJOR, QT_VERSION_MINOR);
421 currentOffset = profileDataOffset;
428 currentOffset += 20 + 20 + 20 + 20 + 34 + 2;
477 rTrcOffset = currentOffset;
479 currentOffset += rTrcSize;
480 if (spaceDPtr->trc[0] == spaceDPtr->trc[1]) {
481 gTrcOffset = rTrcOffset;
484 gTrcOffset = currentOffset;
486 currentOffset += gTrcSize;
488 if (spaceDPtr->trc[0] == spaceDPtr->trc[2]) {
489 bTrcOffset = rTrcOffset;
492 bTrcOffset = currentOffset;
494 currentOffset += bTrcSize;
498 descOffset = currentOffset;
506 descSize = 28 + description.
size() * 2;
507 if (description.
size() & 1) {
511 currentOffset += descSize;
518 *(
quint32_be *)(iccProfile.
data() + variableTagTableOffsets + 4) = rTrcOffset;
519 *(
quint32_be *)(iccProfile.
data() + variableTagTableOffsets + 8) = rTrcSize;
520 *(
quint32_be *)(iccProfile.
data() + variableTagTableOffsets + 12 + 4) = gTrcOffset;
521 *(
quint32_be *)(iccProfile.
data() + variableTagTableOffsets + 12 + 8) = gTrcSize;
522 *(
quint32_be *)(iccProfile.
data() + variableTagTableOffsets + 2 * 12 + 4) = bTrcOffset;
523 *(
quint32_be *)(iccProfile.
data() + variableTagTableOffsets + 2 * 12 + 8) = bTrcSize;
524 *(
quint32_be *)(iccProfile.
data() + variableTagTableOffsets + 3 * 12 + 4) = descOffset;
525 *(
quint32_be *)(iccProfile.
data() + variableTagTableOffsets + 3 * 12 + 8) = descSize;
527#if !defined(QT_NO_DEBUG) || defined(QT_FORCE_ASSERTS)
544 qCWarning(lcIcc) <<
"Undersized XYZ tag";
547 const XYZTagData xyz = qFromUnaligned<XYZTagData>(
data.constData() + tagEntry.offset);
548 if (xyz.type !=
quint32(Tag::XYZ_)) {
549 qCWarning(lcIcc) <<
"Bad XYZ content type";
562 if (tagData.size() < 12)
564 const GenericTagData trcData = qFromUnaligned<GenericTagData>(tagData.constData());
565 if (trcData.type ==
quint32(Tag::curv)) {
567 const CurvTagData curv = qFromUnaligned<CurvTagData>(tagData.constData());
568 if (
curv.valueCount > (1 << 16))
573 if (
curv.valueCount == 0) {
574 gamma.
m_type = QColorTrc::Type::Function;
576 }
else if (
curv.valueCount == 1) {
577 const quint16 v = qFromBigEndian<quint16>(tagData.constData() + valueOffset);
578 gamma.
m_type = QColorTrc::Type::Function;
582 tabl.resize(
curv.valueCount);
584 "GenericTagData has padding. The following code is a subject to UB.");
585 qFromBigEndian<quint16>(tagData.constData() + valueOffset,
curv.valueCount, tabl.data());
588 if (!
table.checkValidity()) {
589 qCWarning(lcIcc) <<
"Invalid curv table";
591 }
else if (!
table.asColorTransferFunction(&curve)) {
592 gamma.
m_type = QColorTrc::Type::Table;
595 qCDebug(lcIcc) <<
"Detected curv table as function";
596 gamma.
m_type = QColorTrc::Type::Function;
600 return 12 + 2 *
curv.valueCount;
602 if (trcData.type ==
quint32(Tag::para)) {
604 const ParaTagData para = qFromUnaligned<ParaTagData>(tagData.constData());
607 switch (
para.curveType) {
609 if (tagData.size() < 12 + 1 * 4)
611 qFromBigEndian<quint32>(tagData.constData() + parametersOffset, 1, parameters);
613 gamma.
m_type = QColorTrc::Type::Function;
618 if (tagData.size() < 12 + 3 * 4)
620 qFromBigEndian<quint32>(tagData.constData() + parametersOffset, 3, parameters);
621 if (parameters[1] == 0)
627 gamma.
m_type = QColorTrc::Type::Function;
632 if (tagData.size() < 12 + 4 * 4)
634 qFromBigEndian<quint32>(tagData.constData() + parametersOffset, 4, parameters);
635 if (parameters[1] == 0)
642 gamma.
m_type = QColorTrc::Type::Function;
647 if (tagData.size() < 12 + 5 * 4)
649 qFromBigEndian<quint32>(tagData.constData() + parametersOffset, 5, parameters);
655 gamma.
m_type = QColorTrc::Type::Function;
660 if (tagData.size() < 12 + 7 * 4)
662 qFromBigEndian<quint32>(tagData.constData() + parametersOffset, 7, parameters);
670 gamma.
m_type = QColorTrc::Type::Function;
687 if (outputChannels == 4) {
690 tableData[
index * 4 + 1] *
f,
691 tableData[
index * 4 + 2] *
f,
692 tableData[
index * 4 + 3] *
f);
698 tableData[
index * 3 + 1] *
f,
699 tableData[
index * 3 + 2] *
f);
708 return (exp <= 1) ?
x :
x *
intPow(
x, exp - 1);
715 if (tagEntry.size <
sizeof(T)) {
716 qCWarning(lcIcc) <<
"Undersized lut8/lut16 tag";
720 qCWarning(lcIcc) <<
"Truncated lut8/lut16 tag";
723 using S = std::conditional_t<std::is_same_v<T, Lut8TagData>, uint8_t, uint16_t>;
724 const T lut = qFromUnaligned<T>(
data.constData() + tagEntry.offset);
725 int inputTableEntries, outputTableEntries,
precision;
726 if constexpr (std::is_same_v<T, Lut8TagData>) {
728 if (!colorSpacePrivate->isPcsLab && isAb) {
729 qCWarning(lcIcc) <<
"Lut8 can not output XYZ values";
732 inputTableEntries = 256;
733 outputTableEntries = 256;
737 inputTableEntries = lut.inputTableEntries;
738 outputTableEntries = lut.outputTableEntries;
739 if (inputTableEntries < 2 || inputTableEntries > 4096)
741 if (outputTableEntries < 2 || outputTableEntries > 4096)
746 bool inTableIsLinear =
true, outTableIsLinear =
true;
761 if (!colorSpacePrivate->isPcsLab && !isAb && !matrixElement.isValid()) {
762 qCWarning(lcIcc) <<
"Invalid matrix values in lut8/lut16";
767 qCWarning(lcIcc) <<
"Unsupported lut8/lut16 input channel count" << lut.inputChannels;
772 qCWarning(lcIcc) <<
"Unsupported lut8/lut16 output channel count" << lut.outputChannels;
776 const qsizetype clutTableSize =
intPow(lut.clutGridPoints, lut.inputChannels);
777 if (tagEntry.size < (
sizeof(T) +
precision * lut.inputChannels * inputTableEntries
778 +
precision * lut.outputChannels * outputTableEntries
779 +
precision * lut.outputChannels * clutTableSize)) {
780 qCWarning(lcIcc) <<
"Undersized lut8/lut16 tag, no room for tables";
784 qCWarning(lcIcc) <<
"Cmyk conversion must have a CLUT";
788 const uint8_t *tableData =
reinterpret_cast<const uint8_t *
>(
data.constData() + tagEntry.offset +
sizeof(T));
790 for (
int j = 0;
j < lut.inputChannels; ++
j) {
791 QList<S>
input(inputTableEntries);
792 qFromBigEndian<S>(tableData, inputTableEntries,
input.data());
794 if (!
table.checkValidity()) {
795 qCWarning(lcIcc) <<
"Bad input table in lut8/lut16";
798 if (!
table.isIdentity())
799 inTableIsLinear =
false;
800 inTableElement.trc[
j] = std::move(
table);
801 tableData += inputTableEntries *
precision;
804 clutElement.table.resize(clutTableSize);
805 clutElement.gridPointsX = clutElement.gridPointsY = clutElement.gridPointsZ = lut.clutGridPoints;
806 if (lut.inputChannels == 4)
807 clutElement.gridPointsW = lut.clutGridPoints;
809 if constexpr (std::is_same_v<T, Lut8TagData>) {
810 parseCLUT(tableData, 1.f / 255.f, &clutElement, lut.outputChannels);
812 float f = 1.0f / 65535.f;
813 if (colorSpacePrivate->isPcsLab && isAb)
815 QList<S> clutTable(clutTableSize * lut.outputChannels);
816 qFromBigEndian<S>(tableData, clutTable.size(), clutTable.data());
817 parseCLUT(clutTable.constData(),
f, &clutElement, lut.outputChannels);
819 tableData += clutTableSize * lut.outputChannels *
precision;
821 for (
int j = 0;
j < lut.outputChannels; ++
j) {
822 QList<S>
output(outputTableEntries);
823 qFromBigEndian<S>(tableData, outputTableEntries,
output.data());
825 if (!
table.checkValidity()) {
826 qCWarning(lcIcc) <<
"Bad output table in lut8/lut16";
829 if (!
table.isIdentity())
830 outTableIsLinear =
false;
831 outTableElement.trc[
j] = std::move(
table);
832 tableData += outputTableEntries *
precision;
836 if (!inTableIsLinear)
837 colorSpacePrivate->mAB.append(inTableElement);
838 if (!clutElement.isEmpty())
839 colorSpacePrivate->mAB.append(clutElement);
840 if (!outTableIsLinear || colorSpacePrivate->mAB.isEmpty())
841 colorSpacePrivate->mAB.append(outTableElement);
844 if (!colorSpacePrivate->isPcsLab && !matrixElement.isIdentity())
845 colorSpacePrivate->mBA.append(matrixElement);
846 if (!inTableIsLinear)
847 colorSpacePrivate->mBA.append(inTableElement);
848 if (!clutElement.isEmpty())
849 colorSpacePrivate->mBA.append(clutElement);
850 if (!outTableIsLinear || colorSpacePrivate->mBA.isEmpty())
851 colorSpacePrivate->mBA.append(outTableElement);
860 qCWarning(lcIcc) <<
"Undersized mAB/mBA tag";
864 qCWarning(lcIcc) <<
"Truncated mAB/mBA tag";
867 const mABTagData mab = qFromUnaligned<mABTagData>(
data.constData() + tagEntry.offset);
868 if ((mab.type !=
quint32(Tag::mAB_) && isAb) || (mab.type !=
quint32(Tag::mBA_) && !isAb)){
869 qCWarning(lcIcc) <<
"Bad mAB/mBA content type";
874 qCWarning(lcIcc) <<
"Unsupported mAB/mBA input channel count" << mab.inputChannels;
879 qCWarning(lcIcc) <<
"Unsupported mAB/mBA output channel count" << mab.outputChannels;
884 if (!mab.bCurvesOffset) {
885 qCWarning(lcIcc) <<
"Illegal mAB/mBA without B table";
888 if (((
bool)mab.matrixOffset != (
bool)mab.mCurvesOffset) ||
889 ((
bool)mab.aCurvesOffset != (
bool)mab.clutOffset)) {
890 qCWarning(lcIcc) <<
"Illegal mAB/mBA element combination";
894 if (mab.aCurvesOffset > (tagEntry.size - 3 *
sizeof(
GenericTagData)) ||
895 mab.bCurvesOffset > (tagEntry.size - 3 *
sizeof(
GenericTagData)) ||
896 mab.mCurvesOffset > (tagEntry.size - 3 *
sizeof(
GenericTagData)) ||
897 mab.matrixOffset > (tagEntry.size - 4 * 12) ||
898 mab.clutOffset > (tagEntry.size - 20)) {
899 qCWarning(lcIcc) <<
"Illegal mAB/mBA element offset";
911 for (
int i = 0;
i < channels; ++
i) {
912 if (
qsizetype(tagEntry.offset + curvesOffset + 12) >
data.size() || curvesOffset + 12 > tagEntry.size) {
913 qCWarning(lcIcc) <<
"Space missing for channel curves in mAB/mBA";
920 curvesOffset +=
size;
925 bool bCurvesAreLinear =
true, aCurvesAreLinear =
true, mCurvesAreLinear =
true;
928 if (!parseCurves(mab.bCurvesOffset, bTableElement.trc, isAb ? mab.outputChannels : mab.inputChannels)) {
932 bCurvesAreLinear = bTableElement.trc[0].isIdentity() && bTableElement.trc[1].isIdentity() && bTableElement.trc[2].isIdentity();
936 if (mab.aCurvesOffset) {
937 if (!parseCurves(mab.aCurvesOffset, aTableElement.trc, isAb ? mab.inputChannels : mab.outputChannels)) {
941 aCurvesAreLinear = aTableElement.trc[0].isIdentity() && aTableElement.trc[1].isIdentity() && aTableElement.trc[2].isIdentity();
946 if (mab.mCurvesOffset) {
947 if (!parseCurves(mab.mCurvesOffset, mTableElement.trc, 3)) {
951 mCurvesAreLinear = mTableElement.trc[0].isIdentity() && mTableElement.trc[1].isIdentity() && mTableElement.trc[2].isIdentity();
956 if (mab.matrixOffset) {
957 const MatrixElement matrix = qFromUnaligned<MatrixElement>(
data.constData() + tagEntry.offset + mab.matrixOffset);
970 if (!matrixElement.isValid() || !offsetElement.isValid()) {
971 qCWarning(lcIcc) <<
"Invalid matrix values in mAB/mBA element";
977 if (mab.clutOffset) {
978 clutElement.gridPointsX = uint8_t(
data[tagEntry.offset + mab.clutOffset]);
979 clutElement.gridPointsY = uint8_t(
data[tagEntry.offset + mab.clutOffset + 1]);
980 clutElement.gridPointsZ = uint8_t(
data[tagEntry.offset + mab.clutOffset + 2]);
981 clutElement.gridPointsW = std::max(uint8_t(
data[tagEntry.offset + mab.clutOffset + 3]), uint8_t(1));
984 qCWarning(lcIcc) <<
"Invalid mAB/mBA element CLUT precision";
987 if (clutElement.gridPointsX < 2 || clutElement.gridPointsY < 2 || clutElement.gridPointsZ < 2) {
991 const qsizetype clutTableSize = clutElement.gridPointsX * clutElement.gridPointsY * clutElement.gridPointsZ * clutElement.gridPointsW;
992 if ((mab.clutOffset + 20 + clutTableSize * mab.outputChannels *
precision) > tagEntry.size) {
993 qCWarning(lcIcc) <<
"CLUT oversized for tag";
997 clutElement.table.resize(clutTableSize);
999 QList<uint16_t> clutTable(clutTableSize * mab.outputChannels);
1000 qFromBigEndian<uint16_t>(
data.constData() + tagEntry.offset + mab.clutOffset + 20, clutTable.size(), clutTable.data());
1001 parseCLUT(clutTable.constData(), (1.f/65535.f), &clutElement, mab.outputChannels);
1003 const uint8_t *clutTable =
reinterpret_cast<const uint8_t *
>(
data.constData() + tagEntry.offset + mab.clutOffset + 20);
1004 parseCLUT(clutTable, (1.f/255.f), &clutElement, mab.outputChannels);
1007 qCWarning(lcIcc) <<
"Cmyk conversion must have a CLUT";
1012 if (mab.aCurvesOffset) {
1013 if (!aCurvesAreLinear)
1014 colorSpacePrivate->mAB.append(std::move(aTableElement));
1015 if (!clutElement.isEmpty())
1016 colorSpacePrivate->mAB.append(std::move(clutElement));
1018 if (mab.mCurvesOffset && mab.outputChannels == 3) {
1019 if (!mCurvesAreLinear)
1020 colorSpacePrivate->mAB.append(std::move(mTableElement));
1021 if (!matrixElement.isIdentity())
1022 colorSpacePrivate->mAB.append(std::move(matrixElement));
1023 if (!offsetElement.isNull())
1024 colorSpacePrivate->mAB.append(std::move(offsetElement));
1026 if (!bCurvesAreLinear|| colorSpacePrivate->mAB.isEmpty())
1027 colorSpacePrivate->mAB.append(std::move(bTableElement));
1029 if (!bCurvesAreLinear)
1030 colorSpacePrivate->mBA.append(std::move(bTableElement));
1031 if (mab.mCurvesOffset && mab.inputChannels == 3) {
1032 if (!matrixElement.isIdentity())
1033 colorSpacePrivate->mBA.append(std::move(matrixElement));
1034 if (!offsetElement.isNull())
1035 colorSpacePrivate->mBA.append(std::move(offsetElement));
1036 if (!mCurvesAreLinear)
1037 colorSpacePrivate->mBA.append(std::move(mTableElement));
1039 if (mab.aCurvesOffset) {
1040 if (!clutElement.isEmpty())
1041 colorSpacePrivate->mBA.append(std::move(clutElement));
1042 if (!aCurvesAreLinear)
1043 colorSpacePrivate->mBA.append(std::move(aTableElement));
1045 if (colorSpacePrivate->mBA.isEmpty())
1046 colorSpacePrivate->mBA.append(std::move(bTableElement));
1054 const GenericTagData a2bData = qFromUnaligned<GenericTagData>(
data.constData() + tagEntry.offset);
1055 if (a2bData.type ==
quint32(Tag::mft1))
1056 return parseLutData<Lut8TagData>(
data, tagEntry, privat, isAb);
1057 else if (a2bData.type ==
quint32(Tag::mft2))
1058 return parseLutData<Lut16TagData>(
data, tagEntry, privat, isAb);
1059 else if (a2bData.type ==
quint32(Tag::mAB_) || a2bData.type ==
quint32(Tag::mBA_))
1062 qCWarning(lcIcc) <<
"fromIccProfile: Unknown A2B/B2A data type";
1079 if (tagEntry.size - 12 <
len)
1081 const char *asciiDescription =
data.constData() + tagEntry.offset +
sizeof(
DescTagData);
1082 if (asciiDescription[
len - 1] !=
'\0')
1093 if (
mluc.recordCount < 1)
1095 if (
mluc.recordSize != 12)
1098 const quint32 stringOffset =
mluc.records[0].offset;
1100 if (tagEntry.size < stringOffset || tagEntry.size - stringOffset < stringSize )
1102 if ((stringSize | stringOffset) & 1)
1104 quint32 stringLen = stringSize / 2;
1105 QVarLengthArray<char16_t> utf16hostendian(stringLen);
1106 qFromBigEndian<char16_t>(
data.constData() + tagEntry.offset + stringOffset, stringLen,
1107 utf16hostendian.data());
1109 if (stringLen > 1 && utf16hostendian[stringLen - 1] == 0)
1126 if (!colorspaceDPtr->toXyz.isValid() || !colorspaceDPtr->whitePoint.isValid() || colorspaceDPtr->whitePoint.isNull()) {
1127 qCWarning(lcIcc) <<
"Invalid XYZ values in RGB matrix";
1133 qCDebug(lcIcc) <<
"fromIccProfile: sRGB primaries detected";
1136 qCDebug(lcIcc) <<
"fromIccProfile: Adobe RGB primaries detected";
1139 qCDebug(lcIcc) <<
"fromIccProfile: DCI-P3 D65 primaries detected";
1143 qCDebug(lcIcc) <<
"fromIccProfile: ProPhoto RGB primaries detected";
1154 if (!whitePoint.
isValid() || !
qFuzzyCompare(whitePoint.
y, 1.0f) || (1.0f + whitePoint.
z + whitePoint.
x) == 0.0f) {
1155 qCWarning(lcIcc) <<
"fromIccProfile: Invalid ICC profile - gray white-point not normalized";
1159 colorspaceDPtr->whitePoint = whitePoint;
1167 const Sf32TagData chadtag = qFromUnaligned<Sf32TagData>(
data.constData() + tagEntry.offset);
1168 if (chadtag.type != uint32_t(Tag::sf32)) {
1169 qCWarning(lcIcc,
"fromIccProfile: bad chad data type");
1183 if (!
chad.isValid()) {
1184 qCWarning(lcIcc,
"fromIccProfile: invalid chad matrix");
1187 colorspaceDPtr->chad =
chad;
1196 if (isColorSpaceTypeGray) {
1197 rTrc = tagIndex[Tag::kTRC];
1198 gTrc = tagIndex[Tag::kTRC];
1199 bTrc = tagIndex[Tag::kTRC];
1200 }
else if (tagIndex.contains(Tag::aarg) && tagIndex.contains(Tag::aagg) && tagIndex.contains(Tag::aabg)) {
1202 rTrc = tagIndex[Tag::aarg];
1203 gTrc = tagIndex[Tag::aagg];
1204 bTrc = tagIndex[Tag::aabg];
1206 rTrc = tagIndex[Tag::rTRC];
1207 gTrc = tagIndex[Tag::gTRC];
1208 bTrc = tagIndex[Tag::bTRC];
1215 qCWarning(lcIcc) <<
"fromIccProfile: Invalid rTRC";
1219 qCWarning(lcIcc) <<
"fromIccProfile: Invalid gTRC";
1223 qCWarning(lcIcc) <<
"fromIccProfile: Invalid bTRC";
1226 if (rCurve == gCurve && gCurve == bCurve) {
1227 if (rCurve.isIdentity()) {
1228 qCDebug(lcIcc) <<
"fromIccProfile: Linear gamma detected";
1231 colorspaceDPtr->gamma = 1.0f;
1232 }
else if (rCurve.m_type == QColorTrc::Type::Function && rCurve.m_fun.isGamma()) {
1233 qCDebug(lcIcc) <<
"fromIccProfile: Simple gamma detected";
1236 colorspaceDPtr->gamma = rCurve.m_fun.m_g;
1237 }
else if (rCurve.m_type == QColorTrc::Type::Function && rCurve.m_fun.isSRgb()) {
1238 qCDebug(lcIcc) <<
"fromIccProfile: sRGB gamma detected";
1242 colorspaceDPtr->trc[0] = rCurve;
1245 colorspaceDPtr->trc[1] = colorspaceDPtr->trc[0];
1246 colorspaceDPtr->trc[2] = colorspaceDPtr->trc[0];
1248 colorspaceDPtr->trc[0] = rCurve;
1249 colorspaceDPtr->trc[1] = gCurve;
1250 colorspaceDPtr->trc[2] = bCurve;
1259 qCWarning(lcIcc) <<
"fromIccProfile: failed size sanity 1";
1266 qCWarning(lcIcc) <<
"fromIccProfile: failed size sanity 2";
1272 if (offsetToData >
data.size()) {
1273 qCWarning(lcIcc) <<
"fromIccProfile: failed index size sanity";
1277 QHash<Tag, TagEntry> tagIndex;
1285 if (
qsizetype(tagTable.offset) < offsetToData) {
1286 qCWarning(lcIcc) <<
"fromIccProfile: failed tag offset sanity 1";
1290 if (tagTable.offset >
header.profileSize) {
1291 qCWarning(lcIcc) <<
"fromIccProfile: failed tag offset sanity 2";
1294 if (tagTable.size < 8) {
1295 qCWarning(lcIcc) <<
"fromIccProfile: failed minimal tag size sanity";
1298 if (tagTable.size >
header.profileSize - tagTable.offset) {
1299 qCWarning(lcIcc) <<
"fromIccProfile: failed tag offset + size sanity";
1302 if (tagTable.offset & 0x03) {
1303 qCWarning(lcIcc) <<
"fromIccProfile: invalid tag offset alignment";
1309 tagIndex.insert(
Tag(
quint32(tagTable.signature)), { tagTable.offset, tagTable.size });
1312 bool threeComponentMatrix =
true;
1316 if (!tagIndex.contains(Tag::rXYZ) || !tagIndex.contains(Tag::gXYZ) || !tagIndex.contains(Tag::bXYZ) ||
1317 !tagIndex.contains(Tag::rTRC) || !tagIndex.contains(Tag::gTRC) || !tagIndex.contains(Tag::bTRC) ||
1318 !tagIndex.contains(Tag::wtpt) ||
header.pcs ==
uint(Tag::Lab_)) {
1319 threeComponentMatrix =
false;
1321 if (!tagIndex.contains(Tag::A2B0)) {
1322 qCWarning(lcIcc) <<
"fromIccProfile: Invalid ICC profile - neither valid three component nor n-LUT";
1327 if (!tagIndex.contains(Tag::kTRC) || !tagIndex.contains(Tag::wtpt)) {
1328 qCWarning(lcIcc) <<
"fromIccProfile: Invalid ICC profile - not valid gray scale based";
1332 threeComponentMatrix =
false;
1333 if (!tagIndex.contains(Tag::A2B0)) {
1334 qCWarning(lcIcc) <<
"fromIccProfile: Invalid ICC profile - CMYK, not n-LUT";
1344 if (threeComponentMatrix) {
1345 colorspaceDPtr->isPcsLab =
false;
1366 colorspaceDPtr->toXyz = colorspaceDPtr->chad;
1370 colorspaceDPtr->setToXyzMatrix();
1375 colorspaceDPtr->isPcsLab = (
header.pcs ==
uint(Tag::Lab_));
1383 if (!
parseA2B(
data, tagIndex[Tag::A2B0], colorspaceDPtr,
true))
1398 qCWarning(lcIcc) <<
"fromIccProfile: Failed to parse description";
1400 qCDebug(lcIcc) <<
"fromIccProfile: Description" << colorspaceDPtr->description;
1403 colorspaceDPtr->identifyColorSpace();
1404 if (colorspaceDPtr->namedColorSpace)
1407 colorspaceDPtr->iccProfile =
data;
1409 Q_ASSERT(colorspaceDPtr->isValid());
\inmodule QtCore \reentrant
bool open(OpenMode openMode) override
\reimp
char * data()
\macro QT_NO_CAST_FROM_BYTEARRAY
qsizetype size() const noexcept
Returns the number of bytes in this byte array.
const char * constData() const noexcept
Returns a pointer to the const data stored in the byte array.
static QColorMatrix toXyzFromSRgb()
static QColorMatrix toXyzFromAdobeRgb()
static QColorMatrix toXyzFromDciP3D65()
static QColorMatrix chromaticAdaptation(const QColorVector &whitePoint)
static QColorMatrix toXyzFromProPhotoRgb()
static const QColorSpacePrivate * get(const QColorSpace &colorSpace)
The QColorSpace class provides a color space abstraction.
bool isValid() const noexcept
Returns true if the color space is valid.
NamedColorSpace
Predefined color spaces.
QString description() const noexcept
Returns the name or short description.
static QColorTransferFunction fromGamma(float gamma)
static QColorTransferFunction fromSRgb()
QList< uint8_t > m_table8
QList< uint16_t > m_table16
QColorTransferFunction m_fun
QColorTransferTable m_table
static constexpr QColorVector D50()
bool isValid() const noexcept
\inmodule QtCore\reentrant
bool isEmpty() const noexcept
const_iterator constEnd() const noexcept
const_iterator constFind(const T &value) const
\macro QT_RESTRICTED_CAST_FROM_ASCII
static QString fromLatin1(QByteArrayView ba)
This is an overloaded member function, provided for convenience. It differs from the above function o...
static QString fromUtf16(const char16_t *, qsizetype size=-1)
qsizetype size() const noexcept
Returns the number of characters in this string.
QSet< QString >::iterator it
static constexpr qsizetype intPow(qsizetype x, qsizetype exp)
static bool parseChad(const QByteArray &data, const TagEntry &tagEntry, QColorSpacePrivate *colorspaceDPtr)
static bool parseMabData(const QByteArray &data, const TagEntry &tagEntry, QColorSpacePrivate *colorSpacePrivate, bool isAb)
static bool parseGrayMatrix(const QByteArray &data, const QHash< Tag, TagEntry > &tagIndex, QColorSpacePrivate *colorspaceDPtr)
static bool parseRgbMatrix(const QByteArray &data, const QHash< Tag, TagEntry > &tagIndex, QColorSpacePrivate *colorspaceDPtr)
bool fromIccProfile(const QByteArray &data, QColorSpace *colorSpace)
constexpr quint32 IccTag(uchar a, uchar b, uchar c, uchar d)
static void parseCLUT(const T *tableData, const float f, QColorCLUT *clut, uchar outputChannels)
static bool parseXyzData(const QByteArray &data, const TagEntry &tagEntry, QColorVector &colorVector)
QByteArray toIccProfile(const QColorSpace &space)
static int toFixedS1516(float x)
static bool parseDesc(const QByteArray &data, const TagEntry &tagEntry, QString &descName)
static bool isValidIccProfile(const ICCProfileHeader &header)
static bool parseTRCs(const QByteArray &data, const QHash< Tag, TagEntry > &tagIndex, QColorSpacePrivate *colorspaceDPtr, bool isColorSpaceTypeGray)
static bool parseLutData(const QByteArray &data, const TagEntry &tagEntry, QColorSpacePrivate *colorSpacePrivate, bool isAb)
static bool parseA2B(const QByteArray &data, const TagEntry &tagEntry, QColorSpacePrivate *privat, bool isAb)
static quint32 parseTRC(const QByteArrayView &tagData, QColorTrc &gamma, QColorTransferTable::Type type=QColorTransferTable::TwoWay)
static int writeColorTrc(QDataStream &stream, const QColorTrc &trc)
static float fromFixedS1516(int x)
Combined button and popup list for selecting options.
QTextStream & hex(QTextStream &stream)
Calls QTextStream::setIntegerBase(16) on stream and returns stream.
#define Q_STATIC_ASSERT(Condition)
AudioChannelLayoutTag tag
static QString header(const QString &name)
typedef QByteArray(EGLAPIENTRYP PFNQGSGETDISPLAYSPROC)()
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
bool qFuzzyCompare(qfloat16 p1, qfloat16 p2) noexcept
bool qFuzzyIsNull(qfloat16 f) noexcept
size_t qHash(const QIcc::Tag &key, size_t seed=0)
#define Q_LOGGING_CATEGORY(name,...)
#define qCInfo(category,...)
#define qCWarning(category,...)
#define qCDebug(category,...)
GLboolean GLboolean GLboolean b
GLsizei const GLfloat * v
[13]
GLuint GLfloat GLfloat GLfloat GLfloat GLfloat z
GLint GLint GLint GLint GLint x
[0]
GLboolean GLboolean GLboolean GLboolean a
[7]
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLenum GLenum GLenum input
GLenum GLenum GLsizei void * table
GLenum GLint GLint * precision
static Q_CONSTINIT QBasicAtomicInteger< unsigned > seed
QT_BEGIN_NAMESPACE typedef uchar * output
quint32_be asciiDescriptionLength
quint16_be inputTableEntries
quint16_be outputTableEntries
quint16_be outputChannels
quint32_be processingElements