Krita Source Code Documentation
Loading...
Searching...
No Matches
LcmsColorProfileContainer Class Reference

#include <LcmsColorProfileContainer.h>

+ Inheritance diagram for LcmsColorProfileContainer:

Classes

class  Private
 

Public Member Functions

ColorPrimaries cicpPrimaries () const override
 
TransferCharacteristics cicpTransfer () const override
 
cmsColorSpaceSignature colorSpaceSignature () const
 
bool compareTRC (TransferCharacteristics characteristics, float error) const override
 
QString copyright () const override
 
virtual void DelinearizeFloatValue (QVector< double > &Value) const
 
virtual void DelinearizeFloatValueFast (QVector< double > &Value) const
 
cmsProfileClassSignature deviceClass () const
 
QVector< KoColorimetryUtils::xyYgetColorantsxyY () const override
 
QVector< KoColorimetryUtils::XYZgetColorantsXYZ () const override
 
QVector< double > getEstimatedTRC () const override
 
QByteArray getProfileUniqueId () const override
 
KoColorimetryUtils::xyY getWhitePointxyY () const override
 
KoColorimetryUtils::XYZ getWhitePointXYZ () const override
 
bool hasCicpValues () const override
 
bool hasColorants () const override
 
virtual bool hasTRC () const
 
std::optional< double > hdrReferenceWhite () const override
 
QString info () const override
 
bool isLinear () const
 
bool isSuitableForDisplay () const override
 
bool isSuitableForInput () const override
 
bool isSuitableForOutput () const override
 
bool isSuitableForPrinting () const override
 
bool isSuitableForWorkspace () const override
 
cmsHPROFILE lcmsProfile () const
 
virtual void LinearizeFloatValue (QVector< double > &Value) const
 
virtual void LinearizeFloatValueFast (QVector< double > &Value) const
 
QString manufacturer () const override
 
QString name () const override
 
virtual bool supportsAbsolute () const
 
virtual bool supportsPerceptual () const
 
virtual bool supportsRelative () const
 
virtual bool supportsSaturation () const
 
bool valid () const override
 
virtual float version () const
 
 ~LcmsColorProfileContainer () override
 
- Public Member Functions inherited from IccColorProfile::Container
 Container ()
 
virtual ~Container ()
 

Static Public Member Functions

static IccColorProfilecreateFromLcmsProfile (const cmsHPROFILE profile)
 
static cmsToneCurve * transferFunction (TransferCharacteristics transferFunction)
 

Protected Member Functions

 LcmsColorProfileContainer ()
 
 LcmsColorProfileContainer (IccColorProfile::Data *)
 

Private Member Functions

bool init ()
 

Static Private Member Functions

static QByteArray lcmsProfileToByteArray (const cmsHPROFILE profile)
 

Private Attributes

Private *const d
 

Friends

class IccColorProfile
 

Detailed Description

This class contains an LCMS color profile. Don't use it outside LcmsColorSpace.

Definition at line 24 of file LcmsColorProfileContainer.h.

Constructor & Destructor Documentation

◆ LcmsColorProfileContainer() [1/2]

LcmsColorProfileContainer::LcmsColorProfileContainer ( IccColorProfile::Data * data)
protected

◆ ~LcmsColorProfileContainer()

LcmsColorProfileContainer::~LcmsColorProfileContainer ( )
override

Definition at line 151 of file LcmsColorProfileContainer.cpp.

152{
153 cmsCloseProfile(d->profile);
154 delete d;
155}

References d, and LcmsColorProfileContainer::Private::profile.

◆ LcmsColorProfileContainer() [2/2]

LcmsColorProfileContainer::LcmsColorProfileContainer ( )
protected

Definition at line 114 of file LcmsColorProfileContainer.cpp.

115 : d(new Private())
116{
117 d->profile = 0;
118}

References d, and LcmsColorProfileContainer::Private::profile.

Member Function Documentation

◆ cicpPrimaries()

ColorPrimaries LcmsColorProfileContainer::cicpPrimaries ( ) const
overridevirtual

Implements IccColorProfile::Container.

Definition at line 666 of file LcmsColorProfileContainer.cpp.

666 {
667 if (!d->cicpValues) return PRIMARIES_UNSPECIFIED;
668 return ColorPrimaries(d->cicpValues->ColourPrimaries);
669}
ColorPrimaries
The colorPrimaries enum Enum of colorants, follows ITU H.273 for values 0 to 255, and has extra known...
@ PRIMARIES_UNSPECIFIED

References LcmsColorProfileContainer::Private::cicpValues, d, and PRIMARIES_UNSPECIFIED.

◆ cicpTransfer()

TransferCharacteristics LcmsColorProfileContainer::cicpTransfer ( ) const
overridevirtual

Implements IccColorProfile::Container.

Definition at line 671 of file LcmsColorProfileContainer.cpp.

672{
673 if (!d->cicpValues) return TRC_UNSPECIFIED;
674 return TransferCharacteristics(d->cicpValues->TransferCharacteristics);
675}
TransferCharacteristics
The transferCharacteristics enum Enum of transfer characteristics, follows ITU H.273 for values 0 to ...

References LcmsColorProfileContainer::Private::cicpValues, d, and TRC_UNSPECIFIED.

◆ colorSpaceSignature()

cmsColorSpaceSignature LcmsColorProfileContainer::colorSpaceSignature ( ) const
Returns
the ICC color space signature

Definition at line 353 of file LcmsColorProfileContainer.cpp.

354{
355 return d->colorSpaceSignature;
356}

References LcmsColorProfileContainer::Private::colorSpaceSignature, and d.

◆ compareTRC()

bool LcmsColorProfileContainer::compareTRC ( TransferCharacteristics characteristics,
float error ) const
overridevirtual

Implements IccColorProfile::Container.

Definition at line 677 of file LcmsColorProfileContainer.cpp.

678{
679 if (!*d->hasTRC) {
680 return false;
681 }
682
683 std::array<cmsFloat32Number, 2> calcValues{};
684
685 cmsToneCurve *mainCurve = [&]() {
686 if (d->hasColorants) {
687 return d->redTRC;
688 }
689 return d->grayTRC;
690 }();
691
692 cmsToneCurve *compareCurve = transferFunction(characteristics);
693
694 // Number of sweep samples across the curve
695 for (uint32_t i = 0; i < 32; i++) {
696 const float step = float(i) / 31.0f;
697 calcValues[0] = cmsEvalToneCurveFloat(mainCurve, step);
698 calcValues[1] = cmsEvalToneCurveFloat(compareCurve, step);
699 if (std::fabs(calcValues[0] - calcValues[1]) >= error) {
700 return false;
701 }
702 }
703
704 return true;
705}
static cmsToneCurve * transferFunction(TransferCharacteristics transferFunction)

References d, LcmsColorProfileContainer::Private::grayTRC, LcmsColorProfileContainer::Private::hasColorants, LcmsColorProfileContainer::Private::hasTRC, LcmsColorProfileContainer::Private::redTRC, and transferFunction().

◆ copyright()

QString LcmsColorProfileContainer::copyright ( ) const
overridevirtual
Returns
the embedded copyright

Implements IccColorProfile::Container.

Definition at line 368 of file LcmsColorProfileContainer.cpp.

References LcmsColorProfileContainer::Private::copyright, and d.

◆ createFromLcmsProfile()

IccColorProfile * LcmsColorProfileContainer::createFromLcmsProfile ( const cmsHPROFILE profile)
static
Parameters
profilelcms memory structure with the profile, it is freed after the call to this function
Returns
an ICC profile created from an LCMS profile

Definition at line 144 of file LcmsColorProfileContainer.cpp.

145{
146 IccColorProfile *iccprofile = new IccColorProfile(lcmsProfileToByteArray(profile));
147 cmsCloseProfile(profile);
148 return iccprofile;
149}
static QByteArray lcmsProfileToByteArray(const cmsHPROFILE profile)

References IccColorProfile, and lcmsProfileToByteArray().

◆ DelinearizeFloatValue()

void LcmsColorProfileContainer::DelinearizeFloatValue ( QVector< double > & Value) const
virtual

Definition at line 552 of file LcmsColorProfileContainer.cpp.

553{
554 if (d->hasColorants && hasTRC()) {
555 if (!cmsIsToneCurveLinear(d->redTRC)) {
556 Value[0] = cmsEvalToneCurveFloat(*d->redTRCReverse, Value[0]);
557 }
558 if (!cmsIsToneCurveLinear(d->greenTRC)) {
559 Value[1] = cmsEvalToneCurveFloat(*d->greenTRCReverse, Value[1]);
560 }
561 if (!cmsIsToneCurveLinear(d->blueTRC)) {
562 Value[2] = cmsEvalToneCurveFloat(*d->blueTRCReverse, Value[2]);
563 }
564
565 } else {
566 if (cmsIsTag(d->profile, cmsSigGrayTRCTag)) {
567 Value[0] = cmsEvalToneCurveFloat(*d->grayTRCReverse, Value[0]);
568 }
569 }
570}

References LcmsColorProfileContainer::Private::blueTRC, LcmsColorProfileContainer::Private::blueTRCReverse, d, LcmsColorProfileContainer::Private::grayTRCReverse, LcmsColorProfileContainer::Private::greenTRC, LcmsColorProfileContainer::Private::greenTRCReverse, LcmsColorProfileContainer::Private::hasColorants, hasTRC(), LcmsColorProfileContainer::Private::profile, LcmsColorProfileContainer::Private::redTRC, and LcmsColorProfileContainer::Private::redTRCReverse.

◆ DelinearizeFloatValueFast()

void LcmsColorProfileContainer::DelinearizeFloatValueFast ( QVector< double > & Value) const
virtual

Definition at line 599 of file LcmsColorProfileContainer.cpp.

600{
601 const qreal scale = 65535.0;
602 const qreal invScale = 1.0 / scale;
603
604 if (d->hasColorants && hasTRC()) {
605 //we can only reliably delinearise in the 0-1.0 range, outside of that leave the value alone.
606
607 if (!cmsIsToneCurveLinear(d->redTRC) && Value[0]<1.0) {
608 quint16 newValue = cmsEvalToneCurve16(*d->redTRCReverse, Value[0] * scale);
609 Value[0] = newValue * invScale;
610 }
611 if (!cmsIsToneCurveLinear(d->greenTRC) && Value[1]<1.0) {
612 quint16 newValue = cmsEvalToneCurve16(*d->greenTRCReverse, Value[1] * scale);
613 Value[1] = newValue * invScale;
614 }
615 if (!cmsIsToneCurveLinear(d->blueTRC) && Value[2]<1.0) {
616 quint16 newValue = cmsEvalToneCurve16(*d->blueTRCReverse, Value[2] * scale);
617 Value[2] = newValue * invScale;
618 }
619 } else {
620 if (cmsIsTag(d->profile, cmsSigGrayTRCTag) && Value[0]<1.0) {
621 quint16 newValue = cmsEvalToneCurve16(*d->grayTRCReverse, Value[0] * scale);
622 Value[0] = newValue * invScale;
623 }
624 }
625}

References LcmsColorProfileContainer::Private::blueTRC, LcmsColorProfileContainer::Private::blueTRCReverse, d, LcmsColorProfileContainer::Private::grayTRCReverse, LcmsColorProfileContainer::Private::greenTRC, LcmsColorProfileContainer::Private::greenTRCReverse, LcmsColorProfileContainer::Private::hasColorants, hasTRC(), LcmsColorProfileContainer::Private::profile, LcmsColorProfileContainer::Private::redTRC, and LcmsColorProfileContainer::Private::redTRCReverse.

◆ deviceClass()

cmsProfileClassSignature LcmsColorProfileContainer::deviceClass ( ) const
Returns
the class of the color space signature

Definition at line 358 of file LcmsColorProfileContainer.cpp.

359{
360 return d->deviceClass;
361}

References d, and LcmsColorProfileContainer::Private::deviceClass.

◆ getColorantsxyY()

QVector< KoColorimetryUtils::xyY > LcmsColorProfileContainer::getColorantsxyY ( ) const
overridevirtual

Implements IccColorProfile::Container.

Definition at line 456 of file LcmsColorProfileContainer.cpp.

457{
458 cmsCIEXYZ temp1;
459 cmsCIExyY temp2;
461
462 temp1.X = d->colorants.Red.X;
463 temp1.Y = d->colorants.Red.Y;
464 temp1.Z = d->colorants.Red.Z;
465 cmsXYZ2xyY(&temp2, &temp1);
466 colorants.append(fromCIExyY(temp2));
467
468 temp1.X = d->colorants.Green.X;
469 temp1.Y = d->colorants.Green.Y;
470 temp1.Z = d->colorants.Green.Z;
471 cmsXYZ2xyY(&temp2, &temp1);
472 colorants.append(fromCIExyY(temp2));
473
474 temp1.X = d->colorants.Blue.X;
475 temp1.Y = d->colorants.Blue.Y;
476 temp1.Z = d->colorants.Blue.Z;
477 cmsXYZ2xyY(&temp2, &temp1);
478 colorants.append(fromCIExyY(temp2));
479
480 return colorants;
481}
KoColorimetryUtils::xyY fromCIExyY(const cmsCIExyY &xyY)

References LcmsColorProfileContainer::Private::colorants, d, and fromCIExyY().

◆ getColorantsXYZ()

QVector< KoColorimetryUtils::XYZ > LcmsColorProfileContainer::getColorantsXYZ ( ) const
overridevirtual

Implements IccColorProfile::Container.

Definition at line 446 of file LcmsColorProfileContainer.cpp.

447{
448 QVector <KoColorimetryUtils::XYZ> colorants(9);
449
450 colorants.append(fromCieXYZ(d->colorants.Red));
451 colorants.append(fromCieXYZ(d->colorants.Green));
452 colorants.append(fromCieXYZ(d->colorants.Blue));
453 return colorants;
454}
KoColorimetryUtils::XYZ fromCieXYZ(const cmsCIEXYZ &xyz)

References LcmsColorProfileContainer::Private::colorants, d, and fromCieXYZ().

◆ getEstimatedTRC()

QVector< double > LcmsColorProfileContainer::getEstimatedTRC ( ) const
overridevirtual

Implements IccColorProfile::Container.

Definition at line 498 of file LcmsColorProfileContainer.cpp.

499{
500 QVector <double> TRCtriplet(3);
501 if (d->hasColorants && hasTRC()) {
502 if (cmsIsToneCurveLinear(d->redTRC)) {
503 TRCtriplet[0] = 1.0;
504 } else {
505 TRCtriplet[0] = cmsEstimateGamma(d->redTRC, 0.01);
506 }
507 if (cmsIsToneCurveLinear(d->greenTRC)) {
508 TRCtriplet[1] = 1.0;
509 } else {
510 TRCtriplet[1] = cmsEstimateGamma(d->greenTRC, 0.01);
511 }
512 if (cmsIsToneCurveLinear(d->blueTRC)) {
513 TRCtriplet[2] = 1.0;
514 } else {
515 TRCtriplet[2] = cmsEstimateGamma(d->blueTRC, 0.01);
516 }
517
518 } else {
519 if (cmsIsTag(d->profile, cmsSigGrayTRCTag)) {
520 if (cmsIsToneCurveLinear(d->grayTRC)) {
521 TRCtriplet.fill(1.0);
522 } else {
523 TRCtriplet.fill(cmsEstimateGamma(d->grayTRC, 0.01));
524 }
525 } else {
526 TRCtriplet.fill(1.0);
527 }
528 }
529 return TRCtriplet;
530}

References LcmsColorProfileContainer::Private::blueTRC, d, LcmsColorProfileContainer::Private::grayTRC, LcmsColorProfileContainer::Private::greenTRC, LcmsColorProfileContainer::Private::hasColorants, hasTRC(), LcmsColorProfileContainer::Private::profile, and LcmsColorProfileContainer::Private::redTRC.

◆ getProfileUniqueId()

QByteArray LcmsColorProfileContainer::getProfileUniqueId ( ) const
overridevirtual

Implements IccColorProfile::Container.

Definition at line 637 of file LcmsColorProfileContainer.cpp.

638{
639 if (d->uniqueId.isEmpty() && d->profile) {
640 QByteArray id(sizeof(cmsProfileID), 0);
641 cmsGetHeaderProfileID(d->profile, (quint8*)id.data());
642
643 bool isNull = std::all_of(id.constBegin(),
644 id.constEnd(),
645 [](char c) {return c == 0;});
646 if (isNull) {
647 if (cmsMD5computeID(d->profile)) {
648 cmsGetHeaderProfileID(d->profile, (quint8*)id.data());
649 isNull = false;
650 }
651 }
652
653 if (!isNull) {
654 d->uniqueId = id;
655 }
656 }
657
658 return d->uniqueId;
659}

References d, LcmsColorProfileContainer::Private::profile, and LcmsColorProfileContainer::Private::uniqueId.

◆ getWhitePointxyY()

KoColorimetryUtils::xyY LcmsColorProfileContainer::getWhitePointxyY ( ) const
overridevirtual

◆ getWhitePointXYZ()

KoColorimetryUtils::XYZ LcmsColorProfileContainer::getWhitePointXYZ ( ) const
overridevirtual

◆ hasCicpValues()

bool LcmsColorProfileContainer::hasCicpValues ( ) const
overridevirtual

Implements IccColorProfile::Container.

Definition at line 661 of file LcmsColorProfileContainer.cpp.

662{
663 return (d->cicpValues);
664}

References LcmsColorProfileContainer::Private::cicpValues, and d.

◆ hasColorants()

bool LcmsColorProfileContainer::hasColorants ( ) const
overridevirtual

Implements IccColorProfile::Container.

Definition at line 425 of file LcmsColorProfileContainer.cpp.

426{
427 return d->hasColorants;
428}

References d, and LcmsColorProfileContainer::Private::hasColorants.

◆ hasTRC()

bool LcmsColorProfileContainer::hasTRC ( ) const
virtual

Definition at line 429 of file LcmsColorProfileContainer.cpp.

430{
431 return *d->hasTRC;
432}

References d, and LcmsColorProfileContainer::Private::hasTRC.

◆ hdrReferenceWhite()

std::optional< double > LcmsColorProfileContainer::hdrReferenceWhite ( ) const
overridevirtual

◆ info()

QString LcmsColorProfileContainer::info ( ) const
overridevirtual

◆ init()

bool LcmsColorProfileContainer::init ( )
private

Definition at line 159 of file LcmsColorProfileContainer.cpp.

160{
161 if (d->profile) {
162 cmsCloseProfile(d->profile);
163 }
164
165 d->profile = cmsOpenProfileFromMem((void *)d->data->rawData().constData(), d->data->rawData().size());
166
167
168#ifndef NDEBUG
169 if (d->data->rawData().size() == 4096) {
170 qWarning() << "Profile has a size of 4096, which is suspicious and indicates a possible misuse of QIODevice::read(int), check your code.";
171 }
172#endif
173
174 if (d->profile) {
175 wchar_t buffer[_BUFFER_SIZE_];
176 d->colorSpaceSignature = cmsGetColorSpace(d->profile);
177 d->deviceClass = cmsGetDeviceClass(d->profile);
178 cmsGetProfileInfo(d->profile, cmsInfoDescription, cmsNoLanguage, cmsNoCountry, buffer, _BUFFER_SIZE_);
179 d->name = QString::fromWCharArray(buffer);
180
181 //apparently this should give us a localised string??? Not sure about this.
182 cmsGetProfileInfo(d->profile, cmsInfoModel, cmsNoLanguage, cmsNoCountry, buffer, _BUFFER_SIZE_);
183 d->productDescription = QString::fromWCharArray(buffer);
184
185 cmsGetProfileInfo(d->profile, cmsInfoManufacturer, cmsNoLanguage, cmsNoCountry, buffer, _BUFFER_SIZE_);
186 d->manufacturer = QString::fromWCharArray(buffer);
187
188 cmsGetProfileInfo(d->profile, cmsInfoCopyright, cmsNoLanguage, cmsNoCountry, buffer, _BUFFER_SIZE_);
189 d->copyright = QString::fromWCharArray(buffer);
190
191 cmsProfileClassSignature profile_class;
192 profile_class = cmsGetDeviceClass(d->profile);
193 d->valid = ( profile_class != cmsSigNamedColorClass
194 && profile_class != cmsSigLinkClass);
195
196 //This is where obtain the whitepoint, and convert it to the actual white point of the profile in the case a Chromatic adaption tag is
197 //present. This is necessary for profiles following the v4 spec.
198 cmsCIEXYZ baseMediaWhitePoint;//dummy to hold copy of mediawhitepoint if this is modified by chromatic adaption.
199 cmsCIEXYZ *mediaWhitePointPtr;
200 bool whiteComp[3];
201 bool whiteIsD50;
202 // Possible bug in profiles: there are in fact some that says they contain that tag
203 // but in fact the pointer is null.
204 // Let's not crash on it anyway, and assume there is no white point instead.
205 // BUG:423685
206 if (cmsIsTag(d->profile, cmsSigMediaWhitePointTag)
207 && (mediaWhitePointPtr = (cmsCIEXYZ *)cmsReadTag(d->profile, cmsSigMediaWhitePointTag))) {
208
209 d->mediaWhitePoint = *(mediaWhitePointPtr);
210 baseMediaWhitePoint = d->mediaWhitePoint;
211
212 whiteComp[0] = std::fabs(baseMediaWhitePoint.X - cmsD50_XYZ()->X) < 0.00001;
213 whiteComp[1] = std::fabs(baseMediaWhitePoint.Y - cmsD50_XYZ()->Y) < 0.00001;
214 whiteComp[2] = std::fabs(baseMediaWhitePoint.Z - cmsD50_XYZ()->Z) < 0.00001;
215 whiteIsD50 = std::all_of(std::begin(whiteComp), std::end(whiteComp), [](bool b) {return b;});
216
217 cmsXYZ2xyY(&d->whitePoint, &d->mediaWhitePoint);
218 cmsCIEXYZ *CAM1;
219 if (cmsIsTag(d->profile, cmsSigChromaticAdaptationTag)
220 && (CAM1 = (cmsCIEXYZ *)cmsReadTag(d->profile, cmsSigChromaticAdaptationTag))
221 && whiteIsD50) {
222 //the chromatic adaption tag represent a matrix from the actual white point of the profile to D50.
223
224 //We first put all our data into structures we can manipulate.
225 double d3dummy [3] = {d->mediaWhitePoint.X, d->mediaWhitePoint.Y, d->mediaWhitePoint.Z};
226 QGenericMatrix<1, 3, double> whitePointMatrix(d3dummy);
227 QTransform invertDummy(CAM1[0].X, CAM1[0].Y, CAM1[0].Z, CAM1[1].X, CAM1[1].Y, CAM1[1].Z, CAM1[2].X, CAM1[2].Y, CAM1[2].Z);
228 //we then abuse QTransform's invert function because it probably does matrix inversion 20 times better than I can program.
229 //if the matrix is uninvertable, invertedDummy will be an identity matrix, which for us means that it won't give any noticeable
230 //effect when we start multiplying.
231 QTransform invertedDummy = invertDummy.inverted();
232 //we then put the QTransform into a generic 3x3 matrix.
233 double d9dummy [9] = {invertedDummy.m11(), invertedDummy.m12(), invertedDummy.m13(),
234 invertedDummy.m21(), invertedDummy.m22(), invertedDummy.m23(),
235 invertedDummy.m31(), invertedDummy.m32(), invertedDummy.m33()
236 };
237 QGenericMatrix<3, 3, double> chromaticAdaptionMatrix(d9dummy);
238 //multiplying our inverted adaption matrix with the whitepoint gives us the right whitepoint.
239 QGenericMatrix<1, 3, double> result = chromaticAdaptionMatrix * whitePointMatrix;
240 //and then we pour the matrix into the whitepoint variable. Generic matrix does row/column for indices even though it
241 //uses column/row for initialising.
242 d->mediaWhitePoint.X = result(0, 0);
243 d->mediaWhitePoint.Y = result(1, 0);
244 d->mediaWhitePoint.Z = result(2, 0);
245 cmsXYZ2xyY(&d->whitePoint, &d->mediaWhitePoint);
246 }
247 }
248 //This is for RGB profiles, but it only works for matrix profiles. Need to design it to work with non-matrix profiles.
249 cmsCIEXYZ *tempColorantsRed, *tempColorantsGreen, *tempColorantsBlue;
250 // Note: don't assume that cmsIsTag is enough to check for errors; check the pointers, too
251 // BUG:423685
252 if (cmsIsTag(d->profile, cmsSigRedColorantTag) && cmsIsTag(d->profile, cmsSigRedColorantTag) && cmsIsTag(d->profile, cmsSigRedColorantTag)
253 && (tempColorantsRed = (cmsCIEXYZ *)cmsReadTag(d->profile, cmsSigRedColorantTag))
254 && (tempColorantsGreen = (cmsCIEXYZ *)cmsReadTag(d->profile, cmsSigGreenColorantTag))
255 && (tempColorantsBlue = (cmsCIEXYZ *)cmsReadTag(d->profile, cmsSigBlueColorantTag))) {
256 cmsCIEXYZTRIPLE tempColorants;
257 tempColorants.Red = *tempColorantsRed;
258 tempColorants.Green = *tempColorantsGreen;
259 tempColorants.Blue = *tempColorantsBlue;
260 //convert to d65, this is useless.
261 cmsAdaptToIlluminant(&d->colorants.Red, cmsD50_XYZ(), &d->mediaWhitePoint, &tempColorants.Red);
262 cmsAdaptToIlluminant(&d->colorants.Green, cmsD50_XYZ(), &d->mediaWhitePoint, &tempColorants.Green);
263 cmsAdaptToIlluminant(&d->colorants.Blue, cmsD50_XYZ(), &d->mediaWhitePoint, &tempColorants.Blue);
264 //d->colorants = tempColorants;
265 d->hasColorants = true;
266 } else {
267 //qDebug()<<d->name<<": has no colorants";
268 d->hasColorants = false;
269 }
270 //retrieve TRC.
271 if (cmsIsTag(d->profile, cmsSigRedTRCTag) && cmsIsTag(d->profile, cmsSigBlueTRCTag) && cmsIsTag(d->profile, cmsSigGreenTRCTag)) {
272
273 d->redTRC = ((cmsToneCurve *)cmsReadTag (d->profile, cmsSigRedTRCTag));
274 d->greenTRC = ((cmsToneCurve *)cmsReadTag (d->profile, cmsSigGreenTRCTag));
275 d->blueTRC = ((cmsToneCurve *)cmsReadTag (d->profile, cmsSigBlueTRCTag));
279
280 d->hasTRC = Private::LazyBool([d = d] () {
281 return d->redTRC && d->greenTRC && d->blueTRC && *d->redTRCReverse && *d->greenTRCReverse && *d->blueTRCReverse;
282 });
283
284 d->isLinear = Private::LazyBool([d = d] () {
285 return *d->hasTRC
286 && cmsIsToneCurveLinear(d->redTRC)
287 && cmsIsToneCurveLinear(d->greenTRC)
288 && cmsIsToneCurveLinear(d->blueTRC);
289 });
290
291 } else if (cmsIsTag(d->profile, cmsSigGrayTRCTag)) {
292 d->grayTRC = ((cmsToneCurve *)cmsReadTag (d->profile, cmsSigGrayTRCTag));
294
295 d->hasTRC = Private::LazyBool([d = d] () {
296 return d->grayTRC && *d->grayTRCReverse;
297 });
298
299 d->isLinear = Private::LazyBool([d = d] () {
300 return *d->hasTRC && cmsIsToneCurveLinear(d->grayTRC);
301 });
302 } else {
303 d->hasTRC = Private::LazyBool(Private::LazyBool::init_value_tag{}, {});
304 }
305
306 if (cmsIsTag(d->profile, cmsSigcicpTag)) {
307 d->cicpValues = ((cmsVideoSignalType *) cmsReadTag (d->profile, cmsSigcicpTag));
308 }
309
310 // Check if the profile can convert (something->this)
311 d->suitableForOutput = cmsIsIntentSupported(d->profile, INTENT_PERCEPTUAL, LCMS_USED_AS_OUTPUT);
312 d->suitableForInput = cmsIsIntentSupported(d->profile, INTENT_PERCEPTUAL, LCMS_USED_AS_INPUT);
313
314 d->version = cmsGetProfileVersion(d->profile);
315 d->defaultIntent = cmsGetHeaderRenderingIntent(d->profile);
316 d->isMatrixShaper = cmsIsMatrixShaper(d->profile);
317 d->isPerceptualCLUT = cmsIsCLUT(d->profile, INTENT_PERCEPTUAL, LCMS_USED_AS_INPUT);
318 d->isSaturationCLUT = cmsIsCLUT(d->profile, INTENT_SATURATION, LCMS_USED_AS_INPUT);
319 d->isAbsoluteCLUT = cmsIsCLUT(d->profile, INTENT_SATURATION, LCMS_USED_AS_INPUT);
320 d->isRelativeCLUT = cmsIsCLUT(d->profile, INTENT_RELATIVE_COLORIMETRIC, LCMS_USED_AS_INPUT);
321
322 if (cmsIsTag(d->profile, cmsSigMetaTag)) {
323 dbgPigment << "icc profile has dictionary entries";
324
325 cmsHANDLE dictionary = (cmsHANDLE) cmsReadTag(d->profile, cmsSigMetaTag);
326 const cmsDICTentry *entry = cmsDictGetEntryList(dictionary);
327 while (entry) {
328 QString name = QString::fromWCharArray(entry->Name, -1);
329 QString value = QString::fromWCharArray(entry->Value, -1);
330 if (name.toLower() == "crwl") {
331 // https://registry.color.org/dicttype-metadata/crwl
333 d->hdrReferenceWhite = std::make_optional(hdrReferenceWhite);
334
335 }
336 dbgPigment << name << value;
337 dbgPigment << entry->DisplayName << entry->DisplayValue;
338 entry = cmsDictNextEntry(entry);
339 }
340 }
341
342 return true;
343 }
344
345 return false;
346}
#define dbgPigment
float value(const T *src, size_t ch)
#define _BUFFER_SIZE_
KisLazyStorage< KisLazyValueWrapper< bool >, std::function< bool()> > LazyBool
KisLazyStorage< ReverseCurveWrapper, cmsToneCurve * > LazyReverseCurve
std::optional< double > hdrReferenceWhite() const override
#define INTENT_PERCEPTUAL
Definition kis_global.h:103
#define INTENT_RELATIVE_COLORIMETRIC
Definition kis_global.h:104
#define INTENT_SATURATION
Definition kis_global.h:105
double toDouble(const QString &str, bool *ok=nullptr)

References _BUFFER_SIZE_, LcmsColorProfileContainer::Private::blueTRC, LcmsColorProfileContainer::Private::blueTRCReverse, LcmsColorProfileContainer::Private::cicpValues, LcmsColorProfileContainer::Private::colorants, LcmsColorProfileContainer::Private::colorSpaceSignature, LcmsColorProfileContainer::Private::copyright, d, LcmsColorProfileContainer::Private::data, dbgPigment, LcmsColorProfileContainer::Private::defaultIntent, LcmsColorProfileContainer::Private::deviceClass, LcmsColorProfileContainer::Private::grayTRC, LcmsColorProfileContainer::Private::grayTRCReverse, LcmsColorProfileContainer::Private::greenTRC, LcmsColorProfileContainer::Private::greenTRCReverse, LcmsColorProfileContainer::Private::hasColorants, LcmsColorProfileContainer::Private::hasTRC, LcmsColorProfileContainer::Private::hdrReferenceWhite, hdrReferenceWhite(), INTENT_PERCEPTUAL, INTENT_RELATIVE_COLORIMETRIC, INTENT_SATURATION, LcmsColorProfileContainer::Private::isAbsoluteCLUT, LcmsColorProfileContainer::Private::isLinear, LcmsColorProfileContainer::Private::isMatrixShaper, LcmsColorProfileContainer::Private::isPerceptualCLUT, LcmsColorProfileContainer::Private::isRelativeCLUT, LcmsColorProfileContainer::Private::isSaturationCLUT, LcmsColorProfileContainer::Private::manufacturer, LcmsColorProfileContainer::Private::mediaWhitePoint, LcmsColorProfileContainer::Private::name, name(), LcmsColorProfileContainer::Private::productDescription, LcmsColorProfileContainer::Private::profile, IccColorProfile::Data::rawData(), LcmsColorProfileContainer::Private::redTRC, LcmsColorProfileContainer::Private::redTRCReverse, LcmsColorProfileContainer::Private::suitableForInput, LcmsColorProfileContainer::Private::suitableForOutput, KisDomUtils::toDouble(), LcmsColorProfileContainer::Private::valid, value(), LcmsColorProfileContainer::Private::version, and LcmsColorProfileContainer::Private::whitePoint.

◆ isLinear()

bool LcmsColorProfileContainer::isLinear ( ) const

Definition at line 433 of file LcmsColorProfileContainer.cpp.

434{
435 return *d->isLinear;
436}

References d, and LcmsColorProfileContainer::Private::isLinear.

◆ isSuitableForDisplay()

bool LcmsColorProfileContainer::isSuitableForDisplay ( ) const
overridevirtual

Implements IccColorProfile::Container.

Definition at line 401 of file LcmsColorProfileContainer.cpp.

402{
403 return deviceClass() == cmsSigDisplayClass;
404}
cmsProfileClassSignature deviceClass() const

References deviceClass().

◆ isSuitableForInput()

bool LcmsColorProfileContainer::isSuitableForInput ( ) const
overridevirtual

Implements IccColorProfile::Container.

Definition at line 387 of file LcmsColorProfileContainer.cpp.

388{
389 return d->suitableForInput;
390}

References d, and LcmsColorProfileContainer::Private::suitableForInput.

◆ isSuitableForOutput()

bool LcmsColorProfileContainer::isSuitableForOutput ( ) const
overridevirtual

Implements IccColorProfile::Container.

Definition at line 383 of file LcmsColorProfileContainer.cpp.

384{
385 return d->suitableForOutput;
386}

References d, and LcmsColorProfileContainer::Private::suitableForOutput.

◆ isSuitableForPrinting()

bool LcmsColorProfileContainer::isSuitableForPrinting ( ) const
overridevirtual

Implements IccColorProfile::Container.

Definition at line 396 of file LcmsColorProfileContainer.cpp.

397{
398 return deviceClass() == cmsSigOutputClass;
399}

References deviceClass().

◆ isSuitableForWorkspace()

bool LcmsColorProfileContainer::isSuitableForWorkspace ( ) const
overridevirtual

◆ lcmsProfile()

cmsHPROFILE LcmsColorProfileContainer::lcmsProfile ( ) const
Returns
the structure to use with LCMS functions

Definition at line 348 of file LcmsColorProfileContainer.cpp.

349{
350 return d->profile;
351}

References d, and LcmsColorProfileContainer::Private::profile.

◆ lcmsProfileToByteArray()

QByteArray LcmsColorProfileContainer::lcmsProfileToByteArray ( const cmsHPROFILE profile)
staticprivate

Create a byte array from a lcms profile.

Definition at line 128 of file LcmsColorProfileContainer.cpp.

129{
130 cmsUInt32Number bytesNeeded = 0;
131 // Make a raw data image ready for saving
132 cmsSaveProfileToMem(profile, 0, &bytesNeeded); // calc size
133 QByteArray rawData;
134 rawData.resize(bytesNeeded);
135 if (rawData.size() >= (int)bytesNeeded) {
136 cmsSaveProfileToMem(profile, rawData.data(), &bytesNeeded); // fill buffer
137 } else {
138 qWarning() << "Couldn't resize the profile buffer, system is probably running out of memory.";
139 rawData.resize(0);
140 }
141 return rawData;
142}

◆ LinearizeFloatValue()

void LcmsColorProfileContainer::LinearizeFloatValue ( QVector< double > & Value) const
virtual

Definition at line 532 of file LcmsColorProfileContainer.cpp.

533{
534 if (d->hasColorants && hasTRC()) {
535 if (!cmsIsToneCurveLinear(d->redTRC)) {
536 Value[0] = cmsEvalToneCurveFloat(d->redTRC, Value[0]);
537 }
538 if (!cmsIsToneCurveLinear(d->greenTRC)) {
539 Value[1] = cmsEvalToneCurveFloat(d->greenTRC, Value[1]);
540 }
541 if (!cmsIsToneCurveLinear(d->blueTRC)) {
542 Value[2] = cmsEvalToneCurveFloat(d->blueTRC, Value[2]);
543 }
544
545 } else {
546 if (cmsIsTag(d->profile, cmsSigGrayTRCTag)) {
547 Value[0] = cmsEvalToneCurveFloat(d->grayTRC, Value[0]);
548 }
549 }
550}

References LcmsColorProfileContainer::Private::blueTRC, d, LcmsColorProfileContainer::Private::grayTRC, LcmsColorProfileContainer::Private::greenTRC, LcmsColorProfileContainer::Private::hasColorants, hasTRC(), LcmsColorProfileContainer::Private::profile, and LcmsColorProfileContainer::Private::redTRC.

◆ LinearizeFloatValueFast()

void LcmsColorProfileContainer::LinearizeFloatValueFast ( QVector< double > & Value) const
virtual

Definition at line 572 of file LcmsColorProfileContainer.cpp.

573{
574 const qreal scale = 65535.0;
575 const qreal invScale = 1.0 / scale;
576
577 if (d->hasColorants && hasTRC()) {
578 //we can only reliably delinearise in the 0-1.0 range, outside of that leave the value alone.
579
580 if (!cmsIsToneCurveLinear(d->redTRC) && Value[0]<1.0) {
581 quint16 newValue = cmsEvalToneCurve16(d->redTRC, Value[0] * scale);
582 Value[0] = newValue * invScale;
583 }
584 if (!cmsIsToneCurveLinear(d->greenTRC) && Value[1]<1.0) {
585 quint16 newValue = cmsEvalToneCurve16(d->greenTRC, Value[1] * scale);
586 Value[1] = newValue * invScale;
587 }
588 if (!cmsIsToneCurveLinear(d->blueTRC) && Value[2]<1.0) {
589 quint16 newValue = cmsEvalToneCurve16(d->blueTRC, Value[2] * scale);
590 Value[2] = newValue * invScale;
591 }
592 } else {
593 if (cmsIsTag(d->profile, cmsSigGrayTRCTag) && Value[0]<1.0) {
594 quint16 newValue = cmsEvalToneCurve16(d->grayTRC, Value[0] * scale);
595 Value[0] = newValue * invScale;
596 }
597 }
598}

References LcmsColorProfileContainer::Private::blueTRC, d, LcmsColorProfileContainer::Private::grayTRC, LcmsColorProfileContainer::Private::greenTRC, LcmsColorProfileContainer::Private::hasColorants, hasTRC(), LcmsColorProfileContainer::Private::profile, and LcmsColorProfileContainer::Private::redTRC.

◆ manufacturer()

QString LcmsColorProfileContainer::manufacturer ( ) const
overridevirtual
Returns
the name of the manufacturer

Implements IccColorProfile::Container.

Definition at line 363 of file LcmsColorProfileContainer.cpp.

364{
365 return d->manufacturer;
366}

References d, and LcmsColorProfileContainer::Private::manufacturer.

◆ name()

QString LcmsColorProfileContainer::name ( ) const
overridevirtual

Implements IccColorProfile::Container.

Definition at line 627 of file LcmsColorProfileContainer.cpp.

628{
629 return d->name;
630}

References d, and LcmsColorProfileContainer::Private::name.

◆ supportsAbsolute()

bool LcmsColorProfileContainer::supportsAbsolute ( ) const
virtual

Definition at line 414 of file LcmsColorProfileContainer.cpp.

415{
416 return d->isAbsoluteCLUT;//LCMS2 doesn't convert matrix shapers via absolute intent, because of V4 workflow.
417}

References d, and LcmsColorProfileContainer::Private::isAbsoluteCLUT.

◆ supportsPerceptual()

bool LcmsColorProfileContainer::supportsPerceptual ( ) const
virtual

Definition at line 406 of file LcmsColorProfileContainer.cpp.

407{
408 return d->isPerceptualCLUT;
409}

References d, and LcmsColorProfileContainer::Private::isPerceptualCLUT.

◆ supportsRelative()

bool LcmsColorProfileContainer::supportsRelative ( ) const
virtual

Definition at line 418 of file LcmsColorProfileContainer.cpp.

419{
421 return true;
422 }
423 return false;
424}

References d, LcmsColorProfileContainer::Private::isMatrixShaper, and LcmsColorProfileContainer::Private::isRelativeCLUT.

◆ supportsSaturation()

bool LcmsColorProfileContainer::supportsSaturation ( ) const
virtual

Definition at line 410 of file LcmsColorProfileContainer.cpp.

411{
412 return d->isSaturationCLUT;
413}

References d, and LcmsColorProfileContainer::Private::isSaturationCLUT.

◆ transferFunction()

cmsToneCurve * LcmsColorProfileContainer::transferFunction ( TransferCharacteristics transferFunction)
static

Definition at line 718 of file LcmsColorProfileContainer.cpp.

719{
720 cmsToneCurve *mainCurve;
721
722 // Values courtesy of Elle Stone
723 cmsFloat64Number srgb_parameters[5] =
724 { 2.4, 1.0 / 1.055, 0.055 / 1.055, 1.0 / 12.92, 0.04045 };
725 cmsFloat64Number rec709_parameters[5] =
726 { 1.0 / 0.45, 1.0 / 1.099, 0.099 / 1.099, 1.0 / 4.5, 0.081 };
727
728 // The following is basically a precise version of rec709.
729 cmsFloat64Number rec202012bit_parameters[5] =
730 { 1.0 / 0.45, 1.0 / 1.0993, 0.0993 / 1.0993, 1.0 / 4.5, 0.0812 };
731
732 cmsFloat64Number SMPTE_240M_parameters[5] =
733 { 1.0 / 0.45, 1.0 / 1.1115, 0.1115 / 1.1115, 1.0 / 4.0, 0.0913 };
734
735 cmsFloat64Number prophoto_parameters[5] =
736 { 1.8, 1.0, 0, 1.0 / 16, (16.0/512) };
737
738 cmsFloat64Number log_100[5] = {1.0, 10, 2.0, -2.0, 0.0};
739 cmsFloat64Number log_100_sqrt[5] = {1.0, 10, 2.5, -2.5, 0.0};
740
741 cmsFloat64Number labl_parameters[5] = {3.0, 0.862076, 0.137924, 0.110703, 0.080002};
742
743 switch (transferFunction) {
745 // Not possible in ICC due to lack of a*pow(bX+c,y) construct.
747 // This is not possible in ICC due to lack of a*pow(bX+c,y) construct.
748 qWarning() << "Neither IEC 61966 2-4 nor Bt. 1361 are supported, returning a rec 709 curve.";
749 Q_FALLTHROUGH();
753 mainCurve = cmsBuildParametricToneCurve(NULL, 4, rec709_parameters);
754 break;
756 mainCurve = cmsBuildParametricToneCurve(NULL, 4, rec202012bit_parameters);
757 break;
759 mainCurve = cmsBuildGamma(NULL, 2.2);
760 break;
762 mainCurve = cmsBuildGamma(NULL, 2.8);
763 break;
764 case TRC_SMPTE_240M:
765 mainCurve = cmsBuildParametricToneCurve(NULL, 4, SMPTE_240M_parameters);
766 break;
768 mainCurve = cmsBuildParametricToneCurve(NULL, 4, srgb_parameters);
769 break;
771 mainCurve = cmsBuildParametricToneCurve(NULL, 8, log_100);
772 break;
774 mainCurve = cmsBuildParametricToneCurve(NULL, 8, log_100_sqrt);
775 break;
776 case TRC_A98:
777 // gamma 563/256
778 mainCurve = cmsBuildGamma(NULL, 563.0 / 256.0);
779 break;
780 case TRC_PROPHOTO:
781 mainCurve = cmsBuildParametricToneCurve(NULL, 4, prophoto_parameters);
782 break;
783 case TRC_GAMMA_1_8:
784 mainCurve = cmsBuildGamma(NULL, 1.8);
785 break;
786 case TRC_GAMMA_2_4:
787 mainCurve = cmsBuildGamma(NULL, 2.4);
788 break;
789 case TRC_LAB_L:
790 mainCurve = cmsBuildParametricToneCurve(NULL, 4, labl_parameters);
791 break;
794 break;
796 // Requires an a*X^y construction, not possible.
798 // Hybrid log gamma.
799 qWarning() << "Cannot generate an icc profile with this transfer function, will generate a linear profile";
800 Q_FALLTHROUGH();
801 case TRC_LINEAR:
802 default:
803 mainCurve = cmsBuildGamma(NULL, 1.0);
804 break;
805 }
806
807 return mainCurve;
808}
@ TRC_IEC_61966_2_4
@ TRC_ITU_R_BT_2020_2_10bit
@ TRC_LOGARITHMIC_100
@ TRC_ITU_R_BT_470_6_SYSTEM_M
@ TRC_ITU_R_BT_470_6_SYSTEM_B_G
@ TRC_ITU_R_BT_1361
@ TRC_ITU_R_BT_2100_0_HLG
@ TRC_ITU_R_BT_2100_0_PQ
@ TRC_ITU_R_BT_601_6
@ TRC_IEC_61966_2_1
@ TRC_ITU_R_BT_709_5
@ TRC_SMPTE_ST_428_1
@ TRC_LOGARITHMIC_100_sqrt10
@ TRC_ITU_R_BT_2020_2_12bit
cmsToneCurve * perceptualQuantizerDummy()

References perceptualQuantizerDummy(), transferFunction(), TRC_A98, TRC_GAMMA_1_8, TRC_GAMMA_2_4, TRC_IEC_61966_2_1, TRC_IEC_61966_2_4, TRC_ITU_R_BT_1361, TRC_ITU_R_BT_2020_2_10bit, TRC_ITU_R_BT_2020_2_12bit, TRC_ITU_R_BT_2100_0_HLG, TRC_ITU_R_BT_2100_0_PQ, TRC_ITU_R_BT_470_6_SYSTEM_B_G, TRC_ITU_R_BT_470_6_SYSTEM_M, TRC_ITU_R_BT_601_6, TRC_ITU_R_BT_709_5, TRC_LAB_L, TRC_LINEAR, TRC_LOGARITHMIC_100, TRC_LOGARITHMIC_100_sqrt10, TRC_PROPHOTO, TRC_SMPTE_240M, and TRC_SMPTE_ST_428_1.

◆ valid()

bool LcmsColorProfileContainer::valid ( ) const
overridevirtual

Implements IccColorProfile::Container.

Definition at line 373 of file LcmsColorProfileContainer.cpp.

374{
375 return d->valid;
376}

References d, and LcmsColorProfileContainer::Private::valid.

◆ version()

float LcmsColorProfileContainer::version ( ) const
virtual

Definition at line 378 of file LcmsColorProfileContainer.cpp.

379{
380 return d->version;
381}

References d, and LcmsColorProfileContainer::Private::version.

Friends And Related Symbol Documentation

◆ IccColorProfile

friend class IccColorProfile
friend

Definition at line 26 of file LcmsColorProfileContainer.h.

Member Data Documentation

◆ d

Private* const LcmsColorProfileContainer::d
private

Definition at line 115 of file LcmsColorProfileContainer.h.


The documentation for this class was generated from the following files: