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 | |
parent | 579b3aad051b9fcf858ea308f9d8f6714f84c7a8 (diff) | |
download | lcms2-078665ecf29b6a9ca31803e6ebd12f22f3da9961.tar.gz |
Merge from Artifex branchlcms2.6rc0
47 files changed, 5559 insertions, 2018 deletions
@@ -32,9 +32,11 @@ XhmikosR Stanislav Brabec (SuSe) Leonhard Gruenschloss (Google) Patrick Noffke +Christopher James Halse Rogers Special Thanks -------------- +Artifex software Jan Morovic Jos Vernon (WebSupergoo) Harald Schneider (Maxon) @@ -131,4 +131,11 @@ Fixed some indexing out of bounds in floating point interpolation Fixed a bug in PCS/Colorspace order when reading V2 Lab devicelinks Added a way to retrieve matrix shaper always, no matter LUT is present Changed endianess detection for PowerPC -Fixed memory leaks on error handling
\ No newline at end of file +Fixed memory leaks on error handling +Big revamp on Contexts, from Artifex +New locking plug-in, from Artifex +Added directories for tiff, jpeg in configure script + +----------------------- +2.6 Featured release +----------------------- diff --git a/Makefile.am b/Makefile.am index e0cba52..9b2b333 100644 --- a/Makefile.am +++ b/Makefile.am @@ -12,7 +12,7 @@ PACKAGE_VERSION = @PACKAGE_VERSION@ SUBDIRS = src include utils/tificc utils/transicc utils/linkicc utils/jpgicc utils/psicc testbed # Additional files to distribute -EXTRA_DIST = AUTHORS COPYING ChangeLog doc Projects include bin Lib INSTALL README.1ST lcms2.pc.in +EXTRA_DIST = AUTHORS COPYING ChangeLog doc Projects include bin Lib INSTALL README.1ST autogen.sh lcms2.pc.in pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = lcms2.pc diff --git a/Makefile.in b/Makefile.in index 89b9605..b97d38e 100644 --- a/Makefile.in +++ b/Makefile.in @@ -300,7 +300,7 @@ AUTOMAKE_OPTIONS = 1.7.2 dist-zip foreign SUBDIRS = src include utils/tificc utils/transicc utils/linkicc utils/jpgicc utils/psicc testbed # Additional files to distribute -EXTRA_DIST = AUTHORS COPYING ChangeLog doc Projects include bin Lib INSTALL README.1ST lcms2.pc.in +EXTRA_DIST = AUTHORS COPYING ChangeLog doc Projects include bin Lib INSTALL README.1ST autogen.sh lcms2.pc.in pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = lcms2.pc all: all-recursive diff --git a/Projects/VC2010/testbed/testbed.vcxproj b/Projects/VC2010/testbed/testbed.vcxproj index fc92b0c..c26e3cc 100644 --- a/Projects/VC2010/testbed/testbed.vcxproj +++ b/Projects/VC2010/testbed/testbed.vcxproj @@ -189,6 +189,11 @@ </ItemGroup>
<ItemGroup>
<ClCompile Include="..\..\..\testbed\testcms2.c" />
+ <ClCompile Include="..\..\..\testbed\testplugin.c" />
+ <ClCompile Include="..\..\..\testbed\zoo_icc.c" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="..\..\..\testbed\testcms2.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
diff --git a/Projects/VC2010/testbed/testbed.vcxproj.filters b/Projects/VC2010/testbed/testbed.vcxproj.filters index 21cbdd4..fecb121 100644 --- a/Projects/VC2010/testbed/testbed.vcxproj.filters +++ b/Projects/VC2010/testbed/testbed.vcxproj.filters @@ -18,5 +18,16 @@ <ClCompile Include="..\..\..\testbed\testcms2.c"> <Filter>Source Files</Filter> </ClCompile> + <ClCompile Include="..\..\..\testbed\testplugin.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="..\..\..\testbed\zoo_icc.c"> + <Filter>Source Files</Filter> + </ClCompile> + </ItemGroup> + <ItemGroup> + <ClInclude Include="..\..\..\testbed\testcms2.h"> + <Filter>Header Files</Filter> + </ClInclude> </ItemGroup> </Project>
\ No newline at end of file @@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.69 for lcms2 2.5. +# Generated by GNU Autoconf 2.69 for lcms2 2.6. # # # Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. @@ -587,8 +587,8 @@ MAKEFLAGS= # Identity of this package. PACKAGE_NAME='lcms2' PACKAGE_TARNAME='lcms2' -PACKAGE_VERSION='2.5' -PACKAGE_STRING='lcms2 2.5' +PACKAGE_VERSION='2.6' +PACKAGE_STRING='lcms2 2.6' PACKAGE_BUGREPORT='' PACKAGE_URL='' @@ -1338,7 +1338,7 @@ if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures lcms2 2.5 to adapt to many kinds of systems. +\`configure' configures lcms2 2.6 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1408,7 +1408,7 @@ fi if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of lcms2 2.5:";; + short | recursive ) echo "Configuration of lcms2 2.6:";; esac cat <<\_ACEOF @@ -1429,8 +1429,8 @@ Optional Features: Optional Packages: --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) - --without-jpeg disable JPEG support - --without-tiff disable TIFF support + --with-jpeg=DIR use jpeg installed in DIR + --with-tiff=DIR use tiff installed in DIR --without-zlib disable ZLIB support --with-pic try to use only PIC/non-PIC objects [default=use both] @@ -1517,7 +1517,7 @@ fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -lcms2 configure 2.5 +lcms2 configure 2.6 generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. @@ -2003,7 +2003,7 @@ cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by lcms2 $as_me 2.5, which was +It was created by lcms2 $as_me 2.6, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ @@ -2374,7 +2374,7 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu # then set age to 0. # LIBRARY_CURRENT=2 -LIBRARY_REVISION=5 +LIBRARY_REVISION=6 LIBRARY_AGE=0 @@ -2918,7 +2918,7 @@ fi # Define the identity of the package. PACKAGE='lcms2' - VERSION='2.5' + VERSION='2.6' # Some tools Automake needs. @@ -2950,21 +2950,45 @@ am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -' -# Disable JPEG. +# Point to JPEG installed in DIR or disable JPEG with --without-jpeg. # Check whether --with-jpeg was given. if test "${with_jpeg+set}" = set; then : - withval=$with_jpeg; with_jpeg=$withval + withval=$with_jpeg; + if test "x$withval" = "xno" ; then + with_jpeg='no' + else + if test "x$withval" != "xyes" ; then + with_jpeg=$withval + JPEG_DIR=$withval + CPPFLAGS="$CPPFLAGS -I$JPEG_DIR/include" + LDFLAGS="$LDFLAGS -L$JPEG_DIR/lib" + fi + with_jpeg='yes' + fi + else with_jpeg='yes' fi -# Disable TIFF. +# Point to TIFF installed in DIR or disable TIFF with --without-tiff. # Check whether --with-tiff was given. if test "${with_tiff+set}" = set; then : - withval=$with_tiff; with_tiff=$withval + withval=$with_tiff; + if test "x$withval" = "xno" ; then + with_tiff='no' + else + if test "x$withval" != "xyes" ; then + with_tiff=$withval + TIFF_DIR=$withval + CPPFLAGS="$CPPFLAGS -I$TIFF_DIR/include" + LDFLAGS="$LDFLAGS -L$TIFF_DIR/lib" + fi + with_tiff='yes' + fi + else with_tiff='yes' fi @@ -15961,8 +15985,8 @@ have_jpeg='no' LIB_JPEG='' if test ! "$with_jpeg" = 'no' then - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for JPEG support " >&5 -$as_echo_n "checking for JPEG support ... " >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for JPEG support" >&5 +$as_echo_n "checking for JPEG support... " >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: " >&5 $as_echo "" >&6; } failed=0; @@ -16443,8 +16467,8 @@ have_tiff='no' LIB_TIFF='' if test ! "$with_tiff" = 'no' then - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for TIFF support " >&5 -$as_echo_n "checking for TIFF support ... " >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for TIFF support" >&5 +$as_echo_n "checking for TIFF support... " >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: " >&5 $as_echo "" >&6; } failed=0; @@ -17256,7 +17280,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by lcms2 $as_me 2.5, which was +This file was extended by lcms2 $as_me 2.6, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -17313,7 +17337,7 @@ _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ -lcms2 config.status 2.5 +lcms2 config.status 2.6 configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" diff --git a/configure.ac b/configure.ac index 7041865..777a962 100644 --- a/configure.ac +++ b/configure.ac @@ -7,7 +7,7 @@ AC_PREREQ(2.60) # # Set the package name and version # -AC_INIT(lcms2,2.5) +AC_INIT(lcms2,2.6) # # Libtool library revision control info @@ -31,7 +31,7 @@ AC_INIT(lcms2,2.5) # then set age to 0. # LIBRARY_CURRENT=2 -LIBRARY_REVISION=5 +LIBRARY_REVISION=6 LIBRARY_AGE=0 AC_SUBST(LIBRARY_CURRENT)dnl @@ -43,17 +43,41 @@ AC_CANONICAL_HOST AM_INIT_AUTOMAKE([foreign 1.7.2 no-define dist-zip]) -# Disable JPEG. +# Point to JPEG installed in DIR or disable JPEG with --without-jpeg. AC_ARG_WITH(jpeg, - [ --without-jpeg disable JPEG support], - [with_jpeg=$withval], - [with_jpeg='yes']) + [ --with-jpeg=DIR use jpeg installed in DIR], + [ + if [ test "x$withval" = "xno" ]; then + [with_jpeg='no'] + else + if [ test "x$withval" != "xyes" ]; then + with_jpeg=$withval + JPEG_DIR=$withval + CPPFLAGS="$CPPFLAGS -I$JPEG_DIR/include" + LDFLAGS="$LDFLAGS -L$JPEG_DIR/lib" + fi + [with_jpeg='yes'] + fi + ], + [with_jpeg='yes']) -# Disable TIFF. +# Point to TIFF installed in DIR or disable TIFF with --without-tiff. AC_ARG_WITH(tiff, - [ --without-tiff disable TIFF support], - [with_tiff=$withval], - [with_tiff='yes']) + [ --with-tiff=DIR use tiff installed in DIR], + [ + if [ test "x$withval" = "xno" ]; then + [with_tiff='no'] + else + if [ test "x$withval" != "xyes" ]; then + with_tiff=$withval + TIFF_DIR=$withval + CPPFLAGS="$CPPFLAGS -I$TIFF_DIR/include" + LDFLAGS="$LDFLAGS -L$TIFF_DIR/lib" + fi + [with_tiff='yes'] + fi + ], + [with_tiff='yes']) # Disable ZLIB AC_ARG_WITH(zlib, @@ -116,7 +140,7 @@ have_jpeg='no' LIB_JPEG='' if test ! "$with_jpeg" = 'no' then - AC_MSG_CHECKING(for JPEG support ) + AC_MSG_CHECKING([for JPEG support]) AC_MSG_RESULT() failed=0; passed=0; @@ -221,7 +245,7 @@ have_tiff='no' LIB_TIFF='' if test ! "$with_tiff" = 'no' then - AC_MSG_CHECKING(for TIFF support ) + AC_MSG_CHECKING([for TIFF support]) AC_MSG_RESULT() failed=0; passed=0; diff --git a/doc/LittleCMS2.5 API.pdf b/doc/LittleCMS2.5 API.pdf Binary files differdeleted file mode 100755 index 581b244..0000000 --- a/doc/LittleCMS2.5 API.pdf +++ /dev/null diff --git a/doc/LittleCMS2.5 Plugin API.pdf b/doc/LittleCMS2.5 Plugin API.pdf Binary files differdeleted file mode 100755 index 8017972..0000000 --- a/doc/LittleCMS2.5 Plugin API.pdf +++ /dev/null diff --git a/doc/LittleCMS2.5 tutorial.pdf b/doc/LittleCMS2.5 tutorial.pdf Binary files differdeleted file mode 100755 index 13d7596..0000000 --- a/doc/LittleCMS2.5 tutorial.pdf +++ /dev/null diff --git a/doc/LittleCMS2.6 API.pdf b/doc/LittleCMS2.6 API.pdf Binary files differnew file mode 100755 index 0000000..e8e004b --- /dev/null +++ b/doc/LittleCMS2.6 API.pdf diff --git a/doc/LittleCMS2.6 Plugin API.pdf b/doc/LittleCMS2.6 Plugin API.pdf Binary files differnew file mode 100755 index 0000000..3a31286 --- /dev/null +++ b/doc/LittleCMS2.6 Plugin API.pdf diff --git a/doc/LittleCMS2.6 tutorial.pdf b/doc/LittleCMS2.6 tutorial.pdf Binary files differnew file mode 100755 index 0000000..abb2c69 --- /dev/null +++ b/doc/LittleCMS2.6 tutorial.pdf diff --git a/include/lcms2.h b/include/lcms2.h index c801409..c993a4b 100644 --- a/include/lcms2.h +++ b/include/lcms2.h @@ -23,7 +23,7 @@ // //--------------------------------------------------------------------------------- // -// Version 2.6b +// Version 2.6 // #ifndef _lcms2_H @@ -55,6 +55,10 @@ // Uncomment to get rid of the tables for "half" float support // #define CMS_NO_HALF_SUPPORT 1 +// Uncomment to get cmsContext legacy behavior: just a void pointer passed through. +// DON'T USE UNLESS STRICTLY NECESSARY! +// #define CMS_CONTEXT_IN_LEGACY_MODE 1 + // ********** End of configuration toggles ****************************** // Needed for streams @@ -173,10 +177,6 @@ typedef int cmsBool; // Try to detect big endian platforms. This list can be endless, so only some checks are performed over here. // you can pass this toggle to the compiler by using -DCMS_USE_BIG_ENDIAN or something similar -#if defined(_HOST_BIG_ENDIAN) || defined(__BIG_ENDIAN__) || defined(WORDS_BIGENDIAN) -# define CMS_USE_BIG_ENDIAN 1 -#endif - #if defined(__sgi__) || defined(__sgi) || defined(sparc) # define CMS_USE_BIG_ENDIAN 1 #endif @@ -193,14 +193,18 @@ typedef int cmsBool; #if defined(__powerpc__) || defined(__ppc__) || defined(TARGET_CPU_PPC) # define CMS_USE_BIG_ENDIAN 1 -# if defined (__GNUC__) -# if ( __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) -# // Don't use big endian for PowerPC little endian mode +# if defined (__GNUC__) && defined(__BYTE_ORDER) && defined(__LITTLE_ENDIAN) +# if __BYTE_ORDER == __LITTLE_ENDIAN +// // Don't use big endian for PowerPC little endian mode # undef CMS_USE_BIG_ENDIAN -# endif +# endif # endif #endif +// WORDS_BIGENDIAN takes precedence +#if defined(_HOST_BIG_ENDIAN) || defined(__BIG_ENDIAN__) || defined(WORDS_BIGENDIAN) +# define CMS_USE_BIG_ENDIAN 1 +#endif #ifdef macintosh # ifdef __BIG_ENDIAN__ @@ -624,7 +628,6 @@ typedef struct { // Little CMS specific typedefs -typedef void* cmsContext; // Context identifier for multithreaded environments typedef void* cmsHANDLE ; // Generic handle typedef void* cmsHPROFILE; // Opaque typedefs to hide internals typedef void* cmsHTRANSFORM; @@ -994,11 +997,29 @@ typedef struct { CMSAPI int CMSEXPORT cmsstrcasecmp(const char* s1, const char* s2); CMSAPI long int CMSEXPORT cmsfilelength(FILE* f); -// Plug-In registering --------------------------------------------------------------------------------------------------- + +// Context handling -------------------------------------------------------------------------------------------------------- + +// Each context holds its owns globals and its own plug-ins. There is a global context with the id = 0 for lecacy compatibility +// though using the global context is not recomended. Proper context handling makes lcms more thread-safe. + +#ifdef CMS_CONTEXT_IN_LEGACY_MODE + typedef void* cmsContext; +#else + typedef struct _cmsContext_struct* cmsContext; +#endif + +CMSAPI cmsContext CMSEXPORT cmsCreateContext(void* Plugin, void* UserData); +CMSAPI void CMSEXPORT cmsDeleteContext(cmsContext ContexID); +CMSAPI cmsContext CMSEXPORT cmsDupContext(cmsContext ContextID, void* NewUserData); +CMSAPI void* CMSEXPORT cmsGetContextUserData(cmsContext ContextID); + +// Plug-In registering -------------------------------------------------------------------------------------------------- CMSAPI cmsBool CMSEXPORT cmsPlugin(void* Plugin); CMSAPI cmsBool CMSEXPORT cmsPluginTHR(cmsContext ContextID, void* Plugin); CMSAPI void CMSEXPORT cmsUnregisterPlugins(void); +CMSAPI void CMSEXPORT cmsUnregisterPluginsTHR(cmsContext ContextID); // Error logging ---------------------------------------------------------------------------------------------------------- @@ -1035,6 +1056,7 @@ typedef void (* cmsLogErrorHandlerFunction)(cmsContext ContextID, cmsUInt32Numb // Allows user to set any specific logger CMSAPI void CMSEXPORT cmsSetLogErrorHandler(cmsLogErrorHandlerFunction Fn); +CMSAPI void CMSEXPORT cmsSetLogErrorHandlerTHR(cmsContext ContextID, cmsLogErrorHandlerFunction Fn); // Conversions -------------------------------------------------------------------------------------------------------------- @@ -1587,6 +1609,7 @@ CMSAPI cmsHPROFILE CMSEXPORT cmsTransform2DeviceLink(cmsHTRANSFORM hTransfo // Call with NULL as parameters to get the intent count CMSAPI cmsUInt32Number CMSEXPORT cmsGetSupportedIntents(cmsUInt32Number nMax, cmsUInt32Number* Codes, char** Descriptions); +CMSAPI cmsUInt32Number CMSEXPORT cmsGetSupportedIntentsTHR(cmsContext ContextID, cmsUInt32Number nMax, cmsUInt32Number* Codes, char** Descriptions); // Flags @@ -1698,11 +1721,22 @@ CMSAPI void CMSEXPORT cmsDoTransformStride(cmsHTRANSFORM Transform, cmsUInt32Number Stride); -CMSAPI void CMSEXPORT cmsSetAlarmCodes(cmsUInt16Number NewAlarm[cmsMAXCHANNELS]); +CMSAPI void CMSEXPORT cmsSetAlarmCodes(const cmsUInt16Number NewAlarm[cmsMAXCHANNELS]); CMSAPI void CMSEXPORT cmsGetAlarmCodes(cmsUInt16Number NewAlarm[cmsMAXCHANNELS]); + +CMSAPI void CMSEXPORT cmsSetAlarmCodesTHR(cmsContext ContextID, + const cmsUInt16Number AlarmCodes[cmsMAXCHANNELS]); +CMSAPI void CMSEXPORT cmsGetAlarmCodesTHR(cmsContext ContextID, + cmsUInt16Number AlarmCodes[cmsMAXCHANNELS]); + + + // Adaptation state for absolute colorimetric intent CMSAPI cmsFloat64Number CMSEXPORT cmsSetAdaptationState(cmsFloat64Number d); +CMSAPI cmsFloat64Number CMSEXPORT cmsSetAdaptationStateTHR(cmsContext ContextID, cmsFloat64Number d); + + // Grab the ContextID from an open transform. Returns NULL if a NULL transform is passed CMSAPI cmsContext CMSEXPORT cmsGetTransformContextID(cmsHTRANSFORM hTransform); diff --git a/include/lcms2_plugin.h b/include/lcms2_plugin.h index 10e61cb..0c95d1f 100644 --- a/include/lcms2_plugin.h +++ b/include/lcms2_plugin.h @@ -202,6 +202,7 @@ typedef void* (* _cmsDupUserDataFn)(cmsContext ContextID, const void* Data); #define cmsPluginMultiProcessElementSig 0x6D706548 // 'mpeH' #define cmsPluginOptimizationSig 0x6F707448 // 'optH' #define cmsPluginTransformSig 0x7A666D48 // 'xfmH' +#define cmsPluginMutexSig 0x6D747A48 // 'mtxH' typedef struct _cmsPluginBaseStruct { @@ -218,19 +219,28 @@ typedef struct _cmsPluginBaseStruct { //---------------------------------------------------------------------------------------------------------- // Memory handler. Each new plug-in type replaces current behaviour + +typedef void* (* _cmsMallocFnPtrType)(cmsContext ContextID, cmsUInt32Number size); +typedef void (* _cmsFreeFnPtrType)(cmsContext ContextID, void *Ptr); +typedef void* (* _cmsReallocFnPtrType)(cmsContext ContextID, void* Ptr, cmsUInt32Number NewSize); + +typedef void* (* _cmsMalloZerocFnPtrType)(cmsContext ContextID, cmsUInt32Number size); +typedef void* (* _cmsCallocFnPtrType)(cmsContext ContextID, cmsUInt32Number num, cmsUInt32Number size); +typedef void* (* _cmsDupFnPtrType)(cmsContext ContextID, const void* Org, cmsUInt32Number size); + typedef struct { cmsPluginBase base; // Required - void * (* MallocPtr)(cmsContext ContextID, cmsUInt32Number size); - void (* FreePtr)(cmsContext ContextID, void *Ptr); - void * (* ReallocPtr)(cmsContext ContextID, void* Ptr, cmsUInt32Number NewSize); + _cmsMallocFnPtrType MallocPtr; + _cmsFreeFnPtrType FreePtr; + _cmsReallocFnPtrType ReallocPtr; // Optional - void * (* MallocZeroPtr)(cmsContext ContextID, cmsUInt32Number size); - void * (* CallocPtr)(cmsContext ContextID, cmsUInt32Number num, cmsUInt32Number size); - void * (* DupPtr)(cmsContext ContextID, const void* Org, cmsUInt32Number size); + _cmsMalloZerocFnPtrType MallocZeroPtr; + _cmsCallocFnPtrType CallocPtr; + _cmsDupFnPtrType DupPtr; } cmsPluginMemHandler; @@ -593,6 +603,29 @@ typedef struct { } cmsPluginTransform; +//---------------------------------------------------------------------------------------------------------- +// Mutex + +typedef void* (* _cmsCreateMutexFnPtrType)(cmsContext ContextID); +typedef void (* _cmsDestroyMutexFnPtrType)(cmsContext ContextID, void* mtx); +typedef cmsBool (* _cmsLockMutexFnPtrType)(cmsContext ContextID, void* mtx); +typedef void (* _cmsUnlockMutexFnPtrType)(cmsContext ContextID, void* mtx); + +typedef struct { + cmsPluginBase base; + + _cmsCreateMutexFnPtrType CreateMutexPtr; + _cmsDestroyMutexFnPtrType DestroyMutexPtr; + _cmsLockMutexFnPtrType LockMutexPtr; + _cmsUnlockMutexFnPtrType UnlockMutexPtr; + +} cmsPluginMutex; + +CMSAPI void* CMSEXPORT _cmsCreateMutex(cmsContext ContextID); +CMSAPI void CMSEXPORT _cmsDestroyMutex(cmsContext ContextID, void* mtx); +CMSAPI cmsBool CMSEXPORT _cmsLockMutex(cmsContext ContextID, void* mtx); +CMSAPI void CMSEXPORT _cmsUnlockMutex(cmsContext ContextID, void* mtx); + #ifndef CMS_USE_CPP_API # ifdef __cplusplus diff --git a/src/cmscam02.c b/src/cmscam02.c index 2a8cf04..9d874aa 100644 --- a/src/cmscam02.c +++ b/src/cmscam02.c @@ -437,12 +437,13 @@ void CMSEXPORT cmsCIECAM02Forward(cmsHANDLE hModel, const cmsCIEXYZ* pIn, cmsJCh { CAM02COLOR clr; cmsCIECAM02* lpMod = (cmsCIECAM02*) hModel; - - memset(&clr, 0, sizeof(clr)); + _cmsAssert(lpMod != NULL); _cmsAssert(pIn != NULL); _cmsAssert(pOut != NULL); + memset(&clr, 0, sizeof(clr)); + clr.XYZ[0] = pIn ->X; clr.XYZ[1] = pIn ->Y; clr.XYZ[2] = pIn ->Z; @@ -462,12 +463,13 @@ void CMSEXPORT cmsCIECAM02Reverse(cmsHANDLE hModel, const cmsJCh* pIn, cmsCIEXYZ { CAM02COLOR clr; cmsCIECAM02* lpMod = (cmsCIECAM02*) hModel; - - memset(&clr, 0, sizeof(clr)); + _cmsAssert(lpMod != NULL); _cmsAssert(pIn != NULL); _cmsAssert(pOut != NULL); + memset(&clr, 0, sizeof(clr)); + clr.J = pIn -> J; clr.C = pIn -> C; clr.h = pIn -> h; diff --git a/src/cmscnvrt.c b/src/cmscnvrt.c index 4696cc8..1a93e83 100644 --- a/src/cmscnvrt.c +++ b/src/cmscnvrt.c @@ -108,15 +108,68 @@ static cmsIntentsList DefaultIntents[] = { // A pointer to the begining of the list -static cmsIntentsList *Intents = DefaultIntents; +_cmsIntentsPluginChunkType _cmsIntentsPluginChunk = { NULL }; + +// Duplicates the zone of memory used by the plug-in in the new context +static +void DupPluginIntentsList(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src) +{ + _cmsIntentsPluginChunkType newHead = { NULL }; + cmsIntentsList* entry; + cmsIntentsList* Anterior = NULL; + _cmsIntentsPluginChunkType* head = (_cmsIntentsPluginChunkType*) src->chunks[IntentPlugin]; + + // Walk the list copying all nodes + for (entry = head->Intents; + entry != NULL; + entry = entry ->Next) { + + cmsIntentsList *newEntry = ( cmsIntentsList *) _cmsSubAllocDup(ctx ->MemPool, entry, sizeof(cmsIntentsList)); + + if (newEntry == NULL) + return; + + // We want to keep the linked list order, so this is a little bit tricky + newEntry -> Next = NULL; + if (Anterior) + Anterior -> Next = newEntry; + + Anterior = newEntry; + + if (newHead.Intents == NULL) + newHead.Intents = newEntry; + } + + ctx ->chunks[IntentPlugin] = _cmsSubAllocDup(ctx->MemPool, &newHead, sizeof(_cmsIntentsPluginChunkType)); +} + +void _cmsAllocIntentsPluginChunk(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src) +{ + if (src != NULL) { + + // Copy all linked list + DupPluginIntentsList(ctx, src); + } + else { + static _cmsIntentsPluginChunkType IntentsPluginChunkType = { NULL }; + ctx ->chunks[IntentPlugin] = _cmsSubAllocDup(ctx ->MemPool, &IntentsPluginChunkType, sizeof(_cmsIntentsPluginChunkType)); + } +} + // Search the list for a suitable intent. Returns NULL if not found static -cmsIntentsList* SearchIntent(cmsUInt32Number Intent) +cmsIntentsList* SearchIntent(cmsContext ContextID, cmsUInt32Number Intent) { + _cmsIntentsPluginChunkType* ctx = ( _cmsIntentsPluginChunkType*) _cmsContextGetClientChunk(ContextID, IntentPlugin); cmsIntentsList* pt; - for (pt = Intents; pt != NULL; pt = pt -> Next) + for (pt = ctx -> Intents; pt != NULL; pt = pt -> Next) + if (pt ->Intent == Intent) return pt; + + for (pt = DefaultIntents; pt != NULL; pt = pt -> Next) if (pt ->Intent == Intent) return pt; return NULL; @@ -1002,7 +1055,7 @@ cmsPipeline* _cmsLinkProfiles(cmsContext ContextID, // this case would present some issues if the custom intent tries to do things like // preserve primaries. This solution is not perfect, but works well on most cases. - Intent = SearchIntent(TheIntents[0]); + Intent = SearchIntent(ContextID, TheIntents[0]); if (Intent == NULL) { cmsSignalError(ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported intent '%d'", TheIntents[0]); return NULL; @@ -1017,12 +1070,14 @@ cmsPipeline* _cmsLinkProfiles(cmsContext ContextID, // Get information about available intents. nMax is the maximum space for the supplied "Codes" // and "Descriptions" the function returns the total number of intents, which may be greater // than nMax, although the matrices are not populated beyond this level. -cmsUInt32Number CMSEXPORT cmsGetSupportedIntents(cmsUInt32Number nMax, cmsUInt32Number* Codes, char** Descriptions) +cmsUInt32Number CMSEXPORT cmsGetSupportedIntentsTHR(cmsContext ContextID, cmsUInt32Number nMax, cmsUInt32Number* Codes, char** Descriptions) { + _cmsIntentsPluginChunkType* ctx = ( _cmsIntentsPluginChunkType*) _cmsContextGetClientChunk(ContextID, IntentPlugin); cmsIntentsList* pt; cmsUInt32Number nIntents; - for (nIntents=0, pt = Intents; pt != NULL; pt = pt -> Next) + + for (nIntents=0, pt = ctx->Intents; pt != NULL; pt = pt -> Next) { if (nIntents < nMax) { if (Codes != NULL) @@ -1035,37 +1090,52 @@ cmsUInt32Number CMSEXPORT cmsGetSupportedIntents(cmsUInt32Number nMax, cmsUInt32 nIntents++; } + for (nIntents=0, pt = DefaultIntents; pt != NULL; pt = pt -> Next) + { + if (nIntents < nMax) { + if (Codes != NULL) + Codes[nIntents] = pt ->Intent; + + if (Descriptions != NULL) + Descriptions[nIntents] = pt ->Description; + } + + nIntents++; + } return nIntents; } +cmsUInt32Number CMSEXPORT cmsGetSupportedIntents(cmsUInt32Number nMax, cmsUInt32Number* Codes, char** Descriptions) +{ + return cmsGetSupportedIntentsTHR(NULL, nMax, Codes, Descriptions); +} + // The plug-in registration. User can add new intents or override default routines cmsBool _cmsRegisterRenderingIntentPlugin(cmsContext id, cmsPluginBase* Data) { + _cmsIntentsPluginChunkType* ctx = ( _cmsIntentsPluginChunkType*) _cmsContextGetClientChunk(id, IntentPlugin); cmsPluginRenderingIntent* Plugin = (cmsPluginRenderingIntent*) Data; cmsIntentsList* fl; - // Do we have to reset the intents? + // Do we have to reset the custom intents? if (Data == NULL) { - Intents = DefaultIntents; - return TRUE; + ctx->Intents = NULL; + return TRUE; } - fl = SearchIntent(Plugin ->Intent); + fl = (cmsIntentsList*) _cmsPluginMalloc(id, sizeof(cmsIntentsList)); + if (fl == NULL) return FALSE; - if (fl == NULL) { - fl = (cmsIntentsList*) _cmsPluginMalloc(id, sizeof(cmsIntentsList)); - if (fl == NULL) return FALSE; - } fl ->Intent = Plugin ->Intent; - strncpy(fl ->Description, Plugin ->Description, 255); - fl ->Description[255] = 0; + strncpy(fl ->Description, Plugin ->Description, sizeof(fl ->Description)-1); + fl ->Description[sizeof(fl ->Description)-1] = 0; fl ->Link = Plugin ->Link; - fl ->Next = Intents; - Intents = fl; + fl ->Next = ctx ->Intents; + ctx ->Intents = fl; return TRUE; } diff --git a/src/cmserr.c b/src/cmserr.c index 166793f..4bfc0a7 100644 --- a/src/cmserr.c +++ b/src/cmserr.c @@ -31,13 +31,14 @@ // compare two strings ignoring case int CMSEXPORT cmsstrcasecmp(const char* s1, const char* s2) { - register const unsigned char *us1 = (const unsigned char *)s1, - *us2 = (const unsigned char *)s2; + register const unsigned char *us1 = (const unsigned char *)s1, + *us2 = (const unsigned char *)s2; - while (toupper(*us1) == toupper(*us2++)) - if (*us1++ == '\0') - return (0); - return (toupper(*us1) - toupper(*--us2)); + while (toupper(*us1) == toupper(*us2++)) + if (*us1++ == '\0') + return 0; + + return (toupper(*us1) - toupper(*--us2)); } // long int because C99 specifies ftell in such way (7.19.9.2) @@ -62,9 +63,8 @@ long int CMSEXPORT cmsfilelength(FILE* f) // // This is the interface to low-level memory management routines. By default a simple // wrapping to malloc/free/realloc is provided, although there is a limit on the max -// amount of memoy that can be reclaimed. This is mostly as a safety feature to -// prevent bogus or malintentionated code to allocate huge blocks that otherwise lcms -// would never need. +// amount of memoy that can be reclaimed. This is mostly as a safety feature to prevent +// bogus or evil code to allocate huge blocks that otherwise lcms would never need. #define MAX_MEMORY_FOR_ALLOC ((cmsUInt32Number)(1024U*1024U*512U)) @@ -74,7 +74,7 @@ long int CMSEXPORT cmsfilelength(FILE* f) // required to be implemented: malloc, realloc and free, although the user may want to // replace the optional mallocZero, calloc and dup as well. -cmsBool _cmsRegisterMemHandlerPlugin(cmsPluginBase* Plugin); +cmsBool _cmsRegisterMemHandlerPlugin(cmsContext ContextID, cmsPluginBase* Plugin); // ********************************************************************************* @@ -114,7 +114,7 @@ void _cmsFreeDefaultFn(cmsContext ContextID, void *Ptr) cmsUNUSED_PARAMETER(ContextID); } -// The default realloc function. Again it check for exploits. If Ptr is NULL, +// The default realloc function. Again it checks for exploits. If Ptr is NULL, // realloc behaves the same way as malloc and allocates a new block of size bytes. static void* _cmsReallocDefaultFn(cmsContext ContextID, void* Ptr, cmsUInt32Number size) @@ -167,28 +167,73 @@ void* _cmsDupDefaultFn(cmsContext ContextID, const void* Org, cmsUInt32Number si return mem; } -// Pointers to malloc and _cmsFree functions in current environment -static void * (* MallocPtr)(cmsContext ContextID, cmsUInt32Number size) = _cmsMallocDefaultFn; -static void * (* MallocZeroPtr)(cmsContext ContextID, cmsUInt32Number size) = _cmsMallocZeroDefaultFn; -static void (* FreePtr)(cmsContext ContextID, void *Ptr) = _cmsFreeDefaultFn; -static void * (* ReallocPtr)(cmsContext ContextID, void *Ptr, cmsUInt32Number NewSize) = _cmsReallocDefaultFn; -static void * (* CallocPtr)(cmsContext ContextID, cmsUInt32Number num, cmsUInt32Number size)= _cmsCallocDefaultFn; -static void * (* DupPtr)(cmsContext ContextID, const void* Org, cmsUInt32Number size) = _cmsDupDefaultFn; + +// Pointers to memory manager functions in Context0 +_cmsMemPluginChunkType _cmsMemPluginChunk = { _cmsMallocDefaultFn, _cmsMallocZeroDefaultFn, _cmsFreeDefaultFn, + _cmsReallocDefaultFn, _cmsCallocDefaultFn, _cmsDupDefaultFn + }; + + +// Reset and duplicate memory manager +void _cmsAllocMemPluginChunk(struct _cmsContext_struct* ctx, const struct _cmsContext_struct* src) +{ + _cmsAssert(ctx != NULL); + + if (src != NULL) { + + // Duplicate + ctx ->chunks[MemPlugin] = _cmsSubAllocDup(ctx ->MemPool, src ->chunks[MemPlugin], sizeof(_cmsMemPluginChunkType)); + } + else { + + // To reset it, we use the default allocators, which cannot be overriden + ctx ->chunks[MemPlugin] = &ctx ->DefaultMemoryManager; + } +} + +// Auxiliar to fill memory management functions from plugin (or context 0 defaults) +void _cmsInstallAllocFunctions(cmsPluginMemHandler* Plugin, _cmsMemPluginChunkType* ptr) +{ + if (Plugin == NULL) { + + memcpy(ptr, &_cmsMemPluginChunk, sizeof(_cmsMemPluginChunk)); + } + else { + + ptr ->MallocPtr = Plugin -> MallocPtr; + ptr ->FreePtr = Plugin -> FreePtr; + ptr ->ReallocPtr = Plugin -> ReallocPtr; + + // Make sure we revert to defaults + ptr ->MallocZeroPtr= _cmsMallocZeroDefaultFn; + ptr ->CallocPtr = _cmsCallocDefaultFn; + ptr ->DupPtr = _cmsDupDefaultFn; + + if (Plugin ->MallocZeroPtr != NULL) ptr ->MallocZeroPtr = Plugin -> MallocZeroPtr; + if (Plugin ->CallocPtr != NULL) ptr ->CallocPtr = Plugin -> CallocPtr; + if (Plugin ->DupPtr != NULL) ptr ->DupPtr = Plugin -> DupPtr; + + } +} + // Plug-in replacement entry -cmsBool _cmsRegisterMemHandlerPlugin(cmsPluginBase *Data) +cmsBool _cmsRegisterMemHandlerPlugin(cmsContext ContextID, cmsPluginBase *Data) { - cmsPluginMemHandler* Plugin = (cmsPluginMemHandler*) Data; + cmsPluginMemHandler* Plugin = (cmsPluginMemHandler*) Data; + _cmsMemPluginChunkType* ptr; - // NULL forces to reset to defaults + // NULL forces to reset to defaults. In this special case, the defaults are stored in the context structure. + // Remaining plug-ins does NOT have any copy in the context structure, but this is somehow special as the + // context internal data should be malloce'd by using those functions. if (Data == NULL) { - MallocPtr = _cmsMallocDefaultFn; - MallocZeroPtr= _cmsMallocZeroDefaultFn; - FreePtr = _cmsFreeDefaultFn; - ReallocPtr = _cmsReallocDefaultFn; - CallocPtr = _cmsCallocDefaultFn; - DupPtr = _cmsDupDefaultFn; + struct _cmsContext_struct* ctx = ( struct _cmsContext_struct*) ContextID; + + // Return to the default allocators + if (ContextID != NULL) { + ctx->chunks[MemPlugin] = (void*) &ctx->DefaultMemoryManager; + } return TRUE; } @@ -198,51 +243,56 @@ cmsBool _cmsRegisterMemHandlerPlugin(cmsPluginBase *Data) Plugin -> ReallocPtr == NULL) return FALSE; // Set replacement functions - MallocPtr = Plugin -> MallocPtr; - FreePtr = Plugin -> FreePtr; - ReallocPtr = Plugin -> ReallocPtr; - - if (Plugin ->MallocZeroPtr != NULL) MallocZeroPtr = Plugin ->MallocZeroPtr; - if (Plugin ->CallocPtr != NULL) CallocPtr = Plugin -> CallocPtr; - if (Plugin ->DupPtr != NULL) DupPtr = Plugin -> DupPtr; + ptr = (_cmsMemPluginChunkType*) _cmsContextGetClientChunk(ContextID, MemPlugin); + if (ptr == NULL) + return FALSE; + _cmsInstallAllocFunctions(Plugin, ptr); return TRUE; } // Generic allocate void* CMSEXPORT _cmsMalloc(cmsContext ContextID, cmsUInt32Number size) { - return MallocPtr(ContextID, size); + _cmsMemPluginChunkType* ptr = (_cmsMemPluginChunkType*) _cmsContextGetClientChunk(ContextID, MemPlugin); + return ptr ->MallocPtr(ContextID, size); } // Generic allocate & zero void* CMSEXPORT _cmsMallocZero(cmsContext ContextID, cmsUInt32Number size) { - return MallocZeroPtr(ContextID, size); + _cmsMemPluginChunkType* ptr = (_cmsMemPluginChunkType*) _cmsContextGetClientChunk(ContextID, MemPlugin); + return ptr->MallocZeroPtr(ContextID, size); } // Generic calloc void* CMSEXPORT _cmsCalloc(cmsContext ContextID, cmsUInt32Number num, cmsUInt32Number size) { - return CallocPtr(ContextID, num, size); + _cmsMemPluginChunkType* ptr = (_cmsMemPluginChunkType*) _cmsContextGetClientChunk(ContextID, MemPlugin); + return ptr->CallocPtr(ContextID, num, size); } // Generic reallocate void* CMSEXPORT _cmsRealloc(cmsContext ContextID, void* Ptr, cmsUInt32Number size) { - return ReallocPtr(ContextID, Ptr, size); + _cmsMemPluginChunkType* ptr = (_cmsMemPluginChunkType*) _cmsContextGetClientChunk(ContextID, MemPlugin); + return ptr->ReallocPtr(ContextID, Ptr, size); } // Generic free memory void CMSEXPORT _cmsFree(cmsContext ContextID, void* Ptr) { - if (Ptr != NULL) FreePtr(ContextID, Ptr); + if (Ptr != NULL) { + _cmsMemPluginChunkType* ptr = (_cmsMemPluginChunkType*) _cmsContextGetClientChunk(ContextID, MemPlugin); + ptr ->FreePtr(ContextID, Ptr); + } } // Generic block duplication void* CMSEXPORT _cmsDupMem(cmsContext ContextID, const void* Org, cmsUInt32Number size) { - return DupPtr(ContextID, Org, size); + _cmsMemPluginChunkType* ptr = (_cmsMemPluginChunkType*) _cmsContextGetClientChunk(ContextID, MemPlugin); + return ptr ->DupPtr(ContextID, Org, size); } // ******************************************************************************************** @@ -351,6 +401,26 @@ void* _cmsSubAlloc(_cmsSubAllocator* sub, cmsUInt32Number size) return (void*) ptr; } +// Duplicate in pool +void* _cmsSubAllocDup(_cmsSubAllocator* s, const void *ptr, cmsUInt32Number size) +{ + void *NewPtr; + + // Dup of null pointer is also NULL + if (ptr == NULL) + return NULL; + + NewPtr = _cmsSubAlloc(s, size); + + if (ptr != NULL && NewPtr != NULL) { + memcpy(NewPtr, ptr, size); + } + + return NewPtr; +} + + + // Error logging ****************************************************************** // There is no error handling at all. When a funtion fails, it returns proper value. @@ -372,8 +442,26 @@ void* _cmsSubAlloc(_cmsSubAllocator* sub, cmsUInt32Number size) // This is our default log error static void DefaultLogErrorHandlerFunction(cmsContext ContextID, cmsUInt32Number ErrorCode, const char *Text); -// The current handler in actual environment -static cmsLogErrorHandlerFunction LogErrorHandler = DefaultLogErrorHandlerFunction; +// Context0 storage, which is global +_cmsLogErrorChunkType _cmsLogErrorChunk = { DefaultLogErrorHandlerFunction }; + +// Allocates and inits error logger container for a given context. If src is NULL, only initializes the value +// to the default. Otherwise, it duplicates the value. The interface is standard across all context clients +void _cmsAllocLogErrorChunk(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src) +{ + static _cmsLogErrorChunkType LogErrorChunk = { DefaultLogErrorHandlerFunction }; + void* from; + + if (src != NULL) { + from = src ->chunks[Logger]; + } + else { + from = &LogErrorChunk; + } + + ctx ->chunks[Logger] = _cmsSubAllocDup(ctx ->MemPool, from, sizeof(_cmsLogErrorChunkType)); +} // The default error logger does nothing. static @@ -387,13 +475,24 @@ void DefaultLogErrorHandlerFunction(cmsContext ContextID, cmsUInt32Number ErrorC cmsUNUSED_PARAMETER(Text); } -// Change log error +// Change log error, context based +void CMSEXPORT cmsSetLogErrorHandlerTHR(cmsContext ContextID, cmsLogErrorHandlerFunction Fn) +{ + _cmsLogErrorChunkType* lhg = (_cmsLogErrorChunkType*) _cmsContextGetClientChunk(ContextID, Logger); + + if (lhg != NULL) { + + if (Fn == NULL) + lhg -> LogErrorHandler = DefaultLogErrorHandlerFunction; + else + lhg -> LogErrorHandler = Fn; + } +} + +// Change log error, legacy void CMSEXPORT cmsSetLogErrorHandler(cmsLogErrorHandlerFunction Fn) { - if (Fn == NULL) - LogErrorHandler = DefaultLogErrorHandlerFunction; - else - LogErrorHandler = Fn; + cmsSetLogErrorHandlerTHR(NULL, Fn); } // Log an error @@ -402,13 +501,18 @@ void CMSEXPORT cmsSignalError(cmsContext ContextID, cmsUInt32Number ErrorCode, c { va_list args; char Buffer[MAX_ERROR_MESSAGE_LEN]; + _cmsLogErrorChunkType* lhg; + va_start(args, ErrorText); vsnprintf(Buffer, MAX_ERROR_MESSAGE_LEN-1, ErrorText, args); va_end(args); - // Call handler - LogErrorHandler(ContextID, ErrorCode, Buffer); + // Check for the context, if specified go there. If not, go for the global + lhg = (_cmsLogErrorChunkType*) _cmsContextGetClientChunk(ContextID, Logger); + if (lhg ->LogErrorHandler) { + lhg ->LogErrorHandler(ContextID, ErrorCode, Buffer); + } } // Utility function to print signatures @@ -426,3 +530,93 @@ void _cmsTagSignature2String(char String[5], cmsTagSignature sig) String[4] = 0; } +//-------------------------------------------------------------------------------------------------- + +// Pointers to memory manager functions in Context0 +_cmsMutexPluginChunkType _cmsMutexPluginChunk = { NULL, NULL, NULL, NULL }; + +// Allocate and init mutex container. +void _cmsAllocMutexPluginChunk(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src) +{ + static _cmsMutexPluginChunkType MutexChunk = { NULL, NULL, NULL, NULL }; + void* from; + + if (src != NULL) { + from = src ->chunks[MutexPlugin]; + } + else { + from = &MutexChunk; + } + + ctx ->chunks[MutexPlugin] = _cmsSubAllocDup(ctx ->MemPool, from, sizeof(_cmsMutexPluginChunkType)); +} + +// Register new ways to transform +cmsBool _cmsRegisterMutexPlugin(cmsContext ContextID, cmsPluginBase* Data) +{ + cmsPluginMutex* Plugin = (cmsPluginMutex*) Data; + _cmsMutexPluginChunkType* ctx = ( _cmsMutexPluginChunkType*) _cmsContextGetClientChunk(ContextID, MutexPlugin); + + if (Data == NULL) { + + // No lock routines + ctx->CreateMutexPtr = NULL; + ctx->DestroyMutexPtr = NULL; + ctx->LockMutexPtr = NULL; + ctx ->UnlockMutexPtr = NULL; + return TRUE; + } + + // Factory callback is required + if (Plugin ->CreateMutexPtr == NULL || Plugin ->DestroyMutexPtr == NULL || + Plugin ->LockMutexPtr == NULL || Plugin ->UnlockMutexPtr == NULL) return FALSE; + + + ctx->CreateMutexPtr = Plugin->CreateMutexPtr; + ctx->DestroyMutexPtr = Plugin ->DestroyMutexPtr; + ctx ->LockMutexPtr = Plugin ->LockMutexPtr; + ctx ->UnlockMutexPtr = Plugin ->UnlockMutexPtr; + + // All is ok + return TRUE; +} + +// Generic Mutex fns +void* CMSEXPORT _cmsCreateMutex(cmsContext ContextID) +{ + _cmsMutexPluginChunkType* ptr = (_cmsMutexPluginChunkType*) _cmsContextGetClientChunk(ContextID, MutexPlugin); + + if (ptr ->CreateMutexPtr == NULL) return NULL; + + return ptr ->CreateMutexPtr(ContextID); +} + +void CMSEXPORT _cmsDestroyMutex(cmsContext ContextID, void* mtx) +{ + _cmsMutexPluginChunkType* ptr = (_cmsMutexPluginChunkType*) _cmsContextGetClientChunk(ContextID, MutexPlugin); + + if (ptr ->DestroyMutexPtr != NULL) { + + ptr ->DestroyMutexPtr(ContextID, mtx); + } +} + +cmsBool CMSEXPORT _cmsLockMutex(cmsContext ContextID, void* mtx) +{ + _cmsMutexPluginChunkType* ptr = (_cmsMutexPluginChunkType*) _cmsContextGetClientChunk(ContextID, MutexPlugin); + + if (ptr ->LockMutexPtr == NULL) return TRUE; + + return ptr ->LockMutexPtr(ContextID, mtx); +} + +void CMSEXPORT _cmsUnlockMutex(cmsContext ContextID, void* mtx) +{ + _cmsMutexPluginChunkType* ptr = (_cmsMutexPluginChunkType*) _cmsContextGetClientChunk(ContextID, MutexPlugin); + + if (ptr ->UnlockMutexPtr != NULL) { + + ptr ->UnlockMutexPtr(ContextID, mtx); + } +} diff --git a/src/cmsgamma.c b/src/cmsgamma.c index e153103..7869166 100644 --- a/src/cmsgamma.c +++ b/src/cmsgamma.c @@ -53,7 +53,6 @@ typedef struct _cmsParametricCurvesCollection_st { } _cmsParametricCurvesCollection; - // This is the default (built-in) evaluator static cmsFloat64Number DefaultEvalParametricFn(cmsInt32Number Type, const cmsFloat64Number Params[], cmsFloat64Number R); @@ -66,22 +65,77 @@ static _cmsParametricCurvesCollection DefaultCurves = { NULL // Next in chain }; +// Duplicates the zone of memory used by the plug-in in the new context +static +void DupPluginCurvesList(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src) +{ + _cmsCurvesPluginChunkType newHead = { NULL }; + _cmsParametricCurvesCollection* entry; + _cmsParametricCurvesCollection* Anterior = NULL; + _cmsCurvesPluginChunkType* head = (_cmsCurvesPluginChunkType*) src->chunks[CurvesPlugin]; + + _cmsAssert(head != NULL); + + // Walk the list copying all nodes + for (entry = head->ParametricCurves; + entry != NULL; + entry = entry ->Next) { + + _cmsParametricCurvesCollection *newEntry = ( _cmsParametricCurvesCollection *) _cmsSubAllocDup(ctx ->MemPool, entry, sizeof(_cmsParametricCurvesCollection)); + + if (newEntry == NULL) + return; + + // We want to keep the linked list order, so this is a little bit tricky + newEntry -> Next = NULL; + if (Anterior) + Anterior -> Next = newEntry; + + Anterior = newEntry; + + if (newHead.ParametricCurves == NULL) + newHead.ParametricCurves = newEntry; + } + + ctx ->chunks[CurvesPlugin] = _cmsSubAllocDup(ctx->MemPool, &newHead, sizeof(_cmsCurvesPluginChunkType)); +} + +// The allocator have to follow the chain +void _cmsAllocCurvesPluginChunk(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src) +{ + _cmsAssert(ctx != NULL); + + if (src != NULL) { + + // Copy all linked list + DupPluginCurvesList(ctx, src); + } + else { + static _cmsCurvesPluginChunkType CurvesPluginChunk = { NULL }; + ctx ->chunks[CurvesPlugin] = _cmsSubAllocDup(ctx ->MemPool, &CurvesPluginChunk, sizeof(_cmsCurvesPluginChunkType)); + } +} + + // The linked list head -static _cmsParametricCurvesCollection* ParametricCurves = &DefaultCurves; +_cmsCurvesPluginChunkType _cmsCurvesPluginChunk = { NULL }; // As a way to install new parametric curves -cmsBool _cmsRegisterParametricCurvesPlugin(cmsContext id, cmsPluginBase* Data) +cmsBool _cmsRegisterParametricCurvesPlugin(cmsContext ContextID, cmsPluginBase* Data) { + _cmsCurvesPluginChunkType* ctx = ( _cmsCurvesPluginChunkType*) _cmsContextGetClientChunk(ContextID, CurvesPlugin); cmsPluginParametricCurves* Plugin = (cmsPluginParametricCurves*) Data; _cmsParametricCurvesCollection* fl; if (Data == NULL) { - ParametricCurves = &DefaultCurves; + ctx -> ParametricCurves = NULL; return TRUE; } - fl = (_cmsParametricCurvesCollection*) _cmsPluginMalloc(id, sizeof(_cmsParametricCurvesCollection)); + fl = (_cmsParametricCurvesCollection*) _cmsPluginMalloc(ContextID, sizeof(_cmsParametricCurvesCollection)); if (fl == NULL) return FALSE; // Copy the parameters @@ -97,8 +151,8 @@ cmsBool _cmsRegisterParametricCurvesPlugin(cmsContext id, cmsPluginBase* Data) memmove(fl->ParameterCount, Plugin ->ParameterCount, fl->nFunctions * sizeof(cmsUInt32Number)); // Keep linked list - fl ->Next = ParametricCurves; - ParametricCurves = fl; + fl ->Next = ctx->ParametricCurves; + ctx->ParametricCurves = fl; // All is ok return TRUE; @@ -120,12 +174,24 @@ int IsInSet(int Type, _cmsParametricCurvesCollection* c) // Search for the collection which contains a specific type static -_cmsParametricCurvesCollection *GetParametricCurveByType(int Type, int* index) +_cmsParametricCurvesCollection *GetParametricCurveByType(cmsContext ContextID, int Type, int* index) { _cmsParametricCurvesCollection* c; int Position; + _cmsCurvesPluginChunkType* ctx = ( _cmsCurvesPluginChunkType*) _cmsContextGetClientChunk(ContextID, CurvesPlugin); + + for (c = ctx->ParametricCurves; c != NULL; c = c ->Next) { + + Position = IsInSet(Type, c); - for (c = ParametricCurves; c != NULL; c = c ->Next) { + if (Position != -1) { + if (index != NULL) + *index = Position; + return c; + } + } + // If none found, revert for defaults + for (c = &DefaultCurves; c != NULL; c = c ->Next) { Position = IsInSet(Type, c); @@ -222,7 +288,7 @@ cmsToneCurve* AllocateToneCurveStruct(cmsContext ContextID, cmsInt32Number nEntr p ->Segments[i].SampledPoints = NULL; - c = GetParametricCurveByType(Segments[i].Type, NULL); + c = GetParametricCurveByType(ContextID, Segments[i].Type, NULL); if (c != NULL) p ->Evals[i] = c ->Evaluator; } @@ -648,12 +714,12 @@ cmsToneCurve* CMSEXPORT cmsBuildParametricToneCurve(cmsContext ContextID, cmsInt cmsCurveSegment Seg0; int Pos = 0; cmsUInt32Number size; - _cmsParametricCurvesCollection* c = GetParametricCurveByType(Type, &Pos); + _cmsParametricCurvesCollection* c = GetParametricCurveByType(ContextID, Type, &Pos); _cmsAssert(Params != NULL); if (c == NULL) { - cmsSignalError(ContextID, cmsERROR_UNKNOWN_EXTENSION, "Invalid parametric curve type %d", Type); + cmsSignalError(ContextID, cmsERROR_UNKNOWN_EXTENSION, "Invalid parametric curve type %d", Type); return NULL; } @@ -843,7 +909,10 @@ cmsToneCurve* CMSEXPORT cmsReverseToneCurveEx(cmsInt32Number nResultSamples, con _cmsAssert(InCurve != NULL); // Try to reverse it analytically whatever possible - if (InCurve ->nSegments == 1 && InCurve ->Segments[0].Type > 0 && InCurve -> Segments[0].Type <= 5) { + + if (InCurve ->nSegments == 1 && InCurve ->Segments[0].Type > 0 && + /* InCurve -> Segments[0].Type <= 5 */ + GetParametricCurveByType(InCurve ->InterpParams->ContextID, InCurve ->Segments[0].Type, NULL) != NULL) { return cmsBuildParametricToneCurve(InCurve ->InterpParams->ContextID, -(InCurve -> Segments[0].Type), diff --git a/src/cmsgmt.c b/src/cmsgmt.c index 2966f0c..0942765 100644 --- a/src/cmsgmt.c +++ b/src/cmsgmt.c @@ -1,590 +1,590 @@ -//--------------------------------------------------------------------------------- -// -// Little Color Management System -// Copyright (c) 1998-2012 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 "lcms2_internal.h" - - -// Auxiliar: append a Lab identity after the given sequence of profiles -// and return the transform. Lab profile is closed, rest of profiles are kept open. -cmsHTRANSFORM _cmsChain2Lab(cmsContext ContextID, - cmsUInt32Number nProfiles, - cmsUInt32Number InputFormat, - cmsUInt32Number OutputFormat, - const cmsUInt32Number Intents[], - const cmsHPROFILE hProfiles[], - const cmsBool BPC[], - const cmsFloat64Number AdaptationStates[], - cmsUInt32Number dwFlags) -{ - cmsHTRANSFORM xform; - cmsHPROFILE hLab; - cmsHPROFILE ProfileList[256]; - cmsBool BPCList[256]; - cmsFloat64Number AdaptationList[256]; - cmsUInt32Number IntentList[256]; - cmsUInt32Number i; - - // This is a rather big number and there is no need of dynamic memory - // since we are adding a profile, 254 + 1 = 255 and this is the limit - if (nProfiles > 254) return NULL; - - // The output space - hLab = cmsCreateLab4ProfileTHR(ContextID, NULL); - if (hLab == NULL) return NULL; - - // Create a copy of parameters - for (i=0; i < nProfiles; i++) { - - ProfileList[i] = hProfiles[i]; - BPCList[i] = BPC[i]; - AdaptationList[i] = AdaptationStates[i]; - IntentList[i] = Intents[i]; - } - - // Place Lab identity at chain's end. - ProfileList[nProfiles] = hLab; - BPCList[nProfiles] = 0; - AdaptationList[nProfiles] = 1.0; - IntentList[nProfiles] = INTENT_RELATIVE_COLORIMETRIC; - - // Create the transform - xform = cmsCreateExtendedTransform(ContextID, nProfiles + 1, ProfileList, - BPCList, - IntentList, - AdaptationList, - NULL, 0, - InputFormat, - OutputFormat, - dwFlags); - - cmsCloseProfile(hLab); - - return xform; -} - - -// Compute K -> L* relationship. Flags may include black point compensation. In this case, -// the relationship is assumed from the profile with BPC to a black point zero. -static -cmsToneCurve* ComputeKToLstar(cmsContext ContextID, - cmsUInt32Number nPoints, - cmsUInt32Number nProfiles, - const cmsUInt32Number Intents[], - const cmsHPROFILE hProfiles[], - const cmsBool BPC[], - const cmsFloat64Number AdaptationStates[], - cmsUInt32Number dwFlags) -{ - cmsToneCurve* out = NULL; - cmsUInt32Number i; - cmsHTRANSFORM xform; - cmsCIELab Lab; - cmsFloat32Number cmyk[4]; - cmsFloat32Number* SampledPoints; - - xform = _cmsChain2Lab(ContextID, nProfiles, TYPE_CMYK_FLT, TYPE_Lab_DBL, Intents, hProfiles, BPC, AdaptationStates, dwFlags); - if (xform == NULL) return NULL; - - SampledPoints = (cmsFloat32Number*) _cmsCalloc(ContextID, nPoints, sizeof(cmsFloat32Number)); - if (SampledPoints == NULL) goto Error; - - for (i=0; i < nPoints; i++) { - - cmyk[0] = 0; - cmyk[1] = 0; - cmyk[2] = 0; - cmyk[3] = (cmsFloat32Number) ((i * 100.0) / (nPoints-1)); - - cmsDoTransform(xform, cmyk, &Lab, 1); - SampledPoints[i]= (cmsFloat32Number) (1.0 - Lab.L / 100.0); // Negate K for easier operation - } - - out = cmsBuildTabulatedToneCurveFloat(ContextID, nPoints, SampledPoints); - -Error: - - cmsDeleteTransform(xform); - if (SampledPoints) _cmsFree(ContextID, SampledPoints); - - return out; -} - - -// Compute Black tone curve on a CMYK -> CMYK transform. This is done by -// using the proof direction on both profiles to find K->L* relationship -// then joining both curves. dwFlags may include black point compensation. -cmsToneCurve* _cmsBuildKToneCurve(cmsContext ContextID, - cmsUInt32Number nPoints, - cmsUInt32Number nProfiles, - const cmsUInt32Number Intents[], - const cmsHPROFILE hProfiles[], - const cmsBool BPC[], - const cmsFloat64Number AdaptationStates[], - cmsUInt32Number dwFlags) -{ - cmsToneCurve *in, *out, *KTone; - - // Make sure CMYK -> CMYK - if (cmsGetColorSpace(hProfiles[0]) != cmsSigCmykData || - cmsGetColorSpace(hProfiles[nProfiles-1])!= cmsSigCmykData) return NULL; - - - // Make sure last is an output profile - if (cmsGetDeviceClass(hProfiles[nProfiles - 1]) != cmsSigOutputClass) return NULL; - - // Create individual curves. BPC works also as each K to L* is - // computed as a BPC to zero black point in case of L* - in = ComputeKToLstar(ContextID, nPoints, nProfiles - 1, Intents, hProfiles, BPC, AdaptationStates, dwFlags); - if (in == NULL) return NULL; - - out = ComputeKToLstar(ContextID, nPoints, 1, - Intents + (nProfiles - 1), - hProfiles + (nProfiles - 1), - BPC + (nProfiles - 1), - AdaptationStates + (nProfiles - 1), - dwFlags); - if (out == NULL) { - cmsFreeToneCurve(in); - return NULL; - } - - // Build the relationship. This effectively limits the maximum accuracy to 16 bits, but - // since this is used on black-preserving LUTs, we are not loosing accuracy in any case - KTone = cmsJoinToneCurve(ContextID, in, out, nPoints); - - // Get rid of components - cmsFreeToneCurve(in); cmsFreeToneCurve(out); - - // Something went wrong... - if (KTone == NULL) return NULL; - - // Make sure it is monotonic - if (!cmsIsToneCurveMonotonic(KTone)) { - cmsFreeToneCurve(KTone); - return NULL; - } - - return KTone; -} - - -// Gamut LUT Creation ----------------------------------------------------------------------------------------- - -// Used by gamut & softproofing - -typedef struct { - - cmsHTRANSFORM hInput; // From whatever input color space. 16 bits to DBL - cmsHTRANSFORM hForward, hReverse; // Transforms going from Lab to colorant and back - cmsFloat64Number Thereshold; // The thereshold after which is considered out of gamut - - } GAMUTCHAIN; - -// This sampler does compute gamut boundaries by comparing original -// values with a transform going back and forth. Values above ERR_THERESHOLD -// of maximum are considered out of gamut. - -#define ERR_THERESHOLD 5 - - -static -int GamutSampler(register const cmsUInt16Number In[], register cmsUInt16Number Out[], register void* Cargo) -{ - GAMUTCHAIN* t = (GAMUTCHAIN* ) Cargo; - cmsCIELab LabIn1, LabOut1; - cmsCIELab LabIn2, LabOut2; - cmsUInt16Number Proof[cmsMAXCHANNELS], Proof2[cmsMAXCHANNELS]; - cmsFloat64Number dE1, dE2, ErrorRatio; - - // Assume in-gamut by default. - ErrorRatio = 1.0; - - // Convert input to Lab - cmsDoTransform(t -> hInput, In, &LabIn1, 1); - - // converts from PCS to colorant. This always - // does return in-gamut values, - cmsDoTransform(t -> hForward, &LabIn1, Proof, 1); - - // Now, do the inverse, from colorant to PCS. - cmsDoTransform(t -> hReverse, Proof, &LabOut1, 1); - - memmove(&LabIn2, &LabOut1, sizeof(cmsCIELab)); - - // Try again, but this time taking Check as input - cmsDoTransform(t -> hForward, &LabOut1, Proof2, 1); - cmsDoTransform(t -> hReverse, Proof2, &LabOut2, 1); - - // Take difference of direct value - dE1 = cmsDeltaE(&LabIn1, &LabOut1); - - // Take difference of converted value - dE2 = cmsDeltaE(&LabIn2, &LabOut2); - - - // if dE1 is small and dE2 is small, value is likely to be in gamut - if (dE1 < t->Thereshold && dE2 < t->Thereshold) - Out[0] = 0; - else { - - // if dE1 is small and dE2 is big, undefined. Assume in gamut - if (dE1 < t->Thereshold && dE2 > t->Thereshold) - Out[0] = 0; - else - // dE1 is big and dE2 is small, clearly out of gamut - if (dE1 > t->Thereshold && dE2 < t->Thereshold) - Out[0] = (cmsUInt16Number) _cmsQuickFloor((dE1 - t->Thereshold) + .5); - else { - - // dE1 is big and dE2 is also big, could be due to perceptual mapping - // so take error ratio - if (dE2 == 0.0) - ErrorRatio = dE1; - else - ErrorRatio = dE1 / dE2; - - if (ErrorRatio > t->Thereshold) - Out[0] = (cmsUInt16Number) _cmsQuickFloor((ErrorRatio - t->Thereshold) + .5); - else - Out[0] = 0; - } - } - - - return TRUE; -} - -// Does compute a gamut LUT going back and forth across pcs -> relativ. colorimetric intent -> pcs -// the dE obtained is then annotated on the LUT. Values truely out of gamut are clipped to dE = 0xFFFE -// and values changed are supposed to be handled by any gamut remapping, so, are out of gamut as well. -// -// **WARNING: This algorithm does assume that gamut remapping algorithms does NOT move in-gamut colors, -// of course, many perceptual and saturation intents does not work in such way, but relativ. ones should. - -cmsPipeline* _cmsCreateGamutCheckPipeline(cmsContext ContextID, - cmsHPROFILE hProfiles[], - cmsBool BPC[], - cmsUInt32Number Intents[], - cmsFloat64Number AdaptationStates[], - cmsUInt32Number nGamutPCSposition, - cmsHPROFILE hGamut) -{ - cmsHPROFILE hLab; - cmsPipeline* Gamut; - cmsStage* CLUT; - cmsUInt32Number dwFormat; - GAMUTCHAIN Chain; - int nChannels, nGridpoints; - cmsColorSpaceSignature ColorSpace; - cmsUInt32Number i; - cmsHPROFILE ProfileList[256]; - cmsBool BPCList[256]; - cmsFloat64Number AdaptationList[256]; - cmsUInt32Number IntentList[256]; - - memset(&Chain, 0, sizeof(GAMUTCHAIN)); - - - if (nGamutPCSposition <= 0 || nGamutPCSposition > 255) { - cmsSignalError(ContextID, cmsERROR_RANGE, "Wrong position of PCS. 1..255 expected, %d found.", nGamutPCSposition); - return NULL; - } - - hLab = cmsCreateLab4ProfileTHR(ContextID, NULL); - if (hLab == NULL) return NULL; - - - // The figure of merit. On matrix-shaper profiles, should be almost zero as - // the conversion is pretty exact. On LUT based profiles, different resolutions - // of input and output CLUT may result in differences. - - if (cmsIsMatrixShaper(hGamut)) { - - Chain.Thereshold = 1.0; - } - else { - Chain.Thereshold = ERR_THERESHOLD; - } - - - // Create a copy of parameters - for (i=0; i < nGamutPCSposition; i++) { - ProfileList[i] = hProfiles[i]; - BPCList[i] = BPC[i]; - AdaptationList[i] = AdaptationStates[i]; - IntentList[i] = Intents[i]; - } - - // Fill Lab identity - ProfileList[nGamutPCSposition] = hLab; - BPCList[nGamutPCSposition] = 0; - AdaptationList[nGamutPCSposition] = 1.0; - IntentList[nGamutPCSposition] = INTENT_RELATIVE_COLORIMETRIC; - - - ColorSpace = cmsGetColorSpace(hGamut); - - nChannels = cmsChannelsOf(ColorSpace); - nGridpoints = _cmsReasonableGridpointsByColorspace(ColorSpace, cmsFLAGS_HIGHRESPRECALC); - dwFormat = (CHANNELS_SH(nChannels)|BYTES_SH(2)); - - // 16 bits to Lab double - Chain.hInput = cmsCreateExtendedTransform(ContextID, - nGamutPCSposition + 1, - ProfileList, - BPCList, - IntentList, - AdaptationList, - NULL, 0, - dwFormat, TYPE_Lab_DBL, - cmsFLAGS_NOCACHE); - - - // Does create the forward step. Lab double to device - dwFormat = (CHANNELS_SH(nChannels)|BYTES_SH(2)); - Chain.hForward = cmsCreateTransformTHR(ContextID, - hLab, TYPE_Lab_DBL, - hGamut, dwFormat, - INTENT_RELATIVE_COLORIMETRIC, - cmsFLAGS_NOCACHE); - - // Does create the backwards step - Chain.hReverse = cmsCreateTransformTHR(ContextID, hGamut, dwFormat, - hLab, TYPE_Lab_DBL, - INTENT_RELATIVE_COLORIMETRIC, - cmsFLAGS_NOCACHE); - - - // All ok? - if (Chain.hInput && Chain.hForward && Chain.hReverse) { - - // Go on, try to compute gamut LUT from PCS. This consist on a single channel containing - // dE when doing a transform back and forth on the colorimetric intent. - - Gamut = cmsPipelineAlloc(ContextID, 3, 1); - if (Gamut != NULL) { - - CLUT = cmsStageAllocCLut16bit(ContextID, nGridpoints, nChannels, 1, NULL); - if (!cmsPipelineInsertStage(Gamut, cmsAT_BEGIN, CLUT)) { - cmsPipelineFree(Gamut); - Gamut = NULL; - } - else { - cmsStageSampleCLut16bit(CLUT, GamutSampler, (void*) &Chain, 0); - } - } - } - else - Gamut = NULL; // Didn't work... - - // Free all needed stuff. - if (Chain.hInput) cmsDeleteTransform(Chain.hInput); - if (Chain.hForward) cmsDeleteTransform(Chain.hForward); - if (Chain.hReverse) cmsDeleteTransform(Chain.hReverse); - if (hLab) cmsCloseProfile(hLab); - - // And return computed hull - return Gamut; -} - -// Total Area Coverage estimation ---------------------------------------------------------------- - -typedef struct { - cmsUInt32Number nOutputChans; - cmsHTRANSFORM hRoundTrip; - cmsFloat32Number MaxTAC; - cmsFloat32Number MaxInput[cmsMAXCHANNELS]; - -} cmsTACestimator; - - -// This callback just accounts the maximum ink dropped in the given node. It does not populate any -// memory, as the destination table is NULL. Its only purpose it to know the global maximum. -static -int EstimateTAC(register const cmsUInt16Number In[], register cmsUInt16Number Out[], register void * Cargo) -{ - cmsTACestimator* bp = (cmsTACestimator*) Cargo; - cmsFloat32Number RoundTrip[cmsMAXCHANNELS]; - cmsUInt32Number i; - cmsFloat32Number Sum; - - - // Evaluate the xform - cmsDoTransform(bp->hRoundTrip, In, RoundTrip, 1); - - // All all amounts of ink - for (Sum=0, i=0; i < bp ->nOutputChans; i++) - Sum += RoundTrip[i]; - - // If above maximum, keep track of input values - if (Sum > bp ->MaxTAC) { - - bp ->MaxTAC = Sum; - - for (i=0; i < bp ->nOutputChans; i++) { - bp ->MaxInput[i] = In[i]; - } - } - - return TRUE; - - cmsUNUSED_PARAMETER(Out); -} - - -// Detect Total area coverage of the profile -cmsFloat64Number CMSEXPORT cmsDetectTAC(cmsHPROFILE hProfile) -{ - cmsTACestimator bp; - cmsUInt32Number dwFormatter; - cmsUInt32Number GridPoints[MAX_INPUT_DIMENSIONS]; - cmsHPROFILE hLab; - cmsContext ContextID = cmsGetProfileContextID(hProfile); - - // TAC only works on output profiles - if (cmsGetDeviceClass(hProfile) != cmsSigOutputClass) { - return 0; - } - - // Create a fake formatter for result - dwFormatter = cmsFormatterForColorspaceOfProfile(hProfile, 4, TRUE); - - bp.nOutputChans = T_CHANNELS(dwFormatter); - bp.MaxTAC = 0; // Initial TAC is 0 - - // for safety - if (bp.nOutputChans >= cmsMAXCHANNELS) return 0; - - hLab = cmsCreateLab4ProfileTHR(ContextID, NULL); - if (hLab == NULL) return 0; - // Setup a roundtrip on perceptual intent in output profile for TAC estimation - bp.hRoundTrip = cmsCreateTransformTHR(ContextID, hLab, TYPE_Lab_16, - hProfile, dwFormatter, INTENT_PERCEPTUAL, cmsFLAGS_NOOPTIMIZE|cmsFLAGS_NOCACHE); - - cmsCloseProfile(hLab); - if (bp.hRoundTrip == NULL) return 0; - - // For L* we only need black and white. For C* we need many points - GridPoints[0] = 6; - GridPoints[1] = 74; - GridPoints[2] = 74; - - - if (!cmsSliceSpace16(3, GridPoints, EstimateTAC, &bp)) { - bp.MaxTAC = 0; - } - - cmsDeleteTransform(bp.hRoundTrip); - - // Results in % - return bp.MaxTAC; -} - - -// Carefully, clamp on CIELab space. - -cmsBool CMSEXPORT cmsDesaturateLab(cmsCIELab* Lab, - double amax, double amin, - double bmax, double bmin) -{ - - // Whole Luma surface to zero - - if (Lab -> L < 0) { - - Lab-> L = Lab->a = Lab-> b = 0.0; - return FALSE; - } - - // Clamp white, DISCARD HIGHLIGHTS. This is done - // in such way because icc spec doesn't allow the - // use of L>100 as a highlight means. - - if (Lab->L > 100) - Lab -> L = 100; - - // Check out gamut prism, on a, b faces - - if (Lab -> a < amin || Lab->a > amax|| - Lab -> b < bmin || Lab->b > bmax) { - - cmsCIELCh LCh; - double h, slope; - - // Falls outside a, b limits. Transports to LCh space, - // and then do the clipping - - - if (Lab -> a == 0.0) { // Is hue exactly 90? - - // atan will not work, so clamp here - Lab -> b = Lab->b < 0 ? bmin : bmax; - return TRUE; - } - - cmsLab2LCh(&LCh, Lab); - - slope = Lab -> b / Lab -> a; - h = LCh.h; - - // There are 4 zones - - if ((h >= 0. && h < 45.) || - (h >= 315 && h <= 360.)) { - - // clip by amax - Lab -> a = amax; - Lab -> b = amax * slope; - } - else - if (h >= 45. && h < 135.) - { - // clip by bmax - Lab -> b = bmax; - Lab -> a = bmax / slope; - } - else - if (h >= 135. && h < 225.) { - // clip by amin - Lab -> a = amin; - Lab -> b = amin * slope; - - } - else - if (h >= 225. && h < 315.) { - // clip by bmin - Lab -> b = bmin; - Lab -> a = bmin / slope; - } - else { - cmsSignalError(0, cmsERROR_RANGE, "Invalid angle"); - return FALSE; - } - - } - - return TRUE; -} +//---------------------------------------------------------------------------------
+//
+// Little Color Management System
+// Copyright (c) 1998-2012 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 "lcms2_internal.h"
+
+
+// Auxiliar: append a Lab identity after the given sequence of profiles
+// and return the transform. Lab profile is closed, rest of profiles are kept open.
+cmsHTRANSFORM _cmsChain2Lab(cmsContext ContextID,
+ cmsUInt32Number nProfiles,
+ cmsUInt32Number InputFormat,
+ cmsUInt32Number OutputFormat,
+ const cmsUInt32Number Intents[],
+ const cmsHPROFILE hProfiles[],
+ const cmsBool BPC[],
+ const cmsFloat64Number AdaptationStates[],
+ cmsUInt32Number dwFlags)
+{
+ cmsHTRANSFORM xform;
+ cmsHPROFILE hLab;
+ cmsHPROFILE ProfileList[256];
+ cmsBool BPCList[256];
+ cmsFloat64Number AdaptationList[256];
+ cmsUInt32Number IntentList[256];
+ cmsUInt32Number i;
+
+ // This is a rather big number and there is no need of dynamic memory
+ // since we are adding a profile, 254 + 1 = 255 and this is the limit
+ if (nProfiles > 254) return NULL;
+
+ // The output space
+ hLab = cmsCreateLab4ProfileTHR(ContextID, NULL);
+ if (hLab == NULL) return NULL;
+
+ // Create a copy of parameters
+ for (i=0; i < nProfiles; i++) {
+
+ ProfileList[i] = hProfiles[i];
+ BPCList[i] = BPC[i];
+ AdaptationList[i] = AdaptationStates[i];
+ IntentList[i] = Intents[i];
+ }
+
+ // Place Lab identity at chain's end.
+ ProfileList[nProfiles] = hLab;
+ BPCList[nProfiles] = 0;
+ AdaptationList[nProfiles] = 1.0;
+ IntentList[nProfiles] = INTENT_RELATIVE_COLORIMETRIC;
+
+ // Create the transform
+ xform = cmsCreateExtendedTransform(ContextID, nProfiles + 1, ProfileList,
+ BPCList,
+ IntentList,
+ AdaptationList,
+ NULL, 0,
+ InputFormat,
+ OutputFormat,
+ dwFlags);
+
+ cmsCloseProfile(hLab);
+
+ return xform;
+}
+
+
+// Compute K -> L* relationship. Flags may include black point compensation. In this case,
+// the relationship is assumed from the profile with BPC to a black point zero.
+static
+cmsToneCurve* ComputeKToLstar(cmsContext ContextID,
+ cmsUInt32Number nPoints,
+ cmsUInt32Number nProfiles,
+ const cmsUInt32Number Intents[],
+ const cmsHPROFILE hProfiles[],
+ const cmsBool BPC[],
+ const cmsFloat64Number AdaptationStates[],
+ cmsUInt32Number dwFlags)
+{
+ cmsToneCurve* out = NULL;
+ cmsUInt32Number i;
+ cmsHTRANSFORM xform;
+ cmsCIELab Lab;
+ cmsFloat32Number cmyk[4];
+ cmsFloat32Number* SampledPoints;
+
+ xform = _cmsChain2Lab(ContextID, nProfiles, TYPE_CMYK_FLT, TYPE_Lab_DBL, Intents, hProfiles, BPC, AdaptationStates, dwFlags);
+ if (xform == NULL) return NULL;
+
+ SampledPoints = (cmsFloat32Number*) _cmsCalloc(ContextID, nPoints, sizeof(cmsFloat32Number));
+ if (SampledPoints == NULL) goto Error;
+
+ for (i=0; i < nPoints; i++) {
+
+ cmyk[0] = 0;
+ cmyk[1] = 0;
+ cmyk[2] = 0;
+ cmyk[3] = (cmsFloat32Number) ((i * 100.0) / (nPoints-1));
+
+ cmsDoTransform(xform, cmyk, &Lab, 1);
+ SampledPoints[i]= (cmsFloat32Number) (1.0 - Lab.L / 100.0); // Negate K for easier operation
+ }
+
+ out = cmsBuildTabulatedToneCurveFloat(ContextID, nPoints, SampledPoints);
+
+Error:
+
+ cmsDeleteTransform(xform);
+ if (SampledPoints) _cmsFree(ContextID, SampledPoints);
+
+ return out;
+}
+
+
+// Compute Black tone curve on a CMYK -> CMYK transform. This is done by
+// using the proof direction on both profiles to find K->L* relationship
+// then joining both curves. dwFlags may include black point compensation.
+cmsToneCurve* _cmsBuildKToneCurve(cmsContext ContextID,
+ cmsUInt32Number nPoints,
+ cmsUInt32Number nProfiles,
+ const cmsUInt32Number Intents[],
+ const cmsHPROFILE hProfiles[],
+ const cmsBool BPC[],
+ const cmsFloat64Number AdaptationStates[],
+ cmsUInt32Number dwFlags)
+{
+ cmsToneCurve *in, *out, *KTone;
+
+ // Make sure CMYK -> CMYK
+ if (cmsGetColorSpace(hProfiles[0]) != cmsSigCmykData ||
+ cmsGetColorSpace(hProfiles[nProfiles-1])!= cmsSigCmykData) return NULL;
+
+
+ // Make sure last is an output profile
+ if (cmsGetDeviceClass(hProfiles[nProfiles - 1]) != cmsSigOutputClass) return NULL;
+
+ // Create individual curves. BPC works also as each K to L* is
+ // computed as a BPC to zero black point in case of L*
+ in = ComputeKToLstar(ContextID, nPoints, nProfiles - 1, Intents, hProfiles, BPC, AdaptationStates, dwFlags);
+ if (in == NULL) return NULL;
+
+ out = ComputeKToLstar(ContextID, nPoints, 1,
+ Intents + (nProfiles - 1),
+ &hProfiles [nProfiles - 1],
+ BPC + (nProfiles - 1),
+ AdaptationStates + (nProfiles - 1),
+ dwFlags);
+ if (out == NULL) {
+ cmsFreeToneCurve(in);
+ return NULL;
+ }
+
+ // Build the relationship. This effectively limits the maximum accuracy to 16 bits, but
+ // since this is used on black-preserving LUTs, we are not loosing accuracy in any case
+ KTone = cmsJoinToneCurve(ContextID, in, out, nPoints);
+
+ // Get rid of components
+ cmsFreeToneCurve(in); cmsFreeToneCurve(out);
+
+ // Something went wrong...
+ if (KTone == NULL) return NULL;
+
+ // Make sure it is monotonic
+ if (!cmsIsToneCurveMonotonic(KTone)) {
+ cmsFreeToneCurve(KTone);
+ return NULL;
+ }
+
+ return KTone;
+}
+
+
+// Gamut LUT Creation -----------------------------------------------------------------------------------------
+
+// Used by gamut & softproofing
+
+typedef struct {
+
+ cmsHTRANSFORM hInput; // From whatever input color space. 16 bits to DBL
+ cmsHTRANSFORM hForward, hReverse; // Transforms going from Lab to colorant and back
+ cmsFloat64Number Thereshold; // The thereshold after which is considered out of gamut
+
+ } GAMUTCHAIN;
+
+// This sampler does compute gamut boundaries by comparing original
+// values with a transform going back and forth. Values above ERR_THERESHOLD
+// of maximum are considered out of gamut.
+
+#define ERR_THERESHOLD 5
+
+
+static
+int GamutSampler(register const cmsUInt16Number In[], register cmsUInt16Number Out[], register void* Cargo)
+{
+ GAMUTCHAIN* t = (GAMUTCHAIN* ) Cargo;
+ cmsCIELab LabIn1, LabOut1;
+ cmsCIELab LabIn2, LabOut2;
+ cmsUInt16Number Proof[cmsMAXCHANNELS], Proof2[cmsMAXCHANNELS];
+ cmsFloat64Number dE1, dE2, ErrorRatio;
+
+ // Assume in-gamut by default.
+ ErrorRatio = 1.0;
+
+ // Convert input to Lab
+ cmsDoTransform(t -> hInput, In, &LabIn1, 1);
+
+ // converts from PCS to colorant. This always
+ // does return in-gamut values,
+ cmsDoTransform(t -> hForward, &LabIn1, Proof, 1);
+
+ // Now, do the inverse, from colorant to PCS.
+ cmsDoTransform(t -> hReverse, Proof, &LabOut1, 1);
+
+ memmove(&LabIn2, &LabOut1, sizeof(cmsCIELab));
+
+ // Try again, but this time taking Check as input
+ cmsDoTransform(t -> hForward, &LabOut1, Proof2, 1);
+ cmsDoTransform(t -> hReverse, Proof2, &LabOut2, 1);
+
+ // Take difference of direct value
+ dE1 = cmsDeltaE(&LabIn1, &LabOut1);
+
+ // Take difference of converted value
+ dE2 = cmsDeltaE(&LabIn2, &LabOut2);
+
+
+ // if dE1 is small and dE2 is small, value is likely to be in gamut
+ if (dE1 < t->Thereshold && dE2 < t->Thereshold)
+ Out[0] = 0;
+ else {
+
+ // if dE1 is small and dE2 is big, undefined. Assume in gamut
+ if (dE1 < t->Thereshold && dE2 > t->Thereshold)
+ Out[0] = 0;
+ else
+ // dE1 is big and dE2 is small, clearly out of gamut
+ if (dE1 > t->Thereshold && dE2 < t->Thereshold)
+ Out[0] = (cmsUInt16Number) _cmsQuickFloor((dE1 - t->Thereshold) + .5);
+ else {
+
+ // dE1 is big and dE2 is also big, could be due to perceptual mapping
+ // so take error ratio
+ if (dE2 == 0.0)
+ ErrorRatio = dE1;
+ else
+ ErrorRatio = dE1 / dE2;
+
+ if (ErrorRatio > t->Thereshold)
+ Out[0] = (cmsUInt16Number) _cmsQuickFloor((ErrorRatio - t->Thereshold) + .5);
+ else
+ Out[0] = 0;
+ }
+ }
+
+
+ return TRUE;
+}
+
+// Does compute a gamut LUT going back and forth across pcs -> relativ. colorimetric intent -> pcs
+// the dE obtained is then annotated on the LUT. Values truely out of gamut are clipped to dE = 0xFFFE
+// and values changed are supposed to be handled by any gamut remapping, so, are out of gamut as well.
+//
+// **WARNING: This algorithm does assume that gamut remapping algorithms does NOT move in-gamut colors,
+// of course, many perceptual and saturation intents does not work in such way, but relativ. ones should.
+
+cmsPipeline* _cmsCreateGamutCheckPipeline(cmsContext ContextID,
+ cmsHPROFILE hProfiles[],
+ cmsBool BPC[],
+ cmsUInt32Number Intents[],
+ cmsFloat64Number AdaptationStates[],
+ cmsUInt32Number nGamutPCSposition,
+ cmsHPROFILE hGamut)
+{
+ cmsHPROFILE hLab;
+ cmsPipeline* Gamut;
+ cmsStage* CLUT;
+ cmsUInt32Number dwFormat;
+ GAMUTCHAIN Chain;
+ int nChannels, nGridpoints;
+ cmsColorSpaceSignature ColorSpace;
+ cmsUInt32Number i;
+ cmsHPROFILE ProfileList[256];
+ cmsBool BPCList[256];
+ cmsFloat64Number AdaptationList[256];
+ cmsUInt32Number IntentList[256];
+
+ memset(&Chain, 0, sizeof(GAMUTCHAIN));
+
+
+ if (nGamutPCSposition <= 0 || nGamutPCSposition > 255) {
+ cmsSignalError(ContextID, cmsERROR_RANGE, "Wrong position of PCS. 1..255 expected, %d found.", nGamutPCSposition);
+ return NULL;
+ }
+
+ hLab = cmsCreateLab4ProfileTHR(ContextID, NULL);
+ if (hLab == NULL) return NULL;
+
+
+ // The figure of merit. On matrix-shaper profiles, should be almost zero as
+ // the conversion is pretty exact. On LUT based profiles, different resolutions
+ // of input and output CLUT may result in differences.
+
+ if (cmsIsMatrixShaper(hGamut)) {
+
+ Chain.Thereshold = 1.0;
+ }
+ else {
+ Chain.Thereshold = ERR_THERESHOLD;
+ }
+
+
+ // Create a copy of parameters
+ for (i=0; i < nGamutPCSposition; i++) {
+ ProfileList[i] = hProfiles[i];
+ BPCList[i] = BPC[i];
+ AdaptationList[i] = AdaptationStates[i];
+ IntentList[i] = Intents[i];
+ }
+
+ // Fill Lab identity
+ ProfileList[nGamutPCSposition] = hLab;
+ BPCList[nGamutPCSposition] = 0;
+ AdaptationList[nGamutPCSposition] = 1.0;
+ IntentList[nGamutPCSposition] = INTENT_RELATIVE_COLORIMETRIC;
+
+
+ ColorSpace = cmsGetColorSpace(hGamut);
+
+ nChannels = cmsChannelsOf(ColorSpace);
+ nGridpoints = _cmsReasonableGridpointsByColorspace(ColorSpace, cmsFLAGS_HIGHRESPRECALC);
+ dwFormat = (CHANNELS_SH(nChannels)|BYTES_SH(2));
+
+ // 16 bits to Lab double
+ Chain.hInput = cmsCreateExtendedTransform(ContextID,
+ nGamutPCSposition + 1,
+ ProfileList,
+ BPCList,
+ IntentList,
+ AdaptationList,
+ NULL, 0,
+ dwFormat, TYPE_Lab_DBL,
+ cmsFLAGS_NOCACHE);
+
+
+ // Does create the forward step. Lab double to device
+ dwFormat = (CHANNELS_SH(nChannels)|BYTES_SH(2));
+ Chain.hForward = cmsCreateTransformTHR(ContextID,
+ hLab, TYPE_Lab_DBL,
+ hGamut, dwFormat,
+ INTENT_RELATIVE_COLORIMETRIC,
+ cmsFLAGS_NOCACHE);
+
+ // Does create the backwards step
+ Chain.hReverse = cmsCreateTransformTHR(ContextID, hGamut, dwFormat,
+ hLab, TYPE_Lab_DBL,
+ INTENT_RELATIVE_COLORIMETRIC,
+ cmsFLAGS_NOCACHE);
+
+
+ // All ok?
+ if (Chain.hInput && Chain.hForward && Chain.hReverse) {
+
+ // Go on, try to compute gamut LUT from PCS. This consist on a single channel containing
+ // dE when doing a transform back and forth on the colorimetric intent.
+
+ Gamut = cmsPipelineAlloc(ContextID, 3, 1);
+ if (Gamut != NULL) {
+
+ CLUT = cmsStageAllocCLut16bit(ContextID, nGridpoints, nChannels, 1, NULL);
+ if (!cmsPipelineInsertStage(Gamut, cmsAT_BEGIN, CLUT)) {
+ cmsPipelineFree(Gamut);
+ Gamut = NULL;
+ }
+ else {
+ cmsStageSampleCLut16bit(CLUT, GamutSampler, (void*) &Chain, 0);
+ }
+ }
+ }
+ else
+ Gamut = NULL; // Didn't work...
+
+ // Free all needed stuff.
+ if (Chain.hInput) cmsDeleteTransform(Chain.hInput);
+ if (Chain.hForward) cmsDeleteTransform(Chain.hForward);
+ if (Chain.hReverse) cmsDeleteTransform(Chain.hReverse);
+ if (hLab) cmsCloseProfile(hLab);
+
+ // And return computed hull
+ return Gamut;
+}
+
+// Total Area Coverage estimation ----------------------------------------------------------------
+
+typedef struct {
+ cmsUInt32Number nOutputChans;
+ cmsHTRANSFORM hRoundTrip;
+ cmsFloat32Number MaxTAC;
+ cmsFloat32Number MaxInput[cmsMAXCHANNELS];
+
+} cmsTACestimator;
+
+
+// This callback just accounts the maximum ink dropped in the given node. It does not populate any
+// memory, as the destination table is NULL. Its only purpose it to know the global maximum.
+static
+int EstimateTAC(register const cmsUInt16Number In[], register cmsUInt16Number Out[], register void * Cargo)
+{
+ cmsTACestimator* bp = (cmsTACestimator*) Cargo;
+ cmsFloat32Number RoundTrip[cmsMAXCHANNELS];
+ cmsUInt32Number i;
+ cmsFloat32Number Sum;
+
+
+ // Evaluate the xform
+ cmsDoTransform(bp->hRoundTrip, In, RoundTrip, 1);
+
+ // All all amounts of ink
+ for (Sum=0, i=0; i < bp ->nOutputChans; i++)
+ Sum += RoundTrip[i];
+
+ // If above maximum, keep track of input values
+ if (Sum > bp ->MaxTAC) {
+
+ bp ->MaxTAC = Sum;
+
+ for (i=0; i < bp ->nOutputChans; i++) {
+ bp ->MaxInput[i] = In[i];
+ }
+ }
+
+ return TRUE;
+
+ cmsUNUSED_PARAMETER(Out);
+}
+
+
+// Detect Total area coverage of the profile
+cmsFloat64Number CMSEXPORT cmsDetectTAC(cmsHPROFILE hProfile)
+{
+ cmsTACestimator bp;
+ cmsUInt32Number dwFormatter;
+ cmsUInt32Number GridPoints[MAX_INPUT_DIMENSIONS];
+ cmsHPROFILE hLab;
+ cmsContext ContextID = cmsGetProfileContextID(hProfile);
+
+ // TAC only works on output profiles
+ if (cmsGetDeviceClass(hProfile) != cmsSigOutputClass) {
+ return 0;
+ }
+
+ // Create a fake formatter for result
+ dwFormatter = cmsFormatterForColorspaceOfProfile(hProfile, 4, TRUE);
+
+ bp.nOutputChans = T_CHANNELS(dwFormatter);
+ bp.MaxTAC = 0; // Initial TAC is 0
+
+ // for safety
+ if (bp.nOutputChans >= cmsMAXCHANNELS) return 0;
+
+ hLab = cmsCreateLab4ProfileTHR(ContextID, NULL);
+ if (hLab == NULL) return 0;
+ // Setup a roundtrip on perceptual intent in output profile for TAC estimation
+ bp.hRoundTrip = cmsCreateTransformTHR(ContextID, hLab, TYPE_Lab_16,
+ hProfile, dwFormatter, INTENT_PERCEPTUAL, cmsFLAGS_NOOPTIMIZE|cmsFLAGS_NOCACHE);
+
+ cmsCloseProfile(hLab);
+ if (bp.hRoundTrip == NULL) return 0;
+
+ // For L* we only need black and white. For C* we need many points
+ GridPoints[0] = 6;
+ GridPoints[1] = 74;
+ GridPoints[2] = 74;
+
+
+ if (!cmsSliceSpace16(3, GridPoints, EstimateTAC, &bp)) {
+ bp.MaxTAC = 0;
+ }
+
+ cmsDeleteTransform(bp.hRoundTrip);
+
+ // Results in %
+ return bp.MaxTAC;
+}
+
+
+// Carefully, clamp on CIELab space.
+
+cmsBool CMSEXPORT cmsDesaturateLab(cmsCIELab* Lab,
+ double amax, double amin,
+ double bmax, double bmin)
+{
+
+ // Whole Luma surface to zero
+
+ if (Lab -> L < 0) {
+
+ Lab-> L = Lab->a = Lab-> b = 0.0;
+ return FALSE;
+ }
+
+ // Clamp white, DISCARD HIGHLIGHTS. This is done
+ // in such way because icc spec doesn't allow the
+ // use of L>100 as a highlight means.
+
+ if (Lab->L > 100)
+ Lab -> L = 100;
+
+ // Check out gamut prism, on a, b faces
+
+ if (Lab -> a < amin || Lab->a > amax||
+ Lab -> b < bmin || Lab->b > bmax) {
+
+ cmsCIELCh LCh;
+ double h, slope;
+
+ // Falls outside a, b limits. Transports to LCh space,
+ // and then do the clipping
+
+
+ if (Lab -> a == 0.0) { // Is hue exactly 90?
+
+ // atan will not work, so clamp here
+ Lab -> b = Lab->b < 0 ? bmin : bmax;
+ return TRUE;
+ }
+
+ cmsLab2LCh(&LCh, Lab);
+
+ slope = Lab -> b / Lab -> a;
+ h = LCh.h;
+
+ // There are 4 zones
+
+ if ((h >= 0. && h < 45.) ||
+ (h >= 315 && h <= 360.)) {
+
+ // clip by amax
+ Lab -> a = amax;
+ Lab -> b = amax * slope;
+ }
+ else
+ if (h >= 45. && h < 135.)
+ {
+ // clip by bmax
+ Lab -> b = bmax;
+ Lab -> a = bmax / slope;
+ }
+ else
+ if (h >= 135. && h < 225.) {
+ // clip by amin
+ Lab -> a = amin;
+ Lab -> b = amin * slope;
+
+ }
+ else
+ if (h >= 225. && h < 315.) {
+ // clip by bmin
+ Lab -> b = bmin;
+ Lab -> a = bmin / slope;
+ }
+ else {
+ cmsSignalError(0, cmsERROR_RANGE, "Invalid angle");
+ return FALSE;
+ }
+
+ }
+
+ return TRUE;
+}
diff --git a/src/cmsintrp.c b/src/cmsintrp.c index 01150d7..5d5f35d 100644 --- a/src/cmsintrp.c +++ b/src/cmsintrp.c @@ -33,32 +33,58 @@ static cmsInterpFunction DefaultInterpolatorsFactory(cmsUInt32Number nInputChannels, cmsUInt32Number nOutputChannels, cmsUInt32Number dwFlags); // This is the default factory -static cmsInterpFnFactory Interpolators = DefaultInterpolatorsFactory; +_cmsInterpPluginChunkType _cmsInterpPluginChunk = { NULL }; + +// The interpolation plug-in memory chunk allocator/dup +void _cmsAllocInterpPluginChunk(struct _cmsContext_struct* ctx, const struct _cmsContext_struct* src) +{ + void* from; + + _cmsAssert(ctx != NULL); + + if (src != NULL) { + from = src ->chunks[InterpPlugin]; + } + else { + static _cmsInterpPluginChunkType InterpPluginChunk = { NULL }; + + from = &InterpPluginChunk; + } + + _cmsAssert(from != NULL); + ctx ->chunks[InterpPlugin] = _cmsSubAllocDup(ctx ->MemPool, from, sizeof(_cmsInterpPluginChunkType)); +} // Main plug-in entry -cmsBool _cmsRegisterInterpPlugin(cmsPluginBase* Data) +cmsBool _cmsRegisterInterpPlugin(cmsContext ContextID, cmsPluginBase* Data) { cmsPluginInterpolation* Plugin = (cmsPluginInterpolation*) Data; + _cmsInterpPluginChunkType* ptr = (_cmsInterpPluginChunkType*) _cmsContextGetClientChunk(ContextID, InterpPlugin); if (Data == NULL) { - Interpolators = DefaultInterpolatorsFactory; + ptr ->Interpolators = NULL; return TRUE; } // Set replacement functions - Interpolators = Plugin ->InterpolatorsFactory; + ptr ->Interpolators = Plugin ->InterpolatorsFactory; return TRUE; } // Set the interpolation method -cmsBool _cmsSetInterpolationRoutine(cmsInterpParams* p) -{ - // Invoke factory, possibly in the Plug-in - p ->Interpolation = Interpolators(p -> nInputs, p ->nOutputs, p ->dwFlags); +cmsBool _cmsSetInterpolationRoutine(cmsContext ContextID, cmsInterpParams* p) +{ + _cmsInterpPluginChunkType* ptr = (_cmsInterpPluginChunkType*) _cmsContextGetClientChunk(ContextID, InterpPlugin); + + p ->Interpolation.Lerp16 = NULL; + // Invoke factory, possibly in the Plug-in + if (ptr ->Interpolators != NULL) + p ->Interpolation = ptr->Interpolators(p -> nInputs, p ->nOutputs, p ->dwFlags); + // If unsupported by the plug-in, go for the LittleCMS default. // If happens only if an extern plug-in is being used if (p ->Interpolation.Lerp16 == NULL) @@ -68,6 +94,7 @@ cmsBool _cmsSetInterpolationRoutine(cmsInterpParams* p) if (p ->Interpolation.Lerp16 == NULL) { return FALSE; } + return TRUE; } @@ -112,7 +139,7 @@ cmsInterpParams* _cmsComputeInterpParamsEx(cmsContext ContextID, p ->opta[i] = p ->opta[i-1] * nSamples[InputChan-i]; - if (!_cmsSetInterpolationRoutine(p)) { + if (!_cmsSetInterpolationRoutine(ContextID, p)) { cmsSignalError(ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported interpolation (%d->%d channels)", InputChan, OutputChan); _cmsFree(ContextID, p); return NULL; diff --git a/src/cmsio0.c b/src/cmsio0.c index 2430e98..4e8cd93 100644 --- a/src/cmsio0.c +++ b/src/cmsio0.c @@ -471,6 +471,9 @@ cmsHPROFILE CMSEXPORT cmsCreateProfilePlaceholder(cmsContext ContextID) // Set creation date/time memmove(&Icc ->Created, gmtime(&now), sizeof(Icc ->Created)); + // Create a mutex if the user provided proper plugin. NULL otherwise + Icc ->UsrMutex = _cmsCreateMutex(ContextID); + // Return the handle return (cmsHPROFILE) Icc; } @@ -549,9 +552,38 @@ int _cmsSearchTag(_cmsICCPROFILE* Icc, cmsTagSignature sig, cmsBool lFollowLinks return n; } +// Deletes a tag entry + +static +void _cmsDeleteTagByPos(_cmsICCPROFILE* Icc, int i) +{ + _cmsAssert(Icc != NULL); + _cmsAssert(i >= 0); + + + if (Icc -> TagPtrs[i] != NULL) { + + // Free previous version + if (Icc ->TagSaveAsRaw[i]) { + _cmsFree(Icc ->ContextID, Icc ->TagPtrs[i]); + } + else { + cmsTagTypeHandler* TypeHandler = Icc ->TagTypeHandlers[i]; + + if (TypeHandler != NULL) { + + cmsTagTypeHandler LocalTypeHandler = *TypeHandler; + LocalTypeHandler.ContextID = Icc ->ContextID; // As an additional parameter + LocalTypeHandler.ICCVersion = Icc ->Version; + LocalTypeHandler.FreePtr(&LocalTypeHandler, Icc -> TagPtrs[i]); + } + } + + } +} -// Create a new tag entry +// Creates a new tag entry static cmsBool _cmsNewTag(_cmsICCPROFILE* Icc, cmsTagSignature sig, int* NewPos) { @@ -559,15 +591,15 @@ cmsBool _cmsNewTag(_cmsICCPROFILE* Icc, cmsTagSignature sig, int* NewPos) // Search for the tag i = _cmsSearchTag(Icc, sig, FALSE); - - // Now let's do it easy. If the tag has been already written, that's an error if (i >= 0) { - cmsSignalError(Icc ->ContextID, cmsERROR_ALREADY_DEFINED, "Tag '%x' already exists", sig); - return FALSE; + + // Already exists? delete it + _cmsDeleteTagByPos(Icc, i); + *NewPos = i; } else { - // New one + // No, make a new one if (Icc -> TagCount >= MAX_TABLE_TAG) { cmsSignalError(Icc ->ContextID, cmsERROR_RANGE, "Too many tags (%d)", MAX_TABLE_TAG); @@ -924,7 +956,7 @@ void CMSEXPORT cmsSetProfileVersion(cmsHPROFILE hProfile, cmsFloat64Number Vers // 4.2 -> 0x4200000 - Icc -> Version = BaseToBase((cmsUInt32Number) floor(Version * 100.0), 10, 16) << 16; + Icc -> Version = BaseToBase((cmsUInt32Number) floor(Version * 100.0 + 0.5), 10, 16) << 16; } cmsFloat64Number CMSEXPORT cmsGetProfileVersion(cmsHPROFILE hProfile) @@ -1147,7 +1179,7 @@ cmsBool SaveTags(_cmsICCPROFILE* Icc, _cmsICCPROFILE* FileOrig) else { // Search for support on this tag - TagDescriptor = _cmsGetTagDescriptor(Icc -> TagNames[i]); + TagDescriptor = _cmsGetTagDescriptor(Icc-> ContextID, Icc -> TagNames[i]); if (TagDescriptor == NULL) continue; // Unsupported, ignore it if (TagDescriptor ->DecideType != NULL) { @@ -1159,7 +1191,7 @@ cmsBool SaveTags(_cmsICCPROFILE* Icc, _cmsICCPROFILE* FileOrig) Type = TagDescriptor ->SupportedTypes[0]; } - TypeHandler = _cmsGetTagTypeHandler(Type); + TypeHandler = _cmsGetTagTypeHandler(Icc->ContextID, Type); if (TypeHandler == NULL) { cmsSignalError(Icc ->ContextID, cmsERROR_INTERNAL, "(Internal) no handler for tag %x", Icc -> TagNames[i]); @@ -1227,7 +1259,7 @@ cmsUInt32Number CMSEXPORT cmsSaveProfileToIOhandler(cmsHPROFILE hProfile, cmsIOH { _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; _cmsICCPROFILE Keep; - cmsIOHANDLER* PrevIO; + cmsIOHANDLER* PrevIO = NULL; cmsUInt32Number UsedSpace; cmsContext ContextID; @@ -1241,8 +1273,8 @@ cmsUInt32Number CMSEXPORT cmsSaveProfileToIOhandler(cmsHPROFILE hProfile, cmsIOH // Pass #1 does compute offsets - if (!_cmsWriteHeader(Icc, 0)) return 0; - if (!SaveTags(Icc, &Keep)) return 0; + if (!_cmsWriteHeader(Icc, 0)) goto Error; + if (!SaveTags(Icc, &Keep)) goto Error; UsedSpace = PrevIO ->UsedSpace; @@ -1251,9 +1283,9 @@ cmsUInt32Number CMSEXPORT cmsSaveProfileToIOhandler(cmsHPROFILE hProfile, cmsIOH if (io != NULL) { Icc ->IOhandler = io; - if (!SetLinks(Icc)) goto CleanUp; - if (!_cmsWriteHeader(Icc, UsedSpace)) goto CleanUp; - if (!SaveTags(Icc, &Keep)) goto CleanUp; + if (!SetLinks(Icc)) goto Error; + if (!_cmsWriteHeader(Icc, UsedSpace)) goto Error; + if (!SaveTags(Icc, &Keep)) goto Error; } memmove(Icc, &Keep, sizeof(_cmsICCPROFILE)); @@ -1262,7 +1294,7 @@ cmsUInt32Number CMSEXPORT cmsSaveProfileToIOhandler(cmsHPROFILE hProfile, cmsIOH return UsedSpace; -CleanUp: +Error: cmsCloseIOhandler(PrevIO); memmove(Icc, &Keep, sizeof(_cmsICCPROFILE)); return 0; @@ -1310,11 +1342,13 @@ cmsBool CMSEXPORT cmsSaveProfileToMem(cmsHPROFILE hProfile, void *MemPtr, cmsUIn cmsIOHANDLER* io; cmsContext ContextID = cmsGetProfileContextID(hProfile); + _cmsAssert(BytesNeeded != NULL); + // Should we just calculate the needed space? if (MemPtr == NULL) { *BytesNeeded = cmsSaveProfileToIOhandler(hProfile, NULL); - return TRUE; + return (*BytesNeeded == 0) ? FALSE : TRUE; } // That is a real write operation @@ -1367,6 +1401,8 @@ cmsBool CMSEXPORT cmsCloseProfile(cmsHPROFILE hProfile) rc &= cmsCloseIOhandler(Icc->IOhandler); } + _cmsDestroyMutex(Icc->ContextID, Icc->UsrMutex); + _cmsFree(Icc ->ContextID, Icc); // Free placeholder memory return rc; @@ -1407,14 +1443,18 @@ void* CMSEXPORT cmsReadTag(cmsHPROFILE hProfile, cmsTagSignature sig) cmsUInt32Number ElemCount; int n; + if (!_cmsLockMutex(Icc->ContextID, Icc ->UsrMutex)) return NULL; + n = _cmsSearchTag(Icc, sig, TRUE); - if (n < 0) return NULL; // Not found, return NULL + if (n < 0) goto Error; // Not found, return NULL // If the element is already in memory, return the pointer if (Icc -> TagPtrs[n]) { - if (Icc ->TagSaveAsRaw[n]) return NULL; // We don't support read raw tags as cooked + if (Icc ->TagSaveAsRaw[n]) goto Error; // We don't support read raw tags as cooked + + _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex); return Icc -> TagPtrs[n]; } @@ -1424,23 +1464,32 @@ void* CMSEXPORT cmsReadTag(cmsHPROFILE hProfile, cmsTagSignature sig) // Seek to its location if (!io -> Seek(io, Offset)) - return NULL; + goto Error; // Search for support on this tag - TagDescriptor = _cmsGetTagDescriptor(sig); - if (TagDescriptor == NULL) return NULL; // Unsupported. + TagDescriptor = _cmsGetTagDescriptor(Icc-> ContextID, sig); + if (TagDescriptor == NULL) { + + char String[5]; + + _cmsTagSignature2String(String, sig); + + // An unknown element was found. + cmsSignalError(Icc ->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unknown tag type '%s' found.", String); + goto Error; // Unsupported. + } // if supported, get type and check if in list BaseType = _cmsReadTypeBase(io); - if (BaseType == 0) return NULL; + if (BaseType == 0) goto Error; - if (!IsTypeSupported(TagDescriptor, BaseType)) return NULL; + if (!IsTypeSupported(TagDescriptor, BaseType)) goto Error; TagSize -= 8; // Alredy read by the type base logic // Get type handler - TypeHandler = _cmsGetTagTypeHandler(BaseType); - if (TypeHandler == NULL) return NULL; + TypeHandler = _cmsGetTagTypeHandler(Icc ->ContextID, BaseType); + if (TypeHandler == NULL) goto Error; LocalTypeHandler = *TypeHandler; @@ -1459,7 +1508,7 @@ void* CMSEXPORT cmsReadTag(cmsHPROFILE hProfile, cmsTagSignature sig) _cmsTagSignature2String(String, sig); cmsSignalError(Icc ->ContextID, cmsERROR_CORRUPTION_DETECTED, "Corrupted tag '%s'", String); - return NULL; + goto Error; } // This is a weird error that may be a symptom of something more serious, the number of @@ -1475,7 +1524,14 @@ void* CMSEXPORT cmsReadTag(cmsHPROFILE hProfile, cmsTagSignature sig) // Return the data + _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex); return Icc -> TagPtrs[n]; + + + // Return error and unlock tha data +Error: + _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex); + return NULL; } @@ -1509,49 +1565,26 @@ cmsBool CMSEXPORT cmsWriteTag(cmsHPROFILE hProfile, cmsTagSignature sig, const v cmsFloat64Number Version; char TypeString[5], SigString[5]; + if (!_cmsLockMutex(Icc->ContextID, Icc ->UsrMutex)) return FALSE; + // To delete tags. if (data == NULL) { + // Delete the tag i = _cmsSearchTag(Icc, sig, FALSE); - if (i >= 0) + if (i >= 0) { + + // Use zero as a mark of deleted + _cmsDeleteTagByPos(Icc, i); Icc ->TagNames[i] = (cmsTagSignature) 0; - // Unsupported by now, reserved for future ampliations (delete) - return FALSE; + _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex); + return TRUE; + } + // Didn't find the tag + goto Error; } - i = _cmsSearchTag(Icc, sig, FALSE); - if (i >=0) { - - if (Icc -> TagPtrs[i] != NULL) { - - // Already exists. Free previous version - if (Icc ->TagSaveAsRaw[i]) { - _cmsFree(Icc ->ContextID, Icc ->TagPtrs[i]); - } - else { - TypeHandler = Icc ->TagTypeHandlers[i]; - - if (TypeHandler != NULL) { - - LocalTypeHandler = *TypeHandler; - LocalTypeHandler.ContextID = Icc ->ContextID; // As an additional parameter - LocalTypeHandler.ICCVersion = Icc ->Version; - LocalTypeHandler.FreePtr(&LocalTypeHandler, Icc -> TagPtrs[i]); - } - } - } - } - else { - // New one - i = Icc -> TagCount; - - if (i >= MAX_TABLE_TAG) { - cmsSignalError(Icc ->ContextID, cmsERROR_RANGE, "Too many tags (%d)", MAX_TABLE_TAG); - return FALSE; - } - - Icc -> TagCount++; - } + if (!_cmsNewTag(Icc, sig, &i)) goto Error; // This is not raw Icc ->TagSaveAsRaw[i] = FALSE; @@ -1560,10 +1593,10 @@ cmsBool CMSEXPORT cmsWriteTag(cmsHPROFILE hProfile, cmsTagSignature sig, const v Icc ->TagLinked[i] = (cmsTagSignature) 0; // Get information about the TAG. - TagDescriptor = _cmsGetTagDescriptor(sig); + TagDescriptor = _cmsGetTagDescriptor(Icc-> ContextID, sig); if (TagDescriptor == NULL){ cmsSignalError(Icc ->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported tag '%x'", sig); - return FALSE; + goto Error; } @@ -1581,7 +1614,6 @@ cmsBool CMSEXPORT cmsWriteTag(cmsHPROFILE hProfile, cmsTagSignature sig, const v } else { - Type = TagDescriptor ->SupportedTypes[0]; } @@ -1592,18 +1624,18 @@ cmsBool CMSEXPORT cmsWriteTag(cmsHPROFILE hProfile, cmsTagSignature sig, const v _cmsTagSignature2String(SigString, sig); cmsSignalError(Icc ->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported type '%s' for tag '%s'", TypeString, SigString); - return FALSE; + goto Error; } // Does we have a handler for this type? - TypeHandler = _cmsGetTagTypeHandler(Type); + TypeHandler = _cmsGetTagTypeHandler(Icc->ContextID, Type); if (TypeHandler == NULL) { _cmsTagSignature2String(TypeString, (cmsTagSignature) Type); _cmsTagSignature2String(SigString, sig); cmsSignalError(Icc ->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported type '%s' for tag '%s'", TypeString, SigString); - return FALSE; // Should never happen + goto Error; // Should never happen } @@ -1616,7 +1648,7 @@ cmsBool CMSEXPORT cmsWriteTag(cmsHPROFILE hProfile, cmsTagSignature sig, const v LocalTypeHandler = *TypeHandler; LocalTypeHandler.ContextID = Icc ->ContextID; LocalTypeHandler.ICCVersion = Icc ->Version; - Icc ->TagPtrs[i] = LocalTypeHandler.DupPtr(&LocalTypeHandler, data, TagDescriptor ->ElemCount); + Icc ->TagPtrs[i] = LocalTypeHandler.DupPtr(&LocalTypeHandler, data, TagDescriptor ->ElemCount); if (Icc ->TagPtrs[i] == NULL) { @@ -1624,10 +1656,16 @@ cmsBool CMSEXPORT cmsWriteTag(cmsHPROFILE hProfile, cmsTagSignature sig, const v _cmsTagSignature2String(SigString, sig); cmsSignalError(Icc ->ContextID, cmsERROR_CORRUPTION_DETECTED, "Malformed struct in type '%s' for tag '%s'", TypeString, SigString); - return FALSE; + goto Error; } + _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex); return TRUE; + +Error: + _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex); + return FALSE; + } // Read and write raw data. The only way those function would work and keep consistence with normal read and write @@ -1648,9 +1686,11 @@ cmsInt32Number CMSEXPORT cmsReadRawTag(cmsHPROFILE hProfile, cmsTagSignature sig cmsUInt32Number rc; cmsUInt32Number Offset, TagSize; + if (!_cmsLockMutex(Icc->ContextID, Icc ->UsrMutex)) return 0; + // Search for given tag in ICC profile directory i = _cmsSearchTag(Icc, sig, TRUE); - if (i < 0) return 0; // Not found, return 0 + if (i < 0) goto Error; // Not found, // It is already read? if (Icc -> TagPtrs[i] == NULL) { @@ -1665,12 +1705,13 @@ cmsInt32Number CMSEXPORT cmsReadRawTag(cmsHPROFILE hProfile, cmsTagSignature sig if (BufferSize < TagSize) TagSize = BufferSize; - if (!Icc ->IOhandler ->Seek(Icc ->IOhandler, Offset)) return 0; - if (!Icc ->IOhandler ->Read(Icc ->IOhandler, data, 1, TagSize)) return 0; + if (!Icc ->IOhandler ->Seek(Icc ->IOhandler, Offset)) goto Error; + if (!Icc ->IOhandler ->Read(Icc ->IOhandler, data, 1, TagSize)) goto Error; return TagSize; } + _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex); return Icc ->TagSizes[i]; } @@ -1686,16 +1727,18 @@ cmsInt32Number CMSEXPORT cmsReadRawTag(cmsHPROFILE hProfile, cmsTagSignature sig memmove(data, Icc ->TagPtrs[i], TagSize); + _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex); return TagSize; } + _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex); return Icc ->TagSizes[i]; } // Already readed, or previously set by cmsWriteTag(). We need to serialize that // data to raw in order to maintain consistency. Object = cmsReadTag(hProfile, sig); - if (Object == NULL) return 0; + if (Object == NULL) goto Error; // Now we need to serialize to a memory block: just use a memory iohandler @@ -1704,17 +1747,18 @@ cmsInt32Number CMSEXPORT cmsReadRawTag(cmsHPROFILE hProfile, cmsTagSignature sig } else{ MemIO = cmsOpenIOhandlerFromMem(cmsGetProfileContextID(hProfile), data, BufferSize, "w"); } - if (MemIO == NULL) return 0; + if (MemIO == NULL) goto Error; // Obtain type handling for the tag TypeHandler = Icc ->TagTypeHandlers[i]; - TagDescriptor = _cmsGetTagDescriptor(sig); + TagDescriptor = _cmsGetTagDescriptor(Icc-> ContextID, sig); if (TagDescriptor == NULL) { cmsCloseIOhandler(MemIO); - return 0; + goto Error; } + + if (TypeHandler == NULL) goto Error; - // FIXME: No handling for TypeHandler == NULL here? // Serialize LocalTypeHandler = *TypeHandler; LocalTypeHandler.ContextID = Icc ->ContextID; @@ -1722,19 +1766,24 @@ cmsInt32Number CMSEXPORT cmsReadRawTag(cmsHPROFILE hProfile, cmsTagSignature sig if (!_cmsWriteTypeBase(MemIO, TypeHandler ->Signature)) { cmsCloseIOhandler(MemIO); - return 0; + goto Error; } if (!LocalTypeHandler.WritePtr(&LocalTypeHandler, MemIO, Object, TagDescriptor ->ElemCount)) { cmsCloseIOhandler(MemIO); - return 0; + goto Error; } // Get Size and close rc = MemIO ->Tell(MemIO); cmsCloseIOhandler(MemIO); // Ignore return code this time + _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex); return rc; + +Error: + _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex); + return 0; } // Similar to the anterior. This function allows to write directly to the ICC profile any data, without @@ -1746,7 +1795,12 @@ cmsBool CMSEXPORT cmsWriteRawTag(cmsHPROFILE hProfile, cmsTagSignature sig, cons _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; int i; - if (!_cmsNewTag(Icc, sig, &i)) return FALSE; + if (!_cmsLockMutex(Icc->ContextID, Icc ->UsrMutex)) return 0; + + if (!_cmsNewTag(Icc, sig, &i)) { + _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex); + return FALSE; + } // Mark the tag as being written as RAW Icc ->TagSaveAsRaw[i] = TRUE; @@ -1757,6 +1811,7 @@ cmsBool CMSEXPORT cmsWriteRawTag(cmsHPROFILE hProfile, cmsTagSignature sig, cons Icc ->TagPtrs[i] = _cmsDupMem(Icc ->ContextID, data, Size); Icc ->TagSizes[i] = Size; + _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex); return TRUE; } @@ -1766,7 +1821,12 @@ cmsBool CMSEXPORT cmsLinkTag(cmsHPROFILE hProfile, cmsTagSignature sig, cmsTagSi _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; int i; - if (!_cmsNewTag(Icc, sig, &i)) return FALSE; + if (!_cmsLockMutex(Icc->ContextID, Icc ->UsrMutex)) return FALSE; + + if (!_cmsNewTag(Icc, sig, &i)) { + _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex); + return FALSE; + } // Keep necessary information Icc ->TagSaveAsRaw[i] = FALSE; @@ -1777,6 +1837,7 @@ cmsBool CMSEXPORT cmsLinkTag(cmsHPROFILE hProfile, cmsTagSignature sig, cmsTagSi Icc ->TagSizes[i] = 0; Icc ->TagOffsets[i] = 0; + _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex); return TRUE; } diff --git a/src/cmsio1.c b/src/cmsio1.c index 3262402..89856e5 100644 --- a/src/cmsio1.c +++ b/src/cmsio1.c @@ -528,7 +528,7 @@ void ChangeInterpolationToTrilinear(cmsPipeline* Lut) _cmsStageCLutData* CLUT = (_cmsStageCLutData*) Stage ->Data; CLUT ->Params->dwFlags |= CMS_LERP_FLAGS_TRILINEAR; - _cmsSetInterpolationRoutine(CLUT ->Params); + _cmsSetInterpolationRoutine(Lut->ContextID, CLUT ->Params); } } } diff --git a/src/cmsopt.c b/src/cmsopt.c index 4bdf0a7..bf95091 100644 --- a/src/cmsopt.c +++ b/src/cmsopt.c @@ -512,8 +512,14 @@ cmsBool FixWhiteMisalignment(cmsPipeline* Lut, cmsColorSpaceSignature EntryColor for (i=0; i < nOuts; i++) { cmsToneCurve* InversePostLin = cmsReverseToneCurve(Curves[i]); - WhiteOut[i] = cmsEvalToneCurve16(InversePostLin, WhitePointOut[i]); - cmsFreeToneCurve(InversePostLin); + if (InversePostLin == NULL) { + WhiteOut[i] = WhitePointOut[i]; + + } else { + + WhiteOut[i] = cmsEvalToneCurve16(InversePostLin, WhitePointOut[i]); + cmsFreeToneCurve(InversePostLin); + } } } else { @@ -1633,44 +1639,102 @@ static _cmsOptimizationCollection DefaultOptimization[] = { }; // The linked list head -static _cmsOptimizationCollection* OptimizationCollection = DefaultOptimization; +_cmsOptimizationPluginChunkType _cmsOptimizationPluginChunk = { NULL }; + + +// Duplicates the zone of memory used by the plug-in in the new context +static +void DupPluginOptimizationList(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src) +{ + _cmsOptimizationPluginChunkType newHead = { NULL }; + _cmsOptimizationCollection* entry; + _cmsOptimizationCollection* Anterior = NULL; + _cmsOptimizationPluginChunkType* head = (_cmsOptimizationPluginChunkType*) src->chunks[OptimizationPlugin]; + + _cmsAssert(ctx != NULL); + _cmsAssert(head != NULL); + + // Walk the list copying all nodes + for (entry = head->OptimizationCollection; + entry != NULL; + entry = entry ->Next) { + + _cmsOptimizationCollection *newEntry = ( _cmsOptimizationCollection *) _cmsSubAllocDup(ctx ->MemPool, entry, sizeof(_cmsOptimizationCollection)); + + if (newEntry == NULL) + return; + + // We want to keep the linked list order, so this is a little bit tricky + newEntry -> Next = NULL; + if (Anterior) + Anterior -> Next = newEntry; + + Anterior = newEntry; + + if (newHead.OptimizationCollection == NULL) + newHead.OptimizationCollection = newEntry; + } + + ctx ->chunks[OptimizationPlugin] = _cmsSubAllocDup(ctx->MemPool, &newHead, sizeof(_cmsOptimizationPluginChunkType)); +} + +void _cmsAllocOptimizationPluginChunk(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src) +{ + if (src != NULL) { + + // Copy all linked list + DupPluginOptimizationList(ctx, src); + } + else { + static _cmsOptimizationPluginChunkType OptimizationPluginChunkType = { NULL }; + ctx ->chunks[OptimizationPlugin] = _cmsSubAllocDup(ctx ->MemPool, &OptimizationPluginChunkType, sizeof(_cmsOptimizationPluginChunkType)); + } +} + // Register new ways to optimize -cmsBool _cmsRegisterOptimizationPlugin(cmsContext id, cmsPluginBase* Data) +cmsBool _cmsRegisterOptimizationPlugin(cmsContext ContextID, cmsPluginBase* Data) { cmsPluginOptimization* Plugin = (cmsPluginOptimization*) Data; + _cmsOptimizationPluginChunkType* ctx = ( _cmsOptimizationPluginChunkType*) _cmsContextGetClientChunk(ContextID, OptimizationPlugin); _cmsOptimizationCollection* fl; if (Data == NULL) { - OptimizationCollection = DefaultOptimization; + ctx->OptimizationCollection = NULL; return TRUE; } // Optimizer callback is required if (Plugin ->OptimizePtr == NULL) return FALSE; - fl = (_cmsOptimizationCollection*) _cmsPluginMalloc(id, sizeof(_cmsOptimizationCollection)); + fl = (_cmsOptimizationCollection*) _cmsPluginMalloc(ContextID, sizeof(_cmsOptimizationCollection)); if (fl == NULL) return FALSE; // Copy the parameters fl ->OptimizePtr = Plugin ->OptimizePtr; // Keep linked list - fl ->Next = OptimizationCollection; - OptimizationCollection = fl; + fl ->Next = ctx->OptimizationCollection; + + // Set the head + ctx ->OptimizationCollection = fl; // All is ok return TRUE; } // The entry point for LUT optimization -cmsBool _cmsOptimizePipeline(cmsPipeline** PtrLut, +cmsBool _cmsOptimizePipeline(cmsContext ContextID, + cmsPipeline** PtrLut, int Intent, cmsUInt32Number* InputFormat, cmsUInt32Number* OutputFormat, cmsUInt32Number* dwFlags) { + _cmsOptimizationPluginChunkType* ctx = ( _cmsOptimizationPluginChunkType*) _cmsContextGetClientChunk(ContextID, OptimizationPlugin); _cmsOptimizationCollection* Opts; cmsBool AnySuccess = FALSE; @@ -1700,8 +1764,8 @@ cmsBool _cmsOptimizePipeline(cmsPipeline** PtrLut, if (*dwFlags & cmsFLAGS_NOOPTIMIZE) return FALSE; - // Try built-in optimizations and plug-in - for (Opts = OptimizationCollection; + // Try plug-in optimizations + for (Opts = ctx->OptimizationCollection; Opts != NULL; Opts = Opts ->Next) { @@ -1712,6 +1776,17 @@ cmsBool _cmsOptimizePipeline(cmsPipeline** PtrLut, } } + // Try built-in optimizations + for (Opts = DefaultOptimization; + Opts != NULL; + Opts = Opts ->Next) { + + if (Opts ->OptimizePtr(PtrLut, Intent, InputFormat, OutputFormat, dwFlags)) { + + return TRUE; + } + } + // Only simple optimizations succeeded return AnySuccess; } diff --git a/src/cmspack.c b/src/cmspack.c index 6509e89..c84fd82 100644 --- a/src/cmspack.c +++ b/src/cmspack.c @@ -2352,9 +2352,9 @@ cmsUInt8Number* PackXYZFloatFrom16(register _cmsTRANSFORM* Info, cmsFloat32Number* Out = (cmsFloat32Number*) output; cmsXYZEncoded2Float(&XYZ, wOut); - Out[0] = XYZ.X; - Out[Stride] = XYZ.Y; - Out[Stride*2] = XYZ.Z; + Out[0] = (cmsFloat32Number) XYZ.X; + Out[Stride] = (cmsFloat32Number) XYZ.Y; + Out[Stride*2] = (cmsFloat32Number) XYZ.Z; return output + sizeof(cmsFloat32Number); @@ -2365,9 +2365,9 @@ cmsUInt8Number* PackXYZFloatFrom16(register _cmsTRANSFORM* Info, cmsFloat32Number* Out = (cmsFloat32Number*) output; cmsXYZEncoded2Float(&XYZ, wOut); - Out[0] = XYZ.X; - Out[1] = XYZ.Y; - Out[2] = XYZ.Z; + Out[0] = (cmsFloat32Number) XYZ.X; + Out[1] = (cmsFloat32Number) XYZ.Y; + Out[2] = (cmsFloat32Number) XYZ.Z; return output + (3 * sizeof(cmsFloat32Number) + T_EXTRA(Info ->OutputFormat) * sizeof(cmsFloat32Number)); } @@ -3224,40 +3224,98 @@ typedef struct _cms_formatters_factory_list { } cmsFormattersFactoryList; -static cmsFormattersFactoryList* FactoryList = NULL; +_cmsFormattersPluginChunkType _cmsFormattersPluginChunk = { NULL }; + + +// Duplicates the zone of memory used by the plug-in in the new context +static +void DupFormatterFactoryList(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src) +{ + _cmsFormattersPluginChunkType newHead = { NULL }; + cmsFormattersFactoryList* entry; + cmsFormattersFactoryList* Anterior = NULL; + _cmsFormattersPluginChunkType* head = (_cmsFormattersPluginChunkType*) src->chunks[FormattersPlugin]; + + _cmsAssert(head != NULL); + + // Walk the list copying all nodes + for (entry = head->FactoryList; + entry != NULL; + entry = entry ->Next) { + + cmsFormattersFactoryList *newEntry = ( cmsFormattersFactoryList *) _cmsSubAllocDup(ctx ->MemPool, entry, sizeof(cmsFormattersFactoryList)); + + if (newEntry == NULL) + return; + + // We want to keep the linked list order, so this is a little bit tricky + newEntry -> Next = NULL; + if (Anterior) + Anterior -> Next = newEntry; + + Anterior = newEntry; + + if (newHead.FactoryList == NULL) + newHead.FactoryList = newEntry; + } + + ctx ->chunks[FormattersPlugin] = _cmsSubAllocDup(ctx->MemPool, &newHead, sizeof(_cmsFormattersPluginChunkType)); +} + +// The interpolation plug-in memory chunk allocator/dup +void _cmsAllocFormattersPluginChunk(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src) +{ + _cmsAssert(ctx != NULL); + + if (src != NULL) { + + // Duplicate the LIST + DupFormatterFactoryList(ctx, src); + } + else { + static _cmsFormattersPluginChunkType FormattersPluginChunk = { NULL }; + ctx ->chunks[FormattersPlugin] = _cmsSubAllocDup(ctx ->MemPool, &FormattersPluginChunk, sizeof(_cmsFormattersPluginChunkType)); + } +} + // Formatters management -cmsBool _cmsRegisterFormattersPlugin(cmsContext id, cmsPluginBase* Data) +cmsBool _cmsRegisterFormattersPlugin(cmsContext ContextID, cmsPluginBase* Data) { + _cmsFormattersPluginChunkType* ctx = ( _cmsFormattersPluginChunkType*) _cmsContextGetClientChunk(ContextID, FormattersPlugin); cmsPluginFormatters* Plugin = (cmsPluginFormatters*) Data; cmsFormattersFactoryList* fl ; - // Reset + // Reset to built-in defaults if (Data == NULL) { - FactoryList = NULL; + ctx ->FactoryList = NULL; return TRUE; } - fl = (cmsFormattersFactoryList*) _cmsPluginMalloc(id, sizeof(cmsFormattersFactoryList)); + fl = (cmsFormattersFactoryList*) _cmsPluginMalloc(ContextID, sizeof(cmsFormattersFactoryList)); if (fl == NULL) return FALSE; fl ->Factory = Plugin ->FormattersFactory; - fl ->Next = FactoryList; - FactoryList = fl; + fl ->Next = ctx -> FactoryList; + ctx ->FactoryList = fl; return TRUE; } -cmsFormatter _cmsGetFormatter(cmsUInt32Number Type, // Specific type, i.e. TYPE_RGB_8 +cmsFormatter _cmsGetFormatter(cmsContext ContextID, + cmsUInt32Number Type, // Specific type, i.e. TYPE_RGB_8 cmsFormatterDirection Dir, cmsUInt32Number dwFlags) { + _cmsFormattersPluginChunkType* ctx = ( _cmsFormattersPluginChunkType*) _cmsContextGetClientChunk(ContextID, FormattersPlugin); cmsFormattersFactoryList* f; - for (f = FactoryList; f != NULL; f = f ->Next) { + for (f =ctx->FactoryList; f != NULL; f = f ->Next) { cmsFormatter fn = f ->Factory(Type, Dir, dwFlags); if (fn.Fmt16 != NULL) return fn; diff --git a/src/cmsplugin.c b/src/cmsplugin.c index e334fac..7c58b60 100644 --- a/src/cmsplugin.c +++ b/src/cmsplugin.c @@ -515,15 +515,18 @@ cmsBool CMSEXPORT _cmsIOPrintf(cmsIOHANDLER* io, const char* frm, ...) // Plugin memory management ------------------------------------------------------------------------------------------------- -static _cmsSubAllocator* PluginPool = NULL; - // Specialized malloc for plug-ins, that is freed upon exit. -void* _cmsPluginMalloc(cmsContext id, cmsUInt32Number size) +void* _cmsPluginMalloc(cmsContext ContextID, cmsUInt32Number size) { - if (PluginPool == NULL) - PluginPool = _cmsCreateSubAlloc(id, 4*1024); + struct _cmsContext_struct* ctx = _cmsGetContext(ContextID); + + if (ctx ->MemPool == NULL) { + + cmsSignalError(ContextID, cmsERROR_CORRUPTION_DETECTED, "NULL memory pool on context"); + return NULL; + } - return _cmsSubAlloc(PluginPool, size); + return _cmsSubAlloc(ctx->MemPool, size); } @@ -542,12 +545,12 @@ cmsBool CMSEXPORT cmsPluginTHR(cmsContext id, void* Plug_in) Plugin = Plugin -> Next) { if (Plugin -> Magic != cmsPluginMagicNumber) { - cmsSignalError(0, cmsERROR_UNKNOWN_EXTENSION, "Unrecognized plugin"); + cmsSignalError(id, cmsERROR_UNKNOWN_EXTENSION, "Unrecognized plugin"); return FALSE; } if (Plugin ->ExpectedVersion > LCMS_VERSION) { - cmsSignalError(0, cmsERROR_UNKNOWN_EXTENSION, "plugin needs Little CMS %d, current version is %d", + cmsSignalError(id, cmsERROR_UNKNOWN_EXTENSION, "plugin needs Little CMS %d, current version is %d", Plugin ->ExpectedVersion, LCMS_VERSION); return FALSE; } @@ -555,11 +558,11 @@ cmsBool CMSEXPORT cmsPluginTHR(cmsContext id, void* Plug_in) switch (Plugin -> Type) { case cmsPluginMemHandlerSig: - if (!_cmsRegisterMemHandlerPlugin(Plugin)) return FALSE; + if (!_cmsRegisterMemHandlerPlugin(id, Plugin)) return FALSE; break; case cmsPluginInterpolationSig: - if (!_cmsRegisterInterpPlugin(Plugin)) return FALSE; + if (!_cmsRegisterInterpPlugin(id, Plugin)) return FALSE; break; case cmsPluginTagTypeSig: @@ -594,8 +597,12 @@ cmsBool CMSEXPORT cmsPluginTHR(cmsContext id, void* Plug_in) if (!_cmsRegisterTransformPlugin(id, Plugin)) return FALSE; break; + case cmsPluginMutexSig: + if (!_cmsRegisterMutexPlugin(id, Plugin)) return FALSE; + break; + default: - cmsSignalError(0, cmsERROR_UNKNOWN_EXTENSION, "Unrecognized plugin type '%X'", Plugin -> Type); + cmsSignalError(id, cmsERROR_UNKNOWN_EXTENSION, "Unrecognized plugin type '%X'", Plugin -> Type); return FALSE; } } @@ -608,19 +615,322 @@ cmsBool CMSEXPORT cmsPluginTHR(cmsContext id, void* Plug_in) // Revert all plug-ins to default void CMSEXPORT cmsUnregisterPlugins(void) { - _cmsRegisterMemHandlerPlugin(NULL); - _cmsRegisterInterpPlugin(NULL); - _cmsRegisterTagTypePlugin(NULL, NULL); - _cmsRegisterTagPlugin(NULL, NULL); - _cmsRegisterFormattersPlugin(NULL, NULL); - _cmsRegisterRenderingIntentPlugin(NULL, NULL); - _cmsRegisterParametricCurvesPlugin(NULL, NULL); - _cmsRegisterMultiProcessElementPlugin(NULL, NULL); - _cmsRegisterOptimizationPlugin(NULL, NULL); - _cmsRegisterTransformPlugin(NULL, NULL); + cmsUnregisterPluginsTHR(NULL); +} + + +// The Global storage for system context. This is the one and only global variable +// pointers structure. All global vars are referenced here. +static struct _cmsContext_struct globalContext = { + + cmsContextMagicNumber, + NULL, // No suballocator + { + NULL, // UserPtr, + &_cmsLogErrorChunk, // Logger, + &_cmsAlarmCodesChunk, // AlarmCodes, + &_cmsAdaptationStateChunk, // AdaptationState, + &_cmsMemPluginChunk, // MemPlugin, + &_cmsInterpPluginChunk, // InterpPlugin, + &_cmsCurvesPluginChunk, // CurvesPlugin, + &_cmsFormattersPluginChunk, // FormattersPlugin, + &_cmsTagTypePluginChunk, // TagTypePlugin, + &_cmsTagPluginChunk, // TagPlugin, + &_cmsIntentsPluginChunk, // IntentPlugin, + &_cmsMPETypePluginChunk, // MPEPlugin, + &_cmsOptimizationPluginChunk, // OptimizationPlugin, + &_cmsTransformPluginChunk, // TransformPlugin, + &_cmsMutexPluginChunk // MutexPlugin + }, + + { NULL, NULL, NULL, NULL, NULL, NULL } // The default memory allocator is not used for context 0 +}; + + +// This is a replacement for (intptr_t), which despite C99, is not supported by some compilers. +// Clever idea from Robin, to use pointer substraction. +#define PTR_TO_INT(ptr) (((cmsUInt8Number*) (ptr)) - (cmsUInt8Number*) 0) + +// Internal, get associated pointer, with guessing. Never returns NULL. +struct _cmsContext_struct* _cmsGetContext(cmsContext ContextID) +{ +#ifdef CMS_CONTEXT_IN_LEGACY_MODE + + return &globalContext; + cmsUNUSED_PARAMETER(ContextID); +#else + struct _cmsContext_struct* ctx = (struct _cmsContext_struct*) ContextID; + + // Check for low numbers. Yes, I know, it is a hack... but it works + if ((PTR_TO_INT(ContextID) < 0x1000) && (PTR_TO_INT(ContextID) > 0)) + return &globalContext; + + // On 0, use global settings + if (ctx == NULL) + return &globalContext; + + // Validate across magic number + if (ctx ->Magic != cmsContextMagicNumber) + return &globalContext; + + // New-style context, + return ctx; +#endif +} + + +// Internal: get the memory area associanted with each context client +// Returns the block assigned to the specific zone. +void* _cmsContextGetClientChunk(cmsContext ContextID, _cmsMemoryClient mc) +{ + struct _cmsContext_struct* ctx; + void *ptr; + + if (mc < 0 || mc >= MemoryClientMax) { + cmsSignalError(ContextID, cmsERROR_RANGE, "Bad context client"); + return NULL; + } + + ctx = _cmsGetContext(ContextID); + ptr = ctx ->chunks[mc]; - if (PluginPool != NULL) - _cmsSubAllocDestroy(PluginPool); + if (ptr != NULL) + return ptr; - PluginPool = NULL; + // A null ptr means no special settings for that context, and this + // reverts to Context0 globals + return globalContext.chunks[mc]; } + + +// This function returns the given context its default pristine state, +// as no plug-ins were declared. There is no way to unregister a single +// plug-in, as a single call to cmsPluginTHR() function may register +// many different plug-ins simultaneously, then there is no way to +// identify which plug-in to unregister. +void CMSEXPORT cmsUnregisterPluginsTHR(cmsContext ContextID) +{ + _cmsRegisterMemHandlerPlugin(ContextID, NULL); + _cmsRegisterInterpPlugin(ContextID, NULL); + _cmsRegisterTagTypePlugin(ContextID, NULL); + _cmsRegisterTagPlugin(ContextID, NULL); + _cmsRegisterFormattersPlugin(ContextID, NULL); + _cmsRegisterRenderingIntentPlugin(ContextID, NULL); + _cmsRegisterParametricCurvesPlugin(ContextID, NULL); + _cmsRegisterMultiProcessElementPlugin(ContextID, NULL); + _cmsRegisterOptimizationPlugin(ContextID, NULL); + _cmsRegisterTransformPlugin(ContextID, NULL); + _cmsRegisterMutexPlugin(ContextID, NULL); +} + + +// Returns the memory manager plug-in, if any, from the Plug-in bundle +static +cmsPluginMemHandler* _cmsFindMemoryPlugin(void* PluginBundle) +{ + cmsPluginBase* Plugin; + + for (Plugin = (cmsPluginBase*) PluginBundle; + Plugin != NULL; + Plugin = Plugin -> Next) { + + if (Plugin -> Magic == cmsPluginMagicNumber && + Plugin -> ExpectedVersion <= LCMS_VERSION && + Plugin -> Type == cmsPluginMemHandlerSig) { + + // Found! + return (cmsPluginMemHandler*) Plugin; + } + } + + // Nope, revert to defaults + return NULL; +} + + +// Creates a new context with optional associated plug-ins. Caller may also specify an optional pointer to user-defined +// data that will be forwarded to plug-ins and logger. +cmsContext CMSEXPORT cmsCreateContext(void* Plugin, void* UserData) +{ +#ifdef CMS_CONTEXT_IN_LEGACY_MODE + cmsSignalError(0, cmsERROR_NOT_SUITABLE, "Lcms is compiled as legacy context mode and you called an advanced context function"); + return UserData; + + cmsUNUSED_PARAMETER(Plugin); + cmsUNUSED_PARAMETER(UserData); +#else + + + struct _cmsContext_struct* ctx; + struct _cmsContext_struct fakeContext; + + _cmsInstallAllocFunctions(_cmsFindMemoryPlugin(Plugin), &fakeContext.DefaultMemoryManager); + + fakeContext.chunks[UserPtr] = UserData; + fakeContext.chunks[MemPlugin] = &fakeContext.DefaultMemoryManager; + + // Create the context structure. + ctx = (struct _cmsContext_struct*) _cmsMalloc(&fakeContext, sizeof(struct _cmsContext_struct)); + if (ctx == NULL) + return NULL; // Something very wrong happened! + + // Init the structure and the memory manager + memset(ctx, 0, sizeof(struct _cmsContext_struct)); + + // Keep memory manager + memcpy(&ctx->DefaultMemoryManager, &fakeContext.DefaultMemoryManager, sizeof(_cmsMemPluginChunk)); + + // Identify it as a context + ctx ->Magic = cmsContextMagicNumber; + + ctx ->chunks[UserPtr] = UserData; + ctx ->chunks[MemPlugin] = &ctx->DefaultMemoryManager; + + // Now we can allocate the pool by using default memory manager + ctx ->MemPool = _cmsCreateSubAlloc(ctx, 22 * sizeof(void*)); // default size about 32 pointers + if (ctx ->MemPool == NULL) { + + cmsDeleteContext(ctx); + return NULL; + } + + _cmsAllocLogErrorChunk(ctx, NULL); + _cmsAllocAlarmCodesChunk(ctx, NULL); + _cmsAllocAdaptationStateChunk(ctx, NULL); + _cmsAllocMemPluginChunk(ctx, NULL); + _cmsAllocInterpPluginChunk(ctx, NULL); + _cmsAllocCurvesPluginChunk(ctx, NULL); + _cmsAllocFormattersPluginChunk(ctx, NULL); + _cmsAllocTagTypePluginChunk(ctx, NULL); + _cmsAllocMPETypePluginChunk(ctx, NULL); + _cmsAllocTagPluginChunk(ctx, NULL); + _cmsAllocIntentsPluginChunk(ctx, NULL); + _cmsAllocOptimizationPluginChunk(ctx, NULL); + _cmsAllocTransformPluginChunk(ctx, NULL); + _cmsAllocMutexPluginChunk(ctx, NULL); + + // Setup the plug-ins + if (!cmsPluginTHR(ctx, Plugin)) { + + cmsDeleteContext(ctx); + return NULL; + } + + return (cmsContext) ctx; +#endif +} + +// Duplicates a context with all associated plug-ins. +// Caller may specify an optional pointer to user-defined +// data that will be forwarded to plug-ins and logger. +cmsContext CMSEXPORT cmsDupContext(cmsContext ContextID, void* NewUserData) +{ +#ifdef CMS_CONTEXT_IN_LEGACY_MODE + cmsSignalError(ContextID, cmsERROR_NOT_SUITABLE, "Lcms is compiled as legacy context mode and you called an advanced context function"); + return ContextID; + cmsUNUSED_PARAMETER(NewUserData); + +#else + int i; + struct _cmsContext_struct* ctx; + const struct _cmsContext_struct* src = _cmsGetContext(ContextID); + + void* userData = (NewUserData != NULL) ? NewUserData : src -> chunks[UserPtr]; + + + ctx = (struct _cmsContext_struct*) _cmsMalloc(ContextID, sizeof(struct _cmsContext_struct)); + if (ctx == NULL) + return NULL; // Something very wrong happened + + // Setup default memory allocators + memcpy(&ctx->DefaultMemoryManager, &src->DefaultMemoryManager, sizeof(ctx->DefaultMemoryManager)); + + ctx ->Magic = cmsContextMagicNumber; + + ctx ->chunks[UserPtr] = userData; + ctx ->chunks[MemPlugin] = &ctx->DefaultMemoryManager; + + ctx ->MemPool = _cmsCreateSubAlloc(ctx, 22 * sizeof(void*)); + if (ctx ->MemPool == NULL) { + + cmsDeleteContext(ctx); + return NULL; + } + + // Allocate all required chunks. + _cmsAllocLogErrorChunk(ctx, src); + _cmsAllocAlarmCodesChunk(ctx, src); + _cmsAllocAdaptationStateChunk(ctx, src); + _cmsAllocMemPluginChunk(ctx, src); + _cmsAllocInterpPluginChunk(ctx, src); + _cmsAllocCurvesPluginChunk(ctx, src); + _cmsAllocFormattersPluginChunk(ctx, src); + _cmsAllocTagTypePluginChunk(ctx, src); + _cmsAllocMPETypePluginChunk(ctx, src); + _cmsAllocTagPluginChunk(ctx, src); + _cmsAllocIntentsPluginChunk(ctx, src); + _cmsAllocOptimizationPluginChunk(ctx, src); + _cmsAllocTransformPluginChunk(ctx, src); + _cmsAllocMutexPluginChunk(ctx, src); + + // Make sure no one failed + for (i=Logger; i < MemoryClientMax; i++) { + + if (src ->chunks[i] == NULL) { + cmsDeleteContext((cmsContext) ctx); + return NULL; + } + } + + return (cmsContext) ctx; +#endif + +} + +// Frees any resources associated with the given context, +// and destroys the context placeholder. +// The ContextID can no longer be used in any THR operation. +void CMSEXPORT cmsDeleteContext(cmsContext ContextID) +{ +#ifdef CMS_CONTEXT_IN_LEGACY_MODE + cmsSignalError(ContextID, cmsERROR_NOT_SUITABLE, "Lcms is compiled as legacy context mode and you called an advanced context function"); + cmsUNUSED_PARAMETER(ContextID); +#else + + if (ContextID != NULL) { + + struct _cmsContext_struct* ctx = (struct _cmsContext_struct*) ContextID; + struct _cmsContext_struct fakeContext; + + memcpy(&fakeContext.DefaultMemoryManager, &ctx->DefaultMemoryManager, sizeof(ctx->DefaultMemoryManager)); + + fakeContext.chunks[UserPtr] = ctx ->chunks[UserPtr]; + fakeContext.chunks[MemPlugin] = &fakeContext.DefaultMemoryManager; + + + // Get rid of plugins + cmsUnregisterPluginsTHR(ContextID); + + // Since all memory is allocated in the private pool, all what we need to do is destroy the pool + if (ctx -> MemPool != NULL) + _cmsSubAllocDestroy(ctx ->MemPool); + ctx -> MemPool = NULL; + + // free the memory block itself + _cmsFree(&fakeContext, ctx); + } +#endif +} + +// Returns the user data associated to the given ContextID, or NULL if no user data was attached on context creation +void* CMSEXPORT cmsGetContextUserData(cmsContext ContextID) +{ +#ifdef CMS_CONTEXT_IN_LEGACY_MODE + cmsSignalError(ContextID, cmsERROR_NOT_SUITABLE, "Lcms is compiled as legacy context mode and you called an advanced context function"); + return ContextID; +#else + return _cmsContextGetClientChunk(ContextID, UserPtr); +#endif +} + + diff --git a/src/cmsps2.c b/src/cmsps2.c index fe91500..224b44b 100644 --- a/src/cmsps2.c +++ b/src/cmsps2.c @@ -913,7 +913,7 @@ int WriteInputLUT(cmsIOHANDLER* m, cmsHPROFILE hProfile, int Intent, cmsUInt32Nu if (DeviceLink == NULL) return 0; dwFlags |= cmsFLAGS_FORCE_CLUT; - _cmsOptimizePipeline(&DeviceLink, Intent, &InputFormat, &OutFrm, &dwFlags); + _cmsOptimizePipeline(m->ContextID, &DeviceLink, Intent, &InputFormat, &OutFrm, &dwFlags); rc = EmitCIEBasedDEF(m, DeviceLink, Intent, &BlackPointAdaptedToD50); cmsPipelineFree(DeviceLink); @@ -1330,7 +1330,7 @@ int WriteOutputLUT(cmsIOHANDLER* m, cmsHPROFILE hProfile, int Intent, cmsUInt32N // We need a CLUT dwFlags |= cmsFLAGS_FORCE_CLUT; - _cmsOptimizePipeline(&DeviceLink, RelativeEncodingIntent, &InFrm, &OutputFormat, &dwFlags); + _cmsOptimizePipeline(m->ContextID, &DeviceLink, RelativeEncodingIntent, &InFrm, &OutputFormat, &dwFlags); _cmsIOPrintf(m, "<<\n"); _cmsIOPrintf(m, "/ColorRenderingType 1\n"); diff --git a/src/cmstypes.c b/src/cmstypes.c index 9114a6e..a9e3fa0 100644 --- a/src/cmstypes.c +++ b/src/cmstypes.c @@ -60,54 +60,49 @@ typedef struct _cmsTagTypeLinkedList_st { // Helper macro to define a MPE handler. Callbacks do have a fixed naming convention #define TYPE_MPE_HANDLER(t, x) { (t), READ_FN(x), WRITE_FN(x), GenericMPEdup, GenericMPEfree, NULL, 0 } -// Register a new type handler. This routine is shared between normal types and MPE +// Register a new type handler. This routine is shared between normal types and MPE. LinkedList points to the optional list head static -cmsBool RegisterTypesPlugin(cmsContext id, cmsPluginBase* Data, _cmsTagTypeLinkedList* LinkedList, cmsUInt32Number DefaultListCount) +cmsBool RegisterTypesPlugin(cmsContext id, cmsPluginBase* Data, _cmsMemoryClient pos) { cmsPluginTagType* Plugin = (cmsPluginTagType*) Data; - _cmsTagTypeLinkedList *pt, *Anterior = NULL; + _cmsTagTypePluginChunkType* ctx = ( _cmsTagTypePluginChunkType*) _cmsContextGetClientChunk(id, pos); + _cmsTagTypeLinkedList *pt; // Calling the function with NULL as plug-in would unregister the plug in. if (Data == NULL) { - LinkedList[DefaultListCount-1].Next = NULL; + // There is no need to set free the memory, as pool is destroyed as a whole. + ctx ->TagTypes = NULL; return TRUE; } - pt = Anterior = LinkedList; - while (pt != NULL) { - - if (Plugin->Handler.Signature == pt -> Handler.Signature) { - pt ->Handler = Plugin ->Handler; // Replace old behaviour. - // Note that since no memory is allocated, unregister does not - // reset this action. - return TRUE; - } - - Anterior = pt; - pt = pt ->Next; - } - - // Registering happens in plug-in memory pool + // Registering happens in plug-in memory pool. pt = (_cmsTagTypeLinkedList*) _cmsPluginMalloc(id, sizeof(_cmsTagTypeLinkedList)); if (pt == NULL) return FALSE; pt ->Handler = Plugin ->Handler; - pt ->Next = NULL; - - if (Anterior) - Anterior -> Next = pt; + pt ->Next = ctx ->TagTypes; + ctx ->TagTypes = pt; + return TRUE; } -// Return handler for a given type or NULL if not found. Shared between normal types and MPE +// Return handler for a given type or NULL if not found. Shared between normal types and MPE. It first tries the additons +// made by plug-ins and then the built-in defaults. static -cmsTagTypeHandler* GetHandler(cmsTagTypeSignature sig, _cmsTagTypeLinkedList* LinkedList) +cmsTagTypeHandler* GetHandler(cmsTagTypeSignature sig, _cmsTagTypeLinkedList* PluginLinkedList, _cmsTagTypeLinkedList* DefaultLinkedList) { _cmsTagTypeLinkedList* pt; - for (pt = LinkedList; + for (pt = PluginLinkedList; + pt != NULL; + pt = pt ->Next) { + + if (sig == pt -> Handler.Signature) return &pt ->Handler; + } + + for (pt = DefaultLinkedList; pt != NULL; pt = pt ->Next) { @@ -134,6 +129,7 @@ cmsBool _cmsWriteWCharArray(cmsIOHANDLER* io, cmsUInt32Number n, const wchar_t* return TRUE; } +// Auxiliar to read an array of wchar_t static cmsBool _cmsReadWCharArray(cmsIOHANDLER* io, cmsUInt32Number n, wchar_t* Array) { @@ -748,6 +744,8 @@ cmsBool Type_Text_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, // Create memory Text = (char*) _cmsMalloc(self ->ContextID, size); + if (Text == NULL) return FALSE; + cmsMLUgetASCII(mlu, cmsNoLanguage, cmsNoCountry, Text, size); // Write it, including separator @@ -4355,7 +4353,7 @@ static _cmsTagTypeLinkedList SupportedMPEtypes[] = { {TYPE_MPE_HANDLER((cmsTagTypeSignature) cmsSigCLutElemType, MPEclut), NULL }, }; -#define DEFAULT_MPE_TYPE_COUNT (sizeof(SupportedMPEtypes) / sizeof(_cmsTagTypeLinkedList)) +_cmsTagTypePluginChunkType _cmsMPETypePluginChunk = { NULL }; static cmsBool ReadMPEElem(struct _cms_typehandler_struct* self, @@ -4368,6 +4366,8 @@ cmsBool ReadMPEElem(struct _cms_typehandler_struct* self, cmsTagTypeHandler* TypeHandler; cmsUInt32Number nItems; cmsPipeline *NewLUT = (cmsPipeline *) Cargo; + _cmsTagTypePluginChunkType* MPETypePluginChunk = ( _cmsTagTypePluginChunkType*) _cmsContextGetClientChunk(self->ContextID, MPEPlugin); + // Take signature and channels for each element. if (!_cmsReadUInt32Number(io, (cmsUInt32Number*) &ElementSig)) return FALSE; @@ -4376,7 +4376,7 @@ cmsBool ReadMPEElem(struct _cms_typehandler_struct* self, if (!_cmsReadUInt32Number(io, NULL)) return FALSE; // Read diverse MPE types - TypeHandler = GetHandler((cmsTagTypeSignature) ElementSig, SupportedMPEtypes); + TypeHandler = GetHandler((cmsTagTypeSignature) ElementSig, MPETypePluginChunk ->TagTypes, SupportedMPEtypes); if (TypeHandler == NULL) { char String[5]; @@ -4453,6 +4453,7 @@ cmsBool Type_MPE_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, v cmsPipeline* Lut = (cmsPipeline*) Ptr; cmsStage* Elem = Lut ->Elements; cmsTagTypeHandler* TypeHandler; + _cmsTagTypePluginChunkType* MPETypePluginChunk = ( _cmsTagTypePluginChunkType*) _cmsContextGetClientChunk(self->ContextID, MPEPlugin); BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase); @@ -4486,7 +4487,7 @@ cmsBool Type_MPE_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, v ElementSig = Elem ->Type; - TypeHandler = GetHandler((cmsTagTypeSignature) ElementSig, SupportedMPEtypes); + TypeHandler = GetHandler((cmsTagTypeSignature) ElementSig, MPETypePluginChunk->TagTypes, SupportedMPEtypes); if (TypeHandler == NULL) { char String[5]; @@ -5263,24 +5264,95 @@ static _cmsTagTypeLinkedList SupportedTagTypes[] = { {TYPE_HANDLER(cmsSigVcgtType, vcgt), NULL } }; -#define DEFAULT_TAG_TYPE_COUNT (sizeof(SupportedTagTypes) / sizeof(_cmsTagTypeLinkedList)) + +_cmsTagTypePluginChunkType _cmsTagTypePluginChunk = { NULL }; + + + +// Duplicates the zone of memory used by the plug-in in the new context +static +void DupTagTypeList(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src, + int loc) +{ + _cmsTagTypePluginChunkType newHead = { NULL }; + _cmsTagTypeLinkedList* entry; + _cmsTagTypeLinkedList* Anterior = NULL; + _cmsTagTypePluginChunkType* head = (_cmsTagTypePluginChunkType*) src->chunks[loc]; + + // Walk the list copying all nodes + for (entry = head->TagTypes; + entry != NULL; + entry = entry ->Next) { + + _cmsTagTypeLinkedList *newEntry = ( _cmsTagTypeLinkedList *) _cmsSubAllocDup(ctx ->MemPool, entry, sizeof(_cmsTagTypeLinkedList)); + + if (newEntry == NULL) + return; + + // We want to keep the linked list order, so this is a little bit tricky + newEntry -> Next = NULL; + if (Anterior) + Anterior -> Next = newEntry; + + Anterior = newEntry; + + if (newHead.TagTypes == NULL) + newHead.TagTypes = newEntry; + } + + ctx ->chunks[loc] = _cmsSubAllocDup(ctx->MemPool, &newHead, sizeof(_cmsTagTypePluginChunkType)); +} + + +void _cmsAllocTagTypePluginChunk(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src) +{ + if (src != NULL) { + + // Duplicate the LIST + DupTagTypeList(ctx, src, TagTypePlugin); + } + else { + static _cmsTagTypePluginChunkType TagTypePluginChunk = { NULL }; + ctx ->chunks[TagTypePlugin] = _cmsSubAllocDup(ctx ->MemPool, &TagTypePluginChunk, sizeof(_cmsTagTypePluginChunkType)); + } +} + +void _cmsAllocMPETypePluginChunk(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src) +{ + if (src != NULL) { + + // Duplicate the LIST + DupTagTypeList(ctx, src, MPEPlugin); + } + else { + static _cmsTagTypePluginChunkType TagTypePluginChunk = { NULL }; + ctx ->chunks[MPEPlugin] = _cmsSubAllocDup(ctx ->MemPool, &TagTypePluginChunk, sizeof(_cmsTagTypePluginChunkType)); + } + +} + // Both kind of plug-ins share same structure cmsBool _cmsRegisterTagTypePlugin(cmsContext id, cmsPluginBase* Data) { - return RegisterTypesPlugin(id, Data, SupportedTagTypes, DEFAULT_TAG_TYPE_COUNT); + return RegisterTypesPlugin(id, Data, TagTypePlugin); } cmsBool _cmsRegisterMultiProcessElementPlugin(cmsContext id, cmsPluginBase* Data) { - return RegisterTypesPlugin(id, Data, SupportedMPEtypes, DEFAULT_MPE_TYPE_COUNT); + return RegisterTypesPlugin(id, Data,MPEPlugin); } // Wrapper for tag types -cmsTagTypeHandler* _cmsGetTagTypeHandler(cmsTagTypeSignature sig) +cmsTagTypeHandler* _cmsGetTagTypeHandler(cmsContext ContextID, cmsTagTypeSignature sig) { - return GetHandler(sig, SupportedTagTypes); + _cmsTagTypePluginChunkType* ctx = ( _cmsTagTypePluginChunkType*) _cmsContextGetClientChunk(ContextID, TagTypePlugin); + + return GetHandler(sig, ctx->TagTypes, SupportedTagTypes); } // ******************************************************************************** @@ -5395,30 +5467,68 @@ static _cmsTagLinkedList SupportedTags[] = { cmsSigDeviceSettingsTag ==> Deprecated, useless */ -#define DEFAULT_TAG_COUNT (sizeof(SupportedTags) / sizeof(_cmsTagLinkedList)) -cmsBool _cmsRegisterTagPlugin(cmsContext id, cmsPluginBase* Data) +_cmsTagPluginChunkType _cmsTagPluginChunk = { NULL }; + + +// Duplicates the zone of memory used by the plug-in in the new context +static +void DupTagList(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src) { - cmsPluginTag* Plugin = (cmsPluginTag*) Data; - _cmsTagLinkedList *pt, *Anterior; + _cmsTagPluginChunkType newHead = { NULL }; + _cmsTagLinkedList* entry; + _cmsTagLinkedList* Anterior = NULL; + _cmsTagPluginChunkType* head = (_cmsTagPluginChunkType*) src->chunks[TagPlugin]; + // Walk the list copying all nodes + for (entry = head->Tag; + entry != NULL; + entry = entry ->Next) { - if (Data == NULL) { + _cmsTagLinkedList *newEntry = ( _cmsTagLinkedList *) _cmsSubAllocDup(ctx ->MemPool, entry, sizeof(_cmsTagLinkedList)); - SupportedTags[DEFAULT_TAG_COUNT-1].Next = NULL; - return TRUE; + if (newEntry == NULL) + return; + + // We want to keep the linked list order, so this is a little bit tricky + newEntry -> Next = NULL; + if (Anterior) + Anterior -> Next = newEntry; + + Anterior = newEntry; + + if (newHead.Tag == NULL) + newHead.Tag = newEntry; + } + + ctx ->chunks[TagPlugin] = _cmsSubAllocDup(ctx->MemPool, &newHead, sizeof(_cmsTagPluginChunkType)); +} + +void _cmsAllocTagPluginChunk(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src) +{ + if (src != NULL) { + + DupTagList(ctx, src); + } + else { + static _cmsTagPluginChunkType TagPluginChunk = { NULL }; + ctx ->chunks[TagPlugin] = _cmsSubAllocDup(ctx ->MemPool, &TagPluginChunk, sizeof(_cmsTagPluginChunkType)); } - pt = Anterior = SupportedTags; - while (pt != NULL) { +} - if (Plugin->Signature == pt -> Signature) { - pt ->Descriptor = Plugin ->Descriptor; // Replace old behaviour - return TRUE; - } +cmsBool _cmsRegisterTagPlugin(cmsContext id, cmsPluginBase* Data) +{ + cmsPluginTag* Plugin = (cmsPluginTag*) Data; + _cmsTagLinkedList *pt; + _cmsTagPluginChunkType* TagPluginChunk = ( _cmsTagPluginChunkType*) _cmsContextGetClientChunk(id, TagPlugin); + + if (Data == NULL) { - Anterior = pt; - pt = pt ->Next; + TagPluginChunk->Tag = NULL; + return TRUE; } pt = (_cmsTagLinkedList*) _cmsPluginMalloc(id, sizeof(_cmsTagLinkedList)); @@ -5426,17 +5536,25 @@ cmsBool _cmsRegisterTagPlugin(cmsContext id, cmsPluginBase* Data) pt ->Signature = Plugin ->Signature; pt ->Descriptor = Plugin ->Descriptor; - pt ->Next = NULL; - - if (Anterior != NULL) Anterior -> Next = pt; + pt ->Next = TagPluginChunk ->Tag; + TagPluginChunk ->Tag = pt; + return TRUE; } // Return a descriptor for a given tag or NULL -cmsTagDescriptor* _cmsGetTagDescriptor(cmsTagSignature sig) +cmsTagDescriptor* _cmsGetTagDescriptor(cmsContext ContextID, cmsTagSignature sig) { _cmsTagLinkedList* pt; + _cmsTagPluginChunkType* TagPluginChunk = ( _cmsTagPluginChunkType*) _cmsContextGetClientChunk(ContextID, TagPlugin); + + for (pt = TagPluginChunk->Tag; + pt != NULL; + pt = pt ->Next) { + + if (sig == pt -> Signature) return &pt ->Descriptor; + } for (pt = SupportedTags; pt != NULL; diff --git a/src/cmsvirt.c b/src/cmsvirt.c index 953377a..deeb7a6 100644 --- a/src/cmsvirt.c +++ b/src/cmsvirt.c @@ -990,7 +990,7 @@ typedef struct { static const cmsAllowedLUT AllowedLUTTypes[] = { - { FALSE, 0, cmsSigLut16Type, 4, { cmsSigMatrixElemType, cmsSigCurveSetElemType, cmsSigCLutElemType, cmsSigCurveSetElemType}}, + { FALSE, 0, cmsSigLut16Type, 4, { cmsSigMatrixElemType, cmsSigCurveSetElemType, cmsSigCLutElemType, cmsSigCurveSetElemType}}, { FALSE, 0, cmsSigLut16Type, 3, { cmsSigCurveSetElemType, cmsSigCLutElemType, cmsSigCurveSetElemType}}, { FALSE, 0, cmsSigLut16Type, 2, { cmsSigCurveSetElemType, cmsSigCLutElemType}}, { TRUE , 0, cmsSigLutAtoBType, 1, { cmsSigCurveSetElemType }}, @@ -1121,7 +1121,7 @@ cmsHPROFILE CMSEXPORT cmsTransform2DeviceLink(cmsHTRANSFORM hTransform, cmsFloat if (AllowedLUT == NULL) { // Try to optimize - _cmsOptimizePipeline(&LUT, xform ->RenderingIntent, &FrmIn, &FrmOut, &dwFlags); + _cmsOptimizePipeline(ContextID, &LUT, xform ->RenderingIntent, &FrmIn, &FrmOut, &dwFlags); AllowedLUT = FindCombination(LUT, Version >= 4.0, DestinationTag); } @@ -1130,7 +1130,7 @@ cmsHPROFILE CMSEXPORT cmsTransform2DeviceLink(cmsHTRANSFORM hTransform, cmsFloat if (AllowedLUT == NULL) { dwFlags |= cmsFLAGS_FORCE_CLUT; - _cmsOptimizePipeline(&LUT, xform ->RenderingIntent, &FrmIn, &FrmOut, &dwFlags); + _cmsOptimizePipeline(ContextID, &LUT, xform ->RenderingIntent, &FrmIn, &FrmOut, &dwFlags); // Put identity curves if needed if (cmsPipelineGetPtrToFirstStage(LUT) ->Type != cmsSigCurveSetElemType) diff --git a/src/cmsxform.c b/src/cmsxform.c index b39c116..b2705cb 100644 --- a/src/cmsxform.c +++ b/src/cmsxform.c @@ -29,44 +29,120 @@ // Transformations stuff // ----------------------------------------------------------------------- -// Alarm codes for 16-bit transformations, because the fixed range of containers there are -// no values left to mark out of gamut. volatile is C99 per 6.2.5 -static volatile cmsUInt16Number Alarm[cmsMAXCHANNELS] = { 0x7F00, 0x7F00, 0x7F00, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; -static volatile cmsFloat64Number GlobalAdaptationState = 1; +#define DEFAULT_OBSERVER_ADAPTATION_STATE 1.0 + +// The Context0 observer adaptation state. +_cmsAdaptationStateChunkType _cmsAdaptationStateChunk = { DEFAULT_OBSERVER_ADAPTATION_STATE }; + +// Init and duplicate observer adaptation state +void _cmsAllocAdaptationStateChunk(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src) +{ + static _cmsAdaptationStateChunkType AdaptationStateChunk = { DEFAULT_OBSERVER_ADAPTATION_STATE }; + void* from; + + if (src != NULL) { + from = src ->chunks[AdaptationStateContext]; + } + else { + from = &AdaptationStateChunk; + } + + ctx ->chunks[AdaptationStateContext] = _cmsSubAllocDup(ctx ->MemPool, from, sizeof(_cmsAdaptationStateChunkType)); +} + + +// Sets adaptation state for absolute colorimetric intent in the given context. Adaptation state applies on all +// but cmsCreateExtendedTransformTHR(). Little CMS can handle incomplete adaptation states. +cmsFloat64Number CMSEXPORT cmsSetAdaptationStateTHR(cmsContext ContextID, cmsFloat64Number d) +{ + cmsFloat64Number prev; + _cmsAdaptationStateChunkType* ptr = (_cmsAdaptationStateChunkType*) _cmsContextGetClientChunk(ContextID, AdaptationStateContext); + + // Get previous value for return + prev = ptr ->AdaptationState; + + // Set the value if d is positive or zero + if (d >= 0.0) { + + ptr ->AdaptationState = d; + } + + // Always return previous value + return prev; +} + // The adaptation state may be defaulted by this function. If you don't like it, use the extended transform routine cmsFloat64Number CMSEXPORT cmsSetAdaptationState(cmsFloat64Number d) -{ - cmsFloat64Number OldVal = GlobalAdaptationState; +{ + return cmsSetAdaptationStateTHR(NULL, d); +} + +// ----------------------------------------------------------------------- + +// Alarm codes for 16-bit transformations, because the fixed range of containers there are +// no values left to mark out of gamut. - if (d >= 0) - GlobalAdaptationState = d; +#define DEFAULT_ALARM_CODES_VALUE {0x7F00, 0x7F00, 0x7F00, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} - return OldVal; +_cmsAlarmCodesChunkType _cmsAlarmCodesChunk = { DEFAULT_ALARM_CODES_VALUE }; + +// Sets the codes used to mark out-out-gamut on Proofing transforms for a given context. Values are meant to be +// encoded in 16 bits. +void CMSEXPORT cmsSetAlarmCodesTHR(cmsContext ContextID, const cmsUInt16Number AlarmCodesP[cmsMAXCHANNELS]) +{ + _cmsAlarmCodesChunkType* ContextAlarmCodes = (_cmsAlarmCodesChunkType*) _cmsContextGetClientChunk(ContextID, AlarmCodesContext); + + _cmsAssert(ContextAlarmCodes != NULL); // Can't happen + + memcpy(ContextAlarmCodes->AlarmCodes, AlarmCodesP, sizeof(ContextAlarmCodes->AlarmCodes)); } -// Alarm codes are always global -void CMSEXPORT cmsSetAlarmCodes(cmsUInt16Number NewAlarm[cmsMAXCHANNELS]) +// Gets the current codes used to mark out-out-gamut on Proofing transforms for the given context. +// Values are meant to be encoded in 16 bits. +void CMSEXPORT cmsGetAlarmCodesTHR(cmsContext ContextID, cmsUInt16Number AlarmCodesP[cmsMAXCHANNELS]) { - int i; + _cmsAlarmCodesChunkType* ContextAlarmCodes = (_cmsAlarmCodesChunkType*) _cmsContextGetClientChunk(ContextID, AlarmCodesContext); - _cmsAssert(NewAlarm != NULL); + _cmsAssert(ContextAlarmCodes != NULL); // Can't happen - for (i=0; i < cmsMAXCHANNELS; i++) - Alarm[i] = NewAlarm[i]; + memcpy(AlarmCodesP, ContextAlarmCodes->AlarmCodes, sizeof(ContextAlarmCodes->AlarmCodes)); } -// You can get the codes cas well -void CMSEXPORT cmsGetAlarmCodes(cmsUInt16Number OldAlarm[cmsMAXCHANNELS]) +void CMSEXPORT cmsSetAlarmCodes(const cmsUInt16Number NewAlarm[cmsMAXCHANNELS]) { - int i; + _cmsAssert(NewAlarm != NULL); + cmsSetAlarmCodesTHR(NULL, NewAlarm); +} + +void CMSEXPORT cmsGetAlarmCodes(cmsUInt16Number OldAlarm[cmsMAXCHANNELS]) +{ _cmsAssert(OldAlarm != NULL); + cmsGetAlarmCodesTHR(NULL, OldAlarm); +} - for (i=0; i < cmsMAXCHANNELS; i++) - OldAlarm[i] = Alarm[i]; + +// Init and duplicate alarm codes +void _cmsAllocAlarmCodesChunk(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src) +{ + static _cmsAlarmCodesChunkType AlarmCodesChunk = { DEFAULT_ALARM_CODES_VALUE }; + void* from; + + if (src != NULL) { + from = src ->chunks[AlarmCodesContext]; + } + else { + from = &AlarmCodesChunk; + } + + ctx ->chunks[AlarmCodesContext] = _cmsSubAllocDup(ctx ->MemPool, from, sizeof(_cmsAlarmCodesChunkType)); } +// ----------------------------------------------------------------------- + // Get rid of transform resources void CMSEXPORT cmsDeleteTransform(cmsHTRANSFORM hTransform) { @@ -173,6 +249,30 @@ void FloatXFORM(_cmsTRANSFORM* p, } } + +static +void NullFloatXFORM(_cmsTRANSFORM* p, + const void* in, + void* out, + cmsUInt32Number Size, + cmsUInt32Number Stride) +{ + cmsUInt8Number* accum; + cmsUInt8Number* output; + cmsFloat32Number fIn[cmsMAXCHANNELS]; + cmsUInt32Number i, n; + + accum = (cmsUInt8Number*) in; + output = (cmsUInt8Number*) out; + n = Size; + + for (i=0; i < n; i++) { + + accum = p -> FromInputFloat(p, fIn, accum, Stride); + output = p -> ToOutputFloat(p, fIn, output, Stride); + } +} + // 16 bit precision ----------------------------------------------------------------------------------------------------------- // Null transformation, only applies formatters. No caché @@ -223,7 +323,7 @@ void PrecalculatedXFORM(_cmsTRANSFORM* p, } -// Auxiliar: Handle precalculated gamut check +// Auxiliar: Handle precalculated gamut check. The retrieval of context may be alittle bit slow, but this function is not critical. static void TransformOnePixelWithGamutCheck(_cmsTRANSFORM* p, const cmsUInt16Number wIn[], @@ -235,9 +335,12 @@ void TransformOnePixelWithGamutCheck(_cmsTRANSFORM* p, if (wOutOfGamut >= 1) { cmsUInt16Number i; + _cmsAlarmCodesChunkType* ContextAlarmCodes = (_cmsAlarmCodesChunkType*) _cmsContextGetClientChunk(p->ContextID, AlarmCodesContext); + + for (i=0; i < p ->Lut->OutputChannels; i++) { - for (i=0; i < p ->Lut->OutputChannels; i++) - wOut[i] = Alarm[i]; + wOut[i] = ContextAlarmCodes ->AlarmCodes[i]; + } } else p ->Lut ->Eval16Fn(wIn, wOut, p -> Lut->Data); @@ -364,34 +467,86 @@ typedef struct _cmsTransformCollection_st { } _cmsTransformCollection; // The linked list head -static _cmsTransformCollection* TransformCollection = NULL; +_cmsTransformPluginChunkType _cmsTransformPluginChunk = { NULL }; + + +// Duplicates the zone of memory used by the plug-in in the new context +static +void DupPluginTransformList(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src) +{ + _cmsTransformPluginChunkType newHead = { NULL }; + _cmsTransformCollection* entry; + _cmsTransformCollection* Anterior = NULL; + _cmsTransformPluginChunkType* head = (_cmsTransformPluginChunkType*) src->chunks[TransformPlugin]; + + // Walk the list copying all nodes + for (entry = head->TransformCollection; + entry != NULL; + entry = entry ->Next) { + + _cmsTransformCollection *newEntry = ( _cmsTransformCollection *) _cmsSubAllocDup(ctx ->MemPool, entry, sizeof(_cmsTransformCollection)); + + if (newEntry == NULL) + return; + + // We want to keep the linked list order, so this is a little bit tricky + newEntry -> Next = NULL; + if (Anterior) + Anterior -> Next = newEntry; + + Anterior = newEntry; + + if (newHead.TransformCollection == NULL) + newHead.TransformCollection = newEntry; + } + + ctx ->chunks[TransformPlugin] = _cmsSubAllocDup(ctx->MemPool, &newHead, sizeof(_cmsTransformPluginChunkType)); +} + +void _cmsAllocTransformPluginChunk(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src) +{ + if (src != NULL) { + + // Copy all linked list + DupPluginTransformList(ctx, src); + } + else { + static _cmsTransformPluginChunkType TransformPluginChunkType = { NULL }; + ctx ->chunks[TransformPlugin] = _cmsSubAllocDup(ctx ->MemPool, &TransformPluginChunkType, sizeof(_cmsTransformPluginChunkType)); + } +} + + // Register new ways to transform -cmsBool _cmsRegisterTransformPlugin(cmsContext id, cmsPluginBase* Data) +cmsBool _cmsRegisterTransformPlugin(cmsContext ContextID, cmsPluginBase* Data) { cmsPluginTransform* Plugin = (cmsPluginTransform*) Data; _cmsTransformCollection* fl; + _cmsTransformPluginChunkType* ctx = ( _cmsTransformPluginChunkType*) _cmsContextGetClientChunk(ContextID,TransformPlugin); - if (Data == NULL) { + if (Data == NULL) { // Free the chain. Memory is safely freed at exit - TransformCollection = NULL; + ctx->TransformCollection = NULL; return TRUE; } // Factory callback is required - if (Plugin ->Factory == NULL) return FALSE; + if (Plugin ->Factory == NULL) return FALSE; - fl = (_cmsTransformCollection*) _cmsPluginMalloc(id, sizeof(_cmsTransformCollection)); + fl = (_cmsTransformCollection*) _cmsPluginMalloc(ContextID, sizeof(_cmsTransformCollection)); if (fl == NULL) return FALSE; - // Copy the parameters + // Copy the parameters fl ->Factory = Plugin ->Factory; // Keep linked list - fl ->Next = TransformCollection; - TransformCollection = fl; + fl ->Next = ctx->TransformCollection; + ctx->TransformCollection = fl; // All is ok return TRUE; @@ -434,6 +589,7 @@ static _cmsTRANSFORM* AllocEmptyTransform(cmsContext ContextID, cmsPipeline* lut, cmsUInt32Number Intent, cmsUInt32Number* InputFormat, cmsUInt32Number* OutputFormat, cmsUInt32Number* dwFlags) { + _cmsTransformPluginChunkType* ctx = ( _cmsTransformPluginChunkType*) _cmsContextGetClientChunk(ContextID, TransformPlugin); _cmsTransformCollection* Plugin; // Allocate needed memory @@ -444,7 +600,7 @@ _cmsTRANSFORM* AllocEmptyTransform(cmsContext ContextID, cmsPipeline* lut, p ->Lut = lut; // Let's see if any plug-in want to do the transform by itself - for (Plugin = TransformCollection; + for (Plugin = ctx ->TransformCollection; Plugin != NULL; Plugin = Plugin ->Next) { @@ -464,10 +620,10 @@ _cmsTRANSFORM* AllocEmptyTransform(cmsContext ContextID, cmsPipeline* lut, // Fill the formatters just in case the optimized routine is interested. // No error is thrown if the formatter doesn't exist. It is up to the optimization // factory to decide what to do in those cases. - p ->FromInput = _cmsGetFormatter(*InputFormat, cmsFormatterInput, CMS_PACK_FLAGS_16BITS).Fmt16; - p ->ToOutput = _cmsGetFormatter(*OutputFormat, cmsFormatterOutput, CMS_PACK_FLAGS_16BITS).Fmt16; - p ->FromInputFloat = _cmsGetFormatter(*InputFormat, cmsFormatterInput, CMS_PACK_FLAGS_FLOAT).FmtFloat; - p ->ToOutputFloat = _cmsGetFormatter(*OutputFormat, cmsFormatterOutput, CMS_PACK_FLAGS_FLOAT).FmtFloat; + p ->FromInput = _cmsGetFormatter(ContextID, *InputFormat, cmsFormatterInput, CMS_PACK_FLAGS_16BITS).Fmt16; + p ->ToOutput = _cmsGetFormatter(ContextID, *OutputFormat, cmsFormatterOutput, CMS_PACK_FLAGS_16BITS).Fmt16; + p ->FromInputFloat = _cmsGetFormatter(ContextID, *InputFormat, cmsFormatterInput, CMS_PACK_FLAGS_FLOAT).FmtFloat; + p ->ToOutputFloat = _cmsGetFormatter(ContextID, *OutputFormat, cmsFormatterOutput, CMS_PACK_FLAGS_FLOAT).FmtFloat; return p; } @@ -475,14 +631,14 @@ _cmsTRANSFORM* AllocEmptyTransform(cmsContext ContextID, cmsPipeline* lut, // Not suitable for the transform plug-in, let's check the pipeline plug-in if (p ->Lut != NULL) - _cmsOptimizePipeline(&p->Lut, Intent, InputFormat, OutputFormat, dwFlags); + _cmsOptimizePipeline(ContextID, &p->Lut, Intent, InputFormat, OutputFormat, dwFlags); // Check whatever this is a true floating point transform if (_cmsFormatterIsFloat(*InputFormat) && _cmsFormatterIsFloat(*OutputFormat)) { // Get formatter function always return a valid union, but the contents of this union may be NULL. - p ->FromInputFloat = _cmsGetFormatter(*InputFormat, cmsFormatterInput, CMS_PACK_FLAGS_FLOAT).FmtFloat; - p ->ToOutputFloat = _cmsGetFormatter(*OutputFormat, cmsFormatterOutput, CMS_PACK_FLAGS_FLOAT).FmtFloat; + p ->FromInputFloat = _cmsGetFormatter(ContextID, *InputFormat, cmsFormatterInput, CMS_PACK_FLAGS_FLOAT).FmtFloat; + p ->ToOutputFloat = _cmsGetFormatter(ContextID, *OutputFormat, cmsFormatterOutput, CMS_PACK_FLAGS_FLOAT).FmtFloat; *dwFlags |= cmsFLAGS_CAN_CHANGE_FORMATTER; if (p ->FromInputFloat == NULL || p ->ToOutputFloat == NULL) { @@ -492,8 +648,15 @@ _cmsTRANSFORM* AllocEmptyTransform(cmsContext ContextID, cmsPipeline* lut, return NULL; } - // Float transforms don't use caché, always are non-NULL - p ->xform = FloatXFORM; + if (*dwFlags & cmsFLAGS_NULLTRANSFORM) { + + p ->xform = NullFloatXFORM; + } + else { + // Float transforms don't use caché, always are non-NULL + p ->xform = FloatXFORM; + } + } else { @@ -505,8 +668,8 @@ _cmsTRANSFORM* AllocEmptyTransform(cmsContext ContextID, cmsPipeline* lut, int BytesPerPixelInput; - p ->FromInput = _cmsGetFormatter(*InputFormat, cmsFormatterInput, CMS_PACK_FLAGS_16BITS).Fmt16; - p ->ToOutput = _cmsGetFormatter(*OutputFormat, cmsFormatterOutput, CMS_PACK_FLAGS_16BITS).Fmt16; + p ->FromInput = _cmsGetFormatter(ContextID, *InputFormat, cmsFormatterInput, CMS_PACK_FLAGS_16BITS).Fmt16; + p ->ToOutput = _cmsGetFormatter(ContextID, *OutputFormat, cmsFormatterOutput, CMS_PACK_FLAGS_16BITS).Fmt16; if (p ->FromInput == NULL || p ->ToOutput == NULL) { @@ -801,7 +964,7 @@ cmsHTRANSFORM CMSEXPORT cmsCreateMultiprofileTransformTHR(cmsContext ContextID, for (i=0; i < nProfiles; i++) { BPC[i] = dwFlags & cmsFLAGS_BLACKPOINTCOMPENSATION ? TRUE : FALSE; Intents[i] = Intent; - AdaptationStates[i] = GlobalAdaptationState; + AdaptationStates[i] = cmsSetAdaptationStateTHR(ContextID, -1); } @@ -881,7 +1044,7 @@ cmsHTRANSFORM CMSEXPORT cmsCreateProofingTransformTHR(cmsContext ContextID, Intents[0] = nIntent; Intents[1] = nIntent; Intents[2] = INTENT_RELATIVE_COLORIMETRIC; Intents[3] = ProofingIntent; BPC[0] = DoBPC; BPC[1] = DoBPC; BPC[2] = 0; BPC[3] = 0; - Adaptation[0] = Adaptation[1] = Adaptation[2] = Adaptation[3] = GlobalAdaptationState; + Adaptation[0] = Adaptation[1] = Adaptation[2] = Adaptation[3] = cmsSetAdaptationStateTHR(ContextID, -1); if (!(dwFlags & (cmsFLAGS_SOFTPROOFING|cmsFLAGS_GAMUTCHECK))) return cmsCreateTransformTHR(ContextID, InputProfile, InputFormat, OutputProfile, OutputFormat, nIntent, dwFlags); @@ -956,8 +1119,8 @@ cmsBool CMSEXPORT cmsChangeBuffersFormat(cmsHTRANSFORM hTransform, return FALSE; } - FromInput = _cmsGetFormatter(InputFormat, cmsFormatterInput, CMS_PACK_FLAGS_16BITS).Fmt16; - ToOutput = _cmsGetFormatter(OutputFormat, cmsFormatterOutput, CMS_PACK_FLAGS_16BITS).Fmt16; + FromInput = _cmsGetFormatter(xform->ContextID, InputFormat, cmsFormatterInput, CMS_PACK_FLAGS_16BITS).Fmt16; + ToOutput = _cmsGetFormatter(xform->ContextID, OutputFormat, cmsFormatterOutput, CMS_PACK_FLAGS_16BITS).Fmt16; if (FromInput == NULL || ToOutput == NULL) { diff --git a/src/lcms2.def b/src/lcms2.def index def9680..a1f69c4 100644 --- a/src/lcms2.def +++ b/src/lcms2.def @@ -1,325 +1,341 @@ -LIBRARY LCMS2.DLL - -EXPORTS - -_cms15Fixed16toDouble = _cms15Fixed16toDouble -_cms8Fixed8toDouble = _cms8Fixed8toDouble -cmsAdaptToIlluminant = cmsAdaptToIlluminant -_cmsAdjustEndianess16 = _cmsAdjustEndianess16 -_cmsAdjustEndianess32 = _cmsAdjustEndianess32 -_cmsAdjustEndianess64 = _cmsAdjustEndianess64 -cmsAllocNamedColorList = cmsAllocNamedColorList -cmsAllocProfileSequenceDescription = cmsAllocProfileSequenceDescription -cmsAppendNamedColor = cmsAppendNamedColor -cmsBFDdeltaE = cmsBFDdeltaE -cmsBuildGamma = cmsBuildGamma -cmsBuildParametricToneCurve = cmsBuildParametricToneCurve -cmsBuildSegmentedToneCurve = cmsBuildSegmentedToneCurve -cmsBuildTabulatedToneCurve16 = cmsBuildTabulatedToneCurve16 -cmsBuildTabulatedToneCurveFloat = cmsBuildTabulatedToneCurveFloat -_cmsCalloc = _cmsCalloc -cmsChannelsOf = cmsChannelsOf -cmsCIE2000DeltaE = cmsCIE2000DeltaE -cmsCIE94DeltaE = cmsCIE94DeltaE -cmsCIECAM02Done = cmsCIECAM02Done -cmsCIECAM02Forward = cmsCIECAM02Forward -cmsCIECAM02Init = cmsCIECAM02Init -cmsCIECAM02Reverse = cmsCIECAM02Reverse -cmsCloseIOhandler = cmsCloseIOhandler -cmsCloseProfile = cmsCloseProfile -cmsCMCdeltaE = cmsCMCdeltaE -cmsCreate_sRGBProfile = cmsCreate_sRGBProfile -cmsCreate_sRGBProfileTHR = cmsCreate_sRGBProfileTHR -cmsCreateBCHSWabstractProfile = cmsCreateBCHSWabstractProfile -cmsCreateBCHSWabstractProfileTHR = cmsCreateBCHSWabstractProfileTHR -cmsCreateExtendedTransform = cmsCreateExtendedTransform -cmsCreateGrayProfile = cmsCreateGrayProfile -cmsCreateGrayProfileTHR = cmsCreateGrayProfileTHR -cmsCreateInkLimitingDeviceLink = cmsCreateInkLimitingDeviceLink -cmsCreateInkLimitingDeviceLinkTHR = cmsCreateInkLimitingDeviceLinkTHR -cmsCreateLab2Profile = cmsCreateLab2Profile -cmsCreateLab2ProfileTHR = cmsCreateLab2ProfileTHR -cmsCreateLab4Profile = cmsCreateLab4Profile -cmsCreateLab4ProfileTHR = cmsCreateLab4ProfileTHR -cmsCreateLinearizationDeviceLink = cmsCreateLinearizationDeviceLink -cmsCreateLinearizationDeviceLinkTHR = cmsCreateLinearizationDeviceLinkTHR -cmsCreateMultiprofileTransform = cmsCreateMultiprofileTransform -cmsCreateMultiprofileTransformTHR = cmsCreateMultiprofileTransformTHR -cmsCreateNULLProfile = cmsCreateNULLProfile -cmsCreateNULLProfileTHR = cmsCreateNULLProfileTHR -cmsCreateProfilePlaceholder = cmsCreateProfilePlaceholder -cmsCreateProofingTransform = cmsCreateProofingTransform -cmsCreateProofingTransformTHR = cmsCreateProofingTransformTHR -cmsCreateRGBProfile = cmsCreateRGBProfile -cmsCreateRGBProfileTHR = cmsCreateRGBProfileTHR -cmsCreateTransform = cmsCreateTransform -cmsCreateTransformTHR = cmsCreateTransformTHR -cmsCreateXYZProfile = cmsCreateXYZProfile -cmsCreateXYZProfileTHR = cmsCreateXYZProfileTHR -cmsD50_xyY = cmsD50_xyY -cmsD50_XYZ = cmsD50_XYZ -_cmsDecodeDateTimeNumber = _cmsDecodeDateTimeNumber -_cmsDefaultICCintents = _cmsDefaultICCintents -cmsDeleteTransform = cmsDeleteTransform -cmsDeltaE = cmsDeltaE -cmsDetectBlackPoint = cmsDetectBlackPoint -cmsDetectDestinationBlackPoint = cmsDetectDestinationBlackPoint -cmsDetectTAC = cmsDetectTAC -cmsDesaturateLab = cmsDesaturateLab -cmsDoTransform = cmsDoTransform -cmsDoTransformStride = cmsDoTransformStride -_cmsDoubleTo15Fixed16 = _cmsDoubleTo15Fixed16 -_cmsDoubleTo8Fixed8 = _cmsDoubleTo8Fixed8 -_cmsDupMem = _cmsDupMem -cmsDupNamedColorList = cmsDupNamedColorList -cmsDupProfileSequenceDescription = cmsDupProfileSequenceDescription -cmsDupToneCurve = cmsDupToneCurve -_cmsEncodeDateTimeNumber = _cmsEncodeDateTimeNumber -cmsEstimateGamma = cmsEstimateGamma -cmsGetToneCurveEstimatedTableEntries = cmsGetToneCurveEstimatedTableEntries -cmsGetToneCurveEstimatedTable = cmsGetToneCurveEstimatedTable -cmsEvalToneCurve16 = cmsEvalToneCurve16 -cmsEvalToneCurveFloat = cmsEvalToneCurveFloat -cmsfilelength = cmsfilelength -cmsFloat2LabEncoded = cmsFloat2LabEncoded -cmsFloat2LabEncodedV2 = cmsFloat2LabEncodedV2 -cmsFloat2XYZEncoded = cmsFloat2XYZEncoded -cmsFormatterForColorspaceOfProfile = cmsFormatterForColorspaceOfProfile -cmsFormatterForPCSOfProfile = cmsFormatterForPCSOfProfile -_cmsFree = _cmsFree -cmsFreeNamedColorList = cmsFreeNamedColorList -cmsFreeProfileSequenceDescription = cmsFreeProfileSequenceDescription -cmsFreeToneCurve = cmsFreeToneCurve -cmsFreeToneCurveTriple = cmsFreeToneCurveTriple -cmsGBDAlloc = cmsGBDAlloc -cmsGBDFree = cmsGBDFree -cmsGDBAddPoint = cmsGDBAddPoint -cmsGDBCheckPoint = cmsGDBCheckPoint -cmsGDBCompute = cmsGDBCompute -cmsGetAlarmCodes = cmsGetAlarmCodes -cmsGetColorSpace = cmsGetColorSpace -cmsGetDeviceClass = cmsGetDeviceClass -cmsGetEncodedICCversion = cmsGetEncodedICCversion -cmsGetHeaderAttributes = cmsGetHeaderAttributes -cmsGetHeaderCreationDateTime = cmsGetHeaderCreationDateTime -cmsGetHeaderFlags = cmsGetHeaderFlags -cmsGetHeaderManufacturer = cmsGetHeaderManufacturer -cmsGetHeaderModel = cmsGetHeaderModel -cmsGetHeaderProfileID = cmsGetHeaderProfileID -cmsGetHeaderRenderingIntent = cmsGetHeaderRenderingIntent -cmsGetNamedColorList = cmsGetNamedColorList -cmsGetPCS = cmsGetPCS -cmsGetPostScriptColorResource = cmsGetPostScriptColorResource -cmsGetPostScriptCRD = cmsGetPostScriptCRD -cmsGetPostScriptCSA = cmsGetPostScriptCSA -cmsGetProfileInfo = cmsGetProfileInfo -cmsGetProfileInfoASCII = cmsGetProfileInfoASCII -cmsGetProfileContextID = cmsGetProfileContextID -cmsGetProfileVersion = cmsGetProfileVersion -cmsGetSupportedIntents = cmsGetSupportedIntents -cmsGetTagCount = cmsGetTagCount -cmsGetTagSignature = cmsGetTagSignature -cmsGetTransformContextID = cmsGetTransformContextID -_cmsICCcolorSpace = _cmsICCcolorSpace -_cmsIOPrintf = _cmsIOPrintf -cmsIsCLUT = cmsIsCLUT -cmsIsIntentSupported = cmsIsIntentSupported -cmsIsMatrixShaper = cmsIsMatrixShaper -cmsIsTag = cmsIsTag -cmsIsToneCurveDescending = cmsIsToneCurveDescending -cmsIsToneCurveLinear = cmsIsToneCurveLinear -cmsIsToneCurveMonotonic = cmsIsToneCurveMonotonic -cmsIsToneCurveMultisegment = cmsIsToneCurveMultisegment -cmsGetToneCurveParametricType = cmsGetToneCurveParametricType -cmsIT8Alloc = cmsIT8Alloc -cmsIT8DefineDblFormat = cmsIT8DefineDblFormat -cmsIT8EnumDataFormat = cmsIT8EnumDataFormat -cmsIT8EnumProperties = cmsIT8EnumProperties -cmsIT8EnumPropertyMulti = cmsIT8EnumPropertyMulti -cmsIT8Free = cmsIT8Free -cmsIT8GetData = cmsIT8GetData -cmsIT8GetDataDbl = cmsIT8GetDataDbl -cmsIT8FindDataFormat = cmsIT8FindDataFormat -cmsIT8GetDataRowCol = cmsIT8GetDataRowCol -cmsIT8GetDataRowColDbl = cmsIT8GetDataRowColDbl -cmsIT8GetPatchName = cmsIT8GetPatchName -cmsIT8GetPatchByName = cmsIT8GetPatchByName -cmsIT8GetProperty = cmsIT8GetProperty -cmsIT8GetPropertyDbl = cmsIT8GetPropertyDbl -cmsIT8GetPropertyMulti = cmsIT8GetPropertyMulti -cmsIT8GetSheetType = cmsIT8GetSheetType -cmsIT8LoadFromFile = cmsIT8LoadFromFile -cmsIT8LoadFromMem = cmsIT8LoadFromMem -cmsIT8SaveToFile = cmsIT8SaveToFile -cmsIT8SaveToMem = cmsIT8SaveToMem -cmsIT8SetComment = cmsIT8SetComment -cmsIT8SetData = cmsIT8SetData -cmsIT8SetDataDbl = cmsIT8SetDataDbl -cmsIT8SetDataFormat = cmsIT8SetDataFormat -cmsIT8SetDataRowCol = cmsIT8SetDataRowCol -cmsIT8SetDataRowColDbl = cmsIT8SetDataRowColDbl -cmsIT8SetPropertyDbl = cmsIT8SetPropertyDbl -cmsIT8SetPropertyHex = cmsIT8SetPropertyHex -cmsIT8SetPropertyStr = cmsIT8SetPropertyStr -cmsIT8SetPropertyMulti = cmsIT8SetPropertyMulti -cmsIT8SetPropertyUncooked = cmsIT8SetPropertyUncooked -cmsIT8SetSheetType = cmsIT8SetSheetType -cmsIT8SetTable = cmsIT8SetTable -cmsIT8SetTableByLabel = cmsIT8SetTableByLabel -cmsIT8SetIndexColumn = cmsIT8SetIndexColumn -cmsIT8TableCount = cmsIT8TableCount -cmsJoinToneCurve = cmsJoinToneCurve -cmsLab2LCh = cmsLab2LCh -cmsLab2XYZ = cmsLab2XYZ -cmsLabEncoded2Float = cmsLabEncoded2Float -cmsLabEncoded2FloatV2 = cmsLabEncoded2FloatV2 -cmsLCh2Lab = cmsLCh2Lab -_cmsLCMScolorSpace = _cmsLCMScolorSpace -cmsLinkTag = cmsLinkTag -cmsTagLinkedTo = cmsTagLinkedTo -cmsPipelineAlloc = cmsPipelineAlloc -cmsPipelineCat = cmsPipelineCat -cmsPipelineCheckAndRetreiveStages = cmsPipelineCheckAndRetreiveStages -cmsPipelineDup = cmsPipelineDup -cmsPipelineStageCount = cmsPipelineStageCount -cmsPipelineEval16 = cmsPipelineEval16 -cmsPipelineEvalFloat = cmsPipelineEvalFloat -cmsPipelineEvalReverseFloat = cmsPipelineEvalReverseFloat -cmsPipelineFree = cmsPipelineFree -cmsPipelineGetPtrToFirstStage = cmsPipelineGetPtrToFirstStage -cmsPipelineGetPtrToLastStage = cmsPipelineGetPtrToLastStage -cmsPipelineInputChannels = cmsPipelineInputChannels -cmsPipelineInsertStage = cmsPipelineInsertStage -cmsPipelineOutputChannels = cmsPipelineOutputChannels -cmsPipelineSetSaveAs8bitsFlag = cmsPipelineSetSaveAs8bitsFlag -_cmsPipelineSetOptimizationParameters = _cmsPipelineSetOptimizationParameters -cmsPipelineUnlinkStage = cmsPipelineUnlinkStage -_cmsMalloc = _cmsMalloc -_cmsMallocZero = _cmsMallocZero -_cmsMAT3eval = _cmsMAT3eval -_cmsMAT3identity = _cmsMAT3identity -_cmsMAT3inverse = _cmsMAT3inverse -_cmsMAT3isIdentity = _cmsMAT3isIdentity -_cmsMAT3per = _cmsMAT3per -_cmsMAT3solve = _cmsMAT3solve -cmsMD5computeID = cmsMD5computeID -cmsMLUalloc = cmsMLUalloc -cmsMLUdup = cmsMLUdup -cmsMLUfree = cmsMLUfree -cmsMLUgetASCII = cmsMLUgetASCII -cmsMLUgetTranslation = cmsMLUgetTranslation -cmsMLUgetWide = cmsMLUgetWide -cmsMLUsetASCII = cmsMLUsetASCII -cmsMLUsetWide = cmsMLUsetWide -cmsStageAllocCLut16bit = cmsStageAllocCLut16bit -cmsStageAllocCLut16bitGranular = cmsStageAllocCLut16bitGranular -cmsStageAllocCLutFloat = cmsStageAllocCLutFloat -cmsStageAllocCLutFloatGranular = cmsStageAllocCLutFloatGranular -cmsStageAllocToneCurves = cmsStageAllocToneCurves -cmsStageAllocIdentity = cmsStageAllocIdentity -cmsStageAllocMatrix = cmsStageAllocMatrix -_cmsStageAllocPlaceholder = _cmsStageAllocPlaceholder -cmsStageDup = cmsStageDup -cmsStageFree = cmsStageFree -cmsStageNext = cmsStageNext -cmsStageInputChannels = cmsStageInputChannels -cmsStageOutputChannels = cmsStageOutputChannels -cmsStageSampleCLut16bit = cmsStageSampleCLut16bit -cmsStageSampleCLutFloat = cmsStageSampleCLutFloat -cmsStageType = cmsStageType -cmsStageData = cmsStageData -cmsNamedColorCount = cmsNamedColorCount -cmsNamedColorIndex = cmsNamedColorIndex -cmsNamedColorInfo = cmsNamedColorInfo -cmsOpenIOhandlerFromFile = cmsOpenIOhandlerFromFile -cmsOpenIOhandlerFromMem = cmsOpenIOhandlerFromMem -cmsOpenIOhandlerFromNULL = cmsOpenIOhandlerFromNULL -cmsOpenIOhandlerFromStream = cmsOpenIOhandlerFromStream -cmsOpenProfileFromFile = cmsOpenProfileFromFile -cmsOpenProfileFromFileTHR = cmsOpenProfileFromFileTHR -cmsOpenProfileFromIOhandlerTHR = cmsOpenProfileFromIOhandlerTHR -cmsOpenProfileFromMem = cmsOpenProfileFromMem -cmsOpenProfileFromMemTHR = cmsOpenProfileFromMemTHR -cmsOpenProfileFromStream = cmsOpenProfileFromStream -cmsOpenProfileFromStreamTHR = cmsOpenProfileFromStreamTHR -cmsPlugin = cmsPlugin -_cmsRead15Fixed16Number = _cmsRead15Fixed16Number -_cmsReadAlignment = _cmsReadAlignment -_cmsReadFloat32Number = _cmsReadFloat32Number -cmsReadRawTag = cmsReadRawTag -cmsReadTag = cmsReadTag -_cmsReadTypeBase = _cmsReadTypeBase -_cmsReadUInt16Array = _cmsReadUInt16Array -_cmsReadUInt16Number = _cmsReadUInt16Number -_cmsReadUInt32Number = _cmsReadUInt32Number -_cmsReadUInt64Number = _cmsReadUInt64Number -_cmsReadUInt8Number = _cmsReadUInt8Number -_cmsReadXYZNumber = _cmsReadXYZNumber -_cmsRealloc = _cmsRealloc -cmsReverseToneCurve = cmsReverseToneCurve -cmsReverseToneCurveEx = cmsReverseToneCurveEx -cmsSaveProfileToFile = cmsSaveProfileToFile -cmsSaveProfileToIOhandler = cmsSaveProfileToIOhandler -cmsSaveProfileToMem = cmsSaveProfileToMem -cmsSaveProfileToStream = cmsSaveProfileToStream -cmsSetAdaptationState = cmsSetAdaptationState -cmsSetAlarmCodes = cmsSetAlarmCodes -cmsSetColorSpace = cmsSetColorSpace -cmsSetDeviceClass = cmsSetDeviceClass -cmsSetEncodedICCversion = cmsSetEncodedICCversion -cmsSetHeaderAttributes = cmsSetHeaderAttributes -cmsSetHeaderFlags = cmsSetHeaderFlags -cmsSetHeaderManufacturer = cmsSetHeaderManufacturer -cmsSetHeaderModel = cmsSetHeaderModel -cmsSetHeaderProfileID = cmsSetHeaderProfileID -cmsSetHeaderRenderingIntent = cmsSetHeaderRenderingIntent -cmsSetLogErrorHandler = cmsSetLogErrorHandler -cmsSetPCS = cmsSetPCS -cmsSetProfileVersion = cmsSetProfileVersion -cmsSignalError = cmsSignalError -cmsSmoothToneCurve = cmsSmoothToneCurve -cmsstrcasecmp = cmsstrcasecmp -cmsTempFromWhitePoint = cmsTempFromWhitePoint -cmsTransform2DeviceLink = cmsTransform2DeviceLink -cmsUnregisterPlugins = cmsUnregisterPlugins -_cmsVEC3cross = _cmsVEC3cross -_cmsVEC3distance = _cmsVEC3distance -_cmsVEC3dot = _cmsVEC3dot -_cmsVEC3init = _cmsVEC3init -_cmsVEC3length = _cmsVEC3length -_cmsVEC3minus = _cmsVEC3minus -cmsWhitePointFromTemp = cmsWhitePointFromTemp -_cmsWrite15Fixed16Number = _cmsWrite15Fixed16Number -_cmsWriteAlignment = _cmsWriteAlignment -_cmsWriteFloat32Number = _cmsWriteFloat32Number -cmsWriteRawTag = cmsWriteRawTag -cmsWriteTag = cmsWriteTag -_cmsWriteTypeBase = _cmsWriteTypeBase -_cmsWriteUInt16Array = _cmsWriteUInt16Array -_cmsWriteUInt16Number = _cmsWriteUInt16Number -_cmsWriteUInt32Number = _cmsWriteUInt32Number -_cmsWriteUInt64Number = _cmsWriteUInt64Number -_cmsWriteUInt8Number = _cmsWriteUInt8Number -_cmsWriteXYZNumber = _cmsWriteXYZNumber -cmsxyY2XYZ = cmsxyY2XYZ -cmsXYZ2Lab = cmsXYZ2Lab -cmsXYZ2xyY = cmsXYZ2xyY -cmsXYZEncoded2Float = cmsXYZEncoded2Float -cmsSliceSpace16 = cmsSliceSpace16 -cmsSliceSpaceFloat = cmsSliceSpaceFloat -cmsChangeBuffersFormat = cmsChangeBuffersFormat -cmsDictAlloc = cmsDictAlloc -cmsDictFree = cmsDictFree -cmsDictDup = cmsDictDup -cmsDictAddEntry = cmsDictAddEntry -cmsDictGetEntryList = cmsDictGetEntryList -cmsDictNextEntry = cmsDictNextEntry -_cmsGetTransformUserData = _cmsGetTransformUserData -_cmsSetTransformUserData = _cmsSetTransformUserData -_cmsGetTransformFormatters16 = _cmsGetTransformFormatters16 -_cmsGetTransformFormattersFloat = _cmsGetTransformFormattersFloat -cmsGetHeaderCreator = cmsGetHeaderCreator -cmsPluginTHR = cmsPluginTHR -cmsGetPipelineContextID = cmsGetPipelineContextID -cmsGetTransformInputFormat = cmsGetTransformInputFormat -cmsGetTransformOutputFormat = cmsGetTransformOutputFormat +LIBRARY LCMS2.DLL
+
+EXPORTS
+
+_cms15Fixed16toDouble = _cms15Fixed16toDouble
+_cms8Fixed8toDouble = _cms8Fixed8toDouble
+cmsAdaptToIlluminant = cmsAdaptToIlluminant
+_cmsAdjustEndianess16 = _cmsAdjustEndianess16
+_cmsAdjustEndianess32 = _cmsAdjustEndianess32
+_cmsAdjustEndianess64 = _cmsAdjustEndianess64
+cmsAllocNamedColorList = cmsAllocNamedColorList
+cmsAllocProfileSequenceDescription = cmsAllocProfileSequenceDescription
+cmsAppendNamedColor = cmsAppendNamedColor
+cmsBFDdeltaE = cmsBFDdeltaE
+cmsBuildGamma = cmsBuildGamma
+cmsBuildParametricToneCurve = cmsBuildParametricToneCurve
+cmsBuildSegmentedToneCurve = cmsBuildSegmentedToneCurve
+cmsBuildTabulatedToneCurve16 = cmsBuildTabulatedToneCurve16
+cmsBuildTabulatedToneCurveFloat = cmsBuildTabulatedToneCurveFloat
+_cmsCalloc = _cmsCalloc
+cmsChannelsOf = cmsChannelsOf
+cmsCIE2000DeltaE = cmsCIE2000DeltaE
+cmsCIE94DeltaE = cmsCIE94DeltaE
+cmsCIECAM02Done = cmsCIECAM02Done
+cmsCIECAM02Forward = cmsCIECAM02Forward
+cmsCIECAM02Init = cmsCIECAM02Init
+cmsCIECAM02Reverse = cmsCIECAM02Reverse
+cmsCloseIOhandler = cmsCloseIOhandler
+cmsCloseProfile = cmsCloseProfile
+cmsCMCdeltaE = cmsCMCdeltaE
+cmsCreate_sRGBProfile = cmsCreate_sRGBProfile
+cmsCreate_sRGBProfileTHR = cmsCreate_sRGBProfileTHR
+cmsCreateBCHSWabstractProfile = cmsCreateBCHSWabstractProfile
+cmsCreateBCHSWabstractProfileTHR = cmsCreateBCHSWabstractProfileTHR
+cmsCreateExtendedTransform = cmsCreateExtendedTransform
+cmsCreateGrayProfile = cmsCreateGrayProfile
+cmsCreateGrayProfileTHR = cmsCreateGrayProfileTHR
+cmsCreateInkLimitingDeviceLink = cmsCreateInkLimitingDeviceLink
+cmsCreateInkLimitingDeviceLinkTHR = cmsCreateInkLimitingDeviceLinkTHR
+cmsCreateLab2Profile = cmsCreateLab2Profile
+cmsCreateLab2ProfileTHR = cmsCreateLab2ProfileTHR
+cmsCreateLab4Profile = cmsCreateLab4Profile
+cmsCreateLab4ProfileTHR = cmsCreateLab4ProfileTHR
+cmsCreateLinearizationDeviceLink = cmsCreateLinearizationDeviceLink
+cmsCreateLinearizationDeviceLinkTHR = cmsCreateLinearizationDeviceLinkTHR
+cmsCreateMultiprofileTransform = cmsCreateMultiprofileTransform
+cmsCreateMultiprofileTransformTHR = cmsCreateMultiprofileTransformTHR
+cmsCreateNULLProfile = cmsCreateNULLProfile
+cmsCreateNULLProfileTHR = cmsCreateNULLProfileTHR
+cmsCreateProfilePlaceholder = cmsCreateProfilePlaceholder
+cmsCreateProofingTransform = cmsCreateProofingTransform
+cmsCreateProofingTransformTHR = cmsCreateProofingTransformTHR
+cmsCreateRGBProfile = cmsCreateRGBProfile
+cmsCreateRGBProfileTHR = cmsCreateRGBProfileTHR
+cmsCreateTransform = cmsCreateTransform
+cmsCreateTransformTHR = cmsCreateTransformTHR
+cmsCreateXYZProfile = cmsCreateXYZProfile
+cmsCreateXYZProfileTHR = cmsCreateXYZProfileTHR
+cmsD50_xyY = cmsD50_xyY
+cmsD50_XYZ = cmsD50_XYZ
+_cmsDecodeDateTimeNumber = _cmsDecodeDateTimeNumber
+_cmsDefaultICCintents = _cmsDefaultICCintents
+cmsDeleteTransform = cmsDeleteTransform
+cmsDeltaE = cmsDeltaE
+cmsDetectBlackPoint = cmsDetectBlackPoint
+cmsDetectDestinationBlackPoint = cmsDetectDestinationBlackPoint
+cmsDetectTAC = cmsDetectTAC
+cmsDesaturateLab = cmsDesaturateLab
+cmsDoTransform = cmsDoTransform
+cmsDoTransformStride = cmsDoTransformStride
+_cmsDoubleTo15Fixed16 = _cmsDoubleTo15Fixed16
+_cmsDoubleTo8Fixed8 = _cmsDoubleTo8Fixed8
+_cmsDupMem = _cmsDupMem
+cmsDupNamedColorList = cmsDupNamedColorList
+cmsDupProfileSequenceDescription = cmsDupProfileSequenceDescription
+cmsDupToneCurve = cmsDupToneCurve
+_cmsEncodeDateTimeNumber = _cmsEncodeDateTimeNumber
+cmsEstimateGamma = cmsEstimateGamma
+cmsGetToneCurveEstimatedTableEntries = cmsGetToneCurveEstimatedTableEntries
+cmsGetToneCurveEstimatedTable = cmsGetToneCurveEstimatedTable
+cmsEvalToneCurve16 = cmsEvalToneCurve16
+cmsEvalToneCurveFloat = cmsEvalToneCurveFloat
+cmsfilelength = cmsfilelength
+cmsFloat2LabEncoded = cmsFloat2LabEncoded
+cmsFloat2LabEncodedV2 = cmsFloat2LabEncodedV2
+cmsFloat2XYZEncoded = cmsFloat2XYZEncoded
+cmsFormatterForColorspaceOfProfile = cmsFormatterForColorspaceOfProfile
+cmsFormatterForPCSOfProfile = cmsFormatterForPCSOfProfile
+_cmsFree = _cmsFree
+cmsFreeNamedColorList = cmsFreeNamedColorList
+cmsFreeProfileSequenceDescription = cmsFreeProfileSequenceDescription
+cmsFreeToneCurve = cmsFreeToneCurve
+cmsFreeToneCurveTriple = cmsFreeToneCurveTriple
+cmsGBDAlloc = cmsGBDAlloc
+cmsGBDFree = cmsGBDFree
+cmsGDBAddPoint = cmsGDBAddPoint
+cmsGDBCheckPoint = cmsGDBCheckPoint
+cmsGDBCompute = cmsGDBCompute
+cmsGetAlarmCodes = cmsGetAlarmCodes
+cmsGetColorSpace = cmsGetColorSpace
+cmsGetDeviceClass = cmsGetDeviceClass
+cmsGetEncodedICCversion = cmsGetEncodedICCversion
+cmsGetHeaderAttributes = cmsGetHeaderAttributes
+cmsGetHeaderCreationDateTime = cmsGetHeaderCreationDateTime
+cmsGetHeaderFlags = cmsGetHeaderFlags
+cmsGetHeaderManufacturer = cmsGetHeaderManufacturer
+cmsGetHeaderModel = cmsGetHeaderModel
+cmsGetHeaderProfileID = cmsGetHeaderProfileID
+cmsGetHeaderRenderingIntent = cmsGetHeaderRenderingIntent
+cmsGetNamedColorList = cmsGetNamedColorList
+cmsGetPCS = cmsGetPCS
+cmsGetPostScriptColorResource = cmsGetPostScriptColorResource
+cmsGetPostScriptCRD = cmsGetPostScriptCRD
+cmsGetPostScriptCSA = cmsGetPostScriptCSA
+cmsGetProfileInfo = cmsGetProfileInfo
+cmsGetProfileInfoASCII = cmsGetProfileInfoASCII
+cmsGetProfileContextID = cmsGetProfileContextID
+cmsGetProfileVersion = cmsGetProfileVersion
+cmsGetSupportedIntents = cmsGetSupportedIntents
+cmsGetTagCount = cmsGetTagCount
+cmsGetTagSignature = cmsGetTagSignature
+cmsGetTransformContextID = cmsGetTransformContextID
+_cmsICCcolorSpace = _cmsICCcolorSpace
+_cmsIOPrintf = _cmsIOPrintf
+cmsIsCLUT = cmsIsCLUT
+cmsIsIntentSupported = cmsIsIntentSupported
+cmsIsMatrixShaper = cmsIsMatrixShaper
+cmsIsTag = cmsIsTag
+cmsIsToneCurveDescending = cmsIsToneCurveDescending
+cmsIsToneCurveLinear = cmsIsToneCurveLinear
+cmsIsToneCurveMonotonic = cmsIsToneCurveMonotonic
+cmsIsToneCurveMultisegment = cmsIsToneCurveMultisegment
+cmsGetToneCurveParametricType = cmsGetToneCurveParametricType
+cmsIT8Alloc = cmsIT8Alloc
+cmsIT8DefineDblFormat = cmsIT8DefineDblFormat
+cmsIT8EnumDataFormat = cmsIT8EnumDataFormat
+cmsIT8EnumProperties = cmsIT8EnumProperties
+cmsIT8EnumPropertyMulti = cmsIT8EnumPropertyMulti
+cmsIT8Free = cmsIT8Free
+cmsIT8GetData = cmsIT8GetData
+cmsIT8GetDataDbl = cmsIT8GetDataDbl
+cmsIT8FindDataFormat = cmsIT8FindDataFormat
+cmsIT8GetDataRowCol = cmsIT8GetDataRowCol
+cmsIT8GetDataRowColDbl = cmsIT8GetDataRowColDbl
+cmsIT8GetPatchName = cmsIT8GetPatchName
+cmsIT8GetPatchByName = cmsIT8GetPatchByName
+cmsIT8GetProperty = cmsIT8GetProperty
+cmsIT8GetPropertyDbl = cmsIT8GetPropertyDbl
+cmsIT8GetPropertyMulti = cmsIT8GetPropertyMulti
+cmsIT8GetSheetType = cmsIT8GetSheetType
+cmsIT8LoadFromFile = cmsIT8LoadFromFile
+cmsIT8LoadFromMem = cmsIT8LoadFromMem
+cmsIT8SaveToFile = cmsIT8SaveToFile
+cmsIT8SaveToMem = cmsIT8SaveToMem
+cmsIT8SetComment = cmsIT8SetComment
+cmsIT8SetData = cmsIT8SetData
+cmsIT8SetDataDbl = cmsIT8SetDataDbl
+cmsIT8SetDataFormat = cmsIT8SetDataFormat
+cmsIT8SetDataRowCol = cmsIT8SetDataRowCol
+cmsIT8SetDataRowColDbl = cmsIT8SetDataRowColDbl
+cmsIT8SetPropertyDbl = cmsIT8SetPropertyDbl
+cmsIT8SetPropertyHex = cmsIT8SetPropertyHex
+cmsIT8SetPropertyStr = cmsIT8SetPropertyStr
+cmsIT8SetPropertyMulti = cmsIT8SetPropertyMulti
+cmsIT8SetPropertyUncooked = cmsIT8SetPropertyUncooked
+cmsIT8SetSheetType = cmsIT8SetSheetType
+cmsIT8SetTable = cmsIT8SetTable
+cmsIT8SetTableByLabel = cmsIT8SetTableByLabel
+cmsIT8SetIndexColumn = cmsIT8SetIndexColumn
+cmsIT8TableCount = cmsIT8TableCount
+cmsJoinToneCurve = cmsJoinToneCurve
+cmsLab2LCh = cmsLab2LCh
+cmsLab2XYZ = cmsLab2XYZ
+cmsLabEncoded2Float = cmsLabEncoded2Float
+cmsLabEncoded2FloatV2 = cmsLabEncoded2FloatV2
+cmsLCh2Lab = cmsLCh2Lab
+_cmsLCMScolorSpace = _cmsLCMScolorSpace
+cmsLinkTag = cmsLinkTag
+cmsTagLinkedTo = cmsTagLinkedTo
+cmsPipelineAlloc = cmsPipelineAlloc
+cmsPipelineCat = cmsPipelineCat
+cmsPipelineCheckAndRetreiveStages = cmsPipelineCheckAndRetreiveStages
+cmsPipelineDup = cmsPipelineDup
+cmsPipelineStageCount = cmsPipelineStageCount
+cmsPipelineEval16 = cmsPipelineEval16
+cmsPipelineEvalFloat = cmsPipelineEvalFloat
+cmsPipelineEvalReverseFloat = cmsPipelineEvalReverseFloat
+cmsPipelineFree = cmsPipelineFree
+cmsPipelineGetPtrToFirstStage = cmsPipelineGetPtrToFirstStage
+cmsPipelineGetPtrToLastStage = cmsPipelineGetPtrToLastStage
+cmsPipelineInputChannels = cmsPipelineInputChannels
+cmsPipelineInsertStage = cmsPipelineInsertStage
+cmsPipelineOutputChannels = cmsPipelineOutputChannels
+cmsPipelineSetSaveAs8bitsFlag = cmsPipelineSetSaveAs8bitsFlag
+_cmsPipelineSetOptimizationParameters = _cmsPipelineSetOptimizationParameters
+cmsPipelineUnlinkStage = cmsPipelineUnlinkStage
+_cmsMalloc = _cmsMalloc
+_cmsMallocZero = _cmsMallocZero
+_cmsMAT3eval = _cmsMAT3eval
+_cmsMAT3identity = _cmsMAT3identity
+_cmsMAT3inverse = _cmsMAT3inverse
+_cmsMAT3isIdentity = _cmsMAT3isIdentity
+_cmsMAT3per = _cmsMAT3per
+_cmsMAT3solve = _cmsMAT3solve
+cmsMD5computeID = cmsMD5computeID
+cmsMLUalloc = cmsMLUalloc
+cmsMLUdup = cmsMLUdup
+cmsMLUfree = cmsMLUfree
+cmsMLUgetASCII = cmsMLUgetASCII
+cmsMLUgetTranslation = cmsMLUgetTranslation
+cmsMLUgetWide = cmsMLUgetWide
+cmsMLUsetASCII = cmsMLUsetASCII
+cmsMLUsetWide = cmsMLUsetWide
+cmsStageAllocCLut16bit = cmsStageAllocCLut16bit
+cmsStageAllocCLut16bitGranular = cmsStageAllocCLut16bitGranular
+cmsStageAllocCLutFloat = cmsStageAllocCLutFloat
+cmsStageAllocCLutFloatGranular = cmsStageAllocCLutFloatGranular
+cmsStageAllocToneCurves = cmsStageAllocToneCurves
+cmsStageAllocIdentity = cmsStageAllocIdentity
+cmsStageAllocMatrix = cmsStageAllocMatrix
+_cmsStageAllocPlaceholder = _cmsStageAllocPlaceholder
+cmsStageDup = cmsStageDup
+cmsStageFree = cmsStageFree
+cmsStageNext = cmsStageNext
+cmsStageInputChannels = cmsStageInputChannels
+cmsStageOutputChannels = cmsStageOutputChannels
+cmsStageSampleCLut16bit = cmsStageSampleCLut16bit
+cmsStageSampleCLutFloat = cmsStageSampleCLutFloat
+cmsStageType = cmsStageType
+cmsStageData = cmsStageData
+cmsNamedColorCount = cmsNamedColorCount
+cmsNamedColorIndex = cmsNamedColorIndex
+cmsNamedColorInfo = cmsNamedColorInfo
+cmsOpenIOhandlerFromFile = cmsOpenIOhandlerFromFile
+cmsOpenIOhandlerFromMem = cmsOpenIOhandlerFromMem
+cmsOpenIOhandlerFromNULL = cmsOpenIOhandlerFromNULL
+cmsOpenIOhandlerFromStream = cmsOpenIOhandlerFromStream
+cmsOpenProfileFromFile = cmsOpenProfileFromFile
+cmsOpenProfileFromFileTHR = cmsOpenProfileFromFileTHR
+cmsOpenProfileFromIOhandlerTHR = cmsOpenProfileFromIOhandlerTHR
+cmsOpenProfileFromMem = cmsOpenProfileFromMem
+cmsOpenProfileFromMemTHR = cmsOpenProfileFromMemTHR
+cmsOpenProfileFromStream = cmsOpenProfileFromStream
+cmsOpenProfileFromStreamTHR = cmsOpenProfileFromStreamTHR
+cmsPlugin = cmsPlugin
+_cmsRead15Fixed16Number = _cmsRead15Fixed16Number
+_cmsReadAlignment = _cmsReadAlignment
+_cmsReadFloat32Number = _cmsReadFloat32Number
+cmsReadRawTag = cmsReadRawTag
+cmsReadTag = cmsReadTag
+_cmsReadTypeBase = _cmsReadTypeBase
+_cmsReadUInt16Array = _cmsReadUInt16Array
+_cmsReadUInt16Number = _cmsReadUInt16Number
+_cmsReadUInt32Number = _cmsReadUInt32Number
+_cmsReadUInt64Number = _cmsReadUInt64Number
+_cmsReadUInt8Number = _cmsReadUInt8Number
+_cmsReadXYZNumber = _cmsReadXYZNumber
+_cmsRealloc = _cmsRealloc
+cmsReverseToneCurve = cmsReverseToneCurve
+cmsReverseToneCurveEx = cmsReverseToneCurveEx
+cmsSaveProfileToFile = cmsSaveProfileToFile
+cmsSaveProfileToIOhandler = cmsSaveProfileToIOhandler
+cmsSaveProfileToMem = cmsSaveProfileToMem
+cmsSaveProfileToStream = cmsSaveProfileToStream
+cmsSetAdaptationState = cmsSetAdaptationState
+cmsSetAlarmCodes = cmsSetAlarmCodes
+cmsSetColorSpace = cmsSetColorSpace
+cmsSetDeviceClass = cmsSetDeviceClass
+cmsSetEncodedICCversion = cmsSetEncodedICCversion
+cmsSetHeaderAttributes = cmsSetHeaderAttributes
+cmsSetHeaderFlags = cmsSetHeaderFlags
+cmsSetHeaderManufacturer = cmsSetHeaderManufacturer
+cmsSetHeaderModel = cmsSetHeaderModel
+cmsSetHeaderProfileID = cmsSetHeaderProfileID
+cmsSetHeaderRenderingIntent = cmsSetHeaderRenderingIntent
+cmsSetLogErrorHandler = cmsSetLogErrorHandler
+cmsSetPCS = cmsSetPCS
+cmsSetProfileVersion = cmsSetProfileVersion
+cmsSignalError = cmsSignalError
+cmsSmoothToneCurve = cmsSmoothToneCurve
+cmsstrcasecmp = cmsstrcasecmp
+cmsTempFromWhitePoint = cmsTempFromWhitePoint
+cmsTransform2DeviceLink = cmsTransform2DeviceLink
+cmsUnregisterPlugins = cmsUnregisterPlugins
+_cmsVEC3cross = _cmsVEC3cross
+_cmsVEC3distance = _cmsVEC3distance
+_cmsVEC3dot = _cmsVEC3dot
+_cmsVEC3init = _cmsVEC3init
+_cmsVEC3length = _cmsVEC3length
+_cmsVEC3minus = _cmsVEC3minus
+cmsWhitePointFromTemp = cmsWhitePointFromTemp
+_cmsWrite15Fixed16Number = _cmsWrite15Fixed16Number
+_cmsWriteAlignment = _cmsWriteAlignment
+_cmsWriteFloat32Number = _cmsWriteFloat32Number
+cmsWriteRawTag = cmsWriteRawTag
+cmsWriteTag = cmsWriteTag
+_cmsWriteTypeBase = _cmsWriteTypeBase
+_cmsWriteUInt16Array = _cmsWriteUInt16Array
+_cmsWriteUInt16Number = _cmsWriteUInt16Number
+_cmsWriteUInt32Number = _cmsWriteUInt32Number
+_cmsWriteUInt64Number = _cmsWriteUInt64Number
+_cmsWriteUInt8Number = _cmsWriteUInt8Number
+_cmsWriteXYZNumber = _cmsWriteXYZNumber
+cmsxyY2XYZ = cmsxyY2XYZ
+cmsXYZ2Lab = cmsXYZ2Lab
+cmsXYZ2xyY = cmsXYZ2xyY
+cmsXYZEncoded2Float = cmsXYZEncoded2Float
+cmsSliceSpace16 = cmsSliceSpace16
+cmsSliceSpaceFloat = cmsSliceSpaceFloat
+cmsChangeBuffersFormat = cmsChangeBuffersFormat
+cmsDictAlloc = cmsDictAlloc
+cmsDictFree = cmsDictFree
+cmsDictDup = cmsDictDup
+cmsDictAddEntry = cmsDictAddEntry
+cmsDictGetEntryList = cmsDictGetEntryList
+cmsDictNextEntry = cmsDictNextEntry
+_cmsGetTransformUserData = _cmsGetTransformUserData
+_cmsSetTransformUserData = _cmsSetTransformUserData
+_cmsGetTransformFormatters16 = _cmsGetTransformFormatters16
+_cmsGetTransformFormattersFloat = _cmsGetTransformFormattersFloat
+cmsGetHeaderCreator = cmsGetHeaderCreator
+cmsPluginTHR = cmsPluginTHR
+cmsGetPipelineContextID = cmsGetPipelineContextID
+cmsGetTransformInputFormat = cmsGetTransformInputFormat
+cmsGetTransformOutputFormat = cmsGetTransformOutputFormat
+cmsCreateContext = cmsCreateContext
+cmsDupContext = cmsDupContext
+cmsDeleteContext = cmsDeleteContext
+cmsGetContextUserData = cmsGetContextUserData
+cmsUnregisterPluginsTHR = cmsUnregisterPluginsTHR
+cmsSetAlarmCodesTHR = cmsSetAlarmCodesTHR
+cmsGetAlarmCodesTHR = cmsGetAlarmCodesTHR
+cmsSetAdaptationStateTHR = cmsSetAdaptationStateTHR
+cmsSetLogErrorHandlerTHR = cmsSetLogErrorHandlerTHR
+cmsGetSupportedIntentsTHR = cmsGetSupportedIntentsTHR
+cmsMLUtranslationsCount = cmsMLUtranslationsCount
+cmsMLUtranslationsCodes = cmsMLUtranslationsCodes
+_cmsCreateMutex = _cmsCreateMutex
+_cmsDestroyMutex = _cmsDestroyMutex
+_cmsLockMutex = _cmsLockMutex
+_cmsUnlockMutex = _cmsUnlockMutex
\ No newline at end of file diff --git a/src/lcms2_internal.h b/src/lcms2_internal.h index d6300df..61ceb00 100644 --- a/src/lcms2_internal.h +++ b/src/lcms2_internal.h @@ -164,16 +164,16 @@ cmsINLINE cmsUInt16Number _cmsQuickSaturateWord(cmsFloat64Number d) return _cmsQuickFloorWord(d); } -// Plug-In registering --------------------------------------------------------------- +// Plug-In registration --------------------------------------------------------------- // Specialized function for plug-in memory management. No pairing free() since whole pool is freed at once. void* _cmsPluginMalloc(cmsContext ContextID, cmsUInt32Number size); // Memory management -cmsBool _cmsRegisterMemHandlerPlugin(cmsPluginBase* Plugin); +cmsBool _cmsRegisterMemHandlerPlugin(cmsContext ContextID, cmsPluginBase* Plugin); // Interpolation -cmsBool _cmsRegisterInterpPlugin(cmsPluginBase* Plugin); +cmsBool _cmsRegisterInterpPlugin(cmsContext ContextID, cmsPluginBase* Plugin); // Parametric curves cmsBool _cmsRegisterParametricCurvesPlugin(cmsContext ContextID, cmsPluginBase* Plugin); @@ -199,6 +199,9 @@ cmsBool _cmsRegisterOptimizationPlugin(cmsContext ContextID, cmsPluginBase* Plu // Transform cmsBool _cmsRegisterTransformPlugin(cmsContext ContextID, cmsPluginBase* Plugin); +// Mutex +cmsBool _cmsRegisterMutexPlugin(cmsContext ContextID, cmsPluginBase* Plugin); + // --------------------------------------------------------------------------------------------------------- // Suballocators. Those are blocks of memory that is freed at the end on whole block. @@ -224,9 +227,266 @@ typedef struct { _cmsSubAllocator* _cmsCreateSubAlloc(cmsContext ContextID, cmsUInt32Number Initial); void _cmsSubAllocDestroy(_cmsSubAllocator* s); void* _cmsSubAlloc(_cmsSubAllocator* s, cmsUInt32Number size); +void* _cmsSubAllocDup(_cmsSubAllocator* s, const void *ptr, cmsUInt32Number size); // ---------------------------------------------------------------------------------- +// The context clients. +typedef enum { + + UserPtr, // User-defined pointer + Logger, + AlarmCodesContext, + AdaptationStateContext, + MemPlugin, + InterpPlugin, + CurvesPlugin, + FormattersPlugin, + TagTypePlugin, + TagPlugin, + IntentPlugin, + MPEPlugin, + OptimizationPlugin, + TransformPlugin, + MutexPlugin, + + // Last in list + MemoryClientMax + +} _cmsMemoryClient; + +// Magic number for identifying a valid context +#define cmsContextMagicNumber 0x63747832 // 'ctx2' + +// Container for memory management plug-in. +typedef struct { + + _cmsMallocFnPtrType MallocPtr; + _cmsMalloZerocFnPtrType MallocZeroPtr; + _cmsFreeFnPtrType FreePtr; + _cmsReallocFnPtrType ReallocPtr; + _cmsCallocFnPtrType CallocPtr; + _cmsDupFnPtrType DupPtr; + +} _cmsMemPluginChunkType; + +// Copy memory management function pointers from plug-in to chunk, taking care of missing routines +void _cmsInstallAllocFunctions(cmsPluginMemHandler* Plugin, _cmsMemPluginChunkType* ptr); + +// Internal structure for context +struct _cmsContext_struct { + + cmsUInt32Number Magic; // Magic number that identifies a valid context id in the new style + _cmsSubAllocator* MemPool; // The memory pool that stores context data + + void* chunks[MemoryClientMax]; // array of pointers to client chunks. Memory itself is hold in the suballocator. + // If NULL, then it reverts to global Context0 + + _cmsMemPluginChunkType DefaultMemoryManager; // The allocators used for creating the context itself. Cannot be overriden +}; + +// Returns a pointer to a valid context structure, including the global one if id is zero. +// Verifies the magic number. +struct _cmsContext_struct* _cmsGetContext(cmsContext ContextID); + +// Returns the block assigned to the specific zone. +void* _cmsContextGetClientChunk(cmsContext id, _cmsMemoryClient mc); + + +// Chunks of context memory by plug-in client ------------------------------------------------------- + +// Those structures encapsulates all variables needed by the several context clients (mostly plug-ins) + +// Container for error logger -- not a plug-in +typedef struct { + + cmsLogErrorHandlerFunction LogErrorHandler; // Set to NULL for Context0 fallback + +} _cmsLogErrorChunkType; + +// The global Context0 storage for error logger +extern _cmsLogErrorChunkType _cmsLogErrorChunk; + +// Allocate and init error logger container. +void _cmsAllocLogErrorChunk(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src); + +// Container for alarm codes -- not a plug-in +typedef struct { + + cmsUInt16Number AlarmCodes[cmsMAXCHANNELS]; + +} _cmsAlarmCodesChunkType; + +// The global Context0 storage for alarm codes +extern _cmsAlarmCodesChunkType _cmsAlarmCodesChunk; + +// Allocate and init alarm codes container. +void _cmsAllocAlarmCodesChunk(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src); + +// Container for adaptation state -- not a plug-in +typedef struct { + + cmsFloat64Number AdaptationState; + +} _cmsAdaptationStateChunkType; + +// The global Context0 storage for adaptation state +extern _cmsAdaptationStateChunkType _cmsAdaptationStateChunk; + +// Allocate and init adaptation state container. +void _cmsAllocAdaptationStateChunk(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src); + + +// The global Context0 storage for memory management +extern _cmsMemPluginChunkType _cmsMemPluginChunk; + +// Allocate and init memory management container. +void _cmsAllocMemPluginChunk(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src); + +// Container for interpolation plug-in +typedef struct { + + cmsInterpFnFactory Interpolators; + +} _cmsInterpPluginChunkType; + +// The global Context0 storage for interpolation plug-in +extern _cmsInterpPluginChunkType _cmsInterpPluginChunk; + +// Allocate and init interpolation container. +void _cmsAllocInterpPluginChunk(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src); + +// Container for parametric curves plug-in +typedef struct { + + struct _cmsParametricCurvesCollection_st* ParametricCurves; + +} _cmsCurvesPluginChunkType; + +// The global Context0 storage for tone curves plug-in +extern _cmsCurvesPluginChunkType _cmsCurvesPluginChunk; + +// Allocate and init parametric curves container. +void _cmsAllocCurvesPluginChunk(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src); + +// Container for formatters plug-in +typedef struct { + + struct _cms_formatters_factory_list* FactoryList; + +} _cmsFormattersPluginChunkType; + +// The global Context0 storage for formatters plug-in +extern _cmsFormattersPluginChunkType _cmsFormattersPluginChunk; + +// Allocate and init formatters container. +void _cmsAllocFormattersPluginChunk(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src); + +// This chunk type is shared by TagType plug-in and MPE Plug-in +typedef struct { + + struct _cmsTagTypeLinkedList_st* TagTypes; + +} _cmsTagTypePluginChunkType; + + +// The global Context0 storage for tag types plug-in +extern _cmsTagTypePluginChunkType _cmsTagTypePluginChunk; + + +// The global Context0 storage for mult process elements plug-in +extern _cmsTagTypePluginChunkType _cmsMPETypePluginChunk; + +// Allocate and init Tag types container. +void _cmsAllocTagTypePluginChunk(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src); +// Allocate and init MPE container. +void _cmsAllocMPETypePluginChunk(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src); +// Container for tag plug-in +typedef struct { + + struct _cmsTagLinkedList_st* Tag; + +} _cmsTagPluginChunkType; + + +// The global Context0 storage for tag plug-in +extern _cmsTagPluginChunkType _cmsTagPluginChunk; + +// Allocate and init Tag container. +void _cmsAllocTagPluginChunk(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src); + +// Container for intents plug-in +typedef struct { + + struct _cms_intents_list* Intents; + +} _cmsIntentsPluginChunkType; + + +// The global Context0 storage for intents plug-in +extern _cmsIntentsPluginChunkType _cmsIntentsPluginChunk; + +// Allocate and init intents container. +void _cmsAllocIntentsPluginChunk(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src); + +// Container for optimization plug-in +typedef struct { + + struct _cmsOptimizationCollection_st* OptimizationCollection; + +} _cmsOptimizationPluginChunkType; + + +// The global Context0 storage for optimizers plug-in +extern _cmsOptimizationPluginChunkType _cmsOptimizationPluginChunk; + +// Allocate and init optimizers container. +void _cmsAllocOptimizationPluginChunk(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src); + +// Container for transform plug-in +typedef struct { + + struct _cmsTransformCollection_st* TransformCollection; + +} _cmsTransformPluginChunkType; + +// The global Context0 storage for full-transform replacement plug-in +extern _cmsTransformPluginChunkType _cmsTransformPluginChunk; + +// Allocate and init transform container. +void _cmsAllocTransformPluginChunk(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src); + +// Container for mutex plug-in +typedef struct { + + _cmsCreateMutexFnPtrType CreateMutexPtr; + _cmsDestroyMutexFnPtrType DestroyMutexPtr; + _cmsLockMutexFnPtrType LockMutexPtr; + _cmsUnlockMutexFnPtrType UnlockMutexPtr; + +} _cmsMutexPluginChunkType; + +// The global Context0 storage for mutex plug-in +extern _cmsMutexPluginChunkType _cmsMutexPluginChunk; + +// Allocate and init mutex container. +void _cmsAllocMutexPluginChunk(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src); + +// ---------------------------------------------------------------------------------- // MLU internal representation typedef struct { @@ -318,10 +578,14 @@ typedef struct _cms_iccprofile_struct { cmsBool TagSaveAsRaw[MAX_TABLE_TAG]; // True to write uncooked void * TagPtrs[MAX_TABLE_TAG]; cmsTagTypeHandler* TagTypeHandlers[MAX_TABLE_TAG]; // Same structure may be serialized on different types - // depending on profile version, so we keep track of the // type handler for each tag in the list. + // depending on profile version, so we keep track of the + // type handler for each tag in the list. // Special cmsBool IsWrite; + // Keep a mutex for cmsReadTag -- Note that this only works if the user includes a mutex plugin + void * UsrMutex; + } _cmsICCPROFILE; // IO helpers for profiles @@ -330,9 +594,9 @@ cmsBool _cmsWriteHeader(_cmsICCPROFILE* Icc, cmsUInt32Number UsedSp int _cmsSearchTag(_cmsICCPROFILE* Icc, cmsTagSignature sig, cmsBool lFollowLinks); // Tag types -cmsTagTypeHandler* _cmsGetTagTypeHandler(cmsTagTypeSignature sig); +cmsTagTypeHandler* _cmsGetTagTypeHandler(cmsContext ContextID, cmsTagTypeSignature sig); cmsTagTypeSignature _cmsGetTagTrueType(cmsHPROFILE hProfile, cmsTagSignature sig); -cmsTagDescriptor* _cmsGetTagDescriptor(cmsTagSignature sig); +cmsTagDescriptor* _cmsGetTagDescriptor(cmsContext ContextID, cmsTagSignature sig); // Error logging --------------------------------------------------------------------------------------------------------- @@ -343,7 +607,7 @@ void _cmsTagSignature2String(char String[5], cmsTagSignature sig cmsInterpParams* _cmsComputeInterpParams(cmsContext ContextID, int nSamples, int InputChan, int OutputChan, const void* Table, cmsUInt32Number dwFlags); cmsInterpParams* _cmsComputeInterpParamsEx(cmsContext ContextID, const cmsUInt32Number nSamples[], int InputChan, int OutputChan, const void* Table, cmsUInt32Number dwFlags); void _cmsFreeInterpParams(cmsInterpParams* p); -cmsBool _cmsSetInterpolationRoutine(cmsInterpParams* p); +cmsBool _cmsSetInterpolationRoutine(cmsContext ContextID, cmsInterpParams* p); // Curves ---------------------------------------------------------------------------------------------------------------- @@ -474,7 +738,8 @@ cmsBool _cmsEndPointsBySpace(cmsColorSpaceSignature Space, cmsUInt16Number **Black, cmsUInt32Number *nOutputs); -cmsBool _cmsOptimizePipeline(cmsPipeline** Lut, +cmsBool _cmsOptimizePipeline(cmsContext ContextID, + cmsPipeline** Lut, int Intent, cmsUInt32Number* InputFormat, cmsUInt32Number* OutputFormat, @@ -499,7 +764,8 @@ cmsPipeline* _cmsCreateGamutCheckPipeline(cmsContext ContextID, cmsBool _cmsFormatterIsFloat(cmsUInt32Number Type); cmsBool _cmsFormatterIs8bit(cmsUInt32Number Type); -cmsFormatter _cmsGetFormatter(cmsUInt32Number Type, // Specific type, i.e. TYPE_RGB_8 +cmsFormatter _cmsGetFormatter(cmsContext ContextID, + cmsUInt32Number Type, // Specific type, i.e. TYPE_RGB_8 cmsFormatterDirection Dir, cmsUInt32Number dwFlags); 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 diff --git a/utils/delphi/lcms2dll.pas b/utils/delphi/lcms2dll.pas index 1c2d674..9262cd3 100644 --- a/utils/delphi/lcms2dll.pas +++ b/utils/delphi/lcms2dll.pas @@ -3,7 +3,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"), @@ -25,16 +25,29 @@ // //--------------------------------------------------------------------------------- // -// Version 2.1 +// Version 2.6 // UNIT lcms2dll; +{$IFDEF FPC} + {$MODE Delphi} +{$ENDIF} + INTERFACE -USES Windows; +{$IFNDEF MSWINDOWS} + USES LCLType, types; + Type PWChar = PWideChar; +{$ELSE} + USES Windows; +{$ENDIF} + + CONST + + LCMS2_SO = {$IFDEF DARWIN} 'liblcms2.2.dylib'; {$ELSE} 'lcms2.dll'; {$ENDIF} - TYPE + TYPE Uint8 = Byte; Int8 = Shortint; @@ -43,7 +56,7 @@ USES Windows; UInt32 = LongWord; Int32 = Longint; - TYPE + TYPE cmsUInt8Number = Uint8; cmsInt8Number = Int8; cmsUInt16Number = UInt16; @@ -58,17 +71,17 @@ USES Windows; cmsFloat64Number = Double; LPcmsUInt8Number = ^cmsUInt8Number; - LPcmsInt8Number = ^cmsInt8Number; - LPcmsUInt16Number = ^cmsUInt16Number; - LPcmsInt16Number = ^cmsInt16Number; - - LPcmsUInt32Number = ^cmsUInt32Number; - LPcmsInt32Number = ^cmsInt32Number; - LPcmsInt64Number = ^cmsInt64Number; - LPcmsUInt64Number = ^cmsUInt64Number; - - LPcmsFloat32Number = ^cmsFloat32Number; - LPcmsFloat64Number = ^cmsFloat64Number; + LPcmsInt8Number = ^cmsInt8Number; + LPcmsUInt16Number = ^cmsUInt16Number; + LPcmsInt16Number = ^cmsInt16Number; + + LPcmsUInt32Number = ^cmsUInt32Number; + LPcmsInt32Number = ^cmsInt32Number; + LPcmsInt64Number = ^cmsInt64Number; + LPcmsUInt64Number = ^cmsUInt64Number; + + LPcmsFloat32Number = ^cmsFloat32Number; + LPcmsFloat64Number = ^cmsFloat64Number; // Derivative types @@ -315,7 +328,7 @@ cmsPlatformSignature = ( cmsSigUnices = $2A6E6978 // '*nix' // From argyll -- Not official ); -CONST +CONST // Reference gamut cmsSigPerceptualReferenceMediumGamut = $70726d67; //'prmg' @@ -357,7 +370,7 @@ cmsCurveSegSignature = ( cmsSigSegmentedCurve = $63757266 // 'curf' ); -CONST +CONST // Used in ResponseCurveType cmsSigStatusA = $53746141; //'StaA' @@ -388,12 +401,12 @@ cmsICCData = PACKED RECORD // ICC date time cmsDateTimeNumber = PACKED RECORD - year: cmsUInt16Number; - month: cmsUInt16Number; - day: cmsUInt16Number; - hours: cmsUInt16Number; - minutes: cmsUInt16Number; - seconds: cmsUInt16Number; + year: cmsUInt16Number; + month: cmsUInt16Number; + day: cmsUInt16Number; + hours: cmsUInt16Number; + minutes: cmsUInt16Number; + seconds: cmsUInt16Number; END; // ICC XYZ @@ -443,8 +456,8 @@ END; // ICC base tag cmsTagBase = PACKED RECORD - sig: cmsTagTypeSignature; - reserved: array[0..3] of cmsInt8Number; + sig: cmsTagTypeSignature; + reserved: array[0..3] of cmsInt8Number; END; // A tag entry in directory @@ -457,7 +470,7 @@ END; cmsContext = Pointer; // Context identifier for multithreaded environments cmsHANDLE = Pointer; // Generic handle -cmsHPROFILE = Pointer; // Opaque typedefs to hide internals +cmsHPROFILE = Pointer; // Opaque typedefs to hide internals cmsHTRANSFORM = Pointer; @@ -494,17 +507,17 @@ CONST FUNCTION BYTES_SH(b: cmsUInt32Number):cmsUInt32Number; - FUNCTION T_FLOAT(a: cmsUInt32Number): cmsUInt32Number; - FUNCTION T_OPTIMIZED(o: cmsUInt32Number): cmsUInt32Number; - FUNCTION T_COLORSPACE(s: cmsUInt32Number): cmsUInt32Number; - FUNCTION T_SWAPFIRST(s: cmsUInt32Number): cmsUInt32Number; - FUNCTION T_FLAVOR(s: cmsUInt32Number): cmsUInt32Number; - FUNCTION T_PLANAR(p: cmsUInt32Number): cmsUInt32Number; - FUNCTION T_ENDIAN16(e: cmsUInt32Number): cmsUInt32Number; - FUNCTION T_DOSWAP(e: cmsUInt32Number): cmsUInt32Number; - FUNCTION T_EXTRA(e: cmsUInt32Number): cmsUInt32Number; - FUNCTION T_CHANNELS(c: cmsUInt32Number): cmsUInt32Number; - FUNCTION T_BYTES(b: cmsUInt32Number): cmsUInt32Number; + FUNCTION T_FLOAT(a: cmsUInt32Number): cmsUInt32Number; + FUNCTION T_OPTIMIZED(o: cmsUInt32Number): cmsUInt32Number; + FUNCTION T_COLORSPACE(s: cmsUInt32Number): cmsUInt32Number; + FUNCTION T_SWAPFIRST(s: cmsUInt32Number): cmsUInt32Number; + FUNCTION T_FLAVOR(s: cmsUInt32Number): cmsUInt32Number; + FUNCTION T_PLANAR(p: cmsUInt32Number): cmsUInt32Number; + FUNCTION T_ENDIAN16(e: cmsUInt32Number): cmsUInt32Number; + FUNCTION T_DOSWAP(e: cmsUInt32Number): cmsUInt32Number; + FUNCTION T_EXTRA(e: cmsUInt32Number): cmsUInt32Number; + FUNCTION T_CHANNELS(c: cmsUInt32Number): cmsUInt32Number; + FUNCTION T_BYTES(b: cmsUInt32Number): cmsUInt32Number; CONST @@ -525,7 +538,7 @@ CONST PT_HSV = 12; PT_HLS = 13; PT_Yxy = 14; - + PT_MCH1 = 15; PT_MCH2 = 16; PT_MCH3 = 17; @@ -544,7 +557,7 @@ CONST PT_LabV2 = 30; // Identical to PT_Lab, but using the V2 old encoding - + // Format descriptors TYPE_GRAY_8 = $030009; TYPE_GRAY_8_REV = $032009; @@ -568,6 +581,9 @@ CONST TYPE_BGR_16_SE = $040c1a; TYPE_RGBA_8 = $040099; TYPE_RGBA_8_PLANAR = $041099; + TYPE_ARGB_8_PLANAR = $045099; + TYPE_ABGR_8_PLANAR = $041499; + TYPE_BGRA_8_PLANAR = $045499; TYPE_RGBA_16 = $04009a; TYPE_RGBA_16_PLANAR = $04109a; TYPE_RGBA_16_SE = $04089a; @@ -686,6 +702,7 @@ CONST TYPE_XYZA_FLT = $49009c; TYPE_LabA_FLT = $4a009c; TYPE_RGBA_FLT = $44009c; + TYPE_XYZ_DBL = $490018; TYPE_Lab_DBL = $4a0018; TYPE_GRAY_DBL = $430008; @@ -695,7 +712,16 @@ CONST TYPE_ALabV2_8 = $1e0499; TYPE_LabV2_16 = $1e001a; - + TYPE_GRAY_HALF_FLT = $43000a; + TYPE_RGB_HALF_FLT = $44001a; + TYPE_RGBA_HALF_FLT = $44009a; + TYPE_CMYK_HALF_FLT = $460022; + + TYPE_ARGB_HALF_FLT = $44409a; + TYPE_BGR_HALF_FLT = $44041a; + TYPE_BGRA_HALF_FLT = $44449a; + TYPE_ABGR_HALF_FLT = $44041a; + TYPE @@ -751,7 +777,7 @@ CONST cmsILLUMINANT_TYPE_A = $0000006; cmsILLUMINANT_TYPE_E = $0000007; cmsILLUMINANT_TYPE_F8 = $0000008; - + TYPE cmsICCMeasurementConditions = PACKED RECORD @@ -771,6 +797,13 @@ TYPE END; +// Context -------------------------------------------------------------------------------------------------------------- + +FUNCTION cmsCreateContext(Plugin : Pointer; UserData : Pointer) : cmsContext; StdCall; +PROCEDURE cmsDeleteContext(ContextID: cmsContext); StdCall; +FUNCTION cmsDupContext(ContextID: cmsContext; NewUserData: Pointer): cmsContext; StdCall; +FUNCTION cmsGetContextUserData(ContextID: cmsContext): Pointer; StdCall; + // Plug-In registering --------------------------------------------------------------------------------------------------- FUNCTION cmsPlugin(Plugin: Pointer): cmsBool; StdCall; @@ -888,7 +921,7 @@ FUNCTION cmsAdaptToIlluminant(Result: LPcmsCIEXYZ; SourceWhitePt: LPcmsCIEXYZ; LPcmsViewingConditions = ^cmsViewingConditions; - + FUNCTION cmsCIECAM02Init(pVC : LPcmsViewingConditions ) : Pointer; StdCall; PROCEDURE cmsCIECAM02Done(hModel : Pointer); StdCall; PROCEDURE cmsCIECAM02Forward(hModel: Pointer; pIn: LPcmsCIEXYZ; pOut: LPcmsJCh ); StdCall; @@ -899,7 +932,7 @@ PROCEDURE cmsCIECAM02Reverse(hModel: Pointer; pIn: LPcmsJCh; pOut: LPcmsCIEX // This describes a curve segment. For a table of supported types, see the manual. User can increase the number of // available types by using a proper plug-in. Parametric segments allow 10 parameters at most -TYPE +TYPE cmsCurveSegment = PACKED RECORD x0, x1: cmsFloat32Number; // Domain; for x0 < x <= x1 PType: cmsInt32Number; // Parametric type, Type == 0 means sampled segment. Negative values are reserved @@ -947,6 +980,8 @@ FUNCTION cmsIsToneCurveMonotonic(t: LPcmsToneCurve):cmsBool; StdCall; FUNCTION cmsIsToneCurveDescending(t: LPcmsToneCurve):cmsBool; StdCall; FUNCTION cmsGetToneCurveParametricType(t: LPcmsToneCurve):cmsInt32Number; StdCall; FUNCTION cmsEstimateGamma(t: LPcmsToneCurve; Precision:cmsFloat64Number):cmsFloat64Number; StdCall; +FUNCTION cmsGetToneCurveEstimatedTableEntries(t: LPcmsToneCurve): cmsUInt32Number; StdCall; +FUNCTION cmsGetToneCurveEstimatedTable(t: LPcmsToneCurve): LPcmsUInt16Number; StdCall; // Implements pipelines of multi-processing elements ------------------------------------------------------------- @@ -955,11 +990,12 @@ TYPE LPcmsPipeline = Pointer; LPcmsStage = Pointer; LPLPcmsStage = ^LPcmsStage; - + // Those are hi-level pipelines FUNCTION cmsPipelineAlloc(ContextID: cmsContext; InputChannels, OutputChannels: cmsUInt32Number): LPcmsPipeline; StdCall; PROCEDURE cmsPipelineFree(lut: LPcmsPipeline); StdCall; -FUNCTION cmsPipelineDup(Orig: LPcmsPipeline): LPcmsPipeline; StdCall; +FUNCTION cmsPipelineDup(Orig: LPcmsPipeline): LPcmsPipeline; StdCall; +FUNCTION cmsGetPipelineContextID(lut: LPcmsPipeline) : cmsContext; StdCall; FUNCTION cmsPipelineInputChannels(lut: LPcmsPipeline): cmsUInt32Number; StdCall; FUNCTION cmsPipelineOutputChannels(lut: LPcmsPipeline): cmsUInt32Number; StdCall; @@ -1011,7 +1047,7 @@ FUNCTION cmsStageType(mpe: LPcmsStage): cmsStageSignature; StdCall; FUNCTION cmsStageData(mpe: LPcmsStage): Pointer; StdCall; // Sampling - + Type cmsSAMPLER16 = FUNCTION (Inp, Outp: LPcmsUInt16NumberArray; Cargo: Pointer): cmsInt32Number; CDecl; cmsSAMPLERFLOAT = FUNCTION (Inp, Outp: LPcmsFloat32NumberArray; Cargo: Pointer): cmsInt32Number; CDecl; @@ -1046,9 +1082,9 @@ cmsNoLanguage = #0#0#0; cmsNoCountry = #0#0#0; -FUNCTION cmsMLUalloc(ContextID: cmsContext; nItems: cmsUInt32Number): LPcmsMLU; StdCall; +FUNCTION cmsMLUalloc(ContextID: cmsContext; nItems: cmsUInt32Number): LPcmsMLU; StdCall; PROCEDURE cmsMLUfree(mlu: LPcmsMLU); StdCall; -FUNCTION cmsMLUdup(mlu: LPcmsMLU): LPcmsMLU; StdCall; +FUNCTION cmsMLUdup(mlu: LPcmsMLU): LPcmsMLU; StdCall; FUNCTION cmsMLUsetASCII(mlu: LPcmsMLU; LanguageCode, CountryCode, ASCIIString: PAnsiChar): cmsBool; StdCall; FUNCTION cmsMLUsetWide(mlu: LPcmsMLU; LanguageCode, CountryCode: PAnsiChar; WideString: PWChar): cmsBool; StdCall; @@ -1056,7 +1092,7 @@ FUNCTION cmsMLUsetWide(mlu: LPcmsMLU; LanguageCode, CountryCode: PAnsiChar; Wid FUNCTION cmsMLUgetASCII(mlu: LPcmsMLU; LanguageCode, CountryCode: PAnsiChar; Buffer: PAnsiChar; BufferSize: cmsUInt32Number): cmsUInt32Number; StdCall; FUNCTION cmsMLUgetWide(mlu: LPcmsMLU; LanguageCode, CountryCode: PAnsiChar; Buffer: PWChar; BufferSize: cmsUInt32Number): cmsUInt32Number; StdCall; - + FUNCTION cmsMLUgetTranslation(mlu: LPcmsMLU; LanguageCode, CountryCode, ObtainedLanguage, ObtainedCountry: PAnsiChar): cmsBool; StdCall; // Undercolorremoval & black generation ------------------------------------------------------------------------------------- @@ -1085,13 +1121,13 @@ Const cmsSPOT_LINE = 5; cmsSPOT_SQUARE = 6; cmsSPOT_CROSS = 7; - + Type cmsScreeningChannel = PACKED RECORD - Frequency, + Frequency, ScreenAngle: cmsFloat64Number; SpotShape: cmsUInt32Number; @@ -1137,12 +1173,12 @@ Type cmsPSEQDESC = PACKED RECORD deviceMfg, deviceModel: cmsSignature; - + attributes: cmsUInt64Number; technology: cmsTechnologySignature; ProfileID: cmsProfileID; - Manufacturer, - Model, + Manufacturer, + Model, Description : LPcmsMLU; END; @@ -1167,11 +1203,11 @@ TYPE LPcmsDICTentry = ^cmsDICTentry; -cmsDICTentry = PACKED RECORD +cmsDICTentry = PACKED RECORD Next: LPcmsDICTentry; - DisplayName, DisplayValue: LPcmsMLU; + DisplayName, DisplayValue: LPcmsMLU; Name, Value : PWChar; END; @@ -1390,7 +1426,7 @@ INTENT_PRESERVE_K_ONLY_SATURATION = 12; INTENT_PRESERVE_K_PLANE_PERCEPTUAL = 13; INTENT_PRESERVE_K_PLANE_RELATIVE_COLORIMETRIC = 14; INTENT_PRESERVE_K_PLANE_SATURATION = 15; - + Type LPPAnsiChar = ^PAnsiChar; @@ -1507,6 +1543,8 @@ FUNCTION cmsCreateExtendedTransform(ContextID: cmsContext; PROCEDURE cmsDeleteTransform(hTransform: cmsHTRANSFORM); StdCall; PROCEDURE cmsDoTransform(Transform: cmsHTRANSFORM; InputBuffer, OutputBuffer: Pointer; size: cmsUInt32Number); StdCall; +PROCEDURE cmsDoTransformStride(Transform: cmsHTRANSFORM; InputBuffer, OutputBuffer: Pointer; size: cmsUInt32Number; stride: cmsUInt32Number); StdCall; + PROCEDURE cmsSetAlarmCodes( NewAlarm: LPcmsUInt16NumberArray); StdCall; PROCEDURE cmsGetAlarmCodes(NewAlarm: LPcmsUInt16NumberArray); StdCall; @@ -1624,7 +1662,7 @@ FUNCTION cmsDetectTAC(hProfile: cmsHPROFILE): cmsFloat64Number; StdCall; // Poor man's gamut mapping FUNCTION cmsDesaturateLab(Lab: LPcmsCIELab; amax, amin, bmax, bmin: cmsFloat64Number): cmsBool; StdCall; - + IMPLEMENTATION @@ -1643,275 +1681,282 @@ IMPLEMENTATION FUNCTION BYTES_SH(b: cmsUInt32Number):cmsUInt32Number; begin BYTES_SH := (b) end; - FUNCTION T_FLOAT(a: cmsUInt32Number): cmsUInt32Number; begin T_FLOAT := (((a) shr 22) and 1) end; - FUNCTION T_OPTIMIZED(o: cmsUInt32Number): cmsUInt32Number; begin T_OPTIMIZED := (((o) shr 21) and 1) end; - FUNCTION T_COLORSPACE(s: cmsUInt32Number): cmsUInt32Number; begin T_COLORSPACE := (((s) shr 16) and 31) end; - FUNCTION T_SWAPFIRST(s: cmsUInt32Number): cmsUInt32Number; begin T_SWAPFIRST := (((s) shr 14) and 1) end; + FUNCTION T_FLOAT(a: cmsUInt32Number): cmsUInt32Number; begin T_FLOAT := (((a) shr 22) and 1) end; + FUNCTION T_OPTIMIZED(o: cmsUInt32Number): cmsUInt32Number; begin T_OPTIMIZED := (((o) shr 21) and 1) end; + FUNCTION T_COLORSPACE(s: cmsUInt32Number): cmsUInt32Number; begin T_COLORSPACE := (((s) shr 16) and 31) end; + FUNCTION T_SWAPFIRST(s: cmsUInt32Number): cmsUInt32Number; begin T_SWAPFIRST := (((s) shr 14) and 1) end; FUNCTION T_FLAVOR(s: cmsUInt32Number): cmsUInt32Number; begin T_FLAVOR := (((s) shr 13) and 1) end; - FUNCTION T_PLANAR(p: cmsUInt32Number): cmsUInt32Number; begin T_PLANAR := (((p) shr 12) and 1) end; - FUNCTION T_ENDIAN16(e: cmsUInt32Number): cmsUInt32Number; begin T_ENDIAN16 := (((e) shr 11) and 1) end; - FUNCTION T_DOSWAP(e: cmsUInt32Number): cmsUInt32Number; begin T_DOSWAP := (((e) shr 10) and 1) end; - FUNCTION T_EXTRA(e: cmsUInt32Number): cmsUInt32Number; begin T_EXTRA := (((e) shr 7) and 7) end; - FUNCTION T_CHANNELS(c: cmsUInt32Number): cmsUInt32Number; begin T_CHANNELS := (((c) shr 3) and 15) end; + FUNCTION T_PLANAR(p: cmsUInt32Number): cmsUInt32Number; begin T_PLANAR := (((p) shr 12) and 1) end; + FUNCTION T_ENDIAN16(e: cmsUInt32Number): cmsUInt32Number; begin T_ENDIAN16 := (((e) shr 11) and 1) end; + FUNCTION T_DOSWAP(e: cmsUInt32Number): cmsUInt32Number; begin T_DOSWAP := (((e) shr 10) and 1) end; + FUNCTION T_EXTRA(e: cmsUInt32Number): cmsUInt32Number; begin T_EXTRA := (((e) shr 7) and 7) end; + FUNCTION T_CHANNELS(c: cmsUInt32Number): cmsUInt32Number; begin T_CHANNELS := (((c) shr 3) and 15) end; FUNCTION T_BYTES(b: cmsUInt32Number): cmsUInt32Number; begin T_BYTES := ((b) and 7) end; -// - - -FUNCTION cmsPlugin(Plugin: Pointer): cmsBool; StdCall; external 'lcms2.dll'; -PROCEDURE cmsUnregisterPlugins; StdCall; external 'lcms2.dll'; -PROCEDURE cmsSetLogErrorHandler(Fn: cmsLogErrorHandlerFunction); StdCall; external 'lcms2.dll'; -FUNCTION cmsD50_XYZ: LPcmsCIEXYZ; StdCall; external 'lcms2.dll'; -FUNCTION cmsD50_xyY: LPcmsCIExyY; StdCall; external 'lcms2.dll'; -PROCEDURE cmsXYZ2xyY(Dest: LPcmsCIExyY; Source: LPcmsCIEXYZ); StdCall; external 'lcms2.dll'; -PROCEDURE cmsxyY2XYZ(Dest: LPcmsCIEXYZ; Source: LPcmsCIExyY); StdCall; external 'lcms2.dll'; -PROCEDURE cmsLab2XYZ(WhitePoint: LPcmsCIEXYZ; xyz: LPcmsCIEXYZ; Lab: LPcmsCIELab); StdCall; external 'lcms2.dll'; -PROCEDURE cmsXYZ2Lab(WhitePoint: LPcmsCIEXYZ; Lab: LPcmsCIELab; xyz: LPcmsCIEXYZ); StdCall; external 'lcms2.dll'; -PROCEDURE cmsLab2LCh(LCh: LPcmsCIELCh; Lab: LPcmsCIELab); StdCall; external 'lcms2.dll'; -PROCEDURE cmsLCh2Lab(Lab: LPcmsCIELab; LCh: LPcmsCIELCh); StdCall; external 'lcms2.dll'; -PROCEDURE cmsLabEncoded2Float(Lab: LPcmsCIELab; wLab: Pointer); StdCall; external 'lcms2.dll'; -PROCEDURE cmsLabEncoded2FloatV2(Lab: LPcmsCIELab; wLab: Pointer); StdCall; external 'lcms2.dll'; -PROCEDURE cmsFloat2LabEncoded(wLab: Pointer; Lab: LPcmsCIELab); StdCall; external 'lcms2.dll'; -PROCEDURE cmsFloat2LabEncodedV2(wLab: Pointer; Lab: LPcmsCIELab); StdCall; external 'lcms2.dll'; -PROCEDURE cmsXYZEncoded2Float(fxyz : LPcmsCIEXYZ; XYZ: Pointer); StdCall; external 'lcms2.dll'; -PROCEDURE cmsFloat2XYZEncoded(XYZ: Pointer; fXYZ: LPcmsCIEXYZ); StdCall; external 'lcms2.dll'; -FUNCTION cmsDeltaE(Lab1, Lab2: LPcmsCIELab): Double; StdCall; external 'lcms2.dll'; -FUNCTION cmsCIE94DeltaE(Lab1, Lab2: LPcmsCIELab): Double; StdCall; external 'lcms2.dll'; -FUNCTION cmsBFDdeltaE(Lab1, Lab2: LPcmsCIELab): Double; StdCall; external 'lcms2.dll'; -FUNCTION cmsCMCdeltaE(Lab1, Lab2: LPcmsCIELab): Double; StdCall; external 'lcms2.dll'; -FUNCTION cmsCIE2000DeltaE(Lab1, Lab2: LPcmsCIELab; Kl, Kc, Kh: Double): Double; StdCall; external 'lcms2.dll'; -FUNCTION cmsWhitePointFromTemp(var WhitePoint: cmsCIExyY; TempK: cmsFloat64Number) : cmsBool; StdCall; external 'lcms2.dll'; -FUNCTION cmsTempFromWhitePoint(var TeampK: cmsFloat64Number; var WhitePoint: cmsCIExyY) : cmsBool; StdCall; external 'lcms2.dll'; +// + +FUNCTION cmsCreateContext(Plugin : Pointer; UserData : Pointer) : cmsContext; StdCall; external LCMS2_SO; +PROCEDURE cmsDeleteContext(ContextID: cmsContext); StdCall; external LCMS2_SO; +FUNCTION cmsDupContext(ContextID: cmsContext; NewUserData: Pointer): cmsContext; StdCall; external LCMS2_SO; +FUNCTION cmsGetContextUserData(ContextID: cmsContext): Pointer; StdCall; external LCMS2_SO; + +FUNCTION cmsPlugin(Plugin: Pointer): cmsBool; StdCall; external LCMS2_SO; +PROCEDURE cmsUnregisterPlugins; StdCall; external LCMS2_SO; +PROCEDURE cmsSetLogErrorHandler(Fn: cmsLogErrorHandlerFunction); StdCall; external LCMS2_SO; +FUNCTION cmsD50_XYZ: LPcmsCIEXYZ; StdCall; external LCMS2_SO; +FUNCTION cmsD50_xyY: LPcmsCIExyY; StdCall; external LCMS2_SO; +PROCEDURE cmsXYZ2xyY(Dest: LPcmsCIExyY; Source: LPcmsCIEXYZ); StdCall; external LCMS2_SO; +PROCEDURE cmsxyY2XYZ(Dest: LPcmsCIEXYZ; Source: LPcmsCIExyY); StdCall; external LCMS2_SO; +PROCEDURE cmsLab2XYZ(WhitePoint: LPcmsCIEXYZ; xyz: LPcmsCIEXYZ; Lab: LPcmsCIELab); StdCall; external LCMS2_SO; +PROCEDURE cmsXYZ2Lab(WhitePoint: LPcmsCIEXYZ; Lab: LPcmsCIELab; xyz: LPcmsCIEXYZ); StdCall; external LCMS2_SO; +PROCEDURE cmsLab2LCh(LCh: LPcmsCIELCh; Lab: LPcmsCIELab); StdCall; external LCMS2_SO; +PROCEDURE cmsLCh2Lab(Lab: LPcmsCIELab; LCh: LPcmsCIELCh); StdCall; external LCMS2_SO; +PROCEDURE cmsLabEncoded2Float(Lab: LPcmsCIELab; wLab: Pointer); StdCall; external LCMS2_SO; +PROCEDURE cmsLabEncoded2FloatV2(Lab: LPcmsCIELab; wLab: Pointer); StdCall; external LCMS2_SO; +PROCEDURE cmsFloat2LabEncoded(wLab: Pointer; Lab: LPcmsCIELab); StdCall; external LCMS2_SO; +PROCEDURE cmsFloat2LabEncodedV2(wLab: Pointer; Lab: LPcmsCIELab); StdCall; external LCMS2_SO; +PROCEDURE cmsXYZEncoded2Float(fxyz : LPcmsCIEXYZ; XYZ: Pointer); StdCall; external LCMS2_SO; +PROCEDURE cmsFloat2XYZEncoded(XYZ: Pointer; fXYZ: LPcmsCIEXYZ); StdCall; external LCMS2_SO; +FUNCTION cmsDeltaE(Lab1, Lab2: LPcmsCIELab): Double; StdCall; external LCMS2_SO; +FUNCTION cmsCIE94DeltaE(Lab1, Lab2: LPcmsCIELab): Double; StdCall; external LCMS2_SO; +FUNCTION cmsBFDdeltaE(Lab1, Lab2: LPcmsCIELab): Double; StdCall; external LCMS2_SO; +FUNCTION cmsCMCdeltaE(Lab1, Lab2: LPcmsCIELab): Double; StdCall; external LCMS2_SO; +FUNCTION cmsCIE2000DeltaE(Lab1, Lab2: LPcmsCIELab; Kl, Kc, Kh: Double): Double; StdCall; external LCMS2_SO; +FUNCTION cmsWhitePointFromTemp(var WhitePoint: cmsCIExyY; TempK: cmsFloat64Number) : cmsBool; StdCall; external LCMS2_SO; +FUNCTION cmsTempFromWhitePoint(var TeampK: cmsFloat64Number; var WhitePoint: cmsCIExyY) : cmsBool; StdCall; external LCMS2_SO; FUNCTION cmsAdaptToIlluminant(Result: LPcmsCIEXYZ; SourceWhitePt: LPcmsCIEXYZ; - Illuminant: LPcmsCIEXYZ; Value: LPcmsCIEXYZ): cmsBool; StdCall; external 'lcms2.dll'; -FUNCTION cmsCIECAM02Init(pVC : LPcmsViewingConditions ) : Pointer; StdCall; external 'lcms2.dll'; -PROCEDURE cmsCIECAM02Done(hModel : Pointer); StdCall; external 'lcms2.dll'; -PROCEDURE cmsCIECAM02Forward(hModel: Pointer; pIn: LPcmsCIEXYZ; pOut: LPcmsJCh ); StdCall; external 'lcms2.dll'; -PROCEDURE cmsCIECAM02Reverse(hModel: Pointer; pIn: LPcmsJCh; pOut: LPcmsCIEXYZ ); StdCall; external 'lcms2.dll'; -FUNCTION cmsBuildSegmentedToneCurve(ContextID: cmsContext; nSegments: cmsInt32Number; Segments: LPcmsCurveSegmentArray): LPcmsToneCurve; StdCall; external 'lcms2.dll'; -FUNCTION cmsBuildParametricToneCurve(ContextID: cmsContext; CType: cmsInt32Number; Params: LPcmsFloat64NumberArray): LPcmsToneCurve; StdCall; external 'lcms2.dll'; -FUNCTION cmsBuildGamma(ContextID: cmsContext; Gamma: cmsFloat64Number): LPcmsToneCurve; StdCall; external 'lcms2.dll'; -FUNCTION cmsBuildTabulatedToneCurve16(ContextID: cmsContext; nEntries: cmsInt32Number; values: LPcmsUInt16NumberArray): LPcmsToneCurve; StdCall; external 'lcms2.dll'; -FUNCTION cmsBuildTabulatedToneCurveFloat(ContextID: cmsContext; nEntries: cmsUInt32Number; values: LPcmsFloat32NumberArray): LPcmsToneCurve; StdCall; external 'lcms2.dll'; -PROCEDURE cmsFreeToneCurve(Curve: LPcmsToneCurve); StdCall; external 'lcms2.dll'; -PROCEDURE cmsFreeToneCurveTriple(Curve: LPLPcmsToneCurveArray); StdCall; external 'lcms2.dll'; -FUNCTION cmsDupToneCurve(Src: LPcmsToneCurve): LPcmsToneCurve; StdCall; external 'lcms2.dll'; -FUNCTION cmsReverseToneCurve(InGamma: LPcmsToneCurve): LPcmsToneCurve; StdCall; external 'lcms2.dll'; -FUNCTION cmsReverseToneCurveEx(nResultSamples: cmsInt32Number; InGamma: LPcmsToneCurve): LPcmsToneCurve; StdCall; external 'lcms2.dll'; -FUNCTION cmsJoinToneCurve(ContextID: cmsContext; X, Y: LPcmsToneCurve; nPoints: cmsUInt32Number ): LPcmsToneCurve; StdCall; external 'lcms2.dll'; -FUNCTION cmsSmoothToneCurve(Tab: LPcmsToneCurve; lambda: cmsFloat64Number): cmsBool; StdCall; external 'lcms2.dll'; -FUNCTION cmsEvalToneCurveFloat(Curve: LPcmsToneCurve; v: cmsFloat32Number):cmsFloat32Number; StdCall; external 'lcms2.dll'; -FUNCTION cmsEvalToneCurve16(Curve: LPcmsToneCurve; v:cmsUInt16Number):cmsUInt16Number; StdCall; external 'lcms2.dll'; -FUNCTION cmsIsToneCurveMultisegment(InGamma: LPcmsToneCurve):cmsBool; StdCall; external 'lcms2.dll'; -FUNCTION cmsIsToneCurveLinear(Curve: LPcmsToneCurve):cmsBool; StdCall; external 'lcms2.dll'; -FUNCTION cmsIsToneCurveMonotonic(t: LPcmsToneCurve):cmsBool; StdCall; external 'lcms2.dll'; -FUNCTION cmsIsToneCurveDescending(t: LPcmsToneCurve):cmsBool; StdCall; external 'lcms2.dll'; -FUNCTION cmsGetToneCurveParametricType(t: LPcmsToneCurve):cmsInt32Number; StdCall; external 'lcms2.dll'; -FUNCTION cmsEstimateGamma(t: LPcmsToneCurve; Precision:cmsFloat64Number):cmsFloat64Number; StdCall; external 'lcms2.dll'; -FUNCTION cmsPipelineAlloc(ContextID: cmsContext; InputChannels, OutputChannels: cmsUInt32Number): LPcmsPipeline; StdCall; external 'lcms2.dll'; -PROCEDURE cmsPipelineFree(lut: LPcmsPipeline); StdCall; external 'lcms2.dll'; -FUNCTION cmsPipelineDup(Orig: LPcmsPipeline): LPcmsPipeline; StdCall; external 'lcms2.dll'; -FUNCTION cmsPipelineInputChannels(lut: LPcmsPipeline): cmsUInt32Number; StdCall; external 'lcms2.dll'; -FUNCTION cmsPipelineOutputChannels(lut: LPcmsPipeline): cmsUInt32Number; StdCall; external 'lcms2.dll'; -FUNCTION cmsPipelineStageCount(lut: LPcmsPipeline): cmsUInt32Number; StdCall; external 'lcms2.dll'; -FUNCTION cmsPipelineGetPtrToFirstStage(lut: LPcmsPipeline): LPcmsStage; StdCall; external 'lcms2.dll'; -FUNCTION cmsPipelineGetPtrToLastStage(lut: LPcmsPipeline): LPcmsStage; StdCall; external 'lcms2.dll'; - -PROCEDURE cmsPipelineEval16(Inv, Outv: LPcmsUInt16NumberArray; lut: LPcmsPipeline); StdCall; external 'lcms2.dll'; -PROCEDURE cmsPipelineEvalFloat(Inv, Outv: LPcmsFloat32NumberArray; lut: LPcmsPipeline); StdCall; external 'lcms2.dll'; - -FUNCTION cmsPipelineEvalReverseFloat(Target, Result, Hint: LPcmsFloat32NumberArray; lut: LPcmsPipeline): cmsBool; StdCall; external 'lcms2.dll'; -FUNCTION cmsPipelineCat(l1, l2: LPcmsPipeline): cmsBool; StdCall; external 'lcms2.dll'; -FUNCTION cmsPipelineSetSaveAs8bitsFlag(lut: LPcmsPipeline; On: cmsBool): cmsBool; StdCall; external 'lcms2.dll'; -PROCEDURE cmsPipelineInsertStage(lut: LPcmsPipeline; loc: cmsStageLoc; mpe: LPcmsStage); StdCall; external 'lcms2.dll'; -PROCEDURE cmsPipelineUnlinkStage(lut: LPcmsPipeline; loc: cmsStageLoc; mpe: LPLPcmsStage); StdCall; external 'lcms2.dll'; -FUNCTION cmsStageAllocIdentity(ContextID: cmsContext; nChannels: cmsUInt32Number): LPcmsStage; StdCall; external 'lcms2.dll'; -FUNCTION cmsStageAllocToneCurves(ContextID: cmsContext; nChannels: cmsUInt32Number; Curves: LPLPcmsToneCurveArray): LPcmsStage; StdCall; external 'lcms2.dll'; -FUNCTION cmsStageAllocMatrix(ContextID: cmsContext; Rows, Cols: cmsUInt32Number; Matrix, Offset: LPcmsFloat64NumberArray): LPcmsStage; StdCall; external 'lcms2.dll'; -FUNCTION cmsStageAllocCLut16bit(ContextID: cmsContext; nGridPoints: cmsUInt32Number; inputChan, outputChan: cmsUInt32Number; Table: LPcmsUInt16NumberArray): LPcmsStage; StdCall; external 'lcms2.dll'; -FUNCTION cmsStageAllocCLutFloat(ContextID: cmsContext; nGridPoints: cmsUInt32Number; inputChan, outputChan: cmsUInt32Number; Table: LPcmsFloat32NumberArray): LPcmsStage; StdCall; external 'lcms2.dll'; -FUNCTION cmsStageAllocCLut16bitGranular(ContextID: cmsContext; nGridPoints: LPcmsUInt32NumberArray; inputChan, outputChan: cmsUInt32Number; Table: LPcmsUInt16NumberArray): LPcmsStage; StdCall; external 'lcms2.dll'; -FUNCTION cmsStageAllocCLutFloatGranular(ContextID: cmsContext; nGridPoints: LPcmsUInt32NumberArray; inputChan, outputChan: cmsUInt32Number; Table: LPcmsFloat32NumberArray): LPcmsStage; StdCall; external 'lcms2.dll'; -FUNCTION cmsStageDup(mpe: LPcmsStage): LPcmsStage; StdCall; external 'lcms2.dll'; -PROCEDURE cmsStageFree(mpe: LPcmsStage); StdCall; external 'lcms2.dll'; -FUNCTION cmsStageNext(mpe: LPcmsStage): LPcmsStage; StdCall; external 'lcms2.dll'; -FUNCTION cmsStageInputChannels(mpe: LPcmsStage): cmsUInt32Number; StdCall; external 'lcms2.dll'; -FUNCTION cmsStageOutputChannels(mpe: LPcmsStage): cmsUInt32Number; StdCall; external 'lcms2.dll'; -FUNCTION cmsStageType(mpe: LPcmsStage): cmsStageSignature; StdCall; external 'lcms2.dll'; -FUNCTION cmsStageData(mpe: LPcmsStage): Pointer; StdCall; external 'lcms2.dll'; -FUNCTION cmsStageSampleCLut16bit(mpe: LPcmsStage; Sampler: cmsSAMPLER16; Cargo: Pointer; dwFlags: cmsUInt32Number): cmsBool; StdCall; external 'lcms2.dll'; -FUNCTION cmsStageSampleCLutFloat(mpe: LPcmsStage; Sampler: cmsSAMPLERFLOAT; Cargo: Pointer; dwFlags: cmsUInt32Number): cmsBool; StdCall; external 'lcms2.dll'; + Illuminant: LPcmsCIEXYZ; Value: LPcmsCIEXYZ): cmsBool; StdCall; external LCMS2_SO; +FUNCTION cmsCIECAM02Init(pVC : LPcmsViewingConditions ) : Pointer; StdCall; external LCMS2_SO; +PROCEDURE cmsCIECAM02Done(hModel : Pointer); StdCall; external LCMS2_SO; +PROCEDURE cmsCIECAM02Forward(hModel: Pointer; pIn: LPcmsCIEXYZ; pOut: LPcmsJCh ); StdCall; external LCMS2_SO; +PROCEDURE cmsCIECAM02Reverse(hModel: Pointer; pIn: LPcmsJCh; pOut: LPcmsCIEXYZ ); StdCall; external LCMS2_SO; +FUNCTION cmsBuildSegmentedToneCurve(ContextID: cmsContext; nSegments: cmsInt32Number; Segments: LPcmsCurveSegmentArray): LPcmsToneCurve; StdCall; external LCMS2_SO; +FUNCTION cmsBuildParametricToneCurve(ContextID: cmsContext; CType: cmsInt32Number; Params: LPcmsFloat64NumberArray): LPcmsToneCurve; StdCall; external LCMS2_SO; +FUNCTION cmsBuildGamma(ContextID: cmsContext; Gamma: cmsFloat64Number): LPcmsToneCurve; StdCall; external LCMS2_SO; +FUNCTION cmsBuildTabulatedToneCurve16(ContextID: cmsContext; nEntries: cmsInt32Number; values: LPcmsUInt16NumberArray): LPcmsToneCurve; StdCall; external LCMS2_SO; +FUNCTION cmsBuildTabulatedToneCurveFloat(ContextID: cmsContext; nEntries: cmsUInt32Number; values: LPcmsFloat32NumberArray): LPcmsToneCurve; StdCall; external LCMS2_SO; +PROCEDURE cmsFreeToneCurve(Curve: LPcmsToneCurve); StdCall; external LCMS2_SO; +PROCEDURE cmsFreeToneCurveTriple(Curve: LPLPcmsToneCurveArray); StdCall; external LCMS2_SO; +FUNCTION cmsDupToneCurve(Src: LPcmsToneCurve): LPcmsToneCurve; StdCall; external LCMS2_SO; +FUNCTION cmsReverseToneCurve(InGamma: LPcmsToneCurve): LPcmsToneCurve; StdCall; external LCMS2_SO; +FUNCTION cmsReverseToneCurveEx(nResultSamples: cmsInt32Number; InGamma: LPcmsToneCurve): LPcmsToneCurve; StdCall; external LCMS2_SO; +FUNCTION cmsJoinToneCurve(ContextID: cmsContext; X, Y: LPcmsToneCurve; nPoints: cmsUInt32Number ): LPcmsToneCurve; StdCall; external LCMS2_SO; +FUNCTION cmsSmoothToneCurve(Tab: LPcmsToneCurve; lambda: cmsFloat64Number): cmsBool; StdCall; external LCMS2_SO; +FUNCTION cmsEvalToneCurveFloat(Curve: LPcmsToneCurve; v: cmsFloat32Number):cmsFloat32Number; StdCall; external LCMS2_SO; +FUNCTION cmsEvalToneCurve16(Curve: LPcmsToneCurve; v:cmsUInt16Number):cmsUInt16Number; StdCall; external LCMS2_SO; +FUNCTION cmsIsToneCurveMultisegment(InGamma: LPcmsToneCurve):cmsBool; StdCall; external LCMS2_SO; +FUNCTION cmsIsToneCurveLinear(Curve: LPcmsToneCurve):cmsBool; StdCall; external LCMS2_SO; +FUNCTION cmsIsToneCurveMonotonic(t: LPcmsToneCurve):cmsBool; StdCall; external LCMS2_SO; +FUNCTION cmsIsToneCurveDescending(t: LPcmsToneCurve):cmsBool; StdCall; external LCMS2_SO; +FUNCTION cmsGetToneCurveParametricType(t: LPcmsToneCurve):cmsInt32Number; StdCall; external LCMS2_SO; +FUNCTION cmsEstimateGamma(t: LPcmsToneCurve; Precision:cmsFloat64Number):cmsFloat64Number; StdCall; external LCMS2_SO; +FUNCTION cmsGetToneCurveEstimatedTableEntries(t: LPcmsToneCurve): cmsUInt32Number; StdCall; external LCMS2_SO; +FUNCTION cmsGetToneCurveEstimatedTable(t: LPcmsToneCurve): LPcmsUInt16Number; StdCall; external LCMS2_SO; +FUNCTION cmsPipelineAlloc(ContextID: cmsContext; InputChannels, OutputChannels: cmsUInt32Number): LPcmsPipeline; StdCall; external LCMS2_SO; +PROCEDURE cmsPipelineFree(lut: LPcmsPipeline); StdCall; external LCMS2_SO; +FUNCTION cmsPipelineDup(Orig: LPcmsPipeline): LPcmsPipeline; StdCall; external LCMS2_SO; +FUNCTION cmsGetPipelineContextID(lut: LPcmsPipeline) : cmsContext; StdCall; external LCMS2_SO; +FUNCTION cmsPipelineInputChannels(lut: LPcmsPipeline): cmsUInt32Number; StdCall; external LCMS2_SO; +FUNCTION cmsPipelineOutputChannels(lut: LPcmsPipeline): cmsUInt32Number; StdCall; external LCMS2_SO; +FUNCTION cmsPipelineStageCount(lut: LPcmsPipeline): cmsUInt32Number; StdCall; external LCMS2_SO; +FUNCTION cmsPipelineGetPtrToFirstStage(lut: LPcmsPipeline): LPcmsStage; StdCall; external LCMS2_SO; +FUNCTION cmsPipelineGetPtrToLastStage(lut: LPcmsPipeline): LPcmsStage; StdCall; external LCMS2_SO; + +PROCEDURE cmsPipelineEval16(Inv, Outv: LPcmsUInt16NumberArray; lut: LPcmsPipeline); StdCall; external LCMS2_SO; +PROCEDURE cmsPipelineEvalFloat(Inv, Outv: LPcmsFloat32NumberArray; lut: LPcmsPipeline); StdCall; external LCMS2_SO; + +FUNCTION cmsPipelineEvalReverseFloat(Target, Result, Hint: LPcmsFloat32NumberArray; lut: LPcmsPipeline): cmsBool; StdCall; external LCMS2_SO; +FUNCTION cmsPipelineCat(l1, l2: LPcmsPipeline): cmsBool; StdCall; external LCMS2_SO; +FUNCTION cmsPipelineSetSaveAs8bitsFlag(lut: LPcmsPipeline; On: cmsBool): cmsBool; StdCall; external LCMS2_SO; +PROCEDURE cmsPipelineInsertStage(lut: LPcmsPipeline; loc: cmsStageLoc; mpe: LPcmsStage); StdCall; external LCMS2_SO; +PROCEDURE cmsPipelineUnlinkStage(lut: LPcmsPipeline; loc: cmsStageLoc; mpe: LPLPcmsStage); StdCall; external LCMS2_SO; +FUNCTION cmsStageAllocIdentity(ContextID: cmsContext; nChannels: cmsUInt32Number): LPcmsStage; StdCall; external LCMS2_SO; +FUNCTION cmsStageAllocToneCurves(ContextID: cmsContext; nChannels: cmsUInt32Number; Curves: LPLPcmsToneCurveArray): LPcmsStage; StdCall; external LCMS2_SO; +FUNCTION cmsStageAllocMatrix(ContextID: cmsContext; Rows, Cols: cmsUInt32Number; Matrix, Offset: LPcmsFloat64NumberArray): LPcmsStage; StdCall; external LCMS2_SO; +FUNCTION cmsStageAllocCLut16bit(ContextID: cmsContext; nGridPoints: cmsUInt32Number; inputChan, outputChan: cmsUInt32Number; Table: LPcmsUInt16NumberArray): LPcmsStage; StdCall; external LCMS2_SO; +FUNCTION cmsStageAllocCLutFloat(ContextID: cmsContext; nGridPoints: cmsUInt32Number; inputChan, outputChan: cmsUInt32Number; Table: LPcmsFloat32NumberArray): LPcmsStage; StdCall; external LCMS2_SO; +FUNCTION cmsStageAllocCLut16bitGranular(ContextID: cmsContext; nGridPoints: LPcmsUInt32NumberArray; inputChan, outputChan: cmsUInt32Number; Table: LPcmsUInt16NumberArray): LPcmsStage; StdCall; external LCMS2_SO; +FUNCTION cmsStageAllocCLutFloatGranular(ContextID: cmsContext; nGridPoints: LPcmsUInt32NumberArray; inputChan, outputChan: cmsUInt32Number; Table: LPcmsFloat32NumberArray): LPcmsStage; StdCall; external LCMS2_SO; +FUNCTION cmsStageDup(mpe: LPcmsStage): LPcmsStage; StdCall; external LCMS2_SO; +PROCEDURE cmsStageFree(mpe: LPcmsStage); StdCall; external LCMS2_SO; +FUNCTION cmsStageNext(mpe: LPcmsStage): LPcmsStage; StdCall; external LCMS2_SO; +FUNCTION cmsStageInputChannels(mpe: LPcmsStage): cmsUInt32Number; StdCall; external LCMS2_SO; +FUNCTION cmsStageOutputChannels(mpe: LPcmsStage): cmsUInt32Number; StdCall; external LCMS2_SO; +FUNCTION cmsStageType(mpe: LPcmsStage): cmsStageSignature; StdCall; external LCMS2_SO; +FUNCTION cmsStageData(mpe: LPcmsStage): Pointer; StdCall; external LCMS2_SO; +FUNCTION cmsStageSampleCLut16bit(mpe: LPcmsStage; Sampler: cmsSAMPLER16; Cargo: Pointer; dwFlags: cmsUInt32Number): cmsBool; StdCall; external LCMS2_SO; +FUNCTION cmsStageSampleCLutFloat(mpe: LPcmsStage; Sampler: cmsSAMPLERFLOAT; Cargo: Pointer; dwFlags: cmsUInt32Number): cmsBool; StdCall; external LCMS2_SO; FUNCTION cmsSliceSpace16(nInputs: cmsUInt32Number; clutPoints: LPcmsUInt32NumberArray; - Sampler: cmsSAMPLER16; Cargo: Pointer): cmsBool; StdCall; external 'lcms2.dll'; + Sampler: cmsSAMPLER16; Cargo: Pointer): cmsBool; StdCall; external LCMS2_SO; FUNCTION cmsSliceSpaceFloat(nInputs: cmsUInt32Number; clutPoints: LPcmsUInt32NumberArray; - Sampler: cmsSAMPLERFLOAT; Cargo: Pointer): cmsBool; StdCall; external 'lcms2.dll'; -FUNCTION cmsMLUalloc(ContextID: cmsContext; nItems: cmsUInt32Number): LPcmsMLU; StdCall; external 'lcms2.dll'; -PROCEDURE cmsMLUfree(mlu: LPcmsMLU); StdCall; external 'lcms2.dll'; -FUNCTION cmsMLUdup(mlu: LPcmsMLU): LPcmsMLU; StdCall; external 'lcms2.dll'; + Sampler: cmsSAMPLERFLOAT; Cargo: Pointer): cmsBool; StdCall; external LCMS2_SO; +FUNCTION cmsMLUalloc(ContextID: cmsContext; nItems: cmsUInt32Number): LPcmsMLU; StdCall; external LCMS2_SO; +PROCEDURE cmsMLUfree(mlu: LPcmsMLU); StdCall; external LCMS2_SO; +FUNCTION cmsMLUdup(mlu: LPcmsMLU): LPcmsMLU; StdCall; external LCMS2_SO; -FUNCTION cmsMLUsetASCII(mlu: LPcmsMLU; LanguageCode, CountryCode, ASCIIString: PAnsiChar): cmsBool; StdCall; external 'lcms2.dll'; -FUNCTION cmsMLUsetWide(mlu: LPcmsMLU; LanguageCode, CountryCode: PAnsiChar; WideString: PWChar): cmsBool; StdCall; external 'lcms2.dll'; +FUNCTION cmsMLUsetASCII(mlu: LPcmsMLU; LanguageCode, CountryCode, ASCIIString: PAnsiChar): cmsBool; StdCall; external LCMS2_SO; +FUNCTION cmsMLUsetWide(mlu: LPcmsMLU; LanguageCode, CountryCode: PAnsiChar; WideString: PWChar): cmsBool; StdCall; external LCMS2_SO; -FUNCTION cmsMLUgetASCII(mlu: LPcmsMLU; LanguageCode, CountryCode: PAnsiChar; Buffer: PAnsiChar; BufferSize: cmsUInt32Number): cmsUInt32Number; StdCall; external 'lcms2.dll'; +FUNCTION cmsMLUgetASCII(mlu: LPcmsMLU; LanguageCode, CountryCode: PAnsiChar; Buffer: PAnsiChar; BufferSize: cmsUInt32Number): cmsUInt32Number; StdCall; external LCMS2_SO; -FUNCTION cmsMLUgetWide(mlu: LPcmsMLU; LanguageCode, CountryCode: PAnsiChar; Buffer: PWChar; BufferSize: cmsUInt32Number): cmsUInt32Number; StdCall; external 'lcms2.dll'; - -FUNCTION cmsMLUgetTranslation(mlu: LPcmsMLU; LanguageCode, CountryCode, ObtainedLanguage, ObtainedCountry: PAnsiChar): cmsBool; StdCall; external 'lcms2.dll'; +FUNCTION cmsMLUgetWide(mlu: LPcmsMLU; LanguageCode, CountryCode: PAnsiChar; Buffer: PWChar; BufferSize: cmsUInt32Number): cmsUInt32Number; StdCall; external LCMS2_SO; + +FUNCTION cmsMLUgetTranslation(mlu: LPcmsMLU; LanguageCode, CountryCode, ObtainedLanguage, ObtainedCountry: PAnsiChar): cmsBool; StdCall; external LCMS2_SO; FUNCTION cmsAllocNamedColorList(ContextID: cmsContext; n, ColorantCount :cmsUInt32Number; - Prefix, Suffix: PAnsiChar): LPcmsNAMEDCOLORLIST; StdCall; external 'lcms2.dll'; + Prefix, Suffix: PAnsiChar): LPcmsNAMEDCOLORLIST; StdCall; external LCMS2_SO; -PROCEDURE cmsFreeNamedColorList(v: LPcmsNAMEDCOLORLIST); StdCall; external 'lcms2.dll'; -FUNCTION cmsDupNamedColorList(v: LPcmsNAMEDCOLORLIST): LPcmsNAMEDCOLORLIST; StdCall; external 'lcms2.dll'; +PROCEDURE cmsFreeNamedColorList(v: LPcmsNAMEDCOLORLIST); StdCall; external LCMS2_SO; +FUNCTION cmsDupNamedColorList(v: LPcmsNAMEDCOLORLIST): LPcmsNAMEDCOLORLIST; StdCall; external LCMS2_SO; FUNCTION cmsAppendNamedColor(v: LPcmsNAMEDCOLORLIST; Name: PAnsiChar; - PCS, Colorant : LPcmsUInt16NumberArray): cmsBool; StdCall; external 'lcms2.dll'; + PCS, Colorant : LPcmsUInt16NumberArray): cmsBool; StdCall; external LCMS2_SO; -FUNCTION cmsNamedColorCount(v: LPcmsNAMEDCOLORLIST): cmsUInt32Number; StdCall; external 'lcms2.dll'; -FUNCTION cmsNamedColorIndex(v: LPcmsNAMEDCOLORLIST; Name: PAnsiChar): cmsInt32Number; StdCall; external 'lcms2.dll'; +FUNCTION cmsNamedColorCount(v: LPcmsNAMEDCOLORLIST): cmsUInt32Number; StdCall; external LCMS2_SO; +FUNCTION cmsNamedColorIndex(v: LPcmsNAMEDCOLORLIST; Name: PAnsiChar): cmsInt32Number; StdCall; external LCMS2_SO; FUNCTION cmsNamedColorInfo(v: LPcmsNAMEDCOLORLIST; nColor : cmsUInt32Number; Name,Prefix, Suffix : PAnsiChar; - PCS, Colorant : LPcmsUInt16NumberArray): cmsBool; StdCall; external 'lcms2.dll'; + PCS, Colorant : LPcmsUInt16NumberArray): cmsBool; StdCall; external LCMS2_SO; -FUNCTION cmsGetNamedColorList(xform: cmsHTRANSFORM ): LPcmsNAMEDCOLORLIST; StdCall; external 'lcms2.dll'; +FUNCTION cmsGetNamedColorList(xform: cmsHTRANSFORM ): LPcmsNAMEDCOLORLIST; StdCall; external LCMS2_SO; -FUNCTION cmsAllocProfileSequenceDescription(ContextID: cmsContext; n: cmsUInt32Number):LPcmsSEQ; StdCall; external 'lcms2.dll'; -FUNCTION cmsDupProfileSequenceDescription(pseq: LPcmsSEQ):LPcmsSEQ; StdCall; external 'lcms2.dll'; -PROCEDURE cmsFreeProfileSequenceDescription(pseq: LPcmsSEQ); StdCall; external 'lcms2.dll'; +FUNCTION cmsAllocProfileSequenceDescription(ContextID: cmsContext; n: cmsUInt32Number):LPcmsSEQ; StdCall; external LCMS2_SO; +FUNCTION cmsDupProfileSequenceDescription(pseq: LPcmsSEQ):LPcmsSEQ; StdCall; external LCMS2_SO; +PROCEDURE cmsFreeProfileSequenceDescription(pseq: LPcmsSEQ); StdCall; external LCMS2_SO; -FUNCTION cmsDictAlloc(ContextID: cmsContext): cmsHANDLE; StdCall; external 'lcms2.dll'; -PROCEDURE cmsDictFree(hDict: cmsHANDLE); StdCall; external 'lcms2.dll'; -FUNCTION cmsDictDup(hDict: cmsHANDLE): cmsHANDLE; StdCall; external 'lcms2.dll'; +FUNCTION cmsDictAlloc(ContextID: cmsContext): cmsHANDLE; StdCall; external LCMS2_SO; +PROCEDURE cmsDictFree(hDict: cmsHANDLE); StdCall; external LCMS2_SO; +FUNCTION cmsDictDup(hDict: cmsHANDLE): cmsHANDLE; StdCall; external LCMS2_SO; -FUNCTION cmsDictAddEntry(hDict: cmsHANDLE; Name, Value: PWChar; DisplayName, DisplayValue : LPcmsMLU): cmsBool; StdCall; external 'lcms2.dll'; -FUNCTION cmsDictGetEntryList(hDict: cmsHANDLE): LPcmsDICTentry; StdCall; external 'lcms2.dll'; -FUNCTION cmsDictNextEntry(e : LPcmsDICTentry): LPcmsDICTentry; StdCall; external 'lcms2.dll'; +FUNCTION cmsDictAddEntry(hDict: cmsHANDLE; Name, Value: PWChar; DisplayName, DisplayValue : LPcmsMLU): cmsBool; StdCall; external LCMS2_SO; +FUNCTION cmsDictGetEntryList(hDict: cmsHANDLE): LPcmsDICTentry; StdCall; external LCMS2_SO; +FUNCTION cmsDictNextEntry(e : LPcmsDICTentry): LPcmsDICTentry; StdCall; external LCMS2_SO; -FUNCTION cmsCreateProfilePlaceholder(ContextID: cmsContext): cmsHPROFILE; StdCall; external 'lcms2.dll'; +FUNCTION cmsCreateProfilePlaceholder(ContextID: cmsContext): cmsHPROFILE; StdCall; external LCMS2_SO; -FUNCTION cmsGetProfileContextID(hProfile: cmsHPROFILE):cmsContext; StdCall; external 'lcms2.dll'; -FUNCTION cmsGetTagCount(hProfile: cmsHPROFILE): cmsInt32Number; StdCall; external 'lcms2.dll'; -FUNCTION cmsGetTagSignature(hProfile: cmsHPROFILE; n: cmsUInt32Number): cmsTagSignature; StdCall; external 'lcms2.dll'; -FUNCTION cmsIsTag(hProfile: cmsHPROFILE; sig: cmsTagSignature ): cmsBool; StdCall; external 'lcms2.dll'; +FUNCTION cmsGetProfileContextID(hProfile: cmsHPROFILE):cmsContext; StdCall; external LCMS2_SO; +FUNCTION cmsGetTagCount(hProfile: cmsHPROFILE): cmsInt32Number; StdCall; external LCMS2_SO; +FUNCTION cmsGetTagSignature(hProfile: cmsHPROFILE; n: cmsUInt32Number): cmsTagSignature; StdCall; external LCMS2_SO; +FUNCTION cmsIsTag(hProfile: cmsHPROFILE; sig: cmsTagSignature ): cmsBool; StdCall; external LCMS2_SO; -FUNCTION cmsReadTag(hProfile: cmsHPROFILE; sig: cmsTagSignature ): Pointer; StdCall; external 'lcms2.dll'; -FUNCTION cmsWriteTag(hProfile: cmsHPROFILE; sig: cmsTagSignature; data: Pointer): cmsBool; StdCall; external 'lcms2.dll'; -FUNCTION cmsLinkTag(hProfile: cmsHPROFILE; sig: cmsTagSignature; dest: cmsTagSignature): cmsBool; StdCall; external 'lcms2.dll'; -FUNCTION cmsTagLinkedTo(hProfile: cmsHPROFILE; sig: cmsTagSignature):cmsTagSignature; StdCall; external 'lcms2.dll'; +FUNCTION cmsReadTag(hProfile: cmsHPROFILE; sig: cmsTagSignature ): Pointer; StdCall; external LCMS2_SO; +FUNCTION cmsWriteTag(hProfile: cmsHPROFILE; sig: cmsTagSignature; data: Pointer): cmsBool; StdCall; external LCMS2_SO; +FUNCTION cmsLinkTag(hProfile: cmsHPROFILE; sig: cmsTagSignature; dest: cmsTagSignature): cmsBool; StdCall; external LCMS2_SO; +FUNCTION cmsTagLinkedTo(hProfile: cmsHPROFILE; sig: cmsTagSignature):cmsTagSignature; StdCall; external LCMS2_SO; -FUNCTION cmsReadRawTag(hProfile: cmsHPROFILE; sig: cmsTagSignature; Buffer: Pointer; BufferSize: cmsUInt32Number): cmsInt32Number; StdCall; external 'lcms2.dll'; -FUNCTION cmsWriteRawTag(hProfile: cmsHPROFILE; sig: cmsTagSignature; data: Pointer; Size: cmsUInt32Number): cmsBool; StdCall; external 'lcms2.dll'; +FUNCTION cmsReadRawTag(hProfile: cmsHPROFILE; sig: cmsTagSignature; Buffer: Pointer; BufferSize: cmsUInt32Number): cmsInt32Number; StdCall; external LCMS2_SO; +FUNCTION cmsWriteRawTag(hProfile: cmsHPROFILE; sig: cmsTagSignature; data: Pointer; Size: cmsUInt32Number): cmsBool; StdCall; external LCMS2_SO; -FUNCTION cmsGetHeaderFlags(hProfile: cmsHPROFILE): cmsUInt32Number; StdCall; external 'lcms2.dll'; -PROCEDURE cmsGetHeaderAttributes(hProfile: cmsHPROFILE; Flags: LPcmsUInt64Number); StdCall; external 'lcms2.dll'; -PROCEDURE cmsGetHeaderProfileID(hProfile: cmsHPROFILE; ProfileID: LPcmsUInt8Number); StdCall; external 'lcms2.dll'; +FUNCTION cmsGetHeaderFlags(hProfile: cmsHPROFILE): cmsUInt32Number; StdCall; external LCMS2_SO; +PROCEDURE cmsGetHeaderAttributes(hProfile: cmsHPROFILE; Flags: LPcmsUInt64Number); StdCall; external LCMS2_SO; +PROCEDURE cmsGetHeaderProfileID(hProfile: cmsHPROFILE; ProfileID: LPcmsUInt8Number); StdCall; external LCMS2_SO; -FUNCTION cmsGetHeaderRenderingIntent(hProfile: cmsHPROFILE): cmsUInt32Number; StdCall; external 'lcms2.dll'; -PROCEDURE cmsSetHeaderFlags(hProfile: cmsHPROFILE; Flags: cmsUInt32Number); StdCall; external 'lcms2.dll'; -FUNCTION cmsGetHeaderManufacturer(hProfile: cmsHPROFILE): cmsUInt32Number; StdCall; external 'lcms2.dll'; -PROCEDURE cmsSetHeaderManufacturer(hProfile: cmsHPROFILE; manufacturer: cmsUInt32Number ); StdCall; external 'lcms2.dll'; -FUNCTION cmsGetHeaderModel(hProfile: cmsHPROFILE): cmsUInt32Number; StdCall; external 'lcms2.dll'; -PROCEDURE cmsSetHeaderModel(hProfile: cmsHPROFILE; model: cmsUInt32Number ); StdCall; external 'lcms2.dll'; -PROCEDURE cmsSetHeaderAttributes(hProfile: cmsHPROFILE; Flags: cmsUInt64Number); StdCall; external 'lcms2.dll'; -PROCEDURE cmsSetHeaderProfileID(hProfile: cmsHPROFILE; ProfileID: LPcmsUInt8Number); StdCall; external 'lcms2.dll'; -PROCEDURE cmsSetHeaderRenderingIntent(hProfile: cmsHPROFILE; RenderingIntent: cmsUInt32Number ); StdCall; external 'lcms2.dll'; +FUNCTION cmsGetHeaderRenderingIntent(hProfile: cmsHPROFILE): cmsUInt32Number; StdCall; external LCMS2_SO; +PROCEDURE cmsSetHeaderFlags(hProfile: cmsHPROFILE; Flags: cmsUInt32Number); StdCall; external LCMS2_SO; +FUNCTION cmsGetHeaderManufacturer(hProfile: cmsHPROFILE): cmsUInt32Number; StdCall; external LCMS2_SO; +PROCEDURE cmsSetHeaderManufacturer(hProfile: cmsHPROFILE; manufacturer: cmsUInt32Number ); StdCall; external LCMS2_SO; +FUNCTION cmsGetHeaderModel(hProfile: cmsHPROFILE): cmsUInt32Number; StdCall; external LCMS2_SO; +PROCEDURE cmsSetHeaderModel(hProfile: cmsHPROFILE; model: cmsUInt32Number ); StdCall; external LCMS2_SO; +PROCEDURE cmsSetHeaderAttributes(hProfile: cmsHPROFILE; Flags: cmsUInt64Number); StdCall; external LCMS2_SO; +PROCEDURE cmsSetHeaderProfileID(hProfile: cmsHPROFILE; ProfileID: LPcmsUInt8Number); StdCall; external LCMS2_SO; +PROCEDURE cmsSetHeaderRenderingIntent(hProfile: cmsHPROFILE; RenderingIntent: cmsUInt32Number ); StdCall; external LCMS2_SO; -FUNCTION cmsGetPCS(hProfile: cmsHPROFILE):cmsColorSpaceSignature; StdCall; external 'lcms2.dll'; -PROCEDURE cmsSetPCS(hProfile: cmsHPROFILE; pcs: cmsColorSpaceSignature); StdCall; external 'lcms2.dll'; -FUNCTION cmsGetColorSpace(hProfile: cmsHPROFILE): cmsColorSpaceSignature; StdCall; external 'lcms2.dll'; -PROCEDURE cmsSetColorSpace(hProfile: cmsHPROFILE; sig: cmsColorSpaceSignature); StdCall; external 'lcms2.dll'; -FUNCTION cmsGetDeviceClass(hProfile: cmsHPROFILE): cmsProfileClassSignature; StdCall; external 'lcms2.dll'; -PROCEDURE cmsSetDeviceClass(hProfile: cmsHPROFILE; sig: cmsProfileClassSignature); StdCall; external 'lcms2.dll'; -PROCEDURE cmsSetProfileVersion(hProfile: cmsHPROFILE; Version: cmsFloat64Number); StdCall; external 'lcms2.dll'; -FUNCTION cmsGetProfileVersion(hProfile: cmsHPROFILE): cmsFloat64Number; StdCall; external 'lcms2.dll'; +FUNCTION cmsGetPCS(hProfile: cmsHPROFILE):cmsColorSpaceSignature; StdCall; external LCMS2_SO; +PROCEDURE cmsSetPCS(hProfile: cmsHPROFILE; pcs: cmsColorSpaceSignature); StdCall; external LCMS2_SO; +FUNCTION cmsGetColorSpace(hProfile: cmsHPROFILE): cmsColorSpaceSignature; StdCall; external LCMS2_SO; +PROCEDURE cmsSetColorSpace(hProfile: cmsHPROFILE; sig: cmsColorSpaceSignature); StdCall; external LCMS2_SO; +FUNCTION cmsGetDeviceClass(hProfile: cmsHPROFILE): cmsProfileClassSignature; StdCall; external LCMS2_SO; +PROCEDURE cmsSetDeviceClass(hProfile: cmsHPROFILE; sig: cmsProfileClassSignature); StdCall; external LCMS2_SO; +PROCEDURE cmsSetProfileVersion(hProfile: cmsHPROFILE; Version: cmsFloat64Number); StdCall; external LCMS2_SO; +FUNCTION cmsGetProfileVersion(hProfile: cmsHPROFILE): cmsFloat64Number; StdCall; external LCMS2_SO; -FUNCTION cmsGetEncodedICCversion(hProfile: cmsHPROFILE): cmsUInt32Number; StdCall; external 'lcms2.dll'; -PROCEDURE cmsSetEncodedICCversion(hProfile: cmsHPROFILE; Version: cmsUInt32Number); StdCall; external 'lcms2.dll'; +FUNCTION cmsGetEncodedICCversion(hProfile: cmsHPROFILE): cmsUInt32Number; StdCall; external LCMS2_SO; +PROCEDURE cmsSetEncodedICCversion(hProfile: cmsHPROFILE; Version: cmsUInt32Number); StdCall; external LCMS2_SO; -FUNCTION cmsIsIntentSupported(hProfile: cmsHPROFILE; Intent: cmsUInt32Number; UsedDirection: cmsUInt32Number): cmsBool; StdCall; external 'lcms2.dll'; -FUNCTION cmsIsMatrixShaper(hProfile: cmsHPROFILE): cmsBool; StdCall; external 'lcms2.dll'; -FUNCTION cmsIsCLUT(hProfile: cmsHPROFILE; Intent: cmsUInt32Number; UsedDirection: cmsUInt32Number): cmsBool; StdCall; external 'lcms2.dll'; -FUNCTION _cmsICCcolorSpace(OurNotation: Integer): cmsColorSpaceSignature; StdCall; external 'lcms2.dll'; -FUNCTION _cmsLCMScolorSpace(ProfileSpace: cmsColorSpaceSignature): Integer; StdCall; external 'lcms2.dll'; +FUNCTION cmsIsIntentSupported(hProfile: cmsHPROFILE; Intent: cmsUInt32Number; UsedDirection: cmsUInt32Number): cmsBool; StdCall; external LCMS2_SO; +FUNCTION cmsIsMatrixShaper(hProfile: cmsHPROFILE): cmsBool; StdCall; external LCMS2_SO; +FUNCTION cmsIsCLUT(hProfile: cmsHPROFILE; Intent: cmsUInt32Number; UsedDirection: cmsUInt32Number): cmsBool; StdCall; external LCMS2_SO; +FUNCTION _cmsICCcolorSpace(OurNotation: Integer): cmsColorSpaceSignature; StdCall; external LCMS2_SO; +FUNCTION _cmsLCMScolorSpace(ProfileSpace: cmsColorSpaceSignature): Integer; StdCall; external LCMS2_SO; -FUNCTION cmsChannelsOf( ColorSpace: cmsColorSpaceSignature): cmsUInt32Number; StdCall; external 'lcms2.dll'; +FUNCTION cmsChannelsOf( ColorSpace: cmsColorSpaceSignature): cmsUInt32Number; StdCall; external LCMS2_SO; -FUNCTION cmsFormatterForColorspaceOfProfile(hProfile: cmsHPROFILE; nBytes: cmsUInt32Number; lIsFloat: cmsBool): cmsUInt32Number; StdCall; external 'lcms2.dll'; -FUNCTION cmsFormatterForPCSOfProfile(hProfile: cmsHPROFILE; nBytes: cmsUInt32Number; lIsFloat: cmsBool): cmsUInt32Number; StdCall; external 'lcms2.dll'; +FUNCTION cmsFormatterForColorspaceOfProfile(hProfile: cmsHPROFILE; nBytes: cmsUInt32Number; lIsFloat: cmsBool): cmsUInt32Number; StdCall; external LCMS2_SO; +FUNCTION cmsFormatterForPCSOfProfile(hProfile: cmsHPROFILE; nBytes: cmsUInt32Number; lIsFloat: cmsBool): cmsUInt32Number; StdCall; external LCMS2_SO; FUNCTION cmsGetProfileInfo(hProfile: cmsHPROFILE; Info: cmsInfoType; LanguageCode, CountryCode: PAnsiChar; - Buffer: PWChar; BufferSize: cmsUInt32Number): cmsUInt32Number; StdCall; external 'lcms2.dll'; + Buffer: PWChar; BufferSize: cmsUInt32Number): cmsUInt32Number; StdCall; external LCMS2_SO; FUNCTION cmsGetProfileInfoASCII(hProfile: cmsHPROFILE; Info: cmsInfoType; LanguageCode, CountryCode: PAnsiChar; - Buffer: PAnsiChar; BufferSize: cmsUInt32Number): cmsUInt32Number; StdCall; external 'lcms2.dll'; + Buffer: PAnsiChar; BufferSize: cmsUInt32Number): cmsUInt32Number; StdCall; external LCMS2_SO; -FUNCTION cmsOpenIOhandlerFromFile(ContextID: cmsContext; FileName, AccessMode: PAnsiChar): LPcmsIOHANDLER; StdCall; external 'lcms2.dll'; -// FUNCTION cmsOpenIOhandlerFromStream(ContextID: cmsContext; FILE* Stream): LPcmsIOHANDLER; StdCall; external 'lcms2.dll'; -FUNCTION cmsOpenIOhandlerFromMem(ContextID: cmsContext; Buffer: Pointer; size: cmsUInt32Number; AccessMode: PAnsiChar): LPcmsIOHANDLER; StdCall; external 'lcms2.dll'; -FUNCTION cmsOpenIOhandlerFromNULL(ContextID: cmsContext): LPcmsIOHANDLER; StdCall; external 'lcms2.dll'; -FUNCTION cmsCloseIOhandler(io: LPcmsIOHANDLER): cmsBool; StdCall; external 'lcms2.dll'; +FUNCTION cmsOpenIOhandlerFromFile(ContextID: cmsContext; FileName, AccessMode: PAnsiChar): LPcmsIOHANDLER; StdCall; external LCMS2_SO; +// FUNCTION cmsOpenIOhandlerFromStream(ContextID: cmsContext; FILE* Stream): LPcmsIOHANDLER; StdCall; external LCMS2_SO; +FUNCTION cmsOpenIOhandlerFromMem(ContextID: cmsContext; Buffer: Pointer; size: cmsUInt32Number; AccessMode: PAnsiChar): LPcmsIOHANDLER; StdCall; external LCMS2_SO; +FUNCTION cmsOpenIOhandlerFromNULL(ContextID: cmsContext): LPcmsIOHANDLER; StdCall; external LCMS2_SO; +FUNCTION cmsCloseIOhandler(io: LPcmsIOHANDLER): cmsBool; StdCall; external LCMS2_SO; -FUNCTION cmsMD5computeID(hProfile: cmsHPROFILE): cmsBool; StdCall; external 'lcms2.dll'; +FUNCTION cmsMD5computeID(hProfile: cmsHPROFILE): cmsBool; StdCall; external LCMS2_SO; -FUNCTION cmsOpenProfileFromFile(ICCProfile : PAnsiChar; sAccess: PAnsiChar): cmsHPROFILE; StdCall; external 'lcms2.dll'; -FUNCTION cmsOpenProfileFromFileTHR(ContextID: cmsContext; ICCProfile, sAccess: PAnsiChar): cmsHPROFILE; StdCall; external 'lcms2.dll'; -// FUNCTION CMSEXPORT cmsOpenProfileFromStream(FILE* ICCProfile, const char* sAccess): cmsHPROFILE; StdCall; external 'lcms2.dll'; -// FUNCTION CMSEXPORT cmsOpenProfileFromStreamTHR(ContextID: cmsContext; FILE* ICCProfile, const char* sAccess): cmsHPROFILE; StdCall; external 'lcms2.dll'; -FUNCTION cmsOpenProfileFromMem(MemPtr: Pointer; dwSize: cmsUInt32Number): cmsHPROFILE; StdCall; external 'lcms2.dll'; -FUNCTION cmsOpenProfileFromMemTHR(ContextID: cmsContext; MemPtr: Pointer; dwSize: cmsUInt32Number): cmsHPROFILE; StdCall; external 'lcms2.dll'; -FUNCTION cmsOpenProfileFromIOhandlerTHR(ContextID: cmsContext; io: LPcmsIOHANDLER): cmsHPROFILE; StdCall; external 'lcms2.dll'; -FUNCTION cmsCloseProfile(hProfile: cmsHPROFILE): cmsBool; StdCall; external 'lcms2.dll'; +FUNCTION cmsOpenProfileFromFile(ICCProfile : PAnsiChar; sAccess: PAnsiChar): cmsHPROFILE; StdCall; external LCMS2_SO; +FUNCTION cmsOpenProfileFromFileTHR(ContextID: cmsContext; ICCProfile, sAccess: PAnsiChar): cmsHPROFILE; StdCall; external LCMS2_SO; +// FUNCTION CMSEXPORT cmsOpenProfileFromStream(FILE* ICCProfile, const char* sAccess): cmsHPROFILE; StdCall; external LCMS2_SO; +// FUNCTION CMSEXPORT cmsOpenProfileFromStreamTHR(ContextID: cmsContext; FILE* ICCProfile, const char* sAccess): cmsHPROFILE; StdCall; external LCMS2_SO; +FUNCTION cmsOpenProfileFromMem(MemPtr: Pointer; dwSize: cmsUInt32Number): cmsHPROFILE; StdCall; external LCMS2_SO; +FUNCTION cmsOpenProfileFromMemTHR(ContextID: cmsContext; MemPtr: Pointer; dwSize: cmsUInt32Number): cmsHPROFILE; StdCall; external LCMS2_SO; +FUNCTION cmsOpenProfileFromIOhandlerTHR(ContextID: cmsContext; io: LPcmsIOHANDLER): cmsHPROFILE; StdCall; external LCMS2_SO; +FUNCTION cmsCloseProfile(hProfile: cmsHPROFILE): cmsBool; StdCall; external LCMS2_SO; -FUNCTION cmsSaveProfileToFile(hProfile: cmsHPROFILE; FileName: PAnsiChar): cmsBool; StdCall; external 'lcms2.dll'; -// FUNCTION CMSEXPORT cmsSaveProfileToStream(hProfile: cmsHPROFILE, FILE* Stream): cmsBool; StdCall; external 'lcms2.dll'; -FUNCTION cmsSaveProfileToMem(hProfile: cmsHPROFILE; MemPtr: Pointer; BytesNeeded: LPcmsUInt32Number): cmsBool; StdCall; external 'lcms2.dll'; -FUNCTION cmsSaveProfileToIOhandler(hProfile: cmsHPROFILE; io: LPcmsIOHANDLER):cmsUInt32Number; StdCall; external 'lcms2.dll'; +FUNCTION cmsSaveProfileToFile(hProfile: cmsHPROFILE; FileName: PAnsiChar): cmsBool; StdCall; external LCMS2_SO; +// FUNCTION CMSEXPORT cmsSaveProfileToStream(hProfile: cmsHPROFILE, FILE* Stream): cmsBool; StdCall; external LCMS2_SO; +FUNCTION cmsSaveProfileToMem(hProfile: cmsHPROFILE; MemPtr: Pointer; BytesNeeded: LPcmsUInt32Number): cmsBool; StdCall; external LCMS2_SO; +FUNCTION cmsSaveProfileToIOhandler(hProfile: cmsHPROFILE; io: LPcmsIOHANDLER):cmsUInt32Number; StdCall; external LCMS2_SO; FUNCTION cmsCreateRGBProfileTHR(ContextID: cmsContext; WhitePoint: LPcmsCIExyY; Primaries: LPcmsCIExyYTRIPLE; - TransferFunction: LPLPcmsToneCurveArray): cmsHPROFILE; StdCall; external 'lcms2.dll'; + TransferFunction: LPLPcmsToneCurveArray): cmsHPROFILE; StdCall; external LCMS2_SO; FUNCTION cmsCreateRGBProfile(WhitePoint: LPcmsCIExyY; Primaries: LPcmsCIExyYTRIPLE; - TransferFunction: LPLPcmsToneCurveArray): cmsHPROFILE; StdCall; external 'lcms2.dll'; + TransferFunction: LPLPcmsToneCurveArray): cmsHPROFILE; StdCall; external LCMS2_SO; FUNCTION cmsCreateGrayProfileTHR(ContextID: cmsContext; WhitePoint: LPcmsCIExyY; - TransferFunction: LPcmsToneCurve): cmsHPROFILE; StdCall; external 'lcms2.dll'; + TransferFunction: LPcmsToneCurve): cmsHPROFILE; StdCall; external LCMS2_SO; FUNCTION cmsCreateGrayProfile(WhitePoint: LPcmsCIExyY; - TransferFunction: LPcmsToneCurve): cmsHPROFILE; StdCall; external 'lcms2.dll'; + TransferFunction: LPcmsToneCurve): cmsHPROFILE; StdCall; external LCMS2_SO; FUNCTION cmsCreateLinearizationDeviceLinkTHR(ContextID: cmsContext; ColorSpace: cmsColorSpaceSignature; - TransferFunctions: LPLPcmsToneCurveArray): cmsHPROFILE; StdCall; external 'lcms2.dll'; + TransferFunctions: LPLPcmsToneCurveArray): cmsHPROFILE; StdCall; external LCMS2_SO; FUNCTION cmsCreateLinearizationDeviceLink(ColorSpace: cmsColorSpaceSignature; - TransferFunctions: LPLPcmsToneCurveArray): cmsHPROFILE; StdCall; external 'lcms2.dll'; + TransferFunctions: LPLPcmsToneCurveArray): cmsHPROFILE; StdCall; external LCMS2_SO; FUNCTION cmsCreateInkLimitingDeviceLinkTHR(ContextID: cmsContext; - ColorSpace: cmsColorSpaceSignature; Limit: cmsFloat64Number): cmsHPROFILE; StdCall; external 'lcms2.dll'; + ColorSpace: cmsColorSpaceSignature; Limit: cmsFloat64Number): cmsHPROFILE; StdCall; external LCMS2_SO; -FUNCTION cmsCreateInkLimitingDeviceLink(ColorSpace: cmsColorSpaceSignature; Limit: cmsFloat64Number): cmsHPROFILE; StdCall; external 'lcms2.dll'; +FUNCTION cmsCreateInkLimitingDeviceLink(ColorSpace: cmsColorSpaceSignature; Limit: cmsFloat64Number): cmsHPROFILE; StdCall; external LCMS2_SO; -FUNCTION cmsCreateLab2ProfileTHR(ContextID: cmsContext; WhitePoint: LPcmsCIExyY): cmsHPROFILE; StdCall; external 'lcms2.dll'; -FUNCTION cmsCreateLab2Profile(WhitePoint: LPcmsCIExyY): cmsHPROFILE; StdCall; external 'lcms2.dll'; -FUNCTION cmsCreateLab4ProfileTHR(ContextID: cmsContext; WhitePoint: LPcmsCIExyY): cmsHPROFILE; StdCall; external 'lcms2.dll'; -FUNCTION cmsCreateLab4Profile(WhitePoint: LPcmsCIExyY): cmsHPROFILE; StdCall; external 'lcms2.dll'; +FUNCTION cmsCreateLab2ProfileTHR(ContextID: cmsContext; WhitePoint: LPcmsCIExyY): cmsHPROFILE; StdCall; external LCMS2_SO; +FUNCTION cmsCreateLab2Profile(WhitePoint: LPcmsCIExyY): cmsHPROFILE; StdCall; external LCMS2_SO; +FUNCTION cmsCreateLab4ProfileTHR(ContextID: cmsContext; WhitePoint: LPcmsCIExyY): cmsHPROFILE; StdCall; external LCMS2_SO; +FUNCTION cmsCreateLab4Profile(WhitePoint: LPcmsCIExyY): cmsHPROFILE; StdCall; external LCMS2_SO; -FUNCTION cmsCreateXYZProfileTHR(ContextID: cmsContext): cmsHPROFILE; StdCall; external 'lcms2.dll'; -FUNCTION cmsCreateXYZProfile: cmsHPROFILE; StdCall; external 'lcms2.dll'; +FUNCTION cmsCreateXYZProfileTHR(ContextID: cmsContext): cmsHPROFILE; StdCall; external LCMS2_SO; +FUNCTION cmsCreateXYZProfile: cmsHPROFILE; StdCall; external LCMS2_SO; -FUNCTION cmsCreate_sRGBProfileTHR(ContextID: cmsContext): cmsHPROFILE; StdCall; external 'lcms2.dll'; -FUNCTION cmsCreate_sRGBProfile: cmsHPROFILE; StdCall; external 'lcms2.dll'; +FUNCTION cmsCreate_sRGBProfileTHR(ContextID: cmsContext): cmsHPROFILE; StdCall; external LCMS2_SO; +FUNCTION cmsCreate_sRGBProfile: cmsHPROFILE; StdCall; external LCMS2_SO; FUNCTION cmsCreateBCHSWabstractProfileTHR(ContextID: cmsContext; nLUTPoints: Integer; @@ -1920,7 +1965,7 @@ FUNCTION cmsCreateBCHSWabstractProfileTHR(ContextID: cmsContext; Hue, Saturation: cmsFloat64Number; TempSrc, - TempDest: Integer): cmsHPROFILE; StdCall; external 'lcms2.dll'; + TempDest: Integer): cmsHPROFILE; StdCall; external LCMS2_SO; FUNCTION cmsCreateBCHSWabstractProfile( nLUTPoints: Integer; Bright, @@ -1928,16 +1973,16 @@ FUNCTION cmsCreateBCHSWabstractProfile( nLUTPoints: Integer; Hue, Saturation: cmsFloat64Number; TempSrc, - TempDest: Integer): cmsHPROFILE; StdCall; external 'lcms2.dll'; + TempDest: Integer): cmsHPROFILE; StdCall; external LCMS2_SO; -FUNCTION cmsCreateNULLProfileTHR(ContextID: cmsContext): cmsHPROFILE; StdCall; external 'lcms2.dll'; -FUNCTION cmsCreateNULLProfile: cmsHPROFILE; StdCall; external 'lcms2.dll'; +FUNCTION cmsCreateNULLProfileTHR(ContextID: cmsContext): cmsHPROFILE; StdCall; external LCMS2_SO; +FUNCTION cmsCreateNULLProfile: cmsHPROFILE; StdCall; external LCMS2_SO; // Converts a transform to a devicelink profile -FUNCTION cmsTransform2DeviceLink(hTransform: cmsHTRANSFORM; Version: cmsFloat64Number; dwFlags: cmsUInt32Number): cmsHPROFILE; StdCall; external 'lcms2.dll'; +FUNCTION cmsTransform2DeviceLink(hTransform: cmsHTRANSFORM; Version: cmsFloat64Number; dwFlags: cmsUInt32Number): cmsHPROFILE; StdCall; external LCMS2_SO; // Call with NULL as parameters to get the intent count -FUNCTION cmsGetSupportedIntents(nMax: cmsUInt32Number; Codes: LPcmsUInt32Number; Descriptions: LPPAnsiChar): cmsUInt32Number; StdCall; external 'lcms2.dll'; +FUNCTION cmsGetSupportedIntents(nMax: cmsUInt32Number; Codes: LPcmsUInt32Number; Descriptions: LPPAnsiChar): cmsUInt32Number; StdCall; external LCMS2_SO; FUNCTION cmsFLAGS_GRIDPOINTS(n: Integer): Integer; begin cmsFLAGS_GRIDPOINTS := (((n) and $FF) shl 16) end; @@ -1948,14 +1993,14 @@ FUNCTION cmsCreateTransformTHR(ContextID: cmsContext; Output: cmsHPROFILE; OutputFormat: cmsUInt32Number; Intent: cmsUInt32Number; - dwFlags: cmsUInt32Number): cmsHTRANSFORM; StdCall; external 'lcms2.dll'; + dwFlags: cmsUInt32Number): cmsHTRANSFORM; StdCall; external LCMS2_SO; FUNCTION cmsCreateTransform(Input: cmsHPROFILE; InputFormat: cmsUInt32Number; Output: cmsHPROFILE; OutputFormat: cmsUInt32Number; Intent: cmsUInt32Number; - dwFlags: cmsUInt32Number): cmsHTRANSFORM; StdCall; external 'lcms2.dll'; + dwFlags: cmsUInt32Number): cmsHTRANSFORM; StdCall; external LCMS2_SO; FUNCTION cmsCreateProofingTransformTHR(ContextID: cmsContext; Input: cmsHPROFILE; @@ -1965,7 +2010,7 @@ FUNCTION cmsCreateProofingTransformTHR(ContextID: cmsContext; Proofing: cmsHPROFILE; Intent: cmsUInt32Number; ProofingIntent: cmsUInt32Number; - dwFlags: cmsUInt32Number): cmsHTRANSFORM; StdCall; external 'lcms2.dll'; + dwFlags: cmsUInt32Number): cmsHTRANSFORM; StdCall; external LCMS2_SO; FUNCTION cmsCreateProofingTransform(Input: cmsHPROFILE; InputFormat: cmsUInt32Number; @@ -1974,7 +2019,7 @@ FUNCTION cmsCreateProofingTransform(Input: cmsHPROFILE; Proofing: cmsHPROFILE; Intent: cmsUInt32Number; ProofingIntent: cmsUInt32Number; - dwFlags: cmsUInt32Number): cmsHTRANSFORM; StdCall; external 'lcms2.dll'; + dwFlags: cmsUInt32Number): cmsHTRANSFORM; StdCall; external LCMS2_SO; FUNCTION cmsCreateMultiprofileTransformTHR(ContextID: cmsContext; hProfiles: LPcmsHPROFILEArray; @@ -1982,7 +2027,7 @@ FUNCTION cmsCreateMultiprofileTransformTHR(ContextID: cmsContext; InputFormat: cmsUInt32Number; OutputFormat: cmsUInt32Number; Intent: cmsUInt32Number; - dwFlags: cmsUInt32Number): cmsHTRANSFORM; StdCall; external 'lcms2.dll'; + dwFlags: cmsUInt32Number): cmsHTRANSFORM; StdCall; external LCMS2_SO; FUNCTION cmsCreateMultiprofileTransform( hProfiles: LPcmsHPROFILEArray; @@ -1990,7 +2035,7 @@ FUNCTION cmsCreateMultiprofileTransform( hProfiles: LPcmsHPROFILEArray; InputFormat: cmsUInt32Number; OutputFormat: cmsUInt32Number; Intent: cmsUInt32Number; - dwFlags: cmsUInt32Number): cmsHTRANSFORM; StdCall; external 'lcms2.dll'; + dwFlags: cmsUInt32Number): cmsHTRANSFORM; StdCall; external LCMS2_SO; FUNCTION cmsCreateExtendedTransform(ContextID: cmsContext; @@ -2003,23 +2048,23 @@ FUNCTION cmsCreateExtendedTransform(ContextID: cmsContext; nGamutPCSposition: cmsUInt32Number; InputFormat, OutputFormat: cmsUInt32Number; - dwFlags: cmsUInt32Number): cmsHTRANSFORM; StdCall; external 'lcms2.dll'; - -PROCEDURE cmsDeleteTransform(hTransform: cmsHTRANSFORM); StdCall; external 'lcms2.dll'; + dwFlags: cmsUInt32Number): cmsHTRANSFORM; StdCall; external LCMS2_SO; -PROCEDURE cmsDoTransform(Transform: cmsHTRANSFORM; InputBuffer, OutputBuffer: Pointer; size: cmsUInt32Number); StdCall; external 'lcms2.dll'; +PROCEDURE cmsDeleteTransform(hTransform: cmsHTRANSFORM); StdCall; external LCMS2_SO; -PROCEDURE cmsSetAlarmCodes( NewAlarm: LPcmsUInt16NumberArray); StdCall; external 'lcms2.dll'; -PROCEDURE cmsGetAlarmCodes(NewAlarm: LPcmsUInt16NumberArray); StdCall; external 'lcms2.dll'; +PROCEDURE cmsDoTransform(Transform: cmsHTRANSFORM; InputBuffer, OutputBuffer: Pointer; size: cmsUInt32Number); StdCall; external LCMS2_SO; +PROCEDURE cmsDoTransformStride(Transform: cmsHTRANSFORM; InputBuffer, OutputBuffer: Pointer; size: cmsUInt32Number; stride: cmsUInt32Number); StdCall; external LCMS2_SO; +PROCEDURE cmsSetAlarmCodes( NewAlarm: LPcmsUInt16NumberArray); StdCall; external LCMS2_SO; +PROCEDURE cmsGetAlarmCodes(NewAlarm: LPcmsUInt16NumberArray); StdCall; external LCMS2_SO; // Adaptation state for absolute colorimetric intent -FUNCTION cmsSetAdaptationState(d: cmsFloat64Number):cmsFloat64Number; StdCall; external 'lcms2.dll'; +FUNCTION cmsSetAdaptationState(d: cmsFloat64Number):cmsFloat64Number; StdCall; external LCMS2_SO; // Grab the ContextID from an open transform. Returns NULL if a NULL transform is passed -FUNCTION cmsGetTransformContextID(hTransform: cmsHTRANSFORM):cmsContext; StdCall; external 'lcms2.dll'; +FUNCTION cmsGetTransformContextID(hTransform: cmsHTRANSFORM):cmsContext; StdCall; external LCMS2_SO; // For backwards compatibility -FUNCTION cmsChangeBuffersFormat(hTransform: cmsHTRANSFORM; InputFormat, OutputFormat: cmsUInt32Number): cmsBool; StdCall; external 'lcms2.dll'; +FUNCTION cmsChangeBuffersFormat(hTransform: cmsHTRANSFORM; InputFormat, OutputFormat: cmsUInt32Number): cmsBool; StdCall; external LCMS2_SO; // lcms2 unified method to access postscript color resources @@ -2027,85 +2072,85 @@ FUNCTION cmsGetPostScriptColorResource(ContextID: cmsContext; RType: cmsPSReso hProfile: cmsHPROFILE; Intent: cmsUInt32Number; dwFlags: cmsUInt32Number; - io: LPcmsIOHANDLER): cmsUInt32Number; StdCall; external 'lcms2.dll'; + io: LPcmsIOHANDLER): cmsUInt32Number; StdCall; external LCMS2_SO; -FUNCTION cmsGetPostScriptCSA(ContextID: cmsContext; hProfile: cmsHPROFILE; Intent: cmsUInt32Number; dwFlags: cmsUInt32Number; Buffer: Pointer; dwBufferLen: cmsUInt32Number ): cmsUInt32Number; StdCall; external 'lcms2.dll'; -FUNCTION cmsGetPostScriptCRD(ContextID: cmsContext; hProfile: cmsHPROFILE; Intent: cmsUInt32Number; dwFlags: cmsUInt32Number; Buffer: Pointer; dwBufferLen: cmsUInt32Number): cmsUInt32Number; StdCall; external 'lcms2.dll'; +FUNCTION cmsGetPostScriptCSA(ContextID: cmsContext; hProfile: cmsHPROFILE; Intent: cmsUInt32Number; dwFlags: cmsUInt32Number; Buffer: Pointer; dwBufferLen: cmsUInt32Number ): cmsUInt32Number; StdCall; external LCMS2_SO; +FUNCTION cmsGetPostScriptCRD(ContextID: cmsContext; hProfile: cmsHPROFILE; Intent: cmsUInt32Number; dwFlags: cmsUInt32Number; Buffer: Pointer; dwBufferLen: cmsUInt32Number): cmsUInt32Number; StdCall; external LCMS2_SO; // CGATS.13 parser -FUNCTION cmsIT8Alloc: cmsHANDLE; StdCall; external 'lcms2.dll'; -PROCEDURE cmsIT8Free(hIT8: cmsHANDLE); StdCall; external 'lcms2.dll'; +FUNCTION cmsIT8Alloc: cmsHANDLE; StdCall; external LCMS2_SO; +PROCEDURE cmsIT8Free(hIT8: cmsHANDLE); StdCall; external LCMS2_SO; // Tables -FUNCTION cmsIT8TableCount(hIT8: cmsHANDLE): Integer; StdCall; external 'lcms2.dll'; -FUNCTION cmsIT8SetTable(hIT8: cmsHANDLE; nTable: Integer): Integer; StdCall; external 'lcms2.dll'; +FUNCTION cmsIT8TableCount(hIT8: cmsHANDLE): Integer; StdCall; external LCMS2_SO; +FUNCTION cmsIT8SetTable(hIT8: cmsHANDLE; nTable: Integer): Integer; StdCall; external LCMS2_SO; // Persistence -FUNCTION cmsIT8LoadFromFile(cFileName: PAnsiChar): cmsHANDLE; StdCall; external 'lcms2.dll'; -FUNCTION cmsIT8LoadFromMem(Ptr: Pointer; size :DWord): cmsHANDLE; StdCall; external 'lcms2.dll'; +FUNCTION cmsIT8LoadFromFile(cFileName: PAnsiChar): cmsHANDLE; StdCall; external LCMS2_SO; +FUNCTION cmsIT8LoadFromMem(Ptr: Pointer; size :DWord): cmsHANDLE; StdCall; external LCMS2_SO; -FUNCTION cmsIT8SaveToFile(hIT8: cmsHANDLE; cFileName: PAnsiChar): cmsBool; StdCall; external 'lcms2.dll'; -FUNCTION cmsIT8SaveToMem(hIT8: cmsHANDLE; MemPtr: Pointer; BytesNeeded: LPcmsUInt32Number): cmsBool; StdCall; external 'lcms2.dll'; +FUNCTION cmsIT8SaveToFile(hIT8: cmsHANDLE; cFileName: PAnsiChar): cmsBool; StdCall; external LCMS2_SO; +FUNCTION cmsIT8SaveToMem(hIT8: cmsHANDLE; MemPtr: Pointer; BytesNeeded: LPcmsUInt32Number): cmsBool; StdCall; external LCMS2_SO; // Properties -FUNCTION cmsIT8GetSheetType(hIT8: cmsHANDLE): PAnsiChar; StdCall; external 'lcms2.dll'; -FUNCTION cmsIT8SetSheetType(hIT8: cmsHANDLE; TheType: PAnsiChar): cmsBool; StdCall; external 'lcms2.dll'; +FUNCTION cmsIT8GetSheetType(hIT8: cmsHANDLE): PAnsiChar; StdCall; external LCMS2_SO; +FUNCTION cmsIT8SetSheetType(hIT8: cmsHANDLE; TheType: PAnsiChar): cmsBool; StdCall; external LCMS2_SO; -FUNCTION cmsIT8SetComment(hIT8: cmsHANDLE; cComment: PAnsiChar): cmsBool; StdCall; external 'lcms2.dll'; +FUNCTION cmsIT8SetComment(hIT8: cmsHANDLE; cComment: PAnsiChar): cmsBool; StdCall; external LCMS2_SO; -FUNCTION cmsIT8SetPropertyStr(hIT8: cmsHANDLE; cProp, Str: PAnsiChar): cmsBool; StdCall; external 'lcms2.dll'; -FUNCTION cmsIT8SetPropertyDbl(hIT8: cmsHANDLE; cProp: PAnsiChar; Val: Double): cmsBool; StdCall; external 'lcms2.dll'; -FUNCTION cmsIT8SetPropertyHex(hIT8: cmsHANDLE; cProp: PAnsiChar; Val: Integer): cmsBool; StdCall; external 'lcms2.dll'; -FUNCTION cmsIT8SetPropertyUncooked(hIT8: cmsHANDLE; Key, Buffer: PAnsiChar): cmsBool; StdCall; external 'lcms2.dll'; +FUNCTION cmsIT8SetPropertyStr(hIT8: cmsHANDLE; cProp, Str: PAnsiChar): cmsBool; StdCall; external LCMS2_SO; +FUNCTION cmsIT8SetPropertyDbl(hIT8: cmsHANDLE; cProp: PAnsiChar; Val: Double): cmsBool; StdCall; external LCMS2_SO; +FUNCTION cmsIT8SetPropertyHex(hIT8: cmsHANDLE; cProp: PAnsiChar; Val: Integer): cmsBool; StdCall; external LCMS2_SO; +FUNCTION cmsIT8SetPropertyUncooked(hIT8: cmsHANDLE; Key, Buffer: PAnsiChar): cmsBool; StdCall; external LCMS2_SO; -FUNCTION cmsIT8GetProperty(hIT8: cmsHANDLE; cProp: PAnsiChar): PAnsiChar; StdCall; external 'lcms2.dll'; -FUNCTION cmsIT8GetPropertyDbl(hIT8: cmsHANDLE; cProp: PAnsiChar): Double; StdCall; external 'lcms2.dll'; -FUNCTION cmsIT8EnumProperties(hIT8: cmsHANDLE; var PropertyNames: LPPAnsiChar): Integer; StdCall; external 'lcms2.dll'; +FUNCTION cmsIT8GetProperty(hIT8: cmsHANDLE; cProp: PAnsiChar): PAnsiChar; StdCall; external LCMS2_SO; +FUNCTION cmsIT8GetPropertyDbl(hIT8: cmsHANDLE; cProp: PAnsiChar): Double; StdCall; external LCMS2_SO; +FUNCTION cmsIT8EnumProperties(hIT8: cmsHANDLE; var PropertyNames: LPPAnsiChar): Integer; StdCall; external LCMS2_SO; // Datasets -FUNCTION cmsIT8GetDataRowCol(hIT8: cmsHANDLE; row, col: Integer): PAnsiChar; StdCall; external 'lcms2.dll'; -FUNCTION cmsIT8GetDataRowColDbl(hIT8: cmsHANDLE; row, col: Integer): Double; StdCall; external 'lcms2.dll'; +FUNCTION cmsIT8GetDataRowCol(hIT8: cmsHANDLE; row, col: Integer): PAnsiChar; StdCall; external LCMS2_SO; +FUNCTION cmsIT8GetDataRowColDbl(hIT8: cmsHANDLE; row, col: Integer): Double; StdCall; external LCMS2_SO; -FUNCTION cmsIT8SetDataRowCol(hIT8: cmsHANDLE; row, col: Integer; Val: PAnsiChar): cmsBool; StdCall; external 'lcms2.dll'; -FUNCTION cmsIT8SetDataRowColDbl(hIT8: cmsHANDLE; row, col: Integer; Val: Double): cmsBool; StdCall; external 'lcms2.dll'; +FUNCTION cmsIT8SetDataRowCol(hIT8: cmsHANDLE; row, col: Integer; Val: PAnsiChar): cmsBool; StdCall; external LCMS2_SO; +FUNCTION cmsIT8SetDataRowColDbl(hIT8: cmsHANDLE; row, col: Integer; Val: Double): cmsBool; StdCall; external LCMS2_SO; -FUNCTION cmsIT8GetData(hIT8: cmsHANDLE; cPatch, cSample: PAnsiChar): PAnsiChar; StdCall; external 'lcms2.dll'; +FUNCTION cmsIT8GetData(hIT8: cmsHANDLE; cPatch, cSample: PAnsiChar): PAnsiChar; StdCall; external LCMS2_SO; -FUNCTION cmsIT8GetDataDbl(hIT8: cmsHANDLE;cPatch, cSample: PAnsiChar): Double; StdCall; external 'lcms2.dll'; +FUNCTION cmsIT8GetDataDbl(hIT8: cmsHANDLE;cPatch, cSample: PAnsiChar): Double; StdCall; external LCMS2_SO; -FUNCTION cmsIT8SetData(hIT8: cmsHANDLE; cPatch, cSample, Val: PAnsiChar): cmsBool; StdCall; external 'lcms2.dll'; +FUNCTION cmsIT8SetData(hIT8: cmsHANDLE; cPatch, cSample, Val: PAnsiChar): cmsBool; StdCall; external LCMS2_SO; -FUNCTION cmsIT8SetDataDbl(hIT8: cmsHANDLE; cPatch, cSample: PAnsiChar; Val: Double): cmsBool; StdCall; external 'lcms2.dll'; +FUNCTION cmsIT8SetDataDbl(hIT8: cmsHANDLE; cPatch, cSample: PAnsiChar; Val: Double): cmsBool; StdCall; external LCMS2_SO; -FUNCTION cmsIT8SetDataFormat(hIT8: cmsHANDLE; n: Integer; Sample: PAnsiChar): cmsBool; StdCall; external 'lcms2.dll'; -FUNCTION cmsIT8EnumDataFormat(hIT8: cmsHANDLE; var SampleNames: LPPAnsiChar): Integer; StdCall; external 'lcms2.dll'; -FUNCTION cmsIT8GetPatchName(hIT8: cmsHANDLE; nPatch: Integer; Buffer: PAnsiChar): PAnsiChar; StdCall; external 'lcms2.dll'; +FUNCTION cmsIT8SetDataFormat(hIT8: cmsHANDLE; n: Integer; Sample: PAnsiChar): cmsBool; StdCall; external LCMS2_SO; +FUNCTION cmsIT8EnumDataFormat(hIT8: cmsHANDLE; var SampleNames: LPPAnsiChar): Integer; StdCall; external LCMS2_SO; +FUNCTION cmsIT8GetPatchName(hIT8: cmsHANDLE; nPatch: Integer; Buffer: PAnsiChar): PAnsiChar; StdCall; external LCMS2_SO; // The LABEL extension -FUNCTION cmsIT8SetTableByLabel(hIT8: cmsHANDLE; cSet, cField, ExpectedType: PAnsiChar): Integer; StdCall; external 'lcms2.dll'; +FUNCTION cmsIT8SetTableByLabel(hIT8: cmsHANDLE; cSet, cField, ExpectedType: PAnsiChar): Integer; StdCall; external LCMS2_SO; -FUNCTION cmsIT8FindDataFormat(hIT8: cmsHANDLE; cSample: PAnsiChar): Integer; StdCall; external 'lcms2.dll'; +FUNCTION cmsIT8FindDataFormat(hIT8: cmsHANDLE; cSample: PAnsiChar): Integer; StdCall; external LCMS2_SO; // Formatter for double -PROCEDURE cmsIT8DefineDblFormat(hIT8: cmsHANDLE; Formatter: PAnsiChar); StdCall; external 'lcms2.dll'; +PROCEDURE cmsIT8DefineDblFormat(hIT8: cmsHANDLE; Formatter: PAnsiChar); StdCall; external LCMS2_SO; + +FUNCTION cmsGBDAlloc(ContextID: cmsContext):cmsHANDLE; StdCall; external LCMS2_SO; +PROCEDURE cmsGBDFree(hGBD: cmsHANDLE); StdCall; external LCMS2_SO; +FUNCTION cmsGDBAddPoint(hGBD: cmsHANDLE; Lab: LPcmsCIELab): cmsBool; StdCall; external LCMS2_SO; +FUNCTION cmsGDBCompute(hGDB: cmsHANDLE; dwFlags: cmsUInt32Number): cmsBool; StdCall; external LCMS2_SO; +FUNCTION cmsGDBCheckPoint(hGBD: cmsHANDLE; Lab: LPcmsCIELab): cmsBool; StdCall; external LCMS2_SO; -FUNCTION cmsGBDAlloc(ContextID: cmsContext):cmsHANDLE; StdCall; external 'lcms2.dll'; -PROCEDURE cmsGBDFree(hGBD: cmsHANDLE); StdCall; external 'lcms2.dll'; -FUNCTION cmsGDBAddPoint(hGBD: cmsHANDLE; Lab: LPcmsCIELab): cmsBool; StdCall; external 'lcms2.dll'; -FUNCTION cmsGDBCompute(hGDB: cmsHANDLE; dwFlags: cmsUInt32Number): cmsBool; StdCall; external 'lcms2.dll'; -FUNCTION cmsGDBCheckPoint(hGBD: cmsHANDLE; Lab: LPcmsCIELab): cmsBool; StdCall; external 'lcms2.dll'; +FUNCTION cmsDetectBlackPoint( BlackPoint: LPcmsCIEXYZ; hProfile: cmsHPROFILE; Intent: cmsUInt32Number; dwFlags: cmsUInt32Number): cmsBool; StdCall; external LCMS2_SO; +FUNCTION cmsDetectDestinationBlackPoint( BlackPoint: LPcmsCIEXYZ; hProfile: cmsHPROFILE; Intent: cmsUInt32Number; dwFlags: cmsUInt32Number): cmsBool; StdCall; external LCMS2_SO; -FUNCTION cmsDetectBlackPoint( BlackPoint: LPcmsCIEXYZ; hProfile: cmsHPROFILE; Intent: cmsUInt32Number; dwFlags: cmsUInt32Number): cmsBool; StdCall; external 'lcms2.dll'; -FUNCTION cmsDetectDestinationBlackPoint( BlackPoint: LPcmsCIEXYZ; hProfile: cmsHPROFILE; Intent: cmsUInt32Number; dwFlags: cmsUInt32Number): cmsBool; StdCall; external 'lcms2.dll'; +FUNCTION cmsDetectTAC(hProfile: cmsHPROFILE): cmsFloat64Number; StdCall; external LCMS2_SO; -FUNCTION cmsDetectTAC(hProfile: cmsHPROFILE): cmsFloat64Number; StdCall; external 'lcms2.dll'; +FUNCTION cmsDesaturateLab(Lab: LPcmsCIELab; amax, amin, bmax, bmin: cmsFloat64Number): cmsBool; StdCall; external LCMS2_SO; -FUNCTION cmsDesaturateLab(Lab: LPcmsCIELab; amax, amin, bmax, bmin: cmsFloat64Number): cmsBool; StdCall; external 'lcms2.dll'; - END. diff --git a/utils/jpgicc/jpgicc.c b/utils/jpgicc/jpgicc.c index 3b18b54..e129a77 100644 --- a/utils/jpgicc/jpgicc.c +++ b/utils/jpgicc/jpgicc.c @@ -72,13 +72,6 @@ static struct my_error_mgr { cmsUInt16Number Alarm[4] = {128,128,128,0}; -// Out of mem -static -void OutOfMem(size_t size) -{ - FatalError("Out of memory on allocating %d bytes.", size); -} - static void my_error_exit (j_common_ptr cinfo) @@ -840,7 +833,7 @@ void DoEmbedProfile(const char* ProfileFile) fclose(f); EmbedBuffer[EmbedLen] = 0; - write_icc_profile (&Compressor, EmbedBuffer, EmbedLen); + write_icc_profile (&Compressor, EmbedBuffer, (unsigned int) EmbedLen); free(EmbedBuffer); } diff --git a/utils/psicc/psicc.c b/utils/psicc/psicc.c index 1c3fe6c..9d6a280 100644 --- a/utils/psicc/psicc.c +++ b/utils/psicc/psicc.c @@ -185,7 +185,7 @@ void GenerateCRD(void) if (n == 0) return; Buffer = (char*) malloc(n + 1); - cmsGetPostScriptCRD(0, hProfile, Intent, dwFlags, Buffer, n); + cmsGetPostScriptCRD(0, hProfile, Intent, dwFlags, Buffer, (cmsUInt32Number) n); Buffer[n] = 0; fprintf(OutFile, "%s", Buffer); diff --git a/utils/tificc/tificc.c b/utils/tificc/tificc.c index 76fb15a..5101932 100644 --- a/utils/tificc/tificc.c +++ b/utils/tificc/tificc.c @@ -670,7 +670,7 @@ void DoEmbedProfile(TIFF* Out, const char* ProfileFile) return; } - EmbedLen = fread(EmbedBuffer, 1, size, f); + EmbedLen = (cmsUInt32Number) fread(EmbedBuffer, 1, (size_t) size, f); if (EmbedLen != size) FatalError("Cannot read %ld bytes to %s", size, ProfileFile); diff --git a/utils/transicc/transicc.1 b/utils/transicc/transicc.1 index d99eb25..eb52ac9 100644 --- a/utils/transicc/transicc.1 +++ b/utils/transicc/transicc.1 @@ -1,5 +1,5 @@ .\"Shiju P. Nair September 30, 2004 -.TH ICCTRANS 1 "September 30, 2004" +.TH TRANSICC 1 "MAY 30, 2011" .SH NAME icctrans - little cms ColorSpace conversion calculator. .SH SYNOPSIS |