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