1 //---------------------------------------------------------------------------------
3 // Little Color Management System
4 // Copyright (c) 1998-2011 Marti Maria Saguer
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:
13 // The above copyright notice and this permission notice shall be included in
14 // all copies or substantial portions of the Software.
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.
24 //---------------------------------------------------------------------------------
27 #include "lcms2_internal.h"
29 // Transformations stuff
30 // -----------------------------------------------------------------------
32 // Alarm codes for 16-bit transformations, because the fixed range of containers there are
33 // no values left to mark out of gamut. volatile is C99 per 6.2.5
34 static volatile cmsUInt16Number Alarm[cmsMAXCHANNELS] = { 0x7F00, 0x7F00, 0x7F00, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
35 static volatile cmsFloat64Number GlobalAdaptationState = 1;
37 // The adaptation state may be defaulted by this function. If you don't like it, use the extended transform routine
38 cmsFloat64Number CMSEXPORT cmsSetAdaptationState(cmsFloat64Number d)
40 cmsFloat64Number OldVal = GlobalAdaptationState;
43 GlobalAdaptationState = d;
48 // Alarm codes are always global
49 void CMSEXPORT cmsSetAlarmCodes(cmsUInt16Number NewAlarm[cmsMAXCHANNELS])
53 _cmsAssert(NewAlarm != NULL);
55 for (i=0; i < cmsMAXCHANNELS; i++)
56 Alarm[i] = NewAlarm[i];
59 // You can get the codes cas well
60 void CMSEXPORT cmsGetAlarmCodes(cmsUInt16Number OldAlarm[cmsMAXCHANNELS])
64 _cmsAssert(OldAlarm != NULL);
66 for (i=0; i < cmsMAXCHANNELS; i++)
67 OldAlarm[i] = Alarm[i];
70 // Get rid of transform resources
71 void CMSEXPORT cmsDeleteTransform(cmsHTRANSFORM hTransform)
73 _cmsTRANSFORM* p = (_cmsTRANSFORM*) hTransform;
75 _cmsAssert(p != NULL);
78 cmsPipelineFree(p -> GamutCheck);
81 cmsPipelineFree(p -> Lut);
83 if (p ->InputColorant)
84 cmsFreeNamedColorList(p ->InputColorant);
86 if (p -> OutputColorant)
87 cmsFreeNamedColorList(p ->OutputColorant);
90 cmsFreeProfileSequenceDescription(p ->Sequence);
92 _cmsFree(p ->ContextID, (void *) p);
96 void CMSEXPORT cmsDoTransform(cmsHTRANSFORM Transform,
97 const void* InputBuffer,
102 _cmsTRANSFORM* p = (_cmsTRANSFORM*) Transform;
104 p -> xform(p, InputBuffer, OutputBuffer, Size);
108 // Transform routines ----------------------------------------------------------------------------------------------------------
110 // Float xform converts floats. Since there are no performance issues, one routine does all job, including gamut check.
111 // Note that because extended range, we can use a -1.0 value for out of gamut in this case.
113 void FloatXFORM(_cmsTRANSFORM* p,
115 void* out, cmsUInt32Number Size)
117 cmsUInt8Number* accum;
118 cmsUInt8Number* output;
119 cmsFloat32Number fIn[cmsMAXCHANNELS], fOut[cmsMAXCHANNELS];
120 cmsFloat32Number OutOfGamut;
121 cmsUInt32Number i, j;
123 accum = (cmsUInt8Number*) in;
124 output = (cmsUInt8Number*) out;
126 for (i=0; i < Size; i++) {
128 accum = p -> FromInputFloat(p, fIn, accum, Size);
130 // Any gamut chack to do?
131 if (p ->GamutCheck != NULL) {
133 // Evaluate gamut marker.
134 cmsPipelineEvalFloat( fIn, &OutOfGamut, p ->GamutCheck);
136 // Is current color out of gamut?
137 if (OutOfGamut > 0.0) {
139 // Certainly, out of gamut
140 for (j=0; j < cmsMAXCHANNELS; j++)
145 // No, proceed normally
146 cmsPipelineEvalFloat(fIn, fOut, p -> Lut);
151 // No gamut check at all
152 cmsPipelineEvalFloat(fIn, fOut, p -> Lut);
155 // Back to asked representation
156 output = p -> ToOutputFloat(p, fOut, output, Size);
160 // 16 bit precision -----------------------------------------------------------------------------------------------------------
162 // Null transformation, only applies formatters. No caché
164 void NullXFORM(_cmsTRANSFORM* p,
166 void* out, cmsUInt32Number Size)
168 cmsUInt8Number* accum;
169 cmsUInt8Number* output;
170 cmsUInt16Number wIn[cmsMAXCHANNELS];
171 cmsUInt32Number i, n;
173 accum = (cmsUInt8Number*) in;
174 output = (cmsUInt8Number*) out;
175 n = Size; // Buffer len
177 for (i=0; i < n; i++) {
179 accum = p -> FromInput(p, wIn, accum, Size);
180 output = p -> ToOutput(p, wIn, output, Size);
185 // No gamut check, no cache, 16 bits
187 void PrecalculatedXFORM(_cmsTRANSFORM* p,
189 void* out, cmsUInt32Number Size)
191 register cmsUInt8Number* accum;
192 register cmsUInt8Number* output;
193 cmsUInt16Number wIn[cmsMAXCHANNELS], wOut[cmsMAXCHANNELS];
194 cmsUInt32Number i, n;
196 accum = (cmsUInt8Number*) in;
197 output = (cmsUInt8Number*) out;
200 for (i=0; i < n; i++) {
202 accum = p -> FromInput(p, wIn, accum, Size);
203 p ->Lut ->Eval16Fn(wIn, wOut, p -> Lut->Data);
204 output = p -> ToOutput(p, wOut, output, Size);
209 // Auxiliar: Handle precalculated gamut check
211 void TransformOnePixelWithGamutCheck(_cmsTRANSFORM* p,
212 const cmsUInt16Number wIn[],
213 cmsUInt16Number wOut[])
215 cmsUInt16Number wOutOfGamut;
217 p ->GamutCheck ->Eval16Fn(wIn, &wOutOfGamut, p ->GamutCheck ->Data);
218 if (wOutOfGamut >= 1) {
222 for (i=0; i < p ->Lut->OutputChannels; i++)
226 p ->Lut ->Eval16Fn(wIn, wOut, p -> Lut->Data);
229 // Gamut check, No caché, 16 bits.
231 void PrecalculatedXFORMGamutCheck(_cmsTRANSFORM* p,
233 void* out, cmsUInt32Number Size)
235 cmsUInt8Number* accum;
236 cmsUInt8Number* output;
237 cmsUInt16Number wIn[cmsMAXCHANNELS], wOut[cmsMAXCHANNELS];
238 cmsUInt32Number i, n;
240 accum = (cmsUInt8Number*) in;
241 output = (cmsUInt8Number*) out;
242 n = Size; // Buffer len
244 for (i=0; i < n; i++) {
246 accum = p -> FromInput(p, wIn, accum, Size);
247 TransformOnePixelWithGamutCheck(p, wIn, wOut);
248 output = p -> ToOutput(p, wOut, output, Size);
253 // No gamut check, Caché, 16 bits,
255 void CachedXFORM(_cmsTRANSFORM* p,
257 void* out, cmsUInt32Number Size)
259 cmsUInt8Number* accum;
260 cmsUInt8Number* output;
261 cmsUInt16Number wIn[cmsMAXCHANNELS], wOut[cmsMAXCHANNELS];
262 cmsUInt32Number i, n;
265 accum = (cmsUInt8Number*) in;
266 output = (cmsUInt8Number*) out;
267 n = Size; // Buffer len
269 // Empty buffers for quick memcmp
270 memset(wIn, 0, sizeof(wIn));
271 memset(wOut, 0, sizeof(wOut));
273 // Get copy of zero cache
274 memcpy(&Cache, &p ->Cache, sizeof(Cache));
276 for (i=0; i < n; i++) {
278 accum = p -> FromInput(p, wIn, accum, Size);
280 if (memcmp(wIn, Cache.CacheIn, sizeof(Cache.CacheIn)) == 0) {
282 memcpy(wOut, Cache.CacheOut, sizeof(Cache.CacheOut));
286 p ->Lut ->Eval16Fn(wIn, wOut, p -> Lut->Data);
288 memcpy(Cache.CacheIn, wIn, sizeof(Cache.CacheIn));
289 memcpy(Cache.CacheOut, wOut, sizeof(Cache.CacheOut));
292 output = p -> ToOutput(p, wOut, output, Size);
298 // All those nice features together
300 void CachedXFORMGamutCheck(_cmsTRANSFORM* p,
302 void* out, cmsUInt32Number Size)
304 cmsUInt8Number* accum;
305 cmsUInt8Number* output;
306 cmsUInt16Number wIn[cmsMAXCHANNELS], wOut[cmsMAXCHANNELS];
307 cmsUInt32Number i, n;
310 accum = (cmsUInt8Number*) in;
311 output = (cmsUInt8Number*) out;
312 n = Size; // Buffer len
314 // Empty buffers for quick memcmp
315 memset(wIn, 0, sizeof(cmsUInt16Number) * cmsMAXCHANNELS);
316 memset(wOut, 0, sizeof(cmsUInt16Number) * cmsMAXCHANNELS);
318 // Get copy of zero cache
319 memcpy(&Cache, &p ->Cache, sizeof(Cache));
321 for (i=0; i < n; i++) {
323 accum = p -> FromInput(p, wIn, accum, Size);
325 if (memcmp(wIn, Cache.CacheIn, sizeof(Cache.CacheIn)) == 0) {
326 memcpy(wOut, Cache.CacheOut, sizeof(Cache.CacheOut));
329 TransformOnePixelWithGamutCheck(p, wIn, wOut);
330 memcpy(Cache.CacheIn, wIn, sizeof(Cache.CacheIn));
331 memcpy(Cache.CacheOut, wOut, sizeof(Cache.CacheOut));
334 output = p -> ToOutput(p, wOut, output, Size);
342 // Allocate transform struct and set it to defaults
344 _cmsTRANSFORM* AllocEmptyTransform(cmsContext ContextID, cmsUInt32Number InputFormat, cmsUInt32Number OutputFormat, cmsUInt32Number dwFlags)
346 // Allocate needed memory
347 _cmsTRANSFORM* p = (_cmsTRANSFORM*) _cmsMallocZero(ContextID, sizeof(_cmsTRANSFORM));
350 // Check whatever this is a true floating point transform
351 if (_cmsFormatterIsFloat(InputFormat) && _cmsFormatterIsFloat(OutputFormat)) {
353 // Get formatter function always return a valid union, but the contents of this union may be NULL.
354 p ->FromInputFloat = _cmsGetFormatter(InputFormat, cmsFormatterInput, CMS_PACK_FLAGS_FLOAT).FmtFloat;
355 p ->ToOutputFloat = _cmsGetFormatter(OutputFormat, cmsFormatterOutput, CMS_PACK_FLAGS_FLOAT).FmtFloat;
356 dwFlags |= cmsFLAGS_CAN_CHANGE_FORMATTER;
358 if (p ->FromInputFloat == NULL || p ->ToOutputFloat == NULL) {
360 cmsSignalError(ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported raster format");
361 _cmsFree(ContextID, p);
365 // Float transforms don't use caché, always are non-NULL
366 p ->xform = FloatXFORM;
370 if (InputFormat == 0 && OutputFormat == 0) {
371 p ->FromInput = p ->ToOutput = NULL;
375 int BytesPerPixelInput;
377 p ->FromInput = _cmsGetFormatter(InputFormat, cmsFormatterInput, CMS_PACK_FLAGS_16BITS).Fmt16;
378 p ->ToOutput = _cmsGetFormatter(OutputFormat, cmsFormatterOutput, CMS_PACK_FLAGS_16BITS).Fmt16;
381 if (p ->FromInput == NULL || p ->ToOutput == NULL) {
383 cmsSignalError(ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported raster format");
384 _cmsFree(ContextID, p);
388 BytesPerPixelInput = T_BYTES(p ->InputFormat);
389 if (BytesPerPixelInput == 0 || BytesPerPixelInput >= 2)
390 dwFlags |= cmsFLAGS_CAN_CHANGE_FORMATTER;
394 if (dwFlags & cmsFLAGS_NULLTRANSFORM) {
396 p ->xform = NullXFORM;
399 if (dwFlags & cmsFLAGS_NOCACHE) {
401 if (dwFlags & cmsFLAGS_GAMUTCHECK)
402 p ->xform = PrecalculatedXFORMGamutCheck; // Gamut check, no caché
404 p ->xform = PrecalculatedXFORM; // No caché, no gamut check
408 if (dwFlags & cmsFLAGS_GAMUTCHECK)
409 p ->xform = CachedXFORMGamutCheck; // Gamut check, caché
411 p ->xform = CachedXFORM; // No gamut check, caché
418 p ->InputFormat = InputFormat;
419 p ->OutputFormat = OutputFormat;
420 p ->dwOriginalFlags = dwFlags;
421 p ->ContextID = ContextID;
426 cmsBool GetXFormColorSpaces(int nProfiles, cmsHPROFILE hProfiles[], cmsColorSpaceSignature* Input, cmsColorSpaceSignature* Output)
428 cmsColorSpaceSignature ColorSpaceIn, ColorSpaceOut;
429 cmsColorSpaceSignature PostColorSpace;
432 if (hProfiles[0] == NULL) return FALSE;
434 *Input = PostColorSpace = cmsGetColorSpace(hProfiles[0]);
436 // Special handling for named color profiles as devicelinks
437 if (nProfiles == 1 && cmsGetDeviceClass(hProfiles[0]) == cmsSigNamedColorClass) {
438 *Input = cmsSig1colorData;
439 *Output = PostColorSpace;
443 for (i=0; i < nProfiles; i++) {
445 cmsHPROFILE hProfile = hProfiles[i];
447 int lIsInput = (PostColorSpace != cmsSigXYZData) &&
448 (PostColorSpace != cmsSigLabData);
452 if (hProfile == NULL) return FALSE;
454 lIsDeviceLink = (cmsGetDeviceClass(hProfile) == cmsSigLinkClass);
456 if (lIsInput || lIsDeviceLink) {
458 ColorSpaceIn = cmsGetColorSpace(hProfile);
459 ColorSpaceOut = cmsGetPCS(hProfile);
463 ColorSpaceIn = cmsGetPCS(hProfile);
464 ColorSpaceOut = cmsGetColorSpace(hProfile);
467 PostColorSpace = ColorSpaceOut;
470 *Output = PostColorSpace;
477 cmsBool IsProperColorSpace(cmsColorSpaceSignature Check, cmsUInt32Number dwFormat)
479 int Space1 = T_COLORSPACE(dwFormat);
480 int Space2 = _cmsLCMScolorSpace(Check);
482 if (Space1 == PT_ANY) return TRUE;
483 if (Space1 == Space2) return TRUE;
485 if (Space1 == PT_LabV2 && Space2 == PT_Lab) return TRUE;
486 if (Space1 == PT_Lab && Space2 == PT_LabV2) return TRUE;
491 // ----------------------------------------------------------------------------------------------------------------
493 // New to lcms 2.0 -- have all parameters available.
494 cmsHTRANSFORM CMSEXPORT cmsCreateExtendedTransform(cmsContext ContextID,
495 cmsUInt32Number nProfiles, cmsHPROFILE hProfiles[],
497 cmsUInt32Number Intents[],
498 cmsFloat64Number AdaptationStates[],
499 cmsHPROFILE hGamutProfile,
500 cmsUInt32Number nGamutPCSposition,
501 cmsUInt32Number InputFormat,
502 cmsUInt32Number OutputFormat,
503 cmsUInt32Number dwFlags)
505 _cmsTRANSFORM* xform;
506 cmsBool FloatTransform;
507 cmsColorSpaceSignature EntryColorSpace;
508 cmsColorSpaceSignature ExitColorSpace;
510 cmsUInt32Number LastIntent = Intents[nProfiles-1];
512 // If gamut check is requested, make sure we have a gamut profile
513 if (dwFlags & cmsFLAGS_GAMUTCHECK) {
514 if (hGamutProfile == NULL) dwFlags &= ~cmsFLAGS_GAMUTCHECK;
517 // On floating point transforms, inhibit optimizations
518 FloatTransform = (_cmsFormatterIsFloat(InputFormat) && _cmsFormatterIsFloat(OutputFormat));
520 if (_cmsFormatterIsFloat(InputFormat) || _cmsFormatterIsFloat(OutputFormat))
521 dwFlags |= cmsFLAGS_NOCACHE;
523 // Mark entry/exit spaces
524 if (!GetXFormColorSpaces(nProfiles, hProfiles, &EntryColorSpace, &ExitColorSpace)) {
525 cmsSignalError(ContextID, cmsERROR_NULL, "NULL input profiles on transform");
529 // Check if proper colorspaces
530 if (!IsProperColorSpace(EntryColorSpace, InputFormat)) {
531 cmsSignalError(ContextID, cmsERROR_COLORSPACE_CHECK, "Wrong input color space on transform");
535 if (!IsProperColorSpace(ExitColorSpace, OutputFormat)) {
536 cmsSignalError(ContextID, cmsERROR_COLORSPACE_CHECK, "Wrong output color space on transform");
540 // Create a pipeline with all transformations
541 Lut = _cmsLinkProfiles(ContextID, nProfiles, Intents, hProfiles, BPC, AdaptationStates, dwFlags);
543 cmsSignalError(ContextID, cmsERROR_NOT_SUITABLE, "Couldn't link the profiles");
547 // Optimize the LUT if possible
548 _cmsOptimizePipeline(&Lut, LastIntent, &InputFormat, &OutputFormat, &dwFlags);
552 xform = AllocEmptyTransform(ContextID, InputFormat, OutputFormat, dwFlags);
554 cmsPipelineFree(Lut);
559 xform ->EntryColorSpace = EntryColorSpace;
560 xform ->ExitColorSpace = ExitColorSpace;
561 xform ->RenderingIntent = Intents[nProfiles-1];
564 // Create a gamut check LUT if requested
565 if (hGamutProfile != NULL && (dwFlags & cmsFLAGS_GAMUTCHECK))
566 xform ->GamutCheck = _cmsCreateGamutCheckPipeline(ContextID, hProfiles,
573 // Try to read input and output colorant table
574 if (cmsIsTag(hProfiles[0], cmsSigColorantTableTag)) {
576 // Input table can only come in this way.
577 xform ->InputColorant = cmsDupNamedColorList((cmsNAMEDCOLORLIST*) cmsReadTag(hProfiles[0], cmsSigColorantTableTag));
580 // Output is a little bit more complex.
581 if (cmsGetDeviceClass(hProfiles[nProfiles-1]) == cmsSigLinkClass) {
583 // This tag may exist only on devicelink profiles.
584 if (cmsIsTag(hProfiles[nProfiles-1], cmsSigColorantTableOutTag)) {
586 // It may be NULL if error
587 xform ->OutputColorant = cmsDupNamedColorList((cmsNAMEDCOLORLIST*) cmsReadTag(hProfiles[nProfiles-1], cmsSigColorantTableOutTag));
592 if (cmsIsTag(hProfiles[nProfiles-1], cmsSigColorantTableTag)) {
594 xform -> OutputColorant = cmsDupNamedColorList((cmsNAMEDCOLORLIST*) cmsReadTag(hProfiles[nProfiles-1], cmsSigColorantTableTag));
598 // Store the sequence of profiles
599 if (dwFlags & cmsFLAGS_KEEP_SEQUENCE) {
600 xform ->Sequence = _cmsCompileProfileSequence(ContextID, nProfiles, hProfiles);
603 xform ->Sequence = NULL;
605 // If this is a cached transform, init first value, which is zero (16 bits only)
606 if (!(dwFlags & cmsFLAGS_NOCACHE)) {
608 memset(&xform ->Cache.CacheIn, 0, sizeof(xform ->Cache.CacheIn));
610 if (xform ->GamutCheck != NULL) {
611 TransformOnePixelWithGamutCheck(xform, xform ->Cache.CacheIn, xform->Cache.CacheOut);
615 xform ->Lut ->Eval16Fn(xform ->Cache.CacheIn, xform->Cache.CacheOut, xform -> Lut->Data);
620 return (cmsHTRANSFORM) xform;
623 // Multiprofile transforms: Gamut check is not available here, as it is unclear from which profile the gamut comes.
624 cmsHTRANSFORM CMSEXPORT cmsCreateMultiprofileTransformTHR(cmsContext ContextID,
625 cmsHPROFILE hProfiles[],
626 cmsUInt32Number nProfiles,
627 cmsUInt32Number InputFormat,
628 cmsUInt32Number OutputFormat,
629 cmsUInt32Number Intent,
630 cmsUInt32Number dwFlags)
634 cmsUInt32Number Intents[256];
635 cmsFloat64Number AdaptationStates[256];
637 if (nProfiles <= 0 || nProfiles > 255) {
638 cmsSignalError(ContextID, cmsERROR_RANGE, "Wrong number of profiles. 1..255 expected, %d found.", nProfiles);
642 for (i=0; i < nProfiles; i++) {
643 BPC[i] = dwFlags & cmsFLAGS_BLACKPOINTCOMPENSATION ? TRUE : FALSE;
645 AdaptationStates[i] = GlobalAdaptationState;
649 return cmsCreateExtendedTransform(ContextID, nProfiles, hProfiles, BPC, Intents, AdaptationStates, NULL, 0, InputFormat, OutputFormat, dwFlags);
654 cmsHTRANSFORM CMSEXPORT cmsCreateMultiprofileTransform(cmsHPROFILE hProfiles[],
655 cmsUInt32Number nProfiles,
656 cmsUInt32Number InputFormat,
657 cmsUInt32Number OutputFormat,
658 cmsUInt32Number Intent,
659 cmsUInt32Number dwFlags)
662 if (nProfiles <= 0 || nProfiles > 255) {
663 cmsSignalError(NULL, cmsERROR_RANGE, "Wrong number of profiles. 1..255 expected, %d found.", nProfiles);
667 return cmsCreateMultiprofileTransformTHR(cmsGetProfileContextID(hProfiles[0]),
676 cmsHTRANSFORM CMSEXPORT cmsCreateTransformTHR(cmsContext ContextID,
678 cmsUInt32Number InputFormat,
680 cmsUInt32Number OutputFormat,
681 cmsUInt32Number Intent,
682 cmsUInt32Number dwFlags)
685 cmsHPROFILE hArray[2];
690 return cmsCreateMultiprofileTransformTHR(ContextID, hArray, Output == NULL ? 1 : 2, InputFormat, OutputFormat, Intent, dwFlags);
693 CMSAPI cmsHTRANSFORM CMSEXPORT cmsCreateTransform(cmsHPROFILE Input,
694 cmsUInt32Number InputFormat,
696 cmsUInt32Number OutputFormat,
697 cmsUInt32Number Intent,
698 cmsUInt32Number dwFlags)
700 return cmsCreateTransformTHR(cmsGetProfileContextID(Input), Input, InputFormat, Output, OutputFormat, Intent, dwFlags);
704 cmsHTRANSFORM CMSEXPORT cmsCreateProofingTransformTHR(cmsContext ContextID,
705 cmsHPROFILE InputProfile,
706 cmsUInt32Number InputFormat,
707 cmsHPROFILE OutputProfile,
708 cmsUInt32Number OutputFormat,
709 cmsHPROFILE ProofingProfile,
710 cmsUInt32Number nIntent,
711 cmsUInt32Number ProofingIntent,
712 cmsUInt32Number dwFlags)
714 cmsHPROFILE hArray[4];
715 cmsUInt32Number Intents[4];
717 cmsFloat64Number Adaptation[4];
718 cmsBool DoBPC = (dwFlags & cmsFLAGS_BLACKPOINTCOMPENSATION) ? TRUE : FALSE;
721 hArray[0] = InputProfile; hArray[1] = ProofingProfile; hArray[2] = ProofingProfile; hArray[3] = OutputProfile;
722 Intents[0] = nIntent; Intents[1] = nIntent; Intents[2] = INTENT_RELATIVE_COLORIMETRIC; Intents[3] = ProofingIntent;
723 BPC[0] = DoBPC; BPC[1] = DoBPC; BPC[2] = 0; BPC[3] = 0;
725 Adaptation[0] = Adaptation[1] = Adaptation[2] = Adaptation[3] = GlobalAdaptationState;
727 if (!(dwFlags & (cmsFLAGS_SOFTPROOFING|cmsFLAGS_GAMUTCHECK)))
728 return cmsCreateTransformTHR(ContextID, InputProfile, InputFormat, OutputProfile, OutputFormat, nIntent, dwFlags);
730 return cmsCreateExtendedTransform(ContextID, 4, hArray, BPC, Intents, Adaptation,
731 ProofingProfile, 1, InputFormat, OutputFormat, dwFlags);
736 cmsHTRANSFORM CMSEXPORT cmsCreateProofingTransform(cmsHPROFILE InputProfile,
737 cmsUInt32Number InputFormat,
738 cmsHPROFILE OutputProfile,
739 cmsUInt32Number OutputFormat,
740 cmsHPROFILE ProofingProfile,
741 cmsUInt32Number nIntent,
742 cmsUInt32Number ProofingIntent,
743 cmsUInt32Number dwFlags)
745 return cmsCreateProofingTransformTHR(cmsGetProfileContextID(InputProfile),
757 // Grab the ContextID from an open transform. Returns NULL if a NULL transform is passed
758 cmsContext CMSEXPORT cmsGetTransformContextID(cmsHTRANSFORM hTransform)
760 _cmsTRANSFORM* xform = (_cmsTRANSFORM*) hTransform;
762 if (xform == NULL) return NULL;
763 return xform -> ContextID;
766 // Grab the input/output formats
767 cmsUInt32Number CMSEXPORT cmsGetTransformInputFormat(cmsHTRANSFORM hTransform)
769 _cmsTRANSFORM* xform = (_cmsTRANSFORM*) hTransform;
771 if (xform == NULL) return 0;
772 return xform->InputFormat;
775 cmsUInt32Number CMSEXPORT cmsGetTransformOutputFormat(cmsHTRANSFORM hTransform)
777 _cmsTRANSFORM* xform = (_cmsTRANSFORM*) hTransform;
779 if (xform == NULL) return 0;
780 return xform->OutputFormat;
783 // For backwards compatibility
784 cmsBool CMSEXPORT cmsChangeBuffersFormat(cmsHTRANSFORM hTransform,
785 cmsUInt32Number InputFormat,
786 cmsUInt32Number OutputFormat)
789 _cmsTRANSFORM* xform = (_cmsTRANSFORM*) hTransform;
790 cmsFormatter16 FromInput, ToOutput;
791 cmsUInt32Number BytesPerPixelInput;
793 // We only can afford to change formatters if previous transform is at least 16 bits
794 BytesPerPixelInput = T_BYTES(xform ->InputFormat);
795 if (!(xform ->dwOriginalFlags & cmsFLAGS_CAN_CHANGE_FORMATTER)) {
797 cmsSignalError(xform ->ContextID, cmsERROR_NOT_SUITABLE, "cmsChangeBuffersFormat works only on transforms created originally with at least 16 bits of precision");
801 FromInput = _cmsGetFormatter(InputFormat, cmsFormatterInput, CMS_PACK_FLAGS_16BITS).Fmt16;
802 ToOutput = _cmsGetFormatter(OutputFormat, cmsFormatterOutput, CMS_PACK_FLAGS_16BITS).Fmt16;
804 if (FromInput == NULL || ToOutput == NULL) {
806 cmsSignalError(xform -> ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported raster format");
810 xform ->InputFormat = InputFormat;
811 xform ->OutputFormat = OutputFormat;
812 xform ->FromInput = FromInput;
813 xform ->ToOutput = ToOutput;