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 CreatePrimaryMatrices(LPMONITORPROFILERDATA sys) { cmsCIExyY White; MAT3 tmp; cmsXYZ2xyY(&White, &sys->hdr.WhitePoint); cmsBuildRGB2XYZtransferMatrix(&sys -> PrimariesMatrix, &White, &sys->hdr.Primaries); CopyMemory(&tmp, &sys -> PrimariesMatrix, sizeof(MAT3)); MAT3inverse(&tmp, &sys->PrimariesMatrixRev); }
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 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 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; }