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