diff options
Diffstat (limited to 'thirdparty/liblcms2/src/cmscnvrt.c')
| -rw-r--r-- | thirdparty/liblcms2/src/cmscnvrt.c | 581 |
1 files changed, 342 insertions, 239 deletions
diff --git a/thirdparty/liblcms2/src/cmscnvrt.c b/thirdparty/liblcms2/src/cmscnvrt.c index 8dadc875..1a93e83f 100644 --- a/thirdparty/liblcms2/src/cmscnvrt.c +++ b/thirdparty/liblcms2/src/cmscnvrt.c @@ -1,24 +1,24 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2010 Marti Maria Saguer +// Copyright (c) 1998-2012 Marti Maria Saguer // -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the Software +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the Software // is furnished to do so, subject to the following conditions: // -// The above copyright notice and this permission notice shall be included in +// The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO -// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // //--------------------------------------------------------------------------------- @@ -27,26 +27,26 @@ #include "lcms2_internal.h" -// Link several profiles to obtain a single LUT modelling the whole color transform. Intents, Black point +// Link several profiles to obtain a single LUT modelling the whole color transform. Intents, Black point // compensation and Adaptation parameters may vary across profiles. BPC and Adaptation refers to the PCS // after the profile. I.e, BPC[0] refers to connexion between profile(0) and profile(1) -cmsPipeline* _cmsLinkProfiles(cmsContext ContextID, +cmsPipeline* _cmsLinkProfiles(cmsContext ContextID, cmsUInt32Number nProfiles, - cmsUInt32Number Intents[], - cmsHPROFILE hProfiles[], + cmsUInt32Number Intents[], + cmsHPROFILE hProfiles[], cmsBool BPC[], cmsFloat64Number AdaptationStates[], cmsUInt32Number dwFlags); - + //--------------------------------------------------------------------------------- -// This is the default routine for ICC-style intents. A user may decide to override it by using a plugin. +// This is the default routine for ICC-style intents. A user may decide to override it by using a plugin. // Supported intents are perceptual, relative colorimetric, saturation and ICC-absolute colorimetric -static -cmsPipeline* DefaultICCintents(cmsContext ContextID, +static +cmsPipeline* DefaultICCintents(cmsContext ContextID, cmsUInt32Number nProfiles, - cmsUInt32Number Intents[], - cmsHPROFILE hProfiles[], + cmsUInt32Number Intents[], + cmsHPROFILE hProfiles[], cmsBool BPC[], cmsFloat64Number AdaptationStates[], cmsUInt32Number dwFlags); @@ -56,10 +56,10 @@ cmsPipeline* DefaultICCintents(cmsContext ContextID, // This is the entry for black-preserving K-only intents, which are non-ICC. Last profile have to be a output profile // to do the trick (no devicelinks allowed at that position) static -cmsPipeline* BlackPreservingKOnlyIntents(cmsContext ContextID, +cmsPipeline* BlackPreservingKOnlyIntents(cmsContext ContextID, cmsUInt32Number nProfiles, - cmsUInt32Number Intents[], - cmsHPROFILE hProfiles[], + cmsUInt32Number Intents[], + cmsHPROFILE hProfiles[], cmsBool BPC[], cmsFloat64Number AdaptationStates[], cmsUInt32Number dwFlags); @@ -69,10 +69,10 @@ cmsPipeline* BlackPreservingKOnlyIntents(cmsContext ContextID, // This is the entry for black-plane preserving, which are non-ICC. Again, Last profile have to be a output profile // to do the trick (no devicelinks allowed at that position) static -cmsPipeline* BlackPreservingKPlaneIntents(cmsContext ContextID, +cmsPipeline* BlackPreservingKPlaneIntents(cmsContext ContextID, cmsUInt32Number nProfiles, - cmsUInt32Number Intents[], - cmsHPROFILE hProfiles[], + cmsUInt32Number Intents[], + cmsHPROFILE hProfiles[], cmsBool BPC[], cmsFloat64Number AdaptationStates[], cmsUInt32Number dwFlags); @@ -92,7 +92,7 @@ typedef struct _cms_intents_list { // Built-in intents -static cmsIntentsList DefaultIntents[] = { +static cmsIntentsList DefaultIntents[] = { { INTENT_PERCEPTUAL, "Perceptual", DefaultICCintents, &DefaultIntents[1] }, { INTENT_RELATIVE_COLORIMETRIC, "Relative colorimetric", DefaultICCintents, &DefaultIntents[2] }, @@ -103,35 +103,88 @@ static cmsIntentsList DefaultIntents[] = { { INTENT_PRESERVE_K_ONLY_SATURATION, "Saturation preserving black ink", BlackPreservingKOnlyIntents, &DefaultIntents[7] }, { INTENT_PRESERVE_K_PLANE_PERCEPTUAL, "Perceptual preserving black plane", BlackPreservingKPlaneIntents, &DefaultIntents[8] }, { INTENT_PRESERVE_K_PLANE_RELATIVE_COLORIMETRIC,"Relative colorimetric preserving black plane", BlackPreservingKPlaneIntents, &DefaultIntents[9] }, - { INTENT_PRESERVE_K_PLANE_SATURATION, "Saturation preserving black plane", BlackPreservingKPlaneIntents, NULL } + { INTENT_PRESERVE_K_PLANE_SATURATION, "Saturation preserving black plane", BlackPreservingKPlaneIntents, NULL } }; // A pointer to the begining of the list -static cmsIntentsList *Intents = DefaultIntents; +_cmsIntentsPluginChunkType _cmsIntentsPluginChunk = { NULL }; + +// Duplicates the zone of memory used by the plug-in in the new context +static +void DupPluginIntentsList(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src) +{ + _cmsIntentsPluginChunkType newHead = { NULL }; + cmsIntentsList* entry; + cmsIntentsList* Anterior = NULL; + _cmsIntentsPluginChunkType* head = (_cmsIntentsPluginChunkType*) src->chunks[IntentPlugin]; + + // Walk the list copying all nodes + for (entry = head->Intents; + entry != NULL; + entry = entry ->Next) { + + cmsIntentsList *newEntry = ( cmsIntentsList *) _cmsSubAllocDup(ctx ->MemPool, entry, sizeof(cmsIntentsList)); + + if (newEntry == NULL) + return; + + // We want to keep the linked list order, so this is a little bit tricky + newEntry -> Next = NULL; + if (Anterior) + Anterior -> Next = newEntry; + + Anterior = newEntry; + + if (newHead.Intents == NULL) + newHead.Intents = newEntry; + } + + ctx ->chunks[IntentPlugin] = _cmsSubAllocDup(ctx->MemPool, &newHead, sizeof(_cmsIntentsPluginChunkType)); +} + +void _cmsAllocIntentsPluginChunk(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src) +{ + if (src != NULL) { + + // Copy all linked list + DupPluginIntentsList(ctx, src); + } + else { + static _cmsIntentsPluginChunkType IntentsPluginChunkType = { NULL }; + ctx ->chunks[IntentPlugin] = _cmsSubAllocDup(ctx ->MemPool, &IntentsPluginChunkType, sizeof(_cmsIntentsPluginChunkType)); + } +} + // Search the list for a suitable intent. Returns NULL if not found -static -cmsIntentsList* SearchIntent(cmsUInt32Number Intent) +static +cmsIntentsList* SearchIntent(cmsContext ContextID, cmsUInt32Number Intent) { + _cmsIntentsPluginChunkType* ctx = ( _cmsIntentsPluginChunkType*) _cmsContextGetClientChunk(ContextID, IntentPlugin); cmsIntentsList* pt; - for (pt = Intents; pt != NULL; pt = pt -> Next) + for (pt = ctx -> Intents; pt != NULL; pt = pt -> Next) + if (pt ->Intent == Intent) return pt; + + for (pt = DefaultIntents; pt != NULL; pt = pt -> Next) if (pt ->Intent == Intent) return pt; return NULL; } -// Black point compensation. Implemented as a linear scaling in XYZ. Black points +// Black point compensation. Implemented as a linear scaling in XYZ. Black points // should come relative to the white point. Fills an matrix/offset element m // which is organized as a 4x4 matrix. static -void ComputeBlackPointCompensation(const cmsCIEXYZ* BlackPointIn, +void ComputeBlackPointCompensation(const cmsCIEXYZ* BlackPointIn, const cmsCIEXYZ* BlackPointOut, cmsMAT3* m, cmsVEC3* off) -{ +{ cmsFloat64Number ax, ay, az, bx, by, bz, tx, ty, tz; - + // Now we need to compute a matrix plus an offset m and of such of // [m]*bpin + off = bpout // [m]*D50 + off = D50 @@ -164,17 +217,21 @@ void ComputeBlackPointCompensation(const cmsCIEXYZ* BlackPointIn, static cmsFloat64Number CHAD2Temp(const cmsMAT3* Chad) { - // Convert D50 across CHAD to get the absolute white point - cmsVEC3 d, s; - cmsCIEXYZ Dest; - cmsCIExyY DestChromaticity; - cmsFloat64Number TempK; + // Convert D50 across inverse CHAD to get the absolute white point + cmsVEC3 d, s; + cmsCIEXYZ Dest; + cmsCIExyY DestChromaticity; + cmsFloat64Number TempK; + cmsMAT3 m1, m2; + + m1 = *Chad; + if (!_cmsMAT3inverse(&m1, &m2)) return FALSE; s.n[VX] = cmsD50_XYZ() -> X; s.n[VY] = cmsD50_XYZ() -> Y; s.n[VZ] = cmsD50_XYZ() -> Z; - _cmsMAT3eval(&d, Chad, &s); + _cmsMAT3eval(&d, &m2, &s); Dest.X = d.n[VX]; Dest.Y = d.n[VY]; @@ -190,33 +247,32 @@ cmsFloat64Number CHAD2Temp(const cmsMAT3* Chad) // Compute a CHAD based on a given temperature static -void Temp2CHAD(cmsMAT3* Chad, cmsFloat64Number Temp) + void Temp2CHAD(cmsMAT3* Chad, cmsFloat64Number Temp) { cmsCIEXYZ White; cmsCIExyY ChromaticityOfWhite; - - cmsWhitePointFromTemp(&ChromaticityOfWhite, Temp); - cmsxyY2XYZ(&White, &ChromaticityOfWhite); - _cmsAdaptationMatrix(Chad, NULL, cmsD50_XYZ(), &White); + cmsWhitePointFromTemp(&ChromaticityOfWhite, Temp); + cmsxyY2XYZ(&White, &ChromaticityOfWhite); + _cmsAdaptationMatrix(Chad, NULL, &White, cmsD50_XYZ()); } // Join scalings to obtain relative input to absolute and then to relative output. // Result is stored in a 3x3 matrix static cmsBool ComputeAbsoluteIntent(cmsFloat64Number AdaptationState, - const cmsCIEXYZ* WhitePointIn, + const cmsCIEXYZ* WhitePointIn, const cmsMAT3* ChromaticAdaptationMatrixIn, const cmsCIEXYZ* WhitePointOut, const cmsMAT3* ChromaticAdaptationMatrixOut, cmsMAT3* m) { - cmsMAT3 Scale, m1, m2, m3; + cmsMAT3 Scale, m1, m2, m3, m4; // Adaptation state if (AdaptationState == 1.0) { - // Observer is fully adapted. Keep chromatic adaptation. + // Observer is fully adapted. Keep chromatic adaptation. // That is the standard V4 behaviour _cmsVEC3init(&m->v[0], WhitePointIn->X / WhitePointOut->X, 0, 0); _cmsVEC3init(&m->v[1], 0, WhitePointIn->Y / WhitePointOut->Y, 0); @@ -230,23 +286,32 @@ cmsBool ComputeAbsoluteIntent(cmsFloat64Number AdaptationState, _cmsVEC3init(&Scale.v[1], 0, WhitePointIn->Y / WhitePointOut->Y, 0); _cmsVEC3init(&Scale.v[2], 0, 0, WhitePointIn->Z / WhitePointOut->Z); - m1 = *ChromaticAdaptationMatrixIn; - if (!_cmsMAT3inverse(&m1, &m2)) return FALSE; - _cmsMAT3per(&m3, &m2, &Scale); - // m3 holds CHAD from input white to D50 times abs. col. scaling if (AdaptationState == 0.0) { + m1 = *ChromaticAdaptationMatrixOut; + _cmsMAT3per(&m2, &m1, &Scale); + // m2 holds CHAD from output white to D50 times abs. col. scaling + // Observer is not adapted, undo the chromatic adaptation - _cmsMAT3per(m, &m3, ChromaticAdaptationMatrixOut); + _cmsMAT3per(m, &m2, ChromaticAdaptationMatrixOut); + + m3 = *ChromaticAdaptationMatrixIn; + if (!_cmsMAT3inverse(&m3, &m4)) return FALSE; + _cmsMAT3per(m, &m2, &m4); } else { cmsMAT3 MixedCHAD; cmsFloat64Number TempSrc, TempDest, Temp; - TempSrc = CHAD2Temp(ChromaticAdaptationMatrixIn); // K for source white - TempDest = CHAD2Temp(ChromaticAdaptationMatrixOut); // K for dest white + m1 = *ChromaticAdaptationMatrixIn; + if (!_cmsMAT3inverse(&m1, &m2)) return FALSE; + _cmsMAT3per(&m3, &m2, &Scale); + // m3 holds CHAD from input white to D50 times abs. col. scaling + + TempSrc = CHAD2Temp(ChromaticAdaptationMatrixIn); + TempDest = CHAD2Temp(ChromaticAdaptationMatrixOut); if (TempSrc < 0.0 || TempDest < 0.0) return FALSE; // Something went wrong @@ -256,9 +321,9 @@ cmsBool ComputeAbsoluteIntent(cmsFloat64Number AdaptationState, return TRUE; } - Temp = AdaptationState * TempSrc + (1.0 - AdaptationState) * TempDest; + Temp = (1.0 - AdaptationState) * TempDest + AdaptationState * TempSrc; - // Get a CHAD from D50 to whatever output temperature. This replaces output CHAD + // Get a CHAD from whatever output temperature to D50. This replaces output CHAD Temp2CHAD(&MixedCHAD, Temp); _cmsMAT3per(m, &m3, &MixedCHAD); @@ -276,12 +341,12 @@ cmsBool IsEmptyLayer(cmsMAT3* m, cmsVEC3* off) cmsFloat64Number diff = 0; cmsMAT3 Ident; int i; - + if (m == NULL && off == NULL) return TRUE; // NULL is allowed as an empty layer if (m == NULL && off != NULL) return FALSE; // This is an internal error _cmsMAT3identity(&Ident); - + for (i=0; i < 3*3; i++) diff += fabs(((cmsFloat64Number*)m)[i] - ((cmsFloat64Number*)&Ident)[i]); @@ -295,10 +360,10 @@ cmsBool IsEmptyLayer(cmsMAT3* m, cmsVEC3* off) // Compute the conversion layer static -cmsBool ComputeConversion(int i, cmsHPROFILE hProfiles[], - cmsUInt32Number Intent, - cmsBool BPC, - cmsFloat64Number AdaptationState, +cmsBool ComputeConversion(int i, cmsHPROFILE hProfiles[], + cmsUInt32Number Intent, + cmsBool BPC, + cmsFloat64Number AdaptationState, cmsMAT3* m, cmsVEC3* off) { @@ -312,7 +377,7 @@ cmsBool ComputeConversion(int i, cmsHPROFILE hProfiles[], if (Intent == INTENT_ABSOLUTE_COLORIMETRIC) { cmsCIEXYZ WhitePointIn, WhitePointOut; - cmsMAT3 ChromaticAdaptationMatrixIn, ChromaticAdaptationMatrixOut; + cmsMAT3 ChromaticAdaptationMatrixIn, ChromaticAdaptationMatrixOut; _cmsReadMediaWhitePoint(&WhitePointIn, hProfiles[i-1]); _cmsReadCHAD(&ChromaticAdaptationMatrixIn, hProfiles[i-1]); @@ -320,8 +385,8 @@ cmsBool ComputeConversion(int i, cmsHPROFILE hProfiles[], _cmsReadMediaWhitePoint(&WhitePointOut, hProfiles[i]); _cmsReadCHAD(&ChromaticAdaptationMatrixOut, hProfiles[i]); - if (!ComputeAbsoluteIntent(AdaptationState, - &WhitePointIn, &ChromaticAdaptationMatrixIn, + if (!ComputeAbsoluteIntent(AdaptationState, + &WhitePointIn, &ChromaticAdaptationMatrixIn, &WhitePointOut, &ChromaticAdaptationMatrixOut, m)) return FALSE; } @@ -333,24 +398,24 @@ cmsBool ComputeConversion(int i, cmsHPROFILE hProfiles[], cmsCIEXYZ BlackPointIn, BlackPointOut; cmsDetectBlackPoint(&BlackPointIn, hProfiles[i-1], Intent, 0); - cmsDetectBlackPoint(&BlackPointOut, hProfiles[i], Intent, 0); + cmsDetectDestinationBlackPoint(&BlackPointOut, hProfiles[i], Intent, 0); // If black points are equal, then do nothing if (BlackPointIn.X != BlackPointOut.X || BlackPointIn.Y != BlackPointOut.Y || - BlackPointIn.Z != BlackPointOut.Z) + BlackPointIn.Z != BlackPointOut.Z) ComputeBlackPointCompensation(&BlackPointIn, &BlackPointOut, m, off); } } // Offset should be adjusted because the encoding. We encode XYZ normalized to 0..1.0, // to do that, we divide by MAX_ENCODEABLE_XZY. The conversion stage goes XYZ -> XYZ so - // we have first to convert from encoded to XYZ and then convert back to encoded. + // we have first to convert from encoded to XYZ and then convert back to encoded. // y = Mx + Off // x = x'c // y = M x'c + Off // y = y'c; y' = y / c - // y' = (Mx'c + Off) /c = Mx' + (Off / c) + // y' = (Mx'c + Off) /c = Mx' + (Off / c) for (k=0; k < 3; k++) { off ->n[k] /= MAX_ENCODEABLE_XYZ; @@ -360,7 +425,7 @@ cmsBool ComputeConversion(int i, cmsHPROFILE hProfiles[], } -// Add a conversion stage if needed. If a matrix/offset m is given, it applies to XYZ space +// Add a conversion stage if needed. If a matrix/offset m is given, it applies to XYZ space static cmsBool AddConversion(cmsPipeline* Result, cmsColorSpaceSignature InPCS, cmsColorSpaceSignature OutPCS, cmsMAT3* m, cmsVEC3* off) { @@ -370,57 +435,61 @@ cmsBool AddConversion(cmsPipeline* Result, cmsColorSpaceSignature InPCS, cmsColo // Handle PCS mismatches. A specialized stage is added to the LUT in such case switch (InPCS) { - case cmsSigXYZData: // Input profile operates in XYZ + case cmsSigXYZData: // Input profile operates in XYZ - switch (OutPCS) { + switch (OutPCS) { - case cmsSigXYZData: // XYZ -> XYZ - if (!IsEmptyLayer(m, off)) - cmsPipelineInsertStage(Result, cmsAT_END, cmsStageAllocMatrix(Result ->ContextID, 3, 3, m_as_dbl, off_as_dbl)); - break; - - case cmsSigLabData: // XYZ -> Lab - if (!IsEmptyLayer(m, off)) - cmsPipelineInsertStage(Result, cmsAT_END, cmsStageAllocMatrix(Result ->ContextID, 3, 3, m_as_dbl, off_as_dbl)); - cmsPipelineInsertStage(Result, cmsAT_END, _cmsStageAllocXYZ2Lab(Result ->ContextID)); - break; - - default: - return FALSE; // Colorspace mismatch - } - break; + case cmsSigXYZData: // XYZ -> XYZ + if (!IsEmptyLayer(m, off) && + !cmsPipelineInsertStage(Result, cmsAT_END, cmsStageAllocMatrix(Result ->ContextID, 3, 3, m_as_dbl, off_as_dbl))) + return FALSE; + break; + case cmsSigLabData: // XYZ -> Lab + if (!IsEmptyLayer(m, off) && + !cmsPipelineInsertStage(Result, cmsAT_END, cmsStageAllocMatrix(Result ->ContextID, 3, 3, m_as_dbl, off_as_dbl))) + return FALSE; + if (!cmsPipelineInsertStage(Result, cmsAT_END, _cmsStageAllocXYZ2Lab(Result ->ContextID))) + return FALSE; + break; - case cmsSigLabData: // Input profile operates in Lab + default: + return FALSE; // Colorspace mismatch + } + break; - switch (OutPCS) { + case cmsSigLabData: // Input profile operates in Lab - case cmsSigXYZData: // Lab -> XYZ + switch (OutPCS) { - cmsPipelineInsertStage(Result, cmsAT_END, _cmsStageAllocLab2XYZ(Result ->ContextID)); - if (!IsEmptyLayer(m, off)) - cmsPipelineInsertStage(Result, cmsAT_END, cmsStageAllocMatrix(Result ->ContextID, 3, 3, m_as_dbl, off_as_dbl)); - break; + case cmsSigXYZData: // Lab -> XYZ - case cmsSigLabData: // Lab -> Lab + if (!cmsPipelineInsertStage(Result, cmsAT_END, _cmsStageAllocLab2XYZ(Result ->ContextID))) + return FALSE; + if (!IsEmptyLayer(m, off) && + !cmsPipelineInsertStage(Result, cmsAT_END, cmsStageAllocMatrix(Result ->ContextID, 3, 3, m_as_dbl, off_as_dbl))) + return FALSE; + break; - if (!IsEmptyLayer(m, off)) { - cmsPipelineInsertStage(Result, cmsAT_END, _cmsStageAllocLab2XYZ(Result ->ContextID)); - cmsPipelineInsertStage(Result, cmsAT_END, cmsStageAllocMatrix(Result ->ContextID, 3, 3, m_as_dbl, off_as_dbl)); - cmsPipelineInsertStage(Result, cmsAT_END, _cmsStageAllocXYZ2Lab(Result ->ContextID)); - } - break; + case cmsSigLabData: // Lab -> Lab - default: - return FALSE; // Mismatch + if (!IsEmptyLayer(m, off)) { + if (!cmsPipelineInsertStage(Result, cmsAT_END, _cmsStageAllocLab2XYZ(Result ->ContextID)) || + !cmsPipelineInsertStage(Result, cmsAT_END, cmsStageAllocMatrix(Result ->ContextID, 3, 3, m_as_dbl, off_as_dbl)) || + !cmsPipelineInsertStage(Result, cmsAT_END, _cmsStageAllocXYZ2Lab(Result ->ContextID))) + return FALSE; } break; - - // On colorspaces other than PCS, check for same space default: - if (InPCS != OutPCS) return FALSE; - break; + return FALSE; // Mismatch + } + break; + + // On colorspaces other than PCS, check for same space + default: + if (InPCS != OutPCS) return FALSE; + break; } return TRUE; @@ -434,6 +503,10 @@ cmsBool ColorSpaceIsCompatible(cmsColorSpaceSignature a, cmsColorSpaceSignature // If they are same, they are compatible. if (a == b) return TRUE; + // Check for MCH4 substitution of CMYK + if ((a == cmsSig4colorData) && (b == cmsSigCmykData)) return TRUE; + if ((a == cmsSigCmykData) && (b == cmsSig4colorData)) return TRUE; + // Check for XYZ/Lab. Those spaces are interchangeable as they can be computed one from other. if ((a == cmsSigXYZData) && (b == cmsSigLabData)) return TRUE; if ((a == cmsSigLabData) && (b == cmsSigXYZData)) return TRUE; @@ -444,30 +517,31 @@ cmsBool ColorSpaceIsCompatible(cmsColorSpaceSignature a, cmsColorSpaceSignature // Default handler for ICC-style intents static -cmsPipeline* DefaultICCintents(cmsContext ContextID, +cmsPipeline* DefaultICCintents(cmsContext ContextID, cmsUInt32Number nProfiles, - cmsUInt32Number TheIntents[], - cmsHPROFILE hProfiles[], + cmsUInt32Number TheIntents[], + cmsHPROFILE hProfiles[], cmsBool BPC[], cmsFloat64Number AdaptationStates[], cmsUInt32Number dwFlags) { - cmsPipeline* Lut, *Result; + cmsPipeline* Lut = NULL; + cmsPipeline* Result; cmsHPROFILE hProfile; cmsMAT3 m; cmsVEC3 off; - cmsColorSpaceSignature ColorSpaceIn, ColorSpaceOut, CurrentColorSpace; + cmsColorSpaceSignature ColorSpaceIn, ColorSpaceOut, CurrentColorSpace; cmsProfileClassSignature ClassSig; cmsUInt32Number i, Intent; - // For safety - if (nProfiles == 0) return NULL; + // For safety + if (nProfiles == 0) return NULL; // Allocate an empty LUT for holding the result. 0 as channel count means 'undefined' Result = cmsPipelineAlloc(ContextID, 0, 0); if (Result == NULL) return NULL; - CurrentColorSpace = cmsGetColorSpace(hProfiles[0]); + CurrentColorSpace = cmsGetColorSpace(hProfiles[0]); for (i=0; i < nProfiles; i++) { @@ -476,16 +550,16 @@ cmsPipeline* DefaultICCintents(cmsContext ContextID, hProfile = hProfiles[i]; ClassSig = cmsGetDeviceClass(hProfile); lIsDeviceLink = (ClassSig == cmsSigLinkClass || ClassSig == cmsSigAbstractClass ); - + // First profile is used as input unless devicelink or abstract - if ((i == 0) && !lIsDeviceLink) { - lIsInput = TRUE; - } - else { - // Else use profile in the input direction if current space is not PCS + if ((i == 0) && !lIsDeviceLink) { + lIsInput = TRUE; + } + else { + // Else use profile in the input direction if current space is not PCS lIsInput = (CurrentColorSpace != cmsSigXYZData) && (CurrentColorSpace != cmsSigLabData); - } + } Intent = TheIntents[i]; @@ -506,9 +580,9 @@ cmsPipeline* DefaultICCintents(cmsContext ContextID, goto Error; } - // If devicelink is found, then no custom intent is allowed and we can - // read the LUT to be applied. Settings don't apply here. - if (lIsDeviceLink) { + // If devicelink is found, then no custom intent is allowed and we can + // read the LUT to be applied. Settings don't apply here. + if (lIsDeviceLink || ((ClassSig == cmsSigNamedColorClass) && (nProfiles == 1))) { // Get the involved LUT from the profile Lut = _cmsReadDevicelinkLUT(hProfile, Intent); @@ -522,7 +596,7 @@ cmsPipeline* DefaultICCintents(cmsContext ContextID, _cmsMAT3identity(&m); _cmsVEC3init(&off, 0, 0, 0); } - + if (!AddConversion(Result, CurrentColorSpace, ColorSpaceIn, &m, &off)) goto Error; @@ -531,13 +605,13 @@ cmsPipeline* DefaultICCintents(cmsContext ContextID, if (lIsInput) { // Input direction means non-pcs connection, so proceed like devicelinks - Lut = _cmsReadInputLUT(hProfile, Intent); + Lut = _cmsReadInputLUT(hProfile, Intent); if (Lut == NULL) goto Error; } else { // Output direction means PCS connection. Intent may apply here - Lut = _cmsReadOutputLUT(hProfile, Intent); + Lut = _cmsReadOutputLUT(hProfile, Intent); if (Lut == NULL) goto Error; @@ -548,17 +622,21 @@ cmsPipeline* DefaultICCintents(cmsContext ContextID, } // Concatenate to the output LUT - cmsPipelineCat(Result, Lut); - cmsPipelineFree(Lut); + if (!cmsPipelineCat(Result, Lut)) + goto Error; + + cmsPipelineFree(Lut); + Lut = NULL; // Update current space - CurrentColorSpace = ColorSpaceOut; + CurrentColorSpace = ColorSpaceOut; } return Result; Error: + if (Lut != NULL) cmsPipelineFree(Lut); if (Result != NULL) cmsPipelineFree(Result); return NULL; @@ -567,10 +645,10 @@ Error: // Wrapper for DLL calling convention -cmsPipeline* CMSEXPORT _cmsDefaultICCintents(cmsContext ContextID, +cmsPipeline* CMSEXPORT _cmsDefaultICCintents(cmsContext ContextID, cmsUInt32Number nProfiles, - cmsUInt32Number TheIntents[], - cmsHPROFILE hProfiles[], + cmsUInt32Number TheIntents[], + cmsHPROFILE hProfiles[], cmsBool BPC[], cmsFloat64Number AdaptationStates[], cmsUInt32Number dwFlags) @@ -587,7 +665,7 @@ int TranslateNonICCIntents(int Intent) switch (Intent) { case INTENT_PRESERVE_K_ONLY_PERCEPTUAL: case INTENT_PRESERVE_K_PLANE_PERCEPTUAL: - return INTENT_PERCEPTUAL; + return INTENT_PERCEPTUAL; case INTENT_PRESERVE_K_ONLY_RELATIVE_COLORIMETRIC: case INTENT_PRESERVE_K_PLANE_RELATIVE_COLORIMETRIC: @@ -632,10 +710,10 @@ int BlackPreservingGrayOnlySampler(register const cmsUInt16Number In[], register // This is the entry for black-preserving K-only intents, which are non-ICC static -cmsPipeline* BlackPreservingKOnlyIntents(cmsContext ContextID, +cmsPipeline* BlackPreservingKOnlyIntents(cmsContext ContextID, cmsUInt32Number nProfiles, - cmsUInt32Number TheIntents[], - cmsHPROFILE hProfiles[], + cmsUInt32Number TheIntents[], + cmsHPROFILE hProfiles[], cmsBool BPC[], cmsFloat64Number AdaptationStates[], cmsUInt32Number dwFlags) @@ -651,12 +729,12 @@ cmsPipeline* BlackPreservingKOnlyIntents(cmsContext ContextID, if (nProfiles < 1 || nProfiles > 255) return NULL; // Translate black-preserving intents to ICC ones - for (i=0; i < nProfiles; i++) - ICCIntents[i] = TranslateNonICCIntents(TheIntents[i]); + for (i=0; i < nProfiles; i++) + ICCIntents[i] = TranslateNonICCIntents(TheIntents[i]); // Check for non-cmyk profiles if (cmsGetColorSpace(hProfiles[0]) != cmsSigCmykData || - cmsGetColorSpace(hProfiles[nProfiles-1]) != cmsSigCmykData) + cmsGetColorSpace(hProfiles[nProfiles-1]) != cmsSigCmykData) return DefaultICCintents(ContextID, nProfiles, ICCIntents, hProfiles, BPC, AdaptationStates, dwFlags); memset(&bp, 0, sizeof(bp)); @@ -666,43 +744,44 @@ cmsPipeline* BlackPreservingKOnlyIntents(cmsContext ContextID, if (Result == NULL) return NULL; // Create a LUT holding normal ICC transform - bp.cmyk2cmyk = DefaultICCintents(ContextID, + bp.cmyk2cmyk = DefaultICCintents(ContextID, nProfiles, - ICCIntents, - hProfiles, + ICCIntents, + hProfiles, BPC, AdaptationStates, dwFlags); if (bp.cmyk2cmyk == NULL) goto Error; - + // Now, compute the tone curve - bp.KTone = _cmsBuildKToneCurve(ContextID, - 4096, + bp.KTone = _cmsBuildKToneCurve(ContextID, + 4096, nProfiles, - ICCIntents, - hProfiles, + ICCIntents, + hProfiles, BPC, AdaptationStates, dwFlags); - + if (bp.KTone == NULL) goto Error; - + // How many gridpoints are we going to use? nGridPoints = _cmsReasonableGridpointsByColorspace(cmsSigCmykData, dwFlags); - + // Create the CLUT. 16 bits CLUT = cmsStageAllocCLut16bit(ContextID, nGridPoints, 4, 4, NULL); if (CLUT == NULL) goto Error; // This is the one and only MPE in this LUT - cmsPipelineInsertStage(Result, cmsAT_BEGIN, CLUT); + if (!cmsPipelineInsertStage(Result, cmsAT_BEGIN, CLUT)) + goto Error; // Sample it. We cannot afford pre/post linearization this time. - if (!cmsStageSampleCLut16bit(CLUT, BlackPreservingGrayOnlySampler, (void*) &bp, 0)) + if (!cmsStageSampleCLut16bit(CLUT, BlackPreservingGrayOnlySampler, (void*) &bp, 0)) goto Error; - + // Get rid of xform and tone curve cmsPipelineFree(bp.cmyk2cmyk); cmsFreeToneCurve(bp.KTone); @@ -729,9 +808,9 @@ typedef struct { cmsPipeline* LabK2cmyk; // The output profile cmsFloat64Number MaxError; - cmsHTRANSFORM hRoundTrip; + cmsHTRANSFORM hRoundTrip; cmsFloat64Number MaxTAC; - + } PreserveKPlaneParams; @@ -742,18 +821,18 @@ int BlackPreservingSampler(register const cmsUInt16Number In[], register cmsUInt { int i; cmsFloat32Number Inf[4], Outf[4]; - cmsFloat32Number LabK[4]; + cmsFloat32Number LabK[4]; cmsFloat64Number SumCMY, SumCMYK, Error, Ratio; cmsCIELab ColorimetricLab, BlackPreservingLab; PreserveKPlaneParams* bp = (PreserveKPlaneParams*) Cargo; - + // Convert from 16 bits to floating point - for (i=0; i < 4; i++) + for (i=0; i < 4; i++) Inf[i] = (cmsFloat32Number) (In[i] / 65535.0); // Get the K across Tone curve LabK[3] = cmsEvalToneCurveFloat(bp ->KTone, Inf[3]); - + // If going across black only, keep black only if (In[0] == 0 && In[1] == 0 && In[2] == 0) { @@ -761,28 +840,28 @@ int BlackPreservingSampler(register const cmsUInt16Number In[], register cmsUInt Out[3] = _cmsQuickSaturateWord(LabK[3] * 65535.0); return TRUE; } - - // Try the original transform, - cmsPipelineEvalFloat( Inf, Outf, bp ->cmyk2cmyk); - + + // Try the original transform, + cmsPipelineEvalFloat( Inf, Outf, bp ->cmyk2cmyk); + // Store a copy of the floating point result into 16-bit - for (i=0; i < 4; i++) + for (i=0; i < 4; i++) Out[i] = _cmsQuickSaturateWord(Outf[i] * 65535.0); // Maybe K is already ok (mostly on K=0) if ( fabs(Outf[3] - LabK[3]) < (3.0 / 65535.0) ) { return TRUE; } - + // K differ, mesure and keep Lab measurement for further usage // this is done in relative colorimetric intent cmsDoTransform(bp->hProofOutput, Out, &ColorimetricLab, 1); - + // Is not black only and the transform doesn't keep black. // Obtain the Lab of output CMYK. After that we have Lab + K cmsDoTransform(bp ->cmyk2Lab, Outf, LabK, 1); - // Obtain the corresponding CMY using reverse interpolation + // Obtain the corresponding CMY using reverse interpolation // (K is fixed in LabK[3]) if (!cmsPipelineEvalReverseFloat(LabK, Outf, Outf, bp ->LabK2cmyk)) { @@ -793,10 +872,10 @@ int BlackPreservingSampler(register const cmsUInt16Number In[], register cmsUInt // Make sure to pass thru K (which now is fixed) Outf[3] = LabK[3]; - - // Apply TAC if needed + + // Apply TAC if needed SumCMY = Outf[0] + Outf[1] + Outf[2]; - SumCMYK = SumCMY + Outf[3]; + SumCMYK = SumCMY + Outf[3]; if (SumCMYK > bp ->MaxTAC) { @@ -813,9 +892,9 @@ int BlackPreservingSampler(register const cmsUInt16Number In[], register cmsUInt Out[3] = _cmsQuickSaturateWord(Outf[3] * 65535.0); // Estimate the error (this goes 16 bits to Lab DBL) - cmsDoTransform(bp->hProofOutput, Out, &BlackPreservingLab, 1); - Error = cmsDeltaE(&ColorimetricLab, &BlackPreservingLab); - if (Error > bp -> MaxError) + cmsDoTransform(bp->hProofOutput, Out, &BlackPreservingLab, 1); + Error = cmsDeltaE(&ColorimetricLab, &BlackPreservingLab); + if (Error > bp -> MaxError) bp->MaxError = Error; return TRUE; @@ -823,10 +902,10 @@ int BlackPreservingSampler(register const cmsUInt16Number In[], register cmsUInt // This is the entry for black-plane preserving, which are non-ICC static -cmsPipeline* BlackPreservingKPlaneIntents(cmsContext ContextID, +cmsPipeline* BlackPreservingKPlaneIntents(cmsContext ContextID, cmsUInt32Number nProfiles, - cmsUInt32Number TheIntents[], - cmsHPROFILE hProfiles[], + cmsUInt32Number TheIntents[], + cmsHPROFILE hProfiles[], cmsBool BPC[], cmsFloat64Number AdaptationStates[], cmsUInt32Number dwFlags) @@ -835,26 +914,27 @@ cmsPipeline* BlackPreservingKPlaneIntents(cmsContext ContextID, cmsPipeline* Result = NULL; cmsUInt32Number ICCIntents[256]; cmsStage* CLUT; - cmsUInt32Number i, nGridPoints; + cmsUInt32Number i, nGridPoints; cmsHPROFILE hLab; // Sanity check if (nProfiles < 1 || nProfiles > 255) return NULL; // Translate black-preserving intents to ICC ones - for (i=0; i < nProfiles; i++) - ICCIntents[i] = TranslateNonICCIntents(TheIntents[i]); + for (i=0; i < nProfiles; i++) + ICCIntents[i] = TranslateNonICCIntents(TheIntents[i]); // Check for non-cmyk profiles if (cmsGetColorSpace(hProfiles[0]) != cmsSigCmykData || - cmsGetColorSpace(hProfiles[nProfiles-1]) != cmsSigCmykData) + !(cmsGetColorSpace(hProfiles[nProfiles-1]) == cmsSigCmykData || + cmsGetDeviceClass(hProfiles[nProfiles-1]) == cmsSigOutputClass)) return DefaultICCintents(ContextID, nProfiles, ICCIntents, hProfiles, BPC, AdaptationStates, dwFlags); // Allocate an empty LUT for holding the result Result = cmsPipelineAlloc(ContextID, 4, 4); if (Result == NULL) return NULL; - + memset(&bp, 0, sizeof(bp)); // We need the input LUT of the last profile, assuming this one is responsible of @@ -864,38 +944,43 @@ cmsPipeline* BlackPreservingKPlaneIntents(cmsContext ContextID, // Get total area coverage (in 0..1 domain) bp.MaxTAC = cmsDetectTAC(hProfiles[nProfiles-1]) / 100.0; + if (bp.MaxTAC <= 0) goto Cleanup; + // Create a LUT holding normal ICC transform bp.cmyk2cmyk = DefaultICCintents(ContextID, nProfiles, - ICCIntents, - hProfiles, + ICCIntents, + hProfiles, BPC, AdaptationStates, dwFlags); + if (bp.cmyk2cmyk == NULL) goto Cleanup; // Now the tone curve bp.KTone = _cmsBuildKToneCurve(ContextID, 4096, nProfiles, - ICCIntents, - hProfiles, - BPC, + ICCIntents, + hProfiles, + BPC, AdaptationStates, dwFlags); - + if (bp.KTone == NULL) goto Cleanup; // To measure the output, Last profile to Lab hLab = cmsCreateLab4ProfileTHR(ContextID, NULL); - bp.hProofOutput = cmsCreateTransformTHR(ContextID, hProfiles[nProfiles-1], - CHANNELS_SH(4)|BYTES_SH(2), hLab, TYPE_Lab_DBL, - INTENT_RELATIVE_COLORIMETRIC, + bp.hProofOutput = cmsCreateTransformTHR(ContextID, hProfiles[nProfiles-1], + CHANNELS_SH(4)|BYTES_SH(2), hLab, TYPE_Lab_DBL, + INTENT_RELATIVE_COLORIMETRIC, cmsFLAGS_NOCACHE|cmsFLAGS_NOOPTIMIZE); + if ( bp.hProofOutput == NULL) goto Cleanup; // Same as anterior, but lab in the 0..1 range - bp.cmyk2Lab = cmsCreateTransformTHR(ContextID, hProfiles[nProfiles-1], - FLOAT_SH(1)|CHANNELS_SH(4)|BYTES_SH(4), hLab, - FLOAT_SH(1)|CHANNELS_SH(3)|BYTES_SH(4), - INTENT_RELATIVE_COLORIMETRIC, + bp.cmyk2Lab = cmsCreateTransformTHR(ContextID, hProfiles[nProfiles-1], + FLOAT_SH(1)|CHANNELS_SH(4)|BYTES_SH(4), hLab, + FLOAT_SH(1)|CHANNELS_SH(3)|BYTES_SH(4), + INTENT_RELATIVE_COLORIMETRIC, cmsFLAGS_NOCACHE|cmsFLAGS_NOOPTIMIZE); + if (bp.cmyk2Lab == NULL) goto Cleanup; cmsCloseProfile(hLab); // Error estimation (for debug only) @@ -904,21 +989,22 @@ cmsPipeline* BlackPreservingKPlaneIntents(cmsContext ContextID, // How many gridpoints are we going to use? nGridPoints = _cmsReasonableGridpointsByColorspace(cmsSigCmykData, dwFlags); - + CLUT = cmsStageAllocCLut16bit(ContextID, nGridPoints, 4, 4, NULL); if (CLUT == NULL) goto Cleanup; - cmsPipelineInsertStage(Result, cmsAT_BEGIN, CLUT); + if (!cmsPipelineInsertStage(Result, cmsAT_BEGIN, CLUT)) + goto Cleanup; cmsStageSampleCLut16bit(CLUT, BlackPreservingSampler, (void*) &bp, 0); Cleanup: if (bp.cmyk2cmyk) cmsPipelineFree(bp.cmyk2cmyk); - if (bp.cmyk2Lab) cmsDeleteTransform(bp.cmyk2Lab); + if (bp.cmyk2Lab) cmsDeleteTransform(bp.cmyk2Lab); if (bp.hProofOutput) cmsDeleteTransform(bp.hProofOutput); - - if (bp.KTone) cmsFreeToneCurve(bp.KTone); + + if (bp.KTone) cmsFreeToneCurve(bp.KTone); if (bp.LabK2cmyk) cmsPipelineFree(bp.LabK2cmyk); return Result; @@ -927,12 +1013,12 @@ Cleanup: // Link routines ------------------------------------------------------------------------------------------------------ // Chain several profiles into a single LUT. It just checks the parameters and then calls the handler -// for the first intent in chain. The handler may be user-defined. Is up to the handler to deal with the +// for the first intent in chain. The handler may be user-defined. Is up to the handler to deal with the // rest of intents in chain. A maximum of 255 profiles at time are supported, which is pretty reasonable. -cmsPipeline* _cmsLinkProfiles(cmsContext ContextID, +cmsPipeline* _cmsLinkProfiles(cmsContext ContextID, cmsUInt32Number nProfiles, - cmsUInt32Number TheIntents[], - cmsHPROFILE hProfiles[], + cmsUInt32Number TheIntents[], + cmsHPROFILE hProfiles[], cmsBool BPC[], cmsFloat64Number AdaptationStates[], cmsUInt32Number dwFlags) @@ -948,9 +1034,9 @@ cmsPipeline* _cmsLinkProfiles(cmsContext ContextID, for (i=0; i < nProfiles; i++) { - // Check if black point is really needed or allowed. Note that + // Check if black point is really needed or allowed. Note that // following Adobe's document: - // BPC does not apply to devicelink profiles, nor to abs colorimetric, + // BPC does not apply to devicelink profiles, nor to abs colorimetric, // and applies always on V4 perceptual and saturation. if (TheIntents[i] == INTENT_ABSOLUTE_COLORIMETRIC) @@ -961,7 +1047,7 @@ cmsPipeline* _cmsLinkProfiles(cmsContext ContextID, // Force BPC for V4 profiles in perceptual and saturation if (cmsGetProfileVersion(hProfiles[i]) >= 4.0) BPC[i] = TRUE; - } + } } // Search for a handler. The first intent in the chain defines the handler. That would @@ -969,11 +1055,11 @@ cmsPipeline* _cmsLinkProfiles(cmsContext ContextID, // this case would present some issues if the custom intent tries to do things like // preserve primaries. This solution is not perfect, but works well on most cases. - Intent = SearchIntent(TheIntents[0]); - if (Intent == NULL) { - cmsSignalError(ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported intent '%d'", TheIntents[0]); - return NULL; - } + Intent = SearchIntent(ContextID, TheIntents[0]); + if (Intent == NULL) { + cmsSignalError(ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported intent '%d'", TheIntents[0]); + return NULL; + } // Call the handler return Intent ->Link(ContextID, nProfiles, TheIntents, hProfiles, BPC, AdaptationStates, dwFlags); @@ -981,58 +1067,75 @@ cmsPipeline* _cmsLinkProfiles(cmsContext ContextID, // ------------------------------------------------------------------------------------------------- -// Get information about available intents. nMax is the maximum space for the supplied "Codes" -// and "Descriptions" the function returns the total number of intents, which may be greater +// Get information about available intents. nMax is the maximum space for the supplied "Codes" +// and "Descriptions" the function returns the total number of intents, which may be greater // than nMax, although the matrices are not populated beyond this level. -cmsUInt32Number CMSEXPORT cmsGetSupportedIntents(cmsUInt32Number nMax, cmsUInt32Number* Codes, char** Descriptions) +cmsUInt32Number CMSEXPORT cmsGetSupportedIntentsTHR(cmsContext ContextID, cmsUInt32Number nMax, cmsUInt32Number* Codes, char** Descriptions) { + _cmsIntentsPluginChunkType* ctx = ( _cmsIntentsPluginChunkType*) _cmsContextGetClientChunk(ContextID, IntentPlugin); cmsIntentsList* pt; cmsUInt32Number nIntents; - for (nIntents=0, pt = Intents; pt != NULL; pt = pt -> Next) + + for (nIntents=0, pt = ctx->Intents; pt != NULL; pt = pt -> Next) { if (nIntents < nMax) { - if (Codes != NULL) + if (Codes != NULL) Codes[nIntents] = pt ->Intent; - if (Descriptions != NULL) + if (Descriptions != NULL) Descriptions[nIntents] = pt ->Description; } nIntents++; } + for (nIntents=0, pt = DefaultIntents; pt != NULL; pt = pt -> Next) + { + if (nIntents < nMax) { + if (Codes != NULL) + Codes[nIntents] = pt ->Intent; + + if (Descriptions != NULL) + Descriptions[nIntents] = pt ->Description; + } + + nIntents++; + } return nIntents; } +cmsUInt32Number CMSEXPORT cmsGetSupportedIntents(cmsUInt32Number nMax, cmsUInt32Number* Codes, char** Descriptions) +{ + return cmsGetSupportedIntentsTHR(NULL, nMax, Codes, Descriptions); +} + // The plug-in registration. User can add new intents or override default routines -cmsBool _cmsRegisterRenderingIntentPlugin(cmsPluginBase* Data) +cmsBool _cmsRegisterRenderingIntentPlugin(cmsContext id, cmsPluginBase* Data) { + _cmsIntentsPluginChunkType* ctx = ( _cmsIntentsPluginChunkType*) _cmsContextGetClientChunk(id, IntentPlugin); cmsPluginRenderingIntent* Plugin = (cmsPluginRenderingIntent*) Data; cmsIntentsList* fl; - // Do we have to reset the intents? + // Do we have to reset the custom intents? if (Data == NULL) { - - Intents = DefaultIntents; - return TRUE; + + ctx->Intents = NULL; + return TRUE; } - fl = SearchIntent(Plugin ->Intent); + fl = (cmsIntentsList*) _cmsPluginMalloc(id, sizeof(cmsIntentsList)); + if (fl == NULL) return FALSE; - if (fl == NULL) { - fl = (cmsIntentsList*) _cmsPluginMalloc(sizeof(cmsIntentsList)); - if (fl == NULL) return FALSE; - } fl ->Intent = Plugin ->Intent; - strncpy(fl ->Description, Plugin ->Description, 255); - fl ->Description[255] = 0; + strncpy(fl ->Description, Plugin ->Description, sizeof(fl ->Description)-1); + fl ->Description[sizeof(fl ->Description)-1] = 0; fl ->Link = Plugin ->Link; - fl ->Next = Intents; - Intents = fl; + fl ->Next = ctx ->Intents; + ctx ->Intents = fl; return TRUE; } |
