< prev index next >

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

Print this page

 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 nG1, cmsUInt32Number nG2)
 562 {
 563     if (nG1 != nG2) return FALSE;
 564     return memcmp(g1, g2, nG1 * sizeof(cmsUInt16Number)) == 0;
 565 }
 566 
 567 
 568 // Does write a set of gamma curves
 569 
 570 static
 571 void EmitNGamma(cmsIOHANDLER* m, cmsUInt32Number n, cmsToneCurve* g[], const char* nameprefix)
 572 {
 573     cmsUInt32Number i;
 574     static char buffer[2048];
 575 
 576     for( i=0; i < n; i++ )
 577     {
 578         if (g[i] == NULL) return; // Error
 579 
 580         if (i > 0 && GammaTableEquals(g[i-1]->Table16, g[i]->Table16, g[i-1]->nEntries, g[i]->nEntries)) {
 581 
 582             _cmsIOPrintf(m, "/%s%d /%s%d load def\n", nameprefix, i, nameprefix, i-1);
 583         }
 584         else {
 585             snprintf(buffer, sizeof(buffer), "%s%d", nameprefix, (int) i);
 586         buffer[sizeof(buffer)-1] = '\0';
 587             Emit1Gamma(m, g[i], buffer);
 588         }
 589     }
 590 
 591 }
 592 
 593 
 594 // Following code dumps a LUT onto memory stream
 595 
 596 
 597 // This is the sampler. Intended to work in SAMPLER_INSPECT mode,
 598 // that is, the callback will be called for each knot with
 599 //
 600 //          In[]  The grid location coordinates, normalized to 0..ffff
 601 //          Out[] The Pipeline values, normalized to 0..ffff
 602 //
 603 //  Returning a value other than 0 does terminate the sampling process
 604 //
 605 //  Each row contains Pipeline values for all but first component. So, I
 606 //  detect row changing by keeping a copy of last value of first
 607 //  component. -1 is used to mark beginning of whole block.

 691                                                const char* PreMin,
 692                                                const char* PostMin,
 693                                                int FixWhite,
 694                                                cmsColorSpaceSignature ColorSpace)
 695 {
 696     cmsUInt32Number i;
 697     cmsPsSamplerCargo sc;
 698 
 699     sc.FirstComponent = -1;
 700     sc.SecondComponent = -1;
 701     sc.Pipeline = (_cmsStageCLutData *) mpe ->Data;
 702     sc.m   = m;
 703     sc.PreMaj = PreMaj;
 704     sc.PostMaj= PostMaj;
 705 
 706     sc.PreMin   = PreMin;
 707     sc.PostMin  = PostMin;
 708     sc.FixWhite = FixWhite;
 709     sc.ColorSpace = ColorSpace;
 710 
 711     _cmsIOPrintf(m, "[");
 712 
 713     for (i=0; i < sc.Pipeline->Params->nInputs; i++)
 714         _cmsIOPrintf(m, " %d ", sc.Pipeline->Params->nSamples[i]);
 715 
 716     _cmsIOPrintf(m, " [\n");

 717 
 718     cmsStageSampleCLut16bit(mpe, OutputValueSampler, (void*) &sc, SAMPLER_INSPECT);
 719 
 720     _cmsIOPrintf(m, PostMin);
 721     _cmsIOPrintf(m, PostMaj);
 722     _cmsIOPrintf(m, "] ");



 723 
 724 }
 725 
 726 
 727 // Dumps CIEBasedA Color Space Array
 728 
 729 static
 730 int EmitCIEBasedA(cmsIOHANDLER* m, cmsToneCurve* Curve, cmsCIEXYZ* BlackPoint)
 731 {
 732 
 733     _cmsIOPrintf(m, "[ /CIEBasedA\n");
 734     _cmsIOPrintf(m, "  <<\n");
 735 
 736     EmitSafeGuardBegin(m, "lcms2gammaproc");
 737     Emit1Gamma(m, Curve, "lcms2gammaproc");

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



 764 
 765     EmitSafeGuardBegin(m, "lcms2gammaproc0");
 766     EmitSafeGuardBegin(m, "lcms2gammaproc1");
 767     EmitSafeGuardBegin(m, "lcms2gammaproc2");
 768     EmitNGamma(m, 3, CurveSet, "lcms2gammaproc");
 769     _cmsIOPrintf(m, "/DecodeABC [\n");
 770     _cmsIOPrintf(m, "   /lcms2gammaproc0 load\n");
 771     _cmsIOPrintf(m, "   /lcms2gammaproc1 load\n");
 772     _cmsIOPrintf(m, "   /lcms2gammaproc2 load\n");
 773     _cmsIOPrintf(m, "]\n");
 774     EmitSafeGuardEnd(m, "lcms2gammaproc2", 3);
 775     EmitSafeGuardEnd(m, "lcms2gammaproc1", 3);
 776     EmitSafeGuardEnd(m, "lcms2gammaproc0", 3);
 777 
 778     _cmsIOPrintf(m, "/MatrixABC [ " );
 779 
 780     for( i=0; i < 3; i++ ) {
 781 
 782         _cmsIOPrintf(m, "%.6f %.6f %.6f ", Matrix[i + 3*0],
 783                                            Matrix[i + 3*1],
 784                                            Matrix[i + 3*2]);
 785     }
 786 
 787 
 788     _cmsIOPrintf(m, "]\n");
 789 
 790     _cmsIOPrintf(m, "/RangeLMN [ 0.0 0.9642 0.0 1.0000 0.0 0.8249 ]\n");
 791 
 792     EmitWhiteBlackD50(m, BlackPoint);
 793     EmitIntent(m, INTENT_PERCEPTUAL);
 794 
 795     _cmsIOPrintf(m, ">>\n");
 796     _cmsIOPrintf(m, "]\n");
 797 
 798 
 799     return 1;
 800 }
 801 
 802 
 803 static
 804 int EmitCIEBasedDEF(cmsIOHANDLER* m, cmsPipeline* Pipeline, cmsUInt32Number Intent, cmsCIEXYZ* BlackPoint)
 805 {
 806     const char* PreMaj;
 807     const char* PostMaj;
 808     const char* PreMin, * PostMin;
 809     cmsStage* mpe;
 810     int i, numchans;
 811     static char buffer[2048];
 812 
 813     mpe = Pipeline->Elements;
 814 
 815     switch (cmsStageInputChannels(mpe)) {
 816     case 3:
 817         _cmsIOPrintf(m, "[ /CIEBasedDEF\n");
 818         PreMaj = "<";
 819         PostMaj = ">\n";
 820         PreMin = PostMin = "";
 821         break;
 822 
 823     case 4:
 824         _cmsIOPrintf(m, "[ /CIEBasedDEFG\n");
 825         PreMaj = "[";
 826         PostMaj = "]\n";
 827         PreMin = "<";
 828         PostMin = ">\n";
 829         break;
 830 
 831     default:
 832         return 0;
 833 
 834     }
 835 
 836     _cmsIOPrintf(m, "<<\n");
 837 
 838     if (cmsStageType(mpe) == cmsSigCurveSetElemType) {
 839 
 840         numchans = (int) cmsStageOutputChannels(mpe);
 841         for (i = 0; i < numchans; ++i) {
 842             snprintf(buffer, sizeof(buffer), "lcms2gammaproc%d", i);
 843             buffer[sizeof(buffer) - 1] = '\0';
 844             EmitSafeGuardBegin(m, buffer);
 845         }
 846         EmitNGamma(m, cmsStageOutputChannels(mpe), _cmsStageGetPtrToCurveSet(mpe), "lcms2gammaproc");
 847         _cmsIOPrintf(m, "/DecodeDEF [\n");
 848         for (i = 0; i < numchans; ++i) {
 849             snprintf(buffer, sizeof(buffer), "  /lcms2gammaproc%d load\n", i);
 850             buffer[sizeof(buffer) - 1] = '\0';
 851             _cmsIOPrintf(m, buffer);
 852         }
 853         _cmsIOPrintf(m, "]\n");
 854         for (i = numchans - 1; i >= 0; --i) {
 855             snprintf(buffer, sizeof(buffer), "lcms2gammaproc%d", i);
 856             buffer[sizeof(buffer) - 1] = '\0';
 857             EmitSafeGuardEnd(m, buffer, 3);
 858         }
 859 
 860         mpe = mpe->Next;
 861     }
 862 
 863     if (cmsStageType(mpe) == cmsSigCLutElemType) {
 864 
 865         _cmsIOPrintf(m, "/Table ");
 866         WriteCLUT(m, mpe, PreMaj, PostMaj, PreMin, PostMin, FALSE, (cmsColorSpaceSignature)0);
 867         _cmsIOPrintf(m, "]\n");
 868     }
 869 
 870     EmitLab2XYZ(m);
 871     EmitWhiteBlackD50(m, BlackPoint);
 872     EmitIntent(m, Intent);
 873 
 874     _cmsIOPrintf(m, "   >>\n");
 875     _cmsIOPrintf(m, "]\n");
 876 
 877     return 1;
 878 }
 879 
 880 // Generates a curve from a gray profile
 881 
 882 static
 883 cmsToneCurve* ExtractGray2Y(cmsContext ContextID, cmsHPROFILE hProfile, cmsUInt32Number Intent)
 884 {
 885     cmsToneCurve* Out = cmsBuildTabulatedToneCurve16(ContextID, 256, NULL);
 886     cmsHPROFILE hXYZ  = cmsCreateXYZProfile();
 887     cmsHTRANSFORM xform = cmsCreateTransformTHR(ContextID, hProfile, TYPE_GRAY_8, hXYZ, TYPE_XYZ_DBL, Intent, cmsFLAGS_NOOPTIMIZE);

1007     cmsDetectBlackPoint(&BlackPointAdaptedToD50, hProfile, INTENT_RELATIVE_COLORIMETRIC, 0);
1008 
1009     if (ColorSpace == cmsSigGrayData) {
1010 
1011         cmsToneCurve** ShaperCurve = _cmsStageGetPtrToCurveSet(Shaper);
1012         rc = EmitCIEBasedA(m, ShaperCurve[0], &BlackPointAdaptedToD50);
1013 
1014     }
1015     else
1016         if (ColorSpace == cmsSigRgbData) {
1017 
1018             cmsMAT3 Mat;
1019             int i, j;
1020 
1021             memmove(&Mat, GetPtrToMatrix(Matrix), sizeof(Mat));
1022 
1023             for (i = 0; i < 3; i++)
1024                 for (j = 0; j < 3; j++)
1025                     Mat.v[i].n[j] *= MAX_ENCODEABLE_XYZ;
1026 
1027             rc = EmitCIEBasedABC(m, (cmsFloat64Number *)&Mat,
1028                 _cmsStageGetPtrToCurveSet(Shaper),
1029                 &BlackPointAdaptedToD50);
1030         }
1031         else {
1032 
1033             cmsSignalError(m->ContextID, cmsERROR_COLORSPACE_CHECK, "Profile is not suitable for CSA. Unsupported colorspace.");
1034             return 0;
1035         }
1036 
1037     return rc;
1038 }
1039 
1040 
1041 
1042 // Creates a PostScript color list from a named profile data.
1043 // This is a HP extension, and it works in Lab instead of XYZ
1044 
1045 static
1046 int WriteNamedColorCSA(cmsIOHANDLER* m, cmsHPROFILE hNamedColor, cmsUInt32Number Intent)
1047 {
1048     cmsHTRANSFORM xform;
1049     cmsHPROFILE   hLab;
1050     cmsUInt32Number i, nColors;
1051     char ColorName[cmsMAX_PATH];
1052     cmsNAMEDCOLORLIST* NamedColorList;
1053 
1054     hLab  = cmsCreateLab4ProfileTHR(m ->ContextID, NULL);
1055     xform = cmsCreateTransform(hNamedColor, TYPE_NAMED_COLOR_INDEX, hLab, TYPE_Lab_DBL, Intent, 0);


1056     if (xform == NULL) return 0;
1057 
1058     NamedColorList = cmsGetNamedColorList(xform);
1059     if (NamedColorList == NULL) return 0;



1060 
1061     _cmsIOPrintf(m, "<<\n");
1062     _cmsIOPrintf(m, "(colorlistcomment) (%s)\n", "Named color CSA");
1063     _cmsIOPrintf(m, "(Prefix) [ (Pantone ) (PANTONE ) ]\n");
1064     _cmsIOPrintf(m, "(Suffix) [ ( CV) ( CVC) ( C) ]\n");
1065 
1066     nColors   = cmsNamedColorCount(NamedColorList);
1067 
1068 
1069     for (i=0; i < nColors; i++) {
1070 
1071         cmsUInt16Number In[1];
1072         cmsCIELab Lab;
1073 
1074         In[0] = (cmsUInt16Number) i;
1075 
1076         if (!cmsNamedColorInfo(NamedColorList, i, ColorName, NULL, NULL, NULL, NULL))
1077                 continue;
1078 
1079         cmsDoTransform(xform, In, &Lab, 1);
1080         _cmsIOPrintf(m, "  (%s) [ %.3f %.3f %.3f ]\n", ColorName, Lab.L, Lab.a, Lab.b);
1081     }
1082 
1083 
1084 
1085     _cmsIOPrintf(m, ">>\n");
1086 
1087     cmsDeleteTransform(xform);
1088     cmsCloseProfile(hLab);
1089     return 1;
1090 }
1091 
1092 
1093 // Does create a Color Space Array on XYZ colorspace for PostScript usage
1094 static
1095 cmsUInt32Number GenerateCSA(cmsContext ContextID,
1096                             cmsHPROFILE hProfile,
1097                             cmsUInt32Number Intent,
1098                             cmsUInt32Number dwFlags,
1099                             cmsIOHANDLER* mem)
1100 {
1101     cmsUInt32Number dwBytesUsed;
1102     cmsPipeline* lut = NULL;
1103     cmsStage* Matrix, *Shaper;
1104 
1105 
1106     // Is a named color profile?
1107     if (cmsGetDeviceClass(hProfile) == cmsSigNamedColorClass) {
1108 

1322 // space on 3D CLUT, but since space seems not to be a problem here, 33 points
1323 // would give a reasonable accuracy. Note also that CRD tables must operate in
1324 // 8 bits.
1325 
1326 static
1327 int WriteOutputLUT(cmsIOHANDLER* m, cmsHPROFILE hProfile, cmsUInt32Number Intent, cmsUInt32Number dwFlags)
1328 {
1329     cmsHPROFILE hLab;
1330     cmsHTRANSFORM xform;
1331     cmsUInt32Number i, nChannels;
1332     cmsUInt32Number OutputFormat;
1333     _cmsTRANSFORM* v;
1334     cmsPipeline* DeviceLink;
1335     cmsHPROFILE Profiles[3];
1336     cmsCIEXYZ BlackPointAdaptedToD50;
1337     cmsBool lDoBPC = (cmsBool) (dwFlags & cmsFLAGS_BLACKPOINTCOMPENSATION);
1338     cmsBool lFixWhite = (cmsBool) !(dwFlags & cmsFLAGS_NOWHITEONWHITEFIXUP);
1339     cmsUInt32Number InFrm = TYPE_Lab_16;
1340     cmsUInt32Number RelativeEncodingIntent;
1341     cmsColorSpaceSignature ColorSpace;
1342 
1343 
1344     hLab = cmsCreateLab4ProfileTHR(m ->ContextID, NULL);
1345     if (hLab == NULL) return 0;
1346 
1347     OutputFormat = cmsFormatterForColorspaceOfProfile(hProfile, 2, FALSE);
1348     nChannels    = T_CHANNELS(OutputFormat);
1349 
1350     ColorSpace = cmsGetColorSpace(hProfile);
1351 
1352     // For absolute colorimetric, the LUT is encoded as relative in order to preserve precision.
1353 
1354     RelativeEncodingIntent = Intent;
1355     if (RelativeEncodingIntent == INTENT_ABSOLUTE_COLORIMETRIC)
1356         RelativeEncodingIntent = INTENT_RELATIVE_COLORIMETRIC;
1357 
1358 
1359     // Use V4 Lab always
1360     Profiles[0] = hLab;
1361     Profiles[1] = hProfile;
1362 
1363     xform = cmsCreateMultiprofileTransformTHR(m ->ContextID,
1364                                               Profiles, 2, TYPE_Lab_DBL,
1365                                               OutputFormat, RelativeEncodingIntent, 0);
1366     cmsCloseProfile(hLab);
1367 
1368     if (xform == NULL) {
1369 
1370         cmsSignalError(m ->ContextID, cmsERROR_COLORSPACE_CHECK, "Cannot create transform Lab -> Profile in CRD creation");
1371         return 0;
1372     }
1373 
1374     // Get a copy of the internal devicelink
1375     v = (_cmsTRANSFORM*) xform;
1376     DeviceLink = cmsPipelineDup(v ->Lut);
1377     if (DeviceLink == NULL) return 0;
1378 


1379 
1380     // We need a CLUT
1381     dwFlags |= cmsFLAGS_FORCE_CLUT;
1382     _cmsOptimizePipeline(m->ContextID, &DeviceLink, RelativeEncodingIntent, &InFrm, &OutputFormat, &dwFlags);
1383 
1384     _cmsIOPrintf(m, "<<\n");
1385     _cmsIOPrintf(m, "/ColorRenderingType 1\n");
1386 
1387 
1388     cmsDetectBlackPoint(&BlackPointAdaptedToD50, hProfile, Intent, 0);
1389 
1390     // Emit headers, etc.
1391     EmitWhiteBlackD50(m, &BlackPointAdaptedToD50);
1392     EmitPQRStage(m, hProfile, lDoBPC, Intent == INTENT_ABSOLUTE_COLORIMETRIC);
1393     EmitXYZ2Lab(m);
1394 
1395 
1396     // FIXUP: map Lab (100, 0, 0) to perfect white, because the particular encoding for Lab
1397     // does map a=b=0 not falling into any specific node. Since range a,b goes -128..127,
1398     // zero is slightly moved towards right, so assure next node (in L=100 slice) is mapped to
1399     // zero. This would sacrifice a bit of highlights, but failure to do so would cause
1400     // scum dot. Ouch.
1401 
1402     if (Intent == INTENT_ABSOLUTE_COLORIMETRIC)
1403             lFixWhite = FALSE;
1404 
1405     _cmsIOPrintf(m, "/RenderTable ");
1406 
1407 
1408     WriteCLUT(m, cmsPipelineGetPtrToFirstStage(DeviceLink), "<", ">\n", "", "", lFixWhite, ColorSpace);


1409 
1410     _cmsIOPrintf(m, " %d {} bind ", nChannels);
1411 
1412     for (i=1; i < nChannels; i++)
1413             _cmsIOPrintf(m, "dup ");
1414 
1415     _cmsIOPrintf(m, "]\n");
1416 
1417 
1418     EmitIntent(m, Intent);
1419 
1420     _cmsIOPrintf(m, ">>\n");
1421 
1422     if (!(dwFlags & cmsFLAGS_NODEFAULTRESOURCEDEF)) {
1423 
1424         _cmsIOPrintf(m, "/Current exch /ColorRendering defineresource pop\n");
1425     }
1426 
1427     cmsPipelineFree(DeviceLink);
1428     cmsDeleteTransform(xform);
1429 
1430     return 1;
1431 }
1432 
1433 
1434 // Builds a ASCII string containing colorant list in 0..1.0 range
1435 static
1436 void BuildColorantList(char *Colorant, cmsUInt32Number nColorant, cmsUInt16Number Out[])
1437 {

1460 static
1461 int WriteNamedColorCRD(cmsIOHANDLER* m, cmsHPROFILE hNamedColor, cmsUInt32Number Intent, cmsUInt32Number dwFlags)
1462 {
1463     cmsHTRANSFORM xform;
1464     cmsUInt32Number i, nColors, nColorant;
1465     cmsUInt32Number OutputFormat;
1466     char ColorName[cmsMAX_PATH];
1467     char Colorant[512];
1468     cmsNAMEDCOLORLIST* NamedColorList;
1469 
1470 
1471     OutputFormat = cmsFormatterForColorspaceOfProfile(hNamedColor, 2, FALSE);
1472     nColorant    = T_CHANNELS(OutputFormat);
1473 
1474 
1475     xform = cmsCreateTransform(hNamedColor, TYPE_NAMED_COLOR_INDEX, NULL, OutputFormat, Intent, dwFlags);
1476     if (xform == NULL) return 0;
1477 
1478 
1479     NamedColorList = cmsGetNamedColorList(xform);
1480     if (NamedColorList == NULL) return 0;



1481 
1482     _cmsIOPrintf(m, "<<\n");
1483     _cmsIOPrintf(m, "(colorlistcomment) (%s) \n", "Named profile");
1484     _cmsIOPrintf(m, "(Prefix) [ (Pantone ) (PANTONE ) ]\n");
1485     _cmsIOPrintf(m, "(Suffix) [ ( CV) ( CVC) ( C) ]\n");
1486 
1487     nColors   = cmsNamedColorCount(NamedColorList);
1488 
1489     for (i=0; i < nColors; i++) {
1490 
1491         cmsUInt16Number In[1];
1492         cmsUInt16Number Out[cmsMAXCHANNELS];
1493 
1494         In[0] = (cmsUInt16Number) i;
1495 
1496         if (!cmsNamedColorInfo(NamedColorList, i, ColorName, NULL, NULL, NULL, NULL))
1497                 continue;
1498 
1499         cmsDoTransform(xform, In, Out, 1);
1500         BuildColorantList(Colorant, nColorant, Out);

 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 










 464 
 465 // Outputs a table of words. It does use 16 bits
 466 
 467 static
 468 void Emit1Gamma(cmsIOHANDLER* m, cmsToneCurve* Table)
 469 {
 470     cmsUInt32Number i;
 471     cmsFloat64Number gamma;
 472 
 473     /**
 474     * On error, empty tables or lienar assume gamma 1.0
 475     */
 476     if (Table == NULL ||
 477         Table->nEntries <= 0 ||
 478         cmsIsToneCurveLinear(Table)) {
 479 
 480         _cmsIOPrintf(m, "{ 1 } bind ");
 481         return;
 482     }
 483 


 484 
 485     // Check if is really an exponential. If so, emit "exp"
 486     gamma = cmsEstimateGamma(Table, 0.001);
 487      if (gamma > 0) {
 488             _cmsIOPrintf(m, "{ %g exp } bind ", gamma);
 489             return;
 490      }
 491 
 492     _cmsIOPrintf(m, "{ ");
 493 
 494     // Bounds check
 495     EmitRangeCheck(m);
 496 
 497     // Emit intepolation code
 498 
 499     // PostScript code                      Stack
 500     // ===============                      ========================
 501                                             // v
 502     _cmsIOPrintf(m, " [");
 503 
 504     for (i=0; i < Table->nEntries; i++) {
 505     if (i % 10 == 0)
 506             _cmsIOPrintf(m, "\n  ");
 507         _cmsIOPrintf(m, "%d ", Table->Table16[i]);
 508     }
 509 
 510     _cmsIOPrintf(m, "] ");                        // v tab
 511 












 512     _cmsIOPrintf(m, "dup ");                      // v tab tab
 513     _cmsIOPrintf(m, "length 1 sub ");             // v tab dom
 514     _cmsIOPrintf(m, "3 -1 roll ");                // tab dom v
 515     _cmsIOPrintf(m, "mul ");                      // tab val2
 516     _cmsIOPrintf(m, "dup ");                      // tab val2 val2
 517     _cmsIOPrintf(m, "dup ");                      // tab val2 val2 val2
 518     _cmsIOPrintf(m, "floor cvi ");                // tab val2 val2 cell0
 519     _cmsIOPrintf(m, "exch ");                     // tab val2 cell0 val2
 520     _cmsIOPrintf(m, "ceiling cvi ");              // tab val2 cell0 cell1
 521     _cmsIOPrintf(m, "3 index ");                  // tab val2 cell0 cell1 tab
 522     _cmsIOPrintf(m, "exch ");                     // tab val2 cell0 tab cell1
 523     _cmsIOPrintf(m, "get\n  ");                   // tab val2 cell0 y1
 524     _cmsIOPrintf(m, "4 -1 roll ");                // val2 cell0 y1 tab
 525     _cmsIOPrintf(m, "3 -1 roll ");                // val2 y1 tab cell0
 526     _cmsIOPrintf(m, "get ");                      // val2 y1 y0
 527     _cmsIOPrintf(m, "dup ");                      // val2 y1 y0 y0
 528     _cmsIOPrintf(m, "3 1 roll ");                 // val2 y0 y1 y0
 529     _cmsIOPrintf(m, "sub ");                      // val2 y0 (y1-y0)
 530     _cmsIOPrintf(m, "3 -1 roll ");                // y0 (y1-y0) val2
 531     _cmsIOPrintf(m, "dup ");                      // y0 (y1-y0) val2 val2
 532     _cmsIOPrintf(m, "floor cvi ");                // y0 (y1-y0) val2 floor(val2)
 533     _cmsIOPrintf(m, "sub ");                      // y0 (y1-y0) rest
 534     _cmsIOPrintf(m, "mul ");                      // y0 t1
 535     _cmsIOPrintf(m, "add ");                      // y
 536     _cmsIOPrintf(m, "65535 div\n");               // result
 537 
 538     _cmsIOPrintf(m, " } bind ");


 539 }
 540 
 541 
 542 // Compare gamma table
 543 
 544 static
 545 cmsBool GammaTableEquals(cmsUInt16Number* g1, cmsUInt16Number* g2, cmsUInt32Number nG1, cmsUInt32Number nG2)
 546 {
 547     if (nG1 != nG2) return FALSE;
 548     return memcmp(g1, g2, nG1 * sizeof(cmsUInt16Number)) == 0;
 549 }
 550 
 551 
 552 // Does write a set of gamma curves
 553 
 554 static
 555 void EmitNGamma(cmsIOHANDLER* m, cmsUInt32Number n, cmsToneCurve* g[])
 556 {
 557     cmsUInt32Number i;
 558 
 559 
 560     for( i=0; i < n; i++ )
 561     {
 562         if (g[i] == NULL) return; // Error
 563 
 564         if (i > 0 && GammaTableEquals(g[i-1]->Table16, g[i]->Table16, g[i-1]->nEntries, g[i]->nEntries)) {
 565 
 566             _cmsIOPrintf(m, "dup ");
 567         }
 568         else {
 569             Emit1Gamma(m, g[i]);


 570         }
 571     }
 572 
 573 }
 574 
 575 
 576 // Following code dumps a LUT onto memory stream
 577 
 578 
 579 // This is the sampler. Intended to work in SAMPLER_INSPECT mode,
 580 // that is, the callback will be called for each knot with
 581 //
 582 //          In[]  The grid location coordinates, normalized to 0..ffff
 583 //          Out[] The Pipeline values, normalized to 0..ffff
 584 //
 585 //  Returning a value other than 0 does terminate the sampling process
 586 //
 587 //  Each row contains Pipeline values for all but first component. So, I
 588 //  detect row changing by keeping a copy of last value of first
 589 //  component. -1 is used to mark beginning of whole block.

 673                                                const char* PreMin,
 674                                                const char* PostMin,
 675                                                int FixWhite,
 676                                                cmsColorSpaceSignature ColorSpace)
 677 {
 678     cmsUInt32Number i;
 679     cmsPsSamplerCargo sc;
 680 
 681     sc.FirstComponent = -1;
 682     sc.SecondComponent = -1;
 683     sc.Pipeline = (_cmsStageCLutData *) mpe ->Data;
 684     sc.m   = m;
 685     sc.PreMaj = PreMaj;
 686     sc.PostMaj= PostMaj;
 687 
 688     sc.PreMin   = PreMin;
 689     sc.PostMin  = PostMin;
 690     sc.FixWhite = FixWhite;
 691     sc.ColorSpace = ColorSpace;
 692 
 693     if (sc.Pipeline != NULL && sc.Pipeline->Params != NULL) {
 694 
 695         _cmsIOPrintf(m, "[");

 696 
 697         for (i = 0; i < sc.Pipeline->Params->nInputs; i++)
 698             _cmsIOPrintf(m, " %d ", sc.Pipeline->Params->nSamples[i]);
 699 
 700         _cmsIOPrintf(m, " [\n");
 701 
 702         cmsStageSampleCLut16bit(mpe, OutputValueSampler, (void*)&sc, SAMPLER_INSPECT);
 703 
 704         _cmsIOPrintf(m, PostMin);
 705         _cmsIOPrintf(m, PostMaj);
 706         _cmsIOPrintf(m, "] ");
 707     }
 708 
 709 }
 710 
 711 
 712 // Dumps CIEBasedA Color Space Array
 713 
 714 static
 715 int EmitCIEBasedA(cmsIOHANDLER* m, cmsToneCurve* Curve, cmsCIEXYZ* BlackPoint)
 716 {
 717 
 718     _cmsIOPrintf(m, "[ /CIEBasedA\n");
 719     _cmsIOPrintf(m, "  <<\n");
 720 
 721     _cmsIOPrintf(m, "/DecodeA ");
 722 
 723     Emit1Gamma(m, Curve);
 724 
 725     _cmsIOPrintf(m, " \n");

 726 
 727     _cmsIOPrintf(m, "/MatrixA [ 0.9642 1.0000 0.8249 ]\n");
 728     _cmsIOPrintf(m, "/RangeLMN [ 0.0 0.9642 0.0 1.0000 0.0 0.8249 ]\n");
 729 
 730     EmitWhiteBlackD50(m, BlackPoint);
 731     EmitIntent(m, INTENT_PERCEPTUAL);
 732 
 733     _cmsIOPrintf(m, ">>\n");
 734     _cmsIOPrintf(m, "]\n");
 735 
 736     return 1;
 737 }
 738 
 739 
 740 // Dumps CIEBasedABC Color Space Array
 741 
 742 static
 743 int EmitCIEBasedABC(cmsIOHANDLER* m, cmsFloat64Number* Matrix, cmsToneCurve** CurveSet, cmsCIEXYZ* BlackPoint)
 744 {
 745     int i;
 746 
 747     _cmsIOPrintf(m, "[ /CIEBasedABC\n");
 748     _cmsIOPrintf(m, "<<\n");
 749     _cmsIOPrintf(m, "/DecodeABC [ ");
 750 
 751     EmitNGamma(m, 3, CurveSet);
 752 








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



 754 
 755     _cmsIOPrintf(m, "/MatrixABC [ " );
 756 
 757     for( i=0; i < 3; i++ ) {
 758 
 759         _cmsIOPrintf(m, "%.6f %.6f %.6f ", Matrix[i + 3*0],
 760                                            Matrix[i + 3*1],
 761                                            Matrix[i + 3*2]);
 762     }
 763 
 764 
 765     _cmsIOPrintf(m, "]\n");
 766 
 767     _cmsIOPrintf(m, "/RangeLMN [ 0.0 0.9642 0.0 1.0000 0.0 0.8249 ]\n");
 768 
 769     EmitWhiteBlackD50(m, BlackPoint);
 770     EmitIntent(m, INTENT_PERCEPTUAL);
 771 
 772     _cmsIOPrintf(m, ">>\n");
 773     _cmsIOPrintf(m, "]\n");
 774 
 775 
 776     return 1;
 777 }
 778 
 779 
 780 static
 781 int EmitCIEBasedDEF(cmsIOHANDLER* m, cmsPipeline* Pipeline, cmsUInt32Number Intent, cmsCIEXYZ* BlackPoint)
 782 {
 783     const char* PreMaj;
 784     const char* PostMaj;
 785     const char* PreMin, *PostMin;
 786     cmsStage* mpe;


 787 
 788     mpe = Pipeline->Elements;
 789 
 790     switch (cmsStageInputChannels(mpe)) {
 791     case 3:
 792         _cmsIOPrintf(m, "[ /CIEBasedDEF\n");
 793         PreMaj = "<";
 794         PostMaj = ">\n";
 795         PreMin = PostMin = "";
 796         break;
 797 
 798     case 4:
 799         _cmsIOPrintf(m, "[ /CIEBasedDEFG\n");
 800         PreMaj = "[";
 801         PostMaj = "]\n";
 802         PreMin = "<";
 803         PostMin = ">\n";
 804         break;
 805 
 806     default:
 807         return 0;
 808 
 809     }
 810 
 811     _cmsIOPrintf(m, "<<\n");
 812 
 813     if (cmsStageType(mpe) == cmsSigCurveSetElemType) {
 814 
 815         _cmsIOPrintf(m, "/DecodeDEF [ ");
 816         EmitNGamma(m, cmsStageOutputChannels(mpe), _cmsStageGetPtrToCurveSet(mpe));











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





 818 
 819         mpe = mpe ->Next;
 820     }
 821 
 822     if (cmsStageType(mpe) == cmsSigCLutElemType) {
 823 
 824             _cmsIOPrintf(m, "/Table ");
 825             WriteCLUT(m, mpe, PreMaj, PostMaj, PreMin, PostMin, FALSE, (cmsColorSpaceSignature) 0);
 826             _cmsIOPrintf(m, "]\n");
 827     }
 828 
 829     EmitLab2XYZ(m);
 830     EmitWhiteBlackD50(m, BlackPoint);
 831     EmitIntent(m, Intent);
 832 
 833     _cmsIOPrintf(m, "   >>\n");
 834     _cmsIOPrintf(m, "]\n");
 835 
 836     return 1;
 837 }
 838 
 839 // Generates a curve from a gray profile
 840 
 841 static
 842 cmsToneCurve* ExtractGray2Y(cmsContext ContextID, cmsHPROFILE hProfile, cmsUInt32Number Intent)
 843 {
 844     cmsToneCurve* Out = cmsBuildTabulatedToneCurve16(ContextID, 256, NULL);
 845     cmsHPROFILE hXYZ  = cmsCreateXYZProfile();
 846     cmsHTRANSFORM xform = cmsCreateTransformTHR(ContextID, hProfile, TYPE_GRAY_8, hXYZ, TYPE_XYZ_DBL, Intent, cmsFLAGS_NOOPTIMIZE);

 966     cmsDetectBlackPoint(&BlackPointAdaptedToD50, hProfile, INTENT_RELATIVE_COLORIMETRIC, 0);
 967 
 968     if (ColorSpace == cmsSigGrayData) {
 969 
 970         cmsToneCurve** ShaperCurve = _cmsStageGetPtrToCurveSet(Shaper);
 971         rc = EmitCIEBasedA(m, ShaperCurve[0], &BlackPointAdaptedToD50);
 972 
 973     }
 974     else
 975         if (ColorSpace == cmsSigRgbData) {
 976 
 977             cmsMAT3 Mat;
 978             int i, j;
 979 
 980             memmove(&Mat, GetPtrToMatrix(Matrix), sizeof(Mat));
 981 
 982             for (i = 0; i < 3; i++)
 983                 for (j = 0; j < 3; j++)
 984                     Mat.v[i].n[j] *= MAX_ENCODEABLE_XYZ;
 985 
 986             rc = EmitCIEBasedABC(m,  (cmsFloat64Number *) &Mat,
 987                                 _cmsStageGetPtrToCurveSet(Shaper),
 988                                  &BlackPointAdaptedToD50);
 989         }
 990         else {
 991 
 992             cmsSignalError(m->ContextID, cmsERROR_COLORSPACE_CHECK, "Profile is not suitable for CSA. Unsupported colorspace.");
 993             return 0;
 994         }
 995 
 996     return rc;
 997 }
 998 
 999 
1000 
1001 // Creates a PostScript color list from a named profile data.
1002 // This is a HP extension, and it works in Lab instead of XYZ
1003 
1004 static
1005 int WriteNamedColorCSA(cmsIOHANDLER* m, cmsHPROFILE hNamedColor, cmsUInt32Number Intent)
1006 {
1007     cmsHTRANSFORM xform;
1008     cmsHPROFILE   hLab;
1009     cmsUInt32Number i, nColors;
1010     char ColorName[cmsMAX_PATH];
1011     cmsNAMEDCOLORLIST* NamedColorList;
1012 
1013     hLab  = cmsCreateLab4ProfileTHR(m ->ContextID, NULL);
1014     xform = cmsCreateTransform(hNamedColor, TYPE_NAMED_COLOR_INDEX, hLab, TYPE_Lab_DBL, Intent, 0);
1015     cmsCloseProfile(hLab);
1016 
1017     if (xform == NULL) return 0;
1018 
1019     NamedColorList = cmsGetNamedColorList(xform);
1020     if (NamedColorList == NULL) {
1021         cmsDeleteTransform(xform);
1022         return 0;
1023     }
1024 
1025     _cmsIOPrintf(m, "<<\n");
1026     _cmsIOPrintf(m, "(colorlistcomment) (%s)\n", "Named color CSA");
1027     _cmsIOPrintf(m, "(Prefix) [ (Pantone ) (PANTONE ) ]\n");
1028     _cmsIOPrintf(m, "(Suffix) [ ( CV) ( CVC) ( C) ]\n");
1029 
1030     nColors   = cmsNamedColorCount(NamedColorList);
1031 

1032     for (i=0; i < nColors; i++) {
1033 
1034         cmsUInt16Number In[1];
1035         cmsCIELab Lab;
1036 
1037         In[0] = (cmsUInt16Number) i;
1038 
1039         if (!cmsNamedColorInfo(NamedColorList, i, ColorName, NULL, NULL, NULL, NULL))
1040                 continue;
1041 
1042         cmsDoTransform(xform, In, &Lab, 1);
1043         _cmsIOPrintf(m, "  (%s) [ %.3f %.3f %.3f ]\n", ColorName, Lab.L, Lab.a, Lab.b);
1044     }
1045 


1046     _cmsIOPrintf(m, ">>\n");
1047 
1048     cmsDeleteTransform(xform);

1049     return 1;
1050 }
1051 
1052 
1053 // Does create a Color Space Array on XYZ colorspace for PostScript usage
1054 static
1055 cmsUInt32Number GenerateCSA(cmsContext ContextID,
1056                             cmsHPROFILE hProfile,
1057                             cmsUInt32Number Intent,
1058                             cmsUInt32Number dwFlags,
1059                             cmsIOHANDLER* mem)
1060 {
1061     cmsUInt32Number dwBytesUsed;
1062     cmsPipeline* lut = NULL;
1063     cmsStage* Matrix, *Shaper;
1064 
1065 
1066     // Is a named color profile?
1067     if (cmsGetDeviceClass(hProfile) == cmsSigNamedColorClass) {
1068 

1282 // space on 3D CLUT, but since space seems not to be a problem here, 33 points
1283 // would give a reasonable accuracy. Note also that CRD tables must operate in
1284 // 8 bits.
1285 
1286 static
1287 int WriteOutputLUT(cmsIOHANDLER* m, cmsHPROFILE hProfile, cmsUInt32Number Intent, cmsUInt32Number dwFlags)
1288 {
1289     cmsHPROFILE hLab;
1290     cmsHTRANSFORM xform;
1291     cmsUInt32Number i, nChannels;
1292     cmsUInt32Number OutputFormat;
1293     _cmsTRANSFORM* v;
1294     cmsPipeline* DeviceLink;
1295     cmsHPROFILE Profiles[3];
1296     cmsCIEXYZ BlackPointAdaptedToD50;
1297     cmsBool lDoBPC = (cmsBool) (dwFlags & cmsFLAGS_BLACKPOINTCOMPENSATION);
1298     cmsBool lFixWhite = (cmsBool) !(dwFlags & cmsFLAGS_NOWHITEONWHITEFIXUP);
1299     cmsUInt32Number InFrm = TYPE_Lab_16;
1300     cmsUInt32Number RelativeEncodingIntent;
1301     cmsColorSpaceSignature ColorSpace;
1302     cmsStage* first;
1303 
1304     hLab = cmsCreateLab4ProfileTHR(m ->ContextID, NULL);
1305     if (hLab == NULL) return 0;
1306 
1307     OutputFormat = cmsFormatterForColorspaceOfProfile(hProfile, 2, FALSE);
1308     nChannels    = T_CHANNELS(OutputFormat);
1309 
1310     ColorSpace = cmsGetColorSpace(hProfile);
1311 
1312     // For absolute colorimetric, the LUT is encoded as relative in order to preserve precision.
1313 
1314     RelativeEncodingIntent = Intent;
1315     if (RelativeEncodingIntent == INTENT_ABSOLUTE_COLORIMETRIC)
1316         RelativeEncodingIntent = INTENT_RELATIVE_COLORIMETRIC;
1317 
1318 
1319     // Use V4 Lab always
1320     Profiles[0] = hLab;
1321     Profiles[1] = hProfile;
1322 
1323     xform = cmsCreateMultiprofileTransformTHR(m ->ContextID,
1324                                               Profiles, 2, TYPE_Lab_DBL,
1325                                               OutputFormat, RelativeEncodingIntent, 0);
1326     cmsCloseProfile(hLab);
1327 
1328     if (xform == NULL) {

1329         cmsSignalError(m ->ContextID, cmsERROR_COLORSPACE_CHECK, "Cannot create transform Lab -> Profile in CRD creation");
1330         return 0;
1331     }
1332 
1333     // Get a copy of the internal devicelink
1334     v = (_cmsTRANSFORM*) xform;
1335     DeviceLink = cmsPipelineDup(v ->Lut);
1336     if (DeviceLink == NULL) {
1337         cmsDeleteTransform(xform);
1338         return 0;
1339     }
1340 
1341      // We need a CLUT
1342     dwFlags |= cmsFLAGS_FORCE_CLUT;
1343     _cmsOptimizePipeline(m->ContextID, &DeviceLink, RelativeEncodingIntent, &InFrm, &OutputFormat, &dwFlags);
1344 
1345     _cmsIOPrintf(m, "<<\n");
1346     _cmsIOPrintf(m, "/ColorRenderingType 1\n");
1347 
1348 
1349     cmsDetectBlackPoint(&BlackPointAdaptedToD50, hProfile, Intent, 0);
1350 
1351     // Emit headers, etc.
1352     EmitWhiteBlackD50(m, &BlackPointAdaptedToD50);
1353     EmitPQRStage(m, hProfile, lDoBPC, Intent == INTENT_ABSOLUTE_COLORIMETRIC);
1354     EmitXYZ2Lab(m);
1355 
1356 
1357     // FIXUP: map Lab (100, 0, 0) to perfect white, because the particular encoding for Lab
1358     // does map a=b=0 not falling into any specific node. Since range a,b goes -128..127,
1359     // zero is slightly moved towards right, so assure next node (in L=100 slice) is mapped to
1360     // zero. This would sacrifice a bit of highlights, but failure to do so would cause
1361     // scum dot. Ouch.
1362 
1363     if (Intent == INTENT_ABSOLUTE_COLORIMETRIC)
1364             lFixWhite = FALSE;
1365 
1366     _cmsIOPrintf(m, "/RenderTable ");
1367 
1368     first = cmsPipelineGetPtrToFirstStage(DeviceLink);
1369     if (first != NULL) {
1370         WriteCLUT(m, first, "<", ">\n", "", "", lFixWhite, ColorSpace);
1371     }
1372 
1373     _cmsIOPrintf(m, " %d {} bind ", nChannels);
1374 
1375     for (i=1; i < nChannels; i++)
1376             _cmsIOPrintf(m, "dup ");
1377 
1378     _cmsIOPrintf(m, "]\n");
1379 

1380     EmitIntent(m, Intent);
1381 
1382     _cmsIOPrintf(m, ">>\n");
1383 
1384     if (!(dwFlags & cmsFLAGS_NODEFAULTRESOURCEDEF)) {
1385 
1386         _cmsIOPrintf(m, "/Current exch /ColorRendering defineresource pop\n");
1387     }
1388 
1389     cmsPipelineFree(DeviceLink);
1390     cmsDeleteTransform(xform);
1391 
1392     return 1;
1393 }
1394 
1395 
1396 // Builds a ASCII string containing colorant list in 0..1.0 range
1397 static
1398 void BuildColorantList(char *Colorant, cmsUInt32Number nColorant, cmsUInt16Number Out[])
1399 {

1422 static
1423 int WriteNamedColorCRD(cmsIOHANDLER* m, cmsHPROFILE hNamedColor, cmsUInt32Number Intent, cmsUInt32Number dwFlags)
1424 {
1425     cmsHTRANSFORM xform;
1426     cmsUInt32Number i, nColors, nColorant;
1427     cmsUInt32Number OutputFormat;
1428     char ColorName[cmsMAX_PATH];
1429     char Colorant[512];
1430     cmsNAMEDCOLORLIST* NamedColorList;
1431 
1432 
1433     OutputFormat = cmsFormatterForColorspaceOfProfile(hNamedColor, 2, FALSE);
1434     nColorant    = T_CHANNELS(OutputFormat);
1435 
1436 
1437     xform = cmsCreateTransform(hNamedColor, TYPE_NAMED_COLOR_INDEX, NULL, OutputFormat, Intent, dwFlags);
1438     if (xform == NULL) return 0;
1439 
1440 
1441     NamedColorList = cmsGetNamedColorList(xform);
1442     if (NamedColorList == NULL) {
1443         cmsDeleteTransform(xform);
1444         return 0;
1445     }
1446 
1447     _cmsIOPrintf(m, "<<\n");
1448     _cmsIOPrintf(m, "(colorlistcomment) (%s) \n", "Named profile");
1449     _cmsIOPrintf(m, "(Prefix) [ (Pantone ) (PANTONE ) ]\n");
1450     _cmsIOPrintf(m, "(Suffix) [ ( CV) ( CVC) ( C) ]\n");
1451 
1452     nColors   = cmsNamedColorCount(NamedColorList);
1453 
1454     for (i=0; i < nColors; i++) {
1455 
1456         cmsUInt16Number In[1];
1457         cmsUInt16Number Out[cmsMAXCHANNELS];
1458 
1459         In[0] = (cmsUInt16Number) i;
1460 
1461         if (!cmsNamedColorInfo(NamedColorList, i, ColorName, NULL, NULL, NULL, NULL))
1462                 continue;
1463 
1464         cmsDoTransform(xform, In, Out, 1);
1465         BuildColorantList(Colorant, nColorant, Out);
< prev index next >