1ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov//--------------------------------------------------------------------------------- 2ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// 3ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// Little Color Management System 4ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// Copyright (c) 1998-2011 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//---------------------------------------------------------------------------------- 31ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 32ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// Optimization for 8 bits, Shaper-CLUT (3 inputs only) 33ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovtypedef struct { 34ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 35ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsContext ContextID; 36ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 37ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov const cmsInterpParams* p; // Tetrahedrical interpolation parameters. This is a not-owned pointer. 38ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 39ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsUInt16Number rx[256], ry[256], rz[256]; 40ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsUInt32Number X0[256], Y0[256], Z0[256]; // Precomputed nodes and offsets for 8-bit input data 41ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 42ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 43ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} Prelin8Data; 44ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 45ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 46ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// Generic optimization for 16 bits Shaper-CLUT-Shaper (any inputs) 47ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovtypedef struct { 48ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 49ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsContext ContextID; 50ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 51ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Number of channels 52ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov int nInputs; 53ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov int nOutputs; 54ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 55ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov _cmsInterpFn16 EvalCurveIn16[MAX_INPUT_DIMENSIONS]; // The maximum number of input channels is known in advance 56ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsInterpParams* ParamsCurveIn16[MAX_INPUT_DIMENSIONS]; 57ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 58ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov _cmsInterpFn16 EvalCLUT; // The evaluator for 3D grid 59ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov const cmsInterpParams* CLUTparams; // (not-owned pointer) 60ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 61ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 62ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov _cmsInterpFn16* EvalCurveOut16; // Points to an array of curve evaluators in 16 bits (not-owned pointer) 63ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsInterpParams** ParamsCurveOut16; // Points to an array of references to interpolation params (not-owned pointer) 64ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 65ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 66ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} Prelin16Data; 67ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 68ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 69ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// Optimization for matrix-shaper in 8 bits. Numbers are operated in n.14 signed, tables are stored in 1.14 fixed 70ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 71ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovtypedef cmsInt32Number cmsS1Fixed14Number; // Note that this may hold more than 16 bits! 72ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 73ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#define DOUBLE_TO_1FIXED14(x) ((cmsS1Fixed14Number) floor((x) * 16384.0 + 0.5)) 74ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 75ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovtypedef struct { 76ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 77ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsContext ContextID; 78ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 79ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsS1Fixed14Number Shaper1R[256]; // from 0..255 to 1.14 (0.0...1.0) 80ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsS1Fixed14Number Shaper1G[256]; 81ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsS1Fixed14Number Shaper1B[256]; 82ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 83ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsS1Fixed14Number Mat[3][3]; // n.14 to n.14 (needs a saturation after that) 84ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsS1Fixed14Number Off[3]; 85ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 86ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsUInt16Number Shaper2R[16385]; // 1.14 to 0..255 87ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsUInt16Number Shaper2G[16385]; 88ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsUInt16Number Shaper2B[16385]; 89ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 90ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} MatShaper8Data; 91ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 92ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// Curves, optimization is shared between 8 and 16 bits 93ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovtypedef struct { 94ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 95ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsContext ContextID; 96ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 97ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov int nCurves; // Number of curves 98ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov int nElements; // Elements in curves 99ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsUInt16Number** Curves; // Points to a dynamically allocated array 100ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 101ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} Curves16Data; 102ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 103ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 104ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// Simple optimizations ---------------------------------------------------------------------------------------------------------- 105ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 106ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 107ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// Remove an element in linked chain 108ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovstatic 109ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovvoid _RemoveElement(cmsStage** head) 110ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{ 111ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsStage* mpe = *head; 112ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsStage* next = mpe ->Next; 113ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov *head = next; 114ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsStageFree(mpe); 115ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} 116ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 117ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// Remove all identities in chain. Note that pt actually is a double pointer to the element that holds the pointer. 118ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovstatic 119ee451cb395940862dad63c85adfe8f2fd55e864cSvet GanovcmsBool _Remove1Op(cmsPipeline* Lut, cmsStageSignature UnaryOp) 120ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{ 121ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsStage** pt = &Lut ->Elements; 122ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsBool AnyOpt = FALSE; 123ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 124ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov while (*pt != NULL) { 125ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 126ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ((*pt) ->Implements == UnaryOp) { 127ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov _RemoveElement(pt); 128ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov AnyOpt = TRUE; 129ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 130ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov else 131ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov pt = &((*pt) -> Next); 132ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 133ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 134ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return AnyOpt; 135ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} 136ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 137ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// Same, but only if two adjacent elements are found 138ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovstatic 139ee451cb395940862dad63c85adfe8f2fd55e864cSvet GanovcmsBool _Remove2Op(cmsPipeline* Lut, cmsStageSignature Op1, cmsStageSignature Op2) 140ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{ 141ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsStage** pt1; 142ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsStage** pt2; 143ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsBool AnyOpt = FALSE; 144ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 145ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov pt1 = &Lut ->Elements; 146ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (*pt1 == NULL) return AnyOpt; 147ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 148ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov while (*pt1 != NULL) { 149ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 150ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov pt2 = &((*pt1) -> Next); 151ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (*pt2 == NULL) return AnyOpt; 152ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 153ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ((*pt1) ->Implements == Op1 && (*pt2) ->Implements == Op2) { 154ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov _RemoveElement(pt2); 155ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov _RemoveElement(pt1); 156ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov AnyOpt = TRUE; 157ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 158ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov else 159ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov pt1 = &((*pt1) -> Next); 160ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 161ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 162ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return AnyOpt; 163ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} 164ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 165ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// Preoptimize just gets rif of no-ops coming paired. Conversion from v2 to v4 followed 166ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// by a v4 to v2 and vice-versa. The elements are then discarded. 167ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovstatic 168ee451cb395940862dad63c85adfe8f2fd55e864cSvet GanovcmsBool PreOptimize(cmsPipeline* Lut) 169ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{ 170ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsBool AnyOpt = FALSE, Opt; 171ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 172ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov do { 173ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 174ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Opt = FALSE; 175ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 176ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Remove all identities 177ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Opt |= _Remove1Op(Lut, cmsSigIdentityElemType); 178ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 179ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Remove XYZ2Lab followed by Lab2XYZ 180ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Opt |= _Remove2Op(Lut, cmsSigXYZ2LabElemType, cmsSigLab2XYZElemType); 181ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 182ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Remove Lab2XYZ followed by XYZ2Lab 183ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Opt |= _Remove2Op(Lut, cmsSigLab2XYZElemType, cmsSigXYZ2LabElemType); 184ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 185ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Remove V4 to V2 followed by V2 to V4 186ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Opt |= _Remove2Op(Lut, cmsSigLabV4toV2, cmsSigLabV2toV4); 187ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 188ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Remove V2 to V4 followed by V4 to V2 189ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Opt |= _Remove2Op(Lut, cmsSigLabV2toV4, cmsSigLabV4toV2); 190ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 191ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Remove float pcs Lab conversions 192ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Opt |= _Remove2Op(Lut, cmsSigLab2FloatPCS, cmsSigFloatPCS2Lab); 193ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 194ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Remove float pcs Lab conversions 195ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Opt |= _Remove2Op(Lut, cmsSigXYZ2FloatPCS, cmsSigFloatPCS2XYZ); 196ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 197ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (Opt) AnyOpt = TRUE; 198ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 199ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } while (Opt); 200ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 201ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return AnyOpt; 202ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} 203ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 204ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovstatic 205ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovvoid Eval16nop1D(register const cmsUInt16Number Input[], 206ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov register cmsUInt16Number Output[], 207ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov register const struct _cms_interp_struc* p) 208ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{ 209ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Output[0] = Input[0]; 210ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 211ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsUNUSED_PARAMETER(p); 212ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} 213ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 214ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovstatic 215ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovvoid PrelinEval16(register const cmsUInt16Number Input[], 216ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov register cmsUInt16Number Output[], 217ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov register const void* D) 218ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{ 219ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Prelin16Data* p16 = (Prelin16Data*) D; 220ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsUInt16Number StageABC[MAX_INPUT_DIMENSIONS]; 221ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsUInt16Number StageDEF[cmsMAXCHANNELS]; 222ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov int i; 223ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 224ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov for (i=0; i < p16 ->nInputs; i++) { 225ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 226ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov p16 ->EvalCurveIn16[i](&Input[i], &StageABC[i], p16 ->ParamsCurveIn16[i]); 227ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 228ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 229ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov p16 ->EvalCLUT(StageABC, StageDEF, p16 ->CLUTparams); 230ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 231ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov for (i=0; i < p16 ->nOutputs; i++) { 232ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 233ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov p16 ->EvalCurveOut16[i](&StageDEF[i], &Output[i], p16 ->ParamsCurveOut16[i]); 234ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 235ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} 236ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 237ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 238ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovstatic 239ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovvoid PrelinOpt16free(cmsContext ContextID, void* ptr) 240ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{ 241ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Prelin16Data* p16 = (Prelin16Data*) ptr; 242ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 243ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov _cmsFree(ContextID, p16 ->EvalCurveOut16); 244ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov _cmsFree(ContextID, p16 ->ParamsCurveOut16); 245ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 246ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov _cmsFree(ContextID, p16); 247ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} 248ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 249ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovstatic 250ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovvoid* Prelin16dup(cmsContext ContextID, const void* ptr) 251ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{ 252ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Prelin16Data* p16 = (Prelin16Data*) ptr; 253ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Prelin16Data* Duped = _cmsDupMem(ContextID, p16, sizeof(Prelin16Data)); 254ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 255ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (Duped == NULL) return NULL; 256ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 257ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Duped ->EvalCurveOut16 = (_cmsInterpFn16*)_cmsDupMem(ContextID, p16 ->EvalCurveOut16, p16 ->nOutputs * sizeof(_cmsInterpFn16)); 258ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Duped ->ParamsCurveOut16 = (cmsInterpParams**)_cmsDupMem(ContextID, p16 ->ParamsCurveOut16, p16 ->nOutputs * sizeof(cmsInterpParams* )); 259ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 260ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return Duped; 261ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} 262ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 263ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 264ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovstatic 265ee451cb395940862dad63c85adfe8f2fd55e864cSvet GanovPrelin16Data* PrelinOpt16alloc(cmsContext ContextID, 266ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov const cmsInterpParams* ColorMap, 267ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov int nInputs, cmsToneCurve** In, 268ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov int nOutputs, cmsToneCurve** Out ) 269ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{ 270ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov int i; 271ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Prelin16Data* p16 = _cmsMallocZero(ContextID, sizeof(Prelin16Data)); 272ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (p16 == NULL) return NULL; 273ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 274ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov p16 ->nInputs = nInputs; 275ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov p16 -> nOutputs = nOutputs; 276ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 277ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 278ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov for (i=0; i < nInputs; i++) { 279ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 280ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (In == NULL) { 281ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov p16 -> ParamsCurveIn16[i] = NULL; 282ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov p16 -> EvalCurveIn16[i] = Eval16nop1D; 283ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 284ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 285ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov else { 286ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov p16 -> ParamsCurveIn16[i] = In[i] ->InterpParams; 287ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov p16 -> EvalCurveIn16[i] = p16 ->ParamsCurveIn16[i]->Interpolation.Lerp16; 288ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 289ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 290ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 291ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov p16 ->CLUTparams = ColorMap; 292ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov p16 ->EvalCLUT = ColorMap ->Interpolation.Lerp16; 293ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 294ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 295ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov p16 -> EvalCurveOut16 = (_cmsInterpFn16*) _cmsCalloc(ContextID, nOutputs, sizeof(_cmsInterpFn16)); 296ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov p16 -> ParamsCurveOut16 = (cmsInterpParams**) _cmsCalloc(ContextID, nOutputs, sizeof(cmsInterpParams* )); 297ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 298ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov for (i=0; i < nOutputs; i++) { 299ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 300ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (Out == NULL) { 301ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov p16 ->ParamsCurveOut16[i] = NULL; 302ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov p16 -> EvalCurveOut16[i] = Eval16nop1D; 303ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 304ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov else { 305ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 306ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov p16 ->ParamsCurveOut16[i] = Out[i] ->InterpParams; 307ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov p16 -> EvalCurveOut16[i] = p16 ->ParamsCurveOut16[i]->Interpolation.Lerp16; 308ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 309ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 310ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 311ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return p16; 312ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} 313ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 314ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 315ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 316ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// Resampling --------------------------------------------------------------------------------- 317ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 318ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#define PRELINEARIZATION_POINTS 4096 319ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 320ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// Sampler implemented by another LUT. This is a clean way to precalculate the devicelink 3D CLUT for 321ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// almost any transform. We use floating point precision and then convert from floating point to 16 bits. 322ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovstatic 323ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovint XFormSampler16(register const cmsUInt16Number In[], register cmsUInt16Number Out[], register void* Cargo) 324ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{ 325ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsPipeline* Lut = (cmsPipeline*) Cargo; 326ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsFloat32Number InFloat[cmsMAXCHANNELS], OutFloat[cmsMAXCHANNELS]; 327ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsUInt32Number i; 328ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 329ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov _cmsAssert(Lut -> InputChannels < cmsMAXCHANNELS); 330ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov _cmsAssert(Lut -> OutputChannels < cmsMAXCHANNELS); 331ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 332ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // From 16 bit to floating point 333ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov for (i=0; i < Lut ->InputChannels; i++) 334ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov InFloat[i] = (cmsFloat32Number) (In[i] / 65535.0); 335ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 336ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Evaluate in floating point 337ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsPipelineEvalFloat(InFloat, OutFloat, Lut); 338ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 339ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Back to 16 bits representation 340ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov for (i=0; i < Lut ->OutputChannels; i++) 341ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Out[i] = _cmsQuickSaturateWord(OutFloat[i] * 65535.0); 342ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 343ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Always succeed 344ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return TRUE; 345ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} 346ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 347ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// Try to see if the curves of a given MPE are linear 348ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovstatic 349ee451cb395940862dad63c85adfe8f2fd55e864cSvet GanovcmsBool AllCurvesAreLinear(cmsStage* mpe) 350ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{ 351ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsToneCurve** Curves; 352ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsUInt32Number i, n; 353ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 354ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Curves = _cmsStageGetPtrToCurveSet(mpe); 355ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (Curves == NULL) return FALSE; 356ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 357ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov n = cmsStageOutputChannels(mpe); 358ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 359ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov for (i=0; i < n; i++) { 360ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (!cmsIsToneCurveLinear(Curves[i])) return FALSE; 361ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 362ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 363ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return TRUE; 364ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} 365ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 366ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// This function replaces a specific node placed in "At" by the "Value" numbers. Its purpose 367ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// is to fix scum dot on broken profiles/transforms. Works on 1, 3 and 4 channels 368ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovstatic 369ee451cb395940862dad63c85adfe8f2fd55e864cSvet GanovcmsBool PatchLUT(cmsStage* CLUT, cmsUInt16Number At[], cmsUInt16Number Value[], 370ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov int nChannelsOut, int nChannelsIn) 371ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{ 372ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov _cmsStageCLutData* Grid = (_cmsStageCLutData*) CLUT ->Data; 373ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsInterpParams* p16 = Grid ->Params; 374ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsFloat64Number px, py, pz, pw; 375ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov int x0, y0, z0, w0; 376ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov int i, index; 377ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 378ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (CLUT -> Type != cmsSigCLutElemType) { 379ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsSignalError(CLUT->ContextID, cmsERROR_INTERNAL, "(internal) Attempt to PatchLUT on non-lut stage"); 380ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return FALSE; 381ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 382ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 383ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (nChannelsIn != 1 && nChannelsIn != 3 && nChannelsIn != 4) { 384ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsSignalError(CLUT->ContextID, cmsERROR_INTERNAL, "(internal) %d Channels are not supported on PatchLUT", nChannelsIn); 385ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return FALSE; 386ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 387ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (nChannelsIn == 4) { 388ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 389ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov px = ((cmsFloat64Number) At[0] * (p16->Domain[0])) / 65535.0; 390ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov py = ((cmsFloat64Number) At[1] * (p16->Domain[1])) / 65535.0; 391ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov pz = ((cmsFloat64Number) At[2] * (p16->Domain[2])) / 65535.0; 392ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov pw = ((cmsFloat64Number) At[3] * (p16->Domain[3])) / 65535.0; 393ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 394ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov x0 = (int) floor(px); 395ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov y0 = (int) floor(py); 396ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov z0 = (int) floor(pz); 397ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov w0 = (int) floor(pw); 398ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 399ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (((px - x0) != 0) || 400ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov ((py - y0) != 0) || 401ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov ((pz - z0) != 0) || 402ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov ((pw - w0) != 0)) return FALSE; // Not on exact node 403ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 404ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov index = p16 -> opta[3] * x0 + 405ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov p16 -> opta[2] * y0 + 406ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov p16 -> opta[1] * z0 + 407ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov p16 -> opta[0] * w0; 408ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 409ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov else 410ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (nChannelsIn == 3) { 411ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 412ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov px = ((cmsFloat64Number) At[0] * (p16->Domain[0])) / 65535.0; 413ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov py = ((cmsFloat64Number) At[1] * (p16->Domain[1])) / 65535.0; 414ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov pz = ((cmsFloat64Number) At[2] * (p16->Domain[2])) / 65535.0; 415ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 416ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov x0 = (int) floor(px); 417ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov y0 = (int) floor(py); 418ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov z0 = (int) floor(pz); 419ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 420ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (((px - x0) != 0) || 421ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov ((py - y0) != 0) || 422ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov ((pz - z0) != 0)) return FALSE; // Not on exact node 423ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 424ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov index = p16 -> opta[2] * x0 + 425ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov p16 -> opta[1] * y0 + 426ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov p16 -> opta[0] * z0; 427ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 428ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov else 429ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (nChannelsIn == 1) { 430ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 431ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov px = ((cmsFloat64Number) At[0] * (p16->Domain[0])) / 65535.0; 432ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 433ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov x0 = (int) floor(px); 434ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 435ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (((px - x0) != 0)) return FALSE; // Not on exact node 436ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 437ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov index = p16 -> opta[0] * x0; 438ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 439ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov else { 440ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsSignalError(CLUT->ContextID, cmsERROR_INTERNAL, "(internal) %d Channels are not supported on PatchLUT", nChannelsIn); 441ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return FALSE; 442ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 443ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 444ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov for (i=0; i < nChannelsOut; i++) 445ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Grid -> Tab.T[index + i] = Value[i]; 446ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 447ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return TRUE; 448ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} 449ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 450ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// Auxiliar, to see if two values are equal or very different 451ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovstatic 452ee451cb395940862dad63c85adfe8f2fd55e864cSvet GanovcmsBool WhitesAreEqual(int n, cmsUInt16Number White1[], cmsUInt16Number White2[] ) 453ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{ 454ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov int i; 455ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 456ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov for (i=0; i < n; i++) { 457ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 458ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (abs(White1[i] - White2[i]) > 0xf000) return TRUE; // Values are so extremly different that the fixup should be avoided 459ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (White1[i] != White2[i]) return FALSE; 460ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 461ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return TRUE; 462ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} 463ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 464ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 465ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// Locate the node for the white point and fix it to pure white in order to avoid scum dot. 466ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovstatic 467ee451cb395940862dad63c85adfe8f2fd55e864cSvet GanovcmsBool FixWhiteMisalignment(cmsPipeline* Lut, cmsColorSpaceSignature EntryColorSpace, cmsColorSpaceSignature ExitColorSpace) 468ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{ 469ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsUInt16Number *WhitePointIn, *WhitePointOut; 470ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsUInt16Number WhiteIn[cmsMAXCHANNELS], WhiteOut[cmsMAXCHANNELS], ObtainedOut[cmsMAXCHANNELS]; 471ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsUInt32Number i, nOuts, nIns; 472ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsStage *PreLin = NULL, *CLUT = NULL, *PostLin = NULL; 473ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 474ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (!_cmsEndPointsBySpace(EntryColorSpace, 475ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov &WhitePointIn, NULL, &nIns)) return FALSE; 476ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 477ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (!_cmsEndPointsBySpace(ExitColorSpace, 478ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov &WhitePointOut, NULL, &nOuts)) return FALSE; 479ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 480ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // It needs to be fixed? 481ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (Lut ->InputChannels != nIns) return FALSE; 482ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (Lut ->OutputChannels != nOuts) return FALSE; 483ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 484ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsPipelineEval16(WhitePointIn, ObtainedOut, Lut); 485ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 486ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (WhitesAreEqual(nOuts, WhitePointOut, ObtainedOut)) return TRUE; // whites already match 487ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 488ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Check if the LUT comes as Prelin, CLUT or Postlin. We allow all combinations 489ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (!cmsPipelineCheckAndRetreiveStages(Lut, 3, cmsSigCurveSetElemType, cmsSigCLutElemType, cmsSigCurveSetElemType, &PreLin, &CLUT, &PostLin)) 490ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (!cmsPipelineCheckAndRetreiveStages(Lut, 2, cmsSigCurveSetElemType, cmsSigCLutElemType, &PreLin, &CLUT)) 491ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (!cmsPipelineCheckAndRetreiveStages(Lut, 2, cmsSigCLutElemType, cmsSigCurveSetElemType, &CLUT, &PostLin)) 492ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (!cmsPipelineCheckAndRetreiveStages(Lut, 1, cmsSigCLutElemType, &CLUT)) 493ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return FALSE; 494ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 495ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // We need to interpolate white points of both, pre and post curves 496ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (PreLin) { 497ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 498ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsToneCurve** Curves = _cmsStageGetPtrToCurveSet(PreLin); 499ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 500ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov for (i=0; i < nIns; i++) { 501ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov WhiteIn[i] = cmsEvalToneCurve16(Curves[i], WhitePointIn[i]); 502ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 503ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 504ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov else { 505ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov for (i=0; i < nIns; i++) 506ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov WhiteIn[i] = WhitePointIn[i]; 507ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 508ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 509ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // If any post-linearization, we need to find how is represented white before the curve, do 510ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // a reverse interpolation in this case. 511ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (PostLin) { 512ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 513ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsToneCurve** Curves = _cmsStageGetPtrToCurveSet(PostLin); 514ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 515ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov for (i=0; i < nOuts; i++) { 516ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 517ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsToneCurve* InversePostLin = cmsReverseToneCurve(Curves[i]); 518ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (InversePostLin == NULL) { 519ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov WhiteOut[i] = WhitePointOut[i]; 520ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 521ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } else { 522ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 523ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov WhiteOut[i] = cmsEvalToneCurve16(InversePostLin, WhitePointOut[i]); 524ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsFreeToneCurve(InversePostLin); 525ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 526ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 527ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 528ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov else { 529ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov for (i=0; i < nOuts; i++) 530ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov WhiteOut[i] = WhitePointOut[i]; 531ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 532ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 533ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Ok, proceed with patching. May fail and we don't care if it fails 534ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov PatchLUT(CLUT, WhiteIn, WhiteOut, nOuts, nIns); 535ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 536ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return TRUE; 537ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} 538ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 539ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// ----------------------------------------------------------------------------------------------------------------------------------------------- 540ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// This function creates simple LUT from complex ones. The generated LUT has an optional set of 541ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// prelinearization curves, a CLUT of nGridPoints and optional postlinearization tables. 542ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// These curves have to exist in the original LUT in order to be used in the simplified output. 543ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// Caller may also use the flags to allow this feature. 544ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// LUTS with all curves will be simplified to a single curve. Parametric curves are lost. 545ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// This function should be used on 16-bits LUTS only, as floating point losses precision when simplified 546ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// ----------------------------------------------------------------------------------------------------------------------------------------------- 547ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 548ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovstatic 549ee451cb395940862dad63c85adfe8f2fd55e864cSvet GanovcmsBool OptimizeByResampling(cmsPipeline** Lut, cmsUInt32Number Intent, cmsUInt32Number* InputFormat, cmsUInt32Number* OutputFormat, cmsUInt32Number* dwFlags) 550ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{ 551ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsPipeline* Src = NULL; 552ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsPipeline* Dest = NULL; 553ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsStage* mpe; 554ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsStage* CLUT; 555ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsStage *KeepPreLin = NULL, *KeepPostLin = NULL; 556ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov int nGridPoints; 557ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsColorSpaceSignature ColorSpace, OutputColorSpace; 558ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsStage *NewPreLin = NULL; 559ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsStage *NewPostLin = NULL; 560ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov _cmsStageCLutData* DataCLUT; 561ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsToneCurve** DataSetIn; 562ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsToneCurve** DataSetOut; 563ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Prelin16Data* p16; 564ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 565ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // This is a loosy optimization! does not apply in floating-point cases 566ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (_cmsFormatterIsFloat(*InputFormat) || _cmsFormatterIsFloat(*OutputFormat)) return FALSE; 567ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 568ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov ColorSpace = _cmsICCcolorSpace(T_COLORSPACE(*InputFormat)); 569ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov OutputColorSpace = _cmsICCcolorSpace(T_COLORSPACE(*OutputFormat)); 570ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov nGridPoints = _cmsReasonableGridpointsByColorspace(ColorSpace, *dwFlags); 571ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 572ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // For empty LUTs, 2 points are enough 573ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (cmsPipelineStageCount(*Lut) == 0) 574ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov nGridPoints = 2; 575ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 576ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Src = *Lut; 577ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 578ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Named color pipelines cannot be optimized either 579ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov for (mpe = cmsPipelineGetPtrToFirstStage(Src); 580ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov mpe != NULL; 581ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov mpe = cmsStageNext(mpe)) { 582ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (cmsStageType(mpe) == cmsSigNamedColorElemType) return FALSE; 583ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 584ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 585ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Allocate an empty LUT 586ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Dest = cmsPipelineAlloc(Src ->ContextID, Src ->InputChannels, Src ->OutputChannels); 587ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (!Dest) return FALSE; 588ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 589ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Prelinearization tables are kept unless indicated by flags 590ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (*dwFlags & cmsFLAGS_CLUT_PRE_LINEARIZATION) { 591ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 592ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Get a pointer to the prelinearization element 593ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsStage* PreLin = cmsPipelineGetPtrToFirstStage(Src); 594ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 595ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Check if suitable 596ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (PreLin ->Type == cmsSigCurveSetElemType) { 597ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 598ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Maybe this is a linear tram, so we can avoid the whole stuff 599ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (!AllCurvesAreLinear(PreLin)) { 600ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 601ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // All seems ok, proceed. 602ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov NewPreLin = cmsStageDup(PreLin); 603ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if(!cmsPipelineInsertStage(Dest, cmsAT_BEGIN, NewPreLin)) 604ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov goto Error; 605ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 606ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Remove prelinearization. Since we have duplicated the curve 607ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // in destination LUT, the sampling shoud be applied after this stage. 608ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsPipelineUnlinkStage(Src, cmsAT_BEGIN, &KeepPreLin); 609ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 610ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 611ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 612ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 613ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Allocate the CLUT 614ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov CLUT = cmsStageAllocCLut16bit(Src ->ContextID, nGridPoints, Src ->InputChannels, Src->OutputChannels, NULL); 615ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (CLUT == NULL) return FALSE; 616ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 617ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Add the CLUT to the destination LUT 618ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (!cmsPipelineInsertStage(Dest, cmsAT_END, CLUT)) { 619ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov goto Error; 620ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 621ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 622ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Postlinearization tables are kept unless indicated by flags 623ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (*dwFlags & cmsFLAGS_CLUT_POST_LINEARIZATION) { 624ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 625ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Get a pointer to the postlinearization if present 626ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsStage* PostLin = cmsPipelineGetPtrToLastStage(Src); 627ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 628ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Check if suitable 629ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (cmsStageType(PostLin) == cmsSigCurveSetElemType) { 630ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 631ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Maybe this is a linear tram, so we can avoid the whole stuff 632ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (!AllCurvesAreLinear(PostLin)) { 633ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 634ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // All seems ok, proceed. 635ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov NewPostLin = cmsStageDup(PostLin); 636ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (!cmsPipelineInsertStage(Dest, cmsAT_END, NewPostLin)) 637ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov goto Error; 638ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 639ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // In destination LUT, the sampling shoud be applied after this stage. 640ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsPipelineUnlinkStage(Src, cmsAT_END, &KeepPostLin); 641ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 642ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 643ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 644ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 645ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Now its time to do the sampling. We have to ignore pre/post linearization 646ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // The source LUT whithout pre/post curves is passed as parameter. 647ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (!cmsStageSampleCLut16bit(CLUT, XFormSampler16, (void*) Src, 0)) { 648ee451cb395940862dad63c85adfe8f2fd55e864cSvet GanovError: 649ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Ops, something went wrong, Restore stages 650ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (KeepPreLin != NULL) { 651ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (!cmsPipelineInsertStage(Src, cmsAT_BEGIN, KeepPreLin)) { 652ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov _cmsAssert(0); // This never happens 653ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 654ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 655ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (KeepPostLin != NULL) { 656ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (!cmsPipelineInsertStage(Src, cmsAT_END, KeepPostLin)) { 657ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov _cmsAssert(0); // This never happens 658ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 659ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 660ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsPipelineFree(Dest); 661ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return FALSE; 662ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 663ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 664ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Done. 665ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 666ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (KeepPreLin != NULL) cmsStageFree(KeepPreLin); 667ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (KeepPostLin != NULL) cmsStageFree(KeepPostLin); 668ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsPipelineFree(Src); 669ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 670ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov DataCLUT = (_cmsStageCLutData*) CLUT ->Data; 671ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 672ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (NewPreLin == NULL) DataSetIn = NULL; 673ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov else DataSetIn = ((_cmsStageToneCurvesData*) NewPreLin ->Data) ->TheCurves; 674ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 675ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (NewPostLin == NULL) DataSetOut = NULL; 676ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov else DataSetOut = ((_cmsStageToneCurvesData*) NewPostLin ->Data) ->TheCurves; 677ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 678ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 679ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (DataSetIn == NULL && DataSetOut == NULL) { 680ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 681ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov _cmsPipelineSetOptimizationParameters(Dest, (_cmsOPTeval16Fn) DataCLUT->Params->Interpolation.Lerp16, DataCLUT->Params, NULL, NULL); 682ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 683ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov else { 684ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 685ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov p16 = PrelinOpt16alloc(Dest ->ContextID, 686ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov DataCLUT ->Params, 687ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Dest ->InputChannels, 688ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov DataSetIn, 689ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Dest ->OutputChannels, 690ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov DataSetOut); 691ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 692ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov _cmsPipelineSetOptimizationParameters(Dest, PrelinEval16, (void*) p16, PrelinOpt16free, Prelin16dup); 693ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 694ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 695ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 696ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Don't fix white on absolute colorimetric 697ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (Intent == INTENT_ABSOLUTE_COLORIMETRIC) 698ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov *dwFlags |= cmsFLAGS_NOWHITEONWHITEFIXUP; 699ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 700ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (!(*dwFlags & cmsFLAGS_NOWHITEONWHITEFIXUP)) { 701ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 702ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FixWhiteMisalignment(Dest, ColorSpace, OutputColorSpace); 703ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 704ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 705ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov *Lut = Dest; 706ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return TRUE; 707ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 708ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsUNUSED_PARAMETER(Intent); 709ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} 710ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 711ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 712ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// ----------------------------------------------------------------------------------------------------------------------------------------------- 713ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// Fixes the gamma balancing of transform. This is described in my paper "Prelinearization Stages on 714ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// Color-Management Application-Specific Integrated Circuits (ASICs)" presented at NIP24. It only works 715ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// for RGB transforms. See the paper for more details 716ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// ----------------------------------------------------------------------------------------------------------------------------------------------- 717ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 718ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 719ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// Normalize endpoints by slope limiting max and min. This assures endpoints as well. 720ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// Descending curves are handled as well. 721ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovstatic 722ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovvoid SlopeLimiting(cmsToneCurve* g) 723ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{ 724ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov int BeginVal, EndVal; 725ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov int AtBegin = (int) floor((cmsFloat64Number) g ->nEntries * 0.02 + 0.5); // Cutoff at 2% 726ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov int AtEnd = g ->nEntries - AtBegin - 1; // And 98% 727ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsFloat64Number Val, Slope, beta; 728ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov int i; 729ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 730ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (cmsIsToneCurveDescending(g)) { 731ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov BeginVal = 0xffff; EndVal = 0; 732ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 733ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov else { 734ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov BeginVal = 0; EndVal = 0xffff; 735ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 736ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 737ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Compute slope and offset for begin of curve 738ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Val = g ->Table16[AtBegin]; 739ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Slope = (Val - BeginVal) / AtBegin; 740ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov beta = Val - Slope * AtBegin; 741ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 742ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov for (i=0; i < AtBegin; i++) 743ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov g ->Table16[i] = _cmsQuickSaturateWord(i * Slope + beta); 744ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 745ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Compute slope and offset for the end 746ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Val = g ->Table16[AtEnd]; 747ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Slope = (EndVal - Val) / AtBegin; // AtBegin holds the X interval, which is same in both cases 748ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov beta = Val - Slope * AtEnd; 749ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 750ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov for (i = AtEnd; i < (int) g ->nEntries; i++) 751ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov g ->Table16[i] = _cmsQuickSaturateWord(i * Slope + beta); 752ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} 753ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 754ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 755ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// Precomputes tables for 8-bit on input devicelink. 756ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovstatic 757ee451cb395940862dad63c85adfe8f2fd55e864cSvet GanovPrelin8Data* PrelinOpt8alloc(cmsContext ContextID, const cmsInterpParams* p, cmsToneCurve* G[3]) 758ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{ 759ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov int i; 760ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsUInt16Number Input[3]; 761ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsS15Fixed16Number v1, v2, v3; 762ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Prelin8Data* p8; 763ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 764ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov p8 = (Prelin8Data*)_cmsMallocZero(ContextID, sizeof(Prelin8Data)); 765ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (p8 == NULL) return NULL; 766ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 767ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Since this only works for 8 bit input, values comes always as x * 257, 768ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // we can safely take msb byte (x << 8 + x) 769ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 770ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov for (i=0; i < 256; i++) { 771ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 772ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (G != NULL) { 773ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 774ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Get 16-bit representation 775ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Input[0] = cmsEvalToneCurve16(G[0], FROM_8_TO_16(i)); 776ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Input[1] = cmsEvalToneCurve16(G[1], FROM_8_TO_16(i)); 777ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Input[2] = cmsEvalToneCurve16(G[2], FROM_8_TO_16(i)); 778ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 779ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov else { 780ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Input[0] = FROM_8_TO_16(i); 781ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Input[1] = FROM_8_TO_16(i); 782ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Input[2] = FROM_8_TO_16(i); 783ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 784ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 785ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 786ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Move to 0..1.0 in fixed domain 787ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov v1 = _cmsToFixedDomain(Input[0] * p -> Domain[0]); 788ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov v2 = _cmsToFixedDomain(Input[1] * p -> Domain[1]); 789ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov v3 = _cmsToFixedDomain(Input[2] * p -> Domain[2]); 790ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 791ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Store the precalculated table of nodes 792ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov p8 ->X0[i] = (p->opta[2] * FIXED_TO_INT(v1)); 793ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov p8 ->Y0[i] = (p->opta[1] * FIXED_TO_INT(v2)); 794ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov p8 ->Z0[i] = (p->opta[0] * FIXED_TO_INT(v3)); 795ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 796ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Store the precalculated table of offsets 797ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov p8 ->rx[i] = (cmsUInt16Number) FIXED_REST_TO_INT(v1); 798ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov p8 ->ry[i] = (cmsUInt16Number) FIXED_REST_TO_INT(v2); 799ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov p8 ->rz[i] = (cmsUInt16Number) FIXED_REST_TO_INT(v3); 800ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 801ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 802ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov p8 ->ContextID = ContextID; 803ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov p8 ->p = p; 804ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 805ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return p8; 806ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} 807ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 808ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovstatic 809ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovvoid Prelin8free(cmsContext ContextID, void* ptr) 810ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{ 811ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov _cmsFree(ContextID, ptr); 812ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} 813ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 814ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovstatic 815ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovvoid* Prelin8dup(cmsContext ContextID, const void* ptr) 816ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{ 817ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return _cmsDupMem(ContextID, ptr, sizeof(Prelin8Data)); 818ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} 819ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 820ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 821ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 822ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// A optimized interpolation for 8-bit input. 823ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#define DENS(i,j,k) (LutTable[(i)+(j)+(k)+OutChan]) 824ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovstatic 825ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovvoid PrelinEval8(register const cmsUInt16Number Input[], 826ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov register cmsUInt16Number Output[], 827ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov register const void* D) 828ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{ 829ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 830ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsUInt8Number r, g, b; 831ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsS15Fixed16Number rx, ry, rz; 832ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsS15Fixed16Number c0, c1, c2, c3, Rest; 833ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov int OutChan; 834ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov register cmsS15Fixed16Number X0, X1, Y0, Y1, Z0, Z1; 835ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Prelin8Data* p8 = (Prelin8Data*) D; 836ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov register const cmsInterpParams* p = p8 ->p; 837ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov int TotalOut = p -> nOutputs; 838ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov const cmsUInt16Number* LutTable = (const cmsUInt16Number*)p -> Table; 839ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 840ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov r = Input[0] >> 8; 841ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov g = Input[1] >> 8; 842ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov b = Input[2] >> 8; 843ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 844ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov X0 = X1 = p8->X0[r]; 845ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Y0 = Y1 = p8->Y0[g]; 846ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Z0 = Z1 = p8->Z0[b]; 847ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 848ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov rx = p8 ->rx[r]; 849ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov ry = p8 ->ry[g]; 850ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov rz = p8 ->rz[b]; 851ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 852ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov X1 = X0 + ((rx == 0) ? 0 : p ->opta[2]); 853ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Y1 = Y0 + ((ry == 0) ? 0 : p ->opta[1]); 854ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Z1 = Z0 + ((rz == 0) ? 0 : p ->opta[0]); 855ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 856ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 857ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // These are the 6 Tetrahedral 858ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov for (OutChan=0; OutChan < TotalOut; OutChan++) { 859ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 860ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov c0 = DENS(X0, Y0, Z0); 861ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 862ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (rx >= ry && ry >= rz) 863ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 864ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov c1 = DENS(X1, Y0, Z0) - c0; 865ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov c2 = DENS(X1, Y1, Z0) - DENS(X1, Y0, Z0); 866ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov c3 = DENS(X1, Y1, Z1) - DENS(X1, Y1, Z0); 867ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 868ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov else 869ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (rx >= rz && rz >= ry) 870ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 871ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov c1 = DENS(X1, Y0, Z0) - c0; 872ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov c2 = DENS(X1, Y1, Z1) - DENS(X1, Y0, Z1); 873ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov c3 = DENS(X1, Y0, Z1) - DENS(X1, Y0, Z0); 874ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 875ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov else 876ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (rz >= rx && rx >= ry) 877ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 878ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov c1 = DENS(X1, Y0, Z1) - DENS(X0, Y0, Z1); 879ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov c2 = DENS(X1, Y1, Z1) - DENS(X1, Y0, Z1); 880ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov c3 = DENS(X0, Y0, Z1) - c0; 881ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 882ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov else 883ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (ry >= rx && rx >= rz) 884ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 885ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov c1 = DENS(X1, Y1, Z0) - DENS(X0, Y1, Z0); 886ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov c2 = DENS(X0, Y1, Z0) - c0; 887ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov c3 = DENS(X1, Y1, Z1) - DENS(X1, Y1, Z0); 888ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 889ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov else 890ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (ry >= rz && rz >= rx) 891ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 892ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov c1 = DENS(X1, Y1, Z1) - DENS(X0, Y1, Z1); 893ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov c2 = DENS(X0, Y1, Z0) - c0; 894ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov c3 = DENS(X0, Y1, Z1) - DENS(X0, Y1, Z0); 895ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 896ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov else 897ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (rz >= ry && ry >= rx) 898ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 899ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov c1 = DENS(X1, Y1, Z1) - DENS(X0, Y1, Z1); 900ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov c2 = DENS(X0, Y1, Z1) - DENS(X0, Y0, Z1); 901ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov c3 = DENS(X0, Y0, Z1) - c0; 902ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 903ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov else { 904ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov c1 = c2 = c3 = 0; 905ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 906ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 907ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 908ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Rest = c1 * rx + c2 * ry + c3 * rz + 0x8001; 909ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Output[OutChan] = (cmsUInt16Number)c0 + ((Rest + (Rest>>16))>>16); 910ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 911ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 912ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} 913ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 914ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#undef DENS 915ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 916ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 917ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// Curves that contain wide empty areas are not optimizeable 918ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovstatic 919ee451cb395940862dad63c85adfe8f2fd55e864cSvet GanovcmsBool IsDegenerated(const cmsToneCurve* g) 920ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{ 921ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov int i, Zeros = 0, Poles = 0; 922ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov int nEntries = g ->nEntries; 923ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 924ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov for (i=0; i < nEntries; i++) { 925ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 926ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (g ->Table16[i] == 0x0000) Zeros++; 927ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (g ->Table16[i] == 0xffff) Poles++; 928ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 929ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 930ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (Zeros == 1 && Poles == 1) return FALSE; // For linear tables 931ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (Zeros > (nEntries / 4)) return TRUE; // Degenerated, mostly zeros 932ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (Poles > (nEntries / 4)) return TRUE; // Degenerated, mostly poles 933ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 934ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return FALSE; 935ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} 936ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 937ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// -------------------------------------------------------------------------------------------------------------- 938ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// We need xput over here 939ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 940ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovstatic 941ee451cb395940862dad63c85adfe8f2fd55e864cSvet GanovcmsBool OptimizeByComputingLinearization(cmsPipeline** Lut, cmsUInt32Number Intent, cmsUInt32Number* InputFormat, cmsUInt32Number* OutputFormat, cmsUInt32Number* dwFlags) 942ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{ 943ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsPipeline* OriginalLut; 944ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov int nGridPoints; 945ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsToneCurve *Trans[cmsMAXCHANNELS], *TransReverse[cmsMAXCHANNELS]; 946ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsUInt32Number t, i; 947ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsFloat32Number v, In[cmsMAXCHANNELS], Out[cmsMAXCHANNELS]; 948ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsBool lIsSuitable, lIsLinear; 949ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsPipeline* OptimizedLUT = NULL, *LutPlusCurves = NULL; 950ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsStage* OptimizedCLUTmpe; 951ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsColorSpaceSignature ColorSpace, OutputColorSpace; 952ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsStage* OptimizedPrelinMpe; 953ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsStage* mpe; 954ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsToneCurve** OptimizedPrelinCurves; 955ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov _cmsStageCLutData* OptimizedPrelinCLUT; 956ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 957ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 958ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // This is a loosy optimization! does not apply in floating-point cases 959ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (_cmsFormatterIsFloat(*InputFormat) || _cmsFormatterIsFloat(*OutputFormat)) return FALSE; 960ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 961ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Only on RGB 962ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (T_COLORSPACE(*InputFormat) != PT_RGB) return FALSE; 963ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (T_COLORSPACE(*OutputFormat) != PT_RGB) return FALSE; 964ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 965ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 966ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // On 16 bits, user has to specify the feature 967ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (!_cmsFormatterIs8bit(*InputFormat)) { 968ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (!(*dwFlags & cmsFLAGS_CLUT_PRE_LINEARIZATION)) return FALSE; 969ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 970ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 971ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov OriginalLut = *Lut; 972ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 973ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Named color pipelines cannot be optimized either 974ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov for (mpe = cmsPipelineGetPtrToFirstStage(OriginalLut); 975ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov mpe != NULL; 976ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov mpe = cmsStageNext(mpe)) { 977ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (cmsStageType(mpe) == cmsSigNamedColorElemType) return FALSE; 978ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 979ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 980ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov ColorSpace = _cmsICCcolorSpace(T_COLORSPACE(*InputFormat)); 981ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov OutputColorSpace = _cmsICCcolorSpace(T_COLORSPACE(*OutputFormat)); 982ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov nGridPoints = _cmsReasonableGridpointsByColorspace(ColorSpace, *dwFlags); 983ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 984ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Empty gamma containers 985ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov memset(Trans, 0, sizeof(Trans)); 986ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov memset(TransReverse, 0, sizeof(TransReverse)); 987ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 988ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov for (t = 0; t < OriginalLut ->InputChannels; t++) { 989ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Trans[t] = cmsBuildTabulatedToneCurve16(OriginalLut ->ContextID, PRELINEARIZATION_POINTS, NULL); 990ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (Trans[t] == NULL) goto Error; 991ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 992ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 993ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Populate the curves 994ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov for (i=0; i < PRELINEARIZATION_POINTS; i++) { 995ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 996ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov v = (cmsFloat32Number) ((cmsFloat64Number) i / (PRELINEARIZATION_POINTS - 1)); 997ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 998ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Feed input with a gray ramp 999ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov for (t=0; t < OriginalLut ->InputChannels; t++) 1000ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov In[t] = v; 1001ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1002ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Evaluate the gray value 1003ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsPipelineEvalFloat(In, Out, OriginalLut); 1004ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1005ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Store result in curve 1006ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov for (t=0; t < OriginalLut ->InputChannels; t++) 1007ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Trans[t] ->Table16[i] = _cmsQuickSaturateWord(Out[t] * 65535.0); 1008ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1009ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1010ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Slope-limit the obtained curves 1011ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov for (t = 0; t < OriginalLut ->InputChannels; t++) 1012ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov SlopeLimiting(Trans[t]); 1013ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1014ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Check for validity 1015ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov lIsSuitable = TRUE; 1016ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov lIsLinear = TRUE; 1017ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov for (t=0; (lIsSuitable && (t < OriginalLut ->InputChannels)); t++) { 1018ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1019ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Exclude if already linear 1020ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (!cmsIsToneCurveLinear(Trans[t])) 1021ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov lIsLinear = FALSE; 1022ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1023ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Exclude if non-monotonic 1024ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (!cmsIsToneCurveMonotonic(Trans[t])) 1025ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov lIsSuitable = FALSE; 1026ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1027ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (IsDegenerated(Trans[t])) 1028ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov lIsSuitable = FALSE; 1029ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1030ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1031ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // If it is not suitable, just quit 1032ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (!lIsSuitable) goto Error; 1033ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1034ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Invert curves if possible 1035ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov for (t = 0; t < OriginalLut ->InputChannels; t++) { 1036ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov TransReverse[t] = cmsReverseToneCurveEx(PRELINEARIZATION_POINTS, Trans[t]); 1037ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (TransReverse[t] == NULL) goto Error; 1038ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1039ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1040ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Now inset the reversed curves at the begin of transform 1041ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov LutPlusCurves = cmsPipelineDup(OriginalLut); 1042ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (LutPlusCurves == NULL) goto Error; 1043ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1044ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (!cmsPipelineInsertStage(LutPlusCurves, cmsAT_BEGIN, cmsStageAllocToneCurves(OriginalLut ->ContextID, OriginalLut ->InputChannels, TransReverse))) 1045ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov goto Error; 1046ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1047ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Create the result LUT 1048ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov OptimizedLUT = cmsPipelineAlloc(OriginalLut ->ContextID, OriginalLut ->InputChannels, OriginalLut ->OutputChannels); 1049ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (OptimizedLUT == NULL) goto Error; 1050ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1051ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov OptimizedPrelinMpe = cmsStageAllocToneCurves(OriginalLut ->ContextID, OriginalLut ->InputChannels, Trans); 1052ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1053ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Create and insert the curves at the beginning 1054ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (!cmsPipelineInsertStage(OptimizedLUT, cmsAT_BEGIN, OptimizedPrelinMpe)) 1055ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov goto Error; 1056ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1057ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Allocate the CLUT for result 1058ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov OptimizedCLUTmpe = cmsStageAllocCLut16bit(OriginalLut ->ContextID, nGridPoints, OriginalLut ->InputChannels, OriginalLut ->OutputChannels, NULL); 1059ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1060ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Add the CLUT to the destination LUT 1061ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (!cmsPipelineInsertStage(OptimizedLUT, cmsAT_END, OptimizedCLUTmpe)) 1062ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov goto Error; 1063ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1064ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Resample the LUT 1065ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (!cmsStageSampleCLut16bit(OptimizedCLUTmpe, XFormSampler16, (void*) LutPlusCurves, 0)) goto Error; 1066ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1067ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Free resources 1068ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov for (t = 0; t < OriginalLut ->InputChannels; t++) { 1069ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1070ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (Trans[t]) cmsFreeToneCurve(Trans[t]); 1071ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (TransReverse[t]) cmsFreeToneCurve(TransReverse[t]); 1072ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1073ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1074ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsPipelineFree(LutPlusCurves); 1075ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1076ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1077ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov OptimizedPrelinCurves = _cmsStageGetPtrToCurveSet(OptimizedPrelinMpe); 1078ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov OptimizedPrelinCLUT = (_cmsStageCLutData*) OptimizedCLUTmpe ->Data; 1079ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1080ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Set the evaluator if 8-bit 1081ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (_cmsFormatterIs8bit(*InputFormat)) { 1082ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1083ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Prelin8Data* p8 = PrelinOpt8alloc(OptimizedLUT ->ContextID, 1084ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov OptimizedPrelinCLUT ->Params, 1085ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov OptimizedPrelinCurves); 1086ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (p8 == NULL) return FALSE; 1087ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1088ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov _cmsPipelineSetOptimizationParameters(OptimizedLUT, PrelinEval8, (void*) p8, Prelin8free, Prelin8dup); 1089ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1090ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1091ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov else 1092ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { 1093ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Prelin16Data* p16 = PrelinOpt16alloc(OptimizedLUT ->ContextID, 1094ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov OptimizedPrelinCLUT ->Params, 1095ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 3, OptimizedPrelinCurves, 3, NULL); 1096ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (p16 == NULL) return FALSE; 1097ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1098ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov _cmsPipelineSetOptimizationParameters(OptimizedLUT, PrelinEval16, (void*) p16, PrelinOpt16free, Prelin16dup); 1099ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1100ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1101ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1102ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Don't fix white on absolute colorimetric 1103ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (Intent == INTENT_ABSOLUTE_COLORIMETRIC) 1104ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov *dwFlags |= cmsFLAGS_NOWHITEONWHITEFIXUP; 1105ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1106ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (!(*dwFlags & cmsFLAGS_NOWHITEONWHITEFIXUP)) { 1107ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1108ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (!FixWhiteMisalignment(OptimizedLUT, ColorSpace, OutputColorSpace)) { 1109ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1110ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return FALSE; 1111ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1112ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1113ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1114ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // And return the obtained LUT 1115ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1116ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsPipelineFree(OriginalLut); 1117ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov *Lut = OptimizedLUT; 1118ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return TRUE; 1119ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1120ee451cb395940862dad63c85adfe8f2fd55e864cSvet GanovError: 1121ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1122ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov for (t = 0; t < OriginalLut ->InputChannels; t++) { 1123ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1124ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (Trans[t]) cmsFreeToneCurve(Trans[t]); 1125ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (TransReverse[t]) cmsFreeToneCurve(TransReverse[t]); 1126ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1127ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1128ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (LutPlusCurves != NULL) cmsPipelineFree(LutPlusCurves); 1129ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (OptimizedLUT != NULL) cmsPipelineFree(OptimizedLUT); 1130ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1131ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return FALSE; 1132ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1133ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsUNUSED_PARAMETER(Intent); 1134ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} 1135ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1136ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1137ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// Curves optimizer ------------------------------------------------------------------------------------------------------------------ 1138ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1139ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovstatic 1140ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovvoid CurvesFree(cmsContext ContextID, void* ptr) 1141ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{ 1142ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Curves16Data* Data = (Curves16Data*) ptr; 1143ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov int i; 1144ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1145ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov for (i=0; i < Data -> nCurves; i++) { 1146ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1147ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov _cmsFree(ContextID, Data ->Curves[i]); 1148ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1149ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1150ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov _cmsFree(ContextID, Data ->Curves); 1151ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov _cmsFree(ContextID, ptr); 1152ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} 1153ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1154ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovstatic 1155ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovvoid* CurvesDup(cmsContext ContextID, const void* ptr) 1156ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{ 1157ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Curves16Data* Data = (Curves16Data*)_cmsDupMem(ContextID, ptr, sizeof(Curves16Data)); 1158ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov int i; 1159ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1160ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (Data == NULL) return NULL; 1161ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1162ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Data ->Curves = (cmsUInt16Number**)_cmsDupMem(ContextID, Data ->Curves, Data ->nCurves * sizeof(cmsUInt16Number*)); 1163ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1164ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov for (i=0; i < Data -> nCurves; i++) { 1165ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Data ->Curves[i] = (cmsUInt16Number*)_cmsDupMem(ContextID, Data ->Curves[i], Data -> nElements * sizeof(cmsUInt16Number)); 1166ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1167ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1168ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return (void*) Data; 1169ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} 1170ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1171ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// Precomputes tables for 8-bit on input devicelink. 1172ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovstatic 1173ee451cb395940862dad63c85adfe8f2fd55e864cSvet GanovCurves16Data* CurvesAlloc(cmsContext ContextID, int nCurves, int nElements, cmsToneCurve** G) 1174ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{ 1175ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov int i, j; 1176ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Curves16Data* c16; 1177ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1178ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov c16 = (Curves16Data*)_cmsMallocZero(ContextID, sizeof(Curves16Data)); 1179ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (c16 == NULL) return NULL; 1180ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1181ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov c16 ->nCurves = nCurves; 1182ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov c16 ->nElements = nElements; 1183ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1184ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov c16 ->Curves = (cmsUInt16Number**)_cmsCalloc(ContextID, nCurves, sizeof(cmsUInt16Number*)); 1185ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (c16 ->Curves == NULL) return NULL; 1186ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1187ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov for (i=0; i < nCurves; i++) { 1188ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1189ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov c16->Curves[i] = (cmsUInt16Number*)_cmsCalloc(ContextID, nElements, sizeof(cmsUInt16Number)); 1190ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1191ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (c16->Curves[i] == NULL) { 1192ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1193ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov for (j=0; j < i; j++) { 1194ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov _cmsFree(ContextID, c16->Curves[j]); 1195ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1196ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov _cmsFree(ContextID, c16->Curves); 1197ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov _cmsFree(ContextID, c16); 1198ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return NULL; 1199ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1200ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1201ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (nElements == 256) { 1202ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1203ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov for (j=0; j < nElements; j++) { 1204ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1205ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov c16 ->Curves[i][j] = cmsEvalToneCurve16(G[i], FROM_8_TO_16(j)); 1206ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1207ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1208ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov else { 1209ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1210ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov for (j=0; j < nElements; j++) { 1211ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov c16 ->Curves[i][j] = cmsEvalToneCurve16(G[i], (cmsUInt16Number) j); 1212ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1213ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1214ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1215ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1216ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return c16; 1217ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} 1218ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1219ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovstatic 1220ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovvoid FastEvaluateCurves8(register const cmsUInt16Number In[], 1221ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov register cmsUInt16Number Out[], 1222ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov register const void* D) 1223ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{ 1224ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Curves16Data* Data = (Curves16Data*) D; 1225ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsUInt8Number x; 1226ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov int i; 1227ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1228ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov for (i=0; i < Data ->nCurves; i++) { 1229ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1230ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov x = (In[i] >> 8); 1231ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Out[i] = Data -> Curves[i][x]; 1232ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1233ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} 1234ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1235ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1236ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovstatic 1237ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovvoid FastEvaluateCurves16(register const cmsUInt16Number In[], 1238ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov register cmsUInt16Number Out[], 1239ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov register const void* D) 1240ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{ 1241ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Curves16Data* Data = (Curves16Data*) D; 1242ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov int i; 1243ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1244ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov for (i=0; i < Data ->nCurves; i++) { 1245ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Out[i] = Data -> Curves[i][In[i]]; 1246ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1247ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} 1248ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1249ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1250ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovstatic 1251ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovvoid FastIdentity16(register const cmsUInt16Number In[], 1252ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov register cmsUInt16Number Out[], 1253ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov register const void* D) 1254ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{ 1255ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsPipeline* Lut = (cmsPipeline*) D; 1256ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsUInt32Number i; 1257ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1258ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov for (i=0; i < Lut ->InputChannels; i++) { 1259ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Out[i] = In[i]; 1260ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1261ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} 1262ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1263ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1264ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// If the target LUT holds only curves, the optimization procedure is to join all those 1265ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// curves together. That only works on curves and does not work on matrices. 1266ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovstatic 1267ee451cb395940862dad63c85adfe8f2fd55e864cSvet GanovcmsBool OptimizeByJoiningCurves(cmsPipeline** Lut, cmsUInt32Number Intent, cmsUInt32Number* InputFormat, cmsUInt32Number* OutputFormat, cmsUInt32Number* dwFlags) 1268ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{ 1269ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsToneCurve** GammaTables = NULL; 1270ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsFloat32Number InFloat[cmsMAXCHANNELS], OutFloat[cmsMAXCHANNELS]; 1271ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsUInt32Number i, j; 1272ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsPipeline* Src = *Lut; 1273ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsPipeline* Dest = NULL; 1274ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsStage* mpe; 1275ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsStage* ObtainedCurves = NULL; 1276ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1277ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1278ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // This is a loosy optimization! does not apply in floating-point cases 1279ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (_cmsFormatterIsFloat(*InputFormat) || _cmsFormatterIsFloat(*OutputFormat)) return FALSE; 1280ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1281ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Only curves in this LUT? 1282ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov for (mpe = cmsPipelineGetPtrToFirstStage(Src); 1283ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov mpe != NULL; 1284ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov mpe = cmsStageNext(mpe)) { 1285ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (cmsStageType(mpe) != cmsSigCurveSetElemType) return FALSE; 1286ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1287ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1288ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Allocate an empty LUT 1289ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Dest = cmsPipelineAlloc(Src ->ContextID, Src ->InputChannels, Src ->OutputChannels); 1290ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (Dest == NULL) return FALSE; 1291ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1292ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Create target curves 1293ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov GammaTables = (cmsToneCurve**) _cmsCalloc(Src ->ContextID, Src ->InputChannels, sizeof(cmsToneCurve*)); 1294ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (GammaTables == NULL) goto Error; 1295ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1296ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov for (i=0; i < Src ->InputChannels; i++) { 1297ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov GammaTables[i] = cmsBuildTabulatedToneCurve16(Src ->ContextID, PRELINEARIZATION_POINTS, NULL); 1298ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (GammaTables[i] == NULL) goto Error; 1299ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1300ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1301ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Compute 16 bit result by using floating point 1302ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov for (i=0; i < PRELINEARIZATION_POINTS; i++) { 1303ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1304ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov for (j=0; j < Src ->InputChannels; j++) 1305ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov InFloat[j] = (cmsFloat32Number) ((cmsFloat64Number) i / (PRELINEARIZATION_POINTS - 1)); 1306ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1307ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsPipelineEvalFloat(InFloat, OutFloat, Src); 1308ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1309ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov for (j=0; j < Src ->InputChannels; j++) 1310ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov GammaTables[j] -> Table16[i] = _cmsQuickSaturateWord(OutFloat[j] * 65535.0); 1311ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1312ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1313ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov ObtainedCurves = cmsStageAllocToneCurves(Src ->ContextID, Src ->InputChannels, GammaTables); 1314ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (ObtainedCurves == NULL) goto Error; 1315ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1316ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov for (i=0; i < Src ->InputChannels; i++) { 1317ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsFreeToneCurve(GammaTables[i]); 1318ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov GammaTables[i] = NULL; 1319ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1320ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1321ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (GammaTables != NULL) _cmsFree(Src ->ContextID, GammaTables); 1322ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1323ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Maybe the curves are linear at the end 1324ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (!AllCurvesAreLinear(ObtainedCurves)) { 1325ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1326ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (!cmsPipelineInsertStage(Dest, cmsAT_BEGIN, ObtainedCurves)) 1327ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov goto Error; 1328ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1329ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // If the curves are to be applied in 8 bits, we can save memory 1330ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (_cmsFormatterIs8bit(*InputFormat)) { 1331ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1332ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov _cmsStageToneCurvesData* Data = (_cmsStageToneCurvesData*) ObtainedCurves ->Data; 1333ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Curves16Data* c16 = CurvesAlloc(Dest ->ContextID, Data ->nCurves, 256, Data ->TheCurves); 1334ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1335ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (c16 == NULL) goto Error; 1336ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov *dwFlags |= cmsFLAGS_NOCACHE; 1337ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov _cmsPipelineSetOptimizationParameters(Dest, FastEvaluateCurves8, c16, CurvesFree, CurvesDup); 1338ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1339ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1340ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov else { 1341ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1342ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov _cmsStageToneCurvesData* Data = (_cmsStageToneCurvesData*) cmsStageData(ObtainedCurves); 1343ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Curves16Data* c16 = CurvesAlloc(Dest ->ContextID, Data ->nCurves, 65536, Data ->TheCurves); 1344ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1345ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (c16 == NULL) goto Error; 1346ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov *dwFlags |= cmsFLAGS_NOCACHE; 1347ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov _cmsPipelineSetOptimizationParameters(Dest, FastEvaluateCurves16, c16, CurvesFree, CurvesDup); 1348ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1349ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1350ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov else { 1351ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1352ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // LUT optimizes to nothing. Set the identity LUT 1353ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsStageFree(ObtainedCurves); 1354ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1355ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (!cmsPipelineInsertStage(Dest, cmsAT_BEGIN, cmsStageAllocIdentity(Dest ->ContextID, Src ->InputChannels))) 1356ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov goto Error; 1357ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1358ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov *dwFlags |= cmsFLAGS_NOCACHE; 1359ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov _cmsPipelineSetOptimizationParameters(Dest, FastIdentity16, (void*) Dest, NULL, NULL); 1360ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1361ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1362ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // We are done. 1363ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsPipelineFree(Src); 1364ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov *Lut = Dest; 1365ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return TRUE; 1366ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1367ee451cb395940862dad63c85adfe8f2fd55e864cSvet GanovError: 1368ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1369ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (ObtainedCurves != NULL) cmsStageFree(ObtainedCurves); 1370ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (GammaTables != NULL) { 1371ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov for (i=0; i < Src ->InputChannels; i++) { 1372ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (GammaTables[i] != NULL) cmsFreeToneCurve(GammaTables[i]); 1373ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1374ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1375ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov _cmsFree(Src ->ContextID, GammaTables); 1376ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1377ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1378ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (Dest != NULL) cmsPipelineFree(Dest); 1379ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return FALSE; 1380ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1381ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsUNUSED_PARAMETER(Intent); 1382ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsUNUSED_PARAMETER(InputFormat); 1383ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsUNUSED_PARAMETER(OutputFormat); 1384ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsUNUSED_PARAMETER(dwFlags); 1385ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} 1386ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1387ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// ------------------------------------------------------------------------------------------------------------------------------------- 1388ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// LUT is Shaper - Matrix - Matrix - Shaper, which is very frequent when combining two matrix-shaper profiles 1389ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1390ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1391ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovstatic 1392ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovvoid FreeMatShaper(cmsContext ContextID, void* Data) 1393ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{ 1394ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (Data != NULL) _cmsFree(ContextID, Data); 1395ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} 1396ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1397ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovstatic 1398ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovvoid* DupMatShaper(cmsContext ContextID, const void* Data) 1399ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{ 1400ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return _cmsDupMem(ContextID, Data, sizeof(MatShaper8Data)); 1401ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} 1402ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1403ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1404ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// A fast matrix-shaper evaluator for 8 bits. This is a bit ticky since I'm using 1.14 signed fixed point 1405ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// to accomplish some performance. Actually it takes 256x3 16 bits tables and 16385 x 3 tables of 8 bits, 1406ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// in total about 50K, and the performance boost is huge! 1407ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovstatic 1408ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovvoid MatShaperEval16(register const cmsUInt16Number In[], 1409ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov register cmsUInt16Number Out[], 1410ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov register const void* D) 1411ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{ 1412ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov MatShaper8Data* p = (MatShaper8Data*) D; 1413ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsS1Fixed14Number l1, l2, l3, r, g, b; 1414ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsUInt32Number ri, gi, bi; 1415ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1416ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // In this case (and only in this case!) we can use this simplification since 1417ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // In[] is assured to come from a 8 bit number. (a << 8 | a) 1418ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov ri = In[0] & 0xFF; 1419ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov gi = In[1] & 0xFF; 1420ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov bi = In[2] & 0xFF; 1421ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1422ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Across first shaper, which also converts to 1.14 fixed point 1423ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov r = p->Shaper1R[ri]; 1424ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov g = p->Shaper1G[gi]; 1425ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov b = p->Shaper1B[bi]; 1426ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1427ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Evaluate the matrix in 1.14 fixed point 1428ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov l1 = (p->Mat[0][0] * r + p->Mat[0][1] * g + p->Mat[0][2] * b + p->Off[0] + 0x2000) >> 14; 1429ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov l2 = (p->Mat[1][0] * r + p->Mat[1][1] * g + p->Mat[1][2] * b + p->Off[1] + 0x2000) >> 14; 1430ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov l3 = (p->Mat[2][0] * r + p->Mat[2][1] * g + p->Mat[2][2] * b + p->Off[2] + 0x2000) >> 14; 1431ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1432ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Now we have to clip to 0..1.0 range 1433ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov ri = (l1 < 0) ? 0 : ((l1 > 16384) ? 16384 : l1); 1434ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov gi = (l2 < 0) ? 0 : ((l2 > 16384) ? 16384 : l2); 1435ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov bi = (l3 < 0) ? 0 : ((l3 > 16384) ? 16384 : l3); 1436ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1437ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // And across second shaper, 1438ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Out[0] = p->Shaper2R[ri]; 1439ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Out[1] = p->Shaper2G[gi]; 1440ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Out[2] = p->Shaper2B[bi]; 1441ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1442ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} 1443ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1444ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// This table converts from 8 bits to 1.14 after applying the curve 1445ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovstatic 1446ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovvoid FillFirstShaper(cmsS1Fixed14Number* Table, cmsToneCurve* Curve) 1447ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{ 1448ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov int i; 1449ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsFloat32Number R, y; 1450ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1451ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov for (i=0; i < 256; i++) { 1452ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1453ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov R = (cmsFloat32Number) (i / 255.0); 1454ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov y = cmsEvalToneCurveFloat(Curve, R); 1455ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1456ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Table[i] = DOUBLE_TO_1FIXED14(y); 1457ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1458ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} 1459ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1460ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// This table converts form 1.14 (being 0x4000 the last entry) to 8 bits after applying the curve 1461ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovstatic 1462ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovvoid FillSecondShaper(cmsUInt16Number* Table, cmsToneCurve* Curve, cmsBool Is8BitsOutput) 1463ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{ 1464ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov int i; 1465ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsFloat32Number R, Val; 1466ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1467ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov for (i=0; i < 16385; i++) { 1468ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1469ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov R = (cmsFloat32Number) (i / 16384.0); 1470ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Val = cmsEvalToneCurveFloat(Curve, R); // Val comes 0..1.0 1471ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1472ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (Is8BitsOutput) { 1473ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1474ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // If 8 bits output, we can optimize further by computing the / 257 part. 1475ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // first we compute the resulting byte and then we store the byte times 1476ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // 257. This quantization allows to round very quick by doing a >> 8, but 1477ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // since the low byte is always equal to msb, we can do a & 0xff and this works! 1478ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsUInt16Number w = _cmsQuickSaturateWord(Val * 65535.0); 1479ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsUInt8Number b = FROM_16_TO_8(w); 1480ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1481ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Table[i] = FROM_8_TO_16(b); 1482ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1483ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov else Table[i] = _cmsQuickSaturateWord(Val * 65535.0); 1484ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1485ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} 1486ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1487ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// Compute the matrix-shaper structure 1488ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovstatic 1489ee451cb395940862dad63c85adfe8f2fd55e864cSvet GanovcmsBool SetMatShaper(cmsPipeline* Dest, cmsToneCurve* Curve1[3], cmsMAT3* Mat, cmsVEC3* Off, cmsToneCurve* Curve2[3], cmsUInt32Number* OutputFormat) 1490ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{ 1491ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov MatShaper8Data* p; 1492ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov int i, j; 1493ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsBool Is8Bits = _cmsFormatterIs8bit(*OutputFormat); 1494ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1495ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Allocate a big chuck of memory to store precomputed tables 1496ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov p = (MatShaper8Data*) _cmsMalloc(Dest ->ContextID, sizeof(MatShaper8Data)); 1497ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (p == NULL) return FALSE; 1498ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1499ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov p -> ContextID = Dest -> ContextID; 1500ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1501ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Precompute tables 1502ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FillFirstShaper(p ->Shaper1R, Curve1[0]); 1503ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FillFirstShaper(p ->Shaper1G, Curve1[1]); 1504ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FillFirstShaper(p ->Shaper1B, Curve1[2]); 1505ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1506ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FillSecondShaper(p ->Shaper2R, Curve2[0], Is8Bits); 1507ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FillSecondShaper(p ->Shaper2G, Curve2[1], Is8Bits); 1508ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov FillSecondShaper(p ->Shaper2B, Curve2[2], Is8Bits); 1509ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1510ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Convert matrix to nFixed14. Note that those values may take more than 16 bits as 1511ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov for (i=0; i < 3; i++) { 1512ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov for (j=0; j < 3; j++) { 1513ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov p ->Mat[i][j] = DOUBLE_TO_1FIXED14(Mat->v[i].n[j]); 1514ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1515ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1516ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1517ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov for (i=0; i < 3; i++) { 1518ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1519ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (Off == NULL) { 1520ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov p ->Off[i] = 0; 1521ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1522ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov else { 1523ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov p ->Off[i] = DOUBLE_TO_1FIXED14(Off->n[i]); 1524ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1525ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1526ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1527ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Mark as optimized for faster formatter 1528ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (Is8Bits) 1529ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov *OutputFormat |= OPTIMIZED_SH(1); 1530ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1531ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Fill function pointers 1532ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov _cmsPipelineSetOptimizationParameters(Dest, MatShaperEval16, (void*) p, FreeMatShaper, DupMatShaper); 1533ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return TRUE; 1534ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} 1535ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1536ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// 8 bits on input allows matrix-shaper boot up to 25 Mpixels per second on RGB. That's fast! 1537ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// TODO: Allow a third matrix for abs. colorimetric 1538ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovstatic 1539ee451cb395940862dad63c85adfe8f2fd55e864cSvet GanovcmsBool OptimizeMatrixShaper(cmsPipeline** Lut, cmsUInt32Number Intent, cmsUInt32Number* InputFormat, cmsUInt32Number* OutputFormat, cmsUInt32Number* dwFlags) 1540ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{ 1541ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsStage* Curve1, *Curve2; 1542ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsStage* Matrix1, *Matrix2; 1543ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov _cmsStageMatrixData* Data1; 1544ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov _cmsStageMatrixData* Data2; 1545ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsMAT3 res; 1546ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsBool IdentityMat; 1547ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsPipeline* Dest, *Src; 1548ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1549ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Only works on RGB to RGB 1550ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (T_CHANNELS(*InputFormat) != 3 || T_CHANNELS(*OutputFormat) != 3) return FALSE; 1551ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1552ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Only works on 8 bit input 1553ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (!_cmsFormatterIs8bit(*InputFormat)) return FALSE; 1554ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1555ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Seems suitable, proceed 1556ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Src = *Lut; 1557ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1558ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Check for shaper-matrix-matrix-shaper structure, that is what this optimizer stands for 1559ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (!cmsPipelineCheckAndRetreiveStages(Src, 4, 1560ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsSigCurveSetElemType, cmsSigMatrixElemType, cmsSigMatrixElemType, cmsSigCurveSetElemType, 1561ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov &Curve1, &Matrix1, &Matrix2, &Curve2)) return FALSE; 1562ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1563ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Get both matrices 1564ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Data1 = (_cmsStageMatrixData*) cmsStageData(Matrix1); 1565ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Data2 = (_cmsStageMatrixData*) cmsStageData(Matrix2); 1566ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1567ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Input offset should be zero 1568ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (Data1 ->Offset != NULL) return FALSE; 1569ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1570ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Multiply both matrices to get the result 1571ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov _cmsMAT3per(&res, (cmsMAT3*) Data2 ->Double, (cmsMAT3*) Data1 ->Double); 1572ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1573ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Now the result is in res + Data2 -> Offset. Maybe is a plain identity? 1574ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov IdentityMat = FALSE; 1575ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (_cmsMAT3isIdentity(&res) && Data2 ->Offset == NULL) { 1576ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1577ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // We can get rid of full matrix 1578ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov IdentityMat = TRUE; 1579ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1580ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1581ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Allocate an empty LUT 1582ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Dest = cmsPipelineAlloc(Src ->ContextID, Src ->InputChannels, Src ->OutputChannels); 1583ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (!Dest) return FALSE; 1584ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1585ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Assamble the new LUT 1586ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (!cmsPipelineInsertStage(Dest, cmsAT_BEGIN, cmsStageDup(Curve1))) 1587ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov goto Error; 1588ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1589ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (!IdentityMat) 1590ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (!cmsPipelineInsertStage(Dest, cmsAT_END, cmsStageAllocMatrix(Dest ->ContextID, 3, 3, (const cmsFloat64Number*) &res, Data2 ->Offset))) 1591ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov goto Error; 1592ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (!cmsPipelineInsertStage(Dest, cmsAT_END, cmsStageDup(Curve2))) 1593ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov goto Error; 1594ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1595ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // If identity on matrix, we can further optimize the curves, so call the join curves routine 1596ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (IdentityMat) { 1597ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1598ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov OptimizeByJoiningCurves(&Dest, Intent, InputFormat, OutputFormat, dwFlags); 1599ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1600ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov else { 1601ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov _cmsStageToneCurvesData* mpeC1 = (_cmsStageToneCurvesData*) cmsStageData(Curve1); 1602ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov _cmsStageToneCurvesData* mpeC2 = (_cmsStageToneCurvesData*) cmsStageData(Curve2); 1603ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1604ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // In this particular optimization, cach?does not help as it takes more time to deal with 1605ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // the cach?that with the pixel handling 1606ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov *dwFlags |= cmsFLAGS_NOCACHE; 1607ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1608ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Setup the optimizarion routines 1609ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov SetMatShaper(Dest, mpeC1 ->TheCurves, &res, (cmsVEC3*) Data2 ->Offset, mpeC2->TheCurves, OutputFormat); 1610ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1611ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1612ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsPipelineFree(Src); 1613ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov *Lut = Dest; 1614ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return TRUE; 1615ee451cb395940862dad63c85adfe8f2fd55e864cSvet GanovError: 1616ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Leave Src unchanged 1617ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsPipelineFree(Dest); 1618ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return FALSE; 1619ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} 1620ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1621ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1622ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// ------------------------------------------------------------------------------------------------------------------------------------- 1623ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// Optimization plug-ins 1624ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1625ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// List of optimizations 1626ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovtypedef struct _cmsOptimizationCollection_st { 1627ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1628ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov _cmsOPToptimizeFn OptimizePtr; 1629ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1630ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov struct _cmsOptimizationCollection_st *Next; 1631ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1632ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} _cmsOptimizationCollection; 1633ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1634ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1635ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// The built-in list. We currently implement 4 types of optimizations. Joining of curves, matrix-shaper, linearization and resampling 1636ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovstatic _cmsOptimizationCollection DefaultOptimization[] = { 1637ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1638ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { OptimizeByJoiningCurves, &DefaultOptimization[1] }, 1639ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { OptimizeMatrixShaper, &DefaultOptimization[2] }, 1640ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { OptimizeByComputingLinearization, &DefaultOptimization[3] }, 1641ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov { OptimizeByResampling, NULL } 1642ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov}; 1643ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1644ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// The linked list head 1645ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov_cmsOptimizationPluginChunkType _cmsOptimizationPluginChunk = { NULL }; 1646ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1647ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1648ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// Duplicates the zone of memory used by the plug-in in the new context 1649ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovstatic 1650ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovvoid DupPluginOptimizationList(struct _cmsContext_struct* ctx, 1651ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov const struct _cmsContext_struct* src) 1652ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{ 1653ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov _cmsOptimizationPluginChunkType newHead = { NULL }; 1654ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov _cmsOptimizationCollection* entry; 1655ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov _cmsOptimizationCollection* Anterior = NULL; 1656ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov _cmsOptimizationPluginChunkType* head = (_cmsOptimizationPluginChunkType*) src->chunks[OptimizationPlugin]; 1657ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1658ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov _cmsAssert(ctx != NULL); 1659ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov _cmsAssert(head != NULL); 1660ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1661ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Walk the list copying all nodes 1662ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov for (entry = head->OptimizationCollection; 1663ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov entry != NULL; 1664ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov entry = entry ->Next) { 1665ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1666ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov _cmsOptimizationCollection *newEntry = ( _cmsOptimizationCollection *) _cmsSubAllocDup(ctx ->MemPool, entry, sizeof(_cmsOptimizationCollection)); 1667ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1668ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (newEntry == NULL) 1669ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return; 1670ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1671ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // We want to keep the linked list order, so this is a little bit tricky 1672ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov newEntry -> Next = NULL; 1673ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (Anterior) 1674ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Anterior -> Next = newEntry; 1675ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1676ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Anterior = newEntry; 1677ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1678ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (newHead.OptimizationCollection == NULL) 1679ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov newHead.OptimizationCollection = newEntry; 1680ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1681ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1682ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov ctx ->chunks[OptimizationPlugin] = _cmsSubAllocDup(ctx->MemPool, &newHead, sizeof(_cmsOptimizationPluginChunkType)); 1683ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} 1684ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1685ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovvoid _cmsAllocOptimizationPluginChunk(struct _cmsContext_struct* ctx, 1686ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov const struct _cmsContext_struct* src) 1687ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{ 1688ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (src != NULL) { 1689ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1690ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Copy all linked list 1691ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov DupPluginOptimizationList(ctx, src); 1692ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1693ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov else { 1694ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov static _cmsOptimizationPluginChunkType OptimizationPluginChunkType = { NULL }; 1695ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov ctx ->chunks[OptimizationPlugin] = _cmsSubAllocDup(ctx ->MemPool, &OptimizationPluginChunkType, sizeof(_cmsOptimizationPluginChunkType)); 1696ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1697ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} 1698ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1699ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1700ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// Register new ways to optimize 1701ee451cb395940862dad63c85adfe8f2fd55e864cSvet GanovcmsBool _cmsRegisterOptimizationPlugin(cmsContext ContextID, cmsPluginBase* Data) 1702ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{ 1703ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsPluginOptimization* Plugin = (cmsPluginOptimization*) Data; 1704ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov _cmsOptimizationPluginChunkType* ctx = ( _cmsOptimizationPluginChunkType*) _cmsContextGetClientChunk(ContextID, OptimizationPlugin); 1705ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov _cmsOptimizationCollection* fl; 1706ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1707ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (Data == NULL) { 1708ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1709ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov ctx->OptimizationCollection = NULL; 1710ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return TRUE; 1711ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1712ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1713ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Optimizer callback is required 1714ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (Plugin ->OptimizePtr == NULL) return FALSE; 1715ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1716ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov fl = (_cmsOptimizationCollection*) _cmsPluginMalloc(ContextID, sizeof(_cmsOptimizationCollection)); 1717ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (fl == NULL) return FALSE; 1718ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1719ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Copy the parameters 1720ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov fl ->OptimizePtr = Plugin ->OptimizePtr; 1721ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1722ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Keep linked list 1723ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov fl ->Next = ctx->OptimizationCollection; 1724ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1725ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Set the head 1726ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov ctx ->OptimizationCollection = fl; 1727ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1728ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // All is ok 1729ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return TRUE; 1730ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} 1731ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1732ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// The entry point for LUT optimization 1733ee451cb395940862dad63c85adfe8f2fd55e864cSvet GanovcmsBool _cmsOptimizePipeline(cmsContext ContextID, 1734ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsPipeline** PtrLut, 1735ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov int Intent, 1736ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsUInt32Number* InputFormat, 1737ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsUInt32Number* OutputFormat, 1738ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsUInt32Number* dwFlags) 1739ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{ 1740ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov _cmsOptimizationPluginChunkType* ctx = ( _cmsOptimizationPluginChunkType*) _cmsContextGetClientChunk(ContextID, OptimizationPlugin); 1741ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov _cmsOptimizationCollection* Opts; 1742ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov cmsBool AnySuccess = FALSE; 1743ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1744ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // A CLUT is being asked, so force this specific optimization 1745ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (*dwFlags & cmsFLAGS_FORCE_CLUT) { 1746ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1747ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov PreOptimize(*PtrLut); 1748ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return OptimizeByResampling(PtrLut, Intent, InputFormat, OutputFormat, dwFlags); 1749ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1750ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1751ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Anything to optimize? 1752ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ((*PtrLut) ->Elements == NULL) { 1753ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov _cmsPipelineSetOptimizationParameters(*PtrLut, FastIdentity16, (void*) *PtrLut, NULL, NULL); 1754ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return TRUE; 1755ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1756ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1757ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Try to get rid of identities and trivial conversions. 1758ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov AnySuccess = PreOptimize(*PtrLut); 1759ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1760ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // After removal do we end with an identity? 1761ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ((*PtrLut) ->Elements == NULL) { 1762ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov _cmsPipelineSetOptimizationParameters(*PtrLut, FastIdentity16, (void*) *PtrLut, NULL, NULL); 1763ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return TRUE; 1764ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1765ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1766ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Do not optimize, keep all precision 1767ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (*dwFlags & cmsFLAGS_NOOPTIMIZE) 1768ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return FALSE; 1769ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1770ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Try plug-in optimizations 1771ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov for (Opts = ctx->OptimizationCollection; 1772ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Opts != NULL; 1773ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Opts = Opts ->Next) { 1774ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1775ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // If one schema succeeded, we are done 1776ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (Opts ->OptimizePtr(PtrLut, Intent, InputFormat, OutputFormat, dwFlags)) { 1777ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1778ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return TRUE; // Optimized! 1779ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1780ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1781ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1782ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Try built-in optimizations 1783ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov for (Opts = DefaultOptimization; 1784ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Opts != NULL; 1785ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Opts = Opts ->Next) { 1786ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1787ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (Opts ->OptimizePtr(PtrLut, Intent, InputFormat, OutputFormat, dwFlags)) { 1788ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1789ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return TRUE; 1790ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1791ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 1792ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 1793ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Only simple optimizations succeeded 1794ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return AnySuccess; 1795ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} 1796