Subversion Repositories Scribus

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2454 craig 1
//
2
//  Little cms - profiler construction set
3
//  Copyright (C) 1998-2001 Marti Maria
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., 59 Temple Place - Suite 330, 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
BOOL cdecl cmsxComputeMatrixShaper(const char* ReferenceSheet,                              
42
                             const char* MeasurementSheet,  
43
                             int Medium,
44
                             LPGAMMATABLE TransferCurves[3],
45
                             LPcmsCIEXYZ WhitePoint,
46
                             LPcmsCIEXYZ BlackPoint,
47
                             LPcmsCIExyYTRIPLE Primaries);
48
 
49
 
50
 
51
// ------------------------------------------------------------- Implementation 
52
 
53
 
54
static
55
void Div100(LPcmsCIEXYZ xyz)
56
{
57
    xyz -> X /= 100; xyz -> Y /= 100; xyz -> Z /= 100;
58
}
59
 
60
 
61
 
62
// Compute endpoints
63
 
64
static
65
BOOL ComputeWhiteAndBlackPoints(LPMEASUREMENT Linearized,
66
                                LPGAMMATABLE TransferCurves[3],
67
                                LPcmsCIEXYZ Black, LPcmsCIEXYZ White)
68
{
69
 
70
    double Zeroes[3], Ones[3], lmin[3], lmax[3];    
71
 
72
    SETOFPATCHES Neutrals = cmsxPCollBuildSet(Linearized, FALSE);
73
 
74
    cmsxPCollPatchesNearNeutral(Linearized, Linearized->Allowed,
75
                                                    15, Neutrals);
76
 
77
    Zeroes[0] = Zeroes[1] = Zeroes[2] = 0.0;
78
    Ones[0]   = Ones[1]   = Ones[2]   = 255.0;
79
 
80
 
81
    cmsxApplyLinearizationTable(Zeroes,  TransferCurves, lmin);
82
    cmsxApplyLinearizationTable(Ones,    TransferCurves, lmax);
83
 
84
 
85
    // Global regression to find White & Black points
86
    if (!cmsxRegressionInterpolatorRGB(Linearized, PT_XYZ,                                      
87
                                       4,
88
                                       TRUE,
89
                                       12,
90
                                       lmin[0], lmin[1], lmin[2],
91
                                       Black)) return FALSE;
92
 
93
    if (!cmsxRegressionInterpolatorRGB(Linearized, PT_XYZ,                                      
94
                                       4,
95
                                       TRUE,
96
                                       12,
97
                                       lmax[0], lmax[1], lmax[2],
98
                                       White)) return FALSE;
99
 
100
    _cmsxClampXYZ100(White);
101
    _cmsxClampXYZ100(Black);
102
 
103
    return TRUE;
104
 
105
}
106
 
107
 
108
// Study convergence of primary axis
109
 
110
static
111
BOOL ComputePrimary(LPMEASUREMENT Linearized,
112
                    LPGAMMATABLE TransferCurves[3],
113
                    int n,
114
                    LPcmsCIExyY Primary)
115
{
116
 
117
    double Ones[3], lmax[3];    
118
    cmsCIEXYZ PrimXYZ;
119
    SETOFPATCHES SetPrimary;
120
    int nR;
121
 
122
 
123
    // At first, try to see if primaries are already in measurement
124
 
125
    SetPrimary = cmsxPCollBuildSet(Linearized, FALSE);
126
    nR = cmsxPCollPatchesNearPrimary(Linearized, Linearized->Allowed,
127
                                           n, 32, SetPrimary);
128
 
129
    Ones[0]  = Ones[1] = Ones[2] = 0;
130
    Ones[n]  = 255.0;
131
 
132
    cmsxApplyLinearizationTable(Ones,  TransferCurves, lmax);
133
 
134
    // Do incremental regression to find primaries
135
    if (!cmsxRegressionInterpolatorRGB(Linearized, PT_XYZ,                                      
136
                                       4,
137
                                       FALSE,
138
                                       12,
139
                                       lmax[0], lmax[1], lmax[2],                                  
140
                                       &PrimXYZ)) return FALSE;
141
 
142
    _cmsxClampXYZ100(&PrimXYZ);
143
    cmsXYZ2xyY(Primary, &PrimXYZ);
144
    return TRUE;
145
 
146
 
147
}
148
 
149
 
150
 
151
// Does compute a matrix-shaper based on patches. 
152
 
153
static
154
double Clip(double d)
155
{
156
    return d > 0 ? d: 0;
157
}
158
 
159
 
160
BOOL cmsxComputeMatrixShaper(const char* ReferenceSheet,                                
161
                             const char* MeasurementSheet,
162
                             int Medium,
163
                             LPGAMMATABLE TransferCurves[3],
164
                             LPcmsCIEXYZ WhitePoint,
165
                             LPcmsCIEXYZ BlackPoint,
166
                             LPcmsCIExyYTRIPLE Primaries)
167
{
168
 
169
    MEASUREMENT Linearized;    
170
    cmsCIEXYZ Black, White;
171
    cmsCIExyYTRIPLE  PrimarySet;
172
    LPPATCH PatchWhite, PatchBlack;
173
    LPPATCH PatchRed, PatchGreen, PatchBlue;
174
    double Distance;
175
 
176
    // Load sheets
177
 
178
    if (!cmsxPCollBuildMeasurement(&Linearized,
179
                             ReferenceSheet,
180
                             MeasurementSheet,
181
                             PATCH_HAS_XYZ|PATCH_HAS_RGB)) return FALSE;
182
 
183
 
184
 
185
    // Any patch to deal of?
186
    if (cmsxPCollCountSet(&Linearized, Linearized.Allowed) <= 0) return FALSE;
187
 
188
 
189
    // Try to see if proper primaries, white and black already present
190
    PatchWhite = cmsxPCollFindWhite(&Linearized, Linearized.Allowed, &Distance);
191
    if (Distance != 0)
192
        PatchWhite = NULL;  
193
 
194
    PatchBlack = cmsxPCollFindBlack(&Linearized, Linearized.Allowed, &Distance);
195
    if (Distance != 0)
196
        PatchBlack = NULL;  
197
 
198
    PatchRed = cmsxPCollFindPrimary(&Linearized, Linearized.Allowed, 0, &Distance);
199
    if (Distance != 0)
200
        PatchRed = NULL;    
201
 
202
    PatchGreen = cmsxPCollFindPrimary(&Linearized, Linearized.Allowed, 1, &Distance);
203
    if (Distance != 0)
204
        PatchGreen = NULL;  
205
 
206
    PatchBlue = cmsxPCollFindPrimary(&Linearized, Linearized.Allowed, 2, &Distance);
207
    if (Distance != 0)
208
        PatchBlue= NULL;    
209
 
210
    // If we got primaries, then we can also get prelinearization
211
    // by  Levenberg-Marquardt. This applies on monitor profiles
212
 
213
    if (PatchWhite && PatchRed && PatchGreen && PatchBlue) {
214
 
215
        // Build matrix with primaries
216
 
217
        MAT3 Mat, MatInv;
218
        LPSAMPLEDCURVE Xr,Yr, Xg, Yg, Xb, Yb;
219
        int i, nRes, cnt;
220
 
221
        VEC3init(&Mat.v[0], PatchRed->XYZ.X, PatchGreen->XYZ.X, PatchBlue->XYZ.X);
222
        VEC3init(&Mat.v[1], PatchRed->XYZ.Y, PatchGreen->XYZ.Y, PatchBlue->XYZ.Y);
223
        VEC3init(&Mat.v[2], PatchRed->XYZ.Z, PatchGreen->XYZ.Z, PatchBlue->XYZ.Z);
224
 
225
        // Invert matrix
226
        MAT3inverse(&Mat, &MatInv);
227
 
228
        nRes = cmsxPCollCountSet(&Linearized, Linearized.Allowed);
229
 
230
        Xr = cmsAllocSampledCurve(nRes);
231
        Yr = cmsAllocSampledCurve(nRes);
232
        Xg = cmsAllocSampledCurve(nRes);
233
        Yg = cmsAllocSampledCurve(nRes);
234
        Xb = cmsAllocSampledCurve(nRes);
235
        Yb = cmsAllocSampledCurve(nRes);
236
 
237
        // Convert XYZ of all patches to RGB
238
        cnt = 0;
239
        for (i=0; i < Linearized.nPatches; i++) {
240
 
241
            if (Linearized.Allowed[i]) {
242
 
243
                VEC3 RGBprime, XYZ;
244
                LPPATCH p;
245
 
246
                p = Linearized.Patches + i;
247
                XYZ.n[0] = p -> XYZ.X;
248
                XYZ.n[1] = p -> XYZ.Y;
249
                XYZ.n[2] = p -> XYZ.Z;
250
 
251
                MAT3eval(&RGBprime, &MatInv, &XYZ);
252
 
253
                Xr ->Values[cnt] = p ->Colorant.RGB[0];
254
                Yr ->Values[cnt] = Clip(RGBprime.n[0]);
255
 
256
                Xg ->Values[cnt] = p ->Colorant.RGB[1];
257
                Yg ->Values[cnt] = Clip(RGBprime.n[1]);
258
 
259
                Xb ->Values[cnt] = p ->Colorant.RGB[2];
260
                Yb ->Values[cnt] = Clip(RGBprime.n[2]);
261
 
262
                cnt++;
263
 
264
            }
265
        }
266
 
267
        TransferCurves[0] = cmsxEstimateGamma(Xr, Yr, 1024);
268
        TransferCurves[1] = cmsxEstimateGamma(Xg, Yg, 1024);
269
        TransferCurves[2] = cmsxEstimateGamma(Xb, Yb, 1024);
270
 
271
        if (WhitePoint) {
272
 
273
            WhitePoint->X = PatchWhite->XYZ.X;
274
            WhitePoint->Y= PatchWhite ->XYZ.Y;
275
            WhitePoint->Z= PatchWhite ->XYZ.Z;
276
        }
277
 
278
        if (BlackPoint && PatchBlack) {
279
 
280
            BlackPoint->X = PatchBlack ->XYZ.X;
281
            BlackPoint->Y = PatchBlack ->XYZ.Y;
282
            BlackPoint->Z = PatchBlack ->XYZ.Z;
283
        }
284
 
285
        if (Primaries) {
286
 
287
            cmsXYZ2xyY(&Primaries->Red,   &PatchRed ->XYZ);
288
            cmsXYZ2xyY(&Primaries->Green, &PatchGreen ->XYZ);
289
            cmsXYZ2xyY(&Primaries->Blue,  &PatchBlue ->XYZ);
290
 
291
        }
292
 
293
 
294
        cmsFreeSampledCurve(Xr);
295
        cmsFreeSampledCurve(Yr);
296
        cmsFreeSampledCurve(Xg);
297
        cmsFreeSampledCurve(Yg);
298
        cmsFreeSampledCurve(Xb);
299
        cmsFreeSampledCurve(Yb);
300
 
301
        cmsxPCollFreeMeasurements(&Linearized);
302
 
303
        return TRUE;
304
    }
305
 
306
 
307
 
308
 
309
    // Compute prelinearization
310
    cmsxComputeLinearizationTables(&Linearized, PT_XYZ, TransferCurves, 1024, Medium);  
311
 
312
    // Linearize measurements
313
    cmsxPCollLinearizePatches(&Linearized, Linearized.Allowed, TransferCurves);
314
 
315
 
316
    // Endpoints
317
    ComputeWhiteAndBlackPoints(&Linearized, TransferCurves, &Black, &White);
318
 
319
    // Primaries
320
    ComputePrimary(&Linearized, TransferCurves, 0, &PrimarySet.Red);
321
    ComputePrimary(&Linearized, TransferCurves, 1, &PrimarySet.Green);
322
    ComputePrimary(&Linearized, TransferCurves, 2, &PrimarySet.Blue);
323
 
324
 
325
    if (BlackPoint) {
326
        *BlackPoint = Black;            
327
        Div100(BlackPoint);
328
    }
329
 
330
    if (WhitePoint) {
331
        *WhitePoint = White;
332
        Div100(WhitePoint);    
333
    }
334
 
335
 
336
    if (Primaries) {
337
        *Primaries = PrimarySet;    
338
    }
339
 
340
    cmsxPCollFreeMeasurements(&Linearized);
341
 
342
    return TRUE;
343
}
344
 
345
 
346