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
|