summaryrefslogtreecommitdiff
path: root/testbed
diff options
context:
space:
mode:
authorMarti Maria <info@littlecms.com>2014-02-12 12:21:45 +0100
committerMarti Maria <info@littlecms.com>2014-02-12 12:21:45 +0100
commit078665ecf29b6a9ca31803e6ebd12f22f3da9961 (patch)
treed5036b7a482babdd8d99a693f3edeabf6877f1c1 /testbed
parent579b3aad051b9fcf858ea308f9d8f6714f84c7a8 (diff)
downloadlcms2-078665ecf29b6a9ca31803e6ebd12f22f3da9961.tar.gz
Merge from Artifex branchlcms2.6rc0
Diffstat (limited to 'testbed')
-rw-r--r--testbed/Makefile.am4
-rw-r--r--testbed/Makefile.in9
-rwxr-xr-xtestbed/ibm-t61.iccbin0 -> 20480 bytes
-rw-r--r--testbed/new.iccbin0 -> 20480 bytes
-rw-r--r--testbed/testcms2.c647
-rwxr-xr-xtestbed/testcms2.h84
-rwxr-xr-xtestbed/testplugin.c1476
-rw-r--r--testbed/testthread.cpp148
-rwxr-xr-xtestbed/zoo_icc.c310
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
new file mode 100755
index 0000000..497f2d8
--- /dev/null
+++ b/testbed/ibm-t61.icc
Binary files differ
diff --git a/testbed/new.icc b/testbed/new.icc
new file mode 100644
index 0000000..dd2f757
--- /dev/null
+++ b/testbed/new.icc
Binary files differ
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