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

#include <LcmsColorProfileContainer.h>

+ Inheritance diagram for LcmsColorProfileContainer:

Classes

class  Private
 

Public Member Functions

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< double > getColorantsxyY () const override
 
QVector< double > getColorantsXYZ () const override
 
QVector< double > getEstimatedTRC () const override
 
QByteArray getProfileUniqueId () const override
 
QVector< double > getWhitePointxyY () const override
 
QVector< double > getWhitePointXYZ () const override
 
bool hasColorants () const override
 
virtual bool hasTRC () const
 
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 23 of file LcmsColorProfileContainer.h.

Constructor & Destructor Documentation

◆ LcmsColorProfileContainer() [1/2]

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

◆ ~LcmsColorProfileContainer()

LcmsColorProfileContainer::~LcmsColorProfileContainer ( )
override

Definition at line 146 of file LcmsColorProfileContainer.cpp.

147{
148 cmsCloseProfile(d->profile);
149 delete d;
150}

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

◆ LcmsColorProfileContainer() [2/2]

LcmsColorProfileContainer::LcmsColorProfileContainer ( )
protected

Definition at line 109 of file LcmsColorProfileContainer.cpp.

110 : d(new Private())
111{
112 d->profile = 0;
113}

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

Member Function Documentation

◆ colorSpaceSignature()

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

Definition at line 324 of file LcmsColorProfileContainer.cpp.

325{
326 return d->colorSpaceSignature;
327}

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

◆ compareTRC()

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

Implements IccColorProfile::Container.

Definition at line 639 of file LcmsColorProfileContainer.cpp.

640{
641 if (!*d->hasTRC) {
642 return false;
643 }
644
645 std::array<cmsFloat32Number, 2> calcValues{};
646
647 cmsToneCurve *mainCurve = [&]() {
648 if (d->hasColorants) {
649 return d->redTRC;
650 }
651 return d->grayTRC;
652 }();
653
654 cmsToneCurve *compareCurve = transferFunction(characteristics);
655
656 // Number of sweep samples across the curve
657 for (uint32_t i = 0; i < 32; i++) {
658 const float step = float(i) / 31.0f;
659 calcValues[0] = cmsEvalToneCurveFloat(mainCurve, step);
660 calcValues[1] = cmsEvalToneCurveFloat(compareCurve, step);
661 if (std::fabs(calcValues[0] - calcValues[1]) >= error) {
662 return false;
663 }
664 }
665
666 return true;
667}
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 339 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 139 of file LcmsColorProfileContainer.cpp.

140{
141 IccColorProfile *iccprofile = new IccColorProfile(lcmsProfileToByteArray(profile));
142 cmsCloseProfile(profile);
143 return iccprofile;
144}
static QByteArray lcmsProfileToByteArray(const cmsHPROFILE profile)

References IccColorProfile, and lcmsProfileToByteArray().

◆ DelinearizeFloatValue()

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

Definition at line 530 of file LcmsColorProfileContainer.cpp.

531{
532 if (d->hasColorants) {
533 if (!cmsIsToneCurveLinear(d->redTRC)) {
534 Value[0] = cmsEvalToneCurveFloat(*d->redTRCReverse, Value[0]);
535 }
536 if (!cmsIsToneCurveLinear(d->greenTRC)) {
537 Value[1] = cmsEvalToneCurveFloat(*d->greenTRCReverse, Value[1]);
538 }
539 if (!cmsIsToneCurveLinear(d->blueTRC)) {
540 Value[2] = cmsEvalToneCurveFloat(*d->blueTRCReverse, Value[2]);
541 }
542
543 } else {
544 if (cmsIsTag(d->profile, cmsSigGrayTRCTag)) {
545 Value[0] = cmsEvalToneCurveFloat(*d->grayTRCReverse, Value[0]);
546 }
547 }
548}

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

◆ DelinearizeFloatValueFast()

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

Definition at line 577 of file LcmsColorProfileContainer.cpp.

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

References LcmsColorProfileContainer::Private::blueTRC, LcmsColorProfileContainer::Private::blueTRCReverse, d, LcmsColorProfileContainer::Private::grayTRCReverse, LcmsColorProfileContainer::Private::greenTRC, LcmsColorProfileContainer::Private::greenTRCReverse, LcmsColorProfileContainer::Private::hasColorants, 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 329 of file LcmsColorProfileContainer.cpp.

330{
331 return d->deviceClass;
332}

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

◆ getColorantsxyY()

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

Implements IccColorProfile::Container.

Definition at line 423 of file LcmsColorProfileContainer.cpp.

424{
425 cmsCIEXYZ temp1;
426 cmsCIExyY temp2;
427 QVector <double> colorants(9);
428
429 temp1.X = d->colorants.Red.X;
430 temp1.Y = d->colorants.Red.Y;
431 temp1.Z = d->colorants.Red.Z;
432 cmsXYZ2xyY(&temp2, &temp1);
433 colorants[0] = temp2.x;
434 colorants[1] = temp2.y;
435 colorants[2] = temp2.Y;
436
437 temp1.X = d->colorants.Green.X;
438 temp1.Y = d->colorants.Green.Y;
439 temp1.Z = d->colorants.Green.Z;
440 cmsXYZ2xyY(&temp2, &temp1);
441 colorants[3] = temp2.x;
442 colorants[4] = temp2.y;
443 colorants[5] = temp2.Y;
444
445 temp1.X = d->colorants.Blue.X;
446 temp1.Y = d->colorants.Blue.Y;
447 temp1.Z = d->colorants.Blue.Z;
448 cmsXYZ2xyY(&temp2, &temp1);
449 colorants[6] = temp2.x;
450 colorants[7] = temp2.y;
451 colorants[8] = temp2.Y;
452
453 return colorants;
454}

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

◆ getColorantsXYZ()

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

Implements IccColorProfile::Container.

Definition at line 408 of file LcmsColorProfileContainer.cpp.

409{
410 QVector <double> colorants(9);
411 colorants[0] = d->colorants.Red.X;
412 colorants[1] = d->colorants.Red.Y;
413 colorants[2] = d->colorants.Red.Z;
414 colorants[3] = d->colorants.Green.X;
415 colorants[4] = d->colorants.Green.Y;
416 colorants[5] = d->colorants.Green.Z;
417 colorants[6] = d->colorants.Blue.X;
418 colorants[7] = d->colorants.Blue.Y;
419 colorants[8] = d->colorants.Blue.Z;
420 return colorants;
421}

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

◆ getEstimatedTRC()

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

Implements IccColorProfile::Container.

Definition at line 476 of file LcmsColorProfileContainer.cpp.

477{
478 QVector <double> TRCtriplet(3);
479 if (d->hasColorants) {
480 if (cmsIsToneCurveLinear(d->redTRC)) {
481 TRCtriplet[0] = 1.0;
482 } else {
483 TRCtriplet[0] = cmsEstimateGamma(d->redTRC, 0.01);
484 }
485 if (cmsIsToneCurveLinear(d->greenTRC)) {
486 TRCtriplet[1] = 1.0;
487 } else {
488 TRCtriplet[1] = cmsEstimateGamma(d->greenTRC, 0.01);
489 }
490 if (cmsIsToneCurveLinear(d->blueTRC)) {
491 TRCtriplet[2] = 1.0;
492 } else {
493 TRCtriplet[2] = cmsEstimateGamma(d->blueTRC, 0.01);
494 }
495
496 } else {
497 if (cmsIsTag(d->profile, cmsSigGrayTRCTag)) {
498 if (cmsIsToneCurveLinear(d->grayTRC)) {
499 TRCtriplet.fill(1.0);
500 } else {
501 TRCtriplet.fill(cmsEstimateGamma(d->grayTRC, 0.01));
502 }
503 } else {
504 TRCtriplet.fill(1.0);
505 }
506 }
507 return TRCtriplet;
508}

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

◆ getProfileUniqueId()

QByteArray LcmsColorProfileContainer::getProfileUniqueId ( ) const
overridevirtual

Implements IccColorProfile::Container.

Definition at line 615 of file LcmsColorProfileContainer.cpp.

616{
617 if (d->uniqueId.isEmpty() && d->profile) {
618 QByteArray id(sizeof(cmsProfileID), 0);
619 cmsGetHeaderProfileID(d->profile, (quint8*)id.data());
620
621 bool isNull = std::all_of(id.constBegin(),
622 id.constEnd(),
623 [](char c) {return c == 0;});
624 if (isNull) {
625 if (cmsMD5computeID(d->profile)) {
626 cmsGetHeaderProfileID(d->profile, (quint8*)id.data());
627 isNull = false;
628 }
629 }
630
631 if (!isNull) {
632 d->uniqueId = id;
633 }
634 }
635
636 return d->uniqueId;
637}

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

◆ getWhitePointxyY()

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

Implements IccColorProfile::Container.

Definition at line 467 of file LcmsColorProfileContainer.cpp.

468{
469 QVector <double> tempWhitePoint(3);
470 tempWhitePoint[0] = d->whitePoint.x;
471 tempWhitePoint[1] = d->whitePoint.y;
472 tempWhitePoint[2] = d->whitePoint.Y;
473 return tempWhitePoint;
474}

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

◆ getWhitePointXYZ()

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

Implements IccColorProfile::Container.

Definition at line 456 of file LcmsColorProfileContainer.cpp.

457{
458 QVector <double> tempWhitePoint(3);
459
460 tempWhitePoint[0] = d->mediaWhitePoint.X;
461 tempWhitePoint[1] = d->mediaWhitePoint.Y;
462 tempWhitePoint[2] = d->mediaWhitePoint.Z;
463
464 return tempWhitePoint;
465}

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

◆ hasColorants()

bool LcmsColorProfileContainer::hasColorants ( ) const
overridevirtual

Implements IccColorProfile::Container.

Definition at line 396 of file LcmsColorProfileContainer.cpp.

397{
398 return d->hasColorants;
399}

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

◆ hasTRC()

bool LcmsColorProfileContainer::hasTRC ( ) const
virtual

Definition at line 400 of file LcmsColorProfileContainer.cpp.

401{
402 return *d->hasTRC;
403}

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

◆ info()

QString LcmsColorProfileContainer::info ( ) const
overridevirtual

◆ init()

bool LcmsColorProfileContainer::init ( )
private

Definition at line 154 of file LcmsColorProfileContainer.cpp.

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

References _BUFFER_SIZE_, LcmsColorProfileContainer::Private::blueTRC, LcmsColorProfileContainer::Private::blueTRCReverse, LcmsColorProfileContainer::Private::colorants, LcmsColorProfileContainer::Private::colorSpaceSignature, LcmsColorProfileContainer::Private::copyright, d, LcmsColorProfileContainer::Private::data, LcmsColorProfileContainer::Private::defaultIntent, LcmsColorProfileContainer::Private::deviceClass, LcmsColorProfileContainer::Private::grayTRC, LcmsColorProfileContainer::Private::grayTRCReverse, LcmsColorProfileContainer::Private::greenTRC, LcmsColorProfileContainer::Private::greenTRCReverse, LcmsColorProfileContainer::Private::hasColorants, LcmsColorProfileContainer::Private::hasTRC, 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, LcmsColorProfileContainer::Private::productDescription, LcmsColorProfileContainer::Private::profile, IccColorProfile::Data::rawData(), LcmsColorProfileContainer::Private::redTRC, LcmsColorProfileContainer::Private::redTRCReverse, LcmsColorProfileContainer::Private::suitableForInput, LcmsColorProfileContainer::Private::suitableForOutput, LcmsColorProfileContainer::Private::valid, LcmsColorProfileContainer::Private::version, and LcmsColorProfileContainer::Private::whitePoint.

◆ isLinear()

bool LcmsColorProfileContainer::isLinear ( ) const

Definition at line 404 of file LcmsColorProfileContainer.cpp.

405{
406 return *d->isLinear;
407}

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

◆ isSuitableForDisplay()

bool LcmsColorProfileContainer::isSuitableForDisplay ( ) const
overridevirtual

Implements IccColorProfile::Container.

Definition at line 372 of file LcmsColorProfileContainer.cpp.

373{
374 return deviceClass() == cmsSigDisplayClass;
375}
cmsProfileClassSignature deviceClass() const

References deviceClass().

◆ isSuitableForInput()

bool LcmsColorProfileContainer::isSuitableForInput ( ) const
overridevirtual

Implements IccColorProfile::Container.

Definition at line 358 of file LcmsColorProfileContainer.cpp.

359{
360 return d->suitableForInput;
361}

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

◆ isSuitableForOutput()

bool LcmsColorProfileContainer::isSuitableForOutput ( ) const
overridevirtual

Implements IccColorProfile::Container.

Definition at line 354 of file LcmsColorProfileContainer.cpp.

355{
356 return d->suitableForOutput;
357}

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

◆ isSuitableForPrinting()

bool LcmsColorProfileContainer::isSuitableForPrinting ( ) const
overridevirtual

Implements IccColorProfile::Container.

Definition at line 367 of file LcmsColorProfileContainer.cpp.

368{
369 return deviceClass() == cmsSigOutputClass;
370}

References deviceClass().

◆ isSuitableForWorkspace()

bool LcmsColorProfileContainer::isSuitableForWorkspace ( ) const
overridevirtual

◆ lcmsProfile()

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

Definition at line 319 of file LcmsColorProfileContainer.cpp.

320{
321 return d->profile;
322}

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 123 of file LcmsColorProfileContainer.cpp.

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

◆ LinearizeFloatValue()

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

Definition at line 510 of file LcmsColorProfileContainer.cpp.

511{
512 if (d->hasColorants) {
513 if (!cmsIsToneCurveLinear(d->redTRC)) {
514 Value[0] = cmsEvalToneCurveFloat(d->redTRC, Value[0]);
515 }
516 if (!cmsIsToneCurveLinear(d->greenTRC)) {
517 Value[1] = cmsEvalToneCurveFloat(d->greenTRC, Value[1]);
518 }
519 if (!cmsIsToneCurveLinear(d->blueTRC)) {
520 Value[2] = cmsEvalToneCurveFloat(d->blueTRC, Value[2]);
521 }
522
523 } else {
524 if (cmsIsTag(d->profile, cmsSigGrayTRCTag)) {
525 Value[0] = cmsEvalToneCurveFloat(d->grayTRC, Value[0]);
526 }
527 }
528}

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

◆ LinearizeFloatValueFast()

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

Definition at line 550 of file LcmsColorProfileContainer.cpp.

551{
552 const qreal scale = 65535.0;
553 const qreal invScale = 1.0 / scale;
554
555 if (d->hasColorants) {
556 //we can only reliably delinearise in the 0-1.0 range, outside of that leave the value alone.
557
558 if (!cmsIsToneCurveLinear(d->redTRC) && Value[0]<1.0) {
559 quint16 newValue = cmsEvalToneCurve16(d->redTRC, Value[0] * scale);
560 Value[0] = newValue * invScale;
561 }
562 if (!cmsIsToneCurveLinear(d->greenTRC) && Value[1]<1.0) {
563 quint16 newValue = cmsEvalToneCurve16(d->greenTRC, Value[1] * scale);
564 Value[1] = newValue * invScale;
565 }
566 if (!cmsIsToneCurveLinear(d->blueTRC) && Value[2]<1.0) {
567 quint16 newValue = cmsEvalToneCurve16(d->blueTRC, Value[2] * scale);
568 Value[2] = newValue * invScale;
569 }
570 } else {
571 if (cmsIsTag(d->profile, cmsSigGrayTRCTag) && Value[0]<1.0) {
572 quint16 newValue = cmsEvalToneCurve16(d->grayTRC, Value[0] * scale);
573 Value[0] = newValue * invScale;
574 }
575 }
576}

References LcmsColorProfileContainer::Private::blueTRC, d, LcmsColorProfileContainer::Private::grayTRC, LcmsColorProfileContainer::Private::greenTRC, LcmsColorProfileContainer::Private::hasColorants, 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 334 of file LcmsColorProfileContainer.cpp.

335{
336 return d->manufacturer;
337}

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

◆ name()

QString LcmsColorProfileContainer::name ( ) const
overridevirtual

Implements IccColorProfile::Container.

Definition at line 605 of file LcmsColorProfileContainer.cpp.

606{
607 return d->name;
608}

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

◆ supportsAbsolute()

bool LcmsColorProfileContainer::supportsAbsolute ( ) const
virtual

Definition at line 385 of file LcmsColorProfileContainer.cpp.

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

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

◆ supportsPerceptual()

bool LcmsColorProfileContainer::supportsPerceptual ( ) const
virtual

Definition at line 377 of file LcmsColorProfileContainer.cpp.

378{
379 return d->isPerceptualCLUT;
380}

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

◆ supportsRelative()

bool LcmsColorProfileContainer::supportsRelative ( ) const
virtual

Definition at line 389 of file LcmsColorProfileContainer.cpp.

390{
392 return true;
393 }
394 return false;
395}

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

◆ supportsSaturation()

bool LcmsColorProfileContainer::supportsSaturation ( ) const
virtual

Definition at line 381 of file LcmsColorProfileContainer.cpp.

382{
383 return d->isSaturationCLUT;
384}

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

◆ transferFunction()

cmsToneCurve * LcmsColorProfileContainer::transferFunction ( TransferCharacteristics transferFunction)
static

Definition at line 669 of file LcmsColorProfileContainer.cpp.

670{
671 cmsToneCurve *mainCurve;
672
673 // Values courtesy of Elle Stone
674 cmsFloat64Number srgb_parameters[5] =
675 { 2.4, 1.0 / 1.055, 0.055 / 1.055, 1.0 / 12.92, 0.04045 };
676 cmsFloat64Number rec709_parameters[5] =
677 { 1.0 / 0.45, 1.0 / 1.099, 0.099 / 1.099, 1.0 / 4.5, 0.081 };
678
679 // The following is basically a precise version of rec709.
680 cmsFloat64Number rec202012bit_parameters[5] =
681 { 1.0 / 0.45, 1.0 / 1.0993, 0.0993 / 1.0993, 1.0 / 4.5, 0.0812 };
682
683 cmsFloat64Number SMPTE_240M_parameters[5] =
684 { 1.0 / 0.45, 1.0 / 1.1115, 0.1115 / 1.1115, 1.0 / 4.0, 0.0913 };
685
686 cmsFloat64Number prophoto_parameters[5] =
687 { 1.8, 1.0, 0, 1.0 / 16, (16.0/512) };
688
689 cmsFloat64Number log_100[5] = {1.0, 10, 2.0, -2.0, 0.0};
690 cmsFloat64Number log_100_sqrt[5] = {1.0, 10, 2.5, -2.5, 0.0};
691
692 cmsFloat64Number labl_parameters[5] = {3.0, 0.862076, 0.137924, 0.110703, 0.080002};
693
694 switch (transferFunction) {
696 // Not possible in ICC due to lack of a*pow(bX+c,y) construct.
698 // This is not possible in ICC due to lack of a*pow(bX+c,y) construct.
699 qWarning() << "Neither IEC 61966 2-4 nor Bt. 1361 are supported, returning a rec 709 curve.";
700 Q_FALLTHROUGH();
704 mainCurve = cmsBuildParametricToneCurve(NULL, 4, rec709_parameters);
705 break;
707 mainCurve = cmsBuildParametricToneCurve(NULL, 4, rec202012bit_parameters);
708 break;
710 mainCurve = cmsBuildGamma(NULL, 2.2);
711 break;
713 mainCurve = cmsBuildGamma(NULL, 2.8);
714 break;
715 case TRC_SMPTE_240M:
716 mainCurve = cmsBuildParametricToneCurve(NULL, 4, SMPTE_240M_parameters);
717 break;
719 mainCurve = cmsBuildParametricToneCurve(NULL, 4, srgb_parameters);
720 break;
722 mainCurve = cmsBuildParametricToneCurve(NULL, 8, log_100);
723 break;
725 mainCurve = cmsBuildParametricToneCurve(NULL, 8, log_100_sqrt);
726 break;
727 case TRC_A98:
728 // gamma 563/256
729 mainCurve = cmsBuildGamma(NULL, 563.0 / 256.0);
730 break;
731 case TRC_PROPHOTO:
732 mainCurve = cmsBuildParametricToneCurve(NULL, 4, prophoto_parameters);
733 break;
734 case TRC_GAMMA_1_8:
735 mainCurve = cmsBuildGamma(NULL, 1.8);
736 break;
737 case TRC_GAMMA_2_4:
738 mainCurve = cmsBuildGamma(NULL, 2.4);
739 break;
740 case TRC_LAB_L:
741 mainCurve = cmsBuildParametricToneCurve(NULL, 4, labl_parameters);
742 break;
744 // Requires an a*X^y construction, not possible.
746 // Perceptual Quantizer
748 // Hybrid log gamma.
749 qWarning() << "Cannot generate an icc profile with this transfer function, will generate a linear profile";
750 Q_FALLTHROUGH();
751 case TRC_LINEAR:
752 default:
753 mainCurve = cmsBuildGamma(NULL, 1.0);
754 break;
755 }
756
757 return mainCurve;
758}
@ 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

References 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 344 of file LcmsColorProfileContainer.cpp.

345{
346 return d->valid;
347}

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

◆ version()

float LcmsColorProfileContainer::version ( ) const
virtual

Definition at line 349 of file LcmsColorProfileContainer.cpp.

350{
351 return d->version;
352}

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

Friends And Related Symbol Documentation

◆ IccColorProfile

friend class IccColorProfile
friend

Definition at line 25 of file LcmsColorProfileContainer.h.

Member Data Documentation

◆ d

Private* const LcmsColorProfileContainer::d
private

Definition at line 109 of file LcmsColorProfileContainer.h.


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