diff options
author | Marti Maria <info@littlecms.com> | 2014-02-12 12:21:45 +0100 |
---|---|---|
committer | Marti Maria <info@littlecms.com> | 2014-02-12 12:21:45 +0100 |
commit | 078665ecf29b6a9ca31803e6ebd12f22f3da9961 (patch) | |
tree | d5036b7a482babdd8d99a693f3edeabf6877f1c1 /testbed | |
parent | 579b3aad051b9fcf858ea308f9d8f6714f84c7a8 (diff) | |
download | lcms2-078665ecf29b6a9ca31803e6ebd12f22f3da9961.tar.gz |
Merge from Artifex branchlcms2.6rc0
Diffstat (limited to 'testbed')
-rw-r--r-- | testbed/Makefile.am | 4 | ||||
-rw-r--r-- | testbed/Makefile.in | 9 | ||||
-rwxr-xr-x | testbed/ibm-t61.icc | bin | 0 -> 20480 bytes | |||
-rw-r--r-- | testbed/new.icc | bin | 0 -> 20480 bytes | |||
-rw-r--r-- | testbed/testcms2.c | 647 | ||||
-rwxr-xr-x | testbed/testcms2.h | 84 | ||||
-rwxr-xr-x | testbed/testplugin.c | 1476 | ||||
-rw-r--r-- | testbed/testthread.cpp | 148 | ||||
-rwxr-xr-x | testbed/zoo_icc.c | 310 |
9 files changed, 2306 insertions, 372 deletions
diff --git a/testbed/Makefile.am b/testbed/Makefile.am index 7961a42..371ded2 100644 --- a/testbed/Makefile.am +++ b/testbed/Makefile.am @@ -13,11 +13,11 @@ check_PROGRAMS = testcms testcms_LDADD = $(top_builddir)/src/liblcms2.la testcms_LDFLAGS = @LDFLAGS@ -testcms_SOURCES = testcms2.c +testcms_SOURCES = testcms2.c testplugin.c zoo_icc.c testcms2.h EXTRA_DIST = test1.icc bad.icc toosmall.icc test2.icc \ test3.icc test4.icc \ - test5.icc + test5.icc ibm-t61.icc new.icc check: if [ $(top_srcdir) != $(top_builddir) ]; then \ diff --git a/testbed/Makefile.in b/testbed/Makefile.in index 11723ec..8c0f64c 100644 --- a/testbed/Makefile.in +++ b/testbed/Makefile.in @@ -64,7 +64,8 @@ am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ mkinstalldirs = $(install_sh) -d CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = -am_testcms_OBJECTS = testcms2.$(OBJEXT) +am_testcms_OBJECTS = testcms2.$(OBJEXT) testplugin.$(OBJEXT) \ + zoo_icc.$(OBJEXT) testcms_OBJECTS = $(am_testcms_OBJECTS) testcms_DEPENDENCIES = $(top_builddir)/src/liblcms2.la testcms_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ @@ -233,10 +234,10 @@ INCLUDES = -I$(top_builddir)/include -I$(top_srcdir)/include -I$(top_srcdir)/src # CFLAGS = --pedantic -Wall -std=c99 -O2 testcms_LDADD = $(top_builddir)/src/liblcms2.la testcms_LDFLAGS = @LDFLAGS@ -testcms_SOURCES = testcms2.c +testcms_SOURCES = testcms2.c testplugin.c zoo_icc.c testcms2.h EXTRA_DIST = test1.icc bad.icc toosmall.icc test2.icc \ test3.icc test4.icc \ - test5.icc + test5.icc ibm-t61.icc new.icc all: all-am @@ -292,6 +293,8 @@ distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/testcms2.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/testplugin.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/zoo_icc.Po@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< diff --git a/testbed/ibm-t61.icc b/testbed/ibm-t61.icc Binary files differnew file mode 100755 index 0000000..497f2d8 --- /dev/null +++ b/testbed/ibm-t61.icc diff --git a/testbed/new.icc b/testbed/new.icc Binary files differnew file mode 100644 index 0000000..dd2f757 --- /dev/null +++ b/testbed/new.icc diff --git a/testbed/testcms2.c b/testbed/testcms2.c index 01deae2..f4e70bb 100644 --- a/testbed/testcms2.c +++ b/testbed/testcms2.c @@ -1,7 +1,7 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2010 Marti Maria Saguer +// Copyright (c) 1998-2014 Marti Maria Saguer // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the "Software"), @@ -24,11 +24,8 @@ //--------------------------------------------------------------------------------- // -#ifdef _MSC_VER -# define _CRT_SECURE_NO_WARNINGS 1 -#endif -#include "lcms2_internal.h" +#include "testcms2.h" // On Visual Studio, use debug CRT #ifdef _MSC_VER @@ -55,7 +52,6 @@ static cmsInt32Number SimultaneousErrors; #define cmsmin(a, b) (((a) < (b)) ? (a) : (b)) // Die, a fatal unexpected error is detected! -static void Die(const char* Reason) { printf("\n\nArrrgggg!!: %s!\n\n", Reason); @@ -75,6 +71,7 @@ static cmsUInt32Number SingleHit, MaxAllocated=0, TotalMemory=0; typedef struct { cmsUInt32Number KeepSize; cmsContext WhoAllocated; + cmsUInt32Number DontCheck; union { cmsUInt64Number HiSparc; @@ -100,7 +97,7 @@ cmsContext DbgThread(void) { static cmsUInt32Number n = 1; - return (cmsContext) n++; + return (cmsContext) (n++ % 0xff0); } // The allocate routine @@ -126,10 +123,12 @@ void* DebugMalloc(cmsContext ContextID, cmsUInt32Number size) blk ->KeepSize = size; blk ->WhoAllocated = ContextID; + blk ->DontCheck = 0; return (void*) ((cmsUInt8Number*) blk + SIZE_OF_MEM_HEADER); } + // The free routine static void DebugFree(cmsContext ContextID, void *Ptr) @@ -143,13 +142,14 @@ void DebugFree(cmsContext ContextID, void *Ptr) blk = (_cmsMemoryBlock*) (((cmsUInt8Number*) Ptr) - SIZE_OF_MEM_HEADER); TotalMemory -= blk ->KeepSize; - if (blk ->WhoAllocated != ContextID) { + if (blk ->WhoAllocated != ContextID && !blk->DontCheck) { Die("Trying to free memory allocated by a different thread"); } free(blk); } + // Reallocate, just a malloc, a copy and a free in this case. static void * DebugRealloc(cmsContext ContextID, void* Ptr, cmsUInt32Number NewSize) @@ -177,11 +177,68 @@ void DebugMemPrintTotals(void) printf("Allocated = %u MaxAlloc = %u Single block hit = %u\n", TotalMemory, MaxAllocated, SingleHit); } + +void DebugMemDontCheckThis(void *Ptr) +{ + _cmsMemoryBlock* blk = (_cmsMemoryBlock*) (((cmsUInt8Number*) Ptr) - SIZE_OF_MEM_HEADER); + + blk ->DontCheck = 1; +} + + +// Memory string +static +const char* MemStr(cmsUInt32Number size) +{ + static char Buffer[1024]; + + if (size > 1024*1024) { + sprintf(Buffer, "%g Mb", (cmsFloat64Number) size / (1024.0*1024.0)); + } + else + if (size > 1024) { + sprintf(Buffer, "%g Kb", (cmsFloat64Number) size / 1024.0); + } + else + sprintf(Buffer, "%g bytes", (cmsFloat64Number) size); + + return Buffer; +} + + +void TestMemoryLeaks(cmsBool ok) +{ + if (TotalMemory > 0) + printf("Ok, but %s are left!\n", MemStr(TotalMemory)); + else { + if (ok) printf("Ok.\n"); + } +} + // Here we go with the plug-in declaration -static cmsPluginMemHandler DebugMemHandler = {{ cmsPluginMagicNumber, 2000, cmsPluginMemHandlerSig, NULL }, +static cmsPluginMemHandler DebugMemHandler = {{ cmsPluginMagicNumber, 2060, cmsPluginMemHandlerSig, NULL }, DebugMalloc, DebugFree, DebugRealloc, NULL, NULL, NULL }; -// Utils ------------------------------------------------------------------------------------- +// Returnds a pointer to the memhandler plugin +void* PluginMemHandler(void) +{ + return (void*) &DebugMemHandler; +} + +cmsContext WatchDogContext(void* usr) +{ + cmsContext ctx; + + ctx = cmsCreateContext(&DebugMemHandler, usr); + + if (ctx == NULL) + Die("Unable to create memory managed context"); + + DebugMemDontCheckThis(ctx); + return ctx; +} + + static void FatalErrorQuit(cmsContext ContextID, cmsUInt32Number ErrorCode, const char *Text) @@ -190,18 +247,29 @@ void FatalErrorQuit(cmsContext ContextID, cmsUInt32Number ErrorCode, const char cmsUNUSED_PARAMETER(ContextID); cmsUNUSED_PARAMETER(ErrorCode); +} + +void ResetFatalError(void) +{ + cmsSetLogErrorHandler(FatalErrorQuit); } + // Print a dot for gauging -static void Dot(void) { fprintf(stdout, "."); fflush(stdout); } +void Say(const char* str) +{ + fprintf(stdout, "%s", str); fflush(stdout); +} + + // Keep track of the reason to fail -static + void Fail(const char* frm, ...) { va_list args; @@ -211,7 +279,7 @@ void Fail(const char* frm, ...) } // Keep track of subtest -static + void SubTest(const char* frm, ...) { va_list args; @@ -222,27 +290,6 @@ void SubTest(const char* frm, ...) va_end(args); } - -// Memory string -static -const char* MemStr(cmsUInt32Number size) -{ - static char Buffer[1024]; - - if (size > 1024*1024) { - sprintf(Buffer, "%g Mb", (cmsFloat64Number) size / (1024.0*1024.0)); - } - else - if (size > 1024) { - sprintf(Buffer, "%g Kb", (cmsFloat64Number) size / 1024.0); - } - else - sprintf(Buffer, "%g bytes", (cmsFloat64Number) size); - - return Buffer; -} - - // The check framework static void Check(const char* Title, TestFn Fn) @@ -259,10 +306,8 @@ void Check(const char* Title, TestFn Fn) if (Fn() && !TrappedError) { // It is a good place to check memory - if (TotalMemory > 0) - printf("Ok, but %s are left!\n", MemStr(TotalMemory)); - else - printf("Ok.\n"); + TestMemoryLeaks(TRUE); + } else { printf("FAIL!\n"); @@ -571,11 +616,8 @@ cmsInt32Number OneVirtual(cmsHPROFILE h, const char* SubTestTxt, const char* Fil h = cmsOpenProfileFromFile(FileName, "r"); if (h == NULL) return 0; - - // Do some teste.... - + cmsCloseProfile(h); - return 1; } @@ -744,7 +786,7 @@ cmsInt32Number CheckQuickFloor(void) (_cmsQuickFloor(-32767.1) != -32768)) { Fail("\nOOOPPSS! _cmsQuickFloor() does not work as expected in your machine!\n\n" - "Please, edit lcms.h and uncomment the CMS_DONT_USE_FAST_FLOOR toggle.\n"); + "Please, edit lcms2.h and uncomment the CMS_DONT_USE_FAST_FLOOR toggle.\n"); return 0; } @@ -763,7 +805,7 @@ cmsInt32Number CheckQuickFloorWord(void) if (_cmsQuickFloorWord((cmsFloat64Number) i + 0.1234) != i) { Fail("\nOOOPPSS! _cmsQuickFloorWord() does not work as expected in your machine!\n\n" - "Please, edit lcms.h and uncomment the CMS_DONT_USE_FAST_FLOOR toggle.\n"); + "Please, edit lcms2.h and uncomment the CMS_DONT_USE_FAST_FLOOR toggle.\n"); return 0; } } @@ -787,7 +829,6 @@ cmsInt32Number CheckQuickFloorWord(void) static cmsFloat64Number MaxErr; static cmsFloat64Number AllowedErr = FIXED_PRECISION_15_16; -static cmsBool IsGoodVal(const char *title, cmsFloat64Number in, cmsFloat64Number out, cmsFloat64Number max) { cmsFloat64Number Err = fabs(in - out); @@ -803,19 +844,18 @@ cmsBool IsGoodVal(const char *title, cmsFloat64Number in, cmsFloat64Number out, return TRUE; } -static + cmsBool IsGoodFixed15_16(const char *title, cmsFloat64Number in, cmsFloat64Number out) { return IsGoodVal(title, in, out, FIXED_PRECISION_15_16); } -static + cmsBool IsGoodFixed8_8(const char *title, cmsFloat64Number in, cmsFloat64Number out) { return IsGoodVal(title, in, out, FIXED_PRECISION_8_8); } -static cmsBool IsGoodWord(const char *title, cmsUInt16Number in, cmsUInt16Number out) { if ((abs(in - out) > 0 )) { @@ -827,7 +867,6 @@ cmsBool IsGoodWord(const char *title, cmsUInt16Number in, cmsUInt16Number out) return TRUE; } -static cmsBool IsGoodWordPrec(const char *title, cmsUInt16Number in, cmsUInt16Number out, cmsUInt16Number maxErr) { if ((abs(in - out) > maxErr )) { @@ -891,6 +930,59 @@ cmsInt32Number CheckFixedPoint8_8(void) return 1; } +// D50 constant -------------------------------------------------------------------------------------------- + +static +cmsInt32Number CheckD50Roundtrip(void) +{ + cmsFloat64Number cmsD50X_2 = 0.96420288; + cmsFloat64Number cmsD50Y_2 = 1.0; + cmsFloat64Number cmsD50Z_2 = 0.82490540; + + cmsS15Fixed16Number xe = _cmsDoubleTo15Fixed16(cmsD50X); + cmsS15Fixed16Number ye = _cmsDoubleTo15Fixed16(cmsD50Y); + cmsS15Fixed16Number ze = _cmsDoubleTo15Fixed16(cmsD50Z); + + cmsFloat64Number x = _cms15Fixed16toDouble(xe); + cmsFloat64Number y = _cms15Fixed16toDouble(ye); + cmsFloat64Number z = _cms15Fixed16toDouble(ze); + + double dx = fabs(cmsD50X - x); + double dy = fabs(cmsD50Y - y); + double dz = fabs(cmsD50Z - z); + + double euc = sqrt(dx*dx + dy*dy + dz* dz); + + if (euc > 1E-5) { + + Fail("D50 roundtrip |err| > (%f) ", euc); + return 0; + } + + xe = _cmsDoubleTo15Fixed16(cmsD50X_2); + ye = _cmsDoubleTo15Fixed16(cmsD50Y_2); + ze = _cmsDoubleTo15Fixed16(cmsD50Z_2); + + x = _cms15Fixed16toDouble(xe); + y = _cms15Fixed16toDouble(ye); + z = _cms15Fixed16toDouble(ze); + + dx = fabs(cmsD50X_2 - x); + dy = fabs(cmsD50Y_2 - y); + dz = fabs(cmsD50Z_2 - z); + + euc = sqrt(dx*dx + dy*dy + dz* dz); + + if (euc > 1E-5) { + + Fail("D50 roundtrip |err| > (%f) ", euc); + return 0; + } + + + return 1; +} + // Linear interpolation ----------------------------------------------------------------------------------------------- // Since prime factors of 65535 (FFFF) are, @@ -3664,7 +3756,7 @@ Error: static cmsBool FormatterFailed; static -void CheckSingleFormatter16(cmsUInt32Number Type, const char* Text) +void CheckSingleFormatter16(cmsContext id, cmsUInt32Number Type, const char* Text) { cmsUInt16Number Values[cmsMAXCHANNELS]; cmsUInt8Number Buffer[1024]; @@ -3679,16 +3771,16 @@ void CheckSingleFormatter16(cmsUInt32Number Type, const char* Text) info.OutputFormat = info.InputFormat = Type; // Go forth and back - f = _cmsGetFormatter(Type, cmsFormatterInput, CMS_PACK_FLAGS_16BITS); - b = _cmsGetFormatter(Type, cmsFormatterOutput, CMS_PACK_FLAGS_16BITS); + f = _cmsGetFormatter(id, Type, cmsFormatterInput, CMS_PACK_FLAGS_16BITS); + b = _cmsGetFormatter(id, Type, cmsFormatterOutput, CMS_PACK_FLAGS_16BITS); if (f.Fmt16 == NULL || b.Fmt16 == NULL) { Fail("no formatter for %s", Text); FormatterFailed = TRUE; // Useful for debug - f = _cmsGetFormatter(Type, cmsFormatterInput, CMS_PACK_FLAGS_16BITS); - b = _cmsGetFormatter(Type, cmsFormatterOutput, CMS_PACK_FLAGS_16BITS); + f = _cmsGetFormatter(id, Type, cmsFormatterInput, CMS_PACK_FLAGS_16BITS); + b = _cmsGetFormatter(id, Type, cmsFormatterOutput, CMS_PACK_FLAGS_16BITS); return; } @@ -3733,7 +3825,7 @@ void CheckSingleFormatter16(cmsUInt32Number Type, const char* Text) } } -#define C(a) CheckSingleFormatter16(a, #a) +#define C(a) CheckSingleFormatter16(0, a, #a) // Check all formatters @@ -3931,16 +4023,16 @@ void CheckSingleFormatterFloat(cmsUInt32Number Type, const char* Text) info.OutputFormat = info.InputFormat = Type; // Go forth and back - f = _cmsGetFormatter(Type, cmsFormatterInput, CMS_PACK_FLAGS_FLOAT); - b = _cmsGetFormatter(Type, cmsFormatterOutput, CMS_PACK_FLAGS_FLOAT); + f = _cmsGetFormatter(0, Type, cmsFormatterInput, CMS_PACK_FLAGS_FLOAT); + b = _cmsGetFormatter(0, Type, cmsFormatterOutput, CMS_PACK_FLAGS_FLOAT); if (f.FmtFloat == NULL || b.FmtFloat == NULL) { Fail("no formatter for %s", Text); FormatterFailed = TRUE; // Useful for debug - f = _cmsGetFormatter(Type, cmsFormatterInput, CMS_PACK_FLAGS_FLOAT); - b = _cmsGetFormatter(Type, cmsFormatterOutput, CMS_PACK_FLAGS_FLOAT); + f = _cmsGetFormatter(0, Type, cmsFormatterInput, CMS_PACK_FLAGS_FLOAT); + b = _cmsGetFormatter(0, Type, cmsFormatterOutput, CMS_PACK_FLAGS_FLOAT); return; } @@ -4017,8 +4109,10 @@ cmsInt32Number CheckFormattersFloat(void) C( TYPE_BGRA_HALF_FLT ); C( TYPE_ABGR_HALF_FLT ); + C( TYPE_XYZ_FLT ); + - return FormatterFailed == 0 ? 1 : 0; + return FormatterFailed == 0 ? 1 : 0; } #undef C @@ -5215,7 +5309,6 @@ cmsInt32Number CheckProfileCreation(void) SubTest("Tags holding ICC viewing conditions"); if (!CheckICCViewingConditions(Pass, h)) return 0; - SubTest("VCGT tags"); if (!CheckVCGT(Pass, h)) return 0; @@ -5249,6 +5342,44 @@ cmsInt32Number CheckProfileCreation(void) } +// Thanks to Christopher James Halse Rogers for the bugfixing and providing this test +static +cmsInt32Number CheckVersionHeaderWriting(void) +{ + cmsHPROFILE h; + int index; + float test_versions[] = { + 2.3f, + 4.08f, + 4.09f, + 4.3f + }; + + for (index = 0; index < sizeof(test_versions)/sizeof(test_versions[0]); index++) { + + h = cmsCreateProfilePlaceholder(DbgThread()); + if (h == NULL) return 0; + + cmsSetProfileVersion(h, test_versions[index]); + + cmsSaveProfileToFile(h, "versions.icc"); + cmsCloseProfile(h); + + h = cmsOpenProfileFromFileTHR(DbgThread(), "versions.icc", "r"); + + // Only the first 3 digits are significant + if (fabs(cmsGetProfileVersion(h) - test_versions[index]) > 0.005) { + Fail("Version failed to round-trip: wrote %.2f, read %.2f", + test_versions[index], cmsGetProfileVersion(h)); + return 0; + } + + cmsCloseProfile(h); + remove("versions.icc"); + } + return 1; +} + // Error reporting ------------------------------------------------------------------------------------------------------- @@ -6448,7 +6579,7 @@ cmsInt32Number CheckGamutCheck(void) SubTest("Gamut check on 16 bits"); - xform = cmsCreateProofingTransformTHR(DbgThread(), hAbove, TYPE_RGB_16, hAbove, TYPE_RGB_16, hAbove, + xform = cmsCreateProofingTransformTHR(DbgThread(), hAbove, TYPE_RGB_16, hAbove, TYPE_RGB_16, hSRGB, INTENT_RELATIVE_COLORIMETRIC, INTENT_RELATIVE_COLORIMETRIC, cmsFLAGS_GAMUTCHECK); cmsCloseProfile(hSRGB); @@ -7484,6 +7615,84 @@ cmsInt32Number CheckReadRAW(void) } +static +cmsInt32Number CheckMeta(void) +{ + char *data; + cmsHANDLE dict; + cmsHPROFILE p; + cmsUInt32Number clen; + FILE *fp; + int rc; + + /* open file */ + p = cmsOpenProfileFromFile("ibm-t61.icc", "r"); + if (p == NULL) return 0; + + /* read dictionary, but don't do anything with the value */ + //COMMENT OUT THE NEXT TWO LINES AND IT WORKS FINE!!! + dict = cmsReadTag(p, cmsSigMetaTag); + if (dict == NULL) return 0; + + /* serialize profile to memory */ + rc = cmsSaveProfileToMem(p, NULL, &clen); + if (!rc) return 0; + + data = (char*) malloc(clen); + rc = cmsSaveProfileToMem(p, data, &clen); + if (!rc) return 0; + + /* write the memory blob to a file */ + //NOTE: The crash does not happen if cmsSaveProfileToFile() is used */ + fp = fopen("new.icc", "wb"); + fwrite(data, 1, clen, fp); + fclose(fp); + free(data); + + cmsCloseProfile(p); + + /* open newly created file and read metadata */ + p = cmsOpenProfileFromFile("new.icc", "r"); + //ERROR: Bad dictionary Name/Value + //ERROR: Corrupted tag 'meta' + //test: test.c:59: main: Assertion `dict' failed. + dict = cmsReadTag(p, cmsSigMetaTag); + if (dict == NULL) return 0; + + cmsCloseProfile(p); + return 1; +} + + +// Bug on applying null transforms on floating point buffers +static +cmsInt32Number CheckFloatNULLxform(void) +{ + int i; + cmsFloat32Number in[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + cmsFloat32Number out[10]; + + cmsHTRANSFORM xform = cmsCreateTransform(NULL, TYPE_GRAY_FLT, NULL, TYPE_GRAY_FLT, INTENT_PERCEPTUAL, cmsFLAGS_NULLTRANSFORM); + + if (xform == NULL) { + Fail("Unable to create float null transform"); + return 0; + } + + cmsDoTransform(xform, in, out, 10); + + cmsDeleteTransform(xform); + for (i=0; i < 10; i++) { + + if (!IsGoodVal("float nullxform", in[i], out[i], 0.001)) { + + return 0; + } + } + + return 1; +} + // -------------------------------------------------------------------------------------------------- // P E R F O R M A N C E C H E C K S @@ -7513,6 +7722,9 @@ void PrintPerformance(cmsUInt32Number Bytes, cmsUInt32Number SizeOfPixel, cmsFlo } + + + static void SpeedTest16bits(const char * Title, cmsHPROFILE hlcmsProfileIn, cmsHPROFILE hlcmsProfileOut, cmsInt32Number Intent) { @@ -7880,271 +8092,23 @@ void PrintSupportedIntents(void) printf("\n"); } -// ZOO checks ------------------------------------------------------------------------------------------------------------ - - -#ifdef CMS_IS_WINDOWS_ - -static char ZOOfolder[cmsMAX_PATH] = "c:\\colormaps\\"; -static char ZOOwrite[cmsMAX_PATH] = "c:\\colormaps\\write\\"; -static char ZOORawWrite[cmsMAX_PATH] = "c:\\colormaps\\rawwrite\\"; - - -// Read all tags on a profile given by its handle -static -void ReadAllTags(cmsHPROFILE h) -{ - cmsInt32Number i, n; - cmsTagSignature sig; - - n = cmsGetTagCount(h); - for (i=0; i < n; i++) { - - sig = cmsGetTagSignature(h, i); - if (cmsReadTag(h, sig) == NULL) return; - } -} - - -// Read all tags on a profile given by its handle -static -void ReadAllRAWTags(cmsHPROFILE h) -{ - cmsInt32Number i, n; - cmsTagSignature sig; - cmsInt32Number len; - - n = cmsGetTagCount(h); - for (i=0; i < n; i++) { - - sig = cmsGetTagSignature(h, i); - len = cmsReadRawTag(h, sig, NULL, 0); - } -} - - -static -void PrintInfo(cmsHPROFILE h, cmsInfoType Info) -{ - wchar_t* text; - cmsInt32Number len; - cmsContext id = DbgThread(); - - len = cmsGetProfileInfo(h, Info, "en", "US", NULL, 0); - if (len == 0) return; - - text = _cmsMalloc(id, len); - cmsGetProfileInfo(h, Info, "en", "US", text, len); - - wprintf(L"%s\n", text); - _cmsFree(id, text); -} - - -static -void PrintAllInfos(cmsHPROFILE h) -{ - PrintInfo(h, cmsInfoDescription); - PrintInfo(h, cmsInfoManufacturer); - PrintInfo(h, cmsInfoModel); - PrintInfo(h, cmsInfoCopyright); - printf("\n\n"); -} - -static -void ReadAllLUTS(cmsHPROFILE h) -{ - cmsPipeline* a; - cmsCIEXYZ Black; - - a = _cmsReadInputLUT(h, INTENT_PERCEPTUAL); - if (a) cmsPipelineFree(a); - - a = _cmsReadInputLUT(h, INTENT_RELATIVE_COLORIMETRIC); - if (a) cmsPipelineFree(a); - - a = _cmsReadInputLUT(h, INTENT_SATURATION); - if (a) cmsPipelineFree(a); - - a = _cmsReadInputLUT(h, INTENT_ABSOLUTE_COLORIMETRIC); - if (a) cmsPipelineFree(a); - - - a = _cmsReadOutputLUT(h, INTENT_PERCEPTUAL); - if (a) cmsPipelineFree(a); - - a = _cmsReadOutputLUT(h, INTENT_RELATIVE_COLORIMETRIC); - if (a) cmsPipelineFree(a); - - a = _cmsReadOutputLUT(h, INTENT_SATURATION); - if (a) cmsPipelineFree(a); - - a = _cmsReadOutputLUT(h, INTENT_ABSOLUTE_COLORIMETRIC); - if (a) cmsPipelineFree(a); - - - a = _cmsReadDevicelinkLUT(h, INTENT_PERCEPTUAL); - if (a) cmsPipelineFree(a); - - a = _cmsReadDevicelinkLUT(h, INTENT_RELATIVE_COLORIMETRIC); - if (a) cmsPipelineFree(a); - - a = _cmsReadDevicelinkLUT(h, INTENT_SATURATION); - if (a) cmsPipelineFree(a); - - a = _cmsReadDevicelinkLUT(h, INTENT_ABSOLUTE_COLORIMETRIC); - if (a) cmsPipelineFree(a); - - - cmsDetectDestinationBlackPoint(&Black, h, INTENT_PERCEPTUAL, 0); - cmsDetectDestinationBlackPoint(&Black, h, INTENT_RELATIVE_COLORIMETRIC, 0); - cmsDetectDestinationBlackPoint(&Black, h, INTENT_SATURATION, 0); - cmsDetectDestinationBlackPoint(&Black, h, INTENT_ABSOLUTE_COLORIMETRIC, 0); - cmsDetectTAC(h); -} - -// Check one specimen in the ZOO - -static -cmsInt32Number CheckSingleSpecimen(const char* Profile) -{ - char BuffSrc[256]; - char BuffDst[256]; - cmsHPROFILE h; - - sprintf(BuffSrc, "%s%s", ZOOfolder, Profile); - sprintf(BuffDst, "%s%s", ZOOwrite, Profile); - - h = cmsOpenProfileFromFile(BuffSrc, "r"); - if (h == NULL) return 0; - - printf("%s\n", Profile); - PrintAllInfos(h); - ReadAllTags(h); - // ReadAllRAWTags(h); - ReadAllLUTS(h); - - cmsSaveProfileToFile(h, BuffDst); - cmsCloseProfile(h); - - h = cmsOpenProfileFromFile(BuffDst, "r"); - if (h == NULL) return 0; - ReadAllTags(h); - - - cmsCloseProfile(h); - - return 1; -} - -static -cmsInt32Number CheckRAWSpecimen(const char* Profile) -{ - char BuffSrc[256]; - char BuffDst[256]; - cmsHPROFILE h; - - sprintf(BuffSrc, "%s%s", ZOOfolder, Profile); - sprintf(BuffDst, "%s%s", ZOORawWrite, Profile); - - h = cmsOpenProfileFromFile(BuffSrc, "r"); - if (h == NULL) return 0; - - ReadAllTags(h); - ReadAllRAWTags(h); - cmsSaveProfileToFile(h, BuffDst); - cmsCloseProfile(h); - - h = cmsOpenProfileFromFile(BuffDst, "r"); - if (h == NULL) return 0; - ReadAllTags(h); - cmsCloseProfile(h); - - return 1; -} - - -static -void CheckProfileZOO(void) -{ - - struct _finddata_t c_file; - intptr_t hFile; - - cmsSetLogErrorHandler(NULL); - - if ( (hFile = _findfirst("c:\\colormaps\\*.*", &c_file)) == -1L ) - printf("No files in current directory"); - else - { - do - { - - printf("%s\n", c_file.name); - if (strcmp(c_file.name, ".") != 0 && - strcmp(c_file.name, "..") != 0) { - - CheckSingleSpecimen( c_file.name); - CheckRAWSpecimen( c_file.name); - - if (TotalMemory > 0) - printf("Ok, but %s are left!\n", MemStr(TotalMemory)); - else - printf("Ok.\n"); - - } - - } while ( _findnext(hFile, &c_file) == 0 ); - - _findclose(hFile); - } - - cmsSetLogErrorHandler(FatalErrorQuit); -} - -#endif - - -#if 0 -#define TYPE_709 709 -static double Rec709Math(int Type, const double Params[], double R) -{ double Fun; - -switch (Type) -{ -case 709: - -if (R <= (Params[3]*Params[4])) Fun = R / Params[3]; -else Fun = pow(((R - Params[2])/Params[1]), Params[0]); -break; -case -709: -if (R <= Params[4]) Fun = R * Params[3]; -else Fun = Params[1] * pow(R, (1/Params[0])) + Params[2]; -break; -} -return Fun; -} +// --------------------------------------------------------------------------------------- -// Add nonstandard TRC curves -> Rec709 -cmsPluginParametricCurves NewCurvePlugin = { -{ cmsPluginMagicNumber, 2000, cmsPluginParametricCurveSig, NULL }, -1, {TYPE_709}, {5}, Rec709Math}; +#ifdef LCMS_FAST_EXTENSIONS + void* cmsFast8Bitextensions(void); #endif - - - -// --------------------------------------------------------------------------------------- - int main(int argc, char* argv[]) { cmsInt32Number Exhaustive = 0; cmsInt32Number DoSpeedTests = 1; cmsInt32Number DoCheckTests = 1; + cmsInt32Number DoPluginTests = 1; + cmsInt32Number DoZooTests = 0; #ifdef _MSC_VER _CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF ); @@ -8158,6 +8122,12 @@ int main(int argc, char* argv[]) printf("Running exhaustive tests (will take a while...)\n\n"); } +#ifdef LCMS_FAST_EXTENSIONS + printf("Installing fast 8 bit extension ..."); + cmsPlugin(cmsFast8Bitextensions()); + printf("done.\n"); +#endif + printf("Installing debug memory plug-in ... "); cmsPlugin(&DebugMemHandler); printf("done.\n"); @@ -8166,26 +8136,23 @@ int main(int argc, char* argv[]) cmsSetLogErrorHandler(FatalErrorQuit); printf("done.\n"); -#ifdef CMS_IS_WINDOWS_ - // CheckProfileZOO(); -#endif PrintSupportedIntents(); - - - // Create utility profiles - Check("Creation of test profiles", CreateTestProfiles); - - if (DoCheckTests) - { Check("Base types", CheckBaseTypes); Check("endianess", CheckEndianess); Check("quick floor", CheckQuickFloor); Check("quick floor word", CheckQuickFloorWord); Check("Fixed point 15.16 representation", CheckFixedPoint15_16); Check("Fixed point 8.8 representation", CheckFixedPoint8_8); + Check("D50 roundtrip", CheckD50Roundtrip); + + // Create utility profiles + if (DoCheckTests || DoSpeedTests) + Check("Creation of test profiles", CreateTestProfiles); + if (DoCheckTests) { + // Forward 1D interpolation Check("1D interpolation in 2pt tables", Check1DLERP2); Check("1D interpolation in 3pt tables", Check1DLERP3); @@ -8303,7 +8270,7 @@ int main(int argc, char* argv[]) // Profile I/O (this one is huge!) Check("Profile creation", CheckProfileCreation); - + Check("Header version", CheckVersionHeaderWriting); // Error reporting Check("Error reporting on bad profiles", CheckErrReportingOnBadProfiles); @@ -8358,18 +8325,44 @@ int main(int argc, char* argv[]) Check("Floating Point sampled curve with non-zero start", CheckFloatSamples); Check("Floating Point segmented curve with short sampled segement", CheckFloatSegments); Check("Read RAW portions", CheckReadRAW); + Check("Check MetaTag", CheckMeta); + Check("Null transform on floats", CheckFloatNULLxform); + } + + if (DoPluginTests) + { +#ifndef CMS_CONTEXT_IN_LEGACY_MODE + Check("Context memory handling", CheckAllocContext); + Check("Simple context functionality", CheckSimpleContext); + Check("Alarm codes context", CheckAlarmColorsContext); + Check("Adaptation state context", CheckAdaptationStateContext); + Check("1D interpolation plugin", CheckInterp1DPlugin); + Check("3D interpolation plugin", CheckInterp3DPlugin); + Check("Parametric curve plugin", CheckParametricCurvePlugin); + Check("Formatters plugin", CheckFormattersPlugin); + Check("Tag type plugin", CheckTagTypePlugin); + Check("MPE type plugin", CheckMPEPlugin); + Check("Optimization plugin", CheckOptimizationPlugin); + Check("Rendering intent plugin", CheckIntentPlugin); + Check("Full transform plugin", CheckTransformPlugin); + Check("Mutex plugin", CheckMutexPlugin); +#endif } if (DoSpeedTests) SpeedTest(); + if (DoZooTests) + CheckProfileZOO(); + DebugMemPrintTotals(); cmsUnregisterPlugins(); // Cleanup - RemoveTestProfiles(); + if (DoCheckTests || DoSpeedTests) + RemoveTestProfiles(); return TotalFail; } diff --git a/testbed/testcms2.h b/testbed/testcms2.h new file mode 100755 index 0000000..a1a69fe --- /dev/null +++ b/testbed/testcms2.h @@ -0,0 +1,84 @@ +//--------------------------------------------------------------------------------- +// +// Little Color Management System +// Copyright (c) 1998-2014 Marti Maria Saguer +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the Software +// is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +//--------------------------------------------------------------------------------- +// + +#ifndef TESTCMS2_H +#define TESTCMS2_H + +#ifdef _MSC_VER +# define _CRT_SECURE_NO_WARNINGS 1 +# include "crtdbg.h" +# include <io.h> +#endif + +#include "lcms2_internal.h" + +#define cmsmin(a, b) (((a) < (b)) ? (a) : (b)) + +// Used to mark special pointers +void DebugMemDontCheckThis(void *Ptr); + + +cmsBool IsGoodVal(const char *title, cmsFloat64Number in, cmsFloat64Number out, cmsFloat64Number max); +cmsBool IsGoodFixed15_16(const char *title, cmsFloat64Number in, cmsFloat64Number out); +cmsBool IsGoodFixed8_8(const char *title, cmsFloat64Number in, cmsFloat64Number out); +cmsBool IsGoodWord(const char *title, cmsUInt16Number in, cmsUInt16Number out); +cmsBool IsGoodWordPrec(const char *title, cmsUInt16Number in, cmsUInt16Number out, cmsUInt16Number maxErr); + +void* PluginMemHandler(void); +cmsContext WatchDogContext(void* usr); + +void ResetFatalError(void); +void Die(const char* Reason); +void Dot(void); +void Fail(const char* frm, ...); +void SubTest(const char* frm, ...); +void TestMemoryLeaks(cmsBool ok); +void Say(const char* str); + +// Plug-in tests +cmsInt32Number CheckSimpleContext(void); +cmsInt32Number CheckAllocContext(void); +cmsInt32Number CheckAlarmColorsContext(void); +cmsInt32Number CheckAdaptationStateContext(void); +cmsInt32Number CheckInterp1DPlugin(void); +cmsInt32Number CheckInterp3DPlugin(void); +cmsInt32Number CheckParametricCurvePlugin(void); +cmsInt32Number CheckFormattersPlugin(void); +cmsInt32Number CheckTagTypePlugin(void); +cmsInt32Number CheckMPEPlugin(void); +cmsInt32Number CheckOptimizationPlugin(void); +cmsInt32Number CheckIntentPlugin(void); +cmsInt32Number CheckTransformPlugin(void); +cmsInt32Number CheckMutexPlugin(void); + + +cmsInt32Number CheckOptimizationPluginLeak(void); + +// Zoo +void CheckProfileZOO(void); + +#endif + diff --git a/testbed/testplugin.c b/testbed/testplugin.c new file mode 100755 index 0000000..1ba00bc --- /dev/null +++ b/testbed/testplugin.c @@ -0,0 +1,1476 @@ +//--------------------------------------------------------------------------------- +// +// Little Color Management System +// Copyright (c) 1998-2014 Marti Maria Saguer +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the Software +// is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +//--------------------------------------------------------------------------------- +// + +#include "testcms2.h" + +// -------------------------------------------------------------------------------------------------- +// Auxiliar, duplicate a context and mark the block as non-debug because in this case the allocator +// and deallocator have different context owners +// -------------------------------------------------------------------------------------------------- + +static +cmsContext DupContext(cmsContext src, void* Data) +{ + cmsContext cpy = cmsDupContext(src, Data); + + DebugMemDontCheckThis(cpy); + + return cpy; +} + +// -------------------------------------------------------------------------------------------------- +// Simple context functions +// -------------------------------------------------------------------------------------------------- + +// Allocation order +cmsInt32Number CheckAllocContext(void) +{ + cmsContext c1, c2, c3, c4; + + + c1 = cmsCreateContext(NULL, NULL); // This creates a context by using the normal malloc + DebugMemDontCheckThis(c1); + cmsDeleteContext(c1); + + c2 = cmsCreateContext(PluginMemHandler(), NULL); // This creates a context by using the debug malloc + DebugMemDontCheckThis(c2); + cmsDeleteContext(c2); + + c1 = cmsCreateContext(NULL, NULL); + DebugMemDontCheckThis(c1); + + c2 = cmsCreateContext(PluginMemHandler(), NULL); + DebugMemDontCheckThis(c2); + + cmsPluginTHR(c1, PluginMemHandler()); // Now the context have custom allocators + + c3 = DupContext(c1, NULL); + c4 = DupContext(c2, NULL); + + + + cmsDeleteContext(c1); // Should be deleted by using nomal malloc + cmsDeleteContext(c2); // Should be deleted by using debug malloc + cmsDeleteContext(c3); // Should be deleted by using nomal malloc + cmsDeleteContext(c4); // Should be deleted by using debug malloc + + return 1; +} + +// Test the very basic context capabilities +cmsInt32Number CheckSimpleContext(void) +{ + int a = 1; + int b = 32; + cmsInt32Number rc = 0; + + cmsContext c1, c2, c3; + + // This function creates a context with a special + // memory manager that check allocation + c1 = WatchDogContext(&a); + cmsDeleteContext(c1); + + c1 = WatchDogContext(&a); + + // Let's check duplication + c2 = DupContext(c1, NULL); + c3 = DupContext(c2, NULL); + + // User data should have been propagated + rc = (*(int*) cmsGetContextUserData(c3)) == 1 ; + + // Free resources + cmsDeleteContext(c1); + cmsDeleteContext(c2); + cmsDeleteContext(c3); + + if (!rc) { + Fail("Creation of user data failed"); + return 0; + } + + // Back to create 3 levels of inherance + c1 = cmsCreateContext(NULL, &a); + DebugMemDontCheckThis(c1); + + c2 = DupContext(c1, NULL); + c3 = DupContext(c2, &b); + + rc = (*(int*) cmsGetContextUserData(c3)) == 32 ; + + cmsDeleteContext(c1); + cmsDeleteContext(c2); + cmsDeleteContext(c3); + + if (!rc) { + Fail("Modification of user data failed"); + return 0; + } + + // All seems ok + return rc; +} + + + + +// -------------------------------------------------------------------------------------------------- +//Alarm color functions +// -------------------------------------------------------------------------------------------------- + +// This function tests the alarm codes across contexts +cmsInt32Number CheckAlarmColorsContext(void) +{ + cmsInt32Number rc = 0; + const cmsUInt16Number codes[] = {0x0000, 0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0x6666, 0x7777, 0x8888, 0x9999, 0xaaaa, 0xbbbb, 0xcccc, 0xdddd, 0xeeee, 0xffff}; + cmsUInt16Number out[16]; + cmsContext c1, c2, c3; + int i; + + c1 = WatchDogContext(NULL); + + cmsSetAlarmCodesTHR(c1, codes); + c2 = DupContext(c1, NULL); + c3 = DupContext(c2, NULL); + + cmsGetAlarmCodesTHR(c3, out); + + rc = 1; + for (i=0; i < 16; i++) { + if (out[i] != codes[i]) { + Fail("Bad alarm code %x != %x", out[i], codes[i]); + rc = 0; + break; + } + } + + cmsDeleteContext(c1); + cmsDeleteContext(c2); + cmsDeleteContext(c3); + + return rc; +} + + +// -------------------------------------------------------------------------------------------------- +//Adaptation state functions +// -------------------------------------------------------------------------------------------------- + +// Similar to the previous, but for adaptation state +cmsInt32Number CheckAdaptationStateContext(void) +{ + cmsInt32Number rc = 0; + cmsContext c1, c2, c3; + cmsFloat64Number old1, old2; + + old1 = cmsSetAdaptationStateTHR(NULL, -1); + + c1 = WatchDogContext(NULL); + + cmsSetAdaptationStateTHR(c1, 0.7); + + c2 = DupContext(c1, NULL); + c3 = DupContext(c2, NULL); + + rc = IsGoodVal("Adaptation state", cmsSetAdaptationStateTHR(c3, -1), 0.7, 0.001); + + cmsDeleteContext(c1); + cmsDeleteContext(c2); + cmsDeleteContext(c3); + + old2 = cmsSetAdaptationStateTHR(NULL, -1); + + if (old1 != old2) { + Fail("Adaptation state has changed"); + return 0; + } + + return rc; +} + +// -------------------------------------------------------------------------------------------------- +// Interpolation plugin check: A fake 1D and 3D interpolation will be used to test the functionality. +// -------------------------------------------------------------------------------------------------- + +// This fake interpolation takes always the closest lower node in the interpolation table for 1D +static +void Fake1Dfloat(const cmsFloat32Number Value[], + cmsFloat32Number Output[], + const cmsInterpParams* p) +{ + cmsFloat32Number val2; + int cell; + const cmsFloat32Number* LutTable = (const cmsFloat32Number*) p ->Table; + + // Clip upper values + if (Value[0] >= 1.0) { + Output[0] = LutTable[p -> Domain[0]]; + return; + } + + val2 = p -> Domain[0] * Value[0]; + cell = (int) floor(val2); + Output[0] = LutTable[cell] ; +} + +// This fake interpolation just uses scrambled negated indexes for output +static +void Fake3D16(register const cmsUInt16Number Input[], + register cmsUInt16Number Output[], + register const struct _cms_interp_struc* p) +{ + Output[0] = 0xFFFF - Input[2]; + Output[1] = 0xFFFF - Input[1]; + Output[2] = 0xFFFF - Input[0]; +} + +// The factory chooses interpolation routines on depending on certain conditions. +cmsInterpFunction my_Interpolators_Factory(cmsUInt32Number nInputChannels, + cmsUInt32Number nOutputChannels, + cmsUInt32Number dwFlags) +{ + cmsInterpFunction Interpolation; + cmsBool IsFloat = (dwFlags & CMS_LERP_FLAGS_FLOAT); + + // Initialize the return to zero as a non-supported mark + memset(&Interpolation, 0, sizeof(Interpolation)); + + // For 1D to 1D and floating point + if (nInputChannels == 1 && nOutputChannels == 1 && IsFloat) { + + Interpolation.LerpFloat = Fake1Dfloat; + } + else + if (nInputChannels == 3 && nOutputChannels == 3 && !IsFloat) { + + // For 3D to 3D and 16 bits + Interpolation.Lerp16 = Fake3D16; + } + + // Here is the interpolation + return Interpolation; +} + +// Interpolation plug-in +static +cmsPluginInterpolation InterpPluginSample = { + + { cmsPluginMagicNumber, 2060, cmsPluginInterpolationSig, NULL }, + my_Interpolators_Factory +}; + + +// This is the check code for 1D interpolation plug-in +cmsInt32Number CheckInterp1DPlugin(void) +{ + cmsToneCurve* Sampled1D = NULL; + cmsContext ctx = NULL; + cmsContext cpy = NULL; + const cmsFloat32Number tab[] = { 0.0f, 0.10f, 0.20f, 0.30f, 0.40f, 0.50f, 0.60f, 0.70f, 0.80f, 0.90f, 1.00f }; // A straight line + + // 1st level context + ctx = WatchDogContext(NULL); + if (ctx == NULL) { + Fail("Cannot create context"); + goto Error; + } + + cmsPluginTHR(ctx, &InterpPluginSample); + + cpy = DupContext(ctx, NULL); + if (cpy == NULL) { + Fail("Cannot create context (2)"); + goto Error; + } + + Sampled1D = cmsBuildTabulatedToneCurveFloat(cpy, 11, tab); + if (Sampled1D == NULL) { + Fail("Cannot create tone curve (1)"); + goto Error; + } + + // Do some interpolations with the plugin + if (!IsGoodVal("0.10", cmsEvalToneCurveFloat(Sampled1D, 0.10f), 0.10, 0.01)) goto Error; + if (!IsGoodVal("0.13", cmsEvalToneCurveFloat(Sampled1D, 0.13f), 0.10, 0.01)) goto Error; + if (!IsGoodVal("0.55", cmsEvalToneCurveFloat(Sampled1D, 0.55f), 0.50, 0.01)) goto Error; + if (!IsGoodVal("0.9999", cmsEvalToneCurveFloat(Sampled1D, 0.9999f), 0.90, 0.01)) goto Error; + + cmsFreeToneCurve(Sampled1D); + cmsDeleteContext(ctx); + cmsDeleteContext(cpy); + + // Now in global context + Sampled1D = cmsBuildTabulatedToneCurveFloat(NULL, 11, tab); + if (Sampled1D == NULL) { + Fail("Cannot create tone curve (2)"); + goto Error; + } + + // Now without the plug-in + if (!IsGoodVal("0.10", cmsEvalToneCurveFloat(Sampled1D, 0.10f), 0.10, 0.001)) goto Error; + if (!IsGoodVal("0.13", cmsEvalToneCurveFloat(Sampled1D, 0.13f), 0.13, 0.001)) goto Error; + if (!IsGoodVal("0.55", cmsEvalToneCurveFloat(Sampled1D, 0.55f), 0.55, 0.001)) goto Error; + if (!IsGoodVal("0.9999", cmsEvalToneCurveFloat(Sampled1D, 0.9999f), 0.9999, 0.001)) goto Error; + + cmsFreeToneCurve(Sampled1D); + return 1; + +Error: + if (ctx != NULL) cmsDeleteContext(ctx); + if (cpy != NULL) cmsDeleteContext(ctx); + if (Sampled1D != NULL) cmsFreeToneCurve(Sampled1D); + return 0; + +} + +// Checks the 3D interpolation +cmsInt32Number CheckInterp3DPlugin(void) +{ + + cmsPipeline* p; + cmsStage* clut; + cmsContext ctx; + cmsUInt16Number In[3], Out[3]; + cmsUInt16Number identity[] = { + + 0, 0, 0, + 0, 0, 0xffff, + 0, 0xffff, 0, + 0, 0xffff, 0xffff, + 0xffff, 0, 0, + 0xffff, 0, 0xffff, + 0xffff, 0xffff, 0, + 0xffff, 0xffff, 0xffff + }; + + + ctx = WatchDogContext(NULL); + if (ctx == NULL) { + Fail("Cannot create context"); + return 0; + } + + + cmsPluginTHR(ctx, &InterpPluginSample); + + + p = cmsPipelineAlloc(ctx, 3, 3); + clut = cmsStageAllocCLut16bit(ctx, 2, 3, 3, identity); + cmsPipelineInsertStage(p, cmsAT_BEGIN, clut); + + // Do some interpolations with the plugin + + In[0] = 0; In[1] = 0; In[2] = 0; + cmsPipelineEval16(In, Out, p); + + if (!IsGoodWord("0", Out[0], 0xFFFF - 0)) goto Error; + if (!IsGoodWord("1", Out[1], 0xFFFF - 0)) goto Error; + if (!IsGoodWord("2", Out[2], 0xFFFF - 0)) goto Error; + + In[0] = 0x1234; In[1] = 0x5678; In[2] = 0x9ABC; + cmsPipelineEval16(In, Out, p); + + if (!IsGoodWord("0", 0xFFFF - 0x9ABC, Out[0])) goto Error; + if (!IsGoodWord("1", 0xFFFF - 0x5678, Out[1])) goto Error; + if (!IsGoodWord("2", 0xFFFF - 0x1234, Out[2])) goto Error; + + cmsPipelineFree(p); + cmsDeleteContext(ctx); + + // Now without the plug-in + + p = cmsPipelineAlloc(NULL, 3, 3); + clut = cmsStageAllocCLut16bit(NULL, 2, 3, 3, identity); + cmsPipelineInsertStage(p, cmsAT_BEGIN, clut); + + In[0] = 0; In[1] = 0; In[2] = 0; + cmsPipelineEval16(In, Out, p); + + if (!IsGoodWord("0", 0, Out[0])) goto Error; + if (!IsGoodWord("1", 0, Out[1])) goto Error; + if (!IsGoodWord("2", 0, Out[2])) goto Error; + + In[0] = 0x1234; In[1] = 0x5678; In[2] = 0x9ABC; + cmsPipelineEval16(In, Out, p); + + if (!IsGoodWord("0", 0x1234, Out[0])) goto Error; + if (!IsGoodWord("1", 0x5678, Out[1])) goto Error; + if (!IsGoodWord("2", 0x9ABC, Out[2])) goto Error; + + cmsPipelineFree(p); + return 1; + +Error: + cmsPipelineFree(p); + return 0; + +} + +// -------------------------------------------------------------------------------------------------- +// Parametric curve plugin check: sin(x)/cos(x) function will be used to test the functionality. +// -------------------------------------------------------------------------------------------------- + +#define TYPE_SIN 1000 +#define TYPE_COS 1010 +#define TYPE_TAN 1020 +#define TYPE_709 709 + +static cmsFloat64Number my_fns(cmsInt32Number Type, + const cmsFloat64Number Params[], + cmsFloat64Number R) +{ + cmsFloat64Number Val; + switch (Type) { + + case TYPE_SIN: + Val = Params[0]* sin(R * M_PI); + break; + + case -TYPE_SIN: + Val = asin(R) / (M_PI * Params[0]); + break; + + case TYPE_COS: + Val = Params[0]* cos(R * M_PI); + break; + + case -TYPE_COS: + Val = acos(R) / (M_PI * Params[0]); + break; + + default: return -1.0; + + } + + return Val; +} + +static +cmsFloat64Number my_fns2(cmsInt32Number Type, + const cmsFloat64Number Params[], + cmsFloat64Number R) +{ + cmsFloat64Number Val; + switch (Type) { + + case TYPE_TAN: + Val = Params[0]* tan(R * M_PI); + break; + + case -TYPE_TAN: + Val = atan(R) / (M_PI * Params[0]); + break; + + default: return -1.0; + } + + return Val; +} + + +static double Rec709Math(int Type, const double Params[], double R) +{ + double Fun; + + switch (Type) + { + case 709: + + if (R <= (Params[3]*Params[4])) Fun = R / Params[3]; + else Fun = pow(((R - Params[2])/Params[1]), Params[0]); + break; + + case -709: + + if (R <= Params[4]) Fun = R * Params[3]; + else Fun = Params[1] * pow(R, (1/Params[0])) + Params[2]; + break; + } + return Fun; +} + + +// Add nonstandard TRC curves -> Rec709 + +cmsPluginParametricCurves Rec709Plugin = { + + { cmsPluginMagicNumber, 2060, cmsPluginParametricCurveSig, NULL }, + + 1, {TYPE_709}, {5}, Rec709Math + +}; + + +static +cmsPluginParametricCurves CurvePluginSample = { + { cmsPluginMagicNumber, 2060, cmsPluginParametricCurveSig, NULL }, + + 2, // nFunctions + { TYPE_SIN, TYPE_COS }, // Function Types + { 1, 1 }, // ParameterCount + my_fns // Evaluator +}; + +static +cmsPluginParametricCurves CurvePluginSample2 = { + { cmsPluginMagicNumber, 2060, cmsPluginParametricCurveSig, NULL }, + + 1, // nFunctions + { TYPE_TAN}, // Function Types + { 1 }, // ParameterCount + my_fns2 // Evaluator +}; + +// -------------------------------------------------------------------------------------------------- +// In this test, the DupContext function will be checked as well +// -------------------------------------------------------------------------------------------------- +cmsInt32Number CheckParametricCurvePlugin(void) +{ + cmsContext ctx = NULL; + cmsContext cpy = NULL; + cmsContext cpy2 = NULL; + cmsToneCurve* sinus; + cmsToneCurve* cosinus; + cmsToneCurve* tangent; + cmsToneCurve* reverse_sinus; + cmsToneCurve* reverse_cosinus; + cmsFloat64Number scale = 1.0; + + + ctx = WatchDogContext(NULL); + + cmsPluginTHR(ctx, &CurvePluginSample); + + cpy = DupContext(ctx, NULL); + + cmsPluginTHR(cpy, &CurvePluginSample2); + + cpy2 = DupContext(cpy, NULL); + + cmsPluginTHR(cpy2, &Rec709Plugin); + + + sinus = cmsBuildParametricToneCurve(cpy, TYPE_SIN, &scale); + cosinus = cmsBuildParametricToneCurve(cpy, TYPE_COS, &scale); + tangent = cmsBuildParametricToneCurve(cpy, TYPE_TAN, &scale); + reverse_sinus = cmsReverseToneCurve(sinus); + reverse_cosinus = cmsReverseToneCurve(cosinus); + + + if (!IsGoodVal("0.10", cmsEvalToneCurveFloat(sinus, 0.10f), sin(0.10 * M_PI) , 0.001)) goto Error; + if (!IsGoodVal("0.60", cmsEvalToneCurveFloat(sinus, 0.60f), sin(0.60* M_PI), 0.001)) goto Error; + if (!IsGoodVal("0.90", cmsEvalToneCurveFloat(sinus, 0.90f), sin(0.90* M_PI), 0.001)) goto Error; + + if (!IsGoodVal("0.10", cmsEvalToneCurveFloat(cosinus, 0.10f), cos(0.10* M_PI), 0.001)) goto Error; + if (!IsGoodVal("0.60", cmsEvalToneCurveFloat(cosinus, 0.60f), cos(0.60* M_PI), 0.001)) goto Error; + if (!IsGoodVal("0.90", cmsEvalToneCurveFloat(cosinus, 0.90f), cos(0.90* M_PI), 0.001)) goto Error; + + if (!IsGoodVal("0.10", cmsEvalToneCurveFloat(tangent, 0.10f), tan(0.10* M_PI), 0.001)) goto Error; + if (!IsGoodVal("0.60", cmsEvalToneCurveFloat(tangent, 0.60f), tan(0.60* M_PI), 0.001)) goto Error; + if (!IsGoodVal("0.90", cmsEvalToneCurveFloat(tangent, 0.90f), tan(0.90* M_PI), 0.001)) goto Error; + + + if (!IsGoodVal("0.10", cmsEvalToneCurveFloat(reverse_sinus, 0.10f), asin(0.10)/M_PI, 0.001)) goto Error; + if (!IsGoodVal("0.60", cmsEvalToneCurveFloat(reverse_sinus, 0.60f), asin(0.60)/M_PI, 0.001)) goto Error; + if (!IsGoodVal("0.90", cmsEvalToneCurveFloat(reverse_sinus, 0.90f), asin(0.90)/M_PI, 0.001)) goto Error; + + if (!IsGoodVal("0.10", cmsEvalToneCurveFloat(reverse_cosinus, 0.10f), acos(0.10)/M_PI, 0.001)) goto Error; + if (!IsGoodVal("0.60", cmsEvalToneCurveFloat(reverse_cosinus, 0.60f), acos(0.60)/M_PI, 0.001)) goto Error; + if (!IsGoodVal("0.90", cmsEvalToneCurveFloat(reverse_cosinus, 0.90f), acos(0.90)/M_PI, 0.001)) goto Error; + + cmsFreeToneCurve(sinus); + cmsFreeToneCurve(cosinus); + cmsFreeToneCurve(tangent); + cmsFreeToneCurve(reverse_sinus); + cmsFreeToneCurve(reverse_cosinus); + + cmsDeleteContext(ctx); + cmsDeleteContext(cpy); + cmsDeleteContext(cpy2); + + return 1; + +Error: + + cmsFreeToneCurve(sinus); + cmsFreeToneCurve(reverse_sinus); + cmsFreeToneCurve(cosinus); + cmsFreeToneCurve(reverse_cosinus); + + if (ctx != NULL) cmsDeleteContext(ctx); + if (cpy != NULL) cmsDeleteContext(cpy); + if (cpy2 != NULL) cmsDeleteContext(cpy2); + return 0; +} + +// -------------------------------------------------------------------------------------------------- +// formatters plugin check: 5-6-5 RGB format +// -------------------------------------------------------------------------------------------------- + +// We define this special type as 0 bytes not float, and set the upper bit + +#define TYPE_RGB_565 (COLORSPACE_SH(PT_RGB)|CHANNELS_SH(3)|BYTES_SH(0) | (1 << 23)) + +cmsUInt8Number* my_Unroll565(register struct _cmstransform_struct* nfo, + register cmsUInt16Number wIn[], + register cmsUInt8Number* accum, + register cmsUInt32Number Stride) +{ + cmsUInt16Number pixel = *(cmsUInt16Number*) accum; // Take whole pixel + + double r = floor(((double) (pixel & 31) * 65535.0) / 31.0 + 0.5); + double g = floor((((pixel >> 5) & 63) * 65535.0) / 63.0 + 0.5); + double b = floor((((pixel >> 11) & 31) * 65535.0) / 31.0 + 0.5); + + wIn[2] = (cmsUInt16Number) r; + wIn[1] = (cmsUInt16Number) g; + wIn[0] = (cmsUInt16Number) b; + + return accum + 2; +} + +cmsUInt8Number* my_Pack565(register _cmsTRANSFORM* info, + register cmsUInt16Number wOut[], + register cmsUInt8Number* output, + register cmsUInt32Number Stride) +{ + + register cmsUInt16Number pixel; + int r, g, b; + + r = (int) floor(( wOut[2] * 31) / 65535.0 + 0.5); + g = (int) floor(( wOut[1] * 63) / 65535.0 + 0.5); + b = (int) floor(( wOut[0] * 31) / 65535.0 + 0.5); + + + pixel = (r & 31) | (( g & 63) << 5) | ((b & 31) << 11); + + + *(cmsUInt16Number*) output = pixel; + return output + 2; +} + + +cmsFormatter my_FormatterFactory(cmsUInt32Number Type, + cmsFormatterDirection Dir, + cmsUInt32Number dwFlags) +{ + cmsFormatter Result = { NULL }; + + if ((Type == TYPE_RGB_565) && + !(dwFlags & CMS_PACK_FLAGS_FLOAT) && + (Dir == cmsFormatterInput)) { + Result.Fmt16 = my_Unroll565; + } + return Result; +} + + +cmsFormatter my_FormatterFactory2(cmsUInt32Number Type, + cmsFormatterDirection Dir, + cmsUInt32Number dwFlags) +{ + cmsFormatter Result = { NULL }; + + if ((Type == TYPE_RGB_565) && + !(dwFlags & CMS_PACK_FLAGS_FLOAT) && + (Dir == cmsFormatterOutput)) { + Result.Fmt16 = my_Pack565; + } + return Result; +} + +static +cmsPluginFormatters FormattersPluginSample = { {cmsPluginMagicNumber, + 2060, + cmsPluginFormattersSig, + NULL}, + my_FormatterFactory }; + + + +static +cmsPluginFormatters FormattersPluginSample2 = { {cmsPluginMagicNumber, + 2060, + cmsPluginFormattersSig, + NULL}, + my_FormatterFactory2 }; + + +cmsInt32Number CheckFormattersPlugin(void) +{ + cmsContext ctx = WatchDogContext(NULL); + cmsContext cpy; + cmsContext cpy2; + cmsHTRANSFORM xform; + cmsUInt16Number stream[]= { 0xffffU, 0x1234U, 0x0000U, 0x33ddU }; + cmsUInt16Number result[4]; + int i; + + + cmsPluginTHR(ctx, &FormattersPluginSample); + + cpy = DupContext(ctx, NULL); + + cmsPluginTHR(cpy, &FormattersPluginSample2); + + cpy2 = DupContext(cpy, NULL); + + xform = cmsCreateTransformTHR(cpy2, NULL, TYPE_RGB_565, NULL, TYPE_RGB_565, INTENT_PERCEPTUAL, cmsFLAGS_NULLTRANSFORM); + + cmsDoTransform(xform, stream, result, 4); + + cmsDeleteTransform(xform); + cmsDeleteContext(ctx); + cmsDeleteContext(cpy); + cmsDeleteContext(cpy2); + + for (i=0; i < 4; i++) + if (stream[i] != result[i]) return 0; + + return 1; +} + +// -------------------------------------------------------------------------------------------------- +// TagTypePlugin plugin check +// -------------------------------------------------------------------------------------------------- + +#define SigIntType ((cmsTagTypeSignature) 0x74747448) // 'tttH' +#define SigInt ((cmsTagSignature) 0x74747448) // 'tttH' + +static +void *Type_int_Read(struct _cms_typehandler_struct* self, + cmsIOHANDLER* io, + cmsUInt32Number* nItems, + cmsUInt32Number SizeOfTag) +{ + cmsUInt32Number* Ptr = (cmsUInt32Number*) _cmsMalloc(self ->ContextID, sizeof(cmsUInt32Number)); + if (Ptr == NULL) return NULL; + if (!_cmsReadUInt32Number(io, Ptr)) return NULL; + *nItems = 1; + return Ptr; +} + +static +cmsBool Type_int_Write(struct _cms_typehandler_struct* self, + cmsIOHANDLER* io, + void* Ptr, cmsUInt32Number nItems) +{ + return _cmsWriteUInt32Number(io, *(cmsUInt32Number*) Ptr); +} + +static +void* Type_int_Dup(struct _cms_typehandler_struct* self, + const void *Ptr, cmsUInt32Number n) +{ + return _cmsDupMem(self ->ContextID, Ptr, n * sizeof(cmsUInt32Number)); +} + +void Type_int_Free(struct _cms_typehandler_struct* self, + void* Ptr) +{ + _cmsFree(self ->ContextID, Ptr); +} + + +static cmsPluginTag HiddenTagPluginSample = { + + { cmsPluginMagicNumber, 2060, cmsPluginTagSig, NULL}, + SigInt, { 1, 1, { SigIntType }, NULL } +}; + +static cmsPluginTagType TagTypePluginSample = { + + { cmsPluginMagicNumber, 2060, cmsPluginTagTypeSig, (cmsPluginBase*) &HiddenTagPluginSample}, + { SigIntType, Type_int_Read, Type_int_Write, Type_int_Dup, Type_int_Free, NULL } +}; + + +cmsInt32Number CheckTagTypePlugin(void) +{ + cmsContext ctx = NULL; + cmsContext cpy = NULL; + cmsContext cpy2 = NULL; + cmsHPROFILE h = NULL; + cmsUInt32Number myTag = 1234; + cmsUInt32Number rc = 0; + char* data = NULL; + cmsUInt32Number *ptr = NULL; + cmsUInt32Number clen = 0; + + + ctx = WatchDogContext(NULL); + cmsPluginTHR(ctx, &TagTypePluginSample); + + cpy = DupContext(ctx, NULL); + cpy2 = DupContext(cpy, NULL); + + cmsDeleteContext(ctx); + cmsDeleteContext(cpy); + + h = cmsCreateProfilePlaceholder(cpy2); + if (h == NULL) { + Fail("Create placeholder failed"); + goto Error; + } + + + if (!cmsWriteTag(h, SigInt, &myTag)) { + Fail("Plug-in failed"); + goto Error; + } + + rc = cmsSaveProfileToMem(h, NULL, &clen); + if (!rc) { + Fail("Fetch mem size failed"); + goto Error; + } + + + data = (char*) malloc(clen); + if (data == NULL) { + Fail("malloc failed ?!?"); + goto Error; + } + + + rc = cmsSaveProfileToMem(h, data, &clen); + if (!rc) { + Fail("Save to mem failed"); + goto Error; + } + + cmsCloseProfile(h); + + cmsSetLogErrorHandler(NULL); + h = cmsOpenProfileFromMem(data, clen); + if (h == NULL) { + Fail("Open profile failed"); + goto Error; + } + + ptr = (cmsUInt32Number*) cmsReadTag(h, SigInt); + if (ptr != NULL) { + + Fail("read tag/context switching failed"); + goto Error; + } + + cmsCloseProfile(h); + ResetFatalError(); + + h = cmsOpenProfileFromMemTHR(cpy2, data, clen); + if (h == NULL) { + Fail("Open profile from mem failed"); + goto Error; + } + + // Get rid of data + free(data); data = NULL; + + ptr = (cmsUInt32Number*) cmsReadTag(h, SigInt); + if (ptr == NULL) { + Fail("Read tag/conext switching failed (2)"); + return 0; + } + + rc = (*ptr == 1234); + + cmsCloseProfile(h); + + cmsDeleteContext(cpy2); + + return rc; + +Error: + + if (h != NULL) cmsCloseProfile(h); + if (ctx != NULL) cmsDeleteContext(ctx); + if (cpy != NULL) cmsDeleteContext(cpy); + if (cpy2 != NULL) cmsDeleteContext(cpy2); + if (data) free(data); + + return 0; +} + +// -------------------------------------------------------------------------------------------------- +// MPE plugin check: +// -------------------------------------------------------------------------------------------------- +#define SigNegateType ((cmsStageSignature)0x6E202020) + +static +void EvaluateNegate(const cmsFloat32Number In[], + cmsFloat32Number Out[], + const cmsStage *mpe) +{ + Out[0] = 1.0f - In[0]; + Out[1] = 1.0f - In[1]; + Out[2] = 1.0f - In[2]; +} + +static +cmsStage* StageAllocNegate(cmsContext ContextID) +{ + return _cmsStageAllocPlaceholder(ContextID, + SigNegateType, 3, 3, EvaluateNegate, + NULL, NULL, NULL); +} + +static +void *Type_negate_Read(struct _cms_typehandler_struct* self, + cmsIOHANDLER* io, + cmsUInt32Number* nItems, + cmsUInt32Number SizeOfTag) +{ + cmsUInt16Number Chans; + if (!_cmsReadUInt16Number(io, &Chans)) return NULL; + if (Chans != 3) return NULL; + + *nItems = 1; + return StageAllocNegate(self -> ContextID); +} + +static +cmsBool Type_negate_Write(struct _cms_typehandler_struct* self, + cmsIOHANDLER* io, + void* Ptr, cmsUInt32Number nItems) +{ + + if (!_cmsWriteUInt16Number(io, 3)) return FALSE; + return TRUE; +} + +static +cmsPluginMultiProcessElement MPEPluginSample = { + + {cmsPluginMagicNumber, 2060, cmsPluginMultiProcessElementSig, NULL}, + + { (cmsTagTypeSignature) SigNegateType, Type_negate_Read, Type_negate_Write, NULL, NULL, NULL } +}; + + +cmsInt32Number CheckMPEPlugin(void) +{ + cmsContext ctx = NULL; + cmsContext cpy = NULL; + cmsContext cpy2 = NULL; + cmsHPROFILE h = NULL; + cmsUInt32Number myTag = 1234; + cmsUInt32Number rc = 0; + char* data = NULL; + cmsUInt32Number clen = 0; + cmsFloat32Number In[3], Out[3]; + cmsPipeline* pipe; + + ctx = WatchDogContext(NULL); + cmsPluginTHR(ctx, &MPEPluginSample); + + cpy = DupContext(ctx, NULL); + cpy2 = DupContext(cpy, NULL); + + cmsDeleteContext(ctx); + cmsDeleteContext(cpy); + + h = cmsCreateProfilePlaceholder(cpy2); + if (h == NULL) { + Fail("Create placeholder failed"); + goto Error; + } + + pipe = cmsPipelineAlloc(cpy2, 3, 3); + cmsPipelineInsertStage(pipe, cmsAT_BEGIN, StageAllocNegate(cpy2)); + + + In[0] = 0.3f; In[1] = 0.2f; In[2] = 0.9f; + cmsPipelineEvalFloat(In, Out, pipe); + + rc = (IsGoodVal("0", Out[0], 1.0-In[0], 0.001) && + IsGoodVal("1", Out[1], 1.0-In[1], 0.001) && + IsGoodVal("2", Out[2], 1.0-In[2], 0.001)); + + if (!rc) { + Fail("Pipeline failed"); + goto Error; + } + + if (!cmsWriteTag(h, cmsSigDToB3Tag, pipe)) { + Fail("Plug-in failed"); + goto Error; + } + + // This cleans the stage as well + cmsPipelineFree(pipe); + + rc = cmsSaveProfileToMem(h, NULL, &clen); + if (!rc) { + Fail("Fetch mem size failed"); + goto Error; + } + + + data = (char*) malloc(clen); + if (data == NULL) { + Fail("malloc failed ?!?"); + goto Error; + } + + + rc = cmsSaveProfileToMem(h, data, &clen); + if (!rc) { + Fail("Save to mem failed"); + goto Error; + } + + cmsCloseProfile(h); + + + cmsSetLogErrorHandler(NULL); + h = cmsOpenProfileFromMem(data, clen); + if (h == NULL) { + Fail("Open profile failed"); + goto Error; + } + + pipe = (cmsPipeline*) cmsReadTag(h, cmsSigDToB3Tag); + if (pipe != NULL) { + + // Unsupported stage, should fail + Fail("read tag/context switching failed"); + goto Error; + } + + cmsCloseProfile(h); + + ResetFatalError(); + + h = cmsOpenProfileFromMemTHR(cpy2, data, clen); + if (h == NULL) { + Fail("Open profile from mem failed"); + goto Error; + } + + // Get rid of data + free(data); data = NULL; + + pipe = (cmsPipeline*) cmsReadTag(h, cmsSigDToB3Tag); + if (pipe == NULL) { + Fail("Read tag/conext switching failed (2)"); + return 0; + } + + // Evaluate for negation + In[0] = 0.3f; In[1] = 0.2f; In[2] = 0.9f; + cmsPipelineEvalFloat(In, Out, pipe); + + rc = (IsGoodVal("0", Out[0], 1.0-In[0], 0.001) && + IsGoodVal("1", Out[1], 1.0-In[1], 0.001) && + IsGoodVal("2", Out[2], 1.0-In[2], 0.001)); + + cmsCloseProfile(h); + + cmsDeleteContext(cpy2); + + return rc; + +Error: + + if (h != NULL) cmsCloseProfile(h); + if (ctx != NULL) cmsDeleteContext(ctx); + if (cpy != NULL) cmsDeleteContext(cpy); + if (cpy2 != NULL) cmsDeleteContext(cpy2); + if (data) free(data); + + return 0; +} + + +// -------------------------------------------------------------------------------------------------- +// Optimization plugin check: +// -------------------------------------------------------------------------------------------------- + +static +void FastEvaluateCurves(register const cmsUInt16Number In[], + register cmsUInt16Number Out[], + register const void* Data) +{ + Out[0] = In[0]; +} + +static +cmsBool MyOptimize(cmsPipeline** Lut, + cmsUInt32Number Intent, + cmsUInt32Number* InputFormat, + cmsUInt32Number* OutputFormat, + cmsUInt32Number* dwFlags) +{ + cmsStage* mpe; + _cmsStageToneCurvesData* Data; + + // Only curves in this LUT? All are identities? + for (mpe = cmsPipelineGetPtrToFirstStage(*Lut); + mpe != NULL; + mpe = cmsStageNext(mpe)) { + + if (cmsStageType(mpe) != cmsSigCurveSetElemType) return FALSE; + + // Check for identity + Data = (_cmsStageToneCurvesData*) cmsStageData(mpe); + if (Data ->nCurves != 1) return FALSE; + if (cmsEstimateGamma(Data->TheCurves[0], 0.1) > 1.0) return FALSE; + + } + + *dwFlags |= cmsFLAGS_NOCACHE; + _cmsPipelineSetOptimizationParameters(*Lut, FastEvaluateCurves, NULL, NULL, NULL); + + return TRUE; +} + +cmsPluginOptimization OptimizationPluginSample = { + + {cmsPluginMagicNumber, 2060, cmsPluginOptimizationSig, NULL}, + MyOptimize +}; + + +cmsInt32Number CheckOptimizationPlugin(void) +{ + cmsContext ctx = WatchDogContext(NULL); + cmsContext cpy; + cmsContext cpy2; + cmsHTRANSFORM xform; + cmsUInt8Number In[]= { 10, 20, 30, 40 }; + cmsUInt8Number Out[4]; + cmsToneCurve* Linear; + cmsHPROFILE h; + int i; + + cmsPluginTHR(ctx, &OptimizationPluginSample); + + cpy = DupContext(ctx, NULL); + cpy2 = DupContext(cpy, NULL); + + Linear = cmsBuildGamma(cpy2, 1.0); + h = cmsCreateLinearizationDeviceLinkTHR(cpy2, cmsSigGrayData, &Linear); + cmsFreeToneCurve(Linear); + + xform = cmsCreateTransformTHR(cpy2, h, TYPE_GRAY_8, h, TYPE_GRAY_8, INTENT_PERCEPTUAL, 0); + cmsCloseProfile(h); + + cmsDoTransform(xform, In, Out, 4); + + cmsDeleteTransform(xform); + cmsDeleteContext(ctx); + cmsDeleteContext(cpy); + cmsDeleteContext(cpy2); + + for (i=0; i < 4; i++) + if (In[i] != Out[i]) return 0; + + return 1; +} + + +// -------------------------------------------------------------------------------------------------- +// Check the intent plug-in +// -------------------------------------------------------------------------------------------------- + +/* + This example creates a new rendering intent, at intent number 300, that is identical to perceptual + intent for all color spaces but gray to gray transforms, in this case it bypasses the data. + Note that it has to clear all occurrences of intent 300 in the intents array to avoid + infinite recursion. +*/ + +#define INTENT_DECEPTIVE 300 + +static +cmsPipeline* MyNewIntent(cmsContext ContextID, + cmsUInt32Number nProfiles, + cmsUInt32Number TheIntents[], + cmsHPROFILE hProfiles[], + cmsBool BPC[], + cmsFloat64Number AdaptationStates[], + cmsUInt32Number dwFlags) +{ + cmsPipeline* Result; + cmsUInt32Number ICCIntents[256]; + cmsUInt32Number i; + + for (i=0; i < nProfiles; i++) + ICCIntents[i] = (TheIntents[i] == INTENT_DECEPTIVE) ? INTENT_PERCEPTUAL : + TheIntents[i]; + + if (cmsGetColorSpace(hProfiles[0]) != cmsSigGrayData || + cmsGetColorSpace(hProfiles[nProfiles-1]) != cmsSigGrayData) + return _cmsDefaultICCintents(ContextID, nProfiles, + ICCIntents, hProfiles, + BPC, AdaptationStates, + dwFlags); + + Result = cmsPipelineAlloc(ContextID, 1, 1); + if (Result == NULL) return NULL; + + cmsPipelineInsertStage(Result, cmsAT_BEGIN, + cmsStageAllocIdentity(ContextID, 1)); + + return Result; +} + +static cmsPluginRenderingIntent IntentPluginSample = { + + {cmsPluginMagicNumber, 2060, cmsPluginRenderingIntentSig, NULL}, + + INTENT_DECEPTIVE, MyNewIntent, "bypass gray to gray rendering intent" +}; + +cmsInt32Number CheckIntentPlugin(void) +{ + cmsContext ctx = WatchDogContext(NULL); + cmsContext cpy; + cmsContext cpy2; + cmsHTRANSFORM xform; + cmsHPROFILE h1, h2; + cmsToneCurve* Linear1; + cmsToneCurve* Linear2; + cmsUInt8Number In[]= { 10, 20, 30, 40 }; + cmsUInt8Number Out[4]; + int i; + + cmsPluginTHR(ctx, &IntentPluginSample); + + cpy = DupContext(ctx, NULL); + cpy2 = DupContext(cpy, NULL); + + Linear1 = cmsBuildGamma(cpy2, 3.0); + Linear2 = cmsBuildGamma(cpy2, 0.1); + h1 = cmsCreateLinearizationDeviceLinkTHR(cpy2, cmsSigGrayData, &Linear1); + h2 = cmsCreateLinearizationDeviceLinkTHR(cpy2, cmsSigGrayData, &Linear2); + + cmsFreeToneCurve(Linear1); + cmsFreeToneCurve(Linear2); + + xform = cmsCreateTransformTHR(cpy2, h1, TYPE_GRAY_8, h2, TYPE_GRAY_8, INTENT_DECEPTIVE, 0); + cmsCloseProfile(h1); cmsCloseProfile(h2); + + cmsDoTransform(xform, In, Out, 4); + + cmsDeleteTransform(xform); + cmsDeleteContext(ctx); + cmsDeleteContext(cpy); + cmsDeleteContext(cpy2); + + for (i=0; i < 4; i++) + if (Out[i] != In[i]) return 0; + + return 1; +} + + +// -------------------------------------------------------------------------------------------------- +// Check the full transform plug-in +// -------------------------------------------------------------------------------------------------- + +// This is a sample intent that only works for gray8 as output, and always returns '42' +static +void TrancendentalTransform(struct _cmstransform_struct * CMM, + const void* InputBuffer, + void* OutputBuffer, + cmsUInt32Number Size, + cmsUInt32Number Stride) +{ + cmsUInt32Number i; + + for (i=0; i < Size; i++) + { + ((cmsUInt8Number*) OutputBuffer)[i] = 0x42; + } + +} + + +cmsBool TransformFactory(_cmsTransformFn* xformPtr, + void** UserData, + _cmsFreeUserDataFn* FreePrivateDataFn, + cmsPipeline** Lut, + cmsUInt32Number* InputFormat, + cmsUInt32Number* OutputFormat, + cmsUInt32Number* dwFlags) + +{ + if (*OutputFormat == TYPE_GRAY_8) + { + // *Lut holds the pipeline to be applied + *xformPtr = TrancendentalTransform; + return TRUE; + } + + return FALSE; +} + + +// The Plug-in entry point +static cmsPluginTransform FullTransformPluginSample = { + + { cmsPluginMagicNumber, 2060, cmsPluginTransformSig, NULL}, + + TransformFactory +}; + +cmsInt32Number CheckTransformPlugin(void) +{ + cmsContext ctx = WatchDogContext(NULL); + cmsContext cpy; + cmsContext cpy2; + cmsHTRANSFORM xform; + cmsUInt8Number In[]= { 10, 20, 30, 40 }; + cmsUInt8Number Out[4]; + cmsToneCurve* Linear; + cmsHPROFILE h; + int i; + + + cmsPluginTHR(ctx, &FullTransformPluginSample); + + cpy = DupContext(ctx, NULL); + cpy2 = DupContext(cpy, NULL); + + Linear = cmsBuildGamma(cpy2, 1.0); + h = cmsCreateLinearizationDeviceLinkTHR(cpy2, cmsSigGrayData, &Linear); + cmsFreeToneCurve(Linear); + + xform = cmsCreateTransformTHR(cpy2, h, TYPE_GRAY_8, h, TYPE_GRAY_8, INTENT_PERCEPTUAL, 0); + cmsCloseProfile(h); + + cmsDoTransform(xform, In, Out, 4); + + + cmsDeleteTransform(xform); + cmsDeleteContext(ctx); + cmsDeleteContext(cpy); + cmsDeleteContext(cpy2); + + for (i=0; i < 4; i++) + if (Out[i] != 0x42) return 0; + + return 1; +} + + +// -------------------------------------------------------------------------------------------------- +// Check the mutex plug-in +// -------------------------------------------------------------------------------------------------- + +typedef struct { + int nlocks; +} MyMtx; + + +static +void* MyMtxCreate(cmsContext id) +{ + MyMtx* mtx = (MyMtx*) _cmsMalloc(id, sizeof(MyMtx)); + mtx ->nlocks = 0; + return mtx; +} + +static +void MyMtxDestroy(cmsContext id, void* mtx) +{ + MyMtx* mtx_ = (MyMtx*) mtx; + + if (mtx_->nlocks != 0) + Die("Locks != 0 when setting free a mutex"); + + _cmsFree(id, mtx); + +} + +static +cmsBool MyMtxLock(cmsContext id, void* mtx) +{ + MyMtx* mtx_ = (MyMtx*) mtx; + mtx_->nlocks++; + + return TRUE; +} + +static +void MyMtxUnlock(cmsContext id, void* mtx) +{ + MyMtx* mtx_ = (MyMtx*) mtx; + mtx_->nlocks--; + +} + + +static cmsPluginMutex MutexPluginSample = { + + { cmsPluginMagicNumber, 2060, cmsPluginMutexSig, NULL}, + + MyMtxCreate, MyMtxDestroy, MyMtxLock, MyMtxUnlock +}; + + +cmsInt32Number CheckMutexPlugin(void) +{ + cmsContext ctx = WatchDogContext(NULL); + cmsContext cpy; + cmsContext cpy2; + cmsHTRANSFORM xform; + cmsUInt8Number In[]= { 10, 20, 30, 40 }; + cmsUInt8Number Out[4]; + cmsToneCurve* Linear; + cmsHPROFILE h; + int i; + + + cmsPluginTHR(ctx, &MutexPluginSample); + + cpy = DupContext(ctx, NULL); + cpy2 = DupContext(cpy, NULL); + + Linear = cmsBuildGamma(cpy2, 1.0); + h = cmsCreateLinearizationDeviceLinkTHR(cpy2, cmsSigGrayData, &Linear); + cmsFreeToneCurve(Linear); + + xform = cmsCreateTransformTHR(cpy2, h, TYPE_GRAY_8, h, TYPE_GRAY_8, INTENT_PERCEPTUAL, 0); + cmsCloseProfile(h); + + cmsDoTransform(xform, In, Out, 4); + + + cmsDeleteTransform(xform); + cmsDeleteContext(ctx); + cmsDeleteContext(cpy); + cmsDeleteContext(cpy2); + + for (i=0; i < 4; i++) + if (Out[i] != In[i]) return 0; + + return 1; +} diff --git a/testbed/testthread.cpp b/testbed/testthread.cpp index 435445c..d553567 100644 --- a/testbed/testthread.cpp +++ b/testbed/testthread.cpp @@ -1,52 +1,120 @@ #include <windows.h> -#include "lcms.h" +#include "lcms2_plugin.h" -static cmsHPROFILE prof_xyz,prof_rgb; -static cmsHTRANSFORM trans_xyz_to_rgb,trans_rgb_to_xyz; +static cmsContext ctx; +static cmsHPROFILE prof_cmyk, prof_rgb; +static volatile int rc = 0; -static DWORD WINAPI make_trans_xyz_to_rgb(LPVOID lpParameter) + +static +void* MyMtxCreate(cmsContext id) { - trans_xyz_to_rgb = cmsCreateTransform( - prof_xyz,TYPE_XYZ_DBL, - prof_rgb,TYPE_RGB_DBL, - INTENT_ABSOLUTE_COLORIMETRIC,cmsFLAGS_NOTPRECALC); - return 0; + return (void*) CreateMutex( NULL, FALSE, NULL); } -static DWORD WINAPI make_trans_rgb_to_xyz(LPVOID lpParameter) +static +void MyMtxDestroy(cmsContext id, void* mtx) { - trans_rgb_to_xyz = cmsCreateTransform( - prof_rgb,TYPE_RGB_DBL, - prof_xyz,TYPE_XYZ_DBL, - INTENT_ABSOLUTE_COLORIMETRIC,cmsFLAGS_NOTPRECALC); - return 0; + CloseHandle((HANDLE) mtx); +} + +static +cmsBool MyMtxLock(cmsContext id, void* mtx) +{ + WaitForSingleObject((HANDLE) mtx, INFINITE); + return TRUE; +} + +static +void MyMtxUnlock(cmsContext id, void* mtx) +{ + ReleaseMutex((HANDLE) mtx); +} + + +static cmsPluginMutex MutexPluginSample = { + + { cmsPluginMagicNumber, 2060, cmsPluginMutexSig, NULL}, + + MyMtxCreate, MyMtxDestroy, MyMtxLock, MyMtxUnlock +}; + + +static DWORD WINAPI one_thread(LPVOID lpParameter) +{ + int i, j; + cmsUInt8Number rgb[3*1000]; + cmsUInt8Number cmyk[4*1000]; + + Sleep(rand() % 500 ); + cmsHTRANSFORM xform = cmsCreateTransformTHR(ctx, prof_rgb, TYPE_RGB_8, prof_cmyk, TYPE_CMYK_8, 0, 0); + + for (i=0; i < 10000; i++) { + + for (j=0; j < 1000; j++) + { + rgb[j * 3 ] = 189; + rgb[j * 3 + 1] = 100; + rgb[j * 3 + 2] = 75; + } + cmsDoTransform(xform, rgb, cmyk, 1000); + for (j=0; j < 1000; j++) + { + if (cmyk[j * 4 ] != 37 || + cmyk[j * 4 + 1 ] != 188 || + cmyk[j * 4 + 2 ] != 195 || + cmyk[j * 4 + 3 ] != 7) + { + OutputDebugString(L"ERROR\n"); + rc = 1; + } + + } + + } + + cmsDeleteTransform(xform); + + return 0; } -int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR -lpCmdLine,int nCmdShow) +int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nCmdShow) { - prof_xyz = cmsCreateXYZProfile(); - prof_rgb = cmsOpenProfileFromFile("AdobeRGB1998.icc","rb"); -//cmsCreate_sRGBProfile(); - for (int i=0;i<10;++i) - { -#define try_threads -#ifdef try_threads - DWORD threadid; - HANDLE workers[2]; - workers[0] = CreateThread(NULL,0,make_trans_xyz_to_rgb,NULL,0,&threadid); - workers[1] = CreateThread(NULL,0,make_trans_rgb_to_xyz,NULL,0,&threadid); - WaitForMultipleObjects(2,workers,TRUE,INFINITE); - for (unsigned i=0;i<2;++i) - CloseHandle(workers[i]); -#else - make_trans_xyz_to_rgb(0); - make_trans_rgb_to_xyz(0); -#endif - cmsDeleteTransform(trans_xyz_to_rgb); - cmsDeleteTransform(trans_rgb_to_xyz); - } - cmsCloseProfile(prof_rgb); - cmsCloseProfile(prof_xyz); + int i; + cmsContext ctx; + + OutputDebugString(L"Test in progress...\n"); + + ctx = cmsCreateContext(&MutexPluginSample, 0); + + prof_cmyk = cmsOpenProfileFromFileTHR(ctx, "USWebCoatedSWOP.icc", "r"); + prof_rgb = cmsOpenProfileFromFileTHR(ctx, "AdobeRGB1998.icc","r"); + + +#define NWORKERS 10 + + HANDLE workers[NWORKERS]; + + + for (int i=0; i<NWORKERS; ++i) + { + DWORD threadid; + + workers[i] = CreateThread(NULL,0,one_thread,NULL,0,&threadid); + } + + WaitForMultipleObjects(NWORKERS,workers,TRUE,INFINITE); + + for ( i=0;i<NWORKERS;++i) + CloseHandle(workers[i]); + + + cmsCloseProfile(prof_rgb); + cmsCloseProfile(prof_cmyk); + cmsDeleteContext(ctx); + + OutputDebugString(L"Test Done\n"); + + return rc; } diff --git a/testbed/zoo_icc.c b/testbed/zoo_icc.c new file mode 100755 index 0000000..c1e9981 --- /dev/null +++ b/testbed/zoo_icc.c @@ -0,0 +1,310 @@ +//--------------------------------------------------------------------------------- +// +// Little Color Management System +// Copyright (c) 1998-2014 Marti Maria Saguer +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the Software +// is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +//--------------------------------------------------------------------------------- +// + + +#include "testcms2.h" + + +// ZOO checks ------------------------------------------------------------------------------------------------------------ + + +#ifdef CMS_IS_WINDOWS_ + +static char ZOOfolder[cmsMAX_PATH] = "c:\\colormaps\\"; +static char ZOOwrite[cmsMAX_PATH] = "c:\\colormaps\\write\\"; +static char ZOORawWrite[cmsMAX_PATH] = "c:\\colormaps\\rawwrite\\"; + + +// Read all tags on a profile given by its handle +static +void ReadAllTags(cmsHPROFILE h) +{ + cmsInt32Number i, n; + cmsTagSignature sig; + + n = cmsGetTagCount(h); + for (i=0; i < n; i++) { + + sig = cmsGetTagSignature(h, i); + if (cmsReadTag(h, sig) == NULL) return; + } +} + + +// Read all tags on a profile given by its handle +static +void ReadAllRAWTags(cmsHPROFILE h) +{ + cmsInt32Number i, n; + cmsTagSignature sig; + cmsInt32Number len; + + n = cmsGetTagCount(h); + for (i=0; i < n; i++) { + + sig = cmsGetTagSignature(h, i); + len = cmsReadRawTag(h, sig, NULL, 0); + } +} + + +static +void PrintInfo(cmsHPROFILE h, cmsInfoType Info) +{ + wchar_t* text; + cmsInt32Number len; + cmsContext id = 0; + + len = cmsGetProfileInfo(h, Info, "en", "US", NULL, 0); + if (len == 0) return; + + text = _cmsMalloc(id, len); + cmsGetProfileInfo(h, Info, "en", "US", text, len); + + wprintf(L"%s\n", text); + _cmsFree(id, text); +} + + +static +void PrintAllInfos(cmsHPROFILE h) +{ + PrintInfo(h, cmsInfoDescription); + PrintInfo(h, cmsInfoManufacturer); + PrintInfo(h, cmsInfoModel); + PrintInfo(h, cmsInfoCopyright); + printf("\n\n"); +} + +static +void ReadAllLUTS(cmsHPROFILE h) +{ + cmsPipeline* a; + cmsCIEXYZ Black; + + a = _cmsReadInputLUT(h, INTENT_PERCEPTUAL); + if (a) cmsPipelineFree(a); + + a = _cmsReadInputLUT(h, INTENT_RELATIVE_COLORIMETRIC); + if (a) cmsPipelineFree(a); + + a = _cmsReadInputLUT(h, INTENT_SATURATION); + if (a) cmsPipelineFree(a); + + a = _cmsReadInputLUT(h, INTENT_ABSOLUTE_COLORIMETRIC); + if (a) cmsPipelineFree(a); + + + a = _cmsReadOutputLUT(h, INTENT_PERCEPTUAL); + if (a) cmsPipelineFree(a); + + a = _cmsReadOutputLUT(h, INTENT_RELATIVE_COLORIMETRIC); + if (a) cmsPipelineFree(a); + + a = _cmsReadOutputLUT(h, INTENT_SATURATION); + if (a) cmsPipelineFree(a); + + a = _cmsReadOutputLUT(h, INTENT_ABSOLUTE_COLORIMETRIC); + if (a) cmsPipelineFree(a); + + + a = _cmsReadDevicelinkLUT(h, INTENT_PERCEPTUAL); + if (a) cmsPipelineFree(a); + + a = _cmsReadDevicelinkLUT(h, INTENT_RELATIVE_COLORIMETRIC); + if (a) cmsPipelineFree(a); + + a = _cmsReadDevicelinkLUT(h, INTENT_SATURATION); + if (a) cmsPipelineFree(a); + + a = _cmsReadDevicelinkLUT(h, INTENT_ABSOLUTE_COLORIMETRIC); + if (a) cmsPipelineFree(a); + + + cmsDetectDestinationBlackPoint(&Black, h, INTENT_PERCEPTUAL, 0); + cmsDetectDestinationBlackPoint(&Black, h, INTENT_RELATIVE_COLORIMETRIC, 0); + cmsDetectDestinationBlackPoint(&Black, h, INTENT_SATURATION, 0); + cmsDetectDestinationBlackPoint(&Black, h, INTENT_ABSOLUTE_COLORIMETRIC, 0); + cmsDetectTAC(h); +} + +// Check one specimen in the ZOO + +static +cmsInt32Number CheckSingleSpecimen(const char* Profile) +{ + char BuffSrc[256]; + char BuffDst[256]; + cmsHPROFILE h; + + sprintf(BuffSrc, "%s%s", ZOOfolder, Profile); + sprintf(BuffDst, "%s%s", ZOOwrite, Profile); + + h = cmsOpenProfileFromFile(BuffSrc, "r"); + if (h == NULL) return 0; + + printf("%s\n", Profile); + + PrintAllInfos(h); + ReadAllTags(h); + ReadAllLUTS(h); + // ReadAllRAWTags(h); + + + cmsSaveProfileToFile(h, BuffDst); + cmsCloseProfile(h); + + h = cmsOpenProfileFromFile(BuffDst, "r"); + if (h == NULL) return 0; + ReadAllTags(h); + + + cmsCloseProfile(h); + + return 1; +} + +static +cmsInt32Number CheckRAWSpecimen(const char* Profile) +{ + char BuffSrc[256]; + char BuffDst[256]; + cmsHPROFILE h; + + sprintf(BuffSrc, "%s%s", ZOOfolder, Profile); + sprintf(BuffDst, "%s%s", ZOORawWrite, Profile); + + h = cmsOpenProfileFromFile(BuffSrc, "r"); + if (h == NULL) return 0; + + ReadAllTags(h); + ReadAllRAWTags(h); + cmsSaveProfileToFile(h, BuffDst); + cmsCloseProfile(h); + + h = cmsOpenProfileFromFile(BuffDst, "r"); + if (h == NULL) return 0; + ReadAllTags(h); + cmsCloseProfile(h); + + return 1; +} + + +static int input = 0, + disp = 0, + output = 0, + link = 0, + abst = 0, + color = 0, + named = 0; + +static int rgb = 0, + cmyk = 0, + gray = 0, + other = 0; + + + +static +int count_stats(const char* Profile) +{ + char BuffSrc[256]; + cmsHPROFILE h; + cmsCIEXYZ Black; + + sprintf(BuffSrc, "%s%s", ZOOfolder, Profile); + + h = cmsOpenProfileFromFile(BuffSrc, "r"); + if (h == NULL) return 0; + + + switch (cmsGetDeviceClass(h)) { + + case cmsSigInputClass : input++; break; + case cmsSigDisplayClass : disp++; break; + case cmsSigOutputClass : output++; break; + case cmsSigLinkClass : link++; break; + case cmsSigAbstractClass : abst++; break; + case cmsSigColorSpaceClass : color++; break; + case cmsSigNamedColorClass : named ++; break; + } + + + switch (cmsGetColorSpace(h)) { + + case cmsSigRgbData: rgb++; break; + case cmsSigCmykData: cmyk++; break; + case cmsSigGrayData: gray++; break; + default: other++; + } + + cmsDetectDestinationBlackPoint(&Black, h, INTENT_PERCEPTUAL, 0); + cmsDetectDestinationBlackPoint(&Black, h, INTENT_RELATIVE_COLORIMETRIC, 0); + cmsDetectDestinationBlackPoint(&Black, h, INTENT_SATURATION, 0); + + cmsCloseProfile(h); + + return 1; +} + + + +void CheckProfileZOO(void) +{ + + struct _finddata_t c_file; + intptr_t hFile; + + cmsSetLogErrorHandler(NULL); + + if ( (hFile = _findfirst("c:\\colormaps\\*.*", &c_file)) == -1L ) + printf("No files in current directory"); + else + { + do + { + if (strcmp(c_file.name, ".") != 0 && + strcmp(c_file.name, "..") != 0) { + + CheckSingleSpecimen( c_file.name); + CheckRAWSpecimen( c_file.name); + + count_stats(c_file.name); + + TestMemoryLeaks(FALSE); + + } + + } while ( _findnext(hFile, &c_file) == 0 ); + + _findclose(hFile); + } + + ResetFatalError(); +} + +#endif |