// Approximate a blackbody illuminant based on CHAD information static cmsFloat64Number CHAD2Temp(const cmsMAT3* Chad) { // Convert D50 across inverse CHAD to get the absolute white point cmsVEC3 d, s; cmsCIEXYZ Dest; cmsCIExyY DestChromaticity; cmsFloat64Number TempK; cmsMAT3 m1, m2; m1 = *Chad; if (!_cmsMAT3inverse(&m1, &m2)) return FALSE; s.n[VX] = cmsD50_XYZ() -> X; s.n[VY] = cmsD50_XYZ() -> Y; s.n[VZ] = cmsD50_XYZ() -> Z; _cmsMAT3eval(&d, &m2, &s); Dest.X = d.n[VX]; Dest.Y = d.n[VY]; Dest.Z = d.n[VZ]; cmsXYZ2xyY(&DestChromaticity, &Dest); if (!cmsTempFromWhitePoint(&TempK, &DestChromaticity)) return -1.0; return TempK; }
// Solve a system in the form Ax = b cmsBool CMSEXPORT _cmsMAT3solve(cmsVEC3* x, cmsMAT3* a, cmsVEC3* b) { cmsMAT3 m, a_1; memmove(&m, a, sizeof(cmsMAT3)); if (!_cmsMAT3inverse(&m, &a_1)) return FALSE; // Singular matrix _cmsMAT3eval(x, &a_1, b); return TRUE; }
static cmsBool ComputeChromaticAdaptation(cmsMAT3* Conversion, const cmsCIEXYZ* SourceWhitePoint, const cmsCIEXYZ* DestWhitePoint, const cmsMAT3* Chad) { cmsMAT3 Chad_Inv; cmsVEC3 ConeSourceXYZ, ConeSourceRGB; cmsVEC3 ConeDestXYZ, ConeDestRGB; cmsMAT3 Cone, Tmp; Tmp = *Chad; if (!_cmsMAT3inverse(&Tmp, &Chad_Inv)) return FALSE; _cmsVEC3init(&ConeSourceXYZ, SourceWhitePoint -> X, SourceWhitePoint -> Y, SourceWhitePoint -> Z); _cmsVEC3init(&ConeDestXYZ, DestWhitePoint -> X, DestWhitePoint -> Y, DestWhitePoint -> Z); _cmsMAT3eval(&ConeSourceRGB, Chad, &ConeSourceXYZ); _cmsMAT3eval(&ConeDestRGB, Chad, &ConeDestXYZ); // Build matrix _cmsVEC3init(&Cone.v[0], ConeDestRGB.n[0]/ConeSourceRGB.n[0], 0.0, 0.0); _cmsVEC3init(&Cone.v[1], 0.0, ConeDestRGB.n[1]/ConeSourceRGB.n[1], 0.0); _cmsVEC3init(&Cone.v[2], 0.0, 0.0, ConeDestRGB.n[2]/ConeSourceRGB.n[2]); // Normalize _cmsMAT3per(&Tmp, &Cone, Chad); _cmsMAT3per(Conversion, &Chad_Inv, &Tmp); return TRUE; }
// Build a White point, primary chromas transfer matrix from RGB to CIE XYZ // This is just an approximation, I am not handling all the non-linear // aspects of the RGB to XYZ process, and assumming that the gamma correction // has transitive property in the transformation chain. // // the alghoritm: // // - First I build the absolute conversion matrix using // primaries in XYZ. This matrix is next inverted // - Then I eval the source white point across this matrix // obtaining the coeficients of the transformation // - Then, I apply these coeficients to the original matrix // cmsBool _cmsBuildRGB2XYZtransferMatrix(cmsMAT3* r, const cmsCIExyY* WhitePt, const cmsCIExyYTRIPLE* Primrs) { cmsVEC3 WhitePoint, Coef; cmsMAT3 Result, Primaries; cmsFloat64Number xn, yn; cmsFloat64Number xr, yr; cmsFloat64Number xg, yg; cmsFloat64Number xb, yb; xn = WhitePt -> x; yn = WhitePt -> y; xr = Primrs -> Red.x; yr = Primrs -> Red.y; xg = Primrs -> Green.x; yg = Primrs -> Green.y; xb = Primrs -> Blue.x; yb = Primrs -> Blue.y; // Build Primaries matrix _cmsVEC3init(&Primaries.v[0], xr, xg, xb); _cmsVEC3init(&Primaries.v[1], yr, yg, yb); _cmsVEC3init(&Primaries.v[2], (1-xr-yr), (1-xg-yg), (1-xb-yb)); // Result = Primaries ^ (-1) inverse matrix if (!_cmsMAT3inverse(&Primaries, &Result)) return FALSE; _cmsVEC3init(&WhitePoint, xn/yn, 1.0, (1.0-xn-yn)/yn); // Across inverse primaries ... _cmsMAT3eval(&Coef, &Result, &WhitePoint); // Give us the Coefs, then I build transformation matrix _cmsVEC3init(&r -> v[0], Coef.n[VX]*xr, Coef.n[VY]*xg, Coef.n[VZ]*xb); _cmsVEC3init(&r -> v[1], Coef.n[VX]*yr, Coef.n[VY]*yg, Coef.n[VZ]*yb); _cmsVEC3init(&r -> v[2], Coef.n[VX]*(1.0-xr-yr), Coef.n[VY]*(1.0-xg-yg), Coef.n[VZ]*(1.0-xb-yb)); return _cmsAdaptMatrixToD50(r, WhitePt); }
// Adapts a color to a given illuminant. Original color is expected to have // a SourceWhitePt white point. cmsBool CMSEXPORT cmsAdaptToIlluminant(cmsCIEXYZ* Result, const cmsCIEXYZ* SourceWhitePt, const cmsCIEXYZ* Illuminant, const cmsCIEXYZ* Value) { cmsMAT3 Bradford; cmsVEC3 In, Out; _cmsAssert(Result != NULL); _cmsAssert(SourceWhitePt != NULL); _cmsAssert(Illuminant != NULL); _cmsAssert(Value != NULL); if (!_cmsAdaptationMatrix(&Bradford, NULL, SourceWhitePt, Illuminant)) return FALSE; _cmsVEC3init(&In, Value -> X, Value -> Y, Value -> Z); _cmsMAT3eval(&Out, &Bradford, &In); Result -> X = Out.n[0]; Result -> Y = Out.n[1]; Result -> Z = Out.n[2]; return TRUE; }