1 //
2 // Little cms
3 // Copyright (C) 1998-2007 Marti Maria
4 //
5 // Permission is hereby granted, free of charge, to any person obtaining
6 // a copy of this software and associated documentation files (the "Software"),
7 // to deal in the Software without restriction, including without limitation
8 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 // and/or sell copies of the Software, and to permit persons to whom the Software
10 // is furnished to do so, subject to the following conditions:
11 //
12 // The above copyright notice and this permission notice shall be included in
13 // all copies or substantial portions of the Software.
14 //
15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
17 // THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
23 // Test Suite for Little cms
24
25 // #define ICM_COMPARATIVE 1
26 // #define CHECK_SPEED 1
27
28 #ifdef __BORLANDC__
29 # include <condefs.h>
30 #endif
31
32 #include "lcms.h"
33
34
35
36 #include <time.h>
37 #include <stdio.h>
38 #include <stdlib.h>
39
40 #ifndef NON_WINDOWS
41 #include <icm.h>
42 #endif
43
44
45 #define PREC 20
46
47 #define TYPE_XYZA_16 (COLORSPACE_SH(PT_XYZ)|CHANNELS_SH(3)|BYTES_SH(2)|EXTRA_SH(1))
48 #define TYPE_LABA_16 (COLORSPACE_SH(PT_Lab)|CHANNELS_SH(3)|BYTES_SH(2)|EXTRA_SH(1))
49
50 typedef struct {BYTE r, g, b, a;} Scanline_rgb1;
51 typedef struct {WORD r, g, b, a;} Scanline_rgb2;
52 typedef struct {BYTE r, g, b;} Scanline_rgb8;
53 typedef struct {WORD r, g, b;} Scanline_rgb0;
54
55
56 // Print a dot for gauging
57
58 static
Dot(void)59 void Dot(void)
60 {
61 fprintf(stdout, "."); fflush(stdout);
62 }
63
64 // #ifndef LCMS_DLL
65
66 // Are we little or big endian? From Harbison&Steele.
67
68 static
CheckEndianess(void)69 int CheckEndianess(void)
70 {
71 int BigEndian, IsOk;
72 union {
73
74 long l;
75 char c[sizeof (long)];
76
77 } u;
78
79 u.l = 1;
80 BigEndian = (u.c[sizeof (long) - 1] == 1);
81
82 #ifdef USE_BIG_ENDIAN
83 IsOk = BigEndian;
84 #else
85 IsOk = !BigEndian;
86 #endif
87
88 if (!IsOk) {
89
90 printf("\nOOOPPSS! You have USE_BIG_ENDIAN toggle misconfigured!\n\n");
91 printf("Please, edit lcms.h and %s the USE_BIG_ENDIAN toggle.\n", BigEndian? "uncomment" : "comment");
92 return 0;
93 }
94
95 return 1;
96
97 }
98
99
100 static
CheckSwab(void)101 int CheckSwab(void)
102 {
103 unsigned char Test[] = { 1, 2, 3, 4, 5, 6};
104
105 #ifdef USE_CUSTOM_SWAB
106 return 1;
107 #endif
108
109 #ifdef USE_BIG_ENDIAN
110 return 1;
111 #endif
112
113 swab((char*) Test, (char*) Test, 6);
114
115 if (strncmp((char*) Test, "\x2\x1\x4\x3\x6\x5", 6) != 0)
116 {
117 printf("\nOOOPPSS! swab() does not work as expected in your machine!\n\n");
118 printf("Please, edit lcms.h and uncomment the USE_CUSTOM_SWAB toggle.\n");
119 return 0;
120
121 }
122 return 1;
123 }
124
125
126 static
CheckQuickFloor(void)127 int CheckQuickFloor(void)
128 {
129
130 if ((_cmsQuickFloor(1.234) != 1) ||
131 (_cmsQuickFloor(32767.234) != 32767) ||
132 (_cmsQuickFloor(-1.234) != -2) ||
133 (_cmsQuickFloor(-32767.1) != -32768)) {
134
135 printf("\nOOOPPSS! _cmsFloor() does not work as expected in your machine!\n\n");
136 printf("Please, edit lcms.h and uncomment the LCMS_DEFAULT_FLOOR_CONVERSION toggle.\n");
137 return 0;
138
139 }
140
141 return 1;
142 }
143
144 typedef struct _Stats {
145 double n, x, y, x2, y2, xy;
146 double Peak;
147 } STATS, FAR* LPSTATS;
148
ClearStats(LPSTATS p)149 static void ClearStats(LPSTATS p)
150 {
151 p -> n = p -> x = p -> y = p -> x2 = p -> y2 = p -> xy
152 = p -> Peak = 0.0;
153 }
154
Std(LPSTATS p)155 static double Std(LPSTATS p)
156 {
157 return sqrt((p->n*p->x2 - p->x * p->x) / (p->n*(p->n-1)));
158 }
159
160
161
162 static
PrintStatistics(clock_t atime,LPSTATS Stats)163 void PrintStatistics(clock_t atime, LPSTATS Stats)
164 {
165
166 clock_t diff;
167 double a;
168
169 diff = clock() - atime;
170 a = (double) diff / CLOCKS_PER_SEC;
171
172 // These are statistics of 16 bit, so divide
173 // by 257 to get dE relative to 8 bits
174
175 printf("\n");
176
177 if (Stats)
178 printf("dE: mean=%g, SD=%g, max=%g ",
179 (Stats->x / Stats -> n) / 257.,
180 (Std(Stats)) / 257.,
181 Stats -> Peak / 257.);
182
183
184 if (atime > 0)
185 printf("[%d tics, %g sec.]", (int) diff, a);
186
187 }
188
189
190 // Simpler fixed-point math
191
192 static
TestFixedPoint(void)193 void TestFixedPoint(void)
194 {
195 Fixed32 a, b, c, d;
196 double f;
197
198 a = DOUBLE_TO_FIXED(1.1234);
199 b = DOUBLE_TO_FIXED(2.5678);
200
201 c = FixedMul(a, b);
202
203 d = FIXED_REST_TO_INT(c);
204 f = ((double) d / 0xffff) * 1000000.0;
205
206 printf("Testing fixed point:\t%f = %d.%d\n", (1.1234 * 2.5678), FIXED_TO_INT(c), (int) f);
207
208 }
209
210
211
212 static
TestFixedScaling(void)213 int TestFixedScaling(void)
214 {
215 int i, j, nfl, nfx;
216 double FloatFactor;
217 Fixed32 FixedFactor;
218
219
220
221 printf("Testing fixed scaling...");
222
223 for (j=5; j<100; j++)
224 {
225 FloatFactor = (double) j / 100.0 ;
226 FloatFactor = FIXED_TO_DOUBLE(DOUBLE_TO_FIXED(FloatFactor));
227 FixedFactor = DOUBLE_TO_FIXED(FloatFactor);
228
229 for (i=0; i < 0x10000L; i++)
230 {
231 nfl = (WORD) ((double) i * FloatFactor);
232 nfx = FixedScale((WORD) i, FixedFactor);
233
234 if (nfl != nfx) {
235 printf("Failed!\ni=%x (%d), float=%x, fixed=%x", i, i, nfl, nfx);
236 return 0;
237 }
238 }
239
240 }
241
242 printf ("pass.\n");
243 return 1;
244 }
245
246 // Curve joining test. Joining two high-gamma of 3.0 curves should
247 // give something like linear
248
249 static
TestJointCurves(void)250 int TestJointCurves(void)
251 {
252 LPGAMMATABLE Forward, Reverse, Result;
253 LCMSBOOL rc;
254
255 printf("Testing curves join ...");
256
257 Forward = cmsBuildGamma(256, 3.0);
258 Reverse = cmsBuildGamma(256, 3.0);
259
260 Result = cmsJoinGammaEx(Forward, Reverse, 256);
261
262 cmsFreeGamma(Forward); cmsFreeGamma(Reverse);
263
264 rc = cmsIsLinear(Result->GammaTable, Result ->nEntries);
265 cmsFreeGamma(Result);
266
267 if (!rc) {
268 printf("failed!\n");
269 return 0;
270 }
271 else {
272 printf("pass.\n");
273 return 1;
274 }
275
276 }
277
278
279
280 // Check reversing of gamma curves
281
282 #define NPOINTS 1024
283
284 static
TestReversingOfCurves(void)285 int TestReversingOfCurves(void)
286 {
287 LPGAMMATABLE Gamma, Reverse, Computed;
288 int i;
289 double dE;
290 STATS Stats;
291
292 printf("Testing reversing of curves ...");
293 ClearStats(&Stats);
294
295
296 Gamma = cmsBuildGamma(NPOINTS, 3.0);
297 Reverse = cmsBuildGamma(NPOINTS, 1.0/3.0);
298
299 Computed = cmsReverseGamma(NPOINTS, Gamma);
300
301 for (i=0; i < NPOINTS; i++) {
302
303 dE = fabs(Reverse->GammaTable[i] - Computed->GammaTable[i]);
304
305 Stats.x += dE;
306 Stats.x2 += (dE * dE);
307 Stats.n += 1.0;
308 if (dE > Stats.Peak) {
309 Stats.Peak = dE;
310 }
311
312 if (dE > 0x0010) {
313 printf("Coarse error! %x on entry %d: %X/%X", (int) dE, i, Reverse->GammaTable[i],
314 Computed->GammaTable[i]);
315 return 0;
316 }
317
318 }
319
320 if (Stats.Peak > 0) PrintStatistics(0, &Stats);
321 printf(" pass.\n");
322 cmsFreeGamma(Gamma);
323 cmsFreeGamma(Reverse);
324 cmsFreeGamma(Computed);
325 return 1;
326 }
327
328 // Linear interpolation test. Here I check the cmsLinearInterpLUT16
329 // Tables are supposed to be monotonic, but the algorithm works on
330 // non-monotonic as well.
331
332 static
TestLinearInterpolation(int lExhaustive)333 int TestLinearInterpolation(int lExhaustive)
334 {
335 static WORD Tab[4098];
336 int j, i, k = 0;
337 L16PARAMS p;
338 int n;
339 clock_t time;
340
341 printf("Testing linear interpolation ...");
342
343 // First I will check exact values. Since prime factors of 65535 (FFFF) are,
344 //
345 // 0xFFFF = 1 * 3 * 5 * 17 * 257
346 //
347 // I test tables of 2, 4, 6, and 18 points, that will be exact.
348 // Then, a table of 3 elements are tested. Error must be < 1
349 // Since no floating point is involved, This will be a measure of speed.
350
351
352 // Perform 10 times, so i can measure average times
353
354 time = clock();
355 for (j=0; j < 10; j++)
356 {
357
358 // 2 points - exact
359
360 Tab[0] = 0;
361 Tab[1] = 0xffffU;
362
363 cmsCalcL16Params(2, &p);
364
365 for (i=0; i <= 0xffffL; i++)
366 {
367 n = cmsLinearInterpLUT16((WORD) i, Tab, &p);
368 if (n != i)
369 {
370 printf("Error in Linear interpolation (2p): Must be i=%x, But is n=%x\n", i, n);
371 return 0;
372 }
373
374 }
375
376
377 // 3 points - Here the error must be <= 1, since
378 // 2 == (3 - 1) is not a factor of 0xffff
379
380 Tab[0] = 0;
381 Tab[1] = 0x7FFF;
382 Tab[2] = 0xffffU;
383
384 cmsCalcL16Params(3, &p);
385
386 for (i=0; i <= 0xffffL; i++)
387 {
388 n = cmsLinearInterpLUT16((WORD) i, Tab, &p);
389 if (abs(n - i) > 1)
390 {
391 printf("Error in Linear interpolation (3p): Must be i=%x, But is n=%x\n", i, n);
392 return 0;
393 }
394
395 }
396
397
398 // 4 points - exact
399
400 Tab[0] = 0;
401 Tab[1] = 0x5555U;
402 Tab[2] = 0xAAAAU;
403 Tab[3] = 0xffffU;
404
405 cmsCalcL16Params(4, &p);
406
407 for (i=0; i <= 0xffffL; i++)
408 {
409 n = cmsLinearInterpLUT16((WORD) i, Tab, &p);
410 if (n != i) {
411 printf("Error in Linear interpolation (4p): Must be i=%x, But is n=%x\n", i, n);
412 return 0;
413 }
414
415 }
416
417
418 // 6 - points
419
420 Tab[0] = 0;
421 Tab[1] = 0x3333U;
422 Tab[2] = 0x6666U;
423 Tab[3] = 0x9999U;
424 Tab[4] = 0xCCCCU;
425 Tab[5] = 0xFFFFU;
426
427 cmsCalcL16Params(6, &p);
428
429 for (i=0; i <= 0xffffL; i++)
430 {
431 n = cmsLinearInterpLUT16((WORD) i, Tab, &p);
432 if (n != i) {
433 printf("Error in Linear interpolation (6p): Must be i=%x, But is n=%x\n", i, n);
434 return 0;
435 }
436
437 }
438
439
440 // 18 points
441
442 for (i=0; i < 18; i++)
443 Tab[i] = (WORD) (0x0f0fU*i);
444
445 cmsCalcL16Params(18, &p);
446
447 for (i=0; i <= 0xffffL; i++)
448 {
449 n = cmsLinearInterpLUT16((WORD) i, Tab, &p);
450 if (n != i) {
451 printf("Error in Linear interpolation (18p): Must be i=%x, But is n=%x\n", i, n);
452 return 0;
453 }
454 }
455 }
456
457
458
459 printf("pass. (%d tics)\n", (int) (clock() - time));
460
461 // Now test descending tables
462 printf("Testing descending tables (linear interpolation)...");
463
464 // 2 points - exact
465
466 Tab[1] = 0;
467 Tab[0] = 0xffffU;
468
469 cmsCalcL16Params(2, &p);
470
471 for (i=0xffffL; i > 0; --i)
472 {
473 n = cmsLinearInterpLUT16((WORD) i, Tab, &p);
474 if ((0xffffL - n) != i) {
475
476 printf("Error in Linear interpolation (descending) (2p): Must be i=%x, But is n=%x\n", i, 0xffff - n);
477 return 0;
478 }
479 }
480
481
482 // 3 points - Here the error must be <= 1, since
483 // 2 = (3 - 1) is not a factor of 0xffff
484
485 Tab[2] = 0;
486 Tab[1] = 0x7FFF;
487 Tab[0] = 0xffffU;
488
489 cmsCalcL16Params(3, &p);
490
491 for (i=0xffffL; i > 0; --i)
492 {
493 n = cmsLinearInterpLUT16((WORD) i, Tab, &p);
494 if (abs((0xffffL - n) - i) > 1) {
495
496 printf("Error in Linear interpolation (descending) (3p): Must be i=%x, But is n=%x\n", i, n);
497 return 0;
498 }
499 }
500
501
502 // 4 points - exact
503
504 Tab[3] = 0;
505 Tab[2] = 0x5555U;
506 Tab[1] = 0xAAAAU;
507 Tab[0] = 0xffffU;
508
509 cmsCalcL16Params(4, &p);
510
511 for (i=0xffffL; i > 0; --i)
512 {
513 n = cmsLinearInterpLUT16((WORD) i, Tab, &p);
514 if ((0xffffL - n) != i) {
515
516 printf("Error in Linear interpolation (descending) (4p): Must be i=%x, But is n=%x\n", i, n);
517 return 0;
518 }
519 }
520
521
522 // 6 - points
523
524 Tab[5] = 0;
525 Tab[4] = 0x3333U;
526 Tab[3] = 0x6666U;
527 Tab[2] = 0x9999U;
528 Tab[1] = 0xCCCCU;
529 Tab[0] = 0xFFFFU;
530
531 cmsCalcL16Params(6, &p);
532
533 for (i=0xffffL; i > 0; --i)
534 {
535 n = cmsLinearInterpLUT16((WORD) i, Tab, &p);
536 if ((0xffffL - n) != i) {
537 printf("Error in Linear interpolation (descending) (6p): Must be i=%x, But is n=%x\n", i, n);
538 return 0;
539 }
540
541 }
542
543
544 // 18 points
545
546 for (i=0; i < 18; i++)
547 Tab[17-i] = (WORD) (0x0f0fU*i);
548
549 cmsCalcL16Params(18, &p);
550
551 for (i=0xffffL; i > 0; --i)
552 {
553 n = cmsLinearInterpLUT16((WORD) i, Tab, &p);
554 if ((0xffffL - n) != i) {
555
556 printf("Error in Linear interpolation (descending) (18p): Must be i=%x, But is n=%x\n", i, n);
557 return 0;
558 }
559 }
560
561 printf("pass.\n");
562
563 if (!lExhaustive) return 1;
564
565 printf("Now, testing interpolation errors for tables of n elements ...\n");
566
567 for (j=10; j < 4096; j ++)
568 {
569 if ((j % 10) == 0) printf("%d\r", j);
570
571 for (i=0; i <= j; i++)
572 {
573 Tab[i] = (WORD) floor((((double) i / ((double) j-1)) * 65535.0) + .5);
574 }
575
576 k =0;
577 cmsCalcL16Params(j, &p);
578 for (i=0; i <= 0xffffL; i++)
579 {
580 n = cmsLinearInterpLUT16((WORD) i, Tab, &p);
581 if (n != i) k++;
582
583 }
584
585 }
586 printf("\n%d: %d errors\n\n", j, k);
587 return 1;
588 }
589
590
591
592 static
IsGood(const char * frm,WORD in,WORD out)593 int IsGood(const char *frm, WORD in, WORD out)
594 {
595
596 // 1 for rounding
597 if ((abs(in - out) > 1)) {
598
599 printf("error %s %x - %x\n", frm, in, out);
600 return 0;
601 }
602
603 return 1;
604 }
605
606 static
TestReverseLinearInterpolation(void)607 LCMSBOOL TestReverseLinearInterpolation(void)
608 {
609 WORD Tab[20];
610 L16PARAMS p;
611 int i, n, v;
612
613 printf("Testing reverse linear interpolation\n");
614
615
616 cmsCalcL16Params(16, &p);
617
618 for (i=0; i < 16; i++) Tab[i] = (WORD) i * 0x1111;
619
620 printf("\ton normal monotonic curve...");
621 for (i=0; i < 16; i++)
622 {
623 v = (i * 0x1111);
624 n = cmsReverseLinearInterpLUT16((WORD) v, Tab, &p);
625 if (!IsGood("unexpected result", (WORD) v, (WORD) n))
626 return FALSE;
627 }
628 printf("pass.\n");
629
630
631 Tab[0] = 0;
632 Tab[1] = 0;
633 Tab[2] = 0;
634 Tab[3] = 0;
635 Tab[4] = 0;
636 Tab[5] = 0x5555;
637 Tab[6] = 0x6666;
638 Tab[7] = 0x7777;
639 Tab[8] = 0x8888;
640 Tab[9] = 0x9999;
641 Tab[10]= 0xffff;
642 Tab[11]= 0xffff;
643 Tab[12]= 0xffff;
644 Tab[13]= 0xffff;
645 Tab[14]= 0xffff;
646 Tab[15]= 0xffff;
647
648
649 printf("\ton degenerated curve ...");
650
651 for (i=0; i < 16; i++)
652 {
653 v = (i * 0x1111);
654 n = cmsReverseLinearInterpLUT16((WORD) v, Tab, &p);
655
656 if (i > 5 && i <= 9) {
657
658 if (!IsGood("unexpected result", (WORD) v, (WORD) n))
659 return FALSE;
660 }
661 }
662
663 printf("pass.\n");
664
665 return TRUE;
666 }
667
668
669
670
671 // 3D LUT test
672
673 static
Test3D(void)674 int Test3D(void)
675 {
676 LPLUT MyLut;
677 LPWORD Table;
678 WORD In[3], Out[3];
679 int r, g, b, i;
680 double *SampleTablePtr, SampleTable[] = { //R G B
681
682 0, 0, 0, // B=0,G=0,R=0
683 0, 0, .25, // B=1,G=0,R=0
684
685 0, .5, 0, // B=0,G=1,R=0
686 0, .5, .25, // B=1,G=1,R=0
687
688 1, 0, 0, // B=0,G=0,R=1
689 1, 0, .25, // B=1,G=0,R=1
690
691 1, .5, 0, // B=0,G=1,R=1
692 1, .5, .25 // B=1,G=1,R=1
693
694 };
695
696
697 printf("Testing 3D interpolation on LUT...");
698
699 // 1.- Allocate an empty LUT
700
701 MyLut = cmsAllocLUT();
702
703 // 2.- In this LUT, allocate a 3D grid of 2 points, from 3 components (RGB)
704 // to 3 components. First 3 is input dimension, last 3 is output one.
705 // 2 is number of grid points.
706
707 MyLut = cmsAlloc3DGrid(MyLut, 2, 3, 3);
708
709 // 3.- Fill the LUT table with values.
710
711 Table = MyLut -> T;
712
713 SampleTablePtr = SampleTable;
714
715 for (i= 0; i < 3; i++)
716 for (r = 0; r < 2; r++)
717 for (g = 0; g < 2; g++)
718 for (b = 0; b < 2; b++) {
719
720 WORD a = (WORD) floor(*SampleTablePtr++ * 65535. + .5);
721
722 *Table++ = a;
723 }
724
725
726 // The sample table gives
727 //
728 // r = input,
729 // g = input divided by 2
730 // b = input divided by 4
731 //
732 // So, I should obtain on output r, g/2, g/4
733
734
735 for (i=0; i < 0xffff; i++) {
736
737 In[0] = In[1] = In[2] = (WORD) i;
738
739 cmsEvalLUT(MyLut, In, Out);
740
741
742
743 // Check results, I will tolerate error <= 1 for rounding
744
745
746
747 if (!IsGood("Channel 1", Out[0], In[0])) return 0;
748 if (!IsGood("Channel 2", Out[1], (WORD) ((double) In[1] / 2))) return 0;
749 if (!IsGood("Channel 3", Out[2], (WORD) ((double) In[2] / 4))) return 0;
750
751 }
752
753
754
755 // Last, remember free stuff
756
757 cmsFreeLUT(MyLut);
758
759 printf("pass.\n");
760 return 1;
761 }
762
763
764
765 static
PrintMatrix(LPMAT3 lpM)766 void PrintMatrix(LPMAT3 lpM)
767 {
768 int i, j;
769
770 for (i=0; i < 3; i++) {
771 printf ("[ ");
772 for (j=0; j < 3; j++)
773 {
774 printf("%1.6f ", (*lpM).v[i].n[j]);
775 }
776 printf("]\n");
777 }
778
779 printf("\n");
780
781 }
782
783
784 static
CmpMatrix(LPMAT3 lpM1,LPMAT3 lpM2,double tolerance)785 LCMSBOOL CmpMatrix(LPMAT3 lpM1, LPMAT3 lpM2, double tolerance)
786 {
787 int i, j;
788
789 for (i=0; i < 3; i++) {
790 for (j=0; j < 3; j++) {
791 if (fabs(lpM1 -> v[i].n[j] - lpM2 -> v[i].n[j]) > tolerance)
792 return FALSE;
793 }
794
795 }
796
797 return TRUE;
798
799 }
800
801
802 static
TestMatrixCreation(void)803 LCMSBOOL TestMatrixCreation(void)
804 {
805 MAT3 Mat;
806 int rc;
807
808 cmsCIExyY WhitePt = {0.3127, 0.3290, 1.0};
809 cmsCIExyYTRIPLE Primaries = {
810 {0.6400, 0.3300, 1.0},
811 {0.3000, 0.6000, 1.0},
812 {0.1500, 0.0600, 1.0}
813 };
814 MAT3 sRGB = {{
815 {{ 0.436066, 0.385147, 0.143066 }},
816 {{ 0.222488, 0.716873, 0.060608 }},
817 {{ 0.013916, 0.097076, 0.714096 }}
818 }};
819
820
821 printf("Testing virtual profiles (Emulating sRGB)...");
822
823 rc = cmsBuildRGB2XYZtransferMatrix(&Mat,
824 &WhitePt,
825 &Primaries);
826 cmsAdaptMatrixToD50(&Mat, &WhitePt);
827
828 if (rc < 0)
829 {
830 printf("TestMatrixCreation failed, rc = %d\n", rc);
831 return FALSE;
832 }
833
834
835 if (!CmpMatrix(&Mat, &sRGB, 0.001)) {
836 printf("FAILED!\n");
837 printf("sRGB final matrix is:\n");
838 PrintMatrix(&sRGB);
839 printf("\nlcms calculated matrix is:\n");
840 PrintMatrix(&Mat);
841 return FALSE;
842 }
843
844 printf("pass.\n");
845 return TRUE;
846
847
848 }
849
850
851 /*
852
853 Used for debug purposes
854 */
855
856 #if 0
857 static
858 void AdaptationMatrixTest(void)
859 {
860 cmsCIExyY D65 = {0.3127, 0.329001, 1.0}; // D65
861 MAT3 sRGB, TosRGB;
862
863
864 VEC3init(&sRGB.v[0], 0.4124, 0.3576, 0.1805);
865 VEC3init(&sRGB.v[1], 0.2126, 0.7152, 0.0722);
866 VEC3init(&sRGB.v[2], 0.0193, 0.1192, 0.9505);
867
868 cmsAdaptMatrixToD50(&sRGB, &D65);
869 printf("Adaptation matrix D65 -> D50 (to PCS)\n");
870 PrintMatrix(&sRGB);
871
872 MAT3inverse(&sRGB, &TosRGB);
873 printf("inverse\n");
874 PrintMatrix(&TosRGB);
875
876 cmsAdaptMatrixFromD50(&TosRGB, &D65);
877 printf("adaptated to D65\n");
878 PrintMatrix(&TosRGB);
879 }
880 #endif
881 // #endif
882
883
884
885 static
VecDist(Scanline_rgb2 * bin,Scanline_rgb2 * bout)886 double VecDist(Scanline_rgb2 *bin, Scanline_rgb2 *bout)
887 {
888 double rdist, gdist, bdist;
889
890 rdist = fabs(bout -> r - bin -> r);
891 gdist = fabs(bout -> g - bin -> g);
892 bdist = fabs(bout -> b - bin -> b);
893
894 return (sqrt((rdist*rdist + gdist*gdist + bdist*bdist)));
895 }
896
897
898
899
900
901
902 // Perform sampling in the full spectrum & acotate error.
903 // I choose red for the lowest incidence in eye.
904 // Green is most lightful, eye is most accurate on blue.
905
906 static
TestFullSpectrum(cmsHTRANSFORM xform,int nRedInterv,int MaxErr)907 int TestFullSpectrum(cmsHTRANSFORM xform, int nRedInterv, int MaxErr)
908 {
909 int r, g, b;
910 double err;
911 Scanline_rgb2 *bin, *bout;
912 STATS Stats;
913 clock_t t;
914
915
916 bin = (Scanline_rgb2 *) _cmsMalloc(256*sizeof(Scanline_rgb2));
917 bout = (Scanline_rgb2 *) _cmsMalloc(256*sizeof(Scanline_rgb2));
918
919
920 ClearStats(&Stats);
921
922 Stats.x = 0.0; Stats.n = 0.0; // GCC BUG HERE!!!!
923
924 t = clock();
925
926 for (r=0; r < 256; r+= nRedInterv)
927 {
928 // printf("\r%02x:", r);
929
930 Dot();
931 for (g=0; g < 256; g++)
932 {
933
934 for (b=0; b < 256; b++)
935 {
936 bin[b].r = (WORD) r << 8; // For L 0nly to 0xFF00
937 bin[b].g = RGB_8_TO_16(g);
938 bin[b].b = RGB_8_TO_16(b);
939 bin[b].a = 0;
940 }
941
942 cmsDoTransform(xform, bin, bout, 256);
943
944 // I'm using b as index
945
946 for (b=0; b < 256; b ++)
947 {
948 // I measure the error using vector distance
949
950 err = VecDist(bin+b, bout+b);
951 Stats.x += (double) err;
952 Stats.x2 += (double) err * err;
953 Stats.n += 1.0;
954 if (err > Stats.Peak)
955 Stats.Peak = err;
956
957
958 if (err > MaxErr)
959 {
960 printf("Coarse error! : In=(%x,%x,%x) Out=(%x,%x,%x)\n",
961 bin[b].r, bin[b].g, bin[b].b,
962 bout[b].r, bout[b].g, bout[b].b);
963 _cmsFree(bin);
964 _cmsFree(bout);
965 return 0;
966 }
967 }
968
969 }
970
971 }
972
973
974 PrintStatistics(t, &Stats);
975 _cmsFree(bin);
976 _cmsFree(bout);
977
978 return 1;
979 }
980
981
982
983
984 static
TestInducedError(DWORD Type)985 int TestInducedError(DWORD Type)
986 {
987 cmsHPROFILE In, Out;
988 cmsHTRANSFORM xform;
989 int nMaxError;
990
991 In = cmsCreateLabProfile(NULL);
992 Out = cmsCreateLabProfile(NULL);
993
994 printf("Error Induced by the CMM due to roundoff (dE) ");
995
996 xform = cmsCreateTransform(In, Type,
997 Out, Type,
998 INTENT_RELATIVE_COLORIMETRIC, 0);
999
1000
1001 nMaxError = TestFullSpectrum(xform, 31, 0x800);
1002
1003 printf("\n");
1004
1005 cmsDeleteTransform(xform);
1006 cmsCloseProfile(In);
1007 cmsCloseProfile(Out);
1008
1009 return nMaxError;
1010 }
1011
1012
1013 static
ConvertL(WORD v)1014 double ConvertL(WORD v)
1015 {
1016 int fix32;
1017
1018 fix32 = v;
1019 return (double)fix32/652.800; /* 0xff00/100.0 */
1020 }
1021
1022
1023 static
Convertab(WORD v)1024 double Convertab(WORD v)
1025 {
1026 int fix32;
1027
1028
1029 fix32 = v;
1030
1031 return ((double)fix32/256.0)-128.0;
1032 }
1033
1034
1035 #define BASE 255
1036
1037 static
CompareTransforms(cmsHTRANSFORM xform1,cmsHTRANSFORM xform2,int nRedInterv,int lWithStats,LCMSBOOL lIsLab)1038 int CompareTransforms(cmsHTRANSFORM xform1, cmsHTRANSFORM xform2,
1039 int nRedInterv, int lWithStats, LCMSBOOL lIsLab)
1040 {
1041 int r, g, b;
1042 double err;
1043 Scanline_rgb2 *bin, *bout1, *bout2;
1044 STATS Stats;
1045 int OutOfGamut = 0;
1046
1047
1048 bin = (Scanline_rgb2 *) _cmsMalloc(256*sizeof(Scanline_rgb2));
1049 bout1 = (Scanline_rgb2 *) _cmsMalloc(256*sizeof(Scanline_rgb2));
1050 bout2 = (Scanline_rgb2 *) _cmsMalloc(256*sizeof(Scanline_rgb2));
1051
1052
1053 ClearStats(&Stats);
1054 Stats.x = 0.0; Stats.n = 0.0; // GCC BUG HERE!!!!
1055
1056
1057 for (r=0; r <= BASE; r+= nRedInterv)
1058 {
1059 // printf("\r%02x:", r);
1060
1061 Dot();
1062 for (g=0; g <= BASE; g++)
1063 {
1064 // I will test random LSB
1065
1066 for (b=0; b <= BASE; b++) // 256
1067 {
1068
1069 bin[b].r = RGB_8_TO_16(r);
1070 bin[b].g = RGB_8_TO_16(g);
1071 bin[b].b = RGB_8_TO_16(b);
1072 bin[b].a = 0;
1073 }
1074
1075 cmsDoTransform(xform1, bin, bout1, 256);
1076 cmsDoTransform(xform2, bin, bout2, 256);
1077
1078 // I'm using b as index
1079
1080 for (b=0; b <= BASE; b ++) {
1081
1082 // I measure the error using vector distance
1083 // Only if encodable values
1084
1085 if (bout1[b].r != 0xffff && bout1[b].g != 0xffff && bout1[b].b != 0xffff)
1086 {
1087
1088 err = VecDist(bout1+b, bout2+b);
1089
1090
1091 if (err > 0x1000L)
1092 {
1093
1094 if (lIsLab) {
1095 printf("Coarse error: In=(%x,%x,%x) Out1=(%g,%g,%g) Out2=(%g,%g,%g)\n",
1096 bin[b].r, bin[b].g, bin[b].b,
1097 ConvertL(bout1[b].r), Convertab(bout1[b].g), Convertab(bout1[b].b),
1098 ConvertL(bout2[b].r), Convertab(bout2[b].g), Convertab(bout2[b].b));
1099 }
1100 else
1101 {
1102 printf("Coarse error: In=(%x,%x,%x) Out1=(%x,%x,%x) Out2=(%x,%x,%x)\n",
1103 bin[b].r, bin[b].g, bin[b].b,
1104 bout1[b].r, bout1[b].g, bout1[b].b,
1105 bout2[b].r, bout2[b].g, bout2[b].b);
1106 }
1107 return 0;
1108
1109 }
1110
1111 else
1112 {
1113 Stats.x += (double) err;
1114 Stats.x2 += (double) err * err;
1115 Stats.n += 1.0;
1116 if (err > Stats.Peak)
1117 Stats.Peak = err;
1118 }
1119 } else
1120 OutOfGamut++;
1121 }
1122
1123 }
1124
1125 }
1126
1127
1128 if (lWithStats) {
1129
1130 PrintStatistics(0, &Stats);
1131 printf(" pass.\n");
1132 }
1133
1134 if (OutOfGamut > 0)
1135 printf("Out of encodeable representation=%d\n\n", OutOfGamut);
1136
1137
1138 _cmsFree(bin);
1139 _cmsFree(bout1);
1140 _cmsFree(bout2);
1141
1142 return 1;
1143 }
1144
1145
1146
1147 static
CheckXYZ(LPcmsCIEXYZ Check,double X,double Y,double Z)1148 LCMSBOOL CheckXYZ(LPcmsCIEXYZ Check, double X, double Y, double Z)
1149 {
1150 return ((fabs(Check->X - X) < 0.001) &&
1151 (fabs(Check->Y - Y) < 0.001) &&
1152 (fabs(Check->Z - Z) < 0.001));
1153 }
1154
1155
1156 static
Build_sRGBGamma(void)1157 LPGAMMATABLE Build_sRGBGamma(void)
1158 {
1159 double Parameters[5];
1160
1161 Parameters[0] = 2.4;
1162 Parameters[1] = 1. / 1.055;
1163 Parameters[2] = 0.055 / 1.055;
1164 Parameters[3] = 1. / 12.92;
1165 Parameters[4] = 0.04045; // d
1166
1167 return cmsBuildParametricGamma(1024, 4, Parameters);
1168 }
1169
1170 static
Check_sRGBGamma(LPGAMMATABLE Shape)1171 LCMSBOOL Check_sRGBGamma(LPGAMMATABLE Shape)
1172 {
1173 LPGAMMATABLE sRGB = Build_sRGBGamma();
1174 int i;
1175
1176 if (Shape ->nEntries != 1024) {
1177 printf("because wrong sizes (%d != 1024), ", Shape -> nEntries);
1178 return 0;
1179 }
1180
1181
1182 for (i=0; i < Shape -> nEntries; i++) {
1183 double nErr = Shape ->GammaTable[i] - sRGB ->GammaTable[i];
1184
1185 if (fabs(nErr) > 1.0) {
1186 int j;
1187 printf("because %x != %x on index %d\n", Shape ->GammaTable[i], sRGB ->GammaTable[i], i);
1188 printf("table dump follows:\n");
1189 for (j=0; j < 10; j++)
1190 printf("%d) %X\n", j, Shape ->GammaTable[j]);
1191 printf("\nso, ");
1192
1193 return 0;
1194 }
1195 }
1196
1197 cmsFreeGamma(sRGB);
1198 return 1;
1199 }
1200
1201
1202 static
GetInfoTest(void)1203 int GetInfoTest(void)
1204 {
1205 cmsHPROFILE hProfile;
1206 cmsCIEXYZ WhitePoint;
1207 cmsCIEXYZTRIPLE Primaries;
1208 const char* Product;
1209 LPGAMMATABLE Shapes[3];
1210
1211
1212 printf("Testing profile decoding (sRGB)");
1213 hProfile = cmsOpenProfileFromFile("sRGB Color Space Profile.icm", "rb");
1214 cmsTakeMediaWhitePoint(&WhitePoint, hProfile);
1215
1216 Dot();
1217 if (!CheckXYZ(&WhitePoint, 0.95045, 1.0, 1.08905)) {
1218 printf("White point read failed!\n");
1219 return 0;
1220 }
1221
1222 Dot();
1223 cmsTakeColorants(&Primaries, hProfile);
1224
1225 if (!CheckXYZ(&Primaries.Red, 0.43607, 0.22249, 0.01392)) {
1226 printf("Red colorant failed!\n");
1227 return 0;
1228 }
1229
1230 if (!CheckXYZ(&Primaries.Green, 0.38515,0.71617, 0.09708)) {
1231 printf("Green colorant failed!\n");
1232 return 0;
1233 }
1234
1235 if (!CheckXYZ(&Primaries.Blue, 0.14307, 0.06061, 0.71410)) {
1236 printf("Blue colorant failed!\n");
1237 return 0;
1238 }
1239
1240 Dot();
1241 Product = cmsTakeProductName(hProfile);
1242 if (strcmp(Product, "IEC 61966-2.1 Default RGB colour space - sRGB") != 0) {
1243 printf("Product name mismatch!\n");
1244 }
1245
1246 Dot();
1247 Shapes[0] = cmsReadICCGamma(hProfile, icSigRedTRCTag);
1248 Shapes[1] = cmsReadICCGamma(hProfile, icSigGreenTRCTag);
1249 Shapes[2] = cmsReadICCGamma(hProfile, icSigBlueTRCTag);
1250
1251 if (!Check_sRGBGamma(Shapes[0]) ||
1252 !Check_sRGBGamma(Shapes[1]) ||
1253 !Check_sRGBGamma(Shapes[2])) {
1254 printf("Gamma curves mismatch!\n");
1255 return 0;
1256 }
1257
1258
1259 cmsFreeGammaTriple(Shapes);
1260
1261
1262 Dot();
1263 cmsCloseProfile(hProfile);
1264 printf("pass.\n");
1265 return 1;
1266
1267 }
1268 static
Test_sRGB(void)1269 int Test_sRGB(void)
1270 {
1271 cmsHPROFILE In1, In2, Out1, Out2;
1272 cmsHTRANSFORM xform1, xform2;
1273 int nMaxErr;
1274
1275 printf("Testing sRGB built-in space");
1276
1277 In1 = cmsOpenProfileFromFile("sRGB Color Space Profile.icm", "rb");
1278 Out1 = cmsCreateXYZProfile();
1279
1280 In2 = cmsCreate_sRGBProfile();
1281 Out2 = cmsCreateXYZProfile();
1282
1283 xform1 = cmsCreateTransform(In1, TYPE_RGBA_16, Out1, TYPE_XYZA_16, 0, cmsFLAGS_NOTPRECALC);
1284 xform2 = cmsCreateTransform(In2, TYPE_RGBA_16, Out2, TYPE_XYZA_16, 0, cmsFLAGS_NOTPRECALC);
1285
1286 nMaxErr = CompareTransforms(xform1, xform2, 31, TRUE, FALSE);
1287
1288 cmsDeleteTransform(xform1);
1289 cmsCloseProfile(In1);
1290 cmsCloseProfile(Out1);
1291
1292 cmsDeleteTransform(xform2);
1293 cmsCloseProfile(In2);
1294 cmsCloseProfile(Out2);
1295
1296 return nMaxErr;
1297
1298 }
1299
1300 static
RealProfilesTest(void)1301 int RealProfilesTest(void)
1302 {
1303 cmsHPROFILE In1, In2, Out1, Out2;
1304 cmsHTRANSFORM xform1, xform2;
1305 int nMaxErr;
1306
1307 printf("Using two real profiles");
1308
1309 // sRGB is a simpler, public domain XYZ PCS profile
1310 // sRGBSpac comes with Win95 Platform SDK, in the public domain.
1311 // (not latest revisions)
1312
1313 // Using LAB identity as output profile, I'm forcing an
1314 // implicit XYZ => L*a*b conversion in xform1.
1315 // xform2 is 8 bits - LUT based, and PCS is L*a*b
1316
1317 In1 = cmsOpenProfileFromFile("sRGB Color Space Profile.icm", "rb");
1318 Out1 = cmsCreateXYZProfile();
1319
1320 In2 = cmsOpenProfileFromFile("sRGBSpac.icm", "rb");
1321 Out2 = cmsCreateXYZProfile();
1322
1323
1324 // Since LUT is 8-bits width,
1325 xform1 = cmsCreateTransform(In1, TYPE_RGBA_16, Out1, TYPE_XYZA_16, 0, cmsFLAGS_NOTPRECALC|cmsFLAGS_MATRIXINPUT);
1326 xform2 = cmsCreateTransform(In2, TYPE_RGBA_16, Out2, TYPE_XYZA_16, 0, cmsFLAGS_NOTPRECALC);
1327
1328 nMaxErr = CompareTransforms(xform1, xform2, 31, FALSE, FALSE);
1329
1330 printf("pass\n");
1331
1332 cmsDeleteTransform(xform1);
1333 cmsCloseProfile(In1);
1334 cmsCloseProfile(Out1);
1335
1336 cmsDeleteTransform(xform2);
1337 cmsCloseProfile(In2);
1338 cmsCloseProfile(Out2);
1339
1340 return nMaxErr;
1341 }
1342
1343
1344
1345 // ---------------------------------------------------------
1346
1347
1348 static
TestPreview(void)1349 int TestPreview(void)
1350 {
1351 cmsHPROFILE In, Out, Proof;
1352 cmsHTRANSFORM xform;
1353 int nMaxErr;
1354
1355 printf("Testing preview");
1356
1357 In = cmsCreateLabProfile(NULL);
1358 Out = cmsCreateLabProfile(NULL);
1359 Proof = cmsCreateLabProfile(NULL);
1360
1361 xform = cmsCreateProofingTransform(In, TYPE_LABA_16, Out, TYPE_LABA_16, Proof, 0, 0, cmsFLAGS_SOFTPROOFING);
1362
1363 nMaxErr = TestFullSpectrum(xform, 31, 0x1000L);
1364
1365 cmsDeleteTransform(xform);
1366 cmsCloseProfile(In);
1367 cmsCloseProfile(Out);
1368 cmsCloseProfile(Proof);
1369 printf("\n");
1370
1371 return nMaxErr;
1372 }
1373
1374
1375 // Check induced error on multiprofile transforms
1376
1377 static
TestMultiprofile(void)1378 int TestMultiprofile(void)
1379 {
1380
1381 cmsHPROFILE hsRGB, hXYZ, hLab;
1382 cmsHTRANSFORM hXForm;
1383 cmsHPROFILE Profiles[10];
1384 int nMaxErr;
1385
1386 hsRGB = cmsCreate_sRGBProfile();
1387 hLab = cmsCreateLabProfile(NULL);
1388 hXYZ = cmsCreateXYZProfile();
1389
1390 Profiles[0] = hsRGB;
1391 Profiles[1] = hLab;
1392 Profiles[2] = hsRGB;
1393 Profiles[3] = hsRGB;
1394
1395 Profiles[4] = hLab;
1396 Profiles[5] = hXYZ;
1397 Profiles[6] = hsRGB;
1398
1399 hXForm = cmsCreateMultiprofileTransform(Profiles, 7, TYPE_RGBA_16, TYPE_RGBA_16, INTENT_RELATIVE_COLORIMETRIC, cmsFLAGS_HIGHRESPRECALC);
1400
1401 printf("Testing multiprofile transforms (6 profiles)");
1402
1403 nMaxErr = TestFullSpectrum(hXForm, 31, 0x1000L);
1404
1405 cmsDeleteTransform(hXForm);
1406 cmsCloseProfile(hsRGB);
1407 cmsCloseProfile(hXYZ);
1408 cmsCloseProfile(hLab);
1409
1410 printf("\n");
1411
1412 return nMaxErr;
1413 }
1414
1415 // Check linearization and other goodies
1416
1417 static
TestLinearizationDevicelink()1418 int TestLinearizationDevicelink()
1419 {
1420 LPGAMMATABLE Transfer[3];
1421 cmsHPROFILE hLin1, hLin2;
1422 cmsHTRANSFORM hXForm;
1423 cmsHPROFILE Profiles[10];
1424 int nMaxErr;
1425
1426 printf("Testing linearization devicelink");
1427
1428 Transfer[0] = cmsBuildGamma(256, 1./2.2);
1429 Transfer[1] = cmsBuildGamma(256, 1./2.2);
1430 Transfer[2] = cmsBuildGamma(256, 1./2.2);
1431
1432 hLin1 = cmsCreateLinearizationDeviceLink(icSigRgbData, Transfer);
1433
1434 cmsFreeGammaTriple(Transfer);
1435
1436
1437
1438 Transfer[0] = cmsBuildGamma(256, 2.2);
1439 Transfer[1] = cmsBuildGamma(256, 2.2);
1440 Transfer[2] = cmsBuildGamma(256, 2.2);
1441
1442 hLin2 = cmsCreateLinearizationDeviceLink(icSigRgbData, Transfer);
1443
1444 cmsFreeGammaTriple(Transfer);
1445
1446 Profiles[0] = hLin1;
1447 Profiles[1] = hLin2;
1448
1449 hXForm = cmsCreateMultiprofileTransform(Profiles, 2, TYPE_RGBA_16, TYPE_RGBA_16, INTENT_RELATIVE_COLORIMETRIC, cmsFLAGS_HIGHRESPRECALC);
1450 if (!hXForm) {
1451
1452 printf("Error!\n");
1453 return 1;
1454 }
1455
1456
1457 nMaxErr = TestFullSpectrum(hXForm, 31, 0x1000L);
1458
1459 cmsDeleteTransform(hXForm);
1460 cmsCloseProfile(hLin1);
1461 cmsCloseProfile(hLin2);
1462
1463 printf("\n");
1464
1465 return nMaxErr;
1466 }
1467
1468
1469 static
TestLinearizationDevicelink2()1470 int TestLinearizationDevicelink2()
1471 {
1472 LPGAMMATABLE Transfer[3];
1473 cmsHPROFILE hLin1;
1474 cmsHTRANSFORM hXForm;
1475 int nMaxErr;
1476
1477 printf("Testing saved linearization devicelink");
1478
1479 Transfer[0] = cmsBuildGamma(256, 1);
1480 Transfer[1] = cmsBuildGamma(256, 1);
1481 Transfer[2] = cmsBuildGamma(256, 1);
1482
1483 hLin1 = cmsCreateLinearizationDeviceLink(icSigRgbData, Transfer);
1484
1485 _cmsSaveProfile(hLin1, "lin1.icc");
1486 cmsFreeGammaTriple(Transfer);
1487 cmsCloseProfile(hLin1);
1488
1489 hLin1 = cmsOpenProfileFromFile("lin1.icc", "r");
1490
1491 hXForm = cmsCreateTransform(hLin1, TYPE_RGBA_16, NULL, TYPE_RGBA_16, INTENT_ABSOLUTE_COLORIMETRIC, 0);
1492
1493 if (!hXForm) {
1494
1495 printf("Error!\n");
1496 return 1;
1497 }
1498
1499 nMaxErr = TestFullSpectrum(hXForm, 31, 1);
1500
1501 cmsDeleteTransform(hXForm);
1502 cmsCloseProfile(hLin1);
1503 unlink("lin1.icc");
1504
1505 printf("\n");
1506
1507 return nMaxErr;
1508 }
1509
1510
1511 static
TestDeviceLinkGeneration()1512 int TestDeviceLinkGeneration()
1513 {
1514 cmsHTRANSFORM hXForm, hIdentity;
1515 cmsHPROFILE hDevLink, hsRGB;
1516 int nMaxErr;
1517
1518
1519 printf("Testing devicelink generation");
1520
1521 hsRGB = cmsOpenProfileFromFile("sRGB Color Space Profile.icm", "r");
1522 hIdentity = cmsCreateTransform(hsRGB, TYPE_RGBA_16, hsRGB, TYPE_RGBA_16, INTENT_RELATIVE_COLORIMETRIC, 0);
1523 hDevLink = cmsTransform2DeviceLink(hIdentity, 0);
1524 _cmsSaveProfile(hDevLink, "devicelink.icm");
1525
1526 cmsCloseProfile(hDevLink);
1527 cmsCloseProfile(hsRGB);
1528 cmsDeleteTransform(hIdentity);
1529
1530
1531 hDevLink = cmsOpenProfileFromFile("devicelink.icm", "r");
1532 hXForm = cmsCreateTransform(hDevLink, TYPE_RGBA_16, NULL, TYPE_RGBA_16, INTENT_RELATIVE_COLORIMETRIC, 0);
1533 nMaxErr = TestFullSpectrum(hXForm, 31, 0x1000L);
1534
1535 cmsDeleteTransform(hXForm);
1536 cmsCloseProfile(hDevLink);
1537
1538 printf("\n");
1539 unlink("devicelink.icm");
1540
1541 return nMaxErr;
1542 }
1543
1544 static
TestInkLimiting()1545 int TestInkLimiting()
1546 {
1547 cmsHPROFILE hIL;
1548 cmsHTRANSFORM hXForm;
1549 BYTE In[4], Out[4];
1550 int i, j, k, l, res;
1551
1552
1553
1554 printf("Testing ink limiting ");
1555
1556 hIL = cmsCreateInkLimitingDeviceLink(icSigCmykData, 100);
1557
1558
1559 hXForm = cmsCreateTransform(hIL, TYPE_CMYK_8, NULL, TYPE_CMYK_8, INTENT_RELATIVE_COLORIMETRIC, 0);
1560 if (!hXForm) {
1561
1562 printf("Error!\n");
1563 return 0;
1564 }
1565
1566 for (l=0; l < 255; l += 8) {
1567 Dot();
1568 for (k=0; k < 255; k += 8)
1569 for (j=0; j < 255; j += 8)
1570 for (i=0; i < 255; i += 8) {
1571
1572 In[0] = (BYTE) i; In[1] = (BYTE) j; In[2] = (BYTE) k; In[3] = (BYTE) l;
1573
1574 cmsDoTransform(hXForm, In, Out, 1);
1575
1576 res = Out[0] + Out[1] + Out[2] + Out[3];
1577
1578 if (res > 0x100) {
1579
1580 printf("Failed! (%d) \n", res);
1581 return 0;
1582 }
1583 }
1584 }
1585
1586 cmsDeleteTransform(hXForm);
1587 cmsCloseProfile(hIL);
1588 printf(" pass.\n");
1589
1590 return 1;
1591 }
1592
1593
1594
1595 static
CheckPlanar(void)1596 void CheckPlanar(void)
1597 {
1598 cmsHTRANSFORM xform;
1599 cmsHPROFILE hsRGB;
1600 int i;
1601 BYTE Out[12];
1602 BYTE Bmp[] = { 0x00, 0x10, 0x20, 0x30, // R Plane
1603 0x00, 0x10, 0x20, 0x30, // G Plane
1604 0x00, 0x10, 0x20, 0x30 }; // B Plane
1605
1606
1607
1608 hsRGB = cmsCreate_sRGBProfile();
1609 xform = cmsCreateTransform(hsRGB, TYPE_RGB_8_PLANAR,
1610 hsRGB, TYPE_RGB_8_PLANAR,
1611 INTENT_PERCEPTUAL, cmsFLAGS_NOTPRECALC);
1612
1613 cmsDoTransform(xform, Bmp, Out, 4);
1614
1615 for (i=0; i < 12; i += 3) {
1616 printf("RGB=(%x, %x, %x)\n", Out[i+0], Out[i+1], Out[i+2]);
1617 }
1618
1619 cmsDeleteTransform(xform);
1620 cmsCloseProfile(hsRGB);
1621 }
1622
1623 #ifdef ICM_COMPARATIVE
1624 #ifndef NON_WINDOWS
1625
1626 static
CompareWithICM_16bit(void)1627 void CompareWithICM_16bit(void)
1628 {
1629
1630 HTRANSFORM hICMxform;
1631 HPROFILE hICMProfileFrom, hICMProfileTo;
1632 LOGCOLORSPACE LogColorSpace;
1633 COLOR In, Out;
1634 COLOR *InBlk, *OutBlk, *InPtr;
1635 size_t size;
1636 int r, g, b;
1637 PROFILE Profile;
1638 clock_t atime;
1639 double seconds, diff;
1640 cmsHPROFILE hlcmsProfileIn, hlcmsProfileOut;
1641 cmsHTRANSFORM hlcmsxform;
1642
1643
1644 printf("\n\nComparative with MS-Windows ICM (16 bits per sample):\n");
1645
1646
1647 Profile.dwType = PROFILE_FILENAME;
1648 Profile.pProfileData = "sRGBSpac.icm";
1649 Profile.cbDataSize = strlen("sRGBSpac.icm");
1650
1651 hICMProfileFrom = OpenColorProfile(&Profile, PROFILE_READ, FILE_SHARE_READ, OPEN_EXISTING);
1652
1653 Profile.pProfileData = "sRGBSpac.icm";
1654 Profile.cbDataSize = strlen("sRGBSpac.icm");
1655 hICMProfileTo = OpenColorProfile(&Profile, PROFILE_READ, FILE_SHARE_READ, OPEN_EXISTING);
1656
1657 ZeroMemory(&LogColorSpace, sizeof(LOGCOLORSPACE));
1658
1659 LogColorSpace.lcsSignature = LCS_SIGNATURE;
1660 LogColorSpace.lcsVersion = 0x400;
1661 LogColorSpace.lcsCSType = LCS_CALIBRATED_RGB;
1662 strcpy(LogColorSpace.lcsFilename, "sRGBSpac.icm");
1663
1664 hICMxform = CreateColorTransform(&LogColorSpace, hICMProfileTo, NULL, BEST_MODE);
1665
1666
1667
1668 size = 256 * 256 * 256;
1669 InBlk = _cmsMalloc((size_t) size * sizeof(COLOR));
1670 OutBlk = _cmsMalloc((size_t) size * sizeof(COLOR));
1671
1672 if (InBlk == NULL || OutBlk == NULL) {
1673 printf("Out of memory\n"); exit(2);
1674 }
1675
1676 printf("Windows ICM is transforming full spectrum...");
1677
1678 InPtr = InBlk;
1679 for (r=0; r < 255; r++)
1680 for (g=0; g < 255; g++)
1681 for (b=0; b < 255; b++) {
1682
1683 InPtr->rgb.red = (r << 8) | r;
1684 InPtr->rgb.green = (g << 8) | g;
1685 InPtr->rgb.blue = (b << 8) | b;
1686
1687 InPtr++;
1688 }
1689
1690 atime = clock();
1691
1692 TranslateColors( hICMxform, InBlk, size, COLOR_RGB, OutBlk, COLOR_RGB);
1693
1694 diff = clock() - atime;
1695 seconds = (double) diff / CLOCKS_PER_SEC;
1696
1697
1698 printf("done. [%d tics, %g sec.]\n", (int) diff, seconds);
1699
1700 CloseColorProfile(hICMProfileFrom);
1701 CloseColorProfile(hICMProfileTo);
1702 DeleteColorTransform(hICMxform);
1703
1704 hlcmsProfileIn = cmsOpenProfileFromFile("sRGBSpac.icm", "r");
1705 hlcmsProfileOut = cmsOpenProfileFromFile("sRGBSpac.icm", "r");
1706
1707 hlcmsxform = cmsCreateTransform(hlcmsProfileIn, TYPE_RGB_16, hlcmsProfileOut, TYPE_RGB_16, INTENT_PERCEPTUAL, 0);
1708
1709 printf("lcms is transforming full spectrum...");
1710
1711 atime = clock();
1712
1713 cmsDoTransform(hlcmsxform, InBlk, OutBlk, size);
1714
1715 diff = clock() - atime;
1716 seconds = (double) diff / CLOCKS_PER_SEC;
1717
1718 printf("done. [%d tics, %g sec.]\n", (int) diff, seconds);
1719
1720 cmsDeleteTransform(hlcmsxform);
1721 cmsCloseProfile(hlcmsProfileIn);
1722 cmsCloseProfile(hlcmsProfileOut);
1723
1724 _cmsFree(InBlk);
1725 _cmsFree(OutBlk);
1726 }
1727
1728 static
CompareWithICM_8bit(void)1729 void CompareWithICM_8bit(void)
1730 {
1731
1732 HTRANSFORM hICMxform;
1733 HPROFILE hICMProfileFrom, hICMProfileTo;
1734 LOGCOLORSPACE LogColorSpace;
1735 RGBQUAD In, Out;
1736 int r, g, b;
1737 PROFILE Profile;
1738 clock_t atime;
1739 double seconds, diff;
1740 cmsHPROFILE hlcmsProfileIn, hlcmsProfileOut;
1741 cmsHTRANSFORM hlcmsxform;
1742
1743
1744 printf("\n\nComparative with MS-Windows ICM (8 bits per sample):\n");
1745
1746
1747 Profile.dwType = PROFILE_FILENAME;
1748 Profile.pProfileData = "sRGBSpac.icm";
1749 Profile.cbDataSize = strlen("sRGBSpac.icm");
1750
1751 hICMProfileFrom = OpenColorProfile(&Profile, PROFILE_READ, FILE_SHARE_READ, OPEN_EXISTING);
1752
1753 Profile.pProfileData = "sRGBSpac.icm";
1754 Profile.cbDataSize = strlen("sRGBSpac.icm");
1755 hICMProfileTo = OpenColorProfile(&Profile, PROFILE_READ, FILE_SHARE_READ, OPEN_EXISTING);
1756
1757 ZeroMemory(&LogColorSpace, sizeof(LOGCOLORSPACE));
1758
1759 LogColorSpace.lcsSignature = LCS_SIGNATURE;
1760 LogColorSpace.lcsVersion = 0x400;
1761 LogColorSpace.lcsCSType = LCS_CALIBRATED_RGB;
1762 strcpy(LogColorSpace.lcsFilename, "sRGBSpac.icm");
1763
1764 hICMxform = CreateColorTransform(&LogColorSpace, hICMProfileTo, NULL, BEST_MODE);
1765
1766 printf("Windows ICM is transforming full spectrum...");
1767
1768 atime = clock();
1769
1770 for (r=0; r < 255; r++)
1771 for (g=0; g < 255; g++)
1772 for (b=0; b < 255; b++) {
1773
1774 In.rgbRed = r;
1775 In.rgbGreen = g;
1776 In.rgbBlue = b;
1777
1778 if (!TranslateBitmapBits(hICMxform, &In, BM_RGBTRIPLETS, 1, 1, 0, &Out, BM_RGBTRIPLETS, 0, NULL, 0))
1779 exit(2);
1780
1781 }
1782
1783 diff = clock() - atime;
1784 seconds = (double) diff / CLOCKS_PER_SEC;
1785
1786
1787 printf("done. [%d tics, %g sec.]\n", (int) diff, seconds);
1788
1789 CloseColorProfile(hICMProfileFrom);
1790 CloseColorProfile(hICMProfileTo);
1791 DeleteColorTransform(hICMxform);
1792
1793 hlcmsProfileIn = cmsOpenProfileFromFile("sRGBSpac.icm", "r");
1794 hlcmsProfileOut = cmsOpenProfileFromFile("sRGBSpac.icm", "r");
1795
1796 hlcmsxform = cmsCreateTransform(hlcmsProfileIn, TYPE_BGRA_8, hlcmsProfileOut, TYPE_BGRA_8, INTENT_PERCEPTUAL, 0);
1797
1798 printf("lcms is transforming full spectrum...");
1799
1800 atime = clock();
1801
1802 for (r=0; r < 255; r++)
1803 for (g=0; g < 255; g++)
1804 for (b=0; b < 255; b++) {
1805
1806 In.rgbRed = r;
1807 In.rgbGreen = g;
1808 In.rgbBlue = b;
1809
1810 cmsDoTransform(hlcmsxform, &In, &Out, 1);
1811 }
1812
1813 diff = clock() - atime;
1814 seconds = (double) diff / CLOCKS_PER_SEC;
1815
1816 printf("done. [%d tics, %g sec.]\n", (int) diff, seconds);
1817
1818 cmsDeleteTransform(hlcmsxform);
1819 cmsCloseProfile(hlcmsProfileIn);
1820 cmsCloseProfile(hlcmsProfileOut);
1821
1822 }
1823
1824
1825 #endif
1826 #endif
1827
1828
1829 #ifdef CHECK_SPEED
1830
1831
1832
1833 static
SpeedTest(void)1834 void SpeedTest(void)
1835 {
1836
1837 int r, g, b, j;
1838 clock_t atime;
1839 double seconds, diff;
1840 cmsHPROFILE hlcmsProfileIn, hlcmsProfileOut;
1841 cmsHTRANSFORM hlcmsxform;
1842 Scanline_rgb0 *In;
1843 size_t Mb;
1844
1845 hlcmsProfileIn = cmsOpenProfileFromFile("sRGB Color Space Profile.icm", "r");
1846 hlcmsProfileOut = cmsOpenProfileFromFile("sRGBSpac.icm", "r");
1847
1848 hlcmsxform = cmsCreateTransform(hlcmsProfileIn, TYPE_RGB_16, hlcmsProfileOut, TYPE_RGB_16, INTENT_PERCEPTUAL, cmsFLAGS_NOTCACHE);
1849
1850 Mb = 256*256*256*sizeof(Scanline_rgb0);
1851
1852 In = (Scanline_rgb0*) _cmsMalloc(Mb);
1853
1854 j = 0;
1855 for (r=0; r < 256; r++)
1856 for (g=0; g < 256; g++)
1857 for (b=0; b < 256; b++) {
1858
1859 In[j].r = (WORD) ((r << 8) | r);
1860 In[j].g = (WORD) ((g << 8) | g);
1861 In[j].b = (WORD) ((b << 8) | b);
1862
1863 j++;
1864 }
1865
1866
1867 printf("lcms is transforming full spectrum...");
1868
1869 atime = clock();
1870
1871 cmsDoTransform(hlcmsxform, In, In, 256*256*256);
1872
1873 diff = clock() - atime;
1874 seconds = (double) diff / CLOCKS_PER_SEC;
1875 _cmsFree(In);
1876
1877
1878 printf("done.\n[%d tics, %g sec, %g Mpixel/sec.]\n", (int) diff, seconds, Mb / (1024*1024*seconds*3*2) );
1879
1880 cmsDeleteTransform(hlcmsxform);
1881 cmsCloseProfile(hlcmsProfileIn);
1882 cmsCloseProfile(hlcmsProfileOut);
1883
1884 }
1885
1886
1887
1888 static
SpeedTest2(void)1889 void SpeedTest2(void)
1890 {
1891
1892 int r, g, b, j;
1893 clock_t atime;
1894 double seconds, diff;
1895 cmsHPROFILE hlcmsProfileIn, hlcmsProfileOut;
1896 cmsHTRANSFORM hlcmsxform;
1897 Scanline_rgb8 *In;
1898 size_t Mb;
1899
1900
1901 hlcmsProfileIn = cmsOpenProfileFromFile("sRGB Color Space Profile.icm", "r");
1902 hlcmsProfileOut = cmsOpenProfileFromFile("sRGBSpac.icm", "r");
1903
1904 hlcmsxform = cmsCreateTransform(hlcmsProfileIn, TYPE_RGB_8, hlcmsProfileOut, TYPE_RGB_8, INTENT_PERCEPTUAL, cmsFLAGS_NOTCACHE);
1905
1906 Mb = 256*256*256*sizeof(Scanline_rgb8);
1907
1908 In = (Scanline_rgb8*) _cmsMalloc(Mb);
1909
1910 j = 0;
1911 for (r=0; r < 256; r++)
1912 for (g=0; g < 256; g++)
1913 for (b=0; b < 256; b++) {
1914
1915 In[j].r = (BYTE) r;
1916 In[j].g = (BYTE) g;
1917 In[j].b = (BYTE) b;
1918
1919 j++;
1920 }
1921
1922
1923 printf("lcms is transforming full spectrum...");
1924
1925 atime = clock();
1926
1927 cmsDoTransform(hlcmsxform, In, In, 256*256*256);
1928
1929 diff = clock() - atime;
1930 seconds = (double) diff / CLOCKS_PER_SEC;
1931 _cmsFree(In);
1932
1933
1934 printf("done.\n[%d tics, %g sec, %g Mpixels/sec.]\n", (int) diff, seconds, Mb / (1024*1024*seconds*3) );
1935
1936 cmsDeleteTransform(hlcmsxform);
1937 cmsCloseProfile(hlcmsProfileIn);
1938 cmsCloseProfile(hlcmsProfileOut);
1939
1940 }
1941
1942 #endif
1943
1944
1945 static
TestSaveToMem(void)1946 int TestSaveToMem(void)
1947 {
1948 void *memPtr=0;
1949 size_t bytesNeeded=0;
1950 int rc = FALSE;
1951 cmsHPROFILE hProfile = cmsCreate_sRGBProfile();
1952
1953 printf("Testing save to memory: ");
1954
1955 // pass 1 - compute length
1956 if (!_cmsSaveProfileToMem(hProfile, memPtr, &bytesNeeded)) {
1957 printf("Failed!\n");
1958 return FALSE;
1959 }
1960 // pass 2 - generate profile
1961 if(!bytesNeeded) {
1962 printf("Failed!\n");
1963 return FALSE;
1964 }
1965
1966 memPtr = _cmsMalloc(bytesNeeded);
1967 if (_cmsSaveProfileToMem(hProfile, memPtr, &bytesNeeded)) {
1968
1969
1970 cmsHPROFILE newProfile = cmsOpenProfileFromMem(memPtr, (DWORD) bytesNeeded);
1971 const char* s = cmsTakeProductName(newProfile);
1972
1973 if (strncmp(s, "sRGB", 4) == 0) rc = TRUE;
1974
1975 cmsCloseProfile(newProfile);
1976 _cmsFree(memPtr);
1977
1978 }
1979
1980 cmsCloseProfile(hProfile);
1981
1982 printf (rc ? "pass.\n" : "failed!\n");
1983 return rc;
1984 }
1985
1986
1987
1988 static
TestNamedColor(void)1989 int TestNamedColor(void)
1990 {
1991 LPcmsNAMEDCOLORLIST nc2;
1992 cmsHPROFILE hProfile, hDevicelink, hsRGB, hLab;
1993 cmsHTRANSFORM xform, rgb2lab;
1994 int i;
1995
1996
1997 printf("Testing Named color profiles: ");
1998
1999
2000 hsRGB = cmsCreate_sRGBProfile();
2001 hLab = cmsCreateLabProfile(NULL);
2002
2003 rgb2lab = cmsCreateTransform(hsRGB, TYPE_RGB_16, hLab, TYPE_Lab_16, INTENT_PERCEPTUAL, cmsFLAGS_NOTPRECALC);
2004
2005 nc2 = cmsAllocNamedColorList(64);
2006
2007 nc2 ->ColorantCount = 3;
2008 strcpy(nc2 ->Prefix, "prefix");
2009 strcpy(nc2 ->Suffix, "suffix");
2010
2011 for (i=0; i < 64; i++) {
2012
2013 WORD vv = RGB_8_TO_16((i*4));
2014
2015 nc2 ->List[i].DeviceColorant[0] = vv;
2016 nc2 ->List[i].DeviceColorant[1] = vv;
2017 nc2 ->List[i].DeviceColorant[2] = vv;
2018
2019 cmsDoTransform(rgb2lab, nc2 ->List[i].DeviceColorant, nc2 ->List[i].PCS, 1);
2020
2021 sprintf(nc2 ->List[i].Name, "Color #%d", i);
2022
2023 }
2024
2025 hProfile = cmsOpenProfileFromFile("named.icc", "w");
2026
2027 cmsSetDeviceClass(hProfile, icSigNamedColorClass);
2028 cmsSetPCS(hProfile, icSigLabData);
2029 cmsSetColorSpace(hProfile, icSigRgbData);
2030
2031 cmsAddTag(hProfile, icSigNamedColor2Tag, (void*) nc2);
2032 cmsAddTag(hProfile, icSigMediaWhitePointTag, cmsD50_XYZ());
2033 cmsCloseProfile(hProfile);
2034
2035 cmsFreeNamedColorList(nc2);
2036
2037
2038 hProfile = cmsOpenProfileFromFile("named.icc", "r");
2039
2040 xform = cmsCreateTransform(hProfile, TYPE_NAMED_COLOR_INDEX, NULL, TYPE_RGB_16, INTENT_PERCEPTUAL, 0);
2041
2042 for (i=0; i < 64; i++) {
2043
2044 WORD index;
2045 WORD Color[3];
2046
2047 index = (WORD) i;
2048
2049 cmsDoTransform(xform, &index, Color, 1);
2050
2051 if (Color[0] != RGB_8_TO_16((i*4)) ||
2052 Color[1] != RGB_8_TO_16((i*4)) ||
2053 Color[2] != RGB_8_TO_16((i*4))) {
2054
2055 printf(" fail on spot color #%d\n", i);
2056 return 0;
2057 }
2058 }
2059
2060
2061 cmsDeleteTransform(xform);
2062 cmsCloseProfile(hProfile);
2063 cmsDeleteTransform(rgb2lab);
2064 cmsCloseProfile(hLab);
2065
2066
2067 hProfile = cmsOpenProfileFromFile("named.icc", "r");
2068
2069 xform = cmsCreateTransform(hProfile, TYPE_NAMED_COLOR_INDEX, hsRGB, TYPE_RGB_16, INTENT_PERCEPTUAL, 0);
2070
2071 hDevicelink = cmsTransform2DeviceLink(xform, 0);
2072
2073 _cmsSaveProfile(hDevicelink, "named2.icc");
2074 cmsCloseProfile(hDevicelink);
2075
2076 cmsDeleteTransform(xform);
2077 cmsCloseProfile(hProfile);
2078
2079 cmsCloseProfile(hsRGB);
2080
2081 unlink("named.icc");
2082 unlink("named2.icc");
2083
2084 printf(" pass.\n");
2085 return 1;
2086 }
2087
2088
2089 static
TestColorantTableTag()2090 int TestColorantTableTag()
2091 {
2092 LPcmsNAMEDCOLORLIST nc2;
2093 cmsHPROFILE hProfile = cmsOpenProfileFromFile("colTable.icc", "w");
2094
2095 nc2 = cmsAllocNamedColorList(3);
2096
2097 strcpy(nc2 ->List[0].Name, "Red");
2098 strcpy(nc2 ->List[1].Name, "Green");
2099 strcpy(nc2 ->List[2].Name, "Blue");
2100
2101
2102 cmsSetDeviceClass(hProfile, icSigOutputClass);
2103 cmsSetPCS(hProfile, icSigLabData);
2104 cmsSetColorSpace(hProfile, icSigRgbData);
2105
2106 cmsAddTag(hProfile, icSigColorantTableTag, (void*) nc2);
2107 cmsAddTag(hProfile, icSigMediaWhitePointTag, cmsD50_XYZ());
2108 cmsCloseProfile(hProfile);
2109 cmsFreeNamedColorList(nc2);
2110
2111
2112 hProfile = cmsOpenProfileFromFile("colTable.icc", "r");
2113
2114 nc2 = cmsReadColorantTable(hProfile, icSigColorantTableTag);
2115
2116 cmsFreeNamedColorList(nc2);
2117 cmsCloseProfile(hProfile);
2118
2119 unlink("colTable.icc");
2120
2121 return 1;
2122
2123 }
2124
2125 // New to 1.13 -- CGATS/IT8.7
2126
2127
2128 #define NPOINTS_IT8 10 // (17*17*17*17)
2129
2130 static
TestIT8(void)2131 int TestIT8(void)
2132 {
2133 LCMSHANDLE it8;
2134 int i;
2135
2136 printf("Testing CGATS parser: ");
2137
2138 it8 = cmsIT8Alloc();
2139
2140 cmsIT8SetSheetType(it8, "LCMS/TESTING");
2141 cmsIT8SetPropertyStr(it8, "ORIGINATOR", "1 2 3 4");
2142 cmsIT8SetPropertyUncooked(it8, "DESCRIPTOR", "1234");
2143 cmsIT8SetPropertyStr(it8, "MANUFACTURER", "3");
2144 cmsIT8SetPropertyDbl(it8, "CREATED", 4);
2145 cmsIT8SetPropertyDbl(it8, "SERIAL", 5);
2146 cmsIT8SetPropertyHex(it8, "MATERIAL", 0x123);
2147
2148 cmsIT8SetPropertyDbl(it8, "NUMBER_OF_SETS", NPOINTS_IT8);
2149 cmsIT8SetPropertyDbl(it8, "NUMBER_OF_FIELDS", 4);
2150
2151 cmsIT8SetDataFormat(it8, 0, "SAMPLE_ID");
2152 cmsIT8SetDataFormat(it8, 1, "RGB_R");
2153 cmsIT8SetDataFormat(it8, 2, "RGB_G");
2154 cmsIT8SetDataFormat(it8, 3, "RGB_B");
2155
2156 for (i=0; i < NPOINTS_IT8; i++) {
2157
2158 char Patch[20];
2159
2160 sprintf(Patch, "P%d", i);
2161
2162 cmsIT8SetDataRowCol(it8, i, 0, Patch);
2163 cmsIT8SetDataRowColDbl(it8, i, 1, i);
2164 cmsIT8SetDataRowColDbl(it8, i, 2, i);
2165 cmsIT8SetDataRowColDbl(it8, i, 3, i);
2166 }
2167
2168 cmsIT8SaveToFile(it8, "TEST.IT8");
2169 cmsIT8Free(it8);
2170
2171
2172 it8 = cmsIT8LoadFromFile("TEST.IT8");
2173 cmsIT8SaveToFile(it8, "TEST.IT8");
2174 cmsIT8Free(it8);
2175
2176
2177
2178 it8 = cmsIT8LoadFromFile("TEST.IT8");
2179
2180 if (cmsIT8GetPropertyDbl(it8, "DESCRIPTOR") != 1234) {
2181
2182 printf("fail!\n");
2183 return 0;
2184 }
2185
2186
2187 cmsIT8SetPropertyDbl(it8, "DESCRIPTOR", 5678);
2188
2189 if (cmsIT8GetPropertyDbl(it8, "DESCRIPTOR") != 5678) {
2190
2191 printf("fail!\n");
2192 return 0;
2193 }
2194
2195
2196 if (cmsIT8GetDataDbl(it8, "P3", "RGB_G") != 3) {
2197 printf("fail!\n");
2198 return 0;
2199 }
2200
2201
2202 cmsIT8Free(it8);
2203
2204 unlink("TEST.IT8");
2205 printf("pass.\n");
2206 return 1;
2207
2208 }
2209
2210
2211 // Create CSA/CRD
2212
2213 static
GenerateCSA(const char * cInProf)2214 void GenerateCSA(const char* cInProf)
2215 {
2216 cmsHPROFILE hProfile;
2217
2218
2219 DWORD n;
2220 char* Buffer;
2221
2222
2223 if (cInProf == NULL)
2224 hProfile = cmsCreateLabProfile(NULL);
2225 else
2226 hProfile = cmsOpenProfileFromFile(cInProf, "r");
2227
2228 n = cmsGetPostScriptCSA(hProfile, 0, NULL, 0);
2229 if (n == 0) return;
2230
2231 Buffer = (char*) _cmsMalloc(n + 1);
2232 cmsGetPostScriptCSA(hProfile, 0, Buffer, n);
2233 Buffer[n] = 0;
2234
2235 _cmsFree(Buffer);
2236 cmsCloseProfile(hProfile);
2237 }
2238
2239
2240 static
GenerateCRD(const char * cOutProf)2241 void GenerateCRD(const char* cOutProf)
2242 {
2243 cmsHPROFILE hProfile;
2244 DWORD n;
2245 char* Buffer;
2246 DWORD dwFlags = 0;
2247
2248
2249 if (cOutProf == NULL)
2250 hProfile = cmsCreateLabProfile(NULL);
2251 else
2252 hProfile = cmsOpenProfileFromFile(cOutProf, "r");
2253
2254 n = cmsGetPostScriptCRDEx(hProfile, 0, dwFlags, NULL, 0);
2255 if (n == 0) return;
2256
2257 Buffer = (char*) _cmsMalloc(n + 1);
2258 cmsGetPostScriptCRDEx(hProfile, 0, dwFlags, Buffer, n);
2259 Buffer[n] = 0;
2260
2261 _cmsFree(Buffer);
2262 cmsCloseProfile(hProfile);
2263 }
2264
2265 static
TestPostScript()2266 int TestPostScript()
2267 {
2268 GenerateCSA("sRGB Color Space Profile.icm");
2269 GenerateCRD("sRGB Color Space Profile.icm");
2270 GenerateCSA(NULL);
2271 GenerateCRD(NULL);
2272
2273 return 1;
2274 }
2275
2276
2277 static
TestLabFloat()2278 void TestLabFloat()
2279 {
2280 #define TYPE_LabA_DBL (COLORSPACE_SH(PT_Lab)|CHANNELS_SH(3)|BYTES_SH(0)|EXTRA_SH(1)|DOSWAP_SH(1))
2281
2282 struct {
2283 double L, a, b;
2284 double A;
2285 } a;
2286 cmsCIELab b;
2287 cmsHPROFILE hLab = cmsCreateLabProfile(NULL);
2288 cmsHTRANSFORM xform = cmsCreateTransform(hLab, TYPE_LabA_DBL, hLab, TYPE_Lab_DBL, 0, 0);
2289
2290 a.L = 100; a.a = 0; a.b= 0;
2291 cmsDoTransform(xform, &a, &b, 1);
2292
2293 cmsDeleteTransform(xform);
2294 cmsCloseProfile(hLab);
2295 }
2296
2297
2298
main(int argc,char * argv[])2299 int main(int argc, char *argv[])
2300 {
2301 int lExhaustive = 0;
2302
2303 // #include "crtdbg.h"
2304 // _CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );
2305
2306
2307
2308 printf("little cms testbed. Ver %1.2f [build %s %s]\n\n", LCMS_VERSION / 100., __DATE__, __TIME__);
2309
2310 #ifndef LCMS_DLL
2311
2312 if (!CheckEndianess()) return 1;
2313 if (!CheckSwab()) return 1;
2314 if (!CheckQuickFloor()) return 1;
2315
2316 TestFixedPoint();
2317
2318 if (!TestFixedScaling()) return 1;
2319 if (!TestJointCurves()) return 1;
2320 if (!TestReversingOfCurves()) return 1;
2321 if (!TestLinearInterpolation(lExhaustive)) return 1;
2322 if (!TestReverseLinearInterpolation()) return 1;
2323
2324
2325
2326
2327 if (!Test3D()) return 1;
2328 if (!TestMatrixCreation()) return 1;
2329 if (!GetInfoTest()) return 1;
2330
2331
2332 #endif
2333
2334 if (!Test_sRGB()) return 1;
2335
2336 if (!RealProfilesTest()) return 1;
2337 if (!TestInducedError(TYPE_LABA_16)) return 1;
2338 if (!TestPreview()) return 1;
2339 if (!TestMultiprofile()) return 1;
2340 if (!TestLinearizationDevicelink()) return 1;
2341
2342 if (!TestDeviceLinkGeneration()) return 1;
2343
2344
2345 if (!TestLinearizationDevicelink2()) return 1;
2346
2347
2348 if (!TestInkLimiting()) return 1;
2349 if (!TestSaveToMem()) return 1;
2350 if (!TestNamedColor()) return 1;
2351 if (!TestIT8()) return 1;
2352 if (!TestPostScript()) return 1;
2353 if (!TestColorantTableTag()) return 1;
2354
2355 #ifdef ICM_COMPARATIVE
2356 #ifndef NON_WINDOWS
2357 CompareWithICM_8bit();
2358 CompareWithICM_16bit();
2359 #endif
2360 #endif
2361
2362 #ifdef CHECK_SPEED
2363 SpeedTest();
2364 SpeedTest2();
2365 #endif
2366
2367 printf("\nSuccess.\n");
2368
2369 return 0;
2370
2371 }
2372
2373
2374
2375
2376
2377
2378
2379