< prev index next >

src/java.desktop/share/native/liblcms/cmsps2.c

Print this page



  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-2017 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 //---------------------------------------------------------------------------------


  90   NOTE: CLUT-based monochrome profiles are NOT supported. So, cmsFLAGS_MATRIXINPUT
  91   flag is forced on such profiles.
  92 
  93     [ /CIEBasedA
  94       <<
  95             /DecodeA { transfer function } bind
  96             /MatrixA [D50]
  97             /RangeLMN [ 0.0 cmsD50X 0.0 cmsD50Y 0.0 cmsD50Z ]
  98             /WhitePoint [D50]
  99             /BlackPoint [BP]
 100             /RenderingIntent (intent)
 101       >>
 102     ]
 103 
 104    On simpler profiles, the PCS is already XYZ, so no conversion is required.
 105 
 106 
 107    Matrix-shaper based
 108    -------------------
 109 
 110    This is implemented both with /CIEBasedABC or /CIEBasedDEF on dependig
 111    of profile implementation. Since here there are no interpolation tables, I do
 112    the conversion directly to XYZ
 113 
 114 
 115 
 116     [ /CIEBasedABC
 117             <<
 118                 /DecodeABC [ {transfer1} {transfer2} {transfer3} ]
 119                 /MatrixABC [Matrix]
 120                 /RangeLMN [ 0.0 cmsD50X 0.0 cmsD50Y 0.0 cmsD50Z ]
 121                 /DecodeLMN [ { / 2} dup dup ]
 122                 /WhitePoint [D50]
 123                 /BlackPoint [BP]
 124                 /RenderingIntent (intent)
 125             >>
 126     ]
 127 
 128 
 129     CLUT based
 130     ----------
 131 


 307     const char* PostMin;
 308 
 309     int  FixWhite;    // Force mapping of pure white
 310 
 311     cmsColorSpaceSignature  ColorSpace;  // ColorSpace of profile
 312 
 313 
 314 } cmsPsSamplerCargo;
 315 
 316 static int _cmsPSActualColumn = 0;
 317 
 318 
 319 // Convert to byte
 320 static
 321 cmsUInt8Number Word2Byte(cmsUInt16Number w)
 322 {
 323     return (cmsUInt8Number) floor((cmsFloat64Number) w / 257.0 + 0.5);
 324 }
 325 
 326 
 327 // Convert to byte (using ICC2 notation)
 328 /*
 329 static
 330 cmsUInt8Number L2Byte(cmsUInt16Number w)
 331 {
 332     int ww = w + 0x0080;
 333 
 334     if (ww > 0xFFFF) return 0xFF;
 335 
 336     return (cmsUInt8Number) ((cmsUInt16Number) (ww >> 8) & 0xFF);
 337 }
 338 */
 339 
 340 // Write a cooked byte
 341 
 342 static
 343 void WriteByte(cmsIOHANDLER* m, cmsUInt8Number b)
 344 {
 345     _cmsIOPrintf(m, "%02x", b);
 346     _cmsPSActualColumn += 2;
 347 
 348     if (_cmsPSActualColumn > MAXPSCOLS) {
 349 
 350         _cmsIOPrintf(m, "\n");
 351         _cmsPSActualColumn = 0;
 352     }
 353 }
 354 
 355 // ----------------------------------------------------------------- PostScript generation
 356 
 357 
 358 // Removes offending Carriage returns

 359 static
 360 char* RemoveCR(const char* txt)
 361 {
 362     static char Buffer[2048];
 363     char* pt;
 364 
 365     strncpy(Buffer, txt, 2047);
 366     Buffer[2047] = 0;
 367     for (pt = Buffer; *pt; pt++)
 368             if (*pt == '\n' || *pt == '\r') *pt = ' ';
 369 
 370     return Buffer;
 371 
 372 }
 373 
 374 static
 375 void EmitHeader(cmsIOHANDLER* m, const char* Title, cmsHPROFILE hProfile)
 376 {
 377     time_t timer;
 378     cmsMLU *Description, *Copyright;


 436     switch (RenderingIntent) {
 437 
 438         case INTENT_PERCEPTUAL:            intent = "Perceptual"; break;
 439         case INTENT_RELATIVE_COLORIMETRIC: intent = "RelativeColorimetric"; break;
 440         case INTENT_ABSOLUTE_COLORIMETRIC: intent = "AbsoluteColorimetric"; break;
 441         case INTENT_SATURATION:            intent = "Saturation"; break;
 442 
 443         default: intent = "Undefined"; break;
 444     }
 445 
 446     _cmsIOPrintf(m, "/RenderingIntent (%s)\n", intent );
 447 }
 448 
 449 //
 450 //  Convert L* to Y
 451 //
 452 //      Y = Yn*[ (L* + 16) / 116] ^ 3   if (L*) >= 6 / 29
 453 //        = Yn*( L* / 116) / 7.787      if (L*) < 6 / 29
 454 //
 455 
 456 /*
 457 static
 458 void EmitL2Y(cmsIOHANDLER* m)
 459 {
 460     _cmsIOPrintf(m,
 461             "{ "
 462                 "100 mul 16 add 116 div "               // (L * 100 + 16) / 116
 463                  "dup 6 29 div ge "                     // >= 6 / 29 ?
 464                  "{ dup dup mul mul } "                 // yes, ^3 and done
 465                  "{ 4 29 div sub 108 841 div mul } "    // no, slope limiting
 466             "ifelse } bind ");
 467 }
 468 */
 469 
 470 
 471 // Lab -> XYZ, see the discussion above
 472 
 473 static
 474 void EmitLab2XYZ(cmsIOHANDLER* m)
 475 {
 476     _cmsIOPrintf(m, "/RangeABC [ 0 1 0 1 0 1]\n");
 477     _cmsIOPrintf(m, "/DecodeABC [\n");
 478     _cmsIOPrintf(m, "{100 mul  16 add 116 div } bind\n");
 479     _cmsIOPrintf(m, "{255 mul 128 sub 500 div } bind\n");
 480     _cmsIOPrintf(m, "{255 mul 128 sub 200 div } bind\n");
 481     _cmsIOPrintf(m, "]\n");
 482     _cmsIOPrintf(m, "/MatrixABC [ 1 1 1 1 0 0 0 0 -1]\n");
 483     _cmsIOPrintf(m, "/RangeLMN [ -0.236 1.254 0 1 -0.635 1.640 ]\n");
 484     _cmsIOPrintf(m, "/DecodeLMN [\n");
 485     _cmsIOPrintf(m, "{dup 6 29 div ge {dup dup mul mul} {4 29 div sub 108 841 div mul} ifelse 0.964200 mul} bind\n");
 486     _cmsIOPrintf(m, "{dup 6 29 div ge {dup dup mul mul} {4 29 div sub 108 841 div mul} ifelse } bind\n");
 487     _cmsIOPrintf(m, "{dup 6 29 div ge {dup dup mul mul} {4 29 div sub 108 841 div mul} ifelse 0.824900 mul} bind\n");
 488     _cmsIOPrintf(m, "]\n");
 489 }
 490 






 491 










 492 
 493 // Outputs a table of words. It does use 16 bits
 494 
 495 static
 496 void Emit1Gamma(cmsIOHANDLER* m, cmsToneCurve* Table)
 497 {
 498     cmsUInt32Number i;
 499     cmsFloat64Number gamma;
 500 
 501     if (Table == NULL) return; // Error
 502 
 503     if (Table ->nEntries <= 0) return;  // Empty table
 504 
 505     // Suppress whole if identity
 506     if (cmsIsToneCurveLinear(Table)) return;
 507 
 508     // Check if is really an exponential. If so, emit "exp"
 509     gamma = cmsEstimateGamma(Table, 0.001);
 510      if (gamma > 0) {
 511             _cmsIOPrintf(m, "{ %g exp } bind ", gamma);
 512             return;
 513      }
 514 
 515     _cmsIOPrintf(m, "{ ");

 516 
 517     // Bounds check
 518     EmitRangeCheck(m);





 519 
 520     // Emit intepolation code

 521 
 522     // PostScript code                      Stack
 523     // ===============                      ========================
 524                                             // v
 525     _cmsIOPrintf(m, " [");
 526 
 527     for (i=0; i < Table->nEntries; i++) {
 528         _cmsIOPrintf(m, "%d ", Table->Table16[i]);
 529     }
 530 
 531     _cmsIOPrintf(m, "] ");                        // v tab
 532 

 533     _cmsIOPrintf(m, "dup ");                      // v tab tab
 534     _cmsIOPrintf(m, "length 1 sub ");             // v tab dom
 535     _cmsIOPrintf(m, "3 -1 roll ");                // tab dom v
 536     _cmsIOPrintf(m, "mul ");                      // tab val2
 537     _cmsIOPrintf(m, "dup ");                      // tab val2 val2
 538     _cmsIOPrintf(m, "dup ");                      // tab val2 val2 val2
 539     _cmsIOPrintf(m, "floor cvi ");                // tab val2 val2 cell0
 540     _cmsIOPrintf(m, "exch ");                     // tab val2 cell0 val2
 541     _cmsIOPrintf(m, "ceiling cvi ");              // tab val2 cell0 cell1
 542     _cmsIOPrintf(m, "3 index ");                  // tab val2 cell0 cell1 tab
 543     _cmsIOPrintf(m, "exch ");                     // tab val2 cell0 tab cell1
 544     _cmsIOPrintf(m, "get ");                      // tab val2 cell0 y1
 545     _cmsIOPrintf(m, "4 -1 roll ");                // val2 cell0 y1 tab
 546     _cmsIOPrintf(m, "3 -1 roll ");                // val2 y1 tab cell0
 547     _cmsIOPrintf(m, "get ");                      // val2 y1 y0
 548     _cmsIOPrintf(m, "dup ");                      // val2 y1 y0 y0
 549     _cmsIOPrintf(m, "3 1 roll ");                 // val2 y0 y1 y0
 550     _cmsIOPrintf(m, "sub ");                      // val2 y0 (y1-y0)
 551     _cmsIOPrintf(m, "3 -1 roll ");                // y0 (y1-y0) val2
 552     _cmsIOPrintf(m, "dup ");                      // y0 (y1-y0) val2 val2
 553     _cmsIOPrintf(m, "floor cvi ");                // y0 (y1-y0) val2 floor(val2)
 554     _cmsIOPrintf(m, "sub ");                      // y0 (y1-y0) rest
 555     _cmsIOPrintf(m, "mul ");                      // y0 t1
 556     _cmsIOPrintf(m, "add ");                      // y
 557     _cmsIOPrintf(m, "65535 div ");                // result


 558 
 559     _cmsIOPrintf(m, " } bind ");
 560 }
 561 
 562 
 563 // Compare gamma table
 564 
 565 static
 566 cmsBool GammaTableEquals(cmsUInt16Number* g1, cmsUInt16Number* g2, cmsUInt32Number nEntries)
 567 {
 568     return memcmp(g1, g2, nEntries* sizeof(cmsUInt16Number)) == 0;
 569 }
 570 
 571 
 572 // Does write a set of gamma curves
 573 
 574 static
 575 void EmitNGamma(cmsIOHANDLER* m, cmsUInt32Number n, cmsToneCurve* g[])
 576 {
 577     cmsUInt32Number i;

 578 
 579     for( i=0; i < n; i++ )
 580     {
 581         if (g[i] == NULL) return; // Error
 582 
 583         if (i > 0 && GammaTableEquals(g[i-1]->Table16, g[i]->Table16, g[i]->nEntries)) {
 584 
 585             _cmsIOPrintf(m, "dup ");
 586         }
 587         else {
 588             Emit1Gamma(m, g[i]);


 589         }
 590     }
 591 
 592 }
 593 
 594 
 595 
 596 
 597 
 598 // Following code dumps a LUT onto memory stream
 599 
 600 
 601 // This is the sampler. Intended to work in SAMPLER_INSPECT mode,
 602 // that is, the callback will be called for each knot with
 603 //
 604 //          In[]  The grid location coordinates, normalized to 0..ffff
 605 //          Out[] The Pipeline values, normalized to 0..ffff
 606 //
 607 //  Returning a value other than 0 does terminate the sampling process
 608 //
 609 //  Each row contains Pipeline values for all but first component. So, I
 610 //  detect row changing by keeping a copy of last value of first
 611 //  component. -1 is used to mark beginning of whole block.
 612 
 613 static
 614 int OutputValueSampler(register const cmsUInt16Number In[], register cmsUInt16Number Out[], register void* Cargo)
 615 {
 616     cmsPsSamplerCargo* sc = (cmsPsSamplerCargo*) Cargo;
 617     cmsUInt32Number i;
 618 
 619 
 620     if (sc -> FixWhite) {
 621 
 622         if (In[0] == 0xFFFF) {  // Only in L* = 100, ab = [-8..8]
 623 
 624             if ((In[1] >= 0x7800 && In[1] <= 0x8800) &&
 625                 (In[2] >= 0x7800 && In[2] <= 0x8800)) {
 626 
 627                 cmsUInt16Number* Black;
 628                 cmsUInt16Number* White;
 629                 cmsUInt32Number nOutputs;
 630 
 631                 if (!_cmsEndPointsBySpace(sc ->ColorSpace, &White, &Black, &nOutputs))
 632                         return 0;
 633 
 634                 for (i=0; i < nOutputs; i++)


 720     _cmsIOPrintf(m, " [\n");
 721 
 722     cmsStageSampleCLut16bit(mpe, OutputValueSampler, (void*) &sc, SAMPLER_INSPECT);
 723 
 724     _cmsIOPrintf(m, PostMin);
 725     _cmsIOPrintf(m, PostMaj);
 726     _cmsIOPrintf(m, "] ");
 727 
 728 }
 729 
 730 
 731 // Dumps CIEBasedA Color Space Array
 732 
 733 static
 734 int EmitCIEBasedA(cmsIOHANDLER* m, cmsToneCurve* Curve, cmsCIEXYZ* BlackPoint)
 735 {
 736 
 737     _cmsIOPrintf(m, "[ /CIEBasedA\n");
 738     _cmsIOPrintf(m, "  <<\n");
 739 
 740     _cmsIOPrintf(m, "/DecodeA ");
 741 
 742     Emit1Gamma(m, Curve);
 743 
 744     _cmsIOPrintf(m, " \n");

 745 
 746     _cmsIOPrintf(m, "/MatrixA [ 0.9642 1.0000 0.8249 ]\n");
 747     _cmsIOPrintf(m, "/RangeLMN [ 0.0 0.9642 0.0 1.0000 0.0 0.8249 ]\n");
 748 
 749     EmitWhiteBlackD50(m, BlackPoint);
 750     EmitIntent(m, INTENT_PERCEPTUAL);
 751 
 752     _cmsIOPrintf(m, ">>\n");
 753     _cmsIOPrintf(m, "]\n");
 754 
 755     return 1;
 756 }
 757 
 758 
 759 // Dumps CIEBasedABC Color Space Array
 760 
 761 static
 762 int EmitCIEBasedABC(cmsIOHANDLER* m, cmsFloat64Number* Matrix, cmsToneCurve** CurveSet, cmsCIEXYZ* BlackPoint)
 763 {
 764     int i;
 765 
 766     _cmsIOPrintf(m, "[ /CIEBasedABC\n");
 767     _cmsIOPrintf(m, "<<\n");
 768     _cmsIOPrintf(m, "/DecodeABC [ ");
 769 
 770     EmitNGamma(m, 3, CurveSet);
 771 








 772     _cmsIOPrintf(m, "]\n");



 773 
 774     _cmsIOPrintf(m, "/MatrixABC [ " );
 775 
 776     for( i=0; i < 3; i++ ) {
 777 
 778         _cmsIOPrintf(m, "%.6f %.6f %.6f ", Matrix[i + 3*0],
 779                                            Matrix[i + 3*1],
 780                                            Matrix[i + 3*2]);
 781     }
 782 
 783 
 784     _cmsIOPrintf(m, "]\n");
 785 
 786     _cmsIOPrintf(m, "/RangeLMN [ 0.0 0.9642 0.0 1.0000 0.0 0.8249 ]\n");
 787 
 788     EmitWhiteBlackD50(m, BlackPoint);
 789     EmitIntent(m, INTENT_PERCEPTUAL);
 790 
 791     _cmsIOPrintf(m, ">>\n");
 792     _cmsIOPrintf(m, "]\n");
 793 
 794 
 795     return 1;
 796 }
 797 
 798 
 799 static
 800 int EmitCIEBasedDEF(cmsIOHANDLER* m, cmsPipeline* Pipeline, cmsUInt32Number Intent, cmsCIEXYZ* BlackPoint)
 801 {
 802     const char* PreMaj;
 803     const char* PostMaj;
 804     const char* PreMin, *PostMin;
 805     cmsStage* mpe;


 806 
 807     mpe = Pipeline ->Elements;
 808 
 809     switch (cmsStageInputChannels(mpe)) {
 810     case 3:
 811 
 812             _cmsIOPrintf(m, "[ /CIEBasedDEF\n");
 813             PreMaj ="<";
 814             PostMaj= ">\n";
 815             PreMin = PostMin = "";
 816             break;

 817     case 4:
 818             _cmsIOPrintf(m, "[ /CIEBasedDEFG\n");
 819             PreMaj = "[";
 820             PostMaj = "]\n";
 821             PreMin = "<";
 822             PostMin = ">\n";
 823             break;

 824     default:
 825             return 0;
 826 
 827     }
 828 
 829     _cmsIOPrintf(m, "<<\n");
 830 
 831     if (cmsStageType(mpe) == cmsSigCurveSetElemType) {
 832 
 833         _cmsIOPrintf(m, "/DecodeDEF [ ");
 834         EmitNGamma(m, cmsStageOutputChannels(mpe), _cmsStageGetPtrToCurveSet(mpe));











 835         _cmsIOPrintf(m, "]\n");





 836 
 837         mpe = mpe ->Next;
 838     }
 839 
 840     if (cmsStageType(mpe) == cmsSigCLutElemType) {
 841 
 842             _cmsIOPrintf(m, "/Table ");
 843             WriteCLUT(m, mpe, PreMaj, PostMaj, PreMin, PostMin, FALSE, (cmsColorSpaceSignature) 0);
 844             _cmsIOPrintf(m, "]\n");
 845     }
 846 
 847     EmitLab2XYZ(m);
 848     EmitWhiteBlackD50(m, BlackPoint);
 849     EmitIntent(m, Intent);
 850 
 851     _cmsIOPrintf(m, "   >>\n");
 852     _cmsIOPrintf(m, "]\n");
 853 
 854     return 1;
 855 }
 856 
 857 // Generates a curve from a gray profile
 858 
 859 static
 860 cmsToneCurve* ExtractGray2Y(cmsContext ContextID, cmsHPROFILE hProfile, cmsUInt32Number Intent)
 861 {
 862     cmsToneCurve* Out = cmsBuildTabulatedToneCurve16(ContextID, 256, NULL);
 863     cmsHPROFILE hXYZ  = cmsCreateXYZProfile();


 935     case 3:
 936     case 4: {
 937             cmsUInt32Number OutFrm = TYPE_Lab_16;
 938             cmsPipeline* DeviceLink;
 939             _cmsTRANSFORM* v = (_cmsTRANSFORM*) xform;
 940 
 941             DeviceLink = cmsPipelineDup(v ->Lut);
 942             if (DeviceLink == NULL) return 0;
 943 
 944             dwFlags |= cmsFLAGS_FORCE_CLUT;
 945             _cmsOptimizePipeline(m->ContextID, &DeviceLink, Intent, &InputFormat, &OutFrm, &dwFlags);
 946 
 947             rc = EmitCIEBasedDEF(m, DeviceLink, Intent, &BlackPointAdaptedToD50);
 948             cmsPipelineFree(DeviceLink);
 949             if (rc == 0) return 0;
 950             }
 951             break;
 952 
 953     default:
 954 
 955         cmsSignalError(m ->ContextID, cmsERROR_COLORSPACE_CHECK, "Only 3, 4 channels supported for CSA. This profile has %d channels.", nChannels);
 956         return 0;
 957     }
 958 
 959 
 960     cmsDeleteTransform(xform);
 961 
 962     return 1;
 963 }
 964 
 965 static
 966 cmsFloat64Number* GetPtrToMatrix(const cmsStage* mpe)
 967 {
 968     _cmsStageMatrixData* Data = (_cmsStageMatrixData*) mpe ->Data;
 969 
 970     return Data -> Double;
 971 }
 972 
 973 
 974 // Does create CSA based on matrix-shaper. Allowed types are gray and RGB based
 975 static


1251 
1252             _cmsIOPrintf(m, "{4 index 3 get div 2 index 3 get mul "
1253                     "2 index 3 get 2 index 3 get sub mul "
1254                     "2 index 3 get 4 index 3 get 3 index 3 get sub mul sub "
1255                     "3 index 3 get 3 index 3 get exch sub div "
1256                     "exch pop exch pop exch pop exch pop } bind\n");
1257 
1258             _cmsIOPrintf(m, "{4 index 4 get div 2 index 4 get mul "
1259                     "2 index 4 get 2 index 4 get sub mul "
1260                     "2 index 4 get 4 index 4 get 3 index 4 get sub mul sub "
1261                     "3 index 4 get 3 index 4 get exch sub div "
1262                     "exch pop exch pop exch pop exch pop } bind\n");
1263 
1264             _cmsIOPrintf(m, "{4 index 5 get div 2 index 5 get mul "
1265                     "2 index 5 get 2 index 5 get sub mul "
1266                     "2 index 5 get 4 index 5 get 3 index 5 get sub mul sub "
1267                     "3 index 5 get 3 index 5 get exch sub div "
1268                     "exch pop exch pop exch pop exch pop } bind\n]\n");
1269 
1270         }
1271 
1272 
1273 }
1274 
1275 
1276 static
1277 void EmitXYZ2Lab(cmsIOHANDLER* m)
1278 {
1279     _cmsIOPrintf(m, "/RangeLMN [ -0.635 2.0 0 2 -0.635 2.0 ]\n");
1280     _cmsIOPrintf(m, "/EncodeLMN [\n");
1281     _cmsIOPrintf(m, "{ 0.964200  div dup 0.008856 le {7.787 mul 16 116 div add}{1 3 div exp} ifelse } bind\n");
1282     _cmsIOPrintf(m, "{ 1.000000  div dup 0.008856 le {7.787 mul 16 116 div add}{1 3 div exp} ifelse } bind\n");
1283     _cmsIOPrintf(m, "{ 0.824900  div dup 0.008856 le {7.787 mul 16 116 div add}{1 3 div exp} ifelse } bind\n");
1284     _cmsIOPrintf(m, "]\n");
1285     _cmsIOPrintf(m, "/MatrixABC [ 0 1 0 1 -1 1 0 0 -1 ]\n");
1286     _cmsIOPrintf(m, "/EncodeABC [\n");
1287 
1288 
1289     _cmsIOPrintf(m, "{ 116 mul  16 sub 100 div  } bind\n");
1290     _cmsIOPrintf(m, "{ 500 mul 128 add 256 div  } bind\n");
1291     _cmsIOPrintf(m, "{ 200 mul 128 add 256 div  } bind\n");
1292 
1293 
1294     _cmsIOPrintf(m, "]\n");
1295 
1296 
1297 }
1298 
1299 // Due to impedance mismatch between XYZ and almost all RGB and CMYK spaces
1300 // I choose to dump LUTS in Lab instead of XYZ. There is still a lot of wasted
1301 // space on 3D CLUT, but since space seems not to be a problem here, 33 points
1302 // would give a reasonable accurancy. Note also that CRD tables must operate in
1303 // 8 bits.
1304 
1305 static
1306 int WriteOutputLUT(cmsIOHANDLER* m, cmsHPROFILE hProfile, cmsUInt32Number Intent, cmsUInt32Number dwFlags)
1307 {
1308     cmsHPROFILE hLab;
1309     cmsHTRANSFORM xform;
1310     cmsUInt32Number i, nChannels;
1311     cmsUInt32Number OutputFormat;
1312     _cmsTRANSFORM* v;
1313     cmsPipeline* DeviceLink;
1314     cmsHPROFILE Profiles[3];
1315     cmsCIEXYZ BlackPointAdaptedToD50;
1316     cmsBool lDoBPC = (cmsBool) (dwFlags & cmsFLAGS_BLACKPOINTCOMPENSATION);
1317     cmsBool lFixWhite = (cmsBool) !(dwFlags & cmsFLAGS_NOWHITEONWHITEFIXUP);
1318     cmsUInt32Number InFrm = TYPE_Lab_16;
1319     cmsUInt32Number RelativeEncodingIntent;
1320     cmsColorSpaceSignature ColorSpace;
1321 
1322 



  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 //---------------------------------------------------------------------------------


  90   NOTE: CLUT-based monochrome profiles are NOT supported. So, cmsFLAGS_MATRIXINPUT
  91   flag is forced on such profiles.
  92 
  93     [ /CIEBasedA
  94       <<
  95             /DecodeA { transfer function } bind
  96             /MatrixA [D50]
  97             /RangeLMN [ 0.0 cmsD50X 0.0 cmsD50Y 0.0 cmsD50Z ]
  98             /WhitePoint [D50]
  99             /BlackPoint [BP]
 100             /RenderingIntent (intent)
 101       >>
 102     ]
 103 
 104    On simpler profiles, the PCS is already XYZ, so no conversion is required.
 105 
 106 
 107    Matrix-shaper based
 108    -------------------
 109 
 110    This is implemented both with /CIEBasedABC or /CIEBasedDEF depending on the
 111    profile implementation. Since here there are no interpolation tables, I do
 112    the conversion directly to XYZ
 113 
 114 
 115 
 116     [ /CIEBasedABC
 117             <<
 118                 /DecodeABC [ {transfer1} {transfer2} {transfer3} ]
 119                 /MatrixABC [Matrix]
 120                 /RangeLMN [ 0.0 cmsD50X 0.0 cmsD50Y 0.0 cmsD50Z ]
 121                 /DecodeLMN [ { / 2} dup dup ]
 122                 /WhitePoint [D50]
 123                 /BlackPoint [BP]
 124                 /RenderingIntent (intent)
 125             >>
 126     ]
 127 
 128 
 129     CLUT based
 130     ----------
 131 


 307     const char* PostMin;
 308 
 309     int  FixWhite;    // Force mapping of pure white
 310 
 311     cmsColorSpaceSignature  ColorSpace;  // ColorSpace of profile
 312 
 313 
 314 } cmsPsSamplerCargo;
 315 
 316 static int _cmsPSActualColumn = 0;
 317 
 318 
 319 // Convert to byte
 320 static
 321 cmsUInt8Number Word2Byte(cmsUInt16Number w)
 322 {
 323     return (cmsUInt8Number) floor((cmsFloat64Number) w / 257.0 + 0.5);
 324 }
 325 
 326 













 327 // Write a cooked byte

 328 static
 329 void WriteByte(cmsIOHANDLER* m, cmsUInt8Number b)
 330 {
 331     _cmsIOPrintf(m, "%02x", b);
 332     _cmsPSActualColumn += 2;
 333 
 334     if (_cmsPSActualColumn > MAXPSCOLS) {
 335 
 336         _cmsIOPrintf(m, "\n");
 337         _cmsPSActualColumn = 0;
 338     }
 339 }
 340 
 341 // ----------------------------------------------------------------- PostScript generation
 342 
 343 
 344 // Removes offending carriage returns
 345 
 346 static
 347 char* RemoveCR(const char* txt)
 348 {
 349     static char Buffer[2048];
 350     char* pt;
 351 
 352     strncpy(Buffer, txt, 2047);
 353     Buffer[2047] = 0;
 354     for (pt = Buffer; *pt; pt++)
 355             if (*pt == '\n' || *pt == '\r') *pt = ' ';
 356 
 357     return Buffer;
 358 
 359 }
 360 
 361 static
 362 void EmitHeader(cmsIOHANDLER* m, const char* Title, cmsHPROFILE hProfile)
 363 {
 364     time_t timer;
 365     cmsMLU *Description, *Copyright;


 423     switch (RenderingIntent) {
 424 
 425         case INTENT_PERCEPTUAL:            intent = "Perceptual"; break;
 426         case INTENT_RELATIVE_COLORIMETRIC: intent = "RelativeColorimetric"; break;
 427         case INTENT_ABSOLUTE_COLORIMETRIC: intent = "AbsoluteColorimetric"; break;
 428         case INTENT_SATURATION:            intent = "Saturation"; break;
 429 
 430         default: intent = "Undefined"; break;
 431     }
 432 
 433     _cmsIOPrintf(m, "/RenderingIntent (%s)\n", intent );
 434 }
 435 
 436 //
 437 //  Convert L* to Y
 438 //
 439 //      Y = Yn*[ (L* + 16) / 116] ^ 3   if (L*) >= 6 / 29
 440 //        = Yn*( L* / 116) / 7.787      if (L*) < 6 / 29
 441 //
 442 















 443 // Lab -> XYZ, see the discussion above
 444 
 445 static
 446 void EmitLab2XYZ(cmsIOHANDLER* m)
 447 {
 448     _cmsIOPrintf(m, "/RangeABC [ 0 1 0 1 0 1]\n");
 449     _cmsIOPrintf(m, "/DecodeABC [\n");
 450     _cmsIOPrintf(m, "{100 mul  16 add 116 div } bind\n");
 451     _cmsIOPrintf(m, "{255 mul 128 sub 500 div } bind\n");
 452     _cmsIOPrintf(m, "{255 mul 128 sub 200 div } bind\n");
 453     _cmsIOPrintf(m, "]\n");
 454     _cmsIOPrintf(m, "/MatrixABC [ 1 1 1 1 0 0 0 0 -1]\n");
 455     _cmsIOPrintf(m, "/RangeLMN [ -0.236 1.254 0 1 -0.635 1.640 ]\n");
 456     _cmsIOPrintf(m, "/DecodeLMN [\n");
 457     _cmsIOPrintf(m, "{dup 6 29 div ge {dup dup mul mul} {4 29 div sub 108 841 div mul} ifelse 0.964200 mul} bind\n");
 458     _cmsIOPrintf(m, "{dup 6 29 div ge {dup dup mul mul} {4 29 div sub 108 841 div mul} ifelse } bind\n");
 459     _cmsIOPrintf(m, "{dup 6 29 div ge {dup dup mul mul} {4 29 div sub 108 841 div mul} ifelse 0.824900 mul} bind\n");
 460     _cmsIOPrintf(m, "]\n");
 461 }
 462 
 463 static
 464 void EmitSafeGuardBegin(cmsIOHANDLER* m, const char* name)
 465 {
 466     _cmsIOPrintf(m, "%%LCMS2: Save previous definition of %s on the operand stack\n", name);
 467     _cmsIOPrintf(m, "currentdict /%s known { /%s load } { null } ifelse\n", name, name);
 468 }
 469 
 470 static
 471 void EmitSafeGuardEnd(cmsIOHANDLER* m, const char* name, int depth)
 472 {
 473     _cmsIOPrintf(m, "%%LCMS2: Restore previous definition of %s\n", name);
 474     if (depth > 1) {
 475         // cycle topmost items on the stack to bring the previous definition to the front
 476         _cmsIOPrintf(m, "%d -1 roll ", depth);
 477     }
 478     _cmsIOPrintf(m, "dup null eq { pop currentdict /%s undef } { /%s exch def } ifelse\n", name, name);
 479 }
 480 
 481 // Outputs a table of words. It does use 16 bits
 482 
 483 static
 484 void Emit1Gamma(cmsIOHANDLER* m, cmsToneCurve* Table, const char* name)
 485 {
 486     cmsUInt32Number i;
 487     cmsFloat64Number gamma;
 488 
 489     if (Table == NULL) return; // Error
 490 
 491     if (Table ->nEntries <= 0) return;  // Empty table
 492 
 493     // Suppress whole if identity
 494     if (cmsIsToneCurveLinear(Table)) return;
 495 
 496     // Check if is really an exponential. If so, emit "exp"
 497     gamma = cmsEstimateGamma(Table, 0.001);
 498      if (gamma > 0) {
 499             _cmsIOPrintf(m, "/%s { %g exp } bind def\n", name, gamma);
 500             return;
 501      }
 502 
 503     EmitSafeGuardBegin(m, "lcms2gammatable");
 504     _cmsIOPrintf(m, "/lcms2gammatable [");
 505 
 506     for (i=0; i < Table->nEntries; i++) {
 507         if (i % 10 == 0)
 508             _cmsIOPrintf(m, "\n  ");
 509         _cmsIOPrintf(m, "%d ", Table->Table16[i]);
 510     }
 511 
 512     _cmsIOPrintf(m, "] def\n");
 513 
 514 
 515     // Emit interpolation code
 516 
 517     // PostScript code                            Stack
 518     // ===============                            ========================
 519                                                   // v
 520     _cmsIOPrintf(m, "/%s {\n  ", name);
 521 
 522     // Bounds check
 523     EmitRangeCheck(m);



 524 
 525     _cmsIOPrintf(m, "\n  //lcms2gammatable ");    // v tab
 526     _cmsIOPrintf(m, "dup ");                      // v tab tab
 527     _cmsIOPrintf(m, "length 1 sub ");             // v tab dom
 528     _cmsIOPrintf(m, "3 -1 roll ");                // tab dom v
 529     _cmsIOPrintf(m, "mul ");                      // tab val2
 530     _cmsIOPrintf(m, "dup ");                      // tab val2 val2
 531     _cmsIOPrintf(m, "dup ");                      // tab val2 val2 val2
 532     _cmsIOPrintf(m, "floor cvi ");                // tab val2 val2 cell0
 533     _cmsIOPrintf(m, "exch ");                     // tab val2 cell0 val2
 534     _cmsIOPrintf(m, "ceiling cvi ");              // tab val2 cell0 cell1
 535     _cmsIOPrintf(m, "3 index ");                  // tab val2 cell0 cell1 tab
 536     _cmsIOPrintf(m, "exch ");                     // tab val2 cell0 tab cell1
 537     _cmsIOPrintf(m, "get\n  ");                   // tab val2 cell0 y1
 538     _cmsIOPrintf(m, "4 -1 roll ");                // val2 cell0 y1 tab
 539     _cmsIOPrintf(m, "3 -1 roll ");                // val2 y1 tab cell0
 540     _cmsIOPrintf(m, "get ");                      // val2 y1 y0
 541     _cmsIOPrintf(m, "dup ");                      // val2 y1 y0 y0
 542     _cmsIOPrintf(m, "3 1 roll ");                 // val2 y0 y1 y0
 543     _cmsIOPrintf(m, "sub ");                      // val2 y0 (y1-y0)
 544     _cmsIOPrintf(m, "3 -1 roll ");                // y0 (y1-y0) val2
 545     _cmsIOPrintf(m, "dup ");                      // y0 (y1-y0) val2 val2
 546     _cmsIOPrintf(m, "floor cvi ");                // y0 (y1-y0) val2 floor(val2)
 547     _cmsIOPrintf(m, "sub ");                      // y0 (y1-y0) rest
 548     _cmsIOPrintf(m, "mul ");                      // y0 t1
 549     _cmsIOPrintf(m, "add ");                      // y
 550     _cmsIOPrintf(m, "65535 div\n");               // result
 551 
 552     _cmsIOPrintf(m, "} bind def\n");
 553 
 554     EmitSafeGuardEnd(m, "lcms2gammatable", 1);
 555 }
 556 
 557 
 558 // Compare gamma table
 559 
 560 static
 561 cmsBool GammaTableEquals(cmsUInt16Number* g1, cmsUInt16Number* g2, cmsUInt32Number nEntries)
 562 {
 563     return memcmp(g1, g2, nEntries* sizeof(cmsUInt16Number)) == 0;
 564 }
 565 
 566 
 567 // Does write a set of gamma curves
 568 
 569 static
 570 void EmitNGamma(cmsIOHANDLER* m, cmsUInt32Number n, cmsToneCurve* g[], const char* nameprefix)
 571 {
 572     cmsUInt32Number i;
 573     static char buffer[2048];
 574 
 575     for( i=0; i < n; i++ )
 576     {
 577         if (g[i] == NULL) return; // Error
 578 
 579         if (i > 0 && GammaTableEquals(g[i-1]->Table16, g[i]->Table16, g[i]->nEntries)) {
 580 
 581             _cmsIOPrintf(m, "/%s%d /%s%d load def\n", nameprefix, i, nameprefix, i-1);
 582         }
 583         else {
 584             snprintf(buffer, sizeof(buffer), "%s%d", nameprefix, i);
 585             buffer[sizeof(buffer)-1] = '\0';
 586             Emit1Gamma(m, g[i], buffer);
 587         }
 588     }
 589 
 590 }
 591 
 592 



 593 // Following code dumps a LUT onto memory stream
 594 
 595 
 596 // This is the sampler. Intended to work in SAMPLER_INSPECT mode,
 597 // that is, the callback will be called for each knot with
 598 //
 599 //          In[]  The grid location coordinates, normalized to 0..ffff
 600 //          Out[] The Pipeline values, normalized to 0..ffff
 601 //
 602 //  Returning a value other than 0 does terminate the sampling process
 603 //
 604 //  Each row contains Pipeline values for all but first component. So, I
 605 //  detect row changing by keeping a copy of last value of first
 606 //  component. -1 is used to mark beginning of whole block.
 607 
 608 static
 609 int OutputValueSampler(CMSREGISTER const cmsUInt16Number In[], CMSREGISTER cmsUInt16Number Out[], CMSREGISTER void* Cargo)
 610 {
 611     cmsPsSamplerCargo* sc = (cmsPsSamplerCargo*) Cargo;
 612     cmsUInt32Number i;
 613 
 614 
 615     if (sc -> FixWhite) {
 616 
 617         if (In[0] == 0xFFFF) {  // Only in L* = 100, ab = [-8..8]
 618 
 619             if ((In[1] >= 0x7800 && In[1] <= 0x8800) &&
 620                 (In[2] >= 0x7800 && In[2] <= 0x8800)) {
 621 
 622                 cmsUInt16Number* Black;
 623                 cmsUInt16Number* White;
 624                 cmsUInt32Number nOutputs;
 625 
 626                 if (!_cmsEndPointsBySpace(sc ->ColorSpace, &White, &Black, &nOutputs))
 627                         return 0;
 628 
 629                 for (i=0; i < nOutputs; i++)


 715     _cmsIOPrintf(m, " [\n");
 716 
 717     cmsStageSampleCLut16bit(mpe, OutputValueSampler, (void*) &sc, SAMPLER_INSPECT);
 718 
 719     _cmsIOPrintf(m, PostMin);
 720     _cmsIOPrintf(m, PostMaj);
 721     _cmsIOPrintf(m, "] ");
 722 
 723 }
 724 
 725 
 726 // Dumps CIEBasedA Color Space Array
 727 
 728 static
 729 int EmitCIEBasedA(cmsIOHANDLER* m, cmsToneCurve* Curve, cmsCIEXYZ* BlackPoint)
 730 {
 731 
 732     _cmsIOPrintf(m, "[ /CIEBasedA\n");
 733     _cmsIOPrintf(m, "  <<\n");
 734 
 735     EmitSafeGuardBegin(m, "lcms2gammaproc");
 736     Emit1Gamma(m, Curve, "lcms2gammaproc");

 737 
 738     _cmsIOPrintf(m, "/DecodeA /lcms2gammaproc load\n");
 739     EmitSafeGuardEnd(m, "lcms2gammaproc", 3);
 740 
 741     _cmsIOPrintf(m, "/MatrixA [ 0.9642 1.0000 0.8249 ]\n");
 742     _cmsIOPrintf(m, "/RangeLMN [ 0.0 0.9642 0.0 1.0000 0.0 0.8249 ]\n");
 743 
 744     EmitWhiteBlackD50(m, BlackPoint);
 745     EmitIntent(m, INTENT_PERCEPTUAL);
 746 
 747     _cmsIOPrintf(m, ">>\n");
 748     _cmsIOPrintf(m, "]\n");
 749 
 750     return 1;
 751 }
 752 
 753 
 754 // Dumps CIEBasedABC Color Space Array
 755 
 756 static
 757 int EmitCIEBasedABC(cmsIOHANDLER* m, cmsFloat64Number* Matrix, cmsToneCurve** CurveSet, cmsCIEXYZ* BlackPoint)
 758 {
 759     int i;
 760 
 761     _cmsIOPrintf(m, "[ /CIEBasedABC\n");
 762     _cmsIOPrintf(m, "<<\n");



 763 
 764     EmitSafeGuardBegin(m, "lcms2gammaproc0");
 765     EmitSafeGuardBegin(m, "lcms2gammaproc1");
 766     EmitSafeGuardBegin(m, "lcms2gammaproc2");
 767     EmitNGamma(m, 3, CurveSet, "lcms2gammaproc");
 768     _cmsIOPrintf(m, "/DecodeABC [\n");
 769     _cmsIOPrintf(m, "   /lcms2gammaproc0 load\n");
 770     _cmsIOPrintf(m, "   /lcms2gammaproc1 load\n");
 771     _cmsIOPrintf(m, "   /lcms2gammaproc2 load\n");
 772     _cmsIOPrintf(m, "]\n");
 773     EmitSafeGuardEnd(m, "lcms2gammaproc2", 3);
 774     EmitSafeGuardEnd(m, "lcms2gammaproc1", 3);
 775     EmitSafeGuardEnd(m, "lcms2gammaproc0", 3);
 776 
 777     _cmsIOPrintf(m, "/MatrixABC [ " );
 778 
 779     for( i=0; i < 3; i++ ) {
 780 
 781         _cmsIOPrintf(m, "%.6f %.6f %.6f ", Matrix[i + 3*0],
 782                                            Matrix[i + 3*1],
 783                                            Matrix[i + 3*2]);
 784     }
 785 
 786 
 787     _cmsIOPrintf(m, "]\n");
 788 
 789     _cmsIOPrintf(m, "/RangeLMN [ 0.0 0.9642 0.0 1.0000 0.0 0.8249 ]\n");
 790 
 791     EmitWhiteBlackD50(m, BlackPoint);
 792     EmitIntent(m, INTENT_PERCEPTUAL);
 793 
 794     _cmsIOPrintf(m, ">>\n");
 795     _cmsIOPrintf(m, "]\n");
 796 
 797 
 798     return 1;
 799 }
 800 
 801 
 802 static
 803 int EmitCIEBasedDEF(cmsIOHANDLER* m, cmsPipeline* Pipeline, cmsUInt32Number Intent, cmsCIEXYZ* BlackPoint)
 804 {
 805     const char* PreMaj;
 806     const char* PostMaj;
 807     const char* PreMin, * PostMin;
 808     cmsStage* mpe;
 809     int i, numchans;
 810     static char buffer[2048];
 811 
 812     mpe = Pipeline->Elements;
 813 
 814     switch (cmsStageInputChannels(mpe)) {
 815     case 3:

 816         _cmsIOPrintf(m, "[ /CIEBasedDEF\n");
 817         PreMaj = "<";
 818         PostMaj = ">\n";
 819         PreMin = PostMin = "";
 820         break;
 821 
 822     case 4:
 823         _cmsIOPrintf(m, "[ /CIEBasedDEFG\n");
 824         PreMaj = "[";
 825         PostMaj = "]\n";
 826         PreMin = "<";
 827         PostMin = ">\n";
 828         break;
 829 
 830     default:
 831         return 0;
 832 
 833     }
 834 
 835     _cmsIOPrintf(m, "<<\n");
 836 
 837     if (cmsStageType(mpe) == cmsSigCurveSetElemType) {
 838 
 839         numchans = cmsStageOutputChannels(mpe);
 840         for (i = 0; i < numchans; ++i) {
 841             snprintf(buffer, sizeof(buffer), "lcms2gammaproc%d", i);
 842             buffer[sizeof(buffer) - 1] = '\0';
 843             EmitSafeGuardBegin(m, buffer);
 844         }
 845         EmitNGamma(m, cmsStageOutputChannels(mpe), _cmsStageGetPtrToCurveSet(mpe), "lcms2gammaproc");
 846         _cmsIOPrintf(m, "/DecodeDEF [\n");
 847         for (i = 0; i < numchans; ++i) {
 848             snprintf(buffer, sizeof(buffer), "  /lcms2gammaproc%d load\n", i);
 849             buffer[sizeof(buffer) - 1] = '\0';
 850             _cmsIOPrintf(m, buffer);
 851         }
 852         _cmsIOPrintf(m, "]\n");
 853         for (i = numchans - 1; i >= 0; --i) {
 854             snprintf(buffer, sizeof(buffer), "lcms2gammaproc%d", i);
 855             buffer[sizeof(buffer) - 1] = '\0';
 856             EmitSafeGuardEnd(m, buffer, 3);
 857         }
 858 
 859         mpe = mpe->Next;
 860     }
 861 
 862     if (cmsStageType(mpe) == cmsSigCLutElemType) {
 863 
 864         _cmsIOPrintf(m, "/Table ");
 865         WriteCLUT(m, mpe, PreMaj, PostMaj, PreMin, PostMin, FALSE, (cmsColorSpaceSignature)0);
 866         _cmsIOPrintf(m, "]\n");
 867     }
 868 
 869     EmitLab2XYZ(m);
 870     EmitWhiteBlackD50(m, BlackPoint);
 871     EmitIntent(m, Intent);
 872 
 873     _cmsIOPrintf(m, "   >>\n");
 874     _cmsIOPrintf(m, "]\n");
 875 
 876     return 1;
 877 }
 878 
 879 // Generates a curve from a gray profile
 880 
 881 static
 882 cmsToneCurve* ExtractGray2Y(cmsContext ContextID, cmsHPROFILE hProfile, cmsUInt32Number Intent)
 883 {
 884     cmsToneCurve* Out = cmsBuildTabulatedToneCurve16(ContextID, 256, NULL);
 885     cmsHPROFILE hXYZ  = cmsCreateXYZProfile();


 957     case 3:
 958     case 4: {
 959             cmsUInt32Number OutFrm = TYPE_Lab_16;
 960             cmsPipeline* DeviceLink;
 961             _cmsTRANSFORM* v = (_cmsTRANSFORM*) xform;
 962 
 963             DeviceLink = cmsPipelineDup(v ->Lut);
 964             if (DeviceLink == NULL) return 0;
 965 
 966             dwFlags |= cmsFLAGS_FORCE_CLUT;
 967             _cmsOptimizePipeline(m->ContextID, &DeviceLink, Intent, &InputFormat, &OutFrm, &dwFlags);
 968 
 969             rc = EmitCIEBasedDEF(m, DeviceLink, Intent, &BlackPointAdaptedToD50);
 970             cmsPipelineFree(DeviceLink);
 971             if (rc == 0) return 0;
 972             }
 973             break;
 974 
 975     default:
 976 
 977         cmsSignalError(m ->ContextID, cmsERROR_COLORSPACE_CHECK, "Only 3, 4 channels are supported for CSA. This profile has %d channels.", nChannels);
 978         return 0;
 979     }
 980 
 981 
 982     cmsDeleteTransform(xform);
 983 
 984     return 1;
 985 }
 986 
 987 static
 988 cmsFloat64Number* GetPtrToMatrix(const cmsStage* mpe)
 989 {
 990     _cmsStageMatrixData* Data = (_cmsStageMatrixData*) mpe ->Data;
 991 
 992     return Data -> Double;
 993 }
 994 
 995 
 996 // Does create CSA based on matrix-shaper. Allowed types are gray and RGB based
 997 static


1273 
1274             _cmsIOPrintf(m, "{4 index 3 get div 2 index 3 get mul "
1275                     "2 index 3 get 2 index 3 get sub mul "
1276                     "2 index 3 get 4 index 3 get 3 index 3 get sub mul sub "
1277                     "3 index 3 get 3 index 3 get exch sub div "
1278                     "exch pop exch pop exch pop exch pop } bind\n");
1279 
1280             _cmsIOPrintf(m, "{4 index 4 get div 2 index 4 get mul "
1281                     "2 index 4 get 2 index 4 get sub mul "
1282                     "2 index 4 get 4 index 4 get 3 index 4 get sub mul sub "
1283                     "3 index 4 get 3 index 4 get exch sub div "
1284                     "exch pop exch pop exch pop exch pop } bind\n");
1285 
1286             _cmsIOPrintf(m, "{4 index 5 get div 2 index 5 get mul "
1287                     "2 index 5 get 2 index 5 get sub mul "
1288                     "2 index 5 get 4 index 5 get 3 index 5 get sub mul sub "
1289                     "3 index 5 get 3 index 5 get exch sub div "
1290                     "exch pop exch pop exch pop exch pop } bind\n]\n");
1291 
1292         }


1293 }
1294 
1295 
1296 static
1297 void EmitXYZ2Lab(cmsIOHANDLER* m)
1298 {
1299     _cmsIOPrintf(m, "/RangeLMN [ -0.635 2.0 0 2 -0.635 2.0 ]\n");
1300     _cmsIOPrintf(m, "/EncodeLMN [\n");
1301     _cmsIOPrintf(m, "{ 0.964200  div dup 0.008856 le {7.787 mul 16 116 div add}{1 3 div exp} ifelse } bind\n");
1302     _cmsIOPrintf(m, "{ 1.000000  div dup 0.008856 le {7.787 mul 16 116 div add}{1 3 div exp} ifelse } bind\n");
1303     _cmsIOPrintf(m, "{ 0.824900  div dup 0.008856 le {7.787 mul 16 116 div add}{1 3 div exp} ifelse } bind\n");
1304     _cmsIOPrintf(m, "]\n");
1305     _cmsIOPrintf(m, "/MatrixABC [ 0 1 0 1 -1 1 0 0 -1 ]\n");
1306     _cmsIOPrintf(m, "/EncodeABC [\n");
1307 
1308 
1309     _cmsIOPrintf(m, "{ 116 mul  16 sub 100 div  } bind\n");
1310     _cmsIOPrintf(m, "{ 500 mul 128 add 256 div  } bind\n");
1311     _cmsIOPrintf(m, "{ 200 mul 128 add 256 div  } bind\n");
1312 
1313 
1314     _cmsIOPrintf(m, "]\n");
1315 
1316 
1317 }
1318 
1319 // Due to impedance mismatch between XYZ and almost all RGB and CMYK spaces
1320 // I choose to dump LUTS in Lab instead of XYZ. There is still a lot of wasted
1321 // space on 3D CLUT, but since space seems not to be a problem here, 33 points
1322 // would give a reasonable accuracy. Note also that CRD tables must operate in
1323 // 8 bits.
1324 
1325 static
1326 int WriteOutputLUT(cmsIOHANDLER* m, cmsHPROFILE hProfile, cmsUInt32Number Intent, cmsUInt32Number dwFlags)
1327 {
1328     cmsHPROFILE hLab;
1329     cmsHTRANSFORM xform;
1330     cmsUInt32Number i, nChannels;
1331     cmsUInt32Number OutputFormat;
1332     _cmsTRANSFORM* v;
1333     cmsPipeline* DeviceLink;
1334     cmsHPROFILE Profiles[3];
1335     cmsCIEXYZ BlackPointAdaptedToD50;
1336     cmsBool lDoBPC = (cmsBool) (dwFlags & cmsFLAGS_BLACKPOINTCOMPENSATION);
1337     cmsBool lFixWhite = (cmsBool) !(dwFlags & cmsFLAGS_NOWHITEONWHITEFIXUP);
1338     cmsUInt32Number InFrm = TYPE_Lab_16;
1339     cmsUInt32Number RelativeEncodingIntent;
1340     cmsColorSpaceSignature ColorSpace;
1341 
1342 


< prev index next >