/* */ /* Little cms - profiler construction set */ /* Copyright (C) 1998-2001 Marti Maria */ /* */ /* THIS SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, */ /* EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY */ /* WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. */ /* */ /* IN NO EVENT SHALL MARTI MARIA BE LIABLE FOR ANY SPECIAL, INCIDENTAL, */ /* INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, */ /* OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, */ /* WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF */ /* LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE */ /* OF THIS SOFTWARE. */ /* */ /* This file is free software; you can redistribute it and/or modify it */ /* under the terms of the GNU General Public License as published by */ /* the Free Software Foundation; either version 2 of the License, or */ /* (at your option) any later version. */ /* */ /* This program is distributed in the hope that it will be useful, but */ /* WITHOUT ANY WARRANTY; without even the implied warranty of */ /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU */ /* General Public License for more details. */ /* */ /* You should have received a copy of the GNU General Public License */ /* along with this program; if not, write to the Free Software */ /* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /* */ /* As a special exception to the GNU General Public License, if you */ /* distribute this file as part of a program that contains a */ /* configuration script generated by Autoconf, you may include it under */ /* the same distribution terms that you use for the rest of that program. */ /* */ /* Version 1.09a */ #include "lcmsprf.h" static void ClampRGB(LPVEC3 RGB) { int i; for (i=0; i < 3; i++) { if (RGB->n[i] > 1.0) RGB->n[i] = 1.0; if (RGB->n[i] < 0) RGB->n[i] = 0; } } static int RegressionSamplerA2B(WORD In[], WORD Out[], 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 */ } static int RegressionSamplerB2A(WORD In[], WORD Out[], 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 cmsxMonitorProfilerInit(LPMONITORPROFILERDATA sys) { if (sys == NULL) return false; ZeroMemory(sys, sizeof(MONITORPROFILERDATA)); sys->hdr.DeviceClass = icSigDisplayClass; sys->hdr.ColorSpace = icSigRgbData; sys->hdr.PCSType = PT_Lab; sys->hdr.Medium = MEDIUM_TRANSMISSIVE; /* Default values for generation */ sys -> hdr.lUseCIECAM97s = false; sys -> hdr.CLUTPoints = 16; /* Default viewing conditions */ sys -> hdr.device.Yb = 20; sys -> hdr.device.La = 20; sys -> hdr.device.surround = AVG_SURROUND; sys -> hdr.device.D_value = 1; /* Complete adaptation */ /* Viewing conditions of PCS */ cmsxInitPCSViewingConditions(&sys ->hdr); strcpy(sys -> hdr.Description, "unknown monitor"); strcpy(sys -> hdr.Manufacturer, "little cms profiler construction set"); strcpy(sys -> hdr.Copyright, "No copyright, use freely"); strcpy(sys -> hdr.Model, "(unknown)"); sys -> hdr.ProfileVerbosityLevel = 0; return true; } 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); } static BOOL CreateLUTS(LPMONITORPROFILERDATA sys, LPLUT* A2B, LPLUT* B2A) { LPLUT AToB0 = cmsAllocLUT(); LPLUT BToA0 = cmsAllocLUT(); LPGAMMATABLE LabG; cmsCIExyY xyY; cmsAlloc3DGrid(AToB0, sys->hdr.CLUTPoints, 3, 3); cmsAlloc3DGrid(BToA0, sys->hdr.CLUTPoints, 3, 3); /* cmsAllocLinearTable(AToB0, sys -> Prelinearization, 1); */ sys->ReverseTables[0] = cmsReverseGamma(4096, sys ->Prelinearization[0]); sys->ReverseTables[1] = cmsReverseGamma(4096, sys ->Prelinearization[1]); sys->ReverseTables[2] = cmsReverseGamma(4096, sys ->Prelinearization[2]); /* Prelinearization */ LabG = cmsBuildGamma(4096, 3.0); sys -> PreLab[0] = cmsJoinGammaEx(LabG, sys ->Prelinearization[0], 4096); sys -> PreLab[1] = cmsJoinGammaEx(LabG, sys ->Prelinearization[1], 4096); sys -> PreLab[2] = cmsJoinGammaEx(LabG, sys ->Prelinearization[2], 4096); sys -> PreLabRev[0] = cmsJoinGammaEx(sys ->Prelinearization[0], LabG, 4096); sys -> PreLabRev[1] = cmsJoinGammaEx(sys ->Prelinearization[1], LabG, 4096); sys -> PreLabRev[2] = cmsJoinGammaEx(sys ->Prelinearization[2], LabG, 4096); cmsFreeGamma(LabG); cmsAllocLinearTable(AToB0, sys->PreLabRev, 1); cmsAllocLinearTable(BToA0, sys->PreLab, 2); /* Set CIECAM97s parameters */ sys -> hdr.device.whitePoint.X = sys -> hdr.WhitePoint.X * 100.; sys -> hdr.device.whitePoint.Y = sys -> hdr.WhitePoint.Y * 100.; sys -> hdr.device.whitePoint.Z = sys -> hdr.WhitePoint.Z * 100.; /* Normalize White point for CIECAM97s model */ cmsXYZ2xyY(&xyY, &sys -> hdr.device.whitePoint); xyY.Y = 100.; cmsxyY2XYZ(&sys -> hdr.device.whitePoint, &xyY); sys->hdr.hDevice = cmsCIECAM97sInit(&sys->hdr.device); sys->hdr.hPCS = cmsCIECAM97sInit(&sys->hdr.PCS); cmsSample3DGrid(AToB0, RegressionSamplerA2B, sys, 0); cmsSample3DGrid(BToA0, RegressionSamplerB2A, sys, 0); cmsCIECAM97sDone(sys->hdr.hDevice); cmsCIECAM97sDone(sys->hdr.hPCS); cmsAddTag(sys->hdr.hProfile, icSigAToB0Tag, AToB0); cmsAddTag(sys->hdr.hProfile, icSigBToA0Tag, BToA0); /* This is the 0xff00 trick to map white at lattice point */ BToA0 ->Matrix.v[0].n[0] = DOUBLE_TO_FIXED((65535.0 / 65280.0)); *A2B = AToB0; *B2A = BToA0; cmsFreeGammaTriple(sys->ReverseTables); cmsFreeGammaTriple(sys->PreLab); cmsFreeGammaTriple(sys->PreLabRev); return true; } BOOL cmsxMonitorProfilerDo(LPMONITORPROFILERDATA sys) { cmsCIExyY White; LPLUT AToB0, BToA0; AToB0 = BToA0 = NULL; if (!*sys -> hdr.OutputProfileFile) return false; if (sys->hdr.ReferenceSheet[0] || sys->hdr.MeasurementSheet[0]) { if (sys->hdr.printf) { sys->hdr.printf("Loading sheets..."); if (sys->hdr.ReferenceSheet[0]) sys->hdr.printf("Reference sheet: %s", sys->hdr.ReferenceSheet); if (sys->hdr.MeasurementSheet[0]) sys->hdr.printf("Measurement sheet: %s", sys->hdr.MeasurementSheet); } if (!cmsxComputeMatrixShaper(sys -> hdr.ReferenceSheet, sys -> hdr.MeasurementSheet, MEDIUM_TRANSMISSIVE, sys -> Prelinearization, &sys -> hdr.WhitePoint, &sys -> hdr.BlackPoint, &sys -> hdr.Primaries)) return false; if (sys->hdr.printf) { char Buffer[1024]; _cmsIdentifyWhitePoint(Buffer, &sys ->hdr.WhitePoint); sys->hdr.printf("%s", Buffer); sys->hdr.printf("Primaries: R:%1.2g, %1.2g G:%1.2g, %1.2g B:%1.2g, %1.2g", sys->hdr.Primaries.Red.x,sys->hdr.Primaries.Red.y, sys->hdr.Primaries.Green.x, sys->hdr.Primaries.Green.y, sys->hdr.Primaries.Blue.x, sys->hdr.Primaries.Blue.y); } } CreatePrimaryMatrices(sys); cmsXYZ2xyY(&White, &sys->hdr.WhitePoint); sys->hdr.hProfile = cmsCreateRGBProfile(&White, &sys-> hdr.Primaries, sys -> Prelinearization); cmsSetDeviceClass(sys->hdr.hProfile, sys->hdr.DeviceClass); if (sys -> hdr.lUseCIECAM97s) sys->hdr.PCSType = PT_Lab; else sys->hdr.PCSType = PT_XYZ; cmsSetPCS(sys->hdr.hProfile, _cmsICCcolorSpace(sys->hdr.PCSType)); if (sys -> hdr.lUseCIECAM97s) CreateLUTS(sys, &AToB0, &BToA0); cmsxEmbedTextualInfo(&sys ->hdr); cmsAddTag(sys->hdr.hProfile, icSigMediaWhitePointTag, &sys->hdr.WhitePoint); cmsAddTag(sys->hdr.hProfile, icSigMediaBlackPointTag, &sys->hdr.BlackPoint); if (sys->hdr.ProfileVerbosityLevel >= 2) { cmsxEmbedCharTarget(&sys ->hdr); } _cmsSaveProfile(sys->hdr.hProfile, sys->hdr.OutputProfileFile); cmsCloseProfile(sys->hdr.hProfile); sys->hdr.hProfile = NULL; if (AToB0) cmsFreeLUT(AToB0); if (BToA0) cmsFreeLUT(BToA0); if (sys ->Prelinearization[0]) cmsFreeGammaTriple(sys -> Prelinearization); return true; }