2
/* Little cms - profiler construction set */
3
/* Copyright (C) 1998-2001 Marti Maria <marti@littlecms.com> */
5
/* THIS SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, */
6
/* EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY */
7
/* WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. */
9
/* IN NO EVENT SHALL MARTI MARIA BE LIABLE FOR ANY SPECIAL, INCIDENTAL, */
10
/* INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, */
11
/* OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, */
12
/* WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF */
13
/* LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE */
14
/* OF THIS SOFTWARE. */
16
/* This file is free software; you can redistribute it and/or modify it */
17
/* under the terms of the GNU General Public License as published by */
18
/* the Free Software Foundation; either version 2 of the License, or */
19
/* (at your option) any later version. */
21
/* This program is distributed in the hope that it will be useful, but */
22
/* WITHOUT ANY WARRANTY; without even the implied warranty of */
23
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU */
24
/* General Public License for more details. */
26
/* You should have received a copy of the GNU General Public License */
27
/* along with this program; if not, write to the Free Software */
28
/* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1307, USA. */
30
/* As a special exception to the GNU General Public License, if you */
31
/* distribute this file as part of a program that contains a */
32
/* configuration script generated by Autoconf, you may include it under */
33
/* the same distribution terms that you use for the rest of that program. */
41
/* ----------------------------------------------------------------- Patch collections */
43
BOOL cdecl cmsxPCollLoadFromSheet(LPMEASUREMENT m, LCMSHANDLE hSheet);
45
BOOL cdecl cmsxPCollBuildMeasurement(LPMEASUREMENT m,
46
const char *ReferenceSheet,
47
const char *MeasurementSheet,
48
DWORD dwNeededSamplesType);
50
LPPATCH cdecl cmsxPCollGetPatch(LPMEASUREMENT m, int n);
52
LPPATCH cdecl cmsxPCollGetPatchByName(LPMEASUREMENT m, const char* Name, int* lpPos);
53
LPPATCH cdecl cmsxPCollGetPatchByPos(LPMEASUREMENT m, int row, int col);
54
LPPATCH cdecl cmsxPCollAddPatchRGB(LPMEASUREMENT m, const char *Name,
55
double r, double g, double b,
56
LPcmsCIEXYZ XYZ, LPcmsCIELab Lab);
60
SETOFPATCHES cdecl cmsxPCollBuildSet(LPMEASUREMENT m, BOOL lDefault);
61
int cdecl cmsxPCollCountSet(LPMEASUREMENT m, SETOFPATCHES Set);
62
BOOL cdecl cmsxPCollValidatePatches(LPMEASUREMENT m, DWORD dwFlags);
65
/* Collect "need" patches of the specific kind, return the number of collected (that */
66
/* could be less if set of patches is exhausted) */
69
void cdecl cmsxPCollPatchesGS(LPMEASUREMENT m, SETOFPATCHES Result);
71
int cdecl cmsxPCollPatchesNearRGB(LPMEASUREMENT m, SETOFPATCHES Valids,
72
double r, double g, double b, int need, SETOFPATCHES Result);
74
int cdecl cmsxPCollPatchesNearNeutral(LPMEASUREMENT m, SETOFPATCHES Valids,
75
int need, SETOFPATCHES Result);
77
int cdecl cmsxPCollPatchesNearPrimary(LPMEASUREMENT m, SETOFPATCHES Valids,
78
int nChannel, int need, SETOFPATCHES Result);
80
int cdecl cmsxPCollPatchesInLabCube(LPMEASUREMENT m, SETOFPATCHES Valids,
81
double Lmin, double LMax, double a, double b, SETOFPATCHES Result);
83
int cdecl cmsxPCollPatchesInGamutLUT(LPMEASUREMENT m, SETOFPATCHES Valids,
84
LPLUT Gamut, SETOFPATCHES Result);
86
LPPATCH cdecl cmsxPCollFindWhite(LPMEASUREMENT m, SETOFPATCHES Valids, double* Distance);
87
LPPATCH cdecl cmsxPCollFindBlack(LPMEASUREMENT m, SETOFPATCHES Valids, double* Distance);
88
LPPATCH cdecl cmsxPCollFindPrimary(LPMEASUREMENT m, SETOFPATCHES Valids, int Channel, double* Distance);
91
/* ------------------------------------------------------------- Implementation */
93
#define IS(x) EqualsTo(c, x)
95
/* A wrapper on stricmp() */
98
BOOL EqualsTo(const char* a, const char *b)
100
return (stricmp(a, b) == 0);
104
/* Does return a bitwise mask holding the measurements contained in a Sheet */
107
DWORD MaskOfDataSet(LCMSHANDLE hSheet)
113
n = cmsxIT8EnumDataFormat(hSheet, &Names);
115
for (i=0; i < n; i++) {
119
if (IS("RGB_R") || IS("RGB_G") || IS("RGB_B"))
120
dwMask |= PATCH_HAS_RGB;
122
if (IS("XYZ_X") || IS("XYZ_Y") || IS("XYZ_Z"))
123
dwMask |= PATCH_HAS_XYZ;
125
if (IS("LAB_L") || IS("LAB_A") ||IS("LAB_B"))
126
dwMask |= PATCH_HAS_Lab;
129
dwMask |= PATCH_HAS_STD_DE;
136
/* Addition of a patch programatically */
138
LPPATCH cmsxPCollAddPatchRGB(LPMEASUREMENT m, const char *Name,
139
double r, double g, double b,
140
LPcmsCIEXYZ XYZ, LPcmsCIELab Lab)
144
p = m->Patches + m->nPatches++;
146
strcpy(p -> Name, Name);
148
p -> Colorant.RGB[0] = r;
149
p -> Colorant.RGB[1] = g;
150
p -> Colorant.RGB[2] = b;
151
p -> dwFlags = PATCH_HAS_RGB;
156
p -> dwFlags |= PATCH_HAS_XYZ;
161
p -> dwFlags |= PATCH_HAS_Lab;
168
/* Some vendors does store colorant data in a non-standard way, */
169
/* i.e, from 0.0..1.0 or from 0.0..100.0 This routine tries to */
170
/* detect such situations */
173
void NormalizeColorant(LPMEASUREMENT m)
176
double MaxColorant=0;
180
for (i=0; i < m -> nPatches; i++) {
183
LPPATCH p = m -> Patches + i;
185
for (j=0; j < MAXCHANNELS; j++) {
186
if (p ->Colorant.Hexa[j] > MaxColorant)
187
MaxColorant = p ->Colorant.Hexa[j];
191
/* Ok, some heuristics */
194
Normalize = 255.0; /* goes 0..1 */
196
if (MaxColorant < 102)
197
Normalize = 2.55; /* goes 0..100 */
199
if (MaxColorant > 300)
200
Normalize = (255.0 / 65535.0); /* Goes 0..65535.0 */
205
/* Rearrange patches */
206
for (i=0; i < m -> nPatches; i++) {
209
LPPATCH p = m -> Patches + i;
210
for (j=0; j < MAXCHANNELS; j++)
211
p ->Colorant.Hexa[j] *= Normalize;
217
/* Load a collection from a Sheet */
219
BOOL cmsxPCollLoadFromSheet(LPMEASUREMENT m, LCMSHANDLE hSheet)
225
if (m -> nPatches == 0) {
227
m -> nPatches = (int) cmsxIT8GetPropertyDbl(hSheet, "NUMBER_OF_SETS");
228
m -> Patches = (PATCH*)calloc(m -> nPatches, sizeof(PATCH)); // C->C++ : cast
230
if (m -> Patches == NULL) {
235
for (i=0; i < m -> nPatches; i++) {
237
LPPATCH p = m -> Patches + i;
239
cmsxIT8GetPatchName(hSheet, i, p ->Name);
246
/* Build mask according to data format */
248
dwMask = MaskOfDataSet(hSheet);
251
/* Read items. Set flags accordly. */
252
for (i = 0; i < m->nPatches; i++) {
254
LPPATCH Patch = m -> Patches + i;
256
/* Fill in data according to mask */
258
if (dwMask & PATCH_HAS_Lab) {
260
if (cmsxIT8GetDataSetDbl(hSheet, Patch->Name, "LAB_L", &Patch -> Lab.L) &&
261
cmsxIT8GetDataSetDbl(hSheet, Patch->Name, "LAB_A", &Patch -> Lab.a) &&
262
cmsxIT8GetDataSetDbl(hSheet, Patch->Name, "LAB_B", &Patch -> Lab.b))
264
Patch -> dwFlags |= PATCH_HAS_Lab;
267
if (dwMask & PATCH_HAS_XYZ) {
269
if (cmsxIT8GetDataSetDbl(hSheet, Patch->Name, "XYZ_X", &Patch -> XYZ.X) &&
270
cmsxIT8GetDataSetDbl(hSheet, Patch->Name, "XYZ_Y", &Patch -> XYZ.Y) &&
271
cmsxIT8GetDataSetDbl(hSheet, Patch->Name, "XYZ_Z", &Patch -> XYZ.Z))
273
Patch -> dwFlags |= PATCH_HAS_XYZ;
277
if (dwMask & PATCH_HAS_RGB) {
279
if (cmsxIT8GetDataSetDbl(hSheet, Patch->Name, "RGB_R", &Patch -> Colorant.RGB[0]) &&
280
cmsxIT8GetDataSetDbl(hSheet, Patch->Name, "RGB_G", &Patch -> Colorant.RGB[1]) &&
281
cmsxIT8GetDataSetDbl(hSheet, Patch->Name, "RGB_B", &Patch -> Colorant.RGB[2]))
283
Patch -> dwFlags |= PATCH_HAS_RGB;
286
if (dwMask & PATCH_HAS_STD_DE) {
288
if (cmsxIT8GetDataSetDbl(hSheet, Patch->Name, "STDEV_DE", &Patch -> dEStd))
290
Patch -> dwFlags |= PATCH_HAS_STD_DE;
296
NormalizeColorant(m);
301
/* Does save parameters to a empty sheet */
303
BOOL cmsxPCollSaveToSheet(LPMEASUREMENT m, LCMSHANDLE it8)
305
int nNumberOfSets = cmsxPCollCountSet(m, m->Allowed);
306
int nNumberOfFields = 0;
310
/* Find mask of fields */
311
for (i=0; i < m ->nPatches; i++) {
312
if (m ->Allowed[i]) {
314
LPPATCH p = m ->Patches + i;
315
dwMask |= p ->dwFlags;
319
nNumberOfFields = 1; /* SampleID */
321
if (dwMask & PATCH_HAS_RGB)
322
nNumberOfFields += 3;
324
if (dwMask & PATCH_HAS_XYZ)
325
nNumberOfFields += 3;
327
if (dwMask & PATCH_HAS_Lab)
328
nNumberOfFields += 3;
331
cmsxIT8SetPropertyDbl(it8, "NUMBER_OF_SETS", nNumberOfSets);
332
cmsxIT8SetPropertyDbl(it8, "NUMBER_OF_FIELDS", nNumberOfFields);
335
cmsxIT8SetDataFormat(it8, nNumberOfFields++, "SAMPLE_ID");
337
if (dwMask & PATCH_HAS_RGB) {
339
cmsxIT8SetDataFormat(it8, nNumberOfFields++, "RGB_R");
340
cmsxIT8SetDataFormat(it8, nNumberOfFields++, "RGB_G");
341
cmsxIT8SetDataFormat(it8, nNumberOfFields++, "RGB_B");
344
if (dwMask & PATCH_HAS_XYZ) {
346
cmsxIT8SetDataFormat(it8, nNumberOfFields++, "XYZ_X");
347
cmsxIT8SetDataFormat(it8, nNumberOfFields++, "XYZ_Y");
348
cmsxIT8SetDataFormat(it8, nNumberOfFields++, "XYZ_Z");
353
if (dwMask & PATCH_HAS_XYZ) {
355
cmsxIT8SetDataFormat(it8, nNumberOfFields++, "LAB_L");
356
cmsxIT8SetDataFormat(it8, nNumberOfFields++, "LAB_A");
357
cmsxIT8SetDataFormat(it8, nNumberOfFields++, "LAB_B");
361
for (i=0; i < m ->nPatches; i++) {
362
if (m ->Allowed[i]) {
364
LPPATCH Patch = m ->Patches + i;
366
cmsxIT8SetDataSet(it8, Patch->Name, "SAMPLE_ID", Patch->Name);
368
if (dwMask & PATCH_HAS_RGB) {
369
cmsxIT8SetDataSetDbl(it8, Patch->Name, "RGB_R", Patch ->Colorant.RGB[0]);
370
cmsxIT8SetDataSetDbl(it8, Patch->Name, "RGB_G", Patch ->Colorant.RGB[1]);
371
cmsxIT8SetDataSetDbl(it8, Patch->Name, "RGB_B", Patch ->Colorant.RGB[2]);
374
if (dwMask & PATCH_HAS_XYZ) {
375
cmsxIT8SetDataSetDbl(it8, Patch->Name, "XYZ_X", Patch ->XYZ.X);
376
cmsxIT8SetDataSetDbl(it8, Patch->Name, "XYZ_Y", Patch ->XYZ.Y);
377
cmsxIT8SetDataSetDbl(it8, Patch->Name, "XYZ_Z", Patch ->XYZ.Z);
380
if (dwMask & PATCH_HAS_Lab) {
381
cmsxIT8SetDataSetDbl(it8, Patch->Name, "LAB_L", Patch ->Lab.L);
382
cmsxIT8SetDataSetDbl(it8, Patch->Name, "LAB_A", Patch ->Lab.a);
383
cmsxIT8SetDataSetDbl(it8, Patch->Name, "LAB_B", Patch ->Lab.b);
393
void FixLabOnly(LPMEASUREMENT m)
397
for (i=0; i < m ->nPatches; i++) {
399
LPPATCH p = m ->Patches + i;
400
if ((p ->dwFlags & PATCH_HAS_Lab) &&
401
!(p ->dwFlags & PATCH_HAS_XYZ))
403
cmsLab2XYZ(cmsD50_XYZ(), &p->XYZ, &p ->Lab);
409
p ->dwFlags |= PATCH_HAS_XYZ;
417
/* Higher level function. Does merge reference and measurement sheet into */
418
/* a MEASUREMENT struct. Data to keep is described in dwNeededSamplesType */
419
/* mask as follows: */
421
/* PATCH_HAS_Lab 0x00000001 */
422
/* PATCH_HAS_XYZ 0x00000002 */
423
/* PATCH_HAS_RGB 0x00000004 */
424
/* PATCH_HAS_CMY 0x00000008 */
425
/* PATCH_HAS_CMYK 0x00000010 */
426
/* PATCH_HAS_HEXACRM 0x00000020 */
427
/* PATCH_HAS_STD_Lab 0x00010000 */
428
/* PATCH_HAS_STD_XYZ 0x00020000 */
429
/* PATCH_HAS_STD_RGB 0x00040000 */
430
/* PATCH_HAS_STD_CMY 0x00080000 */
431
/* PATCH_HAS_STD_CMYK 0x00100000 */
432
/* PATCH_HAS_STD_HEXACRM 0x00100000 */
433
/* PATCH_HAS_MEAN_DE 0x01000000 */
434
/* PATCH_HAS_STD_DE 0x02000000 */
435
/* PATCH_HAS_CHISQ 0x04000000 */
437
/* See lprof.h for further info */
440
BOOL cmsxPCollBuildMeasurement(LPMEASUREMENT m,
441
const char *ReferenceSheet,
442
const char *MeasurementSheet,
443
DWORD dwNeededSamplesType)
448
ZeroMemory(m, sizeof(MEASUREMENT));
451
if (ReferenceSheet != NULL && *ReferenceSheet) {
453
hSheet = cmsxIT8LoadFromFile(ReferenceSheet);
454
if (hSheet == NULL) return false;
456
rc = cmsxPCollLoadFromSheet(m, hSheet);
460
if (!rc) return false;
462
if (MeasurementSheet != NULL && *MeasurementSheet) {
464
hSheet = cmsxIT8LoadFromFile(MeasurementSheet);
465
if (hSheet == NULL) return false;
467
rc = cmsxPCollLoadFromSheet(m, hSheet);
471
if (!rc) return false;
474
/* Fix up -- If only Lab is present, then compute */
475
/* XYZ based on D50 */
479
cmsxPCollValidatePatches(m, dwNeededSamplesType);
485
void cmsxPCollFreeMeasurements(LPMEASUREMENT m)
498
/* Retrieval functions */
500
LPPATCH cmsxPCollGetPatchByName(LPMEASUREMENT m, const char* name, int* lpPos)
503
for (i=0; i < m->nPatches; i++)
506
if (!m -> Allowed[i])
509
if (EqualsTo(m->Patches[i].Name, name)) {
510
if (lpPos) *lpPos = i;
511
return m->Patches + i;
521
/* -------------------------------------------------------------------- Sets */
524
SETOFPATCHES cmsxPCollBuildSet(LPMEASUREMENT m, BOOL lDefault)
526
SETOFPATCHES Full = (SETOFPATCHES) malloc(m -> nPatches * sizeof(BOOL));
529
for (i=0; i < m -> nPatches; i++)
535
int cmsxPCollCountSet(LPMEASUREMENT m, SETOFPATCHES Set)
539
for (i = 0; i < m -> nPatches; i++) {
549
/* Validate patches */
551
BOOL cmsxPCollValidatePatches(LPMEASUREMENT m, DWORD dwFlags)
558
m -> Allowed = cmsxPCollBuildSet(m, true);
560
/* Check for flags */
561
for (i=n=0; i < m -> nPatches; i++) {
563
LPPATCH p = m -> Patches + i;
564
m -> Allowed[i] = ((p -> dwFlags & dwFlags) == dwFlags);
572
/* Several filters */
575
/* This filter does validate patches placed on 'radius' distance of a */
576
/* device-color space. Currently only RGB is supported */
579
void PatchesByRGB(LPMEASUREMENT m, SETOFPATCHES Valids,
580
double R, double G, double B, double radius, SETOFPATCHES Result)
583
double ra, rmax = sqrt(radius / 255.);
587
for (i=0; i < m->nPatches; i++) {
594
dR = fabs(R - p -> Colorant.RGB[0]) / 255.;
595
dG = fabs(G - p -> Colorant.RGB[1]) / 255.;
596
dB = fabs(B - p -> Colorant.RGB[2]) / 255.;
598
ra = sqrt(dR*dR + dG*dG + dB*dB);
611
/* This filter does validate patches placed at dEmax radius */
612
/* in the device-independent side. */
615
void PatchesByLab(LPMEASUREMENT m, SETOFPATCHES Valids,
616
double L, double a, double b, double dEmax, SETOFPATCHES Result)
619
double dE, dEMaxSQR = sqrt(dEmax);
624
for (i=0; i < m->nPatches; i++) {
631
dL = fabs(L - p -> Lab.L);
632
da = fabs(a - p -> Lab.a);
633
db = fabs(b - p -> Lab.b);
635
dE = sqrt(dL*dL + da*da + db*db);
646
/* Restrict Lab in a cube of variable sides. Quick and dirty out-of-gamut */
647
/* stripper used in estimations. */
650
void PatchesInLabCube(LPMEASUREMENT m, SETOFPATCHES Valids,
651
double Lmin, double Lmax, double da, double db, SETOFPATCHES Result)
655
for (i=0; i < m -> nPatches; i++) {
660
LPPATCH p = m -> Patches + i;
662
if ((p->Lab.L >= Lmin && p->Lab.L <= Lmax) &&
663
(fabs(p -> Lab.a) < da) &&
664
(fabs(p -> Lab.b) < db))
674
/* Restrict to low colorfullness */
677
void PatchesOfLowC(LPMEASUREMENT m, SETOFPATCHES Valids,
678
double Cmax, SETOFPATCHES Result)
683
for (i=0; i < m -> nPatches; i++) {
688
LPPATCH p = m -> Patches + i;
690
cmsLab2LCh(&LCh, &p->Lab);
704
/* Primary can be -1 for specifying device gray. Does return patches */
705
/* on device-space Colorants. dEMax is the maximum allowed ratio */
708
void PatchesPrimary(LPMEASUREMENT m, SETOFPATCHES Valids,
709
int nColorant, double dEMax, SETOFPATCHES Result)
714
for (i=0; i < m -> nPatches; i++) {
719
LPPATCH p = m -> Patches + i;
722
if (nColorant < 0) /* device-grey? */
726
double drg = fabs(p -> Colorant.RGB[0] - p -> Colorant.RGB[1]) / 255.;
727
double drb = fabs(p -> Colorant.RGB[0] - p -> Colorant.RGB[2]) / 255.;
728
double dbg = fabs(p -> Colorant.RGB[1] - p -> Colorant.RGB[2]) / 255.;
730
dE = (drg*drg + drb*drb + dbg*dbg);
736
for (j=0; j < 3; j++) {
738
if (j != nColorant) {
740
n = p -> Colorant.RGB[j] / 255.;
750
if (sqrt(dE) < dEMax)
760
/* The high level extractors ----------------------------------------------------- */
762
int cmsxPCollPatchesNearRGB(LPMEASUREMENT m, SETOFPATCHES Valids,
763
double r, double g, double b,
764
int need, SETOFPATCHES Result)
769
/* Collect points inside of a sphere or radius 'radius' by RGB */
773
PatchesByRGB(m, Valids, r, g, b, radius, Result);
775
nCollected = cmsxPCollCountSet(m, Result);
776
if (nCollected <= need) {
781
} while (nCollected <= need && radius < 256.);
783
return nCollected; /* Can be less than needed! */
787
int cmsxPCollPatchesNearNeutral(LPMEASUREMENT m, SETOFPATCHES Valids,
788
int need, SETOFPATCHES Result)
797
PatchesOfLowC(m, Valids, Cmax, Result);
799
nGrays = cmsxPCollCountSet(m, Result);
800
if (nGrays <= need) {
805
} while (nGrays <= need && Cmax < 10.);
811
int cmsxPCollPatchesInLabCube(LPMEASUREMENT m, SETOFPATCHES Valids,
812
double Lmin, double Lmax, double a, double b,
817
PatchesInLabCube(m, Valids, Lmin, Lmax, a, b, Result);
818
return cmsxPCollCountSet(m, Result);
824
int cmsxPCollPatchesNearPrimary(LPMEASUREMENT m,
833
/* Collect points inside of a sphere or radius 'radius' by RGB */
837
PatchesPrimary(m, Valids, nChannel, radius, Result);
839
nCollected = cmsxPCollCountSet(m, Result);
840
if (nCollected <= need) {
845
} while (nCollected <= need && radius < 256.);
853
void AddOneGray(LPMEASUREMENT m, int n, SETOFPATCHES Grays)
856
char Buffer[cmsxIT8_GRAYCOLS];
859
if (n == 0) strcpy(Buffer, "DMIN");
861
if (n == cmsxIT8_GRAYCOLS - 1) strcpy(Buffer, "DMAX");
863
sprintf(Buffer, "GS%d", n);
865
p = cmsxPCollGetPatchByName(m, Buffer, &pos);
873
void cmsxPCollPatchesGS(LPMEASUREMENT m, SETOFPATCHES Result)
878
for (i=0; i < cmsxIT8_GRAYCOLS; i++)
879
AddOneGray(m, i, Result);
884
/* Refresh RGB of all patches after prelinearization */
886
void cmsxPCollLinearizePatches(LPMEASUREMENT m, SETOFPATCHES Valids, LPGAMMATABLE Gamma[3])
890
for (i=0; i < m -> nPatches; i++) {
894
LPPATCH p = m -> Patches + i;
896
cmsxApplyLinearizationTable(p -> Colorant.RGB, Gamma, p -> Colorant.RGB);
903
int cmsxPCollPatchesInGamutLUT(LPMEASUREMENT m, SETOFPATCHES Valids,
904
LPLUT Gamut, SETOFPATCHES Result)
909
for (i=0; i < m -> nPatches; i++) {
913
LPPATCH p = m -> Patches + i;
917
cmsFloat2LabEncoded(EncodedLab, &p->Lab);
918
cmsEvalLUT(Gamut, EncodedLab, &dE);
919
Result[i] = (dE < 2) ? true : false;
920
if (Result[i]) nCollected++;
927
LPPATCH cmsxPCollFindWhite(LPMEASUREMENT m, SETOFPATCHES Valids, double* TheDistance)
930
LPPATCH Candidate = NULL;
931
double Distance, CandidateDistance = 255;
934
Candidate = cmsxPCollGetPatchByName(m, "DMIN", NULL);
937
if (TheDistance) *TheDistance = 0.0;
941
for (i=0; i < m -> nPatches; i++) {
945
LPPATCH p = m -> Patches + i;
947
dR = fabs(255.0 - p -> Colorant.RGB[0]) / 255.0;
948
dG = fabs(255.0 - p -> Colorant.RGB[1]) / 255.0;
949
dB = fabs(255.0 - p -> Colorant.RGB[2]) / 255.0;
951
Distance = sqrt(dR*dR + dG*dG + dB*dB);
953
if (Distance < CandidateDistance) {
955
CandidateDistance = Distance;
961
*TheDistance = floor(CandidateDistance * 255.0 + .5);
966
LPPATCH cmsxPCollFindBlack(LPMEASUREMENT m, SETOFPATCHES Valids, double* TheDistance)
969
LPPATCH Candidate = NULL;
970
double Distance, CandidateDistance = 255;
974
Candidate = cmsxPCollGetPatchByName(m, "DMAX", NULL);
977
if (TheDistance) *TheDistance = 0.0;
981
for (i=0; i < m -> nPatches; i++) {
985
LPPATCH p = m -> Patches + i;
987
dR = (p -> Colorant.RGB[0]) / 255.0;
988
dG = (p -> Colorant.RGB[1]) / 255.0;
989
dB = (p -> Colorant.RGB[2]) / 255.0;
991
Distance = sqrt(dR*dR + dG*dG + dB*dB);
993
if (Distance < CandidateDistance) {
995
CandidateDistance = Distance;
1001
*TheDistance = floor(CandidateDistance * 255.0 + .5);
1007
LPPATCH cmsxPCollFindPrimary(LPMEASUREMENT m, SETOFPATCHES Valids, int Channel, double* TheDistance)
1010
LPPATCH Candidate = NULL;
1011
double Distance, CandidateDistance = 255;
1016
} RGBPrimaries[3] = {
1022
for (i=0; i < m -> nPatches; i++) {
1026
LPPATCH p = m -> Patches + i;
1028
dR = fabs(RGBPrimaries[Channel].r - p -> Colorant.RGB[0]) / 255.0;
1029
dG = fabs(RGBPrimaries[Channel].g - p -> Colorant.RGB[1]) / 255.0;
1030
dB = fabs(RGBPrimaries[Channel].b - p -> Colorant.RGB[2]) / 255.0;
1032
Distance = sqrt(dR*dR + dG*dG + dB*dB);
1034
if (Distance < CandidateDistance) {
1036
CandidateDistance = Distance;
1042
*TheDistance = floor(CandidateDistance * 255.0 + .5);