1 /*
   2  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   3  *
   4  * This code is free software; you can redistribute it and/or modify it
   5  * under the terms of the GNU General Public License version 2 only, as
   6  * published by the Free Software Foundation.  Oracle designates this
   7  * particular file as subject to the "Classpath" exception as provided
   8  * by Oracle in the LICENSE file that accompanied this code.
   9  *
  10  * This code is distributed in the hope that it will be useful, but WITHOUT
  11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  12  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  13  * version 2 for more details (a copy is included in the LICENSE file that
  14  * accompanied this code).
  15  *
  16  * You should have received a copy of the GNU General Public License version
  17  * 2 along with this work; if not, write to the Free Software Foundation,
  18  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  19  *
  20  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  21  * or visit www.oracle.com if you need additional information or have any
  22  * questions.
  23  */
  24 
  25 // This file is available under and governed by the GNU General Public
  26 // License version 2 only, as published by the Free Software Foundation.
  27 // However, the following notice accompanied the original version of this
  28 // file:
  29 //
  30 //---------------------------------------------------------------------------------
  31 //
  32 //  Little Color Management System
  33 //  Copyright (c) 1998-2023 Marti Maria Saguer
  34 //
  35 // Permission is hereby granted, free of charge, to any person obtaining
  36 // a copy of this software and associated documentation files (the "Software"),
  37 // to deal in the Software without restriction, including without limitation
  38 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
  39 // and/or sell copies of the Software, and to permit persons to whom the Software
  40 // is furnished to do so, subject to the following conditions:
  41 //
  42 // The above copyright notice and this permission notice shall be included in
  43 // all copies or substantial portions of the Software.
  44 //
  45 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  46 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
  47 // THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  48 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  49 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  50 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  51 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  52 //
  53 //---------------------------------------------------------------------------------
  54 //
  55 #include "lcms2_internal.h"
  56 
  57 // Tone curves are powerful constructs that can contain curves specified in diverse ways.
  58 // The curve is stored in segments, where each segment can be sampled or specified by parameters.
  59 // a 16.bit simplification of the *whole* curve is kept for optimization purposes. For float operation,
  60 // each segment is evaluated separately. Plug-ins may be used to define new parametric schemes,
  61 // each plug-in may define up to MAX_TYPES_IN_LCMS_PLUGIN functions types. For defining a function,
  62 // the plug-in should provide the type id, how many parameters each type has, and a pointer to
  63 // a procedure that evaluates the function. In the case of reverse evaluation, the evaluator will
  64 // be called with the type id as a negative value, and a sampled version of the reversed curve
  65 // will be built.
  66 
  67 // ----------------------------------------------------------------- Implementation
  68 // Maxim number of nodes
  69 #define MAX_NODES_IN_CURVE   4097
  70 #define MINUS_INF            (-1E22F)
  71 #define PLUS_INF             (+1E22F)
  72 
  73 // The list of supported parametric curves
  74 typedef struct _cmsParametricCurvesCollection_st {
  75 
  76     cmsUInt32Number nFunctions;                                     // Number of supported functions in this chunk
  77     cmsInt32Number  FunctionTypes[MAX_TYPES_IN_LCMS_PLUGIN];        // The identification types
  78     cmsUInt32Number ParameterCount[MAX_TYPES_IN_LCMS_PLUGIN];       // Number of parameters for each function
  79 
  80     cmsParametricCurveEvaluator Evaluator;                          // The evaluator
  81 
  82     struct _cmsParametricCurvesCollection_st* Next; // Next in list
  83 
  84 } _cmsParametricCurvesCollection;
  85 
  86 // This is the default (built-in) evaluator
  87 static cmsFloat64Number DefaultEvalParametricFn(cmsInt32Number Type, const cmsFloat64Number Params[], cmsFloat64Number R);
  88 
  89 // The built-in list
  90 static _cmsParametricCurvesCollection DefaultCurves = {
  91     10,                                      // # of curve types
  92     { 1, 2, 3, 4, 5, 6, 7, 8, 108, 109 },    // Parametric curve ID
  93     { 1, 3, 4, 5, 7, 4, 5, 5,   1,   1 },    // Parameters by type
  94     DefaultEvalParametricFn,                 // Evaluator
  95     NULL                                     // Next in chain
  96 };
  97 
  98 // Duplicates the zone of memory used by the plug-in in the new context
  99 static
 100 void DupPluginCurvesList(struct _cmsContext_struct* ctx,
 101                                                const struct _cmsContext_struct* src)
 102 {
 103    _cmsCurvesPluginChunkType newHead = { NULL };
 104    _cmsParametricCurvesCollection*  entry;
 105    _cmsParametricCurvesCollection*  Anterior = NULL;
 106    _cmsCurvesPluginChunkType* head = (_cmsCurvesPluginChunkType*) src->chunks[CurvesPlugin];
 107 
 108     _cmsAssert(head != NULL);
 109 
 110     // Walk the list copying all nodes
 111    for (entry = head->ParametricCurves;
 112         entry != NULL;
 113         entry = entry ->Next) {
 114 
 115             _cmsParametricCurvesCollection *newEntry = ( _cmsParametricCurvesCollection *) _cmsSubAllocDup(ctx ->MemPool, entry, sizeof(_cmsParametricCurvesCollection));
 116 
 117             if (newEntry == NULL)
 118                 return;
 119 
 120             // We want to keep the linked list order, so this is a little bit tricky
 121             newEntry -> Next = NULL;
 122             if (Anterior)
 123                 Anterior -> Next = newEntry;
 124 
 125             Anterior = newEntry;
 126 
 127             if (newHead.ParametricCurves == NULL)
 128                 newHead.ParametricCurves = newEntry;
 129     }
 130 
 131   ctx ->chunks[CurvesPlugin] = _cmsSubAllocDup(ctx->MemPool, &newHead, sizeof(_cmsCurvesPluginChunkType));
 132 }
 133 
 134 // The allocator have to follow the chain
 135 void _cmsAllocCurvesPluginChunk(struct _cmsContext_struct* ctx,
 136                                 const struct _cmsContext_struct* src)
 137 {
 138     _cmsAssert(ctx != NULL);
 139 
 140     if (src != NULL) {
 141 
 142         // Copy all linked list
 143        DupPluginCurvesList(ctx, src);
 144     }
 145     else {
 146         static _cmsCurvesPluginChunkType CurvesPluginChunk = { NULL };
 147         ctx ->chunks[CurvesPlugin] = _cmsSubAllocDup(ctx ->MemPool, &CurvesPluginChunk, sizeof(_cmsCurvesPluginChunkType));
 148     }
 149 }
 150 
 151 
 152 // The linked list head
 153 _cmsCurvesPluginChunkType _cmsCurvesPluginChunk = { NULL };
 154 
 155 // As a way to install new parametric curves
 156 cmsBool _cmsRegisterParametricCurvesPlugin(cmsContext ContextID, cmsPluginBase* Data)
 157 {
 158     _cmsCurvesPluginChunkType* ctx = ( _cmsCurvesPluginChunkType*) _cmsContextGetClientChunk(ContextID, CurvesPlugin);
 159     cmsPluginParametricCurves* Plugin = (cmsPluginParametricCurves*) Data;
 160     _cmsParametricCurvesCollection* fl;
 161 
 162     if (Data == NULL) {
 163 
 164           ctx -> ParametricCurves =  NULL;
 165           return TRUE;
 166     }
 167 
 168     fl = (_cmsParametricCurvesCollection*) _cmsPluginMalloc(ContextID, sizeof(_cmsParametricCurvesCollection));
 169     if (fl == NULL) return FALSE;
 170 
 171     // Copy the parameters
 172     fl ->Evaluator  = Plugin ->Evaluator;
 173     fl ->nFunctions = Plugin ->nFunctions;
 174 
 175     // Make sure no mem overwrites
 176     if (fl ->nFunctions > MAX_TYPES_IN_LCMS_PLUGIN)
 177         fl ->nFunctions = MAX_TYPES_IN_LCMS_PLUGIN;
 178 
 179     // Copy the data
 180     memmove(fl->FunctionTypes,  Plugin ->FunctionTypes,   fl->nFunctions * sizeof(cmsUInt32Number));
 181     memmove(fl->ParameterCount, Plugin ->ParameterCount,  fl->nFunctions * sizeof(cmsUInt32Number));
 182 
 183     // Keep linked list
 184     fl ->Next = ctx->ParametricCurves;
 185     ctx->ParametricCurves = fl;
 186 
 187     // All is ok
 188     return TRUE;
 189 }
 190 
 191 
 192 // Search in type list, return position or -1 if not found
 193 static
 194 int IsInSet(int Type, _cmsParametricCurvesCollection* c)
 195 {
 196     int i;
 197 
 198     for (i=0; i < (int) c ->nFunctions; i++)
 199         if (abs(Type) == c ->FunctionTypes[i]) return i;
 200 
 201     return -1;
 202 }
 203 
 204 
 205 // Search for the collection which contains a specific type
 206 static
 207 _cmsParametricCurvesCollection *GetParametricCurveByType(cmsContext ContextID, int Type, int* index)
 208 {
 209     _cmsParametricCurvesCollection* c;
 210     int Position;
 211     _cmsCurvesPluginChunkType* ctx = ( _cmsCurvesPluginChunkType*) _cmsContextGetClientChunk(ContextID, CurvesPlugin);
 212 
 213     for (c = ctx->ParametricCurves; c != NULL; c = c ->Next) {
 214 
 215         Position = IsInSet(Type, c);
 216 
 217         if (Position != -1) {
 218             if (index != NULL)
 219                 *index = Position;
 220             return c;
 221         }
 222     }
 223     // If none found, revert for defaults
 224     for (c = &DefaultCurves; c != NULL; c = c ->Next) {
 225 
 226         Position = IsInSet(Type, c);
 227 
 228         if (Position != -1) {
 229             if (index != NULL)
 230                 *index = Position;
 231             return c;
 232         }
 233     }
 234 
 235     return NULL;
 236 }
 237 
 238 // Low level allocate, which takes care of memory details. nEntries may be zero, and in this case
 239 // no optimization curve is computed. nSegments may also be zero in the inverse case, where only the
 240 // optimization curve is given. Both features simultaneously is an error
 241 static
 242 cmsToneCurve* AllocateToneCurveStruct(cmsContext ContextID, cmsUInt32Number nEntries,
 243                                       cmsUInt32Number nSegments, const cmsCurveSegment* Segments,
 244                                       const cmsUInt16Number* Values)
 245 {
 246     cmsToneCurve* p;
 247     cmsUInt32Number i;
 248 
 249     // We allow huge tables, which are then restricted for smoothing operations
 250     if (nEntries > 65530) {
 251         cmsSignalError(ContextID, cmsERROR_RANGE, "Couldn't create tone curve of more than 65530 entries");
 252         return NULL;
 253     }
 254 
 255     if (nEntries == 0 && nSegments == 0) {
 256         cmsSignalError(ContextID, cmsERROR_RANGE, "Couldn't create tone curve with zero segments and no table");
 257         return NULL;
 258     }
 259 
 260     // Allocate all required pointers, etc.
 261     p = (cmsToneCurve*) _cmsMallocZero(ContextID, sizeof(cmsToneCurve));
 262     if (!p) return NULL;
 263 
 264     // In this case, there are no segments
 265     if (nSegments == 0) {
 266         p ->Segments = NULL;
 267         p ->Evals = NULL;
 268     }
 269     else {
 270         p ->Segments = (cmsCurveSegment*) _cmsCalloc(ContextID, nSegments, sizeof(cmsCurveSegment));
 271         if (p ->Segments == NULL) goto Error;
 272 
 273         p ->Evals    = (cmsParametricCurveEvaluator*) _cmsCalloc(ContextID, nSegments, sizeof(cmsParametricCurveEvaluator));
 274         if (p ->Evals == NULL) goto Error;
 275     }
 276 
 277     p -> nSegments = nSegments;
 278 
 279     // This 16-bit table contains a limited precision representation of the whole curve and is kept for
 280     // increasing xput on certain operations.
 281     if (nEntries == 0) {
 282         p ->Table16 = NULL;
 283     }
 284     else {
 285        p ->Table16 = (cmsUInt16Number*)  _cmsCalloc(ContextID, nEntries, sizeof(cmsUInt16Number));
 286        if (p ->Table16 == NULL) goto Error;
 287     }
 288 
 289     p -> nEntries  = nEntries;
 290 
 291     // Initialize members if requested
 292     if (Values != NULL && (nEntries > 0)) {
 293 
 294         for (i=0; i < nEntries; i++)
 295             p ->Table16[i] = Values[i];
 296     }
 297 
 298     // Initialize the segments stuff. The evaluator for each segment is located and a pointer to it
 299     // is placed in advance to maximize performance.
 300     if (Segments != NULL && (nSegments > 0)) {
 301 
 302         _cmsParametricCurvesCollection *c;
 303 
 304         p ->SegInterp = (cmsInterpParams**) _cmsCalloc(ContextID, nSegments, sizeof(cmsInterpParams*));
 305         if (p ->SegInterp == NULL) goto Error;
 306 
 307         for (i=0; i < nSegments; i++) {
 308 
 309             // Type 0 is a special marker for table-based curves
 310             if (Segments[i].Type == 0)
 311                 p ->SegInterp[i] = _cmsComputeInterpParams(ContextID, Segments[i].nGridPoints, 1, 1, NULL, CMS_LERP_FLAGS_FLOAT);
 312 
 313             memmove(&p ->Segments[i], &Segments[i], sizeof(cmsCurveSegment));
 314 
 315             if (Segments[i].Type == 0 && Segments[i].SampledPoints != NULL)
 316                 p ->Segments[i].SampledPoints = (cmsFloat32Number*) _cmsDupMem(ContextID, Segments[i].SampledPoints, sizeof(cmsFloat32Number) * Segments[i].nGridPoints);
 317             else
 318                 p ->Segments[i].SampledPoints = NULL;
 319 
 320 
 321             c = GetParametricCurveByType(ContextID, Segments[i].Type, NULL);
 322             if (c != NULL)
 323                     p ->Evals[i] = c ->Evaluator;
 324         }
 325     }
 326 
 327     p ->InterpParams = _cmsComputeInterpParams(ContextID, p ->nEntries, 1, 1, p->Table16, CMS_LERP_FLAGS_16BITS);
 328     if (p->InterpParams != NULL)
 329         return p;
 330 
 331 Error:
 332     if (p -> SegInterp) _cmsFree(ContextID, p -> SegInterp);
 333     if (p -> Segments) _cmsFree(ContextID, p -> Segments);
 334     if (p -> Evals) _cmsFree(ContextID, p -> Evals);
 335     if (p ->Table16) _cmsFree(ContextID, p ->Table16);
 336     _cmsFree(ContextID, p);
 337     return NULL;
 338 }
 339 
 340 
 341 // Generates a sigmoidal function with desired steepness.
 342 cmsINLINE double sigmoid_base(double k, double t)
 343 {
 344     return (1.0 / (1.0 + exp(-k * t))) - 0.5;
 345 }
 346 
 347 cmsINLINE double inverted_sigmoid_base(double k, double t)
 348 {
 349     return -log((1.0 / (t + 0.5)) - 1.0) / k;
 350 }
 351 
 352 cmsINLINE double sigmoid_factory(double k, double t)
 353 {
 354     double correction = 0.5 / sigmoid_base(k, 1);
 355 
 356     return correction * sigmoid_base(k, 2.0 * t - 1.0) + 0.5;
 357 }
 358 
 359 cmsINLINE double inverse_sigmoid_factory(double k, double t)
 360 {
 361     double correction = 0.5 / sigmoid_base(k, 1);
 362 
 363     return (inverted_sigmoid_base(k, (t - 0.5) / correction) + 1.0) / 2.0;
 364 }
 365 
 366 
 367 // Parametric Fn using floating point
 368 static
 369 cmsFloat64Number DefaultEvalParametricFn(cmsInt32Number Type, const cmsFloat64Number Params[], cmsFloat64Number R)
 370 {
 371     cmsFloat64Number e, Val, disc;
 372 
 373     switch (Type) {
 374 
 375    // X = Y ^ Gamma
 376     case 1:
 377         if (R < 0) {
 378 
 379             if (fabs(Params[0] - 1.0) < MATRIX_DET_TOLERANCE)
 380                 Val = R;
 381             else
 382                 Val = 0;
 383         }
 384         else
 385             Val = pow(R, Params[0]);
 386         break;
 387 
 388     // Type 1 Reversed: X = Y ^1/gamma
 389     case -1:
 390         if (R < 0) {
 391 
 392             if (fabs(Params[0] - 1.0) < MATRIX_DET_TOLERANCE)
 393                 Val = R;
 394             else
 395                 Val = 0;
 396         }
 397         else
 398         {
 399             if (fabs(Params[0]) < MATRIX_DET_TOLERANCE)
 400                 Val = PLUS_INF;
 401             else
 402                 Val = pow(R, 1 / Params[0]);
 403         }
 404         break;
 405 
 406     // CIE 122-1966
 407     // Y = (aX + b)^Gamma  | X >= -b/a
 408     // Y = 0               | else
 409     case 2:
 410     {
 411 
 412         if (fabs(Params[1]) < MATRIX_DET_TOLERANCE)
 413         {
 414             Val = 0;
 415         }
 416         else
 417         {
 418             disc = -Params[2] / Params[1];
 419 
 420             if (R >= disc) {
 421 
 422                 e = Params[1] * R + Params[2];
 423 
 424                 if (e > 0)
 425                     Val = pow(e, Params[0]);
 426                 else
 427                     Val = 0;
 428             }
 429             else
 430                 Val = 0;
 431         }
 432     }
 433     break;
 434 
 435      // Type 2 Reversed
 436      // X = (Y ^1/g  - b) / a
 437      case -2:
 438      {
 439          if (fabs(Params[0]) < MATRIX_DET_TOLERANCE ||
 440              fabs(Params[1]) < MATRIX_DET_TOLERANCE)
 441          {
 442              Val = 0;
 443          }
 444          else
 445          {
 446              if (R < 0)
 447                  Val = 0;
 448              else
 449                  Val = (pow(R, 1.0 / Params[0]) - Params[2]) / Params[1];
 450 
 451              if (Val < 0)
 452                  Val = 0;
 453          }
 454      }
 455      break;
 456 
 457 
 458     // IEC 61966-3
 459     // Y = (aX + b)^Gamma + c | X <= -b/a
 460     // Y = c                  | else
 461     case 3:
 462     {
 463         if (fabs(Params[1]) < MATRIX_DET_TOLERANCE)
 464         {
 465             Val = 0;
 466         }
 467         else
 468         {
 469             disc = -Params[2] / Params[1];
 470             if (disc < 0)
 471                 disc = 0;
 472 
 473             if (R >= disc) {
 474 
 475                 e = Params[1] * R + Params[2];
 476 
 477                 if (e > 0)
 478                     Val = pow(e, Params[0]) + Params[3];
 479                 else
 480                     Val = 0;
 481             }
 482             else
 483                 Val = Params[3];
 484         }
 485     }
 486     break;
 487 
 488 
 489     // Type 3 reversed
 490     // X=((Y-c)^1/g - b)/a      | (Y>=c)
 491     // X=-b/a                   | (Y<c)
 492     case -3:
 493     {
 494         if (fabs(Params[0]) < MATRIX_DET_TOLERANCE ||
 495             fabs(Params[1]) < MATRIX_DET_TOLERANCE)
 496         {
 497             Val = 0;
 498         }
 499         else
 500         {
 501             if (R >= Params[3]) {
 502 
 503                 e = R - Params[3];
 504 
 505                 if (e > 0)
 506                     Val = (pow(e, 1 / Params[0]) - Params[2]) / Params[1];
 507                 else
 508                     Val = 0;
 509             }
 510             else {
 511                 Val = -Params[2] / Params[1];
 512             }
 513         }
 514     }
 515     break;
 516 
 517 
 518     // IEC 61966-2.1 (sRGB)
 519     // Y = (aX + b)^Gamma | X >= d
 520     // Y = cX             | X < d
 521     case 4:
 522         if (R >= Params[4]) {
 523 
 524             e = Params[1]*R + Params[2];
 525 
 526             if (e > 0)
 527                 Val = pow(e, Params[0]);
 528             else
 529                 Val = 0;
 530         }
 531         else
 532             Val = R * Params[3];
 533         break;
 534 
 535     // Type 4 reversed
 536     // X=((Y^1/g-b)/a)    | Y >= (ad+b)^g
 537     // X=Y/c              | Y< (ad+b)^g
 538     case -4:
 539     {
 540 
 541         e = Params[1] * Params[4] + Params[2];
 542         if (e < 0)
 543             disc = 0;
 544         else
 545             disc = pow(e, Params[0]);
 546 
 547         if (R >= disc) {
 548 
 549             if (fabs(Params[0]) < MATRIX_DET_TOLERANCE ||
 550                 fabs(Params[1]) < MATRIX_DET_TOLERANCE)
 551 
 552                 Val = 0;
 553 
 554             else
 555                 Val = (pow(R, 1.0 / Params[0]) - Params[2]) / Params[1];
 556         }
 557         else {
 558 
 559             if (fabs(Params[3]) < MATRIX_DET_TOLERANCE)
 560                 Val = 0;
 561             else
 562                 Val = R / Params[3];
 563         }
 564 
 565     }
 566     break;
 567 
 568 
 569     // Y = (aX + b)^Gamma + e | X >= d
 570     // Y = cX + f             | X < d
 571     case 5:
 572         if (R >= Params[4]) {
 573 
 574             e = Params[1]*R + Params[2];
 575 
 576             if (e > 0)
 577                 Val = pow(e, Params[0]) + Params[5];
 578             else
 579                 Val = Params[5];
 580         }
 581         else
 582             Val = R*Params[3] + Params[6];
 583         break;
 584 
 585 
 586     // Reversed type 5
 587     // X=((Y-e)1/g-b)/a   | Y >=(ad+b)^g+e), cd+f
 588     // X=(Y-f)/c          | else
 589     case -5:
 590     {
 591         disc = Params[3] * Params[4] + Params[6];
 592         if (R >= disc) {
 593 
 594             e = R - Params[5];
 595             if (e < 0)
 596                 Val = 0;
 597             else
 598             {
 599                 if (fabs(Params[0]) < MATRIX_DET_TOLERANCE ||
 600                     fabs(Params[1]) < MATRIX_DET_TOLERANCE)
 601 
 602                     Val = 0;
 603                 else
 604                     Val = (pow(e, 1.0 / Params[0]) - Params[2]) / Params[1];
 605             }
 606         }
 607         else {
 608             if (fabs(Params[3]) < MATRIX_DET_TOLERANCE)
 609                 Val = 0;
 610             else
 611                 Val = (R - Params[6]) / Params[3];
 612         }
 613 
 614     }
 615     break;
 616 
 617 
 618     // Types 6,7,8 comes from segmented curves as described in ICCSpecRevision_02_11_06_Float.pdf
 619     // Type 6 is basically identical to type 5 without d
 620 
 621     // Y = (a * X + b) ^ Gamma + c
 622     case 6:
 623         e = Params[1]*R + Params[2];
 624 
 625         if (e < 0)
 626             Val = Params[3];
 627         else
 628             Val = pow(e, Params[0]) + Params[3];
 629         break;
 630 
 631     // ((Y - c) ^1/Gamma - b) / a
 632     case -6:
 633     {
 634         if (fabs(Params[0]) < MATRIX_DET_TOLERANCE ||
 635             fabs(Params[1]) < MATRIX_DET_TOLERANCE)
 636         {
 637             Val = 0;
 638         }
 639         else
 640         {
 641             e = R - Params[3];
 642             if (e < 0)
 643                 Val = 0;
 644             else
 645                 Val = (pow(e, 1.0 / Params[0]) - Params[2]) / Params[1];
 646         }
 647     }
 648     break;
 649 
 650 
 651     // Y = a * log (b * X^Gamma + c) + d
 652     case 7:
 653 
 654        e = Params[2] * pow(R, Params[0]) + Params[3];
 655        if (e <= 0)
 656            Val = Params[4];
 657        else
 658            Val = Params[1]*log10(e) + Params[4];
 659        break;
 660 
 661     // (Y - d) / a = log(b * X ^Gamma + c)
 662     // pow(10, (Y-d) / a) = b * X ^Gamma + c
 663     // pow((pow(10, (Y-d) / a) - c) / b, 1/g) = X
 664     case -7:
 665     {
 666         if (fabs(Params[0]) < MATRIX_DET_TOLERANCE ||
 667             fabs(Params[1]) < MATRIX_DET_TOLERANCE ||
 668             fabs(Params[2]) < MATRIX_DET_TOLERANCE)
 669         {
 670             Val = 0;
 671         }
 672         else
 673         {
 674             Val = pow((pow(10.0, (R - Params[4]) / Params[1]) - Params[3]) / Params[2], 1.0 / Params[0]);
 675         }
 676     }
 677     break;
 678 
 679 
 680    //Y = a * b^(c*X+d) + e
 681    case 8:
 682        Val = (Params[0] * pow(Params[1], Params[2] * R + Params[3]) + Params[4]);
 683        break;
 684 
 685 
 686    // Y = (log((y-e) / a) / log(b) - d ) / c
 687    // a=0, b=1, c=2, d=3, e=4,
 688    case -8:
 689 
 690        disc = R - Params[4];
 691        if (disc < 0) Val = 0;
 692        else
 693        {
 694            if (fabs(Params[0]) < MATRIX_DET_TOLERANCE ||
 695                fabs(Params[2]) < MATRIX_DET_TOLERANCE)
 696            {
 697                Val = 0;
 698            }
 699            else
 700            {
 701                Val = (log(disc / Params[0]) / log(Params[1]) - Params[3]) / Params[2];
 702            }
 703        }
 704        break;
 705 
 706 
 707    // S-Shaped: (1 - (1-x)^1/g)^1/g
 708    case 108:
 709        if (fabs(Params[0]) < MATRIX_DET_TOLERANCE)
 710            Val = 0;
 711        else
 712            Val = pow(1.0 - pow(1 - R, 1/Params[0]), 1/Params[0]);
 713       break;
 714 
 715     // y = (1 - (1-x)^1/g)^1/g
 716     // y^g = (1 - (1-x)^1/g)
 717     // 1 - y^g = (1-x)^1/g
 718     // (1 - y^g)^g = 1 - x
 719     // 1 - (1 - y^g)^g
 720     case -108:
 721         Val = 1 - pow(1 - pow(R, Params[0]), Params[0]);
 722         break;
 723 
 724     // Sigmoidals
 725     case 109:
 726         Val = sigmoid_factory(Params[0], R);
 727         break;
 728 
 729     case -109:
 730         Val = inverse_sigmoid_factory(Params[0], R);
 731         break;
 732 
 733     default:
 734         // Unsupported parametric curve. Should never reach here
 735         return 0;
 736     }
 737 
 738     return Val;
 739 }
 740 
 741 // Evaluate a segmented function for a single value. Return -Inf if no valid segment found .
 742 // If fn type is 0, perform an interpolation on the table
 743 static
 744 cmsFloat64Number EvalSegmentedFn(const cmsToneCurve *g, cmsFloat64Number R)
 745 {
 746     int i;
 747     cmsFloat32Number Out32;
 748     cmsFloat64Number Out;
 749 
 750     for (i = (int) g->nSegments - 1; i >= 0; --i) {
 751 
 752         // Check for domain
 753         if ((R > g->Segments[i].x0) && (R <= g->Segments[i].x1)) {
 754 
 755             // Type == 0 means segment is sampled
 756             if (g->Segments[i].Type == 0) {
 757 
 758                 cmsFloat32Number R1 = (cmsFloat32Number)(R - g->Segments[i].x0) / (g->Segments[i].x1 - g->Segments[i].x0);
 759 
 760                 // Setup the table (TODO: clean that)
 761                 g->SegInterp[i]->Table = g->Segments[i].SampledPoints;
 762 
 763                 g->SegInterp[i]->Interpolation.LerpFloat(&R1, &Out32, g->SegInterp[i]);
 764                 Out = (cmsFloat64Number) Out32;
 765 
 766             }
 767             else {
 768                 Out = g->Evals[i](g->Segments[i].Type, g->Segments[i].Params, R);
 769             }
 770 
 771             if (isinf(Out))
 772                 return PLUS_INF;
 773             else
 774             {
 775                 if (isinf(-Out))
 776                     return MINUS_INF;
 777             }
 778 
 779             return Out;
 780         }
 781     }
 782 
 783     return MINUS_INF;
 784 }
 785 
 786 // Access to estimated low-res table
 787 cmsUInt32Number CMSEXPORT cmsGetToneCurveEstimatedTableEntries(const cmsToneCurve* t)
 788 {
 789     _cmsAssert(t != NULL);
 790     return t ->nEntries;
 791 }
 792 
 793 const cmsUInt16Number* CMSEXPORT cmsGetToneCurveEstimatedTable(const cmsToneCurve* t)
 794 {
 795     _cmsAssert(t != NULL);
 796     return t ->Table16;
 797 }
 798 
 799 
 800 // Create an empty gamma curve, by using tables. This specifies only the limited-precision part, and leaves the
 801 // floating point description empty.
 802 cmsToneCurve* CMSEXPORT cmsBuildTabulatedToneCurve16(cmsContext ContextID, cmsUInt32Number nEntries, const cmsUInt16Number Values[])
 803 {
 804     return AllocateToneCurveStruct(ContextID, nEntries, 0, NULL, Values);
 805 }
 806 
 807 static
 808 cmsUInt32Number EntriesByGamma(cmsFloat64Number Gamma)
 809 {
 810     if (fabs(Gamma - 1.0) < 0.001) return 2;
 811     return 4096;
 812 }
 813 
 814 
 815 // Create a segmented gamma, fill the table
 816 cmsToneCurve* CMSEXPORT cmsBuildSegmentedToneCurve(cmsContext ContextID,
 817                                                    cmsUInt32Number nSegments, const cmsCurveSegment Segments[])
 818 {
 819     cmsUInt32Number i;
 820     cmsFloat64Number R, Val;
 821     cmsToneCurve* g;
 822     cmsUInt32Number nGridPoints = 4096;
 823 
 824     _cmsAssert(Segments != NULL);
 825 
 826     // Optimizatin for identity curves.
 827     if (nSegments == 1 && Segments[0].Type == 1) {
 828 
 829         nGridPoints = EntriesByGamma(Segments[0].Params[0]);
 830     }
 831 
 832     g = AllocateToneCurveStruct(ContextID, nGridPoints, nSegments, Segments, NULL);
 833     if (g == NULL) return NULL;
 834 
 835     // Once we have the floating point version, we can approximate a 16 bit table of 4096 entries
 836     // for performance reasons. This table would normally not be used except on 8/16 bits transforms.
 837     for (i = 0; i < nGridPoints; i++) {
 838 
 839         R   = (cmsFloat64Number) i / (nGridPoints-1);
 840 
 841         Val = EvalSegmentedFn(g, R);
 842 
 843         // Round and saturate
 844         g ->Table16[i] = _cmsQuickSaturateWord(Val * 65535.0);
 845     }
 846 
 847     return g;
 848 }
 849 
 850 // Use a segmented curve to store the floating point table
 851 cmsToneCurve* CMSEXPORT cmsBuildTabulatedToneCurveFloat(cmsContext ContextID, cmsUInt32Number nEntries, const cmsFloat32Number values[])
 852 {
 853     cmsCurveSegment Seg[3];
 854 
 855     // Do some housekeeping
 856     if (nEntries == 0 || values == NULL)
 857         return NULL;
 858 
 859     // A segmented tone curve should have function segments in the first and last positions
 860     // Initialize segmented curve part up to 0 to constant value = samples[0]
 861     Seg[0].x0 = MINUS_INF;
 862     Seg[0].x1 = 0;
 863     Seg[0].Type = 6;
 864 
 865     Seg[0].Params[0] = 1;
 866     Seg[0].Params[1] = 0;
 867     Seg[0].Params[2] = 0;
 868     Seg[0].Params[3] = values[0];
 869     Seg[0].Params[4] = 0;
 870 
 871     // From zero to 1
 872     Seg[1].x0 = 0;
 873     Seg[1].x1 = 1.0;
 874     Seg[1].Type = 0;
 875 
 876     Seg[1].nGridPoints = nEntries;
 877     Seg[1].SampledPoints = (cmsFloat32Number*) values;
 878 
 879     // Final segment is constant = lastsample
 880     Seg[2].x0 = 1.0;
 881     Seg[2].x1 = PLUS_INF;
 882     Seg[2].Type = 6;
 883 
 884     Seg[2].Params[0] = 1;
 885     Seg[2].Params[1] = 0;
 886     Seg[2].Params[2] = 0;
 887     Seg[2].Params[3] = values[nEntries-1];
 888     Seg[2].Params[4] = 0;
 889 
 890 
 891     return cmsBuildSegmentedToneCurve(ContextID, 3, Seg);
 892 }
 893 
 894 // Parametric curves
 895 //
 896 // Parameters goes as: Curve, a, b, c, d, e, f
 897 // Type is the ICC type +1
 898 // if type is negative, then the curve is analytically inverted
 899 cmsToneCurve* CMSEXPORT cmsBuildParametricToneCurve(cmsContext ContextID, cmsInt32Number Type, const cmsFloat64Number Params[])
 900 {
 901     cmsCurveSegment Seg0;
 902     int Pos = 0;
 903     cmsUInt32Number size;
 904     _cmsParametricCurvesCollection* c = GetParametricCurveByType(ContextID, Type, &Pos);
 905 
 906     _cmsAssert(Params != NULL);
 907 
 908     if (c == NULL) {
 909         cmsSignalError(ContextID, cmsERROR_UNKNOWN_EXTENSION, "Invalid parametric curve type %d", Type);
 910         return NULL;
 911     }
 912 
 913     memset(&Seg0, 0, sizeof(Seg0));
 914 
 915     Seg0.x0   = MINUS_INF;
 916     Seg0.x1   = PLUS_INF;
 917     Seg0.Type = Type;
 918 
 919     size = c->ParameterCount[Pos] * sizeof(cmsFloat64Number);
 920     memmove(Seg0.Params, Params, size);
 921 
 922     return cmsBuildSegmentedToneCurve(ContextID, 1, &Seg0);
 923 }
 924 
 925 
 926 
 927 // Build a gamma table based on gamma constant
 928 cmsToneCurve* CMSEXPORT cmsBuildGamma(cmsContext ContextID, cmsFloat64Number Gamma)
 929 {
 930     return cmsBuildParametricToneCurve(ContextID, 1, &Gamma);
 931 }
 932 
 933 
 934 // Free all memory taken by the gamma curve
 935 void CMSEXPORT cmsFreeToneCurve(cmsToneCurve* Curve)
 936 {
 937     cmsContext ContextID;
 938 
 939     if (Curve == NULL) return;
 940 
 941     ContextID = Curve ->InterpParams->ContextID;
 942 
 943     _cmsFreeInterpParams(Curve ->InterpParams);
 944 
 945     if (Curve -> Table16)
 946         _cmsFree(ContextID, Curve ->Table16);
 947 
 948     if (Curve ->Segments) {
 949 
 950         cmsUInt32Number i;
 951 
 952         for (i=0; i < Curve ->nSegments; i++) {
 953 
 954             if (Curve ->Segments[i].SampledPoints) {
 955                 _cmsFree(ContextID, Curve ->Segments[i].SampledPoints);
 956             }
 957 
 958             if (Curve ->SegInterp[i] != 0)
 959                 _cmsFreeInterpParams(Curve->SegInterp[i]);
 960         }
 961 
 962         _cmsFree(ContextID, Curve ->Segments);
 963         _cmsFree(ContextID, Curve ->SegInterp);
 964     }
 965 
 966     if (Curve -> Evals)
 967         _cmsFree(ContextID, Curve -> Evals);
 968 
 969     _cmsFree(ContextID, Curve);
 970 }
 971 
 972 // Utility function, free 3 gamma tables
 973 void CMSEXPORT cmsFreeToneCurveTriple(cmsToneCurve* Curve[3])
 974 {
 975 
 976     _cmsAssert(Curve != NULL);
 977 
 978     if (Curve[0] != NULL) cmsFreeToneCurve(Curve[0]);
 979     if (Curve[1] != NULL) cmsFreeToneCurve(Curve[1]);
 980     if (Curve[2] != NULL) cmsFreeToneCurve(Curve[2]);
 981 
 982     Curve[0] = Curve[1] = Curve[2] = NULL;
 983 }
 984 
 985 
 986 // Duplicate a gamma table
 987 cmsToneCurve* CMSEXPORT cmsDupToneCurve(const cmsToneCurve* In)
 988 {
 989     if (In == NULL) return NULL;
 990 
 991     return  AllocateToneCurveStruct(In ->InterpParams ->ContextID, In ->nEntries, In ->nSegments, In ->Segments, In ->Table16);
 992 }
 993 
 994 // Joins two curves for X and Y. Curves should be monotonic.
 995 // We want to get
 996 //
 997 //      y = Y^-1(X(t))
 998 //
 999 cmsToneCurve* CMSEXPORT cmsJoinToneCurve(cmsContext ContextID,
1000                                       const cmsToneCurve* X,
1001                                       const cmsToneCurve* Y, cmsUInt32Number nResultingPoints)
1002 {
1003     cmsToneCurve* out = NULL;
1004     cmsToneCurve* Yreversed = NULL;
1005     cmsFloat32Number t, x;
1006     cmsFloat32Number* Res = NULL;
1007     cmsUInt32Number i;
1008 
1009 
1010     _cmsAssert(X != NULL);
1011     _cmsAssert(Y != NULL);
1012 
1013     Yreversed = cmsReverseToneCurveEx(nResultingPoints, Y);
1014     if (Yreversed == NULL) goto Error;
1015 
1016     Res = (cmsFloat32Number*) _cmsCalloc(ContextID, nResultingPoints, sizeof(cmsFloat32Number));
1017     if (Res == NULL) goto Error;
1018 
1019     //Iterate
1020     for (i=0; i <  nResultingPoints; i++) {
1021 
1022         t = (cmsFloat32Number) i / (cmsFloat32Number)(nResultingPoints-1);
1023         x = cmsEvalToneCurveFloat(X,  t);
1024         Res[i] = cmsEvalToneCurveFloat(Yreversed, x);
1025     }
1026 
1027     // Allocate space for output
1028     out = cmsBuildTabulatedToneCurveFloat(ContextID, nResultingPoints, Res);
1029 
1030 Error:
1031 
1032     if (Res != NULL) _cmsFree(ContextID, Res);
1033     if (Yreversed != NULL) cmsFreeToneCurve(Yreversed);
1034 
1035     return out;
1036 }
1037 
1038 
1039 
1040 // Get the surrounding nodes. This is tricky on non-monotonic tables
1041 static
1042 int GetInterval(cmsFloat64Number In, const cmsUInt16Number LutTable[], const struct _cms_interp_struc* p)
1043 {
1044     int i;
1045     int y0, y1;
1046 
1047     // A 1 point table is not allowed
1048     if (p -> Domain[0] < 1) return -1;
1049 
1050     // Let's see if ascending or descending.
1051     if (LutTable[0] < LutTable[p ->Domain[0]]) {
1052 
1053         // Table is overall ascending
1054         for (i = (int) p->Domain[0] - 1; i >= 0; --i) {
1055 
1056             y0 = LutTable[i];
1057             y1 = LutTable[i+1];
1058 
1059             if (y0 <= y1) { // Increasing
1060                 if (In >= y0 && In <= y1) return i;
1061             }
1062             else
1063                 if (y1 < y0) { // Decreasing
1064                     if (In >= y1 && In <= y0) return i;
1065                 }
1066         }
1067     }
1068     else {
1069         // Table is overall descending
1070         for (i=0; i < (int) p -> Domain[0]; i++) {
1071 
1072             y0 = LutTable[i];
1073             y1 = LutTable[i+1];
1074 
1075             if (y0 <= y1) { // Increasing
1076                 if (In >= y0 && In <= y1) return i;
1077             }
1078             else
1079                 if (y1 < y0) { // Decreasing
1080                     if (In >= y1 && In <= y0) return i;
1081                 }
1082         }
1083     }
1084 
1085     return -1;
1086 }
1087 
1088 // Reverse a gamma table
1089 cmsToneCurve* CMSEXPORT cmsReverseToneCurveEx(cmsUInt32Number nResultSamples, const cmsToneCurve* InCurve)
1090 {
1091     cmsToneCurve *out;
1092     cmsFloat64Number a = 0, b = 0, y, x1, y1, x2, y2;
1093     int i, j;
1094     int Ascending;
1095 
1096     _cmsAssert(InCurve != NULL);
1097 
1098     // Try to reverse it analytically whatever possible
1099 
1100     if (InCurve ->nSegments == 1 && InCurve ->Segments[0].Type > 0 &&
1101         /* InCurve -> Segments[0].Type <= 5 */
1102         GetParametricCurveByType(InCurve ->InterpParams->ContextID, InCurve ->Segments[0].Type, NULL) != NULL) {
1103 
1104         return cmsBuildParametricToneCurve(InCurve ->InterpParams->ContextID,
1105                                        -(InCurve -> Segments[0].Type),
1106                                        InCurve -> Segments[0].Params);
1107     }
1108 
1109     // Nope, reverse the table.
1110     out = cmsBuildTabulatedToneCurve16(InCurve ->InterpParams->ContextID, nResultSamples, NULL);
1111     if (out == NULL)
1112         return NULL;
1113 
1114     // We want to know if this is an ascending or descending table
1115     Ascending = !cmsIsToneCurveDescending(InCurve);
1116 
1117     // Iterate across Y axis
1118     for (i=0; i < (int) nResultSamples; i++) {
1119 
1120         y = (cmsFloat64Number) i * 65535.0 / (nResultSamples - 1);
1121 
1122         // Find interval in which y is within.
1123         j = GetInterval(y, InCurve->Table16, InCurve->InterpParams);
1124         if (j >= 0) {
1125 
1126 
1127             // Get limits of interval
1128             x1 = InCurve ->Table16[j];
1129             x2 = InCurve ->Table16[j+1];
1130 
1131             y1 = (cmsFloat64Number) (j * 65535.0) / (InCurve ->nEntries - 1);
1132             y2 = (cmsFloat64Number) ((j+1) * 65535.0 ) / (InCurve ->nEntries - 1);
1133 
1134             // If collapsed, then use any
1135             if (x1 == x2) {
1136 
1137                 out ->Table16[i] = _cmsQuickSaturateWord(Ascending ? y2 : y1);
1138                 continue;
1139 
1140             } else {
1141 
1142                 // Interpolate
1143                 a = (y2 - y1) / (x2 - x1);
1144                 b = y2 - a * x2;
1145             }
1146         }
1147 
1148         out ->Table16[i] = _cmsQuickSaturateWord(a* y + b);
1149     }
1150 
1151 
1152     return out;
1153 }
1154 
1155 // Reverse a gamma table
1156 cmsToneCurve* CMSEXPORT cmsReverseToneCurve(const cmsToneCurve* InGamma)
1157 {
1158     _cmsAssert(InGamma != NULL);
1159 
1160     return cmsReverseToneCurveEx(4096, InGamma);
1161 }
1162 
1163 // From: Eilers, P.H.C. (1994) Smoothing and interpolation with finite
1164 // differences. in: Graphic Gems IV, Heckbert, P.S. (ed.), Academic press.
1165 //
1166 // Smoothing and interpolation with second differences.
1167 //
1168 //   Input:  weights (w), data (y): vector from 1 to m.
1169 //   Input:  smoothing parameter (lambda), length (m).
1170 //   Output: smoothed vector (z): vector from 1 to m.
1171 
1172 static
1173 cmsBool smooth2(cmsContext ContextID, cmsFloat32Number w[], cmsFloat32Number y[],
1174                 cmsFloat32Number z[], cmsFloat32Number lambda, int m)
1175 {
1176     int i, i1, i2;
1177     cmsFloat32Number *c, *d, *e;
1178     cmsBool st;
1179 
1180 
1181     c = (cmsFloat32Number*) _cmsCalloc(ContextID, MAX_NODES_IN_CURVE, sizeof(cmsFloat32Number));
1182     d = (cmsFloat32Number*) _cmsCalloc(ContextID, MAX_NODES_IN_CURVE, sizeof(cmsFloat32Number));
1183     e = (cmsFloat32Number*) _cmsCalloc(ContextID, MAX_NODES_IN_CURVE, sizeof(cmsFloat32Number));
1184 
1185     if (c != NULL && d != NULL && e != NULL) {
1186 
1187 
1188     d[1] = w[1] + lambda;
1189     c[1] = -2 * lambda / d[1];
1190     e[1] = lambda /d[1];
1191     z[1] = w[1] * y[1];
1192     d[2] = w[2] + 5 * lambda - d[1] * c[1] *  c[1];
1193     c[2] = (-4 * lambda - d[1] * c[1] * e[1]) / d[2];
1194     e[2] = lambda / d[2];
1195     z[2] = w[2] * y[2] - c[1] * z[1];
1196 
1197     for (i = 3; i < m - 1; i++) {
1198         i1 = i - 1; i2 = i - 2;
1199         d[i]= w[i] + 6 * lambda - c[i1] * c[i1] * d[i1] - e[i2] * e[i2] * d[i2];
1200         c[i] = (-4 * lambda -d[i1] * c[i1] * e[i1])/ d[i];
1201         e[i] = lambda / d[i];
1202         z[i] = w[i] * y[i] - c[i1] * z[i1] - e[i2] * z[i2];
1203     }
1204 
1205     i1 = m - 2; i2 = m - 3;
1206 
1207     d[m - 1] = w[m - 1] + 5 * lambda -c[i1] * c[i1] * d[i1] - e[i2] * e[i2] * d[i2];
1208     c[m - 1] = (-2 * lambda - d[i1] * c[i1] * e[i1]) / d[m - 1];
1209     z[m - 1] = w[m - 1] * y[m - 1] - c[i1] * z[i1] - e[i2] * z[i2];
1210     i1 = m - 1; i2 = m - 2;
1211 
1212     d[m] = w[m] + lambda - c[i1] * c[i1] * d[i1] - e[i2] * e[i2] * d[i2];
1213     z[m] = (w[m] * y[m] - c[i1] * z[i1] - e[i2] * z[i2]) / d[m];
1214     z[m - 1] = z[m - 1] / d[m - 1] - c[m - 1] * z[m];
1215 
1216     for (i = m - 2; 1<= i; i--)
1217         z[i] = z[i] / d[i] - c[i] * z[i + 1] - e[i] * z[i + 2];
1218 
1219       st = TRUE;
1220     }
1221     else st = FALSE;
1222 
1223     if (c != NULL) _cmsFree(ContextID, c);
1224     if (d != NULL) _cmsFree(ContextID, d);
1225     if (e != NULL) _cmsFree(ContextID, e);
1226 
1227     return st;
1228 }
1229 
1230 // Smooths a curve sampled at regular intervals.
1231 cmsBool  CMSEXPORT cmsSmoothToneCurve(cmsToneCurve* Tab, cmsFloat64Number lambda)
1232 {
1233     cmsBool SuccessStatus = TRUE;
1234     cmsFloat32Number *w, *y, *z;
1235     cmsUInt32Number i, nItems, Zeros, Poles;
1236     cmsBool notCheck = FALSE;
1237 
1238     if (Tab != NULL && Tab->InterpParams != NULL)
1239     {
1240         cmsContext ContextID = Tab->InterpParams->ContextID;
1241 
1242         if (!cmsIsToneCurveLinear(Tab)) // Only non-linear curves need smoothing
1243         {
1244             nItems = Tab->nEntries;
1245             if (nItems < MAX_NODES_IN_CURVE)
1246             {
1247                 // Allocate one more item than needed
1248                 w = (cmsFloat32Number *)_cmsCalloc(ContextID, nItems + 1, sizeof(cmsFloat32Number));
1249                 y = (cmsFloat32Number *)_cmsCalloc(ContextID, nItems + 1, sizeof(cmsFloat32Number));
1250                 z = (cmsFloat32Number *)_cmsCalloc(ContextID, nItems + 1, sizeof(cmsFloat32Number));
1251 
1252                 if (w != NULL && y != NULL && z != NULL) // Ensure no memory allocation failure
1253                 {
1254                     memset(w, 0, (nItems + 1) * sizeof(cmsFloat32Number));
1255                     memset(y, 0, (nItems + 1) * sizeof(cmsFloat32Number));
1256                     memset(z, 0, (nItems + 1) * sizeof(cmsFloat32Number));
1257 
1258                     for (i = 0; i < nItems; i++)
1259                     {
1260                         y[i + 1] = (cmsFloat32Number)Tab->Table16[i];
1261                         w[i + 1] = 1.0;
1262                     }
1263 
1264                     if (lambda < 0)
1265                     {
1266                         notCheck = TRUE;
1267                         lambda = -lambda;
1268                     }
1269 
1270                     if (smooth2(ContextID, w, y, z, (cmsFloat32Number)lambda, (int)nItems))
1271                     {
1272                         // Do some reality - checking...
1273 
1274                         Zeros = Poles = 0;
1275                         for (i = nItems; i > 1; --i)
1276                         {
1277                             if (z[i] == 0.) Zeros++;
1278                             if (z[i] >= 65535.) Poles++;
1279                             if (z[i] < z[i - 1])
1280                             {
1281                                 cmsSignalError(ContextID, cmsERROR_RANGE, "cmsSmoothToneCurve: Non-Monotonic.");
1282                                 SuccessStatus = notCheck;
1283                                 break;
1284                             }
1285                         }
1286 
1287                         if (SuccessStatus && Zeros > (nItems / 3))
1288                         {
1289                             cmsSignalError(ContextID, cmsERROR_RANGE, "cmsSmoothToneCurve: Degenerated, mostly zeros.");
1290                             SuccessStatus = notCheck;
1291                         }
1292 
1293                         if (SuccessStatus && Poles > (nItems / 3))
1294                         {
1295                             cmsSignalError(ContextID, cmsERROR_RANGE, "cmsSmoothToneCurve: Degenerated, mostly poles.");
1296                             SuccessStatus = notCheck;
1297                         }
1298 
1299                         if (SuccessStatus) // Seems ok
1300                         {
1301                             for (i = 0; i < nItems; i++)
1302                             {
1303                                 // Clamp to cmsUInt16Number
1304                                 Tab->Table16[i] = _cmsQuickSaturateWord(z[i + 1]);
1305                             }
1306                         }
1307                     }
1308                     else // Could not smooth
1309                     {
1310                         cmsSignalError(ContextID, cmsERROR_RANGE, "cmsSmoothToneCurve: Function smooth2 failed.");
1311                         SuccessStatus = FALSE;
1312                     }
1313                 }
1314                 else // One or more buffers could not be allocated
1315                 {
1316                     cmsSignalError(ContextID, cmsERROR_RANGE, "cmsSmoothToneCurve: Could not allocate memory.");
1317                     SuccessStatus = FALSE;
1318                 }
1319 
1320                 if (z != NULL)
1321                     _cmsFree(ContextID, z);
1322 
1323                 if (y != NULL)
1324                     _cmsFree(ContextID, y);
1325 
1326                 if (w != NULL)
1327                     _cmsFree(ContextID, w);
1328             }
1329             else // too many items in the table
1330             {
1331                 cmsSignalError(ContextID, cmsERROR_RANGE, "cmsSmoothToneCurve: Too many points.");
1332                 SuccessStatus = FALSE;
1333             }
1334         }
1335     }
1336     else // Tab parameter or Tab->InterpParams is NULL
1337     {
1338         // Can't signal an error here since the ContextID is not known at this point
1339         SuccessStatus = FALSE;
1340     }
1341 
1342     return SuccessStatus;
1343 }
1344 
1345 // Is a table linear? Do not use parametric since we cannot guarantee some weird parameters resulting
1346 // in a linear table. This way assures it is linear in 12 bits, which should be enough in most cases.
1347 cmsBool CMSEXPORT cmsIsToneCurveLinear(const cmsToneCurve* Curve)
1348 {
1349     int i;
1350     int diff;
1351 
1352     _cmsAssert(Curve != NULL);
1353 
1354     for (i=0; i < (int) Curve ->nEntries; i++) {
1355 
1356         diff = abs((int) Curve->Table16[i] - (int) _cmsQuantizeVal(i, Curve ->nEntries));
1357         if (diff > 0x0f)
1358             return FALSE;
1359     }
1360 
1361     return TRUE;
1362 }
1363 
1364 // Same, but for monotonicity
1365 cmsBool  CMSEXPORT cmsIsToneCurveMonotonic(const cmsToneCurve* t)
1366 {
1367     cmsUInt32Number n;
1368     int i, last;
1369     cmsBool lDescending;
1370 
1371     _cmsAssert(t != NULL);
1372 
1373     // Degenerated curves are monotonic? Ok, let's pass them
1374     n = t ->nEntries;
1375     if (n < 2) return TRUE;
1376 
1377     // Curve direction
1378     lDescending = cmsIsToneCurveDescending(t);
1379 
1380     if (lDescending) {
1381 
1382         last = t ->Table16[0];
1383 
1384         for (i = 1; i < (int) n; i++) {
1385 
1386             if (t ->Table16[i] - last > 2) // We allow some ripple
1387                 return FALSE;
1388             else
1389                 last = t ->Table16[i];
1390 
1391         }
1392     }
1393     else {
1394 
1395         last = t ->Table16[n-1];
1396 
1397         for (i = (int) n - 2; i >= 0; --i) {
1398 
1399             if (t ->Table16[i] - last > 2)
1400                 return FALSE;
1401             else
1402                 last = t ->Table16[i];
1403 
1404         }
1405     }
1406 
1407     return TRUE;
1408 }
1409 
1410 // Same, but for descending tables
1411 cmsBool  CMSEXPORT cmsIsToneCurveDescending(const cmsToneCurve* t)
1412 {
1413     _cmsAssert(t != NULL);
1414 
1415     return t ->Table16[0] > t ->Table16[t ->nEntries-1];
1416 }
1417 
1418 
1419 // Another info fn: is out gamma table multisegment?
1420 cmsBool  CMSEXPORT cmsIsToneCurveMultisegment(const cmsToneCurve* t)
1421 {
1422     _cmsAssert(t != NULL);
1423 
1424     return t -> nSegments > 1;
1425 }
1426 
1427 cmsInt32Number  CMSEXPORT cmsGetToneCurveParametricType(const cmsToneCurve* t)
1428 {
1429     _cmsAssert(t != NULL);
1430 
1431     if (t -> nSegments != 1) return 0;
1432     return t ->Segments[0].Type;
1433 }
1434 
1435 // We need accuracy this time
1436 cmsFloat32Number CMSEXPORT cmsEvalToneCurveFloat(const cmsToneCurve* Curve, cmsFloat32Number v)
1437 {
1438     _cmsAssert(Curve != NULL);
1439 
1440     // Check for 16 bits table. If so, this is a limited-precision tone curve
1441     if (Curve ->nSegments == 0) {
1442 
1443         cmsUInt16Number In, Out;
1444 
1445         In = (cmsUInt16Number) _cmsQuickSaturateWord(v * 65535.0);
1446         Out = cmsEvalToneCurve16(Curve, In);
1447 
1448         return (cmsFloat32Number) (Out / 65535.0);
1449     }
1450 
1451     return (cmsFloat32Number) EvalSegmentedFn(Curve, v);
1452 }
1453 
1454 // We need xput over here
1455 cmsUInt16Number CMSEXPORT cmsEvalToneCurve16(const cmsToneCurve* Curve, cmsUInt16Number v)
1456 {
1457     cmsUInt16Number out;
1458 
1459     _cmsAssert(Curve != NULL);
1460 
1461     Curve ->InterpParams ->Interpolation.Lerp16(&v, &out, Curve ->InterpParams);
1462     return out;
1463 }
1464 
1465 
1466 // Least squares fitting.
1467 // A mathematical procedure for finding the best-fitting curve to a given set of points by
1468 // minimizing the sum of the squares of the offsets ("the residuals") of the points from the curve.
1469 // The sum of the squares of the offsets is used instead of the offset absolute values because
1470 // this allows the residuals to be treated as a continuous differentiable quantity.
1471 //
1472 // y = f(x) = x ^ g
1473 //
1474 // R  = (yi - (xi^g))
1475 // R2 = (yi - (xi^g))2
1476 // SUM R2 = SUM (yi - (xi^g))2
1477 //
1478 // dR2/dg = -2 SUM x^g log(x)(y - x^g)
1479 // solving for dR2/dg = 0
1480 //
1481 // g = 1/n * SUM(log(y) / log(x))
1482 
1483 cmsFloat64Number CMSEXPORT cmsEstimateGamma(const cmsToneCurve* t, cmsFloat64Number Precision)
1484 {
1485     cmsFloat64Number gamma, sum, sum2;
1486     cmsFloat64Number n, x, y, Std;
1487     cmsUInt32Number i;
1488 
1489     _cmsAssert(t != NULL);
1490 
1491     sum = sum2 = n = 0;
1492 
1493     // Excluding endpoints
1494     for (i=1; i < (MAX_NODES_IN_CURVE-1); i++) {
1495 
1496         x = (cmsFloat64Number) i / (MAX_NODES_IN_CURVE-1);
1497         y = (cmsFloat64Number) cmsEvalToneCurveFloat(t, (cmsFloat32Number) x);
1498 
1499         // Avoid 7% on lower part to prevent
1500         // artifacts due to linear ramps
1501 
1502         if (y > 0. && y < 1. && x > 0.07) {
1503 
1504             gamma = log(y) / log(x);
1505             sum  += gamma;
1506             sum2 += gamma * gamma;
1507             n++;
1508         }
1509     }
1510 
1511     // We need enough valid samples
1512     if (n <= 1) return -1.0;
1513 
1514     // Take a look on SD to see if gamma isn't exponential at all
1515     Std = sqrt((n * sum2 - sum * sum) / (n*(n-1)));
1516 
1517     if (Std > Precision)
1518         return -1.0;
1519 
1520     return (sum / n);   // The mean
1521 }
1522 
1523 
1524 // Retrieve parameters on one-segment tone curves
1525 
1526 cmsFloat64Number* CMSEXPORT cmsGetToneCurveParams(const cmsToneCurve* t)
1527 {
1528     _cmsAssert(t != NULL);
1529 
1530     if (t->nSegments != 1) return NULL;
1531     return t->Segments[0].Params;
1532 }