diff options
| author | mayeut <mayeut@users.noreply.github.com> | 2015-07-21 23:49:11 +0200 |
|---|---|---|
| committer | mayeut <mayeut@users.noreply.github.com> | 2015-07-21 23:49:11 +0200 |
| commit | 2fc9d4956a5d2ca90d6c89106c373fbd711aaf5e (patch) | |
| tree | 032da672e1baff88ed1230309bf592089f66adbb /thirdparty/liblcms2/src/cmslut.c | |
| parent | 28c6f547987e8cbe5ccaef622da4cf6667068989 (diff) | |
Switch to libcms2-2.6
Diffstat (limited to 'thirdparty/liblcms2/src/cmslut.c')
| -rw-r--r-- | thirdparty/liblcms2/src/cmslut.c | 640 |
1 files changed, 385 insertions, 255 deletions
diff --git a/thirdparty/liblcms2/src/cmslut.c b/thirdparty/liblcms2/src/cmslut.c index d0fe9c80..c491662b 100644 --- a/thirdparty/liblcms2/src/cmslut.c +++ b/thirdparty/liblcms2/src/cmslut.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. // //--------------------------------------------------------------------------------- @@ -28,20 +28,20 @@ // Allocates an empty multi profile element -cmsStage* CMSEXPORT _cmsStageAllocPlaceholder(cmsContext ContextID, +cmsStage* CMSEXPORT _cmsStageAllocPlaceholder(cmsContext ContextID, cmsStageSignature Type, - cmsUInt32Number InputChannels, + cmsUInt32Number InputChannels, cmsUInt32Number OutputChannels, - _cmsStageEvalFn EvalPtr, - _cmsStageDupElemFn DupElemPtr, - _cmsStageFreeElemFn FreePtr, - void* Data) + _cmsStageEvalFn EvalPtr, + _cmsStageDupElemFn DupElemPtr, + _cmsStageFreeElemFn FreePtr, + void* Data) { cmsStage* ph = (cmsStage*) _cmsMallocZero(ContextID, sizeof(cmsStage)); if (ph == NULL) return NULL; - - + + ph ->ContextID = ContextID; ph ->Type = Type; @@ -49,18 +49,18 @@ cmsStage* CMSEXPORT _cmsStageAllocPlaceholder(cmsContext ContextID, ph ->InputChannels = InputChannels; ph ->OutputChannels = OutputChannels; - ph ->EvalPtr = EvalPtr; - ph ->DupElemPtr = DupElemPtr; - ph ->FreePtr = FreePtr; + ph ->EvalPtr = EvalPtr; + ph ->DupElemPtr = DupElemPtr; + ph ->FreePtr = FreePtr; ph ->Data = Data; - return ph; + return ph; } static -void EvaluateIdentity(const cmsFloat32Number In[], - cmsFloat32Number Out[], +void EvaluateIdentity(const cmsFloat32Number In[], + cmsFloat32Number Out[], const cmsStage *mpe) { memmove(Out, In, mpe ->InputChannels * sizeof(cmsFloat32Number)); @@ -69,10 +69,10 @@ void EvaluateIdentity(const cmsFloat32Number In[], cmsStage* CMSEXPORT cmsStageAllocIdentity(cmsContext ContextID, cmsUInt32Number nChannels) { - return _cmsStageAllocPlaceholder(ContextID, - cmsSigIdentityElemType, + return _cmsStageAllocPlaceholder(ContextID, + cmsSigIdentityElemType, nChannels, nChannels, - EvaluateIdentity, + EvaluateIdentity, NULL, NULL, NULL); @@ -84,8 +84,8 @@ void FromFloatTo16(const cmsFloat32Number In[], cmsUInt16Number Out[], cmsUInt32 { cmsUInt32Number i; - for (i=0; i < n; i++) { - Out[i] = _cmsQuickSaturateWord(In[i] * 65535.0); + for (i=0; i < n; i++) { + Out[i] = _cmsQuickSaturateWord(In[i] * 65535.0); } } @@ -105,7 +105,7 @@ void From16ToFloat(const cmsUInt16Number In[], cmsFloat32Number Out[], cmsUInt32 // that conform the LUT. It should be called with the LUT, the number of expected elements and // then a list of expected types followed with a list of cmsFloat64Number pointers to MPE elements. If // the function founds a match with current pipeline, it fills the pointers and returns TRUE -// if not, returns FALSE without touching anything. Setting pointers to NULL does bypass +// if not, returns FALSE without touching anything. Setting pointers to NULL does bypass // the storage process. cmsBool CMSEXPORT cmsPipelineCheckAndRetreiveStages(const cmsPipeline* Lut, cmsUInt32Number n, ...) { @@ -125,11 +125,11 @@ cmsBool CMSEXPORT cmsPipelineCheckAndRetreiveStages(const cmsPipeline* Lut, cms for (i=0; i < n; i++) { // Get asked type - Type = va_arg(args, cmsStageSignature); + Type = (cmsStageSignature)va_arg(args, cmsStageSignature); if (mpe ->Type != Type) { va_end(args); // Mismatch. We are done. - return FALSE; + return FALSE; } mpe = mpe ->Next; } @@ -138,14 +138,14 @@ cmsBool CMSEXPORT cmsPipelineCheckAndRetreiveStages(const cmsPipeline* Lut, cms mpe = Lut ->Elements; for (i=0; i < n; i++) { - ElemPtr = va_arg(args, void**); - if (ElemPtr != NULL) + ElemPtr = va_arg(args, void**); + if (ElemPtr != NULL) *ElemPtr = mpe; mpe = mpe ->Next; } - va_end(args); + va_end(args); return TRUE; } @@ -164,8 +164,8 @@ cmsToneCurve** _cmsStageGetPtrToCurveSet(const cmsStage* mpe) } static -void EvaluateCurves(const cmsFloat32Number In[], - cmsFloat32Number Out[], +void EvaluateCurves(const cmsFloat32Number In[], + cmsFloat32Number Out[], const cmsStage *mpe) { _cmsStageToneCurvesData* Data; @@ -196,7 +196,7 @@ void CurveSetElemTypeFree(cmsStage* mpe) if (Data ->TheCurves != NULL) { for (i=0; i < Data ->nCurves; i++) { - if (Data ->TheCurves[i] != NULL) + if (Data ->TheCurves[i] != NULL) cmsFreeToneCurve(Data ->TheCurves[i]); } } @@ -232,13 +232,13 @@ void* CurveSetDup(cmsStage* mpe) Error: - if (NewElem ->TheCurves != NULL) { + if (NewElem ->TheCurves != NULL) { for (i=0; i < NewElem ->nCurves; i++) { if (NewElem ->TheCurves[i]) - cmsFreeToneCurve(Data ->TheCurves[i]); + cmsFreeToneCurve(NewElem ->TheCurves[i]); } } - _cmsFree(mpe ->ContextID, Data ->TheCurves); + _cmsFree(mpe ->ContextID, NewElem ->TheCurves); _cmsFree(mpe ->ContextID, NewElem); return NULL; } @@ -250,15 +250,15 @@ cmsStage* CMSEXPORT cmsStageAllocToneCurves(cmsContext ContextID, cmsUInt32Numbe cmsUInt32Number i; _cmsStageToneCurvesData* NewElem; cmsStage* NewMPE; - - + + NewMPE = _cmsStageAllocPlaceholder(ContextID, cmsSigCurveSetElemType, nChannels, nChannels, EvaluateCurves, CurveSetDup, CurveSetElemTypeFree, NULL ); if (NewMPE == NULL) return NULL; - NewElem = (_cmsStageToneCurvesData*) _cmsMalloc(ContextID, sizeof(_cmsStageToneCurvesData)); + NewElem = (_cmsStageToneCurvesData*) _cmsMallocZero(ContextID, sizeof(_cmsStageToneCurvesData)); if (NewElem == NULL) { - cmsStageFree(NewMPE); + cmsStageFree(NewMPE); return NULL; } @@ -267,7 +267,7 @@ cmsStage* CMSEXPORT cmsStageAllocToneCurves(cmsContext ContextID, cmsUInt32Numbe NewElem ->nCurves = nChannels; NewElem ->TheCurves = (cmsToneCurve**) _cmsCalloc(ContextID, nChannels, sizeof(cmsToneCurve*)); if (NewElem ->TheCurves == NULL) { - cmsStageFree(NewMPE); + cmsStageFree(NewMPE); return NULL; } @@ -281,12 +281,13 @@ cmsStage* CMSEXPORT cmsStageAllocToneCurves(cmsContext ContextID, cmsUInt32Numbe } if (NewElem ->TheCurves[i] == NULL) { - cmsStageFree(NewMPE); + cmsStageFree(NewMPE); return NULL; } + } - return NewMPE; + return NewMPE; } @@ -294,7 +295,7 @@ cmsStage* CMSEXPORT cmsStageAllocToneCurves(cmsContext ContextID, cmsUInt32Numbe cmsStage* _cmsStageAllocIdentityCurves(cmsContext ContextID, int nChannels) { cmsStage* mpe = cmsStageAllocToneCurves(ContextID, nChannels, NULL); - + if (mpe == NULL) return NULL; mpe ->Implements = cmsSigIdentityElemType; return mpe; @@ -308,8 +309,8 @@ cmsStage* _cmsStageAllocIdentityCurves(cmsContext ContextID, int nChannels) // Special care should be taken here because precision loss. A temporary cmsFloat64Number buffer is being used static -void EvaluateMatrix(const cmsFloat32Number In[], - cmsFloat32Number Out[], +void EvaluateMatrix(const cmsFloat32Number In[], + cmsFloat32Number Out[], const cmsStage *mpe) { cmsUInt32Number i, j; @@ -324,10 +325,10 @@ void EvaluateMatrix(const cmsFloat32Number In[], Tmp += In[j] * Data->Double[i*mpe->InputChannels + j]; } - if (Data ->Offset != NULL) + if (Data ->Offset != NULL) Tmp += Data->Offset[i]; - Out[i] = (cmsFloat32Number) Tmp; + Out[i] = (cmsFloat32Number) Tmp; } @@ -342,7 +343,7 @@ void* MatrixElemDup(cmsStage* mpe) _cmsStageMatrixData* Data = (_cmsStageMatrixData*) mpe ->Data; _cmsStageMatrixData* NewElem; cmsUInt32Number sz; - + NewElem = (_cmsStageMatrixData*) _cmsMallocZero(mpe ->ContextID, sizeof(_cmsStageMatrixData)); if (NewElem == NULL) return NULL; @@ -351,7 +352,7 @@ void* MatrixElemDup(cmsStage* mpe) NewElem ->Double = (cmsFloat64Number*) _cmsDupMem(mpe ->ContextID, Data ->Double, sz * sizeof(cmsFloat64Number)) ; if (Data ->Offset) - NewElem ->Offset = (cmsFloat64Number*) _cmsDupMem(mpe ->ContextID, + NewElem ->Offset = (cmsFloat64Number*) _cmsDupMem(mpe ->ContextID, Data ->Offset, mpe -> OutputChannels * sizeof(cmsFloat64Number)) ; return (void*) NewElem; @@ -362,6 +363,8 @@ static void MatrixElemTypeFree(cmsStage* mpe) { _cmsStageMatrixData* Data = (_cmsStageMatrixData*) mpe ->Data; + if (Data == NULL) + return; if (Data ->Double) _cmsFree(mpe ->ContextID, Data ->Double); @@ -373,7 +376,7 @@ void MatrixElemTypeFree(cmsStage* mpe) -cmsStage* CMSEXPORT cmsStageAllocMatrix(cmsContext ContextID, cmsUInt32Number Rows, cmsUInt32Number Cols, +cmsStage* CMSEXPORT cmsStageAllocMatrix(cmsContext ContextID, cmsUInt32Number Rows, cmsUInt32Number Cols, const cmsFloat64Number* Matrix, const cmsFloat64Number* Offset) { cmsUInt32Number i, n; @@ -392,10 +395,10 @@ cmsStage* CMSEXPORT cmsStageAllocMatrix(cmsContext ContextID, cmsUInt32Number R EvaluateMatrix, MatrixElemDup, MatrixElemTypeFree, NULL ); if (NewMPE == NULL) return NULL; - + NewElem = (_cmsStageMatrixData*) _cmsMallocZero(ContextID, sizeof(_cmsStageMatrixData)); if (NewElem == NULL) return NULL; - + NewElem ->Double = (cmsFloat64Number*) _cmsCalloc(ContextID, n, sizeof(cmsFloat64Number)); @@ -410,7 +413,7 @@ cmsStage* CMSEXPORT cmsStageAllocMatrix(cmsContext ContextID, cmsUInt32Number R if (Offset != NULL) { - + NewElem ->Offset = (cmsFloat64Number*) _cmsCalloc(ContextID, Cols, sizeof(cmsFloat64Number)); if (NewElem->Offset == NULL) { MatrixElemTypeFree(NewMPE); @@ -422,7 +425,7 @@ cmsStage* CMSEXPORT cmsStageAllocMatrix(cmsContext ContextID, cmsUInt32Number R } } - + NewMPE ->Data = (void*) NewElem; return NewMPE; } @@ -437,7 +440,7 @@ cmsStage* CMSEXPORT cmsStageAllocMatrix(cmsContext ContextID, cmsUInt32Number R static void EvaluateCLUTfloat(const cmsFloat32Number In[], cmsFloat32Number Out[], const cmsStage *mpe) { - _cmsStageCLutData* Data = (_cmsStageCLutData*) mpe ->Data; + _cmsStageCLutData* Data = (_cmsStageCLutData*) mpe ->Data; Data -> Params ->Interpolation.LerpFloat(In, Out, Data->Params); } @@ -449,11 +452,11 @@ void EvaluateCLUTfloatIn16(const cmsFloat32Number In[], cmsFloat32Number Out[], { _cmsStageCLutData* Data = (_cmsStageCLutData*) mpe ->Data; cmsUInt16Number In16[MAX_STAGE_CHANNELS], Out16[MAX_STAGE_CHANNELS]; - + _cmsAssert(mpe ->InputChannels <= MAX_STAGE_CHANNELS); _cmsAssert(mpe ->OutputChannels <= MAX_STAGE_CHANNELS); - FromFloatTo16(In, In16, mpe ->InputChannels); + FromFloatTo16(In, In16, mpe ->InputChannels); Data -> Params ->Interpolation.Lerp16(In16, Out16, Data->Params); From16ToFloat(Out16, Out, mpe ->OutputChannels); } @@ -486,8 +489,8 @@ void* CLUTElemDup(cmsStage* mpe) { _cmsStageCLutData* Data = (_cmsStageCLutData*) mpe ->Data; _cmsStageCLutData* NewElem; - - + + NewElem = (_cmsStageCLutData*) _cmsMallocZero(mpe ->ContextID, sizeof(_cmsStageCLutData)); if (NewElem == NULL) return NULL; @@ -496,20 +499,31 @@ void* CLUTElemDup(cmsStage* mpe) if (Data ->Tab.T) { - if (Data ->HasFloatValues) + if (Data ->HasFloatValues) { NewElem ->Tab.TFloat = (cmsFloat32Number*) _cmsDupMem(mpe ->ContextID, Data ->Tab.TFloat, Data ->nEntries * sizeof (cmsFloat32Number)); - else + if (NewElem ->Tab.TFloat == NULL) + goto Error; + } else { NewElem ->Tab.T = (cmsUInt16Number*) _cmsDupMem(mpe ->ContextID, Data ->Tab.T, Data ->nEntries * sizeof (cmsUInt16Number)); + if (NewElem ->Tab.TFloat == NULL) + goto Error; + } } - + NewElem ->Params = _cmsComputeInterpParamsEx(mpe ->ContextID, - Data ->Params ->nSamples, + Data ->Params ->nSamples, Data ->Params ->nInputs, - Data ->Params ->nOutputs, + Data ->Params ->nOutputs, NewElem ->Tab.T, Data ->Params ->dwFlags); - - return (void*) NewElem; + if (NewElem->Params != NULL) + return (void*) NewElem; + Error: + if (NewElem->Tab.T) + // This works for both types + _cmsFree(mpe ->ContextID, NewElem -> Tab.T); + _cmsFree(mpe ->ContextID, NewElem); + return NULL; } @@ -518,7 +532,7 @@ void CLutElemTypeFree(cmsStage* mpe) { _cmsStageCLutData* Data = (_cmsStageCLutData*) mpe ->Data; - + // Already empty if (Data == NULL) return; @@ -526,29 +540,36 @@ void CLutElemTypeFree(cmsStage* mpe) if (Data -> Tab.T) _cmsFree(mpe ->ContextID, Data -> Tab.T); - _cmsFreeInterpParams(Data ->Params); + _cmsFreeInterpParams(Data ->Params); _cmsFree(mpe ->ContextID, mpe ->Data); } // Allocates a 16-bit multidimensional CLUT. This is evaluated at 16-bit precision. Table may have different // granularity on each dimension. -cmsStage* CMSEXPORT cmsStageAllocCLut16bitGranular(cmsContext ContextID, - const cmsUInt32Number clutPoints[], - cmsUInt32Number inputChan, - cmsUInt32Number outputChan, +cmsStage* CMSEXPORT cmsStageAllocCLut16bitGranular(cmsContext ContextID, + const cmsUInt32Number clutPoints[], + cmsUInt32Number inputChan, + cmsUInt32Number outputChan, const cmsUInt16Number* Table) { cmsUInt32Number i, n; _cmsStageCLutData* NewElem; cmsStage* NewMPE; - + + _cmsAssert(clutPoints != NULL); + + if (inputChan > MAX_INPUT_DIMENSIONS) { + cmsSignalError(ContextID, cmsERROR_RANGE, "Too many input channels (%d channels, max=%d)", inputChan, MAX_INPUT_DIMENSIONS); + return NULL; + } + NewMPE = _cmsStageAllocPlaceholder(ContextID, cmsSigCLutElemType, inputChan, outputChan, EvaluateCLUTfloatIn16, CLUTElemDup, CLutElemTypeFree, NULL ); if (NewMPE == NULL) return NULL; - NewElem = (_cmsStageCLutData*) _cmsMalloc(ContextID, sizeof(_cmsStageCLutData)); + NewElem = (_cmsStageCLutData*) _cmsMallocZero(ContextID, sizeof(_cmsStageCLutData)); if (NewElem == NULL) { cmsStageFree(NewMPE); return NULL; @@ -586,10 +607,10 @@ cmsStage* CMSEXPORT cmsStageAllocCLut16bitGranular(cmsContext ContextID, return NewMPE; } -cmsStage* CMSEXPORT cmsStageAllocCLut16bit(cmsContext ContextID, - cmsUInt32Number nGridPoints, - cmsUInt32Number inputChan, - cmsUInt32Number outputChan, +cmsStage* CMSEXPORT cmsStageAllocCLut16bit(cmsContext ContextID, + cmsUInt32Number nGridPoints, + cmsUInt32Number inputChan, + cmsUInt32Number outputChan, const cmsUInt16Number* Table) { cmsUInt32Number Dimensions[MAX_INPUT_DIMENSIONS]; @@ -599,15 +620,14 @@ cmsStage* CMSEXPORT cmsStageAllocCLut16bit(cmsContext ContextID, for (i=0; i < MAX_INPUT_DIMENSIONS; i++) Dimensions[i] = nGridPoints; - return cmsStageAllocCLut16bitGranular(ContextID, Dimensions, inputChan, outputChan, Table); } -cmsStage* CMSEXPORT cmsStageAllocCLutFloat(cmsContext ContextID, - cmsUInt32Number nGridPoints, - cmsUInt32Number inputChan, - cmsUInt32Number outputChan, +cmsStage* CMSEXPORT cmsStageAllocCLutFloat(cmsContext ContextID, + cmsUInt32Number nGridPoints, + cmsUInt32Number inputChan, + cmsUInt32Number outputChan, const cmsFloat32Number* Table) { cmsUInt32Number Dimensions[MAX_INPUT_DIMENSIONS]; @@ -627,15 +647,20 @@ cmsStage* CMSEXPORT cmsStageAllocCLutFloatGranular(cmsContext ContextID, const c cmsUInt32Number i, n; _cmsStageCLutData* NewElem; cmsStage* NewMPE; - + _cmsAssert(clutPoints != NULL); + if (inputChan > MAX_INPUT_DIMENSIONS) { + cmsSignalError(ContextID, cmsERROR_RANGE, "Too many input channels (%d channels, max=%d)", inputChan, MAX_INPUT_DIMENSIONS); + return NULL; + } + NewMPE = _cmsStageAllocPlaceholder(ContextID, cmsSigCLutElemType, inputChan, outputChan, EvaluateCLUTfloat, CLUTElemDup, CLutElemTypeFree, NULL); if (NewMPE == NULL) return NULL; - - NewElem = (_cmsStageCLutData*) _cmsMalloc(ContextID, sizeof(_cmsStageCLutData)); + + NewElem = (_cmsStageCLutData*) _cmsMallocZero(ContextID, sizeof(_cmsStageCLutData)); if (NewElem == NULL) { cmsStageFree(NewMPE); return NULL; @@ -644,7 +669,7 @@ cmsStage* CMSEXPORT cmsStageAllocCLutFloatGranular(cmsContext ContextID, const c NewMPE ->Data = (void*) NewElem; // There is a potential integer overflow on conputing n and nEntries. - NewElem -> nEntries = n = outputChan * CubeSize( clutPoints, inputChan); + NewElem -> nEntries = n = outputChan * CubeSize(clutPoints, inputChan); NewElem -> HasFloatValues = TRUE; if (n == 0) { @@ -664,16 +689,12 @@ cmsStage* CMSEXPORT cmsStageAllocCLutFloatGranular(cmsContext ContextID, const c } } - - NewElem ->Params = _cmsComputeInterpParamsEx(ContextID, clutPoints, inputChan, outputChan, NewElem ->Tab.TFloat, CMS_LERP_FLAGS_FLOAT); if (NewElem ->Params == NULL) { cmsStageFree(NewMPE); return NULL; } - - return NewMPE; } @@ -684,7 +705,7 @@ int IdentitySampler(register const cmsUInt16Number In[], register cmsUInt16Numbe int nChan = *(int*) Cargo; int i; - for (i=0; i < nChan; i++) + for (i=0; i < nChan; i++) Out[i] = In[i]; return 1; @@ -696,13 +717,13 @@ cmsStage* _cmsStageAllocIdentityCLut(cmsContext ContextID, int nChan) cmsUInt32Number Dimensions[MAX_INPUT_DIMENSIONS]; cmsStage* mpe ; int i; - + for (i=0; i < MAX_INPUT_DIMENSIONS; i++) Dimensions[i] = 2; mpe = cmsStageAllocCLut16bitGranular(ContextID, Dimensions, nChan, nChan, NULL); if (mpe == NULL) return NULL; - + if (!cmsStageSampleCLut16bit(mpe, IdentitySampler, &nChan, 0)) { cmsStageFree(mpe); return NULL; @@ -729,17 +750,24 @@ cmsUInt16Number _cmsQuantizeVal(cmsFloat64Number i, int MaxSamples) cmsBool CMSEXPORT cmsStageSampleCLut16bit(cmsStage* mpe, cmsSAMPLER16 Sampler, void * Cargo, cmsUInt32Number dwFlags) { int i, t, nTotalPoints, index, rest; - int nInputs, nOutputs; + int nInputs, nOutputs; cmsUInt32Number* nSamples; - cmsUInt16Number In[cmsMAXCHANNELS], Out[MAX_STAGE_CHANNELS]; - _cmsStageCLutData* clut = (_cmsStageCLutData*) mpe->Data; + cmsUInt16Number In[MAX_INPUT_DIMENSIONS+1], Out[MAX_STAGE_CHANNELS]; + _cmsStageCLutData* clut; + + if (mpe == NULL) return FALSE; + + clut = (_cmsStageCLutData*) mpe->Data; + if (clut == NULL) return FALSE; nSamples = clut->Params ->nSamples; nInputs = clut->Params ->nInputs; nOutputs = clut->Params ->nOutputs; - if (nInputs >= cmsMAXCHANNELS) return FALSE; + if (nInputs <= 0) return FALSE; + if (nOutputs <= 0) return FALSE; + if (nInputs > MAX_INPUT_DIMENSIONS) return FALSE; if (nOutputs >= MAX_STAGE_CHANNELS) return FALSE; nTotalPoints = CubeSize(nSamples, nInputs); @@ -755,7 +783,7 @@ cmsBool CMSEXPORT cmsStageSampleCLut16bit(cmsStage* mpe, cmsSAMPLER16 Sampler, v rest /= nSamples[t]; - In[t] = _cmsQuantizeVal(Colorant, nSamples[t]); + In[t] = _cmsQuantizeVal(Colorant, nSamples[t]); } if (clut ->Tab.T != NULL) { @@ -786,14 +814,16 @@ cmsBool CMSEXPORT cmsStageSampleCLutFloat(cmsStage* mpe, cmsSAMPLERFLOAT Sampler int i, t, nTotalPoints, index, rest; int nInputs, nOutputs; cmsUInt32Number* nSamples; - cmsFloat32Number In[cmsMAXCHANNELS], Out[MAX_STAGE_CHANNELS]; - _cmsStageCLutData* clut = (_cmsStageCLutData*) mpe->Data; + cmsFloat32Number In[MAX_INPUT_DIMENSIONS+1], Out[MAX_STAGE_CHANNELS]; + _cmsStageCLutData* clut = (_cmsStageCLutData*) mpe->Data; nSamples = clut->Params ->nSamples; nInputs = clut->Params ->nInputs; nOutputs = clut->Params ->nOutputs; - if (nInputs >= cmsMAXCHANNELS) return FALSE; + if (nInputs <= 0) return FALSE; + if (nOutputs <= 0) return FALSE; + if (nInputs > MAX_INPUT_DIMENSIONS) return FALSE; if (nOutputs >= MAX_STAGE_CHANNELS) return FALSE; nTotalPoints = CubeSize(nSamples, nInputs); @@ -804,12 +834,12 @@ cmsBool CMSEXPORT cmsStageSampleCLutFloat(cmsStage* mpe, cmsSAMPLERFLOAT Sampler rest = i; for (t = nInputs-1; t >=0; --t) { - + cmsUInt32Number Colorant = rest % nSamples[t]; rest /= nSamples[t]; - In[t] = (cmsFloat32Number) (_cmsQuantizeVal(Colorant, nSamples[t]) / 65535.0); + In[t] = (cmsFloat32Number) (_cmsQuantizeVal(Colorant, nSamples[t]) / 65535.0); } if (clut ->Tab.TFloat != NULL) { @@ -857,7 +887,7 @@ cmsBool CMSEXPORT cmsSliceSpace16(cmsUInt32Number nInputs, const cmsUInt32Number cmsUInt32Number Colorant = rest % clutPoints[t]; rest /= clutPoints[t]; - In[t] = _cmsQuantizeVal(Colorant, clutPoints[t]); + In[t] = _cmsQuantizeVal(Colorant, clutPoints[t]); } @@ -887,7 +917,7 @@ cmsInt32Number CMSEXPORT cmsSliceSpaceFloat(cmsUInt32Number nInputs, const cmsUI cmsUInt32Number Colorant = rest % clutPoints[t]; rest /= clutPoints[t]; - In[t] = (cmsFloat32Number) (_cmsQuantizeVal(Colorant, clutPoints[t]) / 65535.0); + In[t] = (cmsFloat32Number) (_cmsQuantizeVal(Colorant, clutPoints[t]) / 65535.0); } @@ -904,8 +934,8 @@ cmsInt32Number CMSEXPORT cmsSliceSpaceFloat(cmsUInt32Number nInputs, const cmsUI static -void EvaluateLab2XYZ(const cmsFloat32Number In[], - cmsFloat32Number Out[], +void EvaluateLab2XYZ(const cmsFloat32Number In[], + cmsFloat32Number Out[], const cmsStage *mpe) { cmsCIELab Lab; @@ -913,18 +943,18 @@ void EvaluateLab2XYZ(const cmsFloat32Number In[], const cmsFloat64Number XYZadj = MAX_ENCODEABLE_XYZ; // V4 rules - Lab.L = In[0] * 100.0; + Lab.L = In[0] * 100.0; Lab.a = In[1] * 255.0 - 128.0; Lab.b = In[2] * 255.0 - 128.0; cmsLab2XYZ(NULL, &XYZ, &Lab); - // From XYZ, range 0..19997 to 0..1.0, note that 1.99997 comes from 0xffff + // From XYZ, range 0..19997 to 0..1.0, note that 1.99997 comes from 0xffff // encoded as 1.15 fixed point, so 1 + (32767.0 / 32768.0) - Out[0] = (cmsFloat32Number) ((cmsFloat64Number) XYZ.X / XYZadj); - Out[1] = (cmsFloat32Number) ((cmsFloat64Number) XYZ.Y / XYZadj); - Out[2] = (cmsFloat32Number) ((cmsFloat64Number) XYZ.Z / XYZadj); + Out[0] = (cmsFloat32Number) ((cmsFloat64Number) XYZ.X / XYZadj); + Out[1] = (cmsFloat32Number) ((cmsFloat64Number) XYZ.Y / XYZadj); + Out[2] = (cmsFloat32Number) ((cmsFloat64Number) XYZ.Z / XYZadj); return; cmsUNUSED_PARAMETER(mpe); @@ -939,9 +969,9 @@ cmsStage* _cmsStageAllocLab2XYZ(cmsContext ContextID) // ******************************************************************************** -// v2 L=100 is supposed to be placed on 0xFF00. There is no reasonable +// v2 L=100 is supposed to be placed on 0xFF00. There is no reasonable // number of gridpoints that would make exact match. However, a prelinearization -// of 258 entries, would map 0xFF00 exactly on entry 257, and this is good to avoid scum dot. +// of 258 entries, would map 0xFF00 exactly on entry 257, and this is good to avoid scum dot. // Almost all what we need but unfortunately, the rest of entries should be scaled by // (255*257/256) and this is not exact. @@ -956,13 +986,13 @@ cmsStage* _cmsStageAllocLabV2ToV4curves(cmsContext ContextID) LabTable[2] = cmsBuildTabulatedToneCurve16(ContextID, 258, NULL); for (j=0; j < 3; j++) { - + if (LabTable[j] == NULL) { cmsFreeToneCurveTriple(LabTable); return NULL; } - - // We need to map * (0xffff / 0xff00), thats same as (257 / 256) + + // We need to map * (0xffff / 0xff00), thats same as (257 / 256) // So we can use 258-entry tables to do the trick (i / 257) * (255 * 257) * (257 / 256); for (i=0; i < 257; i++) { @@ -975,6 +1005,7 @@ cmsStage* _cmsStageAllocLabV2ToV4curves(cmsContext ContextID) mpe = cmsStageAllocToneCurves(ContextID, 3, LabTable); cmsFreeToneCurveTriple(LabTable); + if (mpe == NULL) return NULL; mpe ->Implements = cmsSigLabV2toV4; return mpe; } @@ -985,8 +1016,8 @@ cmsStage* _cmsStageAllocLabV2ToV4curves(cmsContext ContextID) cmsStage* _cmsStageAllocLabV2ToV4(cmsContext ContextID) { static const cmsFloat64Number V2ToV4[] = { 65535.0/65280.0, 0, 0, - 0, 65535.0/65280.0, 0, - 0, 0, 65535.0/65280.0 + 0, 65535.0/65280.0, 0, + 0, 0, 65535.0/65280.0 }; cmsStage *mpe = cmsStageAllocMatrix(ContextID, 3, 3, V2ToV4, NULL); @@ -1001,8 +1032,8 @@ cmsStage* _cmsStageAllocLabV2ToV4(cmsContext ContextID) cmsStage* _cmsStageAllocLabV4ToV2(cmsContext ContextID) { static const cmsFloat64Number V4ToV2[] = { 65280.0/65535.0, 0, 0, - 0, 65280.0/65535.0, 0, - 0, 0, 65280.0/65535.0 + 0, 65280.0/65535.0, 0, + 0, 0, 65280.0/65535.0 }; cmsStage *mpe = cmsStageAllocMatrix(ContextID, 3, 3, V4ToV2, NULL); @@ -1013,6 +1044,89 @@ cmsStage* _cmsStageAllocLabV4ToV2(cmsContext ContextID) } +// To Lab to float. Note that the MPE gives numbers in normal Lab range +// and we need 0..1.0 range for the formatters +// L* : 0...100 => 0...1.0 (L* / 100) +// ab* : -128..+127 to 0..1 ((ab* + 128) / 255) + +cmsStage* _cmsStageNormalizeFromLabFloat(cmsContext ContextID) +{ + static const cmsFloat64Number a1[] = { + 1.0/100.0, 0, 0, + 0, 1.0/255.0, 0, + 0, 0, 1.0/255.0 + }; + + static const cmsFloat64Number o1[] = { + 0, + 128.0/255.0, + 128.0/255.0 + }; + + cmsStage *mpe = cmsStageAllocMatrix(ContextID, 3, 3, a1, o1); + + if (mpe == NULL) return mpe; + mpe ->Implements = cmsSigLab2FloatPCS; + return mpe; +} + +// Fom XYZ to floating point PCS +cmsStage* _cmsStageNormalizeFromXyzFloat(cmsContext ContextID) +{ +#define n (32768.0/65535.0) + static const cmsFloat64Number a1[] = { + n, 0, 0, + 0, n, 0, + 0, 0, n + }; +#undef n + + cmsStage *mpe = cmsStageAllocMatrix(ContextID, 3, 3, a1, NULL); + + if (mpe == NULL) return mpe; + mpe ->Implements = cmsSigXYZ2FloatPCS; + return mpe; +} + +cmsStage* _cmsStageNormalizeToLabFloat(cmsContext ContextID) +{ + static const cmsFloat64Number a1[] = { + 100.0, 0, 0, + 0, 255.0, 0, + 0, 0, 255.0 + }; + + static const cmsFloat64Number o1[] = { + 0, + -128.0, + -128.0 + }; + + cmsStage *mpe = cmsStageAllocMatrix(ContextID, 3, 3, a1, o1); + if (mpe == NULL) return mpe; + mpe ->Implements = cmsSigFloatPCS2Lab; + return mpe; +} + +cmsStage* _cmsStageNormalizeToXyzFloat(cmsContext ContextID) +{ +#define n (65535.0/32768.0) + + static const cmsFloat64Number a1[] = { + n, 0, 0, + 0, n, 0, + 0, 0, n + }; +#undef n + + cmsStage *mpe = cmsStageAllocMatrix(ContextID, 3, 3, a1, NULL); + if (mpe == NULL) return mpe; + mpe ->Implements = cmsSigFloatPCS2XYZ; + return mpe; +} + + + // ******************************************************************************** // Type cmsSigXYZ2LabElemType // ******************************************************************************** @@ -1022,20 +1136,20 @@ void EvaluateXYZ2Lab(const cmsFloat32Number In[], cmsFloat32Number Out[], const { cmsCIELab Lab; cmsCIEXYZ XYZ; - const cmsFloat64Number XYZadj = MAX_ENCODEABLE_XYZ; + const cmsFloat64Number XYZadj = MAX_ENCODEABLE_XYZ; // From 0..1.0 to XYZ - XYZ.X = In[0] * XYZadj; - XYZ.Y = In[1] * XYZadj; + XYZ.X = In[0] * XYZadj; + XYZ.Y = In[1] * XYZadj; XYZ.Z = In[2] * XYZadj; cmsXYZ2Lab(NULL, &Lab, &XYZ); - + // From V4 Lab to 0..1.0 - Out[0] = (cmsFloat32Number) (Lab.L / 100.0); - Out[1] = (cmsFloat32Number) ((Lab.a + 128.0) / 255.0); + Out[0] = (cmsFloat32Number) (Lab.L / 100.0); + Out[1] = (cmsFloat32Number) ((Lab.a + 128.0) / 255.0); Out[2] = (cmsFloat32Number) ((Lab.b + 128.0) / 255.0); return; @@ -1043,9 +1157,9 @@ void EvaluateXYZ2Lab(const cmsFloat32Number In[], cmsFloat32Number Out[], const } cmsStage* _cmsStageAllocXYZ2Lab(cmsContext ContextID) -{ +{ return _cmsStageAllocPlaceholder(ContextID, cmsSigXYZ2LabElemType, 3, 3, EvaluateXYZ2Lab, NULL, NULL, NULL); - + } // ******************************************************************************** @@ -1065,10 +1179,10 @@ cmsStage* _cmsStageAllocLabPrelin(cmsContext ContextID) } -// Free a single MPE +// Free a single MPE void CMSEXPORT cmsStageFree(cmsStage* mpe) { - if (mpe ->FreePtr) + if (mpe ->FreePtr) mpe ->FreePtr(mpe); _cmsFree(mpe ->ContextID, mpe); @@ -1105,24 +1219,34 @@ cmsStage* CMSEXPORT cmsStageNext(const cmsStage* mpe) cmsStage* CMSEXPORT cmsStageDup(cmsStage* mpe) { cmsStage* NewMPE; - + if (mpe == NULL) return NULL; - NewMPE = _cmsStageAllocPlaceholder(mpe ->ContextID, - mpe ->Type, - mpe ->InputChannels, + NewMPE = _cmsStageAllocPlaceholder(mpe ->ContextID, + mpe ->Type, + mpe ->InputChannels, mpe ->OutputChannels, mpe ->EvalPtr, mpe ->DupElemPtr, mpe ->FreePtr, NULL); if (NewMPE == NULL) return NULL; - - NewMPE ->Implements = mpe ->Implements; - - if (mpe ->DupElemPtr) - NewMPE ->Data = mpe ->DupElemPtr(mpe); - else + + NewMPE ->Implements = mpe ->Implements; + + if (mpe ->DupElemPtr) { + + NewMPE ->Data = mpe ->DupElemPtr(mpe); + + if (NewMPE->Data == NULL) { + + cmsStageFree(NewMPE); + return NULL; + } + + } else { + NewMPE ->Data = NULL; + } return NewMPE; } @@ -1135,7 +1259,7 @@ cmsStage* CMSEXPORT cmsStageDup(cmsStage* mpe) static void BlessLUT(cmsPipeline* lut) { - // We can set the input/ouput channels only if we have elements. + // We can set the input/ouput channels only if we have elements. if (lut ->Elements != NULL) { cmsStage *First, *Last; @@ -1149,50 +1273,50 @@ void BlessLUT(cmsPipeline* lut) } -// Default to evaluate the LUT on 16 bit-basis. Precision is retained. +// Default to evaluate the LUT on 16 bit-basis. Precision is retained. static void _LUTeval16(register const cmsUInt16Number In[], register cmsUInt16Number Out[], register const void* D) { cmsPipeline* lut = (cmsPipeline*) D; - cmsStage *mpe; + cmsStage *mpe; cmsFloat32Number Storage[2][MAX_STAGE_CHANNELS]; int Phase = 0, NextPhase; - + From16ToFloat(In, &Storage[Phase][0], lut ->InputChannels); - for (mpe = lut ->Elements; - mpe != NULL; + for (mpe = lut ->Elements; + mpe != NULL; mpe = mpe ->Next) { - NextPhase = Phase ^ 1; + NextPhase = Phase ^ 1; mpe ->EvalPtr(&Storage[Phase][0], &Storage[NextPhase][0], mpe); Phase = NextPhase; } - + FromFloatTo16(&Storage[Phase][0], Out, lut ->OutputChannels); } -// Does evaluate the LUT on cmsFloat32Number-basis. +// Does evaluate the LUT on cmsFloat32Number-basis. static void _LUTevalFloat(register const cmsFloat32Number In[], register cmsFloat32Number Out[], const void* D) { cmsPipeline* lut = (cmsPipeline*) D; - cmsStage *mpe; + cmsStage *mpe; cmsFloat32Number Storage[2][MAX_STAGE_CHANNELS]; int Phase = 0, NextPhase; - + memmove(&Storage[Phase][0], In, lut ->InputChannels * sizeof(cmsFloat32Number)); - for (mpe = lut ->Elements; - mpe != NULL; + for (mpe = lut ->Elements; + mpe != NULL; mpe = mpe ->Next) { NextPhase = Phase ^ 1; mpe ->EvalPtr(&Storage[Phase][0], &Storage[NextPhase][0], mpe); - Phase = NextPhase; + Phase = NextPhase; } memmove(Out, &Storage[Phase][0], lut ->OutputChannels * sizeof(cmsFloat32Number)); @@ -1221,7 +1345,7 @@ cmsPipeline* CMSEXPORT cmsPipelineAlloc(cmsContext ContextID, cmsUInt32Number In NewLUT ->EvalFloatFn = _LUTevalFloat; NewLUT ->DupDataFn = NULL; NewLUT ->FreeDataFn = NULL; - NewLUT ->Data = NewLUT; + NewLUT ->Data = NewLUT; NewLUT ->ContextID = ContextID; BlessLUT(NewLUT); @@ -1229,30 +1353,37 @@ cmsPipeline* CMSEXPORT cmsPipelineAlloc(cmsContext ContextID, cmsUInt32Number In return NewLUT; } +cmsContext CMSEXPORT cmsGetPipelineContextID(const cmsPipeline* lut) +{ + _cmsAssert(lut != NULL); + return lut ->ContextID; +} cmsUInt32Number CMSEXPORT cmsPipelineInputChannels(const cmsPipeline* lut) { + _cmsAssert(lut != NULL); return lut ->InputChannels; } cmsUInt32Number CMSEXPORT cmsPipelineOutputChannels(const cmsPipeline* lut) { + _cmsAssert(lut != NULL); return lut ->OutputChannels; } // Free a profile elements LUT void CMSEXPORT cmsPipelineFree(cmsPipeline* lut) { - cmsStage *mpe, *Next; + cmsStage *mpe, *Next; if (lut == NULL) return; - for (mpe = lut ->Elements; - mpe != NULL; + for (mpe = lut ->Elements; + mpe != NULL; mpe = Next) { Next = mpe ->Next; - cmsStageFree(mpe); + cmsStageFree(mpe); } if (lut ->FreeDataFn) lut ->FreeDataFn(lut ->ContextID, lut ->Data); @@ -1261,16 +1392,18 @@ void CMSEXPORT cmsPipelineFree(cmsPipeline* lut) } -// Default to evaluate the LUT on 16 bit-basis. +// Default to evaluate the LUT on 16 bit-basis. void CMSEXPORT cmsPipelineEval16(const cmsUInt16Number In[], cmsUInt16Number Out[], const cmsPipeline* lut) { + _cmsAssert(lut != NULL); lut ->Eval16Fn(In, Out, lut->Data); } -// Does evaluate the LUT on cmsFloat32Number-basis. +// Does evaluate the LUT on cmsFloat32Number-basis. void CMSEXPORT cmsPipelineEvalFloat(const cmsFloat32Number In[], cmsFloat32Number Out[], const cmsPipeline* lut) { + _cmsAssert(lut != NULL); lut ->EvalFloatFn(In, Out, lut); } @@ -1280,14 +1413,16 @@ void CMSEXPORT cmsPipelineEvalFloat(const cmsFloat32Number In[], cmsFloat32Numbe cmsPipeline* CMSEXPORT cmsPipelineDup(const cmsPipeline* lut) { cmsPipeline* NewLUT; - cmsStage *NewMPE, *Anterior = NULL, *mpe; + cmsStage *NewMPE, *Anterior = NULL, *mpe; cmsBool First = TRUE; if (lut == NULL) return NULL; - NewLUT = cmsPipelineAlloc(lut ->ContextID, lut ->InputChannels, lut ->OutputChannels); - for (mpe = lut ->Elements; - mpe != NULL; + NewLUT = cmsPipelineAlloc(lut ->ContextID, lut ->InputChannels, lut ->OutputChannels); + if (NewLUT == NULL) return NULL; + + for (mpe = lut ->Elements; + mpe != NULL; mpe = mpe ->Next) { NewMPE = cmsStageDup(mpe); @@ -1296,22 +1431,24 @@ cmsPipeline* CMSEXPORT cmsPipelineDup(const cmsPipeline* lut) cmsPipelineFree(NewLUT); return NULL; } - + if (First) { NewLUT ->Elements = NewMPE; First = FALSE; } else { - Anterior ->Next = NewMPE; + Anterior ->Next = NewMPE; } Anterior = NewMPE; } - NewLUT ->DupDataFn = lut ->DupDataFn; - NewLUT ->FreeDataFn = lut ->FreeDataFn; + NewLUT ->Eval16Fn = lut ->Eval16Fn; + NewLUT ->EvalFloatFn = lut ->EvalFloatFn; + NewLUT ->DupDataFn = lut ->DupDataFn; + NewLUT ->FreeDataFn = lut ->FreeDataFn; - if (NewLUT ->DupDataFn != NULL) + if (NewLUT ->DupDataFn != NULL) NewLUT ->Data = NewLUT ->DupDataFn(lut ->ContextID, lut->Data); @@ -1322,12 +1459,12 @@ cmsPipeline* CMSEXPORT cmsPipelineDup(const cmsPipeline* lut) } -void CMSEXPORT cmsPipelineInsertStage(cmsPipeline* lut, cmsStageLoc loc, cmsStage* mpe) +int CMSEXPORT cmsPipelineInsertStage(cmsPipeline* lut, cmsStageLoc loc, cmsStage* mpe) { cmsStage* Anterior = NULL, *pt; - _cmsAssert(lut != NULL); - _cmsAssert(mpe != NULL); + if (lut == NULL || mpe == NULL) + return FALSE; switch (loc) { @@ -1338,10 +1475,10 @@ void CMSEXPORT cmsPipelineInsertStage(cmsPipeline* lut, cmsStageLoc loc, cmsStag case cmsAT_END: - if (lut ->Elements == NULL) + if (lut ->Elements == NULL) lut ->Elements = mpe; else { - + for (pt = lut ->Elements; pt != NULL; pt = pt -> Next) Anterior = pt; @@ -1351,9 +1488,11 @@ void CMSEXPORT cmsPipelineInsertStage(cmsPipeline* lut, cmsStageLoc loc, cmsStag } break; default:; + return FALSE; } BlessLUT(lut); + return TRUE; } // Unlink an element and return the pointer to it @@ -1362,7 +1501,7 @@ void CMSEXPORT cmsPipelineUnlinkStage(cmsPipeline* lut, cmsStageLoc loc, cmsStag cmsStage *Anterior, *pt, *Last; cmsStage *Unlinked = NULL; - + // If empty LUT, there is nothing to remove if (lut ->Elements == NULL) { if (mpe) *mpe = NULL; @@ -1372,14 +1511,14 @@ void CMSEXPORT cmsPipelineUnlinkStage(cmsPipeline* lut, cmsStageLoc loc, cmsStag // On depending on the strategy... switch (loc) { - case cmsAT_BEGIN: + case cmsAT_BEGIN: { cmsStage* elem = lut ->Elements; - + lut ->Elements = elem -> Next; elem ->Next = NULL; Unlinked = elem; - + } break; @@ -1389,21 +1528,21 @@ void CMSEXPORT cmsPipelineUnlinkStage(cmsPipeline* lut, cmsStageLoc loc, cmsStag pt != NULL; pt = pt -> Next) { Anterior = Last; - Last = pt; + Last = pt; } Unlinked = Last; // Next already points to NULL // Truncate the chain - if (Anterior) + if (Anterior) Anterior ->Next = NULL; - else + else lut ->Elements = NULL; break; default:; } - if (mpe) + if (mpe) *mpe = Unlinked; else cmsStageFree(Unlinked); @@ -1415,9 +1554,9 @@ void CMSEXPORT cmsPipelineUnlinkStage(cmsPipeline* lut, cmsStageLoc loc, cmsStag // Concatenate two LUT into a new single one cmsBool CMSEXPORT cmsPipelineCat(cmsPipeline* l1, const cmsPipeline* l2) { - cmsStage* mpe, *NewMPE; + cmsStage* mpe; - // If both LUTS does not have elements, we need to inherit + // If both LUTS does not have elements, we need to inherit // the number of channels if (l1 ->Elements == NULL && l2 ->Elements == NULL) { l1 ->InputChannels = l2 ->InputChannels; @@ -1425,22 +1564,17 @@ cmsBool CMSEXPORT cmsPipelineCat(cmsPipeline* l1, const cmsPipeline* l2) } // Cat second - for (mpe = l2 ->Elements; - mpe != NULL; + for (mpe = l2 ->Elements; + mpe != NULL; mpe = mpe ->Next) { // We have to dup each element - NewMPE = cmsStageDup(mpe); - - if (NewMPE == NULL) { - return FALSE; - } - - cmsPipelineInsertStage(l1, cmsAT_END, NewMPE); + if (!cmsPipelineInsertStage(l1, cmsAT_END, cmsStageDup(mpe))) + return FALSE; } - BlessLUT(l1); - return TRUE; + BlessLUT(l1); + return TRUE; } @@ -1479,58 +1613,58 @@ cmsUInt32Number CMSEXPORT cmsPipelineStageCount(const cmsPipeline* lut) return n; } -// This function may be used to set the optional evalueator and a block of private data. If private data is being used, an optional +// This function may be used to set the optional evaluator and a block of private data. If private data is being used, an optional // duplicator and free functions should also be specified in order to duplicate the LUT construct. Use NULL to inhibit such functionality. -void CMSEXPORT _cmsPipelineSetOptimizationParameters(cmsPipeline* Lut, - _cmsOPTeval16Fn Eval16, - void* PrivateData, - _cmsOPTfreeDataFn FreePrivateDataFn, - _cmsOPTdupDataFn DupPrivateDataFn) +void CMSEXPORT _cmsPipelineSetOptimizationParameters(cmsPipeline* Lut, + _cmsOPTeval16Fn Eval16, + void* PrivateData, + _cmsFreeUserDataFn FreePrivateDataFn, + _cmsDupUserDataFn DupPrivateDataFn) { Lut ->Eval16Fn = Eval16; Lut ->DupDataFn = DupPrivateDataFn; - Lut ->FreeDataFn = FreePrivateDataFn; + Lut ->FreeDataFn = FreePrivateDataFn; Lut ->Data = PrivateData; } // ----------------------------------------------------------- Reverse interpolation -// Here's how it goes. The derivative Df(x) of the function f is the linear -// transformation that best approximates f near the point x. It can be represented -// by a matrix A whose entries are the partial derivatives of the components of f +// Here's how it goes. The derivative Df(x) of the function f is the linear +// transformation that best approximates f near the point x. It can be represented +// by a matrix A whose entries are the partial derivatives of the components of f // with respect to all the coordinates. This is know as the Jacobian // -// The best linear approximation to f is given by the matrix equation: -// -// y-y0 = A (x-x0) -// -// So, if x0 is a good "guess" for the zero of f, then solving for the zero of this -// linear approximation will give a "better guess" for the zero of f. Thus let y=0, -// and since y0=f(x0) one can solve the above equation for x. This leads to the -// Newton's method formula: +// The best linear approximation to f is given by the matrix equation: +// +// y-y0 = A (x-x0) +// +// So, if x0 is a good "guess" for the zero of f, then solving for the zero of this +// linear approximation will give a "better guess" for the zero of f. Thus let y=0, +// and since y0=f(x0) one can solve the above equation for x. This leads to the +// Newton's method formula: +// +// xn+1 = xn - A-1 f(xn) // -// xn+1 = xn - A-1 f(xn) -// -// where xn+1 denotes the (n+1)-st guess, obtained from the n-th guess xn in the -// fashion described above. Iterating this will give better and better approximations -// if you have a "good enough" initial guess. +// where xn+1 denotes the (n+1)-st guess, obtained from the n-th guess xn in the +// fashion described above. Iterating this will give better and better approximations +// if you have a "good enough" initial guess. #define JACOBIAN_EPSILON 0.001f #define INVERSION_MAX_ITERATIONS 30 // Increment with reflexion on boundary -static +static void IncDelta(cmsFloat32Number *Val) { - if (*Val < (1.0 - JACOBIAN_EPSILON)) + if (*Val < (1.0 - JACOBIAN_EPSILON)) *Val += JACOBIAN_EPSILON; - - else + + else *Val -= JACOBIAN_EPSILON; - + } @@ -1554,7 +1688,7 @@ cmsFloat32Number EuclideanDistance(cmsFloat32Number a[], cmsFloat32Number b[], i // Evaluate a LUT in reverse direction. It only searches on 3->3 LUT. Uses Newton method // // x1 <- x - [J(x)]^-1 * f(x) -// +// // lut: The LUT on where to do the search // Target: LabK, 3 values of Lab plus destination K which is fixed // Result: The obtained CMYK @@ -1566,20 +1700,15 @@ cmsBool CMSEXPORT cmsPipelineEvalReverseFloat(cmsFloat32Number Target[], const cmsPipeline* lut) { cmsUInt32Number i, j; - cmsFloat64Number error, LastError = 1E20; + cmsFloat64Number error, LastError = 1E20; cmsFloat32Number fx[4], x[4], xd[4], fxd[4]; cmsVEC3 tmp, tmp2; - cmsMAT3 Jacobian; - cmsFloat64Number LastResult[4]; - - + cmsMAT3 Jacobian; + // Only 3->3 and 4->3 are supported if (lut ->InputChannels != 3 && lut ->InputChannels != 4) return FALSE; if (lut ->OutputChannels != 3) return FALSE; - - // Mark result of -1 - LastResult[0] = LastResult[1] = LastResult[2] = -1.0f; - + // Take the hint as starting point if specified if (Hint == NULL) { @@ -1589,10 +1718,10 @@ cmsBool CMSEXPORT cmsPipelineEvalReverseFloat(cmsFloat32Number Target[], else { // Only copy 3 channels from hint... - for (j=0; j < 3; j++) - x[j] = Hint[j]; + for (j=0; j < 3; j++) + x[j] = Hint[j]; } - + // If Lut is 4-dimensions, then grab target[3], which is fixed if (lut ->InputChannels == 4) { x[3] = Target[3]; @@ -1600,7 +1729,7 @@ cmsBool CMSEXPORT cmsPipelineEvalReverseFloat(cmsFloat32Number Target[], else x[3] = 0; // To keep lint happy - // Iterate + // Iterate for (i = 0; i < INVERSION_MAX_ITERATIONS; i++) { // Get beginning fx @@ -1610,19 +1739,19 @@ cmsBool CMSEXPORT cmsPipelineEvalReverseFloat(cmsFloat32Number Target[], error = EuclideanDistance(fx, Target, 3); // If not convergent, return last safe value - if (error >= LastError) + if (error >= LastError) break; // Keep latest values LastError = error; - for (j=0; j < lut ->InputChannels; j++) - Result[j] = x[j]; + for (j=0; j < lut ->InputChannels; j++) + Result[j] = x[j]; // Found an exact match? - if (error <= 0) + if (error <= 0) break; - // Obtain slope (the Jacobian) + // Obtain slope (the Jacobian) for (j = 0; j < 3; j++) { xd[0] = x[0]; @@ -1636,7 +1765,7 @@ cmsBool CMSEXPORT cmsPipelineEvalReverseFloat(cmsFloat32Number Target[], Jacobian.v[0].n[j] = ((fxd[0] - fx[0]) / JACOBIAN_EPSILON); Jacobian.v[1].n[j] = ((fxd[1] - fx[1]) / JACOBIAN_EPSILON); - Jacobian.v[2].n[j] = ((fxd[2] - fx[2]) / JACOBIAN_EPSILON); + Jacobian.v[2].n[j] = ((fxd[2] - fx[2]) / JACOBIAN_EPSILON); } // Solve system @@ -1663,3 +1792,4 @@ cmsBool CMSEXPORT cmsPipelineEvalReverseFloat(cmsFloat32Number Target[], return TRUE; } + |
