1ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov//---------------------------------------------------------------------------------
2ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov//
3ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov//  Little Color Management System
4ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov//  Copyright (c) 1998-2014 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// Transformations stuff
30ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// -----------------------------------------------------------------------
31ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
32ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#define DEFAULT_OBSERVER_ADAPTATION_STATE 1.0
33ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
34ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// The Context0 observer adaptation state.
35ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov_cmsAdaptationStateChunkType _cmsAdaptationStateChunk = { DEFAULT_OBSERVER_ADAPTATION_STATE };
36ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
37ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// Init and duplicate observer adaptation state
38ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovvoid _cmsAllocAdaptationStateChunk(struct _cmsContext_struct* ctx,
39ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                   const struct _cmsContext_struct* src)
40ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{
41ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    static _cmsAdaptationStateChunkType AdaptationStateChunk = { DEFAULT_OBSERVER_ADAPTATION_STATE };
42ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    void* from;
43ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
44ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (src != NULL) {
45ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        from = src ->chunks[AdaptationStateContext];
46ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
47ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    else {
48ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov       from = &AdaptationStateChunk;
49ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
50ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
51ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    ctx ->chunks[AdaptationStateContext] = _cmsSubAllocDup(ctx ->MemPool, from, sizeof(_cmsAdaptationStateChunkType));
52ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov}
53ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
54ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
55ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// Sets adaptation state for absolute colorimetric intent in the given context.  Adaptation state applies on all
56ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// but cmsCreateExtendedTransformTHR().  Little CMS can handle incomplete adaptation states.
57ee451cb395940862dad63c85adfe8f2fd55e864cSvet GanovcmsFloat64Number CMSEXPORT cmsSetAdaptationStateTHR(cmsContext ContextID, cmsFloat64Number d)
58ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{
59ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmsFloat64Number prev;
60ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    _cmsAdaptationStateChunkType* ptr = (_cmsAdaptationStateChunkType*) _cmsContextGetClientChunk(ContextID, AdaptationStateContext);
61ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
62ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    // Get previous value for return
63ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    prev = ptr ->AdaptationState;
64ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
65ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    // Set the value if d is positive or zero
66ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (d >= 0.0) {
67ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
68ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        ptr ->AdaptationState = d;
69ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
70ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
71ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    // Always return previous value
72ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return prev;
73ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov}
74ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
75ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
76ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// The adaptation state may be defaulted by this function. If you don't like it, use the extended transform routine
77ee451cb395940862dad63c85adfe8f2fd55e864cSvet GanovcmsFloat64Number CMSEXPORT cmsSetAdaptationState(cmsFloat64Number d)
78ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{
79ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return cmsSetAdaptationStateTHR(NULL, d);
80ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov}
81ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
82ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// -----------------------------------------------------------------------
83ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
84ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// Alarm codes for 16-bit transformations, because the fixed range of containers there are
85ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// no values left to mark out of gamut.
86ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
87ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#define DEFAULT_ALARM_CODES_VALUE {0x7F00, 0x7F00, 0x7F00, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
88ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
89ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov_cmsAlarmCodesChunkType _cmsAlarmCodesChunk = { DEFAULT_ALARM_CODES_VALUE };
90ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
91ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// Sets the codes used to mark out-out-gamut on Proofing transforms for a given context. Values are meant to be
92ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// encoded in 16 bits.
93ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovvoid CMSEXPORT cmsSetAlarmCodesTHR(cmsContext ContextID, const cmsUInt16Number AlarmCodesP[cmsMAXCHANNELS])
94ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{
95ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    _cmsAlarmCodesChunkType* ContextAlarmCodes = (_cmsAlarmCodesChunkType*) _cmsContextGetClientChunk(ContextID, AlarmCodesContext);
96ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
97ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    _cmsAssert(ContextAlarmCodes != NULL); // Can't happen
98ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
99ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    memcpy(ContextAlarmCodes->AlarmCodes, AlarmCodesP, sizeof(ContextAlarmCodes->AlarmCodes));
100ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov}
101ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
102ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// Gets the current codes used to mark out-out-gamut on Proofing transforms for the given context.
103ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// Values are meant to be encoded in 16 bits.
104ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovvoid CMSEXPORT cmsGetAlarmCodesTHR(cmsContext ContextID, cmsUInt16Number AlarmCodesP[cmsMAXCHANNELS])
105ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{
106ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    _cmsAlarmCodesChunkType* ContextAlarmCodes = (_cmsAlarmCodesChunkType*) _cmsContextGetClientChunk(ContextID, AlarmCodesContext);
107ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
108ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    _cmsAssert(ContextAlarmCodes != NULL); // Can't happen
109ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
110ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    memcpy(AlarmCodesP, ContextAlarmCodes->AlarmCodes, sizeof(ContextAlarmCodes->AlarmCodes));
111ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov}
112ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
113ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovvoid CMSEXPORT cmsSetAlarmCodes(const cmsUInt16Number NewAlarm[cmsMAXCHANNELS])
114ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{
115ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    _cmsAssert(NewAlarm != NULL);
116ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
117ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmsSetAlarmCodesTHR(NULL, NewAlarm);
118ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov}
119ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
120ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovvoid CMSEXPORT cmsGetAlarmCodes(cmsUInt16Number OldAlarm[cmsMAXCHANNELS])
121ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{
122ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    _cmsAssert(OldAlarm != NULL);
123ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmsGetAlarmCodesTHR(NULL, OldAlarm);
124ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov}
125ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
126ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
127ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// Init and duplicate alarm codes
128ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovvoid _cmsAllocAlarmCodesChunk(struct _cmsContext_struct* ctx,
129ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                              const struct _cmsContext_struct* src)
130ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{
131ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    static _cmsAlarmCodesChunkType AlarmCodesChunk = { DEFAULT_ALARM_CODES_VALUE };
132ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    void* from;
133ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
134ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (src != NULL) {
135ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        from = src ->chunks[AlarmCodesContext];
136ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
137ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    else {
138ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov       from = &AlarmCodesChunk;
139ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
140ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
141ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    ctx ->chunks[AlarmCodesContext] = _cmsSubAllocDup(ctx ->MemPool, from, sizeof(_cmsAlarmCodesChunkType));
142ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov}
143ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
144ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// -----------------------------------------------------------------------
145ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
146ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// Get rid of transform resources
147ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovvoid CMSEXPORT cmsDeleteTransform(cmsHTRANSFORM hTransform)
148ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{
149ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    _cmsTRANSFORM* p = (_cmsTRANSFORM*) hTransform;
150ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
151ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    _cmsAssert(p != NULL);
152ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
153ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (p -> GamutCheck)
154ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        cmsPipelineFree(p -> GamutCheck);
155ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
156ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (p -> Lut)
157ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        cmsPipelineFree(p -> Lut);
158ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
159ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (p ->InputColorant)
160ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        cmsFreeNamedColorList(p ->InputColorant);
161ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
162ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (p -> OutputColorant)
163ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        cmsFreeNamedColorList(p ->OutputColorant);
164ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
165ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (p ->Sequence)
166ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        cmsFreeProfileSequenceDescription(p ->Sequence);
167ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
168ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (p ->UserData)
169ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        p ->FreeUserData(p ->ContextID, p ->UserData);
170ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
171ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    _cmsFree(p ->ContextID, (void *) p);
172ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov}
173ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
174ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// Apply transform.
175ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovvoid CMSEXPORT cmsDoTransform(cmsHTRANSFORM  Transform,
176ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                              const void* InputBuffer,
177ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                              void* OutputBuffer,
178ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                              cmsUInt32Number Size)
179ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
180ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{
181ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    _cmsTRANSFORM* p = (_cmsTRANSFORM*) Transform;
182ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
183ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    p -> xform(p, InputBuffer, OutputBuffer, Size, Size);
184ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov}
185ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
186ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
187ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// Apply transform.
188ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovvoid CMSEXPORT cmsDoTransformStride(cmsHTRANSFORM  Transform,
189ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                              const void* InputBuffer,
190ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                              void* OutputBuffer,
191ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                              cmsUInt32Number Size, cmsUInt32Number Stride)
192ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
193ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{
194ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    _cmsTRANSFORM* p = (_cmsTRANSFORM*) Transform;
195ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
196ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    p -> xform(p, InputBuffer, OutputBuffer, Size, Stride);
197ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov}
198ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
199ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
200ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// Transform routines ----------------------------------------------------------------------------------------------------------
201ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
202ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// Float xform converts floats. Since there are no performance issues, one routine does all job, including gamut check.
203ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// Note that because extended range, we can use a -1.0 value for out of gamut in this case.
204ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovstatic
205ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovvoid FloatXFORM(_cmsTRANSFORM* p,
206ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                const void* in,
207ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                void* out, cmsUInt32Number Size, cmsUInt32Number Stride)
208ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{
209ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmsUInt8Number* accum;
210ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmsUInt8Number* output;
211ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmsFloat32Number fIn[cmsMAXCHANNELS], fOut[cmsMAXCHANNELS];
212ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmsFloat32Number OutOfGamut;
213ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmsUInt32Number i, j;
214ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
215ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    accum  = (cmsUInt8Number*)  in;
216ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    output = (cmsUInt8Number*)  out;
217ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
218ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    for (i=0; i < Size; i++) {
219ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
220ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        accum = p -> FromInputFloat(p, fIn, accum, Stride);
221ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
222ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        // Any gamut chack to do?
223ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if (p ->GamutCheck != NULL) {
224ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
225ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            // Evaluate gamut marker.
226ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            cmsPipelineEvalFloat( fIn, &OutOfGamut, p ->GamutCheck);
227ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
228ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            // Is current color out of gamut?
229ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            if (OutOfGamut > 0.0) {
230ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
231ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                // Certainly, out of gamut
232ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                for (j=0; j < cmsMAXCHANNELS; j++)
233ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                    fOut[j] = -1.0;
234ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
235ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            }
236ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            else {
237ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                // No, proceed normally
238ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                cmsPipelineEvalFloat(fIn, fOut, p -> Lut);
239ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            }
240ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
241ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        else {
242ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
243ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            // No gamut check at all
244ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            cmsPipelineEvalFloat(fIn, fOut, p -> Lut);
245ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
246ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
247ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        // Back to asked representation
248ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        output = p -> ToOutputFloat(p, fOut, output, Stride);
249ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
250ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov}
251ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
252ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
253ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovstatic
254ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovvoid NullFloatXFORM(_cmsTRANSFORM* p,
255ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                    const void* in,
256ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                    void* out,
257ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                    cmsUInt32Number Size,
258ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                    cmsUInt32Number Stride)
259ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{
260ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmsUInt8Number* accum;
261ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmsUInt8Number* output;
262ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmsFloat32Number fIn[cmsMAXCHANNELS];
263ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmsUInt32Number i, n;
264ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
265ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    accum  = (cmsUInt8Number*)  in;
266ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    output = (cmsUInt8Number*)  out;
267ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    n = Size;
268ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
269ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    for (i=0; i < n; i++) {
270ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
271ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        accum  = p -> FromInputFloat(p, fIn, accum, Stride);
272ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        output = p -> ToOutputFloat(p, fIn, output, Stride);
273ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
274ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov}
275ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
276ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// 16 bit precision -----------------------------------------------------------------------------------------------------------
277ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
278ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// Null transformation, only applies formatters. No cach?static
279ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovvoid NullXFORM(_cmsTRANSFORM* p,
280ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov               const void* in,
281ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov               void* out, cmsUInt32Number Size,
282ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov               cmsUInt32Number Stride)
283ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{
284ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmsUInt8Number* accum;
285ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmsUInt8Number* output;
286ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmsUInt16Number wIn[cmsMAXCHANNELS];
287ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmsUInt32Number i, n;
288ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
289ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    accum  = (cmsUInt8Number*)  in;
290ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    output = (cmsUInt8Number*)  out;
291ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    n = Size;                    // Buffer len
292ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
293ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    for (i=0; i < n; i++) {
294ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
295ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        accum  = p -> FromInput(p, wIn, accum, Stride);
296ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        output = p -> ToOutput(p, wIn, output, Stride);
297ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
298ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov}
299ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
300ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
301ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// No gamut check, no cache, 16 bits
302ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovstatic
303ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovvoid PrecalculatedXFORM(_cmsTRANSFORM* p,
304ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                        const void* in,
305ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                        void* out, cmsUInt32Number Size, cmsUInt32Number Stride)
306ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{
307ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    register cmsUInt8Number* accum;
308ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    register cmsUInt8Number* output;
309ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmsUInt16Number wIn[cmsMAXCHANNELS], wOut[cmsMAXCHANNELS];
310ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmsUInt32Number i, n;
311ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
312ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    accum  = (cmsUInt8Number*)  in;
313ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    output = (cmsUInt8Number*)  out;
314ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    n = Size;
315ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
316ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    for (i=0; i < n; i++) {
317ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
318ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        accum = p -> FromInput(p, wIn, accum, Stride);
319ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        p ->Lut ->Eval16Fn(wIn, wOut, p -> Lut->Data);
320ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        output = p -> ToOutput(p, wOut, output, Stride);
321ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
322ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov}
323ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
324ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
325ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// Auxiliar: Handle precalculated gamut check. The retrieval of context may be alittle bit slow, but this function is not critical.
326ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovstatic
327ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovvoid TransformOnePixelWithGamutCheck(_cmsTRANSFORM* p,
328ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                     const cmsUInt16Number wIn[],
329ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                     cmsUInt16Number wOut[])
330ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{
331ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmsUInt16Number wOutOfGamut;
332ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
333ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    p ->GamutCheck ->Eval16Fn(wIn, &wOutOfGamut, p ->GamutCheck ->Data);
334ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (wOutOfGamut >= 1) {
335ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
336ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        cmsUInt16Number i;
337ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        _cmsAlarmCodesChunkType* ContextAlarmCodes = (_cmsAlarmCodesChunkType*) _cmsContextGetClientChunk(p->ContextID, AlarmCodesContext);
338ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
339ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        for (i=0; i < p ->Lut->OutputChannels; i++) {
340ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
341ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            wOut[i] = ContextAlarmCodes ->AlarmCodes[i];
342ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
343ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
344ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    else
345ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        p ->Lut ->Eval16Fn(wIn, wOut, p -> Lut->Data);
346ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov}
347ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
348ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// Gamut check, No cach? 16 bits.
349ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovstatic
350ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovvoid PrecalculatedXFORMGamutCheck(_cmsTRANSFORM* p,
351ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                  const void* in,
352ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                  void* out, cmsUInt32Number Size, cmsUInt32Number Stride)
353ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{
354ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmsUInt8Number* accum;
355ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmsUInt8Number* output;
356ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmsUInt16Number wIn[cmsMAXCHANNELS], wOut[cmsMAXCHANNELS];
357ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmsUInt32Number i, n;
358ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
359ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    accum  = (cmsUInt8Number*)  in;
360ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    output = (cmsUInt8Number*)  out;
361ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    n = Size;                    // Buffer len
362ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
363ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    for (i=0; i < n; i++) {
364ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
365ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        accum = p -> FromInput(p, wIn, accum, Stride);
366ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        TransformOnePixelWithGamutCheck(p, wIn, wOut);
367ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        output = p -> ToOutput(p, wOut, output, Stride);
368ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
369ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov}
370ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
371ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
372ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// No gamut check, Cach? 16 bits,
373ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovstatic
374ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovvoid CachedXFORM(_cmsTRANSFORM* p,
375ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                 const void* in,
376ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                 void* out, cmsUInt32Number Size, cmsUInt32Number Stride)
377ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{
378ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmsUInt8Number* accum;
379ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmsUInt8Number* output;
380ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmsUInt16Number wIn[cmsMAXCHANNELS], wOut[cmsMAXCHANNELS];
381ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmsUInt32Number i, n;
382ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    _cmsCACHE Cache;
383ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
384ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    accum  = (cmsUInt8Number*)  in;
385ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    output = (cmsUInt8Number*)  out;
386ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    n = Size;                    // Buffer len
387ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
388ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    // Empty buffers for quick memcmp
389ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    memset(wIn,  0, sizeof(wIn));
390ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    memset(wOut, 0, sizeof(wOut));
391ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
392ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    // Get copy of zero cache
393ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    memcpy(&Cache, &p ->Cache, sizeof(Cache));
394ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
395ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    for (i=0; i < n; i++) {
396ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
397ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        accum = p -> FromInput(p, wIn, accum, Stride);
398ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
399ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if (memcmp(wIn, Cache.CacheIn, sizeof(Cache.CacheIn)) == 0) {
400ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
401ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            memcpy(wOut, Cache.CacheOut, sizeof(Cache.CacheOut));
402ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
403ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        else {
404ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
405ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            p ->Lut ->Eval16Fn(wIn, wOut, p -> Lut->Data);
406ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
407ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            memcpy(Cache.CacheIn,  wIn,  sizeof(Cache.CacheIn));
408ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            memcpy(Cache.CacheOut, wOut, sizeof(Cache.CacheOut));
409ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
410ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
411ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        output = p -> ToOutput(p, wOut, output, Stride);
412ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
413ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
414ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov}
415ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
416ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
417ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// All those nice features together
418ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovstatic
419ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovvoid CachedXFORMGamutCheck(_cmsTRANSFORM* p,
420ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                           const void* in,
421ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                           void* out, cmsUInt32Number Size, cmsUInt32Number Stride)
422ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{
423ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov       cmsUInt8Number* accum;
424ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov       cmsUInt8Number* output;
425ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov       cmsUInt16Number wIn[cmsMAXCHANNELS], wOut[cmsMAXCHANNELS];
426ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov       cmsUInt32Number i, n;
427ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov       _cmsCACHE Cache;
428ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
429ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov       accum  = (cmsUInt8Number*)  in;
430ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov       output = (cmsUInt8Number*)  out;
431ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov       n = Size;                    // Buffer len
432ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
433ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov       // Empty buffers for quick memcmp
434ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov       memset(wIn,  0, sizeof(cmsUInt16Number) * cmsMAXCHANNELS);
435ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov       memset(wOut, 0, sizeof(cmsUInt16Number) * cmsMAXCHANNELS);
436ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
437ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov       // Get copy of zero cache
438ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov       memcpy(&Cache, &p ->Cache, sizeof(Cache));
439ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
440ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov       for (i=0; i < n; i++) {
441ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
442ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            accum = p -> FromInput(p, wIn, accum, Stride);
443ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
444ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            if (memcmp(wIn, Cache.CacheIn, sizeof(Cache.CacheIn)) == 0) {
445ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                    memcpy(wOut, Cache.CacheOut, sizeof(Cache.CacheOut));
446ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            }
447ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            else {
448ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                    TransformOnePixelWithGamutCheck(p, wIn, wOut);
449ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                    memcpy(Cache.CacheIn, wIn, sizeof(Cache.CacheIn));
450ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                    memcpy(Cache.CacheOut, wOut, sizeof(Cache.CacheOut));
451ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            }
452ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
453ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            output = p -> ToOutput(p, wOut, output, Stride);
454ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov       }
455ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
456ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov}
457ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
458ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// -------------------------------------------------------------------------------------------------------------
459ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
460ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// List of used-defined transform factories
461ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovtypedef struct _cmsTransformCollection_st {
462ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
463ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    _cmsTransformFactory  Factory;
464ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    struct _cmsTransformCollection_st *Next;
465ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
466ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} _cmsTransformCollection;
467ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
468ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// The linked list head
469ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov_cmsTransformPluginChunkType _cmsTransformPluginChunk = { NULL };
470ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
471ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
472ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// Duplicates the zone of memory used by the plug-in in the new context
473ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovstatic
474ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovvoid DupPluginTransformList(struct _cmsContext_struct* ctx,
475ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                               const struct _cmsContext_struct* src)
476ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{
477ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov   _cmsTransformPluginChunkType newHead = { NULL };
478ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov   _cmsTransformCollection*  entry;
479ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov   _cmsTransformCollection*  Anterior = NULL;
480ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov   _cmsTransformPluginChunkType* head = (_cmsTransformPluginChunkType*) src->chunks[TransformPlugin];
481ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
482ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    // Walk the list copying all nodes
483ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov   for (entry = head->TransformCollection;
484ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        entry != NULL;
485ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        entry = entry ->Next) {
486ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
487ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            _cmsTransformCollection *newEntry = ( _cmsTransformCollection *) _cmsSubAllocDup(ctx ->MemPool, entry, sizeof(_cmsTransformCollection));
488ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
489ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            if (newEntry == NULL)
490ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                return;
491ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
492ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            // We want to keep the linked list order, so this is a little bit tricky
493ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            newEntry -> Next = NULL;
494ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            if (Anterior)
495ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                Anterior -> Next = newEntry;
496ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
497ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            Anterior = newEntry;
498ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
499ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            if (newHead.TransformCollection == NULL)
500ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                newHead.TransformCollection = newEntry;
501ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
502ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
503ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  ctx ->chunks[TransformPlugin] = _cmsSubAllocDup(ctx->MemPool, &newHead, sizeof(_cmsTransformPluginChunkType));
504ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov}
505ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
506ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovvoid _cmsAllocTransformPluginChunk(struct _cmsContext_struct* ctx,
507ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                        const struct _cmsContext_struct* src)
508ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{
509ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (src != NULL) {
510ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
511ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        // Copy all linked list
512ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        DupPluginTransformList(ctx, src);
513ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
514ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    else {
515ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        static _cmsTransformPluginChunkType TransformPluginChunkType = { NULL };
516ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        ctx ->chunks[TransformPlugin] = _cmsSubAllocDup(ctx ->MemPool, &TransformPluginChunkType, sizeof(_cmsTransformPluginChunkType));
517ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
518ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov}
519ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
520ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
521ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
522ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// Register new ways to transform
523ee451cb395940862dad63c85adfe8f2fd55e864cSvet GanovcmsBool  _cmsRegisterTransformPlugin(cmsContext ContextID, cmsPluginBase* Data)
524ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{
525ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmsPluginTransform* Plugin = (cmsPluginTransform*) Data;
526ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    _cmsTransformCollection* fl;
527ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    _cmsTransformPluginChunkType* ctx = ( _cmsTransformPluginChunkType*) _cmsContextGetClientChunk(ContextID,TransformPlugin);
528ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
529ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (Data == NULL) {
530ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
531ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        // Free the chain. Memory is safely freed at exit
532ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        ctx->TransformCollection = NULL;
533ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        return TRUE;
534ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
535ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
536ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    // Factory callback is required
537ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (Plugin ->Factory == NULL) return FALSE;
538ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
539ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
540ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    fl = (_cmsTransformCollection*) _cmsPluginMalloc(ContextID, sizeof(_cmsTransformCollection));
541ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (fl == NULL) return FALSE;
542ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
543ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    // Copy the parameters
544ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    fl ->Factory = Plugin ->Factory;
545ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
546ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    // Keep linked list
547ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    fl ->Next = ctx->TransformCollection;
548ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    ctx->TransformCollection = fl;
549ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
550ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    // All is ok
551ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return TRUE;
552ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov}
553ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
554ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
555ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovvoid CMSEXPORT _cmsSetTransformUserData(struct _cmstransform_struct *CMMcargo, void* ptr, _cmsFreeUserDataFn FreePrivateDataFn)
556ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{
557ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    _cmsAssert(CMMcargo != NULL);
558ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    CMMcargo ->UserData = ptr;
559ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    CMMcargo ->FreeUserData = FreePrivateDataFn;
560ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov}
561ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
562ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// returns the pointer defined by the plug-in to store private data
563ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovvoid * CMSEXPORT _cmsGetTransformUserData(struct _cmstransform_struct *CMMcargo)
564ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{
565ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    _cmsAssert(CMMcargo != NULL);
566ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return CMMcargo ->UserData;
567ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov}
568ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
569ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// returns the current formatters
570ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovvoid CMSEXPORT _cmsGetTransformFormatters16(struct _cmstransform_struct *CMMcargo, cmsFormatter16* FromInput, cmsFormatter16* ToOutput)
571ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{
572ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov     _cmsAssert(CMMcargo != NULL);
573ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov     if (FromInput) *FromInput = CMMcargo ->FromInput;
574ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov     if (ToOutput)  *ToOutput  = CMMcargo ->ToOutput;
575ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov}
576ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
577ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovvoid CMSEXPORT _cmsGetTransformFormattersFloat(struct _cmstransform_struct *CMMcargo, cmsFormatterFloat* FromInput, cmsFormatterFloat* ToOutput)
578ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{
579ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov     _cmsAssert(CMMcargo != NULL);
580ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov     if (FromInput) *FromInput = CMMcargo ->FromInputFloat;
581ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov     if (ToOutput)  *ToOutput  = CMMcargo ->ToOutputFloat;
582ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov}
583ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
584ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
585ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// Allocate transform struct and set it to defaults. Ask the optimization plug-in about if those formats are proper
586ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// for separated transforms. If this is the case,
587ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovstatic
588ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov_cmsTRANSFORM* AllocEmptyTransform(cmsContext ContextID, cmsPipeline* lut,
589ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                               cmsUInt32Number Intent, cmsUInt32Number* InputFormat, cmsUInt32Number* OutputFormat, cmsUInt32Number* dwFlags)
590ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{
591ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov     _cmsTransformPluginChunkType* ctx = ( _cmsTransformPluginChunkType*) _cmsContextGetClientChunk(ContextID, TransformPlugin);
592ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov     _cmsTransformCollection* Plugin;
593ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
594ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    // Allocate needed memory
595ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    _cmsTRANSFORM* p = (_cmsTRANSFORM*) _cmsMallocZero(ContextID, sizeof(_cmsTRANSFORM));
596ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (!p) return NULL;
597ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
598ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    // Store the proposed pipeline
599ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    p ->Lut = lut;
600ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
601ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    // Let's see if any plug-in want to do the transform by itself
602ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    for (Plugin = ctx ->TransformCollection;
603ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        Plugin != NULL;
604ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        Plugin = Plugin ->Next) {
605ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
606ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            if (Plugin ->Factory(&p->xform, &p->UserData, &p ->FreeUserData, &p ->Lut, InputFormat, OutputFormat, dwFlags)) {
607ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
608ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                // Last plugin in the declaration order takes control. We just keep
609ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                // the original parameters as a logging.
610ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                // Note that cmsFLAGS_CAN_CHANGE_FORMATTER is not set, so by default
611ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                // an optimized transform is not reusable. The plug-in can, however, change
612ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                // the flags and make it suitable.
613ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
614ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                p ->ContextID       = ContextID;
615ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                p ->InputFormat     = *InputFormat;
616ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                p ->OutputFormat    = *OutputFormat;
617ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                p ->dwOriginalFlags = *dwFlags;
618ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
619ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                // Fill the formatters just in case the optimized routine is interested.
620ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                // No error is thrown if the formatter doesn't exist. It is up to the optimization
621ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                // factory to decide what to do in those cases.
622ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                p ->FromInput      = _cmsGetFormatter(ContextID, *InputFormat,  cmsFormatterInput, CMS_PACK_FLAGS_16BITS).Fmt16;
623ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                p ->ToOutput       = _cmsGetFormatter(ContextID, *OutputFormat, cmsFormatterOutput, CMS_PACK_FLAGS_16BITS).Fmt16;
624ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                p ->FromInputFloat = _cmsGetFormatter(ContextID, *InputFormat,  cmsFormatterInput, CMS_PACK_FLAGS_FLOAT).FmtFloat;
625ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                p ->ToOutputFloat  = _cmsGetFormatter(ContextID, *OutputFormat, cmsFormatterOutput, CMS_PACK_FLAGS_FLOAT).FmtFloat;
626ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
627ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                return p;
628ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            }
629ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
630ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
631ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    // Not suitable for the transform plug-in, let's check  the pipeline plug-in
632ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (p ->Lut != NULL)
633ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        _cmsOptimizePipeline(ContextID, &p->Lut, Intent, InputFormat, OutputFormat, dwFlags);
634ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
635ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    // Check whatever this is a true floating point transform
636ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (_cmsFormatterIsFloat(*InputFormat) && _cmsFormatterIsFloat(*OutputFormat)) {
637ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
638ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        // Get formatter function always return a valid union, but the contents of this union may be NULL.
639ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        p ->FromInputFloat = _cmsGetFormatter(ContextID, *InputFormat,  cmsFormatterInput, CMS_PACK_FLAGS_FLOAT).FmtFloat;
640ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        p ->ToOutputFloat  = _cmsGetFormatter(ContextID, *OutputFormat, cmsFormatterOutput, CMS_PACK_FLAGS_FLOAT).FmtFloat;
641ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        *dwFlags |= cmsFLAGS_CAN_CHANGE_FORMATTER;
642ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
643ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if (p ->FromInputFloat == NULL || p ->ToOutputFloat == NULL) {
644ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
645ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            cmsSignalError(ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported raster format");
646ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            _cmsFree(ContextID, p);
647ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            return NULL;
648ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
649ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
650ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if (*dwFlags & cmsFLAGS_NULLTRANSFORM) {
651ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
652ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            p ->xform = NullFloatXFORM;
653ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
654ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        else {
655ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            // Float transforms don't use cach? always are non-NULL
656ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            p ->xform = FloatXFORM;
657ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
658ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
659ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
660ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    else {
661ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
662ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if (*InputFormat == 0 && *OutputFormat == 0) {
663ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            p ->FromInput = p ->ToOutput = NULL;
664ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            *dwFlags |= cmsFLAGS_CAN_CHANGE_FORMATTER;
665ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
666ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        else {
667ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
668ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            int BytesPerPixelInput;
669ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
670ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            p ->FromInput = _cmsGetFormatter(ContextID, *InputFormat,  cmsFormatterInput, CMS_PACK_FLAGS_16BITS).Fmt16;
671ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            p ->ToOutput  = _cmsGetFormatter(ContextID, *OutputFormat, cmsFormatterOutput, CMS_PACK_FLAGS_16BITS).Fmt16;
672ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
673ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            if (p ->FromInput == NULL || p ->ToOutput == NULL) {
674ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
675ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                cmsSignalError(ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported raster format");
676ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                _cmsFree(ContextID, p);
677ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                return NULL;
678ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            }
679ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
680ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            BytesPerPixelInput = T_BYTES(p ->InputFormat);
681ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            if (BytesPerPixelInput == 0 || BytesPerPixelInput >= 2)
682ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                   *dwFlags |= cmsFLAGS_CAN_CHANGE_FORMATTER;
683ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
684ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
685ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
686ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if (*dwFlags & cmsFLAGS_NULLTRANSFORM) {
687ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
688ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            p ->xform = NullXFORM;
689ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
690ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        else {
691ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            if (*dwFlags & cmsFLAGS_NOCACHE) {
692ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
693ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                if (*dwFlags & cmsFLAGS_GAMUTCHECK)
694ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                    p ->xform = PrecalculatedXFORMGamutCheck;  // Gamut check, no cach?                else
695ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                    p ->xform = PrecalculatedXFORM;  // No cach? no gamut check
696ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            }
697ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            else {
698ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
699ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                if (*dwFlags & cmsFLAGS_GAMUTCHECK)
700ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                    p ->xform = CachedXFORMGamutCheck;    // Gamut check, cach?                else
701ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                    p ->xform = CachedXFORM;  // No gamut check, cach?
702ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            }
703ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
704ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
705ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
706ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    p ->InputFormat     = *InputFormat;
707ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    p ->OutputFormat    = *OutputFormat;
708ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    p ->dwOriginalFlags = *dwFlags;
709ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    p ->ContextID       = ContextID;
710ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    p ->UserData        = NULL;
711ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return p;
712ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov}
713ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
714ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovstatic
715ee451cb395940862dad63c85adfe8f2fd55e864cSvet GanovcmsBool GetXFormColorSpaces(int nProfiles, cmsHPROFILE hProfiles[], cmsColorSpaceSignature* Input, cmsColorSpaceSignature* Output)
716ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{
717ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmsColorSpaceSignature ColorSpaceIn, ColorSpaceOut;
718ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmsColorSpaceSignature PostColorSpace;
719ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    int i;
720ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
721ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (nProfiles <= 0) return FALSE;
722ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (hProfiles[0] == NULL) return FALSE;
723ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
724ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    *Input = PostColorSpace = cmsGetColorSpace(hProfiles[0]);
725ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
726ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    for (i=0; i < nProfiles; i++) {
727ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
728ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        cmsProfileClassSignature cls;
729ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        cmsHPROFILE hProfile = hProfiles[i];
730ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
731ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        int lIsInput = (PostColorSpace != cmsSigXYZData) &&
732ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                       (PostColorSpace != cmsSigLabData);
733ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
734ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if (hProfile == NULL) return FALSE;
735ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
736ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        cls = cmsGetDeviceClass(hProfile);
737ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
738ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if (cls == cmsSigNamedColorClass) {
739ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
740ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            ColorSpaceIn    = cmsSig1colorData;
741ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            ColorSpaceOut   = (nProfiles > 1) ? cmsGetPCS(hProfile) : cmsGetColorSpace(hProfile);
742ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
743ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        else
744ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if (lIsInput || (cls == cmsSigLinkClass)) {
745ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
746ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            ColorSpaceIn    = cmsGetColorSpace(hProfile);
747ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            ColorSpaceOut   = cmsGetPCS(hProfile);
748ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
749ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        else
750ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        {
751ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            ColorSpaceIn    = cmsGetPCS(hProfile);
752ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            ColorSpaceOut   = cmsGetColorSpace(hProfile);
753ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
754ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
755ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if (i==0)
756ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            *Input = ColorSpaceIn;
757ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
758ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        PostColorSpace = ColorSpaceOut;
759ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
760ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
761ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    *Output = PostColorSpace;
762ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
763ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return TRUE;
764ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov}
765ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
766ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// Check colorspace
767ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovstatic
768ee451cb395940862dad63c85adfe8f2fd55e864cSvet GanovcmsBool  IsProperColorSpace(cmsColorSpaceSignature Check, cmsUInt32Number dwFormat)
769ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{
770ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    int Space1 = T_COLORSPACE(dwFormat);
771ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    int Space2 = _cmsLCMScolorSpace(Check);
772ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
773ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (Space1 == PT_ANY) return TRUE;
774ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (Space1 == Space2) return TRUE;
775ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
776ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (Space1 == PT_LabV2 && Space2 == PT_Lab) return TRUE;
777ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (Space1 == PT_Lab   && Space2 == PT_LabV2) return TRUE;
778ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
779ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return FALSE;
780ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov}
781ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
782ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// ----------------------------------------------------------------------------------------------------------------
783ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
784ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovstatic
785ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovvoid SetWhitePoint(cmsCIEXYZ* wtPt, const cmsCIEXYZ* src)
786ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{
787ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (src == NULL) {
788ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        wtPt ->X = cmsD50X;
789ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        wtPt ->Y = cmsD50Y;
790ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        wtPt ->Z = cmsD50Z;
791ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
792ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    else {
793ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        wtPt ->X = src->X;
794ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        wtPt ->Y = src->Y;
795ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        wtPt ->Z = src->Z;
796ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
797ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
798ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov}
799ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
800ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// New to lcms 2.0 -- have all parameters available.
801ee451cb395940862dad63c85adfe8f2fd55e864cSvet GanovcmsHTRANSFORM CMSEXPORT cmsCreateExtendedTransform(cmsContext ContextID,
802ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                                   cmsUInt32Number nProfiles, cmsHPROFILE hProfiles[],
803ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                                   cmsBool  BPC[],
804ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                                   cmsUInt32Number Intents[],
805ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                                   cmsFloat64Number AdaptationStates[],
806ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                                   cmsHPROFILE hGamutProfile,
807ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                                   cmsUInt32Number nGamutPCSposition,
808ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                                   cmsUInt32Number InputFormat,
809ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                                   cmsUInt32Number OutputFormat,
810ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                                   cmsUInt32Number dwFlags)
811ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{
812ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    _cmsTRANSFORM* xform;
813ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmsColorSpaceSignature EntryColorSpace;
814ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmsColorSpaceSignature ExitColorSpace;
815ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmsPipeline* Lut;
816ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmsUInt32Number LastIntent = Intents[nProfiles-1];
817ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
818ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    // If it is a fake transform
819ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (dwFlags & cmsFLAGS_NULLTRANSFORM)
820ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    {
821ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        return AllocEmptyTransform(ContextID, NULL, INTENT_PERCEPTUAL, &InputFormat, &OutputFormat, &dwFlags);
822ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
823ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
824ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    // If gamut check is requested, make sure we have a gamut profile
825ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (dwFlags & cmsFLAGS_GAMUTCHECK) {
826ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if (hGamutProfile == NULL) dwFlags &= ~cmsFLAGS_GAMUTCHECK;
827ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
828ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
829ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    // On floating point transforms, inhibit cache
830ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (_cmsFormatterIsFloat(InputFormat) || _cmsFormatterIsFloat(OutputFormat))
831ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        dwFlags |= cmsFLAGS_NOCACHE;
832ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
833ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    // Mark entry/exit spaces
834ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (!GetXFormColorSpaces(nProfiles, hProfiles, &EntryColorSpace, &ExitColorSpace)) {
835ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        cmsSignalError(ContextID, cmsERROR_NULL, "NULL input profiles on transform");
836ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        return NULL;
837ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
838ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
839ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    // Check if proper colorspaces
840ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (!IsProperColorSpace(EntryColorSpace, InputFormat)) {
841ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        cmsSignalError(ContextID, cmsERROR_COLORSPACE_CHECK, "Wrong input color space on transform");
842ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        return NULL;
843ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
844ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
845ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (!IsProperColorSpace(ExitColorSpace, OutputFormat)) {
846ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        cmsSignalError(ContextID, cmsERROR_COLORSPACE_CHECK, "Wrong output color space on transform");
847ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        return NULL;
848ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
849ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
850ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    // Create a pipeline with all transformations
851ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    Lut = _cmsLinkProfiles(ContextID, nProfiles, Intents, hProfiles, BPC, AdaptationStates, dwFlags);
852ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (Lut == NULL) {
853ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        cmsSignalError(ContextID, cmsERROR_NOT_SUITABLE, "Couldn't link the profiles");
854ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        return NULL;
855ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
856ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
857ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    // Check channel count
858ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if ((cmsChannelsOf(EntryColorSpace) != cmsPipelineInputChannels(Lut)) ||
859ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        (cmsChannelsOf(ExitColorSpace)  != cmsPipelineOutputChannels(Lut))) {
860ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        cmsPipelineFree(Lut);
861ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        cmsSignalError(ContextID, cmsERROR_NOT_SUITABLE, "Channel count doesn't match. Profile is corrupted");
862ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        return NULL;
863ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
864ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
865ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
866ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    // All seems ok
867ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    xform = AllocEmptyTransform(ContextID, Lut, LastIntent, &InputFormat, &OutputFormat, &dwFlags);
868ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (xform == NULL) {
869ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        return NULL;
870ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
871ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
872ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    // Keep values
873ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    xform ->EntryColorSpace = EntryColorSpace;
874ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    xform ->ExitColorSpace  = ExitColorSpace;
875ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    xform ->RenderingIntent = Intents[nProfiles-1];
876ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
877ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    // Take white points
878ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    SetWhitePoint(&xform->EntryWhitePoint, (cmsCIEXYZ*) cmsReadTag(hProfiles[0], cmsSigMediaWhitePointTag));
879ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    SetWhitePoint(&xform->ExitWhitePoint,  (cmsCIEXYZ*) cmsReadTag(hProfiles[nProfiles-1], cmsSigMediaWhitePointTag));
880ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
881ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
882ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    // Create a gamut check LUT if requested
883ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (hGamutProfile != NULL && (dwFlags & cmsFLAGS_GAMUTCHECK))
884ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        xform ->GamutCheck  = _cmsCreateGamutCheckPipeline(ContextID, hProfiles,
885ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                                        BPC, Intents,
886ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                                        AdaptationStates,
887ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                                        nGamutPCSposition,
888ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                                        hGamutProfile);
889ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
890ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
891ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    // Try to read input and output colorant table
892ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (cmsIsTag(hProfiles[0], cmsSigColorantTableTag)) {
893ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
894ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        // Input table can only come in this way.
895ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        xform ->InputColorant = cmsDupNamedColorList((cmsNAMEDCOLORLIST*) cmsReadTag(hProfiles[0], cmsSigColorantTableTag));
896ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
897ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
898ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    // Output is a little bit more complex.
899ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (cmsGetDeviceClass(hProfiles[nProfiles-1]) == cmsSigLinkClass) {
900ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
901ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        // This tag may exist only on devicelink profiles.
902ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if (cmsIsTag(hProfiles[nProfiles-1], cmsSigColorantTableOutTag)) {
903ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
904ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            // It may be NULL if error
905ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            xform ->OutputColorant = cmsDupNamedColorList((cmsNAMEDCOLORLIST*) cmsReadTag(hProfiles[nProfiles-1], cmsSigColorantTableOutTag));
906ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
907ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
908ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    } else {
909ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
910ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if (cmsIsTag(hProfiles[nProfiles-1], cmsSigColorantTableTag)) {
911ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
912ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            xform -> OutputColorant = cmsDupNamedColorList((cmsNAMEDCOLORLIST*) cmsReadTag(hProfiles[nProfiles-1], cmsSigColorantTableTag));
913ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
914ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
915ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
916ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    // Store the sequence of profiles
917ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (dwFlags & cmsFLAGS_KEEP_SEQUENCE) {
918ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        xform ->Sequence = _cmsCompileProfileSequence(ContextID, nProfiles, hProfiles);
919ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
920ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    else
921ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        xform ->Sequence = NULL;
922ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
923ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    // If this is a cached transform, init first value, which is zero (16 bits only)
924ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (!(dwFlags & cmsFLAGS_NOCACHE)) {
925ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
926ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        memset(&xform ->Cache.CacheIn, 0, sizeof(xform ->Cache.CacheIn));
927ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
928ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if (xform ->GamutCheck != NULL) {
929ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            TransformOnePixelWithGamutCheck(xform, xform ->Cache.CacheIn, xform->Cache.CacheOut);
930ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
931ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        else {
932ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
933ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            xform ->Lut ->Eval16Fn(xform ->Cache.CacheIn, xform->Cache.CacheOut, xform -> Lut->Data);
934ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
935ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
936ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
937ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
938ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return (cmsHTRANSFORM) xform;
939ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov}
940ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
941ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// Multiprofile transforms: Gamut check is not available here, as it is unclear from which profile the gamut comes.
942ee451cb395940862dad63c85adfe8f2fd55e864cSvet GanovcmsHTRANSFORM CMSEXPORT cmsCreateMultiprofileTransformTHR(cmsContext ContextID,
943ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                                       cmsHPROFILE hProfiles[],
944ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                                       cmsUInt32Number nProfiles,
945ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                                       cmsUInt32Number InputFormat,
946ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                                       cmsUInt32Number OutputFormat,
947ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                                       cmsUInt32Number Intent,
948ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                                       cmsUInt32Number dwFlags)
949ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{
950ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmsUInt32Number i;
951ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmsBool BPC[256];
952ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmsUInt32Number Intents[256];
953ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmsFloat64Number AdaptationStates[256];
954ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
955ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (nProfiles <= 0 || nProfiles > 255) {
956ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov         cmsSignalError(ContextID, cmsERROR_RANGE, "Wrong number of profiles. 1..255 expected, %d found.", nProfiles);
957ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        return NULL;
958ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
959ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
960ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    for (i=0; i < nProfiles; i++) {
961ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        BPC[i] = dwFlags & cmsFLAGS_BLACKPOINTCOMPENSATION ? TRUE : FALSE;
962ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        Intents[i] = Intent;
963ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        AdaptationStates[i] = cmsSetAdaptationStateTHR(ContextID, -1);
964ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
965ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
966ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
967ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return cmsCreateExtendedTransform(ContextID, nProfiles, hProfiles, BPC, Intents, AdaptationStates, NULL, 0, InputFormat, OutputFormat, dwFlags);
968ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov}
969ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
970ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
971ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
972ee451cb395940862dad63c85adfe8f2fd55e864cSvet GanovcmsHTRANSFORM CMSEXPORT cmsCreateMultiprofileTransform(cmsHPROFILE hProfiles[],
973ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                                  cmsUInt32Number nProfiles,
974ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                                  cmsUInt32Number InputFormat,
975ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                                  cmsUInt32Number OutputFormat,
976ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                                  cmsUInt32Number Intent,
977ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                                  cmsUInt32Number dwFlags)
978ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{
979ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
980ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (nProfiles <= 0 || nProfiles > 255) {
981ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov         cmsSignalError(NULL, cmsERROR_RANGE, "Wrong number of profiles. 1..255 expected, %d found.", nProfiles);
982ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov         return NULL;
983ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
984ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
985ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return cmsCreateMultiprofileTransformTHR(cmsGetProfileContextID(hProfiles[0]),
986ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                                  hProfiles,
987ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                                  nProfiles,
988ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                                  InputFormat,
989ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                                  OutputFormat,
990ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                                  Intent,
991ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                                  dwFlags);
992ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov}
993ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
994ee451cb395940862dad63c85adfe8f2fd55e864cSvet GanovcmsHTRANSFORM CMSEXPORT cmsCreateTransformTHR(cmsContext ContextID,
995ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                              cmsHPROFILE Input,
996ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                              cmsUInt32Number InputFormat,
997ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                              cmsHPROFILE Output,
998ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                              cmsUInt32Number OutputFormat,
999ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                              cmsUInt32Number Intent,
1000ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                              cmsUInt32Number dwFlags)
1001ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{
1002ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1003ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmsHPROFILE hArray[2];
1004ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1005ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    hArray[0] = Input;
1006ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    hArray[1] = Output;
1007ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1008ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return cmsCreateMultiprofileTransformTHR(ContextID, hArray, Output == NULL ? 1 : 2, InputFormat, OutputFormat, Intent, dwFlags);
1009ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov}
1010ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1011ee451cb395940862dad63c85adfe8f2fd55e864cSvet GanovCMSAPI cmsHTRANSFORM CMSEXPORT cmsCreateTransform(cmsHPROFILE Input,
1012ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                                  cmsUInt32Number InputFormat,
1013ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                                  cmsHPROFILE Output,
1014ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                                  cmsUInt32Number OutputFormat,
1015ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                                  cmsUInt32Number Intent,
1016ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                                  cmsUInt32Number dwFlags)
1017ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{
1018ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return cmsCreateTransformTHR(cmsGetProfileContextID(Input), Input, InputFormat, Output, OutputFormat, Intent, dwFlags);
1019ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov}
1020ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1021ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1022ee451cb395940862dad63c85adfe8f2fd55e864cSvet GanovcmsHTRANSFORM CMSEXPORT cmsCreateProofingTransformTHR(cmsContext ContextID,
1023ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                                   cmsHPROFILE InputProfile,
1024ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                                   cmsUInt32Number InputFormat,
1025ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                                   cmsHPROFILE OutputProfile,
1026ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                                   cmsUInt32Number OutputFormat,
1027ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                                   cmsHPROFILE ProofingProfile,
1028ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                                   cmsUInt32Number nIntent,
1029ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                                   cmsUInt32Number ProofingIntent,
1030ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                                   cmsUInt32Number dwFlags)
1031ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{
1032ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmsHPROFILE hArray[4];
1033ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmsUInt32Number Intents[4];
1034ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmsBool  BPC[4];
1035ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmsFloat64Number Adaptation[4];
1036ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmsBool  DoBPC = (dwFlags & cmsFLAGS_BLACKPOINTCOMPENSATION) ? TRUE : FALSE;
1037ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1038ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1039ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    hArray[0]  = InputProfile; hArray[1] = ProofingProfile; hArray[2]  = ProofingProfile;               hArray[3] = OutputProfile;
1040ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    Intents[0] = nIntent;      Intents[1] = nIntent;        Intents[2] = INTENT_RELATIVE_COLORIMETRIC;  Intents[3] = ProofingIntent;
1041ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    BPC[0]     = DoBPC;        BPC[1] = DoBPC;              BPC[2] = 0;                                 BPC[3] = 0;
1042ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1043ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    Adaptation[0] = Adaptation[1] = Adaptation[2] = Adaptation[3] = cmsSetAdaptationStateTHR(ContextID, -1);
1044ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1045ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (!(dwFlags & (cmsFLAGS_SOFTPROOFING|cmsFLAGS_GAMUTCHECK)))
1046ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        return cmsCreateTransformTHR(ContextID, InputProfile, InputFormat, OutputProfile, OutputFormat, nIntent, dwFlags);
1047ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1048ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return cmsCreateExtendedTransform(ContextID, 4, hArray, BPC, Intents, Adaptation,
1049ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                        ProofingProfile, 1, InputFormat, OutputFormat, dwFlags);
1050ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1051ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov}
1052ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1053ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1054ee451cb395940862dad63c85adfe8f2fd55e864cSvet GanovcmsHTRANSFORM CMSEXPORT cmsCreateProofingTransform(cmsHPROFILE InputProfile,
1055ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                                   cmsUInt32Number InputFormat,
1056ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                                   cmsHPROFILE OutputProfile,
1057ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                                   cmsUInt32Number OutputFormat,
1058ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                                   cmsHPROFILE ProofingProfile,
1059ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                                   cmsUInt32Number nIntent,
1060ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                                   cmsUInt32Number ProofingIntent,
1061ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                                   cmsUInt32Number dwFlags)
1062ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{
1063ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return cmsCreateProofingTransformTHR(cmsGetProfileContextID(InputProfile),
1064ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                                   InputProfile,
1065ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                                   InputFormat,
1066ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                                   OutputProfile,
1067ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                                   OutputFormat,
1068ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                                   ProofingProfile,
1069ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                                   nIntent,
1070ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                                   ProofingIntent,
1071ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                                   dwFlags);
1072ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov}
1073ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1074ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1075ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// Grab the ContextID from an open transform. Returns NULL if a NULL transform is passed
1076ee451cb395940862dad63c85adfe8f2fd55e864cSvet GanovcmsContext CMSEXPORT cmsGetTransformContextID(cmsHTRANSFORM hTransform)
1077ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{
1078ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    _cmsTRANSFORM* xform = (_cmsTRANSFORM*) hTransform;
1079ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1080ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (xform == NULL) return NULL;
1081ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return xform -> ContextID;
1082ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov}
1083ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1084ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// Grab the input/output formats
1085ee451cb395940862dad63c85adfe8f2fd55e864cSvet GanovcmsUInt32Number CMSEXPORT cmsGetTransformInputFormat(cmsHTRANSFORM hTransform)
1086ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{
1087ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    _cmsTRANSFORM* xform = (_cmsTRANSFORM*) hTransform;
1088ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1089ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (xform == NULL) return 0;
1090ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return xform->InputFormat;
1091ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov}
1092ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1093ee451cb395940862dad63c85adfe8f2fd55e864cSvet GanovcmsUInt32Number CMSEXPORT cmsGetTransformOutputFormat(cmsHTRANSFORM hTransform)
1094ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{
1095ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    _cmsTRANSFORM* xform = (_cmsTRANSFORM*) hTransform;
1096ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1097ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (xform == NULL) return 0;
1098ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return xform->OutputFormat;
1099ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov}
1100ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1101ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// For backwards compatibility
1102ee451cb395940862dad63c85adfe8f2fd55e864cSvet GanovcmsBool CMSEXPORT cmsChangeBuffersFormat(cmsHTRANSFORM hTransform,
1103ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                         cmsUInt32Number InputFormat,
1104ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                         cmsUInt32Number OutputFormat)
1105ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{
1106ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1107ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    _cmsTRANSFORM* xform = (_cmsTRANSFORM*) hTransform;
1108ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmsFormatter16 FromInput, ToOutput;
1109ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1110ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1111ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    // We only can afford to change formatters if previous transform is at least 16 bits
1112ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (!(xform ->dwOriginalFlags & cmsFLAGS_CAN_CHANGE_FORMATTER)) {
1113ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1114ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        cmsSignalError(xform ->ContextID, cmsERROR_NOT_SUITABLE, "cmsChangeBuffersFormat works only on transforms created originally with at least 16 bits of precision");
1115ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        return FALSE;
1116ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
1117ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1118ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FromInput = _cmsGetFormatter(xform->ContextID, InputFormat,  cmsFormatterInput, CMS_PACK_FLAGS_16BITS).Fmt16;
1119ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    ToOutput  = _cmsGetFormatter(xform->ContextID, OutputFormat, cmsFormatterOutput, CMS_PACK_FLAGS_16BITS).Fmt16;
1120ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1121ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (FromInput == NULL || ToOutput == NULL) {
1122ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1123ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        cmsSignalError(xform -> ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported raster format");
1124ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        return FALSE;
1125ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
1126ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1127ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    xform ->InputFormat  = InputFormat;
1128ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    xform ->OutputFormat = OutputFormat;
1129ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    xform ->FromInput    = FromInput;
1130ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    xform ->ToOutput     = ToOutput;
1131ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return TRUE;
1132ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov}
1133