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));
5964d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann    if (!p) {
5974d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann      cmsPipelineFree(lut);
5984d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann      return NULL;
5994d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann    }
600ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
601ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    // Store the proposed pipeline
602ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    p ->Lut = lut;
603ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
604ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    // Let's see if any plug-in want to do the transform by itself
605ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    for (Plugin = ctx ->TransformCollection;
606ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        Plugin != NULL;
607ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        Plugin = Plugin ->Next) {
608ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
609ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            if (Plugin ->Factory(&p->xform, &p->UserData, &p ->FreeUserData, &p ->Lut, InputFormat, OutputFormat, dwFlags)) {
610ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
611ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                // Last plugin in the declaration order takes control. We just keep
612ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                // the original parameters as a logging.
613ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                // Note that cmsFLAGS_CAN_CHANGE_FORMATTER is not set, so by default
614ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                // an optimized transform is not reusable. The plug-in can, however, change
615ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                // the flags and make it suitable.
616ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
617ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                p ->ContextID       = ContextID;
618ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                p ->InputFormat     = *InputFormat;
619ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                p ->OutputFormat    = *OutputFormat;
620ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                p ->dwOriginalFlags = *dwFlags;
621ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
622ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                // Fill the formatters just in case the optimized routine is interested.
623ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                // No error is thrown if the formatter doesn't exist. It is up to the optimization
624ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                // factory to decide what to do in those cases.
625ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                p ->FromInput      = _cmsGetFormatter(ContextID, *InputFormat,  cmsFormatterInput, CMS_PACK_FLAGS_16BITS).Fmt16;
626ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                p ->ToOutput       = _cmsGetFormatter(ContextID, *OutputFormat, cmsFormatterOutput, CMS_PACK_FLAGS_16BITS).Fmt16;
627ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                p ->FromInputFloat = _cmsGetFormatter(ContextID, *InputFormat,  cmsFormatterInput, CMS_PACK_FLAGS_FLOAT).FmtFloat;
628ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                p ->ToOutputFloat  = _cmsGetFormatter(ContextID, *OutputFormat, cmsFormatterOutput, CMS_PACK_FLAGS_FLOAT).FmtFloat;
629ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
630ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                return p;
631ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            }
632ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
633ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
634ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    // Not suitable for the transform plug-in, let's check  the pipeline plug-in
635ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (p ->Lut != NULL)
636ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        _cmsOptimizePipeline(ContextID, &p->Lut, Intent, InputFormat, OutputFormat, dwFlags);
637ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
638ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    // Check whatever this is a true floating point transform
639ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (_cmsFormatterIsFloat(*InputFormat) && _cmsFormatterIsFloat(*OutputFormat)) {
640ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
641ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        // Get formatter function always return a valid union, but the contents of this union may be NULL.
642ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        p ->FromInputFloat = _cmsGetFormatter(ContextID, *InputFormat,  cmsFormatterInput, CMS_PACK_FLAGS_FLOAT).FmtFloat;
643ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        p ->ToOutputFloat  = _cmsGetFormatter(ContextID, *OutputFormat, cmsFormatterOutput, CMS_PACK_FLAGS_FLOAT).FmtFloat;
644ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        *dwFlags |= cmsFLAGS_CAN_CHANGE_FORMATTER;
645ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
646ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if (p ->FromInputFloat == NULL || p ->ToOutputFloat == NULL) {
647ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
648ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            cmsSignalError(ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported raster format");
6494d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann            cmsDeleteTransform(p);
650ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            return NULL;
651ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
652ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
653ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if (*dwFlags & cmsFLAGS_NULLTRANSFORM) {
654ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
655ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            p ->xform = NullFloatXFORM;
656ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
657ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        else {
658ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            // Float transforms don't use cach? always are non-NULL
659ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            p ->xform = FloatXFORM;
660ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
661ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
662ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
663ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    else {
664ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
665ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if (*InputFormat == 0 && *OutputFormat == 0) {
666ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            p ->FromInput = p ->ToOutput = NULL;
667ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            *dwFlags |= cmsFLAGS_CAN_CHANGE_FORMATTER;
668ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
669ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        else {
670ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
671ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            int BytesPerPixelInput;
672ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
673ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            p ->FromInput = _cmsGetFormatter(ContextID, *InputFormat,  cmsFormatterInput, CMS_PACK_FLAGS_16BITS).Fmt16;
674ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            p ->ToOutput  = _cmsGetFormatter(ContextID, *OutputFormat, cmsFormatterOutput, CMS_PACK_FLAGS_16BITS).Fmt16;
675ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
676ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            if (p ->FromInput == NULL || p ->ToOutput == NULL) {
677ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
678ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                cmsSignalError(ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported raster format");
6794d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann                cmsDeleteTransform(p);
680ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                return NULL;
681ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            }
682ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
683ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            BytesPerPixelInput = T_BYTES(p ->InputFormat);
684ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            if (BytesPerPixelInput == 0 || BytesPerPixelInput >= 2)
685ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                   *dwFlags |= cmsFLAGS_CAN_CHANGE_FORMATTER;
686ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
687ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
688ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
689ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if (*dwFlags & cmsFLAGS_NULLTRANSFORM) {
690ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
691ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            p ->xform = NullXFORM;
692ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
693ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        else {
694ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            if (*dwFlags & cmsFLAGS_NOCACHE) {
695ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
696ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                if (*dwFlags & cmsFLAGS_GAMUTCHECK)
6974d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann                    p ->xform = PrecalculatedXFORMGamutCheck;  // Gamut check, no cach?
6984d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann                else
699ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                    p ->xform = PrecalculatedXFORM;  // No cach? no gamut check
700ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            }
701ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            else {
702ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
703ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                if (*dwFlags & cmsFLAGS_GAMUTCHECK)
7044d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann                    p ->xform = CachedXFORMGamutCheck;    // Gamut check, cach?
7054d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann                else
706ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                    p ->xform = CachedXFORM;  // No gamut check, cach?
707ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            }
708ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
709ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
710ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
711ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    p ->InputFormat     = *InputFormat;
712ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    p ->OutputFormat    = *OutputFormat;
713ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    p ->dwOriginalFlags = *dwFlags;
714ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    p ->ContextID       = ContextID;
715ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    p ->UserData        = NULL;
716ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return p;
717ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov}
718ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
719ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovstatic
720ee451cb395940862dad63c85adfe8f2fd55e864cSvet GanovcmsBool GetXFormColorSpaces(int nProfiles, cmsHPROFILE hProfiles[], cmsColorSpaceSignature* Input, cmsColorSpaceSignature* Output)
721ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{
722ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmsColorSpaceSignature ColorSpaceIn, ColorSpaceOut;
723ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmsColorSpaceSignature PostColorSpace;
724ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    int i;
725ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
726ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (nProfiles <= 0) return FALSE;
727ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (hProfiles[0] == NULL) return FALSE;
728ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
729ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    *Input = PostColorSpace = cmsGetColorSpace(hProfiles[0]);
730ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
731ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    for (i=0; i < nProfiles; i++) {
732ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
733ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        cmsProfileClassSignature cls;
734ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        cmsHPROFILE hProfile = hProfiles[i];
735ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
736ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        int lIsInput = (PostColorSpace != cmsSigXYZData) &&
737ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                       (PostColorSpace != cmsSigLabData);
738ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
739ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if (hProfile == NULL) return FALSE;
740ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
741ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        cls = cmsGetDeviceClass(hProfile);
742ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
743ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if (cls == cmsSigNamedColorClass) {
744ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
745ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            ColorSpaceIn    = cmsSig1colorData;
746ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            ColorSpaceOut   = (nProfiles > 1) ? cmsGetPCS(hProfile) : cmsGetColorSpace(hProfile);
747ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
748ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        else
749ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if (lIsInput || (cls == cmsSigLinkClass)) {
750ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
751ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            ColorSpaceIn    = cmsGetColorSpace(hProfile);
752ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            ColorSpaceOut   = cmsGetPCS(hProfile);
753ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
754ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        else
755ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        {
756ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            ColorSpaceIn    = cmsGetPCS(hProfile);
757ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            ColorSpaceOut   = cmsGetColorSpace(hProfile);
758ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
759ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
760ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if (i==0)
761ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            *Input = ColorSpaceIn;
762ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
763ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        PostColorSpace = ColorSpaceOut;
764ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
765ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
766ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    *Output = PostColorSpace;
767ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
768ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return TRUE;
769ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov}
770ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
771ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// Check colorspace
772ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovstatic
773ee451cb395940862dad63c85adfe8f2fd55e864cSvet GanovcmsBool  IsProperColorSpace(cmsColorSpaceSignature Check, cmsUInt32Number dwFormat)
774ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{
775ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    int Space1 = T_COLORSPACE(dwFormat);
776ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    int Space2 = _cmsLCMScolorSpace(Check);
777ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
778ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (Space1 == PT_ANY) return TRUE;
779ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (Space1 == Space2) return TRUE;
780ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
781ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (Space1 == PT_LabV2 && Space2 == PT_Lab) return TRUE;
782ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (Space1 == PT_Lab   && Space2 == PT_LabV2) return TRUE;
783ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
784ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return FALSE;
785ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov}
786ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
787ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// ----------------------------------------------------------------------------------------------------------------
788ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
789ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovstatic
790ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovvoid SetWhitePoint(cmsCIEXYZ* wtPt, const cmsCIEXYZ* src)
791ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{
792ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (src == NULL) {
793ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        wtPt ->X = cmsD50X;
794ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        wtPt ->Y = cmsD50Y;
795ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        wtPt ->Z = cmsD50Z;
796ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
797ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    else {
798ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        wtPt ->X = src->X;
799ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        wtPt ->Y = src->Y;
800ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        wtPt ->Z = src->Z;
801ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
802ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
803ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov}
804ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
805ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// New to lcms 2.0 -- have all parameters available.
806ee451cb395940862dad63c85adfe8f2fd55e864cSvet GanovcmsHTRANSFORM CMSEXPORT cmsCreateExtendedTransform(cmsContext ContextID,
807ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                                   cmsUInt32Number nProfiles, cmsHPROFILE hProfiles[],
808ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                                   cmsBool  BPC[],
809ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                                   cmsUInt32Number Intents[],
810ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                                   cmsFloat64Number AdaptationStates[],
811ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                                   cmsHPROFILE hGamutProfile,
812ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                                   cmsUInt32Number nGamutPCSposition,
813ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                                   cmsUInt32Number InputFormat,
814ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                                   cmsUInt32Number OutputFormat,
815ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                                   cmsUInt32Number dwFlags)
816ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{
817ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    _cmsTRANSFORM* xform;
818ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmsColorSpaceSignature EntryColorSpace;
819ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmsColorSpaceSignature ExitColorSpace;
820ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmsPipeline* Lut;
821ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmsUInt32Number LastIntent = Intents[nProfiles-1];
822ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
823ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    // If it is a fake transform
824ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (dwFlags & cmsFLAGS_NULLTRANSFORM)
825ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    {
826ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        return AllocEmptyTransform(ContextID, NULL, INTENT_PERCEPTUAL, &InputFormat, &OutputFormat, &dwFlags);
827ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
828ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
829ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    // If gamut check is requested, make sure we have a gamut profile
830ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (dwFlags & cmsFLAGS_GAMUTCHECK) {
831ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if (hGamutProfile == NULL) dwFlags &= ~cmsFLAGS_GAMUTCHECK;
832ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
833ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
834ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    // On floating point transforms, inhibit cache
835ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (_cmsFormatterIsFloat(InputFormat) || _cmsFormatterIsFloat(OutputFormat))
836ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        dwFlags |= cmsFLAGS_NOCACHE;
837ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
838ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    // Mark entry/exit spaces
839ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (!GetXFormColorSpaces(nProfiles, hProfiles, &EntryColorSpace, &ExitColorSpace)) {
840ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        cmsSignalError(ContextID, cmsERROR_NULL, "NULL input profiles on transform");
841ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        return NULL;
842ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
843ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
844ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    // Check if proper colorspaces
845ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (!IsProperColorSpace(EntryColorSpace, InputFormat)) {
846ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        cmsSignalError(ContextID, cmsERROR_COLORSPACE_CHECK, "Wrong input color space on transform");
847ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        return NULL;
848ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
849ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
850ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (!IsProperColorSpace(ExitColorSpace, OutputFormat)) {
851ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        cmsSignalError(ContextID, cmsERROR_COLORSPACE_CHECK, "Wrong output color space on transform");
852ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        return NULL;
853ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
854ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
855ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    // Create a pipeline with all transformations
856ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    Lut = _cmsLinkProfiles(ContextID, nProfiles, Intents, hProfiles, BPC, AdaptationStates, dwFlags);
857ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (Lut == NULL) {
858ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        cmsSignalError(ContextID, cmsERROR_NOT_SUITABLE, "Couldn't link the profiles");
859ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        return NULL;
860ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
861ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
862ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    // Check channel count
863ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if ((cmsChannelsOf(EntryColorSpace) != cmsPipelineInputChannels(Lut)) ||
864ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        (cmsChannelsOf(ExitColorSpace)  != cmsPipelineOutputChannels(Lut))) {
865ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        cmsPipelineFree(Lut);
866ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        cmsSignalError(ContextID, cmsERROR_NOT_SUITABLE, "Channel count doesn't match. Profile is corrupted");
867ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        return NULL;
868ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
869ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
870ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
871ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    // All seems ok
872ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    xform = AllocEmptyTransform(ContextID, Lut, LastIntent, &InputFormat, &OutputFormat, &dwFlags);
873ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (xform == NULL) {
874ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        return NULL;
875ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
876ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
877ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    // Keep values
878ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    xform ->EntryColorSpace = EntryColorSpace;
879ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    xform ->ExitColorSpace  = ExitColorSpace;
880ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    xform ->RenderingIntent = Intents[nProfiles-1];
881ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
882ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    // Take white points
883ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    SetWhitePoint(&xform->EntryWhitePoint, (cmsCIEXYZ*) cmsReadTag(hProfiles[0], cmsSigMediaWhitePointTag));
884ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    SetWhitePoint(&xform->ExitWhitePoint,  (cmsCIEXYZ*) cmsReadTag(hProfiles[nProfiles-1], cmsSigMediaWhitePointTag));
885ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
886ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
887ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    // Create a gamut check LUT if requested
888ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (hGamutProfile != NULL && (dwFlags & cmsFLAGS_GAMUTCHECK))
889ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        xform ->GamutCheck  = _cmsCreateGamutCheckPipeline(ContextID, hProfiles,
890ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                                        BPC, Intents,
891ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                                        AdaptationStates,
892ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                                        nGamutPCSposition,
893ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                                        hGamutProfile);
894ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
895ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
896ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    // Try to read input and output colorant table
897ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (cmsIsTag(hProfiles[0], cmsSigColorantTableTag)) {
898ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
899ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        // Input table can only come in this way.
900ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        xform ->InputColorant = cmsDupNamedColorList((cmsNAMEDCOLORLIST*) cmsReadTag(hProfiles[0], cmsSigColorantTableTag));
901ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
902ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
903ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    // Output is a little bit more complex.
904ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (cmsGetDeviceClass(hProfiles[nProfiles-1]) == cmsSigLinkClass) {
905ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
906ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        // This tag may exist only on devicelink profiles.
907ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if (cmsIsTag(hProfiles[nProfiles-1], cmsSigColorantTableOutTag)) {
908ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
909ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            // It may be NULL if error
910ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            xform ->OutputColorant = cmsDupNamedColorList((cmsNAMEDCOLORLIST*) cmsReadTag(hProfiles[nProfiles-1], cmsSigColorantTableOutTag));
911ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
912ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
913ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    } else {
914ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
915ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if (cmsIsTag(hProfiles[nProfiles-1], cmsSigColorantTableTag)) {
916ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
917ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            xform -> OutputColorant = cmsDupNamedColorList((cmsNAMEDCOLORLIST*) cmsReadTag(hProfiles[nProfiles-1], cmsSigColorantTableTag));
918ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
919ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
920ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
921ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    // Store the sequence of profiles
922ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (dwFlags & cmsFLAGS_KEEP_SEQUENCE) {
923ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        xform ->Sequence = _cmsCompileProfileSequence(ContextID, nProfiles, hProfiles);
924ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
925ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    else
926ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        xform ->Sequence = NULL;
927ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
928ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    // If this is a cached transform, init first value, which is zero (16 bits only)
929ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (!(dwFlags & cmsFLAGS_NOCACHE)) {
930ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
931ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        memset(&xform ->Cache.CacheIn, 0, sizeof(xform ->Cache.CacheIn));
932ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
933ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if (xform ->GamutCheck != NULL) {
934ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            TransformOnePixelWithGamutCheck(xform, xform ->Cache.CacheIn, xform->Cache.CacheOut);
935ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
936ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        else {
937ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
938ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            xform ->Lut ->Eval16Fn(xform ->Cache.CacheIn, xform->Cache.CacheOut, xform -> Lut->Data);
939ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
940ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
941ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
942ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
943ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return (cmsHTRANSFORM) xform;
944ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov}
945ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
946ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// Multiprofile transforms: Gamut check is not available here, as it is unclear from which profile the gamut comes.
947ee451cb395940862dad63c85adfe8f2fd55e864cSvet GanovcmsHTRANSFORM CMSEXPORT cmsCreateMultiprofileTransformTHR(cmsContext ContextID,
948ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                                       cmsHPROFILE hProfiles[],
949ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                                       cmsUInt32Number nProfiles,
950ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                                       cmsUInt32Number InputFormat,
951ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                                       cmsUInt32Number OutputFormat,
952ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                                       cmsUInt32Number Intent,
953ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                                       cmsUInt32Number dwFlags)
954ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{
955ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmsUInt32Number i;
956ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmsBool BPC[256];
957ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmsUInt32Number Intents[256];
958ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmsFloat64Number AdaptationStates[256];
959ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
960ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (nProfiles <= 0 || nProfiles > 255) {
961ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov         cmsSignalError(ContextID, cmsERROR_RANGE, "Wrong number of profiles. 1..255 expected, %d found.", nProfiles);
962ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        return NULL;
963ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
964ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
965ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    for (i=0; i < nProfiles; i++) {
966ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        BPC[i] = dwFlags & cmsFLAGS_BLACKPOINTCOMPENSATION ? TRUE : FALSE;
967ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        Intents[i] = Intent;
968ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        AdaptationStates[i] = cmsSetAdaptationStateTHR(ContextID, -1);
969ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
970ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
971ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
972ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return cmsCreateExtendedTransform(ContextID, nProfiles, hProfiles, BPC, Intents, AdaptationStates, NULL, 0, InputFormat, OutputFormat, dwFlags);
973ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov}
974ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
975ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
976ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
977ee451cb395940862dad63c85adfe8f2fd55e864cSvet GanovcmsHTRANSFORM CMSEXPORT cmsCreateMultiprofileTransform(cmsHPROFILE hProfiles[],
978ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                                  cmsUInt32Number nProfiles,
979ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                                  cmsUInt32Number InputFormat,
980ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                                  cmsUInt32Number OutputFormat,
981ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                                  cmsUInt32Number Intent,
982ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                                  cmsUInt32Number dwFlags)
983ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{
984ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
985ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (nProfiles <= 0 || nProfiles > 255) {
986ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov         cmsSignalError(NULL, cmsERROR_RANGE, "Wrong number of profiles. 1..255 expected, %d found.", nProfiles);
987ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov         return NULL;
988ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
989ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
990ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return cmsCreateMultiprofileTransformTHR(cmsGetProfileContextID(hProfiles[0]),
991ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                                  hProfiles,
992ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                                  nProfiles,
993ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                                  InputFormat,
994ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                                  OutputFormat,
995ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                                  Intent,
996ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                                  dwFlags);
997ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov}
998ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
999ee451cb395940862dad63c85adfe8f2fd55e864cSvet GanovcmsHTRANSFORM CMSEXPORT cmsCreateTransformTHR(cmsContext ContextID,
1000ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                              cmsHPROFILE Input,
1001ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                              cmsUInt32Number InputFormat,
1002ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                              cmsHPROFILE Output,
1003ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                              cmsUInt32Number OutputFormat,
1004ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                              cmsUInt32Number Intent,
1005ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                              cmsUInt32Number dwFlags)
1006ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{
1007ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1008ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmsHPROFILE hArray[2];
1009ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1010ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    hArray[0] = Input;
1011ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    hArray[1] = Output;
1012ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1013ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return cmsCreateMultiprofileTransformTHR(ContextID, hArray, Output == NULL ? 1 : 2, InputFormat, OutputFormat, Intent, dwFlags);
1014ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov}
1015ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1016ee451cb395940862dad63c85adfe8f2fd55e864cSvet GanovCMSAPI cmsHTRANSFORM CMSEXPORT cmsCreateTransform(cmsHPROFILE Input,
1017ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                                  cmsUInt32Number InputFormat,
1018ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                                  cmsHPROFILE Output,
1019ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                                  cmsUInt32Number OutputFormat,
1020ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                                  cmsUInt32Number Intent,
1021ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                                  cmsUInt32Number dwFlags)
1022ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{
1023ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return cmsCreateTransformTHR(cmsGetProfileContextID(Input), Input, InputFormat, Output, OutputFormat, Intent, dwFlags);
1024ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov}
1025ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1026ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1027ee451cb395940862dad63c85adfe8f2fd55e864cSvet GanovcmsHTRANSFORM CMSEXPORT cmsCreateProofingTransformTHR(cmsContext ContextID,
1028ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                                   cmsHPROFILE InputProfile,
1029ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                                   cmsUInt32Number InputFormat,
1030ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                                   cmsHPROFILE OutputProfile,
1031ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                                   cmsUInt32Number OutputFormat,
1032ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                                   cmsHPROFILE ProofingProfile,
1033ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                                   cmsUInt32Number nIntent,
1034ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                                   cmsUInt32Number ProofingIntent,
1035ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                                   cmsUInt32Number dwFlags)
1036ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{
1037ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmsHPROFILE hArray[4];
1038ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmsUInt32Number Intents[4];
1039ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmsBool  BPC[4];
1040ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmsFloat64Number Adaptation[4];
1041ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmsBool  DoBPC = (dwFlags & cmsFLAGS_BLACKPOINTCOMPENSATION) ? TRUE : FALSE;
1042ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1043ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1044ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    hArray[0]  = InputProfile; hArray[1] = ProofingProfile; hArray[2]  = ProofingProfile;               hArray[3] = OutputProfile;
1045ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    Intents[0] = nIntent;      Intents[1] = nIntent;        Intents[2] = INTENT_RELATIVE_COLORIMETRIC;  Intents[3] = ProofingIntent;
1046ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    BPC[0]     = DoBPC;        BPC[1] = DoBPC;              BPC[2] = 0;                                 BPC[3] = 0;
1047ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1048ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    Adaptation[0] = Adaptation[1] = Adaptation[2] = Adaptation[3] = cmsSetAdaptationStateTHR(ContextID, -1);
1049ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1050ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (!(dwFlags & (cmsFLAGS_SOFTPROOFING|cmsFLAGS_GAMUTCHECK)))
1051ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        return cmsCreateTransformTHR(ContextID, InputProfile, InputFormat, OutputProfile, OutputFormat, nIntent, dwFlags);
1052ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1053ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return cmsCreateExtendedTransform(ContextID, 4, hArray, BPC, Intents, Adaptation,
1054ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                        ProofingProfile, 1, InputFormat, OutputFormat, dwFlags);
1055ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1056ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov}
1057ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1058ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1059ee451cb395940862dad63c85adfe8f2fd55e864cSvet GanovcmsHTRANSFORM CMSEXPORT cmsCreateProofingTransform(cmsHPROFILE InputProfile,
1060ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                                   cmsUInt32Number InputFormat,
1061ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                                   cmsHPROFILE OutputProfile,
1062ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                                   cmsUInt32Number OutputFormat,
1063ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                                   cmsHPROFILE ProofingProfile,
1064ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                                   cmsUInt32Number nIntent,
1065ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                                   cmsUInt32Number ProofingIntent,
1066ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                                   cmsUInt32Number dwFlags)
1067ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{
1068ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return cmsCreateProofingTransformTHR(cmsGetProfileContextID(InputProfile),
1069ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                                   InputProfile,
1070ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                                   InputFormat,
1071ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                                   OutputProfile,
1072ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                                   OutputFormat,
1073ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                                   ProofingProfile,
1074ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                                   nIntent,
1075ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                                   ProofingIntent,
1076ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                                   dwFlags);
1077ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov}
1078ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1079ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1080ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// Grab the ContextID from an open transform. Returns NULL if a NULL transform is passed
1081ee451cb395940862dad63c85adfe8f2fd55e864cSvet GanovcmsContext CMSEXPORT cmsGetTransformContextID(cmsHTRANSFORM hTransform)
1082ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{
1083ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    _cmsTRANSFORM* xform = (_cmsTRANSFORM*) hTransform;
1084ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1085ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (xform == NULL) return NULL;
1086ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return xform -> ContextID;
1087ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov}
1088ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1089ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// Grab the input/output formats
1090ee451cb395940862dad63c85adfe8f2fd55e864cSvet GanovcmsUInt32Number CMSEXPORT cmsGetTransformInputFormat(cmsHTRANSFORM hTransform)
1091ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{
1092ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    _cmsTRANSFORM* xform = (_cmsTRANSFORM*) hTransform;
1093ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1094ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (xform == NULL) return 0;
1095ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return xform->InputFormat;
1096ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov}
1097ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1098ee451cb395940862dad63c85adfe8f2fd55e864cSvet GanovcmsUInt32Number CMSEXPORT cmsGetTransformOutputFormat(cmsHTRANSFORM hTransform)
1099ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{
1100ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    _cmsTRANSFORM* xform = (_cmsTRANSFORM*) hTransform;
1101ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1102ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (xform == NULL) return 0;
1103ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return xform->OutputFormat;
1104ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov}
1105ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1106ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// For backwards compatibility
1107ee451cb395940862dad63c85adfe8f2fd55e864cSvet GanovcmsBool CMSEXPORT cmsChangeBuffersFormat(cmsHTRANSFORM hTransform,
1108ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                         cmsUInt32Number InputFormat,
1109ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                         cmsUInt32Number OutputFormat)
1110ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{
1111ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1112ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    _cmsTRANSFORM* xform = (_cmsTRANSFORM*) hTransform;
1113ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmsFormatter16 FromInput, ToOutput;
1114ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1115ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1116ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    // We only can afford to change formatters if previous transform is at least 16 bits
1117ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (!(xform ->dwOriginalFlags & cmsFLAGS_CAN_CHANGE_FORMATTER)) {
1118ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1119ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        cmsSignalError(xform ->ContextID, cmsERROR_NOT_SUITABLE, "cmsChangeBuffersFormat works only on transforms created originally with at least 16 bits of precision");
1120ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        return FALSE;
1121ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
1122ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1123ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FromInput = _cmsGetFormatter(xform->ContextID, InputFormat,  cmsFormatterInput, CMS_PACK_FLAGS_16BITS).Fmt16;
1124ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    ToOutput  = _cmsGetFormatter(xform->ContextID, OutputFormat, cmsFormatterOutput, CMS_PACK_FLAGS_16BITS).Fmt16;
1125ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1126ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (FromInput == NULL || ToOutput == NULL) {
1127ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1128ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        cmsSignalError(xform -> ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported raster format");
1129ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        return FALSE;
1130ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
1131ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1132ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    xform ->InputFormat  = InputFormat;
1133ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    xform ->OutputFormat = OutputFormat;
1134ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    xform ->FromInput    = FromInput;
1135ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    xform ->ToOutput     = ToOutput;
1136ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return TRUE;
1137ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov}
1138