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-2020 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     9,                                  // # of curve types
  92     { 1, 2, 3, 4, 5, 6, 7, 8, 108 },    // Parametric curve ID
  93     { 1, 3, 4, 5, 7, 4, 5, 5, 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 optimation 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 // Parametric Fn using floating point
 342 static
 343 cmsFloat64Number DefaultEvalParametricFn(cmsInt32Number Type, const cmsFloat64Number Params[], cmsFloat64Number R)
 344 {
 345     cmsFloat64Number e, Val, disc;
 346 
 347     switch (Type) {
 348 
 349    // X = Y ^ Gamma
 350     case 1:
 351         if (R < 0) {
 352 
 353             if (fabs(Params[0] - 1.0) < MATRIX_DET_TOLERANCE)
 354                 Val = R;
 355             else
 356                 Val = 0;
 357         }
 358         else
 359             Val = pow(R, Params[0]);
 360         break;
 361 
 362     // Type 1 Reversed: X = Y ^1/gamma
 363     case -1:
 364         if (R < 0) {
 365 
 366             if (fabs(Params[0] - 1.0) < MATRIX_DET_TOLERANCE)
 367                 Val = R;
 368             else
 369                 Val = 0;
 370         }
 371         else
 372         {
 373             if (fabs(Params[0]) < MATRIX_DET_TOLERANCE)
 374                 Val = PLUS_INF;
 375             else
 376                 Val = pow(R, 1 / Params[0]);
 377         }
 378         break;
 379 
 380     // CIE 122-1966
 381     // Y = (aX + b)^Gamma  | X >= -b/a
 382     // Y = 0               | else
 383     case 2:
 384     {
 385 
 386         if (fabs(Params[1]) < MATRIX_DET_TOLERANCE)
 387         {
 388             Val = 0;
 389         }
 390         else
 391         {
 392             disc = -Params[2] / Params[1];
 393 
 394             if (R >= disc) {
 395 
 396                 e = Params[1] * R + Params[2];
 397 
 398                 if (e > 0)
 399                     Val = pow(e, Params[0]);
 400                 else
 401                     Val = 0;
 402             }
 403             else
 404                 Val = 0;
 405         }
 406     }
 407     break;
 408 
 409      // Type 2 Reversed
 410      // X = (Y ^1/g  - b) / a
 411      case -2:
 412      {
 413          if (fabs(Params[0]) < MATRIX_DET_TOLERANCE ||
 414              fabs(Params[1]) < MATRIX_DET_TOLERANCE)
 415          {
 416              Val = 0;
 417          }
 418          else
 419          {
 420              if (R < 0)
 421                  Val = 0;
 422              else
 423                  Val = (pow(R, 1.0 / Params[0]) - Params[2]) / Params[1];
 424 
 425              if (Val < 0)
 426                  Val = 0;
 427          }
 428      }
 429      break;
 430 
 431 
 432     // IEC 61966-3
 433     // Y = (aX + b)^Gamma | X <= -b/a
 434     // Y = c              | else
 435     case 3:
 436     {
 437         if (fabs(Params[1]) < MATRIX_DET_TOLERANCE)
 438         {
 439             Val = 0;
 440         }
 441         else
 442         {
 443             disc = -Params[2] / Params[1];
 444             if (disc < 0)
 445                 disc = 0;
 446 
 447             if (R >= disc) {
 448 
 449                 e = Params[1] * R + Params[2];
 450 
 451                 if (e > 0)
 452                     Val = pow(e, Params[0]) + Params[3];
 453                 else
 454                     Val = 0;
 455             }
 456             else
 457                 Val = Params[3];
 458         }
 459     }
 460     break;
 461 
 462 
 463     // Type 3 reversed
 464     // X=((Y-c)^1/g - b)/a      | (Y>=c)
 465     // X=-b/a                   | (Y<c)
 466     case -3:
 467     {
 468         if (fabs(Params[1]) < MATRIX_DET_TOLERANCE)
 469         {
 470             Val = 0;
 471         }
 472         else
 473         {
 474             if (R >= Params[3]) {
 475 
 476                 e = R - Params[3];
 477 
 478                 if (e > 0)
 479                     Val = (pow(e, 1 / Params[0]) - Params[2]) / Params[1];
 480                 else
 481                     Val = 0;
 482             }
 483             else {
 484                 Val = -Params[2] / Params[1];
 485             }
 486         }
 487     }
 488     break;
 489 
 490 
 491     // IEC 61966-2.1 (sRGB)
 492     // Y = (aX + b)^Gamma | X >= d
 493     // Y = cX             | X < d
 494     case 4:
 495         if (R >= Params[4]) {
 496 
 497             e = Params[1]*R + Params[2];
 498 
 499             if (e > 0)
 500                 Val = pow(e, Params[0]);
 501             else
 502                 Val = 0;
 503         }
 504         else
 505             Val = R * Params[3];
 506         break;
 507 
 508     // Type 4 reversed
 509     // X=((Y^1/g-b)/a)    | Y >= (ad+b)^g
 510     // X=Y/c              | Y< (ad+b)^g
 511     case -4:
 512     {
 513         if (fabs(Params[0]) < MATRIX_DET_TOLERANCE ||
 514             fabs(Params[1]) < MATRIX_DET_TOLERANCE ||
 515             fabs(Params[3]) < MATRIX_DET_TOLERANCE)
 516         {
 517             Val = 0;
 518         }
 519         else
 520         {
 521             e = Params[1] * Params[4] + Params[2];
 522             if (e < 0)
 523                 disc = 0;
 524             else
 525                 disc = pow(e, Params[0]);
 526 
 527             if (R >= disc) {
 528 
 529                 Val = (pow(R, 1.0 / Params[0]) - Params[2]) / Params[1];
 530             }
 531             else {
 532                 Val = R / Params[3];
 533             }
 534         }
 535     }
 536     break;
 537 
 538 
 539     // Y = (aX + b)^Gamma + e | X >= d
 540     // Y = cX + f             | X < d
 541     case 5:
 542         if (R >= Params[4]) {
 543 
 544             e = Params[1]*R + Params[2];
 545 
 546             if (e > 0)
 547                 Val = pow(e, Params[0]) + Params[5];
 548             else
 549                 Val = Params[5];
 550         }
 551         else
 552             Val = R*Params[3] + Params[6];
 553         break;
 554 
 555 
 556     // Reversed type 5
 557     // X=((Y-e)1/g-b)/a   | Y >=(ad+b)^g+e), cd+f
 558     // X=(Y-f)/c          | else
 559     case -5:
 560     {
 561         if (fabs(Params[1]) < MATRIX_DET_TOLERANCE ||
 562             fabs(Params[3]) < MATRIX_DET_TOLERANCE)
 563         {
 564             Val = 0;
 565         }
 566         else
 567         {
 568             disc = Params[3] * Params[4] + Params[6];
 569             if (R >= disc) {
 570 
 571                 e = R - Params[5];
 572                 if (e < 0)
 573                     Val = 0;
 574                 else
 575                     Val = (pow(e, 1.0 / Params[0]) - Params[2]) / Params[1];
 576             }
 577             else {
 578                 Val = (R - Params[6]) / Params[3];
 579             }
 580         }
 581     }
 582     break;
 583 
 584 
 585     // Types 6,7,8 comes from segmented curves as described in ICCSpecRevision_02_11_06_Float.pdf
 586     // Type 6 is basically identical to type 5 without d
 587 
 588     // Y = (a * X + b) ^ Gamma + c
 589     case 6:
 590         e = Params[1]*R + Params[2];
 591 
 592         if (e < 0)
 593             Val = Params[3];
 594         else
 595             Val = pow(e, Params[0]) + Params[3];
 596         break;
 597 
 598     // ((Y - c) ^1/Gamma - b) / a
 599     case -6:
 600     {
 601         if (fabs(Params[1]) < MATRIX_DET_TOLERANCE)
 602         {
 603             Val = 0;
 604         }
 605         else
 606         {
 607             e = R - Params[3];
 608             if (e < 0)
 609                 Val = 0;
 610             else
 611                 Val = (pow(e, 1.0 / Params[0]) - Params[2]) / Params[1];
 612         }
 613     }
 614     break;
 615 
 616 
 617     // Y = a * log (b * X^Gamma + c) + d
 618     case 7:
 619 
 620        e = Params[2] * pow(R, Params[0]) + Params[3];
 621        if (e <= 0)
 622            Val = Params[4];
 623        else
 624            Val = Params[1]*log10(e) + Params[4];
 625        break;
 626 
 627     // (Y - d) / a = log(b * X ^Gamma + c)
 628     // pow(10, (Y-d) / a) = b * X ^Gamma + c
 629     // pow((pow(10, (Y-d) / a) - c) / b, 1/g) = X
 630     case -7:
 631     {
 632         if (fabs(Params[0]) < MATRIX_DET_TOLERANCE ||
 633             fabs(Params[1]) < MATRIX_DET_TOLERANCE ||
 634             fabs(Params[2]) < MATRIX_DET_TOLERANCE)
 635         {
 636             Val = 0;
 637         }
 638         else
 639         {
 640             Val = pow((pow(10.0, (R - Params[4]) / Params[1]) - Params[3]) / Params[2], 1.0 / Params[0]);
 641         }
 642     }
 643     break;
 644 
 645 
 646    //Y = a * b^(c*X+d) + e
 647    case 8:
 648        Val = (Params[0] * pow(Params[1], Params[2] * R + Params[3]) + Params[4]);
 649        break;
 650 
 651 
 652    // Y = (log((y-e) / a) / log(b) - d ) / c
 653    // a=0, b=1, c=2, d=3, e=4,
 654    case -8:
 655 
 656        disc = R - Params[4];
 657        if (disc < 0) Val = 0;
 658        else
 659        {
 660            if (fabs(Params[0]) < MATRIX_DET_TOLERANCE ||
 661                fabs(Params[2]) < MATRIX_DET_TOLERANCE)
 662            {
 663                Val = 0;
 664            }
 665            else
 666            {
 667                Val = (log(disc / Params[0]) / log(Params[1]) - Params[3]) / Params[2];
 668            }
 669        }
 670        break;
 671 
 672    // S-Shaped: (1 - (1-x)^1/g)^1/g
 673    case 108:
 674        if (fabs(Params[0]) < MATRIX_DET_TOLERANCE)
 675            Val = 0;
 676        else
 677            Val = pow(1.0 - pow(1 - R, 1/Params[0]), 1/Params[0]);
 678       break;
 679 
 680     // y = (1 - (1-x)^1/g)^1/g
 681     // y^g = (1 - (1-x)^1/g)
 682     // 1 - y^g = (1-x)^1/g
 683     // (1 - y^g)^g = 1 - x
 684     // 1 - (1 - y^g)^g
 685     case -108:
 686         Val = 1 - pow(1 - pow(R, Params[0]), Params[0]);
 687         break;
 688 
 689     default:
 690         // Unsupported parametric curve. Should never reach here
 691         return 0;
 692     }
 693 
 694     return Val;
 695 }
 696 
 697 // Evaluate a segmented function for a single value. Return -Inf if no valid segment found .
 698 // If fn type is 0, perform an interpolation on the table
 699 static
 700 cmsFloat64Number EvalSegmentedFn(const cmsToneCurve *g, cmsFloat64Number R)
 701 {
 702     int i;
 703     cmsFloat32Number Out32;
 704     cmsFloat64Number Out;
 705 
 706     for (i = (int) g->nSegments - 1; i >= 0; --i) {
 707 
 708         // Check for domain
 709         if ((R > g->Segments[i].x0) && (R <= g->Segments[i].x1)) {
 710 
 711             // Type == 0 means segment is sampled
 712             if (g->Segments[i].Type == 0) {
 713 
 714                 cmsFloat32Number R1 = (cmsFloat32Number)(R - g->Segments[i].x0) / (g->Segments[i].x1 - g->Segments[i].x0);
 715 
 716                 // Setup the table (TODO: clean that)
 717                 g->SegInterp[i]->Table = g->Segments[i].SampledPoints;
 718 
 719                 g->SegInterp[i]->Interpolation.LerpFloat(&R1, &Out32, g->SegInterp[i]);
 720                 Out = (cmsFloat64Number) Out32;
 721 
 722             }
 723             else {
 724                 Out = g->Evals[i](g->Segments[i].Type, g->Segments[i].Params, R);
 725             }
 726 
 727             if (isinf(Out))
 728                 return PLUS_INF;
 729             else
 730             {
 731                 if (isinf(-Out))
 732                     return MINUS_INF;
 733             }
 734 
 735             return Out;
 736         }
 737     }
 738 
 739     return MINUS_INF;
 740 }
 741 
 742 // Access to estimated low-res table
 743 cmsUInt32Number CMSEXPORT cmsGetToneCurveEstimatedTableEntries(const cmsToneCurve* t)
 744 {
 745     _cmsAssert(t != NULL);
 746     return t ->nEntries;
 747 }
 748 
 749 const cmsUInt16Number* CMSEXPORT cmsGetToneCurveEstimatedTable(const cmsToneCurve* t)
 750 {
 751     _cmsAssert(t != NULL);
 752     return t ->Table16;
 753 }
 754 
 755 
 756 // Create an empty gamma curve, by using tables. This specifies only the limited-precision part, and leaves the
 757 // floating point description empty.
 758 cmsToneCurve* CMSEXPORT cmsBuildTabulatedToneCurve16(cmsContext ContextID, cmsUInt32Number nEntries, const cmsUInt16Number Values[])
 759 {
 760     return AllocateToneCurveStruct(ContextID, nEntries, 0, NULL, Values);
 761 }
 762 
 763 static
 764 cmsUInt32Number EntriesByGamma(cmsFloat64Number Gamma)
 765 {
 766     if (fabs(Gamma - 1.0) < 0.001) return 2;
 767     return 4096;
 768 }
 769 
 770 
 771 // Create a segmented gamma, fill the table
 772 cmsToneCurve* CMSEXPORT cmsBuildSegmentedToneCurve(cmsContext ContextID,
 773                                                    cmsUInt32Number nSegments, const cmsCurveSegment Segments[])
 774 {
 775     cmsUInt32Number i;
 776     cmsFloat64Number R, Val;
 777     cmsToneCurve* g;
 778     cmsUInt32Number nGridPoints = 4096;
 779 
 780     _cmsAssert(Segments != NULL);
 781 
 782     // Optimizatin for identity curves.
 783     if (nSegments == 1 && Segments[0].Type == 1) {
 784 
 785         nGridPoints = EntriesByGamma(Segments[0].Params[0]);
 786     }
 787 
 788     g = AllocateToneCurveStruct(ContextID, nGridPoints, nSegments, Segments, NULL);
 789     if (g == NULL) return NULL;
 790 
 791     // Once we have the floating point version, we can approximate a 16 bit table of 4096 entries
 792     // for performance reasons. This table would normally not be used except on 8/16 bits transforms.
 793     for (i = 0; i < nGridPoints; i++) {
 794 
 795         R   = (cmsFloat64Number) i / (nGridPoints-1);
 796 
 797         Val = EvalSegmentedFn(g, R);
 798 
 799         // Round and saturate
 800         g ->Table16[i] = _cmsQuickSaturateWord(Val * 65535.0);
 801     }
 802 
 803     return g;
 804 }
 805 
 806 // Use a segmented curve to store the floating point table
 807 cmsToneCurve* CMSEXPORT cmsBuildTabulatedToneCurveFloat(cmsContext ContextID, cmsUInt32Number nEntries, const cmsFloat32Number values[])
 808 {
 809     cmsCurveSegment Seg[3];
 810 
 811     // A segmented tone curve should have function segments in the first and last positions
 812     // Initialize segmented curve part up to 0 to constant value = samples[0]
 813     Seg[0].x0 = MINUS_INF;
 814     Seg[0].x1 = 0;
 815     Seg[0].Type = 6;
 816 
 817     Seg[0].Params[0] = 1;
 818     Seg[0].Params[1] = 0;
 819     Seg[0].Params[2] = 0;
 820     Seg[0].Params[3] = values[0];
 821     Seg[0].Params[4] = 0;
 822 
 823     // From zero to 1
 824     Seg[1].x0 = 0;
 825     Seg[1].x1 = 1.0;
 826     Seg[1].Type = 0;
 827 
 828     Seg[1].nGridPoints = nEntries;
 829     Seg[1].SampledPoints = (cmsFloat32Number*) values;
 830 
 831     // Final segment is constant = lastsample
 832     Seg[2].x0 = 1.0;
 833     Seg[2].x1 = PLUS_INF;
 834     Seg[2].Type = 6;
 835 
 836     Seg[2].Params[0] = 1;
 837     Seg[2].Params[1] = 0;
 838     Seg[2].Params[2] = 0;
 839     Seg[2].Params[3] = values[nEntries-1];
 840     Seg[2].Params[4] = 0;
 841 
 842 
 843     return cmsBuildSegmentedToneCurve(ContextID, 3, Seg);
 844 }
 845 
 846 // Parametric curves
 847 //
 848 // Parameters goes as: Curve, a, b, c, d, e, f
 849 // Type is the ICC type +1
 850 // if type is negative, then the curve is analytically inverted
 851 cmsToneCurve* CMSEXPORT cmsBuildParametricToneCurve(cmsContext ContextID, cmsInt32Number Type, const cmsFloat64Number Params[])
 852 {
 853     cmsCurveSegment Seg0;
 854     int Pos = 0;
 855     cmsUInt32Number size;
 856     _cmsParametricCurvesCollection* c = GetParametricCurveByType(ContextID, Type, &Pos);
 857 
 858     _cmsAssert(Params != NULL);
 859 
 860     if (c == NULL) {
 861         cmsSignalError(ContextID, cmsERROR_UNKNOWN_EXTENSION, "Invalid parametric curve type %d", Type);
 862         return NULL;
 863     }
 864 
 865     memset(&Seg0, 0, sizeof(Seg0));
 866 
 867     Seg0.x0   = MINUS_INF;
 868     Seg0.x1   = PLUS_INF;
 869     Seg0.Type = Type;
 870 
 871     size = c->ParameterCount[Pos] * sizeof(cmsFloat64Number);
 872     memmove(Seg0.Params, Params, size);
 873 
 874     return cmsBuildSegmentedToneCurve(ContextID, 1, &Seg0);
 875 }
 876 
 877 
 878 
 879 // Build a gamma table based on gamma constant
 880 cmsToneCurve* CMSEXPORT cmsBuildGamma(cmsContext ContextID, cmsFloat64Number Gamma)
 881 {
 882     return cmsBuildParametricToneCurve(ContextID, 1, &Gamma);
 883 }
 884 
 885 
 886 // Free all memory taken by the gamma curve
 887 void CMSEXPORT cmsFreeToneCurve(cmsToneCurve* Curve)
 888 {
 889     cmsContext ContextID;
 890 
 891     if (Curve == NULL) return;
 892 
 893     ContextID = Curve ->InterpParams->ContextID;
 894 
 895     _cmsFreeInterpParams(Curve ->InterpParams);
 896 
 897     if (Curve -> Table16)
 898         _cmsFree(ContextID, Curve ->Table16);
 899 
 900     if (Curve ->Segments) {
 901 
 902         cmsUInt32Number i;
 903 
 904         for (i=0; i < Curve ->nSegments; i++) {
 905 
 906             if (Curve ->Segments[i].SampledPoints) {
 907                 _cmsFree(ContextID, Curve ->Segments[i].SampledPoints);
 908             }
 909 
 910             if (Curve ->SegInterp[i] != 0)
 911                 _cmsFreeInterpParams(Curve->SegInterp[i]);
 912         }
 913 
 914         _cmsFree(ContextID, Curve ->Segments);
 915         _cmsFree(ContextID, Curve ->SegInterp);
 916     }
 917 
 918     if (Curve -> Evals)
 919         _cmsFree(ContextID, Curve -> Evals);
 920 
 921     _cmsFree(ContextID, Curve);
 922 }
 923 
 924 // Utility function, free 3 gamma tables
 925 void CMSEXPORT cmsFreeToneCurveTriple(cmsToneCurve* Curve[3])
 926 {
 927 
 928     _cmsAssert(Curve != NULL);
 929 
 930     if (Curve[0] != NULL) cmsFreeToneCurve(Curve[0]);
 931     if (Curve[1] != NULL) cmsFreeToneCurve(Curve[1]);
 932     if (Curve[2] != NULL) cmsFreeToneCurve(Curve[2]);
 933 
 934     Curve[0] = Curve[1] = Curve[2] = NULL;
 935 }
 936 
 937 
 938 // Duplicate a gamma table
 939 cmsToneCurve* CMSEXPORT cmsDupToneCurve(const cmsToneCurve* In)
 940 {
 941     if (In == NULL) return NULL;
 942 
 943     return  AllocateToneCurveStruct(In ->InterpParams ->ContextID, In ->nEntries, In ->nSegments, In ->Segments, In ->Table16);
 944 }
 945 
 946 // Joins two curves for X and Y. Curves should be monotonic.
 947 // We want to get
 948 //
 949 //      y = Y^-1(X(t))
 950 //
 951 cmsToneCurve* CMSEXPORT cmsJoinToneCurve(cmsContext ContextID,
 952                                       const cmsToneCurve* X,
 953                                       const cmsToneCurve* Y, cmsUInt32Number nResultingPoints)
 954 {
 955     cmsToneCurve* out = NULL;
 956     cmsToneCurve* Yreversed = NULL;
 957     cmsFloat32Number t, x;
 958     cmsFloat32Number* Res = NULL;
 959     cmsUInt32Number i;
 960 
 961 
 962     _cmsAssert(X != NULL);
 963     _cmsAssert(Y != NULL);
 964 
 965     Yreversed = cmsReverseToneCurveEx(nResultingPoints, Y);
 966     if (Yreversed == NULL) goto Error;
 967 
 968     Res = (cmsFloat32Number*) _cmsCalloc(ContextID, nResultingPoints, sizeof(cmsFloat32Number));
 969     if (Res == NULL) goto Error;
 970 
 971     //Iterate
 972     for (i=0; i <  nResultingPoints; i++) {
 973 
 974         t = (cmsFloat32Number) i / (nResultingPoints-1);
 975         x = cmsEvalToneCurveFloat(X,  t);
 976         Res[i] = cmsEvalToneCurveFloat(Yreversed, x);
 977     }
 978 
 979     // Allocate space for output
 980     out = cmsBuildTabulatedToneCurveFloat(ContextID, nResultingPoints, Res);
 981 
 982 Error:
 983 
 984     if (Res != NULL) _cmsFree(ContextID, Res);
 985     if (Yreversed != NULL) cmsFreeToneCurve(Yreversed);
 986 
 987     return out;
 988 }
 989 
 990 
 991 
 992 // Get the surrounding nodes. This is tricky on non-monotonic tables
 993 static
 994 int GetInterval(cmsFloat64Number In, const cmsUInt16Number LutTable[], const struct _cms_interp_struc* p)
 995 {
 996     int i;
 997     int y0, y1;
 998 
 999     // A 1 point table is not allowed
1000     if (p -> Domain[0] < 1) return -1;
1001 
1002     // Let's see if ascending or descending.
1003     if (LutTable[0] < LutTable[p ->Domain[0]]) {
1004 
1005         // Table is overall ascending
1006         for (i = (int) p->Domain[0] - 1; i >= 0; --i) {
1007 
1008             y0 = LutTable[i];
1009             y1 = LutTable[i+1];
1010 
1011             if (y0 <= y1) { // Increasing
1012                 if (In >= y0 && In <= y1) return i;
1013             }
1014             else
1015                 if (y1 < y0) { // Decreasing
1016                     if (In >= y1 && In <= y0) return i;
1017                 }
1018         }
1019     }
1020     else {
1021         // Table is overall descending
1022         for (i=0; i < (int) p -> Domain[0]; i++) {
1023 
1024             y0 = LutTable[i];
1025             y1 = LutTable[i+1];
1026 
1027             if (y0 <= y1) { // Increasing
1028                 if (In >= y0 && In <= y1) return i;
1029             }
1030             else
1031                 if (y1 < y0) { // Decreasing
1032                     if (In >= y1 && In <= y0) return i;
1033                 }
1034         }
1035     }
1036 
1037     return -1;
1038 }
1039 
1040 // Reverse a gamma table
1041 cmsToneCurve* CMSEXPORT cmsReverseToneCurveEx(cmsUInt32Number nResultSamples, const cmsToneCurve* InCurve)
1042 {
1043     cmsToneCurve *out;
1044     cmsFloat64Number a = 0, b = 0, y, x1, y1, x2, y2;
1045     int i, j;
1046     int Ascending;
1047 
1048     _cmsAssert(InCurve != NULL);
1049 
1050     // Try to reverse it analytically whatever possible
1051 
1052     if (InCurve ->nSegments == 1 && InCurve ->Segments[0].Type > 0 &&
1053         /* InCurve -> Segments[0].Type <= 5 */
1054         GetParametricCurveByType(InCurve ->InterpParams->ContextID, InCurve ->Segments[0].Type, NULL) != NULL) {
1055 
1056         return cmsBuildParametricToneCurve(InCurve ->InterpParams->ContextID,
1057                                        -(InCurve -> Segments[0].Type),
1058                                        InCurve -> Segments[0].Params);
1059     }
1060 
1061     // Nope, reverse the table.
1062     out = cmsBuildTabulatedToneCurve16(InCurve ->InterpParams->ContextID, nResultSamples, NULL);
1063     if (out == NULL)
1064         return NULL;
1065 
1066     // We want to know if this is an ascending or descending table
1067     Ascending = !cmsIsToneCurveDescending(InCurve);
1068 
1069     // Iterate across Y axis
1070     for (i=0; i < (int) nResultSamples; i++) {
1071 
1072         y = (cmsFloat64Number) i * 65535.0 / (nResultSamples - 1);
1073 
1074         // Find interval in which y is within.
1075         j = GetInterval(y, InCurve->Table16, InCurve->InterpParams);
1076         if (j >= 0) {
1077 
1078 
1079             // Get limits of interval
1080             x1 = InCurve ->Table16[j];
1081             x2 = InCurve ->Table16[j+1];
1082 
1083             y1 = (cmsFloat64Number) (j * 65535.0) / (InCurve ->nEntries - 1);
1084             y2 = (cmsFloat64Number) ((j+1) * 65535.0 ) / (InCurve ->nEntries - 1);
1085 
1086             // If collapsed, then use any
1087             if (x1 == x2) {
1088 
1089                 out ->Table16[i] = _cmsQuickSaturateWord(Ascending ? y2 : y1);
1090                 continue;
1091 
1092             } else {
1093 
1094                 // Interpolate
1095                 a = (y2 - y1) / (x2 - x1);
1096                 b = y2 - a * x2;
1097             }
1098         }
1099 
1100         out ->Table16[i] = _cmsQuickSaturateWord(a* y + b);
1101     }
1102 
1103 
1104     return out;
1105 }
1106 
1107 // Reverse a gamma table
1108 cmsToneCurve* CMSEXPORT cmsReverseToneCurve(const cmsToneCurve* InGamma)
1109 {
1110     _cmsAssert(InGamma != NULL);
1111 
1112     return cmsReverseToneCurveEx(4096, InGamma);
1113 }
1114 
1115 // From: Eilers, P.H.C. (1994) Smoothing and interpolation with finite
1116 // differences. in: Graphic Gems IV, Heckbert, P.S. (ed.), Academic press.
1117 //
1118 // Smoothing and interpolation with second differences.
1119 //
1120 //   Input:  weights (w), data (y): vector from 1 to m.
1121 //   Input:  smoothing parameter (lambda), length (m).
1122 //   Output: smoothed vector (z): vector from 1 to m.
1123 
1124 static
1125 cmsBool smooth2(cmsContext ContextID, cmsFloat32Number w[], cmsFloat32Number y[],
1126                 cmsFloat32Number z[], cmsFloat32Number lambda, int m)
1127 {
1128     int i, i1, i2;
1129     cmsFloat32Number *c, *d, *e;
1130     cmsBool st;
1131 
1132 
1133     c = (cmsFloat32Number*) _cmsCalloc(ContextID, MAX_NODES_IN_CURVE, sizeof(cmsFloat32Number));
1134     d = (cmsFloat32Number*) _cmsCalloc(ContextID, MAX_NODES_IN_CURVE, sizeof(cmsFloat32Number));
1135     e = (cmsFloat32Number*) _cmsCalloc(ContextID, MAX_NODES_IN_CURVE, sizeof(cmsFloat32Number));
1136 
1137     if (c != NULL && d != NULL && e != NULL) {
1138 
1139 
1140     d[1] = w[1] + lambda;
1141     c[1] = -2 * lambda / d[1];
1142     e[1] = lambda /d[1];
1143     z[1] = w[1] * y[1];
1144     d[2] = w[2] + 5 * lambda - d[1] * c[1] *  c[1];
1145     c[2] = (-4 * lambda - d[1] * c[1] * e[1]) / d[2];
1146     e[2] = lambda / d[2];
1147     z[2] = w[2] * y[2] - c[1] * z[1];
1148 
1149     for (i = 3; i < m - 1; i++) {
1150         i1 = i - 1; i2 = i - 2;
1151         d[i]= w[i] + 6 * lambda - c[i1] * c[i1] * d[i1] - e[i2] * e[i2] * d[i2];
1152         c[i] = (-4 * lambda -d[i1] * c[i1] * e[i1])/ d[i];
1153         e[i] = lambda / d[i];
1154         z[i] = w[i] * y[i] - c[i1] * z[i1] - e[i2] * z[i2];
1155     }
1156 
1157     i1 = m - 2; i2 = m - 3;
1158 
1159     d[m - 1] = w[m - 1] + 5 * lambda -c[i1] * c[i1] * d[i1] - e[i2] * e[i2] * d[i2];
1160     c[m - 1] = (-2 * lambda - d[i1] * c[i1] * e[i1]) / d[m - 1];
1161     z[m - 1] = w[m - 1] * y[m - 1] - c[i1] * z[i1] - e[i2] * z[i2];
1162     i1 = m - 1; i2 = m - 2;
1163 
1164     d[m] = w[m] + lambda - c[i1] * c[i1] * d[i1] - e[i2] * e[i2] * d[i2];
1165     z[m] = (w[m] * y[m] - c[i1] * z[i1] - e[i2] * z[i2]) / d[m];
1166     z[m - 1] = z[m - 1] / d[m - 1] - c[m - 1] * z[m];
1167 
1168     for (i = m - 2; 1<= i; i--)
1169         z[i] = z[i] / d[i] - c[i] * z[i + 1] - e[i] * z[i + 2];
1170 
1171       st = TRUE;
1172     }
1173     else st = FALSE;
1174 
1175     if (c != NULL) _cmsFree(ContextID, c);
1176     if (d != NULL) _cmsFree(ContextID, d);
1177     if (e != NULL) _cmsFree(ContextID, e);
1178 
1179     return st;
1180 }
1181 
1182 // Smooths a curve sampled at regular intervals.
1183 cmsBool  CMSEXPORT cmsSmoothToneCurve(cmsToneCurve* Tab, cmsFloat64Number lambda)
1184 {
1185     cmsBool SuccessStatus = TRUE;
1186     cmsFloat32Number *w, *y, *z;
1187     cmsUInt32Number i, nItems, Zeros, Poles;
1188 
1189     if (Tab != NULL && Tab->InterpParams != NULL)
1190     {
1191         cmsContext ContextID = Tab->InterpParams->ContextID;
1192 
1193         if (!cmsIsToneCurveLinear(Tab)) // Only non-linear curves need smoothing
1194         {
1195             nItems = Tab->nEntries;
1196             if (nItems < MAX_NODES_IN_CURVE)
1197             {
1198                 // Allocate one more item than needed
1199                 w = (cmsFloat32Number *)_cmsCalloc(ContextID, nItems + 1, sizeof(cmsFloat32Number));
1200                 y = (cmsFloat32Number *)_cmsCalloc(ContextID, nItems + 1, sizeof(cmsFloat32Number));
1201                 z = (cmsFloat32Number *)_cmsCalloc(ContextID, nItems + 1, sizeof(cmsFloat32Number));
1202 
1203                 if (w != NULL && y != NULL && z != NULL) // Ensure no memory allocation failure
1204                 {
1205                     memset(w, 0, (nItems + 1) * sizeof(cmsFloat32Number));
1206                     memset(y, 0, (nItems + 1) * sizeof(cmsFloat32Number));
1207                     memset(z, 0, (nItems + 1) * sizeof(cmsFloat32Number));
1208 
1209                     for (i = 0; i < nItems; i++)
1210                     {
1211                         y[i + 1] = (cmsFloat32Number)Tab->Table16[i];
1212                         w[i + 1] = 1.0;
1213                     }
1214 
1215                     if (smooth2(ContextID, w, y, z, (cmsFloat32Number)lambda, (int)nItems))
1216                     {
1217                         // Do some reality - checking...
1218 
1219                         Zeros = Poles = 0;
1220                         for (i = nItems; i > 1; --i)
1221                         {
1222                             if (z[i] == 0.) Zeros++;
1223                             if (z[i] >= 65535.) Poles++;
1224                             if (z[i] < z[i - 1])
1225                             {
1226                                 cmsSignalError(ContextID, cmsERROR_RANGE, "cmsSmoothToneCurve: Non-Monotonic.");
1227                                 SuccessStatus = FALSE;
1228                                 break;
1229                             }
1230                         }
1231 
1232                         if (SuccessStatus && Zeros > (nItems / 3))
1233                         {
1234                             cmsSignalError(ContextID, cmsERROR_RANGE, "cmsSmoothToneCurve: Degenerated, mostly zeros.");
1235                             SuccessStatus = FALSE;
1236                         }
1237 
1238                         if (SuccessStatus && Poles > (nItems / 3))
1239                         {
1240                             cmsSignalError(ContextID, cmsERROR_RANGE, "cmsSmoothToneCurve: Degenerated, mostly poles.");
1241                             SuccessStatus = FALSE;
1242                         }
1243 
1244                         if (SuccessStatus) // Seems ok
1245                         {
1246                             for (i = 0; i < nItems; i++)
1247                             {
1248                                 // Clamp to cmsUInt16Number
1249                                 Tab->Table16[i] = _cmsQuickSaturateWord(z[i + 1]);
1250                             }
1251                         }
1252                     }
1253                     else // Could not smooth
1254                     {
1255                         cmsSignalError(ContextID, cmsERROR_RANGE, "cmsSmoothToneCurve: Function smooth2 failed.");
1256                         SuccessStatus = FALSE;
1257                     }
1258                 }
1259                 else // One or more buffers could not be allocated
1260                 {
1261                     cmsSignalError(ContextID, cmsERROR_RANGE, "cmsSmoothToneCurve: Could not allocate memory.");
1262                     SuccessStatus = FALSE;
1263                 }
1264 
1265                 if (z != NULL)
1266                     _cmsFree(ContextID, z);
1267 
1268                 if (y != NULL)
1269                     _cmsFree(ContextID, y);
1270 
1271                 if (w != NULL)
1272                     _cmsFree(ContextID, w);
1273             }
1274             else // too many items in the table
1275             {
1276                 cmsSignalError(ContextID, cmsERROR_RANGE, "cmsSmoothToneCurve: Too many points.");
1277                 SuccessStatus = FALSE;
1278             }
1279         }
1280     }
1281     else // Tab parameter or Tab->InterpParams is NULL
1282     {
1283         // Can't signal an error here since the ContextID is not known at this point
1284         SuccessStatus = FALSE;
1285     }
1286 
1287     return SuccessStatus;
1288 }
1289 
1290 // Is a table linear? Do not use parametric since we cannot guarantee some weird parameters resulting
1291 // in a linear table. This way assures it is linear in 12 bits, which should be enough in most cases.
1292 cmsBool CMSEXPORT cmsIsToneCurveLinear(const cmsToneCurve* Curve)
1293 {
1294     int i;
1295     int diff;
1296 
1297     _cmsAssert(Curve != NULL);
1298 
1299     for (i=0; i < (int) Curve ->nEntries; i++) {
1300 
1301         diff = abs((int) Curve->Table16[i] - (int) _cmsQuantizeVal(i, Curve ->nEntries));
1302         if (diff > 0x0f)
1303             return FALSE;
1304     }
1305 
1306     return TRUE;
1307 }
1308 
1309 // Same, but for monotonicity
1310 cmsBool  CMSEXPORT cmsIsToneCurveMonotonic(const cmsToneCurve* t)
1311 {
1312     cmsUInt32Number n;
1313     int i, last;
1314     cmsBool lDescending;
1315 
1316     _cmsAssert(t != NULL);
1317 
1318     // Degenerated curves are monotonic? Ok, let's pass them
1319     n = t ->nEntries;
1320     if (n < 2) return TRUE;
1321 
1322     // Curve direction
1323     lDescending = cmsIsToneCurveDescending(t);
1324 
1325     if (lDescending) {
1326 
1327         last = t ->Table16[0];
1328 
1329         for (i = 1; i < (int) n; i++) {
1330 
1331             if (t ->Table16[i] - last > 2) // We allow some ripple
1332                 return FALSE;
1333             else
1334                 last = t ->Table16[i];
1335 
1336         }
1337     }
1338     else {
1339 
1340         last = t ->Table16[n-1];
1341 
1342         for (i = (int) n - 2; i >= 0; --i) {
1343 
1344             if (t ->Table16[i] - last > 2)
1345                 return FALSE;
1346             else
1347                 last = t ->Table16[i];
1348 
1349         }
1350     }
1351 
1352     return TRUE;
1353 }
1354 
1355 // Same, but for descending tables
1356 cmsBool  CMSEXPORT cmsIsToneCurveDescending(const cmsToneCurve* t)
1357 {
1358     _cmsAssert(t != NULL);
1359 
1360     return t ->Table16[0] > t ->Table16[t ->nEntries-1];
1361 }
1362 
1363 
1364 // Another info fn: is out gamma table multisegment?
1365 cmsBool  CMSEXPORT cmsIsToneCurveMultisegment(const cmsToneCurve* t)
1366 {
1367     _cmsAssert(t != NULL);
1368 
1369     return t -> nSegments > 1;
1370 }
1371 
1372 cmsInt32Number  CMSEXPORT cmsGetToneCurveParametricType(const cmsToneCurve* t)
1373 {
1374     _cmsAssert(t != NULL);
1375 
1376     if (t -> nSegments != 1) return 0;
1377     return t ->Segments[0].Type;
1378 }
1379 
1380 // We need accuracy this time
1381 cmsFloat32Number CMSEXPORT cmsEvalToneCurveFloat(const cmsToneCurve* Curve, cmsFloat32Number v)
1382 {
1383     _cmsAssert(Curve != NULL);
1384 
1385     // Check for 16 bits table. If so, this is a limited-precision tone curve
1386     if (Curve ->nSegments == 0) {
1387 
1388         cmsUInt16Number In, Out;
1389 
1390         In = (cmsUInt16Number) _cmsQuickSaturateWord(v * 65535.0);
1391         Out = cmsEvalToneCurve16(Curve, In);
1392 
1393         return (cmsFloat32Number) (Out / 65535.0);
1394     }
1395 
1396     return (cmsFloat32Number) EvalSegmentedFn(Curve, v);
1397 }
1398 
1399 // We need xput over here
1400 cmsUInt16Number CMSEXPORT cmsEvalToneCurve16(const cmsToneCurve* Curve, cmsUInt16Number v)
1401 {
1402     cmsUInt16Number out;
1403 
1404     _cmsAssert(Curve != NULL);
1405 
1406     Curve ->InterpParams ->Interpolation.Lerp16(&v, &out, Curve ->InterpParams);
1407     return out;
1408 }
1409 
1410 
1411 // Least squares fitting.
1412 // A mathematical procedure for finding the best-fitting curve to a given set of points by
1413 // minimizing the sum of the squares of the offsets ("the residuals") of the points from the curve.
1414 // The sum of the squares of the offsets is used instead of the offset absolute values because
1415 // this allows the residuals to be treated as a continuous differentiable quantity.
1416 //
1417 // y = f(x) = x ^ g
1418 //
1419 // R  = (yi - (xi^g))
1420 // R2 = (yi - (xi^g))2
1421 // SUM R2 = SUM (yi - (xi^g))2
1422 //
1423 // dR2/dg = -2 SUM x^g log(x)(y - x^g)
1424 // solving for dR2/dg = 0
1425 //
1426 // g = 1/n * SUM(log(y) / log(x))
1427 
1428 cmsFloat64Number CMSEXPORT cmsEstimateGamma(const cmsToneCurve* t, cmsFloat64Number Precision)
1429 {
1430     cmsFloat64Number gamma, sum, sum2;
1431     cmsFloat64Number n, x, y, Std;
1432     cmsUInt32Number i;
1433 
1434     _cmsAssert(t != NULL);
1435 
1436     sum = sum2 = n = 0;
1437 
1438     // Excluding endpoints
1439     for (i=1; i < (MAX_NODES_IN_CURVE-1); i++) {
1440 
1441         x = (cmsFloat64Number) i / (MAX_NODES_IN_CURVE-1);
1442         y = (cmsFloat64Number) cmsEvalToneCurveFloat(t, (cmsFloat32Number) x);
1443 
1444         // Avoid 7% on lower part to prevent
1445         // artifacts due to linear ramps
1446 
1447         if (y > 0. && y < 1. && x > 0.07) {
1448 
1449             gamma = log(y) / log(x);
1450             sum  += gamma;
1451             sum2 += gamma * gamma;
1452             n++;
1453         }
1454     }
1455 
1456     // Take a look on SD to see if gamma isn't exponential at all
1457     Std = sqrt((n * sum2 - sum * sum) / (n*(n-1)));
1458 
1459     if (Std > Precision)
1460         return -1.0;
1461 
1462     return (sum / n);   // The mean
1463 }
1464 
1465 
1466 // Retrieve parameters on one-segment tone curves
1467 
1468 cmsFloat64Number* CMSEXPORT cmsGetToneCurveParams(const cmsToneCurve* t)
1469 {
1470     _cmsAssert(t != NULL);
1471 
1472     if (t->nSegments != 1) return NULL;
1473     return t->Segments[0].Params;
1474 }