1ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov//---------------------------------------------------------------------------------
2ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov//
3ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov//  Little Color Management System
4ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov//  Copyright (c) 1998-2011 Marti Maria Saguer
5ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov//
6ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// Permission is hereby granted, free of charge, to any person obtaining
7ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// a copy of this software and associated documentation files (the "Software"),
8ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// to deal in the Software without restriction, including without limitation
9ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// the rights to use, copy, modify, merge, publish, distribute, sublicense,
10ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// and/or sell copies of the Software, and to permit persons to whom the Software
11ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// is furnished to do so, subject to the following conditions:
12ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov//
13ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// The above copyright notice and this permission notice shall be included in
14ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// all copies or substantial portions of the Software.
15ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov//
16ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
18ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov//
24ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov//---------------------------------------------------------------------------------
25ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov//
26ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
27ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#include "lcms2_internal.h"
28ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
29ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// PostScript ColorRenderingDictionary and ColorSpaceArray
30ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
31ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
32ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#define MAXPSCOLS   60      // Columns on tables
33ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
34ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov/*
35ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    Implementation
36ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    --------------
37ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
38ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  PostScript does use XYZ as its internal PCS. But since PostScript
39ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  interpolation tables are limited to 8 bits, I use Lab as a way to
40ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  improve the accuracy, favoring perceptual results. So, for the creation
41ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  of each CRD, CSA the profiles are converted to Lab via a device
42ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  link between  profile -> Lab or Lab -> profile. The PS code necessary to
43ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  convert Lab <-> XYZ is also included.
44ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
45ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
46ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
47ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  Color Space Arrays (CSA)
48ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  ==================================================================================
49ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
50ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  In order to obtain precision, code chooses between three ways to implement
51ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  the device -> XYZ transform. These cases identifies monochrome profiles (often
52ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  implemented as a set of curves), matrix-shaper and Pipeline-based.
53ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
54ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  Monochrome
55ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  -----------
56ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
57ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  This is implemented as /CIEBasedA CSA. The prelinearization curve is
58ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  placed into /DecodeA section, and matrix equals to D50. Since here is
59ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  no interpolation tables, I do the conversion directly to XYZ
60ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
61ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  NOTE: CLUT-based monochrome profiles are NOT supported. So, cmsFLAGS_MATRIXINPUT
62ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  flag is forced on such profiles.
63ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
64ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    [ /CIEBasedA
65ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      <<
66ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            /DecodeA { transfer function } bind
67ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            /MatrixA [D50]
68ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            /RangeLMN [ 0.0 cmsD50X 0.0 cmsD50Y 0.0 cmsD50Z ]
69ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            /WhitePoint [D50]
70ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            /BlackPoint [BP]
71ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            /RenderingIntent (intent)
72ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      >>
73ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    ]
74ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
75ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov   On simpler profiles, the PCS is already XYZ, so no conversion is required.
76ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
77ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
78ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov   Matrix-shaper based
79ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov   -------------------
80ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
81ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov   This is implemented both with /CIEBasedABC or /CIEBasedDEF on dependig
82ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov   of profile implementation. Since here there are no interpolation tables, I do
83ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov   the conversion directly to XYZ
84ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
85ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
86ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
87ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    [ /CIEBasedABC
88ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            <<
89ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                /DecodeABC [ {transfer1} {transfer2} {transfer3} ]
90ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                /MatrixABC [Matrix]
91ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                /RangeLMN [ 0.0 cmsD50X 0.0 cmsD50Y 0.0 cmsD50Z ]
92ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                /DecodeLMN [ { / 2} dup dup ]
93ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                /WhitePoint [D50]
94ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                /BlackPoint [BP]
95ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                /RenderingIntent (intent)
96ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            >>
97ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    ]
98ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
99ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
100ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    CLUT based
101ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    ----------
102ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
103ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov     Lab is used in such cases.
104ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
105ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    [ /CIEBasedDEF
106ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            <<
107ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            /DecodeDEF [ <prelinearization> ]
108ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            /Table [ p p p [<...>]]
109ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            /RangeABC [ 0 1 0 1 0 1]
110ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            /DecodeABC[ <postlinearization> ]
111ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            /RangeLMN [ -0.236 1.254 0 1 -0.635 1.640 ]
112ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov               % -128/500 1+127/500 0 1  -127/200 1+128/200
113ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            /MatrixABC [ 1 1 1 1 0 0 0 0 -1]
114ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            /WhitePoint [D50]
115ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            /BlackPoint [BP]
116ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            /RenderingIntent (intent)
117ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    ]
118ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
119ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
120ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  Color Rendering Dictionaries (CRD)
121ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  ==================================
122ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  These are always implemented as CLUT, and always are using Lab. Since CRD are expected to
123ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  be used as resources, the code adds the definition as well.
124ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
125ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  <<
126ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /ColorRenderingType 1
127ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /WhitePoint [ D50 ]
128ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /BlackPoint [BP]
129ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /MatrixPQR [ Bradford ]
130ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /RangePQR [-0.125 1.375 -0.125 1.375 -0.125 1.375 ]
131ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /TransformPQR [
132ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    {4 index 3 get div 2 index 3 get mul exch pop exch pop exch pop exch pop } bind
133ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    {4 index 4 get div 2 index 4 get mul exch pop exch pop exch pop exch pop } bind
134ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    {4 index 5 get div 2 index 5 get mul exch pop exch pop exch pop exch pop } bind
135ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    ]
136ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /MatrixABC <...>
137ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /EncodeABC <...>
138ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /RangeABC  <.. used for  XYZ -> Lab>
139ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /EncodeLMN
140ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /RenderTable [ p p p [<...>]]
141ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
142ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /RenderingIntent (Perceptual)
143ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  >>
144ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /Current exch /ColorRendering defineresource pop
145ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
146ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
147ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  The following stages are used to convert from XYZ to Lab
148ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  --------------------------------------------------------
149ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
150ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  Input is given at LMN stage on X, Y, Z
151ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
152ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  Encode LMN gives us f(X/Xn), f(Y/Yn), f(Z/Zn)
153ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
154ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /EncodeLMN [
155ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
156ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    { 0.964200  div dup 0.008856 le {7.787 mul 16 116 div add}{1 3 div exp} ifelse } bind
157ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    { 1.000000  div dup 0.008856 le {7.787 mul 16 116 div add}{1 3 div exp} ifelse } bind
158ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    { 0.824900  div dup 0.008856 le {7.787 mul 16 116 div add}{1 3 div exp} ifelse } bind
159ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
160ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    ]
161ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
162ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
163ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  MatrixABC is used to compute f(Y/Yn), f(X/Xn) - f(Y/Yn), f(Y/Yn) - f(Z/Zn)
164ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
165ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  | 0  1  0|
166ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  | 1 -1  0|
167ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  | 0  1 -1|
168ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
169ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /MatrixABC [ 0 1 0 1 -1 1 0 0 -1 ]
170ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
171ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov EncodeABC finally gives Lab values.
172ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
173ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /EncodeABC [
174ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    { 116 mul  16 sub 100 div  } bind
175ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    { 500 mul 128 add 255 div  } bind
176ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    { 200 mul 128 add 255 div  } bind
177ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    ]
178ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
179ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  The following stages are used to convert Lab to XYZ
180ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  ----------------------------------------------------
181ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
182ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /RangeABC [ 0 1 0 1 0 1]
183ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /DecodeABC [ { 100 mul 16 add 116 div } bind
184ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                 { 255 mul 128 sub 500 div } bind
185ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                 { 255 mul 128 sub 200 div } bind
186ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov               ]
187ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
188ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /MatrixABC [ 1 1 1 1 0 0 0 0 -1]
189ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /DecodeLMN [
190ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                {dup 6 29 div ge {dup dup mul mul} {4 29 div sub 108 841 div mul} ifelse 0.964200 mul} bind
191ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                {dup 6 29 div ge {dup dup mul mul} {4 29 div sub 108 841 div mul} ifelse } bind
192ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                {dup 6 29 div ge {dup dup mul mul} {4 29 div sub 108 841 div mul} ifelse 0.824900 mul} bind
193ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                ]
194ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
195ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
196ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov*/
197ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
198ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov/*
199ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
200ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov PostScript algorithms discussion.
201ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov =========================================================================================================
202ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
203ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  1D interpolation algorithm
204ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
205ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
206ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  1D interpolation (float)
207ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  ------------------------
208ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
209ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    val2 = Domain * Value;
210ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
211ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cell0 = (int) floor(val2);
212ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cell1 = (int) ceil(val2);
213ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
214ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    rest = val2 - cell0;
215ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
216ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    y0 = LutTable[cell0] ;
217ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    y1 = LutTable[cell1] ;
218ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
219ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    y = y0 + (y1 - y0) * rest;
220ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
221ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
222ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
223ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  PostScript code                   Stack
224ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  ================================================
225ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
226ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  {                                 % v
227ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    <check 0..1.0>
228ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    [array]                         % v tab
229ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    dup                             % v tab tab
230ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    length 1 sub                    % v tab dom
231ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
232ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    3 -1 roll                       % tab dom v
233ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
234ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    mul                             % tab val2
235ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    dup                             % tab val2 val2
236ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    dup                             % tab val2 val2 val2
237ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    floor cvi                       % tab val2 val2 cell0
238ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    exch                            % tab val2 cell0 val2
239ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    ceiling cvi                     % tab val2 cell0 cell1
240ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
241ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    3 index                         % tab val2 cell0 cell1 tab
242ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    exch                            % tab val2 cell0 tab cell1
243ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    get                             % tab val2 cell0 y1
244ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
245ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    4 -1 roll                       % val2 cell0 y1 tab
246ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    3 -1 roll                       % val2 y1 tab cell0
247ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    get                             % val2 y1 y0
248ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
249ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    dup                             % val2 y1 y0 y0
250ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    3 1 roll                        % val2 y0 y1 y0
251ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
252ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    sub                             % val2 y0 (y1-y0)
253ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    3 -1 roll                       % y0 (y1-y0) val2
254ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    dup                             % y0 (y1-y0) val2 val2
255ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    floor cvi                       % y0 (y1-y0) val2 floor(val2)
256ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    sub                             % y0 (y1-y0) rest
257ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    mul                             % y0 t1
258ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    add                             % y
259ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    65535 div                       % result
260ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
261ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  } bind
262ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
263ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
264ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov*/
265ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
266ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
267ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// This struct holds the memory block currently being write
268ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovtypedef struct {
269ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    _cmsStageCLutData* Pipeline;
270ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmsIOHANDLER* m;
271ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
272ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    int FirstComponent;
273ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    int SecondComponent;
274ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
275ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    const char* PreMaj;
276ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    const char* PostMaj;
277ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    const char* PreMin;
278ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    const char* PostMin;
279ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
280ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    int  FixWhite;    // Force mapping of pure white
281ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
282ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmsColorSpaceSignature  ColorSpace;  // ColorSpace of profile
283ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
284ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
285ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} cmsPsSamplerCargo;
286ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
287ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovstatic int _cmsPSActualColumn = 0;
288ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
289ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
290ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// Convert to byte
291ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovstatic
292ee451cb395940862dad63c85adfe8f2fd55e864cSvet GanovcmsUInt8Number Word2Byte(cmsUInt16Number w)
293ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{
294ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return (cmsUInt8Number) floor((cmsFloat64Number) w / 257.0 + 0.5);
295ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov}
296ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
297ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
298ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// Convert to byte (using ICC2 notation)
299ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov/*
300ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovstatic
301ee451cb395940862dad63c85adfe8f2fd55e864cSvet GanovcmsUInt8Number L2Byte(cmsUInt16Number w)
302ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{
303ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    int ww = w + 0x0080;
304ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
305ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (ww > 0xFFFF) return 0xFF;
306ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
307ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return (cmsUInt8Number) ((cmsUInt16Number) (ww >> 8) & 0xFF);
308ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov}
309ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov*/
310ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
311ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// Write a cooked byte
312ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
313ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovstatic
314ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovvoid WriteByte(cmsIOHANDLER* m, cmsUInt8Number b)
315ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{
316ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    _cmsIOPrintf(m, "%02x", b);
317ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    _cmsPSActualColumn += 2;
318ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
319ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (_cmsPSActualColumn > MAXPSCOLS) {
320ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
321ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        _cmsIOPrintf(m, "\n");
322ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        _cmsPSActualColumn = 0;
323ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
324ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov}
325ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
326ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// ----------------------------------------------------------------- PostScript generation
327ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
328ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
329ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// Removes offending Carriage returns
330ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovstatic
331ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovchar* RemoveCR(const char* txt)
332ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{
333ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    static char Buffer[2048];
334ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    char* pt;
335ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
336ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    strncpy(Buffer, txt, 2047);
337ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    Buffer[2047] = 0;
338ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    for (pt = Buffer; *pt; pt++)
339ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            if (*pt == '\n' || *pt == '\r') *pt = ' ';
340ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
341ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return Buffer;
342ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
343ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov}
344ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
345ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovstatic
346ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovvoid EmitHeader(cmsIOHANDLER* m, const char* Title, cmsHPROFILE hProfile)
347ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{
348ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    time_t timer;
349ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmsMLU *Description, *Copyright;
350ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    char DescASCII[256], CopyrightASCII[256];
351ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
352ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    time(&timer);
353ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
354ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    Description = (cmsMLU*) cmsReadTag(hProfile, cmsSigProfileDescriptionTag);
355ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    Copyright   = (cmsMLU*) cmsReadTag(hProfile, cmsSigCopyrightTag);
356ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
357ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    DescASCII[0] = DescASCII[255] = 0;
358ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    CopyrightASCII[0] = CopyrightASCII[255] = 0;
359ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
360ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (Description != NULL) cmsMLUgetASCII(Description,  cmsNoLanguage, cmsNoCountry, DescASCII,       255);
361ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (Copyright != NULL)   cmsMLUgetASCII(Copyright,    cmsNoLanguage, cmsNoCountry, CopyrightASCII,  255);
362ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
363ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    _cmsIOPrintf(m, "%%!PS-Adobe-3.0\n");
364ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    _cmsIOPrintf(m, "%%\n");
365ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    _cmsIOPrintf(m, "%% %s\n", Title);
366ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    _cmsIOPrintf(m, "%% Source: %s\n", RemoveCR(DescASCII));
367ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    _cmsIOPrintf(m, "%%         %s\n", RemoveCR(CopyrightASCII));
368ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    _cmsIOPrintf(m, "%% Created: %s", ctime(&timer)); // ctime appends a \n!!!
369ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    _cmsIOPrintf(m, "%%\n");
370ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    _cmsIOPrintf(m, "%%%%BeginResource\n");
371ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
372ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov}
373ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
374ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
375ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// Emits White & Black point. White point is always D50, Black point is the device
376ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// Black point adapted to D50.
377ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
378ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovstatic
379ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovvoid EmitWhiteBlackD50(cmsIOHANDLER* m, cmsCIEXYZ* BlackPoint)
380ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{
381ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
382ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    _cmsIOPrintf(m, "/BlackPoint [%f %f %f]\n", BlackPoint -> X,
383ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                          BlackPoint -> Y,
384ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                          BlackPoint -> Z);
385ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
386ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    _cmsIOPrintf(m, "/WhitePoint [%f %f %f]\n", cmsD50_XYZ()->X,
387ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                          cmsD50_XYZ()->Y,
388ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                          cmsD50_XYZ()->Z);
389ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov}
390ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
391ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
392ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovstatic
393ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovvoid EmitRangeCheck(cmsIOHANDLER* m)
394ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{
395ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    _cmsIOPrintf(m, "dup 0.0 lt { pop 0.0 } if "
396ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                    "dup 1.0 gt { pop 1.0 } if ");
397ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
398ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov}
399ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
400ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// Does write the intent
401ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
402ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovstatic
403ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovvoid EmitIntent(cmsIOHANDLER* m, int RenderingIntent)
404ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{
405ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    const char *intent;
406ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
407ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    switch (RenderingIntent) {
408ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
409ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        case INTENT_PERCEPTUAL:            intent = "Perceptual"; break;
410ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        case INTENT_RELATIVE_COLORIMETRIC: intent = "RelativeColorimetric"; break;
411ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        case INTENT_ABSOLUTE_COLORIMETRIC: intent = "AbsoluteColorimetric"; break;
412ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        case INTENT_SATURATION:            intent = "Saturation"; break;
413ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
414ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        default: intent = "Undefined"; break;
415ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
416ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
417ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    _cmsIOPrintf(m, "/RenderingIntent (%s)\n", intent );
418ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov}
419ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
420ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov//
421ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov//  Convert L* to Y
422ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov//
423ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov//      Y = Yn*[ (L* + 16) / 116] ^ 3   if (L*) >= 6 / 29
424ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov//        = Yn*( L* / 116) / 7.787      if (L*) < 6 / 29
425ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov//
426ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
427ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov/*
428ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovstatic
429ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovvoid EmitL2Y(cmsIOHANDLER* m)
430ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{
431ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    _cmsIOPrintf(m,
432ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            "{ "
433ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                "100 mul 16 add 116 div "               // (L * 100 + 16) / 116
434ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                 "dup 6 29 div ge "                     // >= 6 / 29 ?
435ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                 "{ dup dup mul mul } "                 // yes, ^3 and done
436ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                 "{ 4 29 div sub 108 841 div mul } "    // no, slope limiting
437ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            "ifelse } bind ");
438ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov}
439ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov*/
440ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
441ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
442ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// Lab -> XYZ, see the discussion above
443ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
444ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovstatic
445ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovvoid EmitLab2XYZ(cmsIOHANDLER* m)
446ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{
447ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    _cmsIOPrintf(m, "/RangeABC [ 0 1 0 1 0 1]\n");
448ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    _cmsIOPrintf(m, "/DecodeABC [\n");
449ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    _cmsIOPrintf(m, "{100 mul  16 add 116 div } bind\n");
450ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    _cmsIOPrintf(m, "{255 mul 128 sub 500 div } bind\n");
451ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    _cmsIOPrintf(m, "{255 mul 128 sub 200 div } bind\n");
452ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    _cmsIOPrintf(m, "]\n");
453ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    _cmsIOPrintf(m, "/MatrixABC [ 1 1 1 1 0 0 0 0 -1]\n");
454ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    _cmsIOPrintf(m, "/RangeLMN [ -0.236 1.254 0 1 -0.635 1.640 ]\n");
455ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    _cmsIOPrintf(m, "/DecodeLMN [\n");
456ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    _cmsIOPrintf(m, "{dup 6 29 div ge {dup dup mul mul} {4 29 div sub 108 841 div mul} ifelse 0.964200 mul} bind\n");
457ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    _cmsIOPrintf(m, "{dup 6 29 div ge {dup dup mul mul} {4 29 div sub 108 841 div mul} ifelse } bind\n");
458ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    _cmsIOPrintf(m, "{dup 6 29 div ge {dup dup mul mul} {4 29 div sub 108 841 div mul} ifelse 0.824900 mul} bind\n");
459ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    _cmsIOPrintf(m, "]\n");
460ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov}
461ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
462ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
463ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
464ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// Outputs a table of words. It does use 16 bits
465ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
466ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovstatic
467ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovvoid Emit1Gamma(cmsIOHANDLER* m, cmsToneCurve* Table)
468ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{
469ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmsUInt32Number i;
470ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmsFloat64Number gamma;
471ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
472ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (Table == NULL) return; // Error
473ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
474ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (Table ->nEntries <= 0) return;  // Empty table
475ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
476ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    // Suppress whole if identity
477ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (cmsIsToneCurveLinear(Table)) return;
478ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
479ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    // Check if is really an exponential. If so, emit "exp"
480ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    gamma = cmsEstimateGamma(Table, 0.001);
481ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov     if (gamma > 0) {
482ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            _cmsIOPrintf(m, "{ %g exp } bind ", gamma);
483ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            return;
484ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov     }
485ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
486ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    _cmsIOPrintf(m, "{ ");
487ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
488ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    // Bounds check
489ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    EmitRangeCheck(m);
490ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
491ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    // Emit intepolation code
492ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
493ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    // PostScript code                      Stack
494ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    // ===============                      ========================
495ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                            // v
496ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    _cmsIOPrintf(m, " [");
497ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
498ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    for (i=0; i < Table->nEntries; i++) {
499ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        _cmsIOPrintf(m, "%d ", Table->Table16[i]);
500ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
501ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
502ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    _cmsIOPrintf(m, "] ");                        // v tab
503ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
504ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    _cmsIOPrintf(m, "dup ");                      // v tab tab
505ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    _cmsIOPrintf(m, "length 1 sub ");             // v tab dom
506ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    _cmsIOPrintf(m, "3 -1 roll ");                // tab dom v
507ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    _cmsIOPrintf(m, "mul ");                      // tab val2
508ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    _cmsIOPrintf(m, "dup ");                      // tab val2 val2
509ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    _cmsIOPrintf(m, "dup ");                      // tab val2 val2 val2
510ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    _cmsIOPrintf(m, "floor cvi ");                // tab val2 val2 cell0
511ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    _cmsIOPrintf(m, "exch ");                     // tab val2 cell0 val2
512ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    _cmsIOPrintf(m, "ceiling cvi ");              // tab val2 cell0 cell1
513ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    _cmsIOPrintf(m, "3 index ");                  // tab val2 cell0 cell1 tab
514ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    _cmsIOPrintf(m, "exch ");                     // tab val2 cell0 tab cell1
515ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    _cmsIOPrintf(m, "get ");                      // tab val2 cell0 y1
516ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    _cmsIOPrintf(m, "4 -1 roll ");                // val2 cell0 y1 tab
517ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    _cmsIOPrintf(m, "3 -1 roll ");                // val2 y1 tab cell0
518ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    _cmsIOPrintf(m, "get ");                      // val2 y1 y0
519ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    _cmsIOPrintf(m, "dup ");                      // val2 y1 y0 y0
520ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    _cmsIOPrintf(m, "3 1 roll ");                 // val2 y0 y1 y0
521ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    _cmsIOPrintf(m, "sub ");                      // val2 y0 (y1-y0)
522ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    _cmsIOPrintf(m, "3 -1 roll ");                // y0 (y1-y0) val2
523ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    _cmsIOPrintf(m, "dup ");                      // y0 (y1-y0) val2 val2
524ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    _cmsIOPrintf(m, "floor cvi ");                // y0 (y1-y0) val2 floor(val2)
525ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    _cmsIOPrintf(m, "sub ");                      // y0 (y1-y0) rest
526ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    _cmsIOPrintf(m, "mul ");                      // y0 t1
527ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    _cmsIOPrintf(m, "add ");                      // y
528ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    _cmsIOPrintf(m, "65535 div ");                // result
529ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
530ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    _cmsIOPrintf(m, " } bind ");
531ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov}
532ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
533ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
534ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// Compare gamma table
535ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
536ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovstatic
537ee451cb395940862dad63c85adfe8f2fd55e864cSvet GanovcmsBool GammaTableEquals(cmsUInt16Number* g1, cmsUInt16Number* g2, int nEntries)
538ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{
539ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return memcmp(g1, g2, nEntries* sizeof(cmsUInt16Number)) == 0;
540ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov}
541ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
542ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
543ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// Does write a set of gamma curves
544ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
545ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovstatic
546ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovvoid EmitNGamma(cmsIOHANDLER* m, int n, cmsToneCurve* g[])
547ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{
548ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    int i;
549ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
550ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    for( i=0; i < n; i++ )
551ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    {
552ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if (g[i] == NULL) return; // Error
553ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
554ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if (i > 0 && GammaTableEquals(g[i-1]->Table16, g[i]->Table16, g[i]->nEntries)) {
555ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
556ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            _cmsIOPrintf(m, "dup ");
557ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
558ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        else {
559ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            Emit1Gamma(m, g[i]);
560ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
561ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
562ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
563ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov}
564ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
565ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
566ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
567ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
568ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
569ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// Following code dumps a LUT onto memory stream
570ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
571ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
572ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// This is the sampler. Intended to work in SAMPLER_INSPECT mode,
573ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// that is, the callback will be called for each knot with
574ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov//
575ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov//          In[]  The grid location coordinates, normalized to 0..ffff
576ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov//          Out[] The Pipeline values, normalized to 0..ffff
577ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov//
578ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov//  Returning a value other than 0 does terminate the sampling process
579ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov//
580ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov//  Each row contains Pipeline values for all but first component. So, I
581ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov//  detect row changing by keeping a copy of last value of first
582ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov//  component. -1 is used to mark begining of whole block.
583ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
584ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovstatic
585ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovint OutputValueSampler(register const cmsUInt16Number In[], register cmsUInt16Number Out[], register void* Cargo)
586ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{
587ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmsPsSamplerCargo* sc = (cmsPsSamplerCargo*) Cargo;
588ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmsUInt32Number i;
589ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
590ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
591ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (sc -> FixWhite) {
592ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
593ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if (In[0] == 0xFFFF) {  // Only in L* = 100, ab = [-8..8]
594ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
595ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            if ((In[1] >= 0x7800 && In[1] <= 0x8800) &&
596ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                (In[2] >= 0x7800 && In[2] <= 0x8800)) {
597ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
598ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                cmsUInt16Number* Black;
599ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                cmsUInt16Number* White;
600ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                cmsUInt32Number nOutputs;
601ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
602ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                if (!_cmsEndPointsBySpace(sc ->ColorSpace, &White, &Black, &nOutputs))
603ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                        return 0;
604ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
605ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                for (i=0; i < nOutputs; i++)
606ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                        Out[i] = White[i];
607ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            }
608ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
609ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
610ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
611ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
612ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
613ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
614ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    // Hadle the parenthesis on rows
615ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
616ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (In[0] != sc ->FirstComponent) {
617ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
618ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            if (sc ->FirstComponent != -1) {
619ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
620ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                    _cmsIOPrintf(sc ->m, sc ->PostMin);
621ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                    sc ->SecondComponent = -1;
622ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                    _cmsIOPrintf(sc ->m, sc ->PostMaj);
623ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            }
624ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
625ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            // Begin block
626ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            _cmsPSActualColumn = 0;
627ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
628ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            _cmsIOPrintf(sc ->m, sc ->PreMaj);
629ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            sc ->FirstComponent = In[0];
630ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
631ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
632ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
633ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      if (In[1] != sc ->SecondComponent) {
634ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
635ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            if (sc ->SecondComponent != -1) {
636ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
637ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                    _cmsIOPrintf(sc ->m, sc ->PostMin);
638ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            }
639ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
640ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            _cmsIOPrintf(sc ->m, sc ->PreMin);
641ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            sc ->SecondComponent = In[1];
642ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
643ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
644ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      // Dump table.
645ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
646ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      for (i=0; i < sc -> Pipeline ->Params->nOutputs; i++) {
647ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
648ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          cmsUInt16Number wWordOut = Out[i];
649ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          cmsUInt8Number wByteOut;           // Value as byte
650ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
651ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
652ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          // We always deal with Lab4
653ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
654ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          wByteOut = Word2Byte(wWordOut);
655ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          WriteByte(sc -> m, wByteOut);
656ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      }
657ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
658ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      return 1;
659ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov}
660ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
661ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// Writes a Pipeline on memstream. Could be 8 or 16 bits based
662ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
663ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovstatic
664ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovvoid WriteCLUT(cmsIOHANDLER* m, cmsStage* mpe, const char* PreMaj,
665ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                             const char* PostMaj,
666ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                             const char* PreMin,
667ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                             const char* PostMin,
668ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                             int FixWhite,
669ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                             cmsColorSpaceSignature ColorSpace)
670ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{
671ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmsUInt32Number i;
672ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmsPsSamplerCargo sc;
673ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
674ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    sc.FirstComponent = -1;
675ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    sc.SecondComponent = -1;
676ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    sc.Pipeline = (_cmsStageCLutData *) mpe ->Data;
677ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    sc.m   = m;
678ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    sc.PreMaj = PreMaj;
679ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    sc.PostMaj= PostMaj;
680ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
681ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    sc.PreMin   = PreMin;
682ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    sc.PostMin  = PostMin;
683ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    sc.FixWhite = FixWhite;
684ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    sc.ColorSpace = ColorSpace;
685ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
686ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    _cmsIOPrintf(m, "[");
687ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
688ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    for (i=0; i < sc.Pipeline->Params->nInputs; i++)
689ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        _cmsIOPrintf(m, " %d ", sc.Pipeline->Params->nSamples[i]);
690ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
691ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    _cmsIOPrintf(m, " [\n");
692ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
693ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmsStageSampleCLut16bit(mpe, OutputValueSampler, (void*) &sc, SAMPLER_INSPECT);
694ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
695ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    _cmsIOPrintf(m, PostMin);
696ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    _cmsIOPrintf(m, PostMaj);
697ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    _cmsIOPrintf(m, "] ");
698ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
699ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov}
700ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
701ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
702ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// Dumps CIEBasedA Color Space Array
703ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
704ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovstatic
705ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovint EmitCIEBasedA(cmsIOHANDLER* m, cmsToneCurve* Curve, cmsCIEXYZ* BlackPoint)
706ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{
707ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
708ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    _cmsIOPrintf(m, "[ /CIEBasedA\n");
709ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    _cmsIOPrintf(m, "  <<\n");
710ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
711ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    _cmsIOPrintf(m, "/DecodeA ");
712ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
713ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    Emit1Gamma(m, Curve);
714ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
715ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    _cmsIOPrintf(m, " \n");
716ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
717ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    _cmsIOPrintf(m, "/MatrixA [ 0.9642 1.0000 0.8249 ]\n");
718ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    _cmsIOPrintf(m, "/RangeLMN [ 0.0 0.9642 0.0 1.0000 0.0 0.8249 ]\n");
719ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
720ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    EmitWhiteBlackD50(m, BlackPoint);
721ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    EmitIntent(m, INTENT_PERCEPTUAL);
722ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
723ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    _cmsIOPrintf(m, ">>\n");
724ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    _cmsIOPrintf(m, "]\n");
725ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
726ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return 1;
727ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov}
728ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
729ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
730ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// Dumps CIEBasedABC Color Space Array
731ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
732ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovstatic
733ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovint EmitCIEBasedABC(cmsIOHANDLER* m, cmsFloat64Number* Matrix, cmsToneCurve** CurveSet, cmsCIEXYZ* BlackPoint)
734ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{
735ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    int i;
736ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
737ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    _cmsIOPrintf(m, "[ /CIEBasedABC\n");
738ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    _cmsIOPrintf(m, "<<\n");
739ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    _cmsIOPrintf(m, "/DecodeABC [ ");
740ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
741ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    EmitNGamma(m, 3, CurveSet);
742ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
743ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    _cmsIOPrintf(m, "]\n");
744ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
745ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    _cmsIOPrintf(m, "/MatrixABC [ " );
746ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
747ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    for( i=0; i < 3; i++ ) {
748ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
749ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        _cmsIOPrintf(m, "%.6f %.6f %.6f ", Matrix[i + 3*0],
750ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                           Matrix[i + 3*1],
751ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                           Matrix[i + 3*2]);
752ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
753ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
754ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
755ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    _cmsIOPrintf(m, "]\n");
756ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
757ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    _cmsIOPrintf(m, "/RangeLMN [ 0.0 0.9642 0.0 1.0000 0.0 0.8249 ]\n");
758ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
759ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    EmitWhiteBlackD50(m, BlackPoint);
760ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    EmitIntent(m, INTENT_PERCEPTUAL);
761ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
762ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    _cmsIOPrintf(m, ">>\n");
763ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    _cmsIOPrintf(m, "]\n");
764ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
765ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
766ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return 1;
767ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov}
768ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
769ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
770ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovstatic
771ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovint EmitCIEBasedDEF(cmsIOHANDLER* m, cmsPipeline* Pipeline, int Intent, cmsCIEXYZ* BlackPoint)
772ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{
773ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    const char* PreMaj;
774ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    const char* PostMaj;
775ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    const char* PreMin, *PostMin;
776ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmsStage* mpe;
777ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
778ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    mpe = Pipeline ->Elements;
779ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
780ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    switch (cmsStageInputChannels(mpe)) {
781ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    case 3:
782ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
783ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            _cmsIOPrintf(m, "[ /CIEBasedDEF\n");
784ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            PreMaj ="<";
785ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            PostMaj= ">\n";
786ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            PreMin = PostMin = "";
787ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            break;
788ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    case 4:
789ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            _cmsIOPrintf(m, "[ /CIEBasedDEFG\n");
790ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            PreMaj = "[";
791ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            PostMaj = "]\n";
792ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            PreMin = "<";
793ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            PostMin = ">\n";
794ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            break;
795ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    default:
796ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            return 0;
797ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
798ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
799ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
800ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    _cmsIOPrintf(m, "<<\n");
801ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
802ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (cmsStageType(mpe) == cmsSigCurveSetElemType) {
803ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
804ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        _cmsIOPrintf(m, "/DecodeDEF [ ");
805ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        EmitNGamma(m, cmsStageOutputChannels(mpe), _cmsStageGetPtrToCurveSet(mpe));
806ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        _cmsIOPrintf(m, "]\n");
807ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
808ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        mpe = mpe ->Next;
809ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
810ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
811ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (cmsStageType(mpe) == cmsSigCLutElemType) {
812ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
813ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            _cmsIOPrintf(m, "/Table ");
814ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            WriteCLUT(m, mpe, PreMaj, PostMaj, PreMin, PostMin, FALSE, (cmsColorSpaceSignature) 0);
815ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            _cmsIOPrintf(m, "]\n");
816ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
817ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
818ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    EmitLab2XYZ(m);
819ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    EmitWhiteBlackD50(m, BlackPoint);
820ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    EmitIntent(m, Intent);
821ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
822ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    _cmsIOPrintf(m, "   >>\n");
823ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    _cmsIOPrintf(m, "]\n");
824ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
825ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return 1;
826ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov}
827ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
828ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// Generates a curve from a gray profile
829ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
830ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovstatic
831ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmsToneCurve* ExtractGray2Y(cmsContext ContextID, cmsHPROFILE hProfile, int Intent)
832ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{
833ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmsToneCurve* Out = cmsBuildTabulatedToneCurve16(ContextID, 256, NULL);
834ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmsHPROFILE hXYZ  = cmsCreateXYZProfile();
835ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmsHTRANSFORM xform = cmsCreateTransformTHR(ContextID, hProfile, TYPE_GRAY_8, hXYZ, TYPE_XYZ_DBL, Intent, cmsFLAGS_NOOPTIMIZE);
836ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    int i;
837ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
838ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (Out != NULL) {
839ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        for (i=0; i < 256; i++) {
840ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
841ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            cmsUInt8Number Gray = (cmsUInt8Number) i;
842ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            cmsCIEXYZ XYZ;
843ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
844ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            cmsDoTransform(xform, &Gray, &XYZ, 1);
845ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
846ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            Out ->Table16[i] =_cmsQuickSaturateWord(XYZ.Y * 65535.0);
847ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
848ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
849ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
850ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmsDeleteTransform(xform);
851ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmsCloseProfile(hXYZ);
852ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return Out;
853ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov}
854ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
855ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
856ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
857ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// Because PostScript has only 8 bits in /Table, we should use
858ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// a more perceptually uniform space... I do choose Lab.
859ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
860ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovstatic
861ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovint WriteInputLUT(cmsIOHANDLER* m, cmsHPROFILE hProfile, int Intent, cmsUInt32Number dwFlags)
862ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{
863ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmsHPROFILE hLab;
864ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmsHTRANSFORM xform;
865ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmsUInt32Number nChannels;
866ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmsUInt32Number InputFormat;
867ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    int rc;
868ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmsHPROFILE Profiles[2];
869ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmsCIEXYZ BlackPointAdaptedToD50;
870ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
871ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    // Does create a device-link based transform.
872ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    // The DeviceLink is next dumped as working CSA.
873ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
874ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    InputFormat = cmsFormatterForColorspaceOfProfile(hProfile, 2, FALSE);
875ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    nChannels   = T_CHANNELS(InputFormat);
876ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
877ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
878ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmsDetectBlackPoint(&BlackPointAdaptedToD50, hProfile, Intent, 0);
879ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
880ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    // Adjust output to Lab4
881ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    hLab = cmsCreateLab4ProfileTHR(m ->ContextID, NULL);
882ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
883ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    Profiles[0] = hProfile;
884ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    Profiles[1] = hLab;
885ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
886ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    xform = cmsCreateMultiprofileTransform(Profiles, 2,  InputFormat, TYPE_Lab_DBL, Intent, 0);
887ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmsCloseProfile(hLab);
888ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
889ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (xform == NULL) {
890ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
891ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        cmsSignalError(m ->ContextID, cmsERROR_COLORSPACE_CHECK, "Cannot create transform Profile -> Lab");
892ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        return 0;
893ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
894ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
895ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    // Only 1, 3 and 4 channels are allowed
896ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
897ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    switch (nChannels) {
898ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
899ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    case 1: {
900ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            cmsToneCurve* Gray2Y = ExtractGray2Y(m ->ContextID, hProfile, Intent);
901ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            EmitCIEBasedA(m, Gray2Y, &BlackPointAdaptedToD50);
902ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            cmsFreeToneCurve(Gray2Y);
903ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            }
904ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            break;
905ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
906ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    case 3:
907ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    case 4: {
908ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            cmsUInt32Number OutFrm = TYPE_Lab_16;
909ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            cmsPipeline* DeviceLink;
910ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            _cmsTRANSFORM* v = (_cmsTRANSFORM*) xform;
911ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
912ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            DeviceLink = cmsPipelineDup(v ->Lut);
913ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            if (DeviceLink == NULL) return 0;
914ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
915ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            dwFlags |= cmsFLAGS_FORCE_CLUT;
916ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            _cmsOptimizePipeline(m->ContextID, &DeviceLink, Intent, &InputFormat, &OutFrm, &dwFlags);
917ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
918ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            rc = EmitCIEBasedDEF(m, DeviceLink, Intent, &BlackPointAdaptedToD50);
919ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            cmsPipelineFree(DeviceLink);
920ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            if (rc == 0) return 0;
921ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            }
922ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            break;
923ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
924ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    default:
925ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
926ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        cmsSignalError(m ->ContextID, cmsERROR_COLORSPACE_CHECK, "Only 3, 4 channels supported for CSA. This profile has %d channels.", nChannels);
927ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        return 0;
928ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
929ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
930ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
931ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmsDeleteTransform(xform);
932ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
933ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return 1;
934ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov}
935ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
936ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovstatic
937ee451cb395940862dad63c85adfe8f2fd55e864cSvet GanovcmsFloat64Number* GetPtrToMatrix(const cmsStage* mpe)
938ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{
939ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    _cmsStageMatrixData* Data = (_cmsStageMatrixData*) mpe ->Data;
940ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
941ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return Data -> Double;
942ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov}
943ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
944ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
945ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// Does create CSA based on matrix-shaper. Allowed types are gray and RGB based
946ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
947ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovstatic
948ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovint WriteInputMatrixShaper(cmsIOHANDLER* m, cmsHPROFILE hProfile, cmsStage* Matrix, cmsStage* Shaper)
949ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{
950ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmsColorSpaceSignature ColorSpace;
951ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    int rc;
952ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmsCIEXYZ BlackPointAdaptedToD50;
953ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
954ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    ColorSpace = cmsGetColorSpace(hProfile);
955ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
956ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmsDetectBlackPoint(&BlackPointAdaptedToD50, hProfile, INTENT_RELATIVE_COLORIMETRIC, 0);
957ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
958ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (ColorSpace == cmsSigGrayData) {
959ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
960ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        cmsToneCurve** ShaperCurve = _cmsStageGetPtrToCurveSet(Shaper);
961ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        rc = EmitCIEBasedA(m, ShaperCurve[0], &BlackPointAdaptedToD50);
962ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
963ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
964ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    else
965ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if (ColorSpace == cmsSigRgbData) {
966ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
967ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            cmsMAT3 Mat;
968ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            int i, j;
969ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
970ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            memmove(&Mat, GetPtrToMatrix(Matrix), sizeof(Mat));
971ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
972ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            for (i=0; i < 3; i++)
973ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                for (j=0; j < 3; j++)
974ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                    Mat.v[i].n[j] *= MAX_ENCODEABLE_XYZ;
975ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
976ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            rc = EmitCIEBasedABC(m,  (cmsFloat64Number *) &Mat,
977ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                _cmsStageGetPtrToCurveSet(Shaper),
978ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                 &BlackPointAdaptedToD50);
979ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
980ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        else  {
981ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
982ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            cmsSignalError(m ->ContextID, cmsERROR_COLORSPACE_CHECK, "Profile is not suitable for CSA. Unsupported colorspace.");
983ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            return 0;
984ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
985ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
986ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        return rc;
987ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov}
988ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
989ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
990ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
991ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// Creates a PostScript color list from a named profile data.
992ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// This is a HP extension, and it works in Lab instead of XYZ
993ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
994ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovstatic
995ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovint WriteNamedColorCSA(cmsIOHANDLER* m, cmsHPROFILE hNamedColor, int Intent)
996ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{
997ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmsHTRANSFORM xform;
998ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmsHPROFILE   hLab;
999ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    int i, nColors;
1000ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    char ColorName[32];
1001ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmsNAMEDCOLORLIST* NamedColorList;
1002ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1003ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    hLab  = cmsCreateLab4ProfileTHR(m ->ContextID, NULL);
1004ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    xform = cmsCreateTransform(hNamedColor, TYPE_NAMED_COLOR_INDEX, hLab, TYPE_Lab_DBL, Intent, 0);
1005ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (xform == NULL) return 0;
1006ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1007ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    NamedColorList = cmsGetNamedColorList(xform);
1008ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (NamedColorList == NULL) return 0;
1009ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1010ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    _cmsIOPrintf(m, "<<\n");
1011ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    _cmsIOPrintf(m, "(colorlistcomment) (%s)\n", "Named color CSA");
1012ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    _cmsIOPrintf(m, "(Prefix) [ (Pantone ) (PANTONE ) ]\n");
1013ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    _cmsIOPrintf(m, "(Suffix) [ ( CV) ( CVC) ( C) ]\n");
1014ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1015ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    nColors   = cmsNamedColorCount(NamedColorList);
1016ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1017ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1018ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    for (i=0; i < nColors; i++) {
1019ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1020ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        cmsUInt16Number In[1];
1021ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        cmsCIELab Lab;
1022ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1023ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        In[0] = (cmsUInt16Number) i;
1024ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1025ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if (!cmsNamedColorInfo(NamedColorList, i, ColorName, NULL, NULL, NULL, NULL))
1026ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                continue;
1027ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1028ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        cmsDoTransform(xform, In, &Lab, 1);
1029ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        _cmsIOPrintf(m, "  (%s) [ %.3f %.3f %.3f ]\n", ColorName, Lab.L, Lab.a, Lab.b);
1030ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
1031ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1032ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1033ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1034ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    _cmsIOPrintf(m, ">>\n");
1035ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1036ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmsDeleteTransform(xform);
1037ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmsCloseProfile(hLab);
1038ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return 1;
1039ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov}
1040ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1041ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1042ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// Does create a Color Space Array on XYZ colorspace for PostScript usage
1043ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovstatic
1044ee451cb395940862dad63c85adfe8f2fd55e864cSvet GanovcmsUInt32Number GenerateCSA(cmsContext ContextID,
1045ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                            cmsHPROFILE hProfile,
1046ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                            cmsUInt32Number Intent,
1047ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                            cmsUInt32Number dwFlags,
1048ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                            cmsIOHANDLER* mem)
1049ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{
1050ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmsUInt32Number dwBytesUsed;
1051ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmsPipeline* lut = NULL;
1052ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmsStage* Matrix, *Shaper;
1053ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1054ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1055ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    // Is a named color profile?
1056ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (cmsGetDeviceClass(hProfile) == cmsSigNamedColorClass) {
1057ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1058ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if (!WriteNamedColorCSA(mem, hProfile, Intent)) goto Error;
1059ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
1060ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    else {
1061ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1062ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1063ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        // Any profile class are allowed (including devicelink), but
1064ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        // output (PCS) colorspace must be XYZ or Lab
1065ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        cmsColorSpaceSignature ColorSpace = cmsGetPCS(hProfile);
1066ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1067ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if (ColorSpace != cmsSigXYZData &&
1068ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            ColorSpace != cmsSigLabData) {
1069ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1070ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                cmsSignalError(ContextID, cmsERROR_COLORSPACE_CHECK, "Invalid output color space");
1071ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                goto Error;
1072ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
1073ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1074ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1075ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        // Read the lut with all necessary conversion stages
1076ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        lut = _cmsReadInputLUT(hProfile, Intent);
1077ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if (lut == NULL) goto Error;
1078ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1079ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1080ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        // Tone curves + matrix can be implemented without any LUT
1081ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if (cmsPipelineCheckAndRetreiveStages(lut, 2, cmsSigCurveSetElemType, cmsSigMatrixElemType, &Shaper, &Matrix)) {
1082ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1083ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            if (!WriteInputMatrixShaper(mem, hProfile, Matrix, Shaper)) goto Error;
1084ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1085ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
1086ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        else {
1087ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov           // We need a LUT for the rest
1088ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov           if (!WriteInputLUT(mem, hProfile, Intent, dwFlags)) goto Error;
1089ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
1090ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
1091ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1092ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1093ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    // Done, keep memory usage
1094ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    dwBytesUsed = mem ->UsedSpace;
1095ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1096ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    // Get rid of LUT
1097ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (lut != NULL) cmsPipelineFree(lut);
1098ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1099ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    // Finally, return used byte count
1100ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return dwBytesUsed;
1101ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1102ee451cb395940862dad63c85adfe8f2fd55e864cSvet GanovError:
1103ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (lut != NULL) cmsPipelineFree(lut);
1104ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return 0;
1105ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov}
1106ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1107ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// ------------------------------------------------------ Color Rendering Dictionary (CRD)
1108ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1109ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1110ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1111ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov/*
1112ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1113ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  Black point compensation plus chromatic adaptation:
1114ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1115ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  Step 1 - Chromatic adaptation
1116ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  =============================
1117ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1118ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          WPout
1119ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    X = ------- PQR
1120ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          Wpin
1121ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1122ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  Step 2 - Black point compensation
1123ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  =================================
1124ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1125ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          (WPout - BPout)*X - WPout*(BPin - BPout)
1126ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    out = ---------------------------------------
1127ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                        WPout - BPin
1128ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1129ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1130ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  Algorithm discussion
1131ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  ====================
1132ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1133ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  TransformPQR(WPin, BPin, WPout, BPout, PQR)
1134ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1135ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  Wpin,etc= { Xws Yws Zws Pws Qws Rws }
1136ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1137ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1138ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  Algorithm             Stack 0...n
1139ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  ===========================================================
1140ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                        PQR BPout WPout BPin WPin
1141ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  4 index 3 get         WPin PQR BPout WPout BPin WPin
1142ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  div                   (PQR/WPin) BPout WPout BPin WPin
1143ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  2 index 3 get         WPout (PQR/WPin) BPout WPout BPin WPin
1144ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  mult                  WPout*(PQR/WPin) BPout WPout BPin WPin
1145ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1146ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  2 index 3 get         WPout WPout*(PQR/WPin) BPout WPout BPin WPin
1147ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  2 index 3 get         BPout WPout WPout*(PQR/WPin) BPout WPout BPin WPin
1148ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  sub                   (WPout-BPout) WPout*(PQR/WPin) BPout WPout BPin WPin
1149ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  mult                  (WPout-BPout)* WPout*(PQR/WPin) BPout WPout BPin WPin
1150ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1151ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  2 index 3 get         WPout (BPout-WPout)* WPout*(PQR/WPin) BPout WPout BPin WPin
1152ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  4 index 3 get         BPin WPout (BPout-WPout)* WPout*(PQR/WPin) BPout WPout BPin WPin
1153ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  3 index 3 get         BPout BPin WPout (BPout-WPout)* WPout*(PQR/WPin) BPout WPout BPin WPin
1154ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1155ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  sub                   (BPin-BPout) WPout (BPout-WPout)* WPout*(PQR/WPin) BPout WPout BPin WPin
1156ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  mult                  (BPin-BPout)*WPout (BPout-WPout)* WPout*(PQR/WPin) BPout WPout BPin WPin
1157ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  sub                   (BPout-WPout)* WPout*(PQR/WPin)-(BPin-BPout)*WPout BPout WPout BPin WPin
1158ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1159ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  3 index 3 get         BPin (BPout-WPout)* WPout*(PQR/WPin)-(BPin-BPout)*WPout BPout WPout BPin WPin
1160ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  3 index 3 get         WPout BPin (BPout-WPout)* WPout*(PQR/WPin)-(BPin-BPout)*WPout BPout WPout BPin WPin
1161ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  exch
1162ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  sub                   (WPout-BPin) (BPout-WPout)* WPout*(PQR/WPin)-(BPin-BPout)*WPout BPout WPout BPin WPin
1163ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  div
1164ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1165ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  exch pop
1166ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  exch pop
1167ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  exch pop
1168ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  exch pop
1169ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1170ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov*/
1171ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1172ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1173ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovstatic
1174ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovvoid EmitPQRStage(cmsIOHANDLER* m, cmsHPROFILE hProfile, int DoBPC, int lIsAbsolute)
1175ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{
1176ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1177ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1178ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if (lIsAbsolute) {
1179ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1180ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            // For absolute colorimetric intent, encode back to relative
1181ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            // and generate a relative Pipeline
1182ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1183ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            // Relative encoding is obtained across XYZpcs*(D50/WhitePoint)
1184ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1185ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            cmsCIEXYZ White;
1186ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1187ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            _cmsReadMediaWhitePoint(&White, hProfile);
1188ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1189ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            _cmsIOPrintf(m,"/MatrixPQR [1 0 0 0 1 0 0 0 1 ]\n");
1190ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            _cmsIOPrintf(m,"/RangePQR [ -0.5 2 -0.5 2 -0.5 2 ]\n");
1191ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1192ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            _cmsIOPrintf(m, "%% Absolute colorimetric -- encode to relative to maximize LUT usage\n"
1193ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                      "/TransformPQR [\n"
1194ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                      "{0.9642 mul %g div exch pop exch pop exch pop exch pop} bind\n"
1195ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                      "{1.0000 mul %g div exch pop exch pop exch pop exch pop} bind\n"
1196ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                      "{0.8249 mul %g div exch pop exch pop exch pop exch pop} bind\n]\n",
1197ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                      White.X, White.Y, White.Z);
1198ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            return;
1199ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
1200ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1201ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1202ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        _cmsIOPrintf(m,"%% Bradford Cone Space\n"
1203ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                 "/MatrixPQR [0.8951 -0.7502 0.0389 0.2664 1.7135 -0.0685 -0.1614 0.0367 1.0296 ] \n");
1204ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1205ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        _cmsIOPrintf(m, "/RangePQR [ -0.5 2 -0.5 2 -0.5 2 ]\n");
1206ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1207ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1208ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        // No BPC
1209ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1210ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if (!DoBPC) {
1211ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1212ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            _cmsIOPrintf(m, "%% VonKries-like transform in Bradford Cone Space\n"
1213ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                      "/TransformPQR [\n"
1214ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                      "{exch pop exch 3 get mul exch pop exch 3 get div} bind\n"
1215ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                      "{exch pop exch 4 get mul exch pop exch 4 get div} bind\n"
1216ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                      "{exch pop exch 5 get mul exch pop exch 5 get div} bind\n]\n");
1217ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        } else {
1218ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1219ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            // BPC
1220ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1221ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            _cmsIOPrintf(m, "%% VonKries-like transform in Bradford Cone Space plus BPC\n"
1222ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                      "/TransformPQR [\n");
1223ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1224ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            _cmsIOPrintf(m, "{4 index 3 get div 2 index 3 get mul "
1225ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                    "2 index 3 get 2 index 3 get sub mul "
1226ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                    "2 index 3 get 4 index 3 get 3 index 3 get sub mul sub "
1227ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                    "3 index 3 get 3 index 3 get exch sub div "
1228ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                    "exch pop exch pop exch pop exch pop } bind\n");
1229ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1230ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            _cmsIOPrintf(m, "{4 index 4 get div 2 index 4 get mul "
1231ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                    "2 index 4 get 2 index 4 get sub mul "
1232ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                    "2 index 4 get 4 index 4 get 3 index 4 get sub mul sub "
1233ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                    "3 index 4 get 3 index 4 get exch sub div "
1234ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                    "exch pop exch pop exch pop exch pop } bind\n");
1235ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1236ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            _cmsIOPrintf(m, "{4 index 5 get div 2 index 5 get mul "
1237ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                    "2 index 5 get 2 index 5 get sub mul "
1238ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                    "2 index 5 get 4 index 5 get 3 index 5 get sub mul sub "
1239ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                    "3 index 5 get 3 index 5 get exch sub div "
1240ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                    "exch pop exch pop exch pop exch pop } bind\n]\n");
1241ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1242ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
1243ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1244ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1245ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov}
1246ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1247ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1248ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovstatic
1249ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovvoid EmitXYZ2Lab(cmsIOHANDLER* m)
1250ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{
1251ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    _cmsIOPrintf(m, "/RangeLMN [ -0.635 2.0 0 2 -0.635 2.0 ]\n");
1252ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    _cmsIOPrintf(m, "/EncodeLMN [\n");
1253ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    _cmsIOPrintf(m, "{ 0.964200  div dup 0.008856 le {7.787 mul 16 116 div add}{1 3 div exp} ifelse } bind\n");
1254ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    _cmsIOPrintf(m, "{ 1.000000  div dup 0.008856 le {7.787 mul 16 116 div add}{1 3 div exp} ifelse } bind\n");
1255ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    _cmsIOPrintf(m, "{ 0.824900  div dup 0.008856 le {7.787 mul 16 116 div add}{1 3 div exp} ifelse } bind\n");
1256ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    _cmsIOPrintf(m, "]\n");
1257ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    _cmsIOPrintf(m, "/MatrixABC [ 0 1 0 1 -1 1 0 0 -1 ]\n");
1258ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    _cmsIOPrintf(m, "/EncodeABC [\n");
1259ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1260ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1261ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    _cmsIOPrintf(m, "{ 116 mul  16 sub 100 div  } bind\n");
1262ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    _cmsIOPrintf(m, "{ 500 mul 128 add 256 div  } bind\n");
1263ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    _cmsIOPrintf(m, "{ 200 mul 128 add 256 div  } bind\n");
1264ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1265ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1266ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    _cmsIOPrintf(m, "]\n");
1267ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1268ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1269ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov}
1270ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1271ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// Due to impedance mismatch between XYZ and almost all RGB and CMYK spaces
1272ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// I choose to dump LUTS in Lab instead of XYZ. There is still a lot of wasted
1273ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// space on 3D CLUT, but since space seems not to be a problem here, 33 points
1274ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// would give a reasonable accurancy. Note also that CRD tables must operate in
1275ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// 8 bits.
1276ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1277ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovstatic
1278ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovint WriteOutputLUT(cmsIOHANDLER* m, cmsHPROFILE hProfile, int Intent, cmsUInt32Number dwFlags)
1279ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{
1280ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmsHPROFILE hLab;
1281ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmsHTRANSFORM xform;
1282ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    int i, nChannels;
1283ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmsUInt32Number OutputFormat;
1284ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    _cmsTRANSFORM* v;
1285ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmsPipeline* DeviceLink;
1286ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmsHPROFILE Profiles[3];
1287ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmsCIEXYZ BlackPointAdaptedToD50;
1288ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmsBool lDoBPC = (dwFlags & cmsFLAGS_BLACKPOINTCOMPENSATION);
1289ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmsBool lFixWhite = !(dwFlags & cmsFLAGS_NOWHITEONWHITEFIXUP);
1290ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmsUInt32Number InFrm = TYPE_Lab_16;
1291ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    int RelativeEncodingIntent;
1292ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmsColorSpaceSignature ColorSpace;
1293ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1294ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1295ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    hLab = cmsCreateLab4ProfileTHR(m ->ContextID, NULL);
1296ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (hLab == NULL) return 0;
1297ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1298ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    OutputFormat = cmsFormatterForColorspaceOfProfile(hProfile, 2, FALSE);
1299ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    nChannels    = T_CHANNELS(OutputFormat);
1300ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1301ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    ColorSpace = cmsGetColorSpace(hProfile);
1302ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1303ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    // For absolute colorimetric, the LUT is encoded as relative in order to preserve precision.
1304ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1305ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    RelativeEncodingIntent = Intent;
1306ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (RelativeEncodingIntent == INTENT_ABSOLUTE_COLORIMETRIC)
1307ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        RelativeEncodingIntent = INTENT_RELATIVE_COLORIMETRIC;
1308ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1309ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1310ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    // Use V4 Lab always
1311ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    Profiles[0] = hLab;
1312ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    Profiles[1] = hProfile;
1313ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1314ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    xform = cmsCreateMultiprofileTransformTHR(m ->ContextID,
1315ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                              Profiles, 2, TYPE_Lab_DBL,
1316ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                              OutputFormat, RelativeEncodingIntent, 0);
1317ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmsCloseProfile(hLab);
1318ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1319ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (xform == NULL) {
1320ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1321ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        cmsSignalError(m ->ContextID, cmsERROR_COLORSPACE_CHECK, "Cannot create transform Lab -> Profile in CRD creation");
1322ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        return 0;
1323ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
1324ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1325ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    // Get a copy of the internal devicelink
1326ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    v = (_cmsTRANSFORM*) xform;
1327ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    DeviceLink = cmsPipelineDup(v ->Lut);
1328ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (DeviceLink == NULL) return 0;
1329ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1330ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1331ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    // We need a CLUT
1332ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    dwFlags |= cmsFLAGS_FORCE_CLUT;
1333ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    _cmsOptimizePipeline(m->ContextID, &DeviceLink, RelativeEncodingIntent, &InFrm, &OutputFormat, &dwFlags);
1334ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1335ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    _cmsIOPrintf(m, "<<\n");
1336ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    _cmsIOPrintf(m, "/ColorRenderingType 1\n");
1337ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1338ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1339ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmsDetectBlackPoint(&BlackPointAdaptedToD50, hProfile, Intent, 0);
1340ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1341ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    // Emit headers, etc.
1342ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    EmitWhiteBlackD50(m, &BlackPointAdaptedToD50);
1343ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    EmitPQRStage(m, hProfile, lDoBPC, Intent == INTENT_ABSOLUTE_COLORIMETRIC);
1344ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    EmitXYZ2Lab(m);
1345ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1346ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1347ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    // FIXUP: map Lab (100, 0, 0) to perfect white, because the particular encoding for Lab
1348ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    // does map a=b=0 not falling into any specific node. Since range a,b goes -128..127,
1349ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    // zero is slightly moved towards right, so assure next node (in L=100 slice) is mapped to
1350ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    // zero. This would sacrifice a bit of highlights, but failure to do so would cause
1351ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    // scum dot. Ouch.
1352ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1353ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (Intent == INTENT_ABSOLUTE_COLORIMETRIC)
1354ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            lFixWhite = FALSE;
1355ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1356ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    _cmsIOPrintf(m, "/RenderTable ");
1357ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1358ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1359ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    WriteCLUT(m, cmsPipelineGetPtrToFirstStage(DeviceLink), "<", ">\n", "", "", lFixWhite, ColorSpace);
1360ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1361ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    _cmsIOPrintf(m, " %d {} bind ", nChannels);
1362ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1363ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    for (i=1; i < nChannels; i++)
1364ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            _cmsIOPrintf(m, "dup ");
1365ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1366ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    _cmsIOPrintf(m, "]\n");
1367ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1368ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1369ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    EmitIntent(m, Intent);
1370ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1371ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    _cmsIOPrintf(m, ">>\n");
1372ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1373ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (!(dwFlags & cmsFLAGS_NODEFAULTRESOURCEDEF)) {
1374ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1375ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        _cmsIOPrintf(m, "/Current exch /ColorRendering defineresource pop\n");
1376ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
1377ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1378ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmsPipelineFree(DeviceLink);
1379ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmsDeleteTransform(xform);
1380ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1381ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return 1;
1382ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov}
1383ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1384ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1385ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// Builds a ASCII string containing colorant list in 0..1.0 range
1386ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovstatic
1387ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovvoid BuildColorantList(char *Colorant, int nColorant, cmsUInt16Number Out[])
1388ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{
1389ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    char Buff[32];
1390ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    int j;
1391ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1392ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    Colorant[0] = 0;
1393ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (nColorant > cmsMAXCHANNELS)
1394ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        nColorant = cmsMAXCHANNELS;
1395ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1396ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    for (j=0; j < nColorant; j++) {
1397ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1398ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                sprintf(Buff, "%.3f", Out[j] / 65535.0);
1399ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                strcat(Colorant, Buff);
1400ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                if (j < nColorant -1)
1401ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                        strcat(Colorant, " ");
1402ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1403ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
1404ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov}
1405ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1406ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1407ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// Creates a PostScript color list from a named profile data.
1408ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// This is a HP extension.
1409ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1410ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovstatic
1411ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovint WriteNamedColorCRD(cmsIOHANDLER* m, cmsHPROFILE hNamedColor, int Intent, cmsUInt32Number dwFlags)
1412ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{
1413ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmsHTRANSFORM xform;
1414ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    int i, nColors, nColorant;
1415ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmsUInt32Number OutputFormat;
1416ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    char ColorName[32];
1417ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    char Colorant[128];
1418ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmsNAMEDCOLORLIST* NamedColorList;
1419ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1420ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1421ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    OutputFormat = cmsFormatterForColorspaceOfProfile(hNamedColor, 2, FALSE);
1422ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    nColorant    = T_CHANNELS(OutputFormat);
1423ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1424ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1425ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    xform = cmsCreateTransform(hNamedColor, TYPE_NAMED_COLOR_INDEX, NULL, OutputFormat, Intent, dwFlags);
1426ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (xform == NULL) return 0;
1427ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1428ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1429ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    NamedColorList = cmsGetNamedColorList(xform);
1430ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (NamedColorList == NULL) return 0;
1431ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1432ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    _cmsIOPrintf(m, "<<\n");
1433ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    _cmsIOPrintf(m, "(colorlistcomment) (%s) \n", "Named profile");
1434ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    _cmsIOPrintf(m, "(Prefix) [ (Pantone ) (PANTONE ) ]\n");
1435ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    _cmsIOPrintf(m, "(Suffix) [ ( CV) ( CVC) ( C) ]\n");
1436ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1437ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    nColors   = cmsNamedColorCount(NamedColorList);
1438ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1439ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    for (i=0; i < nColors; i++) {
1440ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1441ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        cmsUInt16Number In[1];
1442ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        cmsUInt16Number Out[cmsMAXCHANNELS];
1443ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1444ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        In[0] = (cmsUInt16Number) i;
1445ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1446ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if (!cmsNamedColorInfo(NamedColorList, i, ColorName, NULL, NULL, NULL, NULL))
1447ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                continue;
1448ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1449ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        cmsDoTransform(xform, In, Out, 1);
1450ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        BuildColorantList(Colorant, nColorant, Out);
1451ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        _cmsIOPrintf(m, "  (%s) [ %s ]\n", ColorName, Colorant);
1452ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
1453ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1454ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    _cmsIOPrintf(m, "   >>");
1455ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1456ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (!(dwFlags & cmsFLAGS_NODEFAULTRESOURCEDEF)) {
1457ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1458ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    _cmsIOPrintf(m, " /Current exch /HPSpotTable defineresource pop\n");
1459ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
1460ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1461ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmsDeleteTransform(xform);
1462ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return 1;
1463ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov}
1464ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1465ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1466ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1467ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// This one does create a Color Rendering Dictionary.
1468ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// CRD are always LUT-Based, no matter if profile is
1469ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// implemented as matrix-shaper.
1470ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1471ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovstatic
1472ee451cb395940862dad63c85adfe8f2fd55e864cSvet GanovcmsUInt32Number  GenerateCRD(cmsContext ContextID,
1473ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                             cmsHPROFILE hProfile,
1474ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                             cmsUInt32Number Intent, cmsUInt32Number dwFlags,
1475ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                             cmsIOHANDLER* mem)
1476ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{
1477ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmsUInt32Number dwBytesUsed;
1478ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1479ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (!(dwFlags & cmsFLAGS_NODEFAULTRESOURCEDEF)) {
1480ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1481ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        EmitHeader(mem, "Color Rendering Dictionary (CRD)", hProfile);
1482ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
1483ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1484ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1485ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    // Is a named color profile?
1486ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (cmsGetDeviceClass(hProfile) == cmsSigNamedColorClass) {
1487ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1488ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if (!WriteNamedColorCRD(mem, hProfile, Intent, dwFlags)) {
1489ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            return 0;
1490ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
1491ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
1492ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    else {
1493ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1494ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        // CRD are always implemented as LUT
1495ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1496ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if (!WriteOutputLUT(mem, hProfile, Intent, dwFlags)) {
1497ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            return 0;
1498ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
1499ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
1500ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1501ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (!(dwFlags & cmsFLAGS_NODEFAULTRESOURCEDEF)) {
1502ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1503ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        _cmsIOPrintf(mem, "%%%%EndResource\n");
1504ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        _cmsIOPrintf(mem, "\n%% CRD End\n");
1505ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
1506ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1507ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    // Done, keep memory usage
1508ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    dwBytesUsed = mem ->UsedSpace;
1509ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1510ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    // Finally, return used byte count
1511ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return dwBytesUsed;
1512ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1513ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmsUNUSED_PARAMETER(ContextID);
1514ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov}
1515ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1516ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1517ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1518ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1519ee451cb395940862dad63c85adfe8f2fd55e864cSvet GanovcmsUInt32Number CMSEXPORT cmsGetPostScriptColorResource(cmsContext ContextID,
1520ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                                               cmsPSResourceType Type,
1521ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                                               cmsHPROFILE hProfile,
1522ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                                               cmsUInt32Number Intent,
1523ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                                               cmsUInt32Number dwFlags,
1524ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                                               cmsIOHANDLER* io)
1525ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{
1526ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmsUInt32Number  rc;
1527ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1528ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1529ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    switch (Type) {
1530ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1531ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        case cmsPS_RESOURCE_CSA:
1532ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            rc = GenerateCSA(ContextID, hProfile, Intent, dwFlags, io);
1533ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            break;
1534ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1535ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        default:
1536ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        case cmsPS_RESOURCE_CRD:
1537ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            rc = GenerateCRD(ContextID, hProfile, Intent, dwFlags, io);
1538ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            break;
1539ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
1540ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1541ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return rc;
1542ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov}
1543ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1544ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1545ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1546ee451cb395940862dad63c85adfe8f2fd55e864cSvet GanovcmsUInt32Number CMSEXPORT cmsGetPostScriptCRD(cmsContext ContextID,
1547ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                              cmsHPROFILE hProfile,
1548ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                              cmsUInt32Number Intent, cmsUInt32Number dwFlags,
1549ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                              void* Buffer, cmsUInt32Number dwBufferLen)
1550ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{
1551ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmsIOHANDLER* mem;
1552ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmsUInt32Number dwBytesUsed;
1553ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1554ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    // Set up the serialization engine
1555ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (Buffer == NULL)
1556ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        mem = cmsOpenIOhandlerFromNULL(ContextID);
1557ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    else
1558ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        mem = cmsOpenIOhandlerFromMem(ContextID, Buffer, dwBufferLen, "w");
1559ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1560ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (!mem) return 0;
1561ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1562ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    dwBytesUsed =  cmsGetPostScriptColorResource(ContextID, cmsPS_RESOURCE_CRD, hProfile, Intent, dwFlags, mem);
1563ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1564ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    // Get rid of memory stream
1565ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmsCloseIOhandler(mem);
1566ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1567ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return dwBytesUsed;
1568ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov}
1569ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1570ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1571ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1572ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// Does create a Color Space Array on XYZ colorspace for PostScript usage
1573ee451cb395940862dad63c85adfe8f2fd55e864cSvet GanovcmsUInt32Number CMSEXPORT cmsGetPostScriptCSA(cmsContext ContextID,
1574ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                              cmsHPROFILE hProfile,
1575ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                              cmsUInt32Number Intent,
1576ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                              cmsUInt32Number dwFlags,
1577ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                              void* Buffer,
1578ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                              cmsUInt32Number dwBufferLen)
1579ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{
1580ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmsIOHANDLER* mem;
1581ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmsUInt32Number dwBytesUsed;
1582ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1583ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (Buffer == NULL)
1584ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        mem = cmsOpenIOhandlerFromNULL(ContextID);
1585ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    else
1586ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        mem = cmsOpenIOhandlerFromMem(ContextID, Buffer, dwBufferLen, "w");
1587ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1588ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (!mem) return 0;
1589ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1590ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    dwBytesUsed =  cmsGetPostScriptColorResource(ContextID, cmsPS_RESOURCE_CSA, hProfile, Intent, dwFlags, mem);
1591ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1592ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    // Get rid of memory stream
1593ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmsCloseIOhandler(mem);
1594ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1595ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return dwBytesUsed;
1596ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1597ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov}
1598