diff options
Diffstat (limited to 'digikam/libs/lprof/cmspcoll.cpp')
-rw-r--r-- | digikam/libs/lprof/cmspcoll.cpp | 1045 |
1 files changed, 1045 insertions, 0 deletions
diff --git a/digikam/libs/lprof/cmspcoll.cpp b/digikam/libs/lprof/cmspcoll.cpp new file mode 100644 index 00000000..3177e6b6 --- /dev/null +++ b/digikam/libs/lprof/cmspcoll.cpp @@ -0,0 +1,1045 @@ +/* */ +/* 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 02111-1307, 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" + + +/* ----------------------------------------------------------------- Patch collections */ + +BOOL cdecl cmsxPCollLoadFromSheet(LPMEASUREMENT m, LCMSHANDLE hSheet); + +BOOL cdecl cmsxPCollBuildMeasurement(LPMEASUREMENT m, + const char *ReferenceSheet, + const char *MeasurementSheet, + DWORD dwNeededSamplesType); + +LPPATCH cdecl cmsxPCollGetPatch(LPMEASUREMENT m, int n); + +LPPATCH cdecl cmsxPCollGetPatchByName(LPMEASUREMENT m, const char* Name, int* lpPos); +LPPATCH cdecl cmsxPCollGetPatchByPos(LPMEASUREMENT m, int row, int col); +LPPATCH cdecl cmsxPCollAddPatchRGB(LPMEASUREMENT m, const char *Name, + double r, double g, double b, + LPcmsCIEXYZ XYZ, LPcmsCIELab Lab); + +/* Sets of patches */ + +SETOFPATCHES cdecl cmsxPCollBuildSet(LPMEASUREMENT m, BOOL lDefault); +int cdecl cmsxPCollCountSet(LPMEASUREMENT m, SETOFPATCHES Set); +BOOL cdecl cmsxPCollValidatePatches(LPMEASUREMENT m, DWORD dwFlags); + + +/* Collect "need" patches of the specific kind, return the number of collected (that */ +/* could be less if set of patches is exhausted) */ + + +void cdecl cmsxPCollPatchesGS(LPMEASUREMENT m, SETOFPATCHES Result); + +int cdecl cmsxPCollPatchesNearRGB(LPMEASUREMENT m, SETOFPATCHES Valids, + double r, double g, double b, int need, SETOFPATCHES Result); + +int cdecl cmsxPCollPatchesNearNeutral(LPMEASUREMENT m, SETOFPATCHES Valids, + int need, SETOFPATCHES Result); + +int cdecl cmsxPCollPatchesNearPrimary(LPMEASUREMENT m, SETOFPATCHES Valids, + int nChannel, int need, SETOFPATCHES Result); + +int cdecl cmsxPCollPatchesInLabCube(LPMEASUREMENT m, SETOFPATCHES Valids, + double Lmin, double LMax, double a, double b, SETOFPATCHES Result); + +int cdecl cmsxPCollPatchesInGamutLUT(LPMEASUREMENT m, SETOFPATCHES Valids, + LPLUT Gamut, SETOFPATCHES Result); + +LPPATCH cdecl cmsxPCollFindWhite(LPMEASUREMENT m, SETOFPATCHES Valids, double* Distance); +LPPATCH cdecl cmsxPCollFindBlack(LPMEASUREMENT m, SETOFPATCHES Valids, double* Distance); +LPPATCH cdecl cmsxPCollFindPrimary(LPMEASUREMENT m, SETOFPATCHES Valids, int Channel, double* Distance); + + +/* ------------------------------------------------------------- Implementation */ + +#define IS(x) EqualsTo(c, x) + +/* A wrapper on stricmp() */ + +static +BOOL EqualsTo(const char* a, const char *b) +{ + return (stricmp(a, b) == 0); +} + + +/* Does return a bitwise mask holding the measurements contained in a Sheet */ + +static +DWORD MaskOfDataSet(LCMSHANDLE hSheet) +{ + char** Names; + int i, n; + DWORD dwMask = 0; + + n = cmsxIT8EnumDataFormat(hSheet, &Names); + + for (i=0; i < n; i++) { + + char *c = Names[i]; + + if (IS("RGB_R") || IS("RGB_G") || IS("RGB_B")) + dwMask |= PATCH_HAS_RGB; + else + if (IS("XYZ_X") || IS("XYZ_Y") || IS("XYZ_Z")) + dwMask |= PATCH_HAS_XYZ; + else + if (IS("LAB_L") || IS("LAB_A") ||IS("LAB_B")) + dwMask |= PATCH_HAS_Lab; + else + if (IS("STDEV_DE")) + dwMask |= PATCH_HAS_STD_DE; + } + + return dwMask; +} + + +/* Addition of a patch programatically */ + +LPPATCH cmsxPCollAddPatchRGB(LPMEASUREMENT m, const char *Name, + double r, double g, double b, + LPcmsCIEXYZ XYZ, LPcmsCIELab Lab) +{ + LPPATCH p; + + p = m->Patches + m->nPatches++; + + strcpy(p -> Name, Name); + + p -> Colorant.RGB[0] = r; + p -> Colorant.RGB[1] = g; + p -> Colorant.RGB[2] = b; + p -> dwFlags = PATCH_HAS_RGB; + + if (XYZ) { + + p -> XYZ = *XYZ; + p -> dwFlags |= PATCH_HAS_XYZ; + } + + if (Lab) { + p -> Lab = *Lab; + p -> dwFlags |= PATCH_HAS_Lab; + } + + + return p; +} + +/* Some vendors does store colorant data in a non-standard way, */ +/* i.e, from 0.0..1.0 or from 0.0..100.0 This routine tries to */ +/* detect such situations */ + +static +void NormalizeColorant(LPMEASUREMENT m) +{ + int i, j; + double MaxColorant=0; + double Normalize; + + + for (i=0; i < m -> nPatches; i++) { + + + LPPATCH p = m -> Patches + i; + + for (j=0; j < MAXCHANNELS; j++) { + if (p ->Colorant.Hexa[j] > MaxColorant) + MaxColorant = p ->Colorant.Hexa[j]; + } + } + + /* Ok, some heuristics */ + + if (MaxColorant < 2) + Normalize = 255.0; /* goes 0..1 */ + else + if (MaxColorant < 102) + Normalize = 2.55; /* goes 0..100 */ + else + if (MaxColorant > 300) + Normalize = (255.0 / 65535.0); /* Goes 0..65535.0 */ + else + return; /* Is ok */ + + + /* Rearrange patches */ + for (i=0; i < m -> nPatches; i++) { + + + LPPATCH p = m -> Patches + i; + for (j=0; j < MAXCHANNELS; j++) + p ->Colorant.Hexa[j] *= Normalize; + } + +} + + +/* Load a collection from a Sheet */ + +BOOL cmsxPCollLoadFromSheet(LPMEASUREMENT m, LCMSHANDLE hSheet) +{ + int i; + DWORD dwMask; + + + if (m -> nPatches == 0) { + + m -> nPatches = (int) cmsxIT8GetPropertyDbl(hSheet, "NUMBER_OF_SETS"); + m -> Patches = (PATCH*)calloc(m -> nPatches, sizeof(PATCH)); // C->C++ : cast + + if (m -> Patches == NULL) { + cmsxIT8Free(hSheet); + return false; + } + + for (i=0; i < m -> nPatches; i++) { + + LPPATCH p = m -> Patches + i; + p -> dwFlags = 0; + cmsxIT8GetPatchName(hSheet, i, p ->Name); + + } + + } + + + /* Build mask according to data format */ + + dwMask = MaskOfDataSet(hSheet); + + + /* Read items. Set flags accordly. */ + for (i = 0; i < m->nPatches; i++) { + + LPPATCH Patch = m -> Patches + i; + + /* Fill in data according to mask */ + + if (dwMask & PATCH_HAS_Lab) { + + if (cmsxIT8GetDataSetDbl(hSheet, Patch->Name, "LAB_L", &Patch -> Lab.L) && + cmsxIT8GetDataSetDbl(hSheet, Patch->Name, "LAB_A", &Patch -> Lab.a) && + cmsxIT8GetDataSetDbl(hSheet, Patch->Name, "LAB_B", &Patch -> Lab.b)) + + Patch -> dwFlags |= PATCH_HAS_Lab; + } + + if (dwMask & PATCH_HAS_XYZ) { + + if (cmsxIT8GetDataSetDbl(hSheet, Patch->Name, "XYZ_X", &Patch -> XYZ.X) && + cmsxIT8GetDataSetDbl(hSheet, Patch->Name, "XYZ_Y", &Patch -> XYZ.Y) && + cmsxIT8GetDataSetDbl(hSheet, Patch->Name, "XYZ_Z", &Patch -> XYZ.Z)) + + Patch -> dwFlags |= PATCH_HAS_XYZ; + + } + + if (dwMask & PATCH_HAS_RGB) { + + if (cmsxIT8GetDataSetDbl(hSheet, Patch->Name, "RGB_R", &Patch -> Colorant.RGB[0]) && + cmsxIT8GetDataSetDbl(hSheet, Patch->Name, "RGB_G", &Patch -> Colorant.RGB[1]) && + cmsxIT8GetDataSetDbl(hSheet, Patch->Name, "RGB_B", &Patch -> Colorant.RGB[2])) + + Patch -> dwFlags |= PATCH_HAS_RGB; + } + + if (dwMask & PATCH_HAS_STD_DE) { + + if (cmsxIT8GetDataSetDbl(hSheet, Patch->Name, "STDEV_DE", &Patch -> dEStd)) + + Patch -> dwFlags |= PATCH_HAS_STD_DE; + + } + + } + + NormalizeColorant(m); + return true; +} + + +/* Does save parameters to a empty sheet */ + +BOOL cmsxPCollSaveToSheet(LPMEASUREMENT m, LCMSHANDLE it8) +{ + int nNumberOfSets = cmsxPCollCountSet(m, m->Allowed); + int nNumberOfFields = 0; + DWORD dwMask = 0; + int i; + + /* Find mask of fields */ + for (i=0; i < m ->nPatches; i++) { + if (m ->Allowed[i]) { + + LPPATCH p = m ->Patches + i; + dwMask |= p ->dwFlags; + } + } + + nNumberOfFields = 1; /* SampleID */ + + if (dwMask & PATCH_HAS_RGB) + nNumberOfFields += 3; + + if (dwMask & PATCH_HAS_XYZ) + nNumberOfFields += 3; + + if (dwMask & PATCH_HAS_Lab) + nNumberOfFields += 3; + + + cmsxIT8SetPropertyDbl(it8, "NUMBER_OF_SETS", nNumberOfSets); + cmsxIT8SetPropertyDbl(it8, "NUMBER_OF_FIELDS", nNumberOfFields); + + nNumberOfFields = 0; + cmsxIT8SetDataFormat(it8, nNumberOfFields++, "SAMPLE_ID"); + + if (dwMask & PATCH_HAS_RGB) { + + cmsxIT8SetDataFormat(it8, nNumberOfFields++, "RGB_R"); + cmsxIT8SetDataFormat(it8, nNumberOfFields++, "RGB_G"); + cmsxIT8SetDataFormat(it8, nNumberOfFields++, "RGB_B"); + } + + if (dwMask & PATCH_HAS_XYZ) { + + cmsxIT8SetDataFormat(it8, nNumberOfFields++, "XYZ_X"); + cmsxIT8SetDataFormat(it8, nNumberOfFields++, "XYZ_Y"); + cmsxIT8SetDataFormat(it8, nNumberOfFields++, "XYZ_Z"); + + } + + + if (dwMask & PATCH_HAS_XYZ) { + + cmsxIT8SetDataFormat(it8, nNumberOfFields++, "LAB_L"); + cmsxIT8SetDataFormat(it8, nNumberOfFields++, "LAB_A"); + cmsxIT8SetDataFormat(it8, nNumberOfFields++, "LAB_B"); + + } + + for (i=0; i < m ->nPatches; i++) { + if (m ->Allowed[i]) { + + LPPATCH Patch = m ->Patches + i; + + cmsxIT8SetDataSet(it8, Patch->Name, "SAMPLE_ID", Patch->Name); + + if (dwMask & PATCH_HAS_RGB) { + cmsxIT8SetDataSetDbl(it8, Patch->Name, "RGB_R", Patch ->Colorant.RGB[0]); + cmsxIT8SetDataSetDbl(it8, Patch->Name, "RGB_G", Patch ->Colorant.RGB[1]); + cmsxIT8SetDataSetDbl(it8, Patch->Name, "RGB_B", Patch ->Colorant.RGB[2]); + } + + if (dwMask & PATCH_HAS_XYZ) { + cmsxIT8SetDataSetDbl(it8, Patch->Name, "XYZ_X", Patch ->XYZ.X); + cmsxIT8SetDataSetDbl(it8, Patch->Name, "XYZ_Y", Patch ->XYZ.Y); + cmsxIT8SetDataSetDbl(it8, Patch->Name, "XYZ_Z", Patch ->XYZ.Z); + } + + if (dwMask & PATCH_HAS_Lab) { + cmsxIT8SetDataSetDbl(it8, Patch->Name, "LAB_L", Patch ->Lab.L); + cmsxIT8SetDataSetDbl(it8, Patch->Name, "LAB_A", Patch ->Lab.a); + cmsxIT8SetDataSetDbl(it8, Patch->Name, "LAB_B", Patch ->Lab.b); + + } + } + } + + return true; +} + +static +void FixLabOnly(LPMEASUREMENT m) +{ + int i; + + for (i=0; i < m ->nPatches; i++) { + + LPPATCH p = m ->Patches + i; + if ((p ->dwFlags & PATCH_HAS_Lab) && + !(p ->dwFlags & PATCH_HAS_XYZ)) + { + cmsLab2XYZ(cmsD50_XYZ(), &p->XYZ, &p ->Lab); + + p ->XYZ.X *= 100.; + p ->XYZ.Y *= 100.; + p ->XYZ.Z *= 100.; + + p ->dwFlags |= PATCH_HAS_XYZ; + } + + } + +} + + +/* Higher level function. Does merge reference and measurement sheet into */ +/* a MEASUREMENT struct. Data to keep is described in dwNeededSamplesType */ +/* mask as follows: */ +/* */ +/* PATCH_HAS_Lab 0x00000001 */ +/* PATCH_HAS_XYZ 0x00000002 */ +/* PATCH_HAS_RGB 0x00000004 */ +/* PATCH_HAS_CMY 0x00000008 */ +/* PATCH_HAS_CMYK 0x00000010 */ +/* PATCH_HAS_HEXACRM 0x00000020 */ +/* PATCH_HAS_STD_Lab 0x00010000 */ +/* PATCH_HAS_STD_XYZ 0x00020000 */ +/* PATCH_HAS_STD_RGB 0x00040000 */ +/* PATCH_HAS_STD_CMY 0x00080000 */ +/* PATCH_HAS_STD_CMYK 0x00100000 */ +/* PATCH_HAS_STD_HEXACRM 0x00100000 */ +/* PATCH_HAS_MEAN_DE 0x01000000 */ +/* PATCH_HAS_STD_DE 0x02000000 */ +/* PATCH_HAS_CHISQ 0x04000000 */ +/* */ +/* See lprof.h for further info */ + + +BOOL cmsxPCollBuildMeasurement(LPMEASUREMENT m, + const char *ReferenceSheet, + const char *MeasurementSheet, + DWORD dwNeededSamplesType) +{ + LCMSHANDLE hSheet; + BOOL rc = true; + + ZeroMemory(m, sizeof(MEASUREMENT)); + + + if (ReferenceSheet != NULL && *ReferenceSheet) { + + hSheet = cmsxIT8LoadFromFile(ReferenceSheet); + if (hSheet == NULL) return false; + + rc = cmsxPCollLoadFromSheet(m, hSheet); + cmsxIT8Free(hSheet); + } + + if (!rc) return false; + + if (MeasurementSheet != NULL && *MeasurementSheet) { + + hSheet = cmsxIT8LoadFromFile(MeasurementSheet); + if (hSheet == NULL) return false; + + rc = cmsxPCollLoadFromSheet(m, hSheet); + cmsxIT8Free(hSheet); + } + + if (!rc) return false; + + + /* Fix up -- If only Lab is present, then compute */ + /* XYZ based on D50 */ + + FixLabOnly(m); + + cmsxPCollValidatePatches(m, dwNeededSamplesType); + return true; +} + + + +void cmsxPCollFreeMeasurements(LPMEASUREMENT m) +{ + if (m->Patches) + free(m->Patches); + + m->Patches = NULL; + m->nPatches = 0; + + if (m -> Allowed) + free(m -> Allowed); + +} + +/* Retrieval functions */ + +LPPATCH cmsxPCollGetPatchByName(LPMEASUREMENT m, const char* name, int* lpPos) +{ + int i; + for (i=0; i < m->nPatches; i++) + { + if (m -> Allowed) + if (!m -> Allowed[i]) + continue; + + if (EqualsTo(m->Patches[i].Name, name)) { + if (lpPos) *lpPos = i; + return m->Patches + i; + } + } + + return NULL; +} + + + + +/* -------------------------------------------------------------------- Sets */ + + +SETOFPATCHES cmsxPCollBuildSet(LPMEASUREMENT m, BOOL lDefault) +{ + SETOFPATCHES Full = (SETOFPATCHES) malloc(m -> nPatches * sizeof(BOOL)); + int i; + + for (i=0; i < m -> nPatches; i++) + Full[i] = lDefault; + + return Full; +} + +int cmsxPCollCountSet(LPMEASUREMENT m, SETOFPATCHES Set) +{ + int i, Count = 0; + + for (i = 0; i < m -> nPatches; i++) { + + if (Set[i]) + Count++; + } + + return Count; +} + + +/* Validate patches */ + +BOOL cmsxPCollValidatePatches(LPMEASUREMENT m, DWORD dwFlags) +{ + int i, n; + + if (m->Allowed) + free(m->Allowed); + + m -> Allowed = cmsxPCollBuildSet(m, true); + + /* Check for flags */ + for (i=n=0; i < m -> nPatches; i++) { + + LPPATCH p = m -> Patches + i; + m -> Allowed[i] = ((p -> dwFlags & dwFlags) == dwFlags); + + } + + return true; +} + + +/* Several filters */ + + +/* This filter does validate patches placed on 'radius' distance of a */ +/* device-color space. Currently only RGB is supported */ + +static +void PatchesByRGB(LPMEASUREMENT m, SETOFPATCHES Valids, + double R, double G, double B, double radius, SETOFPATCHES Result) +{ + int i; + double ra, rmax = sqrt(radius / 255.); + double dR, dG, dB; + LPPATCH p; + + for (i=0; i < m->nPatches; i++) { + + + if (Valids[i]) { + + p = m->Patches + i; + + dR = fabs(R - p -> Colorant.RGB[0]) / 255.; + dG = fabs(G - p -> Colorant.RGB[1]) / 255.; + dB = fabs(B - p -> Colorant.RGB[2]) / 255.; + + ra = sqrt(dR*dR + dG*dG + dB*dB); + + if (ra <= rmax) + Result[i] = true; + else + Result[i] = false; + + } + } + +} + + +/* This filter does validate patches placed at dEmax radius */ +/* in the device-independent side. */ + +static +void PatchesByLab(LPMEASUREMENT m, SETOFPATCHES Valids, + double L, double a, double b, double dEmax, SETOFPATCHES Result) +{ + int i; + double dE, dEMaxSQR = sqrt(dEmax); + double dL, da, db; + LPPATCH p; + + + for (i=0; i < m->nPatches; i++) { + + + if (Valids[i]) { + + p = m->Patches + i; + + dL = fabs(L - p -> Lab.L); + da = fabs(a - p -> Lab.a); + db = fabs(b - p -> Lab.b); + + dE = sqrt(dL*dL + da*da + db*db); + + if (dE <= dEMaxSQR) + Result[i] = true; + else + Result[i] = false; + } + } +} + + +/* Restrict Lab in a cube of variable sides. Quick and dirty out-of-gamut */ +/* stripper used in estimations. */ + +static +void PatchesInLabCube(LPMEASUREMENT m, SETOFPATCHES Valids, + double Lmin, double Lmax, double da, double db, SETOFPATCHES Result) +{ + int i; + + for (i=0; i < m -> nPatches; i++) { + + + if (Valids[i]) { + + LPPATCH p = m -> Patches + i; + + if ((p->Lab.L >= Lmin && p->Lab.L <= Lmax) && + (fabs(p -> Lab.a) < da) && + (fabs(p -> Lab.b) < db)) + + Result[i] = true; + else + Result[i] = false; + } + } + +} + +/* Restrict to low colorfullness */ + +static +void PatchesOfLowC(LPMEASUREMENT m, SETOFPATCHES Valids, + double Cmax, SETOFPATCHES Result) +{ + int i; + cmsCIELCh LCh; + + for (i=0; i < m -> nPatches; i++) { + + + if (Valids[i]) { + + LPPATCH p = m -> Patches + i; + + cmsLab2LCh(&LCh, &p->Lab); + + + if (LCh.C < Cmax) + Result[i] = true; + else + Result[i] = false; + } + } + +} + + + +/* Primary can be -1 for specifying device gray. Does return patches */ +/* on device-space Colorants. dEMax is the maximum allowed ratio */ + +static +void PatchesPrimary(LPMEASUREMENT m, SETOFPATCHES Valids, + int nColorant, double dEMax, SETOFPATCHES Result) +{ + int i, j; + double n, dE; + + for (i=0; i < m -> nPatches; i++) { + + + if (Valids[i]) { + + LPPATCH p = m -> Patches + i; + + + if (nColorant < 0) /* device-grey? */ + { + /* cross. */ + + double drg = fabs(p -> Colorant.RGB[0] - p -> Colorant.RGB[1]) / 255.; + double drb = fabs(p -> Colorant.RGB[0] - p -> Colorant.RGB[2]) / 255.; + double dbg = fabs(p -> Colorant.RGB[1] - p -> Colorant.RGB[2]) / 255.; + + dE = (drg*drg + drb*drb + dbg*dbg); + + + } + else { + dE = 0.; + for (j=0; j < 3; j++) { + + if (j != nColorant) { + + n = p -> Colorant.RGB[j] / 255.; + dE += (n * n); + + + } + } + } + + + + if (sqrt(dE) < dEMax) + Result[i] = true; + else + Result[i] = false; + } + } + +} + + +/* The high level extractors ----------------------------------------------------- */ + +int cmsxPCollPatchesNearRGB(LPMEASUREMENT m, SETOFPATCHES Valids, + double r, double g, double b, + int need, SETOFPATCHES Result) +{ + double radius; + int nCollected; + + /* Collect points inside of a sphere or radius 'radius' by RGB */ + + radius = 1; + do { + PatchesByRGB(m, Valids, r, g, b, radius, Result); + + nCollected = cmsxPCollCountSet(m, Result); + if (nCollected <= need) { + + radius += 1.0; + } + + } while (nCollected <= need && radius < 256.); + + return nCollected; /* Can be less than needed! */ +} + + +int cmsxPCollPatchesNearNeutral(LPMEASUREMENT m, SETOFPATCHES Valids, + int need, SETOFPATCHES Result) +{ + int nGrays; + double Cmax; + + Cmax = 1.; + do { + + + PatchesOfLowC(m, Valids, Cmax, Result); + + nGrays = cmsxPCollCountSet(m, Result); + if (nGrays <= need) { + + Cmax += .2; + } + + } while (nGrays <= need && Cmax < 10.); + + return nGrays; +} + + +int cmsxPCollPatchesInLabCube(LPMEASUREMENT m, SETOFPATCHES Valids, + double Lmin, double Lmax, double a, double b, + SETOFPATCHES Result) + + +{ + PatchesInLabCube(m, Valids, Lmin, Lmax, a, b, Result); + return cmsxPCollCountSet(m, Result); +} + + + + +int cmsxPCollPatchesNearPrimary(LPMEASUREMENT m, + SETOFPATCHES Valids, + int nChannel, + int need, + SETOFPATCHES Result) +{ + double radius; + int nCollected; + + /* Collect points inside of a sphere or radius 'radius' by RGB */ + + radius = 0.05; + do { + PatchesPrimary(m, Valids, nChannel, radius, Result); + + nCollected = cmsxPCollCountSet(m, Result); + if (nCollected <= need) { + + radius += 0.01; + } + + } while (nCollected <= need && radius < 256.); + + return nCollected; + +} + + +static +void AddOneGray(LPMEASUREMENT m, int n, SETOFPATCHES Grays) +{ + LPPATCH p; + char Buffer[cmsxIT8_GRAYCOLS]; + int pos; + + if (n == 0) strcpy(Buffer, "DMIN"); + else + if (n == cmsxIT8_GRAYCOLS - 1) strcpy(Buffer, "DMAX"); + else + sprintf(Buffer, "GS%d", n); + + p = cmsxPCollGetPatchByName(m, Buffer, &pos); + + if (p) + Grays[pos] = true; +} + + + +void cmsxPCollPatchesGS(LPMEASUREMENT m, SETOFPATCHES Result) +{ + + int i; + + for (i=0; i < cmsxIT8_GRAYCOLS; i++) + AddOneGray(m, i, Result); +} + + + +/* Refresh RGB of all patches after prelinearization */ + +void cmsxPCollLinearizePatches(LPMEASUREMENT m, SETOFPATCHES Valids, LPGAMMATABLE Gamma[3]) +{ + int i; + + for (i=0; i < m -> nPatches; i++) { + + if (Valids[i]) { + + LPPATCH p = m -> Patches + i; + + cmsxApplyLinearizationTable(p -> Colorant.RGB, Gamma, p -> Colorant.RGB); + } + } + +} + + +int cmsxPCollPatchesInGamutLUT(LPMEASUREMENT m, SETOFPATCHES Valids, + LPLUT Gamut, SETOFPATCHES Result) +{ + int i; + int nCollected = 0; + + for (i=0; i < m -> nPatches; i++) { + + if (Valids[i]) { + + LPPATCH p = m -> Patches + i; + WORD EncodedLab[3]; + WORD dE; + + cmsFloat2LabEncoded(EncodedLab, &p->Lab); + cmsEvalLUT(Gamut, EncodedLab, &dE); + Result[i] = (dE < 2) ? true : false; + if (Result[i]) nCollected++; + } + } + + return nCollected; +} + +LPPATCH cmsxPCollFindWhite(LPMEASUREMENT m, SETOFPATCHES Valids, double* TheDistance) +{ + int i; + LPPATCH Candidate = NULL; + double Distance, CandidateDistance = 255; + double dR, dG, dB; + + Candidate = cmsxPCollGetPatchByName(m, "DMIN", NULL); + if (Candidate) { + + if (TheDistance) *TheDistance = 0.0; + return Candidate; + } + + for (i=0; i < m -> nPatches; i++) { + + if (Valids[i]) { + + LPPATCH p = m -> Patches + i; + + dR = fabs(255.0 - p -> Colorant.RGB[0]) / 255.0; + dG = fabs(255.0 - p -> Colorant.RGB[1]) / 255.0; + dB = fabs(255.0 - p -> Colorant.RGB[2]) / 255.0; + + Distance = sqrt(dR*dR + dG*dG + dB*dB); + + if (Distance < CandidateDistance) { + Candidate = p; + CandidateDistance = Distance; + } + } + } + + if (TheDistance) + *TheDistance = floor(CandidateDistance * 255.0 + .5); + + return Candidate; +} + +LPPATCH cmsxPCollFindBlack(LPMEASUREMENT m, SETOFPATCHES Valids, double* TheDistance) +{ + int i; + LPPATCH Candidate = NULL; + double Distance, CandidateDistance = 255; + double dR, dG, dB; + + + Candidate = cmsxPCollGetPatchByName(m, "DMAX", NULL); + if (Candidate) { + + if (TheDistance) *TheDistance = 0.0; + return Candidate; + } + + for (i=0; i < m -> nPatches; i++) { + + if (Valids[i]) { + + LPPATCH p = m -> Patches + i; + + dR = (p -> Colorant.RGB[0]) / 255.0; + dG = (p -> Colorant.RGB[1]) / 255.0; + dB = (p -> Colorant.RGB[2]) / 255.0; + + Distance = sqrt(dR*dR + dG*dG + dB*dB); + + if (Distance < CandidateDistance) { + Candidate = p; + CandidateDistance = Distance; + } + } + } + + if (TheDistance) + *TheDistance = floor(CandidateDistance * 255.0 + .5); + + return Candidate; +} + + +LPPATCH cmsxPCollFindPrimary(LPMEASUREMENT m, SETOFPATCHES Valids, int Channel, double* TheDistance) +{ + int i; + LPPATCH Candidate = NULL; + double Distance, CandidateDistance = 255; + double dR, dG, dB; + const struct { + double r, g, b; + + } RGBPrimaries[3] = { + { 255.0, 0, 0}, + { 0, 255.0, 0}, + { 0, 0, 255 }}; + + + for (i=0; i < m -> nPatches; i++) { + + if (Valids[i]) { + + LPPATCH p = m -> Patches + i; + + dR = fabs(RGBPrimaries[Channel].r - p -> Colorant.RGB[0]) / 255.0; + dG = fabs(RGBPrimaries[Channel].g - p -> Colorant.RGB[1]) / 255.0; + dB = fabs(RGBPrimaries[Channel].b - p -> Colorant.RGB[2]) / 255.0; + + Distance = sqrt(dR*dR + dG*dG + dB*dB); + + if (Distance < CandidateDistance) { + Candidate = p; + CandidateDistance = Distance; + } + } + } + + if (TheDistance) + *TheDistance = floor(CandidateDistance * 255.0 + .5); + + return Candidate; +} |