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