summaryrefslogtreecommitdiffstats
path: root/src/libs/lprof/cmsscn.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/libs/lprof/cmsscn.cpp')
-rw-r--r--src/libs/lprof/cmsscn.cpp422
1 files changed, 422 insertions, 0 deletions
diff --git a/src/libs/lprof/cmsscn.cpp b/src/libs/lprof/cmsscn.cpp
new file mode 100644
index 00000000..b99fed87
--- /dev/null
+++ b/src/libs/lprof/cmsscn.cpp
@@ -0,0 +1,422 @@
+/* */
+/* Little cms - profiler construction set */
+/* Copyright (C) 1998-2001 Marti Maria <marti@littlecms.com> */
+/* */
+/* 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.08a */
+
+
+#include "lcmsprf.h"
+#include <stdio.h>
+
+/* The scanner profiler */
+
+
+BOOL cdecl cmsxScannerProfilerInit(LPSCANNERPROFILERDATA sys);
+BOOL cdecl cmsxScannerProfilerDo(LPSCANNERPROFILERDATA sys);
+
+/* ------------------------------------------------------------ Implementation */
+
+
+
+/* Does create regression matrix */
+
+static
+void ComputeGlobalRegression(LPSCANNERPROFILERDATA sys)
+{
+ BOOL lAllOk;
+ int nTerms;
+ MLRSTATISTICS Stat;
+
+ nTerms = cmsxFindOptimumNumOfTerms(&sys ->hdr, 55, &lAllOk);
+
+
+ if (!lAllOk) {
+ if (sys -> hdr.printf)
+ sys -> hdr.printf("*** WARNING: Inconsistence found, profile may be wrong. Check the target!");
+ nTerms = 4;
+ }
+
+ /* Create high terms matrix used by interpolation */
+ cmsxRegressionCreateMatrix(&sys -> hdr.m,
+ sys -> hdr.m.Allowed,
+ nTerms,
+ sys -> hdr.PCSType,
+ &sys -> HiTerms,
+ &Stat);
+
+ if (sys -> hdr.printf)
+ sys -> hdr.printf("Global regression: %d terms, R2Adj = %g", nTerms, Stat.R2adj);
+
+ /* Create low terms matrix used by extrapolation */
+ cmsxRegressionCreateMatrix(&sys -> hdr.m,
+ sys -> hdr.m.Allowed,
+ (nTerms > 10 ? 10 : nTerms),
+ sys -> hdr.PCSType,
+ &sys -> LoTerms,
+ &Stat);
+ if (sys -> hdr.printf)
+ sys -> hdr.printf("Extrapolation: R2Adj = %g", Stat.R2adj);
+
+}
+
+
+/* Fill struct with default values */
+
+BOOL cmsxScannerProfilerInit(LPSCANNERPROFILERDATA sys)
+{
+
+
+ if (sys == NULL) return false;
+ ZeroMemory(sys, sizeof(SCANNERPROFILERDATA));
+
+ sys->hdr.DeviceClass = icSigInputClass;
+ sys->hdr.ColorSpace = icSigRgbData;
+ sys->hdr.PCSType = PT_Lab;
+ sys->hdr.Medium = MEDIUM_REFLECTIVE_D50;
+
+ /* Default values for generation */
+
+ sys -> hdr.lUseCIECAM97s = false;
+ sys -> hdr.CLUTPoints = 16;
+
+
+ /* Default viewing conditions for scanner */
+
+ sys -> hdr.device.Yb = 20;
+ sys -> hdr.device.La = 20;
+ sys -> hdr.device.surround = AVG_SURROUND;
+ sys -> hdr.device.D_value = 1.0; /* Complete adaptation */
+
+
+ /* Viewing conditions of PCS */
+ cmsxInitPCSViewingConditions(&sys -> hdr);
+
+
+ sys -> HiTerms = NULL;
+ sys -> LoTerms = NULL;
+
+ strcpy(sys -> hdr.Description, "no description");
+ strcpy(sys -> hdr.Manufacturer, "little cms profiler construction set");
+ strcpy(sys -> hdr.Copyright, "No copyright, use freely");
+ strcpy(sys -> hdr.Model, "(unknown)");
+
+ sys ->lLocalConvergenceExtrapolation = false;
+ sys ->hdr.ProfileVerbosityLevel = 0;
+
+
+ return true;
+}
+
+/* Auxiliar: take RGB and update gauge */
+static
+void GetRGB(LPPROFILERCOMMONDATA hdr, WORD In[], double* r, double* g, double* b)
+{
+ static int Count = 0, n_old = 0;
+ double R, G, B;
+ int n;
+
+
+ R = _cmsxSaturate65535To255(In[0]); /* Convert from the sheet notation */
+ G = _cmsxSaturate65535To255(In[1]); /* 0..255.0, to our notation */
+ B = _cmsxSaturate65535To255(In[2]); /* of 0..0xffff, 0xffff/255 = 257 */
+
+ if (R == 0 && G == 0 && B == 0) {
+ Count = 0; n_old = -1;
+ }
+
+ n = (int) (double) (100. * Count) / (hdr->CLUTPoints * hdr->CLUTPoints * hdr->CLUTPoints);
+ Count++;
+
+ if (n > n_old) {
+ if (hdr->Gauger) hdr->Gauger("", 0, 100, (int) n);
+ }
+
+ n_old = n;
+ *r = R; *g = G; *b = B;
+
+}
+
+
+
+
+
+/* The sampler for Lab */
+static
+int RegressionSamplerLab(WORD In[], WORD Out[], LPVOID Cargo)
+{
+ cmsCIEXYZ xyz;
+ cmsCIELab Lab;
+ double r, g, b;
+ LPSCANNERPROFILERDATA sys = (LPSCANNERPROFILERDATA) Cargo;
+ char code;
+
+
+ GetRGB(&sys->hdr, In, &r, &g, &b);
+
+
+ code = cmsxHullCheckpoint(sys->hdr.hRGBHull,
+ (int) floor(r + .5),
+ (int) floor(g + .5),
+ (int) floor(b + .5));
+
+
+ if (code == 'i') { /* Inside gamut */
+
+ if (!cmsxRegressionRGB2Lab(r, g, b, sys -> HiTerms, &Lab)) return false;
+ }
+ else
+ if (!sys -> lLocalConvergenceExtrapolation && code == 'o') { /* outside gamut */
+
+ if (!cmsxRegressionRGB2Lab(r, g, b, sys -> LoTerms, &Lab)) return false;
+ }
+ else { /* At gamut hull boundaries */
+
+ if (!cmsxRegressionInterpolatorRGB(&sys -> hdr.m,
+ PT_Lab,
+ 10,
+ true,
+ 30,
+ r, g, b,
+ &Lab)) return false;
+ }
+
+
+ /* Regression CAN deliver wrong values. Clamp these. */
+ cmsClampLab(&Lab, 127.9961, -128, 127.9961, -128);
+
+ /* Normalize */
+ cmsLab2XYZ(cmsD50_XYZ(), &xyz, &Lab);
+ cmsxChromaticAdaptationAndNormalization(&sys->hdr, &xyz, false);
+ cmsXYZ2Lab(cmsD50_XYZ(), &Lab, &xyz);
+
+ /* Clamping again, adaptation could move slightly values */
+ cmsClampLab(&Lab, 127.9961, -128, 127.9961, -128);
+
+ /* To PCS encoding */
+ cmsFloat2LabEncoded(Out, &Lab);
+
+
+ return true; /* And done with success */
+}
+
+
+
+
+
+/* The sampler for XYZ */
+static
+int RegressionSamplerXYZ(WORD In[], WORD Out[], LPVOID Cargo)
+{
+ cmsCIEXYZ xyz;
+ double r, g, b;
+ LPSCANNERPROFILERDATA sys = (LPSCANNERPROFILERDATA) Cargo;
+ char code;
+
+ GetRGB(&sys -> hdr, In, &r, &g, &b);
+
+ code = cmsxHullCheckpoint(sys ->hdr.hRGBHull,
+ (int) floor(r + .5),
+ (int) floor(g + .5),
+ (int) floor(b + .5));
+
+ if (code == 'i') { /* Inside gamut */
+
+ if (!cmsxRegressionRGB2XYZ(r, g, b, sys -> HiTerms, &xyz)) return false;
+ }
+ else
+ if (!sys -> lLocalConvergenceExtrapolation && code == 'o') { /* outside gamut */
+
+ if (!cmsxRegressionRGB2XYZ(r, g, b, sys -> LoTerms, &xyz)) return false;
+ }
+
+ else { /* At gamut hull boundaries */
+
+ if (!cmsxRegressionInterpolatorRGB(&sys -> hdr.m,
+ PT_XYZ,
+ 10,
+ true,
+ 30,
+ r, g, b,
+ &xyz)) return false;
+ }
+
+
+ xyz.X /= 100.;
+ xyz.Y /= 100.;
+ xyz.Z /= 100.;
+
+ cmsxChromaticAdaptationAndNormalization(&sys->hdr, &xyz, false);
+
+ /* To PCS encoding. It also claps bad values */
+ cmsFloat2XYZEncoded(Out, &xyz);
+
+ return true; /* And done witch success */
+}
+
+
+
+/* The main scanner profiler */
+BOOL cmsxScannerProfilerDo(LPSCANNERPROFILERDATA sys)
+{
+
+ LPLUT AToB0;
+ DWORD dwNeedSamples;
+
+
+ if (!*sys -> hdr.OutputProfileFile)
+ return false;
+
+
+ if (!cmsxChoosePCS(&sys->hdr))
+ return false;
+
+ dwNeedSamples = PATCH_HAS_RGB;
+ if (sys ->hdr.PCSType == PT_Lab)
+ dwNeedSamples |= PATCH_HAS_Lab;
+ else
+ dwNeedSamples |= PATCH_HAS_XYZ;
+
+
+ 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 (!cmsxPCollBuildMeasurement(&sys->hdr.m,
+ sys->hdr.ReferenceSheet,
+ sys->hdr.MeasurementSheet,
+ dwNeedSamples)) return false;
+
+
+
+ sys->hdr.hProfile = cmsCreateRGBProfile(NULL, NULL, NULL);
+
+
+ cmsSetDeviceClass(sys->hdr.hProfile, sys->hdr.DeviceClass);
+ cmsSetColorSpace(sys->hdr.hProfile, sys->hdr.ColorSpace);
+ cmsSetPCS(sys->hdr. hProfile, _cmsICCcolorSpace(sys->hdr.PCSType));
+
+ /* Save char target tag */
+ if (sys->hdr.ProfileVerbosityLevel >= 2) {
+
+ cmsxEmbedCharTarget(&sys ->hdr);
+ }
+
+ AToB0 = cmsAllocLUT();
+
+ cmsAlloc3DGrid(AToB0, sys->hdr.CLUTPoints, 3, 3);
+
+ cmsxComputeLinearizationTables(&sys-> hdr.m,
+ sys -> hdr.PCSType,
+ sys -> Prelinearization,
+ 1024,
+ MEDIUM_REFLECTIVE_D50);
+
+ /* Refresh RGB of all patches. This converts all regression into */
+ /* near linear RGB->Lab or XYZ */
+
+ cmsxPCollLinearizePatches(&sys->hdr.m, sys -> hdr.m.Allowed, sys -> Prelinearization);
+
+ cmsxComputeGamutHull(&sys->hdr);
+ ComputeGlobalRegression(sys);
+
+ cmsAllocLinearTable(AToB0, sys -> Prelinearization, 1);
+
+ /* 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.;
+
+
+ sys->hdr.hDevice = cmsCIECAM97sInit(&sys->hdr.device);
+ sys->hdr.hPCS = cmsCIECAM97sInit(&sys->hdr.PCS);
+
+
+ if (sys -> hdr.PCSType == PT_Lab)
+ cmsSample3DGrid(AToB0, RegressionSamplerLab, sys, 0);
+ else
+ cmsSample3DGrid(AToB0, RegressionSamplerXYZ, sys, 0);
+
+ cmsCIECAM97sDone(sys->hdr.hDevice);
+ cmsCIECAM97sDone(sys->hdr.hPCS);
+
+ cmsAddTag(sys->hdr.hProfile, icSigAToB0Tag, AToB0);
+
+
+ cmsxEmbedTextualInfo(&sys -> hdr);
+
+ cmsAddTag(sys->hdr.hProfile, icSigMediaWhitePointTag, &sys->hdr.WhitePoint);
+ cmsAddTag(sys->hdr.hProfile, icSigMediaBlackPointTag, &sys->hdr.BlackPoint);
+
+
+ /* Save primaries & gamma curves */
+ if (sys->hdr.ProfileVerbosityLevel >= 1) {
+
+ cmsxEmbedMatrixShaper(&sys ->hdr);
+ }
+
+ _cmsSaveProfile(sys->hdr.hProfile, sys->hdr.OutputProfileFile);
+
+ cmsCloseProfile(sys->hdr.hProfile);
+ sys->hdr.hProfile = NULL;
+
+ cmsxPCollFreeMeasurements(&sys->hdr.m);
+
+ cmsFreeLUT(AToB0);
+
+ if (sys -> HiTerms)
+ MATNfree(sys -> HiTerms);
+ sys -> HiTerms = NULL;
+
+
+ if (sys -> LoTerms)
+ MATNfree(sys -> LoTerms);
+ sys -> LoTerms = NULL;
+
+
+
+ if (sys ->Prelinearization[0])
+ cmsFreeGammaTriple(sys -> Prelinearization);
+
+ if (sys ->hdr.Gamma)
+ cmsFreeGammaTriple(sys->hdr.Gamma);
+
+ return true;
+}