1 //---------------------------------------------------------------------------------
3 // Little Color Management System
4 // Copyright (c) 1998-2010 Marti Maria Saguer
6 // Permission is hereby granted, free of charge, to any person obtaining
7 // a copy of this software and associated documentation files (the "Software"),
8 // to deal in the Software without restriction, including without limitation
9 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 // and/or sell copies of the Software, and to permit persons to whom the Software
11 // is furnished to do so, subject to the following conditions:
13 // The above copyright notice and this permission notice shall be included in
14 // all copies or substantial portions of the Software.
16 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
18 // THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 //---------------------------------------------------------------------------------
28 # define _CRT_SECURE_NO_WARNINGS 1
31 #include "lcms2_internal.h"
33 // On Visual Studio, use debug CRT
39 // A single check. Returns 1 if success, 0 if failed
40 typedef cmsInt32Number (*TestFn
)(void);
42 // A parametric Tone curve test function
43 typedef cmsFloat32Number (* dblfnptr
)(cmsFloat32Number x
, const cmsFloat64Number Params
[]);
45 // Some globals to keep track of error
46 #define TEXT_ERROR_BUFFER_SIZE 4096
48 static char ReasonToFailBuffer
[TEXT_ERROR_BUFFER_SIZE
];
49 static char SubTestBuffer
[TEXT_ERROR_BUFFER_SIZE
];
50 static cmsInt32Number TotalTests
= 0, TotalFail
= 0;
51 static cmsBool TrappedError
;
52 static cmsInt32Number SimultaneousErrors
;
55 #define cmsmin(a, b) (((a) < (b)) ? (a) : (b))
57 // Die, a fatal unexpected error is detected!
59 void Die(const char* Reason
)
61 printf("\n\nArrrgggg!!: %s!\n\n", Reason
);
66 // Memory management replacement -----------------------------------------------------------------------------
69 // This is just a simple plug-in for malloc, free and realloc to keep track of memory allocated,
70 // maximum requested as a single block and maximum allocated at a given time. Results are printed at the end
71 static cmsUInt32Number SingleHit
, MaxAllocated
=0, TotalMemory
=0;
73 // I'm hidding the size before the block. This is a well-known technique and probably the blocks coming from
74 // malloc are built in a way similar to that, but I do on my own to be portable.
76 cmsUInt32Number KeepSize
;
77 cmsContext WhoAllocated
;
80 cmsUInt64Number HiSparc
;
82 // '_cmsMemoryBlock' block is prepended by the
83 // allocator for any requested size. Thus, union holds
84 // "widest" type to guarantee proper '_cmsMemoryBlock'
85 // alignment for any requested size.
92 #define SIZE_OF_MEM_HEADER (sizeof(_cmsMemoryBlock))
94 // This is a fake thread descriptor used to check thread integrity.
95 // Basically it returns a different threadID each time it is called.
96 // Then the memory management replacement functions does check if each
97 // free() is being called with same ContextID used on malloc()
99 cmsContext
DbgThread(void)
101 static cmsUInt32Number n
= 1;
103 return (cmsContext
) n
++;
106 // The allocate routine
108 void* DebugMalloc(cmsContext ContextID
, cmsUInt32Number size
)
110 _cmsMemoryBlock
* blk
;
113 Die("malloc requested with zero bytes");
118 if (TotalMemory
> MaxAllocated
)
119 MaxAllocated
= TotalMemory
;
121 if (size
> SingleHit
)
124 blk
= (_cmsMemoryBlock
*) malloc(size
+ SIZE_OF_MEM_HEADER
);
125 if (blk
== NULL
) return NULL
;
127 blk
->KeepSize
= size
;
128 blk
->WhoAllocated
= ContextID
;
130 return (void*) ((cmsUInt8Number
*) blk
+ SIZE_OF_MEM_HEADER
);
135 void DebugFree(cmsContext ContextID
, void *Ptr
)
137 _cmsMemoryBlock
* blk
;
140 Die("NULL free (which is a no-op in C, but may be an clue of something going wrong)");
143 blk
= (_cmsMemoryBlock
*) (((cmsUInt8Number
*) Ptr
) - SIZE_OF_MEM_HEADER
);
144 TotalMemory
-= blk
->KeepSize
;
146 if (blk
->WhoAllocated
!= ContextID
) {
147 Die("Trying to free memory allocated by a different thread");
153 // Reallocate, just a malloc, a copy and a free in this case.
155 void * DebugRealloc(cmsContext ContextID
, void* Ptr
, cmsUInt32Number NewSize
)
157 _cmsMemoryBlock
* blk
;
159 cmsUInt32Number max_sz
;
161 NewPtr
= DebugMalloc(ContextID
, NewSize
);
162 if (Ptr
== NULL
) return NewPtr
;
164 blk
= (_cmsMemoryBlock
*) (((cmsUInt8Number
*) Ptr
) - SIZE_OF_MEM_HEADER
);
165 max_sz
= blk
-> KeepSize
> NewSize
? NewSize
: blk
->KeepSize
;
166 memmove(NewPtr
, Ptr
, max_sz
);
167 DebugFree(ContextID
, Ptr
);
172 // Let's know the totals
174 void DebugMemPrintTotals(void)
176 printf("[Memory statistics]\n");
177 printf("Allocated = %u MaxAlloc = %u Single block hit = %u\n", TotalMemory
, MaxAllocated
, SingleHit
);
180 // Here we go with the plug-in declaration
181 static cmsPluginMemHandler DebugMemHandler
= {{ cmsPluginMagicNumber
, 2000, cmsPluginMemHandlerSig
, NULL
},
182 DebugMalloc
, DebugFree
, DebugRealloc
, NULL
, NULL
, NULL
};
184 // Utils -------------------------------------------------------------------------------------
187 void FatalErrorQuit(cmsContext ContextID
, cmsUInt32Number ErrorCode
, const char *Text
)
191 cmsUNUSED_PARAMETER(ContextID
);
192 cmsUNUSED_PARAMETER(ErrorCode
);
196 // Print a dot for gauging
200 fprintf(stdout
, "."); fflush(stdout
);
203 // Keep track of the reason to fail
205 void Fail(const char* frm
, ...)
209 vsprintf(ReasonToFailBuffer
, frm
, args
);
213 // Keep track of subtest
215 void SubTest(const char* frm
, ...)
221 vsprintf(SubTestBuffer
, frm
, args
);
228 const char* MemStr(cmsUInt32Number size
)
230 static char Buffer
[1024];
232 if (size
> 1024*1024) {
233 sprintf(Buffer
, "%g Mb", (cmsFloat64Number
) size
/ (1024.0*1024.0));
237 sprintf(Buffer
, "%g Kb", (cmsFloat64Number
) size
/ 1024.0);
240 sprintf(Buffer
, "%g bytes", (cmsFloat64Number
) size
);
246 // The check framework
248 void Check(const char* Title
, TestFn Fn
)
250 printf("Checking %s ...", Title
);
253 ReasonToFailBuffer
[0] = 0;
254 SubTestBuffer
[0] = 0;
255 TrappedError
= FALSE
;
256 SimultaneousErrors
= 0;
259 if (Fn() && !TrappedError
) {
261 // It is a good place to check memory
263 printf("Ok, but %s are left!\n", MemStr(TotalMemory
));
270 if (SubTestBuffer
[0])
271 printf("%s: [%s]\n\t%s\n", Title
, SubTestBuffer
, ReasonToFailBuffer
);
273 printf("%s:\n\t%s\n", Title
, ReasonToFailBuffer
);
275 if (SimultaneousErrors
> 1)
276 printf("\tMore than one (%d) errors were reported\n", SimultaneousErrors
);
283 // Dump a tone curve, for easy diagnostic
284 void DumpToneCurve(cmsToneCurve
* gamma
, const char* FileName
)
289 hIT8
= cmsIT8Alloc(gamma
->InterpParams
->ContextID
);
291 cmsIT8SetPropertyDbl(hIT8
, "NUMBER_OF_FIELDS", 2);
292 cmsIT8SetPropertyDbl(hIT8
, "NUMBER_OF_SETS", gamma
->nEntries
);
294 cmsIT8SetDataFormat(hIT8
, 0, "SAMPLE_ID");
295 cmsIT8SetDataFormat(hIT8
, 1, "VALUE");
297 for (i
=0; i
< gamma
->nEntries
; i
++) {
300 sprintf(Val
, "%u", i
);
301 cmsIT8SetDataRowCol(hIT8
, i
, 0, Val
);
302 sprintf(Val
, "0x%x", gamma
->Table16
[i
]);
303 cmsIT8SetDataRowCol(hIT8
, i
, 1, Val
);
306 cmsIT8SaveToFile(hIT8
, FileName
);
310 // -------------------------------------------------------------------------------------------------
313 // Used to perform several checks.
314 // The space used is a clone of a well-known commercial
315 // color space which I will name "Above RGB"
317 cmsHPROFILE
Create_AboveRGB(void)
319 cmsToneCurve
* Curve
[3];
320 cmsHPROFILE hProfile
;
322 cmsCIExyYTRIPLE Primaries
= {{0.64, 0.33, 1 },
326 Curve
[0] = Curve
[1] = Curve
[2] = cmsBuildGamma(DbgThread(), 2.19921875);
328 cmsWhitePointFromTemp(&D65
, 6504);
329 hProfile
= cmsCreateRGBProfileTHR(DbgThread(), &D65
, &Primaries
, Curve
);
330 cmsFreeToneCurve(Curve
[0]);
335 // A gamma-2.2 gray space
337 cmsHPROFILE
Create_Gray22(void)
339 cmsHPROFILE hProfile
;
340 cmsToneCurve
* Curve
= cmsBuildGamma(DbgThread(), 2.2);
341 if (Curve
== NULL
) return NULL
;
343 hProfile
= cmsCreateGrayProfileTHR(DbgThread(), cmsD50_xyY(), Curve
);
344 cmsFreeToneCurve(Curve
);
349 // A gamma-3.0 gray space
351 cmsHPROFILE
Create_Gray30(void)
353 cmsHPROFILE hProfile
;
354 cmsToneCurve
* Curve
= cmsBuildGamma(DbgThread(), 3.0);
355 if (Curve
== NULL
) return NULL
;
357 hProfile
= cmsCreateGrayProfileTHR(DbgThread(), cmsD50_xyY(), Curve
);
358 cmsFreeToneCurve(Curve
);
365 cmsHPROFILE
Create_GrayLab(void)
367 cmsHPROFILE hProfile
;
368 cmsToneCurve
* Curve
= cmsBuildGamma(DbgThread(), 1.0);
369 if (Curve
== NULL
) return NULL
;
371 hProfile
= cmsCreateGrayProfileTHR(DbgThread(), cmsD50_xyY(), Curve
);
372 cmsFreeToneCurve(Curve
);
374 cmsSetPCS(hProfile
, cmsSigLabData
);
378 // A CMYK devicelink that adds gamma 3.0 to each channel
380 cmsHPROFILE
Create_CMYK_DeviceLink(void)
382 cmsHPROFILE hProfile
;
383 cmsToneCurve
* Tab
[4];
384 cmsToneCurve
* Curve
= cmsBuildGamma(DbgThread(), 3.0);
385 if (Curve
== NULL
) return NULL
;
392 hProfile
= cmsCreateLinearizationDeviceLinkTHR(DbgThread(), cmsSigCmykData
, Tab
);
393 if (hProfile
== NULL
) return NULL
;
395 cmsFreeToneCurve(Curve
);
401 // Create a fake CMYK profile, without any other requeriment that being coarse CMYK.
402 // DONT USE THIS PROFILE FOR ANYTHING, IT IS USELESS BUT FOR TESTING PURPOSES.
405 cmsHTRANSFORM hLab2sRGB
;
406 cmsHTRANSFORM sRGB2Lab
;
407 cmsHTRANSFORM hIlimit
;
412 cmsFloat64Number
Clip(cmsFloat64Number v
)
421 cmsInt32Number
ForwardSampler(register const cmsUInt16Number In
[], cmsUInt16Number Out
[], void* Cargo
)
423 FakeCMYKParams
* p
= (FakeCMYKParams
*) Cargo
;
424 cmsFloat64Number rgb
[3], cmyk
[4];
425 cmsFloat64Number c
, m
, y
, k
;
427 cmsDoTransform(p
->hLab2sRGB
, In
, rgb
, 1);
433 k
= (c
< m
? cmsmin(c
, y
) : cmsmin(m
, y
));
435 // NONSENSE WARNING!: I'm doing this just because this is a test
436 // profile that may have ink limit up to 400%. There is no UCR here
437 // so the profile is basically useless for anything but testing.
444 cmsDoTransform(p
->hIlimit
, cmyk
, Out
, 1);
451 cmsInt32Number
ReverseSampler(register const cmsUInt16Number In
[], register cmsUInt16Number Out
[], register void* Cargo
)
453 FakeCMYKParams
* p
= (FakeCMYKParams
*) Cargo
;
454 cmsFloat64Number c
, m
, y
, k
, rgb
[3];
463 rgb
[0] = Clip(1 - c
);
464 rgb
[1] = Clip(1 - m
);
465 rgb
[2] = Clip(1 - y
);
470 rgb
[0] = rgb
[1] = rgb
[2] = 0;
474 rgb
[0] = Clip((1 - c
) * (1 - k
));
475 rgb
[1] = Clip((1 - m
) * (1 - k
));
476 rgb
[2] = Clip((1 - y
) * (1 - k
));
479 cmsDoTransform(p
->sRGB2Lab
, rgb
, Out
, 1);
486 cmsHPROFILE
CreateFakeCMYK(cmsFloat64Number InkLimit
, cmsBool lUseAboveRGB
)
489 cmsPipeline
* AToB0
, *BToA0
;
491 cmsContext ContextID
;
493 cmsHPROFILE hLab
, hsRGB
, hLimit
;
494 cmsUInt32Number cmykfrm
;
498 hsRGB
= Create_AboveRGB();
500 hsRGB
= cmsCreate_sRGBProfile();
502 hLab
= cmsCreateLab4Profile(NULL
);
503 hLimit
= cmsCreateInkLimitingDeviceLink(cmsSigCmykData
, InkLimit
);
505 cmykfrm
= FLOAT_SH(1) | BYTES_SH(0)|CHANNELS_SH(4);
506 p
.hLab2sRGB
= cmsCreateTransform(hLab
, TYPE_Lab_16
, hsRGB
, TYPE_RGB_DBL
, INTENT_PERCEPTUAL
, cmsFLAGS_NOOPTIMIZE
|cmsFLAGS_NOCACHE
);
507 p
.sRGB2Lab
= cmsCreateTransform(hsRGB
, TYPE_RGB_DBL
, hLab
, TYPE_Lab_16
, INTENT_PERCEPTUAL
, cmsFLAGS_NOOPTIMIZE
|cmsFLAGS_NOCACHE
);
508 p
.hIlimit
= cmsCreateTransform(hLimit
, cmykfrm
, NULL
, TYPE_CMYK_16
, INTENT_PERCEPTUAL
, cmsFLAGS_NOOPTIMIZE
|cmsFLAGS_NOCACHE
);
510 cmsCloseProfile(hLab
); cmsCloseProfile(hsRGB
); cmsCloseProfile(hLimit
);
512 ContextID
= DbgThread();
513 hICC
= cmsCreateProfilePlaceholder(ContextID
);
514 if (!hICC
) return NULL
;
516 cmsSetProfileVersion(hICC
, 4.3);
518 cmsSetDeviceClass(hICC
, cmsSigOutputClass
);
519 cmsSetColorSpace(hICC
, cmsSigCmykData
);
520 cmsSetPCS(hICC
, cmsSigLabData
);
522 BToA0
= cmsPipelineAlloc(ContextID
, 3, 4);
523 if (BToA0
== NULL
) return 0;
524 CLUT
= cmsStageAllocCLut16bit(ContextID
, 17, 3, 4, NULL
);
525 if (CLUT
== NULL
) return 0;
526 if (!cmsStageSampleCLut16bit(CLUT
, ForwardSampler
, &p
, 0)) return 0;
528 cmsPipelineInsertStage(BToA0
, cmsAT_BEGIN
, _cmsStageAllocIdentityCurves(ContextID
, 3));
529 cmsPipelineInsertStage(BToA0
, cmsAT_END
, CLUT
);
530 cmsPipelineInsertStage(BToA0
, cmsAT_END
, _cmsStageAllocIdentityCurves(ContextID
, 4));
532 if (!cmsWriteTag(hICC
, cmsSigBToA0Tag
, (void*) BToA0
)) return 0;
533 cmsPipelineFree(BToA0
);
535 AToB0
= cmsPipelineAlloc(ContextID
, 4, 3);
536 if (AToB0
== NULL
) return 0;
537 CLUT
= cmsStageAllocCLut16bit(ContextID
, 17, 4, 3, NULL
);
538 if (CLUT
== NULL
) return 0;
539 if (!cmsStageSampleCLut16bit(CLUT
, ReverseSampler
, &p
, 0)) return 0;
541 cmsPipelineInsertStage(AToB0
, cmsAT_BEGIN
, _cmsStageAllocIdentityCurves(ContextID
, 4));
542 cmsPipelineInsertStage(AToB0
, cmsAT_END
, CLUT
);
543 cmsPipelineInsertStage(AToB0
, cmsAT_END
, _cmsStageAllocIdentityCurves(ContextID
, 3));
545 if (!cmsWriteTag(hICC
, cmsSigAToB0Tag
, (void*) AToB0
)) return 0;
546 cmsPipelineFree(AToB0
);
548 cmsDeleteTransform(p
.hLab2sRGB
);
549 cmsDeleteTransform(p
.sRGB2Lab
);
550 cmsDeleteTransform(p
.hIlimit
);
552 cmsLinkTag(hICC
, cmsSigAToB1Tag
, cmsSigAToB0Tag
);
553 cmsLinkTag(hICC
, cmsSigAToB2Tag
, cmsSigAToB0Tag
);
554 cmsLinkTag(hICC
, cmsSigBToA1Tag
, cmsSigBToA0Tag
);
555 cmsLinkTag(hICC
, cmsSigBToA2Tag
, cmsSigBToA0Tag
);
561 // Does create several profiles for latter use------------------------------------------------------------------------------------------------
564 cmsInt32Number
OneVirtual(cmsHPROFILE h
, const char* SubTestTxt
, const char* FileName
)
567 if (h
== NULL
) return 0;
569 if (!cmsSaveProfileToFile(h
, FileName
)) return 0;
572 h
= cmsOpenProfileFromFile(FileName
, "r");
573 if (h
== NULL
) return 0;
584 // This test checks the ability of lcms2 to save its built-ins as valid profiles.
585 // It does not check the functionality of such profiles
587 cmsInt32Number
CreateTestProfiles(void)
591 h
= cmsCreate_sRGBProfileTHR(DbgThread());
592 if (!OneVirtual(h
, "sRGB profile", "sRGBlcms2.icc")) return 0;
596 h
= Create_AboveRGB();
597 if (!OneVirtual(h
, "aRGB profile", "aRGBlcms2.icc")) return 0;
602 if (!OneVirtual(h
, "Gray profile", "graylcms2.icc")) return 0;
607 if (!OneVirtual(h
, "Gray 3.0 profile", "gray3lcms2.icc")) return 0;
611 h
= Create_GrayLab();
612 if (!OneVirtual(h
, "Gray Lab profile", "glablcms2.icc")) return 0;
616 h
= Create_CMYK_DeviceLink();
617 if (!OneVirtual(h
, "Linearization profile", "linlcms2.icc")) return 0;
620 h
= cmsCreateInkLimitingDeviceLinkTHR(DbgThread(), cmsSigCmykData
, 150);
621 if (h
== NULL
) return 0;
622 if (!OneVirtual(h
, "Ink-limiting profile", "limitlcms2.icc")) return 0;
626 h
= cmsCreateLab2ProfileTHR(DbgThread(), NULL
);
627 if (!OneVirtual(h
, "Lab 2 identity profile", "labv2lcms2.icc")) return 0;
631 h
= cmsCreateLab4ProfileTHR(DbgThread(), NULL
);
632 if (!OneVirtual(h
, "Lab 4 identity profile", "labv4lcms2.icc")) return 0;
636 h
= cmsCreateXYZProfileTHR(DbgThread());
637 if (!OneVirtual(h
, "XYZ identity profile", "xyzlcms2.icc")) return 0;
641 h
= cmsCreateNULLProfileTHR(DbgThread());
642 if (!OneVirtual(h
, "NULL profile", "nullcms2.icc")) return 0;
646 h
= cmsCreateBCHSWabstractProfileTHR(DbgThread(), 17, 0, 0, 0, 0, 5000, 6000);
647 if (!OneVirtual(h
, "BCHS profile", "bchslcms2.icc")) return 0;
651 h
= CreateFakeCMYK(300, FALSE
);
652 if (!OneVirtual(h
, "Fake CMYK profile", "lcms2cmyk.icc")) return 0;
658 void RemoveTestProfiles(void)
660 remove("sRGBlcms2.icc");
661 remove("aRGBlcms2.icc");
662 remove("graylcms2.icc");
663 remove("gray3lcms2.icc");
664 remove("linlcms2.icc");
665 remove("limitlcms2.icc");
666 remove("labv2lcms2.icc");
667 remove("labv4lcms2.icc");
668 remove("xyzlcms2.icc");
669 remove("nullcms2.icc");
670 remove("bchslcms2.icc");
671 remove("lcms2cmyk.icc");
672 remove("glablcms2.icc");
673 remove("lcms2link.icc");
674 remove("lcms2link2.icc");
677 // -------------------------------------------------------------------------------------------------
679 // Check the size of basic types. If this test fails, nothing is going to work anyway
681 cmsInt32Number
CheckBaseTypes(void)
683 // Ignore warnings about conditional expression
685 #pragma warning(disable: 4127)
688 if (sizeof(cmsUInt8Number
) != 1) return 0;
689 if (sizeof(cmsInt8Number
) != 1) return 0;
690 if (sizeof(cmsUInt16Number
) != 2) return 0;
691 if (sizeof(cmsInt16Number
) != 2) return 0;
692 if (sizeof(cmsUInt32Number
) != 4) return 0;
693 if (sizeof(cmsInt32Number
) != 4) return 0;
694 if (sizeof(cmsUInt64Number
) != 8) return 0;
695 if (sizeof(cmsInt64Number
) != 8) return 0;
696 if (sizeof(cmsFloat32Number
) != 4) return 0;
697 if (sizeof(cmsFloat64Number
) != 8) return 0;
698 if (sizeof(cmsSignature
) != 4) return 0;
699 if (sizeof(cmsU8Fixed8Number
) != 2) return 0;
700 if (sizeof(cmsS15Fixed16Number
) != 4) return 0;
701 if (sizeof(cmsU16Fixed16Number
) != 4) return 0;
706 // -------------------------------------------------------------------------------------------------
709 // Are we little or big endian? From Harbison&Steele.
711 cmsInt32Number
CheckEndianess(void)
713 cmsInt32Number BigEndian
, IsOk
;
716 char c
[sizeof (long)];
720 BigEndian
= (u
.c
[sizeof (long) - 1] == 1);
722 #ifdef CMS_USE_BIG_ENDIAN
729 Fail("\nOOOPPSS! You have CMS_USE_BIG_ENDIAN toggle misconfigured!\n\n"
730 "Please, edit lcms2.h and %s the CMS_USE_BIG_ENDIAN toggle.\n", BigEndian
? "uncomment" : "comment");
739 cmsInt32Number
CheckQuickFloor(void)
741 if ((_cmsQuickFloor(1.234) != 1) ||
742 (_cmsQuickFloor(32767.234) != 32767) ||
743 (_cmsQuickFloor(-1.234) != -2) ||
744 (_cmsQuickFloor(-32767.1) != -32768)) {
746 Fail("\nOOOPPSS! _cmsQuickFloor() does not work as expected in your machine!\n\n"
747 "Please, edit lcms.h and uncomment the CMS_DONT_USE_FAST_FLOOR toggle.\n");
755 // Quick floor restricted to word
757 cmsInt32Number
CheckQuickFloorWord(void)
761 for (i
=0; i
< 65535; i
++) {
763 if (_cmsQuickFloorWord((cmsFloat64Number
) i
+ 0.1234) != i
) {
765 Fail("\nOOOPPSS! _cmsQuickFloorWord() does not work as expected in your machine!\n\n"
766 "Please, edit lcms.h and uncomment the CMS_DONT_USE_FAST_FLOOR toggle.\n");
774 // -------------------------------------------------------------------------------------------------
778 // On 15.16 fixed point, this is the maximum we can obtain. Remember ICC profiles have storage limits on this number
779 #define FIXED_PRECISION_15_16 (1.0 / 65535.0)
781 // On 8.8 fixed point, that is the max we can obtain.
782 #define FIXED_PRECISION_8_8 (1.0 / 255.0)
784 // On cmsFloat32Number type, this is the precision we expect
785 #define FLOAT_PRECISSION (0.00001)
787 static cmsFloat64Number MaxErr
;
788 static cmsFloat64Number AllowedErr
= FIXED_PRECISION_15_16
;
791 cmsBool
IsGoodVal(const char *title
, cmsFloat64Number in
, cmsFloat64Number out
, cmsFloat64Number max
)
793 cmsFloat64Number Err
= fabs(in
- out
);
795 if (Err
> MaxErr
) MaxErr
= Err
;
799 Fail("(%s): Must be %f, But is %f ", title
, in
, out
);
807 cmsBool
IsGoodFixed15_16(const char *title
, cmsFloat64Number in
, cmsFloat64Number out
)
809 return IsGoodVal(title
, in
, out
, FIXED_PRECISION_15_16
);
813 cmsBool
IsGoodFixed8_8(const char *title
, cmsFloat64Number in
, cmsFloat64Number out
)
815 return IsGoodVal(title
, in
, out
, FIXED_PRECISION_8_8
);
819 cmsBool
IsGoodWord(const char *title
, cmsUInt16Number in
, cmsUInt16Number out
)
821 if ((abs(in
- out
) > 0 )) {
823 Fail("(%s): Must be %x, But is %x ", title
, in
, out
);
831 cmsBool
IsGoodWordPrec(const char *title
, cmsUInt16Number in
, cmsUInt16Number out
, cmsUInt16Number maxErr
)
833 if ((abs(in
- out
) > maxErr
)) {
835 Fail("(%s): Must be %x, But is %x ", title
, in
, out
);
842 // Fixed point ----------------------------------------------------------------------------------------------
845 cmsInt32Number
TestSingleFixed15_16(cmsFloat64Number d
)
847 cmsS15Fixed16Number f
= _cmsDoubleTo15Fixed16(d
);
848 cmsFloat64Number RoundTrip
= _cms15Fixed16toDouble(f
);
849 cmsFloat64Number Error
= fabs(d
- RoundTrip
);
851 return ( Error
<= FIXED_PRECISION_15_16
);
855 cmsInt32Number
CheckFixedPoint15_16(void)
857 if (!TestSingleFixed15_16(1.0)) return 0;
858 if (!TestSingleFixed15_16(2.0)) return 0;
859 if (!TestSingleFixed15_16(1.23456)) return 0;
860 if (!TestSingleFixed15_16(0.99999)) return 0;
861 if (!TestSingleFixed15_16(0.1234567890123456789099999)) return 0;
862 if (!TestSingleFixed15_16(-1.0)) return 0;
863 if (!TestSingleFixed15_16(-2.0)) return 0;
864 if (!TestSingleFixed15_16(-1.23456)) return 0;
865 if (!TestSingleFixed15_16(-1.1234567890123456789099999)) return 0;
866 if (!TestSingleFixed15_16(+32767.1234567890123456789099999)) return 0;
867 if (!TestSingleFixed15_16(-32767.1234567890123456789099999)) return 0;
872 cmsInt32Number
TestSingleFixed8_8(cmsFloat64Number d
)
874 cmsS15Fixed16Number f
= _cmsDoubleTo8Fixed8(d
);
875 cmsFloat64Number RoundTrip
= _cms8Fixed8toDouble((cmsUInt16Number
) f
);
876 cmsFloat64Number Error
= fabs(d
- RoundTrip
);
878 return ( Error
<= FIXED_PRECISION_8_8
);
882 cmsInt32Number
CheckFixedPoint8_8(void)
884 if (!TestSingleFixed8_8(1.0)) return 0;
885 if (!TestSingleFixed8_8(2.0)) return 0;
886 if (!TestSingleFixed8_8(1.23456)) return 0;
887 if (!TestSingleFixed8_8(0.99999)) return 0;
888 if (!TestSingleFixed8_8(0.1234567890123456789099999)) return 0;
889 if (!TestSingleFixed8_8(+255.1234567890123456789099999)) return 0;
894 // Linear interpolation -----------------------------------------------------------------------------------------------
896 // Since prime factors of 65535 (FFFF) are,
898 // 0xFFFF = 3 * 5 * 17 * 257
900 // I test tables of 2, 4, 6, and 18 points, that will be exact.
903 void BuildTable(cmsInt32Number n
, cmsUInt16Number Tab
[], cmsBool Descending
)
907 for (i
=0; i
< n
; i
++) {
908 cmsFloat64Number v
= (cmsFloat64Number
) ((cmsFloat64Number
) 65535.0 * i
) / (n
-1);
910 Tab
[Descending
? (n
- i
- 1) : i
] = (cmsUInt16Number
) floor(v
+ 0.5);
914 // A single function that does check 1D interpolation
915 // nNodesToCheck = number on nodes to check
916 // Down = Create decreasing tables
917 // Reverse = Check reverse interpolation
918 // max_err = max allowed error
921 cmsInt32Number
Check1D(cmsInt32Number nNodesToCheck
, cmsBool Down
, cmsInt32Number max_err
)
924 cmsUInt16Number in
, out
;
926 cmsUInt16Number
* Tab
;
928 Tab
= (cmsUInt16Number
*) malloc(sizeof(cmsUInt16Number
)* nNodesToCheck
);
929 if (Tab
== NULL
) return 0;
931 p
= _cmsComputeInterpParams(DbgThread(), nNodesToCheck
, 1, 1, Tab
, CMS_LERP_FLAGS_16BITS
);
932 if (p
== NULL
) return 0;
934 BuildTable(nNodesToCheck
, Tab
, Down
);
936 for (i
=0; i
<= 0xffff; i
++) {
938 in
= (cmsUInt16Number
) i
;
941 p
->Interpolation
.Lerp16(&in
, &out
, p
);
943 if (Down
) out
= 0xffff - out
;
945 if (abs(out
- in
) > max_err
) {
947 Fail("(%dp): Must be %x, But is %x : ", nNodesToCheck
, in
, out
);
948 _cmsFreeInterpParams(p
);
954 _cmsFreeInterpParams(p
);
961 cmsInt32Number
Check1DLERP2(void)
963 return Check1D(2, FALSE
, 0);
968 cmsInt32Number
Check1DLERP3(void)
970 return Check1D(3, FALSE
, 1);
975 cmsInt32Number
Check1DLERP4(void)
977 return Check1D(4, FALSE
, 0);
981 cmsInt32Number
Check1DLERP6(void)
983 return Check1D(6, FALSE
, 0);
987 cmsInt32Number
Check1DLERP18(void)
989 return Check1D(18, FALSE
, 0);
994 cmsInt32Number
Check1DLERP2Down(void)
996 return Check1D(2, TRUE
, 0);
1001 cmsInt32Number
Check1DLERP3Down(void)
1003 return Check1D(3, TRUE
, 1);
1007 cmsInt32Number
Check1DLERP6Down(void)
1009 return Check1D(6, TRUE
, 0);
1013 cmsInt32Number
Check1DLERP18Down(void)
1015 return Check1D(18, TRUE
, 0);
1019 cmsInt32Number
ExhaustiveCheck1DLERP(void)
1024 for (j
=10; j
<= 4096; j
++) {
1026 if ((j
% 10) == 0) printf("%u \r", j
);
1028 if (!Check1D(j
, FALSE
, 1)) return 0;
1031 printf("\rResult is ");
1036 cmsInt32Number
ExhaustiveCheck1DLERPDown(void)
1041 for (j
=10; j
<= 4096; j
++) {
1043 if ((j
% 10) == 0) printf("%u \r", j
);
1045 if (!Check1D(j
, TRUE
, 1)) return 0;
1049 printf("\rResult is ");
1055 // 3D interpolation -------------------------------------------------------------------------------------------------
1058 cmsInt32Number
Check3DinterpolationFloatTetrahedral(void)
1062 cmsFloat32Number In
[3], Out
[3];
1063 cmsFloat32Number FloatTable
[] = { //R G B
1065 0, 0, 0, // B=0,G=0,R=0
1066 0, 0, .25, // B=1,G=0,R=0
1068 0, .5, 0, // B=0,G=1,R=0
1069 0, .5, .25, // B=1,G=1,R=0
1071 1, 0, 0, // B=0,G=0,R=1
1072 1, 0, .25, // B=1,G=0,R=1
1074 1, .5, 0, // B=0,G=1,R=1
1075 1, .5, .25 // B=1,G=1,R=1
1079 p
= _cmsComputeInterpParams(DbgThread(), 2, 3, 3, FloatTable
, CMS_LERP_FLAGS_FLOAT
);
1083 for (i
=0; i
< 0xffff; i
++) {
1085 In
[0] = In
[1] = In
[2] = (cmsFloat32Number
) ( (cmsFloat32Number
) i
/ 65535.0F
);
1087 p
->Interpolation
.LerpFloat(In
, Out
, p
);
1089 if (!IsGoodFixed15_16("Channel 1", Out
[0], In
[0])) goto Error
;
1090 if (!IsGoodFixed15_16("Channel 2", Out
[1], (cmsFloat32Number
) In
[1] / 2.F
)) goto Error
;
1091 if (!IsGoodFixed15_16("Channel 3", Out
[2], (cmsFloat32Number
) In
[2] / 4.F
)) goto Error
;
1094 if (MaxErr
> 0) printf("|Err|<%lf ", MaxErr
);
1095 _cmsFreeInterpParams(p
);
1099 _cmsFreeInterpParams(p
);
1104 cmsInt32Number
Check3DinterpolationFloatTrilinear(void)
1108 cmsFloat32Number In
[3], Out
[3];
1109 cmsFloat32Number FloatTable
[] = { //R G B
1111 0, 0, 0, // B=0,G=0,R=0
1112 0, 0, .25, // B=1,G=0,R=0
1114 0, .5, 0, // B=0,G=1,R=0
1115 0, .5, .25, // B=1,G=1,R=0
1117 1, 0, 0, // B=0,G=0,R=1
1118 1, 0, .25, // B=1,G=0,R=1
1120 1, .5, 0, // B=0,G=1,R=1
1121 1, .5, .25 // B=1,G=1,R=1
1125 p
= _cmsComputeInterpParams(DbgThread(), 2, 3, 3, FloatTable
, CMS_LERP_FLAGS_FLOAT
|CMS_LERP_FLAGS_TRILINEAR
);
1128 for (i
=0; i
< 0xffff; i
++) {
1130 In
[0] = In
[1] = In
[2] = (cmsFloat32Number
) ( (cmsFloat32Number
) i
/ 65535.0F
);
1132 p
->Interpolation
.LerpFloat(In
, Out
, p
);
1134 if (!IsGoodFixed15_16("Channel 1", Out
[0], In
[0])) goto Error
;
1135 if (!IsGoodFixed15_16("Channel 2", Out
[1], (cmsFloat32Number
) In
[1] / 2.F
)) goto Error
;
1136 if (!IsGoodFixed15_16("Channel 3", Out
[2], (cmsFloat32Number
) In
[2] / 4.F
)) goto Error
;
1139 if (MaxErr
> 0) printf("|Err|<%lf ", MaxErr
);
1140 _cmsFreeInterpParams(p
);
1144 _cmsFreeInterpParams(p
);
1150 cmsInt32Number
Check3DinterpolationTetrahedral16(void)
1154 cmsUInt16Number In
[3], Out
[3];
1155 cmsUInt16Number Table
[] = {
1167 0xffff, 0xffff, 0xffff
1170 p
= _cmsComputeInterpParams(DbgThread(), 2, 3, 3, Table
, CMS_LERP_FLAGS_16BITS
);
1173 for (i
=0; i
< 0xffff; i
++) {
1175 In
[0] = In
[1] = In
[2] = (cmsUInt16Number
) i
;
1177 p
->Interpolation
.Lerp16(In
, Out
, p
);
1179 if (!IsGoodWord("Channel 1", Out
[0], In
[0])) goto Error
;
1180 if (!IsGoodWord("Channel 2", Out
[1], In
[1])) goto Error
;
1181 if (!IsGoodWord("Channel 3", Out
[2], In
[2])) goto Error
;
1184 if (MaxErr
> 0) printf("|Err|<%lf ", MaxErr
);
1185 _cmsFreeInterpParams(p
);
1189 _cmsFreeInterpParams(p
);
1194 cmsInt32Number
Check3DinterpolationTrilinear16(void)
1198 cmsUInt16Number In
[3], Out
[3];
1199 cmsUInt16Number Table
[] = {
1211 0xffff, 0xffff, 0xffff
1214 p
= _cmsComputeInterpParams(DbgThread(), 2, 3, 3, Table
, CMS_LERP_FLAGS_TRILINEAR
);
1217 for (i
=0; i
< 0xffff; i
++) {
1219 In
[0] = In
[1] = In
[2] = (cmsUInt16Number
) i
;
1221 p
->Interpolation
.Lerp16(In
, Out
, p
);
1223 if (!IsGoodWord("Channel 1", Out
[0], In
[0])) goto Error
;
1224 if (!IsGoodWord("Channel 2", Out
[1], In
[1])) goto Error
;
1225 if (!IsGoodWord("Channel 3", Out
[2], In
[2])) goto Error
;
1228 if (MaxErr
> 0) printf("|Err|<%lf ", MaxErr
);
1229 _cmsFreeInterpParams(p
);
1233 _cmsFreeInterpParams(p
);
1239 cmsInt32Number
ExaustiveCheck3DinterpolationFloatTetrahedral(void)
1242 cmsInt32Number r
, g
, b
;
1243 cmsFloat32Number In
[3], Out
[3];
1244 cmsFloat32Number FloatTable
[] = { //R G B
1246 0, 0, 0, // B=0,G=0,R=0
1247 0, 0, .25, // B=1,G=0,R=0
1249 0, .5, 0, // B=0,G=1,R=0
1250 0, .5, .25, // B=1,G=1,R=0
1252 1, 0, 0, // B=0,G=0,R=1
1253 1, 0, .25, // B=1,G=0,R=1
1255 1, .5, 0, // B=0,G=1,R=1
1256 1, .5, .25 // B=1,G=1,R=1
1260 p
= _cmsComputeInterpParams(DbgThread(), 2, 3, 3, FloatTable
, CMS_LERP_FLAGS_FLOAT
);
1263 for (r
=0; r
< 0xff; r
++)
1264 for (g
=0; g
< 0xff; g
++)
1265 for (b
=0; b
< 0xff; b
++)
1268 In
[0] = (cmsFloat32Number
) r
/ 255.0F
;
1269 In
[1] = (cmsFloat32Number
) g
/ 255.0F
;
1270 In
[2] = (cmsFloat32Number
) b
/ 255.0F
;
1273 p
->Interpolation
.LerpFloat(In
, Out
, p
);
1275 if (!IsGoodFixed15_16("Channel 1", Out
[0], In
[0])) goto Error
;
1276 if (!IsGoodFixed15_16("Channel 2", Out
[1], (cmsFloat32Number
) In
[1] / 2.F
)) goto Error
;
1277 if (!IsGoodFixed15_16("Channel 3", Out
[2], (cmsFloat32Number
) In
[2] / 4.F
)) goto Error
;
1280 if (MaxErr
> 0) printf("|Err|<%lf ", MaxErr
);
1281 _cmsFreeInterpParams(p
);
1285 _cmsFreeInterpParams(p
);
1290 cmsInt32Number
ExaustiveCheck3DinterpolationFloatTrilinear(void)
1293 cmsInt32Number r
, g
, b
;
1294 cmsFloat32Number In
[3], Out
[3];
1295 cmsFloat32Number FloatTable
[] = { //R G B
1297 0, 0, 0, // B=0,G=0,R=0
1298 0, 0, .25, // B=1,G=0,R=0
1300 0, .5, 0, // B=0,G=1,R=0
1301 0, .5, .25, // B=1,G=1,R=0
1303 1, 0, 0, // B=0,G=0,R=1
1304 1, 0, .25, // B=1,G=0,R=1
1306 1, .5, 0, // B=0,G=1,R=1
1307 1, .5, .25 // B=1,G=1,R=1
1311 p
= _cmsComputeInterpParams(DbgThread(), 2, 3, 3, FloatTable
, CMS_LERP_FLAGS_FLOAT
|CMS_LERP_FLAGS_TRILINEAR
);
1314 for (r
=0; r
< 0xff; r
++)
1315 for (g
=0; g
< 0xff; g
++)
1316 for (b
=0; b
< 0xff; b
++)
1319 In
[0] = (cmsFloat32Number
) r
/ 255.0F
;
1320 In
[1] = (cmsFloat32Number
) g
/ 255.0F
;
1321 In
[2] = (cmsFloat32Number
) b
/ 255.0F
;
1324 p
->Interpolation
.LerpFloat(In
, Out
, p
);
1326 if (!IsGoodFixed15_16("Channel 1", Out
[0], In
[0])) goto Error
;
1327 if (!IsGoodFixed15_16("Channel 2", Out
[1], (cmsFloat32Number
) In
[1] / 2.F
)) goto Error
;
1328 if (!IsGoodFixed15_16("Channel 3", Out
[2], (cmsFloat32Number
) In
[2] / 4.F
)) goto Error
;
1331 if (MaxErr
> 0) printf("|Err|<%lf ", MaxErr
);
1332 _cmsFreeInterpParams(p
);
1336 _cmsFreeInterpParams(p
);
1342 cmsInt32Number
ExhaustiveCheck3DinterpolationTetrahedral16(void)
1345 cmsInt32Number r
, g
, b
;
1346 cmsUInt16Number In
[3], Out
[3];
1347 cmsUInt16Number Table
[] = {
1359 0xffff, 0xffff, 0xffff
1362 p
= _cmsComputeInterpParams(DbgThread(), 2, 3, 3, Table
, CMS_LERP_FLAGS_16BITS
);
1364 for (r
=0; r
< 0xff; r
++)
1365 for (g
=0; g
< 0xff; g
++)
1366 for (b
=0; b
< 0xff; b
++)
1368 In
[0] = (cmsUInt16Number
) r
;
1369 In
[1] = (cmsUInt16Number
) g
;
1370 In
[2] = (cmsUInt16Number
) b
;
1373 p
->Interpolation
.Lerp16(In
, Out
, p
);
1375 if (!IsGoodWord("Channel 1", Out
[0], In
[0])) goto Error
;
1376 if (!IsGoodWord("Channel 2", Out
[1], In
[1])) goto Error
;
1377 if (!IsGoodWord("Channel 3", Out
[2], In
[2])) goto Error
;
1380 _cmsFreeInterpParams(p
);
1384 _cmsFreeInterpParams(p
);
1389 cmsInt32Number
ExhaustiveCheck3DinterpolationTrilinear16(void)
1392 cmsInt32Number r
, g
, b
;
1393 cmsUInt16Number In
[3], Out
[3];
1394 cmsUInt16Number Table
[] = {
1406 0xffff, 0xffff, 0xffff
1409 p
= _cmsComputeInterpParams(DbgThread(), 2, 3, 3, Table
, CMS_LERP_FLAGS_TRILINEAR
);
1411 for (r
=0; r
< 0xff; r
++)
1412 for (g
=0; g
< 0xff; g
++)
1413 for (b
=0; b
< 0xff; b
++)
1415 In
[0] = (cmsUInt16Number
) r
;
1416 In
[1] = (cmsUInt16Number
)g
;
1417 In
[2] = (cmsUInt16Number
)b
;
1420 p
->Interpolation
.Lerp16(In
, Out
, p
);
1422 if (!IsGoodWord("Channel 1", Out
[0], In
[0])) goto Error
;
1423 if (!IsGoodWord("Channel 2", Out
[1], In
[1])) goto Error
;
1424 if (!IsGoodWord("Channel 3", Out
[2], In
[2])) goto Error
;
1428 _cmsFreeInterpParams(p
);
1432 _cmsFreeInterpParams(p
);
1436 // Check reverse interpolation on LUTS. This is right now exclusively used by K preservation algorithm
1438 cmsInt32Number
CheckReverseInterpolation3x3(void)
1442 cmsFloat32Number Target
[3], Result
[3], Hint
[3];
1443 cmsFloat32Number err
, max
;
1445 cmsUInt16Number Table
[] = {
1448 0, 0, 0xffff, // 0 0 1
1450 0, 0xffff, 0, // 0 1 0
1451 0, 0xffff, 0xffff, // 0 1 1
1453 0xffff, 0, 0, // 1 0 0
1454 0xffff, 0, 0xffff, // 1 0 1
1456 0xffff, 0xffff, 0, // 1 1 0
1457 0xffff, 0xffff, 0xffff, // 1 1 1
1462 Lut
= cmsPipelineAlloc(DbgThread(), 3, 3);
1464 clut
= cmsStageAllocCLut16bit(DbgThread(), 2, 3, 3, Table
);
1465 cmsPipelineInsertStage(Lut
, cmsAT_BEGIN
, clut
);
1467 Target
[0] = 0; Target
[1] = 0; Target
[2] = 0;
1468 Hint
[0] = 0; Hint
[1] = 0; Hint
[2] = 0;
1469 cmsPipelineEvalReverseFloat(Target
, Result
, NULL
, Lut
);
1470 if (Result
[0] != 0 || Result
[1] != 0 || Result
[2] != 0){
1472 Fail("Reverse interpolation didn't find zero");
1476 // Transverse identity
1478 for (i
=0; i
<= 100; i
++) {
1480 cmsFloat32Number in
= i
/ 100.0F
;
1482 Target
[0] = in
; Target
[1] = 0; Target
[2] = 0;
1483 cmsPipelineEvalReverseFloat(Target
, Result
, Hint
, Lut
);
1485 err
= fabsf(in
- Result
[0]);
1486 if (err
> max
) max
= err
;
1488 memcpy(Hint
, Result
, sizeof(Hint
));
1491 cmsPipelineFree(Lut
);
1492 return (max
<= FLOAT_PRECISSION
);
1497 cmsInt32Number
CheckReverseInterpolation4x3(void)
1501 cmsFloat32Number Target
[4], Result
[4], Hint
[4];
1502 cmsFloat32Number err
, max
;
1505 // 4 -> 3, output gets 3 first channels copied
1506 cmsUInt16Number Table
[] = {
1508 0, 0, 0, // 0 0 0 0 = ( 0, 0, 0)
1509 0, 0, 0, // 0 0 0 1 = ( 0, 0, 0)
1511 0, 0, 0xffff, // 0 0 1 0 = ( 0, 0, 1)
1512 0, 0, 0xffff, // 0 0 1 1 = ( 0, 0, 1)
1514 0, 0xffff, 0, // 0 1 0 0 = ( 0, 1, 0)
1515 0, 0xffff, 0, // 0 1 0 1 = ( 0, 1, 0)
1517 0, 0xffff, 0xffff, // 0 1 1 0 = ( 0, 1, 1)
1518 0, 0xffff, 0xffff, // 0 1 1 1 = ( 0, 1, 1)
1520 0xffff, 0, 0, // 1 0 0 0 = ( 1, 0, 0)
1521 0xffff, 0, 0, // 1 0 0 1 = ( 1, 0, 0)
1523 0xffff, 0, 0xffff, // 1 0 1 0 = ( 1, 0, 1)
1524 0xffff, 0, 0xffff, // 1 0 1 1 = ( 1, 0, 1)
1526 0xffff, 0xffff, 0, // 1 1 0 0 = ( 1, 1, 0)
1527 0xffff, 0xffff, 0, // 1 1 0 1 = ( 1, 1, 0)
1529 0xffff, 0xffff, 0xffff, // 1 1 1 0 = ( 1, 1, 1)
1530 0xffff, 0xffff, 0xffff, // 1 1 1 1 = ( 1, 1, 1)
1534 Lut
= cmsPipelineAlloc(DbgThread(), 4, 3);
1536 clut
= cmsStageAllocCLut16bit(DbgThread(), 2, 4, 3, Table
);
1537 cmsPipelineInsertStage(Lut
, cmsAT_BEGIN
, clut
);
1539 // Check if the LUT is behaving as expected
1540 SubTest("4->3 feasibility");
1541 for (i
=0; i
<= 100; i
++) {
1543 Target
[0] = i
/ 100.0F
;
1544 Target
[1] = Target
[0];
1548 cmsPipelineEvalFloat(Target
, Result
, Lut
);
1550 if (!IsGoodFixed15_16("0", Target
[0], Result
[0])) return 0;
1551 if (!IsGoodFixed15_16("1", Target
[1], Result
[1])) return 0;
1552 if (!IsGoodFixed15_16("2", Target
[2], Result
[2])) return 0;
1555 SubTest("4->3 zero");
1560 // This one holds the fixed K
1563 // This is our hint (which is a big lie in this case)
1564 Hint
[0] = 0.1F
; Hint
[1] = 0.1F
; Hint
[2] = 0.1F
;
1566 cmsPipelineEvalReverseFloat(Target
, Result
, Hint
, Lut
);
1568 if (Result
[0] != 0 || Result
[1] != 0 || Result
[2] != 0 || Result
[3] != 0){
1570 Fail("Reverse interpolation didn't find zero");
1574 SubTest("4->3 find CMY");
1576 for (i
=0; i
<= 100; i
++) {
1578 cmsFloat32Number in
= i
/ 100.0F
;
1580 Target
[0] = in
; Target
[1] = 0; Target
[2] = 0;
1581 cmsPipelineEvalReverseFloat(Target
, Result
, Hint
, Lut
);
1583 err
= fabsf(in
- Result
[0]);
1584 if (err
> max
) max
= err
;
1586 memcpy(Hint
, Result
, sizeof(Hint
));
1589 cmsPipelineFree(Lut
);
1590 return (max
<= FLOAT_PRECISSION
);
1595 // Check all interpolation.
1598 cmsUInt16Number
Fn8D1(cmsUInt16Number a1
, cmsUInt16Number a2
, cmsUInt16Number a3
, cmsUInt16Number a4
,
1599 cmsUInt16Number a5
, cmsUInt16Number a6
, cmsUInt16Number a7
, cmsUInt16Number a8
,
1602 return (cmsUInt16Number
) ((a1
+ a2
+ a3
+ a4
+ a5
+ a6
+ a7
+ a8
) / m
);
1607 cmsUInt16Number
Fn8D2(cmsUInt16Number a1
, cmsUInt16Number a2
, cmsUInt16Number a3
, cmsUInt16Number a4
,
1608 cmsUInt16Number a5
, cmsUInt16Number a6
, cmsUInt16Number a7
, cmsUInt16Number a8
,
1611 return (cmsUInt16Number
) ((a1
+ 3* a2
+ 3* a3
+ a4
+ a5
+ a6
+ a7
+ a8
) / (m
+ 4));
1616 cmsUInt16Number
Fn8D3(cmsUInt16Number a1
, cmsUInt16Number a2
, cmsUInt16Number a3
, cmsUInt16Number a4
,
1617 cmsUInt16Number a5
, cmsUInt16Number a6
, cmsUInt16Number a7
, cmsUInt16Number a8
,
1620 return (cmsUInt16Number
) ((3*a1
+ 2*a2
+ 3*a3
+ a4
+ a5
+ a6
+ a7
+ a8
) / (m
+ 5));
1627 cmsInt32Number
Sampler3D(register const cmsUInt16Number In
[],
1628 register cmsUInt16Number Out
[],
1629 register void * Cargo
)
1632 Out
[0] = Fn8D1(In
[0], In
[1], In
[2], 0, 0, 0, 0, 0, 3);
1633 Out
[1] = Fn8D2(In
[0], In
[1], In
[2], 0, 0, 0, 0, 0, 3);
1634 Out
[2] = Fn8D3(In
[0], In
[1], In
[2], 0, 0, 0, 0, 0, 3);
1638 cmsUNUSED_PARAMETER(Cargo
);
1643 cmsInt32Number
Sampler4D(register const cmsUInt16Number In
[],
1644 register cmsUInt16Number Out
[],
1645 register void * Cargo
)
1648 Out
[0] = Fn8D1(In
[0], In
[1], In
[2], In
[3], 0, 0, 0, 0, 4);
1649 Out
[1] = Fn8D2(In
[0], In
[1], In
[2], In
[3], 0, 0, 0, 0, 4);
1650 Out
[2] = Fn8D3(In
[0], In
[1], In
[2], In
[3], 0, 0, 0, 0, 4);
1654 cmsUNUSED_PARAMETER(Cargo
);
1658 cmsInt32Number
Sampler5D(register const cmsUInt16Number In
[],
1659 register cmsUInt16Number Out
[],
1660 register void * Cargo
)
1663 Out
[0] = Fn8D1(In
[0], In
[1], In
[2], In
[3], In
[4], 0, 0, 0, 5);
1664 Out
[1] = Fn8D2(In
[0], In
[1], In
[2], In
[3], In
[4], 0, 0, 0, 5);
1665 Out
[2] = Fn8D3(In
[0], In
[1], In
[2], In
[3], In
[4], 0, 0, 0, 5);
1669 cmsUNUSED_PARAMETER(Cargo
);
1673 cmsInt32Number
Sampler6D(register const cmsUInt16Number In
[],
1674 register cmsUInt16Number Out
[],
1675 register void * Cargo
)
1678 Out
[0] = Fn8D1(In
[0], In
[1], In
[2], In
[3], In
[4], In
[5], 0, 0, 6);
1679 Out
[1] = Fn8D2(In
[0], In
[1], In
[2], In
[3], In
[4], In
[5], 0, 0, 6);
1680 Out
[2] = Fn8D3(In
[0], In
[1], In
[2], In
[3], In
[4], In
[5], 0, 0, 6);
1684 cmsUNUSED_PARAMETER(Cargo
);
1688 cmsInt32Number
Sampler7D(register const cmsUInt16Number In
[],
1689 register cmsUInt16Number Out
[],
1690 register void * Cargo
)
1693 Out
[0] = Fn8D1(In
[0], In
[1], In
[2], In
[3], In
[4], In
[5], In
[6], 0, 7);
1694 Out
[1] = Fn8D2(In
[0], In
[1], In
[2], In
[3], In
[4], In
[5], In
[6], 0, 7);
1695 Out
[2] = Fn8D3(In
[0], In
[1], In
[2], In
[3], In
[4], In
[5], In
[6], 0, 7);
1699 cmsUNUSED_PARAMETER(Cargo
);
1703 cmsInt32Number
Sampler8D(register const cmsUInt16Number In
[],
1704 register cmsUInt16Number Out
[],
1705 register void * Cargo
)
1708 Out
[0] = Fn8D1(In
[0], In
[1], In
[2], In
[3], In
[4], In
[5], In
[6], In
[7], 8);
1709 Out
[1] = Fn8D2(In
[0], In
[1], In
[2], In
[3], In
[4], In
[5], In
[6], In
[7], 8);
1710 Out
[2] = Fn8D3(In
[0], In
[1], In
[2], In
[3], In
[4], In
[5], In
[6], In
[7], 8);
1714 cmsUNUSED_PARAMETER(Cargo
);
1718 cmsBool
CheckOne3D(cmsPipeline
* lut
, cmsUInt16Number a1
, cmsUInt16Number a2
, cmsUInt16Number a3
)
1720 cmsUInt16Number In
[3], Out1
[3], Out2
[3];
1722 In
[0] = a1
; In
[1] = a2
; In
[2] = a3
;
1724 // This is the interpolated value
1725 cmsPipelineEval16(In
, Out1
, lut
);
1727 // This is the real value
1728 Sampler3D(In
, Out2
, NULL
);
1730 // Let's see the difference
1732 if (!IsGoodWordPrec("Channel 1", Out1
[0], Out2
[0], 2)) return FALSE
;
1733 if (!IsGoodWordPrec("Channel 2", Out1
[1], Out2
[1], 2)) return FALSE
;
1734 if (!IsGoodWordPrec("Channel 3", Out1
[2], Out2
[2], 2)) return FALSE
;
1740 cmsBool
CheckOne4D(cmsPipeline
* lut
, cmsUInt16Number a1
, cmsUInt16Number a2
, cmsUInt16Number a3
, cmsUInt16Number a4
)
1742 cmsUInt16Number In
[4], Out1
[3], Out2
[3];
1744 In
[0] = a1
; In
[1] = a2
; In
[2] = a3
; In
[3] = a4
;
1746 // This is the interpolated value
1747 cmsPipelineEval16(In
, Out1
, lut
);
1749 // This is the real value
1750 Sampler4D(In
, Out2
, NULL
);
1752 // Let's see the difference
1754 if (!IsGoodWordPrec("Channel 1", Out1
[0], Out2
[0], 2)) return FALSE
;
1755 if (!IsGoodWordPrec("Channel 2", Out1
[1], Out2
[1], 2)) return FALSE
;
1756 if (!IsGoodWordPrec("Channel 3", Out1
[2], Out2
[2], 2)) return FALSE
;
1762 cmsBool
CheckOne5D(cmsPipeline
* lut
, cmsUInt16Number a1
, cmsUInt16Number a2
,
1763 cmsUInt16Number a3
, cmsUInt16Number a4
, cmsUInt16Number a5
)
1765 cmsUInt16Number In
[5], Out1
[3], Out2
[3];
1767 In
[0] = a1
; In
[1] = a2
; In
[2] = a3
; In
[3] = a4
; In
[4] = a5
;
1769 // This is the interpolated value
1770 cmsPipelineEval16(In
, Out1
, lut
);
1772 // This is the real value
1773 Sampler5D(In
, Out2
, NULL
);
1775 // Let's see the difference
1777 if (!IsGoodWordPrec("Channel 1", Out1
[0], Out2
[0], 2)) return FALSE
;
1778 if (!IsGoodWordPrec("Channel 2", Out1
[1], Out2
[1], 2)) return FALSE
;
1779 if (!IsGoodWordPrec("Channel 3", Out1
[2], Out2
[2], 2)) return FALSE
;
1785 cmsBool
CheckOne6D(cmsPipeline
* lut
, cmsUInt16Number a1
, cmsUInt16Number a2
,
1786 cmsUInt16Number a3
, cmsUInt16Number a4
,
1787 cmsUInt16Number a5
, cmsUInt16Number a6
)
1789 cmsUInt16Number In
[6], Out1
[3], Out2
[3];
1791 In
[0] = a1
; In
[1] = a2
; In
[2] = a3
; In
[3] = a4
; In
[4] = a5
; In
[5] = a6
;
1793 // This is the interpolated value
1794 cmsPipelineEval16(In
, Out1
, lut
);
1796 // This is the real value
1797 Sampler6D(In
, Out2
, NULL
);
1799 // Let's see the difference
1801 if (!IsGoodWordPrec("Channel 1", Out1
[0], Out2
[0], 2)) return FALSE
;
1802 if (!IsGoodWordPrec("Channel 2", Out1
[1], Out2
[1], 2)) return FALSE
;
1803 if (!IsGoodWordPrec("Channel 3", Out1
[2], Out2
[2], 2)) return FALSE
;
1810 cmsBool
CheckOne7D(cmsPipeline
* lut
, cmsUInt16Number a1
, cmsUInt16Number a2
,
1811 cmsUInt16Number a3
, cmsUInt16Number a4
,
1812 cmsUInt16Number a5
, cmsUInt16Number a6
,
1815 cmsUInt16Number In
[7], Out1
[3], Out2
[3];
1817 In
[0] = a1
; In
[1] = a2
; In
[2] = a3
; In
[3] = a4
; In
[4] = a5
; In
[5] = a6
; In
[6] = a7
;
1819 // This is the interpolated value
1820 cmsPipelineEval16(In
, Out1
, lut
);
1822 // This is the real value
1823 Sampler7D(In
, Out2
, NULL
);
1825 // Let's see the difference
1827 if (!IsGoodWordPrec("Channel 1", Out1
[0], Out2
[0], 2)) return FALSE
;
1828 if (!IsGoodWordPrec("Channel 2", Out1
[1], Out2
[1], 2)) return FALSE
;
1829 if (!IsGoodWordPrec("Channel 3", Out1
[2], Out2
[2], 2)) return FALSE
;
1836 cmsBool
CheckOne8D(cmsPipeline
* lut
, cmsUInt16Number a1
, cmsUInt16Number a2
,
1837 cmsUInt16Number a3
, cmsUInt16Number a4
,
1838 cmsUInt16Number a5
, cmsUInt16Number a6
,
1839 cmsUInt16Number a7
, cmsUInt16Number a8
)
1841 cmsUInt16Number In
[8], Out1
[3], Out2
[3];
1843 In
[0] = a1
; In
[1] = a2
; In
[2] = a3
; In
[3] = a4
; In
[4] = a5
; In
[5] = a6
; In
[6] = a7
; In
[7] = a8
;
1845 // This is the interpolated value
1846 cmsPipelineEval16(In
, Out1
, lut
);
1848 // This is the real value
1849 Sampler8D(In
, Out2
, NULL
);
1851 // Let's see the difference
1853 if (!IsGoodWordPrec("Channel 1", Out1
[0], Out2
[0], 2)) return FALSE
;
1854 if (!IsGoodWordPrec("Channel 2", Out1
[1], Out2
[1], 2)) return FALSE
;
1855 if (!IsGoodWordPrec("Channel 3", Out1
[2], Out2
[2], 2)) return FALSE
;
1862 cmsInt32Number
Check3Dinterp(void)
1867 lut
= cmsPipelineAlloc(DbgThread(), 3, 3);
1868 mpe
= cmsStageAllocCLut16bit(DbgThread(), 9, 3, 3, NULL
);
1869 cmsStageSampleCLut16bit(mpe
, Sampler3D
, NULL
, 0);
1870 cmsPipelineInsertStage(lut
, cmsAT_BEGIN
, mpe
);
1874 if (!CheckOne3D(lut
, 0, 0, 0)) return 0;
1875 if (!CheckOne3D(lut
, 0xffff, 0xffff, 0xffff)) return 0;
1877 if (!CheckOne3D(lut
, 0x8080, 0x8080, 0x8080)) return 0;
1878 if (!CheckOne3D(lut
, 0x0000, 0xFE00, 0x80FF)) return 0;
1879 if (!CheckOne3D(lut
, 0x1111, 0x2222, 0x3333)) return 0;
1880 if (!CheckOne3D(lut
, 0x0000, 0x0012, 0x0013)) return 0;
1881 if (!CheckOne3D(lut
, 0x3141, 0x1415, 0x1592)) return 0;
1882 if (!CheckOne3D(lut
, 0xFF00, 0xFF01, 0xFF12)) return 0;
1884 cmsPipelineFree(lut
);
1890 cmsInt32Number
Check3DinterpGranular(void)
1894 cmsUInt32Number Dimensions
[] = { 7, 8, 9 };
1896 lut
= cmsPipelineAlloc(DbgThread(), 3, 3);
1897 mpe
= cmsStageAllocCLut16bitGranular(DbgThread(), Dimensions
, 3, 3, NULL
);
1898 cmsStageSampleCLut16bit(mpe
, Sampler3D
, NULL
, 0);
1899 cmsPipelineInsertStage(lut
, cmsAT_BEGIN
, mpe
);
1903 if (!CheckOne3D(lut
, 0, 0, 0)) return 0;
1904 if (!CheckOne3D(lut
, 0xffff, 0xffff, 0xffff)) return 0;
1906 if (!CheckOne3D(lut
, 0x8080, 0x8080, 0x8080)) return 0;
1907 if (!CheckOne3D(lut
, 0x0000, 0xFE00, 0x80FF)) return 0;
1908 if (!CheckOne3D(lut
, 0x1111, 0x2222, 0x3333)) return 0;
1909 if (!CheckOne3D(lut
, 0x0000, 0x0012, 0x0013)) return 0;
1910 if (!CheckOne3D(lut
, 0x3141, 0x1415, 0x1592)) return 0;
1911 if (!CheckOne3D(lut
, 0xFF00, 0xFF01, 0xFF12)) return 0;
1913 cmsPipelineFree(lut
);
1920 cmsInt32Number
Check4Dinterp(void)
1925 lut
= cmsPipelineAlloc(DbgThread(), 4, 3);
1926 mpe
= cmsStageAllocCLut16bit(DbgThread(), 9, 4, 3, NULL
);
1927 cmsStageSampleCLut16bit(mpe
, Sampler4D
, NULL
, 0);
1928 cmsPipelineInsertStage(lut
, cmsAT_BEGIN
, mpe
);
1932 if (!CheckOne4D(lut
, 0, 0, 0, 0)) return 0;
1933 if (!CheckOne4D(lut
, 0xffff, 0xffff, 0xffff, 0xffff)) return 0;
1935 if (!CheckOne4D(lut
, 0x8080, 0x8080, 0x8080, 0x8080)) return 0;
1936 if (!CheckOne4D(lut
, 0x0000, 0xFE00, 0x80FF, 0x8888)) return 0;
1937 if (!CheckOne4D(lut
, 0x1111, 0x2222, 0x3333, 0x4444)) return 0;
1938 if (!CheckOne4D(lut
, 0x0000, 0x0012, 0x0013, 0x0014)) return 0;
1939 if (!CheckOne4D(lut
, 0x3141, 0x1415, 0x1592, 0x9261)) return 0;
1940 if (!CheckOne4D(lut
, 0xFF00, 0xFF01, 0xFF12, 0xFF13)) return 0;
1942 cmsPipelineFree(lut
);
1950 cmsInt32Number
Check4DinterpGranular(void)
1954 cmsUInt32Number Dimensions
[] = { 9, 8, 7, 6 };
1956 lut
= cmsPipelineAlloc(DbgThread(), 4, 3);
1957 mpe
= cmsStageAllocCLut16bitGranular(DbgThread(), Dimensions
, 4, 3, NULL
);
1958 cmsStageSampleCLut16bit(mpe
, Sampler4D
, NULL
, 0);
1959 cmsPipelineInsertStage(lut
, cmsAT_BEGIN
, mpe
);
1963 if (!CheckOne4D(lut
, 0, 0, 0, 0)) return 0;
1964 if (!CheckOne4D(lut
, 0xffff, 0xffff, 0xffff, 0xffff)) return 0;
1966 if (!CheckOne4D(lut
, 0x8080, 0x8080, 0x8080, 0x8080)) return 0;
1967 if (!CheckOne4D(lut
, 0x0000, 0xFE00, 0x80FF, 0x8888)) return 0;
1968 if (!CheckOne4D(lut
, 0x1111, 0x2222, 0x3333, 0x4444)) return 0;
1969 if (!CheckOne4D(lut
, 0x0000, 0x0012, 0x0013, 0x0014)) return 0;
1970 if (!CheckOne4D(lut
, 0x3141, 0x1415, 0x1592, 0x9261)) return 0;
1971 if (!CheckOne4D(lut
, 0xFF00, 0xFF01, 0xFF12, 0xFF13)) return 0;
1973 cmsPipelineFree(lut
);
1980 cmsInt32Number
Check5DinterpGranular(void)
1984 cmsUInt32Number Dimensions
[] = { 3, 2, 2, 2, 2 };
1986 lut
= cmsPipelineAlloc(DbgThread(), 5, 3);
1987 mpe
= cmsStageAllocCLut16bitGranular(DbgThread(), Dimensions
, 5, 3, NULL
);
1988 cmsStageSampleCLut16bit(mpe
, Sampler5D
, NULL
, 0);
1989 cmsPipelineInsertStage(lut
, cmsAT_BEGIN
, mpe
);
1993 if (!CheckOne5D(lut
, 0, 0, 0, 0, 0)) return 0;
1994 if (!CheckOne5D(lut
, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff)) return 0;
1996 if (!CheckOne5D(lut
, 0x8080, 0x8080, 0x8080, 0x8080, 0x1234)) return 0;
1997 if (!CheckOne5D(lut
, 0x0000, 0xFE00, 0x80FF, 0x8888, 0x8078)) return 0;
1998 if (!CheckOne5D(lut
, 0x1111, 0x2222, 0x3333, 0x4444, 0x1455)) return 0;
1999 if (!CheckOne5D(lut
, 0x0000, 0x0012, 0x0013, 0x0014, 0x2333)) return 0;
2000 if (!CheckOne5D(lut
, 0x3141, 0x1415, 0x1592, 0x9261, 0x4567)) return 0;
2001 if (!CheckOne5D(lut
, 0xFF00, 0xFF01, 0xFF12, 0xFF13, 0xF344)) return 0;
2003 cmsPipelineFree(lut
);
2009 cmsInt32Number
Check6DinterpGranular(void)
2013 cmsUInt32Number Dimensions
[] = { 4, 3, 3, 2, 2, 2 };
2015 lut
= cmsPipelineAlloc(DbgThread(), 6, 3);
2016 mpe
= cmsStageAllocCLut16bitGranular(DbgThread(), Dimensions
, 6, 3, NULL
);
2017 cmsStageSampleCLut16bit(mpe
, Sampler6D
, NULL
, 0);
2018 cmsPipelineInsertStage(lut
, cmsAT_BEGIN
, mpe
);
2022 if (!CheckOne6D(lut
, 0, 0, 0, 0, 0, 0)) return 0;
2023 if (!CheckOne6D(lut
, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff)) return 0;
2025 if (!CheckOne6D(lut
, 0x8080, 0x8080, 0x8080, 0x8080, 0x1234, 0x1122)) return 0;
2026 if (!CheckOne6D(lut
, 0x0000, 0xFE00, 0x80FF, 0x8888, 0x8078, 0x2233)) return 0;
2027 if (!CheckOne6D(lut
, 0x1111, 0x2222, 0x3333, 0x4444, 0x1455, 0x3344)) return 0;
2028 if (!CheckOne6D(lut
, 0x0000, 0x0012, 0x0013, 0x0014, 0x2333, 0x4455)) return 0;
2029 if (!CheckOne6D(lut
, 0x3141, 0x1415, 0x1592, 0x9261, 0x4567, 0x5566)) return 0;
2030 if (!CheckOne6D(lut
, 0xFF00, 0xFF01, 0xFF12, 0xFF13, 0xF344, 0x6677)) return 0;
2032 cmsPipelineFree(lut
);
2038 cmsInt32Number
Check7DinterpGranular(void)
2042 cmsUInt32Number Dimensions
[] = { 4, 3, 3, 2, 2, 2, 2 };
2044 lut
= cmsPipelineAlloc(DbgThread(), 7, 3);
2045 mpe
= cmsStageAllocCLut16bitGranular(DbgThread(), Dimensions
, 7, 3, NULL
);
2046 cmsStageSampleCLut16bit(mpe
, Sampler7D
, NULL
, 0);
2047 cmsPipelineInsertStage(lut
, cmsAT_BEGIN
, mpe
);
2051 if (!CheckOne7D(lut
, 0, 0, 0, 0, 0, 0, 0)) return 0;
2052 if (!CheckOne7D(lut
, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff)) return 0;
2054 if (!CheckOne7D(lut
, 0x8080, 0x8080, 0x8080, 0x8080, 0x1234, 0x1122, 0x0056)) return 0;
2055 if (!CheckOne7D(lut
, 0x0000, 0xFE00, 0x80FF, 0x8888, 0x8078, 0x2233, 0x0088)) return 0;
2056 if (!CheckOne7D(lut
, 0x1111, 0x2222, 0x3333, 0x4444, 0x1455, 0x3344, 0x1987)) return 0;
2057 if (!CheckOne7D(lut
, 0x0000, 0x0012, 0x0013, 0x0014, 0x2333, 0x4455, 0x9988)) return 0;
2058 if (!CheckOne7D(lut
, 0x3141, 0x1415, 0x1592, 0x9261, 0x4567, 0x5566, 0xfe56)) return 0;
2059 if (!CheckOne7D(lut
, 0xFF00, 0xFF01, 0xFF12, 0xFF13, 0xF344, 0x6677, 0xbabe)) return 0;
2061 cmsPipelineFree(lut
);
2068 cmsInt32Number
Check8DinterpGranular(void)
2072 cmsUInt32Number Dimensions
[] = { 4, 3, 3, 2, 2, 2, 2, 2 };
2074 lut
= cmsPipelineAlloc(DbgThread(), 8, 3);
2075 mpe
= cmsStageAllocCLut16bitGranular(DbgThread(), Dimensions
, 8, 3, NULL
);
2076 cmsStageSampleCLut16bit(mpe
, Sampler8D
, NULL
, 0);
2077 cmsPipelineInsertStage(lut
, cmsAT_BEGIN
, mpe
);
2081 if (!CheckOne8D(lut
, 0, 0, 0, 0, 0, 0, 0, 0)) return 0;
2082 if (!CheckOne8D(lut
, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff)) return 0;
2084 if (!CheckOne8D(lut
, 0x8080, 0x8080, 0x8080, 0x8080, 0x1234, 0x1122, 0x0056, 0x0011)) return 0;
2085 if (!CheckOne8D(lut
, 0x0000, 0xFE00, 0x80FF, 0x8888, 0x8078, 0x2233, 0x0088, 0x2020)) return 0;
2086 if (!CheckOne8D(lut
, 0x1111, 0x2222, 0x3333, 0x4444, 0x1455, 0x3344, 0x1987, 0x4532)) return 0;
2087 if (!CheckOne8D(lut
, 0x0000, 0x0012, 0x0013, 0x0014, 0x2333, 0x4455, 0x9988, 0x1200)) return 0;
2088 if (!CheckOne8D(lut
, 0x3141, 0x1415, 0x1592, 0x9261, 0x4567, 0x5566, 0xfe56, 0x6666)) return 0;
2089 if (!CheckOne8D(lut
, 0xFF00, 0xFF01, 0xFF12, 0xFF13, 0xF344, 0x6677, 0xbabe, 0xface)) return 0;
2091 cmsPipelineFree(lut
);
2096 // Colorimetric conversions -------------------------------------------------------------------------------------------------
2098 // Lab to LCh and back should be performed at 1E-12 accuracy at least
2100 cmsInt32Number
CheckLab2LCh(void)
2102 cmsInt32Number l
, a
, b
;
2103 cmsFloat64Number dist
, Max
= 0;
2104 cmsCIELab Lab
, Lab2
;
2107 for (l
=0; l
<= 100; l
+= 10) {
2109 for (a
=-128; a
<= +128; a
+= 8) {
2111 for (b
=-128; b
<= 128; b
+= 8) {
2117 cmsLab2LCh(&LCh
, &Lab
);
2118 cmsLCh2Lab(&Lab2
, &LCh
);
2120 dist
= cmsDeltaE(&Lab
, &Lab2
);
2121 if (dist
> Max
) Max
= dist
;
2129 // Lab to LCh and back should be performed at 1E-12 accuracy at least
2131 cmsInt32Number
CheckLab2XYZ(void)
2133 cmsInt32Number l
, a
, b
;
2134 cmsFloat64Number dist
, Max
= 0;
2135 cmsCIELab Lab
, Lab2
;
2138 for (l
=0; l
<= 100; l
+= 10) {
2140 for (a
=-128; a
<= +128; a
+= 8) {
2142 for (b
=-128; b
<= 128; b
+= 8) {
2148 cmsLab2XYZ(NULL
, &XYZ
, &Lab
);
2149 cmsXYZ2Lab(NULL
, &Lab2
, &XYZ
);
2151 dist
= cmsDeltaE(&Lab
, &Lab2
);
2152 if (dist
> Max
) Max
= dist
;
2161 // Lab to xyY and back should be performed at 1E-12 accuracy at least
2163 cmsInt32Number
CheckLab2xyY(void)
2165 cmsInt32Number l
, a
, b
;
2166 cmsFloat64Number dist
, Max
= 0;
2167 cmsCIELab Lab
, Lab2
;
2171 for (l
=0; l
<= 100; l
+= 10) {
2173 for (a
=-128; a
<= +128; a
+= 8) {
2175 for (b
=-128; b
<= 128; b
+= 8) {
2181 cmsLab2XYZ(NULL
, &XYZ
, &Lab
);
2182 cmsXYZ2xyY(&xyY
, &XYZ
);
2183 cmsxyY2XYZ(&XYZ
, &xyY
);
2184 cmsXYZ2Lab(NULL
, &Lab2
, &XYZ
);
2186 dist
= cmsDeltaE(&Lab
, &Lab2
);
2187 if (dist
> Max
) Max
= dist
;
2198 cmsInt32Number
CheckLabV2encoding(void)
2200 cmsInt32Number n2
, i
, j
;
2201 cmsUInt16Number Inw
[3], aw
[3];
2206 for (j
=0; j
< 65535; j
++) {
2208 Inw
[0] = Inw
[1] = Inw
[2] = (cmsUInt16Number
) j
;
2210 cmsLabEncoded2FloatV2(&Lab
, Inw
);
2211 cmsFloat2LabEncodedV2(aw
, &Lab
);
2213 for (i
=0; i
< 3; i
++) {
2226 cmsInt32Number
CheckLabV4encoding(void)
2228 cmsInt32Number n2
, i
, j
;
2229 cmsUInt16Number Inw
[3], aw
[3];
2234 for (j
=0; j
< 65535; j
++) {
2236 Inw
[0] = Inw
[1] = Inw
[2] = (cmsUInt16Number
) j
;
2238 cmsLabEncoded2Float(&Lab
, Inw
);
2239 cmsFloat2LabEncoded(aw
, &Lab
);
2241 for (i
=0; i
< 3; i
++) {
2254 // BlackBody -----------------------------------------------------------------------------------------------------
2257 cmsInt32Number
CheckTemp2CHRM(void)
2260 cmsFloat64Number d
, v
, Max
= 0;
2263 for (j
=4000; j
< 25000; j
++) {
2265 cmsWhitePointFromTemp(&White
, j
);
2266 if (!cmsTempFromWhitePoint(&v
, &White
)) return 0;
2269 if (d
> Max
) Max
= d
;
2272 // 100 degree is the actual resolution
2278 // Tone curves -----------------------------------------------------------------------------------------------------
2281 cmsInt32Number
CheckGammaEstimation(cmsToneCurve
* c
, cmsFloat64Number g
)
2283 cmsFloat64Number est
= cmsEstimateGamma(c
, 0.001);
2285 SubTest("Gamma estimation");
2286 if (fabs(est
- g
) > 0.001) return 0;
2291 cmsInt32Number
CheckGammaCreation16(void)
2293 cmsToneCurve
* LinGamma
= cmsBuildGamma(DbgThread(), 1.0);
2295 cmsUInt16Number in
, out
;
2297 for (i
=0; i
< 0xffff; i
++) {
2299 in
= (cmsUInt16Number
) i
;
2300 out
= cmsEvalToneCurve16(LinGamma
, in
);
2302 Fail("(lin gamma): Must be %x, But is %x : ", in
, out
);
2303 cmsFreeToneCurve(LinGamma
);
2308 if (!CheckGammaEstimation(LinGamma
, 1.0)) return 0;
2310 cmsFreeToneCurve(LinGamma
);
2316 cmsInt32Number
CheckGammaCreationFlt(void)
2318 cmsToneCurve
* LinGamma
= cmsBuildGamma(DbgThread(), 1.0);
2320 cmsFloat32Number in
, out
;
2322 for (i
=0; i
< 0xffff; i
++) {
2324 in
= (cmsFloat32Number
) (i
/ 65535.0);
2325 out
= cmsEvalToneCurveFloat(LinGamma
, in
);
2326 if (fabs(in
- out
) > (1/65535.0)) {
2327 Fail("(lin gamma): Must be %f, But is %f : ", in
, out
);
2328 cmsFreeToneCurve(LinGamma
);
2333 if (!CheckGammaEstimation(LinGamma
, 1.0)) return 0;
2334 cmsFreeToneCurve(LinGamma
);
2338 // Curve curves using a single power function
2339 // Error is given in 0..ffff counts
2341 cmsInt32Number
CheckGammaFloat(cmsFloat64Number g
)
2343 cmsToneCurve
* Curve
= cmsBuildGamma(DbgThread(), g
);
2345 cmsFloat32Number in
, out
;
2346 cmsFloat64Number val
, Err
;
2349 for (i
=0; i
< 0xffff; i
++) {
2351 in
= (cmsFloat32Number
) (i
/ 65535.0);
2352 out
= cmsEvalToneCurveFloat(Curve
, in
);
2353 val
= pow((cmsFloat64Number
) in
, g
);
2355 Err
= fabs( val
- out
);
2356 if (Err
> MaxErr
) MaxErr
= Err
;
2359 if (MaxErr
> 0) printf("|Err|<%lf ", MaxErr
* 65535.0);
2361 if (!CheckGammaEstimation(Curve
, g
)) return 0;
2363 cmsFreeToneCurve(Curve
);
2367 static cmsInt32Number
CheckGamma18(void)
2369 return CheckGammaFloat(1.8);
2372 static cmsInt32Number
CheckGamma22(void)
2374 return CheckGammaFloat(2.2);
2377 static cmsInt32Number
CheckGamma30(void)
2379 return CheckGammaFloat(3.0);
2383 // Check table-based gamma functions
2385 cmsInt32Number
CheckGammaFloatTable(cmsFloat64Number g
)
2387 cmsFloat32Number Values
[1025];
2388 cmsToneCurve
* Curve
;
2390 cmsFloat32Number in
, out
;
2391 cmsFloat64Number val
, Err
;
2393 for (i
=0; i
<= 1024; i
++) {
2395 in
= (cmsFloat32Number
) (i
/ 1024.0);
2396 Values
[i
] = powf(in
, (float) g
);
2399 Curve
= cmsBuildTabulatedToneCurveFloat(DbgThread(), 1025, Values
);
2402 for (i
=0; i
<= 0xffff; i
++) {
2404 in
= (cmsFloat32Number
) (i
/ 65535.0);
2405 out
= cmsEvalToneCurveFloat(Curve
, in
);
2408 Err
= fabs(val
- out
);
2409 if (Err
> MaxErr
) MaxErr
= Err
;
2412 if (MaxErr
> 0) printf("|Err|<%lf ", MaxErr
* 65535.0);
2414 if (!CheckGammaEstimation(Curve
, g
)) return 0;
2416 cmsFreeToneCurve(Curve
);
2421 static cmsInt32Number
CheckGamma18Table(void)
2423 return CheckGammaFloatTable(1.8);
2426 static cmsInt32Number
CheckGamma22Table(void)
2428 return CheckGammaFloatTable(2.2);
2431 static cmsInt32Number
CheckGamma30Table(void)
2433 return CheckGammaFloatTable(3.0);
2436 // Create a curve from a table (which is a pure gamma function) and check it against the pow function.
2438 cmsInt32Number
CheckGammaWordTable(cmsFloat64Number g
)
2440 cmsUInt16Number Values
[1025];
2441 cmsToneCurve
* Curve
;
2443 cmsFloat32Number in
, out
;
2444 cmsFloat64Number val
, Err
;
2446 for (i
=0; i
<= 1024; i
++) {
2448 in
= (cmsFloat32Number
) (i
/ 1024.0);
2449 Values
[i
] = (cmsUInt16Number
) floor(pow(in
, g
) * 65535.0 + 0.5);
2452 Curve
= cmsBuildTabulatedToneCurve16(DbgThread(), 1025, Values
);
2455 for (i
=0; i
<= 0xffff; i
++) {
2457 in
= (cmsFloat32Number
) (i
/ 65535.0);
2458 out
= cmsEvalToneCurveFloat(Curve
, in
);
2461 Err
= fabs(val
- out
);
2462 if (Err
> MaxErr
) MaxErr
= Err
;
2465 if (MaxErr
> 0) printf("|Err|<%lf ", MaxErr
* 65535.0);
2467 if (!CheckGammaEstimation(Curve
, g
)) return 0;
2469 cmsFreeToneCurve(Curve
);
2473 static cmsInt32Number
CheckGamma18TableWord(void)
2475 return CheckGammaWordTable(1.8);
2478 static cmsInt32Number
CheckGamma22TableWord(void)
2480 return CheckGammaWordTable(2.2);
2483 static cmsInt32Number
CheckGamma30TableWord(void)
2485 return CheckGammaWordTable(3.0);
2489 // Curve joining test. Joining two high-gamma of 3.0 curves should
2490 // give something like linear
2492 cmsInt32Number
CheckJointCurves(void)
2494 cmsToneCurve
*Forward
, *Reverse
, *Result
;
2497 Forward
= cmsBuildGamma(DbgThread(), 3.0);
2498 Reverse
= cmsBuildGamma(DbgThread(), 3.0);
2500 Result
= cmsJoinToneCurve(DbgThread(), Forward
, Reverse
, 256);
2502 cmsFreeToneCurve(Forward
); cmsFreeToneCurve(Reverse
);
2504 rc
= cmsIsToneCurveLinear(Result
);
2505 cmsFreeToneCurve(Result
);
2508 Fail("Joining same curve twice does not result in a linear ramp");
2514 // Create a gamma curve by cheating the table
2516 cmsToneCurve
* GammaTableLinear(cmsInt32Number nEntries
, cmsBool Dir
)
2519 cmsToneCurve
* g
= cmsBuildTabulatedToneCurve16(DbgThread(), nEntries
, NULL
);
2521 for (i
=0; i
< nEntries
; i
++) {
2523 cmsInt32Number v
= _cmsQuantizeVal(i
, nEntries
);
2526 g
->Table16
[i
] = (cmsUInt16Number
) v
;
2528 g
->Table16
[i
] = (cmsUInt16Number
) (0xFFFF - v
);
2536 cmsInt32Number
CheckJointCurvesDescending(void)
2538 cmsToneCurve
*Forward
, *Reverse
, *Result
;
2539 cmsInt32Number i
, rc
;
2541 Forward
= cmsBuildGamma(DbgThread(), 2.2);
2543 // Fake the curve to be table-based
2545 for (i
=0; i
< 4096; i
++)
2546 Forward
->Table16
[i
] = 0xffff - Forward
->Table16
[i
];
2547 Forward
->Segments
[0].Type
= 0;
2549 Reverse
= cmsReverseToneCurve(Forward
);
2551 Result
= cmsJoinToneCurve(DbgThread(), Reverse
, Reverse
, 256);
2553 cmsFreeToneCurve(Forward
);
2554 cmsFreeToneCurve(Reverse
);
2556 rc
= cmsIsToneCurveLinear(Result
);
2557 cmsFreeToneCurve(Result
);
2564 cmsInt32Number
CheckFToneCurvePoint(cmsToneCurve
* c
, cmsUInt16Number Point
, cmsInt32Number Value
)
2566 cmsInt32Number Result
;
2568 Result
= cmsEvalToneCurve16(c
, Point
);
2570 return (abs(Value
- Result
) < 2);
2574 cmsInt32Number
CheckReverseDegenerated(void)
2576 cmsToneCurve
* p
, *g
;
2577 cmsUInt16Number Tab
[16];
2596 p
= cmsBuildTabulatedToneCurve16(DbgThread(), 16, Tab
);
2597 g
= cmsReverseToneCurve(p
);
2599 // Now let's check some points
2600 if (!CheckFToneCurvePoint(g
, 0x5555, 0x5555)) return 0;
2601 if (!CheckFToneCurvePoint(g
, 0x7777, 0x7777)) return 0;
2603 // First point for zero
2604 if (!CheckFToneCurvePoint(g
, 0x0000, 0x4444)) return 0;
2607 if (!CheckFToneCurvePoint(g
, 0xFFFF, 0xFFFF)) return 0;
2609 cmsFreeToneCurve(p
);
2610 cmsFreeToneCurve(g
);
2616 // Build a parametric sRGB-like curve
2618 cmsToneCurve
* Build_sRGBGamma(void)
2620 cmsFloat64Number Parameters
[5];
2622 Parameters
[0] = 2.4;
2623 Parameters
[1] = 1. / 1.055;
2624 Parameters
[2] = 0.055 / 1.055;
2625 Parameters
[3] = 1. / 12.92;
2626 Parameters
[4] = 0.04045; // d
2628 return cmsBuildParametricToneCurve(DbgThread(), 4, Parameters
);
2633 // Join two gamma tables in floting point format. Result should be a straight line
2635 cmsToneCurve
* CombineGammaFloat(cmsToneCurve
* g1
, cmsToneCurve
* g2
)
2637 cmsUInt16Number Tab
[256];
2641 for (i
=0; i
< 256; i
++) {
2643 f
= (cmsFloat32Number
) i
/ 255.0F
;
2644 f
= cmsEvalToneCurveFloat(g2
, cmsEvalToneCurveFloat(g1
, f
));
2646 Tab
[i
] = (cmsUInt16Number
) floor(f
* 65535.0 + 0.5);
2649 return cmsBuildTabulatedToneCurve16(DbgThread(), 256, Tab
);
2652 // Same of anterior, but using quantized tables
2654 cmsToneCurve
* CombineGamma16(cmsToneCurve
* g1
, cmsToneCurve
* g2
)
2656 cmsUInt16Number Tab
[256];
2660 for (i
=0; i
< 256; i
++) {
2662 cmsUInt16Number wValIn
;
2664 wValIn
= _cmsQuantizeVal(i
, 256);
2665 Tab
[i
] = cmsEvalToneCurve16(g2
, cmsEvalToneCurve16(g1
, wValIn
));
2668 return cmsBuildTabulatedToneCurve16(DbgThread(), 256, Tab
);
2672 cmsInt32Number
CheckJointFloatCurves_sRGB(void)
2674 cmsToneCurve
*Forward
, *Reverse
, *Result
;
2677 Forward
= Build_sRGBGamma();
2678 Reverse
= cmsReverseToneCurve(Forward
);
2679 Result
= CombineGammaFloat(Forward
, Reverse
);
2680 cmsFreeToneCurve(Forward
); cmsFreeToneCurve(Reverse
);
2682 rc
= cmsIsToneCurveLinear(Result
);
2683 cmsFreeToneCurve(Result
);
2689 cmsInt32Number
CheckJoint16Curves_sRGB(void)
2691 cmsToneCurve
*Forward
, *Reverse
, *Result
;
2694 Forward
= Build_sRGBGamma();
2695 Reverse
= cmsReverseToneCurve(Forward
);
2696 Result
= CombineGamma16(Forward
, Reverse
);
2697 cmsFreeToneCurve(Forward
); cmsFreeToneCurve(Reverse
);
2699 rc
= cmsIsToneCurveLinear(Result
);
2700 cmsFreeToneCurve(Result
);
2705 // sigmoidal curve f(x) = (1-x^g) ^(1/g)
2708 cmsInt32Number
CheckJointCurvesSShaped(void)
2710 cmsFloat64Number p
= 3.2;
2711 cmsToneCurve
*Forward
, *Reverse
, *Result
;
2714 Forward
= cmsBuildParametricToneCurve(DbgThread(), 108, &p
);
2715 Reverse
= cmsReverseToneCurve(Forward
);
2716 Result
= cmsJoinToneCurve(DbgThread(), Forward
, Forward
, 4096);
2718 cmsFreeToneCurve(Forward
);
2719 cmsFreeToneCurve(Reverse
);
2721 rc
= cmsIsToneCurveLinear(Result
);
2722 cmsFreeToneCurve(Result
);
2727 // --------------------------------------------------------------------------------------------------------
2729 // Implementation of some tone curve functions
2731 cmsFloat32Number
Gamma(cmsFloat32Number x
, const cmsFloat64Number Params
[])
2733 return (cmsFloat32Number
) pow(x
, Params
[0]);
2737 cmsFloat32Number
CIE122(cmsFloat32Number x
, const cmsFloat64Number Params
[])
2740 cmsFloat64Number e
, Val
;
2742 if (x
>= -Params
[2] / Params
[1]) {
2744 e
= Params
[1]*x
+ Params
[2];
2747 Val
= pow(e
, Params
[0]);
2754 return (cmsFloat32Number
) Val
;
2758 cmsFloat32Number
IEC61966_3(cmsFloat32Number x
, const cmsFloat64Number Params
[])
2760 cmsFloat64Number e
, Val
;
2762 if (x
>= -Params
[2] / Params
[1]) {
2764 e
= Params
[1]*x
+ Params
[2];
2767 Val
= pow(e
, Params
[0]) + Params
[3];
2774 return (cmsFloat32Number
) Val
;
2778 cmsFloat32Number
IEC61966_21(cmsFloat32Number x
, const cmsFloat64Number Params
[])
2780 cmsFloat64Number e
, Val
;
2782 if (x
>= Params
[4]) {
2784 e
= Params
[1]*x
+ Params
[2];
2787 Val
= pow(e
, Params
[0]);
2792 Val
= x
* Params
[3];
2794 return (cmsFloat32Number
) Val
;
2798 cmsFloat32Number
param_5(cmsFloat32Number x
, const cmsFloat64Number Params
[])
2800 cmsFloat64Number e
, Val
;
2801 // Y = (aX + b)^Gamma + e | X >= d
2802 // Y = cX + f | else
2803 if (x
>= Params
[4]) {
2805 e
= Params
[1]*x
+ Params
[2];
2807 Val
= pow(e
, Params
[0]) + Params
[5];
2812 Val
= x
*Params
[3] + Params
[6];
2814 return (cmsFloat32Number
) Val
;
2818 cmsFloat32Number
param_6(cmsFloat32Number x
, const cmsFloat64Number Params
[])
2820 cmsFloat64Number e
, Val
;
2822 e
= Params
[1]*x
+ Params
[2];
2824 Val
= pow(e
, Params
[0]) + Params
[3];
2828 return (cmsFloat32Number
) Val
;
2832 cmsFloat32Number
param_7(cmsFloat32Number x
, const cmsFloat64Number Params
[])
2834 cmsFloat64Number Val
;
2837 Val
= Params
[1]*log10(Params
[2] * pow(x
, Params
[0]) + Params
[3]) + Params
[4];
2839 return (cmsFloat32Number
) Val
;
2844 cmsFloat32Number
param_8(cmsFloat32Number x
, const cmsFloat64Number Params
[])
2846 cmsFloat64Number Val
;
2848 Val
= (Params
[0] * pow(Params
[1], Params
[2] * x
+ Params
[3]) + Params
[4]);
2850 return (cmsFloat32Number
) Val
;
2855 cmsFloat32Number
sigmoidal(cmsFloat32Number x
, const cmsFloat64Number Params
[])
2857 cmsFloat64Number Val
;
2859 Val
= pow(1.0 - pow(1 - x
, 1/Params
[0]), 1/Params
[0]);
2861 return (cmsFloat32Number
) Val
;
2866 cmsBool
CheckSingleParametric(const char* Name
, dblfnptr fn
, cmsInt32Number Type
, const cmsFloat64Number Params
[])
2871 char InverseText
[256];
2873 tc
= cmsBuildParametricToneCurve(DbgThread(), Type
, Params
);
2874 tc_1
= cmsBuildParametricToneCurve(DbgThread(), -Type
, Params
);
2876 for (i
=0; i
<= 1000; i
++) {
2878 cmsFloat32Number x
= (cmsFloat32Number
) i
/ 1000;
2879 cmsFloat32Number y_fn
, y_param
, x_param
, y_param2
;
2881 y_fn
= fn(x
, Params
);
2882 y_param
= cmsEvalToneCurveFloat(tc
, x
);
2883 x_param
= cmsEvalToneCurveFloat(tc_1
, y_param
);
2885 y_param2
= fn(x_param
, Params
);
2887 if (!IsGoodVal(Name
, y_fn
, y_param
, FIXED_PRECISION_15_16
))
2890 sprintf(InverseText
, "Inverse %s", Name
);
2891 if (!IsGoodVal(InverseText
, y_fn
, y_param2
, FIXED_PRECISION_15_16
))
2895 cmsFreeToneCurve(tc
);
2896 cmsFreeToneCurve(tc_1
);
2900 cmsFreeToneCurve(tc
);
2901 cmsFreeToneCurve(tc_1
);
2905 // Check against some known values
2907 cmsInt32Number
CheckParametricToneCurves(void)
2909 cmsFloat64Number Params
[10];
2915 if (!CheckSingleParametric("Gamma", Gamma
, 1, Params
)) return 0;
2918 // Y = (aX + b)^Gamma | X >= -b/a
2925 if (!CheckSingleParametric("CIE122-1966", CIE122
, 2, Params
)) return 0;
2928 // Y = (aX + b)^Gamma | X <= -b/a
2937 if (!CheckSingleParametric("IEC 61966-3", IEC61966_3
, 3, Params
)) return 0;
2939 // 4) IEC 61966-2.1 (sRGB)
2940 // Y = (aX + b)^Gamma | X >= d
2944 Params
[1] = 1. / 1.055;
2945 Params
[2] = 0.055 / 1.055;
2946 Params
[3] = 1. / 12.92;
2947 Params
[4] = 0.04045;
2949 if (!CheckSingleParametric("IEC 61966-2.1", IEC61966_21
, 4, Params
)) return 0;
2952 // 5) Y = (aX + b)^Gamma + e | X >= d
2953 // Y = cX + f | else
2963 if (!CheckSingleParametric("param_5", param_5
, 5, Params
)) return 0;
2965 // 6) Y = (aX + b) ^ Gamma + c
2972 if (!CheckSingleParametric("param_6", param_6
, 6, Params
)) return 0;
2974 // 7) Y = a * log (b * X^Gamma + c) + d
2982 if (!CheckSingleParametric("param_7", param_7
, 7, Params
)) return 0;
2984 // 8) Y = a * b ^ (c*X+d) + e
2992 if (!CheckSingleParametric("param_8", param_8
, 8, Params
)) return 0;
2994 // 108: S-Shaped: (1 - (1-x)^1/g)^1/g
2997 if (!CheckSingleParametric("sigmoidal", sigmoidal
, 108, Params
)) return 0;
3004 // LUT checks ------------------------------------------------------------------------------
3007 cmsInt32Number
CheckLUTcreation(void)
3011 cmsInt32Number n1
, n2
;
3013 lut
= cmsPipelineAlloc(DbgThread(), 1, 1);
3014 n1
= cmsPipelineStageCount(lut
);
3015 lut2
= cmsPipelineDup(lut
);
3016 n2
= cmsPipelineStageCount(lut2
);
3018 cmsPipelineFree(lut
);
3019 cmsPipelineFree(lut2
);
3021 return (n1
== 0) && (n2
== 0);
3024 // Create a MPE for a identity matrix
3026 void AddIdentityMatrix(cmsPipeline
* lut
)
3028 const cmsFloat64Number Identity
[] = { 1, 0, 0,
3033 cmsPipelineInsertStage(lut
, cmsAT_END
, cmsStageAllocMatrix(DbgThread(), 3, 3, Identity
, NULL
));
3036 // Create a MPE for identity cmsFloat32Number CLUT
3038 void AddIdentityCLUTfloat(cmsPipeline
* lut
)
3040 const cmsFloat32Number Table
[] = {
3055 cmsPipelineInsertStage(lut
, cmsAT_END
, cmsStageAllocCLutFloat(DbgThread(), 2, 3, 3, Table
));
3058 // Create a MPE for identity cmsFloat32Number CLUT
3060 void AddIdentityCLUT16(cmsPipeline
* lut
)
3062 const cmsUInt16Number Table
[] = {
3074 0xffff, 0xffff, 0xffff
3078 cmsPipelineInsertStage(lut
, cmsAT_END
, cmsStageAllocCLut16bit(DbgThread(), 2, 3, 3, Table
));
3082 // Create a 3 fn identity curves
3085 void Add3GammaCurves(cmsPipeline
* lut
, cmsFloat64Number Curve
)
3087 cmsToneCurve
* id
= cmsBuildGamma(DbgThread(), Curve
);
3088 cmsToneCurve
* id3
[3];
3094 cmsPipelineInsertStage(lut
, cmsAT_END
, cmsStageAllocToneCurves(DbgThread(), 3, id3
));
3096 cmsFreeToneCurve(id
);
3101 cmsInt32Number
CheckFloatLUT(cmsPipeline
* lut
)
3103 cmsInt32Number n1
, i
, j
;
3104 cmsFloat32Number Inf
[3], Outf
[3];
3108 for (j
=0; j
< 65535; j
++) {
3110 cmsInt32Number af
[3];
3112 Inf
[0] = Inf
[1] = Inf
[2] = (cmsFloat32Number
) j
/ 65535.0F
;
3113 cmsPipelineEvalFloat(Inf
, Outf
, lut
);
3115 af
[0] = (cmsInt32Number
) floor(Outf
[0]*65535.0 + 0.5);
3116 af
[1] = (cmsInt32Number
) floor(Outf
[1]*65535.0 + 0.5);
3117 af
[2] = (cmsInt32Number
) floor(Outf
[2]*65535.0 + 0.5);
3119 for (i
=0; i
< 3; i
++) {
3133 cmsInt32Number
Check16LUT(cmsPipeline
* lut
)
3135 cmsInt32Number n2
, i
, j
;
3136 cmsUInt16Number Inw
[3], Outw
[3];
3140 for (j
=0; j
< 65535; j
++) {
3142 cmsInt32Number aw
[3];
3144 Inw
[0] = Inw
[1] = Inw
[2] = (cmsUInt16Number
) j
;
3145 cmsPipelineEval16(Inw
, Outw
, lut
);
3150 for (i
=0; i
< 3; i
++) {
3163 // Check any LUT that is linear
3165 cmsInt32Number
CheckStagesLUT(cmsPipeline
* lut
, cmsInt32Number ExpectedStages
)
3168 cmsInt32Number nInpChans
, nOutpChans
, nStages
;
3170 nInpChans
= cmsPipelineInputChannels(lut
);
3171 nOutpChans
= cmsPipelineOutputChannels(lut
);
3172 nStages
= cmsPipelineStageCount(lut
);
3174 return (nInpChans
== 3) && (nOutpChans
== 3) && (nStages
== ExpectedStages
);
3179 cmsInt32Number
CheckFullLUT(cmsPipeline
* lut
, cmsInt32Number ExpectedStages
)
3181 cmsInt32Number rc
= CheckStagesLUT(lut
, ExpectedStages
) && Check16LUT(lut
) && CheckFloatLUT(lut
);
3183 cmsPipelineFree(lut
);
3189 cmsInt32Number
Check1StageLUT(void)
3191 cmsPipeline
* lut
= cmsPipelineAlloc(DbgThread(), 3, 3);
3193 AddIdentityMatrix(lut
);
3194 return CheckFullLUT(lut
, 1);
3200 cmsInt32Number
Check2StageLUT(void)
3202 cmsPipeline
* lut
= cmsPipelineAlloc(DbgThread(), 3, 3);
3204 AddIdentityMatrix(lut
);
3205 AddIdentityCLUTfloat(lut
);
3207 return CheckFullLUT(lut
, 2);
3211 cmsInt32Number
Check2Stage16LUT(void)
3213 cmsPipeline
* lut
= cmsPipelineAlloc(DbgThread(), 3, 3);
3215 AddIdentityMatrix(lut
);
3216 AddIdentityCLUT16(lut
);
3218 return CheckFullLUT(lut
, 2);
3224 cmsInt32Number
Check3StageLUT(void)
3226 cmsPipeline
* lut
= cmsPipelineAlloc(DbgThread(), 3, 3);
3228 AddIdentityMatrix(lut
);
3229 AddIdentityCLUTfloat(lut
);
3230 Add3GammaCurves(lut
, 1.0);
3232 return CheckFullLUT(lut
, 3);
3236 cmsInt32Number
Check3Stage16LUT(void)
3238 cmsPipeline
* lut
= cmsPipelineAlloc(DbgThread(), 3, 3);
3240 AddIdentityMatrix(lut
);
3241 AddIdentityCLUT16(lut
);
3242 Add3GammaCurves(lut
, 1.0);
3244 return CheckFullLUT(lut
, 3);
3250 cmsInt32Number
Check4StageLUT(void)
3252 cmsPipeline
* lut
= cmsPipelineAlloc(DbgThread(), 3, 3);
3254 AddIdentityMatrix(lut
);
3255 AddIdentityCLUTfloat(lut
);
3256 Add3GammaCurves(lut
, 1.0);
3257 AddIdentityMatrix(lut
);
3259 return CheckFullLUT(lut
, 4);
3263 cmsInt32Number
Check4Stage16LUT(void)
3265 cmsPipeline
* lut
= cmsPipelineAlloc(DbgThread(), 3, 3);
3267 AddIdentityMatrix(lut
);
3268 AddIdentityCLUT16(lut
);
3269 Add3GammaCurves(lut
, 1.0);
3270 AddIdentityMatrix(lut
);
3272 return CheckFullLUT(lut
, 4);
3276 cmsInt32Number
Check5StageLUT(void)
3278 cmsPipeline
* lut
= cmsPipelineAlloc(DbgThread(), 3, 3);
3280 AddIdentityMatrix(lut
);
3281 AddIdentityCLUTfloat(lut
);
3282 Add3GammaCurves(lut
, 1.0);
3283 AddIdentityMatrix(lut
);
3284 Add3GammaCurves(lut
, 1.0);
3286 return CheckFullLUT(lut
, 5);
3291 cmsInt32Number
Check5Stage16LUT(void)
3293 cmsPipeline
* lut
= cmsPipelineAlloc(DbgThread(), 3, 3);
3295 AddIdentityMatrix(lut
);
3296 AddIdentityCLUT16(lut
);
3297 Add3GammaCurves(lut
, 1.0);
3298 AddIdentityMatrix(lut
);
3299 Add3GammaCurves(lut
, 1.0);
3301 return CheckFullLUT(lut
, 5);
3305 cmsInt32Number
Check6StageLUT(void)
3307 cmsPipeline
* lut
= cmsPipelineAlloc(DbgThread(), 3, 3);
3309 AddIdentityMatrix(lut
);
3310 Add3GammaCurves(lut
, 1.0);
3311 AddIdentityCLUTfloat(lut
);
3312 Add3GammaCurves(lut
, 1.0);
3313 AddIdentityMatrix(lut
);
3314 Add3GammaCurves(lut
, 1.0);
3316 return CheckFullLUT(lut
, 6);
3320 cmsInt32Number
Check6Stage16LUT(void)
3322 cmsPipeline
* lut
= cmsPipelineAlloc(DbgThread(), 3, 3);
3324 AddIdentityMatrix(lut
);
3325 Add3GammaCurves(lut
, 1.0);
3326 AddIdentityCLUT16(lut
);
3327 Add3GammaCurves(lut
, 1.0);
3328 AddIdentityMatrix(lut
);
3329 Add3GammaCurves(lut
, 1.0);
3331 return CheckFullLUT(lut
, 6);
3336 cmsInt32Number
CheckLab2LabLUT(void)
3338 cmsPipeline
* lut
= cmsPipelineAlloc(DbgThread(), 3, 3);
3341 cmsPipelineInsertStage(lut
, cmsAT_END
, _cmsStageAllocLab2XYZ(DbgThread()));
3342 cmsPipelineInsertStage(lut
, cmsAT_END
, _cmsStageAllocXYZ2Lab(DbgThread()));
3344 rc
= CheckFloatLUT(lut
) && CheckStagesLUT(lut
, 2);
3346 cmsPipelineFree(lut
);
3353 cmsInt32Number
CheckXYZ2XYZLUT(void)
3355 cmsPipeline
* lut
= cmsPipelineAlloc(DbgThread(), 3, 3);
3358 cmsPipelineInsertStage(lut
, cmsAT_END
, _cmsStageAllocXYZ2Lab(DbgThread()));
3359 cmsPipelineInsertStage(lut
, cmsAT_END
, _cmsStageAllocLab2XYZ(DbgThread()));
3361 rc
= CheckFloatLUT(lut
) && CheckStagesLUT(lut
, 2);
3363 cmsPipelineFree(lut
);
3371 cmsInt32Number
CheckLab2LabMatLUT(void)
3373 cmsPipeline
* lut
= cmsPipelineAlloc(DbgThread(), 3, 3);
3376 cmsPipelineInsertStage(lut
, cmsAT_END
, _cmsStageAllocLab2XYZ(DbgThread()));
3377 AddIdentityMatrix(lut
);
3378 cmsPipelineInsertStage(lut
, cmsAT_END
, _cmsStageAllocXYZ2Lab(DbgThread()));
3380 rc
= CheckFloatLUT(lut
) && CheckStagesLUT(lut
, 3);
3382 cmsPipelineFree(lut
);
3388 cmsInt32Number
CheckNamedColorLUT(void)
3390 cmsPipeline
* lut
= cmsPipelineAlloc(DbgThread(), 3, 3);
3391 cmsNAMEDCOLORLIST
* nc
;
3392 cmsInt32Number i
,j
, rc
= 1, n2
;
3393 cmsUInt16Number PCS
[3];
3394 cmsUInt16Number Colorant
[cmsMAXCHANNELS
];
3396 cmsUInt16Number Inw
[3], Outw
[3];
3400 nc
= cmsAllocNamedColorList(DbgThread(), 256, 3, "pre", "post");
3401 if (nc
== NULL
) return 0;
3403 for (i
=0; i
< 256; i
++) {
3405 PCS
[0] = PCS
[1] = PCS
[2] = (cmsUInt16Number
) i
;
3406 Colorant
[0] = Colorant
[1] = Colorant
[2] = Colorant
[3] = (cmsUInt16Number
) i
;
3408 sprintf(Name
, "#%d", i
);
3409 if (!cmsAppendNamedColor(nc
, Name
, PCS
, Colorant
)) { rc
= 0; break; }
3412 cmsPipelineInsertStage(lut
, cmsAT_END
, _cmsStageAllocNamedColor(nc
, FALSE
));
3414 cmsFreeNamedColorList(nc
);
3415 if (rc
== 0) return 0;
3419 for (j
=0; j
< 256; j
++) {
3421 Inw
[0] = (cmsUInt16Number
) j
;
3423 cmsPipelineEval16(Inw
, Outw
, lut
);
3424 for (i
=0; i
< 3; i
++) {
3433 cmsPipelineFree(lut
);
3439 // --------------------------------------------------------------------------------------------
3441 // A lightweight test of multilocalized unicode structures.
3444 cmsInt32Number
CheckMLU(void)
3446 cmsMLU
* mlu
, *mlu2
, *mlu3
;
3447 char Buffer
[256], Buffer2
[256];
3448 cmsInt32Number rc
= 1;
3450 cmsHPROFILE h
= NULL
;
3452 // Allocate a MLU structure, no preferred size
3453 mlu
= cmsMLUalloc(DbgThread(), 0);
3455 // Add some localizations
3456 cmsMLUsetWide(mlu
, "en", "US", L
"Hello, world");
3457 cmsMLUsetWide(mlu
, "es", "ES", L
"Hola, mundo");
3458 cmsMLUsetWide(mlu
, "fr", "FR", L
"Bonjour, le monde");
3459 cmsMLUsetWide(mlu
, "ca", "CA", L
"Hola, mon");
3462 // Check the returned string for each language
3464 cmsMLUgetASCII(mlu
, "en", "US", Buffer
, 256);
3465 if (strcmp(Buffer
, "Hello, world") != 0) rc
= 0;
3468 cmsMLUgetASCII(mlu
, "es", "ES", Buffer
, 256);
3469 if (strcmp(Buffer
, "Hola, mundo") != 0) rc
= 0;
3472 cmsMLUgetASCII(mlu
, "fr", "FR", Buffer
, 256);
3473 if (strcmp(Buffer
, "Bonjour, le monde") != 0) rc
= 0;
3476 cmsMLUgetASCII(mlu
, "ca", "CA", Buffer
, 256);
3477 if (strcmp(Buffer
, "Hola, mon") != 0) rc
= 0;
3480 Fail("Unexpected string '%s'", Buffer
);
3485 // Now for performance, allocate an empty struct
3486 mlu
= cmsMLUalloc(DbgThread(), 0);
3488 // Fill it with several thousands of different lenguages
3489 for (i
=0; i
< 4096; i
++) {
3493 Lang
[0] = (char) (i
% 255);
3494 Lang
[1] = (char) (i
/ 255);
3497 sprintf(Buffer
, "String #%i", i
);
3498 cmsMLUsetASCII(mlu
, Lang
, Lang
, Buffer
);
3502 mlu2
= cmsMLUdup(mlu
);
3504 // Get rid of original
3507 // Check all is still in place
3508 for (i
=0; i
< 4096; i
++) {
3512 Lang
[0] = (char)(i
% 255);
3513 Lang
[1] = (char)(i
/ 255);
3516 cmsMLUgetASCII(mlu2
, Lang
, Lang
, Buffer2
, 256);
3517 sprintf(Buffer
, "String #%i", i
);
3519 if (strcmp(Buffer
, Buffer2
) != 0) { rc
= 0; break; }
3523 Fail("Unexpected string '%s'", Buffer2
);
3527 h
= cmsOpenProfileFromFileTHR(DbgThread(), "mlucheck.icc", "w");
3529 cmsSetProfileVersion(h
, 4.3);
3531 cmsWriteTag(h
, cmsSigProfileDescriptionTag
, mlu2
);
3536 h
= cmsOpenProfileFromFileTHR(DbgThread(), "mlucheck.icc", "r");
3538 mlu3
= cmsReadTag(h
, cmsSigProfileDescriptionTag
);
3539 if (mlu3
== NULL
) { Fail("Profile didn't get the MLU\n"); rc
= 0; goto Error
; }
3541 // Check all is still in place
3542 for (i
=0; i
< 4096; i
++) {
3546 Lang
[0] = (char) (i
% 255);
3547 Lang
[1] = (char) (i
/ 255);
3550 cmsMLUgetASCII(mlu3
, Lang
, Lang
, Buffer2
, 256);
3551 sprintf(Buffer
, "String #%i", i
);
3553 if (strcmp(Buffer
, Buffer2
) != 0) { rc
= 0; break; }
3556 if (rc
== 0) Fail("Unexpected string '%s'", Buffer2
);
3560 if (h
!= NULL
) cmsCloseProfile(h
);
3561 remove("mlucheck.icc");
3567 // A lightweight test of named color structures.
3569 cmsInt32Number
CheckNamedColorList(void)
3571 cmsNAMEDCOLORLIST
* nc
= NULL
, *nc2
;
3572 cmsInt32Number i
, j
, rc
=1;
3574 cmsUInt16Number PCS
[3];
3575 cmsUInt16Number Colorant
[cmsMAXCHANNELS
];
3576 char CheckName
[255];
3577 cmsUInt16Number CheckPCS
[3];
3578 cmsUInt16Number CheckColorant
[cmsMAXCHANNELS
];
3581 nc
= cmsAllocNamedColorList(DbgThread(), 0, 4, "prefix", "suffix");
3582 if (nc
== NULL
) return 0;
3584 for (i
=0; i
< 4096; i
++) {
3587 PCS
[0] = PCS
[1] = PCS
[2] = (cmsUInt16Number
) i
;
3588 Colorant
[0] = Colorant
[1] = Colorant
[2] = Colorant
[3] = (cmsUInt16Number
) (4096 - i
);
3590 sprintf(Name
, "#%d", i
);
3591 if (!cmsAppendNamedColor(nc
, Name
, PCS
, Colorant
)) { rc
= 0; break; }
3594 for (i
=0; i
< 4096; i
++) {
3596 CheckPCS
[0] = CheckPCS
[1] = CheckPCS
[2] = (cmsUInt16Number
) i
;
3597 CheckColorant
[0] = CheckColorant
[1] = CheckColorant
[2] = CheckColorant
[3] = (cmsUInt16Number
) (4096 - i
);
3599 sprintf(CheckName
, "#%d", i
);
3600 if (!cmsNamedColorInfo(nc
, i
, Name
, NULL
, NULL
, PCS
, Colorant
)) { rc
= 0; goto Error
; }
3603 for (j
=0; j
< 3; j
++) {
3604 if (CheckPCS
[j
] != PCS
[j
]) { rc
= 0; Fail("Invalid PCS"); goto Error
; }
3607 for (j
=0; j
< 4; j
++) {
3608 if (CheckColorant
[j
] != Colorant
[j
]) { rc
= 0; Fail("Invalid Colorant"); goto Error
; };
3611 if (strcmp(Name
, CheckName
) != 0) {rc
= 0; Fail("Invalid Name"); goto Error
; };
3614 h
= cmsOpenProfileFromFileTHR(DbgThread(), "namedcol.icc", "w");
3615 if (h
== NULL
) return 0;
3616 if (!cmsWriteTag(h
, cmsSigNamedColor2Tag
, nc
)) return 0;
3618 cmsFreeNamedColorList(nc
);
3621 h
= cmsOpenProfileFromFileTHR(DbgThread(), "namedcol.icc", "r");
3622 nc2
= cmsReadTag(h
, cmsSigNamedColor2Tag
);
3624 if (cmsNamedColorCount(nc2
) != 4096) { rc
= 0; Fail("Invalid count"); goto Error
; }
3626 i
= cmsNamedColorIndex(nc2
, "#123");
3627 if (i
!= 123) { rc
= 0; Fail("Invalid index"); goto Error
; }
3630 for (i
=0; i
< 4096; i
++) {
3632 CheckPCS
[0] = CheckPCS
[1] = CheckPCS
[2] = (cmsUInt16Number
) i
;
3633 CheckColorant
[0] = CheckColorant
[1] = CheckColorant
[2] = CheckColorant
[3] = (cmsUInt16Number
) (4096 - i
);
3635 sprintf(CheckName
, "#%d", i
);
3636 if (!cmsNamedColorInfo(nc2
, i
, Name
, NULL
, NULL
, PCS
, Colorant
)) { rc
= 0; goto Error
; }
3639 for (j
=0; j
< 3; j
++) {
3640 if (CheckPCS
[j
] != PCS
[j
]) { rc
= 0; Fail("Invalid PCS"); goto Error
; }
3643 for (j
=0; j
< 4; j
++) {
3644 if (CheckColorant
[j
] != Colorant
[j
]) { rc
= 0; Fail("Invalid Colorant"); goto Error
; };
3647 if (strcmp(Name
, CheckName
) != 0) {rc
= 0; Fail("Invalid Name"); goto Error
; };
3651 remove("namedcol.icc");
3654 if (nc
!= NULL
) cmsFreeNamedColorList(nc
);
3660 // ----------------------------------------------------------------------------------------------------------
3664 static cmsBool FormatterFailed
;
3667 void CheckSingleFormatter16(cmsUInt32Number Type
, const char* Text
)
3669 cmsUInt16Number Values
[cmsMAXCHANNELS
];
3670 cmsUInt8Number Buffer
[1024];
3672 cmsInt32Number i
, j
, nChannels
, bytes
;
3676 if (FormatterFailed
) return;
3678 memset(&info
, 0, sizeof(info
));
3679 info
.OutputFormat
= info
.InputFormat
= Type
;
3681 // Go forth and back
3682 f
= _cmsGetFormatter(Type
, cmsFormatterInput
, CMS_PACK_FLAGS_16BITS
);
3683 b
= _cmsGetFormatter(Type
, cmsFormatterOutput
, CMS_PACK_FLAGS_16BITS
);
3685 if (f
.Fmt16
== NULL
|| b
.Fmt16
== NULL
) {
3686 Fail("no formatter for %s", Text
);
3687 FormatterFailed
= TRUE
;
3690 f
= _cmsGetFormatter(Type
, cmsFormatterInput
, CMS_PACK_FLAGS_16BITS
);
3691 b
= _cmsGetFormatter(Type
, cmsFormatterOutput
, CMS_PACK_FLAGS_16BITS
);
3695 nChannels
= T_CHANNELS(Type
);
3696 bytes
= T_BYTES(Type
);
3698 for (j
=0; j
< 5; j
++) {
3700 for (i
=0; i
< nChannels
; i
++) {
3701 Values
[i
] = (cmsUInt16Number
) (i
+j
);
3707 b
.Fmt16(&info
, Values
, Buffer
, 1);
3708 memset(Values
, 0, sizeof(Values
));
3709 f
.Fmt16(&info
, Values
, Buffer
, 1);
3711 for (i
=0; i
< nChannels
; i
++) {
3715 if (Values
[i
] != i
+j
) {
3717 Fail("%s failed", Text
);
3718 FormatterFailed
= TRUE
;
3721 for (i
=0; i
< nChannels
; i
++) {
3722 Values
[i
] = (cmsUInt16Number
) (i
+j
);
3728 b
.Fmt16(&info
, Values
, Buffer
, 1);
3729 f
.Fmt16(&info
, Values
, Buffer
, 1);
3736 #define C(a) CheckSingleFormatter16(a, #a)
3739 // Check all formatters
3741 cmsInt32Number
CheckFormatters16(void)
3743 FormatterFailed
= FALSE
;
3746 C( TYPE_GRAY_8_REV
);
3748 C( TYPE_GRAY_16_REV
);
3749 C( TYPE_GRAY_16_SE
);
3752 C( TYPE_GRAYA_16_SE
);
3753 C( TYPE_GRAYA_8_PLANAR
);
3754 C( TYPE_GRAYA_16_PLANAR
);
3756 C( TYPE_RGB_8_PLANAR
);
3758 C( TYPE_BGR_8_PLANAR
);
3760 C( TYPE_RGB_16_PLANAR
);
3761 C( TYPE_RGB_16_SE
);
3763 C( TYPE_BGR_16_PLANAR
);
3764 C( TYPE_BGR_16_SE
);
3766 C( TYPE_RGBA_8_PLANAR
);
3768 C( TYPE_RGBA_16_PLANAR
);
3769 C( TYPE_RGBA_16_SE
);
3771 C( TYPE_ARGB_8_PLANAR
);
3774 C( TYPE_ABGR_8_PLANAR
);
3776 C( TYPE_ABGR_16_PLANAR
);
3777 C( TYPE_ABGR_16_SE
);
3779 C( TYPE_BGRA_8_PLANAR
);
3781 C( TYPE_BGRA_16_SE
);
3783 C( TYPE_CMY_8_PLANAR
);
3785 C( TYPE_CMY_16_PLANAR
);
3786 C( TYPE_CMY_16_SE
);
3789 C( TYPE_CMYK_8_REV
);
3791 C( TYPE_CMYK_8_PLANAR
);
3793 C( TYPE_CMYK_16_REV
);
3795 C( TYPE_CMYK_16_PLANAR
);
3796 C( TYPE_CMYK_16_SE
);
3799 C( TYPE_KYMC_16_SE
);
3801 C( TYPE_KCMY_8_REV
);
3803 C( TYPE_KCMY_16_REV
);
3804 C( TYPE_KCMY_16_SE
);
3807 C( TYPE_CMYK5_16_SE
);
3810 C( TYPE_KYMC5_16_SE
);
3812 C( TYPE_CMYK6_8_PLANAR
);
3814 C( TYPE_CMYK6_16_PLANAR
);
3815 C( TYPE_CMYK6_16_SE
);
3818 C( TYPE_CMYK7_16_SE
);
3821 C( TYPE_KYMC7_16_SE
);
3824 C( TYPE_CMYK8_16_SE
);
3827 C( TYPE_KYMC8_16_SE
);
3830 C( TYPE_CMYK9_16_SE
);
3833 C( TYPE_KYMC9_16_SE
);
3835 C( TYPE_CMYK10_16
);
3836 C( TYPE_CMYK10_16_SE
);
3838 C( TYPE_KYMC10_16
);
3839 C( TYPE_KYMC10_16_SE
);
3841 C( TYPE_CMYK11_16
);
3842 C( TYPE_CMYK11_16_SE
);
3844 C( TYPE_KYMC11_16
);
3845 C( TYPE_KYMC11_16_SE
);
3847 C( TYPE_CMYK12_16
);
3848 C( TYPE_CMYK12_16_SE
);
3850 C( TYPE_KYMC12_16
);
3851 C( TYPE_KYMC12_16_SE
);
3858 C( TYPE_YCbCr_8_PLANAR
);
3860 C( TYPE_YCbCr_16_PLANAR
);
3861 C( TYPE_YCbCr_16_SE
);
3863 C( TYPE_YUV_8_PLANAR
);
3865 C( TYPE_YUV_16_PLANAR
);
3866 C( TYPE_YUV_16_SE
);
3868 C( TYPE_HLS_8_PLANAR
);
3870 C( TYPE_HLS_16_PLANAR
);
3871 C( TYPE_HLS_16_SE
);
3873 C( TYPE_HSV_8_PLANAR
);
3875 C( TYPE_HSV_16_PLANAR
);
3876 C( TYPE_HSV_16_SE
);
3902 C( TYPE_GRAY_HALF_FLT
);
3903 C( TYPE_RGB_HALF_FLT
);
3904 C( TYPE_CMYK_HALF_FLT
);
3905 C( TYPE_RGBA_HALF_FLT
);
3907 C( TYPE_RGBA_HALF_FLT
);
3908 C( TYPE_ARGB_HALF_FLT
);
3909 C( TYPE_BGR_HALF_FLT
);
3910 C( TYPE_BGRA_HALF_FLT
);
3911 C( TYPE_ABGR_HALF_FLT
);
3914 return FormatterFailed
== 0 ? 1 : 0;
3919 void CheckSingleFormatterFloat(cmsUInt32Number Type
, const char* Text
)
3921 cmsFloat32Number Values
[cmsMAXCHANNELS
];
3922 cmsUInt8Number Buffer
[1024];
3924 cmsInt32Number i
, j
, nChannels
;
3928 if (FormatterFailed
) return;
3930 memset(&info
, 0, sizeof(info
));
3931 info
.OutputFormat
= info
.InputFormat
= Type
;
3933 // Go forth and back
3934 f
= _cmsGetFormatter(Type
, cmsFormatterInput
, CMS_PACK_FLAGS_FLOAT
);
3935 b
= _cmsGetFormatter(Type
, cmsFormatterOutput
, CMS_PACK_FLAGS_FLOAT
);
3937 if (f
.FmtFloat
== NULL
|| b
.FmtFloat
== NULL
) {
3938 Fail("no formatter for %s", Text
);
3939 FormatterFailed
= TRUE
;
3942 f
= _cmsGetFormatter(Type
, cmsFormatterInput
, CMS_PACK_FLAGS_FLOAT
);
3943 b
= _cmsGetFormatter(Type
, cmsFormatterOutput
, CMS_PACK_FLAGS_FLOAT
);
3947 nChannels
= T_CHANNELS(Type
);
3949 for (j
=0; j
< 5; j
++) {
3951 for (i
=0; i
< nChannels
; i
++) {
3952 Values
[i
] = (cmsFloat32Number
) (i
+j
);
3955 b
.FmtFloat(&info
, Values
, Buffer
, 1);
3956 memset(Values
, 0, sizeof(Values
));
3957 f
.FmtFloat(&info
, Values
, Buffer
, 1);
3959 for (i
=0; i
< nChannels
; i
++) {
3961 cmsFloat64Number delta
= fabs(Values
[i
] - ( i
+j
));
3963 if (delta
> 0.000000001) {
3965 Fail("%s failed", Text
);
3966 FormatterFailed
= TRUE
;
3969 for (i
=0; i
< nChannels
; i
++) {
3970 Values
[i
] = (cmsFloat32Number
) (i
+j
);
3973 b
.FmtFloat(&info
, Values
, Buffer
, 1);
3974 f
.FmtFloat(&info
, Values
, Buffer
, 1);
3981 #define C(a) CheckSingleFormatterFloat(a, #a)
3984 cmsInt32Number
CheckFormattersFloat(void)
3986 FormatterFailed
= FALSE
;
4009 C( TYPE_GRAY_HALF_FLT
);
4010 C( TYPE_RGB_HALF_FLT
);
4011 C( TYPE_CMYK_HALF_FLT
);
4012 C( TYPE_RGBA_HALF_FLT
);
4014 C( TYPE_RGBA_HALF_FLT
);
4015 C( TYPE_ARGB_HALF_FLT
);
4016 C( TYPE_BGR_HALF_FLT
);
4017 C( TYPE_BGRA_HALF_FLT
);
4018 C( TYPE_ABGR_HALF_FLT
);
4021 return FormatterFailed
== 0 ? 1 : 0;
4025 #ifndef CMS_NO_HALF_SUPPORT
4028 #define my_isfinite(x) ((x) != (x))
4030 cmsInt32Number
CheckFormattersHalf(void)
4035 for (i
=0; i
< 0xffff; i
++) {
4037 cmsFloat32Number f
= _cmsHalf2Float((cmsUInt16Number
) i
);
4039 if (!my_isfinite(f
)) {
4041 j
= _cmsFloat2Half(f
);
4044 Fail("%d != %d in Half float support!\n", i
, j
);
4056 cmsInt32Number
CheckOneRGB(cmsHTRANSFORM xform
, cmsUInt16Number R
, cmsUInt16Number G
, cmsUInt16Number B
, cmsUInt16Number Ro
, cmsUInt16Number Go
, cmsUInt16Number Bo
)
4058 cmsUInt16Number RGB
[3];
4059 cmsUInt16Number Out
[3];
4065 cmsDoTransform(xform
, RGB
, Out
, 1);
4067 return IsGoodWord("R", Ro
, Out
[0]) &&
4068 IsGoodWord("G", Go
, Out
[1]) &&
4069 IsGoodWord("B", Bo
, Out
[2]);
4072 // Check known values going from sRGB to XYZ
4074 cmsInt32Number
CheckOneRGB_double(cmsHTRANSFORM xform
, cmsFloat64Number R
, cmsFloat64Number G
, cmsFloat64Number B
, cmsFloat64Number Ro
, cmsFloat64Number Go
, cmsFloat64Number Bo
)
4076 cmsFloat64Number RGB
[3];
4077 cmsFloat64Number Out
[3];
4083 cmsDoTransform(xform
, RGB
, Out
, 1);
4085 return IsGoodVal("R", Ro
, Out
[0], 0.01) &&
4086 IsGoodVal("G", Go
, Out
[1], 0.01) &&
4087 IsGoodVal("B", Bo
, Out
[2], 0.01);
4092 cmsInt32Number
CheckChangeBufferFormat(void)
4094 cmsHPROFILE hsRGB
= cmsCreate_sRGBProfile();
4095 cmsHTRANSFORM xform
;
4098 xform
= cmsCreateTransform(hsRGB
, TYPE_RGB_16
, hsRGB
, TYPE_RGB_16
, INTENT_PERCEPTUAL
, 0);
4099 cmsCloseProfile(hsRGB
);
4100 if (xform
== NULL
) return 0;
4103 if (!CheckOneRGB(xform
, 0, 0, 0, 0, 0, 0)) return 0;
4104 if (!CheckOneRGB(xform
, 120, 0, 0, 120, 0, 0)) return 0;
4105 if (!CheckOneRGB(xform
, 0, 222, 255, 0, 222, 255)) return 0;
4108 if (!cmsChangeBuffersFormat(xform
, TYPE_BGR_16
, TYPE_RGB_16
)) return 0;
4110 if (!CheckOneRGB(xform
, 0, 0, 123, 123, 0, 0)) return 0;
4111 if (!CheckOneRGB(xform
, 154, 234, 0, 0, 234, 154)) return 0;
4113 if (!cmsChangeBuffersFormat(xform
, TYPE_RGB_DBL
, TYPE_RGB_DBL
)) return 0;
4115 if (!CheckOneRGB_double(xform
, 0.20, 0, 0, 0.20, 0, 0)) return 0;
4116 if (!CheckOneRGB_double(xform
, 0, 0.9, 1, 0, 0.9, 1)) return 0;
4118 cmsDeleteTransform(xform
);
4124 // Write tag testbed ----------------------------------------------------------------------------------------
4127 cmsInt32Number
CheckXYZ(cmsInt32Number Pass
, cmsHPROFILE hProfile
, cmsTagSignature tag
)
4136 XYZ
.X
= 1.0; XYZ
.Y
= 1.1; XYZ
.Z
= 1.2;
4137 return cmsWriteTag(hProfile
, tag
, &XYZ
);
4140 Pt
= cmsReadTag(hProfile
, tag
);
4141 if (Pt
== NULL
) return 0;
4142 return IsGoodFixed15_16("X", 1.0, Pt
->X
) &&
4143 IsGoodFixed15_16("Y", 1.1, Pt
->Y
) &&
4144 IsGoodFixed15_16("Z", 1.2, Pt
-> Z
);
4153 cmsInt32Number
CheckGamma(cmsInt32Number Pass
, cmsHPROFILE hProfile
, cmsTagSignature tag
)
4155 cmsToneCurve
*g
, *Pt
;
4162 g
= cmsBuildGamma(DbgThread(), 1.0);
4163 rc
= cmsWriteTag(hProfile
, tag
, g
);
4164 cmsFreeToneCurve(g
);
4168 Pt
= cmsReadTag(hProfile
, tag
);
4169 if (Pt
== NULL
) return 0;
4170 return cmsIsToneCurveLinear(Pt
);
4178 cmsInt32Number
CheckText(cmsInt32Number Pass
, cmsHPROFILE hProfile
, cmsTagSignature tag
)
4188 m
= cmsMLUalloc(DbgThread(), 0);
4189 cmsMLUsetASCII(m
, cmsNoLanguage
, cmsNoCountry
, "Test test");
4190 rc
= cmsWriteTag(hProfile
, tag
, m
);
4195 Pt
= cmsReadTag(hProfile
, tag
);
4196 if (Pt
== NULL
) return 0;
4197 cmsMLUgetASCII(Pt
, cmsNoLanguage
, cmsNoCountry
, Buffer
, 256);
4198 return strcmp(Buffer
, "Test test") == 0;
4206 cmsInt32Number
CheckData(cmsInt32Number Pass
, cmsHPROFILE hProfile
, cmsTagSignature tag
)
4209 cmsICCData d
= { 1, 0, { '?' }};
4216 rc
= cmsWriteTag(hProfile
, tag
, &d
);
4220 Pt
= cmsReadTag(hProfile
, tag
);
4221 if (Pt
== NULL
) return 0;
4222 return (Pt
->data
[0] == '?') && (Pt
->flag
== 0) && (Pt
->len
== 1);
4231 cmsInt32Number
CheckSignature(cmsInt32Number Pass
, cmsHPROFILE hProfile
, cmsTagSignature tag
)
4233 cmsTagSignature
*Pt
, Holder
;
4238 Holder
= cmsSigPerceptualReferenceMediumGamut
;
4239 return cmsWriteTag(hProfile
, tag
, &Holder
);
4242 Pt
= cmsReadTag(hProfile
, tag
);
4243 if (Pt
== NULL
) return 0;
4244 return *Pt
== cmsSigPerceptualReferenceMediumGamut
;
4253 cmsInt32Number
CheckDateTime(cmsInt32Number Pass
, cmsHPROFILE hProfile
, cmsTagSignature tag
)
4255 struct tm
*Pt
, Holder
;
4266 Holder
.tm_year
= 2009 - 1900;
4267 return cmsWriteTag(hProfile
, tag
, &Holder
);
4270 Pt
= cmsReadTag(hProfile
, tag
);
4271 if (Pt
== NULL
) return 0;
4273 return (Pt
->tm_hour
== 1 &&
4276 Pt
->tm_mday
== 4 &&
4278 Pt
->tm_year
== 2009 - 1900);
4288 cmsInt32Number
CheckNamedColor(cmsInt32Number Pass
, cmsHPROFILE hProfile
, cmsTagSignature tag
, cmsInt32Number max_check
, cmsBool colorant_check
)
4290 cmsNAMEDCOLORLIST
* nc
;
4291 cmsInt32Number i
, j
, rc
;
4293 cmsUInt16Number PCS
[3];
4294 cmsUInt16Number Colorant
[cmsMAXCHANNELS
];
4295 char CheckName
[255];
4296 cmsUInt16Number CheckPCS
[3];
4297 cmsUInt16Number CheckColorant
[cmsMAXCHANNELS
];
4303 nc
= cmsAllocNamedColorList(DbgThread(), 0, 4, "prefix", "suffix");
4304 if (nc
== NULL
) return 0;
4306 for (i
=0; i
< max_check
; i
++) {
4308 PCS
[0] = PCS
[1] = PCS
[2] = (cmsUInt16Number
) i
;
4309 Colorant
[0] = Colorant
[1] = Colorant
[2] = Colorant
[3] = (cmsUInt16Number
) (max_check
- i
);
4311 sprintf(Name
, "#%d", i
);
4312 if (!cmsAppendNamedColor(nc
, Name
, PCS
, Colorant
)) { Fail("Couldn't append named color"); return 0; }
4315 rc
= cmsWriteTag(hProfile
, tag
, nc
);
4316 cmsFreeNamedColorList(nc
);
4321 nc
= cmsReadTag(hProfile
, tag
);
4322 if (nc
== NULL
) return 0;
4324 for (i
=0; i
< max_check
; i
++) {
4326 CheckPCS
[0] = CheckPCS
[1] = CheckPCS
[2] = (cmsUInt16Number
) i
;
4327 CheckColorant
[0] = CheckColorant
[1] = CheckColorant
[2] = CheckColorant
[3] = (cmsUInt16Number
) (max_check
- i
);
4329 sprintf(CheckName
, "#%d", i
);
4330 if (!cmsNamedColorInfo(nc
, i
, Name
, NULL
, NULL
, PCS
, Colorant
)) { Fail("Invalid string"); return 0; }
4333 for (j
=0; j
< 3; j
++) {
4334 if (CheckPCS
[j
] != PCS
[j
]) { Fail("Invalid PCS"); return 0; }
4337 // This is only used on named color list
4338 if (colorant_check
) {
4340 for (j
=0; j
< 4; j
++) {
4341 if (CheckColorant
[j
] != Colorant
[j
]) { Fail("Invalid Colorant"); return 0; };
4345 if (strcmp(Name
, CheckName
) != 0) { Fail("Invalid Name"); return 0; };
4356 cmsInt32Number
CheckLUT(cmsInt32Number Pass
, cmsHPROFILE hProfile
, cmsTagSignature tag
)
4358 cmsPipeline
* Lut
, *Pt
;
4366 Lut
= cmsPipelineAlloc(DbgThread(), 3, 3);
4367 if (Lut
== NULL
) return 0;
4369 // Create an identity LUT
4370 cmsPipelineInsertStage(Lut
, cmsAT_BEGIN
, _cmsStageAllocIdentityCurves(DbgThread(), 3));
4371 cmsPipelineInsertStage(Lut
, cmsAT_END
, _cmsStageAllocIdentityCLut(DbgThread(), 3));
4372 cmsPipelineInsertStage(Lut
, cmsAT_END
, _cmsStageAllocIdentityCurves(DbgThread(), 3));
4374 rc
= cmsWriteTag(hProfile
, tag
, Lut
);
4375 cmsPipelineFree(Lut
);
4379 Pt
= cmsReadTag(hProfile
, tag
);
4380 if (Pt
== NULL
) return 0;
4382 // Transform values, check for identity
4383 return Check16LUT(Pt
);
4391 cmsInt32Number
CheckCHAD(cmsInt32Number Pass
, cmsHPROFILE hProfile
, cmsTagSignature tag
)
4393 cmsFloat64Number
*Pt
;
4394 cmsFloat64Number CHAD
[] = { 0, .1, .2, .3, .4, .5, .6, .7, .8 };
4400 return cmsWriteTag(hProfile
, tag
, CHAD
);
4404 Pt
= cmsReadTag(hProfile
, tag
);
4405 if (Pt
== NULL
) return 0;
4407 for (i
=0; i
< 9; i
++) {
4408 if (!IsGoodFixed15_16("CHAD", Pt
[i
], CHAD
[i
])) return 0;
4419 cmsInt32Number
CheckChromaticity(cmsInt32Number Pass
, cmsHPROFILE hProfile
, cmsTagSignature tag
)
4421 cmsCIExyYTRIPLE
*Pt
, c
= { {0, .1, 1 }, { .3, .4, 1 }, { .6, .7, 1 }};
4426 return cmsWriteTag(hProfile
, tag
, &c
);
4430 Pt
= cmsReadTag(hProfile
, tag
);
4431 if (Pt
== NULL
) return 0;
4433 if (!IsGoodFixed15_16("xyY", Pt
->Red
.x
, c
.Red
.x
)) return 0;
4434 if (!IsGoodFixed15_16("xyY", Pt
->Red
.y
, c
.Red
.y
)) return 0;
4435 if (!IsGoodFixed15_16("xyY", Pt
->Green
.x
, c
.Green
.x
)) return 0;
4436 if (!IsGoodFixed15_16("xyY", Pt
->Green
.y
, c
.Green
.y
)) return 0;
4437 if (!IsGoodFixed15_16("xyY", Pt
->Blue
.x
, c
.Blue
.x
)) return 0;
4438 if (!IsGoodFixed15_16("xyY", Pt
->Blue
.y
, c
.Blue
.y
)) return 0;
4448 cmsInt32Number
CheckColorantOrder(cmsInt32Number Pass
, cmsHPROFILE hProfile
, cmsTagSignature tag
)
4450 cmsUInt8Number
*Pt
, c
[cmsMAXCHANNELS
];
4456 for (i
=0; i
< cmsMAXCHANNELS
; i
++) c
[i
] = (cmsUInt8Number
) (cmsMAXCHANNELS
- i
- 1);
4457 return cmsWriteTag(hProfile
, tag
, c
);
4461 Pt
= cmsReadTag(hProfile
, tag
);
4462 if (Pt
== NULL
) return 0;
4464 for (i
=0; i
< cmsMAXCHANNELS
; i
++) {
4465 if (Pt
[i
] != ( cmsMAXCHANNELS
- i
- 1 )) return 0;
4475 cmsInt32Number
CheckMeasurement(cmsInt32Number Pass
, cmsHPROFILE hProfile
, cmsTagSignature tag
)
4477 cmsICCMeasurementConditions
*Pt
, m
;
4487 m
.IlluminantType
= cmsILLUMINANT_TYPE_D50
;
4489 return cmsWriteTag(hProfile
, tag
, &m
);
4493 Pt
= cmsReadTag(hProfile
, tag
);
4494 if (Pt
== NULL
) return 0;
4496 if (!IsGoodFixed15_16("Backing", Pt
->Backing
.X
, 0.1)) return 0;
4497 if (!IsGoodFixed15_16("Backing", Pt
->Backing
.Y
, 0.2)) return 0;
4498 if (!IsGoodFixed15_16("Backing", Pt
->Backing
.Z
, 0.3)) return 0;
4499 if (!IsGoodFixed15_16("Flare", Pt
->Flare
, 1.0)) return 0;
4501 if (Pt
->Geometry
!= 1) return 0;
4502 if (Pt
->IlluminantType
!= cmsILLUMINANT_TYPE_D50
) return 0;
4503 if (Pt
->Observer
!= 1) return 0;
4513 cmsInt32Number
CheckUcrBg(cmsInt32Number Pass
, cmsHPROFILE hProfile
, cmsTagSignature tag
)
4522 m
.Ucr
= cmsBuildGamma(DbgThread(), 2.4);
4523 m
.Bg
= cmsBuildGamma(DbgThread(), -2.2);
4524 m
.Desc
= cmsMLUalloc(DbgThread(), 1);
4525 cmsMLUsetASCII(m
.Desc
, cmsNoLanguage
, cmsNoCountry
, "test UCR/BG");
4526 rc
= cmsWriteTag(hProfile
, tag
, &m
);
4528 cmsFreeToneCurve(m
.Bg
);
4529 cmsFreeToneCurve(m
.Ucr
);
4534 Pt
= cmsReadTag(hProfile
, tag
);
4535 if (Pt
== NULL
) return 0;
4537 cmsMLUgetASCII(Pt
->Desc
, cmsNoLanguage
, cmsNoCountry
, Buffer
, 256);
4538 if (strcmp(Buffer
, "test UCR/BG") != 0) return 0;
4548 cmsInt32Number
CheckCRDinfo(cmsInt32Number Pass
, cmsHPROFILE hProfile
, cmsTagSignature tag
)
4557 mlu
= cmsMLUalloc(DbgThread(), 5);
4559 cmsMLUsetWide(mlu
, "PS", "nm", L
"test postscript");
4560 cmsMLUsetWide(mlu
, "PS", "#0", L
"perceptual");
4561 cmsMLUsetWide(mlu
, "PS", "#1", L
"relative_colorimetric");
4562 cmsMLUsetWide(mlu
, "PS", "#2", L
"saturation");
4563 cmsMLUsetWide(mlu
, "PS", "#3", L
"absolute_colorimetric");
4564 rc
= cmsWriteTag(hProfile
, tag
, mlu
);
4570 mlu
= (cmsMLU
*) cmsReadTag(hProfile
, tag
);
4571 if (mlu
== NULL
) return 0;
4575 cmsMLUgetASCII(mlu
, "PS", "nm", Buffer
, 256);
4576 if (strcmp(Buffer
, "test postscript") != 0) return 0;
4579 cmsMLUgetASCII(mlu
, "PS", "#0", Buffer
, 256);
4580 if (strcmp(Buffer
, "perceptual") != 0) return 0;
4583 cmsMLUgetASCII(mlu
, "PS", "#1", Buffer
, 256);
4584 if (strcmp(Buffer
, "relative_colorimetric") != 0) return 0;
4587 cmsMLUgetASCII(mlu
, "PS", "#2", Buffer
, 256);
4588 if (strcmp(Buffer
, "saturation") != 0) return 0;
4591 cmsMLUgetASCII(mlu
, "PS", "#3", Buffer
, 256);
4592 if (strcmp(Buffer
, "absolute_colorimetric") != 0) return 0;
4602 cmsToneCurve
*CreateSegmentedCurve(void)
4604 cmsCurveSegment Seg
[3];
4605 cmsFloat32Number Sampled
[2] = { 0, 1};
4608 Seg
[0].Params
[0] = 1;
4609 Seg
[0].Params
[1] = 0;
4610 Seg
[0].Params
[2] = 0;
4611 Seg
[0].Params
[3] = 0;
4616 Seg
[1].nGridPoints
= 2;
4617 Seg
[1].SampledPoints
= Sampled
;
4622 Seg
[2].Params
[0] = 1;
4623 Seg
[2].Params
[1] = 0;
4624 Seg
[2].Params
[2] = 0;
4625 Seg
[2].Params
[3] = 0;
4629 return cmsBuildSegmentedToneCurve(DbgThread(), 3, Seg
);
4634 cmsInt32Number
CheckMPE(cmsInt32Number Pass
, cmsHPROFILE hProfile
, cmsTagSignature tag
)
4636 cmsPipeline
* Lut
, *Pt
;
4644 Lut
= cmsPipelineAlloc(DbgThread(), 3, 3);
4646 cmsPipelineInsertStage(Lut
, cmsAT_BEGIN
, _cmsStageAllocLabV2ToV4(DbgThread()));
4647 cmsPipelineInsertStage(Lut
, cmsAT_END
, _cmsStageAllocLabV4ToV2(DbgThread()));
4648 AddIdentityCLUTfloat(Lut
);
4650 G
[0] = G
[1] = G
[2] = CreateSegmentedCurve();
4651 cmsPipelineInsertStage(Lut
, cmsAT_END
, cmsStageAllocToneCurves(DbgThread(), 3, G
));
4652 cmsFreeToneCurve(G
[0]);
4654 rc
= cmsWriteTag(hProfile
, tag
, Lut
);
4655 cmsPipelineFree(Lut
);
4659 Pt
= cmsReadTag(hProfile
, tag
);
4660 if (Pt
== NULL
) return 0;
4661 return CheckFloatLUT(Pt
);
4670 cmsInt32Number
CheckScreening(cmsInt32Number Pass
, cmsHPROFILE hProfile
, cmsTagSignature tag
)
4672 cmsScreening
*Pt
, sc
;
4681 sc
.Channels
[0].Frequency
= 2.0;
4682 sc
.Channels
[0].ScreenAngle
= 3.0;
4683 sc
.Channels
[0].SpotShape
= cmsSPOT_ELLIPSE
;
4685 rc
= cmsWriteTag(hProfile
, tag
, &sc
);
4690 Pt
= cmsReadTag(hProfile
, tag
);
4691 if (Pt
== NULL
) return 0;
4693 if (Pt
->nChannels
!= 1) return 0;
4694 if (Pt
->Flag
!= 0) return 0;
4695 if (!IsGoodFixed15_16("Freq", Pt
->Channels
[0].Frequency
, 2.0)) return 0;
4696 if (!IsGoodFixed15_16("Angle", Pt
->Channels
[0].ScreenAngle
, 3.0)) return 0;
4697 if (Pt
->Channels
[0].SpotShape
!= cmsSPOT_ELLIPSE
) return 0;
4707 cmsBool
CheckOneStr(cmsMLU
* mlu
, cmsInt32Number n
)
4709 char Buffer
[256], Buffer2
[256];
4712 cmsMLUgetASCII(mlu
, "en", "US", Buffer
, 255);
4713 sprintf(Buffer2
, "Hello, world %d", n
);
4714 if (strcmp(Buffer
, Buffer2
) != 0) return FALSE
;
4717 cmsMLUgetASCII(mlu
, "es", "ES", Buffer
, 255);
4718 sprintf(Buffer2
, "Hola, mundo %d", n
);
4719 if (strcmp(Buffer
, Buffer2
) != 0) return FALSE
;
4726 void SetOneStr(cmsMLU
** mlu
, wchar_t* s1
, wchar_t* s2
)
4728 *mlu
= cmsMLUalloc(DbgThread(), 0);
4729 cmsMLUsetWide(*mlu
, "en", "US", s1
);
4730 cmsMLUsetWide(*mlu
, "es", "ES", s2
);
4735 cmsInt32Number
CheckProfileSequenceTag(cmsInt32Number Pass
, cmsHPROFILE hProfile
)
4744 s
= cmsAllocProfileSequenceDescription(DbgThread(), 3);
4745 if (s
== NULL
) return 0;
4747 SetOneStr(&s
-> seq
[0].Manufacturer
, L
"Hello, world 0", L
"Hola, mundo 0");
4748 SetOneStr(&s
-> seq
[0].Model
, L
"Hello, world 0", L
"Hola, mundo 0");
4749 SetOneStr(&s
-> seq
[1].Manufacturer
, L
"Hello, world 1", L
"Hola, mundo 1");
4750 SetOneStr(&s
-> seq
[1].Model
, L
"Hello, world 1", L
"Hola, mundo 1");
4751 SetOneStr(&s
-> seq
[2].Manufacturer
, L
"Hello, world 2", L
"Hola, mundo 2");
4752 SetOneStr(&s
-> seq
[2].Model
, L
"Hello, world 2", L
"Hola, mundo 2");
4755 #ifdef CMS_DONT_USE_INT64
4756 s
->seq
[0].attributes
[0] = cmsTransparency
|cmsMatte
;
4757 s
->seq
[0].attributes
[1] = 0;
4759 s
->seq
[0].attributes
= cmsTransparency
|cmsMatte
;
4762 #ifdef CMS_DONT_USE_INT64
4763 s
->seq
[1].attributes
[0] = cmsReflective
|cmsMatte
;
4764 s
->seq
[1].attributes
[1] = 0;
4766 s
->seq
[1].attributes
= cmsReflective
|cmsMatte
;
4769 #ifdef CMS_DONT_USE_INT64
4770 s
->seq
[2].attributes
[0] = cmsTransparency
|cmsGlossy
;
4771 s
->seq
[2].attributes
[1] = 0;
4773 s
->seq
[2].attributes
= cmsTransparency
|cmsGlossy
;
4776 if (!cmsWriteTag(hProfile
, cmsSigProfileSequenceDescTag
, s
)) return 0;
4777 cmsFreeProfileSequenceDescription(s
);
4782 s
= cmsReadTag(hProfile
, cmsSigProfileSequenceDescTag
);
4783 if (s
== NULL
) return 0;
4785 if (s
->n
!= 3) return 0;
4787 #ifdef CMS_DONT_USE_INT64
4788 if (s
->seq
[0].attributes
[0] != (cmsTransparency
|cmsMatte
)) return 0;
4789 if (s
->seq
[0].attributes
[1] != 0) return 0;
4791 if (s
->seq
[0].attributes
!= (cmsTransparency
|cmsMatte
)) return 0;
4794 #ifdef CMS_DONT_USE_INT64
4795 if (s
->seq
[1].attributes
[0] != (cmsReflective
|cmsMatte
)) return 0;
4796 if (s
->seq
[1].attributes
[1] != 0) return 0;
4798 if (s
->seq
[1].attributes
!= (cmsReflective
|cmsMatte
)) return 0;
4801 #ifdef CMS_DONT_USE_INT64
4802 if (s
->seq
[2].attributes
[0] != (cmsTransparency
|cmsGlossy
)) return 0;
4803 if (s
->seq
[2].attributes
[1] != 0) return 0;
4805 if (s
->seq
[2].attributes
!= (cmsTransparency
|cmsGlossy
)) return 0;
4809 for (i
=0; i
< 3; i
++) {
4811 if (!CheckOneStr(s
-> seq
[i
].Manufacturer
, i
)) return 0;
4812 if (!CheckOneStr(s
-> seq
[i
].Model
, i
)) return 0;
4823 cmsInt32Number
CheckProfileSequenceIDTag(cmsInt32Number Pass
, cmsHPROFILE hProfile
)
4832 s
= cmsAllocProfileSequenceDescription(DbgThread(), 3);
4833 if (s
== NULL
) return 0;
4835 memcpy(s
->seq
[0].ProfileID
.ID8
, "0123456789ABCDEF", 16);
4836 memcpy(s
->seq
[1].ProfileID
.ID8
, "1111111111111111", 16);
4837 memcpy(s
->seq
[2].ProfileID
.ID8
, "2222222222222222", 16);
4840 SetOneStr(&s
-> seq
[0].Description
, L
"Hello, world 0", L
"Hola, mundo 0");
4841 SetOneStr(&s
-> seq
[1].Description
, L
"Hello, world 1", L
"Hola, mundo 1");
4842 SetOneStr(&s
-> seq
[2].Description
, L
"Hello, world 2", L
"Hola, mundo 2");
4844 if (!cmsWriteTag(hProfile
, cmsSigProfileSequenceIdTag
, s
)) return 0;
4845 cmsFreeProfileSequenceDescription(s
);
4850 s
= cmsReadTag(hProfile
, cmsSigProfileSequenceIdTag
);
4851 if (s
== NULL
) return 0;
4853 if (s
->n
!= 3) return 0;
4855 if (memcmp(s
->seq
[0].ProfileID
.ID8
, "0123456789ABCDEF", 16) != 0) return 0;
4856 if (memcmp(s
->seq
[1].ProfileID
.ID8
, "1111111111111111", 16) != 0) return 0;
4857 if (memcmp(s
->seq
[2].ProfileID
.ID8
, "2222222222222222", 16) != 0) return 0;
4859 for (i
=0; i
< 3; i
++) {
4861 if (!CheckOneStr(s
-> seq
[i
].Description
, i
)) return 0;
4873 cmsInt32Number
CheckICCViewingConditions(cmsInt32Number Pass
, cmsHPROFILE hProfile
)
4875 cmsICCViewingConditions
* v
;
4876 cmsICCViewingConditions s
;
4881 s
.IlluminantType
= 1;
4882 s
.IlluminantXYZ
.X
= 0.1;
4883 s
.IlluminantXYZ
.Y
= 0.2;
4884 s
.IlluminantXYZ
.Z
= 0.3;
4885 s
.SurroundXYZ
.X
= 0.4;
4886 s
.SurroundXYZ
.Y
= 0.5;
4887 s
.SurroundXYZ
.Z
= 0.6;
4889 if (!cmsWriteTag(hProfile
, cmsSigViewingConditionsTag
, &s
)) return 0;
4893 v
= cmsReadTag(hProfile
, cmsSigViewingConditionsTag
);
4894 if (v
== NULL
) return 0;
4896 if (v
->IlluminantType
!= 1) return 0;
4897 if (!IsGoodVal("IlluminantXYZ.X", v
->IlluminantXYZ
.X
, 0.1, 0.001)) return 0;
4898 if (!IsGoodVal("IlluminantXYZ.Y", v
->IlluminantXYZ
.Y
, 0.2, 0.001)) return 0;
4899 if (!IsGoodVal("IlluminantXYZ.Z", v
->IlluminantXYZ
.Z
, 0.3, 0.001)) return 0;
4901 if (!IsGoodVal("SurroundXYZ.X", v
->SurroundXYZ
.X
, 0.4, 0.001)) return 0;
4902 if (!IsGoodVal("SurroundXYZ.Y", v
->SurroundXYZ
.Y
, 0.5, 0.001)) return 0;
4903 if (!IsGoodVal("SurroundXYZ.Z", v
->SurroundXYZ
.Z
, 0.6, 0.001)) return 0;
4915 cmsInt32Number
CheckVCGT(cmsInt32Number Pass
, cmsHPROFILE hProfile
)
4917 cmsToneCurve
* Curves
[3];
4918 cmsToneCurve
** PtrCurve
;
4923 Curves
[0] = cmsBuildGamma(DbgThread(), 1.1);
4924 Curves
[1] = cmsBuildGamma(DbgThread(), 2.2);
4925 Curves
[2] = cmsBuildGamma(DbgThread(), 3.4);
4927 if (!cmsWriteTag(hProfile
, cmsSigVcgtTag
, Curves
)) return 0;
4929 cmsFreeToneCurveTriple(Curves
);
4935 PtrCurve
= cmsReadTag(hProfile
, cmsSigVcgtTag
);
4936 if (PtrCurve
== NULL
) return 0;
4937 if (!IsGoodVal("VCGT R", cmsEstimateGamma(PtrCurve
[0], 0.01), 1.1, 0.001)) return 0;
4938 if (!IsGoodVal("VCGT G", cmsEstimateGamma(PtrCurve
[1], 0.01), 2.2, 0.001)) return 0;
4939 if (!IsGoodVal("VCGT B", cmsEstimateGamma(PtrCurve
[2], 0.01), 3.4, 0.001)) return 0;
4949 // Only one of the two following may be used, as they share the same tag
4951 cmsInt32Number
CheckDictionary16(cmsInt32Number Pass
, cmsHPROFILE hProfile
)
4954 const cmsDICTentry
* e
;
4958 hDict
= cmsDictAlloc(DbgThread());
4959 cmsDictAddEntry(hDict
, L
"Name0", NULL
, NULL
, NULL
);
4960 cmsDictAddEntry(hDict
, L
"Name1", L
"", NULL
, NULL
);
4961 cmsDictAddEntry(hDict
, L
"Name", L
"String", NULL
, NULL
);
4962 cmsDictAddEntry(hDict
, L
"Name2", L
"12", NULL
, NULL
);
4963 if (!cmsWriteTag(hProfile
, cmsSigMetaTag
, hDict
)) return 0;
4970 hDict
= cmsReadTag(hProfile
, cmsSigMetaTag
);
4971 if (hDict
== NULL
) return 0;
4972 e
= cmsDictGetEntryList(hDict
);
4973 if (memcmp(e
->Name
, L
"Name2", sizeof(wchar_t) * 5) != 0) return 0;
4974 if (memcmp(e
->Value
, L
"12", sizeof(wchar_t) * 2) != 0) return 0;
4975 e
= cmsDictNextEntry(e
);
4976 if (memcmp(e
->Name
, L
"Name", sizeof(wchar_t) * 4) != 0) return 0;
4977 if (memcmp(e
->Value
, L
"String", sizeof(wchar_t) * 5) != 0) return 0;
4978 e
= cmsDictNextEntry(e
);
4979 if (memcmp(e
->Name
, L
"Name1", sizeof(wchar_t) *5) != 0) return 0;
4980 if (e
->Value
== NULL
) return 0;
4981 if (*e
->Value
!= 0) return 0;
4982 e
= cmsDictNextEntry(e
);
4983 if (memcmp(e
->Name
, L
"Name0", sizeof(wchar_t) * 5) != 0) return 0;
4984 if (e
->Value
!= NULL
) return 0;
4997 cmsInt32Number
CheckDictionary24(cmsInt32Number Pass
, cmsHPROFILE hProfile
)
5000 const cmsDICTentry
* e
;
5001 cmsMLU
* DisplayName
;
5003 cmsInt32Number rc
= 1;
5008 hDict
= cmsDictAlloc(DbgThread());
5010 DisplayName
= cmsMLUalloc(DbgThread(), 0);
5012 cmsMLUsetWide(DisplayName
, "en", "US", L
"Hello, world");
5013 cmsMLUsetWide(DisplayName
, "es", "ES", L
"Hola, mundo");
5014 cmsMLUsetWide(DisplayName
, "fr", "FR", L
"Bonjour, le monde");
5015 cmsMLUsetWide(DisplayName
, "ca", "CA", L
"Hola, mon");
5017 cmsDictAddEntry(hDict
, L
"Name", L
"String", DisplayName
, NULL
);
5018 cmsMLUfree(DisplayName
);
5020 cmsDictAddEntry(hDict
, L
"Name2", L
"12", NULL
, NULL
);
5021 if (!cmsWriteTag(hProfile
, cmsSigMetaTag
, hDict
)) return 0;
5029 hDict
= cmsReadTag(hProfile
, cmsSigMetaTag
);
5030 if (hDict
== NULL
) return 0;
5032 e
= cmsDictGetEntryList(hDict
);
5033 if (memcmp(e
->Name
, L
"Name2", sizeof(wchar_t) * 5) != 0) return 0;
5034 if (memcmp(e
->Value
, L
"12", sizeof(wchar_t) * 2) != 0) return 0;
5035 e
= cmsDictNextEntry(e
);
5036 if (memcmp(e
->Name
, L
"Name", sizeof(wchar_t) * 4) != 0) return 0;
5037 if (memcmp(e
->Value
, L
"String", sizeof(wchar_t) * 5) != 0) return 0;
5039 cmsMLUgetASCII(e
->DisplayName
, "en", "US", Buffer
, 256);
5040 if (strcmp(Buffer
, "Hello, world") != 0) rc
= 0;
5043 cmsMLUgetASCII(e
->DisplayName
, "es", "ES", Buffer
, 256);
5044 if (strcmp(Buffer
, "Hola, mundo") != 0) rc
= 0;
5047 cmsMLUgetASCII(e
->DisplayName
, "fr", "FR", Buffer
, 256);
5048 if (strcmp(Buffer
, "Bonjour, le monde") != 0) rc
= 0;
5051 cmsMLUgetASCII(e
->DisplayName
, "ca", "CA", Buffer
, 256);
5052 if (strcmp(Buffer
, "Hola, mon") != 0) rc
= 0;
5055 Fail("Unexpected string '%s'", Buffer
);
5065 cmsInt32Number
CheckRAWtags(cmsInt32Number Pass
, cmsHPROFILE hProfile
)
5072 return cmsWriteRawTag(hProfile
, 0x31323334, "data123", 7);
5075 if (!cmsReadRawTag(hProfile
, 0x31323334, Buffer
, 7)) return 0;
5077 if (strncmp(Buffer
, "data123", 7) != 0) return 0;
5086 // This is a very big test that checks every single tag
5088 cmsInt32Number
CheckProfileCreation(void)
5091 cmsInt32Number Pass
;
5093 h
= cmsCreateProfilePlaceholder(DbgThread());
5094 if (h
== NULL
) return 0;
5096 cmsSetProfileVersion(h
, 4.3);
5097 if (cmsGetTagCount(h
) != 0) { Fail("Empty profile with nonzero number of tags"); return 0; }
5098 if (cmsIsTag(h
, cmsSigAToB0Tag
)) { Fail("Found a tag in an empty profile"); return 0; }
5100 cmsSetColorSpace(h
, cmsSigRgbData
);
5101 if (cmsGetColorSpace(h
) != cmsSigRgbData
) { Fail("Unable to set colorspace"); return 0; }
5103 cmsSetPCS(h
, cmsSigLabData
);
5104 if (cmsGetPCS(h
) != cmsSigLabData
) { Fail("Unable to set colorspace"); return 0; }
5106 cmsSetDeviceClass(h
, cmsSigDisplayClass
);
5107 if (cmsGetDeviceClass(h
) != cmsSigDisplayClass
) { Fail("Unable to set deviceclass"); return 0; }
5109 cmsSetHeaderRenderingIntent(h
, INTENT_SATURATION
);
5110 if (cmsGetHeaderRenderingIntent(h
) != INTENT_SATURATION
) { Fail("Unable to set rendering intent"); return 0; }
5112 for (Pass
= 1; Pass
<= 2; Pass
++) {
5114 SubTest("Tags holding XYZ");
5116 if (!CheckXYZ(Pass
, h
, cmsSigBlueColorantTag
)) return 0;
5117 if (!CheckXYZ(Pass
, h
, cmsSigGreenColorantTag
)) return 0;
5118 if (!CheckXYZ(Pass
, h
, cmsSigRedColorantTag
)) return 0;
5119 if (!CheckXYZ(Pass
, h
, cmsSigMediaBlackPointTag
)) return 0;
5120 if (!CheckXYZ(Pass
, h
, cmsSigMediaWhitePointTag
)) return 0;
5121 if (!CheckXYZ(Pass
, h
, cmsSigLuminanceTag
)) return 0;
5123 SubTest("Tags holding curves");
5125 if (!CheckGamma(Pass
, h
, cmsSigBlueTRCTag
)) return 0;
5126 if (!CheckGamma(Pass
, h
, cmsSigGrayTRCTag
)) return 0;
5127 if (!CheckGamma(Pass
, h
, cmsSigGreenTRCTag
)) return 0;
5128 if (!CheckGamma(Pass
, h
, cmsSigRedTRCTag
)) return 0;
5130 SubTest("Tags holding text");
5132 if (!CheckText(Pass
, h
, cmsSigCharTargetTag
)) return 0;
5133 if (!CheckText(Pass
, h
, cmsSigCopyrightTag
)) return 0;
5134 if (!CheckText(Pass
, h
, cmsSigProfileDescriptionTag
)) return 0;
5135 if (!CheckText(Pass
, h
, cmsSigDeviceMfgDescTag
)) return 0;
5136 if (!CheckText(Pass
, h
, cmsSigDeviceModelDescTag
)) return 0;
5137 if (!CheckText(Pass
, h
, cmsSigViewingCondDescTag
)) return 0;
5138 if (!CheckText(Pass
, h
, cmsSigScreeningDescTag
)) return 0;
5140 SubTest("Tags holding cmsICCData");
5142 if (!CheckData(Pass
, h
, cmsSigPs2CRD0Tag
)) return 0;
5143 if (!CheckData(Pass
, h
, cmsSigPs2CRD1Tag
)) return 0;
5144 if (!CheckData(Pass
, h
, cmsSigPs2CRD2Tag
)) return 0;
5145 if (!CheckData(Pass
, h
, cmsSigPs2CRD3Tag
)) return 0;
5146 if (!CheckData(Pass
, h
, cmsSigPs2CSATag
)) return 0;
5147 if (!CheckData(Pass
, h
, cmsSigPs2RenderingIntentTag
)) return 0;
5149 SubTest("Tags holding signatures");
5151 if (!CheckSignature(Pass
, h
, cmsSigColorimetricIntentImageStateTag
)) return 0;
5152 if (!CheckSignature(Pass
, h
, cmsSigPerceptualRenderingIntentGamutTag
)) return 0;
5153 if (!CheckSignature(Pass
, h
, cmsSigSaturationRenderingIntentGamutTag
)) return 0;
5154 if (!CheckSignature(Pass
, h
, cmsSigTechnologyTag
)) return 0;
5156 SubTest("Tags holding date_time");
5158 if (!CheckDateTime(Pass
, h
, cmsSigCalibrationDateTimeTag
)) return 0;
5159 if (!CheckDateTime(Pass
, h
, cmsSigDateTimeTag
)) return 0;
5161 SubTest("Tags holding named color lists");
5163 if (!CheckNamedColor(Pass
, h
, cmsSigColorantTableTag
, 15, FALSE
)) return 0;
5164 if (!CheckNamedColor(Pass
, h
, cmsSigColorantTableOutTag
, 15, FALSE
)) return 0;
5165 if (!CheckNamedColor(Pass
, h
, cmsSigNamedColor2Tag
, 4096, TRUE
)) return 0;
5167 SubTest("Tags holding LUTs");
5169 if (!CheckLUT(Pass
, h
, cmsSigAToB0Tag
)) return 0;
5170 if (!CheckLUT(Pass
, h
, cmsSigAToB1Tag
)) return 0;
5171 if (!CheckLUT(Pass
, h
, cmsSigAToB2Tag
)) return 0;
5172 if (!CheckLUT(Pass
, h
, cmsSigBToA0Tag
)) return 0;
5173 if (!CheckLUT(Pass
, h
, cmsSigBToA1Tag
)) return 0;
5174 if (!CheckLUT(Pass
, h
, cmsSigBToA2Tag
)) return 0;
5175 if (!CheckLUT(Pass
, h
, cmsSigPreview0Tag
)) return 0;
5176 if (!CheckLUT(Pass
, h
, cmsSigPreview1Tag
)) return 0;
5177 if (!CheckLUT(Pass
, h
, cmsSigPreview2Tag
)) return 0;
5178 if (!CheckLUT(Pass
, h
, cmsSigGamutTag
)) return 0;
5180 SubTest("Tags holding CHAD");
5181 if (!CheckCHAD(Pass
, h
, cmsSigChromaticAdaptationTag
)) return 0;
5183 SubTest("Tags holding Chromaticity");
5184 if (!CheckChromaticity(Pass
, h
, cmsSigChromaticityTag
)) return 0;
5186 SubTest("Tags holding colorant order");
5187 if (!CheckColorantOrder(Pass
, h
, cmsSigColorantOrderTag
)) return 0;
5189 SubTest("Tags holding measurement");
5190 if (!CheckMeasurement(Pass
, h
, cmsSigMeasurementTag
)) return 0;
5192 SubTest("Tags holding CRD info");
5193 if (!CheckCRDinfo(Pass
, h
, cmsSigCrdInfoTag
)) return 0;
5195 SubTest("Tags holding UCR/BG");
5196 if (!CheckUcrBg(Pass
, h
, cmsSigUcrBgTag
)) return 0;
5198 SubTest("Tags holding MPE");
5199 if (!CheckMPE(Pass
, h
, cmsSigDToB0Tag
)) return 0;
5200 if (!CheckMPE(Pass
, h
, cmsSigDToB1Tag
)) return 0;
5201 if (!CheckMPE(Pass
, h
, cmsSigDToB2Tag
)) return 0;
5202 if (!CheckMPE(Pass
, h
, cmsSigDToB3Tag
)) return 0;
5203 if (!CheckMPE(Pass
, h
, cmsSigBToD0Tag
)) return 0;
5204 if (!CheckMPE(Pass
, h
, cmsSigBToD1Tag
)) return 0;
5205 if (!CheckMPE(Pass
, h
, cmsSigBToD2Tag
)) return 0;
5206 if (!CheckMPE(Pass
, h
, cmsSigBToD3Tag
)) return 0;
5208 SubTest("Tags using screening");
5209 if (!CheckScreening(Pass
, h
, cmsSigScreeningTag
)) return 0;
5211 SubTest("Tags holding profile sequence description");
5212 if (!CheckProfileSequenceTag(Pass
, h
)) return 0;
5213 if (!CheckProfileSequenceIDTag(Pass
, h
)) return 0;
5215 SubTest("Tags holding ICC viewing conditions");
5216 if (!CheckICCViewingConditions(Pass
, h
)) return 0;
5219 SubTest("VCGT tags");
5220 if (!CheckVCGT(Pass
, h
)) return 0;
5222 SubTest("RAW tags");
5223 if (!CheckRAWtags(Pass
, h
)) return 0;
5225 SubTest("Dictionary meta tags");
5226 // if (!CheckDictionary16(Pass, h)) return 0;
5227 if (!CheckDictionary24(Pass
, h
)) return 0;
5230 cmsSaveProfileToFile(h
, "alltags.icc");
5232 h
= cmsOpenProfileFromFileTHR(DbgThread(), "alltags.icc", "r");
5238 Not implemented (by design):
5240 cmsSigDataTag = 0x64617461, // 'data' -- Unused
5241 cmsSigDeviceSettingsTag = 0x64657673, // 'devs' -- Unused
5242 cmsSigNamedColorTag = 0x6E636f6C, // 'ncol' -- Don't use this one, deprecated by ICC
5243 cmsSigOutputResponseTag = 0x72657370, // 'resp' -- Possible patent on this
5247 remove("alltags.icc");
5252 // Error reporting -------------------------------------------------------------------------------------------------------
5256 void ErrorReportingFunction(cmsContext ContextID
, cmsUInt32Number ErrorCode
, const char *Text
)
5258 TrappedError
= TRUE
;
5259 SimultaneousErrors
++;
5260 strncpy(ReasonToFailBuffer
, Text
, TEXT_ERROR_BUFFER_SIZE
-1);
5262 cmsUNUSED_PARAMETER(ContextID
);
5263 cmsUNUSED_PARAMETER(ErrorCode
);
5268 cmsInt32Number
CheckBadProfiles(void)
5272 h
= cmsOpenProfileFromFileTHR(DbgThread(), "IDoNotExist.icc", "r");
5278 h
= cmsOpenProfileFromFileTHR(DbgThread(), "IAmIllFormed*.icc", "r");
5284 // No profile name given
5285 h
= cmsOpenProfileFromFileTHR(DbgThread(), "", "r");
5291 h
= cmsOpenProfileFromFileTHR(DbgThread(), "..", "r");
5297 h
= cmsOpenProfileFromFileTHR(DbgThread(), "IHaveBadAccessMode.icc", "@");
5303 h
= cmsOpenProfileFromFileTHR(DbgThread(), "bad.icc", "r");
5309 h
= cmsOpenProfileFromFileTHR(DbgThread(), "toosmall.icc", "r");
5315 h
= cmsOpenProfileFromMemTHR(DbgThread(), NULL
, 3);
5321 h
= cmsOpenProfileFromMemTHR(DbgThread(), "123", 3);
5327 if (SimultaneousErrors
!= 9) return 0;
5334 cmsInt32Number
CheckErrReportingOnBadProfiles(void)
5338 cmsSetLogErrorHandler(ErrorReportingFunction
);
5339 rc
= CheckBadProfiles();
5340 cmsSetLogErrorHandler(FatalErrorQuit
);
5342 // Reset the error state
5343 TrappedError
= FALSE
;
5349 cmsInt32Number
CheckBadTransforms(void)
5351 cmsHPROFILE h1
= cmsCreate_sRGBProfile();
5354 x1
= cmsCreateTransform(NULL
, 0, NULL
, 0, 0, 0);
5356 cmsDeleteTransform(x1
);
5362 x1
= cmsCreateTransform(h1
, TYPE_RGB_8
, h1
, TYPE_RGB_8
, 12345, 0);
5364 cmsDeleteTransform(x1
);
5368 x1
= cmsCreateTransform(h1
, TYPE_CMYK_8
, h1
, TYPE_RGB_8
, 0, 0);
5370 cmsDeleteTransform(x1
);
5374 x1
= cmsCreateTransform(h1
, TYPE_RGB_8
, h1
, TYPE_CMYK_8
, 1, 0);
5376 cmsDeleteTransform(x1
);
5380 // sRGB does its output as XYZ!
5381 x1
= cmsCreateTransform(h1
, TYPE_RGB_8
, NULL
, TYPE_Lab_8
, 1, 0);
5383 cmsDeleteTransform(x1
);
5387 cmsCloseProfile(h1
);
5392 cmsHPROFILE hp1
= cmsOpenProfileFromFile("test1.icc", "r");
5393 cmsHPROFILE hp2
= cmsCreate_sRGBProfile();
5395 x1
= cmsCreateTransform(hp1
, TYPE_BGR_8
, hp2
, TYPE_BGR_8
, INTENT_PERCEPTUAL
, 0);
5397 cmsCloseProfile(hp1
); cmsCloseProfile(hp2
);
5399 cmsDeleteTransform(x1
);
5409 cmsInt32Number
CheckErrReportingOnBadTransforms(void)
5413 cmsSetLogErrorHandler(ErrorReportingFunction
);
5414 rc
= CheckBadTransforms();
5415 cmsSetLogErrorHandler(FatalErrorQuit
);
5417 // Reset the error state
5418 TrappedError
= FALSE
;
5425 // ---------------------------------------------------------------------------------------------------------
5427 // Check a linear xform
5429 cmsInt32Number
Check8linearXFORM(cmsHTRANSFORM xform
, cmsInt32Number nChan
)
5431 cmsInt32Number n2
, i
, j
;
5432 cmsUInt8Number Inw
[cmsMAXCHANNELS
], Outw
[cmsMAXCHANNELS
];
5436 for (j
=0; j
< 0xFF; j
++) {
5438 memset(Inw
, j
, sizeof(Inw
));
5439 cmsDoTransform(xform
, Inw
, Outw
, 1);
5441 for (i
=0; i
< nChan
; i
++) {
5443 cmsInt32Number dif
= abs(Outw
[i
] - j
);
5444 if (dif
> n2
) n2
= dif
;
5449 // We allow 2 contone of difference on 8 bits
5452 Fail("Differences too big (%x)", n2
);
5460 cmsInt32Number
Compare8bitXFORM(cmsHTRANSFORM xform1
, cmsHTRANSFORM xform2
, cmsInt32Number nChan
)
5462 cmsInt32Number n2
, i
, j
;
5463 cmsUInt8Number Inw
[cmsMAXCHANNELS
], Outw1
[cmsMAXCHANNELS
], Outw2
[cmsMAXCHANNELS
];;
5467 for (j
=0; j
< 0xFF; j
++) {
5469 memset(Inw
, j
, sizeof(Inw
));
5470 cmsDoTransform(xform1
, Inw
, Outw1
, 1);
5471 cmsDoTransform(xform2
, Inw
, Outw2
, 1);
5473 for (i
=0; i
< nChan
; i
++) {
5475 cmsInt32Number dif
= abs(Outw2
[i
] - Outw1
[i
]);
5476 if (dif
> n2
) n2
= dif
;
5481 // We allow 2 contone of difference on 8 bits
5484 Fail("Differences too big (%x)", n2
);
5493 // Check a linear xform
5495 cmsInt32Number
Check16linearXFORM(cmsHTRANSFORM xform
, cmsInt32Number nChan
)
5497 cmsInt32Number n2
, i
, j
;
5498 cmsUInt16Number Inw
[cmsMAXCHANNELS
], Outw
[cmsMAXCHANNELS
];
5501 for (j
=0; j
< 0xFFFF; j
++) {
5503 for (i
=0; i
< nChan
; i
++) Inw
[i
] = (cmsUInt16Number
) j
;
5505 cmsDoTransform(xform
, Inw
, Outw
, 1);
5507 for (i
=0; i
< nChan
; i
++) {
5509 cmsInt32Number dif
= abs(Outw
[i
] - j
);
5510 if (dif
> n2
) n2
= dif
;
5515 // We allow 2 contone of difference on 16 bits
5518 Fail("Differences too big (%x)", n2
);
5527 cmsInt32Number
Compare16bitXFORM(cmsHTRANSFORM xform1
, cmsHTRANSFORM xform2
, cmsInt32Number nChan
)
5529 cmsInt32Number n2
, i
, j
;
5530 cmsUInt16Number Inw
[cmsMAXCHANNELS
], Outw1
[cmsMAXCHANNELS
], Outw2
[cmsMAXCHANNELS
];;
5534 for (j
=0; j
< 0xFFFF; j
++) {
5536 for (i
=0; i
< nChan
; i
++) Inw
[i
] = (cmsUInt16Number
) j
;
5538 cmsDoTransform(xform1
, Inw
, Outw1
, 1);
5539 cmsDoTransform(xform2
, Inw
, Outw2
, 1);
5541 for (i
=0; i
< nChan
; i
++) {
5543 cmsInt32Number dif
= abs(Outw2
[i
] - Outw1
[i
]);
5544 if (dif
> n2
) n2
= dif
;
5549 // We allow 2 contone of difference on 16 bits
5552 Fail("Differences too big (%x)", n2
);
5561 // Check a linear xform
5563 cmsInt32Number
CheckFloatlinearXFORM(cmsHTRANSFORM xform
, cmsInt32Number nChan
)
5565 cmsInt32Number i
, j
;
5566 cmsFloat32Number In
[cmsMAXCHANNELS
], Out
[cmsMAXCHANNELS
];
5568 for (j
=0; j
< 0xFFFF; j
++) {
5570 for (i
=0; i
< nChan
; i
++) In
[i
] = (cmsFloat32Number
) (j
/ 65535.0);;
5572 cmsDoTransform(xform
, In
, Out
, 1);
5574 for (i
=0; i
< nChan
; i
++) {
5576 // We allow no difference in floating point
5577 if (!IsGoodFixed15_16("linear xform cmsFloat32Number", Out
[i
], (cmsFloat32Number
) (j
/ 65535.0)))
5586 // Check a linear xform
5588 cmsInt32Number
CompareFloatXFORM(cmsHTRANSFORM xform1
, cmsHTRANSFORM xform2
, cmsInt32Number nChan
)
5590 cmsInt32Number i
, j
;
5591 cmsFloat32Number In
[cmsMAXCHANNELS
], Out1
[cmsMAXCHANNELS
], Out2
[cmsMAXCHANNELS
];
5593 for (j
=0; j
< 0xFFFF; j
++) {
5595 for (i
=0; i
< nChan
; i
++) In
[i
] = (cmsFloat32Number
) (j
/ 65535.0);;
5597 cmsDoTransform(xform1
, In
, Out1
, 1);
5598 cmsDoTransform(xform2
, In
, Out2
, 1);
5600 for (i
=0; i
< nChan
; i
++) {
5602 // We allow no difference in floating point
5603 if (!IsGoodFixed15_16("linear xform cmsFloat32Number", Out1
[i
], Out2
[i
]))
5613 // Curves only transforms ----------------------------------------------------------------------------------------
5616 cmsInt32Number
CheckCurvesOnlyTransforms(void)
5619 cmsHTRANSFORM xform1
, xform2
;
5620 cmsHPROFILE h1
, h2
, h3
;
5621 cmsToneCurve
* c1
, *c2
, *c3
;
5622 cmsInt32Number rc
= 1;
5625 c1
= cmsBuildGamma(DbgThread(), 2.2);
5626 c2
= cmsBuildGamma(DbgThread(), 1/2.2);
5627 c3
= cmsBuildGamma(DbgThread(), 4.84);
5629 h1
= cmsCreateLinearizationDeviceLinkTHR(DbgThread(), cmsSigGrayData
, &c1
);
5630 h2
= cmsCreateLinearizationDeviceLinkTHR(DbgThread(), cmsSigGrayData
, &c2
);
5631 h3
= cmsCreateLinearizationDeviceLinkTHR(DbgThread(), cmsSigGrayData
, &c3
);
5633 SubTest("Gray float optimizeable transform");
5634 xform1
= cmsCreateTransform(h1
, TYPE_GRAY_FLT
, h2
, TYPE_GRAY_FLT
, INTENT_PERCEPTUAL
, 0);
5635 rc
&= CheckFloatlinearXFORM(xform1
, 1);
5636 cmsDeleteTransform(xform1
);
5637 if (rc
== 0) goto Error
;
5639 SubTest("Gray 8 optimizeable transform");
5640 xform1
= cmsCreateTransform(h1
, TYPE_GRAY_8
, h2
, TYPE_GRAY_8
, INTENT_PERCEPTUAL
, 0);
5641 rc
&= Check8linearXFORM(xform1
, 1);
5642 cmsDeleteTransform(xform1
);
5643 if (rc
== 0) goto Error
;
5645 SubTest("Gray 16 optimizeable transform");
5646 xform1
= cmsCreateTransform(h1
, TYPE_GRAY_16
, h2
, TYPE_GRAY_16
, INTENT_PERCEPTUAL
, 0);
5647 rc
&= Check16linearXFORM(xform1
, 1);
5648 cmsDeleteTransform(xform1
);
5649 if (rc
== 0) goto Error
;
5651 SubTest("Gray float non-optimizeable transform");
5652 xform1
= cmsCreateTransform(h1
, TYPE_GRAY_FLT
, h1
, TYPE_GRAY_FLT
, INTENT_PERCEPTUAL
, 0);
5653 xform2
= cmsCreateTransform(h3
, TYPE_GRAY_FLT
, NULL
, TYPE_GRAY_FLT
, INTENT_PERCEPTUAL
, 0);
5655 rc
&= CompareFloatXFORM(xform1
, xform2
, 1);
5656 cmsDeleteTransform(xform1
);
5657 cmsDeleteTransform(xform2
);
5658 if (rc
== 0) goto Error
;
5660 SubTest("Gray 8 non-optimizeable transform");
5661 xform1
= cmsCreateTransform(h1
, TYPE_GRAY_8
, h1
, TYPE_GRAY_8
, INTENT_PERCEPTUAL
, 0);
5662 xform2
= cmsCreateTransform(h3
, TYPE_GRAY_8
, NULL
, TYPE_GRAY_8
, INTENT_PERCEPTUAL
, 0);
5664 rc
&= Compare8bitXFORM(xform1
, xform2
, 1);
5665 cmsDeleteTransform(xform1
);
5666 cmsDeleteTransform(xform2
);
5667 if (rc
== 0) goto Error
;
5670 SubTest("Gray 16 non-optimizeable transform");
5671 xform1
= cmsCreateTransform(h1
, TYPE_GRAY_16
, h1
, TYPE_GRAY_16
, INTENT_PERCEPTUAL
, 0);
5672 xform2
= cmsCreateTransform(h3
, TYPE_GRAY_16
, NULL
, TYPE_GRAY_16
, INTENT_PERCEPTUAL
, 0);
5674 rc
&= Compare16bitXFORM(xform1
, xform2
, 1);
5675 cmsDeleteTransform(xform1
);
5676 cmsDeleteTransform(xform2
);
5677 if (rc
== 0) goto Error
;
5681 cmsCloseProfile(h1
); cmsCloseProfile(h2
); cmsCloseProfile(h3
);
5682 cmsFreeToneCurve(c1
); cmsFreeToneCurve(c2
); cmsFreeToneCurve(c3
);
5689 // Lab to Lab trivial transforms ----------------------------------------------------------------------------------------
5691 static cmsFloat64Number MaxDE
;
5694 cmsInt32Number
CheckOneLab(cmsHTRANSFORM xform
, cmsFloat64Number L
, cmsFloat64Number a
, cmsFloat64Number b
)
5697 cmsFloat64Number dE
;
5699 In
.L
= L
; In
.a
= a
; In
.b
= b
;
5700 cmsDoTransform(xform
, &In
, &Out
, 1);
5702 dE
= cmsDeltaE(&In
, &Out
);
5704 if (dE
> MaxDE
) MaxDE
= dE
;
5706 if (MaxDE
> 0.003) {
5707 Fail("dE=%f Lab1=(%f, %f, %f)\n\tLab2=(%f %f %f)", MaxDE
, In
.L
, In
.a
, In
.b
, Out
.L
, Out
.a
, Out
.b
);
5708 cmsDoTransform(xform
, &In
, &Out
, 1);
5715 // Check several Lab, slicing at non-exact values. Precision should be 16 bits. 50x50x50 checks aprox.
5717 cmsInt32Number
CheckSeveralLab(cmsHTRANSFORM xform
)
5719 cmsInt32Number L
, a
, b
;
5722 for (L
=0; L
< 65536; L
+= 1311) {
5724 for (a
= 0; a
< 65536; a
+= 1232) {
5726 for (b
= 0; b
< 65536; b
+= 1111) {
5728 if (!CheckOneLab(xform
, (L
* 100.0) / 65535.0,
5729 (a
/ 257.0) - 128, (b
/ 257.0) - 128))
5741 cmsInt32Number
OneTrivialLab(cmsHPROFILE hLab1
, cmsHPROFILE hLab2
, const char* txt
)
5743 cmsHTRANSFORM xform
;
5747 xform
= cmsCreateTransformTHR(DbgThread(), hLab1
, TYPE_Lab_DBL
, hLab2
, TYPE_Lab_DBL
, INTENT_RELATIVE_COLORIMETRIC
, 0);
5748 cmsCloseProfile(hLab1
); cmsCloseProfile(hLab2
);
5750 rc
= CheckSeveralLab(xform
);
5751 cmsDeleteTransform(xform
);
5757 cmsInt32Number
CheckFloatLabTransforms(void)
5759 return OneTrivialLab(cmsCreateLab4ProfileTHR(DbgThread(), NULL
), cmsCreateLab4ProfileTHR(DbgThread(), NULL
), "Lab4/Lab4") &&
5760 OneTrivialLab(cmsCreateLab2ProfileTHR(DbgThread(), NULL
), cmsCreateLab2ProfileTHR(DbgThread(), NULL
), "Lab2/Lab2") &&
5761 OneTrivialLab(cmsCreateLab4ProfileTHR(DbgThread(), NULL
), cmsCreateLab2ProfileTHR(DbgThread(), NULL
), "Lab4/Lab2") &&
5762 OneTrivialLab(cmsCreateLab2ProfileTHR(DbgThread(), NULL
), cmsCreateLab4ProfileTHR(DbgThread(), NULL
), "Lab2/Lab4");
5767 cmsInt32Number
CheckEncodedLabTransforms(void)
5769 cmsHTRANSFORM xform
;
5770 cmsUInt16Number In
[3];
5772 cmsCIELab White
= { 100, 0, 0 };
5773 cmsHPROFILE hLab1
= cmsCreateLab4ProfileTHR(DbgThread(), NULL
);
5774 cmsHPROFILE hLab2
= cmsCreateLab4ProfileTHR(DbgThread(), NULL
);
5777 xform
= cmsCreateTransformTHR(DbgThread(), hLab1
, TYPE_Lab_16
, hLab2
, TYPE_Lab_DBL
, INTENT_RELATIVE_COLORIMETRIC
, 0);
5778 cmsCloseProfile(hLab1
); cmsCloseProfile(hLab2
);
5784 cmsDoTransform(xform
, In
, &Lab
, 1);
5786 if (cmsDeltaE(&Lab
, &White
) > 0.0001) return 0;
5787 cmsDeleteTransform(xform
);
5789 hLab1
= cmsCreateLab2ProfileTHR(DbgThread(), NULL
);
5790 hLab2
= cmsCreateLab4ProfileTHR(DbgThread(), NULL
);
5792 xform
= cmsCreateTransformTHR(DbgThread(), hLab1
, TYPE_LabV2_16
, hLab2
, TYPE_Lab_DBL
, INTENT_RELATIVE_COLORIMETRIC
, 0);
5793 cmsCloseProfile(hLab1
); cmsCloseProfile(hLab2
);
5800 cmsDoTransform(xform
, In
, &Lab
, 1);
5802 if (cmsDeltaE(&Lab
, &White
) > 0.0001) return 0;
5804 cmsDeleteTransform(xform
);
5806 hLab2
= cmsCreateLab2ProfileTHR(DbgThread(), NULL
);
5807 hLab1
= cmsCreateLab4ProfileTHR(DbgThread(), NULL
);
5809 xform
= cmsCreateTransformTHR(DbgThread(), hLab1
, TYPE_Lab_DBL
, hLab2
, TYPE_LabV2_16
, INTENT_RELATIVE_COLORIMETRIC
, 0);
5810 cmsCloseProfile(hLab1
); cmsCloseProfile(hLab2
);
5816 cmsDoTransform(xform
, &Lab
, In
, 1);
5817 if (In
[0] != 0xFF00 ||
5819 In
[2] != 0x8000) return 0;
5821 cmsDeleteTransform(xform
);
5823 hLab1
= cmsCreateLab4ProfileTHR(DbgThread(), NULL
);
5824 hLab2
= cmsCreateLab4ProfileTHR(DbgThread(), NULL
);
5826 xform
= cmsCreateTransformTHR(DbgThread(), hLab1
, TYPE_Lab_DBL
, hLab2
, TYPE_Lab_16
, INTENT_RELATIVE_COLORIMETRIC
, 0);
5827 cmsCloseProfile(hLab1
); cmsCloseProfile(hLab2
);
5833 cmsDoTransform(xform
, &Lab
, In
, 1);
5835 if (In
[0] != 0xFFFF ||
5837 In
[2] != 0x8080) return 0;
5839 cmsDeleteTransform(xform
);
5845 cmsInt32Number
CheckStoredIdentities(void)
5847 cmsHPROFILE hLab
, hLink
, h4
, h2
;
5848 cmsHTRANSFORM xform
;
5849 cmsInt32Number rc
= 1;
5851 hLab
= cmsCreateLab4ProfileTHR(DbgThread(), NULL
);
5852 xform
= cmsCreateTransformTHR(DbgThread(), hLab
, TYPE_Lab_8
, hLab
, TYPE_Lab_8
, 0, 0);
5854 hLink
= cmsTransform2DeviceLink(xform
, 3.4, 0);
5855 cmsSaveProfileToFile(hLink
, "abstractv2.icc");
5856 cmsCloseProfile(hLink
);
5858 hLink
= cmsTransform2DeviceLink(xform
, 4.3, 0);
5859 cmsSaveProfileToFile(hLink
, "abstractv4.icc");
5860 cmsCloseProfile(hLink
);
5862 cmsDeleteTransform(xform
);
5863 cmsCloseProfile(hLab
);
5865 h4
= cmsOpenProfileFromFileTHR(DbgThread(), "abstractv4.icc", "r");
5867 xform
= cmsCreateTransformTHR(DbgThread(), h4
, TYPE_Lab_DBL
, h4
, TYPE_Lab_DBL
, INTENT_RELATIVE_COLORIMETRIC
, 0);
5870 rc
&= CheckSeveralLab(xform
);
5872 cmsDeleteTransform(xform
);
5873 cmsCloseProfile(h4
);
5874 if (!rc
) goto Error
;
5878 h2
= cmsOpenProfileFromFileTHR(DbgThread(), "abstractv2.icc", "r");
5880 xform
= cmsCreateTransformTHR(DbgThread(), h2
, TYPE_Lab_DBL
, h2
, TYPE_Lab_DBL
, INTENT_RELATIVE_COLORIMETRIC
, 0);
5881 rc
&= CheckSeveralLab(xform
);
5882 cmsDeleteTransform(xform
);
5883 cmsCloseProfile(h2
);
5884 if (!rc
) goto Error
;
5887 SubTest("V2 -> V4");
5888 h2
= cmsOpenProfileFromFileTHR(DbgThread(), "abstractv2.icc", "r");
5889 h4
= cmsOpenProfileFromFileTHR(DbgThread(), "abstractv4.icc", "r");
5891 xform
= cmsCreateTransformTHR(DbgThread(), h4
, TYPE_Lab_DBL
, h2
, TYPE_Lab_DBL
, INTENT_RELATIVE_COLORIMETRIC
, 0);
5892 rc
&= CheckSeveralLab(xform
);
5893 cmsDeleteTransform(xform
);
5894 cmsCloseProfile(h2
);
5895 cmsCloseProfile(h4
);
5897 SubTest("V4 -> V2");
5898 h2
= cmsOpenProfileFromFileTHR(DbgThread(), "abstractv2.icc", "r");
5899 h4
= cmsOpenProfileFromFileTHR(DbgThread(), "abstractv4.icc", "r");
5901 xform
= cmsCreateTransformTHR(DbgThread(), h2
, TYPE_Lab_DBL
, h4
, TYPE_Lab_DBL
, INTENT_RELATIVE_COLORIMETRIC
, 0);
5902 rc
&= CheckSeveralLab(xform
);
5903 cmsDeleteTransform(xform
);
5904 cmsCloseProfile(h2
);
5905 cmsCloseProfile(h4
);
5908 remove("abstractv2.icc");
5909 remove("abstractv4.icc");
5916 // Check a simple xform from a matrix profile to itself. Test floating point accuracy.
5918 cmsInt32Number
CheckMatrixShaperXFORMFloat(void)
5920 cmsHPROFILE hAbove
, hSRGB
;
5921 cmsHTRANSFORM xform
;
5922 cmsInt32Number rc1
, rc2
;
5924 hAbove
= Create_AboveRGB();
5925 xform
= cmsCreateTransformTHR(DbgThread(), hAbove
, TYPE_RGB_FLT
, hAbove
, TYPE_RGB_FLT
, INTENT_RELATIVE_COLORIMETRIC
, 0);
5926 cmsCloseProfile(hAbove
);
5927 rc1
= CheckFloatlinearXFORM(xform
, 3);
5928 cmsDeleteTransform(xform
);
5930 hSRGB
= cmsCreate_sRGBProfileTHR(DbgThread());
5931 xform
= cmsCreateTransformTHR(DbgThread(), hSRGB
, TYPE_RGB_FLT
, hSRGB
, TYPE_RGB_FLT
, INTENT_RELATIVE_COLORIMETRIC
, 0);
5932 cmsCloseProfile(hSRGB
);
5933 rc2
= CheckFloatlinearXFORM(xform
, 3);
5934 cmsDeleteTransform(xform
);
5940 // Check a simple xform from a matrix profile to itself. Test 16 bits accuracy.
5942 cmsInt32Number
CheckMatrixShaperXFORM16(void)
5944 cmsHPROFILE hAbove
, hSRGB
;
5945 cmsHTRANSFORM xform
;
5946 cmsInt32Number rc1
, rc2
;
5948 hAbove
= Create_AboveRGB();
5949 xform
= cmsCreateTransformTHR(DbgThread(), hAbove
, TYPE_RGB_16
, hAbove
, TYPE_RGB_16
, INTENT_RELATIVE_COLORIMETRIC
, 0);
5950 cmsCloseProfile(hAbove
);
5952 rc1
= Check16linearXFORM(xform
, 3);
5953 cmsDeleteTransform(xform
);
5955 hSRGB
= cmsCreate_sRGBProfileTHR(DbgThread());
5956 xform
= cmsCreateTransformTHR(DbgThread(), hSRGB
, TYPE_RGB_16
, hSRGB
, TYPE_RGB_16
, INTENT_RELATIVE_COLORIMETRIC
, 0);
5957 cmsCloseProfile(hSRGB
);
5958 rc2
= Check16linearXFORM(xform
, 3);
5959 cmsDeleteTransform(xform
);
5966 // Check a simple xform from a matrix profile to itself. Test 8 bits accuracy.
5968 cmsInt32Number
CheckMatrixShaperXFORM8(void)
5970 cmsHPROFILE hAbove
, hSRGB
;
5971 cmsHTRANSFORM xform
;
5972 cmsInt32Number rc1
, rc2
;
5974 hAbove
= Create_AboveRGB();
5975 xform
= cmsCreateTransformTHR(DbgThread(), hAbove
, TYPE_RGB_8
, hAbove
, TYPE_RGB_8
, INTENT_RELATIVE_COLORIMETRIC
, 0);
5976 cmsCloseProfile(hAbove
);
5977 rc1
= Check8linearXFORM(xform
, 3);
5978 cmsDeleteTransform(xform
);
5980 hSRGB
= cmsCreate_sRGBProfileTHR(DbgThread());
5981 xform
= cmsCreateTransformTHR(DbgThread(), hSRGB
, TYPE_RGB_8
, hSRGB
, TYPE_RGB_8
, INTENT_RELATIVE_COLORIMETRIC
, 0);
5982 cmsCloseProfile(hSRGB
);
5983 rc2
= Check8linearXFORM(xform
, 3);
5984 cmsDeleteTransform(xform
);
5991 // TODO: Check LUT based to LUT based transforms for CMYK
5998 // -----------------------------------------------------------------------------------------------------------------
6001 // Check known values going from sRGB to XYZ
6003 cmsInt32Number
CheckOneRGB_f(cmsHTRANSFORM xform
, cmsInt32Number R
, cmsInt32Number G
, cmsInt32Number B
, cmsFloat64Number X
, cmsFloat64Number Y
, cmsFloat64Number Z
, cmsFloat64Number err
)
6005 cmsFloat32Number RGB
[3];
6006 cmsFloat64Number Out
[3];
6008 RGB
[0] = (cmsFloat32Number
) (R
/ 255.0);
6009 RGB
[1] = (cmsFloat32Number
) (G
/ 255.0);
6010 RGB
[2] = (cmsFloat32Number
) (B
/ 255.0);
6012 cmsDoTransform(xform
, RGB
, Out
, 1);
6014 return IsGoodVal("X", X
, Out
[0], err
) &&
6015 IsGoodVal("Y", Y
, Out
[1], err
) &&
6016 IsGoodVal("Z", Z
, Out
[2], err
);
6020 cmsInt32Number
Chack_sRGB_Float(void)
6022 cmsHPROFILE hsRGB
, hXYZ
, hLab
;
6023 cmsHTRANSFORM xform1
, xform2
;
6027 hsRGB
= cmsCreate_sRGBProfileTHR(DbgThread());
6028 hXYZ
= cmsCreateXYZProfileTHR(DbgThread());
6029 hLab
= cmsCreateLab4ProfileTHR(DbgThread(), NULL
);
6031 xform1
= cmsCreateTransformTHR(DbgThread(), hsRGB
, TYPE_RGB_FLT
, hXYZ
, TYPE_XYZ_DBL
,
6032 INTENT_RELATIVE_COLORIMETRIC
, 0);
6034 xform2
= cmsCreateTransformTHR(DbgThread(), hsRGB
, TYPE_RGB_FLT
, hLab
, TYPE_Lab_DBL
,
6035 INTENT_RELATIVE_COLORIMETRIC
, 0);
6036 cmsCloseProfile(hsRGB
);
6037 cmsCloseProfile(hXYZ
);
6038 cmsCloseProfile(hLab
);
6042 // Xform 1 goes from 8 bits to XYZ,
6043 rc
= CheckOneRGB_f(xform1
, 1, 1, 1, 0.0002926, 0.00030352, 0.00025037, 0.0001);
6044 rc
&= CheckOneRGB_f(xform1
, 127, 127, 127, 0.2046329, 0.212230, 0.175069, 0.0001);
6045 rc
&= CheckOneRGB_f(xform1
, 12, 13, 15, 0.0038364, 0.0039928, 0.00385212, 0.0001);
6046 rc
&= CheckOneRGB_f(xform1
, 128, 0, 0, 0.0940846, 0.0480030, 0.00300543, 0.0001);
6047 rc
&= CheckOneRGB_f(xform1
, 190, 25, 210, 0.3203491, 0.1605240, 0.46817115, 0.0001);
6049 // Xform 2 goes from 8 bits to Lab, we allow 0.01 error max
6050 rc
&= CheckOneRGB_f(xform2
, 1, 1, 1, 0.2741748, 0, 0, 0.01);
6051 rc
&= CheckOneRGB_f(xform2
, 127, 127, 127, 53.192776, 0, 0, 0.01);
6052 rc
&= CheckOneRGB_f(xform2
, 190, 25, 210, 47.043171, 74.564576, -56.89373, 0.01);
6053 rc
&= CheckOneRGB_f(xform2
, 128, 0, 0, 26.158100, 48.474477, 39.425916, 0.01);
6055 cmsDeleteTransform(xform1
);
6056 cmsDeleteTransform(xform2
);
6061 // ---------------------------------------------------
6064 cmsBool
GetProfileRGBPrimaries(cmsHPROFILE hProfile
,
6065 cmsCIEXYZTRIPLE
*result
,
6066 cmsUInt32Number intent
)
6069 cmsHTRANSFORM hTransform
;
6070 cmsFloat64Number rgb
[3][3] = {{1., 0., 0.},
6074 hXYZ
= cmsCreateXYZProfile();
6075 if (hXYZ
== NULL
) return FALSE
;
6077 hTransform
= cmsCreateTransform(hProfile
, TYPE_RGB_DBL
, hXYZ
, TYPE_XYZ_DBL
,
6078 intent
, cmsFLAGS_NOCACHE
| cmsFLAGS_NOOPTIMIZE
);
6079 cmsCloseProfile(hXYZ
);
6080 if (hTransform
== NULL
) return FALSE
;
6082 cmsDoTransform(hTransform
, rgb
, result
, 3);
6083 cmsDeleteTransform(hTransform
);
6089 int CheckRGBPrimaries(void)
6092 cmsCIEXYZTRIPLE tripXYZ
;
6093 cmsCIExyYTRIPLE tripxyY
;
6096 cmsSetAdaptationState(0);
6097 hsRGB
= cmsCreate_sRGBProfileTHR(DbgThread());
6098 if (!hsRGB
) return 0;
6100 result
= GetProfileRGBPrimaries(hsRGB
, &tripXYZ
,
6101 INTENT_ABSOLUTE_COLORIMETRIC
);
6103 cmsCloseProfile(hsRGB
);
6104 if (!result
) return 0;
6106 cmsXYZ2xyY(&tripxyY
.Red
, &tripXYZ
.Red
);
6107 cmsXYZ2xyY(&tripxyY
.Green
, &tripXYZ
.Green
);
6108 cmsXYZ2xyY(&tripxyY
.Blue
, &tripXYZ
.Blue
);
6110 /* valus were taken from
6111 http://en.wikipedia.org/wiki/RGB_color_spaces#Specifications */
6113 if (!IsGoodFixed15_16("xRed", tripxyY
.Red
.x
, 0.64) ||
6114 !IsGoodFixed15_16("yRed", tripxyY
.Red
.y
, 0.33) ||
6115 !IsGoodFixed15_16("xGreen", tripxyY
.Green
.x
, 0.30) ||
6116 !IsGoodFixed15_16("yGreen", tripxyY
.Green
.y
, 0.60) ||
6117 !IsGoodFixed15_16("xBlue", tripxyY
.Blue
.x
, 0.15) ||
6118 !IsGoodFixed15_16("yBlue", tripxyY
.Blue
.y
, 0.06)) {
6119 Fail("One or more primaries are wrong.");
6127 // -----------------------------------------------------------------------------------------------------------------
6129 // This function will check CMYK -> CMYK transforms. It uses FOGRA29 and SWOP ICC profiles
6132 cmsInt32Number
CheckCMYK(cmsInt32Number Intent
, const char *Profile1
, const char* Profile2
)
6134 cmsHPROFILE hSWOP
= cmsOpenProfileFromFileTHR(DbgThread(), Profile1
, "r");
6135 cmsHPROFILE hFOGRA
= cmsOpenProfileFromFileTHR(DbgThread(), Profile2
, "r");
6136 cmsHTRANSFORM xform
, swop_lab
, fogra_lab
;
6137 cmsFloat32Number CMYK1
[4], CMYK2
[4];
6138 cmsCIELab Lab1
, Lab2
;
6140 cmsFloat64Number DeltaL
, Max
;
6143 hLab
= cmsCreateLab4ProfileTHR(DbgThread(), NULL
);
6145 xform
= cmsCreateTransformTHR(DbgThread(), hSWOP
, TYPE_CMYK_FLT
, hFOGRA
, TYPE_CMYK_FLT
, Intent
, 0);
6147 swop_lab
= cmsCreateTransformTHR(DbgThread(), hSWOP
, TYPE_CMYK_FLT
, hLab
, TYPE_Lab_DBL
, Intent
, 0);
6148 fogra_lab
= cmsCreateTransformTHR(DbgThread(), hFOGRA
, TYPE_CMYK_FLT
, hLab
, TYPE_Lab_DBL
, Intent
, 0);
6151 for (i
=0; i
<= 100; i
++) {
6156 CMYK1
[3] = (cmsFloat32Number
) i
;
6158 cmsDoTransform(swop_lab
, CMYK1
, &Lab1
, 1);
6159 cmsDoTransform(xform
, CMYK1
, CMYK2
, 1);
6160 cmsDoTransform(fogra_lab
, CMYK2
, &Lab2
, 1);
6162 DeltaL
= fabs(Lab1
.L
- Lab2
.L
);
6164 if (DeltaL
> Max
) Max
= DeltaL
;
6168 cmsDeleteTransform(xform
);
6170 if (Max
> 3.0) return 0;
6172 xform
= cmsCreateTransformTHR(DbgThread(), hFOGRA
, TYPE_CMYK_FLT
, hSWOP
, TYPE_CMYK_FLT
, Intent
, 0);
6176 for (i
=0; i
<= 100; i
++) {
6180 CMYK1
[3] = (cmsFloat32Number
) i
;
6182 cmsDoTransform(fogra_lab
, CMYK1
, &Lab1
, 1);
6183 cmsDoTransform(xform
, CMYK1
, CMYK2
, 1);
6184 cmsDoTransform(swop_lab
, CMYK2
, &Lab2
, 1);
6186 DeltaL
= fabs(Lab1
.L
- Lab2
.L
);
6188 if (DeltaL
> Max
) Max
= DeltaL
;
6192 cmsCloseProfile(hSWOP
);
6193 cmsCloseProfile(hFOGRA
);
6194 cmsCloseProfile(hLab
);
6196 cmsDeleteTransform(xform
);
6197 cmsDeleteTransform(swop_lab
);
6198 cmsDeleteTransform(fogra_lab
);
6204 cmsInt32Number
CheckCMYKRoundtrip(void)
6206 return CheckCMYK(INTENT_RELATIVE_COLORIMETRIC
, "test1.icc", "test1.icc");
6211 cmsInt32Number
CheckCMYKPerceptual(void)
6213 return CheckCMYK(INTENT_PERCEPTUAL
, "test1.icc", "test2.icc");
6219 cmsInt32Number
CheckCMYKRelCol(void)
6221 return CheckCMYK(INTENT_RELATIVE_COLORIMETRIC
, "test1.icc", "test2.icc");
6227 cmsInt32Number
CheckKOnlyBlackPreserving(void)
6229 cmsHPROFILE hSWOP
= cmsOpenProfileFromFileTHR(DbgThread(), "test1.icc", "r");
6230 cmsHPROFILE hFOGRA
= cmsOpenProfileFromFileTHR(DbgThread(), "test2.icc", "r");
6231 cmsHTRANSFORM xform
, swop_lab
, fogra_lab
;
6232 cmsFloat32Number CMYK1
[4], CMYK2
[4];
6233 cmsCIELab Lab1
, Lab2
;
6235 cmsFloat64Number DeltaL
, Max
;
6238 hLab
= cmsCreateLab4ProfileTHR(DbgThread(), NULL
);
6240 xform
= cmsCreateTransformTHR(DbgThread(), hSWOP
, TYPE_CMYK_FLT
, hFOGRA
, TYPE_CMYK_FLT
, INTENT_PRESERVE_K_ONLY_PERCEPTUAL
, 0);
6242 swop_lab
= cmsCreateTransformTHR(DbgThread(), hSWOP
, TYPE_CMYK_FLT
, hLab
, TYPE_Lab_DBL
, INTENT_PERCEPTUAL
, 0);
6243 fogra_lab
= cmsCreateTransformTHR(DbgThread(), hFOGRA
, TYPE_CMYK_FLT
, hLab
, TYPE_Lab_DBL
, INTENT_PERCEPTUAL
, 0);
6247 for (i
=0; i
<= 100; i
++) {
6251 CMYK1
[3] = (cmsFloat32Number
) i
;
6253 // SWOP CMYK to Lab1
6254 cmsDoTransform(swop_lab
, CMYK1
, &Lab1
, 1);
6256 // SWOP To FOGRA using black preservation
6257 cmsDoTransform(xform
, CMYK1
, CMYK2
, 1);
6259 // Obtained FOGRA CMYK to Lab2
6260 cmsDoTransform(fogra_lab
, CMYK2
, &Lab2
, 1);
6262 // We care only on L*
6263 DeltaL
= fabs(Lab1
.L
- Lab2
.L
);
6265 if (DeltaL
> Max
) Max
= DeltaL
;
6269 cmsDeleteTransform(xform
);
6271 // dL should be below 3.0
6272 if (Max
> 3.0) return 0;
6275 // Same, but FOGRA to SWOP
6276 xform
= cmsCreateTransformTHR(DbgThread(), hFOGRA
, TYPE_CMYK_FLT
, hSWOP
, TYPE_CMYK_FLT
, INTENT_PRESERVE_K_ONLY_PERCEPTUAL
, 0);
6280 for (i
=0; i
<= 100; i
++) {
6284 CMYK1
[3] = (cmsFloat32Number
) i
;
6286 cmsDoTransform(fogra_lab
, CMYK1
, &Lab1
, 1);
6287 cmsDoTransform(xform
, CMYK1
, CMYK2
, 1);
6288 cmsDoTransform(swop_lab
, CMYK2
, &Lab2
, 1);
6290 DeltaL
= fabs(Lab1
.L
- Lab2
.L
);
6292 if (DeltaL
> Max
) Max
= DeltaL
;
6296 cmsCloseProfile(hSWOP
);
6297 cmsCloseProfile(hFOGRA
);
6298 cmsCloseProfile(hLab
);
6300 cmsDeleteTransform(xform
);
6301 cmsDeleteTransform(swop_lab
);
6302 cmsDeleteTransform(fogra_lab
);
6308 cmsInt32Number
CheckKPlaneBlackPreserving(void)
6310 cmsHPROFILE hSWOP
= cmsOpenProfileFromFileTHR(DbgThread(), "test1.icc", "r");
6311 cmsHPROFILE hFOGRA
= cmsOpenProfileFromFileTHR(DbgThread(), "test2.icc", "r");
6312 cmsHTRANSFORM xform
, swop_lab
, fogra_lab
;
6313 cmsFloat32Number CMYK1
[4], CMYK2
[4];
6314 cmsCIELab Lab1
, Lab2
;
6316 cmsFloat64Number DeltaE
, Max
;
6319 hLab
= cmsCreateLab4ProfileTHR(DbgThread(), NULL
);
6321 xform
= cmsCreateTransformTHR(DbgThread(), hSWOP
, TYPE_CMYK_FLT
, hFOGRA
, TYPE_CMYK_FLT
, INTENT_PERCEPTUAL
, 0);
6323 swop_lab
= cmsCreateTransformTHR(DbgThread(), hSWOP
, TYPE_CMYK_FLT
, hLab
, TYPE_Lab_DBL
, INTENT_PERCEPTUAL
, 0);
6324 fogra_lab
= cmsCreateTransformTHR(DbgThread(), hFOGRA
, TYPE_CMYK_FLT
, hLab
, TYPE_Lab_DBL
, INTENT_PERCEPTUAL
, 0);
6328 for (i
=0; i
<= 100; i
++) {
6332 CMYK1
[3] = (cmsFloat32Number
) i
;
6334 cmsDoTransform(swop_lab
, CMYK1
, &Lab1
, 1);
6335 cmsDoTransform(xform
, CMYK1
, CMYK2
, 1);
6336 cmsDoTransform(fogra_lab
, CMYK2
, &Lab2
, 1);
6338 DeltaE
= cmsDeltaE(&Lab1
, &Lab2
);
6340 if (DeltaE
> Max
) Max
= DeltaE
;
6344 cmsDeleteTransform(xform
);
6346 xform
= cmsCreateTransformTHR(DbgThread(), hFOGRA
, TYPE_CMYK_FLT
, hSWOP
, TYPE_CMYK_FLT
, INTENT_PRESERVE_K_PLANE_PERCEPTUAL
, 0);
6348 for (i
=0; i
<= 100; i
++) {
6352 CMYK1
[3] = (cmsFloat32Number
) i
;
6354 cmsDoTransform(fogra_lab
, CMYK1
, &Lab1
, 1);
6355 cmsDoTransform(xform
, CMYK1
, CMYK2
, 1);
6356 cmsDoTransform(swop_lab
, CMYK2
, &Lab2
, 1);
6358 DeltaE
= cmsDeltaE(&Lab1
, &Lab2
);
6360 if (DeltaE
> Max
) Max
= DeltaE
;
6363 cmsDeleteTransform(xform
);
6367 cmsCloseProfile(hSWOP
);
6368 cmsCloseProfile(hFOGRA
);
6369 cmsCloseProfile(hLab
);
6372 cmsDeleteTransform(swop_lab
);
6373 cmsDeleteTransform(fogra_lab
);
6379 // ------------------------------------------------------------------------------------------------------
6383 cmsInt32Number
CheckProofingXFORMFloat(void)
6386 cmsHTRANSFORM xform
;
6389 hAbove
= Create_AboveRGB();
6390 xform
= cmsCreateProofingTransformTHR(DbgThread(), hAbove
, TYPE_RGB_FLT
, hAbove
, TYPE_RGB_FLT
, hAbove
,
6391 INTENT_RELATIVE_COLORIMETRIC
, INTENT_RELATIVE_COLORIMETRIC
, cmsFLAGS_SOFTPROOFING
);
6392 cmsCloseProfile(hAbove
);
6393 rc
= CheckFloatlinearXFORM(xform
, 3);
6394 cmsDeleteTransform(xform
);
6399 cmsInt32Number
CheckProofingXFORM16(void)
6402 cmsHTRANSFORM xform
;
6405 hAbove
= Create_AboveRGB();
6406 xform
= cmsCreateProofingTransformTHR(DbgThread(), hAbove
, TYPE_RGB_16
, hAbove
, TYPE_RGB_16
, hAbove
,
6407 INTENT_RELATIVE_COLORIMETRIC
, INTENT_RELATIVE_COLORIMETRIC
, cmsFLAGS_SOFTPROOFING
|cmsFLAGS_NOCACHE
);
6408 cmsCloseProfile(hAbove
);
6409 rc
= Check16linearXFORM(xform
, 3);
6410 cmsDeleteTransform(xform
);
6416 cmsInt32Number
CheckGamutCheck(void)
6418 cmsHPROFILE hSRGB
, hAbove
;
6419 cmsHTRANSFORM xform
;
6421 cmsUInt16Number Alarm
[3] = { 0xDEAD, 0xBABE, 0xFACE };
6423 // Set alarm codes to fancy values so we could check the out of gamut condition
6424 cmsSetAlarmCodes(Alarm
);
6426 // Create the profiles
6427 hSRGB
= cmsCreate_sRGBProfileTHR(DbgThread());
6428 hAbove
= Create_AboveRGB();
6430 if (hSRGB
== NULL
|| hAbove
== NULL
) return 0; // Failed
6432 SubTest("Gamut check on floating point");
6434 // Create a gamut checker in the same space. No value should be out of gamut
6435 xform
= cmsCreateProofingTransformTHR(DbgThread(), hAbove
, TYPE_RGB_FLT
, hAbove
, TYPE_RGB_FLT
, hAbove
,
6436 INTENT_RELATIVE_COLORIMETRIC
, INTENT_RELATIVE_COLORIMETRIC
, cmsFLAGS_GAMUTCHECK
);
6439 if (!CheckFloatlinearXFORM(xform
, 3)) {
6440 cmsCloseProfile(hSRGB
);
6441 cmsCloseProfile(hAbove
);
6442 cmsDeleteTransform(xform
);
6443 Fail("Gamut check on same profile failed");
6447 cmsDeleteTransform(xform
);
6449 SubTest("Gamut check on 16 bits");
6451 xform
= cmsCreateProofingTransformTHR(DbgThread(), hAbove
, TYPE_RGB_16
, hAbove
, TYPE_RGB_16
, hAbove
,
6452 INTENT_RELATIVE_COLORIMETRIC
, INTENT_RELATIVE_COLORIMETRIC
, cmsFLAGS_GAMUTCHECK
);
6454 cmsCloseProfile(hSRGB
);
6455 cmsCloseProfile(hAbove
);
6457 rc
= Check16linearXFORM(xform
, 3);
6459 cmsDeleteTransform(xform
);
6466 // -------------------------------------------------------------------------------------------------------------------
6469 cmsInt32Number
CheckBlackPoint(void)
6471 cmsHPROFILE hProfile
;
6475 hProfile
= cmsOpenProfileFromFileTHR(DbgThread(), "test5.icc", "r");
6476 cmsDetectDestinationBlackPoint(&Black
, hProfile
, INTENT_RELATIVE_COLORIMETRIC
, 0);
6477 cmsCloseProfile(hProfile
);
6480 hProfile
= cmsOpenProfileFromFileTHR(DbgThread(), "test1.icc", "r");
6481 cmsDetectDestinationBlackPoint(&Black
, hProfile
, INTENT_RELATIVE_COLORIMETRIC
, 0);
6482 cmsXYZ2Lab(NULL
, &Lab
, &Black
);
6483 cmsCloseProfile(hProfile
);
6485 hProfile
= cmsOpenProfileFromFileTHR(DbgThread(), "lcms2cmyk.icc", "r");
6486 cmsDetectDestinationBlackPoint(&Black
, hProfile
, INTENT_RELATIVE_COLORIMETRIC
, 0);
6487 cmsXYZ2Lab(NULL
, &Lab
, &Black
);
6488 cmsCloseProfile(hProfile
);
6490 hProfile
= cmsOpenProfileFromFileTHR(DbgThread(), "test2.icc", "r");
6491 cmsDetectDestinationBlackPoint(&Black
, hProfile
, INTENT_RELATIVE_COLORIMETRIC
, 0);
6492 cmsXYZ2Lab(NULL
, &Lab
, &Black
);
6493 cmsCloseProfile(hProfile
);
6495 hProfile
= cmsOpenProfileFromFileTHR(DbgThread(), "test1.icc", "r");
6496 cmsDetectDestinationBlackPoint(&Black
, hProfile
, INTENT_PERCEPTUAL
, 0);
6497 cmsXYZ2Lab(NULL
, &Lab
, &Black
);
6498 cmsCloseProfile(hProfile
);
6505 cmsInt32Number
CheckOneTAC(cmsFloat64Number InkLimit
)
6510 h
=CreateFakeCMYK(InkLimit
, TRUE
);
6511 cmsSaveProfileToFile(h
, "lcmstac.icc");
6514 h
= cmsOpenProfileFromFile("lcmstac.icc", "r");
6515 d
= cmsDetectTAC(h
);
6518 remove("lcmstac.icc");
6520 if (fabs(d
- InkLimit
) > 5) return 0;
6527 cmsInt32Number
CheckTAC(void)
6529 if (!CheckOneTAC(180)) return 0;
6530 if (!CheckOneTAC(220)) return 0;
6531 if (!CheckOneTAC(286)) return 0;
6532 if (!CheckOneTAC(310)) return 0;
6533 if (!CheckOneTAC(330)) return 0;
6538 // -------------------------------------------------------------------------------------------------------
6541 #define NPOINTS_IT8 10 // (17*17*17*17)
6544 cmsInt32Number
CheckCGATS(void)
6549 SubTest("IT8 creation");
6550 it8
= cmsIT8Alloc(DbgThread());
6551 if (it8
== NULL
) return 0;
6553 cmsIT8SetSheetType(it8
, "LCMS/TESTING");
6554 cmsIT8SetPropertyStr(it8
, "ORIGINATOR", "1 2 3 4");
6555 cmsIT8SetPropertyUncooked(it8
, "DESCRIPTOR", "1234");
6556 cmsIT8SetPropertyStr(it8
, "MANUFACTURER", "3");
6557 cmsIT8SetPropertyDbl(it8
, "CREATED", 4);
6558 cmsIT8SetPropertyDbl(it8
, "SERIAL", 5);
6559 cmsIT8SetPropertyHex(it8
, "MATERIAL", 0x123);
6561 cmsIT8SetPropertyDbl(it8
, "NUMBER_OF_SETS", NPOINTS_IT8
);
6562 cmsIT8SetPropertyDbl(it8
, "NUMBER_OF_FIELDS", 4);
6564 cmsIT8SetDataFormat(it8
, 0, "SAMPLE_ID");
6565 cmsIT8SetDataFormat(it8
, 1, "RGB_R");
6566 cmsIT8SetDataFormat(it8
, 2, "RGB_G");
6567 cmsIT8SetDataFormat(it8
, 3, "RGB_B");
6569 SubTest("Table creation");
6570 for (i
=0; i
< NPOINTS_IT8
; i
++) {
6574 sprintf(Patch
, "P%d", i
);
6576 cmsIT8SetDataRowCol(it8
, i
, 0, Patch
);
6577 cmsIT8SetDataRowColDbl(it8
, i
, 1, i
);
6578 cmsIT8SetDataRowColDbl(it8
, i
, 2, i
);
6579 cmsIT8SetDataRowColDbl(it8
, i
, 3, i
);
6582 SubTest("Save to file");
6583 cmsIT8SaveToFile(it8
, "TEST.IT8");
6586 SubTest("Load from file");
6587 it8
= cmsIT8LoadFromFile(DbgThread(), "TEST.IT8");
6588 if (it8
== NULL
) return 0;
6590 SubTest("Save again file");
6591 cmsIT8SaveToFile(it8
, "TEST.IT8");
6595 SubTest("Load from file (II)");
6596 it8
= cmsIT8LoadFromFile(DbgThread(), "TEST.IT8");
6597 if (it8
== NULL
) return 0;
6600 SubTest("Change prop value");
6601 if (cmsIT8GetPropertyDbl(it8
, "DESCRIPTOR") != 1234) {
6607 cmsIT8SetPropertyDbl(it8
, "DESCRIPTOR", 5678);
6608 if (cmsIT8GetPropertyDbl(it8
, "DESCRIPTOR") != 5678) {
6613 SubTest("Positive numbers");
6614 if (cmsIT8GetDataDbl(it8
, "P3", "RGB_G") != 3) {
6620 SubTest("Positive exponent numbers");
6621 cmsIT8SetPropertyDbl(it8
, "DBL_PROP", 123E+12);
6622 if ((cmsIT8GetPropertyDbl(it8
, "DBL_PROP") - 123E+12) > 1 ) {
6627 SubTest("Negative exponent numbers");
6628 cmsIT8SetPropertyDbl(it8
, "DBL_PROP_NEG", 123E-45);
6629 if ((cmsIT8GetPropertyDbl(it8
, "DBL_PROP_NEG") - 123E-45) > 1E-45 ) {
6635 SubTest("Negative numbers");
6636 cmsIT8SetPropertyDbl(it8
, "DBL_NEG_VAL", -123);
6637 if ((cmsIT8GetPropertyDbl(it8
, "DBL_NEG_VAL")) != -123 ) {
6653 void GenerateCSA(const char* cInProf
, const char* FileName
)
6655 cmsHPROFILE hProfile
;
6658 cmsContext BuffThread
= DbgThread();
6662 if (cInProf
== NULL
)
6663 hProfile
= cmsCreateLab4Profile(NULL
);
6665 hProfile
= cmsOpenProfileFromFile(cInProf
, "r");
6667 n
= cmsGetPostScriptCSA(DbgThread(), hProfile
, 0, 0, NULL
, 0);
6670 Buffer
= (char*) _cmsMalloc(BuffThread
, n
+ 1);
6671 cmsGetPostScriptCSA(DbgThread(), hProfile
, 0, 0, Buffer
, n
);
6674 if (FileName
!= NULL
) {
6675 o
= fopen(FileName
, "wb");
6676 fwrite(Buffer
, n
, 1, o
);
6680 _cmsFree(BuffThread
, Buffer
);
6681 cmsCloseProfile(hProfile
);
6682 if (FileName
!= NULL
)
6688 void GenerateCRD(const char* cOutProf
, const char* FileName
)
6690 cmsHPROFILE hProfile
;
6693 cmsUInt32Number dwFlags
= 0;
6694 cmsContext BuffThread
= DbgThread();
6697 if (cOutProf
== NULL
)
6698 hProfile
= cmsCreateLab4Profile(NULL
);
6700 hProfile
= cmsOpenProfileFromFile(cOutProf
, "r");
6702 n
= cmsGetPostScriptCRD(DbgThread(), hProfile
, 0, dwFlags
, NULL
, 0);
6705 Buffer
= (char*) _cmsMalloc(BuffThread
, n
+ 1);
6706 cmsGetPostScriptCRD(DbgThread(), hProfile
, 0, dwFlags
, Buffer
, n
);
6709 if (FileName
!= NULL
) {
6710 FILE* o
= fopen(FileName
, "wb");
6711 fwrite(Buffer
, n
, 1, o
);
6715 _cmsFree(BuffThread
, Buffer
);
6716 cmsCloseProfile(hProfile
);
6717 if (FileName
!= NULL
)
6722 cmsInt32Number
CheckPostScript(void)
6724 GenerateCSA("test5.icc", "sRGB_CSA.ps");
6725 GenerateCSA("aRGBlcms2.icc", "aRGB_CSA.ps");
6726 GenerateCSA("test4.icc", "sRGBV4_CSA.ps");
6727 GenerateCSA("test1.icc", "SWOP_CSA.ps");
6728 GenerateCSA(NULL
, "Lab_CSA.ps");
6729 GenerateCSA("graylcms2.icc", "gray_CSA.ps");
6731 GenerateCRD("test5.icc", "sRGB_CRD.ps");
6732 GenerateCRD("aRGBlcms2.icc", "aRGB_CRD.ps");
6733 GenerateCRD(NULL
, "Lab_CRD.ps");
6734 GenerateCRD("test1.icc", "SWOP_CRD.ps");
6735 GenerateCRD("test4.icc", "sRGBV4_CRD.ps");
6736 GenerateCRD("graylcms2.icc", "gray_CRD.ps");
6743 cmsInt32Number
CheckGray(cmsHTRANSFORM xform
, cmsUInt8Number g
, double L
)
6747 cmsDoTransform(xform
, &g
, &Lab
, 1);
6749 if (!IsGoodVal("a axis on gray", 0, Lab
.a
, 0.001)) return 0;
6750 if (!IsGoodVal("b axis on gray", 0, Lab
.b
, 0.001)) return 0;
6752 return IsGoodVal("Gray value", L
, Lab
.L
, 0.01);
6756 cmsInt32Number
CheckInputGray(void)
6758 cmsHPROFILE hGray
= Create_Gray22();
6759 cmsHPROFILE hLab
= cmsCreateLab4Profile(NULL
);
6760 cmsHTRANSFORM xform
;
6762 if (hGray
== NULL
|| hLab
== NULL
) return 0;
6764 xform
= cmsCreateTransform(hGray
, TYPE_GRAY_8
, hLab
, TYPE_Lab_DBL
, INTENT_RELATIVE_COLORIMETRIC
, 0);
6765 cmsCloseProfile(hGray
); cmsCloseProfile(hLab
);
6767 if (!CheckGray(xform
, 0, 0)) return 0;
6768 if (!CheckGray(xform
, 125, 52.768)) return 0;
6769 if (!CheckGray(xform
, 200, 81.069)) return 0;
6770 if (!CheckGray(xform
, 255, 100.0)) return 0;
6772 cmsDeleteTransform(xform
);
6777 cmsInt32Number
CheckLabInputGray(void)
6779 cmsHPROFILE hGray
= Create_GrayLab();
6780 cmsHPROFILE hLab
= cmsCreateLab4Profile(NULL
);
6781 cmsHTRANSFORM xform
;
6783 if (hGray
== NULL
|| hLab
== NULL
) return 0;
6785 xform
= cmsCreateTransform(hGray
, TYPE_GRAY_8
, hLab
, TYPE_Lab_DBL
, INTENT_RELATIVE_COLORIMETRIC
, 0);
6786 cmsCloseProfile(hGray
); cmsCloseProfile(hLab
);
6788 if (!CheckGray(xform
, 0, 0)) return 0;
6789 if (!CheckGray(xform
, 125, 49.019)) return 0;
6790 if (!CheckGray(xform
, 200, 78.431)) return 0;
6791 if (!CheckGray(xform
, 255, 100.0)) return 0;
6793 cmsDeleteTransform(xform
);
6799 cmsInt32Number
CheckOutGray(cmsHTRANSFORM xform
, double L
, cmsUInt8Number g
)
6802 cmsUInt8Number g_out
;
6808 cmsDoTransform(xform
, &Lab
, &g_out
, 1);
6810 return IsGoodVal("Gray value", g
, (double) g_out
, 0.01);
6814 cmsInt32Number
CheckOutputGray(void)
6816 cmsHPROFILE hGray
= Create_Gray22();
6817 cmsHPROFILE hLab
= cmsCreateLab4Profile(NULL
);
6818 cmsHTRANSFORM xform
;
6820 if (hGray
== NULL
|| hLab
== NULL
) return 0;
6822 xform
= cmsCreateTransform( hLab
, TYPE_Lab_DBL
, hGray
, TYPE_GRAY_8
, INTENT_RELATIVE_COLORIMETRIC
, 0);
6823 cmsCloseProfile(hGray
); cmsCloseProfile(hLab
);
6825 if (!CheckOutGray(xform
, 0, 0)) return 0;
6826 if (!CheckOutGray(xform
, 100, 255)) return 0;
6828 if (!CheckOutGray(xform
, 20, 52)) return 0;
6829 if (!CheckOutGray(xform
, 50, 118)) return 0;
6832 cmsDeleteTransform(xform
);
6838 cmsInt32Number
CheckLabOutputGray(void)
6840 cmsHPROFILE hGray
= Create_GrayLab();
6841 cmsHPROFILE hLab
= cmsCreateLab4Profile(NULL
);
6842 cmsHTRANSFORM xform
;
6845 if (hGray
== NULL
|| hLab
== NULL
) return 0;
6847 xform
= cmsCreateTransform( hLab
, TYPE_Lab_DBL
, hGray
, TYPE_GRAY_8
, INTENT_RELATIVE_COLORIMETRIC
, 0);
6848 cmsCloseProfile(hGray
); cmsCloseProfile(hLab
);
6850 if (!CheckOutGray(xform
, 0, 0)) return 0;
6851 if (!CheckOutGray(xform
, 100, 255)) return 0;
6853 for (i
=0; i
< 100; i
++) {
6857 g
= (cmsUInt8Number
) floor(i
* 255.0 / 100.0 + 0.5);
6859 if (!CheckOutGray(xform
, i
, g
)) return 0;
6863 cmsDeleteTransform(xform
);
6869 cmsInt32Number
CheckV4gamma(void)
6872 cmsUInt16Number Lin
[] = {0, 0xffff};
6873 cmsToneCurve
*g
= cmsBuildTabulatedToneCurve16(DbgThread(), 2, Lin
);
6875 h
= cmsOpenProfileFromFileTHR(DbgThread(), "v4gamma.icc", "w");
6876 if (h
== NULL
) return 0;
6879 cmsSetProfileVersion(h
, 4.3);
6881 if (!cmsWriteTag(h
, cmsSigGrayTRCTag
, g
)) return 0;
6884 cmsFreeToneCurve(g
);
6885 remove("v4gamma.icc");
6889 // cmsBool cmsGBDdumpVRML(cmsHANDLE hGBD, const char* fname);
6891 // Gamut descriptor routines
6893 cmsInt32Number
CheckGBD(void)
6897 cmsInt32Number L
, a
, b
;
6898 cmsUInt32Number r1
, g1
, b1
;
6899 cmsHPROFILE hLab
, hsRGB
;
6900 cmsHTRANSFORM xform
;
6902 h
= cmsGBDAlloc(DbgThread());
6903 if (h
== NULL
) return 0;
6905 // Fill all Lab gamut as valid
6906 SubTest("Filling RAW gamut");
6908 for (L
=0; L
<= 100; L
+= 10)
6909 for (a
= -128; a
<= 128; a
+= 5)
6910 for (b
= -128; b
<= 128; b
+= 5) {
6915 if (!cmsGDBAddPoint(h
, &Lab
)) return 0;
6918 // Complete boundaries
6919 SubTest("computing Lab gamut");
6920 if (!cmsGDBCompute(h
, 0)) return 0;
6923 // All points should be inside gamut
6924 SubTest("checking Lab gamut");
6925 for (L
=10; L
<= 90; L
+= 25)
6926 for (a
= -120; a
<= 120; a
+= 25)
6927 for (b
= -120; b
<= 120; b
+= 25) {
6932 if (!cmsGDBCheckPoint(h
, &Lab
)) {
6940 SubTest("checking sRGB gamut");
6941 h
= cmsGBDAlloc(DbgThread());
6942 hsRGB
= cmsCreate_sRGBProfile();
6943 hLab
= cmsCreateLab4Profile(NULL
);
6945 xform
= cmsCreateTransform(hsRGB
, TYPE_RGB_8
, hLab
, TYPE_Lab_DBL
, INTENT_RELATIVE_COLORIMETRIC
, cmsFLAGS_NOCACHE
);
6946 cmsCloseProfile(hsRGB
); cmsCloseProfile(hLab
);
6949 for (r1
=0; r1
< 256; r1
+= 5) {
6950 for (g1
=0; g1
< 256; g1
+= 5)
6951 for (b1
=0; b1
< 256; b1
+= 5) {
6954 cmsUInt8Number rgb
[3];
6956 rgb
[0] = (cmsUInt8Number
) r1
;
6957 rgb
[1] = (cmsUInt8Number
) g1
;
6958 rgb
[2] = (cmsUInt8Number
) b1
;
6960 cmsDoTransform(xform
, rgb
, &Lab
, 1);
6962 // if (fabs(Lab.b) < 20 && Lab.a > 0) continue;
6964 if (!cmsGDBAddPoint(h
, &Lab
)) {
6974 if (!cmsGDBCompute(h
, 0)) return 0;
6975 // cmsGBDdumpVRML(h, "c:\\colormaps\\lab.wrl");
6977 for (r1
=10; r1
< 200; r1
+= 10) {
6978 for (g1
=10; g1
< 200; g1
+= 10)
6979 for (b1
=10; b1
< 200; b1
+= 10) {
6982 cmsUInt8Number rgb
[3];
6984 rgb
[0] = (cmsUInt8Number
) r1
;
6985 rgb
[1] = (cmsUInt8Number
) g1
;
6986 rgb
[2] = (cmsUInt8Number
) b1
;
6988 cmsDoTransform(xform
, rgb
, &Lab
, 1);
6989 if (!cmsGDBCheckPoint(h
, &Lab
)) {
6991 cmsDeleteTransform(xform
);
6999 cmsDeleteTransform(xform
);
7002 SubTest("checking LCh chroma ring");
7003 h
= cmsGBDAlloc(DbgThread());
7006 for (r1
=0; r1
< 360; r1
++) {
7014 cmsLCh2Lab(&Lab
, &LCh
);
7015 if (!cmsGDBAddPoint(h
, &Lab
)) {
7022 if (!cmsGDBCompute(h
, 0)) return 0;
7034 cmsHPROFILE pProfile
= cmsOpenProfileFromFile("sRGBlcms2.icc", "r");
7035 cmsProfileID ProfileID1
, ProfileID2
, ProfileID3
, ProfileID4
;
7037 h
=(_cmsICCPROFILE
*) pProfile
;
7038 if (cmsMD5computeID(pProfile
)) cmsGetHeaderProfileID(pProfile
, ProfileID1
.ID8
);
7039 if (cmsMD5computeID(pProfile
)) cmsGetHeaderProfileID(pProfile
,ProfileID2
.ID8
);
7041 cmsCloseProfile(pProfile
);
7044 pProfile
= cmsOpenProfileFromFile("sRGBlcms2.icc", "r");
7046 h
=(_cmsICCPROFILE
*) pProfile
;
7047 if (cmsMD5computeID(pProfile
)) cmsGetHeaderProfileID(pProfile
, ProfileID3
.ID8
);
7048 if (cmsMD5computeID(pProfile
)) cmsGetHeaderProfileID(pProfile
,ProfileID4
.ID8
);
7050 cmsCloseProfile(pProfile
);
7052 return ((memcmp(ProfileID1
.ID8
, ProfileID3
.ID8
, sizeof(ProfileID1
)) == 0) &&
7053 (memcmp(ProfileID2
.ID8
, ProfileID4
.ID8
, sizeof(ProfileID2
)) == 0));
7059 int CheckLinking(void)
7062 cmsPipeline
* pipeline
;
7063 cmsStage
*stageBegin
, *stageEnd
;
7065 // Create a CLUT based profile
7066 h
= cmsCreateInkLimitingDeviceLinkTHR(DbgThread(), cmsSigCmykData
, 150);
7068 // link a second tag
7069 cmsLinkTag(h
, cmsSigAToB1Tag
, cmsSigAToB0Tag
);
7071 // Save the linked devicelink
7072 if (!cmsSaveProfileToFile(h
, "lcms2link.icc")) return 0;
7075 // Now open the profile and read the pipeline
7076 h
= cmsOpenProfileFromFile("lcms2link.icc", "r");
7077 if (h
== NULL
) return 0;
7079 pipeline
= (cmsPipeline
*) cmsReadTag(h
, cmsSigAToB1Tag
);
7080 if (pipeline
== NULL
)
7085 pipeline
= cmsPipelineDup(pipeline
);
7087 // extract stage from pipe line
7088 cmsPipelineUnlinkStage(pipeline
, cmsAT_BEGIN
, &stageBegin
);
7089 cmsPipelineUnlinkStage(pipeline
, cmsAT_END
, &stageEnd
);
7090 cmsPipelineInsertStage(pipeline
, cmsAT_END
, stageEnd
);
7091 cmsPipelineInsertStage(pipeline
, cmsAT_BEGIN
, stageBegin
);
7093 if (cmsTagLinkedTo(h
, cmsSigAToB1Tag
) != cmsSigAToB0Tag
) return 0;
7095 cmsWriteTag(h
, cmsSigAToB0Tag
, pipeline
);
7096 cmsPipelineFree(pipeline
);
7098 if (!cmsSaveProfileToFile(h
, "lcms2link2.icc")) return 0;
7108 // Created by Paul Miller on 30/08/2012.
7111 cmsHPROFILE
IdentityMatrixProfile( cmsColorSpaceSignature dataSpace
)
7114 cmsVEC3 zero
= {{0,0,0}};
7116 cmsPipeline
* forward
;
7117 cmsPipeline
* reverse
;
7118 cmsHPROFILE identityProfile
= cmsCreateProfilePlaceholder( ctx
);
7121 cmsSetProfileVersion(identityProfile
, 4.3);
7123 cmsSetDeviceClass( identityProfile
, cmsSigColorSpaceClass
);
7124 cmsSetColorSpace(identityProfile
, dataSpace
);
7125 cmsSetPCS(identityProfile
, cmsSigXYZData
);
7127 cmsSetHeaderRenderingIntent(identityProfile
, INTENT_RELATIVE_COLORIMETRIC
);
7129 cmsWriteTag(identityProfile
, cmsSigMediaWhitePointTag
, cmsD50_XYZ());
7133 _cmsMAT3identity( &identity
);
7135 // build forward transform.... (RGB to PCS)
7136 forward
= cmsPipelineAlloc( 0, 3, 3);
7137 cmsPipelineInsertStage( forward
, cmsAT_END
, cmsStageAllocMatrix( ctx
, 3, 3, (cmsFloat64Number
*)&identity
, (cmsFloat64Number
*)&zero
));
7138 cmsWriteTag( identityProfile
, cmsSigDToB1Tag
, forward
);
7140 cmsPipelineFree( forward
);
7142 reverse
= cmsPipelineAlloc( 0, 3, 3);
7143 cmsPipelineInsertStage( reverse
, cmsAT_END
, cmsStageAllocMatrix( ctx
, 3, 3, (cmsFloat64Number
*)&identity
, (cmsFloat64Number
*)&zero
));
7144 cmsWriteTag( identityProfile
, cmsSigBToD1Tag
, reverse
);
7146 cmsPipelineFree( reverse
);
7148 return identityProfile
;
7152 cmsInt32Number
CheckFloatXYZ(void)
7155 cmsHPROFILE xyzProfile
= cmsCreateXYZProfile();
7156 cmsHTRANSFORM xform
;
7157 cmsFloat32Number in
[3];
7158 cmsFloat32Number out
[3];
7165 input
= IdentityMatrixProfile( cmsSigRgbData
);
7167 xform
= cmsCreateTransform( input
, TYPE_RGB_FLT
, xyzProfile
, TYPE_XYZ_FLT
, INTENT_RELATIVE_COLORIMETRIC
, 0);
7168 cmsCloseProfile(input
);
7170 cmsDoTransform( xform
, in
, out
, 1);
7171 cmsDeleteTransform( xform
);
7173 if (!IsGoodVal("Float RGB->XYZ", in
[0], out
[0], FLOAT_PRECISSION
) ||
7174 !IsGoodVal("Float RGB->XYZ", in
[1], out
[1], FLOAT_PRECISSION
) ||
7175 !IsGoodVal("Float RGB->XYZ", in
[2], out
[2], FLOAT_PRECISSION
))
7180 input
= IdentityMatrixProfile( cmsSigXYZData
);
7182 xform
= cmsCreateTransform( input
, TYPE_XYZ_FLT
, xyzProfile
, TYPE_XYZ_FLT
, INTENT_RELATIVE_COLORIMETRIC
, 0);
7183 cmsCloseProfile(input
);
7185 cmsDoTransform( xform
, in
, out
, 1);
7188 cmsDeleteTransform( xform
);
7190 if (!IsGoodVal("Float XYZ->XYZ", in
[0], out
[0], FLOAT_PRECISSION
) ||
7191 !IsGoodVal("Float XYZ->XYZ", in
[1], out
[1], FLOAT_PRECISSION
) ||
7192 !IsGoodVal("Float XYZ->XYZ", in
[2], out
[2], FLOAT_PRECISSION
))
7197 input
= IdentityMatrixProfile( cmsSigRgbData
);
7199 xform
= cmsCreateTransform( xyzProfile
, TYPE_XYZ_FLT
, input
, TYPE_RGB_FLT
, INTENT_RELATIVE_COLORIMETRIC
, 0);
7200 cmsCloseProfile(input
);
7202 cmsDoTransform( xform
, in
, out
, 1);
7204 cmsDeleteTransform( xform
);
7206 if (!IsGoodVal("Float XYZ->RGB", in
[0], out
[0], FLOAT_PRECISSION
) ||
7207 !IsGoodVal("Float XYZ->RGB", in
[1], out
[1], FLOAT_PRECISSION
) ||
7208 !IsGoodVal("Float XYZ->RGB", in
[2], out
[2], FLOAT_PRECISSION
))
7212 // Now the optimizer should remove a stage
7215 input
= IdentityMatrixProfile( cmsSigRgbData
);
7217 xform
= cmsCreateTransform( input
, TYPE_RGB_FLT
, input
, TYPE_RGB_FLT
, INTENT_RELATIVE_COLORIMETRIC
, 0);
7218 cmsCloseProfile(input
);
7220 cmsDoTransform( xform
, in
, out
, 1);
7222 cmsDeleteTransform( xform
);
7224 if (!IsGoodVal("Float RGB->RGB", in
[0], out
[0], FLOAT_PRECISSION
) ||
7225 !IsGoodVal("Float RGB->RGB", in
[1], out
[1], FLOAT_PRECISSION
) ||
7226 !IsGoodVal("Float RGB->RGB", in
[2], out
[2], FLOAT_PRECISSION
))
7229 cmsCloseProfile(xyzProfile
);
7240 sRGB built-in V4.3 -> Lab identity built-in V4.3
7241 Flags: "cmsFLAGS_NOCACHE", "cmsFLAGS_NOOPTIMIZE"
7242 Input format: TYPE_RGBA_FLT
7243 Output format: TYPE_LabA_FLT
7246 Lab identity built-in V4.3 -> sRGB built-in V4.3
7247 Flags: "cmsFLAGS_NOCACHE", "cmsFLAGS_NOOPTIMIZE"
7248 Input format: TYPE_LabA_FLT
7249 Output format: TYPE_RGBA_FLT
7253 cmsInt32Number
ChecksRGB2LabFLT(void)
7255 cmsHPROFILE hSRGB
= cmsCreate_sRGBProfile();
7256 cmsHPROFILE hLab
= cmsCreateLab4Profile(NULL
);
7258 cmsHTRANSFORM xform1
= cmsCreateTransform(hSRGB
, TYPE_RGBA_FLT
, hLab
, TYPE_LabA_FLT
, 0, cmsFLAGS_NOCACHE
|cmsFLAGS_NOOPTIMIZE
);
7259 cmsHTRANSFORM xform2
= cmsCreateTransform(hLab
, TYPE_LabA_FLT
, hSRGB
, TYPE_RGBA_FLT
, 0, cmsFLAGS_NOCACHE
|cmsFLAGS_NOOPTIMIZE
);
7261 cmsFloat32Number RGBA1
[4], RGBA2
[4], LabA
[4];
7265 for (i
= 0; i
<= 100; i
++)
7267 RGBA1
[0] = i
/ 100.0F
;
7268 RGBA1
[1] = i
/ 100.0F
;
7269 RGBA1
[2] = i
/ 100.0F
;
7272 cmsDoTransform(xform1
, RGBA1
, LabA
, 1);
7273 cmsDoTransform(xform2
, LabA
, RGBA2
, 1);
7275 if (!IsGoodVal("Float RGB->RGB", RGBA1
[0], RGBA2
[0], FLOAT_PRECISSION
) ||
7276 !IsGoodVal("Float RGB->RGB", RGBA1
[1], RGBA2
[1], FLOAT_PRECISSION
) ||
7277 !IsGoodVal("Float RGB->RGB", RGBA1
[2], RGBA2
[2], FLOAT_PRECISSION
))
7282 cmsDeleteTransform(xform1
);
7283 cmsDeleteTransform(xform2
);
7284 cmsCloseProfile(hSRGB
);
7285 cmsCloseProfile(hLab
);
7291 * parametric curve for Rec709
7294 double Rec709(double L
)
7296 if (L
<0.018) return 4.5*L
;
7299 double a
= 1.099* pow(L
, 0.45);
7308 cmsInt32Number
CheckParametricRec709(void)
7310 cmsFloat64Number params
[7];
7314 params
[0] = 0.45; /* y */
7315 params
[1] = pow(1.099, 1.0 / 0.45); /* a */
7316 params
[2] = 0.0; /* b */
7317 params
[3] = 4.5; /* c */
7318 params
[4] = 0.018; /* d */
7319 params
[5] = -0.099; /* e */
7320 params
[6] = 0.0; /* f */
7322 t
= cmsBuildParametricToneCurve (NULL
, 5, params
);
7325 for (i
=0; i
< 256; i
++)
7327 cmsFloat32Number n
= (cmsFloat32Number
) i
/ 255.0F
;
7328 cmsUInt16Number f1
= (cmsUInt16Number
) floor(255.0 * cmsEvalToneCurveFloat(t
, n
) + 0.5);
7329 cmsUInt16Number f2
= (cmsUInt16Number
) floor(255.0*Rec709((double) i
/ 255.0) + 0.5);
7333 cmsFreeToneCurve(t
);
7338 cmsFreeToneCurve(t
);
7343 #define kNumPoints 10
7345 typedef cmsFloat32Number(*Function
)(cmsFloat32Number x
);
7347 static cmsFloat32Number
StraightLine( cmsFloat32Number x
)
7349 return (cmsFloat32Number
) (0.1 + 0.9 * x
);
7352 static cmsInt32Number
TestCurve( const char* label
, cmsToneCurve
* curve
, Function fn
)
7354 cmsInt32Number ok
= 1;
7356 for (i
= 0; i
< kNumPoints
*3; i
++) {
7358 cmsFloat32Number x
= (cmsFloat32Number
)i
/ (kNumPoints
*3 - 1);
7359 cmsFloat32Number expectedY
= fn(x
);
7360 cmsFloat32Number out
= cmsEvalToneCurveFloat( curve
, x
);
7362 if (!IsGoodVal(label
, expectedY
, out
, FLOAT_PRECISSION
)) {
7370 cmsInt32Number
CheckFloatSamples(void)
7372 cmsFloat32Number y
[kNumPoints
];
7374 cmsToneCurve
*curve
;
7377 for (i
= 0; i
< kNumPoints
; i
++) {
7378 cmsFloat32Number x
= (cmsFloat32Number
)i
/ (kNumPoints
-1);
7380 y
[i
] = StraightLine(x
);
7383 curve
= cmsBuildTabulatedToneCurveFloat(NULL
, kNumPoints
, y
);
7384 ok
= TestCurve( "Float Samples", curve
, StraightLine
);
7385 cmsFreeToneCurve(curve
);
7391 cmsInt32Number
CheckFloatSegments(void)
7393 cmsInt32Number ok
= 1;
7395 cmsToneCurve
*curve
;
7397 cmsFloat32Number y
[ kNumPoints
];
7399 // build a segmented curve with a sampled section...
7400 cmsCurveSegment Seg
[3];
7402 // Initialize segmented curve part up to 0.1
7403 Seg
[0].x0
= -1e22f
; // -infinity
7405 Seg
[0].Type
= 6; // Y = (a * X + b) ^ Gamma + c
7406 Seg
[0].Params
[0] = 1.0f
; // gamma
7407 Seg
[0].Params
[1] = 0.9f
; // a
7408 Seg
[0].Params
[2] = 0.0f
; // b
7409 Seg
[0].Params
[3] = 0.1f
; // c
7410 Seg
[0].Params
[4] = 0.0f
;
7417 Seg
[1].nGridPoints
= kNumPoints
;
7418 Seg
[1].SampledPoints
= y
;
7420 for (i
= 0; i
< kNumPoints
; i
++) {
7421 cmsFloat32Number x
= (cmsFloat32Number
) (0.1 + ((cmsFloat32Number
)i
/ (kNumPoints
-1)) * (0.9 - 0.1));
7422 y
[i
] = StraightLine(x
);
7425 // from 1 to +infinity
7427 Seg
[2].x1
= 1e22f
; // +infinity
7430 Seg
[2].Params
[0] = 1.0f
;
7431 Seg
[2].Params
[1] = 0.9f
;
7432 Seg
[2].Params
[2] = 0.0f
;
7433 Seg
[2].Params
[3] = 0.1f
;
7434 Seg
[2].Params
[4] = 0.0f
;
7436 curve
= cmsBuildSegmentedToneCurve(0, 3, Seg
);
7438 ok
= TestCurve( "Float Segmented Curve", curve
, StraightLine
);
7440 cmsFreeToneCurve( curve
);
7447 cmsInt32Number
CheckReadRAW(void)
7449 cmsInt32Number tag_size
, tag_size1
;
7451 cmsHPROFILE hProfile
;
7454 SubTest("RAW read on on-disk");
7455 hProfile
= cmsOpenProfileFromFile("test1.icc", "r");
7457 if (hProfile
== NULL
)
7460 tag_size
= cmsReadRawTag(hProfile
, cmsSigGamutTag
, buffer
, 4);
7461 tag_size1
= cmsReadRawTag(hProfile
, cmsSigGamutTag
, NULL
, 0);
7463 cmsCloseProfile(hProfile
);
7468 if (tag_size1
!= 37009)
7471 SubTest("RAW read on in-memory created profiles");
7472 hProfile
= cmsCreate_sRGBProfile();
7473 tag_size
= cmsReadRawTag(hProfile
, cmsSigGreenColorantTag
, buffer
, 4);
7474 tag_size1
= cmsReadRawTag(hProfile
, cmsSigGreenColorantTag
, NULL
, 0);
7476 cmsCloseProfile(hProfile
);
7480 if (tag_size1
!= 20)
7488 // --------------------------------------------------------------------------------------------------
7489 // P E R F O R M A N C E C H E C K S
7490 // --------------------------------------------------------------------------------------------------
7493 typedef struct {cmsUInt8Number r
, g
, b
, a
;} Scanline_rgb1
;
7494 typedef struct {cmsUInt16Number r
, g
, b
, a
;} Scanline_rgb2
;
7495 typedef struct {cmsUInt8Number r
, g
, b
;} Scanline_rgb8
;
7496 typedef struct {cmsUInt16Number r
, g
, b
;} Scanline_rgb0
;
7500 void TitlePerformance(const char* Txt
)
7502 printf("%-45s: ", Txt
); fflush(stdout
);
7506 void PrintPerformance(cmsUInt32Number Bytes
, cmsUInt32Number SizeOfPixel
, cmsFloat64Number diff
)
7508 cmsFloat64Number seconds
= (cmsFloat64Number
) diff
/ CLOCKS_PER_SEC
;
7509 cmsFloat64Number mpix_sec
= Bytes
/ (1024.0*1024.0*seconds
*SizeOfPixel
);
7511 printf("%g MPixel/sec.\n", mpix_sec
);
7517 void SpeedTest16bits(const char * Title
, cmsHPROFILE hlcmsProfileIn
, cmsHPROFILE hlcmsProfileOut
, cmsInt32Number Intent
)
7520 cmsInt32Number r
, g
, b
, j
;
7522 cmsFloat64Number diff
;
7523 cmsHTRANSFORM hlcmsxform
;
7527 if (hlcmsProfileIn
== NULL
|| hlcmsProfileOut
== NULL
)
7528 Die("Unable to open profiles");
7530 hlcmsxform
= cmsCreateTransformTHR(DbgThread(), hlcmsProfileIn
, TYPE_RGB_16
,
7531 hlcmsProfileOut
, TYPE_RGB_16
, Intent
, cmsFLAGS_NOCACHE
);
7532 cmsCloseProfile(hlcmsProfileIn
);
7533 cmsCloseProfile(hlcmsProfileOut
);
7535 Mb
= 256*256*256*sizeof(Scanline_rgb0
);
7536 In
= (Scanline_rgb0
*) malloc(Mb
);
7539 for (r
=0; r
< 256; r
++)
7540 for (g
=0; g
< 256; g
++)
7541 for (b
=0; b
< 256; b
++) {
7543 In
[j
].r
= (cmsUInt16Number
) ((r
<< 8) | r
);
7544 In
[j
].g
= (cmsUInt16Number
) ((g
<< 8) | g
);
7545 In
[j
].b
= (cmsUInt16Number
) ((b
<< 8) | b
);
7551 TitlePerformance(Title
);
7555 cmsDoTransform(hlcmsxform
, In
, In
, 256*256*256);
7557 diff
= clock() - atime
;
7560 PrintPerformance(Mb
, sizeof(Scanline_rgb0
), diff
);
7561 cmsDeleteTransform(hlcmsxform
);
7567 void SpeedTest16bitsCMYK(const char * Title
, cmsHPROFILE hlcmsProfileIn
, cmsHPROFILE hlcmsProfileOut
)
7569 cmsInt32Number r
, g
, b
, j
;
7571 cmsFloat64Number diff
;
7572 cmsHTRANSFORM hlcmsxform
;
7576 if (hlcmsProfileIn
== NULL
|| hlcmsProfileOut
== NULL
)
7577 Die("Unable to open profiles");
7579 hlcmsxform
= cmsCreateTransformTHR(DbgThread(), hlcmsProfileIn
, TYPE_CMYK_16
,
7580 hlcmsProfileOut
, TYPE_CMYK_16
, INTENT_PERCEPTUAL
, cmsFLAGS_NOCACHE
);
7581 cmsCloseProfile(hlcmsProfileIn
);
7582 cmsCloseProfile(hlcmsProfileOut
);
7584 Mb
= 256*256*256*sizeof(Scanline_rgb2
);
7586 In
= (Scanline_rgb2
*) malloc(Mb
);
7589 for (r
=0; r
< 256; r
++)
7590 for (g
=0; g
< 256; g
++)
7591 for (b
=0; b
< 256; b
++) {
7593 In
[j
].r
= (cmsUInt16Number
) ((r
<< 8) | r
);
7594 In
[j
].g
= (cmsUInt16Number
) ((g
<< 8) | g
);
7595 In
[j
].b
= (cmsUInt16Number
) ((b
<< 8) | b
);
7602 TitlePerformance(Title
);
7606 cmsDoTransform(hlcmsxform
, In
, In
, 256*256*256);
7608 diff
= clock() - atime
;
7612 PrintPerformance(Mb
, sizeof(Scanline_rgb2
), diff
);
7614 cmsDeleteTransform(hlcmsxform
);
7620 void SpeedTest8bits(const char * Title
, cmsHPROFILE hlcmsProfileIn
, cmsHPROFILE hlcmsProfileOut
, cmsInt32Number Intent
)
7622 cmsInt32Number r
, g
, b
, j
;
7624 cmsFloat64Number diff
;
7625 cmsHTRANSFORM hlcmsxform
;
7629 if (hlcmsProfileIn
== NULL
|| hlcmsProfileOut
== NULL
)
7630 Die("Unable to open profiles");
7632 hlcmsxform
= cmsCreateTransformTHR(DbgThread(), hlcmsProfileIn
, TYPE_RGB_8
,
7633 hlcmsProfileOut
, TYPE_RGB_8
, Intent
, cmsFLAGS_NOCACHE
);
7634 cmsCloseProfile(hlcmsProfileIn
);
7635 cmsCloseProfile(hlcmsProfileOut
);
7637 Mb
= 256*256*256*sizeof(Scanline_rgb8
);
7639 In
= (Scanline_rgb8
*) malloc(Mb
);
7642 for (r
=0; r
< 256; r
++)
7643 for (g
=0; g
< 256; g
++)
7644 for (b
=0; b
< 256; b
++) {
7646 In
[j
].r
= (cmsUInt8Number
) r
;
7647 In
[j
].g
= (cmsUInt8Number
) g
;
7648 In
[j
].b
= (cmsUInt8Number
) b
;
7653 TitlePerformance(Title
);
7657 cmsDoTransform(hlcmsxform
, In
, In
, 256*256*256);
7659 diff
= clock() - atime
;
7663 PrintPerformance(Mb
, sizeof(Scanline_rgb8
), diff
);
7665 cmsDeleteTransform(hlcmsxform
);
7671 void SpeedTest8bitsCMYK(const char * Title
, cmsHPROFILE hlcmsProfileIn
, cmsHPROFILE hlcmsProfileOut
)
7673 cmsInt32Number r
, g
, b
, j
;
7675 cmsFloat64Number diff
;
7676 cmsHTRANSFORM hlcmsxform
;
7680 if (hlcmsProfileIn
== NULL
|| hlcmsProfileOut
== NULL
)
7681 Die("Unable to open profiles");
7683 hlcmsxform
= cmsCreateTransformTHR(DbgThread(), hlcmsProfileIn
, TYPE_CMYK_8
,
7684 hlcmsProfileOut
, TYPE_CMYK_8
, INTENT_PERCEPTUAL
, cmsFLAGS_NOCACHE
);
7685 cmsCloseProfile(hlcmsProfileIn
);
7686 cmsCloseProfile(hlcmsProfileOut
);
7688 Mb
= 256*256*256*sizeof(Scanline_rgb2
);
7690 In
= (Scanline_rgb2
*) malloc(Mb
);
7693 for (r
=0; r
< 256; r
++)
7694 for (g
=0; g
< 256; g
++)
7695 for (b
=0; b
< 256; b
++) {
7697 In
[j
].r
= (cmsUInt8Number
) r
;
7698 In
[j
].g
= (cmsUInt8Number
) g
;
7699 In
[j
].b
= (cmsUInt8Number
) b
;
7700 In
[j
].a
= (cmsUInt8Number
) 0;
7705 TitlePerformance(Title
);
7709 cmsDoTransform(hlcmsxform
, In
, In
, 256*256*256);
7711 diff
= clock() - atime
;
7715 PrintPerformance(Mb
, sizeof(Scanline_rgb2
), diff
);
7718 cmsDeleteTransform(hlcmsxform
);
7724 void SpeedTest8bitsGray(const char * Title
, cmsHPROFILE hlcmsProfileIn
, cmsHPROFILE hlcmsProfileOut
, cmsInt32Number Intent
)
7726 cmsInt32Number r
, g
, b
, j
;
7728 cmsFloat64Number diff
;
7729 cmsHTRANSFORM hlcmsxform
;
7734 if (hlcmsProfileIn
== NULL
|| hlcmsProfileOut
== NULL
)
7735 Die("Unable to open profiles");
7737 hlcmsxform
= cmsCreateTransformTHR(DbgThread(), hlcmsProfileIn
,
7738 TYPE_GRAY_8
, hlcmsProfileOut
, TYPE_GRAY_8
, Intent
, cmsFLAGS_NOCACHE
);
7739 cmsCloseProfile(hlcmsProfileIn
);
7740 cmsCloseProfile(hlcmsProfileOut
);
7743 In
= (cmsUInt8Number
*) malloc(Mb
);
7746 for (r
=0; r
< 256; r
++)
7747 for (g
=0; g
< 256; g
++)
7748 for (b
=0; b
< 256; b
++) {
7750 In
[j
] = (cmsUInt8Number
) r
;
7755 TitlePerformance(Title
);
7759 cmsDoTransform(hlcmsxform
, In
, In
, 256*256*256);
7761 diff
= clock() - atime
;
7764 PrintPerformance(Mb
, sizeof(cmsUInt8Number
), diff
);
7765 cmsDeleteTransform(hlcmsxform
);
7770 cmsHPROFILE
CreateCurves(void)
7772 cmsToneCurve
* Gamma
= cmsBuildGamma(DbgThread(), 1.1);
7773 cmsToneCurve
* Transfer
[3];
7776 Transfer
[0] = Transfer
[1] = Transfer
[2] = Gamma
;
7777 h
= cmsCreateLinearizationDeviceLink(cmsSigRgbData
, Transfer
);
7779 cmsFreeToneCurve(Gamma
);
7786 void SpeedTest(void)
7788 printf("\n\nP E R F O R M A N C E T E S T S\n");
7789 printf( "=================================\n\n");
7792 SpeedTest16bits("16 bits on CLUT profiles",
7793 cmsOpenProfileFromFile("test5.icc", "r"),
7794 cmsOpenProfileFromFile("test3.icc", "r"), INTENT_PERCEPTUAL
);
7796 SpeedTest8bits("8 bits on CLUT profiles",
7797 cmsOpenProfileFromFile("test5.icc", "r"),
7798 cmsOpenProfileFromFile("test3.icc", "r"),
7801 SpeedTest8bits("8 bits on Matrix-Shaper profiles",
7802 cmsOpenProfileFromFile("test5.icc", "r"),
7803 cmsOpenProfileFromFile("aRGBlcms2.icc", "r"),
7806 SpeedTest8bits("8 bits on SAME Matrix-Shaper profiles",
7807 cmsOpenProfileFromFile("test5.icc", "r"),
7808 cmsOpenProfileFromFile("test5.icc", "r"),
7811 SpeedTest8bits("8 bits on Matrix-Shaper profiles (AbsCol)",
7812 cmsOpenProfileFromFile("test5.icc", "r"),
7813 cmsOpenProfileFromFile("aRGBlcms2.icc", "r"),
7814 INTENT_ABSOLUTE_COLORIMETRIC
);
7816 SpeedTest16bits("16 bits on Matrix-Shaper profiles",
7817 cmsOpenProfileFromFile("test5.icc", "r"),
7818 cmsOpenProfileFromFile("aRGBlcms2.icc", "r"),
7821 SpeedTest16bits("16 bits on SAME Matrix-Shaper profiles",
7822 cmsOpenProfileFromFile("aRGBlcms2.icc", "r"),
7823 cmsOpenProfileFromFile("aRGBlcms2.icc", "r"),
7826 SpeedTest16bits("16 bits on Matrix-Shaper profiles (AbsCol)",
7827 cmsOpenProfileFromFile("test5.icc", "r"),
7828 cmsOpenProfileFromFile("aRGBlcms2.icc", "r"),
7829 INTENT_ABSOLUTE_COLORIMETRIC
);
7831 SpeedTest8bits("8 bits on curves",
7836 SpeedTest16bits("16 bits on curves",
7841 SpeedTest8bitsCMYK("8 bits on CMYK profiles",
7842 cmsOpenProfileFromFile("test1.icc", "r"),
7843 cmsOpenProfileFromFile("test2.icc", "r"));
7845 SpeedTest16bitsCMYK("16 bits on CMYK profiles",
7846 cmsOpenProfileFromFile("test1.icc", "r"),
7847 cmsOpenProfileFromFile("test2.icc", "r"));
7849 SpeedTest8bitsGray("8 bits on gray-to gray",
7850 cmsOpenProfileFromFile("gray3lcms2.icc", "r"),
7851 cmsOpenProfileFromFile("graylcms2.icc", "r"), INTENT_RELATIVE_COLORIMETRIC
);
7853 SpeedTest8bitsGray("8 bits on gray-to-lab gray",
7854 cmsOpenProfileFromFile("graylcms2.icc", "r"),
7855 cmsOpenProfileFromFile("glablcms2.icc", "r"), INTENT_RELATIVE_COLORIMETRIC
);
7857 SpeedTest8bitsGray("8 bits on SAME gray-to-gray",
7858 cmsOpenProfileFromFile("graylcms2.icc", "r"),
7859 cmsOpenProfileFromFile("graylcms2.icc", "r"), INTENT_PERCEPTUAL
);
7863 // -----------------------------------------------------------------------------------------------------
7866 // Print the supported intents
7868 void PrintSupportedIntents(void)
7870 cmsUInt32Number n
, i
;
7871 cmsUInt32Number Codes
[200];
7872 char* Descriptions
[200];
7874 n
= cmsGetSupportedIntents(200, Codes
, Descriptions
);
7876 printf("Supported intents:\n");
7877 for (i
=0; i
< n
; i
++) {
7878 printf("\t%u - %s\n", Codes
[i
], Descriptions
[i
]);
7883 // ZOO checks ------------------------------------------------------------------------------------------------------------
7886 #ifdef CMS_IS_WINDOWS_
7888 static char ZOOfolder
[cmsMAX_PATH
] = "c:\\colormaps\\";
7889 static char ZOOwrite
[cmsMAX_PATH
] = "c:\\colormaps\\write\\";
7890 static char ZOORawWrite
[cmsMAX_PATH
] = "c:\\colormaps\\rawwrite\\";
7893 // Read all tags on a profile given by its handle
7895 void ReadAllTags(cmsHPROFILE h
)
7897 cmsInt32Number i
, n
;
7898 cmsTagSignature sig
;
7900 n
= cmsGetTagCount(h
);
7901 for (i
=0; i
< n
; i
++) {
7903 sig
= cmsGetTagSignature(h
, i
);
7904 if (cmsReadTag(h
, sig
) == NULL
) return;
7909 // Read all tags on a profile given by its handle
7911 void ReadAllRAWTags(cmsHPROFILE h
)
7913 cmsInt32Number i
, n
;
7914 cmsTagSignature sig
;
7917 n
= cmsGetTagCount(h
);
7918 for (i
=0; i
< n
; i
++) {
7920 sig
= cmsGetTagSignature(h
, i
);
7921 len
= cmsReadRawTag(h
, sig
, NULL
, 0);
7927 void PrintInfo(cmsHPROFILE h
, cmsInfoType Info
)
7931 cmsContext id
= DbgThread();
7933 len
= cmsGetProfileInfo(h
, Info
, "en", "US", NULL
, 0);
7934 if (len
== 0) return;
7936 text
= _cmsMalloc(id
, len
);
7937 cmsGetProfileInfo(h
, Info
, "en", "US", text
, len
);
7939 wprintf(L
"%s\n", text
);
7945 void PrintAllInfos(cmsHPROFILE h
)
7947 PrintInfo(h
, cmsInfoDescription
);
7948 PrintInfo(h
, cmsInfoManufacturer
);
7949 PrintInfo(h
, cmsInfoModel
);
7950 PrintInfo(h
, cmsInfoCopyright
);
7955 void ReadAllLUTS(cmsHPROFILE h
)
7960 a
= _cmsReadInputLUT(h
, INTENT_PERCEPTUAL
);
7961 if (a
) cmsPipelineFree(a
);
7963 a
= _cmsReadInputLUT(h
, INTENT_RELATIVE_COLORIMETRIC
);
7964 if (a
) cmsPipelineFree(a
);
7966 a
= _cmsReadInputLUT(h
, INTENT_SATURATION
);
7967 if (a
) cmsPipelineFree(a
);
7969 a
= _cmsReadInputLUT(h
, INTENT_ABSOLUTE_COLORIMETRIC
);
7970 if (a
) cmsPipelineFree(a
);
7973 a
= _cmsReadOutputLUT(h
, INTENT_PERCEPTUAL
);
7974 if (a
) cmsPipelineFree(a
);
7976 a
= _cmsReadOutputLUT(h
, INTENT_RELATIVE_COLORIMETRIC
);
7977 if (a
) cmsPipelineFree(a
);
7979 a
= _cmsReadOutputLUT(h
, INTENT_SATURATION
);
7980 if (a
) cmsPipelineFree(a
);
7982 a
= _cmsReadOutputLUT(h
, INTENT_ABSOLUTE_COLORIMETRIC
);
7983 if (a
) cmsPipelineFree(a
);
7986 a
= _cmsReadDevicelinkLUT(h
, INTENT_PERCEPTUAL
);
7987 if (a
) cmsPipelineFree(a
);
7989 a
= _cmsReadDevicelinkLUT(h
, INTENT_RELATIVE_COLORIMETRIC
);
7990 if (a
) cmsPipelineFree(a
);
7992 a
= _cmsReadDevicelinkLUT(h
, INTENT_SATURATION
);
7993 if (a
) cmsPipelineFree(a
);
7995 a
= _cmsReadDevicelinkLUT(h
, INTENT_ABSOLUTE_COLORIMETRIC
);
7996 if (a
) cmsPipelineFree(a
);
7999 cmsDetectDestinationBlackPoint(&Black
, h
, INTENT_PERCEPTUAL
, 0);
8000 cmsDetectDestinationBlackPoint(&Black
, h
, INTENT_RELATIVE_COLORIMETRIC
, 0);
8001 cmsDetectDestinationBlackPoint(&Black
, h
, INTENT_SATURATION
, 0);
8002 cmsDetectDestinationBlackPoint(&Black
, h
, INTENT_ABSOLUTE_COLORIMETRIC
, 0);
8006 // Check one specimen in the ZOO
8009 cmsInt32Number
CheckSingleSpecimen(const char* Profile
)
8015 sprintf(BuffSrc
, "%s%s", ZOOfolder
, Profile
);
8016 sprintf(BuffDst
, "%s%s", ZOOwrite
, Profile
);
8018 h
= cmsOpenProfileFromFile(BuffSrc
, "r");
8019 if (h
== NULL
) return 0;
8021 printf("%s\n", Profile
);
8024 // ReadAllRAWTags(h);
8027 cmsSaveProfileToFile(h
, BuffDst
);
8030 h
= cmsOpenProfileFromFile(BuffDst
, "r");
8031 if (h
== NULL
) return 0;
8041 cmsInt32Number
CheckRAWSpecimen(const char* Profile
)
8047 sprintf(BuffSrc
, "%s%s", ZOOfolder
, Profile
);
8048 sprintf(BuffDst
, "%s%s", ZOORawWrite
, Profile
);
8050 h
= cmsOpenProfileFromFile(BuffSrc
, "r");
8051 if (h
== NULL
) return 0;
8055 cmsSaveProfileToFile(h
, BuffDst
);
8058 h
= cmsOpenProfileFromFile(BuffDst
, "r");
8059 if (h
== NULL
) return 0;
8068 void CheckProfileZOO(void)
8071 struct _finddata_t c_file
;
8074 cmsSetLogErrorHandler(NULL
);
8076 if ( (hFile
= _findfirst("c:\\colormaps\\*.*", &c_file
)) == -1L )
8077 printf("No files in current directory");
8083 printf("%s\n", c_file
.name
);
8084 if (strcmp(c_file
.name
, ".") != 0 &&
8085 strcmp(c_file
.name
, "..") != 0) {
8087 CheckSingleSpecimen( c_file
.name
);
8088 CheckRAWSpecimen( c_file
.name
);
8090 if (TotalMemory
> 0)
8091 printf("Ok, but %s are left!\n", MemStr(TotalMemory
));
8097 } while ( _findnext(hFile
, &c_file
) == 0 );
8102 cmsSetLogErrorHandler(FatalErrorQuit
);
8109 #define TYPE_709 709
8110 static double Rec709Math(int Type
, const double Params
[], double R
)
8117 if (R
<= (Params
[3]*Params
[4])) Fun
= R
/ Params
[3];
8118 else Fun
= pow(((R
- Params
[2])/Params
[1]), Params
[0]);
8123 if (R
<= Params
[4]) Fun
= R
* Params
[3];
8124 else Fun
= Params
[1] * pow(R
, (1/Params
[0])) + Params
[2];
8131 // Add nonstandard TRC curves -> Rec709
8132 cmsPluginParametricCurves NewCurvePlugin
= {
8133 { cmsPluginMagicNumber
, 2000, cmsPluginParametricCurveSig
, NULL
},
8134 1, {TYPE_709
}, {5}, Rec709Math
};
8140 // ---------------------------------------------------------------------------------------
8142 int main(int argc
, char* argv
[])
8145 cmsInt32Number Exhaustive
= 0;
8146 cmsInt32Number DoSpeedTests
= 1;
8147 cmsInt32Number DoCheckTests
= 1;
8150 _CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF
| _CRTDBG_LEAK_CHECK_DF
);
8153 printf("LittleCMS %2.2f test bed %s %s\n\n", LCMS_VERSION
/ 1000.0, __DATE__
, __TIME__
);
8155 if ((argc
== 2) && strcmp(argv
[1], "--exhaustive") == 0) {
8158 printf("Running exhaustive tests (will take a while...)\n\n");
8161 printf("Installing debug memory plug-in ... ");
8162 cmsPlugin(&DebugMemHandler
);
8165 printf("Installing error logger ... ");
8166 cmsSetLogErrorHandler(FatalErrorQuit
);
8169 #ifdef CMS_IS_WINDOWS_
8170 // CheckProfileZOO();
8173 PrintSupportedIntents();
8177 // Create utility profiles
8178 Check("Creation of test profiles", CreateTestProfiles
);
8182 Check("Base types", CheckBaseTypes
);
8183 Check("endianess", CheckEndianess
);
8184 Check("quick floor", CheckQuickFloor
);
8185 Check("quick floor word", CheckQuickFloorWord
);
8186 Check("Fixed point 15.16 representation", CheckFixedPoint15_16
);
8187 Check("Fixed point 8.8 representation", CheckFixedPoint8_8
);
8189 // Forward 1D interpolation
8190 Check("1D interpolation in 2pt tables", Check1DLERP2
);
8191 Check("1D interpolation in 3pt tables", Check1DLERP3
);
8192 Check("1D interpolation in 4pt tables", Check1DLERP4
);
8193 Check("1D interpolation in 6pt tables", Check1DLERP6
);
8194 Check("1D interpolation in 18pt tables", Check1DLERP18
);
8195 Check("1D interpolation in descending 2pt tables", Check1DLERP2Down
);
8196 Check("1D interpolation in descending 3pt tables", Check1DLERP3Down
);
8197 Check("1D interpolation in descending 6pt tables", Check1DLERP6Down
);
8198 Check("1D interpolation in descending 18pt tables", Check1DLERP18Down
);
8202 Check("1D interpolation in n tables", ExhaustiveCheck1DLERP
);
8203 Check("1D interpolation in descending tables", ExhaustiveCheck1DLERPDown
);
8206 // Forward 3D interpolation
8207 Check("3D interpolation Tetrahedral (float) ", Check3DinterpolationFloatTetrahedral
);
8208 Check("3D interpolation Trilinear (float) ", Check3DinterpolationFloatTrilinear
);
8209 Check("3D interpolation Tetrahedral (16) ", Check3DinterpolationTetrahedral16
);
8210 Check("3D interpolation Trilinear (16) ", Check3DinterpolationTrilinear16
);
8214 Check("Exhaustive 3D interpolation Tetrahedral (float) ", ExaustiveCheck3DinterpolationFloatTetrahedral
);
8215 Check("Exhaustive 3D interpolation Trilinear (float) ", ExaustiveCheck3DinterpolationFloatTrilinear
);
8216 Check("Exhaustive 3D interpolation Tetrahedral (16) ", ExhaustiveCheck3DinterpolationTetrahedral16
);
8217 Check("Exhaustive 3D interpolation Trilinear (16) ", ExhaustiveCheck3DinterpolationTrilinear16
);
8220 Check("Reverse interpolation 3 -> 3", CheckReverseInterpolation3x3
);
8221 Check("Reverse interpolation 4 -> 3", CheckReverseInterpolation4x3
);
8224 // High dimensionality interpolation
8226 Check("3D interpolation", Check3Dinterp
);
8227 Check("3D interpolation with granularity", Check3DinterpGranular
);
8228 Check("4D interpolation", Check4Dinterp
);
8229 Check("4D interpolation with granularity", Check4DinterpGranular
);
8230 Check("5D interpolation with granularity", Check5DinterpGranular
);
8231 Check("6D interpolation with granularity", Check6DinterpGranular
);
8232 Check("7D interpolation with granularity", Check7DinterpGranular
);
8233 Check("8D interpolation with granularity", Check8DinterpGranular
);
8235 // Encoding of colorspaces
8236 Check("Lab to LCh and back (float only) ", CheckLab2LCh
);
8237 Check("Lab to XYZ and back (float only) ", CheckLab2XYZ
);
8238 Check("Lab to xyY and back (float only) ", CheckLab2xyY
);
8239 Check("Lab V2 encoding", CheckLabV2encoding
);
8240 Check("Lab V4 encoding", CheckLabV4encoding
);
8243 Check("Blackbody radiator", CheckTemp2CHRM
);
8246 Check("Linear gamma curves (16 bits)", CheckGammaCreation16
);
8247 Check("Linear gamma curves (float)", CheckGammaCreationFlt
);
8249 Check("Curve 1.8 (float)", CheckGamma18
);
8250 Check("Curve 2.2 (float)", CheckGamma22
);
8251 Check("Curve 3.0 (float)", CheckGamma30
);
8253 Check("Curve 1.8 (table)", CheckGamma18Table
);
8254 Check("Curve 2.2 (table)", CheckGamma22Table
);
8255 Check("Curve 3.0 (table)", CheckGamma30Table
);
8257 Check("Curve 1.8 (word table)", CheckGamma18TableWord
);
8258 Check("Curve 2.2 (word table)", CheckGamma22TableWord
);
8259 Check("Curve 3.0 (word table)", CheckGamma30TableWord
);
8261 Check("Parametric curves", CheckParametricToneCurves
);
8263 Check("Join curves", CheckJointCurves
);
8264 Check("Join curves descending", CheckJointCurvesDescending
);
8265 Check("Join curves degenerated", CheckReverseDegenerated
);
8266 Check("Join curves sRGB (Float)", CheckJointFloatCurves_sRGB
);
8267 Check("Join curves sRGB (16 bits)", CheckJoint16Curves_sRGB
);
8268 Check("Join curves sigmoidal", CheckJointCurvesSShaped
);
8271 Check("LUT creation & dup", CheckLUTcreation
);
8272 Check("1 Stage LUT ", Check1StageLUT
);
8273 Check("2 Stage LUT ", Check2StageLUT
);
8274 Check("2 Stage LUT (16 bits)", Check2Stage16LUT
);
8275 Check("3 Stage LUT ", Check3StageLUT
);
8276 Check("3 Stage LUT (16 bits)", Check3Stage16LUT
);
8277 Check("4 Stage LUT ", Check4StageLUT
);
8278 Check("4 Stage LUT (16 bits)", Check4Stage16LUT
);
8279 Check("5 Stage LUT ", Check5StageLUT
);
8280 Check("5 Stage LUT (16 bits) ", Check5Stage16LUT
);
8281 Check("6 Stage LUT ", Check6StageLUT
);
8282 Check("6 Stage LUT (16 bits) ", Check6Stage16LUT
);
8285 Check("Lab to Lab LUT (float only) ", CheckLab2LabLUT
);
8286 Check("XYZ to XYZ LUT (float only) ", CheckXYZ2XYZLUT
);
8287 Check("Lab to Lab MAT LUT (float only) ", CheckLab2LabMatLUT
);
8288 Check("Named Color LUT", CheckNamedColorLUT
);
8289 Check("Usual formatters", CheckFormatters16
);
8290 Check("Floating point formatters", CheckFormattersFloat
);
8292 #ifndef CMS_NO_HALF_SUPPORT
8293 Check("HALF formatters", CheckFormattersHalf
);
8295 // ChangeBuffersFormat
8296 Check("ChangeBuffersFormat", CheckChangeBufferFormat
);
8299 Check("Multilocalized Unicode", CheckMLU
);
8302 Check("Named color lists", CheckNamedColorList
);
8304 // Profile I/O (this one is huge!)
8305 Check("Profile creation", CheckProfileCreation
);
8309 Check("Error reporting on bad profiles", CheckErrReportingOnBadProfiles
);
8310 Check("Error reporting on bad transforms", CheckErrReportingOnBadTransforms
);
8313 Check("Curves only transforms", CheckCurvesOnlyTransforms
);
8314 Check("Float Lab->Lab transforms", CheckFloatLabTransforms
);
8315 Check("Encoded Lab->Lab transforms", CheckEncodedLabTransforms
);
8316 Check("Stored identities", CheckStoredIdentities
);
8318 Check("Matrix-shaper transform (float)", CheckMatrixShaperXFORMFloat
);
8319 Check("Matrix-shaper transform (16 bits)", CheckMatrixShaperXFORM16
);
8320 Check("Matrix-shaper transform (8 bits)", CheckMatrixShaperXFORM8
);
8322 Check("Primaries of sRGB", CheckRGBPrimaries
);
8325 Check("Known values across matrix-shaper", Chack_sRGB_Float
);
8326 Check("Gray input profile", CheckInputGray
);
8327 Check("Gray Lab input profile", CheckLabInputGray
);
8328 Check("Gray output profile", CheckOutputGray
);
8329 Check("Gray Lab output profile", CheckLabOutputGray
);
8331 Check("Matrix-shaper proofing transform (float)", CheckProofingXFORMFloat
);
8332 Check("Matrix-shaper proofing transform (16 bits)", CheckProofingXFORM16
);
8334 Check("Gamut check", CheckGamutCheck
);
8336 Check("CMYK roundtrip on perceptual transform", CheckCMYKRoundtrip
);
8338 Check("CMYK perceptual transform", CheckCMYKPerceptual
);
8339 // Check("CMYK rel.col. transform", CheckCMYKRelCol);
8341 Check("Black ink only preservation", CheckKOnlyBlackPreserving
);
8342 Check("Black plane preservation", CheckKPlaneBlackPreserving
);
8345 Check("Deciding curve types", CheckV4gamma
);
8347 Check("Black point detection", CheckBlackPoint
);
8348 Check("TAC detection", CheckTAC
);
8350 Check("CGATS parser", CheckCGATS
);
8351 Check("PostScript generator", CheckPostScript
);
8352 Check("Segment maxima GBD", CheckGBD
);
8353 Check("MD5 digest", CheckMD5
);
8354 Check("Linking", CheckLinking
);
8355 Check("floating point tags on XYZ", CheckFloatXYZ
);
8356 Check("RGB->Lab->RGB with alpha on FLT", ChecksRGB2LabFLT
);
8357 Check("Parametric curve on Rec709", CheckParametricRec709
);
8358 Check("Floating Point sampled curve with non-zero start", CheckFloatSamples
);
8359 Check("Floating Point segmented curve with short sampled segement", CheckFloatSegments
);
8360 Check("Read RAW portions", CheckReadRAW
);
8367 DebugMemPrintTotals();
8369 cmsUnregisterPlugins();
8372 RemoveTestProfiles();