static void Rel2RelStepAbsCoefs(double AdaptationState, LPcmsCIEXYZ BlackPointIn, LPcmsCIEXYZ WhitePointIn, LPcmsCIEXYZ IlluminantIn, LPMAT3 ChromaticAdaptationMatrixIn, LPcmsCIEXYZ BlackPointOut, LPcmsCIEXYZ WhitePointOut, LPcmsCIEXYZ IlluminantOut, LPMAT3 ChromaticAdaptationMatrixOut, LPMAT3 m, LPVEC3 of) { VEC3 WtPtIn, WtPtInAdapted; VEC3 WtPtOut, WtPtOutAdapted; MAT3 Scale, m1, m2, m3; VEC3init(&WtPtIn, WhitePointIn->X, WhitePointIn->Y, WhitePointIn->Z); MAT3eval(&WtPtInAdapted, ChromaticAdaptationMatrixIn, &WtPtIn); VEC3init(&WtPtOut, WhitePointOut->X, WhitePointOut->Y, WhitePointOut->Z); MAT3eval(&WtPtOutAdapted, ChromaticAdaptationMatrixOut, &WtPtOut); VEC3init(&Scale.v[0], WtPtInAdapted.n[0] / WtPtOutAdapted.n[0], 0, 0); VEC3init(&Scale.v[1], 0, WtPtInAdapted.n[1] / WtPtOutAdapted.n[1], 0); VEC3init(&Scale.v[2], 0, 0, WtPtInAdapted.n[2] / WtPtOutAdapted.n[2]); // Adaptation state if (AdaptationState == 1.0) { // Observer is fully adapted. Keep chromatic adaptation CopyMemory(m, &Scale, sizeof(MAT3)); } else { // Observer is not adapted, undo the chromatic adaptation m1 = *ChromaticAdaptationMatrixIn; MAT3inverse(&m1, &m2); MAT3per(&m3, &m2, &Scale); MAT3per(m, &m3, ChromaticAdaptationMatrixOut); } VEC3init(of, 0.0, 0.0, 0.0); }
static void ComputeChromaticAdaptation(LPMAT3 Conversion, LPcmsCIEXYZ SourceWhitePoint, LPcmsCIEXYZ DestWhitePoint, LPMAT3 Chad) { MAT3 Chad_Inv; VEC3 ConeSourceXYZ, ConeSourceRGB; VEC3 ConeDestXYZ, ConeDestRGB; MAT3 Cone, Tmp; Tmp = *Chad; MAT3inverse(&Tmp, &Chad_Inv); VEC3init(&ConeSourceXYZ, SourceWhitePoint -> X, SourceWhitePoint -> Y, SourceWhitePoint -> Z); VEC3init(&ConeDestXYZ, DestWhitePoint -> X, DestWhitePoint -> Y, DestWhitePoint -> Z); MAT3eval(&ConeSourceRGB, Chad, &ConeSourceXYZ); MAT3eval(&ConeDestRGB, Chad, &ConeDestXYZ); // Build matrix VEC3init(&Cone.v[0], ConeDestRGB.n[0]/ConeSourceRGB.n[0], 0.0, 0.0); VEC3init(&Cone.v[1], 0.0, ConeDestRGB.n[1]/ConeSourceRGB.n[1], 0.0); VEC3init(&Cone.v[2], 0.0, 0.0, ConeDestRGB.n[2]/ConeSourceRGB.n[2]); // Normalize MAT3per(&Tmp, &Cone, Chad); MAT3per(Conversion, &Chad_Inv, &Tmp); }
BOOL LCMSEXPORT cmsBuildRGB2XYZtransferMatrix(LPMAT3 r, LPcmsCIExyY WhitePt, LPcmsCIExyYTRIPLE Primrs) { VEC3 WhitePoint, Coef; MAT3 Result, Primaries; double xn, yn; double xr, yr; double xg, yg; double 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 VEC3init(&Primaries.v[0], xr, xg, xb); VEC3init(&Primaries.v[1], yr, yg, yb); VEC3init(&Primaries.v[2], (1-xr-yr), (1-xg-yg), (1-xb-yb)); // Result = Primaries ^ (-1) inverse matrix if (!MAT3inverse(&Primaries, &Result)) return FALSE; VEC3init(&WhitePoint, xn/yn, 1.0, (1.0-xn-yn)/yn); // Across inverse primaries ... MAT3eval(&Coef, &Result, &WhitePoint); // Give us the Coefs, then I build transformation matrix VEC3init(&r -> v[0], Coef.n[VX]*xr, Coef.n[VY]*xg, Coef.n[VZ]*xb); VEC3init(&r -> v[1], Coef.n[VX]*yr, Coef.n[VY]*yg, Coef.n[VZ]*yb); VEC3init(&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 TRUE; }
static int RegressionSamplerB2A(register WORD In[], register WORD Out[], register LPVOID Cargo) { cmsCIELab Lab; cmsCIEXYZ xyz; VEC3 vxyz, RGB; /* cmsJCh JCh; */ WORD Lin[3], Llab[3]; LPMONITORPROFILERDATA sys = (LPMONITORPROFILERDATA) Cargo; double L; /* Pass L back to 0..0xff00 domain */ L = (double) (In[0] * 65280.0) / 65535.0; In[0] = (WORD) floor(L + .5); /* To float values */ cmsLabEncoded2Float(&Lab, In); cmsLab2XYZ(NULL, &xyz, &Lab); cmsxChromaticAdaptationAndNormalization(&sys ->hdr, &xyz, true); vxyz.n[0] = xyz.X; vxyz.n[1] = xyz.Y; vxyz.n[2] = xyz.Z; MAT3eval(&RGB, &sys-> PrimariesMatrixRev, &vxyz); /* Clamp RGB */ ClampRGB(&RGB); /* Encode output */ Lin[0] = (WORD) ((double) RGB.n[0] * 65535. + .5); Lin[1] = (WORD) ((double) RGB.n[1] * 65535. + .5); Lin[2] = (WORD) ((double) RGB.n[2] * 65535. + .5); cmsxApplyLinearizationGamma(Lin, sys ->ReverseTables, Llab); cmsxApplyLinearizationGamma(Llab, sys ->PreLabRev, Out); return true; /* And done witch success */ }
BOOL LCMSEXPORT cmsAdaptToIlluminant(LPcmsCIEXYZ Result, LPcmsCIEXYZ SourceWhitePt, LPcmsCIEXYZ Illuminant, LPcmsCIEXYZ Value) { MAT3 Bradford; VEC3 In, Out; // BradfordLamRiggChromaticAdaptation(&Bradford, SourceWhitePt, Illuminant); cmsAdaptationMatrix(&Bradford, NULL, SourceWhitePt, Illuminant); VEC3init(&In, Value -> X, Value -> Y, Value -> Z); MAT3eval(&Out, &Bradford, &In); Result -> X = Out.n[0]; Result -> Y = Out.n[1]; Result -> Z = Out.n[2]; return TRUE; }
static int RegressionSamplerA2B(register WORD In[], register WORD Out[], register LPVOID Cargo) { cmsCIEXYZ xyz; cmsCIELab Lab; VEC3 RGB, RGBlinear, vxyz; LPMONITORPROFILERDATA sys = (LPMONITORPROFILERDATA) Cargo; RGB.n[0] = _cmsxSaturate65535To255(In[0]); RGB.n[1] = _cmsxSaturate65535To255(In[1]); RGB.n[2] = _cmsxSaturate65535To255(In[2]); cmsxApplyLinearizationTable(RGB.n, sys->PreLab, RGBlinear.n); cmsxApplyLinearizationTable(RGBlinear.n, sys->Prelinearization, RGBlinear.n); RGBlinear.n[0] /= 255.; RGBlinear.n[1] /= 255.; RGBlinear.n[2] /= 255.; MAT3eval(&vxyz, &sys->PrimariesMatrix, &RGBlinear); xyz.X = vxyz.n[0]; xyz.Y = vxyz.n[1]; xyz.Z = vxyz.n[2]; cmsxChromaticAdaptationAndNormalization(&sys ->hdr, &xyz, false); /* To PCS encoding */ cmsXYZ2Lab(NULL, &Lab, &xyz); cmsFloat2LabEncoded(Out, &Lab); return true; /* And done witch success */ }
BOOL cmsxComputeMatrixShaper(const char* ReferenceSheet, const char* MeasurementSheet, int Medium, LPGAMMATABLE TransferCurves[3], LPcmsCIEXYZ WhitePoint, LPcmsCIEXYZ BlackPoint, LPcmsCIExyYTRIPLE Primaries) { MEASUREMENT Linearized; cmsCIEXYZ Black, White; cmsCIExyYTRIPLE PrimarySet; LPPATCH PatchWhite, PatchBlack; LPPATCH PatchRed, PatchGreen, PatchBlue; double Distance; /* Load sheets */ if (!cmsxPCollBuildMeasurement(&Linearized, ReferenceSheet, MeasurementSheet, PATCH_HAS_XYZ|PATCH_HAS_RGB)) return false; /* Any patch to deal of? */ if (cmsxPCollCountSet(&Linearized, Linearized.Allowed) <= 0) return false; /* Try to see if proper primaries, white and black already present */ PatchWhite = cmsxPCollFindWhite(&Linearized, Linearized.Allowed, &Distance); if (Distance != 0) PatchWhite = NULL; PatchBlack = cmsxPCollFindBlack(&Linearized, Linearized.Allowed, &Distance); if (Distance != 0) PatchBlack = NULL; PatchRed = cmsxPCollFindPrimary(&Linearized, Linearized.Allowed, 0, &Distance); if (Distance != 0) PatchRed = NULL; PatchGreen = cmsxPCollFindPrimary(&Linearized, Linearized.Allowed, 1, &Distance); if (Distance != 0) PatchGreen = NULL; PatchBlue = cmsxPCollFindPrimary(&Linearized, Linearized.Allowed, 2, &Distance); if (Distance != 0) PatchBlue= NULL; /* If we got primaries, then we can also get prelinearization */ /* by Levenberg-Marquardt. This applies on monitor profiles */ if (PatchWhite && PatchRed && PatchGreen && PatchBlue) { /* Build matrix with primaries */ MAT3 Mat, MatInv; LPSAMPLEDCURVE Xr,Yr, Xg, Yg, Xb, Yb; int i, nRes, cnt; VEC3init(&Mat.v[0], PatchRed->XYZ.X, PatchGreen->XYZ.X, PatchBlue->XYZ.X); VEC3init(&Mat.v[1], PatchRed->XYZ.Y, PatchGreen->XYZ.Y, PatchBlue->XYZ.Y); VEC3init(&Mat.v[2], PatchRed->XYZ.Z, PatchGreen->XYZ.Z, PatchBlue->XYZ.Z); /* Invert matrix */ MAT3inverse(&Mat, &MatInv); nRes = cmsxPCollCountSet(&Linearized, Linearized.Allowed); Xr = cmsAllocSampledCurve(nRes); Yr = cmsAllocSampledCurve(nRes); Xg = cmsAllocSampledCurve(nRes); Yg = cmsAllocSampledCurve(nRes); Xb = cmsAllocSampledCurve(nRes); Yb = cmsAllocSampledCurve(nRes); /* Convert XYZ of all patches to RGB */ cnt = 0; for (i=0; i < Linearized.nPatches; i++) { if (Linearized.Allowed[i]) { VEC3 RGBprime, XYZ; LPPATCH p; p = Linearized.Patches + i; XYZ.n[0] = p -> XYZ.X; XYZ.n[1] = p -> XYZ.Y; XYZ.n[2] = p -> XYZ.Z; MAT3eval(&RGBprime, &MatInv, &XYZ); Xr ->Values[cnt] = p ->Colorant.RGB[0]; Yr ->Values[cnt] = Clip(RGBprime.n[0]); Xg ->Values[cnt] = p ->Colorant.RGB[1]; Yg ->Values[cnt] = Clip(RGBprime.n[1]); Xb ->Values[cnt] = p ->Colorant.RGB[2]; Yb ->Values[cnt] = Clip(RGBprime.n[2]); cnt++; } } TransferCurves[0] = cmsxEstimateGamma(Xr, Yr, 1024); TransferCurves[1] = cmsxEstimateGamma(Xg, Yg, 1024); TransferCurves[2] = cmsxEstimateGamma(Xb, Yb, 1024); if (WhitePoint) { WhitePoint->X = PatchWhite->XYZ.X; WhitePoint->Y= PatchWhite ->XYZ.Y; WhitePoint->Z= PatchWhite ->XYZ.Z; } if (BlackPoint && PatchBlack) { BlackPoint->X = PatchBlack ->XYZ.X; BlackPoint->Y = PatchBlack ->XYZ.Y; BlackPoint->Z = PatchBlack ->XYZ.Z; } if (Primaries) { cmsXYZ2xyY(&Primaries->Red, &PatchRed ->XYZ); cmsXYZ2xyY(&Primaries->Green, &PatchGreen ->XYZ); cmsXYZ2xyY(&Primaries->Blue, &PatchBlue ->XYZ); } cmsFreeSampledCurve(Xr); cmsFreeSampledCurve(Yr); cmsFreeSampledCurve(Xg); cmsFreeSampledCurve(Yg); cmsFreeSampledCurve(Xb); cmsFreeSampledCurve(Yb); cmsxPCollFreeMeasurements(&Linearized); return true; } /* Compute prelinearization */ cmsxComputeLinearizationTables(&Linearized, PT_XYZ, TransferCurves, 1024, Medium); /* Linearize measurements */ cmsxPCollLinearizePatches(&Linearized, Linearized.Allowed, TransferCurves); /* Endpoints */ ComputeWhiteAndBlackPoints(&Linearized, TransferCurves, &Black, &White); /* Primaries */ ComputePrimary(&Linearized, TransferCurves, 0, &PrimarySet.Red); ComputePrimary(&Linearized, TransferCurves, 1, &PrimarySet.Green); ComputePrimary(&Linearized, TransferCurves, 2, &PrimarySet.Blue); if (BlackPoint) { *BlackPoint = Black; Div100(BlackPoint); } if (WhitePoint) { *WhitePoint = White; Div100(WhitePoint); } if (Primaries) { *Primaries = PrimarySet; } cmsxPCollFreeMeasurements(&Linearized); return true; }