diff options
Diffstat (limited to 'debian/lcms/lcms-1.19.dfsg2/testbed/testcms.c')
-rwxr-xr-x | debian/lcms/lcms-1.19.dfsg2/testbed/testcms.c | 2378 |
1 files changed, 2378 insertions, 0 deletions
diff --git a/debian/lcms/lcms-1.19.dfsg2/testbed/testcms.c b/debian/lcms/lcms-1.19.dfsg2/testbed/testcms.c new file mode 100755 index 00000000..98ec1535 --- /dev/null +++ b/debian/lcms/lcms-1.19.dfsg2/testbed/testcms.c @@ -0,0 +1,2378 @@ +// +// Little cms +// Copyright (C) 1998-2007 Marti Maria +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the Software +// is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +// Test Suite for Little cms + +// #define ICM_COMPARATIVE 1 +// #define CHECK_SPEED 1 + +#ifdef __BORLANDC__ +# include <condefs.h> +#endif + +#include "lcms.h" + + + +#include <time.h> +#include <stdio.h> +#include <stdlib.h> + +#ifndef NON_WINDOWS +#include <icm.h> +#endif + + +#define PREC 20 + +#define TYPE_XYZA_16 (COLORSPACE_SH(PT_XYZ)|CHANNELS_SH(3)|BYTES_SH(2)|EXTRA_SH(1)) +#define TYPE_LABA_16 (COLORSPACE_SH(PT_Lab)|CHANNELS_SH(3)|BYTES_SH(2)|EXTRA_SH(1)) + +typedef struct {BYTE r, g, b, a;} Scanline_rgb1; +typedef struct {WORD r, g, b, a;} Scanline_rgb2; +typedef struct {BYTE r, g, b;} Scanline_rgb8; +typedef struct {WORD r, g, b;} Scanline_rgb0; + + +// Print a dot for gauging + +static +void Dot(void) +{ + fprintf(stdout, "."); fflush(stdout); +} + +// #ifndef LCMS_DLL + +// Are we little or big endian? From Harbison&Steele. + +static +int CheckEndianess(void) +{ + int BigEndian, IsOk; + union { + + long l; + char c[sizeof (long)]; + + } u; + + u.l = 1; + BigEndian = (u.c[sizeof (long) - 1] == 1); + +#ifdef USE_BIG_ENDIAN + IsOk = BigEndian; +#else + IsOk = !BigEndian; +#endif + + if (!IsOk) { + + printf("\nOOOPPSS! You have USE_BIG_ENDIAN toggle misconfigured!\n\n"); + printf("Please, edit lcms.h and %s the USE_BIG_ENDIAN toggle.\n", BigEndian? "uncomment" : "comment"); + return 0; + } + + return 1; + +} + + +static +int CheckSwab(void) +{ + unsigned char Test[] = { 1, 2, 3, 4, 5, 6}; + +#ifdef USE_CUSTOM_SWAB + return 1; +#endif + +#ifdef USE_BIG_ENDIAN + return 1; +#endif + + swab((char*) Test, (char*) Test, 6); + + if (strncmp((char*) Test, "\x2\x1\x4\x3\x6\x5", 6) != 0) + { + printf("\nOOOPPSS! swab() does not work as expected in your machine!\n\n"); + printf("Please, edit lcms.h and uncomment the USE_CUSTOM_SWAB toggle.\n"); + return 0; + + } + return 1; +} + + +static +int CheckQuickFloor(void) +{ + + if ((_cmsQuickFloor(1.234) != 1) || + (_cmsQuickFloor(32767.234) != 32767) || + (_cmsQuickFloor(-1.234) != -2) || + (_cmsQuickFloor(-32767.1) != -32768)) { + + printf("\nOOOPPSS! _cmsFloor() does not work as expected in your machine!\n\n"); + printf("Please, edit lcms.h and uncomment the LCMS_DEFAULT_FLOOR_CONVERSION toggle.\n"); + return 0; + + } + + return 1; +} + +typedef struct _Stats { + double n, x, y, x2, y2, xy; + double Peak; + } STATS, FAR* LPSTATS; + +static void ClearStats(LPSTATS p) +{ + p -> n = p -> x = p -> y = p -> x2 = p -> y2 = p -> xy + = p -> Peak = 0.0; +} + +static double Std(LPSTATS p) +{ + return sqrt((p->n*p->x2 - p->x * p->x) / (p->n*(p->n-1))); +} + + + +static +void PrintStatistics(clock_t atime, LPSTATS Stats) +{ + + clock_t diff; + double a; + + diff = clock() - atime; + a = (double) diff / CLOCKS_PER_SEC; + + // These are statistics of 16 bit, so divide + // by 257 to get dE relative to 8 bits + + printf("\n"); + + if (Stats) + printf("dE: mean=%g, SD=%g, max=%g ", + (Stats->x / Stats -> n) / 257., + (Std(Stats)) / 257., + Stats -> Peak / 257.); + + + if (atime > 0) + printf("[%d tics, %g sec.]", (int) diff, a); + +} + + +// Simpler fixed-point math + +static +void TestFixedPoint(void) +{ + Fixed32 a, b, c, d; + double f; + + a = DOUBLE_TO_FIXED(1.1234); + b = DOUBLE_TO_FIXED(2.5678); + + c = FixedMul(a, b); + + d = FIXED_REST_TO_INT(c); + f = ((double) d / 0xffff) * 1000000.0; + + printf("Testing fixed point:\t%f = %d.%d\n", (1.1234 * 2.5678), FIXED_TO_INT(c), (int) f); + +} + + + +static +int TestFixedScaling(void) +{ + int i, j, nfl, nfx; + double FloatFactor; + Fixed32 FixedFactor; + + + + printf("Testing fixed scaling..."); + + for (j=5; j<100; j++) + { + FloatFactor = (double) j / 100.0 ; + FloatFactor = FIXED_TO_DOUBLE(DOUBLE_TO_FIXED(FloatFactor)); + FixedFactor = DOUBLE_TO_FIXED(FloatFactor); + + for (i=0; i < 0x10000L; i++) + { + nfl = (WORD) ((double) i * FloatFactor); + nfx = FixedScale((WORD) i, FixedFactor); + + if (nfl != nfx) { + printf("Failed!\ni=%x (%d), float=%x, fixed=%x", i, i, nfl, nfx); + return 0; + } + } + + } + + printf ("pass.\n"); + return 1; +} + +// Curve joining test. Joining two high-gamma of 3.0 curves should +// give something like linear + +static +int TestJointCurves(void) +{ + LPGAMMATABLE Forward, Reverse, Result; + LCMSBOOL rc; + + printf("Testing curves join ..."); + + Forward = cmsBuildGamma(256, 3.0); + Reverse = cmsBuildGamma(256, 3.0); + + Result = cmsJoinGammaEx(Forward, Reverse, 256); + + cmsFreeGamma(Forward); cmsFreeGamma(Reverse); + + rc = cmsIsLinear(Result->GammaTable, Result ->nEntries); + cmsFreeGamma(Result); + + if (!rc) { + printf("failed!\n"); + return 0; + } + else { + printf("pass.\n"); + return 1; + } + +} + + + +// Check reversing of gamma curves + +#define NPOINTS 1024 + +static +int TestReversingOfCurves(void) +{ + LPGAMMATABLE Gamma, Reverse, Computed; + int i; + double dE; + STATS Stats; + + printf("Testing reversing of curves ..."); + ClearStats(&Stats); + + + Gamma = cmsBuildGamma(NPOINTS, 3.0); + Reverse = cmsBuildGamma(NPOINTS, 1.0/3.0); + + Computed = cmsReverseGamma(NPOINTS, Gamma); + + for (i=0; i < NPOINTS; i++) { + + dE = fabs(Reverse->GammaTable[i] - Computed->GammaTable[i]); + + Stats.x += dE; + Stats.x2 += (dE * dE); + Stats.n += 1.0; + if (dE > Stats.Peak) { + Stats.Peak = dE; + } + + if (dE > 0x0010) { + printf("Coarse error! %x on entry %d: %X/%X", (int) dE, i, Reverse->GammaTable[i], + Computed->GammaTable[i]); + return 0; + } + + } + + if (Stats.Peak > 0) PrintStatistics(0, &Stats); + printf(" pass.\n"); + cmsFreeGamma(Gamma); + cmsFreeGamma(Reverse); + cmsFreeGamma(Computed); + return 1; +} + +// Linear interpolation test. Here I check the cmsLinearInterpLUT16 +// Tables are supposed to be monotonic, but the algorithm works on +// non-monotonic as well. + +static +int TestLinearInterpolation(int lExhaustive) +{ + static WORD Tab[4098]; + int j, i, k = 0; + L16PARAMS p; + int n; + clock_t time; + + printf("Testing linear interpolation ..."); + + // First I will check exact values. Since prime factors of 65535 (FFFF) are, + // + // 0xFFFF = 1 * 3 * 5 * 17 * 257 + // + // I test tables of 2, 4, 6, and 18 points, that will be exact. + // Then, a table of 3 elements are tested. Error must be < 1 + // Since no floating point is involved, This will be a measure of speed. + + + // Perform 10 times, so i can measure average times + + time = clock(); + for (j=0; j < 10; j++) + { + + // 2 points - exact + + Tab[0] = 0; + Tab[1] = 0xffffU; + + cmsCalcL16Params(2, &p); + + for (i=0; i <= 0xffffL; i++) + { + n = cmsLinearInterpLUT16((WORD) i, Tab, &p); + if (n != i) + { + printf("Error in Linear interpolation (2p): Must be i=%x, But is n=%x\n", i, n); + return 0; + } + + } + + + // 3 points - Here the error must be <= 1, since + // 2 == (3 - 1) is not a factor of 0xffff + + Tab[0] = 0; + Tab[1] = 0x7FFF; + Tab[2] = 0xffffU; + + cmsCalcL16Params(3, &p); + + for (i=0; i <= 0xffffL; i++) + { + n = cmsLinearInterpLUT16((WORD) i, Tab, &p); + if (abs(n - i) > 1) + { + printf("Error in Linear interpolation (3p): Must be i=%x, But is n=%x\n", i, n); + return 0; + } + + } + + + // 4 points - exact + + Tab[0] = 0; + Tab[1] = 0x5555U; + Tab[2] = 0xAAAAU; + Tab[3] = 0xffffU; + + cmsCalcL16Params(4, &p); + + for (i=0; i <= 0xffffL; i++) + { + n = cmsLinearInterpLUT16((WORD) i, Tab, &p); + if (n != i) { + printf("Error in Linear interpolation (4p): Must be i=%x, But is n=%x\n", i, n); + return 0; + } + + } + + + // 6 - points + + Tab[0] = 0; + Tab[1] = 0x3333U; + Tab[2] = 0x6666U; + Tab[3] = 0x9999U; + Tab[4] = 0xCCCCU; + Tab[5] = 0xFFFFU; + + cmsCalcL16Params(6, &p); + + for (i=0; i <= 0xffffL; i++) + { + n = cmsLinearInterpLUT16((WORD) i, Tab, &p); + if (n != i) { + printf("Error in Linear interpolation (6p): Must be i=%x, But is n=%x\n", i, n); + return 0; + } + + } + + + // 18 points + + for (i=0; i < 18; i++) + Tab[i] = (WORD) (0x0f0fU*i); + + cmsCalcL16Params(18, &p); + + for (i=0; i <= 0xffffL; i++) + { + n = cmsLinearInterpLUT16((WORD) i, Tab, &p); + if (n != i) { + printf("Error in Linear interpolation (18p): Must be i=%x, But is n=%x\n", i, n); + return 0; + } + } + } + + + + printf("pass. (%d tics)\n", (int) (clock() - time)); + + // Now test descending tables + printf("Testing descending tables (linear interpolation)..."); + + // 2 points - exact + + Tab[1] = 0; + Tab[0] = 0xffffU; + + cmsCalcL16Params(2, &p); + + for (i=0xffffL; i > 0; --i) + { + n = cmsLinearInterpLUT16((WORD) i, Tab, &p); + if ((0xffffL - n) != i) { + + printf("Error in Linear interpolation (descending) (2p): Must be i=%x, But is n=%x\n", i, 0xffff - n); + return 0; + } + } + + + // 3 points - Here the error must be <= 1, since + // 2 = (3 - 1) is not a factor of 0xffff + + Tab[2] = 0; + Tab[1] = 0x7FFF; + Tab[0] = 0xffffU; + + cmsCalcL16Params(3, &p); + + for (i=0xffffL; i > 0; --i) + { + n = cmsLinearInterpLUT16((WORD) i, Tab, &p); + if (abs((0xffffL - n) - i) > 1) { + + printf("Error in Linear interpolation (descending) (3p): Must be i=%x, But is n=%x\n", i, n); + return 0; + } + } + + + // 4 points - exact + + Tab[3] = 0; + Tab[2] = 0x5555U; + Tab[1] = 0xAAAAU; + Tab[0] = 0xffffU; + + cmsCalcL16Params(4, &p); + + for (i=0xffffL; i > 0; --i) + { + n = cmsLinearInterpLUT16((WORD) i, Tab, &p); + if ((0xffffL - n) != i) { + + printf("Error in Linear interpolation (descending) (4p): Must be i=%x, But is n=%x\n", i, n); + return 0; + } + } + + + // 6 - points + + Tab[5] = 0; + Tab[4] = 0x3333U; + Tab[3] = 0x6666U; + Tab[2] = 0x9999U; + Tab[1] = 0xCCCCU; + Tab[0] = 0xFFFFU; + + cmsCalcL16Params(6, &p); + + for (i=0xffffL; i > 0; --i) + { + n = cmsLinearInterpLUT16((WORD) i, Tab, &p); + if ((0xffffL - n) != i) { + printf("Error in Linear interpolation (descending) (6p): Must be i=%x, But is n=%x\n", i, n); + return 0; + } + + } + + + // 18 points + + for (i=0; i < 18; i++) + Tab[17-i] = (WORD) (0x0f0fU*i); + + cmsCalcL16Params(18, &p); + + for (i=0xffffL; i > 0; --i) + { + n = cmsLinearInterpLUT16((WORD) i, Tab, &p); + if ((0xffffL - n) != i) { + + printf("Error in Linear interpolation (descending) (18p): Must be i=%x, But is n=%x\n", i, n); + return 0; + } + } + + printf("pass.\n"); + + if (!lExhaustive) return 1; + + printf("Now, testing interpolation errors for tables of n elements ...\n"); + + for (j=10; j < 4096; j ++) + { + if ((j % 10) == 0) printf("%d\r", j); + + for (i=0; i <= j; i++) + { + Tab[i] = (WORD) floor((((double) i / ((double) j-1)) * 65535.0) + .5); + } + + k =0; + cmsCalcL16Params(j, &p); + for (i=0; i <= 0xffffL; i++) + { + n = cmsLinearInterpLUT16((WORD) i, Tab, &p); + if (n != i) k++; + + } + + } + printf("\n%d: %d errors\n\n", j, k); + return 1; +} + + + +static +int IsGood(const char *frm, WORD in, WORD out) +{ + + // 1 for rounding + if ((abs(in - out) > 1)) { + + printf("error %s %x - %x\n", frm, in, out); + return 0; + } + + return 1; +} + +static +LCMSBOOL TestReverseLinearInterpolation(void) +{ + WORD Tab[20]; + L16PARAMS p; + int i, n, v; + + printf("Testing reverse linear interpolation\n"); + + + cmsCalcL16Params(16, &p); + + for (i=0; i < 16; i++) Tab[i] = (WORD) i * 0x1111; + + printf("\ton normal monotonic curve..."); + for (i=0; i < 16; i++) + { + v = (i * 0x1111); + n = cmsReverseLinearInterpLUT16((WORD) v, Tab, &p); + if (!IsGood("unexpected result", (WORD) v, (WORD) n)) + return FALSE; + } + printf("pass.\n"); + + + Tab[0] = 0; + Tab[1] = 0; + Tab[2] = 0; + Tab[3] = 0; + Tab[4] = 0; + Tab[5] = 0x5555; + Tab[6] = 0x6666; + Tab[7] = 0x7777; + Tab[8] = 0x8888; + Tab[9] = 0x9999; + Tab[10]= 0xffff; + Tab[11]= 0xffff; + Tab[12]= 0xffff; + Tab[13]= 0xffff; + Tab[14]= 0xffff; + Tab[15]= 0xffff; + + + printf("\ton degenerated curve ..."); + + for (i=0; i < 16; i++) + { + v = (i * 0x1111); + n = cmsReverseLinearInterpLUT16((WORD) v, Tab, &p); + + if (i > 5 && i <= 9) { + + if (!IsGood("unexpected result", (WORD) v, (WORD) n)) + return FALSE; + } + } + + printf("pass.\n"); + + return TRUE; +} + + + + +// 3D LUT test + +static +int Test3D(void) +{ + LPLUT MyLut; + LPWORD Table; + WORD In[3], Out[3]; + int r, g, b, i; + double *SampleTablePtr, SampleTable[] = { //R G B + + 0, 0, 0, // B=0,G=0,R=0 + 0, 0, .25, // B=1,G=0,R=0 + + 0, .5, 0, // B=0,G=1,R=0 + 0, .5, .25, // B=1,G=1,R=0 + + 1, 0, 0, // B=0,G=0,R=1 + 1, 0, .25, // B=1,G=0,R=1 + + 1, .5, 0, // B=0,G=1,R=1 + 1, .5, .25 // B=1,G=1,R=1 + + }; + + + printf("Testing 3D interpolation on LUT..."); + + // 1.- Allocate an empty LUT + + MyLut = cmsAllocLUT(); + + // 2.- In this LUT, allocate a 3D grid of 2 points, from 3 components (RGB) + // to 3 components. First 3 is input dimension, last 3 is output one. + // 2 is number of grid points. + + MyLut = cmsAlloc3DGrid(MyLut, 2, 3, 3); + + // 3.- Fill the LUT table with values. + + Table = MyLut -> T; + + SampleTablePtr = SampleTable; + + for (i= 0; i < 3; i++) + for (r = 0; r < 2; r++) + for (g = 0; g < 2; g++) + for (b = 0; b < 2; b++) { + + WORD a = (WORD) floor(*SampleTablePtr++ * 65535. + .5); + + *Table++ = a; + } + + + // The sample table gives + // + // r = input, + // g = input divided by 2 + // b = input divided by 4 + // + // So, I should obtain on output r, g/2, g/4 + + + for (i=0; i < 0xffff; i++) { + + In[0] = In[1] = In[2] = (WORD) i; + + cmsEvalLUT(MyLut, In, Out); + + + + // Check results, I will tolerate error <= 1 for rounding + + + + if (!IsGood("Channel 1", Out[0], In[0])) return 0; + if (!IsGood("Channel 2", Out[1], (WORD) ((double) In[1] / 2))) return 0; + if (!IsGood("Channel 3", Out[2], (WORD) ((double) In[2] / 4))) return 0; + + } + + + + // Last, remember free stuff + + cmsFreeLUT(MyLut); + + printf("pass.\n"); + return 1; +} + + + +static +void PrintMatrix(LPMAT3 lpM) +{ + int i, j; + + for (i=0; i < 3; i++) { + printf ("[ "); + for (j=0; j < 3; j++) + { + printf("%1.6f ", (*lpM).v[i].n[j]); + } + printf("]\n"); + } + + printf("\n"); + +} + + +static +LCMSBOOL CmpMatrix(LPMAT3 lpM1, LPMAT3 lpM2, double tolerance) +{ + int i, j; + + for (i=0; i < 3; i++) { + for (j=0; j < 3; j++) { + if (fabs(lpM1 -> v[i].n[j] - lpM2 -> v[i].n[j]) > tolerance) + return FALSE; + } + + } + + return TRUE; + +} + + +static +LCMSBOOL TestMatrixCreation(void) +{ + MAT3 Mat; + int rc; + + cmsCIExyY WhitePt = {0.3127, 0.3290, 1.0}; + cmsCIExyYTRIPLE Primaries = { + {0.6400, 0.3300, 1.0}, + {0.3000, 0.6000, 1.0}, + {0.1500, 0.0600, 1.0} + }; + MAT3 sRGB = {{ + {{ 0.436066, 0.385147, 0.143066 }}, + {{ 0.222488, 0.716873, 0.060608 }}, + {{ 0.013916, 0.097076, 0.714096 }} + }}; + + + printf("Testing virtual profiles (Emulating sRGB)..."); + + rc = cmsBuildRGB2XYZtransferMatrix(&Mat, + &WhitePt, + &Primaries); + cmsAdaptMatrixToD50(&Mat, &WhitePt); + + if (rc < 0) + { + printf("TestMatrixCreation failed, rc = %d\n", rc); + return FALSE; + } + + + if (!CmpMatrix(&Mat, &sRGB, 0.001)) { + printf("FAILED!\n"); + printf("sRGB final matrix is:\n"); + PrintMatrix(&sRGB); + printf("\nlcms calculated matrix is:\n"); + PrintMatrix(&Mat); + return FALSE; + } + + printf("pass.\n"); + return TRUE; + + +} + + +/* + + Used for debug purposes +*/ + +#if 0 +static +void AdaptationMatrixTest(void) +{ + cmsCIExyY D65 = {0.3127, 0.329001, 1.0}; // D65 + MAT3 sRGB, TosRGB; + + + VEC3init(&sRGB.v[0], 0.4124, 0.3576, 0.1805); + VEC3init(&sRGB.v[1], 0.2126, 0.7152, 0.0722); + VEC3init(&sRGB.v[2], 0.0193, 0.1192, 0.9505); + + cmsAdaptMatrixToD50(&sRGB, &D65); + printf("Adaptation matrix D65 -> D50 (to PCS)\n"); + PrintMatrix(&sRGB); + + MAT3inverse(&sRGB, &TosRGB); + printf("inverse\n"); + PrintMatrix(&TosRGB); + + cmsAdaptMatrixFromD50(&TosRGB, &D65); + printf("adaptated to D65\n"); + PrintMatrix(&TosRGB); +} +#endif +// #endif + + + +static +double VecDist(Scanline_rgb2 *bin, Scanline_rgb2 *bout) +{ + double rdist, gdist, bdist; + + rdist = fabs(bout -> r - bin -> r); + gdist = fabs(bout -> g - bin -> g); + bdist = fabs(bout -> b - bin -> b); + + return (sqrt((rdist*rdist + gdist*gdist + bdist*bdist))); +} + + + + + + +// Perform sampling in the full spectrum & acotate error. +// I choose red for the lowest incidence in eye. +// Green is most lightful, eye is most accurate on blue. + +static +int TestFullSpectrum(cmsHTRANSFORM xform, int nRedInterv, int MaxErr) +{ + int r, g, b; + double err; + Scanline_rgb2 *bin, *bout; + STATS Stats; + clock_t t; + + + bin = (Scanline_rgb2 *) _cmsMalloc(256*sizeof(Scanline_rgb2)); + bout = (Scanline_rgb2 *) _cmsMalloc(256*sizeof(Scanline_rgb2)); + + + ClearStats(&Stats); + + Stats.x = 0.0; Stats.n = 0.0; // GCC BUG HERE!!!! + + t = clock(); + + for (r=0; r < 256; r+= nRedInterv) + { + // printf("\r%02x:", r); + + Dot(); + for (g=0; g < 256; g++) + { + + for (b=0; b < 256; b++) + { + bin[b].r = (WORD) r << 8; // For L 0nly to 0xFF00 + bin[b].g = RGB_8_TO_16(g); + bin[b].b = RGB_8_TO_16(b); + bin[b].a = 0; + } + + cmsDoTransform(xform, bin, bout, 256); + + // I'm using b as index + + for (b=0; b < 256; b ++) + { + // I measure the error using vector distance + + err = VecDist(bin+b, bout+b); + Stats.x += (double) err; + Stats.x2 += (double) err * err; + Stats.n += 1.0; + if (err > Stats.Peak) + Stats.Peak = err; + + + if (err > MaxErr) + { + printf("Coarse error! : In=(%x,%x,%x) Out=(%x,%x,%x)\n", + bin[b].r, bin[b].g, bin[b].b, + bout[b].r, bout[b].g, bout[b].b); + _cmsFree(bin); + _cmsFree(bout); + return 0; + } + } + + } + + } + + + PrintStatistics(t, &Stats); + _cmsFree(bin); + _cmsFree(bout); + + return 1; +} + + + + +static +int TestInducedError(DWORD Type) +{ + cmsHPROFILE In, Out; + cmsHTRANSFORM xform; + int nMaxError; + + In = cmsCreateLabProfile(NULL); + Out = cmsCreateLabProfile(NULL); + + printf("Error Induced by the CMM due to roundoff (dE) "); + + xform = cmsCreateTransform(In, Type, + Out, Type, + INTENT_RELATIVE_COLORIMETRIC, 0); + + + nMaxError = TestFullSpectrum(xform, 31, 0x800); + + printf("\n"); + + cmsDeleteTransform(xform); + cmsCloseProfile(In); + cmsCloseProfile(Out); + + return nMaxError; +} + + +static +double ConvertL(WORD v) +{ + int fix32; + + fix32 = v; + return (double)fix32/652.800; /* 0xff00/100.0 */ +} + + +static +double Convertab(WORD v) +{ + int fix32; + + + fix32 = v; + + return ((double)fix32/256.0)-128.0; +} + + +#define BASE 255 + +static +int CompareTransforms(cmsHTRANSFORM xform1, cmsHTRANSFORM xform2, + int nRedInterv, int lWithStats, LCMSBOOL lIsLab) +{ + int r, g, b; + double err; + Scanline_rgb2 *bin, *bout1, *bout2; + STATS Stats; + int OutOfGamut = 0; + + + bin = (Scanline_rgb2 *) _cmsMalloc(256*sizeof(Scanline_rgb2)); + bout1 = (Scanline_rgb2 *) _cmsMalloc(256*sizeof(Scanline_rgb2)); + bout2 = (Scanline_rgb2 *) _cmsMalloc(256*sizeof(Scanline_rgb2)); + + + ClearStats(&Stats); + Stats.x = 0.0; Stats.n = 0.0; // GCC BUG HERE!!!! + + + for (r=0; r <= BASE; r+= nRedInterv) + { + // printf("\r%02x:", r); + + Dot(); + for (g=0; g <= BASE; g++) + { + // I will test random LSB + + for (b=0; b <= BASE; b++) // 256 + { + + bin[b].r = RGB_8_TO_16(r); + bin[b].g = RGB_8_TO_16(g); + bin[b].b = RGB_8_TO_16(b); + bin[b].a = 0; + } + + cmsDoTransform(xform1, bin, bout1, 256); + cmsDoTransform(xform2, bin, bout2, 256); + + // I'm using b as index + + for (b=0; b <= BASE; b ++) { + + // I measure the error using vector distance + // Only if encodable values + + if (bout1[b].r != 0xffff && bout1[b].g != 0xffff && bout1[b].b != 0xffff) + { + + err = VecDist(bout1+b, bout2+b); + + + if (err > 0x1000L) + { + + if (lIsLab) { + printf("Coarse error: In=(%x,%x,%x) Out1=(%g,%g,%g) Out2=(%g,%g,%g)\n", + bin[b].r, bin[b].g, bin[b].b, + ConvertL(bout1[b].r), Convertab(bout1[b].g), Convertab(bout1[b].b), + ConvertL(bout2[b].r), Convertab(bout2[b].g), Convertab(bout2[b].b)); + } + else + { + printf("Coarse error: In=(%x,%x,%x) Out1=(%x,%x,%x) Out2=(%x,%x,%x)\n", + bin[b].r, bin[b].g, bin[b].b, + bout1[b].r, bout1[b].g, bout1[b].b, + bout2[b].r, bout2[b].g, bout2[b].b); + } + return 0; + + } + + else + { + Stats.x += (double) err; + Stats.x2 += (double) err * err; + Stats.n += 1.0; + if (err > Stats.Peak) + Stats.Peak = err; + } + } else + OutOfGamut++; + } + + } + + } + + + if (lWithStats) { + + PrintStatistics(0, &Stats); + printf(" pass.\n"); + } + + if (OutOfGamut > 0) + printf("Out of encodeable representation=%d\n\n", OutOfGamut); + + + _cmsFree(bin); + _cmsFree(bout1); + _cmsFree(bout2); + + return 1; +} + + + +static +LCMSBOOL CheckXYZ(LPcmsCIEXYZ Check, double X, double Y, double Z) +{ + return ((fabs(Check->X - X) < 0.001) && + (fabs(Check->Y - Y) < 0.001) && + (fabs(Check->Z - Z) < 0.001)); +} + + +static +LPGAMMATABLE Build_sRGBGamma(void) +{ + double Parameters[5]; + + Parameters[0] = 2.4; + Parameters[1] = 1. / 1.055; + Parameters[2] = 0.055 / 1.055; + Parameters[3] = 1. / 12.92; + Parameters[4] = 0.04045; // d + + return cmsBuildParametricGamma(1024, 4, Parameters); +} + +static +LCMSBOOL Check_sRGBGamma(LPGAMMATABLE Shape) +{ + LPGAMMATABLE sRGB = Build_sRGBGamma(); + int i; + + if (Shape ->nEntries != 1024) { + printf("because wrong sizes (%d != 1024), ", Shape -> nEntries); + return 0; + } + + + for (i=0; i < Shape -> nEntries; i++) { + double nErr = Shape ->GammaTable[i] - sRGB ->GammaTable[i]; + + if (fabs(nErr) > 1.0) { + int j; + printf("because %x != %x on index %d\n", Shape ->GammaTable[i], sRGB ->GammaTable[i], i); + printf("table dump follows:\n"); + for (j=0; j < 10; j++) + printf("%d) %X\n", j, Shape ->GammaTable[j]); + printf("\nso, "); + + return 0; + } + } + + cmsFreeGamma(sRGB); + return 1; +} + + +static +int GetInfoTest(void) +{ + cmsHPROFILE hProfile; + cmsCIEXYZ WhitePoint; + cmsCIEXYZTRIPLE Primaries; + const char* Product; + LPGAMMATABLE Shapes[3]; + + + printf("Testing profile decoding (sRGB)"); + hProfile = cmsOpenProfileFromFile("sRGB Color Space Profile.icm", "rb"); + cmsTakeMediaWhitePoint(&WhitePoint, hProfile); + + Dot(); + if (!CheckXYZ(&WhitePoint, 0.95045, 1.0, 1.08905)) { + printf("White point read failed!\n"); + return 0; + } + + Dot(); + cmsTakeColorants(&Primaries, hProfile); + + if (!CheckXYZ(&Primaries.Red, 0.43607, 0.22249, 0.01392)) { + printf("Red colorant failed!\n"); + return 0; + } + + if (!CheckXYZ(&Primaries.Green, 0.38515,0.71617, 0.09708)) { + printf("Green colorant failed!\n"); + return 0; + } + + if (!CheckXYZ(&Primaries.Blue, 0.14307, 0.06061, 0.71410)) { + printf("Blue colorant failed!\n"); + return 0; + } + + Dot(); + Product = cmsTakeProductName(hProfile); + if (strcmp(Product, "IEC 61966-2.1 Default RGB colour space - sRGB") != 0) { + printf("Product name mismatch!\n"); + } + + Dot(); + Shapes[0] = cmsReadICCGamma(hProfile, icSigRedTRCTag); + Shapes[1] = cmsReadICCGamma(hProfile, icSigGreenTRCTag); + Shapes[2] = cmsReadICCGamma(hProfile, icSigBlueTRCTag); + + if (!Check_sRGBGamma(Shapes[0]) || + !Check_sRGBGamma(Shapes[1]) || + !Check_sRGBGamma(Shapes[2])) { + printf("Gamma curves mismatch!\n"); + return 0; + } + + + cmsFreeGammaTriple(Shapes); + + + Dot(); + cmsCloseProfile(hProfile); + printf("pass.\n"); + return 1; + +} +static +int Test_sRGB(void) +{ + cmsHPROFILE In1, In2, Out1, Out2; + cmsHTRANSFORM xform1, xform2; + int nMaxErr; + + printf("Testing sRGB built-in space"); + + In1 = cmsOpenProfileFromFile("sRGB Color Space Profile.icm", "rb"); + Out1 = cmsCreateXYZProfile(); + + In2 = cmsCreate_sRGBProfile(); + Out2 = cmsCreateXYZProfile(); + + xform1 = cmsCreateTransform(In1, TYPE_RGBA_16, Out1, TYPE_XYZA_16, 0, cmsFLAGS_NOTPRECALC); + xform2 = cmsCreateTransform(In2, TYPE_RGBA_16, Out2, TYPE_XYZA_16, 0, cmsFLAGS_NOTPRECALC); + + nMaxErr = CompareTransforms(xform1, xform2, 31, TRUE, FALSE); + + cmsDeleteTransform(xform1); + cmsCloseProfile(In1); + cmsCloseProfile(Out1); + + cmsDeleteTransform(xform2); + cmsCloseProfile(In2); + cmsCloseProfile(Out2); + + return nMaxErr; + +} + +static +int RealProfilesTest(void) +{ + cmsHPROFILE In1, In2, Out1, Out2; + cmsHTRANSFORM xform1, xform2; + int nMaxErr; + + printf("Using two real profiles"); + + // sRGB is a simpler, public domain XYZ PCS profile + // sRGBSpac comes with Win95 Platform SDK, in the public domain. + // (not latest revisions) + + // Using LAB identity as output profile, I'm forcing an + // implicit XYZ => L*a*b conversion in xform1. + // xform2 is 8 bits - LUT based, and PCS is L*a*b + + In1 = cmsOpenProfileFromFile("sRGB Color Space Profile.icm", "rb"); + Out1 = cmsCreateXYZProfile(); + + In2 = cmsOpenProfileFromFile("sRGBSpac.icm", "rb"); + Out2 = cmsCreateXYZProfile(); + + + // Since LUT is 8-bits width, + xform1 = cmsCreateTransform(In1, TYPE_RGBA_16, Out1, TYPE_XYZA_16, 0, cmsFLAGS_NOTPRECALC|cmsFLAGS_MATRIXINPUT); + xform2 = cmsCreateTransform(In2, TYPE_RGBA_16, Out2, TYPE_XYZA_16, 0, cmsFLAGS_NOTPRECALC); + + nMaxErr = CompareTransforms(xform1, xform2, 31, FALSE, FALSE); + + printf("pass\n"); + + cmsDeleteTransform(xform1); + cmsCloseProfile(In1); + cmsCloseProfile(Out1); + + cmsDeleteTransform(xform2); + cmsCloseProfile(In2); + cmsCloseProfile(Out2); + + return nMaxErr; +} + + + +// --------------------------------------------------------- + + +static +int TestPreview(void) +{ + cmsHPROFILE In, Out, Proof; + cmsHTRANSFORM xform; + int nMaxErr; + + printf("Testing preview"); + + In = cmsCreateLabProfile(NULL); + Out = cmsCreateLabProfile(NULL); + Proof = cmsCreateLabProfile(NULL); + + xform = cmsCreateProofingTransform(In, TYPE_LABA_16, Out, TYPE_LABA_16, Proof, 0, 0, cmsFLAGS_SOFTPROOFING); + + nMaxErr = TestFullSpectrum(xform, 31, 0x1000L); + + cmsDeleteTransform(xform); + cmsCloseProfile(In); + cmsCloseProfile(Out); + cmsCloseProfile(Proof); + printf("\n"); + + return nMaxErr; +} + + +// Check induced error on multiprofile transforms + +static +int TestMultiprofile(void) +{ + + cmsHPROFILE hsRGB, hXYZ, hLab; + cmsHTRANSFORM hXForm; + cmsHPROFILE Profiles[10]; + int nMaxErr; + + hsRGB = cmsCreate_sRGBProfile(); + hLab = cmsCreateLabProfile(NULL); + hXYZ = cmsCreateXYZProfile(); + + Profiles[0] = hsRGB; + Profiles[1] = hLab; + Profiles[2] = hsRGB; + Profiles[3] = hsRGB; + + Profiles[4] = hLab; + Profiles[5] = hXYZ; + Profiles[6] = hsRGB; + + hXForm = cmsCreateMultiprofileTransform(Profiles, 7, TYPE_RGBA_16, TYPE_RGBA_16, INTENT_RELATIVE_COLORIMETRIC, cmsFLAGS_HIGHRESPRECALC); + + printf("Testing multiprofile transforms (6 profiles)"); + + nMaxErr = TestFullSpectrum(hXForm, 31, 0x1000L); + + cmsDeleteTransform(hXForm); + cmsCloseProfile(hsRGB); + cmsCloseProfile(hXYZ); + cmsCloseProfile(hLab); + + printf("\n"); + + return nMaxErr; +} + +// Check linearization and other goodies + +static +int TestLinearizationDevicelink() +{ + LPGAMMATABLE Transfer[3]; + cmsHPROFILE hLin1, hLin2; + cmsHTRANSFORM hXForm; + cmsHPROFILE Profiles[10]; + int nMaxErr; + + printf("Testing linearization devicelink"); + + Transfer[0] = cmsBuildGamma(256, 1./2.2); + Transfer[1] = cmsBuildGamma(256, 1./2.2); + Transfer[2] = cmsBuildGamma(256, 1./2.2); + + hLin1 = cmsCreateLinearizationDeviceLink(icSigRgbData, Transfer); + + cmsFreeGammaTriple(Transfer); + + + + Transfer[0] = cmsBuildGamma(256, 2.2); + Transfer[1] = cmsBuildGamma(256, 2.2); + Transfer[2] = cmsBuildGamma(256, 2.2); + + hLin2 = cmsCreateLinearizationDeviceLink(icSigRgbData, Transfer); + + cmsFreeGammaTriple(Transfer); + + Profiles[0] = hLin1; + Profiles[1] = hLin2; + + hXForm = cmsCreateMultiprofileTransform(Profiles, 2, TYPE_RGBA_16, TYPE_RGBA_16, INTENT_RELATIVE_COLORIMETRIC, cmsFLAGS_HIGHRESPRECALC); + if (!hXForm) { + + printf("Error!\n"); + return 1; + } + + + nMaxErr = TestFullSpectrum(hXForm, 31, 0x1000L); + + cmsDeleteTransform(hXForm); + cmsCloseProfile(hLin1); + cmsCloseProfile(hLin2); + + printf("\n"); + + return nMaxErr; +} + + +static +int TestLinearizationDevicelink2() +{ + LPGAMMATABLE Transfer[3]; + cmsHPROFILE hLin1; + cmsHTRANSFORM hXForm; + int nMaxErr; + + printf("Testing saved linearization devicelink"); + + Transfer[0] = cmsBuildGamma(256, 1); + Transfer[1] = cmsBuildGamma(256, 1); + Transfer[2] = cmsBuildGamma(256, 1); + + hLin1 = cmsCreateLinearizationDeviceLink(icSigRgbData, Transfer); + + _cmsSaveProfile(hLin1, "lin1.icc"); + cmsFreeGammaTriple(Transfer); + cmsCloseProfile(hLin1); + + hLin1 = cmsOpenProfileFromFile("lin1.icc", "r"); + + hXForm = cmsCreateTransform(hLin1, TYPE_RGBA_16, NULL, TYPE_RGBA_16, INTENT_ABSOLUTE_COLORIMETRIC, 0); + + if (!hXForm) { + + printf("Error!\n"); + return 1; + } + + nMaxErr = TestFullSpectrum(hXForm, 31, 1); + + cmsDeleteTransform(hXForm); + cmsCloseProfile(hLin1); + unlink("lin1.icc"); + + printf("\n"); + + return nMaxErr; +} + + +static +int TestDeviceLinkGeneration() +{ + cmsHTRANSFORM hXForm, hIdentity; + cmsHPROFILE hDevLink, hsRGB; + int nMaxErr; + + + printf("Testing devicelink generation"); + + hsRGB = cmsOpenProfileFromFile("sRGB Color Space Profile.icm", "r"); + hIdentity = cmsCreateTransform(hsRGB, TYPE_RGBA_16, hsRGB, TYPE_RGBA_16, INTENT_RELATIVE_COLORIMETRIC, 0); + hDevLink = cmsTransform2DeviceLink(hIdentity, 0); + _cmsSaveProfile(hDevLink, "devicelink.icm"); + + cmsCloseProfile(hDevLink); + cmsCloseProfile(hsRGB); + cmsDeleteTransform(hIdentity); + + + hDevLink = cmsOpenProfileFromFile("devicelink.icm", "r"); + hXForm = cmsCreateTransform(hDevLink, TYPE_RGBA_16, NULL, TYPE_RGBA_16, INTENT_RELATIVE_COLORIMETRIC, 0); + nMaxErr = TestFullSpectrum(hXForm, 31, 0x1000L); + + cmsDeleteTransform(hXForm); + cmsCloseProfile(hDevLink); + + printf("\n"); + unlink("devicelink.icm"); + + return nMaxErr; +} + +static +int TestInkLimiting() +{ + cmsHPROFILE hIL; + cmsHTRANSFORM hXForm; + BYTE In[4], Out[4]; + int i, j, k, l, res; + + + + printf("Testing ink limiting "); + + hIL = cmsCreateInkLimitingDeviceLink(icSigCmykData, 100); + + + hXForm = cmsCreateTransform(hIL, TYPE_CMYK_8, NULL, TYPE_CMYK_8, INTENT_RELATIVE_COLORIMETRIC, 0); + if (!hXForm) { + + printf("Error!\n"); + return 0; + } + + for (l=0; l < 255; l += 8) { + Dot(); + for (k=0; k < 255; k += 8) + for (j=0; j < 255; j += 8) + for (i=0; i < 255; i += 8) { + + In[0] = (BYTE) i; In[1] = (BYTE) j; In[2] = (BYTE) k; In[3] = (BYTE) l; + + cmsDoTransform(hXForm, In, Out, 1); + + res = Out[0] + Out[1] + Out[2] + Out[3]; + + if (res > 0x100) { + + printf("Failed! (%d) \n", res); + return 0; + } + } + } + + cmsDeleteTransform(hXForm); + cmsCloseProfile(hIL); + printf(" pass.\n"); + + return 1; +} + + + +static +void CheckPlanar(void) +{ + cmsHTRANSFORM xform; + cmsHPROFILE hsRGB; + int i; + BYTE Out[12]; + BYTE Bmp[] = { 0x00, 0x10, 0x20, 0x30, // R Plane + 0x00, 0x10, 0x20, 0x30, // G Plane + 0x00, 0x10, 0x20, 0x30 }; // B Plane + + + + hsRGB = cmsCreate_sRGBProfile(); + xform = cmsCreateTransform(hsRGB, TYPE_RGB_8_PLANAR, + hsRGB, TYPE_RGB_8_PLANAR, + INTENT_PERCEPTUAL, cmsFLAGS_NOTPRECALC); + + cmsDoTransform(xform, Bmp, Out, 4); + + for (i=0; i < 12; i += 3) { + printf("RGB=(%x, %x, %x)\n", Out[i+0], Out[i+1], Out[i+2]); + } + + cmsDeleteTransform(xform); + cmsCloseProfile(hsRGB); +} + +#ifdef ICM_COMPARATIVE +#ifndef NON_WINDOWS + +static +void CompareWithICM_16bit(void) +{ + + HTRANSFORM hICMxform; + HPROFILE hICMProfileFrom, hICMProfileTo; + LOGCOLORSPACE LogColorSpace; + COLOR In, Out; + COLOR *InBlk, *OutBlk, *InPtr; + size_t size; + int r, g, b; + PROFILE Profile; + clock_t atime; + double seconds, diff; + cmsHPROFILE hlcmsProfileIn, hlcmsProfileOut; + cmsHTRANSFORM hlcmsxform; + + + printf("\n\nComparative with MS-Windows ICM (16 bits per sample):\n"); + + + Profile.dwType = PROFILE_FILENAME; + Profile.pProfileData = "sRGBSpac.icm"; + Profile.cbDataSize = strlen("sRGBSpac.icm"); + + hICMProfileFrom = OpenColorProfile(&Profile, PROFILE_READ, FILE_SHARE_READ, OPEN_EXISTING); + + Profile.pProfileData = "sRGBSpac.icm"; + Profile.cbDataSize = strlen("sRGBSpac.icm"); + hICMProfileTo = OpenColorProfile(&Profile, PROFILE_READ, FILE_SHARE_READ, OPEN_EXISTING); + + ZeroMemory(&LogColorSpace, sizeof(LOGCOLORSPACE)); + + LogColorSpace.lcsSignature = LCS_SIGNATURE; + LogColorSpace.lcsVersion = 0x400; + LogColorSpace.lcsCSType = LCS_CALIBRATED_RGB; + strcpy(LogColorSpace.lcsFilename, "sRGBSpac.icm"); + + hICMxform = CreateColorTransform(&LogColorSpace, hICMProfileTo, NULL, BEST_MODE); + + + + size = 256 * 256 * 256; + InBlk = _cmsMalloc((size_t) size * sizeof(COLOR)); + OutBlk = _cmsMalloc((size_t) size * sizeof(COLOR)); + + if (InBlk == NULL || OutBlk == NULL) { + printf("Out of memory\n"); exit(2); + } + + printf("Windows ICM is transforming full spectrum..."); + + InPtr = InBlk; + for (r=0; r < 255; r++) + for (g=0; g < 255; g++) + for (b=0; b < 255; b++) { + + InPtr->rgb.red = (r << 8) | r; + InPtr->rgb.green = (g << 8) | g; + InPtr->rgb.blue = (b << 8) | b; + + InPtr++; + } + + atime = clock(); + + TranslateColors( hICMxform, InBlk, size, COLOR_RGB, OutBlk, COLOR_RGB); + + diff = clock() - atime; + seconds = (double) diff / CLOCKS_PER_SEC; + + + printf("done. [%d tics, %g sec.]\n", (int) diff, seconds); + + CloseColorProfile(hICMProfileFrom); + CloseColorProfile(hICMProfileTo); + DeleteColorTransform(hICMxform); + + hlcmsProfileIn = cmsOpenProfileFromFile("sRGBSpac.icm", "r"); + hlcmsProfileOut = cmsOpenProfileFromFile("sRGBSpac.icm", "r"); + + hlcmsxform = cmsCreateTransform(hlcmsProfileIn, TYPE_RGB_16, hlcmsProfileOut, TYPE_RGB_16, INTENT_PERCEPTUAL, 0); + + printf("lcms is transforming full spectrum..."); + + atime = clock(); + + cmsDoTransform(hlcmsxform, InBlk, OutBlk, size); + + diff = clock() - atime; + seconds = (double) diff / CLOCKS_PER_SEC; + + printf("done. [%d tics, %g sec.]\n", (int) diff, seconds); + + cmsDeleteTransform(hlcmsxform); + cmsCloseProfile(hlcmsProfileIn); + cmsCloseProfile(hlcmsProfileOut); + + _cmsFree(InBlk); + _cmsFree(OutBlk); +} + +static +void CompareWithICM_8bit(void) +{ + + HTRANSFORM hICMxform; + HPROFILE hICMProfileFrom, hICMProfileTo; + LOGCOLORSPACE LogColorSpace; + RGBQUAD In, Out; + int r, g, b; + PROFILE Profile; + clock_t atime; + double seconds, diff; + cmsHPROFILE hlcmsProfileIn, hlcmsProfileOut; + cmsHTRANSFORM hlcmsxform; + + + printf("\n\nComparative with MS-Windows ICM (8 bits per sample):\n"); + + + Profile.dwType = PROFILE_FILENAME; + Profile.pProfileData = "sRGBSpac.icm"; + Profile.cbDataSize = strlen("sRGBSpac.icm"); + + hICMProfileFrom = OpenColorProfile(&Profile, PROFILE_READ, FILE_SHARE_READ, OPEN_EXISTING); + + Profile.pProfileData = "sRGBSpac.icm"; + Profile.cbDataSize = strlen("sRGBSpac.icm"); + hICMProfileTo = OpenColorProfile(&Profile, PROFILE_READ, FILE_SHARE_READ, OPEN_EXISTING); + + ZeroMemory(&LogColorSpace, sizeof(LOGCOLORSPACE)); + + LogColorSpace.lcsSignature = LCS_SIGNATURE; + LogColorSpace.lcsVersion = 0x400; + LogColorSpace.lcsCSType = LCS_CALIBRATED_RGB; + strcpy(LogColorSpace.lcsFilename, "sRGBSpac.icm"); + + hICMxform = CreateColorTransform(&LogColorSpace, hICMProfileTo, NULL, BEST_MODE); + + printf("Windows ICM is transforming full spectrum..."); + + atime = clock(); + + for (r=0; r < 255; r++) + for (g=0; g < 255; g++) + for (b=0; b < 255; b++) { + + In.rgbRed = r; + In.rgbGreen = g; + In.rgbBlue = b; + + if (!TranslateBitmapBits(hICMxform, &In, BM_RGBTRIPLETS, 1, 1, 0, &Out, BM_RGBTRIPLETS, 0, NULL, 0)) + exit(2); + + } + + diff = clock() - atime; + seconds = (double) diff / CLOCKS_PER_SEC; + + + printf("done. [%d tics, %g sec.]\n", (int) diff, seconds); + + CloseColorProfile(hICMProfileFrom); + CloseColorProfile(hICMProfileTo); + DeleteColorTransform(hICMxform); + + hlcmsProfileIn = cmsOpenProfileFromFile("sRGBSpac.icm", "r"); + hlcmsProfileOut = cmsOpenProfileFromFile("sRGBSpac.icm", "r"); + + hlcmsxform = cmsCreateTransform(hlcmsProfileIn, TYPE_BGRA_8, hlcmsProfileOut, TYPE_BGRA_8, INTENT_PERCEPTUAL, 0); + + printf("lcms is transforming full spectrum..."); + + atime = clock(); + + for (r=0; r < 255; r++) + for (g=0; g < 255; g++) + for (b=0; b < 255; b++) { + + In.rgbRed = r; + In.rgbGreen = g; + In.rgbBlue = b; + + cmsDoTransform(hlcmsxform, &In, &Out, 1); + } + + diff = clock() - atime; + seconds = (double) diff / CLOCKS_PER_SEC; + + printf("done. [%d tics, %g sec.]\n", (int) diff, seconds); + + cmsDeleteTransform(hlcmsxform); + cmsCloseProfile(hlcmsProfileIn); + cmsCloseProfile(hlcmsProfileOut); + +} + + +#endif +#endif + + +#ifdef CHECK_SPEED + + + +static +void SpeedTest(void) +{ + + int r, g, b, j; + clock_t atime; + double seconds, diff; + cmsHPROFILE hlcmsProfileIn, hlcmsProfileOut; + cmsHTRANSFORM hlcmsxform; + Scanline_rgb0 *In; + size_t Mb; + + hlcmsProfileIn = cmsOpenProfileFromFile("sRGB Color Space Profile.icm", "r"); + hlcmsProfileOut = cmsOpenProfileFromFile("sRGBSpac.icm", "r"); + + hlcmsxform = cmsCreateTransform(hlcmsProfileIn, TYPE_RGB_16, hlcmsProfileOut, TYPE_RGB_16, INTENT_PERCEPTUAL, cmsFLAGS_NOTCACHE); + + Mb = 256*256*256*sizeof(Scanline_rgb0); + + In = (Scanline_rgb0*) _cmsMalloc(Mb); + + j = 0; + for (r=0; r < 256; r++) + for (g=0; g < 256; g++) + for (b=0; b < 256; b++) { + + In[j].r = (WORD) ((r << 8) | r); + In[j].g = (WORD) ((g << 8) | g); + In[j].b = (WORD) ((b << 8) | b); + + j++; + } + + + printf("lcms is transforming full spectrum..."); + + atime = clock(); + + cmsDoTransform(hlcmsxform, In, In, 256*256*256); + + diff = clock() - atime; + seconds = (double) diff / CLOCKS_PER_SEC; + _cmsFree(In); + + + printf("done.\n[%d tics, %g sec, %g Mpixel/sec.]\n", (int) diff, seconds, Mb / (1024*1024*seconds*3*2) ); + + cmsDeleteTransform(hlcmsxform); + cmsCloseProfile(hlcmsProfileIn); + cmsCloseProfile(hlcmsProfileOut); + +} + + + +static +void SpeedTest2(void) +{ + + int r, g, b, j; + clock_t atime; + double seconds, diff; + cmsHPROFILE hlcmsProfileIn, hlcmsProfileOut; + cmsHTRANSFORM hlcmsxform; + Scanline_rgb8 *In; + size_t Mb; + + + hlcmsProfileIn = cmsOpenProfileFromFile("sRGB Color Space Profile.icm", "r"); + hlcmsProfileOut = cmsOpenProfileFromFile("sRGBSpac.icm", "r"); + + hlcmsxform = cmsCreateTransform(hlcmsProfileIn, TYPE_RGB_8, hlcmsProfileOut, TYPE_RGB_8, INTENT_PERCEPTUAL, cmsFLAGS_NOTCACHE); + + Mb = 256*256*256*sizeof(Scanline_rgb8); + + In = (Scanline_rgb8*) _cmsMalloc(Mb); + + j = 0; + for (r=0; r < 256; r++) + for (g=0; g < 256; g++) + for (b=0; b < 256; b++) { + + In[j].r = (BYTE) r; + In[j].g = (BYTE) g; + In[j].b = (BYTE) b; + + j++; + } + + + printf("lcms is transforming full spectrum..."); + + atime = clock(); + + cmsDoTransform(hlcmsxform, In, In, 256*256*256); + + diff = clock() - atime; + seconds = (double) diff / CLOCKS_PER_SEC; + _cmsFree(In); + + + printf("done.\n[%d tics, %g sec, %g Mpixels/sec.]\n", (int) diff, seconds, Mb / (1024*1024*seconds*3) ); + + cmsDeleteTransform(hlcmsxform); + cmsCloseProfile(hlcmsProfileIn); + cmsCloseProfile(hlcmsProfileOut); + +} + +#endif + + +static +int TestSaveToMem(void) +{ + void *memPtr=0; + size_t bytesNeeded=0; + int rc = FALSE; + cmsHPROFILE hProfile = cmsCreate_sRGBProfile(); + + printf("Testing save to memory: "); + + // pass 1 - compute length + if (!_cmsSaveProfileToMem(hProfile, memPtr, &bytesNeeded)) { + printf("Failed!\n"); + return FALSE; + } + // pass 2 - generate profile + if(!bytesNeeded) { + printf("Failed!\n"); + return FALSE; + } + + memPtr = _cmsMalloc(bytesNeeded); + if (_cmsSaveProfileToMem(hProfile, memPtr, &bytesNeeded)) { + + + cmsHPROFILE newProfile = cmsOpenProfileFromMem(memPtr, (DWORD) bytesNeeded); + const char* s = cmsTakeProductName(newProfile); + + if (strncmp(s, "sRGB", 4) == 0) rc = TRUE; + + cmsCloseProfile(newProfile); + _cmsFree(memPtr); + + } + + cmsCloseProfile(hProfile); + + printf (rc ? "pass.\n" : "failed!\n"); + return rc; +} + + + +static +int TestNamedColor(void) +{ + LPcmsNAMEDCOLORLIST nc2; + cmsHPROFILE hProfile, hDevicelink, hsRGB, hLab; + cmsHTRANSFORM xform, rgb2lab; + int i; + + + printf("Testing Named color profiles: "); + + + hsRGB = cmsCreate_sRGBProfile(); + hLab = cmsCreateLabProfile(NULL); + + rgb2lab = cmsCreateTransform(hsRGB, TYPE_RGB_16, hLab, TYPE_Lab_16, INTENT_PERCEPTUAL, cmsFLAGS_NOTPRECALC); + + nc2 = cmsAllocNamedColorList(64); + + nc2 ->ColorantCount = 3; + strcpy(nc2 ->Prefix, "prefix"); + strcpy(nc2 ->Suffix, "suffix"); + + for (i=0; i < 64; i++) { + + WORD vv = RGB_8_TO_16((i*4)); + + nc2 ->List[i].DeviceColorant[0] = vv; + nc2 ->List[i].DeviceColorant[1] = vv; + nc2 ->List[i].DeviceColorant[2] = vv; + + cmsDoTransform(rgb2lab, nc2 ->List[i].DeviceColorant, nc2 ->List[i].PCS, 1); + + sprintf(nc2 ->List[i].Name, "Color #%d", i); + + } + + hProfile = cmsOpenProfileFromFile("named.icc", "w"); + + cmsSetDeviceClass(hProfile, icSigNamedColorClass); + cmsSetPCS(hProfile, icSigLabData); + cmsSetColorSpace(hProfile, icSigRgbData); + + cmsAddTag(hProfile, icSigNamedColor2Tag, (void*) nc2); + cmsAddTag(hProfile, icSigMediaWhitePointTag, cmsD50_XYZ()); + cmsCloseProfile(hProfile); + + cmsFreeNamedColorList(nc2); + + + hProfile = cmsOpenProfileFromFile("named.icc", "r"); + + xform = cmsCreateTransform(hProfile, TYPE_NAMED_COLOR_INDEX, NULL, TYPE_RGB_16, INTENT_PERCEPTUAL, 0); + + for (i=0; i < 64; i++) { + + WORD index; + WORD Color[3]; + + index = (WORD) i; + + cmsDoTransform(xform, &index, Color, 1); + + if (Color[0] != RGB_8_TO_16((i*4)) || + Color[1] != RGB_8_TO_16((i*4)) || + Color[2] != RGB_8_TO_16((i*4))) { + + printf(" fail on spot color #%d\n", i); + return 0; + } + } + + + cmsDeleteTransform(xform); + cmsCloseProfile(hProfile); + cmsDeleteTransform(rgb2lab); + cmsCloseProfile(hLab); + + + hProfile = cmsOpenProfileFromFile("named.icc", "r"); + + xform = cmsCreateTransform(hProfile, TYPE_NAMED_COLOR_INDEX, hsRGB, TYPE_RGB_16, INTENT_PERCEPTUAL, 0); + + hDevicelink = cmsTransform2DeviceLink(xform, 0); + + _cmsSaveProfile(hDevicelink, "named2.icc"); + cmsCloseProfile(hDevicelink); + + cmsDeleteTransform(xform); + cmsCloseProfile(hProfile); + + cmsCloseProfile(hsRGB); + + unlink("named.icc"); + unlink("named2.icc"); + + printf(" pass.\n"); + return 1; +} + + +static +int TestColorantTableTag() +{ + LPcmsNAMEDCOLORLIST nc2; + cmsHPROFILE hProfile = cmsOpenProfileFromFile("colTable.icc", "w"); + + nc2 = cmsAllocNamedColorList(3); + + strcpy(nc2 ->List[0].Name, "Red"); + strcpy(nc2 ->List[1].Name, "Green"); + strcpy(nc2 ->List[2].Name, "Blue"); + + + cmsSetDeviceClass(hProfile, icSigOutputClass); + cmsSetPCS(hProfile, icSigLabData); + cmsSetColorSpace(hProfile, icSigRgbData); + + cmsAddTag(hProfile, icSigColorantTableTag, (void*) nc2); + cmsAddTag(hProfile, icSigMediaWhitePointTag, cmsD50_XYZ()); + cmsCloseProfile(hProfile); + cmsFreeNamedColorList(nc2); + + + hProfile = cmsOpenProfileFromFile("colTable.icc", "r"); + + nc2 = cmsReadColorantTable(hProfile, icSigColorantTableTag); + + cmsFreeNamedColorList(nc2); + cmsCloseProfile(hProfile); + + unlink("colTable.icc"); + + return 1; + +} + +// New to 1.13 -- CGATS/IT8.7 + + +#define NPOINTS_IT8 10 // (17*17*17*17) + +static +int TestIT8(void) +{ + LCMSHANDLE it8; + int i; + + printf("Testing CGATS parser: "); + + it8 = cmsIT8Alloc(); + + cmsIT8SetSheetType(it8, "LCMS/TESTING"); + cmsIT8SetPropertyStr(it8, "ORIGINATOR", "1 2 3 4"); + cmsIT8SetPropertyUncooked(it8, "DESCRIPTOR", "1234"); + cmsIT8SetPropertyStr(it8, "MANUFACTURER", "3"); + cmsIT8SetPropertyDbl(it8, "CREATED", 4); + cmsIT8SetPropertyDbl(it8, "SERIAL", 5); + cmsIT8SetPropertyHex(it8, "MATERIAL", 0x123); + + cmsIT8SetPropertyDbl(it8, "NUMBER_OF_SETS", NPOINTS_IT8); + cmsIT8SetPropertyDbl(it8, "NUMBER_OF_FIELDS", 4); + + cmsIT8SetDataFormat(it8, 0, "SAMPLE_ID"); + cmsIT8SetDataFormat(it8, 1, "RGB_R"); + cmsIT8SetDataFormat(it8, 2, "RGB_G"); + cmsIT8SetDataFormat(it8, 3, "RGB_B"); + + for (i=0; i < NPOINTS_IT8; i++) { + + char Patch[20]; + + sprintf(Patch, "P%d", i); + + cmsIT8SetDataRowCol(it8, i, 0, Patch); + cmsIT8SetDataRowColDbl(it8, i, 1, i); + cmsIT8SetDataRowColDbl(it8, i, 2, i); + cmsIT8SetDataRowColDbl(it8, i, 3, i); + } + + cmsIT8SaveToFile(it8, "TEST.IT8"); + cmsIT8Free(it8); + + + it8 = cmsIT8LoadFromFile("TEST.IT8"); + cmsIT8SaveToFile(it8, "TEST.IT8"); + cmsIT8Free(it8); + + + + it8 = cmsIT8LoadFromFile("TEST.IT8"); + + if (cmsIT8GetPropertyDbl(it8, "DESCRIPTOR") != 1234) { + + printf("fail!\n"); + return 0; + } + + + cmsIT8SetPropertyDbl(it8, "DESCRIPTOR", 5678); + + if (cmsIT8GetPropertyDbl(it8, "DESCRIPTOR") != 5678) { + + printf("fail!\n"); + return 0; + } + + + if (cmsIT8GetDataDbl(it8, "P3", "RGB_G") != 3) { + printf("fail!\n"); + return 0; + } + + + cmsIT8Free(it8); + + unlink("TEST.IT8"); + printf("pass.\n"); + return 1; + +} + + +// Create CSA/CRD + +static +void GenerateCSA(const char* cInProf) +{ + cmsHPROFILE hProfile; + + + DWORD n; + char* Buffer; + + + if (cInProf == NULL) + hProfile = cmsCreateLabProfile(NULL); + else + hProfile = cmsOpenProfileFromFile(cInProf, "r"); + + n = cmsGetPostScriptCSA(hProfile, 0, NULL, 0); + if (n == 0) return; + + Buffer = (char*) _cmsMalloc(n + 1); + cmsGetPostScriptCSA(hProfile, 0, Buffer, n); + Buffer[n] = 0; + + _cmsFree(Buffer); + cmsCloseProfile(hProfile); +} + + +static +void GenerateCRD(const char* cOutProf) +{ + cmsHPROFILE hProfile; + DWORD n; + char* Buffer; + DWORD dwFlags = 0; + + + if (cOutProf == NULL) + hProfile = cmsCreateLabProfile(NULL); + else + hProfile = cmsOpenProfileFromFile(cOutProf, "r"); + + n = cmsGetPostScriptCRDEx(hProfile, 0, dwFlags, NULL, 0); + if (n == 0) return; + + Buffer = (char*) _cmsMalloc(n + 1); + cmsGetPostScriptCRDEx(hProfile, 0, dwFlags, Buffer, n); + Buffer[n] = 0; + + _cmsFree(Buffer); + cmsCloseProfile(hProfile); +} + +static +int TestPostScript() +{ + GenerateCSA("sRGB Color Space Profile.icm"); + GenerateCRD("sRGB Color Space Profile.icm"); + GenerateCSA(NULL); + GenerateCRD(NULL); + + return 1; +} + + +static +void TestLabFloat() +{ +#define TYPE_LabA_DBL (COLORSPACE_SH(PT_Lab)|CHANNELS_SH(3)|BYTES_SH(0)|EXTRA_SH(1)|DOSWAP_SH(1)) + + struct { + double L, a, b; + double A; + } a; + cmsCIELab b; + cmsHPROFILE hLab = cmsCreateLabProfile(NULL); + cmsHTRANSFORM xform = cmsCreateTransform(hLab, TYPE_LabA_DBL, hLab, TYPE_Lab_DBL, 0, 0); + + a.L = 100; a.a = 0; a.b= 0; + cmsDoTransform(xform, &a, &b, 1); + + cmsDeleteTransform(xform); + cmsCloseProfile(hLab); +} + + + +int main(int argc, char *argv[]) +{ + int lExhaustive = 0; + + // #include "crtdbg.h" + // _CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF ); + + + + printf("little cms testbed. Ver %1.2f [build %s %s]\n\n", LCMS_VERSION / 100., __DATE__, __TIME__); + +#ifndef LCMS_DLL + + if (!CheckEndianess()) return 1; + if (!CheckSwab()) return 1; + if (!CheckQuickFloor()) return 1; + + TestFixedPoint(); + + if (!TestFixedScaling()) return 1; + if (!TestJointCurves()) return 1; + if (!TestReversingOfCurves()) return 1; + if (!TestLinearInterpolation(lExhaustive)) return 1; + if (!TestReverseLinearInterpolation()) return 1; + + + + + if (!Test3D()) return 1; + if (!TestMatrixCreation()) return 1; + if (!GetInfoTest()) return 1; + + +#endif + + if (!Test_sRGB()) return 1; + + if (!RealProfilesTest()) return 1; + if (!TestInducedError(TYPE_LABA_16)) return 1; + if (!TestPreview()) return 1; + if (!TestMultiprofile()) return 1; + if (!TestLinearizationDevicelink()) return 1; + + if (!TestDeviceLinkGeneration()) return 1; + + + if (!TestLinearizationDevicelink2()) return 1; + + + if (!TestInkLimiting()) return 1; + if (!TestSaveToMem()) return 1; + if (!TestNamedColor()) return 1; + if (!TestIT8()) return 1; + if (!TestPostScript()) return 1; + if (!TestColorantTableTag()) return 1; + +#ifdef ICM_COMPARATIVE +#ifndef NON_WINDOWS + CompareWithICM_8bit(); + CompareWithICM_16bit(); +#endif +#endif + +#ifdef CHECK_SPEED + SpeedTest(); + SpeedTest2(); +#endif + + printf("\nSuccess.\n"); + + return 0; + +} + + + + + + + |