1ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov//--------------------------------------------------------------------------------- 2ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// 3ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// Little Color Management System 4ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// Copyright (c) 1998-2012 Marti Maria Saguer 5ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// 6ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// Permission is hereby granted, free of charge, to any person obtaining 7ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// a copy of this software and associated documentation files (the "Software"), 8ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// to deal in the Software without restriction, including without limitation 9ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// the rights to use, copy, modify, merge, publish, distribute, sublicense, 10ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// and/or sell copies of the Software, and to permit persons to whom the Software 11ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// is furnished to do so, subject to the following conditions: 12ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// 13ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// The above copyright notice and this permission notice shall be included in 14ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// all copies or substantial portions of the Software. 15ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// 16ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO 18ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// 24ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov//--------------------------------------------------------------------------------- 25ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// 26ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 27ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#include "lcms2_internal.h" 28ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 29ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 30ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// Allocates an empty multi profile element 31ee451cb395940862dad63c85adfe8f2fd55e864cSvet GanovcmsStage* CMSEXPORT _cmsStageAllocPlaceholder(cmsContext ContextID, 32ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsStageSignature Type, 33ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsUInt32Number InputChannels, 34ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsUInt32Number OutputChannels, 35ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov _cmsStageEvalFn EvalPtr, 36ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov _cmsStageDupElemFn DupElemPtr, 37ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov _cmsStageFreeElemFn FreePtr, 38ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov void* Data) 39ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{ 40ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsStage* ph = (cmsStage*) _cmsMallocZero(ContextID, sizeof(cmsStage)); 41ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 42ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (ph == NULL) return NULL; 43ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 44ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 45ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov ph ->ContextID = ContextID; 46ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 47ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov ph ->Type = Type; 48ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov ph ->Implements = Type; // By default, no clue on what is implementing 49ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 50ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov ph ->InputChannels = InputChannels; 51ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov ph ->OutputChannels = OutputChannels; 52ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov ph ->EvalPtr = EvalPtr; 53ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov ph ->DupElemPtr = DupElemPtr; 54ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov ph ->FreePtr = FreePtr; 55ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov ph ->Data = Data; 56ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 57ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return ph; 58ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} 59ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 60ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 61ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovstatic 62ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovvoid EvaluateIdentity(const cmsFloat32Number In[], 63ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsFloat32Number Out[], 64ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov const cmsStage *mpe) 65ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{ 66ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov memmove(Out, In, mpe ->InputChannels * sizeof(cmsFloat32Number)); 67ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} 68ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 69ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 70ee451cb395940862dad63c85adfe8f2fd55e864cSvet GanovcmsStage* CMSEXPORT cmsStageAllocIdentity(cmsContext ContextID, cmsUInt32Number nChannels) 71ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{ 72ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return _cmsStageAllocPlaceholder(ContextID, 73ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsSigIdentityElemType, 74ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov nChannels, nChannels, 75ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov EvaluateIdentity, 76ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov NULL, 77ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov NULL, 78ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov NULL); 79ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 80ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 81ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// Conversion functions. From floating point to 16 bits 82ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovstatic 83ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovvoid FromFloatTo16(const cmsFloat32Number In[], cmsUInt16Number Out[], cmsUInt32Number n) 84ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{ 85ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsUInt32Number i; 86ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 87ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov for (i=0; i < n; i++) { 88ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Out[i] = _cmsQuickSaturateWord(In[i] * 65535.0); 89ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 90ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} 91ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 92ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// From 16 bits to floating point 93ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovstatic 94ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovvoid From16ToFloat(const cmsUInt16Number In[], cmsFloat32Number Out[], cmsUInt32Number n) 95ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{ 96ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsUInt32Number i; 97ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 98ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov for (i=0; i < n; i++) { 99ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Out[i] = (cmsFloat32Number) In[i] / 65535.0F; 100ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 101ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} 102ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 103ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 104ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// This function is quite useful to analyze the structure of a LUT and retrieve the MPE elements 105ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// that conform the LUT. It should be called with the LUT, the number of expected elements and 106ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// then a list of expected types followed with a list of cmsFloat64Number pointers to MPE elements. If 107ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// the function founds a match with current pipeline, it fills the pointers and returns TRUE 108ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// if not, returns FALSE without touching anything. Setting pointers to NULL does bypass 109ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// the storage process. 110ee451cb395940862dad63c85adfe8f2fd55e864cSvet GanovcmsBool CMSEXPORT cmsPipelineCheckAndRetreiveStages(const cmsPipeline* Lut, cmsUInt32Number n, ...) 111ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{ 112ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov va_list args; 113ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsUInt32Number i; 114ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsStage* mpe; 115ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsStageSignature Type; 116ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov void** ElemPtr; 117ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 118ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Make sure same number of elements 119ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (cmsPipelineStageCount(Lut) != n) return FALSE; 120ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 121ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov va_start(args, n); 122ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 123ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Iterate across asked types 124ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov mpe = Lut ->Elements; 125ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov for (i=0; i < n; i++) { 126ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 127ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Get asked type 128ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Type = (cmsStageSignature)va_arg(args, cmsStageSignature); 129ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (mpe ->Type != Type) { 130ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 131ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov va_end(args); // Mismatch. We are done. 132ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return FALSE; 133ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 134ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov mpe = mpe ->Next; 135ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 136ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 137ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Found a combination, fill pointers if not NULL 138ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov mpe = Lut ->Elements; 139ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov for (i=0; i < n; i++) { 140ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 141ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov ElemPtr = va_arg(args, void**); 142ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (ElemPtr != NULL) 143ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov *ElemPtr = mpe; 144ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 145ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov mpe = mpe ->Next; 146ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 147ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 148ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov va_end(args); 149ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return TRUE; 150ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} 151ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 152ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// Below there are implementations for several types of elements. Each type may be implemented by a 153ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// evaluation function, a duplication function, a function to free resources and a constructor. 154ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 155ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// ************************************************************************************************* 156ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// Type cmsSigCurveSetElemType (curves) 157ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// ************************************************************************************************* 158ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 159ee451cb395940862dad63c85adfe8f2fd55e864cSvet GanovcmsToneCurve** _cmsStageGetPtrToCurveSet(const cmsStage* mpe) 160ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{ 161ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov _cmsStageToneCurvesData* Data = (_cmsStageToneCurvesData*) mpe ->Data; 162ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 163ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return Data ->TheCurves; 164ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} 165ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 166ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovstatic 167ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovvoid EvaluateCurves(const cmsFloat32Number In[], 168ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsFloat32Number Out[], 169ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov const cmsStage *mpe) 170ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{ 171ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov _cmsStageToneCurvesData* Data; 172ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsUInt32Number i; 173ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 174ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov _cmsAssert(mpe != NULL); 175ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 176ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Data = (_cmsStageToneCurvesData*) mpe ->Data; 177ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (Data == NULL) return; 178ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 179ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (Data ->TheCurves == NULL) return; 180ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 181ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov for (i=0; i < Data ->nCurves; i++) { 182ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Out[i] = cmsEvalToneCurveFloat(Data ->TheCurves[i], In[i]); 183ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 184ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} 185ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 186ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovstatic 187ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovvoid CurveSetElemTypeFree(cmsStage* mpe) 188ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{ 189ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov _cmsStageToneCurvesData* Data; 190ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsUInt32Number i; 191ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 192ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov _cmsAssert(mpe != NULL); 193ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 194ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Data = (_cmsStageToneCurvesData*) mpe ->Data; 195ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (Data == NULL) return; 196ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 197ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (Data ->TheCurves != NULL) { 198ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov for (i=0; i < Data ->nCurves; i++) { 199ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (Data ->TheCurves[i] != NULL) 200ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsFreeToneCurve(Data ->TheCurves[i]); 201ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 202ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 203ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov _cmsFree(mpe ->ContextID, Data ->TheCurves); 204ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov _cmsFree(mpe ->ContextID, Data); 205ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} 206ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 207ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 208ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovstatic 209ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovvoid* CurveSetDup(cmsStage* mpe) 210ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{ 211ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov _cmsStageToneCurvesData* Data = (_cmsStageToneCurvesData*) mpe ->Data; 212ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov _cmsStageToneCurvesData* NewElem; 213ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsUInt32Number i; 214ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 215ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov NewElem = (_cmsStageToneCurvesData*) _cmsMallocZero(mpe ->ContextID, sizeof(_cmsStageToneCurvesData)); 216ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (NewElem == NULL) return NULL; 217ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 218ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov NewElem ->nCurves = Data ->nCurves; 219ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov NewElem ->TheCurves = (cmsToneCurve**) _cmsCalloc(mpe ->ContextID, NewElem ->nCurves, sizeof(cmsToneCurve*)); 220ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 221ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (NewElem ->TheCurves == NULL) goto Error; 222ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 223ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov for (i=0; i < NewElem ->nCurves; i++) { 224ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 225ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Duplicate each curve. It may fail. 226ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov NewElem ->TheCurves[i] = cmsDupToneCurve(Data ->TheCurves[i]); 227ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (NewElem ->TheCurves[i] == NULL) goto Error; 228ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 229ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 230ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 231ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return (void*) NewElem; 232ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 233ee451cb395940862dad63c85adfe8f2fd55e864cSvet GanovError: 234ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 235ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (NewElem ->TheCurves != NULL) { 236ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov for (i=0; i < NewElem ->nCurves; i++) { 237ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (NewElem ->TheCurves[i]) 238ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsFreeToneCurve(NewElem ->TheCurves[i]); 239ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 240ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 241ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov _cmsFree(mpe ->ContextID, NewElem ->TheCurves); 242ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov _cmsFree(mpe ->ContextID, NewElem); 243ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return NULL; 244ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} 245ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 246ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 247ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// Curves == NULL forces identity curves 248ee451cb395940862dad63c85adfe8f2fd55e864cSvet GanovcmsStage* CMSEXPORT cmsStageAllocToneCurves(cmsContext ContextID, cmsUInt32Number nChannels, cmsToneCurve* const Curves[]) 249ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{ 250ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsUInt32Number i; 251ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov _cmsStageToneCurvesData* NewElem; 252ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsStage* NewMPE; 253ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 254ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 255ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov NewMPE = _cmsStageAllocPlaceholder(ContextID, cmsSigCurveSetElemType, nChannels, nChannels, 256ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov EvaluateCurves, CurveSetDup, CurveSetElemTypeFree, NULL ); 257ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (NewMPE == NULL) return NULL; 258ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 259ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov NewElem = (_cmsStageToneCurvesData*) _cmsMallocZero(ContextID, sizeof(_cmsStageToneCurvesData)); 260ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (NewElem == NULL) { 261ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsStageFree(NewMPE); 262ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return NULL; 263ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 264ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 265ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov NewMPE ->Data = (void*) NewElem; 266ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 267ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov NewElem ->nCurves = nChannels; 268ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov NewElem ->TheCurves = (cmsToneCurve**) _cmsCalloc(ContextID, nChannels, sizeof(cmsToneCurve*)); 269ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (NewElem ->TheCurves == NULL) { 270ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsStageFree(NewMPE); 271ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return NULL; 272ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 273ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 274ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov for (i=0; i < nChannels; i++) { 275ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 276ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (Curves == NULL) { 277ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov NewElem ->TheCurves[i] = cmsBuildGamma(ContextID, 1.0); 278ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 279ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov else { 280ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov NewElem ->TheCurves[i] = cmsDupToneCurve(Curves[i]); 281ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 282ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 283ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (NewElem ->TheCurves[i] == NULL) { 284ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsStageFree(NewMPE); 285ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return NULL; 286ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 287ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 288ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 289ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 290ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return NewMPE; 291ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} 292ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 293ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 294ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// Create a bunch of identity curves 295ee451cb395940862dad63c85adfe8f2fd55e864cSvet GanovcmsStage* _cmsStageAllocIdentityCurves(cmsContext ContextID, int nChannels) 296ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{ 297ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsStage* mpe = cmsStageAllocToneCurves(ContextID, nChannels, NULL); 298ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 299ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (mpe == NULL) return NULL; 300ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov mpe ->Implements = cmsSigIdentityElemType; 301ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return mpe; 302ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} 303ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 304ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 305ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// ************************************************************************************************* 306ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// Type cmsSigMatrixElemType (Matrices) 307ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// ************************************************************************************************* 308ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 309ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 310ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// Special care should be taken here because precision loss. A temporary cmsFloat64Number buffer is being used 311ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovstatic 312ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovvoid EvaluateMatrix(const cmsFloat32Number In[], 313ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsFloat32Number Out[], 314ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov const cmsStage *mpe) 315ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{ 316ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsUInt32Number i, j; 317ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov _cmsStageMatrixData* Data = (_cmsStageMatrixData*) mpe ->Data; 318ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsFloat64Number Tmp; 319ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 320ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Input is already in 0..1.0 notation 321ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov for (i=0; i < mpe ->OutputChannels; i++) { 322ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 323ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Tmp = 0; 324ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov for (j=0; j < mpe->InputChannels; j++) { 325ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Tmp += In[j] * Data->Double[i*mpe->InputChannels + j]; 326ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 327ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 328ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (Data ->Offset != NULL) 329ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Tmp += Data->Offset[i]; 330ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 331ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Out[i] = (cmsFloat32Number) Tmp; 332ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 333ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 334ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 335ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Output in 0..1.0 domain 336ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} 337ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 338ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 339ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// Duplicate a yet-existing matrix element 340ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovstatic 341ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovvoid* MatrixElemDup(cmsStage* mpe) 342ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{ 343ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov _cmsStageMatrixData* Data = (_cmsStageMatrixData*) mpe ->Data; 344ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov _cmsStageMatrixData* NewElem; 345ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsUInt32Number sz; 346ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 347ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov NewElem = (_cmsStageMatrixData*) _cmsMallocZero(mpe ->ContextID, sizeof(_cmsStageMatrixData)); 348ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (NewElem == NULL) return NULL; 349ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 350ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov sz = mpe ->InputChannels * mpe ->OutputChannels; 351ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 352ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov NewElem ->Double = (cmsFloat64Number*) _cmsDupMem(mpe ->ContextID, Data ->Double, sz * sizeof(cmsFloat64Number)) ; 353ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 354ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (Data ->Offset) 355ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov NewElem ->Offset = (cmsFloat64Number*) _cmsDupMem(mpe ->ContextID, 356ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Data ->Offset, mpe -> OutputChannels * sizeof(cmsFloat64Number)) ; 357ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 358ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return (void*) NewElem; 359ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} 360ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 361ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 362ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovstatic 363ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovvoid MatrixElemTypeFree(cmsStage* mpe) 364ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{ 365ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov _cmsStageMatrixData* Data = (_cmsStageMatrixData*) mpe ->Data; 366ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (Data == NULL) 367ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return; 368ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (Data ->Double) 369ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov _cmsFree(mpe ->ContextID, Data ->Double); 370ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 371ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (Data ->Offset) 372ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov _cmsFree(mpe ->ContextID, Data ->Offset); 373ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 374ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov _cmsFree(mpe ->ContextID, mpe ->Data); 375ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} 376ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 377ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 378ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 379ee451cb395940862dad63c85adfe8f2fd55e864cSvet GanovcmsStage* CMSEXPORT cmsStageAllocMatrix(cmsContext ContextID, cmsUInt32Number Rows, cmsUInt32Number Cols, 380ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov const cmsFloat64Number* Matrix, const cmsFloat64Number* Offset) 381ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{ 382ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsUInt32Number i, n; 383ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov _cmsStageMatrixData* NewElem; 384ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsStage* NewMPE; 385ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 386ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov n = Rows * Cols; 387ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 388ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Check for overflow 389ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (n == 0) return NULL; 390ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (n >= UINT_MAX / Cols) return NULL; 391ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (n >= UINT_MAX / Rows) return NULL; 392ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (n < Rows || n < Cols) return NULL; 393ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 394ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov NewMPE = _cmsStageAllocPlaceholder(ContextID, cmsSigMatrixElemType, Cols, Rows, 395ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov EvaluateMatrix, MatrixElemDup, MatrixElemTypeFree, NULL ); 396ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (NewMPE == NULL) return NULL; 397ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 398ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 399ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov NewElem = (_cmsStageMatrixData*) _cmsMallocZero(ContextID, sizeof(_cmsStageMatrixData)); 400ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (NewElem == NULL) return NULL; 401ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 402ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 403ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov NewElem ->Double = (cmsFloat64Number*) _cmsCalloc(ContextID, n, sizeof(cmsFloat64Number)); 404ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 405ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (NewElem->Double == NULL) { 406ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov MatrixElemTypeFree(NewMPE); 407ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return NULL; 408ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 409ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 410ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov for (i=0; i < n; i++) { 411ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov NewElem ->Double[i] = Matrix[i]; 412ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 413ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 414ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 415ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (Offset != NULL) { 416ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 417ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov NewElem ->Offset = (cmsFloat64Number*) _cmsCalloc(ContextID, Cols, sizeof(cmsFloat64Number)); 418ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (NewElem->Offset == NULL) { 419ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov MatrixElemTypeFree(NewMPE); 420ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return NULL; 421ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 422ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 423ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov for (i=0; i < Cols; i++) { 424ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov NewElem ->Offset[i] = Offset[i]; 425ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 426ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 427ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 428ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 429ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov NewMPE ->Data = (void*) NewElem; 430ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return NewMPE; 431ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} 432ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 433ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 434ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// ************************************************************************************************* 435ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// Type cmsSigCLutElemType 436ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// ************************************************************************************************* 437ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 438ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 439ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// Evaluate in true floating point 440ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovstatic 441ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovvoid EvaluateCLUTfloat(const cmsFloat32Number In[], cmsFloat32Number Out[], const cmsStage *mpe) 442ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{ 443ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov _cmsStageCLutData* Data = (_cmsStageCLutData*) mpe ->Data; 444ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 445ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Data -> Params ->Interpolation.LerpFloat(In, Out, Data->Params); 446ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} 447ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 448ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 449ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// Convert to 16 bits, evaluate, and back to floating point 450ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovstatic 451ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovvoid EvaluateCLUTfloatIn16(const cmsFloat32Number In[], cmsFloat32Number Out[], const cmsStage *mpe) 452ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{ 453ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov _cmsStageCLutData* Data = (_cmsStageCLutData*) mpe ->Data; 454ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsUInt16Number In16[MAX_STAGE_CHANNELS], Out16[MAX_STAGE_CHANNELS]; 455ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 456ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov _cmsAssert(mpe ->InputChannels <= MAX_STAGE_CHANNELS); 457ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov _cmsAssert(mpe ->OutputChannels <= MAX_STAGE_CHANNELS); 458ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 459ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FromFloatTo16(In, In16, mpe ->InputChannels); 460ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Data -> Params ->Interpolation.Lerp16(In16, Out16, Data->Params); 461ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov From16ToFloat(Out16, Out, mpe ->OutputChannels); 462ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} 463ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 464ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 465ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// Given an hypercube of b dimensions, with Dims[] number of nodes by dimension, calculate the total amount of nodes 466ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovstatic 467ee451cb395940862dad63c85adfe8f2fd55e864cSvet GanovcmsUInt32Number CubeSize(const cmsUInt32Number Dims[], cmsUInt32Number b) 468ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{ 469ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsUInt32Number rv, dim; 470ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 471ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov _cmsAssert(Dims != NULL); 472ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 473ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov for (rv = 1; b > 0; b--) { 474ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 475ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov dim = Dims[b-1]; 476ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (dim == 0) return 0; // Error 477ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 478ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov rv *= dim; 479ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 480ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Check for overflow 481ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (rv > UINT_MAX / dim) return 0; 482ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 483ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 484ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return rv; 485ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} 486ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 487ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovstatic 488ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovvoid* CLUTElemDup(cmsStage* mpe) 489ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{ 490ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov _cmsStageCLutData* Data = (_cmsStageCLutData*) mpe ->Data; 491ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov _cmsStageCLutData* NewElem; 492ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 493ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 494ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov NewElem = (_cmsStageCLutData*) _cmsMallocZero(mpe ->ContextID, sizeof(_cmsStageCLutData)); 495ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (NewElem == NULL) return NULL; 496ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 497ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov NewElem ->nEntries = Data ->nEntries; 498ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov NewElem ->HasFloatValues = Data ->HasFloatValues; 499ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 500ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (Data ->Tab.T) { 501ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 502ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (Data ->HasFloatValues) { 503ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov NewElem ->Tab.TFloat = (cmsFloat32Number*) _cmsDupMem(mpe ->ContextID, Data ->Tab.TFloat, Data ->nEntries * sizeof (cmsFloat32Number)); 504ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (NewElem ->Tab.TFloat == NULL) 505ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov goto Error; 506ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } else { 507ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov NewElem ->Tab.T = (cmsUInt16Number*) _cmsDupMem(mpe ->ContextID, Data ->Tab.T, Data ->nEntries * sizeof (cmsUInt16Number)); 508ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (NewElem ->Tab.TFloat == NULL) 509ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov goto Error; 510ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 511ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 512ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 513ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov NewElem ->Params = _cmsComputeInterpParamsEx(mpe ->ContextID, 514ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Data ->Params ->nSamples, 515ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Data ->Params ->nInputs, 516ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Data ->Params ->nOutputs, 517ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov NewElem ->Tab.T, 518ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Data ->Params ->dwFlags); 519ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (NewElem->Params != NULL) 520ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return (void*) NewElem; 521ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Error: 522ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (NewElem->Tab.T) 523ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // This works for both types 524ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov _cmsFree(mpe ->ContextID, NewElem -> Tab.T); 525ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov _cmsFree(mpe ->ContextID, NewElem); 526ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return NULL; 527ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} 528ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 529ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 530ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovstatic 531ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovvoid CLutElemTypeFree(cmsStage* mpe) 532ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{ 533ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 534ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov _cmsStageCLutData* Data = (_cmsStageCLutData*) mpe ->Data; 535ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 536ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Already empty 537ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (Data == NULL) return; 538ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 539ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // This works for both types 540ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (Data -> Tab.T) 541ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov _cmsFree(mpe ->ContextID, Data -> Tab.T); 542ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 543ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov _cmsFreeInterpParams(Data ->Params); 544ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov _cmsFree(mpe ->ContextID, mpe ->Data); 545ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} 546ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 547ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 548ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// Allocates a 16-bit multidimensional CLUT. This is evaluated at 16-bit precision. Table may have different 549ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// granularity on each dimension. 550ee451cb395940862dad63c85adfe8f2fd55e864cSvet GanovcmsStage* CMSEXPORT cmsStageAllocCLut16bitGranular(cmsContext ContextID, 551ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov const cmsUInt32Number clutPoints[], 552ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsUInt32Number inputChan, 553ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsUInt32Number outputChan, 554ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov const cmsUInt16Number* Table) 555ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{ 556ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsUInt32Number i, n; 557ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov _cmsStageCLutData* NewElem; 558ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsStage* NewMPE; 559ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 560ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov _cmsAssert(clutPoints != NULL); 561ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 562ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (inputChan > MAX_INPUT_DIMENSIONS) { 563ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsSignalError(ContextID, cmsERROR_RANGE, "Too many input channels (%d channels, max=%d)", inputChan, MAX_INPUT_DIMENSIONS); 564ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return NULL; 565ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 566ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 567ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov NewMPE = _cmsStageAllocPlaceholder(ContextID, cmsSigCLutElemType, inputChan, outputChan, 568ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov EvaluateCLUTfloatIn16, CLUTElemDup, CLutElemTypeFree, NULL ); 569ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 570ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (NewMPE == NULL) return NULL; 571ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 572ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov NewElem = (_cmsStageCLutData*) _cmsMallocZero(ContextID, sizeof(_cmsStageCLutData)); 573ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (NewElem == NULL) { 574ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsStageFree(NewMPE); 575ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return NULL; 576ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 577ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 578ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov NewMPE ->Data = (void*) NewElem; 579ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 580ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov NewElem -> nEntries = n = outputChan * CubeSize(clutPoints, inputChan); 581ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov NewElem -> HasFloatValues = FALSE; 582ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 583ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (n == 0) { 584ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsStageFree(NewMPE); 585ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return NULL; 586ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 587ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 588ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 589ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov NewElem ->Tab.T = (cmsUInt16Number*) _cmsCalloc(ContextID, n, sizeof(cmsUInt16Number)); 590ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (NewElem ->Tab.T == NULL) { 591ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsStageFree(NewMPE); 592ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return NULL; 593ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 594ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 595ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (Table != NULL) { 596ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov for (i=0; i < n; i++) { 597ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov NewElem ->Tab.T[i] = Table[i]; 598ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 599ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 600ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 601ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov NewElem ->Params = _cmsComputeInterpParamsEx(ContextID, clutPoints, inputChan, outputChan, NewElem ->Tab.T, CMS_LERP_FLAGS_16BITS); 602ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (NewElem ->Params == NULL) { 603ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsStageFree(NewMPE); 604ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return NULL; 605ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 606ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 607ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return NewMPE; 608ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} 609ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 610ee451cb395940862dad63c85adfe8f2fd55e864cSvet GanovcmsStage* CMSEXPORT cmsStageAllocCLut16bit(cmsContext ContextID, 611ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsUInt32Number nGridPoints, 612ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsUInt32Number inputChan, 613ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsUInt32Number outputChan, 614ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov const cmsUInt16Number* Table) 615ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{ 616ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsUInt32Number Dimensions[MAX_INPUT_DIMENSIONS]; 617ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov int i; 618ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 619ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Our resulting LUT would be same gridpoints on all dimensions 620ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov for (i=0; i < MAX_INPUT_DIMENSIONS; i++) 621ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Dimensions[i] = nGridPoints; 622ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 623ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return cmsStageAllocCLut16bitGranular(ContextID, Dimensions, inputChan, outputChan, Table); 624ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} 625ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 626ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 627ee451cb395940862dad63c85adfe8f2fd55e864cSvet GanovcmsStage* CMSEXPORT cmsStageAllocCLutFloat(cmsContext ContextID, 628ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsUInt32Number nGridPoints, 629ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsUInt32Number inputChan, 630ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsUInt32Number outputChan, 631ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov const cmsFloat32Number* Table) 632ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{ 633ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsUInt32Number Dimensions[MAX_INPUT_DIMENSIONS]; 634ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov int i; 635ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 636ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Our resulting LUT would be same gridpoints on all dimensions 637ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov for (i=0; i < MAX_INPUT_DIMENSIONS; i++) 638ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Dimensions[i] = nGridPoints; 639ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 640ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return cmsStageAllocCLutFloatGranular(ContextID, Dimensions, inputChan, outputChan, Table); 641ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} 642ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 643ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 644ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 645ee451cb395940862dad63c85adfe8f2fd55e864cSvet GanovcmsStage* CMSEXPORT cmsStageAllocCLutFloatGranular(cmsContext ContextID, const cmsUInt32Number clutPoints[], cmsUInt32Number inputChan, cmsUInt32Number outputChan, const cmsFloat32Number* Table) 646ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{ 647ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsUInt32Number i, n; 648ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov _cmsStageCLutData* NewElem; 649ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsStage* NewMPE; 650ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 651ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov _cmsAssert(clutPoints != NULL); 652ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 653ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (inputChan > MAX_INPUT_DIMENSIONS) { 654ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsSignalError(ContextID, cmsERROR_RANGE, "Too many input channels (%d channels, max=%d)", inputChan, MAX_INPUT_DIMENSIONS); 655ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return NULL; 656ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 657ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 658ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov NewMPE = _cmsStageAllocPlaceholder(ContextID, cmsSigCLutElemType, inputChan, outputChan, 659ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov EvaluateCLUTfloat, CLUTElemDup, CLutElemTypeFree, NULL); 660ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (NewMPE == NULL) return NULL; 661ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 662ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 663ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov NewElem = (_cmsStageCLutData*) _cmsMallocZero(ContextID, sizeof(_cmsStageCLutData)); 664ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (NewElem == NULL) { 665ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsStageFree(NewMPE); 666ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return NULL; 667ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 668ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 669ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov NewMPE ->Data = (void*) NewElem; 670ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 671ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // There is a potential integer overflow on conputing n and nEntries. 672ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov NewElem -> nEntries = n = outputChan * CubeSize(clutPoints, inputChan); 673ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov NewElem -> HasFloatValues = TRUE; 674ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 675ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (n == 0) { 676ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsStageFree(NewMPE); 677ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return NULL; 678ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 679ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 680ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov NewElem ->Tab.TFloat = (cmsFloat32Number*) _cmsCalloc(ContextID, n, sizeof(cmsFloat32Number)); 681ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (NewElem ->Tab.TFloat == NULL) { 682ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsStageFree(NewMPE); 683ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return NULL; 684ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 685ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 686ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (Table != NULL) { 687ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov for (i=0; i < n; i++) { 688ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov NewElem ->Tab.TFloat[i] = Table[i]; 689ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 690ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 691ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 692ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov NewElem ->Params = _cmsComputeInterpParamsEx(ContextID, clutPoints, inputChan, outputChan, NewElem ->Tab.TFloat, CMS_LERP_FLAGS_FLOAT); 693ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (NewElem ->Params == NULL) { 694ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsStageFree(NewMPE); 695ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return NULL; 696ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 697ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 698ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return NewMPE; 699ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} 700ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 701ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 702ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovstatic 703ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovint IdentitySampler(register const cmsUInt16Number In[], register cmsUInt16Number Out[], register void * Cargo) 704ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{ 705ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov int nChan = *(int*) Cargo; 706ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov int i; 707ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 708ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov for (i=0; i < nChan; i++) 709ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Out[i] = In[i]; 710ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 711ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return 1; 712ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} 713ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 714ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// Creates an MPE that just copies input to output 715ee451cb395940862dad63c85adfe8f2fd55e864cSvet GanovcmsStage* _cmsStageAllocIdentityCLut(cmsContext ContextID, int nChan) 716ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{ 717ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsUInt32Number Dimensions[MAX_INPUT_DIMENSIONS]; 718ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsStage* mpe ; 719ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov int i; 720ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 721ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov for (i=0; i < MAX_INPUT_DIMENSIONS; i++) 722ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Dimensions[i] = 2; 723ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 724ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov mpe = cmsStageAllocCLut16bitGranular(ContextID, Dimensions, nChan, nChan, NULL); 725ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (mpe == NULL) return NULL; 726ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 727ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (!cmsStageSampleCLut16bit(mpe, IdentitySampler, &nChan, 0)) { 728ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsStageFree(mpe); 729ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return NULL; 730ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 731ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 732ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov mpe ->Implements = cmsSigIdentityElemType; 733ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return mpe; 734ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} 735ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 736ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 737ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 738ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// Quantize a value 0 <= i < MaxSamples to 0..0xffff 739ee451cb395940862dad63c85adfe8f2fd55e864cSvet GanovcmsUInt16Number _cmsQuantizeVal(cmsFloat64Number i, int MaxSamples) 740ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{ 741ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsFloat64Number x; 742ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 743ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov x = ((cmsFloat64Number) i * 65535.) / (cmsFloat64Number) (MaxSamples - 1); 744ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return _cmsQuickSaturateWord(x); 745ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} 746ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 747ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 748ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// This routine does a sweep on whole input space, and calls its callback 749ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// function on knots. returns TRUE if all ok, FALSE otherwise. 750ee451cb395940862dad63c85adfe8f2fd55e864cSvet GanovcmsBool CMSEXPORT cmsStageSampleCLut16bit(cmsStage* mpe, cmsSAMPLER16 Sampler, void * Cargo, cmsUInt32Number dwFlags) 751ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{ 752ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov int i, t, nTotalPoints, index, rest; 753ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov int nInputs, nOutputs; 754ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsUInt32Number* nSamples; 755ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsUInt16Number In[MAX_INPUT_DIMENSIONS+1], Out[MAX_STAGE_CHANNELS]; 756ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov _cmsStageCLutData* clut; 757ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 758ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (mpe == NULL) return FALSE; 759ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 760ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov clut = (_cmsStageCLutData*) mpe->Data; 761ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 762ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (clut == NULL) return FALSE; 763ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 764ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov nSamples = clut->Params ->nSamples; 765ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov nInputs = clut->Params ->nInputs; 766ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov nOutputs = clut->Params ->nOutputs; 767ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 768ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (nInputs <= 0) return FALSE; 769ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (nOutputs <= 0) return FALSE; 770ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (nInputs > MAX_INPUT_DIMENSIONS) return FALSE; 771ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (nOutputs >= MAX_STAGE_CHANNELS) return FALSE; 772ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 773ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov nTotalPoints = CubeSize(nSamples, nInputs); 774ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (nTotalPoints == 0) return FALSE; 775ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 776ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov index = 0; 777ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov for (i = 0; i < nTotalPoints; i++) { 778ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 779ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov rest = i; 780ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov for (t = nInputs-1; t >=0; --t) { 781ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 782ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsUInt32Number Colorant = rest % nSamples[t]; 783ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 784ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov rest /= nSamples[t]; 785ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 786ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov In[t] = _cmsQuantizeVal(Colorant, nSamples[t]); 787ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 788ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 789ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (clut ->Tab.T != NULL) { 790ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov for (t=0; t < nOutputs; t++) 791ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Out[t] = clut->Tab.T[index + t]; 792ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 793ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 794ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (!Sampler(In, Out, Cargo)) 795ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return FALSE; 796ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 797ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (!(dwFlags & SAMPLER_INSPECT)) { 798ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 799ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (clut ->Tab.T != NULL) { 800ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov for (t=0; t < nOutputs; t++) 801ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov clut->Tab.T[index + t] = Out[t]; 802ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 803ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 804ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 805ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov index += nOutputs; 806ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 807ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 808ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return TRUE; 809ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} 810ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 811ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// Same as anterior, but for floting point 812ee451cb395940862dad63c85adfe8f2fd55e864cSvet GanovcmsBool CMSEXPORT cmsStageSampleCLutFloat(cmsStage* mpe, cmsSAMPLERFLOAT Sampler, void * Cargo, cmsUInt32Number dwFlags) 813ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{ 814ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov int i, t, nTotalPoints, index, rest; 815ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov int nInputs, nOutputs; 816ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsUInt32Number* nSamples; 817ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsFloat32Number In[MAX_INPUT_DIMENSIONS+1], Out[MAX_STAGE_CHANNELS]; 818ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov _cmsStageCLutData* clut = (_cmsStageCLutData*) mpe->Data; 819ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 820ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov nSamples = clut->Params ->nSamples; 821ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov nInputs = clut->Params ->nInputs; 822ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov nOutputs = clut->Params ->nOutputs; 823ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 824ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (nInputs <= 0) return FALSE; 825ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (nOutputs <= 0) return FALSE; 826ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (nInputs > MAX_INPUT_DIMENSIONS) return FALSE; 827ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (nOutputs >= MAX_STAGE_CHANNELS) return FALSE; 828ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 829ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov nTotalPoints = CubeSize(nSamples, nInputs); 830ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (nTotalPoints == 0) return FALSE; 831ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 832ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov index = 0; 833ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov for (i = 0; i < nTotalPoints; i++) { 834ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 835ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov rest = i; 836ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov for (t = nInputs-1; t >=0; --t) { 837ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 838ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsUInt32Number Colorant = rest % nSamples[t]; 839ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 840ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov rest /= nSamples[t]; 841ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 842ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov In[t] = (cmsFloat32Number) (_cmsQuantizeVal(Colorant, nSamples[t]) / 65535.0); 843ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 844ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 845ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (clut ->Tab.TFloat != NULL) { 846ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov for (t=0; t < nOutputs; t++) 847ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Out[t] = clut->Tab.TFloat[index + t]; 848ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 849ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 850ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (!Sampler(In, Out, Cargo)) 851ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return FALSE; 852ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 853ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (!(dwFlags & SAMPLER_INSPECT)) { 854ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 855ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (clut ->Tab.TFloat != NULL) { 856ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov for (t=0; t < nOutputs; t++) 857ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov clut->Tab.TFloat[index + t] = Out[t]; 858ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 859ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 860ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 861ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov index += nOutputs; 862ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 863ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 864ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return TRUE; 865ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} 866ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 867ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 868ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 869ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// This routine does a sweep on whole input space, and calls its callback 870ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// function on knots. returns TRUE if all ok, FALSE otherwise. 871ee451cb395940862dad63c85adfe8f2fd55e864cSvet GanovcmsBool CMSEXPORT cmsSliceSpace16(cmsUInt32Number nInputs, const cmsUInt32Number clutPoints[], 872ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsSAMPLER16 Sampler, void * Cargo) 873ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{ 874ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov int i, t, nTotalPoints, rest; 875ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsUInt16Number In[cmsMAXCHANNELS]; 876ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 877ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (nInputs >= cmsMAXCHANNELS) return FALSE; 878ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 879ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov nTotalPoints = CubeSize(clutPoints, nInputs); 880ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (nTotalPoints == 0) return FALSE; 881ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 882ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov for (i = 0; i < nTotalPoints; i++) { 883ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 884ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov rest = i; 885ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov for (t = nInputs-1; t >=0; --t) { 886ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 887ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsUInt32Number Colorant = rest % clutPoints[t]; 888ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 889ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov rest /= clutPoints[t]; 890ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov In[t] = _cmsQuantizeVal(Colorant, clutPoints[t]); 891ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 892ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 893ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 894ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (!Sampler(In, NULL, Cargo)) 895ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return FALSE; 896ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 897ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 898ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return TRUE; 899ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} 900ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 901ee451cb395940862dad63c85adfe8f2fd55e864cSvet GanovcmsInt32Number CMSEXPORT cmsSliceSpaceFloat(cmsUInt32Number nInputs, const cmsUInt32Number clutPoints[], 902ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsSAMPLERFLOAT Sampler, void * Cargo) 903ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{ 904ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov int i, t, nTotalPoints, rest; 905ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsFloat32Number In[cmsMAXCHANNELS]; 906ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 907ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (nInputs >= cmsMAXCHANNELS) return FALSE; 908ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 909ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov nTotalPoints = CubeSize(clutPoints, nInputs); 910ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (nTotalPoints == 0) return FALSE; 911ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 912ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov for (i = 0; i < nTotalPoints; i++) { 913ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 914ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov rest = i; 915ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov for (t = nInputs-1; t >=0; --t) { 916ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 917ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsUInt32Number Colorant = rest % clutPoints[t]; 918ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 919ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov rest /= clutPoints[t]; 920ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov In[t] = (cmsFloat32Number) (_cmsQuantizeVal(Colorant, clutPoints[t]) / 65535.0); 921ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 922ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 923ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 924ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (!Sampler(In, NULL, Cargo)) 925ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return FALSE; 926ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 927ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 928ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return TRUE; 929ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} 930ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 931ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// ******************************************************************************** 932ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// Type cmsSigLab2XYZElemType 933ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// ******************************************************************************** 934ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 935ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 936ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovstatic 937ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovvoid EvaluateLab2XYZ(const cmsFloat32Number In[], 938ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsFloat32Number Out[], 939ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov const cmsStage *mpe) 940ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{ 941ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsCIELab Lab; 942ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsCIEXYZ XYZ; 943ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov const cmsFloat64Number XYZadj = MAX_ENCODEABLE_XYZ; 944ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 945ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // V4 rules 946ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Lab.L = In[0] * 100.0; 947ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Lab.a = In[1] * 255.0 - 128.0; 948ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Lab.b = In[2] * 255.0 - 128.0; 949ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 950ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsLab2XYZ(NULL, &XYZ, &Lab); 951ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 952ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // From XYZ, range 0..19997 to 0..1.0, note that 1.99997 comes from 0xffff 953ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // encoded as 1.15 fixed point, so 1 + (32767.0 / 32768.0) 954ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 955ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Out[0] = (cmsFloat32Number) ((cmsFloat64Number) XYZ.X / XYZadj); 956ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Out[1] = (cmsFloat32Number) ((cmsFloat64Number) XYZ.Y / XYZadj); 957ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Out[2] = (cmsFloat32Number) ((cmsFloat64Number) XYZ.Z / XYZadj); 958ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return; 959ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 960ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsUNUSED_PARAMETER(mpe); 961ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} 962ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 963ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 964ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// No dup or free routines needed, as the structure has no pointers in it. 965ee451cb395940862dad63c85adfe8f2fd55e864cSvet GanovcmsStage* _cmsStageAllocLab2XYZ(cmsContext ContextID) 966ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{ 967ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return _cmsStageAllocPlaceholder(ContextID, cmsSigLab2XYZElemType, 3, 3, EvaluateLab2XYZ, NULL, NULL, NULL); 968ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} 969ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 970ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// ******************************************************************************** 971ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 972ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// v2 L=100 is supposed to be placed on 0xFF00. There is no reasonable 973ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// number of gridpoints that would make exact match. However, a prelinearization 974ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// of 258 entries, would map 0xFF00 exactly on entry 257, and this is good to avoid scum dot. 975ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// Almost all what we need but unfortunately, the rest of entries should be scaled by 976ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// (255*257/256) and this is not exact. 977ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 978ee451cb395940862dad63c85adfe8f2fd55e864cSvet GanovcmsStage* _cmsStageAllocLabV2ToV4curves(cmsContext ContextID) 979ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{ 980ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsStage* mpe; 981ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsToneCurve* LabTable[3]; 982ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov int i, j; 983ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 984ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov LabTable[0] = cmsBuildTabulatedToneCurve16(ContextID, 258, NULL); 985ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov LabTable[1] = cmsBuildTabulatedToneCurve16(ContextID, 258, NULL); 986ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov LabTable[2] = cmsBuildTabulatedToneCurve16(ContextID, 258, NULL); 987ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 988ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov for (j=0; j < 3; j++) { 989ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 990ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (LabTable[j] == NULL) { 991ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsFreeToneCurveTriple(LabTable); 992ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return NULL; 993ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 994ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 995ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // We need to map * (0xffff / 0xff00), thats same as (257 / 256) 996ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // So we can use 258-entry tables to do the trick (i / 257) * (255 * 257) * (257 / 256); 997ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov for (i=0; i < 257; i++) { 998ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 999ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov LabTable[j]->Table16[i] = (cmsUInt16Number) ((i * 0xffff + 0x80) >> 8); 1000ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1001ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1002ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov LabTable[j] ->Table16[257] = 0xffff; 1003ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1004ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1005ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov mpe = cmsStageAllocToneCurves(ContextID, 3, LabTable); 1006ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsFreeToneCurveTriple(LabTable); 1007ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1008ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (mpe == NULL) return NULL; 1009ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov mpe ->Implements = cmsSigLabV2toV4; 1010ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return mpe; 1011ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} 1012ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1013ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// ******************************************************************************** 1014ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1015ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// Matrix-based conversion, which is more accurate, but slower and cannot properly be saved in devicelink profiles 1016ee451cb395940862dad63c85adfe8f2fd55e864cSvet GanovcmsStage* _cmsStageAllocLabV2ToV4(cmsContext ContextID) 1017ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{ 1018ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov static const cmsFloat64Number V2ToV4[] = { 65535.0/65280.0, 0, 0, 1019ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 0, 65535.0/65280.0, 0, 1020ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 0, 0, 65535.0/65280.0 1021ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov }; 1022ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1023ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsStage *mpe = cmsStageAllocMatrix(ContextID, 3, 3, V2ToV4, NULL); 1024ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1025ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (mpe == NULL) return mpe; 1026ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov mpe ->Implements = cmsSigLabV2toV4; 1027ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return mpe; 1028ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} 1029ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1030ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1031ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// Reverse direction 1032ee451cb395940862dad63c85adfe8f2fd55e864cSvet GanovcmsStage* _cmsStageAllocLabV4ToV2(cmsContext ContextID) 1033ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{ 1034ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov static const cmsFloat64Number V4ToV2[] = { 65280.0/65535.0, 0, 0, 1035ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 0, 65280.0/65535.0, 0, 1036ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 0, 0, 65280.0/65535.0 1037ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov }; 1038ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1039ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsStage *mpe = cmsStageAllocMatrix(ContextID, 3, 3, V4ToV2, NULL); 1040ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1041ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (mpe == NULL) return mpe; 1042ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov mpe ->Implements = cmsSigLabV4toV2; 1043ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return mpe; 1044ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} 1045ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1046ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1047ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// To Lab to float. Note that the MPE gives numbers in normal Lab range 1048ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// and we need 0..1.0 range for the formatters 1049ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// L* : 0...100 => 0...1.0 (L* / 100) 1050ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// ab* : -128..+127 to 0..1 ((ab* + 128) / 255) 1051ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1052ee451cb395940862dad63c85adfe8f2fd55e864cSvet GanovcmsStage* _cmsStageNormalizeFromLabFloat(cmsContext ContextID) 1053ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{ 1054ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov static const cmsFloat64Number a1[] = { 1055ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1.0/100.0, 0, 0, 1056ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 0, 1.0/255.0, 0, 1057ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 0, 0, 1.0/255.0 1058ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov }; 1059ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1060ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov static const cmsFloat64Number o1[] = { 1061ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 0, 1062ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 128.0/255.0, 1063ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 128.0/255.0 1064ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov }; 1065ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1066ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsStage *mpe = cmsStageAllocMatrix(ContextID, 3, 3, a1, o1); 1067ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1068ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (mpe == NULL) return mpe; 1069ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov mpe ->Implements = cmsSigLab2FloatPCS; 1070ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return mpe; 1071ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} 1072ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1073ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// Fom XYZ to floating point PCS 1074ee451cb395940862dad63c85adfe8f2fd55e864cSvet GanovcmsStage* _cmsStageNormalizeFromXyzFloat(cmsContext ContextID) 1075ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{ 1076ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#define n (32768.0/65535.0) 1077ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov static const cmsFloat64Number a1[] = { 1078ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov n, 0, 0, 1079ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 0, n, 0, 1080ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 0, 0, n 1081ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov }; 1082ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#undef n 1083ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1084ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsStage *mpe = cmsStageAllocMatrix(ContextID, 3, 3, a1, NULL); 1085ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1086ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (mpe == NULL) return mpe; 1087ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov mpe ->Implements = cmsSigXYZ2FloatPCS; 1088ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return mpe; 1089ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} 1090ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1091ee451cb395940862dad63c85adfe8f2fd55e864cSvet GanovcmsStage* _cmsStageNormalizeToLabFloat(cmsContext ContextID) 1092ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{ 1093ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov static const cmsFloat64Number a1[] = { 1094ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 100.0, 0, 0, 1095ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 0, 255.0, 0, 1096ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 0, 0, 255.0 1097ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov }; 1098ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1099ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov static const cmsFloat64Number o1[] = { 1100ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 0, 1101ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov -128.0, 1102ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov -128.0 1103ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov }; 1104ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1105ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsStage *mpe = cmsStageAllocMatrix(ContextID, 3, 3, a1, o1); 1106ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (mpe == NULL) return mpe; 1107ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov mpe ->Implements = cmsSigFloatPCS2Lab; 1108ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return mpe; 1109ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} 1110ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1111ee451cb395940862dad63c85adfe8f2fd55e864cSvet GanovcmsStage* _cmsStageNormalizeToXyzFloat(cmsContext ContextID) 1112ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{ 1113ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#define n (65535.0/32768.0) 1114ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1115ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov static const cmsFloat64Number a1[] = { 1116ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov n, 0, 0, 1117ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 0, n, 0, 1118ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 0, 0, n 1119ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov }; 1120ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#undef n 1121ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1122ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsStage *mpe = cmsStageAllocMatrix(ContextID, 3, 3, a1, NULL); 1123ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (mpe == NULL) return mpe; 1124ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov mpe ->Implements = cmsSigFloatPCS2XYZ; 1125ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return mpe; 1126ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} 1127ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1128ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1129ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1130ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// ******************************************************************************** 1131ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// Type cmsSigXYZ2LabElemType 1132ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// ******************************************************************************** 1133ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1134ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovstatic 1135ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovvoid EvaluateXYZ2Lab(const cmsFloat32Number In[], cmsFloat32Number Out[], const cmsStage *mpe) 1136ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{ 1137ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsCIELab Lab; 1138ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsCIEXYZ XYZ; 1139ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov const cmsFloat64Number XYZadj = MAX_ENCODEABLE_XYZ; 1140ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1141ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // From 0..1.0 to XYZ 1142ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1143ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov XYZ.X = In[0] * XYZadj; 1144ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov XYZ.Y = In[1] * XYZadj; 1145ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov XYZ.Z = In[2] * XYZadj; 1146ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1147ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsXYZ2Lab(NULL, &Lab, &XYZ); 1148ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1149ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // From V4 Lab to 0..1.0 1150ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1151ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Out[0] = (cmsFloat32Number) (Lab.L / 100.0); 1152ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Out[1] = (cmsFloat32Number) ((Lab.a + 128.0) / 255.0); 1153ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Out[2] = (cmsFloat32Number) ((Lab.b + 128.0) / 255.0); 1154ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return; 1155ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1156ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsUNUSED_PARAMETER(mpe); 1157ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} 1158ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1159ee451cb395940862dad63c85adfe8f2fd55e864cSvet GanovcmsStage* _cmsStageAllocXYZ2Lab(cmsContext ContextID) 1160ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{ 1161ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return _cmsStageAllocPlaceholder(ContextID, cmsSigXYZ2LabElemType, 3, 3, EvaluateXYZ2Lab, NULL, NULL, NULL); 1162ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1163ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} 1164ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1165ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// ******************************************************************************** 1166ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1167ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// For v4, S-Shaped curves are placed in a/b axis to increase resolution near gray 1168ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1169ee451cb395940862dad63c85adfe8f2fd55e864cSvet GanovcmsStage* _cmsStageAllocLabPrelin(cmsContext ContextID) 1170ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{ 1171ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsToneCurve* LabTable[3]; 1172ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsFloat64Number Params[1] = {2.4} ; 1173ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1174ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov LabTable[0] = cmsBuildGamma(ContextID, 1.0); 1175ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov LabTable[1] = cmsBuildParametricToneCurve(ContextID, 108, Params); 1176ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov LabTable[2] = cmsBuildParametricToneCurve(ContextID, 108, Params); 1177ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1178ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return cmsStageAllocToneCurves(ContextID, 3, LabTable); 1179ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} 1180ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1181ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1182ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// Free a single MPE 1183ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovvoid CMSEXPORT cmsStageFree(cmsStage* mpe) 1184ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{ 1185ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (mpe ->FreePtr) 1186ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov mpe ->FreePtr(mpe); 1187ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1188ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov _cmsFree(mpe ->ContextID, mpe); 1189ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} 1190ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1191ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1192ee451cb395940862dad63c85adfe8f2fd55e864cSvet GanovcmsUInt32Number CMSEXPORT cmsStageInputChannels(const cmsStage* mpe) 1193ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{ 1194ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return mpe ->InputChannels; 1195ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} 1196ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1197ee451cb395940862dad63c85adfe8f2fd55e864cSvet GanovcmsUInt32Number CMSEXPORT cmsStageOutputChannels(const cmsStage* mpe) 1198ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{ 1199ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return mpe ->OutputChannels; 1200ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} 1201ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1202ee451cb395940862dad63c85adfe8f2fd55e864cSvet GanovcmsStageSignature CMSEXPORT cmsStageType(const cmsStage* mpe) 1203ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{ 1204ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return mpe -> Type; 1205ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} 1206ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1207ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovvoid* CMSEXPORT cmsStageData(const cmsStage* mpe) 1208ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{ 1209ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return mpe -> Data; 1210ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} 1211ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1212ee451cb395940862dad63c85adfe8f2fd55e864cSvet GanovcmsStage* CMSEXPORT cmsStageNext(const cmsStage* mpe) 1213ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{ 1214ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return mpe -> Next; 1215ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} 1216ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1217ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1218ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// Duplicates an MPE 1219ee451cb395940862dad63c85adfe8f2fd55e864cSvet GanovcmsStage* CMSEXPORT cmsStageDup(cmsStage* mpe) 1220ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{ 1221ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsStage* NewMPE; 1222ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1223ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (mpe == NULL) return NULL; 1224ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov NewMPE = _cmsStageAllocPlaceholder(mpe ->ContextID, 1225ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov mpe ->Type, 1226ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov mpe ->InputChannels, 1227ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov mpe ->OutputChannels, 1228ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov mpe ->EvalPtr, 1229ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov mpe ->DupElemPtr, 1230ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov mpe ->FreePtr, 1231ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov NULL); 1232ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (NewMPE == NULL) return NULL; 1233ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1234ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov NewMPE ->Implements = mpe ->Implements; 1235ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1236ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (mpe ->DupElemPtr) { 1237ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1238ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov NewMPE ->Data = mpe ->DupElemPtr(mpe); 1239ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1240ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (NewMPE->Data == NULL) { 1241ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1242ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsStageFree(NewMPE); 1243ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return NULL; 1244ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1245ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1246ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } else { 1247ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1248ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov NewMPE ->Data = NULL; 1249ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1250ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1251ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return NewMPE; 1252ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} 1253ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1254ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1255ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// *********************************************************************************************************** 1256ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1257ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// This function sets up the channel count 1258ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1259ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovstatic 1260ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovvoid BlessLUT(cmsPipeline* lut) 1261ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{ 1262ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // We can set the input/ouput channels only if we have elements. 1263ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (lut ->Elements != NULL) { 1264ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1265ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsStage *First, *Last; 1266ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1267ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov First = cmsPipelineGetPtrToFirstStage(lut); 1268ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Last = cmsPipelineGetPtrToLastStage(lut); 1269ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1270ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (First != NULL)lut ->InputChannels = First ->InputChannels; 1271ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (Last != NULL) lut ->OutputChannels = Last ->OutputChannels; 1272ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1273ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} 1274ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1275ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1276ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// Default to evaluate the LUT on 16 bit-basis. Precision is retained. 1277ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovstatic 1278ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovvoid _LUTeval16(register const cmsUInt16Number In[], register cmsUInt16Number Out[], register const void* D) 1279ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{ 1280ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsPipeline* lut = (cmsPipeline*) D; 1281ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsStage *mpe; 1282ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsFloat32Number Storage[2][MAX_STAGE_CHANNELS]; 1283ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov int Phase = 0, NextPhase; 1284ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1285ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov From16ToFloat(In, &Storage[Phase][0], lut ->InputChannels); 1286ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1287ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov for (mpe = lut ->Elements; 1288ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov mpe != NULL; 1289ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov mpe = mpe ->Next) { 1290ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1291ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov NextPhase = Phase ^ 1; 1292ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov mpe ->EvalPtr(&Storage[Phase][0], &Storage[NextPhase][0], mpe); 1293ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Phase = NextPhase; 1294ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1295ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1296ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1297ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FromFloatTo16(&Storage[Phase][0], Out, lut ->OutputChannels); 1298ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} 1299ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1300ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1301ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1302ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// Does evaluate the LUT on cmsFloat32Number-basis. 1303ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovstatic 1304ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovvoid _LUTevalFloat(register const cmsFloat32Number In[], register cmsFloat32Number Out[], const void* D) 1305ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{ 1306ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsPipeline* lut = (cmsPipeline*) D; 1307ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsStage *mpe; 1308ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsFloat32Number Storage[2][MAX_STAGE_CHANNELS]; 1309ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov int Phase = 0, NextPhase; 1310ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1311ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov memmove(&Storage[Phase][0], In, lut ->InputChannels * sizeof(cmsFloat32Number)); 1312ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1313ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov for (mpe = lut ->Elements; 1314ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov mpe != NULL; 1315ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov mpe = mpe ->Next) { 1316ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1317ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov NextPhase = Phase ^ 1; 1318ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov mpe ->EvalPtr(&Storage[Phase][0], &Storage[NextPhase][0], mpe); 1319ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Phase = NextPhase; 1320ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1321ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1322ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov memmove(Out, &Storage[Phase][0], lut ->OutputChannels * sizeof(cmsFloat32Number)); 1323ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} 1324ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1325ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1326ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1327ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1328ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// LUT Creation & Destruction 1329ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1330ee451cb395940862dad63c85adfe8f2fd55e864cSvet GanovcmsPipeline* CMSEXPORT cmsPipelineAlloc(cmsContext ContextID, cmsUInt32Number InputChannels, cmsUInt32Number OutputChannels) 1331ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{ 1332ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsPipeline* NewLUT; 1333ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1334ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (InputChannels >= cmsMAXCHANNELS || 1335ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov OutputChannels >= cmsMAXCHANNELS) return NULL; 1336ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1337ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov NewLUT = (cmsPipeline*) _cmsMallocZero(ContextID, sizeof(cmsPipeline)); 1338ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (NewLUT == NULL) return NULL; 1339ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1340ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1341ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov NewLUT -> InputChannels = InputChannels; 1342ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov NewLUT -> OutputChannels = OutputChannels; 1343ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1344ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov NewLUT ->Eval16Fn = _LUTeval16; 1345ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov NewLUT ->EvalFloatFn = _LUTevalFloat; 1346ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov NewLUT ->DupDataFn = NULL; 1347ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov NewLUT ->FreeDataFn = NULL; 1348ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov NewLUT ->Data = NewLUT; 1349ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov NewLUT ->ContextID = ContextID; 1350ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1351ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov BlessLUT(NewLUT); 1352ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1353ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return NewLUT; 1354ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} 1355ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1356ee451cb395940862dad63c85adfe8f2fd55e864cSvet GanovcmsContext CMSEXPORT cmsGetPipelineContextID(const cmsPipeline* lut) 1357ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{ 1358ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov _cmsAssert(lut != NULL); 1359ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return lut ->ContextID; 1360ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} 1361ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1362ee451cb395940862dad63c85adfe8f2fd55e864cSvet GanovcmsUInt32Number CMSEXPORT cmsPipelineInputChannels(const cmsPipeline* lut) 1363ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{ 1364ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov _cmsAssert(lut != NULL); 1365ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return lut ->InputChannels; 1366ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} 1367ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1368ee451cb395940862dad63c85adfe8f2fd55e864cSvet GanovcmsUInt32Number CMSEXPORT cmsPipelineOutputChannels(const cmsPipeline* lut) 1369ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{ 1370ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov _cmsAssert(lut != NULL); 1371ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return lut ->OutputChannels; 1372ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} 1373ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1374ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// Free a profile elements LUT 1375ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovvoid CMSEXPORT cmsPipelineFree(cmsPipeline* lut) 1376ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{ 1377ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsStage *mpe, *Next; 1378ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1379ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (lut == NULL) return; 1380ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1381ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov for (mpe = lut ->Elements; 1382ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov mpe != NULL; 1383ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov mpe = Next) { 1384ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1385ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Next = mpe ->Next; 1386ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsStageFree(mpe); 1387ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1388ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1389ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (lut ->FreeDataFn) lut ->FreeDataFn(lut ->ContextID, lut ->Data); 1390ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1391ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov _cmsFree(lut ->ContextID, lut); 1392ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} 1393ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1394ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1395ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// Default to evaluate the LUT on 16 bit-basis. 1396ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovvoid CMSEXPORT cmsPipelineEval16(const cmsUInt16Number In[], cmsUInt16Number Out[], const cmsPipeline* lut) 1397ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{ 1398ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov _cmsAssert(lut != NULL); 1399ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov lut ->Eval16Fn(In, Out, lut->Data); 1400ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} 1401ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1402ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1403ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// Does evaluate the LUT on cmsFloat32Number-basis. 1404ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovvoid CMSEXPORT cmsPipelineEvalFloat(const cmsFloat32Number In[], cmsFloat32Number Out[], const cmsPipeline* lut) 1405ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{ 1406ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov _cmsAssert(lut != NULL); 1407ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov lut ->EvalFloatFn(In, Out, lut); 1408ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} 1409ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1410ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1411ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1412ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// Duplicates a LUT 1413ee451cb395940862dad63c85adfe8f2fd55e864cSvet GanovcmsPipeline* CMSEXPORT cmsPipelineDup(const cmsPipeline* lut) 1414ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{ 1415ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsPipeline* NewLUT; 1416ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsStage *NewMPE, *Anterior = NULL, *mpe; 1417ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsBool First = TRUE; 1418ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1419ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (lut == NULL) return NULL; 1420ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1421ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov NewLUT = cmsPipelineAlloc(lut ->ContextID, lut ->InputChannels, lut ->OutputChannels); 1422ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (NewLUT == NULL) return NULL; 1423ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1424ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov for (mpe = lut ->Elements; 1425ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov mpe != NULL; 1426ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov mpe = mpe ->Next) { 1427ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1428ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov NewMPE = cmsStageDup(mpe); 1429ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1430ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (NewMPE == NULL) { 1431ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsPipelineFree(NewLUT); 1432ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return NULL; 1433ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1434ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1435ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (First) { 1436ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov NewLUT ->Elements = NewMPE; 1437ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov First = FALSE; 1438ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1439ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov else { 1440ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Anterior ->Next = NewMPE; 1441ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1442ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1443ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Anterior = NewMPE; 1444ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1445ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1446ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov NewLUT ->Eval16Fn = lut ->Eval16Fn; 1447ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov NewLUT ->EvalFloatFn = lut ->EvalFloatFn; 1448ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov NewLUT ->DupDataFn = lut ->DupDataFn; 1449ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov NewLUT ->FreeDataFn = lut ->FreeDataFn; 1450ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1451ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (NewLUT ->DupDataFn != NULL) 1452ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov NewLUT ->Data = NewLUT ->DupDataFn(lut ->ContextID, lut->Data); 1453ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1454ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1455ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov NewLUT ->SaveAs8Bits = lut ->SaveAs8Bits; 1456ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1457ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov BlessLUT(NewLUT); 1458ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return NewLUT; 1459ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} 1460ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1461ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1462ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovint CMSEXPORT cmsPipelineInsertStage(cmsPipeline* lut, cmsStageLoc loc, cmsStage* mpe) 1463ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{ 1464ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsStage* Anterior = NULL, *pt; 1465ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1466ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (lut == NULL || mpe == NULL) 1467ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return FALSE; 1468ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1469ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov switch (loc) { 1470ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1471ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov case cmsAT_BEGIN: 1472ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov mpe ->Next = lut ->Elements; 1473ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov lut ->Elements = mpe; 1474ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov break; 1475ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1476ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov case cmsAT_END: 1477ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1478ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (lut ->Elements == NULL) 1479ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov lut ->Elements = mpe; 1480ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov else { 1481ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1482ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov for (pt = lut ->Elements; 1483ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov pt != NULL; 1484ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov pt = pt -> Next) Anterior = pt; 1485ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1486ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Anterior ->Next = mpe; 1487ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov mpe ->Next = NULL; 1488ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1489ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov break; 1490ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov default:; 1491ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return FALSE; 1492ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1493ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1494ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov BlessLUT(lut); 1495ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return TRUE; 1496ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} 1497ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1498ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// Unlink an element and return the pointer to it 1499ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovvoid CMSEXPORT cmsPipelineUnlinkStage(cmsPipeline* lut, cmsStageLoc loc, cmsStage** mpe) 1500ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{ 1501ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsStage *Anterior, *pt, *Last; 1502ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsStage *Unlinked = NULL; 1503ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1504ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1505ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // If empty LUT, there is nothing to remove 1506ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (lut ->Elements == NULL) { 1507ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (mpe) *mpe = NULL; 1508ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return; 1509ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1510ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1511ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // On depending on the strategy... 1512ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov switch (loc) { 1513ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1514ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov case cmsAT_BEGIN: 1515ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 1516ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsStage* elem = lut ->Elements; 1517ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1518ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov lut ->Elements = elem -> Next; 1519ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov elem ->Next = NULL; 1520ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Unlinked = elem; 1521ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1522ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1523ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov break; 1524ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1525ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov case cmsAT_END: 1526ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Anterior = Last = NULL; 1527ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov for (pt = lut ->Elements; 1528ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov pt != NULL; 1529ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov pt = pt -> Next) { 1530ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Anterior = Last; 1531ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Last = pt; 1532ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1533ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1534ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Unlinked = Last; // Next already points to NULL 1535ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1536ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Truncate the chain 1537ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (Anterior) 1538ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Anterior ->Next = NULL; 1539ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov else 1540ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov lut ->Elements = NULL; 1541ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov break; 1542ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov default:; 1543ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1544ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1545ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (mpe) 1546ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov *mpe = Unlinked; 1547ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov else 1548ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsStageFree(Unlinked); 1549ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1550ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov BlessLUT(lut); 1551ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} 1552ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1553ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1554ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// Concatenate two LUT into a new single one 1555ee451cb395940862dad63c85adfe8f2fd55e864cSvet GanovcmsBool CMSEXPORT cmsPipelineCat(cmsPipeline* l1, const cmsPipeline* l2) 1556ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{ 1557ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsStage* mpe; 1558ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1559ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // If both LUTS does not have elements, we need to inherit 1560ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // the number of channels 1561ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (l1 ->Elements == NULL && l2 ->Elements == NULL) { 1562ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov l1 ->InputChannels = l2 ->InputChannels; 1563ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov l1 ->OutputChannels = l2 ->OutputChannels; 1564ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1565ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1566ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Cat second 1567ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov for (mpe = l2 ->Elements; 1568ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov mpe != NULL; 1569ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov mpe = mpe ->Next) { 1570ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1571ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // We have to dup each element 1572ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (!cmsPipelineInsertStage(l1, cmsAT_END, cmsStageDup(mpe))) 1573ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return FALSE; 1574ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1575ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1576ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov BlessLUT(l1); 1577ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return TRUE; 1578ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} 1579ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1580ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1581ee451cb395940862dad63c85adfe8f2fd55e864cSvet GanovcmsBool CMSEXPORT cmsPipelineSetSaveAs8bitsFlag(cmsPipeline* lut, cmsBool On) 1582ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{ 1583ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsBool Anterior = lut ->SaveAs8Bits; 1584ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1585ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov lut ->SaveAs8Bits = On; 1586ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return Anterior; 1587ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} 1588ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1589ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1590ee451cb395940862dad63c85adfe8f2fd55e864cSvet GanovcmsStage* CMSEXPORT cmsPipelineGetPtrToFirstStage(const cmsPipeline* lut) 1591ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{ 1592ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return lut ->Elements; 1593ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} 1594ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1595ee451cb395940862dad63c85adfe8f2fd55e864cSvet GanovcmsStage* CMSEXPORT cmsPipelineGetPtrToLastStage(const cmsPipeline* lut) 1596ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{ 1597ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsStage *mpe, *Anterior = NULL; 1598ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1599ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov for (mpe = lut ->Elements; mpe != NULL; mpe = mpe ->Next) 1600ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Anterior = mpe; 1601ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1602ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return Anterior; 1603ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} 1604ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1605ee451cb395940862dad63c85adfe8f2fd55e864cSvet GanovcmsUInt32Number CMSEXPORT cmsPipelineStageCount(const cmsPipeline* lut) 1606ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{ 1607ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsStage *mpe; 1608ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsUInt32Number n; 1609ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1610ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov for (n=0, mpe = lut ->Elements; mpe != NULL; mpe = mpe ->Next) 1611ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov n++; 1612ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1613ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return n; 1614ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} 1615ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1616ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// This function may be used to set the optional evaluator and a block of private data. If private data is being used, an optional 1617ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// duplicator and free functions should also be specified in order to duplicate the LUT construct. Use NULL to inhibit such functionality. 1618ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovvoid CMSEXPORT _cmsPipelineSetOptimizationParameters(cmsPipeline* Lut, 1619ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov _cmsOPTeval16Fn Eval16, 1620ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov void* PrivateData, 1621ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov _cmsFreeUserDataFn FreePrivateDataFn, 1622ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov _cmsDupUserDataFn DupPrivateDataFn) 1623ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{ 1624ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1625ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Lut ->Eval16Fn = Eval16; 1626ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Lut ->DupDataFn = DupPrivateDataFn; 1627ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Lut ->FreeDataFn = FreePrivateDataFn; 1628ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Lut ->Data = PrivateData; 1629ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} 1630ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1631ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1632ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// ----------------------------------------------------------- Reverse interpolation 1633ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// Here's how it goes. The derivative Df(x) of the function f is the linear 1634ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// transformation that best approximates f near the point x. It can be represented 1635ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// by a matrix A whose entries are the partial derivatives of the components of f 1636ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// with respect to all the coordinates. This is know as the Jacobian 1637ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// 1638ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// The best linear approximation to f is given by the matrix equation: 1639ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// 1640ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// y-y0 = A (x-x0) 1641ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// 1642ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// So, if x0 is a good "guess" for the zero of f, then solving for the zero of this 1643ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// linear approximation will give a "better guess" for the zero of f. Thus let y=0, 1644ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// and since y0=f(x0) one can solve the above equation for x. This leads to the 1645ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// Newton's method formula: 1646ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// 1647ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// xn+1 = xn - A-1 f(xn) 1648ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// 1649ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// where xn+1 denotes the (n+1)-st guess, obtained from the n-th guess xn in the 1650ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// fashion described above. Iterating this will give better and better approximations 1651ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// if you have a "good enough" initial guess. 1652ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1653ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1654ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#define JACOBIAN_EPSILON 0.001f 1655ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#define INVERSION_MAX_ITERATIONS 30 1656ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1657ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// Increment with reflexion on boundary 1658ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovstatic 1659ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovvoid IncDelta(cmsFloat32Number *Val) 1660ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{ 1661ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (*Val < (1.0 - JACOBIAN_EPSILON)) 1662ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1663ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov *Val += JACOBIAN_EPSILON; 1664ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1665ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov else 1666ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov *Val -= JACOBIAN_EPSILON; 1667ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1668ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} 1669ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1670ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1671ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1672ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// Euclidean distance between two vectors of n elements each one 1673ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovstatic 1674ee451cb395940862dad63c85adfe8f2fd55e864cSvet GanovcmsFloat32Number EuclideanDistance(cmsFloat32Number a[], cmsFloat32Number b[], int n) 1675ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{ 1676ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsFloat32Number sum = 0; 1677ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov int i; 1678ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1679ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov for (i=0; i < n; i++) { 1680ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsFloat32Number dif = b[i] - a[i]; 1681ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov sum += dif * dif; 1682ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1683ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1684ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return sqrtf(sum); 1685ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} 1686ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1687ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1688ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// Evaluate a LUT in reverse direction. It only searches on 3->3 LUT. Uses Newton method 1689ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// 1690ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// x1 <- x - [J(x)]^-1 * f(x) 1691ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// 1692ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// lut: The LUT on where to do the search 1693ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// Target: LabK, 3 values of Lab plus destination K which is fixed 1694ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// Result: The obtained CMYK 1695ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// Hint: Location where begin the search 1696ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1697ee451cb395940862dad63c85adfe8f2fd55e864cSvet GanovcmsBool CMSEXPORT cmsPipelineEvalReverseFloat(cmsFloat32Number Target[], 1698ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsFloat32Number Result[], 1699ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsFloat32Number Hint[], 1700ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov const cmsPipeline* lut) 1701ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{ 1702ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsUInt32Number i, j; 1703ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsFloat64Number error, LastError = 1E20; 1704ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsFloat32Number fx[4], x[4], xd[4], fxd[4]; 1705ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsVEC3 tmp, tmp2; 1706ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsMAT3 Jacobian; 1707ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1708ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Only 3->3 and 4->3 are supported 1709ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (lut ->InputChannels != 3 && lut ->InputChannels != 4) return FALSE; 1710ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (lut ->OutputChannels != 3) return FALSE; 1711ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1712ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Take the hint as starting point if specified 1713ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (Hint == NULL) { 1714ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1715ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Begin at any point, we choose 1/3 of CMY axis 1716ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov x[0] = x[1] = x[2] = 0.3f; 1717ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1718ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov else { 1719ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1720ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Only copy 3 channels from hint... 1721ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov for (j=0; j < 3; j++) 1722ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov x[j] = Hint[j]; 1723ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1724ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1725ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // If Lut is 4-dimensions, then grab target[3], which is fixed 1726ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (lut ->InputChannels == 4) { 1727ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov x[3] = Target[3]; 1728ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1729ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov else x[3] = 0; // To keep lint happy 1730ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1731ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1732ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Iterate 1733ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov for (i = 0; i < INVERSION_MAX_ITERATIONS; i++) { 1734ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1735ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Get beginning fx 1736ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsPipelineEvalFloat(x, fx, lut); 1737ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1738ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Compute error 1739ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov error = EuclideanDistance(fx, Target, 3); 1740ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1741ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // If not convergent, return last safe value 1742ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (error >= LastError) 1743ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov break; 1744ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1745ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Keep latest values 1746ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov LastError = error; 1747ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov for (j=0; j < lut ->InputChannels; j++) 1748ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Result[j] = x[j]; 1749ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1750ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Found an exact match? 1751ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (error <= 0) 1752ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov break; 1753ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1754ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Obtain slope (the Jacobian) 1755ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov for (j = 0; j < 3; j++) { 1756ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1757ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov xd[0] = x[0]; 1758ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov xd[1] = x[1]; 1759ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov xd[2] = x[2]; 1760ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov xd[3] = x[3]; // Keep fixed channel 1761ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1762ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov IncDelta(&xd[j]); 1763ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1764ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsPipelineEvalFloat(xd, fxd, lut); 1765ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1766ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Jacobian.v[0].n[j] = ((fxd[0] - fx[0]) / JACOBIAN_EPSILON); 1767ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Jacobian.v[1].n[j] = ((fxd[1] - fx[1]) / JACOBIAN_EPSILON); 1768ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Jacobian.v[2].n[j] = ((fxd[2] - fx[2]) / JACOBIAN_EPSILON); 1769ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1770ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1771ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Solve system 1772ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov tmp2.n[0] = fx[0] - Target[0]; 1773ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov tmp2.n[1] = fx[1] - Target[1]; 1774ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov tmp2.n[2] = fx[2] - Target[2]; 1775ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1776ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (!_cmsMAT3solve(&tmp, &Jacobian, &tmp2)) 1777ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return FALSE; 1778ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1779ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Move our guess 1780ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov x[0] -= (cmsFloat32Number) tmp.n[0]; 1781ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov x[1] -= (cmsFloat32Number) tmp.n[1]; 1782ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov x[2] -= (cmsFloat32Number) tmp.n[2]; 1783ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1784ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Some clipping.... 1785ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov for (j=0; j < 3; j++) { 1786ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (x[j] < 0) x[j] = 0; 1787ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov else 1788ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (x[j] > 1.0) x[j] = 1.0; 1789ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1790ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1791ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1792ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return TRUE; 1793ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} 1794