~ubuntu-branches/ubuntu/intrepid/digikam/intrepid

« back to all changes in this revision

Viewing changes to digikam/libs/lprof/cmspcoll.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Mark Purcell
  • Date: 2008-07-17 20:25:39 UTC
  • mfrom: (1.3.2 upstream) (37 hardy)
  • mto: This revision was merged to the branch mainline in revision 39.
  • Revision ID: james.westby@ubuntu.com-20080717202539-1bw3w3nrsso7yj4z
* New upstream release
  - digiKam 0.9.4 Release Plan (KDE3) ~ 13 July 08 (Closes: #490144)
* DEB_CONFIGURE_EXTRA_FLAGS := --without-included-sqlite3
* Debhelper compatibility level V7
* Install pixmaps in debian/*.install
* Add debian/digikam.lintian-overrides

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* */
 
2
/*  Little cms - profiler construction set */
 
3
/*  Copyright (C) 1998-2001 Marti Maria <marti@littlecms.com> */
 
4
/* */
 
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. */
 
8
/* */
 
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. */
 
15
/* */
 
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. */
 
20
/* */
 
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. */
 
25
/* */
 
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. */
 
29
/* */
 
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. */
 
34
/* */
 
35
/* Version 1.08a */
 
36
 
 
37
 
 
38
#include "lcmsprf.h"
 
39
 
 
40
 
 
41
/* ----------------------------------------------------------------- Patch collections */
 
42
 
 
43
BOOL        cdecl cmsxPCollLoadFromSheet(LPMEASUREMENT m, LCMSHANDLE hSheet);
 
44
 
 
45
BOOL        cdecl cmsxPCollBuildMeasurement(LPMEASUREMENT m, 
 
46
                                            const char *ReferenceSheet,
 
47
                                            const char *MeasurementSheet,
 
48
                                            DWORD dwNeededSamplesType);
 
49
 
 
50
LPPATCH     cdecl cmsxPCollGetPatch(LPMEASUREMENT m, int n);
 
51
 
 
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);
 
57
 
 
58
/* Sets of patches */
 
59
 
 
60
SETOFPATCHES cdecl cmsxPCollBuildSet(LPMEASUREMENT m, BOOL lDefault);
 
61
int          cdecl cmsxPCollCountSet(LPMEASUREMENT m, SETOFPATCHES Set);
 
62
BOOL         cdecl cmsxPCollValidatePatches(LPMEASUREMENT m, DWORD dwFlags);
 
63
 
 
64
 
 
65
/* Collect "need" patches of the specific kind, return the number of collected (that */
 
66
/* could be less if set of patches is exhausted) */
 
67
 
 
68
 
 
69
void         cdecl cmsxPCollPatchesGS(LPMEASUREMENT m, SETOFPATCHES Result);
 
70
 
 
71
int          cdecl cmsxPCollPatchesNearRGB(LPMEASUREMENT m, SETOFPATCHES Valids,
 
72
                                            double r, double g, double b, int need, SETOFPATCHES Result);
 
73
 
 
74
int          cdecl cmsxPCollPatchesNearNeutral(LPMEASUREMENT m, SETOFPATCHES Valids,
 
75
                                            int need, SETOFPATCHES Result);
 
76
 
 
77
int          cdecl cmsxPCollPatchesNearPrimary(LPMEASUREMENT m, SETOFPATCHES Valids,
 
78
                                           int nChannel, int need, SETOFPATCHES Result);
 
79
 
 
80
int          cdecl cmsxPCollPatchesInLabCube(LPMEASUREMENT m, SETOFPATCHES Valids, 
 
81
                                           double Lmin, double LMax, double a, double b, SETOFPATCHES Result);
 
82
 
 
83
int          cdecl cmsxPCollPatchesInGamutLUT(LPMEASUREMENT m, SETOFPATCHES Valids, 
 
84
                                                                                          LPLUT Gamut, SETOFPATCHES Result);
 
85
 
 
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);
 
89
 
 
90
 
 
91
/* ------------------------------------------------------------- Implementation */
 
92
 
 
93
#define IS(x)   EqualsTo(c, x)
 
94
 
 
95
/* A wrapper on stricmp() */
 
96
 
 
97
static
 
98
BOOL EqualsTo(const char* a, const char *b)
 
99
{
 
100
        return (stricmp(a, b) == 0);
 
101
}
 
102
 
 
103
 
 
104
/* Does return a bitwise mask holding the measurements contained in a Sheet */
 
105
 
 
106
static
 
107
DWORD MaskOfDataSet(LCMSHANDLE hSheet)
 
108
{
 
109
        char** Names;
 
110
        int i, n;
 
111
        DWORD dwMask = 0;
 
112
 
 
113
        n = cmsxIT8EnumDataFormat(hSheet, &Names);
 
114
 
 
115
        for (i=0; i < n; i++) {
 
116
 
 
117
                char *c = Names[i];
 
118
 
 
119
                if (IS("RGB_R") || IS("RGB_G") || IS("RGB_B"))
 
120
                                dwMask |= PATCH_HAS_RGB;
 
121
                else
 
122
                if (IS("XYZ_X") || IS("XYZ_Y") || IS("XYZ_Z"))
 
123
                                dwMask |= PATCH_HAS_XYZ;
 
124
                else
 
125
                if (IS("LAB_L") || IS("LAB_A") ||IS("LAB_B"))
 
126
                                dwMask |= PATCH_HAS_Lab;
 
127
                else
 
128
                if (IS("STDEV_DE"))
 
129
                    dwMask |= PATCH_HAS_STD_DE;
 
130
        }
 
131
 
 
132
        return dwMask;
 
133
}
 
134
 
 
135
 
 
136
/* Addition of a patch programatically */
 
137
 
 
138
LPPATCH cmsxPCollAddPatchRGB(LPMEASUREMENT m, const char *Name,
 
139
                        double r, double g, double b,
 
140
                        LPcmsCIEXYZ XYZ, LPcmsCIELab Lab)
 
141
{
 
142
        LPPATCH p;
 
143
 
 
144
        p = m->Patches + m->nPatches++;
 
145
 
 
146
        strcpy(p -> Name, Name);
 
147
 
 
148
        p -> Colorant.RGB[0] = r;
 
149
        p -> Colorant.RGB[1] = g;
 
150
        p -> Colorant.RGB[2] = b;
 
151
        p -> dwFlags = PATCH_HAS_RGB;
 
152
 
 
153
        if (XYZ) {
 
154
 
 
155
                p -> XYZ = *XYZ;
 
156
                p -> dwFlags |= PATCH_HAS_XYZ;
 
157
        }
 
158
 
 
159
        if (Lab) {
 
160
                p -> Lab = *Lab;
 
161
                p -> dwFlags |= PATCH_HAS_Lab;
 
162
        }
 
163
 
 
164
        
 
165
        return p;
 
166
}
 
167
 
 
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 */
 
171
 
 
172
static 
 
173
void NormalizeColorant(LPMEASUREMENT m)
 
174
{
 
175
        int i, j;
 
176
        double MaxColorant=0;
 
177
        double Normalize;
 
178
 
 
179
        
 
180
        for (i=0; i < m -> nPatches; i++) {
 
181
 
 
182
 
 
183
           LPPATCH p = m -> Patches + i;
 
184
                        
 
185
                   for (j=0; j < MAXCHANNELS; j++) {
 
186
                                                if (p ->Colorant.Hexa[j] > MaxColorant)
 
187
                                                                MaxColorant = p ->Colorant.Hexa[j];
 
188
                   }
 
189
        }
 
190
 
 
191
        /* Ok, some heuristics */
 
192
 
 
193
        if (MaxColorant < 2) 
 
194
                Normalize = 255.0;  /* goes 0..1 */
 
195
        else
 
196
        if (MaxColorant < 102)
 
197
                Normalize = 2.55;  /* goes 0..100 */
 
198
        else
 
199
        if (MaxColorant > 300)
 
200
                Normalize = (255.0 / 65535.0);  /* Goes 0..65535.0 */
 
201
        else 
 
202
                return;         /* Is ok */
 
203
 
 
204
 
 
205
        /* Rearrange patches */
 
206
        for (i=0; i < m -> nPatches; i++) {
 
207
 
 
208
 
 
209
           LPPATCH p = m -> Patches + i;
 
210
                   for (j=0; j < MAXCHANNELS; j++)
 
211
                                p ->Colorant.Hexa[j] *= Normalize;
 
212
        }
 
213
 
 
214
}
 
215
 
 
216
 
 
217
/* Load a collection from a Sheet */
 
218
 
 
219
BOOL cmsxPCollLoadFromSheet(LPMEASUREMENT m, LCMSHANDLE hSheet)
 
220
{
 
221
    int i;   
 
222
    DWORD dwMask;
 
223
 
 
224
 
 
225
    if (m -> nPatches == 0) {
 
226
 
 
227
            m -> nPatches = (int) cmsxIT8GetPropertyDbl(hSheet, "NUMBER_OF_SETS");                              
 
228
            m -> Patches  = (PATCH*)calloc(m -> nPatches, sizeof(PATCH));            // C->C++ : cast
 
229
 
 
230
            if (m -> Patches == NULL) {
 
231
                cmsxIT8Free(hSheet);
 
232
                return false;
 
233
            }
 
234
 
 
235
            for (i=0; i < m -> nPatches; i++) {
 
236
 
 
237
                    LPPATCH p = m -> Patches + i;
 
238
                                        p -> dwFlags = 0; 
 
239
                                        cmsxIT8GetPatchName(hSheet, i, p ->Name);                               
 
240
                                 
 
241
            }
 
242
 
 
243
    }
 
244
 
 
245
 
 
246
    /* Build mask according to data format */
 
247
 
 
248
    dwMask = MaskOfDataSet(hSheet);
 
249
 
 
250
 
 
251
    /* Read items. Set flags accordly. */
 
252
    for (i = 0; i < m->nPatches; i++) {
 
253
 
 
254
        LPPATCH Patch = m -> Patches + i;
 
255
                              
 
256
        /* Fill in data according to mask */
 
257
 
 
258
        if (dwMask & PATCH_HAS_Lab) {
 
259
 
 
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))
 
263
 
 
264
                                   Patch -> dwFlags |= PATCH_HAS_Lab;
 
265
        }
 
266
 
 
267
        if (dwMask & PATCH_HAS_XYZ) {
 
268
 
 
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))
 
272
 
 
273
                                  Patch -> dwFlags |= PATCH_HAS_XYZ;
 
274
 
 
275
        }
 
276
 
 
277
        if (dwMask & PATCH_HAS_RGB) {
 
278
 
 
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]))
 
282
 
 
283
                                Patch -> dwFlags |= PATCH_HAS_RGB;
 
284
        }
 
285
 
 
286
        if (dwMask & PATCH_HAS_STD_DE) {
 
287
            
 
288
            if (cmsxIT8GetDataSetDbl(hSheet, Patch->Name, "STDEV_DE", &Patch -> dEStd))
 
289
 
 
290
                                Patch -> dwFlags |= PATCH_HAS_STD_DE;
 
291
 
 
292
        }
 
293
        
 
294
    }
 
295
 
 
296
        NormalizeColorant(m);
 
297
    return true;
 
298
}
 
299
 
 
300
 
 
301
/* Does save parameters to a empty sheet */
 
302
 
 
303
BOOL cmsxPCollSaveToSheet(LPMEASUREMENT m, LCMSHANDLE it8)
 
304
{                       
 
305
        int nNumberOfSets   = cmsxPCollCountSet(m, m->Allowed); 
 
306
        int nNumberOfFields = 0;
 
307
        DWORD dwMask = 0;
 
308
        int i;
 
309
 
 
310
        /* Find mask of fields */
 
311
        for (i=0; i < m ->nPatches; i++) {
 
312
                if (m ->Allowed[i]) {
 
313
 
 
314
                                LPPATCH p = m ->Patches + i;
 
315
                                dwMask |= p ->dwFlags;
 
316
                }
 
317
        }
 
318
 
 
319
        nNumberOfFields = 1; /* SampleID */
 
320
 
 
321
        if (dwMask & PATCH_HAS_RGB)
 
322
                        nNumberOfFields += 3;
 
323
 
 
324
        if (dwMask & PATCH_HAS_XYZ)
 
325
                        nNumberOfFields += 3;
 
326
 
 
327
        if (dwMask & PATCH_HAS_Lab)
 
328
                        nNumberOfFields += 3;
 
329
        
 
330
 
 
331
    cmsxIT8SetPropertyDbl(it8, "NUMBER_OF_SETS", nNumberOfSets);
 
332
    cmsxIT8SetPropertyDbl(it8, "NUMBER_OF_FIELDS", nNumberOfFields);
 
333
 
 
334
        nNumberOfFields = 0;
 
335
    cmsxIT8SetDataFormat(it8, nNumberOfFields++, "SAMPLE_ID");
 
336
 
 
337
        if (dwMask & PATCH_HAS_RGB) {
 
338
 
 
339
                cmsxIT8SetDataFormat(it8, nNumberOfFields++, "RGB_R");
 
340
                cmsxIT8SetDataFormat(it8, nNumberOfFields++, "RGB_G");
 
341
                cmsxIT8SetDataFormat(it8, nNumberOfFields++, "RGB_B");
 
342
        }
 
343
    
 
344
        if (dwMask & PATCH_HAS_XYZ) {
 
345
                
 
346
                cmsxIT8SetDataFormat(it8, nNumberOfFields++, "XYZ_X");
 
347
                cmsxIT8SetDataFormat(it8, nNumberOfFields++, "XYZ_Y");
 
348
                cmsxIT8SetDataFormat(it8, nNumberOfFields++, "XYZ_Z");
 
349
                
 
350
        }
 
351
 
 
352
 
 
353
        if (dwMask & PATCH_HAS_XYZ) {
 
354
                
 
355
                cmsxIT8SetDataFormat(it8, nNumberOfFields++, "LAB_L");
 
356
                cmsxIT8SetDataFormat(it8, nNumberOfFields++, "LAB_A");
 
357
                cmsxIT8SetDataFormat(it8, nNumberOfFields++, "LAB_B");
 
358
                
 
359
        }
 
360
 
 
361
        for (i=0; i < m ->nPatches; i++) {
 
362
                if (m ->Allowed[i]) {
 
363
 
 
364
                        LPPATCH Patch = m ->Patches + i;
 
365
 
 
366
                        cmsxIT8SetDataSet(it8, Patch->Name, "SAMPLE_ID", Patch->Name);
 
367
                        
 
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]);
 
372
                        } 
 
373
 
 
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);                         
 
378
                        }       
 
379
 
 
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);
 
384
                                
 
385
                        }       
 
386
                }
 
387
        }
 
388
 
 
389
        return true;
 
390
}
 
391
 
 
392
static
 
393
void FixLabOnly(LPMEASUREMENT m)
 
394
{
 
395
        int i;
 
396
 
 
397
        for (i=0; i < m ->nPatches; i++) {
 
398
        
 
399
                        LPPATCH p = m ->Patches + i;
 
400
                        if ((p ->dwFlags & PATCH_HAS_Lab) && 
 
401
                                !(p ->dwFlags & PATCH_HAS_XYZ))
 
402
                        {
 
403
                                cmsLab2XYZ(cmsD50_XYZ(), &p->XYZ, &p ->Lab);
 
404
 
 
405
                                p ->XYZ.X *= 100.;
 
406
                                p ->XYZ.Y *= 100.;
 
407
                                p ->XYZ.Z *= 100.;
 
408
 
 
409
                                p ->dwFlags |= PATCH_HAS_XYZ;
 
410
                        }
 
411
        
 
412
        }
 
413
 
 
414
}
 
415
 
 
416
 
 
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: */
 
420
/*   */
 
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 */
 
436
/* */
 
437
/* See lprof.h for further info */
 
438
 
 
439
 
 
440
BOOL cmsxPCollBuildMeasurement(LPMEASUREMENT m, 
 
441
                               const char *ReferenceSheet,
 
442
                               const char *MeasurementSheet,
 
443
                               DWORD dwNeededSamplesType)
 
444
{
 
445
    LCMSHANDLE hSheet;
 
446
        BOOL rc = true;
 
447
 
 
448
    ZeroMemory(m, sizeof(MEASUREMENT));
 
449
 
 
450
 
 
451
    if (ReferenceSheet != NULL && *ReferenceSheet) {
 
452
 
 
453
                hSheet = cmsxIT8LoadFromFile(ReferenceSheet);       
 
454
                if (hSheet == NULL) return false;               
 
455
                
 
456
                                rc = cmsxPCollLoadFromSheet(m,  hSheet);
 
457
                cmsxIT8Free(hSheet);
 
458
    }
 
459
 
 
460
    if (!rc) return false;
 
461
 
 
462
    if (MeasurementSheet != NULL && *MeasurementSheet) {
 
463
 
 
464
                hSheet = cmsxIT8LoadFromFile(MeasurementSheet);
 
465
                if (hSheet == NULL) return false;
 
466
 
 
467
                rc = cmsxPCollLoadFromSheet(m,  hSheet);
 
468
                cmsxIT8Free(hSheet);
 
469
    }
 
470
 
 
471
    if (!rc) return false;
 
472
 
 
473
 
 
474
        /* Fix up -- If only Lab is present, then compute  */
 
475
        /* XYZ based on D50 */
 
476
 
 
477
        FixLabOnly(m);
 
478
 
 
479
    cmsxPCollValidatePatches(m, dwNeededSamplesType);
 
480
    return true;
 
481
}
 
482
 
 
483
 
 
484
 
 
485
void cmsxPCollFreeMeasurements(LPMEASUREMENT m)
 
486
{
 
487
    if (m->Patches)
 
488
        free(m->Patches);
 
489
 
 
490
    m->Patches  = NULL;
 
491
    m->nPatches = 0;
 
492
    
 
493
    if (m -> Allowed)
 
494
        free(m -> Allowed);
 
495
 
 
496
}
 
497
 
 
498
/* Retrieval functions */
 
499
 
 
500
LPPATCH cmsxPCollGetPatchByName(LPMEASUREMENT m, const char* name, int* lpPos)
 
501
{
 
502
    int i;
 
503
    for (i=0; i < m->nPatches; i++)
 
504
    {
 
505
            if (m -> Allowed)
 
506
                if (!m -> Allowed[i])
 
507
                        continue;
 
508
 
 
509
                if (EqualsTo(m->Patches[i].Name, name)) {
 
510
                        if (lpPos) *lpPos = i;
 
511
                        return m->Patches + i;
 
512
                }
 
513
    }
 
514
 
 
515
    return NULL;
 
516
}
 
517
 
 
518
 
 
519
 
 
520
 
 
521
/* -------------------------------------------------------------------- Sets */
 
522
 
 
523
 
 
524
SETOFPATCHES cmsxPCollBuildSet(LPMEASUREMENT m, BOOL lDefault)
 
525
{
 
526
    SETOFPATCHES Full = (SETOFPATCHES) malloc(m -> nPatches * sizeof(BOOL));
 
527
    int i;
 
528
 
 
529
    for (i=0; i < m -> nPatches; i++)
 
530
        Full[i] = lDefault;
 
531
 
 
532
    return Full;
 
533
}
 
534
 
 
535
int cmsxPCollCountSet(LPMEASUREMENT m, SETOFPATCHES Set)
 
536
{
 
537
    int i, Count = 0;
 
538
 
 
539
    for (i = 0; i < m -> nPatches; i++) {
 
540
 
 
541
        if (Set[i])
 
542
            Count++;
 
543
        }
 
544
 
 
545
    return Count;
 
546
}
 
547
 
 
548
 
 
549
/* Validate patches */
 
550
 
 
551
BOOL cmsxPCollValidatePatches(LPMEASUREMENT m, DWORD dwFlags)
 
552
{
 
553
        int i, n;
 
554
 
 
555
                if (m->Allowed) 
 
556
                                free(m->Allowed);
 
557
 
 
558
        m -> Allowed = cmsxPCollBuildSet(m, true);
 
559
        
 
560
        /* Check for flags */
 
561
        for (i=n=0; i < m -> nPatches; i++) {
 
562
 
 
563
                LPPATCH p = m -> Patches + i;               
 
564
                m -> Allowed[i] = ((p -> dwFlags & dwFlags) == dwFlags);
 
565
                
 
566
        }
 
567
 
 
568
        return true;
 
569
}
 
570
 
 
571
 
 
572
/* Several filters */
 
573
 
 
574
 
 
575
/* This filter does validate patches placed on 'radius' distance of a */
 
576
/* device-color space. Currently only RGB is supported */
 
577
 
 
578
static
 
579
void PatchesByRGB(LPMEASUREMENT m, SETOFPATCHES Valids, 
 
580
                                  double R, double G, double B, double radius, SETOFPATCHES Result)
 
581
{
 
582
    int  i;
 
583
    double ra, rmax = sqrt(radius / 255.);
 
584
    double dR, dG, dB;
 
585
    LPPATCH p;
 
586
 
 
587
    for (i=0; i < m->nPatches; i++) {
 
588
 
 
589
       
 
590
       if (Valids[i]) {
 
591
 
 
592
        p = m->Patches + i;
 
593
 
 
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.;
 
597
 
 
598
        ra = sqrt(dR*dR + dG*dG + dB*dB);
 
599
 
 
600
        if (ra <= rmax) 
 
601
            Result[i] = true;       
 
602
        else 
 
603
            Result[i] = false;
 
604
 
 
605
       }
 
606
    }
 
607
 
 
608
}
 
609
 
 
610
 
 
611
/* This filter does validate patches placed at dEmax radius */
 
612
/* in the device-independent side. */
 
613
 
 
614
static
 
615
void PatchesByLab(LPMEASUREMENT m, SETOFPATCHES Valids, 
 
616
                  double L, double a, double b, double dEmax, SETOFPATCHES Result)
 
617
{
 
618
    int  i;
 
619
    double dE, dEMaxSQR = sqrt(dEmax);
 
620
    double dL, da, db;
 
621
    LPPATCH p;
 
622
 
 
623
 
 
624
    for (i=0; i < m->nPatches; i++) {
 
625
 
 
626
       
 
627
       if (Valids[i]) {
 
628
 
 
629
        p = m->Patches + i;
 
630
 
 
631
        dL = fabs(L - p -> Lab.L);
 
632
        da = fabs(a - p -> Lab.a);
 
633
        db = fabs(b - p -> Lab.b);
 
634
 
 
635
        dE = sqrt(dL*dL + da*da + db*db);
 
636
       
 
637
        if (dE <= dEMaxSQR) 
 
638
            Result[i] = true; 
 
639
        else 
 
640
            Result[i] = false;
 
641
       }
 
642
    }
 
643
}
 
644
 
 
645
 
 
646
/* Restrict Lab in a cube of variable sides. Quick and dirty out-of-gamut  */
 
647
/* stripper used in estimations. */
 
648
 
 
649
static
 
650
void  PatchesInLabCube(LPMEASUREMENT m, SETOFPATCHES Valids, 
 
651
                            double Lmin, double Lmax, double da, double db, SETOFPATCHES Result)
 
652
{
 
653
        int i;
 
654
 
 
655
        for (i=0; i < m -> nPatches; i++) {
 
656
 
 
657
    
 
658
                if (Valids[i]) {
 
659
 
 
660
                        LPPATCH p = m -> Patches + i;
 
661
 
 
662
                        if ((p->Lab.L >= Lmin && p->Lab.L <= Lmax) && 
 
663
                            (fabs(p -> Lab.a) < da) &&
 
664
                            (fabs(p -> Lab.b) < db)) 
 
665
 
 
666
                             Result[i] = true;
 
667
                         else   
 
668
                             Result[i] = false;
 
669
                }
 
670
        }
 
671
 
 
672
}
 
673
 
 
674
/* Restrict to low colorfullness */
 
675
 
 
676
static
 
677
void PatchesOfLowC(LPMEASUREMENT m, SETOFPATCHES Valids, 
 
678
                            double Cmax, SETOFPATCHES Result)
 
679
{
 
680
        int i;
 
681
                cmsCIELCh LCh;
 
682
 
 
683
        for (i=0; i < m -> nPatches; i++) {
 
684
 
 
685
    
 
686
                if (Valids[i]) {
 
687
 
 
688
                        LPPATCH p = m -> Patches + i;
 
689
 
 
690
                                                cmsLab2LCh(&LCh, &p->Lab);
 
691
 
 
692
 
 
693
                        if (LCh.C < Cmax)
 
694
                             Result[i] = true;
 
695
                         else   
 
696
                             Result[i] = false;
 
697
                }
 
698
        }
 
699
 
 
700
}
 
701
 
 
702
 
 
703
 
 
704
/* Primary can be -1 for specifying device gray. Does return patches */
 
705
/* on device-space Colorants. dEMax is the maximum allowed ratio */
 
706
 
 
707
static
 
708
void PatchesPrimary(LPMEASUREMENT m, SETOFPATCHES Valids, 
 
709
                           int nColorant, double dEMax, SETOFPATCHES Result)
 
710
{
 
711
        int i, j;
 
712
        double n, dE;
 
713
 
 
714
        for (i=0; i < m -> nPatches; i++) {
 
715
 
 
716
    
 
717
                if (Valids[i]) {
 
718
 
 
719
                        LPPATCH p = m -> Patches + i;
 
720
 
 
721
 
 
722
                        if (nColorant < 0) /* device-grey? */
 
723
                        {
 
724
                                                            /* cross. */
 
725
                                                        
 
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.;
 
729
 
 
730
                                dE = (drg*drg + drb*drb + dbg*dbg);
 
731
 
 
732
 
 
733
                        }
 
734
                        else {
 
735
                                dE = 0.;
 
736
                                for (j=0; j < 3; j++) {
 
737
 
 
738
                                        if (j != nColorant) {
 
739
 
 
740
                                                n = p -> Colorant.RGB[j] / 255.;
 
741
                                                dE += (n * n);
 
742
 
 
743
 
 
744
                                        }
 
745
                                }
 
746
                        }
 
747
 
 
748
 
 
749
 
 
750
                        if (sqrt(dE) < dEMax) 
 
751
                             Result[i] = true;
 
752
                         else   
 
753
                             Result[i] = false;
 
754
                }
 
755
        }
 
756
 
 
757
}
 
758
 
 
759
 
 
760
/* The high level extractors ----------------------------------------------------- */
 
761
 
 
762
int cmsxPCollPatchesNearRGB(LPMEASUREMENT m, SETOFPATCHES Valids,
 
763
                                                        double r, double g, double b, 
 
764
                                                        int need, SETOFPATCHES Result)
 
765
{
 
766
    double radius;
 
767
    int nCollected;
 
768
 
 
769
    /* Collect points inside of a sphere or radius 'radius' by RGB */
 
770
 
 
771
    radius = 1;
 
772
    do {
 
773
        PatchesByRGB(m, Valids, r, g, b, radius, Result);
 
774
 
 
775
        nCollected = cmsxPCollCountSet(m, Result);
 
776
        if (nCollected <= need) {
 
777
 
 
778
            radius += 1.0;
 
779
        }
 
780
 
 
781
    } while (nCollected <= need && radius < 256.);
 
782
 
 
783
    return nCollected; /* Can be less than needed! */
 
784
}
 
785
 
 
786
 
 
787
int cmsxPCollPatchesNearNeutral(LPMEASUREMENT m, SETOFPATCHES Valids, 
 
788
                                                                int need, SETOFPATCHES Result)
 
789
{
 
790
        int nGrays;
 
791
        double Cmax;
 
792
 
 
793
        Cmax = 1.;
 
794
        do {
 
795
 
 
796
 
 
797
                                PatchesOfLowC(m, Valids, Cmax, Result);                            
 
798
               
 
799
                nGrays = cmsxPCollCountSet(m, Result);
 
800
                if (nGrays <= need) {
 
801
 
 
802
                        Cmax += .2;
 
803
                }
 
804
 
 
805
        } while (nGrays <= need && Cmax < 10.);
 
806
 
 
807
        return nGrays;
 
808
}
 
809
 
 
810
 
 
811
int cmsxPCollPatchesInLabCube(LPMEASUREMENT m, SETOFPATCHES Valids, 
 
812
                              double Lmin, double Lmax, double a, double b, 
 
813
                                                          SETOFPATCHES Result)
 
814
 
 
815
 
 
816
{        
 
817
        PatchesInLabCube(m, Valids, Lmin, Lmax, a, b, Result);
 
818
        return cmsxPCollCountSet(m, Result);                
 
819
}
 
820
 
 
821
 
 
822
 
 
823
 
 
824
int cmsxPCollPatchesNearPrimary(LPMEASUREMENT m,
 
825
                          SETOFPATCHES Valids,
 
826
                          int nChannel,
 
827
                          int need,
 
828
                          SETOFPATCHES Result)
 
829
{
 
830
    double radius;
 
831
    int nCollected;
 
832
 
 
833
    /* Collect points inside of a sphere or radius 'radius' by RGB */
 
834
 
 
835
    radius = 0.05;
 
836
    do {
 
837
        PatchesPrimary(m, Valids, nChannel, radius, Result);
 
838
 
 
839
        nCollected = cmsxPCollCountSet(m, Result);
 
840
        if (nCollected <= need) {
 
841
 
 
842
            radius += 0.01;
 
843
        }
 
844
 
 
845
    } while (nCollected <= need && radius < 256.);
 
846
 
 
847
    return nCollected;
 
848
 
 
849
}
 
850
 
 
851
 
 
852
static
 
853
void AddOneGray(LPMEASUREMENT m, int n, SETOFPATCHES Grays)
 
854
{
 
855
    LPPATCH p;
 
856
    char Buffer[cmsxIT8_GRAYCOLS];
 
857
    int pos;
 
858
 
 
859
    if (n == 0) strcpy(Buffer, "DMIN");
 
860
    else
 
861
        if (n == cmsxIT8_GRAYCOLS - 1) strcpy(Buffer, "DMAX");
 
862
        else
 
863
            sprintf(Buffer, "GS%d", n);
 
864
 
 
865
    p = cmsxPCollGetPatchByName(m, Buffer, &pos);
 
866
 
 
867
    if (p) 
 
868
        Grays[pos] = true;
 
869
}
 
870
 
 
871
 
 
872
 
 
873
void cmsxPCollPatchesGS(LPMEASUREMENT m, SETOFPATCHES Result)
 
874
{
 
875
 
 
876
    int i;
 
877
 
 
878
    for (i=0; i < cmsxIT8_GRAYCOLS; i++) 
 
879
        AddOneGray(m, i, Result);
 
880
}
 
881
 
 
882
 
 
883
 
 
884
/* Refresh RGB of all patches after prelinearization */
 
885
 
 
886
void cmsxPCollLinearizePatches(LPMEASUREMENT m, SETOFPATCHES Valids, LPGAMMATABLE Gamma[3])
 
887
{
 
888
    int i;
 
889
 
 
890
    for (i=0; i < m -> nPatches; i++) {
 
891
 
 
892
       if (Valids[i]) {
 
893
 
 
894
        LPPATCH p = m -> Patches + i;
 
895
 
 
896
        cmsxApplyLinearizationTable(p -> Colorant.RGB, Gamma, p -> Colorant.RGB);
 
897
        }
 
898
    }
 
899
 
 
900
}
 
901
 
 
902
 
 
903
int cmsxPCollPatchesInGamutLUT(LPMEASUREMENT m, SETOFPATCHES Valids, 
 
904
                                                                                LPLUT Gamut, SETOFPATCHES Result)
 
905
{
 
906
        int i;
 
907
        int nCollected = 0;
 
908
 
 
909
    for (i=0; i < m -> nPatches; i++) {
 
910
 
 
911
       if (Valids[i]) {
 
912
 
 
913
        LPPATCH p = m -> Patches + i;
 
914
                WORD EncodedLab[3];
 
915
                WORD dE;
 
916
 
 
917
                cmsFloat2LabEncoded(EncodedLab, &p->Lab);
 
918
                cmsEvalLUT(Gamut, EncodedLab, &dE);
 
919
                Result[i] = (dE < 2) ? true : false;                            
 
920
                if (Result[i]) nCollected++;
 
921
        }
 
922
    }
 
923
 
 
924
        return nCollected;
 
925
}
 
926
 
 
927
LPPATCH cmsxPCollFindWhite(LPMEASUREMENT m, SETOFPATCHES Valids, double* TheDistance)
 
928
{
 
929
        int i;
 
930
        LPPATCH Candidate = NULL;
 
931
        double Distance, CandidateDistance = 255;
 
932
        double dR, dG, dB;
 
933
 
 
934
        Candidate = cmsxPCollGetPatchByName(m, "DMIN", NULL);
 
935
        if (Candidate) {
 
936
 
 
937
                if (TheDistance) *TheDistance = 0.0;
 
938
                return Candidate;
 
939
        }
 
940
 
 
941
    for (i=0; i < m -> nPatches; i++) {
 
942
 
 
943
       if (Valids[i]) {
 
944
 
 
945
        LPPATCH p = m -> Patches + i;
 
946
 
 
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;
 
950
 
 
951
        Distance = sqrt(dR*dR + dG*dG + dB*dB);
 
952
 
 
953
                if (Distance < CandidateDistance) {
 
954
                        Candidate = p;
 
955
                        CandidateDistance = Distance;
 
956
                }
 
957
           }                    
 
958
    }
 
959
 
 
960
        if (TheDistance) 
 
961
                *TheDistance = floor(CandidateDistance * 255.0 + .5);
 
962
 
 
963
        return Candidate;
 
964
}
 
965
 
 
966
LPPATCH cmsxPCollFindBlack(LPMEASUREMENT m, SETOFPATCHES Valids, double* TheDistance)
 
967
{
 
968
        int i;
 
969
        LPPATCH Candidate = NULL;
 
970
        double Distance, CandidateDistance = 255;
 
971
        double dR, dG, dB;
 
972
 
 
973
 
 
974
        Candidate = cmsxPCollGetPatchByName(m, "DMAX", NULL);
 
975
        if (Candidate) {
 
976
 
 
977
                if (TheDistance) *TheDistance = 0.0;
 
978
                return Candidate;
 
979
        }
 
980
 
 
981
    for (i=0; i < m -> nPatches; i++) {
 
982
 
 
983
       if (Valids[i]) {
 
984
 
 
985
        LPPATCH p = m -> Patches + i;
 
986
 
 
987
                dR = (p -> Colorant.RGB[0]) / 255.0;
 
988
        dG = (p -> Colorant.RGB[1]) / 255.0;
 
989
        dB = (p -> Colorant.RGB[2]) / 255.0;
 
990
 
 
991
        Distance = sqrt(dR*dR + dG*dG + dB*dB);
 
992
 
 
993
                if (Distance < CandidateDistance) {
 
994
                        Candidate = p;
 
995
                        CandidateDistance = Distance;
 
996
                }
 
997
           }                    
 
998
    }
 
999
 
 
1000
        if (TheDistance) 
 
1001
                *TheDistance = floor(CandidateDistance * 255.0 + .5);
 
1002
 
 
1003
        return Candidate;
 
1004
}
 
1005
 
 
1006
 
 
1007
LPPATCH cmsxPCollFindPrimary(LPMEASUREMENT m, SETOFPATCHES Valids, int Channel, double* TheDistance)
 
1008
{
 
1009
        int i;
 
1010
        LPPATCH Candidate = NULL;
 
1011
        double Distance, CandidateDistance = 255;
 
1012
        double dR, dG, dB;
 
1013
        const struct { 
 
1014
                                 double r, g, b; 
 
1015
 
 
1016
                                } RGBPrimaries[3] = {           
 
1017
                                        { 255.0, 0, 0}, 
 
1018
                                        { 0, 255.0, 0},
 
1019
                                        { 0, 0, 255  }};
 
1020
 
 
1021
 
 
1022
    for (i=0; i < m -> nPatches; i++) {
 
1023
 
 
1024
       if (Valids[i]) {
 
1025
 
 
1026
        LPPATCH p = m -> Patches + i;
 
1027
 
 
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;
 
1031
 
 
1032
        Distance = sqrt(dR*dR + dG*dG + dB*dB);
 
1033
 
 
1034
                if (Distance < CandidateDistance) {
 
1035
                        Candidate = p;
 
1036
                        CandidateDistance = Distance;
 
1037
                }
 
1038
           }                    
 
1039
    }
 
1040
 
 
1041
        if (TheDistance) 
 
1042
                *TheDistance = floor(CandidateDistance * 255.0 + .5);
 
1043
 
 
1044
        return Candidate;
 
1045
}