1 //
2 //  Little cms
3 //  Copyright (C) 1998-2007 Marti Maria
4 //
5 // Permission is hereby granted, free of charge, to any person obtaining
6 // a copy of this software and associated documentation files (the "Software"),
7 // to deal in the Software without restriction, including without limitation
8 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 // and/or sell copies of the Software, and to permit persons to whom the Software
10 // is furnished to do so, subject to the following conditions:
11 //
12 // The above copyright notice and this permission notice shall be included in
13 // all copies or substantial portions of the Software.
14 //
15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
17 // THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 
23 #include "lcms.h"
24 
25 
26 
27 
28 /*
29        This module provides conversion stages for handling intents.
30 
31 The chain of evaluation in a transform is:
32 
33                 PCS1            PCS2                    PCS3          PCS4
34 
35 |From |  |From  |  |Conversion |  |Preview |  |Gamut   |  |Conversion |  |To    |  |To     |
36 |Input|->|Device|->|Stage 1    |->|handling|->|Checking|->|Stage 2    |->|Device|->|output |
37 
38 --------  -------  -------------   ---------  ----------  -------------   -------  ---------
39 
40           AToB0                     prew0       gamut                     BToA0
41 Formatting LUT      Adjusting        LUT         LUT       Adjusting       LUT      Formatting
42           Intent     Intent 1       intent      intent      Intent 2      Intent
43 
44 
45 Some of these LUT may be missing
46 
47 There are two intents involved here, the intent of the transform itself, and the
48 intent the proof is being done, if is the case. Since the first intent is to be
49 applied to preview, is the proofing intent. The second intent  identifies the
50 transform intent. Input data of any stage is taked as relative colorimetric
51 always.
52 
53 
54 NOTES: V4 states than perceptual & saturation intents between mixed v2 & v4 profiles should
55 scale PCS from a black point equal to ZERO in v2 profiles to the reference media black of
56 perceptual v4 PCS. Since I found many v2 profiles to be using a perceptual intent with black
57 point not zero at all, I'm implementing that as a black point compensation from whatever
58 black from perceptal intent to the reference media black for v4 profiles.
59 
60 */
61 
62 
63 
64 
65 int cdecl cmsChooseCnvrt(int Absolute,
66                  int Phase1, LPcmsCIEXYZ BlackPointIn,
67                              LPcmsCIEXYZ WhitePointIn,
68                              LPcmsCIEXYZ IlluminantIn,
69                              LPMAT3 ChromaticAdaptationMatrixIn,
70 
71                  int Phase2, LPcmsCIEXYZ BlackPointOut,
72                              LPcmsCIEXYZ WhitePointOut,
73                              LPcmsCIEXYZ IlluminantOut,
74                              LPMAT3 ChromaticAdaptationMatrixOut,
75 
76                 int DoBlackPointCompensation,
77                 double AdaptationState,
78                  _cmsADJFN *fn1,
79                  LPWMAT3 wm, LPWVEC3 wof);
80 
81 
82 // -------------------------------------------------------------------------
83 
84 // D50 - Widely used
85 
cmsD50_XYZ(void)86 LCMSAPI LPcmsCIEXYZ LCMSEXPORT cmsD50_XYZ(void)
87 {
88     static cmsCIEXYZ D50XYZ = {D50X, D50Y, D50Z};
89 
90     return &D50XYZ;
91 }
92 
cmsD50_xyY(void)93 LCMSAPI LPcmsCIExyY LCMSEXPORT cmsD50_xyY(void)
94 {
95     static cmsCIExyY D50xyY;
96     cmsXYZ2xyY(&D50xyY, cmsD50_XYZ());
97 
98     return &D50xyY;
99 }
100 
101 
102 // ---------------- From LUT to LUT --------------------------
103 
104 
105 // Calculate m, offset Relativ -> Absolute undoing any chromatic
106 // adaptation done by the profile.
107 
108 #ifdef _MSC_VER
109 #pragma warning(disable : 4100 4505)
110 #endif
111 
112 
113 
114 // join scalings to obtain:
115 //     relative input to absolute and then to relative output
116 
117 static
Rel2RelStepAbsCoefs(double AdaptationState,LPcmsCIEXYZ BlackPointIn,LPcmsCIEXYZ WhitePointIn,LPcmsCIEXYZ IlluminantIn,LPMAT3 ChromaticAdaptationMatrixIn,LPcmsCIEXYZ BlackPointOut,LPcmsCIEXYZ WhitePointOut,LPcmsCIEXYZ IlluminantOut,LPMAT3 ChromaticAdaptationMatrixOut,LPMAT3 m,LPVEC3 of)118 void Rel2RelStepAbsCoefs(double AdaptationState,
119 
120                          LPcmsCIEXYZ BlackPointIn,
121                          LPcmsCIEXYZ WhitePointIn,
122                          LPcmsCIEXYZ IlluminantIn,
123                          LPMAT3 ChromaticAdaptationMatrixIn,
124 
125                          LPcmsCIEXYZ BlackPointOut,
126                          LPcmsCIEXYZ WhitePointOut,
127                          LPcmsCIEXYZ IlluminantOut,
128                          LPMAT3 ChromaticAdaptationMatrixOut,
129 
130                          LPMAT3 m, LPVEC3 of)
131 {
132 
133        VEC3 WtPtIn, WtPtInAdapted;
134        VEC3 WtPtOut, WtPtOutAdapted;
135        MAT3 Scale, m1, m2, m3;
136 
137        VEC3init(&WtPtIn, WhitePointIn->X, WhitePointIn->Y, WhitePointIn->Z);
138        MAT3eval(&WtPtInAdapted, ChromaticAdaptationMatrixIn, &WtPtIn);
139 
140        VEC3init(&WtPtOut, WhitePointOut->X, WhitePointOut->Y, WhitePointOut->Z);
141        MAT3eval(&WtPtOutAdapted, ChromaticAdaptationMatrixOut, &WtPtOut);
142 
143        VEC3init(&Scale.v[0], WtPtInAdapted.n[0] / WtPtOutAdapted.n[0], 0, 0);
144        VEC3init(&Scale.v[1], 0, WtPtInAdapted.n[1] / WtPtOutAdapted.n[1], 0);
145        VEC3init(&Scale.v[2], 0, 0, WtPtInAdapted.n[2] / WtPtOutAdapted.n[2]);
146 
147 
148        // Adaptation state
149 
150        if (AdaptationState == 1.0) {
151 
152            // Observer is fully adapted. Keep chromatic adaptation
153 
154            CopyMemory(m, &Scale, sizeof(MAT3));
155 
156        }
157        else {
158 
159             // Observer is not adapted, undo the chromatic adaptation
160             m1 = *ChromaticAdaptationMatrixIn;
161             MAT3inverse(&m1, &m2);
162 
163             MAT3per(&m3, &m2, &Scale);
164             MAT3per(m, &m3, ChromaticAdaptationMatrixOut);
165        }
166 
167 
168        VEC3init(of, 0.0, 0.0, 0.0);
169 
170 }
171 
172 
173 // The (in)famous black point compensation. Right now implemented as
174 // a linear scaling in XYZ
175 
176 static
ComputeBlackPointCompensationFactors(LPcmsCIEXYZ BlackPointIn,LPcmsCIEXYZ WhitePointIn,LPcmsCIEXYZ IlluminantIn,LPcmsCIEXYZ BlackPointOut,LPcmsCIEXYZ WhitePointOut,LPcmsCIEXYZ IlluminantOut,LPMAT3 m,LPVEC3 of)177 void ComputeBlackPointCompensationFactors(LPcmsCIEXYZ BlackPointIn,
178                       LPcmsCIEXYZ WhitePointIn,
179                       LPcmsCIEXYZ IlluminantIn,
180                       LPcmsCIEXYZ BlackPointOut,
181                       LPcmsCIEXYZ WhitePointOut,
182                       LPcmsCIEXYZ IlluminantOut,
183                       LPMAT3 m, LPVEC3 of)
184 {
185 
186 
187    cmsCIEXYZ RelativeBlackPointIn, RelativeBlackPointOut;
188    double ax, ay, az, bx, by, bz, tx, ty, tz;
189 
190    // At first, convert both black points to relative.
191 
192    cmsAdaptToIlluminant(&RelativeBlackPointIn,  WhitePointIn, IlluminantIn, BlackPointIn);
193    cmsAdaptToIlluminant(&RelativeBlackPointOut, WhitePointOut, IlluminantOut, BlackPointOut);
194 
195    // Now we need to compute a matrix plus an offset m and of such of
196    // [m]*bpin + off = bpout
197    // [m]*D50  + off = D50
198    //
199    // This is a linear scaling in the form ax+b, where
200    // a = (bpout - D50) / (bpin - D50)
201    // b = - D50* (bpout - bpin) / (bpin - D50)
202 
203 
204    tx = RelativeBlackPointIn.X - IlluminantIn ->X;
205    ty = RelativeBlackPointIn.Y - IlluminantIn ->Y;
206    tz = RelativeBlackPointIn.Z - IlluminantIn ->Z;
207 
208    ax = (RelativeBlackPointOut.X - IlluminantOut ->X) / tx;
209    ay = (RelativeBlackPointOut.Y - IlluminantOut ->Y) / ty;
210    az = (RelativeBlackPointOut.Z - IlluminantOut ->Z) / tz;
211 
212    bx = - IlluminantOut -> X * (RelativeBlackPointOut.X - RelativeBlackPointIn.X) / tx;
213    by = - IlluminantOut -> Y * (RelativeBlackPointOut.Y - RelativeBlackPointIn.Y) / ty;
214    bz = - IlluminantOut -> Z * (RelativeBlackPointOut.Z - RelativeBlackPointIn.Z) / tz;
215 
216 
217    MAT3identity(m);
218 
219    m->v[VX].n[0] = ax;
220    m->v[VY].n[1] = ay;
221    m->v[VZ].n[2] = az;
222 
223    VEC3init(of, bx, by, bz);
224 
225 }
226 
227 // Return TRUE if both m and of are empy -- "m" being identity and "of" being 0
228 
229 static
IdentityParameters(LPWMAT3 m,LPWVEC3 of)230 LCMSBOOL IdentityParameters(LPWMAT3 m, LPWVEC3 of)
231 {
232     WVEC3 wv0;
233 
234     VEC3initF(&wv0, 0, 0, 0);
235 
236     if (!MAT3isIdentity(m, 0.00001)) return FALSE;
237     if (!VEC3equal(of, &wv0, 0.00001)) return FALSE;
238 
239     return TRUE;
240 }
241 
242 
243 
244 
245 // ----------------------------------------- Inter PCS conversions
246 
247 // XYZ to XYZ linear scaling. Aso used on Black point compensation
248 
249 static
XYZ2XYZ(WORD In[],WORD Out[],LPWMAT3 m,LPWVEC3 of)250 void XYZ2XYZ(WORD In[], WORD Out[], LPWMAT3 m, LPWVEC3 of)
251 {
252 
253     WVEC3 a, r;
254 
255     a.n[0] = In[0] << 1;
256     a.n[1] = In[1] << 1;
257     a.n[2] = In[2] << 1;
258 
259     MAT3evalW(&r, m, &a);
260 
261     Out[0] = _cmsClampWord((r.n[VX] + of->n[VX]) >> 1);
262     Out[1] = _cmsClampWord((r.n[VY] + of->n[VY]) >> 1);
263     Out[2] = _cmsClampWord((r.n[VZ] + of->n[VZ]) >> 1);
264 }
265 
266 
267 // XYZ to Lab, scaling first
268 
269 static
XYZ2Lab(WORD In[],WORD Out[],LPWMAT3 m,LPWVEC3 of)270 void XYZ2Lab(WORD In[], WORD Out[], LPWMAT3 m, LPWVEC3 of)
271 {
272   WORD XYZ[3];
273 
274   XYZ2XYZ(In, XYZ, m, of);
275   cmsXYZ2LabEncoded(XYZ, Out);
276 }
277 
278 // Lab to XYZ, then scalling
279 
280 static
Lab2XYZ(WORD In[],WORD Out[],LPWMAT3 m,LPWVEC3 of)281 void Lab2XYZ(WORD In[], WORD Out[], LPWMAT3 m, LPWVEC3 of)
282 {
283        WORD XYZ[3];
284 
285        cmsLab2XYZEncoded(In, XYZ);
286        XYZ2XYZ(XYZ, Out, m, of);
287 }
288 
289 // Lab to XYZ, scalling and then, back to Lab
290 
291 static
Lab2XYZ2Lab(WORD In[],WORD Out[],LPWMAT3 m,LPWVEC3 of)292 void Lab2XYZ2Lab(WORD In[], WORD Out[], LPWMAT3 m, LPWVEC3 of)
293 {
294        WORD XYZ[3], XYZ2[3];
295 
296        cmsLab2XYZEncoded(In, XYZ);
297        XYZ2XYZ(XYZ, XYZ2, m, of);
298        cmsXYZ2LabEncoded(XYZ2, Out);
299 }
300 
301 // ------------------------------------------------------------------
302 
303 // Dispatcher for XYZ Relative LUT
304 
305 static
FromXYZRelLUT(int Absolute,LPcmsCIEXYZ BlackPointIn,LPcmsCIEXYZ WhitePointIn,LPcmsCIEXYZ IlluminantIn,LPMAT3 ChromaticAdaptationMatrixIn,int Phase2,LPcmsCIEXYZ BlackPointOut,LPcmsCIEXYZ WhitePointOut,LPcmsCIEXYZ IlluminantOut,LPMAT3 ChromaticAdaptationMatrixOut,int DoBlackPointCompensation,double AdaptationState,_cmsADJFN * fn1,LPMAT3 m,LPVEC3 of)306 int FromXYZRelLUT(int Absolute,
307                              LPcmsCIEXYZ BlackPointIn,
308                              LPcmsCIEXYZ WhitePointIn,
309                              LPcmsCIEXYZ IlluminantIn,
310                              LPMAT3 ChromaticAdaptationMatrixIn,
311 
312                  int Phase2, LPcmsCIEXYZ BlackPointOut,
313                              LPcmsCIEXYZ WhitePointOut,
314                              LPcmsCIEXYZ IlluminantOut,
315                              LPMAT3 ChromaticAdaptationMatrixOut,
316 
317                  int DoBlackPointCompensation,
318                  double AdaptationState,
319                  _cmsADJFN *fn1,
320                  LPMAT3 m, LPVEC3 of)
321 
322 {
323               switch (Phase2) {
324 
325                      // From relative XYZ to Relative XYZ.
326 
327                      case XYZRel:
328 
329                             if (Absolute)
330                             {
331                                    // From input relative to absolute, and then
332                                    // back to output relative
333 
334                                    Rel2RelStepAbsCoefs(AdaptationState,
335                                                        BlackPointIn,
336                                                        WhitePointIn,
337                                                        IlluminantIn,
338                                                        ChromaticAdaptationMatrixIn,
339                                                        BlackPointOut,
340                                                        WhitePointOut,
341                                                        IlluminantOut,
342                                                        ChromaticAdaptationMatrixOut,
343                                                        m, of);
344                                    *fn1 = XYZ2XYZ;
345 
346                             }
347                             else
348                             {
349                                    // XYZ Relative to XYZ relative, no op required
350                                    *fn1 = NULL;
351                                    if (DoBlackPointCompensation) {
352 
353                                       *fn1 = XYZ2XYZ;
354                                       ComputeBlackPointCompensationFactors(BlackPointIn,
355                                                                       WhitePointIn,
356                                                                       IlluminantIn,
357                                                                       BlackPointOut,
358                                                                       WhitePointOut,
359                                                                       IlluminantOut,
360                                                                       m, of);
361 
362                                    }
363                             }
364                             break;
365 
366 
367                      // From relative XYZ to Relative Lab
368 
369                      case LabRel:
370 
371                             // First pass XYZ to absolute, then to relative and
372                             // finally to Lab. I use here D50 for output in order
373                             // to prepare the "to Lab" conversion.
374 
375                             if (Absolute)
376                             {
377 
378                                 Rel2RelStepAbsCoefs(AdaptationState,
379                                                     BlackPointIn,
380                                                     WhitePointIn,
381                                                     IlluminantIn,
382                                                     ChromaticAdaptationMatrixIn,
383                                                     BlackPointOut,
384                                                     WhitePointOut,
385                                                     IlluminantOut,
386                                                     ChromaticAdaptationMatrixOut,
387                                                     m, of);
388 
389                                 *fn1 = XYZ2Lab;
390 
391                             }
392                             else
393                             {
394                                    // Just Convert to Lab
395 
396                                    MAT3identity(m);
397                                    VEC3init(of, 0, 0, 0);
398                                    *fn1 = XYZ2Lab;
399 
400                                    if (DoBlackPointCompensation) {
401 
402                                     ComputeBlackPointCompensationFactors(BlackPointIn,
403                                                                           WhitePointIn,
404                                                                           IlluminantIn,
405                                                                           BlackPointOut,
406                                                                           WhitePointOut,
407                                                                           IlluminantOut,
408                                                                           m, of);
409                                    }
410                             }
411                             break;
412 
413 
414                      default: return FALSE;
415                      }
416 
417               return TRUE;
418 }
419 
420 
421 
422 
423 // From Lab Relative type LUT
424 
425 static
FromLabRelLUT(int Absolute,LPcmsCIEXYZ BlackPointIn,LPcmsCIEXYZ WhitePointIn,LPcmsCIEXYZ IlluminantIn,LPMAT3 ChromaticAdaptationMatrixIn,int Phase2,LPcmsCIEXYZ BlackPointOut,LPcmsCIEXYZ WhitePointOut,LPcmsCIEXYZ IlluminantOut,LPMAT3 ChromaticAdaptationMatrixOut,int DoBlackPointCompensation,double AdaptationState,_cmsADJFN * fn1,LPMAT3 m,LPVEC3 of)426 int FromLabRelLUT(int Absolute,
427                              LPcmsCIEXYZ BlackPointIn,
428                              LPcmsCIEXYZ WhitePointIn,
429                              LPcmsCIEXYZ IlluminantIn,
430                              LPMAT3 ChromaticAdaptationMatrixIn,
431 
432                  int Phase2, LPcmsCIEXYZ BlackPointOut,
433                              LPcmsCIEXYZ WhitePointOut,
434                              LPcmsCIEXYZ IlluminantOut,
435                              LPMAT3 ChromaticAdaptationMatrixOut,
436 
437                 int DoBlackPointCompensation,
438                 double AdaptationState,
439 
440                  _cmsADJFN *fn1,
441                  LPMAT3 m, LPVEC3 of)
442 {
443 
444           switch (Phase2) {
445 
446               // From Lab Relative to XYZ Relative, very usual case
447 
448               case XYZRel:
449 
450                   if (Absolute) {  // Absolute intent
451 
452                             // From lab relative, to XYZ absolute, and then,
453                             // back to XYZ relative
454 
455                             Rel2RelStepAbsCoefs(AdaptationState,
456                                                 BlackPointIn,
457                                                 WhitePointIn,
458                                                 cmsD50_XYZ(),
459                                                 ChromaticAdaptationMatrixIn,
460                                                 BlackPointOut,
461                                                 WhitePointOut,
462                                                 IlluminantOut,
463                                                 ChromaticAdaptationMatrixOut,
464                                                 m, of);
465 
466                             *fn1 = Lab2XYZ;
467 
468                      }
469                      else
470                      {
471                             // From Lab relative, to XYZ relative.
472 
473                             *fn1 = Lab2XYZ;
474                             if (DoBlackPointCompensation) {
475 
476                                  ComputeBlackPointCompensationFactors(BlackPointIn,
477                                                                       WhitePointIn,
478                                                                       IlluminantIn,
479                                                                       BlackPointOut,
480                                                                       WhitePointOut,
481                                                                       IlluminantOut,
482                                                                       m, of);
483 
484                             }
485                      }
486                      break;
487 
488 
489 
490               case LabRel:
491 
492                      if (Absolute) {
493 
494                              // First pass to XYZ using the input illuminant
495                              // * InIlluminant / D50, then to absolute. Then
496                              // to relative, but for input
497 
498                              Rel2RelStepAbsCoefs(AdaptationState,
499                                                  BlackPointIn,
500                                                  WhitePointIn, IlluminantIn,
501                                                  ChromaticAdaptationMatrixIn,
502                                                  BlackPointOut,
503                                                  WhitePointOut, cmsD50_XYZ(),
504                                                  ChromaticAdaptationMatrixOut,
505                                                  m, of);
506                              *fn1 = Lab2XYZ2Lab;
507                      }
508                      else
509                      {      // Lab -> Lab relative don't need any adjust unless
510                             // black point compensation
511 
512                             *fn1 = NULL;
513                              if (DoBlackPointCompensation) {
514 
515                                  *fn1 = Lab2XYZ2Lab;
516                                  ComputeBlackPointCompensationFactors(BlackPointIn,
517                                                                       WhitePointIn,
518                                                                       IlluminantIn,
519                                                                       BlackPointOut,
520                                                                       WhitePointOut,
521                                                                       IlluminantOut,
522                                                                       m, of);
523 
524 
525                             }
526                      }
527                      break;
528 
529 
530               default: return FALSE;
531               }
532 
533    return TRUE;
534 }
535 
536 
537 // This function does calculate the necessary conversion operations
538 // needed from transpassing data from a LUT to a LUT. The conversion
539 // is modeled as a pointer of function and two coefficients, a and b
540 // The function is actually called only if not null pointer is provided,
541 // and the two paramaters are passed in. There are several types of
542 // conversions, but basically they do a linear scalling and a interchange
543 
544 
545 
546 // Main dispatcher
547 
cmsChooseCnvrt(int Absolute,int Phase1,LPcmsCIEXYZ BlackPointIn,LPcmsCIEXYZ WhitePointIn,LPcmsCIEXYZ IlluminantIn,LPMAT3 ChromaticAdaptationMatrixIn,int Phase2,LPcmsCIEXYZ BlackPointOut,LPcmsCIEXYZ WhitePointOut,LPcmsCIEXYZ IlluminantOut,LPMAT3 ChromaticAdaptationMatrixOut,int DoBlackPointCompensation,double AdaptationState,_cmsADJFN * fn1,LPWMAT3 wm,LPWVEC3 wof)548 int cmsChooseCnvrt(int Absolute,
549                   int Phase1, LPcmsCIEXYZ BlackPointIn,
550                               LPcmsCIEXYZ WhitePointIn,
551                               LPcmsCIEXYZ IlluminantIn,
552                               LPMAT3 ChromaticAdaptationMatrixIn,
553 
554                   int Phase2, LPcmsCIEXYZ BlackPointOut,
555                               LPcmsCIEXYZ WhitePointOut,
556                               LPcmsCIEXYZ IlluminantOut,
557                               LPMAT3 ChromaticAdaptationMatrixOut,
558 
559                   int DoBlackPointCompensation,
560                   double AdaptationState,
561                   _cmsADJFN *fn1,
562                   LPWMAT3 wm, LPWVEC3 wof)
563 {
564 
565        int rc;
566        MAT3 m;
567        VEC3 of;
568 
569 
570        MAT3identity(&m);
571        VEC3init(&of, 0, 0, 0);
572 
573        switch (Phase1) {
574 
575        // Input LUT is giving XYZ relative values.
576 
577        case XYZRel:  rc = FromXYZRelLUT(Absolute,
578                                           BlackPointIn,
579                                           WhitePointIn,
580                                           IlluminantIn,
581                                           ChromaticAdaptationMatrixIn,
582                                           Phase2,
583                                           BlackPointOut,
584                                           WhitePointOut,
585                                           IlluminantOut,
586                                           ChromaticAdaptationMatrixOut,
587                                           DoBlackPointCompensation,
588                                           AdaptationState,
589                                           fn1, &m, &of);
590                      break;
591 
592 
593 
594        // Input LUT is giving Lab relative values
595 
596        case LabRel:  rc =  FromLabRelLUT(Absolute,
597                                           BlackPointIn,
598                                           WhitePointIn,
599                                           IlluminantIn,
600                                           ChromaticAdaptationMatrixIn,
601                                           Phase2,
602                                           BlackPointOut,
603                                           WhitePointOut,
604                                           IlluminantOut,
605                                           ChromaticAdaptationMatrixOut,
606                                           DoBlackPointCompensation,
607                                           AdaptationState,
608                                           fn1, &m, &of);
609                      break;
610 
611 
612 
613 
614        // Unrecognized combination
615 
616        default:    cmsSignalError(LCMS_ERRC_ABORTED, "(internal) Phase error");
617                    return FALSE;
618 
619        }
620 
621        MAT3toFix(wm, &m);
622        VEC3toFix(wof, &of);
623 
624        // Do some optimization -- discard conversion if identity parameters.
625 
626        if (*fn1 == XYZ2XYZ || *fn1 == Lab2XYZ2Lab) {
627 
628            if (IdentityParameters(wm, wof))
629                *fn1 = NULL;
630        }
631 
632 
633        return rc;
634 }
635 
636 
637 
638