From 0bd847232a1f430c70dd9d8df177ce68a3cde010 Mon Sep 17 00:00:00 2001 From: Nicolas Pena Date: Mon, 14 Aug 2017 10:36:01 -0400 Subject: LCMS: upgrade to 2.8 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This CL upgrades LCMS from version 2.6 to 2.8. All changes from LCMS original version 2.8 are stored in patch files: - Patch 0: memory management modifications to use PDFium methods. This was previously not in any patch, so the changes were manually applied. - Patches 1-5: new patch files corresponding to old changes that can be seen in the history, but did not previously have patch files. - Patches 6-25: previous patches (patch numbers shifted by 6). The one for from16-to-8-overflow.patch was deleted as it was already upstream. Some patches did not apply cleanly so their .patch files were modified. - Patch 26: as I just moved files directly, unsupported characters were moved in unchanged, so I had to fix all of them: e with tilde and other characters were replaced to allow compilation on Windows. - Patch 27: Went over the code and re-applied changes that included comments clearly indicating this was Foxit. These changes are all already seen in the initial PDFium commit. Change-Id: Ic1d84e54803ef9e6b280ef7619bbf0b757312fbf Reviewed-on: https://pdfium-review.googlesource.com/10590 Commit-Queue: Nicolás Peña Reviewed-by: dsinclair --- DEPS | 2 +- third_party/BUILD.gn | 1 + third_party/lcms/0000-cmserr-changes.patch | 285 +++++ third_party/lcms/0000-tag-type-confusion.patch | 14 - third_party/lcms/0001-fix-include.patch | 13 + third_party/lcms/0001-from16-to-8-overflow.patch | 13 - .../0002-infinite-loop-GrowNamedColorList.patch | 34 - third_party/lcms/0002-old-performance-fix.patch | 13 + .../0003-old-uninitialized-in-LUTevalFloat.patch | 13 + third_party/lcms/0003-uninit.patch | 30 - .../lcms/0004-memory-leak-Type_Curve_Read.patch | 28 - .../lcms/0004-old-uninitialized-in-LUTeval16.patch | 13 + .../0005-memory-leak-AllocEmptyTransform.patch | 34 - third_party/lcms/0005-old-fix-e-with-tilde.patch | 61 + .../0006-memory-leak-Type_NamedColor_Read.patch | 22 - third_party/lcms/0006-tag-type-confusion.patch | 14 + .../0007-memory-leak-OptimizeByResampling.patch | 13 - .../0008-infinite-loop-GrowNamedColorList.patch | 28 + .../0008-memory-leak-Type_MPEmatrix_Read.patch | 30 - .../lcms/0009-cmsStageAllocMatrix-param-swap.patch | 20 - third_party/lcms/0009-uninit.patch | 23 + .../lcms/0010-memory-leak-Type_Curve_Read.patch | 28 + third_party/lcms/0010-reject-nan.patch | 13 - .../0011-memory-leak-AllocEmptyTransform.patch | 34 + .../lcms/0011-memory-leak-ReadSegmentedCurve.patch | 36 - third_party/lcms/0012-backport-c0a98d86.patch | 53 - .../0012-memory-leak-Type_NamedColor_Read.patch | 22 + .../0013-memory-leak-OptimizeByResampling.patch | 13 + third_party/lcms/0013-utf8.patch | 99 -- third_party/lcms/0014-avoid-fixed-inf.patch | 95 -- .../0014-memory-leak-Type_MPEmatrix_Read.patch | 30 + .../lcms/0015-cmsStageAllocMatrix-param-swap.patch | 20 + third_party/lcms/0015-sanitize-float-read.patch | 15 - third_party/lcms/0016-check-LUT-and-MPE.patch | 170 --- third_party/lcms/0016-reject-nan.patch | 13 + .../lcms/0017-memory-leak-ReadSegmentedCurve.patch | 36 + ...-upstream-integer-overflow-MPEmatrix_Read.patch | 85 -- third_party/lcms/0018-backport-c0a98d86.patch | 53 + .../lcms/0018-verify-size-before-reading.patch | 17 - .../0019-upstream-direct-leak-Type_MPE_Read.patch | 31 - third_party/lcms/0019-utf8.patch | 98 ++ third_party/lcms/0020-avoid-fixed-inf.patch | 95 ++ third_party/lcms/0021-sanitize-float-read.patch | 15 + third_party/lcms/0022-check-LUT-and-MPE.patch | 170 +++ ...-upstream-integer-overflow-MPEmatrix_Read.patch | 85 ++ .../lcms/0024-verify-size-before-reading.patch | 17 + .../0025-upstream-direct-leak-Type_MPE_Read.patch | 31 + .../lcms/0026-more-unsupported-characters.patch | 73 ++ .../lcms/0027-changes-from-beginning-of-time.patch | 152 +++ third_party/lcms/README.pdfium | 50 +- third_party/lcms/include/lcms2.h | 113 +- third_party/lcms/include/lcms2_plugin.h | 42 +- third_party/lcms/src/cmsalpha.c | 518 +++++++++ third_party/lcms/src/cmscam02.c | 2 +- third_party/lcms/src/cmscgats.c | 43 +- third_party/lcms/src/cmscnvrt.c | 33 +- third_party/lcms/src/cmserr.c | 318 ++---- third_party/lcms/src/cmsgamma.c | 55 +- third_party/lcms/src/cmsgmt.c | 1180 ++++++++++---------- third_party/lcms/src/cmshalf.c | 5 +- third_party/lcms/src/cmsintrp.c | 8 +- third_party/lcms/src/cmsio0.c | 117 +- third_party/lcms/src/cmsio1.c | 75 +- third_party/lcms/src/cmslut.c | 33 +- third_party/lcms/src/cmsmd5.c | 30 +- third_party/lcms/src/cmsmtrx.c | 5 +- third_party/lcms/src/cmsnamed.c | 81 +- third_party/lcms/src/cmsopt.c | 273 +++-- third_party/lcms/src/cmspack.c | 341 +++--- third_party/lcms/src/cmspcs.c | 17 +- third_party/lcms/src/cmsplugin.c | 57 +- third_party/lcms/src/cmsps2.c | 17 +- third_party/lcms/src/cmssamp.c | 29 +- third_party/lcms/src/cmssm.c | 12 +- third_party/lcms/src/cmstypes.c | 90 +- third_party/lcms/src/cmsvirt.c | 50 +- third_party/lcms/src/cmswtpnt.c | 4 +- third_party/lcms/src/cmsxform.c | 518 ++++++--- third_party/lcms/src/lcms2_internal.h | 63 +- 79 files changed, 3966 insertions(+), 2516 deletions(-) create mode 100644 third_party/lcms/0000-cmserr-changes.patch delete mode 100644 third_party/lcms/0000-tag-type-confusion.patch create mode 100644 third_party/lcms/0001-fix-include.patch delete mode 100644 third_party/lcms/0001-from16-to-8-overflow.patch delete mode 100644 third_party/lcms/0002-infinite-loop-GrowNamedColorList.patch create mode 100644 third_party/lcms/0002-old-performance-fix.patch create mode 100644 third_party/lcms/0003-old-uninitialized-in-LUTevalFloat.patch delete mode 100644 third_party/lcms/0003-uninit.patch delete mode 100644 third_party/lcms/0004-memory-leak-Type_Curve_Read.patch create mode 100644 third_party/lcms/0004-old-uninitialized-in-LUTeval16.patch delete mode 100644 third_party/lcms/0005-memory-leak-AllocEmptyTransform.patch create mode 100644 third_party/lcms/0005-old-fix-e-with-tilde.patch delete mode 100644 third_party/lcms/0006-memory-leak-Type_NamedColor_Read.patch create mode 100644 third_party/lcms/0006-tag-type-confusion.patch delete mode 100644 third_party/lcms/0007-memory-leak-OptimizeByResampling.patch create mode 100644 third_party/lcms/0008-infinite-loop-GrowNamedColorList.patch delete mode 100644 third_party/lcms/0008-memory-leak-Type_MPEmatrix_Read.patch delete mode 100644 third_party/lcms/0009-cmsStageAllocMatrix-param-swap.patch create mode 100644 third_party/lcms/0009-uninit.patch create mode 100644 third_party/lcms/0010-memory-leak-Type_Curve_Read.patch delete mode 100644 third_party/lcms/0010-reject-nan.patch create mode 100644 third_party/lcms/0011-memory-leak-AllocEmptyTransform.patch delete mode 100644 third_party/lcms/0011-memory-leak-ReadSegmentedCurve.patch delete mode 100644 third_party/lcms/0012-backport-c0a98d86.patch create mode 100644 third_party/lcms/0012-memory-leak-Type_NamedColor_Read.patch create mode 100644 third_party/lcms/0013-memory-leak-OptimizeByResampling.patch delete mode 100644 third_party/lcms/0013-utf8.patch delete mode 100644 third_party/lcms/0014-avoid-fixed-inf.patch create mode 100644 third_party/lcms/0014-memory-leak-Type_MPEmatrix_Read.patch create mode 100644 third_party/lcms/0015-cmsStageAllocMatrix-param-swap.patch delete mode 100644 third_party/lcms/0015-sanitize-float-read.patch delete mode 100644 third_party/lcms/0016-check-LUT-and-MPE.patch create mode 100644 third_party/lcms/0016-reject-nan.patch create mode 100644 third_party/lcms/0017-memory-leak-ReadSegmentedCurve.patch delete mode 100644 third_party/lcms/0017-upstream-integer-overflow-MPEmatrix_Read.patch create mode 100644 third_party/lcms/0018-backport-c0a98d86.patch delete mode 100644 third_party/lcms/0018-verify-size-before-reading.patch delete mode 100644 third_party/lcms/0019-upstream-direct-leak-Type_MPE_Read.patch create mode 100644 third_party/lcms/0019-utf8.patch create mode 100644 third_party/lcms/0020-avoid-fixed-inf.patch create mode 100644 third_party/lcms/0021-sanitize-float-read.patch create mode 100644 third_party/lcms/0022-check-LUT-and-MPE.patch create mode 100644 third_party/lcms/0023-upstream-integer-overflow-MPEmatrix_Read.patch create mode 100644 third_party/lcms/0024-verify-size-before-reading.patch create mode 100644 third_party/lcms/0025-upstream-direct-leak-Type_MPE_Read.patch create mode 100644 third_party/lcms/0026-more-unsupported-characters.patch create mode 100644 third_party/lcms/0027-changes-from-beginning-of-time.patch create mode 100644 third_party/lcms/src/cmsalpha.c diff --git a/DEPS b/DEPS index 50f9b93f9c..f4813010f8 100644 --- a/DEPS +++ b/DEPS @@ -19,7 +19,7 @@ vars = { 'jinja2_revision': 'd34383206fa42d52faa10bb9931d6d538f3a57e0', 'jpeg_turbo_revision': '7260e4d8b8e1e40b17f03fafdf1cd83296900f76', 'markupsafe_revision': '8f45f5cfa0009d2a70589bcda0349b8cb2b72783', - 'pdfium_tests_revision': 'ab561f0075518d699636b884b0db46293cd76261', + 'pdfium_tests_revision': '056a182ccff4c6f21e80f70a5601706dece34d84', 'skia_revision': 'bb581ce30f55360fd3a12e7f5aa1fe324b16d085', 'tools_memory_revision': '427f10475e1a8d72424c29d00bf689122b738e5d', 'trace_event_revision': '06294c8a4a6f744ef284cd63cfe54dbf61eea290', diff --git a/third_party/BUILD.gn b/third_party/BUILD.gn index 743bbb0064..029272d8fe 100644 --- a/third_party/BUILD.gn +++ b/third_party/BUILD.gn @@ -255,6 +255,7 @@ static_library("fx_lcms2") { sources = [ "lcms/include/lcms2.h", "lcms/include/lcms2_plugin.h", + "lcms/src/cmsalpha.c", "lcms/src/cmscam02.c", "lcms/src/cmscgats.c", "lcms/src/cmscnvrt.c", diff --git a/third_party/lcms/0000-cmserr-changes.patch b/third_party/lcms/0000-cmserr-changes.patch new file mode 100644 index 0000000000..5ccaac9ee1 --- /dev/null +++ b/third_party/lcms/0000-cmserr-changes.patch @@ -0,0 +1,285 @@ +diff --git a/third_party/lcms/src/cmserr.c b/third_party/lcms/src/cmserr.c +index 700152ee3..3c3848b2a 100644 +--- a/third_party/lcms/src/cmserr.c ++++ b/third_party/lcms/src/cmserr.c +@@ -25,6 +25,8 @@ + + #include "lcms2_internal.h" + ++#include "core/fxcrt/fx_memory.h" ++#include "core/fxcrt/fx_system.h" + + // This function is here to help applications to prevent mixing lcms versions on header and shared objects. + int CMSEXPORT cmsGetEncodedCMMversion(void) +@@ -65,140 +67,75 @@ long int CMSEXPORT cmsfilelength(FILE* f) + return n; + } + +- +-// Memory handling ------------------------------------------------------------------ +-// +-// 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 evil code to allocate huge blocks that otherwise lcms would never need. +- +-#define MAX_MEMORY_FOR_ALLOC ((cmsUInt32Number)(1024U*1024U*512U)) +- +-// User may override this behaviour by using a memory plug-in, which basically replaces +-// the default memory management functions. In this case, no check is performed and it +-// is up to the plug-in writter to keep in the safe side. There are only three functions +-// 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(cmsContext ContextID, cmsPluginBase* Plugin); +- +-// ********************************************************************************* +- +-// This is the default memory allocation function. It does a very coarse +-// check of amout of memory, just to prevent exploits +-static +-void* _cmsMallocDefaultFn(cmsContext ContextID, cmsUInt32Number size) ++cmsBool _cmsRegisterMemHandlerPlugin(cmsContext ContextID, cmsPluginBase* Plugin) + { +- if (size > MAX_MEMORY_FOR_ALLOC) return NULL; // Never allow over maximum +- +- return (void*) malloc(size); ++ return TRUE; ++} + +- cmsUNUSED_PARAMETER(ContextID); ++// Generic allocate ++void* CMSEXPORT _cmsMalloc(cmsContext ContextID, cmsUInt32Number size) ++{ ++ return FXMEM_DefaultAlloc(size, 1); + } + + // Generic allocate & zero +-static +-void* _cmsMallocZeroDefaultFn(cmsContext ContextID, cmsUInt32Number size) ++void* CMSEXPORT _cmsMallocZero(cmsContext ContextID, cmsUInt32Number size) + { +- void *pt = _cmsMalloc(ContextID, size); +- if (pt == NULL) return NULL; +- +- memset(pt, 0, size); +- return pt; ++ void* p = FXMEM_DefaultAlloc(size, 1); ++ if (p) memset(p, 0, size); ++ return p; + } + +- +-// The default free function. The only check proformed is against NULL pointers +-static +-void _cmsFreeDefaultFn(cmsContext ContextID, void *Ptr) ++// Generic calloc ++void* CMSEXPORT _cmsCalloc(cmsContext ContextID, cmsUInt32Number num, cmsUInt32Number size) + { +- // free(NULL) is defined a no-op by C99, therefore it is safe to +- // avoid the check, but it is here just in case... +- +- if (Ptr) free(Ptr); ++ cmsUInt32Number total = num * size; ++ if (total == 0 || total / size != num || total >= 512 * 1024 * 1024) ++ return NULL; + +- cmsUNUSED_PARAMETER(ContextID); ++ return _cmsMallocZero(ContextID, num * size); + } + +-// 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) ++// Generic reallocate ++void* CMSEXPORT _cmsRealloc(cmsContext ContextID, void* Ptr, cmsUInt32Number size) + { +- +- if (size > MAX_MEMORY_FOR_ALLOC) return NULL; // Never realloc over 512Mb +- +- return realloc(Ptr, size); +- +- cmsUNUSED_PARAMETER(ContextID); ++ return FXMEM_DefaultRealloc(Ptr, size, 1); + } + +- +-// The default calloc function. Allocates an array of num elements, each one of size bytes +-// all memory is initialized to zero. +-static +-void* _cmsCallocDefaultFn(cmsContext ContextID, cmsUInt32Number num, cmsUInt32Number size) ++// Generic free memory ++void CMSEXPORT _cmsFree(cmsContext ContextID, void* Ptr) + { +- cmsUInt32Number Total = num * size; +- +- // Preserve calloc behaviour +- if (Total == 0) return NULL; +- +- // Safe check for overflow. +- if (num >= UINT_MAX / size) return NULL; +- +- // Check for overflow +- if (Total < num || Total < size) { +- return NULL; +- } +- +- if (Total > MAX_MEMORY_FOR_ALLOC) return NULL; // Never alloc over 512Mb +- +- return _cmsMallocZero(ContextID, Total); ++ if (Ptr != NULL) FXMEM_DefaultFree(Ptr, 0); + } + + // Generic block duplication +-static +-void* _cmsDupDefaultFn(cmsContext ContextID, const void* Org, cmsUInt32Number size) ++void* CMSEXPORT _cmsDupMem(cmsContext ContextID, const void* Org, cmsUInt32Number size) + { +- void* mem; +- +- if (size > MAX_MEMORY_FOR_ALLOC) return NULL; // Never dup over 512Mb +- +- mem = _cmsMalloc(ContextID, size); +- +- if (mem != NULL && Org != NULL) +- memmove(mem, Org, size); +- +- return mem; ++ void* p = FXMEM_DefaultAlloc(size, 1); ++ memmove(p, Org, size); ++ return p; + } + +- +-// Pointers to memory manager functions in Context0 +-_cmsMemPluginChunkType _cmsMemPluginChunk = { _cmsMallocDefaultFn, _cmsMallocZeroDefaultFn, _cmsFreeDefaultFn, +- _cmsReallocDefaultFn, _cmsCallocDefaultFn, _cmsDupDefaultFn ++_cmsMemPluginChunkType _cmsMemPluginChunk = {_cmsMalloc, _cmsMallocZero, _cmsFree, ++ _cmsRealloc, _cmsCalloc, _cmsDupMem + }; + +- +-// Reset and duplicate memory manager + void _cmsAllocMemPluginChunk(struct _cmsContext_struct* ctx, const struct _cmsContext_struct* src) + { + _cmsAssert(ctx != NULL); + +- if (src != NULL) { ++ if (src != NULL) { + + // Duplicate +- ctx ->chunks[MemPlugin] = _cmsSubAllocDup(ctx ->MemPool, src ->chunks[MemPlugin], sizeof(_cmsMemPluginChunkType)); ++ 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; +- } ++ } + } + +-// Auxiliary to fill memory management functions from plugin (or context 0 defaults) + void _cmsInstallAllocFunctions(cmsPluginMemHandler* Plugin, _cmsMemPluginChunkType* ptr) + { + if (Plugin == NULL) { +@@ -212,94 +149,15 @@ void _cmsInstallAllocFunctions(cmsPluginMemHandler* Plugin, _cmsMemPluginChunkTy + ptr ->ReallocPtr = Plugin -> ReallocPtr; + + // Make sure we revert to defaults +- ptr ->MallocZeroPtr= _cmsMallocZeroDefaultFn; +- ptr ->CallocPtr = _cmsCallocDefaultFn; +- ptr ->DupPtr = _cmsDupDefaultFn; +- ++ ptr ->MallocZeroPtr= _cmsMallocZero; ++ ptr ->CallocPtr = _cmsCalloc; ++ ptr ->DupPtr = _cmsDupMem; ++ + 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(cmsContext ContextID, cmsPluginBase *Data) +-{ +- cmsPluginMemHandler* Plugin = (cmsPluginMemHandler*) Data; +- _cmsMemPluginChunkType* ptr; +- +- // 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) { +- +- struct _cmsContext_struct* ctx = ( struct _cmsContext_struct*) ContextID; +- +- // Return to the default allocators +- if (ContextID != NULL) { +- ctx->chunks[MemPlugin] = (void*) &ctx->DefaultMemoryManager; +- } +- return TRUE; + } +- +- // Check for required callbacks +- if (Plugin -> MallocPtr == NULL || +- Plugin -> FreePtr == NULL || +- Plugin -> ReallocPtr == NULL) return FALSE; +- +- // Set replacement functions +- ptr = (_cmsMemPluginChunkType*) _cmsContextGetClientChunk(ContextID, MemPlugin); +- if (ptr == NULL) +- return FALSE; +- +- _cmsInstallAllocFunctions(Plugin, ptr); +- return TRUE; +-} +- +-// Generic allocate +-void* CMSEXPORT _cmsMalloc(cmsContext ContextID, cmsUInt32Number size) +-{ +- _cmsMemPluginChunkType* ptr = (_cmsMemPluginChunkType*) _cmsContextGetClientChunk(ContextID, MemPlugin); +- return ptr ->MallocPtr(ContextID, size); +-} +- +-// Generic allocate & zero +-void* CMSEXPORT _cmsMallocZero(cmsContext ContextID, cmsUInt32Number size) +-{ +- _cmsMemPluginChunkType* ptr = (_cmsMemPluginChunkType*) _cmsContextGetClientChunk(ContextID, MemPlugin); +- return ptr->MallocZeroPtr(ContextID, size); +-} +- +-// Generic calloc +-void* CMSEXPORT _cmsCalloc(cmsContext ContextID, cmsUInt32Number num, cmsUInt32Number size) +-{ +- _cmsMemPluginChunkType* ptr = (_cmsMemPluginChunkType*) _cmsContextGetClientChunk(ContextID, MemPlugin); +- return ptr->CallocPtr(ContextID, num, size); +-} +- +-// Generic reallocate +-void* CMSEXPORT _cmsRealloc(cmsContext ContextID, void* Ptr, cmsUInt32Number 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) { +- _cmsMemPluginChunkType* ptr = (_cmsMemPluginChunkType*) _cmsContextGetClientChunk(ContextID, MemPlugin); +- ptr ->FreePtr(ContextID, Ptr); +- } +-} +- +-// Generic block duplication +-void* CMSEXPORT _cmsDupMem(cmsContext ContextID, const void* Org, cmsUInt32Number size) +-{ +- _cmsMemPluginChunkType* ptr = (_cmsMemPluginChunkType*) _cmsContextGetClientChunk(ContextID, MemPlugin); +- return ptr ->DupPtr(ContextID, Org, size); + } + + // ******************************************************************************************** diff --git a/third_party/lcms/0000-tag-type-confusion.patch b/third_party/lcms/0000-tag-type-confusion.patch deleted file mode 100644 index 97d3c7f4d9..0000000000 --- a/third_party/lcms/0000-tag-type-confusion.patch +++ /dev/null @@ -1,14 +0,0 @@ -diff --git a/third_party/lcms/src/cmsio0.c b/third_party/lcms/src/cmsio0.c -index 6549d15..5f9f08a 100644 ---- a/third_party/lcms/src/cmsio0.c -+++ b/third_party/lcms/src/cmsio0.c -@@ -719,7 +719,8 @@ cmsBool _cmsReadHeader(_cmsICCPROFILE* Icc) - for (j=0; j < Icc ->TagCount; j++) { - - if ((Icc ->TagOffsets[j] == Tag.offset) && -- (Icc ->TagSizes[j] == Tag.size)) { -+ (Icc ->TagSizes[j] == Tag.size) && -+ (Icc ->TagNames[j] == Tag.sig)) { - - Icc ->TagLinked[Icc ->TagCount] = Icc ->TagNames[j]; - } diff --git a/third_party/lcms/0001-fix-include.patch b/third_party/lcms/0001-fix-include.patch new file mode 100644 index 0000000000..d95dba6ee2 --- /dev/null +++ b/third_party/lcms/0001-fix-include.patch @@ -0,0 +1,13 @@ +diff --git a/third_party/lcms/src/lcms2_internal.h b/third_party/lcms/src/lcms2_internal.h +index 727cb06e3..115ac5970 100644 +--- a/third_party/lcms/src/lcms2_internal.h ++++ b/third_party/lcms/src/lcms2_internal.h +@@ -28,7 +28,7 @@ + + // Include plug-in foundation + #ifndef _lcms_plugin_H +-# include "lcms2_plugin.h" ++# include "third_party/lcms/include/lcms2_plugin.h" + #endif + + // ctype is part of C99 as per 7.1.2 diff --git a/third_party/lcms/0001-from16-to-8-overflow.patch b/third_party/lcms/0001-from16-to-8-overflow.patch deleted file mode 100644 index 9d31c84b36..0000000000 --- a/third_party/lcms/0001-from16-to-8-overflow.patch +++ /dev/null @@ -1,13 +0,0 @@ -diff --git a/third_party/lcms/src/lcms2_internal.h b/third_party/lcms/src/lcms2_internal.h -index 8617e92..cc76d48 100644 ---- a/third_party/lcms/src/lcms2_internal.h -+++ b/third_party/lcms/src/lcms2_internal.h -@@ -94,7 +94,7 @@ - - // A fast way to convert from/to 16 <-> 8 bits - #define FROM_8_TO_16(rgb) (cmsUInt16Number) ((((cmsUInt16Number) (rgb)) << 8)|(rgb)) --#define FROM_16_TO_8(rgb) (cmsUInt8Number) ((((rgb) * 65281 + 8388608) >> 24) & 0xFF) -+#define FROM_16_TO_8(rgb) (cmsUInt8Number) ((((cmsUInt32Number)(rgb) * 65281U + 8388608U) >> 24) & 0xFFU) - - // Code analysis is broken on asserts - #ifdef _MSC_VER diff --git a/third_party/lcms/0002-infinite-loop-GrowNamedColorList.patch b/third_party/lcms/0002-infinite-loop-GrowNamedColorList.patch deleted file mode 100644 index 2a6f3df6c7..0000000000 --- a/third_party/lcms/0002-infinite-loop-GrowNamedColorList.patch +++ /dev/null @@ -1,34 +0,0 @@ -diff --git a/third_party/lcms/src/cmsnamed.c b/third_party/lcms/src/cmsnamed.c -index acfd1c8..ef1eb30 100644 ---- a/third_party/lcms/src/cmsnamed.c -+++ b/third_party/lcms/src/cmsnamed.c -@@ -514,8 +514,12 @@ cmsNAMEDCOLORLIST* CMSEXPORT cmsAllocNamedColorList(cmsContext ContextID, cmsUIn - v ->nColors = 0; - v ->ContextID = ContextID; - -- while (v -> Allocated < n) -- GrowNamedColorList(v); -+ while (v -> Allocated < n) { -+ if (!GrowNamedColorList(v)) { -+ cmsFreeNamedColorList(v); -+ return NULL; -+ } -+ } - - strncpy(v ->Prefix, Prefix, sizeof(v ->Prefix)-1); - strncpy(v ->Suffix, Suffix, sizeof(v ->Suffix)-1); -@@ -544,8 +548,12 @@ cmsNAMEDCOLORLIST* CMSEXPORT cmsDupNamedColorList(const cmsNAMEDCOLORLIST* v) - if (NewNC == NULL) return NULL; - - // For really large tables we need this -- while (NewNC ->Allocated < v ->Allocated) -- GrowNamedColorList(NewNC); -+ while (NewNC ->Allocated < v ->Allocated) { -+ if (!GrowNamedColorList(NewNC)) { -+ cmsFreeNamedColorList(NewNC); -+ return NULL; -+ } -+ } - - memmove(NewNC ->Prefix, v ->Prefix, sizeof(v ->Prefix)); - memmove(NewNC ->Suffix, v ->Suffix, sizeof(v ->Suffix)); diff --git a/third_party/lcms/0002-old-performance-fix.patch b/third_party/lcms/0002-old-performance-fix.patch new file mode 100644 index 0000000000..cea2bee94b --- /dev/null +++ b/third_party/lcms/0002-old-performance-fix.patch @@ -0,0 +1,13 @@ +diff --git a/third_party/lcms/src/cmsgamma.c b/third_party/lcms/src/cmsgamma.c +index edb8f6bba..eb3dd881c 100644 +--- a/third_party/lcms/src/cmsgamma.c ++++ b/third_party/lcms/src/cmsgamma.c +@@ -799,7 +799,7 @@ void CMSEXPORT cmsFreeToneCurveTriple(cmsToneCurve* Curve[3]) + // Duplicate a gamma table + cmsToneCurve* CMSEXPORT cmsDupToneCurve(const cmsToneCurve* In) + { +- if (In == NULL) return NULL; ++ if (In == NULL || In ->Segments == NULL || In ->Table16 == NULL) return NULL; + + return AllocateToneCurveStruct(In ->InterpParams ->ContextID, In ->nEntries, In ->nSegments, In ->Segments, In ->Table16); + } diff --git a/third_party/lcms/0003-old-uninitialized-in-LUTevalFloat.patch b/third_party/lcms/0003-old-uninitialized-in-LUTevalFloat.patch new file mode 100644 index 0000000000..8091eefd7c --- /dev/null +++ b/third_party/lcms/0003-old-uninitialized-in-LUTevalFloat.patch @@ -0,0 +1,13 @@ +diff --git a/third_party/lcms/src/cmslut.c b/third_party/lcms/src/cmslut.c +index df3dfc1ad..45f05c61d 100644 +--- a/third_party/lcms/src/cmslut.c ++++ b/third_party/lcms/src/cmslut.c +@@ -1321,7 +1321,7 @@ void _LUTevalFloat(register const cmsFloat32Number In[], register cmsFloat32Numb + { + cmsPipeline* lut = (cmsPipeline*) D; + cmsStage *mpe; +- cmsFloat32Number Storage[2][MAX_STAGE_CHANNELS]; ++ cmsFloat32Number Storage[2][MAX_STAGE_CHANNELS] = {0.0f}; + int Phase = 0, NextPhase; + + memmove(&Storage[Phase][0], In, lut ->InputChannels * sizeof(cmsFloat32Number)); diff --git a/third_party/lcms/0003-uninit.patch b/third_party/lcms/0003-uninit.patch deleted file mode 100644 index 4017c0150b..0000000000 --- a/third_party/lcms/0003-uninit.patch +++ /dev/null @@ -1,30 +0,0 @@ -diff --git a/third_party/lcms/src/cmstypes.c b/third_party/lcms/src/cmstypes.c -index 06742b5..44c5b87 100644 ---- a/third_party/lcms/src/cmstypes.c -+++ b/third_party/lcms/src/cmstypes.c -@@ -2964,7 +2964,7 @@ void *Type_ColorantTable_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER - { - cmsUInt32Number i, Count; - cmsNAMEDCOLORLIST* List; -- char Name[34]; -+ char Name[33]; - cmsUInt16Number PCS[3]; - - -@@ -2979,7 +2979,7 @@ void *Type_ColorantTable_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER - for (i=0; i < Count; i++) { - - if (io ->Read(io, Name, 32, 1) != 1) goto Error; -- Name[33] = 0; -+ Name[32] = 0; - - if (!_cmsReadUInt16Array(io, 3, PCS)) goto Error; - -@@ -3106,6 +3106,7 @@ void *Type_NamedColor_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* i - - memset(Colorant, 0, sizeof(Colorant)); - if (io -> Read(io, Root, 32, 1) != 1) return NULL; -+ Root[32] = 0; - if (!_cmsReadUInt16Array(io, 3, PCS)) goto Error; - if (!_cmsReadUInt16Array(io, nDeviceCoords, Colorant)) goto Error; - diff --git a/third_party/lcms/0004-memory-leak-Type_Curve_Read.patch b/third_party/lcms/0004-memory-leak-Type_Curve_Read.patch deleted file mode 100644 index 7edc7f9e0f..0000000000 --- a/third_party/lcms/0004-memory-leak-Type_Curve_Read.patch +++ /dev/null @@ -1,28 +0,0 @@ -diff --git a/third_party/lcms/src/cmstypes.c b/third_party/lcms/src/cmstypes.c -index 06742b5..9fe5e2a 100644 ---- a/third_party/lcms/src/cmstypes.c -+++ b/third_party/lcms/src/cmstypes.c -@@ -1112,7 +1112,10 @@ void *Type_Curve_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cm - NewGamma = cmsBuildTabulatedToneCurve16(self ->ContextID, Count, NULL); - if (!NewGamma) return NULL; - -- if (!_cmsReadUInt16Array(io, Count, NewGamma -> Table16)) return NULL; -+ if (!_cmsReadUInt16Array(io, Count, NewGamma -> Table16)) { -+ cmsFreeToneCurve(NewGamma); -+ return NULL; -+ } - - *nItems = 1; - return NewGamma; -@@ -2350,7 +2353,10 @@ cmsStage* ReadCLUT(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUI - - for (i=0; i < Data ->nEntries; i++) { - -- if (io ->Read(io, &v, sizeof(cmsUInt8Number), 1) != 1) return NULL; -+ if (io ->Read(io, &v, sizeof(cmsUInt8Number), 1) != 1) { -+ cmsStageFree(CLUT); -+ return NULL; -+ } - Data ->Tab.T[i] = FROM_8_TO_16(v); - } - diff --git a/third_party/lcms/0004-old-uninitialized-in-LUTeval16.patch b/third_party/lcms/0004-old-uninitialized-in-LUTeval16.patch new file mode 100644 index 0000000000..dce315257d --- /dev/null +++ b/third_party/lcms/0004-old-uninitialized-in-LUTeval16.patch @@ -0,0 +1,13 @@ +diff --git a/third_party/lcms/src/cmslut.c b/third_party/lcms/src/cmslut.c +index 45f05c61d..18b88a545 100644 +--- a/third_party/lcms/src/cmslut.c ++++ b/third_party/lcms/src/cmslut.c +@@ -1295,7 +1295,7 @@ void _LUTeval16(register const cmsUInt16Number In[], register cmsUInt16Number Ou + { + cmsPipeline* lut = (cmsPipeline*) D; + cmsStage *mpe; +- cmsFloat32Number Storage[2][MAX_STAGE_CHANNELS]; ++ cmsFloat32Number Storage[2][MAX_STAGE_CHANNELS] = {0.0f}; + int Phase = 0, NextPhase; + + From16ToFloat(In, &Storage[Phase][0], lut ->InputChannels); diff --git a/third_party/lcms/0005-memory-leak-AllocEmptyTransform.patch b/third_party/lcms/0005-memory-leak-AllocEmptyTransform.patch deleted file mode 100644 index 481d421292..0000000000 --- a/third_party/lcms/0005-memory-leak-AllocEmptyTransform.patch +++ /dev/null @@ -1,34 +0,0 @@ -diff --git a/third_party/lcms/src/cmsxform.c b/third_party/lcms/src/cmsxform.c -index eddb9bd..6466d27 100644 ---- a/third_party/lcms/src/cmsxform.c -+++ b/third_party/lcms/src/cmsxform.c -@@ -593,7 +593,10 @@ _cmsTRANSFORM* AllocEmptyTransform(cmsContext ContextID, cmsPipeline* lut, - - // Allocate needed memory - _cmsTRANSFORM* p = (_cmsTRANSFORM*) _cmsMallocZero(ContextID, sizeof(_cmsTRANSFORM)); -- if (!p) return NULL; -+ if (!p) { -+ cmsPipelineFree(lut); -+ return NULL; -+ } - - // Store the proposed pipeline - p ->Lut = lut; -@@ -643,7 +646,7 @@ _cmsTRANSFORM* AllocEmptyTransform(cmsContext ContextID, cmsPipeline* lut, - if (p ->FromInputFloat == NULL || p ->ToOutputFloat == NULL) { - - cmsSignalError(ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported raster format"); -- _cmsFree(ContextID, p); -+ cmsDeleteTransform(p); - return NULL; - } - -@@ -673,7 +676,7 @@ _cmsTRANSFORM* AllocEmptyTransform(cmsContext ContextID, cmsPipeline* lut, - if (p ->FromInput == NULL || p ->ToOutput == NULL) { - - cmsSignalError(ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported raster format"); -- _cmsFree(ContextID, p); -+ cmsDeleteTransform(p); - return NULL; - } - diff --git a/third_party/lcms/0005-old-fix-e-with-tilde.patch b/third_party/lcms/0005-old-fix-e-with-tilde.patch new file mode 100644 index 0000000000..2fc054dae8 --- /dev/null +++ b/third_party/lcms/0005-old-fix-e-with-tilde.patch @@ -0,0 +1,61 @@ +diff --git a/third_party/lcms/src/cmsxform.c b/third_party/lcms/src/cmsxform.c +index 4a5a4f093..9c20c49b0 100644 +--- a/third_party/lcms/src/cmsxform.c ++++ b/third_party/lcms/src/cmsxform.c +@@ -338,7 +338,7 @@ void NullFloatXFORM(_cmsTRANSFORM* p, + + // 16 bit precision ----------------------------------------------------------------------------------------------------------- + +-// Null transformation, only applies formatters. No cach ++// Null transformation, only applies formatters. No cache + static + void NullXFORM(_cmsTRANSFORM* p, + const void* in, +@@ -436,7 +436,7 @@ void TransformOnePixelWithGamutCheck(_cmsTRANSFORM* p, + p ->Lut ->Eval16Fn(wIn, wOut, p -> Lut->Data); + } + +-// Gamut check, No cach, 16 bits. ++// Gamut check, No cache, 16 bits. + static + void PrecalculatedXFORMGamutCheck(_cmsTRANSFORM* p, + const void* in, +@@ -473,7 +473,7 @@ void PrecalculatedXFORMGamutCheck(_cmsTRANSFORM* p, + } + + +-// No gamut check, Cach, 16 bits, ++// No gamut check, Cache, 16 bits, + static + void CachedXFORM(_cmsTRANSFORM* p, + const void* in, +@@ -828,7 +828,7 @@ _cmsTRANSFORM* AllocEmptyTransform(cmsContext ContextID, cmsPipeline* lut, + p ->xform = NullFloatXFORM; + } + else { +- // Float transforms don't use cach, always are non-NULL ++ // Float transforms don't use cache, always are non-NULL + p ->xform = FloatXFORM; + } + +@@ -867,16 +867,16 @@ _cmsTRANSFORM* AllocEmptyTransform(cmsContext ContextID, cmsPipeline* lut, + if (*dwFlags & cmsFLAGS_NOCACHE) { + + if (*dwFlags & cmsFLAGS_GAMUTCHECK) +- p ->xform = PrecalculatedXFORMGamutCheck; // Gamut check, no cach ++ p ->xform = PrecalculatedXFORMGamutCheck; // Gamut check, no cache + else +- p ->xform = PrecalculatedXFORM; // No cach, no gamut check ++ p ->xform = PrecalculatedXFORM; // No cache, no gamut check + } + else { + + if (*dwFlags & cmsFLAGS_GAMUTCHECK) +- p ->xform = CachedXFORMGamutCheck; // Gamut check, cach ++ p ->xform = CachedXFORMGamutCheck; // Gamut check, cache + else +- p ->xform = CachedXFORM; // No gamut check, cach ++ p ->xform = CachedXFORM; // No gamut check, cache + + } + } diff --git a/third_party/lcms/0006-memory-leak-Type_NamedColor_Read.patch b/third_party/lcms/0006-memory-leak-Type_NamedColor_Read.patch deleted file mode 100644 index f6fa010357..0000000000 --- a/third_party/lcms/0006-memory-leak-Type_NamedColor_Read.patch +++ /dev/null @@ -1,22 +0,0 @@ -diff --git a/third_party/lcms/src/cmstypes.c b/third_party/lcms/src/cmstypes.c -index feba387..4d24fc2 100644 ---- a/third_party/lcms/src/cmstypes.c -+++ b/third_party/lcms/src/cmstypes.c -@@ -3102,7 +3102,7 @@ void *Type_NamedColor_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* i - - if (nDeviceCoords > cmsMAXCHANNELS) { - cmsSignalError(self->ContextID, cmsERROR_RANGE, "Too many device coordinates '%d'", nDeviceCoords); -- return 0; -+ goto Error; - } - for (i=0; i < count; i++) { - -@@ -3111,7 +3111,7 @@ void *Type_NamedColor_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* i - char Root[33]; - - memset(Colorant, 0, sizeof(Colorant)); -- if (io -> Read(io, Root, 32, 1) != 1) return NULL; -+ if (io -> Read(io, Root, 32, 1) != 1) goto Error; - Root[32] = 0; - if (!_cmsReadUInt16Array(io, 3, PCS)) goto Error; - if (!_cmsReadUInt16Array(io, nDeviceCoords, Colorant)) goto Error; diff --git a/third_party/lcms/0006-tag-type-confusion.patch b/third_party/lcms/0006-tag-type-confusion.patch new file mode 100644 index 0000000000..97d3c7f4d9 --- /dev/null +++ b/third_party/lcms/0006-tag-type-confusion.patch @@ -0,0 +1,14 @@ +diff --git a/third_party/lcms/src/cmsio0.c b/third_party/lcms/src/cmsio0.c +index 6549d15..5f9f08a 100644 +--- a/third_party/lcms/src/cmsio0.c ++++ b/third_party/lcms/src/cmsio0.c +@@ -719,7 +719,8 @@ cmsBool _cmsReadHeader(_cmsICCPROFILE* Icc) + for (j=0; j < Icc ->TagCount; j++) { + + if ((Icc ->TagOffsets[j] == Tag.offset) && +- (Icc ->TagSizes[j] == Tag.size)) { ++ (Icc ->TagSizes[j] == Tag.size) && ++ (Icc ->TagNames[j] == Tag.sig)) { + + Icc ->TagLinked[Icc ->TagCount] = Icc ->TagNames[j]; + } diff --git a/third_party/lcms/0007-memory-leak-OptimizeByResampling.patch b/third_party/lcms/0007-memory-leak-OptimizeByResampling.patch deleted file mode 100644 index 48645d1f01..0000000000 --- a/third_party/lcms/0007-memory-leak-OptimizeByResampling.patch +++ /dev/null @@ -1,13 +0,0 @@ -diff --git a/third_party/lcms/src/cmsopt.c b/third_party/lcms/src/cmsopt.c -index f885ef3..684910d 100644 ---- a/third_party/lcms/src/cmsopt.c -+++ b/third_party/lcms/src/cmsopt.c -@@ -612,7 +612,7 @@ cmsBool OptimizeByResampling(cmsPipeline** Lut, cmsUInt32Number Intent, cmsUInt3 - - // Allocate the CLUT - CLUT = cmsStageAllocCLut16bit(Src ->ContextID, nGridPoints, Src ->InputChannels, Src->OutputChannels, NULL); -- if (CLUT == NULL) return FALSE; -+ if (CLUT == NULL) goto Error; - - // Add the CLUT to the destination LUT - if (!cmsPipelineInsertStage(Dest, cmsAT_END, CLUT)) { diff --git a/third_party/lcms/0008-infinite-loop-GrowNamedColorList.patch b/third_party/lcms/0008-infinite-loop-GrowNamedColorList.patch new file mode 100644 index 0000000000..eabf6a938d --- /dev/null +++ b/third_party/lcms/0008-infinite-loop-GrowNamedColorList.patch @@ -0,0 +1,28 @@ +diff --git a/third_party/lcms/src/cmsnamed.c b/third_party/lcms/src/cmsnamed.c +index 9b27ca0cc..9ed4cad39 100644 +--- a/third_party/lcms/src/cmsnamed.c ++++ b/third_party/lcms/src/cmsnamed.c +@@ -540,7 +540,10 @@ cmsNAMEDCOLORLIST* CMSEXPORT cmsAllocNamedColorList(cmsContext ContextID, cmsUIn + v ->ContextID = ContextID; + + while (v -> Allocated < n){ +- if (!GrowNamedColorList(v)) return NULL; ++ if (!GrowNamedColorList(v)) { ++ cmsFreeNamedColorList(v); ++ return NULL; ++ } + } + + strncpy(v ->Prefix, Prefix, sizeof(v ->Prefix)-1); +@@ -571,7 +574,10 @@ cmsNAMEDCOLORLIST* CMSEXPORT cmsDupNamedColorList(const cmsNAMEDCOLORLIST* v) + + // For really large tables we need this + while (NewNC ->Allocated < v ->Allocated){ +- if (!GrowNamedColorList(NewNC)) return NULL; ++ if (!GrowNamedColorList(NewNC)) { ++ cmsFreeNamedColorList(NewNC); ++ return NULL; ++ } + } + + memmove(NewNC ->Prefix, v ->Prefix, sizeof(v ->Prefix)); diff --git a/third_party/lcms/0008-memory-leak-Type_MPEmatrix_Read.patch b/third_party/lcms/0008-memory-leak-Type_MPEmatrix_Read.patch deleted file mode 100644 index 8cc477fb8e..0000000000 --- a/third_party/lcms/0008-memory-leak-Type_MPEmatrix_Read.patch +++ /dev/null @@ -1,30 +0,0 @@ -diff --git a/third_party/lcms/src/cmstypes.c b/third_party/lcms/src/cmstypes.c -index 441d6bb..15199c7 100644 ---- a/third_party/lcms/src/cmstypes.c -+++ b/third_party/lcms/src/cmstypes.c -@@ -4203,7 +4203,11 @@ void *Type_MPEmatrix_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io - - cmsFloat32Number v; - -- if (!_cmsReadFloat32Number(io, &v)) return NULL; -+ if (!_cmsReadFloat32Number(io, &v)) { -+ _cmsFree(self ->ContextID, Matrix); -+ _cmsFree(self ->ContextID, Offsets); -+ return NULL; -+ } - Matrix[i] = v; - } - -@@ -4212,7 +4216,11 @@ void *Type_MPEmatrix_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io - - cmsFloat32Number v; - -- if (!_cmsReadFloat32Number(io, &v)) return NULL; -+ if (!_cmsReadFloat32Number(io, &v)) { -+ _cmsFree(self ->ContextID, Matrix); -+ _cmsFree(self ->ContextID, Offsets); -+ return NULL; -+ } - Offsets[i] = v; - } - diff --git a/third_party/lcms/0009-cmsStageAllocMatrix-param-swap.patch b/third_party/lcms/0009-cmsStageAllocMatrix-param-swap.patch deleted file mode 100644 index 04f854398c..0000000000 --- a/third_party/lcms/0009-cmsStageAllocMatrix-param-swap.patch +++ /dev/null @@ -1,20 +0,0 @@ -diff --git a/third_party/lcms/src/cmslut.c b/third_party/lcms/src/cmslut.c -index 73e6726..9b0eb4b 100644 ---- a/third_party/lcms/src/cmslut.c -+++ b/third_party/lcms/src/cmslut.c -@@ -414,13 +414,13 @@ cmsStage* CMSEXPORT cmsStageAllocMatrix(cmsContext ContextID, cmsUInt32Number R - - if (Offset != NULL) { - -- NewElem ->Offset = (cmsFloat64Number*) _cmsCalloc(ContextID, Cols, sizeof(cmsFloat64Number)); -+ NewElem ->Offset = (cmsFloat64Number*) _cmsCalloc(ContextID, Rows, sizeof(cmsFloat64Number)); - if (NewElem->Offset == NULL) { - MatrixElemTypeFree(NewMPE); - return NULL; - } - -- for (i=0; i < Cols; i++) { -+ for (i=0; i < Rows; i++) { - NewElem ->Offset[i] = Offset[i]; - } - diff --git a/third_party/lcms/0009-uninit.patch b/third_party/lcms/0009-uninit.patch new file mode 100644 index 0000000000..e9538c1f22 --- /dev/null +++ b/third_party/lcms/0009-uninit.patch @@ -0,0 +1,23 @@ +npm@npm0:~/pdfium/pdfium/third_party/lcms$ git diff src/cmstypes.c +diff --git a/third_party/lcms/src/cmstypes.c b/third_party/lcms/src/cmstypes.c +index cb618600a..2a0ea9448 100644 +--- a/third_party/lcms/src/cmstypes.c ++++ b/third_party/lcms/src/cmstypes.c +@@ -2966,7 +2966,7 @@ void *Type_ColorantTable_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER + { + cmsUInt32Number i, Count; + cmsNAMEDCOLORLIST* List; +- char Name[34]; ++ char Name[33]; + cmsUInt16Number PCS[3]; + + +@@ -2981,7 +2981,7 @@ void *Type_ColorantTable_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER + for (i=0; i < Count; i++) { + + if (io ->Read(io, Name, 32, 1) != 1) goto Error; +- Name[33] = 0; ++ Name[32] = 0; + + if (!_cmsReadUInt16Array(io, 3, PCS)) goto Error; + diff --git a/third_party/lcms/0010-memory-leak-Type_Curve_Read.patch b/third_party/lcms/0010-memory-leak-Type_Curve_Read.patch new file mode 100644 index 0000000000..7edc7f9e0f --- /dev/null +++ b/third_party/lcms/0010-memory-leak-Type_Curve_Read.patch @@ -0,0 +1,28 @@ +diff --git a/third_party/lcms/src/cmstypes.c b/third_party/lcms/src/cmstypes.c +index 06742b5..9fe5e2a 100644 +--- a/third_party/lcms/src/cmstypes.c ++++ b/third_party/lcms/src/cmstypes.c +@@ -1112,7 +1112,10 @@ void *Type_Curve_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cm + NewGamma = cmsBuildTabulatedToneCurve16(self ->ContextID, Count, NULL); + if (!NewGamma) return NULL; + +- if (!_cmsReadUInt16Array(io, Count, NewGamma -> Table16)) return NULL; ++ if (!_cmsReadUInt16Array(io, Count, NewGamma -> Table16)) { ++ cmsFreeToneCurve(NewGamma); ++ return NULL; ++ } + + *nItems = 1; + return NewGamma; +@@ -2350,7 +2353,10 @@ cmsStage* ReadCLUT(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUI + + for (i=0; i < Data ->nEntries; i++) { + +- if (io ->Read(io, &v, sizeof(cmsUInt8Number), 1) != 1) return NULL; ++ if (io ->Read(io, &v, sizeof(cmsUInt8Number), 1) != 1) { ++ cmsStageFree(CLUT); ++ return NULL; ++ } + Data ->Tab.T[i] = FROM_8_TO_16(v); + } + diff --git a/third_party/lcms/0010-reject-nan.patch b/third_party/lcms/0010-reject-nan.patch deleted file mode 100644 index 8aa325a749..0000000000 --- a/third_party/lcms/0010-reject-nan.patch +++ /dev/null @@ -1,13 +0,0 @@ -diff --git a/third_party/lcms/src/cmsplugin.c b/third_party/lcms/src/cmsplugin.c -index 8903d2b..b95befb 100644 ---- a/third_party/lcms/src/cmsplugin.c -+++ b/third_party/lcms/src/cmsplugin.c -@@ -179,6 +179,8 @@ cmsBool CMSEXPORT _cmsReadFloat32Number(cmsIOHANDLER* io, cmsFloat32Number* n) - - tmp = _cmsAdjustEndianess32(tmp); - *n = *(cmsFloat32Number*) &tmp; -+ if (isnan(*n)) -+ return FALSE; - } - return TRUE; - } diff --git a/third_party/lcms/0011-memory-leak-AllocEmptyTransform.patch b/third_party/lcms/0011-memory-leak-AllocEmptyTransform.patch new file mode 100644 index 0000000000..332519601e --- /dev/null +++ b/third_party/lcms/0011-memory-leak-AllocEmptyTransform.patch @@ -0,0 +1,34 @@ +diff --git a/third_party/lcms/src/cmsxform.c b/third_party/lcms/src/cmsxform.c +index 9c20c49b0..b3802f0d5 100644 +--- a/third_party/lcms/src/cmsxform.c ++++ b/third_party/lcms/src/cmsxform.c +@@ -761,7 +761,10 @@ _cmsTRANSFORM* AllocEmptyTransform(cmsContext ContextID, cmsPipeline* lut, + + // Allocate needed memory + _cmsTRANSFORM* p = (_cmsTRANSFORM*)_cmsMallocZero(ContextID, sizeof(_cmsTRANSFORM)); +- if (!p) return NULL; ++ if (!p) { ++ cmsPipelineFree(lut); ++ return NULL; ++ } + + // Store the proposed pipeline + p->Lut = lut; +@@ -819,7 +822,7 @@ _cmsTRANSFORM* AllocEmptyTransform(cmsContext ContextID, cmsPipeline* lut, + if (p ->FromInputFloat == NULL || p ->ToOutputFloat == NULL) { + + cmsSignalError(ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported raster format"); +- _cmsFree(ContextID, p); ++ cmsDeleteTransform(p); + return NULL; + } + +@@ -849,7 +852,7 @@ _cmsTRANSFORM* AllocEmptyTransform(cmsContext ContextID, cmsPipeline* lut, + if (p ->FromInput == NULL || p ->ToOutput == NULL) { + + cmsSignalError(ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported raster format"); +- _cmsFree(ContextID, p); ++ cmsDeleteTransform(p); + return NULL; + } + diff --git a/third_party/lcms/0011-memory-leak-ReadSegmentedCurve.patch b/third_party/lcms/0011-memory-leak-ReadSegmentedCurve.patch deleted file mode 100644 index 472bcadf05..0000000000 --- a/third_party/lcms/0011-memory-leak-ReadSegmentedCurve.patch +++ /dev/null @@ -1,36 +0,0 @@ -diff --git a/third_party/lcms/src/cmstypes.c b/third_party/lcms/src/cmstypes.c -index 15199c7..04dd0c4 100644 ---- a/third_party/lcms/src/cmstypes.c -+++ b/third_party/lcms/src/cmstypes.c -@@ -3968,7 +3968,7 @@ cmsToneCurve* ReadSegmentedCurve(struct _cms_typehandler_struct* self, cmsIOHAND - case cmsSigSampledCurveSeg: { - cmsUInt32Number Count; - -- if (!_cmsReadUInt32Number(io, &Count)) return NULL; -+ if (!_cmsReadUInt32Number(io, &Count)) goto Error; - - Segments[i].nGridPoints = Count; - Segments[i].SampledPoints = (cmsFloat32Number*) _cmsCalloc(self ->ContextID, Count, sizeof(cmsFloat32Number)); -@@ -3987,7 +3987,7 @@ cmsToneCurve* ReadSegmentedCurve(struct _cms_typehandler_struct* self, cmsIOHAND - _cmsTagSignature2String(String, (cmsTagSignature) ElementSig); - cmsSignalError(self->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unknown curve element type '%s' found.", String); - } -- return NULL; -+ goto Error; - - } - } -@@ -4001,7 +4001,12 @@ cmsToneCurve* ReadSegmentedCurve(struct _cms_typehandler_struct* self, cmsIOHAND - return Curve; - - Error: -- if (Segments) _cmsFree(self ->ContextID, Segments); -+ if (Segments) { -+ for (i=0; i < nSegments; i++) { -+ if (Segments[i].SampledPoints) _cmsFree(self ->ContextID, Segments[i].SampledPoints); -+ } -+ _cmsFree(self ->ContextID, Segments); -+ } - return NULL; - } - diff --git a/third_party/lcms/0012-backport-c0a98d86.patch b/third_party/lcms/0012-backport-c0a98d86.patch deleted file mode 100644 index 3835b0d6cc..0000000000 --- a/third_party/lcms/0012-backport-c0a98d86.patch +++ /dev/null @@ -1,53 +0,0 @@ -diff --git a/third_party/lcms/src/cmsintrp.c b/third_party/lcms/src/cmsintrp.c -index 5d5f35d..14c6856 100644 ---- a/third_party/lcms/src/cmsintrp.c -+++ b/third_party/lcms/src/cmsintrp.c -@@ -215,7 +215,7 @@ void LinLerp1D(register const cmsUInt16Number Value[], - // To prevent out of bounds indexing - cmsINLINE cmsFloat32Number fclamp(cmsFloat32Number v) - { -- return v < 0.0f ? 0.0f : (v > 1.0f ? 1.0f : v); -+ return ((v < 0.0f) || isnan(v)) ? 0.0f : (v > 1.0f ? 1.0f : v); - } - - // Floating-point version of 1D interpolation -diff --git a/third_party/lcms/src/cmsio0.c b/third_party/lcms/src/cmsio0.c -index 5f9f08a..3ed730a 100644 ---- a/third_party/lcms/src/cmsio0.c -+++ b/third_party/lcms/src/cmsio0.c -@@ -1475,6 +1475,17 @@ void* CMSEXPORT cmsReadTag(cmsHPROFILE hProfile, cmsTagSignature sig) - // If the element is already in memory, return the pointer - if (Icc -> TagPtrs[n]) { - -+ if (Icc->TagTypeHandlers[n] == NULL) goto Error; -+ -+ // Sanity check -+ BaseType = Icc->TagTypeHandlers[n]->Signature; -+ if (BaseType == 0) goto Error; -+ -+ TagDescriptor = _cmsGetTagDescriptor(Icc->ContextID, sig); -+ if (TagDescriptor == NULL) goto Error; -+ -+ if (!IsTypeSupported(TagDescriptor, BaseType)) goto Error; -+ - if (Icc ->TagSaveAsRaw[n]) goto Error; // We don't support read raw tags as cooked - - _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex); -diff --git a/third_party/lcms/src/cmstypes.c b/third_party/lcms/src/cmstypes.c -index 04dd0c4..386439b 100644 ---- a/third_party/lcms/src/cmstypes.c -+++ b/third_party/lcms/src/cmstypes.c -@@ -4297,8 +4297,12 @@ void *Type_MPEclut_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, - - // Copy MAX_INPUT_DIMENSIONS at most. Expand to cmsUInt32Number - nMaxGrids = InputChans > MAX_INPUT_DIMENSIONS ? MAX_INPUT_DIMENSIONS : InputChans; -- for (i=0; i < nMaxGrids; i++) GridPoints[i] = (cmsUInt32Number) Dimensions8[i]; - -+ for (i = 0; i < nMaxGrids; i++) { -+ if (Dimensions8[i] == 1) goto Error; // Impossible value, 0 for no CLUT and then 2 at least -+ GridPoints[i] = (cmsUInt32Number)Dimensions8[i]; -+ } -+ - // Allocate the true CLUT - mpe = cmsStageAllocCLutFloatGranular(self ->ContextID, GridPoints, InputChans, OutputChans, NULL); - if (mpe == NULL) goto Error; diff --git a/third_party/lcms/0012-memory-leak-Type_NamedColor_Read.patch b/third_party/lcms/0012-memory-leak-Type_NamedColor_Read.patch new file mode 100644 index 0000000000..ce9e1bf5b6 --- /dev/null +++ b/third_party/lcms/0012-memory-leak-Type_NamedColor_Read.patch @@ -0,0 +1,22 @@ +diff --git a/third_party/lcms/src/cmstypes.c b/third_party/lcms/src/cmstypes.c +index 941107e1a..f2119ae0a 100644 +--- a/third_party/lcms/src/cmstypes.c ++++ b/third_party/lcms/src/cmstypes.c +@@ -3105,7 +3105,7 @@ void *Type_NamedColor_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* i + + if (nDeviceCoords > cmsMAXCHANNELS) { + cmsSignalError(self->ContextID, cmsERROR_RANGE, "Too many device coordinates '%d'", nDeviceCoords); +- return 0; ++ goto Error; + } + for (i=0; i < count; i++) { + +@@ -3114,7 +3114,7 @@ void *Type_NamedColor_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* i + char Root[33]; + + memset(Colorant, 0, sizeof(Colorant)); +- if (io -> Read(io, Root, 32, 1) != 1) return NULL; ++ if (io -> Read(io, Root, 32, 1) != 1) goto Error; + Root[32] = 0; // To prevent exploits + + if (!_cmsReadUInt16Array(io, 3, PCS)) goto Error; diff --git a/third_party/lcms/0013-memory-leak-OptimizeByResampling.patch b/third_party/lcms/0013-memory-leak-OptimizeByResampling.patch new file mode 100644 index 0000000000..48645d1f01 --- /dev/null +++ b/third_party/lcms/0013-memory-leak-OptimizeByResampling.patch @@ -0,0 +1,13 @@ +diff --git a/third_party/lcms/src/cmsopt.c b/third_party/lcms/src/cmsopt.c +index f885ef3..684910d 100644 +--- a/third_party/lcms/src/cmsopt.c ++++ b/third_party/lcms/src/cmsopt.c +@@ -612,7 +612,7 @@ cmsBool OptimizeByResampling(cmsPipeline** Lut, cmsUInt32Number Intent, cmsUInt3 + + // Allocate the CLUT + CLUT = cmsStageAllocCLut16bit(Src ->ContextID, nGridPoints, Src ->InputChannels, Src->OutputChannels, NULL); +- if (CLUT == NULL) return FALSE; ++ if (CLUT == NULL) goto Error; + + // Add the CLUT to the destination LUT + if (!cmsPipelineInsertStage(Dest, cmsAT_END, CLUT)) { diff --git a/third_party/lcms/0013-utf8.patch b/third_party/lcms/0013-utf8.patch deleted file mode 100644 index c143aa8793..0000000000 --- a/third_party/lcms/0013-utf8.patch +++ /dev/null @@ -1,99 +0,0 @@ -diff --git a/third_party/lcms/src/cmscgats.c b/third_party/lcms/src/cmscgats.c -index 9017435..5720c66 100644 ---- a/third_party/lcms/src/cmscgats.c -+++ b/third_party/lcms/src/cmscgats.c -@@ -258,7 +258,7 @@ static PROPERTY PredefinedProperties[] = { - // needed. - - {"SAMPLE_BACKING", WRITE_STRINGIFY}, // Identifies the backing material used behind the sample during -- // measurement. Allowed values are “black? “white? or {"na". -+ // measurement. Allowed values are "black" "white" or "na". - - {"CHISQ_DOF", WRITE_STRINGIFY}, // Degrees of freedom associated with the Chi squared statistic - -@@ -274,7 +274,7 @@ static PROPERTY PredefinedProperties[] = { - // denote the use of filters such as none, D65, Red, Green or Blue. - - {"POLARIZATION", WRITE_STRINGIFY}, // Identifies the use of a physical polarization filter during measurement. Allowed -- // values are {"yes? “white? “none?or “na? -+ // values are "yes" "white" "none" or "na" - - {"WEIGHTING_FUNCTION", WRITE_PAIR}, // Indicates such functions as: the CIE standard observer functions used in the - // calculation of various data parameters (2 degree and 10 degree), CIE standard -diff --git a/third_party/lcms/src/cmstypes.c b/third_party/lcms/src/cmstypes.c -index 386439b..e5ed06c 100644 ---- a/third_party/lcms/src/cmstypes.c -+++ b/third_party/lcms/src/cmstypes.c -@@ -962,7 +962,7 @@ cmsBool Type_Text_Description_Write(struct _cms_typehandler_struct* self, cmsIO - len = cmsMLUgetASCII(mlu, cmsNoLanguage, cmsNoCountry, NULL, 0); - - // From ICC3.4: It has been found that textDescriptionType can contain misaligned data -- //(see clause 4.1 for the definition of “aligned?. Because the Unicode language -+ //(see clause 4.1 for the definition of 'aligned'. Because the Unicode language - // code and Unicode count immediately follow the ASCII description, their - // alignment is not correct if the ASCII count is not a multiple of four. The - // ScriptCode code is misaligned when the ASCII count is odd. Profile reading and -@@ -3064,9 +3064,10 @@ void Type_ColorantTable_Free(struct _cms_typehandler_struct* self, void* Ptr) - //The namedColor2Type is a count value and array of structures that provide color - //coordinates for 7-bit ASCII color names. For each named color, a PCS and optional - //device representation of the color are given. Both representations are 16-bit values. --//The device representation corresponds to the header’s “color space of data?field. --//This representation should be consistent with the “number of device components?//field in the namedColor2Type. If this field is 0, device coordinates are not provided. --//The PCS representation corresponds to the header’s PCS field. The PCS representation -+//The device representation corresponds to the header's 'color space of data' field. -+//This representation should be consistent with the 'number of device components' -+//field in the namedColor2Type. If this field is 0, device coordinates are not provided. -+//The PCS representation corresponds to the header's PCS field. The PCS representation - //is always provided. Color names are fixed-length, 32-byte fields including null - //termination. In order to maintain maximum portability, it is strongly recommended - //that special characters of the 7-bit ASCII set not be used. -@@ -3809,7 +3810,8 @@ void Type_Screening_Free(struct _cms_typehandler_struct* self, void* Ptr) - // ******************************************************************************** - // - //This type represents a set of viewing condition parameters including: --//CIE ’absolute?illuminant white point tristimulus values and CIE ’absolute?//surround tristimulus values. -+//CIE 'absolute'illuminant white point tristimulus values and CIE 'absolute' -+//surround tristimulus values. - - static - void *Type_ViewingConditions_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag) -@@ -3895,7 +3897,7 @@ void GenericMPEfree(struct _cms_typehandler_struct* self, void *Ptr) - } - - // Each curve is stored in one or more curve segments, with break-points specified between curve segments. --// The first curve segment always starts at –Infinity, and the last curve segment always ends at +Infinity. The -+// The first curve segment always starts at -Infinity, and the last curve segment always ends at +Infinity. The - // first and last curve segments shall be specified in terms of a formula, whereas the other segments shall be - // specified either in terms of a formula, or by a sampled curve. - -diff --git a/third_party/lcms/src/cmsvirt.c b/third_party/lcms/src/cmsvirt.c -index b324c99..d19ace1 100644 ---- a/third_party/lcms/src/cmsvirt.c -+++ b/third_party/lcms/src/cmsvirt.c -@@ -612,18 +612,18 @@ cmsHPROFILE CMSEXPORT cmsCreateXYZProfile(void) - - //sRGB Curves are defined by: - // --//If R’sRGB,G’sRGB, B’sRGB < 0.04045 -+//If R'sRGB,G'sRGB, B'sRGB < 0.04045 - // --// R = R’sRGB / 12.92 --// G = G’sRGB / 12.92 --// B = B’sRGB / 12.92 -+// R = R'sRGB / 12.92 -+// G = G'sRGB / 12.92 -+// B = B'sRGB / 12.92 - // - // --//else if R’sRGB,G’sRGB, B’sRGB >= 0.04045 -+//else if R'sRGB,G'sRGB, B'sRGB >= 0.04045 - // --// R = ((R’sRGB + 0.055) / 1.055)^2.4 --// G = ((G’sRGB + 0.055) / 1.055)^2.4 --// B = ((B’sRGB + 0.055) / 1.055)^2.4 -+// R = ((R'sRGB + 0.055) / 1.055)^2.4 -+// G = ((G'sRGB + 0.055) / 1.055)^2.4 -+// B = ((B'sRGB + 0.055) / 1.055)^2.4 - - static - cmsToneCurve* Build_sRGBGamma(cmsContext ContextID) diff --git a/third_party/lcms/0014-avoid-fixed-inf.patch b/third_party/lcms/0014-avoid-fixed-inf.patch deleted file mode 100644 index b7960e6885..0000000000 --- a/third_party/lcms/0014-avoid-fixed-inf.patch +++ /dev/null @@ -1,95 +0,0 @@ -diff --git a/third_party/lcms/src/cmsopt.c b/third_party/lcms/src/cmsopt.c -index 684910d..76de015 100644 ---- a/third_party/lcms/src/cmsopt.c -+++ b/third_party/lcms/src/cmsopt.c -@@ -1443,7 +1443,7 @@ void MatShaperEval16(register const cmsUInt16Number In[], - - // This table converts from 8 bits to 1.14 after applying the curve - static --void FillFirstShaper(cmsS1Fixed14Number* Table, cmsToneCurve* Curve) -+cmsBool FillFirstShaper(cmsS1Fixed14Number* Table, cmsToneCurve* Curve) - { - int i; - cmsFloat32Number R, y; -@@ -1452,14 +1452,17 @@ void FillFirstShaper(cmsS1Fixed14Number* Table, cmsToneCurve* Curve) - - R = (cmsFloat32Number) (i / 255.0); - y = cmsEvalToneCurveFloat(Curve, R); -+ if (isinf(y)) -+ return FALSE; - - Table[i] = DOUBLE_TO_1FIXED14(y); - } -+ return TRUE; - } - - // This table converts form 1.14 (being 0x4000 the last entry) to 8 bits after applying the curve - static --void FillSecondShaper(cmsUInt16Number* Table, cmsToneCurve* Curve, cmsBool Is8BitsOutput) -+cmsBool FillSecondShaper(cmsUInt16Number* Table, cmsToneCurve* Curve, cmsBool Is8BitsOutput) - { - int i; - cmsFloat32Number R, Val; -@@ -1468,6 +1471,8 @@ void FillSecondShaper(cmsUInt16Number* Table, cmsToneCurve* Curve, cmsBool Is8Bi - - R = (cmsFloat32Number) (i / 16384.0); - Val = cmsEvalToneCurveFloat(Curve, R); // Val comes 0..1.0 -+ if (isinf(Val)) -+ return FALSE; - - if (Is8BitsOutput) { - -@@ -1482,6 +1487,7 @@ void FillSecondShaper(cmsUInt16Number* Table, cmsToneCurve* Curve, cmsBool Is8Bi - } - else Table[i] = _cmsQuickSaturateWord(Val * 65535.0); - } -+ return TRUE; - } - - // Compute the matrix-shaper structure -@@ -1499,13 +1505,19 @@ cmsBool SetMatShaper(cmsPipeline* Dest, cmsToneCurve* Curve1[3], cmsMAT3* Mat, c - p -> ContextID = Dest -> ContextID; - - // Precompute tables -- FillFirstShaper(p ->Shaper1R, Curve1[0]); -- FillFirstShaper(p ->Shaper1G, Curve1[1]); -- FillFirstShaper(p ->Shaper1B, Curve1[2]); -+ if (!FillFirstShaper(p ->Shaper1R, Curve1[0])) -+ goto Error; -+ if (!FillFirstShaper(p ->Shaper1G, Curve1[1])) -+ goto Error; -+ if (!FillFirstShaper(p ->Shaper1B, Curve1[2])) -+ goto Error; - -- FillSecondShaper(p ->Shaper2R, Curve2[0], Is8Bits); -- FillSecondShaper(p ->Shaper2G, Curve2[1], Is8Bits); -- FillSecondShaper(p ->Shaper2B, Curve2[2], Is8Bits); -+ if (!FillSecondShaper(p ->Shaper2R, Curve2[0], Is8Bits)) -+ goto Error; -+ if (!FillSecondShaper(p ->Shaper2G, Curve2[1], Is8Bits)) -+ goto Error; -+ if (!FillSecondShaper(p ->Shaper2B, Curve2[2], Is8Bits)) -+ goto Error; - - // Convert matrix to nFixed14. Note that those values may take more than 16 bits as - for (i=0; i < 3; i++) { -@@ -1531,6 +1543,9 @@ cmsBool SetMatShaper(cmsPipeline* Dest, cmsToneCurve* Curve1[3], cmsMAT3* Mat, c - // Fill function pointers - _cmsPipelineSetOptimizationParameters(Dest, MatShaperEval16, (void*) p, FreeMatShaper, DupMatShaper); - return TRUE; -+Error: -+ _cmsFree(Dest->ContextID, p); -+ return FALSE; - } - - // 8 bits on input allows matrix-shaper boot up to 25 Mpixels per second on RGB. That's fast! -@@ -1606,7 +1621,8 @@ cmsBool OptimizeMatrixShaper(cmsPipeline** Lut, cmsUInt32Number Intent, cmsUInt3 - *dwFlags |= cmsFLAGS_NOCACHE; - - // Setup the optimizarion routines -- SetMatShaper(Dest, mpeC1 ->TheCurves, &res, (cmsVEC3*) Data2 ->Offset, mpeC2->TheCurves, OutputFormat); -+ if (!SetMatShaper(Dest, mpeC1 ->TheCurves, &res, (cmsVEC3*) Data2 ->Offset, mpeC2->TheCurves, OutputFormat)) -+ goto Error; - } - - cmsPipelineFree(Src); diff --git a/third_party/lcms/0014-memory-leak-Type_MPEmatrix_Read.patch b/third_party/lcms/0014-memory-leak-Type_MPEmatrix_Read.patch new file mode 100644 index 0000000000..8cc477fb8e --- /dev/null +++ b/third_party/lcms/0014-memory-leak-Type_MPEmatrix_Read.patch @@ -0,0 +1,30 @@ +diff --git a/third_party/lcms/src/cmstypes.c b/third_party/lcms/src/cmstypes.c +index 441d6bb..15199c7 100644 +--- a/third_party/lcms/src/cmstypes.c ++++ b/third_party/lcms/src/cmstypes.c +@@ -4203,7 +4203,11 @@ void *Type_MPEmatrix_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io + + cmsFloat32Number v; + +- if (!_cmsReadFloat32Number(io, &v)) return NULL; ++ if (!_cmsReadFloat32Number(io, &v)) { ++ _cmsFree(self ->ContextID, Matrix); ++ _cmsFree(self ->ContextID, Offsets); ++ return NULL; ++ } + Matrix[i] = v; + } + +@@ -4212,7 +4216,11 @@ void *Type_MPEmatrix_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io + + cmsFloat32Number v; + +- if (!_cmsReadFloat32Number(io, &v)) return NULL; ++ if (!_cmsReadFloat32Number(io, &v)) { ++ _cmsFree(self ->ContextID, Matrix); ++ _cmsFree(self ->ContextID, Offsets); ++ return NULL; ++ } + Offsets[i] = v; + } + diff --git a/third_party/lcms/0015-cmsStageAllocMatrix-param-swap.patch b/third_party/lcms/0015-cmsStageAllocMatrix-param-swap.patch new file mode 100644 index 0000000000..04f854398c --- /dev/null +++ b/third_party/lcms/0015-cmsStageAllocMatrix-param-swap.patch @@ -0,0 +1,20 @@ +diff --git a/third_party/lcms/src/cmslut.c b/third_party/lcms/src/cmslut.c +index 73e6726..9b0eb4b 100644 +--- a/third_party/lcms/src/cmslut.c ++++ b/third_party/lcms/src/cmslut.c +@@ -414,13 +414,13 @@ cmsStage* CMSEXPORT cmsStageAllocMatrix(cmsContext ContextID, cmsUInt32Number R + + if (Offset != NULL) { + +- NewElem ->Offset = (cmsFloat64Number*) _cmsCalloc(ContextID, Cols, sizeof(cmsFloat64Number)); ++ NewElem ->Offset = (cmsFloat64Number*) _cmsCalloc(ContextID, Rows, sizeof(cmsFloat64Number)); + if (NewElem->Offset == NULL) { + MatrixElemTypeFree(NewMPE); + return NULL; + } + +- for (i=0; i < Cols; i++) { ++ for (i=0; i < Rows; i++) { + NewElem ->Offset[i] = Offset[i]; + } + diff --git a/third_party/lcms/0015-sanitize-float-read.patch b/third_party/lcms/0015-sanitize-float-read.patch deleted file mode 100644 index 568fd0e112..0000000000 --- a/third_party/lcms/0015-sanitize-float-read.patch +++ /dev/null @@ -1,15 +0,0 @@ -diff --git a/third_party/lcms/src/cmsplugin.c b/third_party/lcms/src/cmsplugin.c -index b95befb..4ba998b 100644 ---- a/third_party/lcms/src/cmsplugin.c -+++ b/third_party/lcms/src/cmsplugin.c -@@ -182,7 +182,9 @@ cmsBool CMSEXPORT _cmsReadFloat32Number(cmsIOHANDLER* io, cmsFloat32Number* n) - if (isnan(*n)) - return FALSE; - } -- return TRUE; -+ -+ // fpclassify() required by C99 -+ return (fpclassify(*n) == FP_ZERO) || (fpclassify(*n) == FP_NORMAL); - } - - diff --git a/third_party/lcms/0016-check-LUT-and-MPE.patch b/third_party/lcms/0016-check-LUT-and-MPE.patch deleted file mode 100644 index e2efe5a3a7..0000000000 --- a/third_party/lcms/0016-check-LUT-and-MPE.patch +++ /dev/null @@ -1,170 +0,0 @@ -diff --git a/third_party/lcms/src/cmslut.c b/third_party/lcms/src/cmslut.c -index 9b0eb4b54..19d43361f 100644 ---- a/third_party/lcms/src/cmslut.c -+++ b/third_party/lcms/src/cmslut.c -@@ -1255,21 +1255,39 @@ cmsStage* CMSEXPORT cmsStageDup(cmsStage* mpe) - // *********************************************************************************************************** - - // This function sets up the channel count -- - static --void BlessLUT(cmsPipeline* lut) -+cmsBool BlessLUT(cmsPipeline* lut) - { - // We can set the input/ouput channels only if we have elements. - if (lut ->Elements != NULL) { - -- cmsStage *First, *Last; -+ cmsStage* prev; -+ cmsStage* next; -+ cmsStage* First; -+ cmsStage* Last; - - First = cmsPipelineGetPtrToFirstStage(lut); - Last = cmsPipelineGetPtrToLastStage(lut); - -- if (First != NULL)lut ->InputChannels = First ->InputChannels; -- if (Last != NULL) lut ->OutputChannels = Last ->OutputChannels; -+ if (First == NULL || Last == NULL) return FALSE; -+ -+ lut->InputChannels = First->InputChannels; -+ lut->OutputChannels = Last->OutputChannels; -+ -+ // Check chain consistency -+ prev = First; -+ next = prev->Next; -+ -+ while (next != NULL) -+ { -+ if (next->InputChannels != prev->OutputChannels) -+ return FALSE; -+ -+ next = next->Next; -+ prev = prev->Next; -+ } - } -+ return TRUE; - } - - -@@ -1331,6 +1349,7 @@ cmsPipeline* CMSEXPORT cmsPipelineAlloc(cmsContext ContextID, cmsUInt32Number In - { - cmsPipeline* NewLUT; - -+ // A value of zero in channels is allowed as placeholder - if (InputChannels >= cmsMAXCHANNELS || - OutputChannels >= cmsMAXCHANNELS) return NULL; - -@@ -1348,7 +1367,11 @@ cmsPipeline* CMSEXPORT cmsPipelineAlloc(cmsContext ContextID, cmsUInt32Number In - NewLUT ->Data = NewLUT; - NewLUT ->ContextID = ContextID; - -- BlessLUT(NewLUT); -+ if (!BlessLUT(NewLUT)) -+ { -+ _cmsFree(ContextID, NewLUT); -+ return NULL; -+ } - - return NewLUT; - } -@@ -1454,7 +1477,12 @@ cmsPipeline* CMSEXPORT cmsPipelineDup(const cmsPipeline* lut) - - NewLUT ->SaveAs8Bits = lut ->SaveAs8Bits; - -- BlessLUT(NewLUT); -+ if (!BlessLUT(NewLUT)) -+ { -+ _cmsFree(lut->ContextID, NewLUT); -+ return NULL; -+ } -+ - return NewLUT; - } - -@@ -1491,8 +1519,7 @@ int CMSEXPORT cmsPipelineInsertStage(cmsPipeline* lut, cmsStageLoc loc, cmsStage - return FALSE; - } - -- BlessLUT(lut); -- return TRUE; -+ return BlessLUT(lut); - } - - // Unlink an element and return the pointer to it -@@ -1547,6 +1574,7 @@ void CMSEXPORT cmsPipelineUnlinkStage(cmsPipeline* lut, cmsStageLoc loc, cmsStag - else - cmsStageFree(Unlinked); - -+ // May fail, but we ignore it - BlessLUT(lut); - } - -@@ -1573,8 +1601,7 @@ cmsBool CMSEXPORT cmsPipelineCat(cmsPipeline* l1, const cmsPipeline* l2) - return FALSE; - } - -- BlessLUT(l1); -- return TRUE; -+ return BlessLUT(l1); - } - - -diff --git a/third_party/lcms/src/cmstypes.c b/third_party/lcms/src/cmstypes.c -index e5ed06c33..0256e247b 100644 ---- a/third_party/lcms/src/cmstypes.c -+++ b/third_party/lcms/src/cmstypes.c -@@ -1755,8 +1755,8 @@ void *Type_LUT8_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cms - if (!_cmsReadUInt8Number(io, NULL)) goto Error; - - // Do some checking -- if (InputChannels > cmsMAXCHANNELS) goto Error; -- if (OutputChannels > cmsMAXCHANNELS) goto Error; -+ if (InputChannels == 0 || InputChannels > cmsMAXCHANNELS) goto Error; -+ if (OutputChannels == 0 || OutputChannels > cmsMAXCHANNELS) goto Error; - - // Allocates an empty Pipeline - NewLUT = cmsPipelineAlloc(self ->ContextID, InputChannels, OutputChannels); -@@ -2048,8 +2048,8 @@ void *Type_LUT16_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cm - if (!_cmsReadUInt8Number(io, NULL)) return NULL; - - // Do some checking -- if (InputChannels > cmsMAXCHANNELS) goto Error; -- if (OutputChannels > cmsMAXCHANNELS) goto Error; -+ if (InputChannels == 0 || InputChannels > cmsMAXCHANNELS) goto Error; -+ if (OutputChannels == 0 || OutputChannels > cmsMAXCHANNELS) goto Error; - - // Allocates an empty LUT - NewLUT = cmsPipelineAlloc(self ->ContextID, InputChannels, OutputChannels); -@@ -2486,7 +2486,10 @@ void* Type_LUTA2B_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, c - if (!_cmsReadUInt32Number(io, &offsetC)) return NULL; - if (!_cmsReadUInt32Number(io, &offsetA)) return NULL; - -- // Allocates an empty LUT -+ if (inputChan == 0 || inputChan >= cmsMAXCHANNELS) return NULL; -+ if (outputChan == 0 || outputChan >= cmsMAXCHANNELS) return NULL; -+ -+ // Allocates an empty LUT - NewLUT = cmsPipelineAlloc(self ->ContextID, inputChan, outputChan); - if (NewLUT == NULL) return NULL; - -@@ -2794,6 +2797,9 @@ void* Type_LUTB2A_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, c - if (!_cmsReadUInt8Number(io, &inputChan)) return NULL; - if (!_cmsReadUInt8Number(io, &outputChan)) return NULL; - -+ if (inputChan == 0 || inputChan >= cmsMAXCHANNELS) return NULL; -+ if (outputChan == 0 || outputChan >= cmsMAXCHANNELS) return NULL; -+ - // Padding - if (!_cmsReadUInt16Number(io, NULL)) return NULL; - -@@ -4443,6 +4449,9 @@ void *Type_MPE_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsU - if (!_cmsReadUInt16Number(io, &InputChans)) return NULL; - if (!_cmsReadUInt16Number(io, &OutputChans)) return NULL; - -+ if (InputChans == 0 || InputChans >= cmsMAXCHANNELS) return NULL; -+ if (OutputChans == 0 || OutputChans >= cmsMAXCHANNELS) return NULL; -+ - // Allocates an empty LUT - NewLUT = cmsPipelineAlloc(self ->ContextID, InputChans, OutputChans); - if (NewLUT == NULL) return NULL; diff --git a/third_party/lcms/0016-reject-nan.patch b/third_party/lcms/0016-reject-nan.patch new file mode 100644 index 0000000000..c2b5068645 --- /dev/null +++ b/third_party/lcms/0016-reject-nan.patch @@ -0,0 +1,13 @@ +diff --git a/third_party/lcms/src/cmsplugin.c b/third_party/lcms/src/cmsplugin.c +index 79b145d2d..29ddd9a49 100644 +--- a/third_party/lcms/src/cmsplugin.c ++++ b/third_party/lcms/src/cmsplugin.c +@@ -179,6 +179,8 @@ cmsBool CMSEXPORT _cmsReadFloat32Number(cmsIOHANDLER* io, cmsFloat32Number* n) + + tmp = _cmsAdjustEndianess32(tmp); + *n = *(cmsFloat32Number*) (void*) &tmp; ++ if (isnan(*n)) ++ return FALSE; + } + return TRUE; + } diff --git a/third_party/lcms/0017-memory-leak-ReadSegmentedCurve.patch b/third_party/lcms/0017-memory-leak-ReadSegmentedCurve.patch new file mode 100644 index 0000000000..472bcadf05 --- /dev/null +++ b/third_party/lcms/0017-memory-leak-ReadSegmentedCurve.patch @@ -0,0 +1,36 @@ +diff --git a/third_party/lcms/src/cmstypes.c b/third_party/lcms/src/cmstypes.c +index 15199c7..04dd0c4 100644 +--- a/third_party/lcms/src/cmstypes.c ++++ b/third_party/lcms/src/cmstypes.c +@@ -3968,7 +3968,7 @@ cmsToneCurve* ReadSegmentedCurve(struct _cms_typehandler_struct* self, cmsIOHAND + case cmsSigSampledCurveSeg: { + cmsUInt32Number Count; + +- if (!_cmsReadUInt32Number(io, &Count)) return NULL; ++ if (!_cmsReadUInt32Number(io, &Count)) goto Error; + + Segments[i].nGridPoints = Count; + Segments[i].SampledPoints = (cmsFloat32Number*) _cmsCalloc(self ->ContextID, Count, sizeof(cmsFloat32Number)); +@@ -3987,7 +3987,7 @@ cmsToneCurve* ReadSegmentedCurve(struct _cms_typehandler_struct* self, cmsIOHAND + _cmsTagSignature2String(String, (cmsTagSignature) ElementSig); + cmsSignalError(self->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unknown curve element type '%s' found.", String); + } +- return NULL; ++ goto Error; + + } + } +@@ -4001,7 +4001,12 @@ cmsToneCurve* ReadSegmentedCurve(struct _cms_typehandler_struct* self, cmsIOHAND + return Curve; + + Error: +- if (Segments) _cmsFree(self ->ContextID, Segments); ++ if (Segments) { ++ for (i=0; i < nSegments; i++) { ++ if (Segments[i].SampledPoints) _cmsFree(self ->ContextID, Segments[i].SampledPoints); ++ } ++ _cmsFree(self ->ContextID, Segments); ++ } + return NULL; + } + diff --git a/third_party/lcms/0017-upstream-integer-overflow-MPEmatrix_Read.patch b/third_party/lcms/0017-upstream-integer-overflow-MPEmatrix_Read.patch deleted file mode 100644 index 70a6bb9b20..0000000000 --- a/third_party/lcms/0017-upstream-integer-overflow-MPEmatrix_Read.patch +++ /dev/null @@ -1,85 +0,0 @@ -diff --git a/third_party/lcms/src/cmscgats.c b/third_party/lcms/src/cmscgats.c -index 5720c66a7..cce4cedba 100644 ---- a/third_party/lcms/src/cmscgats.c -+++ b/third_party/lcms/src/cmscgats.c -@@ -150,23 +150,24 @@ typedef struct { - SUBALLOCATOR Allocator; // String suballocator -- just to keep it fast - - // Parser state machine -- SYMBOL sy; // Current symbol -- int ch; // Current character -+ SYMBOL sy; // Current symbol -+ int ch; // Current character -+ -+ cmsInt32Number inum; // integer value -+ cmsFloat64Number dnum; // real value - -- int inum; // integer value -- cmsFloat64Number dnum; // real value - char id[MAXID]; // identifier - char str[MAXSTR]; // string - - // Allowed keywords & datasets. They have visibility on whole stream -- KEYVALUE* ValidKeywords; -- KEYVALUE* ValidSampleID; -+ KEYVALUE* ValidKeywords; -+ KEYVALUE* ValidSampleID; - - char* Source; // Points to loc. being parsed -- int lineno; // line counter for error reporting -+ cmsInt32Number lineno; // line counter for error reporting - - FILECTX* FileStack[MAXINCLUDE]; // Stack of files being parsed -- int IncludeSP; // Include Stack Pointer -+ cmsInt32Number IncludeSP; // Include Stack Pointer - - char* MemoryBlock; // The stream if holded in memory - -@@ -568,8 +569,8 @@ void ReadReal(cmsIT8* it8, int inum) - // Exponent, example 34.00E+20 - if (toupper(it8->ch) == 'E') { - -- int e; -- int sgn; -+ cmsInt32Number e; -+ cmsInt32Number sgn; - - NextCh(it8); sgn = 1; - -@@ -587,7 +588,7 @@ void ReadReal(cmsIT8* it8, int inum) - e = 0; - while (isdigit(it8->ch)) { - -- if ((cmsFloat64Number) e * 10L < INT_MAX) -+ if ((cmsFloat64Number) e * 10L < (cmsFloat64Number) +2147483647.0) - e = e * 10 + (it8->ch - '0'); - - NextCh(it8); -@@ -777,7 +778,7 @@ void InSymbol(cmsIT8* it8) - - while (isdigit(it8->ch)) { - -- if ((long) it8->inum * 10L > (long) INT_MAX) { -+ if ((cmsFloat64Number) it8->inum * 10L > (cmsFloat64Number) +2147483647.0) { - ReadReal(it8, it8->inum); - it8->sy = SDNUM; - it8->dnum *= sign; -diff --git a/third_party/lcms/src/cmstypes.c b/third_party/lcms/src/cmstypes.c -index 0256e247b..75f1fae32 100644 ---- a/third_party/lcms/src/cmstypes.c -+++ b/third_party/lcms/src/cmstypes.c -@@ -4199,9 +4199,13 @@ void *Type_MPEmatrix_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io - if (!_cmsReadUInt16Number(io, &OutputChans)) return NULL; - - -+ // Input and output chans may be ANY (up to 0xffff), -+ // but we choose to limit to 16 channels for now -+ if (InputChans >= cmsMAXCHANNELS) return NULL; -+ if (OutputChans >= cmsMAXCHANNELS) return NULL; -+ - nElems = InputChans * OutputChans; - -- // Input and output chans may be ANY (up to 0xffff) - Matrix = (cmsFloat64Number*) _cmsCalloc(self ->ContextID, nElems, sizeof(cmsFloat64Number)); - if (Matrix == NULL) return NULL; - diff --git a/third_party/lcms/0018-backport-c0a98d86.patch b/third_party/lcms/0018-backport-c0a98d86.patch new file mode 100644 index 0000000000..34b5477b34 --- /dev/null +++ b/third_party/lcms/0018-backport-c0a98d86.patch @@ -0,0 +1,53 @@ +diff --git a/third_party/lcms/src/cmsintrp.c b/third_party/lcms/src/cmsintrp.c +index 5d5f35d..14c6856 100644 +--- a/third_party/lcms/src/cmsintrp.c ++++ b/third_party/lcms/src/cmsintrp.c +@@ -215,7 +215,7 @@ void LinLerp1D(register const cmsUInt16Number Value[], + // To prevent out of bounds indexing + cmsINLINE cmsFloat32Number fclamp(cmsFloat32Number v) + { +- return v < 0.0f ? 0.0f : (v > 1.0f ? 1.0f : v); ++ return ((v < 0.0f) || isnan(v)) ? 0.0f : (v > 1.0f ? 1.0f : v); + } + + // Floating-point version of 1D interpolation +diff --git a/third_party/lcms/src/cmsio0.c b/third_party/lcms/src/cmsio0.c +index 5f9f08a..3ed730a 100644 +--- a/third_party/lcms/src/cmsio0.c ++++ b/third_party/lcms/src/cmsio0.c +@@ -1475,6 +1475,17 @@ void* CMSEXPORT cmsReadTag(cmsHPROFILE hProfile, cmsTagSignature sig) + // If the element is already in memory, return the pointer + if (Icc -> TagPtrs[n]) { + ++ if (Icc->TagTypeHandlers[n] == NULL) goto Error; ++ ++ // Sanity check ++ BaseType = Icc->TagTypeHandlers[n]->Signature; ++ if (BaseType == 0) goto Error; ++ ++ TagDescriptor = _cmsGetTagDescriptor(Icc->ContextID, sig); ++ if (TagDescriptor == NULL) goto Error; ++ ++ if (!IsTypeSupported(TagDescriptor, BaseType)) goto Error; ++ + if (Icc ->TagSaveAsRaw[n]) goto Error; // We don't support read raw tags as cooked + + _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex); +diff --git a/third_party/lcms/src/cmstypes.c b/third_party/lcms/src/cmstypes.c +index 04dd0c4..386439b 100644 +--- a/third_party/lcms/src/cmstypes.c ++++ b/third_party/lcms/src/cmstypes.c +@@ -4297,8 +4297,12 @@ void *Type_MPEclut_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, + + // Copy MAX_INPUT_DIMENSIONS at most. Expand to cmsUInt32Number + nMaxGrids = InputChans > MAX_INPUT_DIMENSIONS ? MAX_INPUT_DIMENSIONS : InputChans; +- for (i=0; i < nMaxGrids; i++) GridPoints[i] = (cmsUInt32Number) Dimensions8[i]; + ++ for (i = 0; i < nMaxGrids; i++) { ++ if (Dimensions8[i] == 1) goto Error; // Impossible value, 0 for no CLUT and then 2 at least ++ GridPoints[i] = (cmsUInt32Number)Dimensions8[i]; ++ } ++ + // Allocate the true CLUT + mpe = cmsStageAllocCLutFloatGranular(self ->ContextID, GridPoints, InputChans, OutputChans, NULL); + if (mpe == NULL) goto Error; diff --git a/third_party/lcms/0018-verify-size-before-reading.patch b/third_party/lcms/0018-verify-size-before-reading.patch deleted file mode 100644 index e72e310a1b..0000000000 --- a/third_party/lcms/0018-verify-size-before-reading.patch +++ /dev/null @@ -1,17 +0,0 @@ -diff --git a/third_party/lcms/src/cmstypes.c b/third_party/lcms/src/cmstypes.c -index 75f1fae32..4d96a1ed6 100644 ---- a/third_party/lcms/src/cmstypes.c -+++ b/third_party/lcms/src/cmstypes.c -@@ -173,6 +173,12 @@ cmsBool ReadPositionTable(struct _cms_typehandler_struct* self, - { - cmsUInt32Number i; - cmsUInt32Number *ElementOffsets = NULL, *ElementSizes = NULL; -+ cmsUInt32Number currentPosition; -+ -+ currentPosition = io->Tell(io); -+ // Verify there is enough space left to read two cmsUInt32Number items for Count items. -+ if (((io->ReportedSize - currentPosition) / (2 * sizeof(cmsUInt32Number))) < Count) -+ return FALSE; - - // Let's take the offsets to each element - ElementOffsets = (cmsUInt32Number *) _cmsCalloc(io ->ContextID, Count, sizeof(cmsUInt32Number)); diff --git a/third_party/lcms/0019-upstream-direct-leak-Type_MPE_Read.patch b/third_party/lcms/0019-upstream-direct-leak-Type_MPE_Read.patch deleted file mode 100644 index 339333188a..0000000000 --- a/third_party/lcms/0019-upstream-direct-leak-Type_MPE_Read.patch +++ /dev/null @@ -1,31 +0,0 @@ -diff --git a/third_party/lcms/src/cmstypes.c b/third_party/lcms/src/cmstypes.c -index 75f1fae32..f92a92822 100644 ---- a/third_party/lcms/src/cmstypes.c -+++ b/third_party/lcms/src/cmstypes.c -@@ -4460,18 +4460,19 @@ void *Type_MPE_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsU - NewLUT = cmsPipelineAlloc(self ->ContextID, InputChans, OutputChans); - if (NewLUT == NULL) return NULL; - -- if (!_cmsReadUInt32Number(io, &ElementCount)) return NULL; -- -- if (!ReadPositionTable(self, io, ElementCount, BaseOffset, NewLUT, ReadMPEElem)) { -- if (NewLUT != NULL) cmsPipelineFree(NewLUT); -- *nItems = 0; -- return NULL; -- } -+ if (!_cmsReadUInt32Number(io, &ElementCount)) goto Error; -+ if (!ReadPositionTable(self, io, ElementCount, BaseOffset, NewLUT, ReadMPEElem)) goto Error; - - // Success - *nItems = 1; - return NewLUT; - -+ // Error -+Error: -+ if (NewLUT != NULL) cmsPipelineFree(NewLUT); -+ *nItems = 0; -+ return NULL; -+ - cmsUNUSED_PARAMETER(SizeOfTag); - } - diff --git a/third_party/lcms/0019-utf8.patch b/third_party/lcms/0019-utf8.patch new file mode 100644 index 0000000000..351659d409 --- /dev/null +++ b/third_party/lcms/0019-utf8.patch @@ -0,0 +1,98 @@ +diff --git a/third_party/lcms/src/cmscgats.c b/third_party/lcms/src/cmscgats.c +index 6011fb201..d53360b1f 100644 +--- a/third_party/lcms/src/cmscgats.c ++++ b/third_party/lcms/src/cmscgats.c +@@ -255,7 +255,7 @@ static PROPERTY PredefinedProperties[] = { + // needed. + + {"SAMPLE_BACKING", WRITE_STRINGIFY}, // Identifies the backing material used behind the sample during +- // measurement. Allowed values are <93>black<94>, <93>white<94>, or {"na". ++ // measurement. Allowed values are "black" "white" or "na". + + {"CHISQ_DOF", WRITE_STRINGIFY}, // Degrees of freedom associated with the Chi squared statistic + +@@ -271,7 +271,7 @@ static PROPERTY PredefinedProperties[] = { + // denote the use of filters such as none, D65, Red, Green or Blue. + + {"POLARIZATION", WRITE_STRINGIFY}, // Identifies the use of a physical polarization filter during measurement. Allowed +- // values are {"yes<94>, <93>white<94>, <93>none<94> or <93>na<94>. ++ // values are "yes" "white" "none" or "na". + + {"WEIGHTING_FUNCTION", WRITE_PAIR}, // Indicates such functions as: the CIE standard observer functions used in the + // calculation of various data parameters (2 degree and 10 degree), CIE standard +diff --git a/third_party/lcms/src/cmstypes.c b/third_party/lcms/src/cmstypes.c +index 5647264a6..64845e263 100644 +--- a/third_party/lcms/src/cmstypes.c ++++ b/third_party/lcms/src/cmstypes.c +@@ -962,7 +962,7 @@ cmsBool Type_Text_Description_Write(struct _cms_typehandler_struct* self, cmsIO + len = cmsMLUgetASCII(mlu, cmsNoLanguage, cmsNoCountry, NULL, 0); + + // Specification ICC.1:2001-04 (v2.4.0): It has been found that textDescriptionType can contain misaligned data +- //(see clause 4.1 for the definition of <93>aligned<94>). Because the Unicode language ++ //(see clause 4.1 for the definition of 'aligned'. Because the Unicode language + // code and Unicode count immediately follow the ASCII description, their + // alignment is not correct if the ASCII count is not a multiple of four. The + // ScriptCode code is misaligned when the ASCII count is odd. Profile reading and +@@ -3066,10 +3066,10 @@ void Type_ColorantTable_Free(struct _cms_typehandler_struct* self, void* Ptr) + //The namedColor2Type is a count value and array of structures that provide color + //coordinates for 7-bit ASCII color names. For each named color, a PCS and optional + //device representation of the color are given. Both representations are 16-bit values. +-//The device representation corresponds to the header<92>s <93>color space of data<94> field. +-//This representation should be consistent with the <93>number of device components<94> ++//The device representation corresponds to the header's 'color space of data' field. ++//This representation should be consistent with the 'number of device components' + //field in the namedColor2Type. If this field is 0, device coordinates are not provided. +-//The PCS representation corresponds to the header<92>s PCS field. The PCS representation ++//The PCS representation corresponds to the header's PCS field. The PCS representation + //is always provided. Color names are fixed-length, 32-byte fields including null + //termination. In order to maintain maximum portability, it is strongly recommended + //that special characters of the 7-bit ASCII set not be used. +@@ -3814,7 +3814,7 @@ void Type_Screening_Free(struct _cms_typehandler_struct* self, void* Ptr) + // ******************************************************************************** + // + //This type represents a set of viewing condition parameters including: +-//CIE <92>absolute<92> illuminant white point tristimulus values and CIE <92>absolute<92> ++//CIE 'absolute'illuminant white point tristimulus values and CIE 'absolute' + //surround tristimulus values. + + static +@@ -3901,7 +3901,7 @@ void GenericMPEfree(struct _cms_typehandler_struct* self, void *Ptr) + } + + // Each curve is stored in one or more curve segments, with break-points specified between curve segments. +-// The first curve segment always starts at <96>Infinity, and the last curve segment always ends at +Infinity. The ++// The first curve segment always starts at -Infinity, and the last curve segment always ends at +Infinity. The + // first and last curve segments shall be specified in terms of a formula, whereas the other segments shall be + // specified either in terms of a formula, or by a sampled curve. + +diff --git a/third_party/lcms/src/cmsvirt.c b/third_party/lcms/src/cmsvirt.c +index b8795be2c..9eff1f7be 100644 +--- a/third_party/lcms/src/cmsvirt.c ++++ b/third_party/lcms/src/cmsvirt.c +@@ -612,18 +612,18 @@ cmsHPROFILE CMSEXPORT cmsCreateXYZProfile(void) + + //sRGB Curves are defined by: + // +-//If R<92>sRGB,G<92>sRGB, B<92>sRGB < 0.04045 ++//If R'sRGB,G'sRGB, B'sRGB < 0.04045 + // +-// R = R<92>sRGB / 12.92 +-// G = G<92>sRGB / 12.92 +-// B = B<92>sRGB / 12.92 ++// R = R'sRGB / 12.92 ++// G = G'sRGB / 12.92 ++// B = B'sRGB / 12.92 + // + // +-//else if R<92>sRGB,G<92>sRGB, B<92>sRGB >= 0.04045 ++//else if R'sRGB,G'sRGB, B'sRGB >= 0.04045 + // +-// R = ((R<92>sRGB + 0.055) / 1.055)^2.4 +-// G = ((G<92>sRGB + 0.055) / 1.055)^2.4 +-// B = ((B<92>sRGB + 0.055) / 1.055)^2.4 ++// R = ((R'sRGB + 0.055) / 1.055)^2.4 ++// G = ((G'sRGB + 0.055) / 1.055)^2.4 ++// B = ((B'sRGB + 0.055) / 1.055)^2.4 + + static + cmsToneCurve* Build_sRGBGamma(cmsContext ContextID) diff --git a/third_party/lcms/0020-avoid-fixed-inf.patch b/third_party/lcms/0020-avoid-fixed-inf.patch new file mode 100644 index 0000000000..b2397d73f9 --- /dev/null +++ b/third_party/lcms/0020-avoid-fixed-inf.patch @@ -0,0 +1,95 @@ +diff --git a/third_party/lcms/src/cmsopt.c b/third_party/lcms/src/cmsopt.c +index e4a7e4521..23aa54402 100644 +--- a/third_party/lcms/src/cmsopt.c ++++ b/third_party/lcms/src/cmsopt.c +@@ -1546,7 +1546,7 @@ void MatShaperEval16(register const cmsUInt16Number In[], + + // This table converts from 8 bits to 1.14 after applying the curve + static +-void FillFirstShaper(cmsS1Fixed14Number* Table, cmsToneCurve* Curve) ++cmsBool FillFirstShaper(cmsS1Fixed14Number* Table, cmsToneCurve* Curve) + { + int i; + cmsFloat32Number R, y; +@@ -1555,14 +1555,17 @@ void FillFirstShaper(cmsS1Fixed14Number* Table, cmsToneCurve* Curve) + + R = (cmsFloat32Number) (i / 255.0); + y = cmsEvalToneCurveFloat(Curve, R); ++ if (isinf(y)) ++ return FALSE; + + Table[i] = DOUBLE_TO_1FIXED14(y); + } ++ return TRUE; + } + + // This table converts form 1.14 (being 0x4000 the last entry) to 8 bits after applying the curve + static +-void FillSecondShaper(cmsUInt16Number* Table, cmsToneCurve* Curve, cmsBool Is8BitsOutput) ++cmsBool FillSecondShaper(cmsUInt16Number* Table, cmsToneCurve* Curve, cmsBool Is8BitsOutput) + { + int i; + cmsFloat32Number R, Val; +@@ -1571,6 +1574,8 @@ void FillSecondShaper(cmsUInt16Number* Table, cmsToneCurve* Curve, cmsBool Is8Bi + + R = (cmsFloat32Number) (i / 16384.0); + Val = cmsEvalToneCurveFloat(Curve, R); // Val comes 0..1.0 ++ if (isinf(Val)) ++ return FALSE; + + if (Is8BitsOutput) { + +@@ -1585,6 +1590,7 @@ void FillSecondShaper(cmsUInt16Number* Table, cmsToneCurve* Curve, cmsBool Is8Bi + } + else Table[i] = _cmsQuickSaturateWord(Val * 65535.0); + } ++ return TRUE; + } + + // Compute the matrix-shaper structure +@@ -1602,13 +1608,19 @@ cmsBool SetMatShaper(cmsPipeline* Dest, cmsToneCurve* Curve1[3], cmsMAT3* Mat, c + p -> ContextID = Dest -> ContextID; + + // Precompute tables +- FillFirstShaper(p ->Shaper1R, Curve1[0]); +- FillFirstShaper(p ->Shaper1G, Curve1[1]); +- FillFirstShaper(p ->Shaper1B, Curve1[2]); ++ if (!FillFirstShaper(p ->Shaper1R, Curve1[0])) ++ goto Error; ++ if (!FillFirstShaper(p ->Shaper1G, Curve1[1])) ++ goto Error; ++ if (!FillFirstShaper(p ->Shaper1B, Curve1[2])) ++ goto Error; + +- FillSecondShaper(p ->Shaper2R, Curve2[0], Is8Bits); +- FillSecondShaper(p ->Shaper2G, Curve2[1], Is8Bits); +- FillSecondShaper(p ->Shaper2B, Curve2[2], Is8Bits); ++ if (!FillSecondShaper(p ->Shaper2R, Curve2[0], Is8Bits)) ++ goto Error; ++ if (!FillSecondShaper(p ->Shaper2G, Curve2[1], Is8Bits)) ++ goto Error; ++ if (!FillSecondShaper(p ->Shaper2B, Curve2[2], Is8Bits)) ++ goto Error; + + // Convert matrix to nFixed14. Note that those values may take more than 16 bits as + for (i=0; i < 3; i++) { +@@ -1634,6 +1646,9 @@ cmsBool SetMatShaper(cmsPipeline* Dest, cmsToneCurve* Curve1[3], cmsMAT3* Mat, c + // Fill function pointers + _cmsPipelineSetOptimizationParameters(Dest, MatShaperEval16, (void*) p, FreeMatShaper, DupMatShaper); + return TRUE; ++ Error: ++ _cmsFree(Dest->ContextID, p); ++ return FALSE; + } + + // 8 bits on input allows matrix-shaper boot up to 25 Mpixels per second on RGB. That's fast! +@@ -1746,7 +1761,8 @@ cmsBool OptimizeMatrixShaper(cmsPipeline** Lut, cmsUInt32Number Intent, cmsUInt3 + *dwFlags |= cmsFLAGS_NOCACHE; + + // Setup the optimizarion routines +- SetMatShaper(Dest, mpeC1 ->TheCurves, &res, (cmsVEC3*) Offset, mpeC2->TheCurves, OutputFormat); ++ if (!SetMatShaper(Dest, mpeC1 ->TheCurves, &res, (cmsVEC3*) Offset, mpeC2->TheCurves, OutputFormat)) ++ goto Error; + } + + cmsPipelineFree(Src); diff --git a/third_party/lcms/0021-sanitize-float-read.patch b/third_party/lcms/0021-sanitize-float-read.patch new file mode 100644 index 0000000000..568fd0e112 --- /dev/null +++ b/third_party/lcms/0021-sanitize-float-read.patch @@ -0,0 +1,15 @@ +diff --git a/third_party/lcms/src/cmsplugin.c b/third_party/lcms/src/cmsplugin.c +index b95befb..4ba998b 100644 +--- a/third_party/lcms/src/cmsplugin.c ++++ b/third_party/lcms/src/cmsplugin.c +@@ -182,7 +182,9 @@ cmsBool CMSEXPORT _cmsReadFloat32Number(cmsIOHANDLER* io, cmsFloat32Number* n) + if (isnan(*n)) + return FALSE; + } +- return TRUE; ++ ++ // fpclassify() required by C99 ++ return (fpclassify(*n) == FP_ZERO) || (fpclassify(*n) == FP_NORMAL); + } + + diff --git a/third_party/lcms/0022-check-LUT-and-MPE.patch b/third_party/lcms/0022-check-LUT-and-MPE.patch new file mode 100644 index 0000000000..04ddac81ed --- /dev/null +++ b/third_party/lcms/0022-check-LUT-and-MPE.patch @@ -0,0 +1,170 @@ +diff --git a/third_party/lcms/src/cmslut.c b/third_party/lcms/src/cmslut.c +index 9b0eb4b54..19d43361f 100644 +--- a/third_party/lcms/src/cmslut.c ++++ b/third_party/lcms/src/cmslut.c +@@ -1255,21 +1255,39 @@ cmsStage* CMSEXPORT cmsStageDup(cmsStage* mpe) + // *********************************************************************************************************** + + // This function sets up the channel count +- + static +-void BlessLUT(cmsPipeline* lut) ++cmsBool BlessLUT(cmsPipeline* lut) + { + // We can set the input/ouput channels only if we have elements. + if (lut ->Elements != NULL) { + +- cmsStage *First, *Last; ++ cmsStage* prev; ++ cmsStage* next; ++ cmsStage* First; ++ cmsStage* Last; + + First = cmsPipelineGetPtrToFirstStage(lut); + Last = cmsPipelineGetPtrToLastStage(lut); + +- if (First != NULL)lut ->InputChannels = First ->InputChannels; +- if (Last != NULL) lut ->OutputChannels = Last ->OutputChannels; ++ if (First == NULL || Last == NULL) return FALSE; ++ ++ lut->InputChannels = First->InputChannels; ++ lut->OutputChannels = Last->OutputChannels; ++ ++ // Check chain consistency ++ prev = First; ++ next = prev->Next; ++ ++ while (next != NULL) ++ { ++ if (next->InputChannels != prev->OutputChannels) ++ return FALSE; ++ ++ next = next->Next; ++ prev = prev->Next; ++ } + } ++ return TRUE; + } + + +@@ -1331,6 +1349,7 @@ cmsPipeline* CMSEXPORT cmsPipelineAlloc(cmsContext ContextID, cmsUInt32Number In + { + cmsPipeline* NewLUT; + ++ // A value of zero in channels is allowed as placeholder + if (InputChannels >= cmsMAXCHANNELS || + OutputChannels >= cmsMAXCHANNELS) return NULL; + +@@ -1348,7 +1367,11 @@ cmsPipeline* CMSEXPORT cmsPipelineAlloc(cmsContext ContextID, cmsUInt32Number In + NewLUT ->Data = NewLUT; + NewLUT ->ContextID = ContextID; + +- BlessLUT(NewLUT); ++ if (!BlessLUT(NewLUT)) ++ { ++ _cmsFree(ContextID, NewLUT); ++ return NULL; ++ } + + return NewLUT; + } +@@ -1454,7 +1477,12 @@ cmsPipeline* CMSEXPORT cmsPipelineDup(const cmsPipeline* lut) + + NewLUT ->SaveAs8Bits = lut ->SaveAs8Bits; + +- BlessLUT(NewLUT); ++ if (!BlessLUT(NewLUT)) ++ { ++ _cmsFree(lut->ContextID, NewLUT); ++ return NULL; ++ } ++ + return NewLUT; + } + +@@ -1491,8 +1519,7 @@ int CMSEXPORT cmsPipelineInsertStage(cmsPipeline* lut, cmsStageLoc loc, cmsStage + return FALSE; + } + +- BlessLUT(lut); +- return TRUE; ++ return BlessLUT(lut); + } + + // Unlink an element and return the pointer to it +@@ -1547,6 +1574,7 @@ void CMSEXPORT cmsPipelineUnlinkStage(cmsPipeline* lut, cmsStageLoc loc, cmsStag + else + cmsStageFree(Unlinked); + ++ // May fail, but we ignore it + BlessLUT(lut); + } + +@@ -1573,8 +1601,7 @@ cmsBool CMSEXPORT cmsPipelineCat(cmsPipeline* l1, const cmsPipeline* l2) + return FALSE; + } + +- BlessLUT(l1); +- return TRUE; ++ return BlessLUT(l1); + } + + +diff --git a/third_party/lcms/src/cmstypes.c b/third_party/lcms/src/cmstypes.c +index e5ed06c33..0256e247b 100644 +--- a/third_party/lcms/src/cmstypes.c ++++ b/third_party/lcms/src/cmstypes.c +@@ -1755,8 +1755,8 @@ void *Type_LUT8_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cms + if (!_cmsReadUInt8Number(io, NULL)) goto Error; + + // Do some checking +- if (InputChannels > cmsMAXCHANNELS) goto Error; +- if (OutputChannels > cmsMAXCHANNELS) goto Error; ++ if (InputChannels == 0 || InputChannels > cmsMAXCHANNELS) goto Error; ++ if (OutputChannels == 0 || OutputChannels > cmsMAXCHANNELS) goto Error; + + // Allocates an empty Pipeline + NewLUT = cmsPipelineAlloc(self ->ContextID, InputChannels, OutputChannels); +@@ -2048,8 +2048,8 @@ void *Type_LUT16_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cm + if (!_cmsReadUInt8Number(io, NULL)) return NULL; + + // Do some checking +- if (InputChannels > cmsMAXCHANNELS) goto Error; +- if (OutputChannels > cmsMAXCHANNELS) goto Error; ++ if (InputChannels == 0 || InputChannels > cmsMAXCHANNELS) goto Error; ++ if (OutputChannels == 0 || OutputChannels > cmsMAXCHANNELS) goto Error; + + // Allocates an empty LUT + NewLUT = cmsPipelineAlloc(self ->ContextID, InputChannels, OutputChannels); +@@ -2486,7 +2486,10 @@ void* Type_LUTA2B_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, c + if (!_cmsReadUInt32Number(io, &offsetC)) return NULL; + if (!_cmsReadUInt32Number(io, &offsetA)) return NULL; + +- // Allocates an empty LUT ++ if (inputChan == 0 || inputChan >= cmsMAXCHANNELS) return NULL; ++ if (outputChan == 0 || outputChan >= cmsMAXCHANNELS) return NULL; ++ ++ // Allocates an empty LUT + NewLUT = cmsPipelineAlloc(self ->ContextID, inputChan, outputChan); + if (NewLUT == NULL) return NULL; + +@@ -2794,6 +2797,9 @@ void* Type_LUTB2A_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, c + if (!_cmsReadUInt8Number(io, &inputChan)) return NULL; + if (!_cmsReadUInt8Number(io, &outputChan)) return NULL; + ++ if (inputChan == 0 || inputChan >= cmsMAXCHANNELS) return NULL; ++ if (outputChan == 0 || outputChan >= cmsMAXCHANNELS) return NULL; ++ + // Padding + if (!_cmsReadUInt16Number(io, NULL)) return NULL; + +@@ -4443,6 +4449,9 @@ void *Type_MPE_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsU + if (!_cmsReadUInt16Number(io, &InputChans)) return NULL; + if (!_cmsReadUInt16Number(io, &OutputChans)) return NULL; + ++ if (InputChans == 0 || InputChans >= cmsMAXCHANNELS) return NULL; ++ if (OutputChans == 0 || OutputChans >= cmsMAXCHANNELS) return NULL; ++ + // Allocates an empty LUT + NewLUT = cmsPipelineAlloc(self ->ContextID, InputChans, OutputChans); + if (NewLUT == NULL) return NULL; diff --git a/third_party/lcms/0023-upstream-integer-overflow-MPEmatrix_Read.patch b/third_party/lcms/0023-upstream-integer-overflow-MPEmatrix_Read.patch new file mode 100644 index 0000000000..70a6bb9b20 --- /dev/null +++ b/third_party/lcms/0023-upstream-integer-overflow-MPEmatrix_Read.patch @@ -0,0 +1,85 @@ +diff --git a/third_party/lcms/src/cmscgats.c b/third_party/lcms/src/cmscgats.c +index 5720c66a7..cce4cedba 100644 +--- a/third_party/lcms/src/cmscgats.c ++++ b/third_party/lcms/src/cmscgats.c +@@ -150,23 +150,24 @@ typedef struct { + SUBALLOCATOR Allocator; // String suballocator -- just to keep it fast + + // Parser state machine +- SYMBOL sy; // Current symbol +- int ch; // Current character ++ SYMBOL sy; // Current symbol ++ int ch; // Current character ++ ++ cmsInt32Number inum; // integer value ++ cmsFloat64Number dnum; // real value + +- int inum; // integer value +- cmsFloat64Number dnum; // real value + char id[MAXID]; // identifier + char str[MAXSTR]; // string + + // Allowed keywords & datasets. They have visibility on whole stream +- KEYVALUE* ValidKeywords; +- KEYVALUE* ValidSampleID; ++ KEYVALUE* ValidKeywords; ++ KEYVALUE* ValidSampleID; + + char* Source; // Points to loc. being parsed +- int lineno; // line counter for error reporting ++ cmsInt32Number lineno; // line counter for error reporting + + FILECTX* FileStack[MAXINCLUDE]; // Stack of files being parsed +- int IncludeSP; // Include Stack Pointer ++ cmsInt32Number IncludeSP; // Include Stack Pointer + + char* MemoryBlock; // The stream if holded in memory + +@@ -568,8 +569,8 @@ void ReadReal(cmsIT8* it8, int inum) + // Exponent, example 34.00E+20 + if (toupper(it8->ch) == 'E') { + +- int e; +- int sgn; ++ cmsInt32Number e; ++ cmsInt32Number sgn; + + NextCh(it8); sgn = 1; + +@@ -587,7 +588,7 @@ void ReadReal(cmsIT8* it8, int inum) + e = 0; + while (isdigit(it8->ch)) { + +- if ((cmsFloat64Number) e * 10L < INT_MAX) ++ if ((cmsFloat64Number) e * 10L < (cmsFloat64Number) +2147483647.0) + e = e * 10 + (it8->ch - '0'); + + NextCh(it8); +@@ -777,7 +778,7 @@ void InSymbol(cmsIT8* it8) + + while (isdigit(it8->ch)) { + +- if ((long) it8->inum * 10L > (long) INT_MAX) { ++ if ((cmsFloat64Number) it8->inum * 10L > (cmsFloat64Number) +2147483647.0) { + ReadReal(it8, it8->inum); + it8->sy = SDNUM; + it8->dnum *= sign; +diff --git a/third_party/lcms/src/cmstypes.c b/third_party/lcms/src/cmstypes.c +index 0256e247b..75f1fae32 100644 +--- a/third_party/lcms/src/cmstypes.c ++++ b/third_party/lcms/src/cmstypes.c +@@ -4199,9 +4199,13 @@ void *Type_MPEmatrix_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io + if (!_cmsReadUInt16Number(io, &OutputChans)) return NULL; + + ++ // Input and output chans may be ANY (up to 0xffff), ++ // but we choose to limit to 16 channels for now ++ if (InputChans >= cmsMAXCHANNELS) return NULL; ++ if (OutputChans >= cmsMAXCHANNELS) return NULL; ++ + nElems = InputChans * OutputChans; + +- // Input and output chans may be ANY (up to 0xffff) + Matrix = (cmsFloat64Number*) _cmsCalloc(self ->ContextID, nElems, sizeof(cmsFloat64Number)); + if (Matrix == NULL) return NULL; + diff --git a/third_party/lcms/0024-verify-size-before-reading.patch b/third_party/lcms/0024-verify-size-before-reading.patch new file mode 100644 index 0000000000..e72e310a1b --- /dev/null +++ b/third_party/lcms/0024-verify-size-before-reading.patch @@ -0,0 +1,17 @@ +diff --git a/third_party/lcms/src/cmstypes.c b/third_party/lcms/src/cmstypes.c +index 75f1fae32..4d96a1ed6 100644 +--- a/third_party/lcms/src/cmstypes.c ++++ b/third_party/lcms/src/cmstypes.c +@@ -173,6 +173,12 @@ cmsBool ReadPositionTable(struct _cms_typehandler_struct* self, + { + cmsUInt32Number i; + cmsUInt32Number *ElementOffsets = NULL, *ElementSizes = NULL; ++ cmsUInt32Number currentPosition; ++ ++ currentPosition = io->Tell(io); ++ // Verify there is enough space left to read two cmsUInt32Number items for Count items. ++ if (((io->ReportedSize - currentPosition) / (2 * sizeof(cmsUInt32Number))) < Count) ++ return FALSE; + + // Let's take the offsets to each element + ElementOffsets = (cmsUInt32Number *) _cmsCalloc(io ->ContextID, Count, sizeof(cmsUInt32Number)); diff --git a/third_party/lcms/0025-upstream-direct-leak-Type_MPE_Read.patch b/third_party/lcms/0025-upstream-direct-leak-Type_MPE_Read.patch new file mode 100644 index 0000000000..339333188a --- /dev/null +++ b/third_party/lcms/0025-upstream-direct-leak-Type_MPE_Read.patch @@ -0,0 +1,31 @@ +diff --git a/third_party/lcms/src/cmstypes.c b/third_party/lcms/src/cmstypes.c +index 75f1fae32..f92a92822 100644 +--- a/third_party/lcms/src/cmstypes.c ++++ b/third_party/lcms/src/cmstypes.c +@@ -4460,18 +4460,19 @@ void *Type_MPE_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsU + NewLUT = cmsPipelineAlloc(self ->ContextID, InputChans, OutputChans); + if (NewLUT == NULL) return NULL; + +- if (!_cmsReadUInt32Number(io, &ElementCount)) return NULL; +- +- if (!ReadPositionTable(self, io, ElementCount, BaseOffset, NewLUT, ReadMPEElem)) { +- if (NewLUT != NULL) cmsPipelineFree(NewLUT); +- *nItems = 0; +- return NULL; +- } ++ if (!_cmsReadUInt32Number(io, &ElementCount)) goto Error; ++ if (!ReadPositionTable(self, io, ElementCount, BaseOffset, NewLUT, ReadMPEElem)) goto Error; + + // Success + *nItems = 1; + return NewLUT; + ++ // Error ++Error: ++ if (NewLUT != NULL) cmsPipelineFree(NewLUT); ++ *nItems = 0; ++ return NULL; ++ + cmsUNUSED_PARAMETER(SizeOfTag); + } + diff --git a/third_party/lcms/0026-more-unsupported-characters.patch b/third_party/lcms/0026-more-unsupported-characters.patch new file mode 100644 index 0000000000..a66d50ca9a --- /dev/null +++ b/third_party/lcms/0026-more-unsupported-characters.patch @@ -0,0 +1,73 @@ +diff --git a/third_party/lcms/src/cmsopt.c b/third_party/lcms/src/cmsopt.c +index 23aa54402..abe26b93a 100644 +--- a/third_party/lcms/src/cmsopt.c ++++ b/third_party/lcms/src/cmsopt.c +@@ -1756,8 +1756,8 @@ cmsBool OptimizeMatrixShaper(cmsPipeline** Lut, cmsUInt32Number Intent, cmsUInt3 + _cmsStageToneCurvesData* mpeC1 = (_cmsStageToneCurvesData*) cmsStageData(Curve1); + _cmsStageToneCurvesData* mpeC2 = (_cmsStageToneCurvesData*) cmsStageData(Curve2); + +- // In this particular optimization, cach does not help as it takes more time to deal with +- // the cach that with the pixel handling ++ // In this particular optimization, cache does not help as it takes more time to deal with ++ // the cache that with the pixel handling + *dwFlags |= cmsFLAGS_NOCACHE; + + // Setup the optimizarion routines +diff --git a/third_party/lcms/src/cmstypes.c b/third_party/lcms/src/cmstypes.c +index 38091f159..5ea1d2d87 100644 +--- a/third_party/lcms/src/cmstypes.c ++++ b/third_party/lcms/src/cmstypes.c +@@ -4194,7 +4194,7 @@ cmsBool Type_MPEcurve_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* + // The matrix is organized as an array of PxQ+Q elements, where P is the number of input channels to the + // matrix, and Q is the number of output channels. The matrix elements are each float32Numbers. The array + // is organized as follows: +-// array = [e11, e12, <85>, e1P, e21, e22, <85>, e2P, <85>, eQ1, eQ2, <85>, eQP, e1, e2, <85>, eQ] ++// array = [e11, e12, ..., e1P, e21, e22, ..., e2P, ..., eQ1, eQ2, ..., eQP, e1, e2, ..., eQ] + + static + void *Type_MPEmatrix_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag) +npm@npm0:~/pdfium/pdfium$ +npm@npm0:~/pdfium/pdfium$ +npm@npm0:~/pdfium/pdfium$ +npm@npm0:~/pdfium/pdfium$ git diff +diff --git a/third_party/lcms/src/cmsopt.c b/third_party/lcms/src/cmsopt.c +index 23aa54402..abe26b93a 100644 +--- a/third_party/lcms/src/cmsopt.c ++++ b/third_party/lcms/src/cmsopt.c +@@ -1756,8 +1756,8 @@ cmsBool OptimizeMatrixShaper(cmsPipeline** Lut, cmsUInt32Number Intent, cmsUInt3 + _cmsStageToneCurvesData* mpeC1 = (_cmsStageToneCurvesData*) cmsStageData(Curve1); + _cmsStageToneCurvesData* mpeC2 = (_cmsStageToneCurvesData*) cmsStageData(Curve2); + +- // In this particular optimization, cach does not help as it takes more time to deal with +- // the cach that with the pixel handling ++ // In this particular optimization, cache does not help as it takes more time to deal with ++ // the cache that with the pixel handling + *dwFlags |= cmsFLAGS_NOCACHE; + + // Setup the optimizarion routines +diff --git a/third_party/lcms/src/cmstypes.c b/third_party/lcms/src/cmstypes.c +index 38091f159..8b02f86ca 100644 +--- a/third_party/lcms/src/cmstypes.c ++++ b/third_party/lcms/src/cmstypes.c +@@ -4194,7 +4194,7 @@ cmsBool Type_MPEcurve_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* + // The matrix is organized as an array of PxQ+Q elements, where P is the number of input channels to the + // matrix, and Q is the number of output channels. The matrix elements are each float32Numbers. The array + // is organized as follows: +-// array = [e11, e12, <85>, e1P, e21, e22, <85>, e2P, <85>, eQ1, eQ2, <85>, eQP, e1, e2, <85>, eQ] ++// array = [e11, e12, ..., e1P, e21, e22, ..., e2P, ..., eQ1, eQ2, ..., eQP, e1, e2, ..., eQ] + + static + void *Type_MPEmatrix_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag) +@@ -4713,10 +4713,10 @@ void *Type_vcgt_Read(struct _cms_typehandler_struct* self, + // Y = cX + f | X < d + + // vcgt formula is: +- // Y = (Max <96> Min) * (X ^ Gamma) + Min ++ // Y = (Max - Min) * (X ^ Gamma) + Min + + // So, the translation is +- // a = (Max <96> Min) ^ ( 1 / Gamma) ++ // a = (Max - Min) ^ ( 1 / Gamma) + // e = Min + // b=c=d=f=0 + diff --git a/third_party/lcms/0027-changes-from-beginning-of-time.patch b/third_party/lcms/0027-changes-from-beginning-of-time.patch new file mode 100644 index 0000000000..9eeedd8102 --- /dev/null +++ b/third_party/lcms/0027-changes-from-beginning-of-time.patch @@ -0,0 +1,152 @@ +diff --git a/third_party/lcms/src/cmscgats.c b/third_party/lcms/src/cmscgats.c +index a0c25c024..55f74ede8 100644 +--- a/third_party/lcms/src/cmscgats.c ++++ b/third_party/lcms/src/cmscgats.c +@@ -38,7 +38,10 @@ + #define DEFAULT_DBL_FORMAT "%.10g" // Double formatting + + #ifdef CMS_IS_WINDOWS_ +-# include ++//sunliang.liu modified 2010426 for wince error ++# ifndef _WIN32_WCE ++# include ++# endif + # define DIR_CHAR '\\' + #else + # define DIR_CHAR '/' +diff --git a/third_party/lcms/src/cmsgamma.c b/third_party/lcms/src/cmsgamma.c +index eb3dd881c..6e36cf462 100644 +--- a/third_party/lcms/src/cmsgamma.c ++++ b/third_party/lcms/src/cmsgamma.c +@@ -749,14 +749,19 @@ void CMSEXPORT cmsFreeToneCurve(cmsToneCurve* Curve) + { + cmsContext ContextID; + +- if (Curve == NULL) return; ++ // added by Xiaochuan Liu ++ // Curve->InterpParams may be null ++ if (Curve == NULL || Curve->InterpParams == NULL) return; + + ContextID = Curve ->InterpParams->ContextID; + + _cmsFreeInterpParams(Curve ->InterpParams); ++ Curve ->InterpParams = NULL; + +- if (Curve -> Table16) ++ if (Curve -> Table16) { + _cmsFree(ContextID, Curve ->Table16); ++ Curve ->Table16 = NULL; ++ } + + if (Curve ->Segments) { + +@@ -766,20 +771,30 @@ void CMSEXPORT cmsFreeToneCurve(cmsToneCurve* Curve) + + if (Curve ->Segments[i].SampledPoints) { + _cmsFree(ContextID, Curve ->Segments[i].SampledPoints); ++ Curve ->Segments[i].SampledPoints = NULL; + } + +- if (Curve ->SegInterp[i] != 0) ++ if (Curve ->SegInterp[i] != 0) { + _cmsFreeInterpParams(Curve->SegInterp[i]); ++ Curve->SegInterp[i] = NULL; ++ } + } + + _cmsFree(ContextID, Curve ->Segments); ++ Curve ->Segments = NULL; + _cmsFree(ContextID, Curve ->SegInterp); ++ Curve ->SegInterp = NULL; + } + +- if (Curve -> Evals) ++ if (Curve -> Evals) { + _cmsFree(ContextID, Curve -> Evals); ++ Curve -> Evals = NULL; ++ } + +- if (Curve) _cmsFree(ContextID, Curve); ++ if (Curve) { ++ _cmsFree(ContextID, Curve); ++ Curve = NULL; ++ } + } + + // Utility function, free 3 gamma tables +@@ -799,7 +814,10 @@ void CMSEXPORT cmsFreeToneCurveTriple(cmsToneCurve* Curve[3]) + // Duplicate a gamma table + cmsToneCurve* CMSEXPORT cmsDupToneCurve(const cmsToneCurve* In) + { +- if (In == NULL || In ->Segments == NULL || In ->Table16 == NULL) return NULL; ++ // Xiaochuan Liu ++ // fix openpdf bug(mantis id:0055683, google id:360198) ++ // the function CurveSetElemTypeFree in cmslut.c also needs to check pointer ++ if (In == NULL || In ->InterpParams == NULL || In ->Segments == NULL || In ->Table16 == NULL) return NULL; + + return AllocateToneCurveStruct(In ->InterpParams ->ContextID, In ->nEntries, In ->nSegments, In ->Segments, In ->Table16); + } +diff --git a/third_party/lcms/src/cmsio0.c b/third_party/lcms/src/cmsio0.c +index 1b026488d..cc5f89064 100644 +--- a/third_party/lcms/src/cmsio0.c ++++ b/third_party/lcms/src/cmsio0.c +@@ -479,6 +479,14 @@ cmsIOHANDLER* CMSEXPORT cmsGetProfileIOhandler(cmsHPROFILE hProfile) + return Icc->IOhandler; + } + ++#ifdef _WIN32_WCE ++time_t wceex_time(time_t *timer); ++struct tm * wceex_gmtime(const time_t *timer); ++ ++#define time wceex_time ++#define gmtime wceex_gmtime ++#endif ++ + // Creates an empty structure holding all required parameters + cmsHPROFILE CMSEXPORT cmsCreateProfilePlaceholder(cmsContext ContextID) + { +@@ -570,6 +578,14 @@ int _cmsSearchTag(_cmsICCPROFILE* Icc, cmsTagSignature sig, cmsBool lFollowLinks + + // Yes, follow link + if (LinkedSig != (cmsTagSignature) 0) { ++ // fix bug mantis id#0055942 ++ // assume that TRCTag and ColorantTag can't be linked. ++ // Xiaochuan Liu 2014-04-23 ++ if ((sig == cmsSigRedTRCTag || sig == cmsSigGreenTRCTag || sig == cmsSigBlueTRCTag) && ++ (LinkedSig == cmsSigRedColorantTag || LinkedSig == cmsSigGreenColorantTag || LinkedSig == cmsSigBlueColorantTag)) ++ { ++ return n; ++ } + sig = LinkedSig; + } + +@@ -1363,6 +1379,12 @@ Error: + return 0; + } + ++#ifdef _WIN32_WCE ++int wceex_unlink(const char *filename); ++#ifndef remove ++# define remove wceex_unlink ++#endif ++#endif + + // Low-level save to disk. + cmsBool CMSEXPORT cmsSaveProfileToFile(cmsHPROFILE hProfile, const char* FileName) +diff --git a/third_party/lcms/src/cmsio1.c b/third_party/lcms/src/cmsio1.c +index 364741c9e..4b12ae18e 100644 +--- a/third_party/lcms/src/cmsio1.c ++++ b/third_party/lcms/src/cmsio1.c +@@ -201,7 +201,11 @@ cmsPipeline* BuildGrayInputMatrixPipeline(cmsHPROFILE hProfile) + return Lut; + + Error: +- cmsFreeToneCurve(GrayTRC); ++ // memory pointed by GrayTRC is not a new malloc memory, so don't free it here, ++ // memory pointed by GrayTRC will be freed when hProfile is closed. ++ // test file :0047776_Pocket Medicine_ The Massachusetts General Hospital Handbook of Internal Medicine-2.pdf ++ // Xiaochuan Liu, 20140421 ++ //cmsFreeToneCurve(GrayTRC); + cmsPipelineFree(Lut); + return NULL; + } diff --git a/third_party/lcms/README.pdfium b/third_party/lcms/README.pdfium index 94dc67a7e3..3167130c56 100644 --- a/third_party/lcms/README.pdfium +++ b/third_party/lcms/README.pdfium @@ -1,6 +1,6 @@ Name: Little CMS URL: http://www.littlecms.com/ -Version: 2.6 +Version: 2.8 Security Critical: yes License: MIT License @@ -9,27 +9,33 @@ Color Management Engine. Local Modifications: -0000-tag-type-confusion.patch: Fix a type confusion. -0001-from16-to-8-overflow.patch: Prevent a UBSan warning. -0002-infinite-loop-GrowNamedColorList.patch: Fix infinite loop when calling GrowNamedColorList. -0003-uninit.patch: Fix use uninitialized value and stack buffer overflow read. -0004-memory-leak-Type_Curve_Read.patch: Fix memory leak in Type_Curve_Read. -0005-memory-leak-AllocEmptyTransform.patch: Fix memory leak in AllocEmptyTransform. -0006-memory-leak-Type_NamedColor_Read.patch: Fix memory leak in Type_NamedColor_Read. -0007-memory-leak-OptimizeByResampling.patch: Fix memory leak in OptimizeByResampling. -0008-memory-leak-Type_MPEmatrix_Read.patch: Fix memory leak in MPEmatrix_Read. -0009-cmsStageAllocMatrix-param-swap.patch: Fix rows/cols swap in cmsStageAllocMatrix. -0010-reject-nan.patch: Reject NaN when reading float numbers. -0011-memory-leak-ReadSegmentedCurve.patch: Fix memory leak in ReadSegmentedCurve. -0012-backport-c0a98d86.patch: Fix several issues. Backport from upstream +0000-cmserr-changes.patch: change LCMS memory management methods to use PDFium's. +0001-fix-include.patch: fix include in lcms2_internal.h. +0002-old-performance-fix.patch: https://codereview.chromium.org/534363002/ +0003-old-uninitialized-in-LUTevalFloat.patch: https://codereview.chromium.org/380293002/ +0004-old-uninitialized-in-LUTeval16.patch: https://codereview.chromium.org/387273002/ +0005-old-fix-e-with-tilde.patch: like https://codereview.chromium.org/2411123003/ but better. +0006-tag-type-confusion.patch: Fix a type confusion. +0008-infinite-loop-GrowNamedColorList.patch: Fix infinite loop when calling GrowNamedColorList. +0009-uninit.patch: Fix use uninitialized value and stack buffer overflow read. +0010-memory-leak-Type_Curve_Read.patch: Fix memory leak in Type_Curve_Read. +0011-memory-leak-AllocEmptyTransform.patch: Fix memory leak in AllocEmptyTransform. +0012-memory-leak-Type_NamedColor_Read.patch: Fix memory leak in Type_NamedColor_Read. +0013-memory-leak-OptimizeByResampling.patch: Fix memory leak in OptimizeByResampling. +0014-memory-leak-Type_MPEmatrix_Read.patch: Fix memory leak in MPEmatrix_Read. +0015-cmsStageAllocMatrix-param-swap.patch: Fix rows/cols swap in cmsStageAllocMatrix. +0016-reject-nan.patch: Reject NaN when reading float numbers. +0017-memory-leak-ReadSegmentedCurve.patch: Fix memory leak in ReadSegmentedCurve. +0018-backport-c0a98d86.patch: Fix several issues. Backport from upstream https://github.com/mm2/Little-CMS/commit/c0a98d86 -0013-utf8.patch: Encode source files as utf-8. -0014-avoid-fixed-inf.patch: Avoid fixed number LUT optimization on inf values. -0015-sanitize-float-read.patch: Sanitize floating point read. Partially backport +0019-utf8.patch: Encode source files as utf-8. +0020-avoid-fixed-inf.patch: Avoid fixed number LUT optimization on inf values. +0021-sanitize-float-read.patch: Sanitize floating point read. Partially backport from upstream https://github.com/mm2/Little-CMS/commit/4011a6e3 -0016-check-LUT-and-MPE.patch: check LUT consistency and sanitize MPE profiles. -0017-upstream-integer-overflow-MPEmatrix_Read.patch: fix some integer overflows. -0018-verify-size-before-reading.patch: fix OOM issue when there won't be enough +0022-check-LUT-and-MPE.patch: check LUT consistency and sanitize MPE profiles. +0023-upstream-integer-overflow-MPEmatrix_Read.patch: fix some integer overflows. +0024-verify-size-before-reading.patch: fix OOM issue when there won't be enough data to read anyway. -0019-upstream-direct-leak-Type_MPE_Read.patch: fix leak in cmstypes.c. -TODO(ochang): List other patches. +0025-upstream-direct-leak-Type_MPE_Read.patch: fix leak in cmstypes.c. +0026-more-unsupported-characters.patch: remove other unsupported characters. +0027-changes-from-beginning-of-time.patch: commented changes from initial commit. diff --git a/third_party/lcms/include/lcms2.h b/third_party/lcms/include/lcms2.h index 8595f70203..739e6e1f82 100644 --- a/third_party/lcms/include/lcms2.h +++ b/third_party/lcms/include/lcms2.h @@ -1,7 +1,7 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2014 Marti Maria Saguer +// Copyright (c) 1998-2016 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"), @@ -23,7 +23,7 @@ // //--------------------------------------------------------------------------------- // -// Version 2.6 +// Version 2.8 // #ifndef _lcms2_H @@ -75,7 +75,7 @@ extern "C" { #endif // Version/release -#define LCMS_VERSION 2060 +#define LCMS_VERSION 2080 // I will give the chance of redefining basic types for compilers that are not fully C99 compliant #ifndef CMS_BASIC_TYPES_ALREADY_DEFINED @@ -173,46 +173,45 @@ typedef int cmsBool; # define CMS_IS_WINDOWS_ 1 #endif -// 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 +// Try to detect big endian platforms. This list can be endless, so primarily rely on the configure script +// on Unix-like systems, and allow it to be set on the compiler command line using +// -DCMS_USE_BIG_ENDIAN or something similar +#ifdef CMS_USE_BIG_ENDIAN // set at compiler command line takes overall precedence -#if defined(__sgi__) || defined(__sgi) || defined(sparc) -# define CMS_USE_BIG_ENDIAN 1 -#endif +# if CMS_USE_BIG_ENDIAN == 0 +# undef CMS_USE_BIG_ENDIAN +# endif -#if defined(__s390__) || defined(__s390x__) -# define CMS_USE_BIG_ENDIAN 1 -#endif +#else // CMS_USE_BIG_ENDIAN -# ifdef TARGET_CPU_PPC -# if TARGET_CPU_PPC +# ifdef WORDS_BIGENDIAN // set by configure (or explicitly on compiler command line) +# define CMS_USE_BIG_ENDIAN 1 +# else // WORDS_BIGENDIAN +// Fall back to platform/compiler specific tests +# if defined(__sgi__) || defined(__sgi) || defined(sparc) +# define CMS_USE_BIG_ENDIAN 1 +# endif + +# if defined(__s390__) || defined(__s390x__) # define CMS_USE_BIG_ENDIAN 1 # endif -# endif -#if defined(__powerpc__) || defined(__ppc__) || defined(TARGET_CPU_PPC) -# define CMS_USE_BIG_ENDIAN 1 -# 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 +# ifdef macintosh +# ifdef __BIG_ENDIAN__ +# define CMS_USE_BIG_ENDIAN 1 +# endif +# ifdef __LITTLE_ENDIAN__ +# undef CMS_USE_BIG_ENDIAN +# endif +# endif +# endif // WORDS_BIGENDIAN -// WORDS_BIGENDIAN takes precedence -#if defined(_HOST_BIG_ENDIAN) || defined(__BIG_ENDIAN__) || defined(WORDS_BIGENDIAN) -# define CMS_USE_BIG_ENDIAN 1 -#endif +# if defined(_HOST_BIG_ENDIAN) || defined(__BIG_ENDIAN__) +# define CMS_USE_BIG_ENDIAN 1 +# endif + +#endif // CMS_USE_BIG_ENDIAN -#ifdef macintosh -# ifdef __BIG_ENDIAN__ -# define CMS_USE_BIG_ENDIAN 1 -# endif -# ifdef __LITTLE_ENDIAN__ -# undef CMS_USE_BIG_ENDIAN -# endif -#endif // Calling convention -- this is hardly platform and compiler dependent #ifdef CMS_IS_WINDOWS_ @@ -221,7 +220,7 @@ typedef int cmsBool; # define CMSEXPORT __stdcall _export # define CMSAPI # else -# define CMSEXPORT _stdcall +# define CMSEXPORT __stdcall # ifdef CMS_DLL_BUILD # define CMSAPI __declspec(dllexport) # else @@ -383,7 +382,8 @@ typedef enum { cmsSigViewingCondDescTag = 0x76756564, // 'vued' cmsSigViewingConditionsTag = 0x76696577, // 'view' cmsSigVcgtTag = 0x76636774, // 'vcgt' - cmsSigMetaTag = 0x6D657461 // 'meta' + cmsSigMetaTag = 0x6D657461, // 'meta' + cmsSigArgyllArtsTag = 0x61727473 // 'arts' } cmsTagSignature; @@ -516,7 +516,7 @@ typedef enum { cmsSigNamedColorElemType = 0x6E636C20, // 'ncl ' cmsSigLabV2toV4 = 0x32203420, // '2 4 ' cmsSigLabV4toV2 = 0x34203220, // '4 2 ' - + // Identities cmsSigIdentityElemType = 0x69646E20, // 'idn ' @@ -524,7 +524,8 @@ typedef enum { cmsSigLab2FloatPCS = 0x64326C20, // 'd2l ' cmsSigFloatPCS2Lab = 0x6C326420, // 'l2d ' cmsSigXYZ2FloatPCS = 0x64327820, // 'd2x ' - cmsSigFloatPCS2XYZ = 0x78326420 // 'x2d ' + cmsSigFloatPCS2XYZ = 0x78326420, // 'x2d ' + cmsSigClipNegativesElemType = 0x636c7020 // 'clp ' } cmsStageSignature; @@ -655,7 +656,7 @@ typedef void* cmsHTRANSFORM; // T: Pixeltype // F: Flavor 0=MinIsBlack(Chocolate) 1=MinIsWhite(Vanilla) // P: Planar? 0=Chunky, 1=Planar -// X: swap 16 bps endianess? +// X: swap 16 bps endianness? // S: Do swap? ie, BGR, KYMC // E: Extra samples // C: Channels (Samples per pixel) @@ -898,7 +899,7 @@ typedef void* cmsHTRANSFORM; #define TYPE_ARGB_FLT (FLOAT_SH(1)|COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(4)|SWAPFIRST_SH(1)) #define TYPE_BGR_FLT (FLOAT_SH(1)|COLORSPACE_SH(PT_RGB)|CHANNELS_SH(3)|BYTES_SH(4)|DOSWAP_SH(1)) #define TYPE_BGRA_FLT (FLOAT_SH(1)|COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(4)|DOSWAP_SH(1)|SWAPFIRST_SH(1)) -#define TYPE_ABGR_FLT (FLOAT_SH(1)|COLORSPACE_SH(PT_RGB)|CHANNELS_SH(3)|BYTES_SH(4)|DOSWAP_SH(1)) +#define TYPE_ABGR_FLT (FLOAT_SH(1)|COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(4)|DOSWAP_SH(1)) #define TYPE_CMYK_FLT (FLOAT_SH(1)|COLORSPACE_SH(PT_CMYK)|CHANNELS_SH(4)|BYTES_SH(4)) @@ -1002,6 +1003,10 @@ typedef struct { } cmsICCViewingConditions; +// Get LittleCMS version (for shared objects) ----------------------------------------------------------------------------- + +CMSAPI int CMSEXPORT cmsGetEncodedCMMversion(void); + // Support of non-standard functions -------------------------------------------------------------------------------------- CMSAPI int CMSEXPORT cmsstrcasecmp(const char* s1, const char* s2); @@ -1011,7 +1016,7 @@ CMSAPI long int CMSEXPORT cmsfilelength(FILE* f); // 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. +// though using the global context is not recommended. Proper context handling makes lcms more thread-safe. typedef struct _cmsContext_struct* cmsContext; @@ -1380,7 +1385,7 @@ typedef struct { typedef struct { cmsUInt32Number n; - cmsContext ContextID; + cmsContext ContextID; cmsPSEQDESC* seq; } cmsSEQ; @@ -1480,7 +1485,7 @@ CMSAPI int CMSEXPORT _cmsLCMScolorSpace(cmsColorSpaceSignat CMSAPI cmsUInt32Number CMSEXPORT cmsChannelsOf(cmsColorSpaceSignature ColorSpace); -// Build a suitable formatter for the colorspace of this profile +// Build a suitable formatter for the colorspace of this profile. nBytes=1 means 8 bits, nBytes=2 means 16 bits. CMSAPI cmsUInt32Number CMSEXPORT cmsFormatterForColorspaceOfProfile(cmsHPROFILE hProfile, cmsUInt32Number nBytes, cmsBool lIsFloat); CMSAPI cmsUInt32Number CMSEXPORT cmsFormatterForPCSOfProfile(cmsHPROFILE hProfile, cmsUInt32Number nBytes, cmsBool lIsFloat); @@ -1509,12 +1514,12 @@ CMSAPI cmsIOHANDLER* CMSEXPORT cmsOpenIOhandlerFromFile(cmsContext ContextID CMSAPI cmsIOHANDLER* CMSEXPORT cmsOpenIOhandlerFromStream(cmsContext ContextID, FILE* Stream); CMSAPI cmsIOHANDLER* CMSEXPORT cmsOpenIOhandlerFromMem(cmsContext ContextID, void *Buffer, cmsUInt32Number size, const char* AccessMode); CMSAPI cmsIOHANDLER* CMSEXPORT cmsOpenIOhandlerFromNULL(cmsContext ContextID); +CMSAPI cmsIOHANDLER* CMSEXPORT cmsGetProfileIOhandler(cmsHPROFILE hProfile); CMSAPI cmsBool CMSEXPORT cmsCloseIOhandler(cmsIOHANDLER* io); // MD5 message digest -------------------------------------------------------------------------------------------------- CMSAPI cmsBool CMSEXPORT cmsMD5computeID(cmsHPROFILE hProfile); -CMSAPI cmsBool CMSEXPORT cmsMD5computeIDExt(const void* buf, unsigned long size, unsigned char ProfileID[16]); // Profile high level funtions ------------------------------------------------------------------------------------------ @@ -1644,6 +1649,12 @@ CMSAPI cmsUInt32Number CMSEXPORT cmsGetSupportedIntentsTHR(cmsContext ContextID #define cmsFLAGS_CLUT_POST_LINEARIZATION 0x0001 // create postlinearization tables if possible #define cmsFLAGS_CLUT_PRE_LINEARIZATION 0x0010 // create prelinearization tables if possible +// Specific to unbounded mode +#define cmsFLAGS_NONEGATIVES 0x8000 // Prevent negative numbers in floating point transforms + +// Copy alpha channels when transforming +#define cmsFLAGS_COPY_ALPHA 0x04000000 // Alpha channels are copied on cmsDoTransform() + // Fine-tune control over number of gridpoints #define cmsFLAGS_GRIDPOINTS(n) (((n) & 0xFF) << 16) @@ -1721,12 +1732,22 @@ CMSAPI void CMSEXPORT cmsDoTransform(cmsHTRANSFORM Transform, void * OutputBuffer, cmsUInt32Number Size); -CMSAPI void CMSEXPORT cmsDoTransformStride(cmsHTRANSFORM Transform, +CMSAPI void CMSEXPORT cmsDoTransformStride(cmsHTRANSFORM Transform, // Deprecated const void * InputBuffer, void * OutputBuffer, cmsUInt32Number Size, cmsUInt32Number Stride); +CMSAPI void CMSEXPORT cmsDoTransformLineStride(cmsHTRANSFORM Transform, + const void* InputBuffer, + void* OutputBuffer, + cmsUInt32Number PixelsPerLine, + cmsUInt32Number LineCount, + cmsUInt32Number BytesPerLineIn, + cmsUInt32Number BytesPerLineOut, + cmsUInt32Number BytesPerPlaneIn, + cmsUInt32Number BytesPerPlaneOut); + CMSAPI void CMSEXPORT cmsSetAlarmCodes(const cmsUInt16Number NewAlarm[cmsMAXCHANNELS]); CMSAPI void CMSEXPORT cmsGetAlarmCodes(cmsUInt16Number NewAlarm[cmsMAXCHANNELS]); diff --git a/third_party/lcms/include/lcms2_plugin.h b/third_party/lcms/include/lcms2_plugin.h index 0c95d1f73c..7eda009608 100644 --- a/third_party/lcms/include/lcms2_plugin.h +++ b/third_party/lcms/include/lcms2_plugin.h @@ -1,7 +1,7 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2011 Marti Maria Saguer +// Copyright (c) 1998-2016 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"), @@ -128,7 +128,7 @@ struct _cms_io_handler { const void* Buffer); }; -// Endianess adjust functions +// Endianness adjust functions CMSAPI cmsUInt16Number CMSEXPORT _cmsAdjustEndianess16(cmsUInt16Number Word); CMSAPI cmsUInt32Number CMSEXPORT _cmsAdjustEndianess32(cmsUInt32Number Value); CMSAPI void CMSEXPORT _cmsAdjustEndianess64(cmsUInt64Number* Result, cmsUInt64Number* QWord); @@ -342,8 +342,8 @@ struct _cmstransform_struct; typedef cmsUInt8Number* (* cmsFormatter16)(register struct _cmstransform_struct* CMMcargo, register cmsUInt16Number Values[], - register cmsUInt8Number* Buffer, - register cmsUInt32Number Stride); + register cmsUInt8Number* Buffer, + register cmsUInt32Number Stride); typedef cmsUInt8Number* (* cmsFormatterFloat)(struct _cmstransform_struct* CMMcargo, cmsFloat32Number Values[], @@ -571,11 +571,28 @@ typedef struct { //---------------------------------------------------------------------------------------------------------- // Full xform -typedef void (* _cmsTransformFn)(struct _cmstransform_struct *CMMcargo, + +typedef struct { + cmsUInt32Number BytesPerLineIn; + cmsUInt32Number BytesPerLineOut; + cmsUInt32Number BytesPerPlaneIn; + cmsUInt32Number BytesPerPlaneOut; + +} cmsStride; + +typedef void (* _cmsTransformFn)(struct _cmstransform_struct *CMMcargo, // Legacy function, handles just ONE scanline. const void* InputBuffer, void* OutputBuffer, cmsUInt32Number Size, - cmsUInt32Number Stride); + cmsUInt32Number Stride); // Stride in bytes to the next plana in planar formats + + +typedef void (*_cmsTransform2Fn)(struct _cmstransform_struct *CMMcargo, + const void* InputBuffer, + void* OutputBuffer, + cmsUInt32Number PixelsPerLine, + cmsUInt32Number LineCount, + const cmsStride* Stride); typedef cmsBool (* _cmsTransformFactory)(_cmsTransformFn* xform, void** UserData, @@ -585,6 +602,14 @@ typedef cmsBool (* _cmsTransformFactory)(_cmsTransformFn* xform, cmsUInt32Number* OutputFormat, cmsUInt32Number* dwFlags); +typedef cmsBool (* _cmsTransform2Factory)(_cmsTransform2Fn* xform, + void** UserData, + _cmsFreeUserDataFn* FreePrivateDataFn, + cmsPipeline** Lut, + cmsUInt32Number* InputFormat, + cmsUInt32Number* OutputFormat, + cmsUInt32Number* dwFlags); + // Retrieve user data as specified by the factory CMSAPI void CMSEXPORT _cmsSetTransformUserData(struct _cmstransform_struct *CMMcargo, void* ptr, _cmsFreeUserDataFn FreePrivateDataFn); @@ -599,7 +624,10 @@ typedef struct { cmsPluginBase base; // Transform entry point - _cmsTransformFactory Factory; + union { + _cmsTransformFactory legacy_xform; + _cmsTransform2Factory xform; + } factories; } cmsPluginTransform; diff --git a/third_party/lcms/src/cmsalpha.c b/third_party/lcms/src/cmsalpha.c new file mode 100644 index 0000000000..7d6aa345f4 --- /dev/null +++ b/third_party/lcms/src/cmsalpha.c @@ -0,0 +1,518 @@ +//--------------------------------------------------------------------------------- +// +// Little Color Management System +// Copyright (c) 1998-2016 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" + + +// Alpha copy ------------------------------------------------------------------------------------------------------------------ + +// Floor to byte, taking care of saturation +cmsINLINE cmsUInt8Number _cmsQuickSaturateByte(cmsFloat64Number d) +{ + d += 0.5; + if (d <= 0) return 0; + if (d >= 255.0) return 255; + + return (cmsUInt8Number) _cmsQuickFloorWord(d); +} + + +// Return the size in bytes of a given formatter +static +int trueBytesSize(cmsUInt32Number Format) +{ + int fmt_bytes = T_BYTES(Format); + + // For double, the T_BYTES field returns zero + if (fmt_bytes == 0) + return sizeof(double); + + // Otherwise, it is already correct for all formats + return fmt_bytes; +} + + +// Several format converters + +typedef void(*cmsFormatterAlphaFn)(void* dst, const void* src); + + +// From 8 + +static +void copy8(void* dst, const void* src) +{ + memmove(dst, src, 1); +} + +static +void from8to16(void* dst, const void* src) +{ + cmsUInt8Number n = *(cmsUInt8Number*)src; + *(cmsUInt16Number*) dst = FROM_8_TO_16(n); +} + +static +void from8toFLT(void* dst, const void* src) +{ + *(cmsFloat32Number*)dst = (*(cmsUInt8Number*)src) / 255.0f; +} + +static +void from8toDBL(void* dst, const void* src) +{ + *(cmsFloat64Number*)dst = (*(cmsUInt8Number*)src) / 255.0; +} + +static +void from8toHLF(void* dst, const void* src) +{ + cmsFloat32Number n = (*(cmsUInt8Number*)src) / 255.0f; + *(cmsUInt16Number*)dst = _cmsFloat2Half(n); +} + +// From 16 + +static +void from16to8(void* dst, const void* src) +{ + cmsUInt16Number n = *(cmsUInt16Number*)src; + *(cmsUInt8Number*) dst = FROM_16_TO_8(n); +} + +static +void copy16(void* dst, const void* src) +{ + memmove(dst, src, 2); +} + +void from16toFLT(void* dst, const void* src) +{ + *(cmsFloat32Number*)dst = (*(cmsUInt16Number*)src) / 65535.0f; +} + +void from16toDBL(void* dst, const void* src) +{ + *(cmsFloat64Number*)dst = (*(cmsUInt16Number*)src) / 65535.0f; +} + +static +void from16toHLF(void* dst, const void* src) +{ + cmsFloat32Number n = (*(cmsUInt16Number*)src) / 65535.0f; + *(cmsUInt16Number*)dst = _cmsFloat2Half(n); +} + +// From Float + +static +void fromFLTto8(void* dst, const void* src) +{ + cmsFloat32Number n = *(cmsFloat32Number*)src; + *(cmsUInt8Number*)dst = _cmsQuickSaturateByte(n * 255.0f); +} + +static +void fromFLTto16(void* dst, const void* src) +{ + cmsFloat32Number n = *(cmsFloat32Number*)src; + *(cmsUInt16Number*)dst = _cmsQuickSaturateWord(n * 65535.0f); +} + +static +void copy32(void* dst, const void* src) +{ + memmove(dst, src, sizeof(cmsFloat32Number)); +} + +static +void fromFLTtoDBL(void* dst, const void* src) +{ + cmsFloat32Number n = *(cmsFloat32Number*)src; + *(cmsFloat64Number*)dst = (cmsFloat64Number)n; +} + +static +void fromFLTtoHLF(void* dst, const void* src) +{ + cmsFloat32Number n = *(cmsFloat32Number*)src; + *(cmsUInt16Number*)dst = _cmsFloat2Half(n); +} + + +// From HALF + +static +void fromHLFto8(void* dst, const void* src) +{ + cmsFloat32Number n = _cmsHalf2Float(*(cmsUInt16Number*)src); + *(cmsUInt8Number*)dst = _cmsQuickSaturateByte(n * 255.0f); +} + +static +void fromHLFto16(void* dst, const void* src) +{ + cmsFloat32Number n = _cmsHalf2Float(*(cmsUInt16Number*)src); + *(cmsUInt16Number*)dst = _cmsQuickSaturateWord(n * 65535.0f); +} + +static +void fromHLFtoFLT(void* dst, const void* src) +{ + *(cmsFloat32Number*)dst = _cmsHalf2Float(*(cmsUInt16Number*)src); +} + +static +void fromHLFtoDBL(void* dst, const void* src) +{ + *(cmsFloat64Number*)dst = (cmsFloat64Number)_cmsHalf2Float(*(cmsUInt16Number*)src); +} + +// From double +static +void fromDBLto8(void* dst, const void* src) +{ + cmsFloat64Number n = *(cmsFloat64Number*)src; + *(cmsUInt8Number*)dst = _cmsQuickSaturateByte(n * 255.0); +} + +static +void fromDBLto16(void* dst, const void* src) +{ + cmsFloat64Number n = *(cmsFloat64Number*)src; + *(cmsUInt16Number*)dst = _cmsQuickSaturateWord(n * 65535.0f); +} + +static +void fromDBLtoFLT(void* dst, const void* src) +{ + cmsFloat64Number n = *(cmsFloat64Number*)src; + *(cmsFloat32Number*)dst = (cmsFloat32Number) n; +} + +static +void fromDBLtoHLF(void* dst, const void* src) +{ + cmsFloat32Number n = (cmsFloat32Number) *(cmsFloat64Number*)src; + *(cmsUInt16Number*)dst = _cmsFloat2Half(n); +} + +static +void copy64(void* dst, const void* src) +{ + memmove(dst, src, sizeof(cmsFloat64Number)); +} + + +// Returns the position (x or y) of the formatter in the table of functions +static +int FormatterPos(cmsUInt32Number frm) +{ + int b = T_BYTES(frm); + + if (b == 0 && T_FLOAT(frm)) + return 4; // DBL + if (b == 2 && T_FLOAT(frm)) + return 2; // HLF + if (b == 4 && T_FLOAT(frm)) + return 3; // FLT + if (b == 2 && !T_FLOAT(frm)) + return 1; // 16 + if (b == 1 && !T_FLOAT(frm)) + return 0; // 8 + + return -1; // not recognized + +} + +// Obtains a alpha-to-alpha funmction formatter +static +cmsFormatterAlphaFn _cmsGetFormatterAlpha(cmsContext id, cmsUInt32Number in, cmsUInt32Number out) +{ +static cmsFormatterAlphaFn FormattersAlpha[5][5] = { + + /* from 8 */ { copy8, from8to16, from8toHLF, from8toFLT, from8toDBL }, + /* from 16*/ { from16to8, copy16, from16toHLF, from16toFLT, from16toDBL }, + /* from HLF*/ { fromHLFto8, fromHLFto16, copy16, fromHLFtoFLT, fromHLFtoDBL }, + /* from FLT*/ { fromFLTto8, fromFLTto16, fromFLTtoHLF, copy32, fromFLTtoDBL }, + /* from DBL*/ { fromDBLto8, fromDBLto16, fromDBLtoHLF, fromDBLtoFLT, copy64 }}; + + int in_n = FormatterPos(in); + int out_n = FormatterPos(out); + + if (in_n < 0 || out_n < 0 || in_n > 4 || out_n > 4) { + + cmsSignalError(id, cmsERROR_UNKNOWN_EXTENSION, "Unrecognized alpha channel width"); + return NULL; + } + + return FormattersAlpha[in_n][out_n]; +} + + + +// This function computes the distance from each component to the next one in bytes. +static +void ComputeIncrementsForChunky(cmsUInt32Number Format, + cmsUInt32Number ComponentStartingOrder[], + cmsUInt32Number ComponentPointerIncrements[]) +{ + cmsUInt32Number channels[cmsMAXCHANNELS]; + int extra = T_EXTRA(Format); + int nchannels = T_CHANNELS(Format); + int total_chans = nchannels + extra; + int i; + int channelSize = trueBytesSize(Format); + int pixelSize = channelSize * total_chans; + + // Sanity check + if (total_chans <= 0 || total_chans >= cmsMAXCHANNELS) + return; + + memset(channels, 0, sizeof(channels)); + + // Separation is independent of starting point and only depends on channel size + for (i = 0; i < extra; i++) + ComponentPointerIncrements[i] = pixelSize; + + // Handle do swap + for (i = 0; i < total_chans; i++) + { + if (T_DOSWAP(Format)) { + channels[i] = total_chans - i - 1; + } + else { + channels[i] = i; + } + } + + // Handle swap first (ROL of positions), example CMYK -> KCMY | 0123 -> 3012 + if (T_SWAPFIRST(Format) && total_chans > 1) { + + cmsUInt32Number tmp = channels[0]; + for (i = 0; i < total_chans-1; i++) + channels[i] = channels[i + 1]; + + channels[total_chans - 1] = tmp; + } + + // Handle size + if (channelSize > 1) + for (i = 0; i < total_chans; i++) { + channels[i] *= channelSize; + } + + for (i = 0; i < extra; i++) + ComponentStartingOrder[i] = channels[i + nchannels]; +} + + + +// On planar configurations, the distance is the stride added to any non-negative +static +void ComputeIncrementsForPlanar(cmsUInt32Number Format, + cmsUInt32Number BytesPerPlane, + cmsUInt32Number ComponentStartingOrder[], + cmsUInt32Number ComponentPointerIncrements[]) +{ + cmsUInt32Number channels[cmsMAXCHANNELS]; + int extra = T_EXTRA(Format); + int nchannels = T_CHANNELS(Format); + int total_chans = nchannels + extra; + int i; + int channelSize = trueBytesSize(Format); + + // Sanity check + if (total_chans <= 0 || total_chans >= cmsMAXCHANNELS) + return; + + memset(channels, 0, sizeof(channels)); + + // Separation is independent of starting point and only depends on channel size + for (i = 0; i < extra; i++) + ComponentPointerIncrements[i] = channelSize; + + // Handle do swap + for (i = 0; i < total_chans; i++) + { + if (T_DOSWAP(Format)) { + channels[i] = total_chans - i - 1; + } + else { + channels[i] = i; + } + } + + // Handle swap first (ROL of positions), example CMYK -> KCMY | 0123 -> 3012 + if (T_SWAPFIRST(Format) && total_chans > 0) { + + cmsUInt32Number tmp = channels[0]; + for (i = 0; i < total_chans - 1; i++) + channels[i] = channels[i + 1]; + + channels[total_chans - 1] = tmp; + } + + // Handle size + for (i = 0; i < total_chans; i++) { + channels[i] *= BytesPerPlane; + } + + for (i = 0; i < extra; i++) + ComponentStartingOrder[i] = channels[i + nchannels]; +} + + + +// Dispatcher por chunky and planar RGB +static +void ComputeComponentIncrements(cmsUInt32Number Format, + cmsUInt32Number BytesPerPlane, + cmsUInt32Number ComponentStartingOrder[], + cmsUInt32Number ComponentPointerIncrements[]) +{ + if (T_PLANAR(Format)) { + + ComputeIncrementsForPlanar(Format, BytesPerPlane, ComponentStartingOrder, ComponentPointerIncrements); + } + else { + ComputeIncrementsForChunky(Format, ComponentStartingOrder, ComponentPointerIncrements); + } + +} + + + +// Handles extra channels copying alpha if requested by the flags +void _cmsHandleExtraChannels(_cmsTRANSFORM* p, const void* in, + void* out, + cmsUInt32Number PixelsPerLine, + cmsUInt32Number LineCount, + const cmsStride* Stride) +{ + cmsUInt32Number i, j, k; + cmsUInt32Number nExtra; + cmsUInt32Number SourceStartingOrder[cmsMAXCHANNELS]; + cmsUInt32Number SourceIncrements[cmsMAXCHANNELS]; + cmsUInt32Number DestStartingOrder[cmsMAXCHANNELS]; + cmsUInt32Number DestIncrements[cmsMAXCHANNELS]; + + cmsFormatterAlphaFn copyValueFn; + + // Make sure we need some copy + if (!(p->dwOriginalFlags & cmsFLAGS_COPY_ALPHA)) + return; + + // Exit early if in-place color-management is occurring - no need to copy extra channels to themselves. + if (p->InputFormat == p->OutputFormat && in == out) + return; + + // Make sure we have same number of alpha channels. If not, just return as this should be checked at transform creation time. + nExtra = T_EXTRA(p->InputFormat); + if (nExtra != T_EXTRA(p->OutputFormat)) + return; + + // Anything to do? + if (nExtra == 0) + return; + + // Compute the increments + ComputeComponentIncrements(p->InputFormat, Stride->BytesPerPlaneIn, SourceStartingOrder, SourceIncrements); + ComputeComponentIncrements(p->OutputFormat, Stride->BytesPerPlaneOut, DestStartingOrder, DestIncrements); + + // Check for conversions 8, 16, half, float, dbl + copyValueFn = _cmsGetFormatterAlpha(p->ContextID, p->InputFormat, p->OutputFormat); + + if (nExtra == 1) { // Optimized routine for copying a single extra channel quickly + + cmsUInt8Number* SourcePtr; + cmsUInt8Number* DestPtr; + + cmsUInt32Number SourceStrideIncrement = 0; + cmsUInt32Number DestStrideIncrement = 0; + + // The loop itself + for (i = 0; i < LineCount; i++) { + + // Prepare pointers for the loop + SourcePtr = (cmsUInt8Number*)in + SourceStartingOrder[0] + SourceStrideIncrement; + DestPtr = (cmsUInt8Number*)out + DestStartingOrder[0] + DestStrideIncrement; + + for (j = 0; j < PixelsPerLine; j++) { + + copyValueFn(DestPtr, SourcePtr); + + SourcePtr += SourceIncrements[0]; + DestPtr += DestIncrements[0]; + } + + SourceStrideIncrement += Stride->BytesPerLineIn; + DestStrideIncrement += Stride->BytesPerLineOut; + } + + } + else { // General case with more than one extra channel + + cmsUInt8Number* SourcePtr[cmsMAXCHANNELS]; + cmsUInt8Number* DestPtr[cmsMAXCHANNELS]; + + cmsUInt32Number SourceStrideIncrements[cmsMAXCHANNELS]; + cmsUInt32Number DestStrideIncrements[cmsMAXCHANNELS]; + + memset(SourceStrideIncrements, 0, sizeof(SourceStrideIncrements)); + memset(DestStrideIncrements, 0, sizeof(DestStrideIncrements)); + + // The loop itself + for (i = 0; i < LineCount; i++) { + + // Prepare pointers for the loop + for (j = 0; j < nExtra; j++) { + + SourcePtr[j] = (cmsUInt8Number*)in + SourceStartingOrder[j] + SourceStrideIncrements[j]; + DestPtr[j] = (cmsUInt8Number*)out + DestStartingOrder[j] + DestStrideIncrements[j]; + } + + for (j = 0; j < PixelsPerLine; j++) { + + for (k = 0; k < nExtra; k++) { + + copyValueFn(DestPtr[k], SourcePtr[k]); + + SourcePtr[k] += SourceIncrements[k]; + DestPtr[k] += DestIncrements[k]; + } + } + + for (j = 0; j < nExtra; j++) { + + SourceStrideIncrements[j] += Stride->BytesPerLineIn; + DestStrideIncrements[j] += Stride->BytesPerLineOut; + } + } + } +} + + diff --git a/third_party/lcms/src/cmscam02.c b/third_party/lcms/src/cmscam02.c index 9d874aa205..5f0ac1f878 100644 --- a/third_party/lcms/src/cmscam02.c +++ b/third_party/lcms/src/cmscam02.c @@ -1,7 +1,7 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2012 Marti Maria Saguer +// Copyright (c) 1998-2016 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"), diff --git a/third_party/lcms/src/cmscgats.c b/third_party/lcms/src/cmscgats.c index cce4cedbad..55f74ede8b 100644 --- a/third_party/lcms/src/cmscgats.c +++ b/third_party/lcms/src/cmscgats.c @@ -1,7 +1,7 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2012 Marti Maria Saguer +// Copyright (c) 1998-2016 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"), @@ -39,9 +39,9 @@ #ifdef CMS_IS_WINDOWS_ //sunliang.liu modified 2010426 for wince error -# ifndef _WIN32_WCE -# include -# endif +# ifndef _WIN32_WCE +# include +# endif # define DIR_CHAR '\\' #else # define DIR_CHAR '/' @@ -51,7 +51,7 @@ // Symbols typedef enum { - SNONE, + SUNDEFINED, SINUM, // Integer SDNUM, // Real SIDENT, // Identifier @@ -275,7 +275,7 @@ static PROPERTY PredefinedProperties[] = { // denote the use of filters such as none, D65, Red, Green or Blue. {"POLARIZATION", WRITE_STRINGIFY}, // Identifies the use of a physical polarization filter during measurement. Allowed - // values are "yes" "white" "none" or "na" + // values are "yes" "white" "none" or "na". {"WEIGHTING_FUNCTION", WRITE_PAIR}, // Indicates such functions as: the CIE standard observer functions used in the // calculation of various data parameters (2 degree and 10 degree), CIE standard @@ -328,7 +328,7 @@ static const char* PredefinedSampleID[] = { "XYZ_X", // X component of tristimulus data "XYZ_Y", // Y component of tristimulus data "XYZ_Z", // Z component of tristimulus data - "XYY_X" // x component of chromaticity data + "XYY_X", // x component of chromaticity data "XYY_Y", // y component of chromaticity data "XYY_CAPY", // Y component of tristimulus data "LAB_L", // L* component of Lab data @@ -525,7 +525,7 @@ SYMBOL BinSrchKey(const char *id) else l = x + 1; } - return SNONE; + return SUNDEFINED; } @@ -600,7 +600,7 @@ void ReadReal(cmsIT8* it8, int inum) } // Parses a float number -// This can not call directly atof because it uses locale dependant +// This can not call directly atof because it uses locale dependent // parsing, while CCMX files always use . as decimal separator static cmsFloat64Number ParseFloatNumber(const char *Buffer) @@ -710,7 +710,7 @@ void InSymbol(cmsIT8* it8) key = BinSrchKey(it8->id); - if (key == SNONE) it8->sy = SIDENT; + if (key == SUNDEFINED) it8->sy = SIDENT; else it8->sy = key; } @@ -805,11 +805,11 @@ void InSymbol(cmsIT8* it8) if (it8 ->sy == SINUM) { - sprintf(it8->id, "%d", it8->inum); + snprintf(it8->id, 127, "%d", it8->inum); } else { - sprintf(it8->id, it8 ->DoubleFormatter, it8->dnum); + snprintf(it8->id, 127, it8 ->DoubleFormatter, it8->dnum); } k = (int) strlen(it8 ->id); @@ -1301,7 +1301,7 @@ cmsHANDLE CMSEXPORT cmsIT8Alloc(cmsContext ContextID) it8->ValidKeywords = NULL; it8->ValidSampleID = NULL; - it8 -> sy = SNONE; + it8 -> sy = SUNDEFINED; it8 -> ch = ' '; it8 -> Source = NULL; it8 -> inum = 0; @@ -1367,7 +1367,7 @@ cmsBool CMSEXPORT cmsIT8SetPropertyDbl(cmsHANDLE hIT8, const char* cProp, cmsFlo cmsIT8* it8 = (cmsIT8*) hIT8; char Buffer[1024]; - sprintf(Buffer, it8->DoubleFormatter, Val); + snprintf(Buffer, 1023, it8->DoubleFormatter, Val); return AddToList(it8, &GetTable(it8)->HeaderList, cProp, NULL, Buffer, WRITE_UNCOOKED) != NULL; } @@ -1377,7 +1377,7 @@ cmsBool CMSEXPORT cmsIT8SetPropertyHex(cmsHANDLE hIT8, const char* cProp, cmsUIn cmsIT8* it8 = (cmsIT8*) hIT8; char Buffer[1024]; - sprintf(Buffer, "%u", Val); + snprintf(Buffer, 1023, "%u", Val); return AddToList(it8, &GetTable(it8)->HeaderList, cProp, NULL, Buffer, WRITE_HEXADECIMAL) != NULL; } @@ -1821,7 +1821,7 @@ cmsBool CMSEXPORT cmsIT8SaveToMem(cmsHANDLE hIT8, void *MemPtr, cmsUInt32Number* } -// -------------------------------------------------------------- Higer level parsing +// -------------------------------------------------------------- Higher level parsing static cmsBool DataFormatSection(cmsIT8* it8) @@ -2124,7 +2124,7 @@ cmsBool ParseIT8(cmsIT8* it8, cmsBool nosheet) -// Init usefull pointers +// Init useful pointers static void CookPointers(cmsIT8* it8) @@ -2520,8 +2520,10 @@ int LocateSample(cmsIT8* it8, const char* cSample) for (i=0; i < t->nSamples; i++) { fld = GetDataFormat(it8, i); - if (cmsstrcasecmp(fld, cSample) == 0) - return i; + if (fld != NULL) { + if (cmsstrcasecmp(fld, cSample) == 0) + return i; + } } return -1; @@ -2579,7 +2581,7 @@ cmsBool CMSEXPORT cmsIT8SetDataRowColDbl(cmsHANDLE hIT8, int row, int col, cmsFl _cmsAssert(hIT8 != NULL); - sprintf(Buff, it8->DoubleFormatter, Val); + snprintf(Buff, 255, it8->DoubleFormatter, Val); return SetData(it8, row, col, Buff); } @@ -2774,3 +2776,4 @@ void CMSEXPORT cmsIT8DefineDblFormat(cmsHANDLE hIT8, const char* Formatter) it8 ->DoubleFormatter[sizeof(it8 ->DoubleFormatter)-1] = 0; } + diff --git a/third_party/lcms/src/cmscnvrt.c b/third_party/lcms/src/cmscnvrt.c index 1a93e83f90..6c9214850e 100644 --- a/third_party/lcms/src/cmscnvrt.c +++ b/third_party/lcms/src/cmscnvrt.c @@ -1,7 +1,7 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2012 Marti Maria Saguer +// Copyright (c) 1998-2016 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"), @@ -107,7 +107,7 @@ static cmsIntentsList DefaultIntents[] = { }; -// A pointer to the begining of the list +// A pointer to the beginning of the list _cmsIntentsPluginChunkType _cmsIntentsPluginChunk = { NULL }; // Duplicates the zone of memory used by the plug-in in the new context @@ -269,6 +269,9 @@ cmsBool ComputeAbsoluteIntent(cmsFloat64Number AdaptationState, { cmsMAT3 Scale, m1, m2, m3, m4; + // TODO: Follow Marc Mahy's recommendation to check if CHAD is same by using M1*M2 == M2*M1. If so, do nothing. + // TODO: Add support for ArgyllArts tag + // Adaptation state if (AdaptationState == 1.0) { @@ -288,7 +291,7 @@ cmsBool ComputeAbsoluteIntent(cmsFloat64Number AdaptationState, if (AdaptationState == 0.0) { - + m1 = *ChromaticAdaptationMatrixOut; _cmsMAT3per(&m2, &m1, &Scale); // m2 holds CHAD from output white to D50 times abs. col. scaling @@ -530,7 +533,7 @@ cmsPipeline* DefaultICCintents(cmsContext ContextID, cmsHPROFILE hProfile; cmsMAT3 m; cmsVEC3 off; - cmsColorSpaceSignature ColorSpaceIn, ColorSpaceOut, CurrentColorSpace; + cmsColorSpaceSignature ColorSpaceIn, ColorSpaceOut = cmsSigLabData, CurrentColorSpace; cmsProfileClassSignature ClassSig; cmsUInt32Number i, Intent; @@ -632,6 +635,22 @@ cmsPipeline* DefaultICCintents(cmsContext ContextID, CurrentColorSpace = ColorSpaceOut; } + // Check for non-negatives clip + if (dwFlags & cmsFLAGS_NONEGATIVES) { + + if (ColorSpaceOut == cmsSigGrayData || + ColorSpaceOut == cmsSigRgbData || + ColorSpaceOut == cmsSigCmykData) { + + cmsStage* clip = _cmsStageClipNegatives(Result->ContextID, cmsChannelsOf(ColorSpaceOut)); + if (clip == NULL) goto Error; + + if (!cmsPipelineInsertStage(Result, cmsAT_END, clip)) + goto Error; + } + + } + return Result; Error: @@ -870,7 +889,7 @@ int BlackPreservingSampler(register const cmsUInt16Number In[], register cmsUInt return TRUE; } - // Make sure to pass thru K (which now is fixed) + // Make sure to pass through K (which now is fixed) Outf[3] = LabK[3]; // Apply TAC if needed @@ -938,7 +957,7 @@ cmsPipeline* BlackPreservingKPlaneIntents(cmsContext ContextID, memset(&bp, 0, sizeof(bp)); // We need the input LUT of the last profile, assuming this one is responsible of - // black generation. This LUT will be seached in inverse order. + // black generation. This LUT will be searched in inverse order. bp.LabK2cmyk = _cmsReadInputLUT(hProfiles[nProfiles-1], INTENT_RELATIVE_COLORIMETRIC); if (bp.LabK2cmyk == NULL) goto Cleanup; @@ -1045,7 +1064,7 @@ cmsPipeline* _cmsLinkProfiles(cmsContext ContextID, if (TheIntents[i] == INTENT_PERCEPTUAL || TheIntents[i] == INTENT_SATURATION) { // Force BPC for V4 profiles in perceptual and saturation - if (cmsGetProfileVersion(hProfiles[i]) >= 4.0) + if (cmsGetEncodedICCversion(hProfiles[i]) >= 0x4000000) BPC[i] = TRUE; } } diff --git a/third_party/lcms/src/cmserr.c b/third_party/lcms/src/cmserr.c index f9adc3824a..3c3848b2a2 100644 --- a/third_party/lcms/src/cmserr.c +++ b/third_party/lcms/src/cmserr.c @@ -1,7 +1,7 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2012 Marti Maria Saguer +// Copyright (c) 1998-2016 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,6 +25,15 @@ #include "lcms2_internal.h" +#include "core/fxcrt/fx_memory.h" +#include "core/fxcrt/fx_system.h" + +// This function is here to help applications to prevent mixing lcms versions on header and shared objects. +int CMSEXPORT cmsGetEncodedCMMversion(void) +{ + return LCMS_VERSION; +} + // I am so tired about incompatibilities on those functions that here are some replacements // that hopefully would be fully portable. @@ -58,123 +67,59 @@ long int CMSEXPORT cmsfilelength(FILE* f) return n; } -#if 0 -// Memory handling ------------------------------------------------------------------ -// -// 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 evil code to allocate huge blocks that otherwise lcms would never need. - -#define MAX_MEMORY_FOR_ALLOC ((cmsUInt32Number)(1024U*1024U*512U)) - -// User may override this behaviour by using a memory plug-in, which basically replaces -// the default memory management functions. In this case, no check is performed and it -// is up to the plug-in writter to keep in the safe side. There are only three functions -// 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(cmsContext ContextID, cmsPluginBase* Plugin); - -// ********************************************************************************* - -// This is the default memory allocation function. It does a very coarse -// check of amout of memory, just to prevent exploits -static -void* _cmsMallocDefaultFn(cmsContext ContextID, cmsUInt32Number size) +cmsBool _cmsRegisterMemHandlerPlugin(cmsContext ContextID, cmsPluginBase* Plugin) { - if (size > MAX_MEMORY_FOR_ALLOC) return NULL; // Never allow over maximum - - return (void*) malloc(size); + return TRUE; +} - cmsUNUSED_PARAMETER(ContextID); +// Generic allocate +void* CMSEXPORT _cmsMalloc(cmsContext ContextID, cmsUInt32Number size) +{ + return FXMEM_DefaultAlloc(size, 1); } // Generic allocate & zero -static -void* _cmsMallocZeroDefaultFn(cmsContext ContextID, cmsUInt32Number size) +void* CMSEXPORT _cmsMallocZero(cmsContext ContextID, cmsUInt32Number size) { - void *pt = _cmsMalloc(ContextID, size); - if (pt == NULL) return NULL; - - memset(pt, 0, size); - return pt; + void* p = FXMEM_DefaultAlloc(size, 1); + if (p) memset(p, 0, size); + return p; } - -// The default free function. The only check proformed is against NULL pointers -static -void _cmsFreeDefaultFn(cmsContext ContextID, void *Ptr) +// Generic calloc +void* CMSEXPORT _cmsCalloc(cmsContext ContextID, cmsUInt32Number num, cmsUInt32Number size) { - // free(NULL) is defined a no-op by C99, therefore it is safe to - // avoid the check, but it is here just in case... - - if (Ptr) free(Ptr); + cmsUInt32Number total = num * size; + if (total == 0 || total / size != num || total >= 512 * 1024 * 1024) + return NULL; - cmsUNUSED_PARAMETER(ContextID); + return _cmsMallocZero(ContextID, num * size); } -// 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) +// Generic reallocate +void* CMSEXPORT _cmsRealloc(cmsContext ContextID, void* Ptr, cmsUInt32Number size) { - - if (size > MAX_MEMORY_FOR_ALLOC) return NULL; // Never realloc over 512Mb - - return realloc(Ptr, size); - - cmsUNUSED_PARAMETER(ContextID); + return FXMEM_DefaultRealloc(Ptr, size, 1); } - -// The default calloc function. Allocates an array of num elements, each one of size bytes -// all memory is initialized to zero. -static -void* _cmsCallocDefaultFn(cmsContext ContextID, cmsUInt32Number num, cmsUInt32Number size) +// Generic free memory +void CMSEXPORT _cmsFree(cmsContext ContextID, void* Ptr) { - cmsUInt32Number Total = num * size; - - // Preserve calloc behaviour - if (Total == 0) return NULL; - - // Safe check for overflow. - if (num >= UINT_MAX / size) return NULL; - - // Check for overflow - if (Total < num || Total < size) { - return NULL; - } - - if (Total > MAX_MEMORY_FOR_ALLOC) return NULL; // Never alloc over 512Mb - - return _cmsMallocZero(ContextID, Total); + if (Ptr != NULL) FXMEM_DefaultFree(Ptr, 0); } // Generic block duplication -static -void* _cmsDupDefaultFn(cmsContext ContextID, const void* Org, cmsUInt32Number size) +void* CMSEXPORT _cmsDupMem(cmsContext ContextID, const void* Org, cmsUInt32Number size) { - void* mem; - - if (size > MAX_MEMORY_FOR_ALLOC) return NULL; // Never dup over 512Mb - - mem = _cmsMalloc(ContextID, size); - - if (mem != NULL && Org != NULL) - memmove(mem, Org, size); - - return mem; + void* p = FXMEM_DefaultAlloc(size, 1); + memmove(p, Org, size); + return p; } - -// Pointers to memory manager functions in Context0 -_cmsMemPluginChunkType _cmsMemPluginChunk = { _cmsMallocDefaultFn, _cmsMallocZeroDefaultFn, _cmsFreeDefaultFn, - _cmsReallocDefaultFn, _cmsCallocDefaultFn, _cmsDupDefaultFn +_cmsMemPluginChunkType _cmsMemPluginChunk = {_cmsMalloc, _cmsMallocZero, _cmsFree, + _cmsRealloc, _cmsCalloc, _cmsDupMem }; - -// Reset and duplicate memory manager void _cmsAllocMemPluginChunk(struct _cmsContext_struct* ctx, const struct _cmsContext_struct* src) { _cmsAssert(ctx != NULL); @@ -191,7 +136,6 @@ void _cmsAllocMemPluginChunk(struct _cmsContext_struct* ctx, const struct _cmsCo } } -// Auxiliar to fill memory management functions from plugin (or context 0 defaults) void _cmsInstallAllocFunctions(cmsPluginMemHandler* Plugin, _cmsMemPluginChunkType* ptr) { if (Plugin == NULL) { @@ -205,9 +149,9 @@ void _cmsInstallAllocFunctions(cmsPluginMemHandler* Plugin, _cmsMemPluginChunkTy ptr ->ReallocPtr = Plugin -> ReallocPtr; // Make sure we revert to defaults - ptr ->MallocZeroPtr= _cmsMallocZeroDefaultFn; - ptr ->CallocPtr = _cmsCallocDefaultFn; - ptr ->DupPtr = _cmsDupDefaultFn; + ptr ->MallocZeroPtr= _cmsMallocZero; + ptr ->CallocPtr = _cmsCalloc; + ptr ->DupPtr = _cmsDupMem; if (Plugin ->MallocZeroPtr != NULL) ptr ->MallocZeroPtr = Plugin -> MallocZeroPtr; if (Plugin ->CallocPtr != NULL) ptr ->CallocPtr = Plugin -> CallocPtr; @@ -216,138 +160,6 @@ void _cmsInstallAllocFunctions(cmsPluginMemHandler* Plugin, _cmsMemPluginChunkTy } } - -// Plug-in replacement entry -cmsBool _cmsRegisterMemHandlerPlugin(cmsContext ContextID, cmsPluginBase *Data) -{ - cmsPluginMemHandler* Plugin = (cmsPluginMemHandler*) Data; - _cmsMemPluginChunkType* ptr; - - // 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) { - - struct _cmsContext_struct* ctx = ( struct _cmsContext_struct*) ContextID; - - // Return to the default allocators - if (ContextID != NULL) { - ctx->chunks[MemPlugin] = (void*) &ctx->DefaultMemoryManager; - } - return TRUE; - } - - // Check for required callbacks - if (Plugin -> MallocPtr == NULL || - Plugin -> FreePtr == NULL || - Plugin -> ReallocPtr == NULL) return FALSE; - - // Set replacement functions - ptr = (_cmsMemPluginChunkType*) _cmsContextGetClientChunk(ContextID, MemPlugin); - if (ptr == NULL) - return FALSE; - - _cmsInstallAllocFunctions(Plugin, ptr); - return TRUE; -} -#else -#include "core/fxcrt/fx_memory.h" -#include "core/fxcrt/fx_system.h" - -cmsBool _cmsRegisterMemHandlerPlugin(cmsContext ContextID, cmsPluginBase* Plugin) -{ - return TRUE; -} - -// Generic allocate -void* CMSEXPORT _cmsMalloc(cmsContext ContextID, cmsUInt32Number size) -{ - return FXMEM_DefaultAlloc(size, 1); -} - -// Generic allocate & zero -void* CMSEXPORT _cmsMallocZero(cmsContext ContextID, cmsUInt32Number size) -{ - void* p = FXMEM_DefaultAlloc(size, 1); - if (p) memset(p, 0, size); - return p; -} - -// Generic calloc -void* CMSEXPORT _cmsCalloc(cmsContext ContextID, cmsUInt32Number num, cmsUInt32Number size) -{ - cmsUInt32Number total = num * size; - if (total == 0 || total / size != num || total >= 512 * 1024 * 1024) - return NULL; - - return _cmsMallocZero(ContextID, num * size); -} - -// Generic reallocate -void* CMSEXPORT _cmsRealloc(cmsContext ContextID, void* Ptr, cmsUInt32Number size) -{ - return FXMEM_DefaultRealloc(Ptr, size, 1); -} - -// Generic free memory -void CMSEXPORT _cmsFree(cmsContext ContextID, void* Ptr) -{ - if (Ptr != NULL) FXMEM_DefaultFree(Ptr, 0); -} - -// Generic block duplication -void* CMSEXPORT _cmsDupMem(cmsContext ContextID, const void* Org, cmsUInt32Number size) -{ - void* p = FXMEM_DefaultAlloc(size, 1); - memmove(p, Org, size); - return p; -} - -_cmsMemPluginChunkType _cmsMemPluginChunk = {_cmsMalloc, _cmsMallocZero, _cmsFree, - _cmsRealloc, _cmsCalloc, _cmsDupMem - }; - -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; - } -} - -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= _cmsMallocZero; - ptr ->CallocPtr = _cmsCalloc; - ptr ->DupPtr = _cmsDupMem; - - if (Plugin ->MallocZeroPtr != NULL) ptr ->MallocZeroPtr = Plugin -> MallocZeroPtr; - if (Plugin ->CallocPtr != NULL) ptr ->CallocPtr = Plugin -> CallocPtr; - if (Plugin ->DupPtr != NULL) ptr ->DupPtr = Plugin -> DupPtr; - - } -} -#endif - // ******************************************************************************************** // Sub allocation takes care of many pointers of small size. The memory allocated in @@ -458,7 +270,7 @@ void* _cmsSubAlloc(_cmsSubAllocator* sub, cmsUInt32Number size) void* _cmsSubAllocDup(_cmsSubAllocator* s, const void *ptr, cmsUInt32Number size) { void *NewPtr; - + // Dup of null pointer is also NULL if (ptr == NULL) return NULL; @@ -476,14 +288,14 @@ void* _cmsSubAllocDup(_cmsSubAllocator* s, const void *ptr, cmsUInt32Number size // Error logging ****************************************************************** -// There is no error handling at all. When a funtion fails, it returns proper value. +// There is no error handling at all. When a function fails, it returns proper value. // For example, all create functions does return NULL on failure. Other return FALSE // It may be interesting, for the developer, to know why the function is failing. // for that reason, lcms2 does offer a logging function. This function does recive // a ENGLISH string with some clues on what is going wrong. You can show this // info to the end user, or just create some sort of log. // The logging function should NOT terminate the program, as this obviously can leave -// resources. It is the programmer's responsability to check each function return code +// resources. It is the programmer's responsibility to check each function return code // to make sure it didn't fail. // Error messages are limited to MAX_ERROR_MESSAGE_LEN @@ -500,20 +312,20 @@ _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, +void _cmsAllocLogErrorChunk(struct _cmsContext_struct* ctx, const struct _cmsContext_struct* src) -{ +{ static _cmsLogErrorChunkType LogErrorChunk = { DefaultLogErrorHandlerFunction }; void* from; - + if (src != NULL) { - from = src ->chunks[Logger]; + from = src ->chunks[Logger]; } else { from = &LogErrorChunk; } - - ctx ->chunks[Logger] = _cmsSubAllocDup(ctx ->MemPool, from, sizeof(_cmsLogErrorChunkType)); + + ctx ->chunks[Logger] = _cmsSubAllocDup(ctx ->MemPool, from, sizeof(_cmsLogErrorChunkType)); } // The default error logger does nothing. @@ -545,7 +357,7 @@ void CMSEXPORT cmsSetLogErrorHandlerTHR(cmsContext ContextID, cmsLogErrorHandler // Change log error, legacy void CMSEXPORT cmsSetLogErrorHandler(cmsLogErrorHandlerFunction Fn) { - cmsSetLogErrorHandlerTHR(NULL, Fn); + cmsSetLogErrorHandlerTHR(NULL, Fn); } // Log an error @@ -565,7 +377,7 @@ void CMSEXPORT cmsSignalError(cmsContext ContextID, cmsUInt32Number ErrorCode, c lhg = (_cmsLogErrorChunkType*) _cmsContextGetClientChunk(ContextID, Logger); if (lhg ->LogErrorHandler) { lhg ->LogErrorHandler(ContextID, ErrorCode, Buffer); - } + } } // Utility function to print signatures @@ -591,13 +403,13 @@ void* defMtxCreate(cmsContext id) { _cmsMutex* ptr_mutex = (_cmsMutex*) _cmsMalloc(id, sizeof(_cmsMutex)); _cmsInitMutexPrimitive(ptr_mutex); - return (void*) ptr_mutex; + return (void*) ptr_mutex; } static void defMtxDestroy(cmsContext id, void* mtx) { - _cmsDestroyMutexPrimitive((_cmsMutex *) mtx); + _cmsDestroyMutexPrimitive((_cmsMutex *) mtx); _cmsFree(id, mtx); } @@ -605,14 +417,14 @@ static cmsBool defMtxLock(cmsContext id, void* mtx) { cmsUNUSED_PARAMETER(id); - return _cmsLockPrimitive((_cmsMutex *) mtx) == 0; + return _cmsLockPrimitive((_cmsMutex *) mtx) == 0; } static void defMtxUnlock(cmsContext id, void* mtx) { cmsUNUSED_PARAMETER(id); - _cmsUnlockPrimitive((_cmsMutex *) mtx); + _cmsUnlockPrimitive((_cmsMutex *) mtx); } @@ -621,20 +433,20 @@ void defMtxUnlock(cmsContext id, void* mtx) _cmsMutexPluginChunkType _cmsMutexPluginChunk = { defMtxCreate, defMtxDestroy, defMtxLock, defMtxUnlock }; // Allocate and init mutex container. -void _cmsAllocMutexPluginChunk(struct _cmsContext_struct* ctx, +void _cmsAllocMutexPluginChunk(struct _cmsContext_struct* ctx, const struct _cmsContext_struct* src) { static _cmsMutexPluginChunkType MutexChunk = {defMtxCreate, defMtxDestroy, defMtxLock, defMtxUnlock }; void* from; - + if (src != NULL) { - from = src ->chunks[MutexPlugin]; + from = src ->chunks[MutexPlugin]; } else { from = &MutexChunk; } - - ctx ->chunks[MutexPlugin] = _cmsSubAllocDup(ctx ->MemPool, from, sizeof(_cmsMutexPluginChunkType)); + + ctx ->chunks[MutexPlugin] = _cmsSubAllocDup(ctx ->MemPool, from, sizeof(_cmsMutexPluginChunkType)); } // Register new ways to transform @@ -646,15 +458,15 @@ cmsBool _cmsRegisterMutexPlugin(cmsContext ContextID, cmsPluginBase* Data) if (Data == NULL) { // No lock routines - ctx->CreateMutexPtr = NULL; - ctx->DestroyMutexPtr = NULL; + 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 || + if (Plugin ->CreateMutexPtr == NULL || Plugin ->DestroyMutexPtr == NULL || Plugin ->LockMutexPtr == NULL || Plugin ->UnlockMutexPtr == NULL) return FALSE; diff --git a/third_party/lcms/src/cmsgamma.c b/third_party/lcms/src/cmsgamma.c index 97aeb7cc16..6e36cf462e 100644 --- a/third_party/lcms/src/cmsgamma.c +++ b/third_party/lcms/src/cmsgamma.c @@ -23,7 +23,6 @@ // //--------------------------------------------------------------------------------- // - #include "lcms2_internal.h" // Tone curves are powerful constructs that can contain curves specified in diverse ways. @@ -568,7 +567,7 @@ cmsFloat64Number DefaultEvalParametricFn(cmsInt32Number Type, const cmsFloat64Nu return Val; } -// Evaluate a segmented funtion for a single value. Return -1 if no valid segment found . +// Evaluate a segmented function for a single value. Return -1 if no valid segment found . // If fn type is 0, perform an interpolation on the table static cmsFloat64Number EvalSegmentedFn(const cmsToneCurve *g, cmsFloat64Number R) @@ -750,20 +749,19 @@ void CMSEXPORT cmsFreeToneCurve(cmsToneCurve* Curve) { cmsContext ContextID; - // added by Xiaochuan Liu - // Curve->InterpParams may be null + // added by Xiaochuan Liu + // Curve->InterpParams may be null if (Curve == NULL || Curve->InterpParams == NULL) return; ContextID = Curve ->InterpParams->ContextID; _cmsFreeInterpParams(Curve ->InterpParams); - Curve ->InterpParams = NULL; + Curve ->InterpParams = NULL; - if (Curve -> Table16) - { + if (Curve -> Table16) { _cmsFree(ContextID, Curve ->Table16); - Curve ->Table16 = NULL; - } + Curve ->Table16 = NULL; + } if (Curve ->Segments) { @@ -773,33 +771,30 @@ void CMSEXPORT cmsFreeToneCurve(cmsToneCurve* Curve) if (Curve ->Segments[i].SampledPoints) { _cmsFree(ContextID, Curve ->Segments[i].SampledPoints); - Curve ->Segments[i].SampledPoints = NULL; + Curve ->Segments[i].SampledPoints = NULL; } - if (Curve ->SegInterp[i] != 0) - { + if (Curve ->SegInterp[i] != 0) { _cmsFreeInterpParams(Curve->SegInterp[i]); - Curve->SegInterp[i] = NULL; - } + Curve->SegInterp[i] = NULL; + } } _cmsFree(ContextID, Curve ->Segments); - Curve ->Segments = NULL; + Curve ->Segments = NULL; _cmsFree(ContextID, Curve ->SegInterp); - Curve ->SegInterp = NULL; + Curve ->SegInterp = NULL; } - if (Curve -> Evals) - { + if (Curve -> Evals) { _cmsFree(ContextID, Curve -> Evals); - Curve -> Evals = NULL; - } - - if (Curve) - { - _cmsFree(ContextID, Curve); - Curve = NULL; - } + Curve -> Evals = NULL; + } + + if (Curve) { + _cmsFree(ContextID, Curve); + Curve = NULL; + } } // Utility function, free 3 gamma tables @@ -818,10 +813,10 @@ void CMSEXPORT cmsFreeToneCurveTriple(cmsToneCurve* Curve[3]) // Duplicate a gamma table cmsToneCurve* CMSEXPORT cmsDupToneCurve(const cmsToneCurve* In) -{ - // Xiaochuan Liu - // fix openpdf bug(mantis id:0055683, google id:360198) - // the function CurveSetElemTypeFree in cmslut.c also needs to check pointer +{ + // Xiaochuan Liu + // fix openpdf bug(mantis id:0055683, google id:360198) + // the function CurveSetElemTypeFree in cmslut.c also needs to check pointer if (In == NULL || In ->InterpParams == NULL || In ->Segments == NULL || In ->Table16 == NULL) return NULL; return AllocateToneCurveStruct(In ->InterpParams ->ContextID, In ->nEntries, In ->nSegments, In ->Segments, In ->Table16); diff --git a/third_party/lcms/src/cmsgmt.c b/third_party/lcms/src/cmsgmt.c index 1103363a78..b82f3beca8 100644 --- a/third_party/lcms/src/cmsgmt.c +++ b/third_party/lcms/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-2016 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" + + +// Auxiliary: 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 losing 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 truly 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/third_party/lcms/src/cmshalf.c b/third_party/lcms/src/cmshalf.c index f038b57b4c..cdd4e37b7f 100644 --- a/third_party/lcms/src/cmshalf.c +++ b/third_party/lcms/src/cmshalf.c @@ -1,7 +1,7 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2012 Marti Maria Saguer +// Copyright (c) 1998-2016 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"), @@ -22,7 +22,8 @@ // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // //--------------------------------------------------------------------------------- - +// +// #include "lcms2_internal.h" #ifndef CMS_NO_HALF_SUPPORT diff --git a/third_party/lcms/src/cmsintrp.c b/third_party/lcms/src/cmsintrp.c index 14c68563ca..60d6a0e497 100644 --- a/third_party/lcms/src/cmsintrp.c +++ b/third_party/lcms/src/cmsintrp.c @@ -1,7 +1,7 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2012 Marti Maria Saguer +// Copyright (c) 1998-2016 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"), @@ -156,7 +156,7 @@ cmsInterpParams* _cmsComputeInterpParams(cmsContext ContextID, int nSamples, int int i; cmsUInt32Number Samples[MAX_INPUT_DIMENSIONS]; - // Fill the auxiliar array + // Fill the auxiliary array for (i=0; i < MAX_INPUT_DIMENSIONS; i++) Samples[i] = nSamples; @@ -929,7 +929,7 @@ void Eval4Inputs(register const cmsUInt16Number Input[], Rest = c1 * rx + c2 * ry + c3 * rz; - Tmp1[OutChan] = (cmsUInt16Number) c0 + ROUND_FIXED_TO_INT(_cmsToFixedDomain(Rest)); + Tmp1[OutChan] = (cmsUInt16Number) ( c0 + ROUND_FIXED_TO_INT(_cmsToFixedDomain(Rest))); } @@ -993,7 +993,7 @@ void Eval4Inputs(register const cmsUInt16Number Input[], Rest = c1 * rx + c2 * ry + c3 * rz; - Tmp2[OutChan] = (cmsUInt16Number) c0 + ROUND_FIXED_TO_INT(_cmsToFixedDomain(Rest)); + Tmp2[OutChan] = (cmsUInt16Number) (c0 + ROUND_FIXED_TO_INT(_cmsToFixedDomain(Rest))); } diff --git a/third_party/lcms/src/cmsio0.c b/third_party/lcms/src/cmsio0.c index 3ed730a92a..cc5f890644 100644 --- a/third_party/lcms/src/cmsio0.c +++ b/third_party/lcms/src/cmsio0.c @@ -1,7 +1,7 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2012 Marti Maria Saguer +// Copyright (c) 1998-2016 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"), @@ -23,6 +23,7 @@ // //--------------------------------------------------------------------------------- // + #include "lcms2_internal.h" // Generic I/O, tag dictionary management, profile struct @@ -323,7 +324,7 @@ cmsUInt32Number FileRead(cmsIOHANDLER* iohandler, void *Buffer, cmsUInt32Number return nReaded; } -// Postion file pointer in the file +// Position file pointer in the file static cmsBool FileSeek(cmsIOHANDLER* iohandler, cmsUInt32Number offset) { @@ -367,6 +368,7 @@ cmsIOHANDLER* CMSEXPORT cmsOpenIOhandlerFromFile(cmsContext ContextID, const cha { cmsIOHANDLER* iohandler = NULL; FILE* fm = NULL; + cmsInt32Number fileLen; _cmsAssert(FileName != NULL); _cmsAssert(AccessMode != NULL); @@ -382,8 +384,17 @@ cmsIOHANDLER* CMSEXPORT cmsOpenIOhandlerFromFile(cmsContext ContextID, const cha _cmsFree(ContextID, iohandler); cmsSignalError(ContextID, cmsERROR_FILE, "File '%s' not found", FileName); return NULL; + } + fileLen = cmsfilelength(fm); + if (fileLen < 0) + { + fclose(fm); + _cmsFree(ContextID, iohandler); + cmsSignalError(ContextID, cmsERROR_FILE, "Cannot get size of file '%s'", FileName); + return NULL; } - iohandler -> ReportedSize = (cmsUInt32Number) cmsfilelength(fm); + + iohandler -> ReportedSize = (cmsUInt32Number) fileLen; break; case 'w': @@ -423,6 +434,14 @@ cmsIOHANDLER* CMSEXPORT cmsOpenIOhandlerFromFile(cmsContext ContextID, const cha cmsIOHANDLER* CMSEXPORT cmsOpenIOhandlerFromStream(cmsContext ContextID, FILE* Stream) { cmsIOHANDLER* iohandler = NULL; + cmsInt32Number fileSize; + + fileSize = cmsfilelength(Stream); + if (fileSize < 0) + { + cmsSignalError(ContextID, cmsERROR_FILE, "Cannot get size of stream"); + return NULL; + } iohandler = (cmsIOHANDLER*) _cmsMallocZero(ContextID, sizeof(cmsIOHANDLER)); if (iohandler == NULL) return NULL; @@ -430,7 +449,7 @@ cmsIOHANDLER* CMSEXPORT cmsOpenIOhandlerFromStream(cmsContext ContextID, FILE* S iohandler -> ContextID = ContextID; iohandler -> stream = (void*) Stream; iohandler -> UsedSpace = 0; - iohandler -> ReportedSize = (cmsUInt32Number) cmsfilelength(Stream); + iohandler -> ReportedSize = (cmsUInt32Number) fileSize; iohandler -> PhysicalFile[0] = 0; iohandler ->Read = FileRead; @@ -452,6 +471,14 @@ cmsBool CMSEXPORT cmsCloseIOhandler(cmsIOHANDLER* io) // ------------------------------------------------------------------------------------------------------- +cmsIOHANDLER* CMSEXPORT cmsGetProfileIOhandler(cmsHPROFILE hProfile) +{ + _cmsICCPROFILE* Icc = (_cmsICCPROFILE*)hProfile; + + if (Icc == NULL) return NULL; + return Icc->IOhandler; +} + #ifdef _WIN32_WCE time_t wceex_time(time_t *timer); struct tm * wceex_gmtime(const time_t *timer); @@ -551,14 +578,14 @@ int _cmsSearchTag(_cmsICCPROFILE* Icc, cmsTagSignature sig, cmsBool lFollowLinks // Yes, follow link if (LinkedSig != (cmsTagSignature) 0) { - // fix bug mantis id#0055942 - // assume that TRCTag and ColorantTag can't be linked. - // Xiaochuan Liu 2014-04-23 - if ((sig == cmsSigRedTRCTag || sig == cmsSigGreenTRCTag || sig == cmsSigBlueTRCTag) && - (LinkedSig == cmsSigRedColorantTag || LinkedSig == cmsSigGreenColorantTag || LinkedSig == cmsSigBlueColorantTag)) - { - return n; - } + // fix bug mantis id#0055942 + // assume that TRCTag and ColorantTag can't be linked. + // Xiaochuan Liu 2014-04-23 + if ((sig == cmsSigRedTRCTag || sig == cmsSigGreenTRCTag || sig == cmsSigBlueTRCTag) && + (LinkedSig == cmsSigRedColorantTag || LinkedSig == cmsSigGreenColorantTag || LinkedSig == cmsSigBlueColorantTag)) + { + return n; + } sig = LinkedSig; } @@ -630,7 +657,7 @@ cmsBool _cmsNewTag(_cmsICCPROFILE* Icc, cmsTagSignature sig, int* NewPos) } -// Check existance +// Check existence cmsBool CMSEXPORT cmsIsTag(cmsHPROFILE hProfile, cmsTagSignature sig) { _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) (void*) hProfile; @@ -638,6 +665,32 @@ cmsBool CMSEXPORT cmsIsTag(cmsHPROFILE hProfile, cmsTagSignature sig) } + +// Enforces that the profile version is per. spec. +// Operates on the big endian bytes from the profile. +// Called before converting to platform endianness. +// Byte 0 is BCD major version, so max 9. +// Byte 1 is 2 BCD digits, one per nibble. +// Reserved bytes 2 & 3 must be 0. +static +cmsUInt32Number _validatedVersion(cmsUInt32Number DWord) +{ + cmsUInt8Number* pByte = (cmsUInt8Number*) &DWord; + cmsUInt8Number temp1; + cmsUInt8Number temp2; + + if (*pByte > 0x09) *pByte = (cmsUInt8Number) 0x09; + temp1 = *(pByte+1) & 0xf0; + temp2 = *(pByte+1) & 0x0f; + if (temp1 > 0x90) temp1 = 0x90; + if (temp2 > 0x09) temp2 = 0x09; + *(pByte+1) = (cmsUInt8Number)(temp1 | temp2); + *(pByte+2) = (cmsUInt8Number)0; + *(pByte+3) = (cmsUInt8Number)0; + + return DWord; +} + // Read profile header and validate it cmsBool _cmsReadHeader(_cmsICCPROFILE* Icc) { @@ -660,7 +713,7 @@ cmsBool _cmsReadHeader(_cmsICCPROFILE* Icc) return FALSE; } - // Adjust endianess of the used parameters + // Adjust endianness of the used parameters Icc -> DeviceClass = (cmsProfileClassSignature) _cmsAdjustEndianess32(Header.deviceClass); Icc -> ColorSpace = (cmsColorSpaceSignature) _cmsAdjustEndianess32(Header.colorSpace); Icc -> PCS = (cmsColorSpaceSignature) _cmsAdjustEndianess32(Header.pcs); @@ -672,7 +725,7 @@ cmsBool _cmsReadHeader(_cmsICCPROFILE* Icc) Icc -> creator = _cmsAdjustEndianess32(Header.creator); _cmsAdjustEndianess64(&Icc -> attributes, &Header.attributes); - Icc -> Version = _cmsAdjustEndianess32(Header.version); + Icc -> Version = _cmsAdjustEndianess32(_validatedVersion(Header.version)); // Get size as reported in header HeaderSize = _cmsAdjustEndianess32(Header.size); @@ -779,7 +832,7 @@ cmsBool _cmsWriteHeader(_cmsICCPROFILE* Icc, cmsUInt32Number UsedSpace) memset(&Header.reserved, 0, sizeof(Header.reserved)); - // Set profile ID. Endianess is always big endian + // Set profile ID. Endianness is always big endian memmove(&Header.profileID, &Icc ->ProfileID, 16); // Dump the header @@ -789,7 +842,7 @@ cmsBool _cmsWriteHeader(_cmsICCPROFILE* Icc, cmsUInt32Number UsedSpace) // Get true count for (i=0; i < Icc -> TagCount; i++) { - if (Icc ->TagNames[i] != 0) + if (Icc ->TagNames[i] != (cmsTagSignature) 0) Count++; } @@ -798,7 +851,7 @@ cmsBool _cmsWriteHeader(_cmsICCPROFILE* Icc, cmsUInt32Number UsedSpace) for (i=0; i < Icc -> TagCount; i++) { - if (Icc ->TagNames[i] == 0) continue; // It is just a placeholder + if (Icc ->TagNames[i] == (cmsTagSignature) 0) continue; // It is just a placeholder Tag.sig = (cmsTagSignature) _cmsAdjustEndianess32((cmsInt32Number) Icc -> TagNames[i]); Tag.offset = _cmsAdjustEndianess32((cmsInt32Number) Icc -> TagOffsets[i]); @@ -1148,7 +1201,7 @@ cmsBool SaveTags(_cmsICCPROFILE* Icc, _cmsICCPROFILE* FileOrig) for (i=0; i < Icc -> TagCount; i++) { - if (Icc ->TagNames[i] == 0) continue; + if (Icc ->TagNames[i] == (cmsTagSignature) 0) continue; // Linked tags are not written if (Icc ->TagLinked[i] != (cmsTagSignature) 0) continue; @@ -1281,12 +1334,16 @@ cmsUInt32Number CMSEXPORT cmsSaveProfileToIOhandler(cmsHPROFILE hProfile, cmsIOH cmsContext ContextID; _cmsAssert(hProfile != NULL); - + + if (!_cmsLockMutex(Icc->ContextID, Icc->UsrMutex)) return 0; memmove(&Keep, Icc, sizeof(_cmsICCPROFILE)); ContextID = cmsGetProfileContextID(hProfile); PrevIO = Icc ->IOhandler = cmsOpenIOhandlerFromNULL(ContextID); - if (PrevIO == NULL) return 0; + if (PrevIO == NULL) { + _cmsUnlockMutex(Icc->ContextID, Icc->UsrMutex); + return 0; + } // Pass #1 does compute offsets @@ -1306,7 +1363,10 @@ cmsUInt32Number CMSEXPORT cmsSaveProfileToIOhandler(cmsHPROFILE hProfile, cmsIOH } memmove(Icc, &Keep, sizeof(_cmsICCPROFILE)); - if (!cmsCloseIOhandler(PrevIO)) return 0; + if (!cmsCloseIOhandler(PrevIO)) + UsedSpace = 0; // As a error marker + + _cmsUnlockMutex(Icc->ContextID, Icc->UsrMutex); return UsedSpace; @@ -1314,13 +1374,15 @@ cmsUInt32Number CMSEXPORT cmsSaveProfileToIOhandler(cmsHPROFILE hProfile, cmsIOH Error: cmsCloseIOhandler(PrevIO); memmove(Icc, &Keep, sizeof(_cmsICCPROFILE)); + _cmsUnlockMutex(Icc->ContextID, Icc->UsrMutex); + return 0; } #ifdef _WIN32_WCE int wceex_unlink(const char *filename); #ifndef remove -# define remove wceex_unlink +# define remove wceex_unlink #endif #endif @@ -1534,7 +1596,7 @@ void* CMSEXPORT cmsReadTag(cmsHPROFILE hProfile, cmsTagSignature sig) LocalTypeHandler.ICCVersion = Icc ->Version; Icc -> TagPtrs[n] = LocalTypeHandler.ReadPtr(&LocalTypeHandler, io, &ElemCount, TagSize); - // The tag type is supported, but something wrong happend and we cannot read the tag. + // The tag type is supported, but something wrong happened and we cannot read the tag. // let know the user about this (although it is just a warning) if (Icc -> TagPtrs[n] == NULL) { @@ -1827,7 +1889,7 @@ Error: // Similar to the anterior. This function allows to write directly to the ICC profile any data, without // checking anything. As a rule, mixing Raw with cooked doesn't work, so writting a tag as raw and then reading -// it as cooked without serializing does result into an error. If that is wha you want, you will need to dump +// it as cooked without serializing does result into an error. If that is what you want, you will need to dump // the profile to memry or disk and then reopen it. cmsBool CMSEXPORT cmsWriteRawTag(cmsHPROFILE hProfile, cmsTagSignature sig, const void* data, cmsUInt32Number Size) { @@ -1851,6 +1913,11 @@ cmsBool CMSEXPORT cmsWriteRawTag(cmsHPROFILE hProfile, cmsTagSignature sig, cons Icc ->TagSizes[i] = Size; _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex); + + if (Icc->TagPtrs[i] == NULL) { + Icc->TagNames[i] = (cmsTagSignature) 0; + return FALSE; + } return TRUE; } diff --git a/third_party/lcms/src/cmsio1.c b/third_party/lcms/src/cmsio1.c index 778aa2b4fc..4b12ae18ea 100644 --- a/third_party/lcms/src/cmsio1.c +++ b/third_party/lcms/src/cmsio1.c @@ -1,7 +1,7 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2012 Marti Maria Saguer +// Copyright (c) 1998-2016 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"), @@ -128,7 +128,7 @@ cmsBool _cmsReadCHAD(cmsMAT3* Dest, cmsHPROFILE hProfile) } -// Auxiliar, read colorants as a MAT3 structure. Used by any function that needs a matrix-shaper +// Auxiliary, read colorants as a MAT3 structure. Used by any function that needs a matrix-shaper static cmsBool ReadICCMatrixRGB2XYZ(cmsMAT3* r, cmsHPROFILE hProfile) { @@ -201,10 +201,10 @@ cmsPipeline* BuildGrayInputMatrixPipeline(cmsHPROFILE hProfile) return Lut; Error: - // memory pointed by GrayTRC is not a new malloc memory, so don't free it here, - // memory pointed by GrayTRC will be freed when hProfile is closed. - // test file :0047776_Pocket Medicine_ The Massachusetts General Hospital Handbook of Internal Medicine-2.pdf - // Xiaochuan Liu, 20140421 + // memory pointed by GrayTRC is not a new malloc memory, so don't free it here, + // memory pointed by GrayTRC will be freed when hProfile is closed. + // test file :0047776_Pocket Medicine_ The Massachusetts General Hospital Handbook of Internal Medicine-2.pdf + // Xiaochuan Liu, 20140421 //cmsFreeToneCurve(GrayTRC); cmsPipelineFree(Lut); return NULL; @@ -314,11 +314,11 @@ Error: cmsPipeline* _cmsReadInputLUT(cmsHPROFILE hProfile, int Intent) { cmsTagTypeSignature OriginalType; - cmsTagSignature tag16 = Device2PCS16[Intent]; - cmsTagSignature tagFloat = Device2PCSFloat[Intent]; + cmsTagSignature tag16; + cmsTagSignature tagFloat; cmsContext ContextID = cmsGetProfileContextID(hProfile); - // On named color, take the appropiate tag + // On named color, take the appropriate tag if (cmsGetDeviceClass(hProfile) == cmsSigNamedColorClass) { cmsPipeline* Lut; @@ -340,9 +340,12 @@ cmsPipeline* _cmsReadInputLUT(cmsHPROFILE hProfile, int Intent) return Lut; } - // This is an attempt to reuse this funtion to retrieve the matrix-shaper as pipeline no + // This is an attempt to reuse this function to retrieve the matrix-shaper as pipeline no // matter other LUT are present and have precedence. Intent = -1 means just this. - if (Intent != -1) { + if (Intent >= INTENT_PERCEPTUAL && Intent <= INTENT_ABSOLUTE_COLORIMETRIC) { + + tag16 = Device2PCS16[Intent]; + tagFloat = Device2PCSFloat[Intent]; if (cmsIsTag(hProfile, tagFloat)) { // Float tag takes precedence @@ -395,7 +398,7 @@ Error: // Check if this is a grayscale profile. if (cmsGetColorSpace(hProfile) == cmsSigGrayData) { - // if so, build appropiate conversion tables. + // if so, build appropriate conversion tables. // The tables are the PCS iluminant, scaled across GrayTRC return BuildGrayInputMatrixPipeline(hProfile); } @@ -550,7 +553,7 @@ cmsPipeline* _cmsReadFloatOutputTag(cmsHPROFILE hProfile, cmsTagSignature tagFlo if (Lut == NULL) return NULL; // If PCS is Lab or XYZ, the floating point tag is accepting data in the space encoding, - // and since the formatter has already accomodated to 0..1.0, we should undo this change + // and since the formatter has already accommodated to 0..1.0, we should undo this change if ( PCS == cmsSigLabData) { if (!cmsPipelineInsertStage(Lut, cmsAT_BEGIN, _cmsStageNormalizeToLabFloat(ContextID))) @@ -586,12 +589,15 @@ Error: cmsPipeline* _cmsReadOutputLUT(cmsHPROFILE hProfile, int Intent) { cmsTagTypeSignature OriginalType; - cmsTagSignature tag16 = PCS2Device16[Intent]; - cmsTagSignature tagFloat = PCS2DeviceFloat[Intent]; - cmsContext ContextID = cmsGetProfileContextID(hProfile); + cmsTagSignature tag16; + cmsTagSignature tagFloat; + cmsContext ContextID = cmsGetProfileContextID(hProfile); + + if (Intent >= INTENT_PERCEPTUAL && Intent <= INTENT_ABSOLUTE_COLORIMETRIC) { - if (Intent != -1) { + tag16 = PCS2Device16[Intent]; + tagFloat = PCS2DeviceFloat[Intent]; if (cmsIsTag(hProfile, tagFloat)) { // Float tag takes precedence @@ -649,7 +655,7 @@ Error: // Check if this is a grayscale profile. if (cmsGetColorSpace(hProfile) == cmsSigGrayData) { - // if so, build appropiate conversion tables. + // if so, build appropriate conversion tables. // The tables are the PCS iluminant, scaled across GrayTRC return BuildGrayOutputPipeline(hProfile); } @@ -707,15 +713,21 @@ cmsPipeline* _cmsReadDevicelinkLUT(cmsHPROFILE hProfile, int Intent) { cmsPipeline* Lut; cmsTagTypeSignature OriginalType; - cmsTagSignature tag16 = Device2PCS16[Intent]; - cmsTagSignature tagFloat = Device2PCSFloat[Intent]; + cmsTagSignature tag16; + cmsTagSignature tagFloat; cmsContext ContextID = cmsGetProfileContextID(hProfile); - // On named color, take the appropiate tag + if (Intent < INTENT_PERCEPTUAL || Intent > INTENT_ABSOLUTE_COLORIMETRIC) + return NULL; + + tag16 = Device2PCS16[Intent]; + tagFloat = Device2PCSFloat[Intent]; + + // On named color, take the appropriate tag if (cmsGetDeviceClass(hProfile) == cmsSigNamedColorClass) { - cmsNAMEDCOLORLIST* nc = (cmsNAMEDCOLORLIST*) cmsReadTag(hProfile, cmsSigNamedColor2Tag); + cmsNAMEDCOLORLIST* nc = (cmsNAMEDCOLORLIST*)cmsReadTag(hProfile, cmsSigNamedColor2Tag); if (nc == NULL) return NULL; @@ -731,12 +743,13 @@ cmsPipeline* _cmsReadDevicelinkLUT(cmsHPROFILE hProfile, int Intent) goto Error; return Lut; -Error: + Error: cmsPipelineFree(Lut); cmsFreeNamedColorList(nc); return NULL; } + if (cmsIsTag(hProfile, tagFloat)) { // Float tag takes precedence // Floating point LUT are always V @@ -746,19 +759,19 @@ Error: tagFloat = Device2PCSFloat[0]; if (cmsIsTag(hProfile, tagFloat)) { - return cmsPipelineDup((cmsPipeline*) cmsReadTag(hProfile, tagFloat)); + return cmsPipelineDup((cmsPipeline*)cmsReadTag(hProfile, tagFloat)); } if (!cmsIsTag(hProfile, tag16)) { // Is there any LUT-Based table? - tag16 = Device2PCS16[0]; + tag16 = Device2PCS16[0]; if (!cmsIsTag(hProfile, tag16)) return NULL; } // Check profile version and LUT type. Do the necessary adjustments if needed // Read the tag - Lut = (cmsPipeline*) cmsReadTag(hProfile, tag16); + Lut = (cmsPipeline*)cmsReadTag(hProfile, tag16); if (Lut == NULL) return NULL; // The profile owns the Lut, so we need to copy it @@ -771,7 +784,7 @@ Error: ChangeInterpolationToTrilinear(Lut); // After reading it, we have info about the original type - OriginalType = _cmsGetTagTrueType(hProfile, tag16); + OriginalType = _cmsGetTagTrueType(hProfile, tag16); // We need to adjust data for Lab16 on output if (OriginalType != cmsSigLut16Type) return Lut; @@ -779,12 +792,12 @@ Error: // Here it is possible to get Lab on both sides if (cmsGetColorSpace(hProfile) == cmsSigLabData) { - if(!cmsPipelineInsertStage(Lut, cmsAT_BEGIN, _cmsStageAllocLabV4ToV2(ContextID))) + if (!cmsPipelineInsertStage(Lut, cmsAT_BEGIN, _cmsStageAllocLabV4ToV2(ContextID))) goto Error2; } if (cmsGetPCS(hProfile) == cmsSigLabData) { - if(!cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageAllocLabV2ToV4(ContextID))) + if (!cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageAllocLabV2ToV4(ContextID))) goto Error2; } @@ -910,7 +923,7 @@ cmsBool _cmsWriteProfileSequence(cmsHPROFILE hProfile, const cmsSEQ* seq) { if (!cmsWriteTag(hProfile, cmsSigProfileSequenceDescTag, seq)) return FALSE; - if (cmsGetProfileVersion(hProfile) >= 4.0) { + if (cmsGetEncodedICCversion(hProfile) >= 0x4000000) { if (!cmsWriteTag(hProfile, cmsSigProfileSequenceIdTag, seq)) return FALSE; } @@ -919,7 +932,7 @@ cmsBool _cmsWriteProfileSequence(cmsHPROFILE hProfile, const cmsSEQ* seq) } -// Auxiliar, read and duplicate a MLU if found. +// Auxiliary, read and duplicate a MLU if found. static cmsMLU* GetMLUFromProfile(cmsHPROFILE h, cmsTagSignature sig) { diff --git a/third_party/lcms/src/cmslut.c b/third_party/lcms/src/cmslut.c index 19d43361f0..8d5815902a 100644 --- a/third_party/lcms/src/cmslut.c +++ b/third_party/lcms/src/cmslut.c @@ -1,7 +1,7 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2012 Marti Maria Saguer +// Copyright (c) 1998-2016 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"), @@ -505,7 +505,7 @@ void* CLUTElemDup(cmsStage* mpe) goto Error; } else { NewElem ->Tab.T = (cmsUInt16Number*) _cmsDupMem(mpe ->ContextID, Data ->Tab.T, Data ->nEntries * sizeof (cmsUInt16Number)); - if (NewElem ->Tab.TFloat == NULL) + if (NewElem ->Tab.T == NULL) goto Error; } } @@ -1125,7 +1125,23 @@ cmsStage* _cmsStageNormalizeToXyzFloat(cmsContext ContextID) return mpe; } +// Clips values smaller than zero +static +void Clipper(const cmsFloat32Number In[], cmsFloat32Number Out[], const cmsStage *mpe) +{ + cmsUInt32Number i; + for (i = 0; i < mpe->InputChannels; i++) { + + cmsFloat32Number n = In[i]; + Out[i] = n < 0 ? 0 : n; + } +} +cmsStage* _cmsStageClipNegatives(cmsContext ContextID, int nChannels) +{ + return _cmsStageAllocPlaceholder(ContextID, cmsSigClipNegativesElemType, + nChannels, nChannels, Clipper, NULL, NULL, NULL); +} // ******************************************************************************** // Type cmsSigXYZ2LabElemType @@ -1287,7 +1303,7 @@ cmsBool BlessLUT(cmsPipeline* lut) prev = prev->Next; } } - return TRUE; + return TRUE; } @@ -1460,7 +1476,8 @@ cmsPipeline* CMSEXPORT cmsPipelineDup(const cmsPipeline* lut) First = FALSE; } else { - Anterior ->Next = NewMPE; + if (Anterior != NULL) + Anterior ->Next = NewMPE; } Anterior = NewMPE; @@ -1510,7 +1527,7 @@ int CMSEXPORT cmsPipelineInsertStage(cmsPipeline* lut, cmsStageLoc loc, cmsStage for (pt = lut ->Elements; pt != NULL; pt = pt -> Next) Anterior = pt; - + Anterior ->Next = mpe; mpe ->Next = NULL; } @@ -1519,7 +1536,7 @@ int CMSEXPORT cmsPipelineInsertStage(cmsPipeline* lut, cmsStageLoc loc, cmsStage return FALSE; } - return BlessLUT(lut); + return BlessLUT(lut); } // Unlink an element and return the pointer to it @@ -1601,7 +1618,7 @@ cmsBool CMSEXPORT cmsPipelineCat(cmsPipeline* l1, const cmsPipeline* l2) return FALSE; } - return BlessLUT(l1); + return BlessLUT(l1); } @@ -1818,3 +1835,5 @@ cmsBool CMSEXPORT cmsPipelineEvalReverseFloat(cmsFloat32Number Target[], return TRUE; } + + diff --git a/third_party/lcms/src/cmsmd5.c b/third_party/lcms/src/cmsmd5.c index a4758ff662..c7380ca8f0 100644 --- a/third_party/lcms/src/cmsmd5.c +++ b/third_party/lcms/src/cmsmd5.c @@ -1,7 +1,7 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2012 Marti Maria Saguer +// Copyright (c) 1998-2016 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"), @@ -23,6 +23,7 @@ // //--------------------------------------------------------------------------------- + #include "lcms2_internal.h" #ifdef CMS_USE_BIG_ENDIAN @@ -314,30 +315,3 @@ Error: return FALSE; } -cmsBool CMSEXPORT cmsMD5computeIDExt(const void* buf, unsigned long size, unsigned char ProfileID[16]) -{ - cmsHANDLE MD5; - cmsUInt8Number* Mem; - - if (buf == NULL) - return FALSE; - MD5 = NULL; - Mem = (cmsUInt8Number*)_cmsMalloc(NULL,size); - memmove(Mem,buf,size); - // Create MD5 object - MD5 = MD5alloc(NULL); - if (MD5 == NULL) goto Error; - - // Add all bytes - MD5add(MD5, Mem, size); - - // Temp storage is no longer needed - _cmsFree(NULL, Mem); - - // And store the ID - MD5finish((cmsProfileID*)ProfileID, MD5); - return TRUE; -Error: - if (MD5 != NULL) _cmsFree(NULL, MD5); - return FALSE; -} diff --git a/third_party/lcms/src/cmsmtrx.c b/third_party/lcms/src/cmsmtrx.c index fb7b91caf1..d0e5461e9f 100644 --- a/third_party/lcms/src/cmsmtrx.c +++ b/third_party/lcms/src/cmsmtrx.c @@ -1,7 +1,7 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2012 Marti Maria Saguer +// Copyright (c) 1998-2016 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"), @@ -38,7 +38,7 @@ void CMSEXPORT _cmsVEC3init(cmsVEC3* r, cmsFloat64Number x, cmsFloat64Number y, r -> n[VZ] = z; } -// Vector substraction +// Vector subtraction void CMSEXPORT _cmsVEC3minus(cmsVEC3* r, const cmsVEC3* a, const cmsVEC3* b) { r -> n[VX] = a -> n[VX] - b -> n[VX]; @@ -173,3 +173,4 @@ void CMSEXPORT _cmsMAT3eval(cmsVEC3* r, const cmsMAT3* a, const cmsVEC3* v) r->n[VZ] = a->v[2].n[VX]*v->n[VX] + a->v[2].n[VY]*v->n[VY] + a->v[2].n[VZ]*v->n[VZ]; } + diff --git a/third_party/lcms/src/cmsnamed.c b/third_party/lcms/src/cmsnamed.c index ef1eb3089e..9ed4cad398 100644 --- a/third_party/lcms/src/cmsnamed.c +++ b/third_party/lcms/src/cmsnamed.c @@ -1,7 +1,7 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2012 Marti Maria Saguer +// Copyright (c) 1998-2016 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"), @@ -92,7 +92,7 @@ cmsBool GrowMLUpool(cmsMLU* mlu) static cmsBool GrowMLUtable(cmsMLU* mlu) { - int AllocatedEntries; + cmsUInt32Number AllocatedEntries; _cmsMLUentry *NewPtr; // Sanity check @@ -118,7 +118,7 @@ cmsBool GrowMLUtable(cmsMLU* mlu) static int SearchMLUEntry(cmsMLU* mlu, cmsUInt16Number LanguageCode, cmsUInt16Number CountryCode) { - int i; + cmsUInt32Number i; // Sanity check if (mlu == NULL) return -1; @@ -178,15 +178,42 @@ cmsBool AddMLUBlock(cmsMLU* mlu, cmsUInt32Number size, const wchar_t *Block, return TRUE; } +// Convert from a 3-char code to a cmsUInt16Number. It is done inthis way because some +// compilers don't properly align beginning of strings + +static +cmsUInt16Number strTo16(const char str[3]) +{ + cmsUInt16Number n = ((cmsUInt16Number) str[0] << 8) | str[1]; + + return n; // Always big endian in this case +} + +static +void strFrom16(char str[3], cmsUInt16Number n) +{ + // Assiming this would be aligned + union { + + cmsUInt16Number n; + char str[2]; + + } c; + + c.n = n; // Always big endian in this case + + str[0] = c.str[0]; str[1] = c.str[1]; str[2] = 0; -// Add an ASCII entry. +} + +// Add an ASCII entry. Do not add any \0 termination (ICC1v43_2010-12.pdf page 61) cmsBool CMSEXPORT cmsMLUsetASCII(cmsMLU* mlu, const char LanguageCode[3], const char CountryCode[3], const char* ASCIIString) { - cmsUInt32Number i, len = (cmsUInt32Number) strlen(ASCIIString)+1; + cmsUInt32Number i, len = (cmsUInt32Number) strlen(ASCIIString); wchar_t* WStr; cmsBool rc; - cmsUInt16Number Lang = _cmsAdjustEndianess16(*(cmsUInt16Number*) LanguageCode); - cmsUInt16Number Cntry = _cmsAdjustEndianess16(*(cmsUInt16Number*) CountryCode); + cmsUInt16Number Lang = strTo16(LanguageCode); + cmsUInt16Number Cntry = strTo16(CountryCode); if (mlu == NULL) return FALSE; @@ -216,18 +243,17 @@ cmsUInt32Number mywcslen(const wchar_t *s) return (cmsUInt32Number)(p - s); } - -// Add a wide entry +// Add a wide entry. Do not add any \0 terminator (ICC1v43_2010-12.pdf page 61) cmsBool CMSEXPORT cmsMLUsetWide(cmsMLU* mlu, const char Language[3], const char Country[3], const wchar_t* WideString) { - cmsUInt16Number Lang = _cmsAdjustEndianess16(*(cmsUInt16Number*) Language); - cmsUInt16Number Cntry = _cmsAdjustEndianess16(*(cmsUInt16Number*) Country); + cmsUInt16Number Lang = strTo16(Language); + cmsUInt16Number Cntry = strTo16(Country); cmsUInt32Number len; if (mlu == NULL) return FALSE; if (WideString == NULL) return FALSE; - len = (cmsUInt32Number) (mywcslen(WideString) + 1) * sizeof(wchar_t); + len = (cmsUInt32Number) (mywcslen(WideString)) * sizeof(wchar_t); return AddMLUBlock(mlu, len, WideString, Lang, Cntry); } @@ -298,8 +324,8 @@ const wchar_t* _cmsMLUgetWide(const cmsMLU* mlu, cmsUInt16Number LanguageCode, cmsUInt16Number CountryCode, cmsUInt16Number* UsedLanguageCode, cmsUInt16Number* UsedCountryCode) { - int i; - int Best = -1; + cmsUInt32Number i; + cmsInt32Number Best = -1; _cmsMLUentry* v; if (mlu == NULL) return NULL; @@ -350,8 +376,8 @@ cmsUInt32Number CMSEXPORT cmsMLUgetASCII(const cmsMLU* mlu, cmsUInt32Number StrLen = 0; cmsUInt32Number ASCIIlen, i; - cmsUInt16Number Lang = _cmsAdjustEndianess16(*(cmsUInt16Number*) LanguageCode); - cmsUInt16Number Cntry = _cmsAdjustEndianess16(*(cmsUInt16Number*) CountryCode); + cmsUInt16Number Lang = strTo16(LanguageCode); + cmsUInt16Number Cntry = strTo16(CountryCode); // Sanitize if (mlu == NULL) return 0; @@ -394,8 +420,8 @@ cmsUInt32Number CMSEXPORT cmsMLUgetWide(const cmsMLU* mlu, const wchar_t *Wide; cmsUInt32Number StrLen = 0; - cmsUInt16Number Lang = _cmsAdjustEndianess16(*(cmsUInt16Number*) LanguageCode); - cmsUInt16Number Cntry = _cmsAdjustEndianess16(*(cmsUInt16Number*) CountryCode); + cmsUInt16Number Lang = strTo16(LanguageCode); + cmsUInt16Number Cntry = strTo16(CountryCode); // Sanitize if (mlu == NULL) return 0; @@ -427,8 +453,8 @@ CMSAPI cmsBool CMSEXPORT cmsMLUgetTranslation(const cmsMLU* mlu, { const wchar_t *Wide; - cmsUInt16Number Lang = _cmsAdjustEndianess16(*(cmsUInt16Number*) LanguageCode); - cmsUInt16Number Cntry = _cmsAdjustEndianess16(*(cmsUInt16Number*) CountryCode); + cmsUInt16Number Lang = strTo16(LanguageCode); + cmsUInt16Number Cntry = strTo16(CountryCode); cmsUInt16Number ObtLang, ObtCode; // Sanitize @@ -438,10 +464,9 @@ CMSAPI cmsBool CMSEXPORT cmsMLUgetTranslation(const cmsMLU* mlu, if (Wide == NULL) return FALSE; // Get used language and code - *(cmsUInt16Number *)ObtainedLanguage = _cmsAdjustEndianess16(ObtLang); - *(cmsUInt16Number *)ObtainedCountry = _cmsAdjustEndianess16(ObtCode); + strFrom16(ObtainedLanguage, ObtLang); + strFrom16(ObtainedCountry, ObtCode); - ObtainedLanguage[2] = ObtainedCountry[2] = 0; return TRUE; } @@ -464,12 +489,12 @@ cmsBool CMSEXPORT cmsMLUtranslationsCodes(const cmsMLU* mlu, if (mlu == NULL) return FALSE; - if (idx >= (cmsUInt32Number) mlu->UsedEntries) return FALSE; + if (idx >= mlu->UsedEntries) return FALSE; entry = &mlu->Entries[idx]; - *(cmsUInt16Number *)LanguageCode = _cmsAdjustEndianess16(entry->Language); - *(cmsUInt16Number *)CountryCode = _cmsAdjustEndianess16(entry->Country); + strFrom16(LanguageCode, entry->Language); + strFrom16(CountryCode, entry->Country); return TRUE; } @@ -514,7 +539,7 @@ cmsNAMEDCOLORLIST* CMSEXPORT cmsAllocNamedColorList(cmsContext ContextID, cmsUIn v ->nColors = 0; v ->ContextID = ContextID; - while (v -> Allocated < n) { + while (v -> Allocated < n){ if (!GrowNamedColorList(v)) { cmsFreeNamedColorList(v); return NULL; @@ -548,7 +573,7 @@ cmsNAMEDCOLORLIST* CMSEXPORT cmsDupNamedColorList(const cmsNAMEDCOLORLIST* v) if (NewNC == NULL) return NULL; // For really large tables we need this - while (NewNC ->Allocated < v ->Allocated) { + while (NewNC ->Allocated < v ->Allocated){ if (!GrowNamedColorList(NewNC)) { cmsFreeNamedColorList(NewNC); return NULL; diff --git a/third_party/lcms/src/cmsopt.c b/third_party/lcms/src/cmsopt.c index 76de01554c..abe26b93af 100644 --- a/third_party/lcms/src/cmsopt.c +++ b/third_party/lcms/src/cmsopt.c @@ -1,7 +1,7 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2011 Marti Maria Saguer +// Copyright (c) 1998-2016 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"), @@ -162,6 +162,89 @@ cmsBool _Remove2Op(cmsPipeline* Lut, cmsStageSignature Op1, cmsStageSignature Op return AnyOpt; } + +static +cmsBool CloseEnoughFloat(cmsFloat64Number a, cmsFloat64Number b) +{ + return fabs(b - a) < 0.00001f; +} + +static +cmsBool isFloatMatrixIdentity(const cmsMAT3* a) +{ + cmsMAT3 Identity; + int i, j; + + _cmsMAT3identity(&Identity); + + for (i = 0; i < 3; i++) + for (j = 0; j < 3; j++) + if (!CloseEnoughFloat(a->v[i].n[j], Identity.v[i].n[j])) return FALSE; + + return TRUE; +} +// if two adjacent matrices are found, multiply them. +static +cmsBool _MultiplyMatrix(cmsPipeline* Lut) +{ + cmsStage** pt1; + cmsStage** pt2; + cmsStage* chain; + cmsBool AnyOpt = FALSE; + + pt1 = &Lut->Elements; + if (*pt1 == NULL) return AnyOpt; + + while (*pt1 != NULL) { + + pt2 = &((*pt1)->Next); + if (*pt2 == NULL) return AnyOpt; + + if ((*pt1)->Implements == cmsSigMatrixElemType && (*pt2)->Implements == cmsSigMatrixElemType) { + + // Get both matrices + _cmsStageMatrixData* m1 = (_cmsStageMatrixData*) cmsStageData(*pt1); + _cmsStageMatrixData* m2 = (_cmsStageMatrixData*) cmsStageData(*pt2); + cmsMAT3 res; + + // Input offset and output offset should be zero to use this optimization + if (m1->Offset != NULL || m2 ->Offset != NULL || + cmsStageInputChannels(*pt1) != 3 || cmsStageOutputChannels(*pt1) != 3 || + cmsStageInputChannels(*pt2) != 3 || cmsStageOutputChannels(*pt2) != 3) + return FALSE; + + // Multiply both matrices to get the result + _cmsMAT3per(&res, (cmsMAT3*)m2->Double, (cmsMAT3*)m1->Double); + + // Get the next in chain afer the matrices + chain = (*pt2)->Next; + + // Remove both matrices + _RemoveElement(pt2); + _RemoveElement(pt1); + + // Now what if the result is a plain identity? + if (!isFloatMatrixIdentity(&res)) { + + // We can not get rid of full matrix + cmsStage* Multmat = cmsStageAllocMatrix(Lut->ContextID, 3, 3, (const cmsFloat64Number*) &res, NULL); + if (Multmat == NULL) return FALSE; // Should never happen + + // Recover the chain + Multmat->Next = chain; + *pt1 = Multmat; + } + + AnyOpt = TRUE; + } + else + pt1 = &((*pt1)->Next); + } + + return AnyOpt; +} + + // Preoptimize just gets rif of no-ops coming paired. Conversion from v2 to v4 followed // by a v4 to v2 and vice-versa. The elements are then discarded. static @@ -194,6 +277,9 @@ cmsBool PreOptimize(cmsPipeline* Lut) // Remove float pcs Lab conversions Opt |= _Remove2Op(Lut, cmsSigXYZ2FloatPCS, cmsSigFloatPCS2XYZ); + // Simplify matrix. + Opt |= _MultiplyMatrix(Lut); + if (Opt) AnyOpt = TRUE; } while (Opt); @@ -250,12 +336,12 @@ static void* Prelin16dup(cmsContext ContextID, const void* ptr) { Prelin16Data* p16 = (Prelin16Data*) ptr; - Prelin16Data* Duped = _cmsDupMem(ContextID, p16, sizeof(Prelin16Data)); + Prelin16Data* Duped = (Prelin16Data*) _cmsDupMem(ContextID, p16, sizeof(Prelin16Data)); if (Duped == NULL) return NULL; - Duped ->EvalCurveOut16 = (_cmsInterpFn16*)_cmsDupMem(ContextID, p16 ->EvalCurveOut16, p16 ->nOutputs * sizeof(_cmsInterpFn16)); - Duped ->ParamsCurveOut16 = (cmsInterpParams**)_cmsDupMem(ContextID, p16 ->ParamsCurveOut16, p16 ->nOutputs * sizeof(cmsInterpParams* )); + Duped->EvalCurveOut16 = (_cmsInterpFn16*) _cmsDupMem(ContextID, p16->EvalCurveOut16, p16->nOutputs * sizeof(_cmsInterpFn16)); + Duped->ParamsCurveOut16 = (cmsInterpParams**)_cmsDupMem(ContextID, p16->ParamsCurveOut16, p16->nOutputs * sizeof(cmsInterpParams*)); return Duped; } @@ -268,7 +354,7 @@ Prelin16Data* PrelinOpt16alloc(cmsContext ContextID, int nOutputs, cmsToneCurve** Out ) { int i; - Prelin16Data* p16 = _cmsMallocZero(ContextID, sizeof(Prelin16Data)); + Prelin16Data* p16 = (Prelin16Data*)_cmsMallocZero(ContextID, sizeof(Prelin16Data)); if (p16 == NULL) return NULL; p16 ->nInputs = nInputs; @@ -380,10 +466,6 @@ cmsBool PatchLUT(cmsStage* CLUT, cmsUInt16Number At[], cmsUInt16Number Value[], return FALSE; } - if (nChannelsIn != 1 && nChannelsIn != 3 && nChannelsIn != 4) { - cmsSignalError(CLUT->ContextID, cmsERROR_INTERNAL, "(internal) %d Channels are not supported on PatchLUT", nChannelsIn); - return FALSE; - } if (nChannelsIn == 4) { px = ((cmsFloat64Number) At[0] * (p16->Domain[0])) / 65535.0; @@ -447,7 +529,7 @@ cmsBool PatchLUT(cmsStage* CLUT, cmsUInt16Number At[], cmsUInt16Number Value[], return TRUE; } -// Auxiliar, to see if two values are equal or very different +// Auxiliary, to see if two values are equal or very different static cmsBool WhitesAreEqual(int n, cmsUInt16Number White1[], cmsUInt16Number White2[] ) { @@ -455,7 +537,7 @@ cmsBool WhitesAreEqual(int n, cmsUInt16Number White1[], cmsUInt16Number White2[] for (i=0; i < n; i++) { - if (abs(White1[i] - White2[i]) > 0xf000) return TRUE; // Values are so extremly different that the fixup should be avoided + if (abs(White1[i] - White2[i]) > 0xf000) return TRUE; // Values are so extremely different that the fixup should be avoided if (White1[i] != White2[i]) return FALSE; } return TRUE; @@ -593,7 +675,7 @@ cmsBool OptimizeByResampling(cmsPipeline** Lut, cmsUInt32Number Intent, cmsUInt3 cmsStage* PreLin = cmsPipelineGetPtrToFirstStage(Src); // Check if suitable - if (PreLin ->Type == cmsSigCurveSetElemType) { + if (PreLin && PreLin ->Type == cmsSigCurveSetElemType) { // Maybe this is a linear tram, so we can avoid the whole stuff if (!AllCurvesAreLinear(PreLin)) { @@ -626,7 +708,7 @@ cmsBool OptimizeByResampling(cmsPipeline** Lut, cmsUInt32Number Intent, cmsUInt3 cmsStage* PostLin = cmsPipelineGetPtrToLastStage(Src); // Check if suitable - if (cmsStageType(PostLin) == cmsSigCurveSetElemType) { + if (PostLin && cmsStageType(PostLin) == cmsSigCurveSetElemType) { // Maybe this is a linear tram, so we can avoid the whole stuff if (!AllCurvesAreLinear(PostLin)) { @@ -835,7 +917,7 @@ void PrelinEval8(register const cmsUInt16Number Input[], Prelin8Data* p8 = (Prelin8Data*) D; register const cmsInterpParams* p = p8 ->p; int TotalOut = p -> nOutputs; - const cmsUInt16Number* LutTable = (const cmsUInt16Number*)p -> Table; + const cmsUInt16Number* LutTable = (const cmsUInt16Number*) p->Table; r = Input[0] >> 8; g = Input[1] >> 8; @@ -928,8 +1010,8 @@ cmsBool IsDegenerated(const cmsToneCurve* g) } if (Zeros == 1 && Poles == 1) return FALSE; // For linear tables - if (Zeros > (nEntries / 4)) return TRUE; // Degenerated, mostly zeros - if (Poles > (nEntries / 4)) return TRUE; // Degenerated, mostly poles + if (Zeros > (nEntries / 20)) return TRUE; // Degenerated, many zeros + if (Poles > (nEntries / 20)) return TRUE; // Degenerated, many poles return FALSE; } @@ -951,17 +1033,19 @@ cmsBool OptimizeByComputingLinearization(cmsPipeline** Lut, cmsUInt32Number Inte cmsColorSpaceSignature ColorSpace, OutputColorSpace; cmsStage* OptimizedPrelinMpe; cmsStage* mpe; - cmsToneCurve** OptimizedPrelinCurves; - _cmsStageCLutData* OptimizedPrelinCLUT; + cmsToneCurve** OptimizedPrelinCurves; + _cmsStageCLutData* OptimizedPrelinCLUT; // This is a loosy optimization! does not apply in floating-point cases if (_cmsFormatterIsFloat(*InputFormat) || _cmsFormatterIsFloat(*OutputFormat)) return FALSE; - // Only on RGB + // Only on chunky RGB if (T_COLORSPACE(*InputFormat) != PT_RGB) return FALSE; - if (T_COLORSPACE(*OutputFormat) != PT_RGB) return FALSE; + if (T_PLANAR(*InputFormat)) return FALSE; + if (T_COLORSPACE(*OutputFormat) != PT_RGB) return FALSE; + if (T_PLANAR(*OutputFormat)) return FALSE; // On 16 bits, user has to specify the feature if (!_cmsFormatterIs8bit(*InputFormat)) { @@ -985,6 +1069,22 @@ cmsBool OptimizeByComputingLinearization(cmsPipeline** Lut, cmsUInt32Number Inte memset(Trans, 0, sizeof(Trans)); memset(TransReverse, 0, sizeof(TransReverse)); + // If the last stage of the original lut are curves, and those curves are + // degenerated, it is likely the transform is squeezing and clipping + // the output from previous CLUT. We cannot optimize this case + { + cmsStage* last = cmsPipelineGetPtrToLastStage(OriginalLut); + + if (cmsStageType(last) == cmsSigCurveSetElemType) { + + _cmsStageToneCurvesData* Data = (_cmsStageToneCurvesData*)cmsStageData(last); + for (i = 0; i < Data->nCurves; i++) { + if (IsDegenerated(Data->TheCurves[i])) + goto Error; + } + } + } + for (t = 0; t < OriginalLut ->InputChannels; t++) { Trans[t] = cmsBuildTabulatedToneCurve16(OriginalLut ->ContextID, PRELINEARIZATION_POINTS, NULL); if (Trans[t] == NULL) goto Error; @@ -1159,10 +1259,10 @@ void* CurvesDup(cmsContext ContextID, const void* ptr) if (Data == NULL) return NULL; - Data ->Curves = (cmsUInt16Number**)_cmsDupMem(ContextID, Data ->Curves, Data ->nCurves * sizeof(cmsUInt16Number*)); + Data->Curves = (cmsUInt16Number**) _cmsDupMem(ContextID, Data->Curves, Data->nCurves * sizeof(cmsUInt16Number*)); for (i=0; i < Data -> nCurves; i++) { - Data ->Curves[i] = (cmsUInt16Number*)_cmsDupMem(ContextID, Data ->Curves[i], Data -> nElements * sizeof(cmsUInt16Number)); + Data->Curves[i] = (cmsUInt16Number*) _cmsDupMem(ContextID, Data->Curves[i], Data->nElements * sizeof(cmsUInt16Number)); } return (void*) Data; @@ -1181,12 +1281,12 @@ Curves16Data* CurvesAlloc(cmsContext ContextID, int nCurves, int nElements, cmsT c16 ->nCurves = nCurves; c16 ->nElements = nElements; - c16 ->Curves = (cmsUInt16Number**)_cmsCalloc(ContextID, nCurves, sizeof(cmsUInt16Number*)); + c16->Curves = (cmsUInt16Number**) _cmsCalloc(ContextID, nCurves, sizeof(cmsUInt16Number*)); if (c16 ->Curves == NULL) return NULL; for (i=0; i < nCurves; i++) { - c16->Curves[i] = (cmsUInt16Number*)_cmsCalloc(ContextID, nElements, sizeof(cmsUInt16Number)); + c16->Curves[i] = (cmsUInt16Number*) _cmsCalloc(ContextID, nElements, sizeof(cmsUInt16Number)); if (c16->Curves[i] == NULL) { @@ -1318,7 +1418,10 @@ cmsBool OptimizeByJoiningCurves(cmsPipeline** Lut, cmsUInt32Number Intent, cmsUI GammaTables[i] = NULL; } - if (GammaTables != NULL) _cmsFree(Src ->ContextID, GammaTables); + if (GammaTables != NULL) { + _cmsFree(Src->ContextID, GammaTables); + GammaTables = NULL; + } // Maybe the curves are linear at the end if (!AllCurvesAreLinear(ObtainedCurves)) { @@ -1543,55 +1646,89 @@ cmsBool SetMatShaper(cmsPipeline* Dest, cmsToneCurve* Curve1[3], cmsMAT3* Mat, c // Fill function pointers _cmsPipelineSetOptimizationParameters(Dest, MatShaperEval16, (void*) p, FreeMatShaper, DupMatShaper); return TRUE; -Error: - _cmsFree(Dest->ContextID, p); - return FALSE; + Error: + _cmsFree(Dest->ContextID, p); + return FALSE; } // 8 bits on input allows matrix-shaper boot up to 25 Mpixels per second on RGB. That's fast! -// TODO: Allow a third matrix for abs. colorimetric static cmsBool OptimizeMatrixShaper(cmsPipeline** Lut, cmsUInt32Number Intent, cmsUInt32Number* InputFormat, cmsUInt32Number* OutputFormat, cmsUInt32Number* dwFlags) { - cmsStage* Curve1, *Curve2; - cmsStage* Matrix1, *Matrix2; - _cmsStageMatrixData* Data1; - _cmsStageMatrixData* Data2; - cmsMAT3 res; - cmsBool IdentityMat; - cmsPipeline* Dest, *Src; + cmsStage* Curve1, *Curve2; + cmsStage* Matrix1, *Matrix2; + cmsMAT3 res; + cmsBool IdentityMat; + cmsPipeline* Dest, *Src; + cmsFloat64Number* Offset; - // Only works on RGB to RGB - if (T_CHANNELS(*InputFormat) != 3 || T_CHANNELS(*OutputFormat) != 3) return FALSE; + // Only works on RGB to RGB + if (T_CHANNELS(*InputFormat) != 3 || T_CHANNELS(*OutputFormat) != 3) return FALSE; - // Only works on 8 bit input - if (!_cmsFormatterIs8bit(*InputFormat)) return FALSE; + // Only works on 8 bit input + if (!_cmsFormatterIs8bit(*InputFormat)) return FALSE; - // Seems suitable, proceed - Src = *Lut; + // Seems suitable, proceed + Src = *Lut; - // Check for shaper-matrix-matrix-shaper structure, that is what this optimizer stands for - if (!cmsPipelineCheckAndRetreiveStages(Src, 4, - cmsSigCurveSetElemType, cmsSigMatrixElemType, cmsSigMatrixElemType, cmsSigCurveSetElemType, - &Curve1, &Matrix1, &Matrix2, &Curve2)) return FALSE; + // Check for: + // + // shaper-matrix-matrix-shaper + // shaper-matrix-shaper + // + // Both of those constructs are possible (first because abs. colorimetric). + // additionally, In the first case, the input matrix offset should be zero. - // Get both matrices - Data1 = (_cmsStageMatrixData*) cmsStageData(Matrix1); - Data2 = (_cmsStageMatrixData*) cmsStageData(Matrix2); + IdentityMat = FALSE; + if (cmsPipelineCheckAndRetreiveStages(Src, 4, + cmsSigCurveSetElemType, cmsSigMatrixElemType, cmsSigMatrixElemType, cmsSigCurveSetElemType, + &Curve1, &Matrix1, &Matrix2, &Curve2)) { - // Input offset should be zero - if (Data1 ->Offset != NULL) return FALSE; + // Get both matrices + _cmsStageMatrixData* Data1 = (_cmsStageMatrixData*)cmsStageData(Matrix1); + _cmsStageMatrixData* Data2 = (_cmsStageMatrixData*)cmsStageData(Matrix2); - // Multiply both matrices to get the result - _cmsMAT3per(&res, (cmsMAT3*) Data2 ->Double, (cmsMAT3*) Data1 ->Double); + // Input offset should be zero + if (Data1->Offset != NULL) return FALSE; - // Now the result is in res + Data2 -> Offset. Maybe is a plain identity? - IdentityMat = FALSE; - if (_cmsMAT3isIdentity(&res) && Data2 ->Offset == NULL) { + // Multiply both matrices to get the result + _cmsMAT3per(&res, (cmsMAT3*)Data2->Double, (cmsMAT3*)Data1->Double); - // We can get rid of full matrix - IdentityMat = TRUE; - } + // Only 2nd matrix has offset, or it is zero + Offset = Data2->Offset; + + // Now the result is in res + Data2 -> Offset. Maybe is a plain identity? + if (_cmsMAT3isIdentity(&res) && Offset == NULL) { + + // We can get rid of full matrix + IdentityMat = TRUE; + } + + } + else { + + if (cmsPipelineCheckAndRetreiveStages(Src, 3, + cmsSigCurveSetElemType, cmsSigMatrixElemType, cmsSigCurveSetElemType, + &Curve1, &Matrix1, &Curve2)) { + + _cmsStageMatrixData* Data = (_cmsStageMatrixData*)cmsStageData(Matrix1); + + // Copy the matrix to our result + memcpy(&res, Data->Double, sizeof(res)); + + // Preserve the Odffset (may be NULL as a zero offset) + Offset = Data->Offset; + + if (_cmsMAT3isIdentity(&res) && Offset == NULL) { + + // We can get rid of full matrix + IdentityMat = TRUE; + } + } + else + return FALSE; // Not optimizeable this time + + } // Allocate an empty LUT Dest = cmsPipelineAlloc(Src ->ContextID, Src ->InputChannels, Src ->OutputChannels); @@ -1601,9 +1738,12 @@ cmsBool OptimizeMatrixShaper(cmsPipeline** Lut, cmsUInt32Number Intent, cmsUInt3 if (!cmsPipelineInsertStage(Dest, cmsAT_BEGIN, cmsStageDup(Curve1))) goto Error; - if (!IdentityMat) - if (!cmsPipelineInsertStage(Dest, cmsAT_END, cmsStageAllocMatrix(Dest ->ContextID, 3, 3, (const cmsFloat64Number*) &res, Data2 ->Offset))) - goto Error; + if (!IdentityMat) { + + if (!cmsPipelineInsertStage(Dest, cmsAT_END, cmsStageAllocMatrix(Dest->ContextID, 3, 3, (const cmsFloat64Number*)&res, Offset))) + goto Error; + } + if (!cmsPipelineInsertStage(Dest, cmsAT_END, cmsStageDup(Curve2))) goto Error; @@ -1616,12 +1756,12 @@ cmsBool OptimizeMatrixShaper(cmsPipeline** Lut, cmsUInt32Number Intent, cmsUInt3 _cmsStageToneCurvesData* mpeC1 = (_cmsStageToneCurvesData*) cmsStageData(Curve1); _cmsStageToneCurvesData* mpeC2 = (_cmsStageToneCurvesData*) cmsStageData(Curve2); - // In this particular optimization, cach?does not help as it takes more time to deal with - // the cach?that with the pixel handling + // In this particular optimization, cache does not help as it takes more time to deal with + // the cache that with the pixel handling *dwFlags |= cmsFLAGS_NOCACHE; // Setup the optimizarion routines - if (!SetMatShaper(Dest, mpeC1 ->TheCurves, &res, (cmsVEC3*) Data2 ->Offset, mpeC2->TheCurves, OutputFormat)) + if (!SetMatShaper(Dest, mpeC1 ->TheCurves, &res, (cmsVEC3*) Offset, mpeC2->TheCurves, OutputFormat)) goto Error; } @@ -1809,3 +1949,6 @@ cmsBool _cmsOptimizePipeline(cmsContext ContextID, // Only simple optimizations succeeded return AnySuccess; } + + + diff --git a/third_party/lcms/src/cmspack.c b/third_party/lcms/src/cmspack.c index 9323b53ec5..6ed41da870 100644 --- a/third_party/lcms/src/cmspack.c +++ b/third_party/lcms/src/cmspack.c @@ -1,7 +1,7 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2010 Marti Maria Saguer +// Copyright (c) 1998-2016 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"), @@ -23,6 +23,7 @@ // //--------------------------------------------------------------------------------- // + #include "lcms2_internal.h" // This module handles all formats supported by lcms. There are two flavors, 16 bits and @@ -80,7 +81,7 @@ typedef struct { #define ANYFLAVOR FLAVOR_SH(1) -// Supress waning about info never being used +// Suppress waning about info never being used #ifdef _MSC_VER #pragma warning(disable : 4100) @@ -2408,9 +2409,6 @@ cmsUInt8Number* PackDoubleFrom16(register _cmsTRANSFORM* info, ((cmsFloat64Number*) output)[i + start] = v; } - if (!ExtraFirst) { - output += Extra * sizeof(cmsFloat64Number); - } if (Extra == 0 && SwapFirst) { @@ -2421,7 +2419,7 @@ cmsUInt8Number* PackDoubleFrom16(register _cmsTRANSFORM* info, if (T_PLANAR(info -> OutputFormat)) return output + sizeof(cmsFloat64Number); else - return output + nChan * sizeof(cmsFloat64Number); + return output + (nChan + Extra) * sizeof(cmsFloat64Number); } @@ -2432,50 +2430,47 @@ cmsUInt8Number* PackFloatFrom16(register _cmsTRANSFORM* info, register cmsUInt8Number* output, register cmsUInt32Number Stride) { - int nChan = T_CHANNELS(info -> OutputFormat); - int DoSwap = T_DOSWAP(info ->OutputFormat); - int Reverse = T_FLAVOR(info ->OutputFormat); - int Extra = T_EXTRA(info -> OutputFormat); - int SwapFirst = T_SWAPFIRST(info -> OutputFormat); - int Planar = T_PLANAR(info -> OutputFormat); - int ExtraFirst = DoSwap ^ SwapFirst; - cmsFloat64Number maximum = IsInkSpace(info ->OutputFormat) ? 655.35 : 65535.0; - cmsFloat64Number v = 0; - cmsFloat32Number* swap1 = (cmsFloat32Number*) output; - int i, start = 0; + int nChan = T_CHANNELS(info->OutputFormat); + int DoSwap = T_DOSWAP(info->OutputFormat); + int Reverse = T_FLAVOR(info->OutputFormat); + int Extra = T_EXTRA(info->OutputFormat); + int SwapFirst = T_SWAPFIRST(info->OutputFormat); + int Planar = T_PLANAR(info->OutputFormat); + int ExtraFirst = DoSwap ^ SwapFirst; + cmsFloat64Number maximum = IsInkSpace(info->OutputFormat) ? 655.35 : 65535.0; + cmsFloat64Number v = 0; + cmsFloat32Number* swap1 = (cmsFloat32Number*)output; + int i, start = 0; - if (ExtraFirst) - start = Extra; + if (ExtraFirst) + start = Extra; - for (i=0; i < nChan; i++) { + for (i = 0; i < nChan; i++) { - int index = DoSwap ? (nChan - i - 1) : i; + int index = DoSwap ? (nChan - i - 1) : i; - v = (cmsFloat64Number) wOut[index] / maximum; - - if (Reverse) - v = maximum - v; + v = (cmsFloat64Number)wOut[index] / maximum; - if (Planar) - ((cmsFloat32Number*) output)[(i + start ) * Stride]= (cmsFloat32Number) v; - else - ((cmsFloat32Number*) output)[i + start] = (cmsFloat32Number) v; - } + if (Reverse) + v = maximum - v; - if (!ExtraFirst) { - output += Extra * sizeof(cmsFloat32Number); - } + if (Planar) + ((cmsFloat32Number*)output)[(i + start) * Stride] = (cmsFloat32Number)v; + else + ((cmsFloat32Number*)output)[i + start] = (cmsFloat32Number)v; + } - if (Extra == 0 && SwapFirst) { + + if (Extra == 0 && SwapFirst) { - memmove(swap1 + 1, swap1, (nChan-1)* sizeof(cmsFloat32Number)); - *swap1 = (cmsFloat32Number) v; - } + memmove(swap1 + 1, swap1, (nChan - 1)* sizeof(cmsFloat32Number)); + *swap1 = (cmsFloat32Number)v; + } - if (T_PLANAR(info -> OutputFormat)) - return output + sizeof(cmsFloat32Number); - else - return output + nChan * sizeof(cmsFloat32Number); + if (T_PLANAR(info->OutputFormat)) + return output + sizeof(cmsFloat32Number); + else + return output + (nChan + Extra) * sizeof(cmsFloat32Number); } @@ -2488,50 +2483,47 @@ cmsUInt8Number* PackFloatsFromFloat(_cmsTRANSFORM* info, cmsUInt8Number* output, cmsUInt32Number Stride) { - int nChan = T_CHANNELS(info -> OutputFormat); - int DoSwap = T_DOSWAP(info ->OutputFormat); - int Reverse = T_FLAVOR(info ->OutputFormat); - int Extra = T_EXTRA(info -> OutputFormat); - int SwapFirst = T_SWAPFIRST(info -> OutputFormat); - int Planar = T_PLANAR(info -> OutputFormat); - int ExtraFirst = DoSwap ^ SwapFirst; - cmsFloat64Number maximum = IsInkSpace(info ->OutputFormat) ? 100.0 : 1.0; - cmsFloat32Number* swap1 = (cmsFloat32Number*) output; - cmsFloat64Number v = 0; - int i, start = 0; + int nChan = T_CHANNELS(info->OutputFormat); + int DoSwap = T_DOSWAP(info->OutputFormat); + int Reverse = T_FLAVOR(info->OutputFormat); + int Extra = T_EXTRA(info->OutputFormat); + int SwapFirst = T_SWAPFIRST(info->OutputFormat); + int Planar = T_PLANAR(info->OutputFormat); + int ExtraFirst = DoSwap ^ SwapFirst; + cmsFloat64Number maximum = IsInkSpace(info->OutputFormat) ? 100.0 : 1.0; + cmsFloat32Number* swap1 = (cmsFloat32Number*)output; + cmsFloat64Number v = 0; + int i, start = 0; - if (ExtraFirst) - start = Extra; + if (ExtraFirst) + start = Extra; - for (i=0; i < nChan; i++) { + for (i = 0; i < nChan; i++) { - int index = DoSwap ? (nChan - i - 1) : i; + int index = DoSwap ? (nChan - i - 1) : i; - v = wOut[index] * maximum; + v = wOut[index] * maximum; - if (Reverse) - v = maximum - v; + if (Reverse) + v = maximum - v; - if (Planar) - ((cmsFloat32Number*) output)[(i + start)* Stride]= (cmsFloat32Number) v; - else - ((cmsFloat32Number*) output)[i + start] = (cmsFloat32Number) v; - } + if (Planar) + ((cmsFloat32Number*)output)[(i + start)* Stride] = (cmsFloat32Number)v; + else + ((cmsFloat32Number*)output)[i + start] = (cmsFloat32Number)v; + } - if (!ExtraFirst) { - output += Extra * sizeof(cmsFloat32Number); - } - if (Extra == 0 && SwapFirst) { + if (Extra == 0 && SwapFirst) { - memmove(swap1 + 1, swap1, (nChan-1)* sizeof(cmsFloat32Number)); - *swap1 = (cmsFloat32Number) v; - } + memmove(swap1 + 1, swap1, (nChan - 1)* sizeof(cmsFloat32Number)); + *swap1 = (cmsFloat32Number)v; + } - if (T_PLANAR(info -> OutputFormat)) - return output + sizeof(cmsFloat32Number); - else - return output + nChan * sizeof(cmsFloat32Number); + if (T_PLANAR(info->OutputFormat)) + return output + sizeof(cmsFloat32Number); + else + return output + (nChan + Extra) * sizeof(cmsFloat32Number); } static @@ -2540,51 +2532,47 @@ cmsUInt8Number* PackDoublesFromFloat(_cmsTRANSFORM* info, cmsUInt8Number* output, cmsUInt32Number Stride) { - int nChan = T_CHANNELS(info -> OutputFormat); - int DoSwap = T_DOSWAP(info ->OutputFormat); - int Reverse = T_FLAVOR(info ->OutputFormat); - int Extra = T_EXTRA(info -> OutputFormat); - int SwapFirst = T_SWAPFIRST(info -> OutputFormat); - int Planar = T_PLANAR(info -> OutputFormat); - int ExtraFirst = DoSwap ^ SwapFirst; - cmsFloat64Number maximum = IsInkSpace(info ->OutputFormat) ? 100.0 : 1.0; - cmsFloat64Number v = 0; - cmsFloat64Number* swap1 = (cmsFloat64Number*) output; - int i, start = 0; + int nChan = T_CHANNELS(info->OutputFormat); + int DoSwap = T_DOSWAP(info->OutputFormat); + int Reverse = T_FLAVOR(info->OutputFormat); + int Extra = T_EXTRA(info->OutputFormat); + int SwapFirst = T_SWAPFIRST(info->OutputFormat); + int Planar = T_PLANAR(info->OutputFormat); + int ExtraFirst = DoSwap ^ SwapFirst; + cmsFloat64Number maximum = IsInkSpace(info->OutputFormat) ? 100.0 : 1.0; + cmsFloat64Number v = 0; + cmsFloat64Number* swap1 = (cmsFloat64Number*)output; + int i, start = 0; - if (ExtraFirst) - start = Extra; + if (ExtraFirst) + start = Extra; - for (i=0; i < nChan; i++) { + for (i = 0; i < nChan; i++) { - int index = DoSwap ? (nChan - i - 1) : i; + int index = DoSwap ? (nChan - i - 1) : i; - v = wOut[index] * maximum; + v = wOut[index] * maximum; - if (Reverse) - v = maximum - v; + if (Reverse) + v = maximum - v; - if (Planar) - ((cmsFloat64Number*) output)[(i + start) * Stride] = v; - else - ((cmsFloat64Number*) output)[i + start] = v; - } + if (Planar) + ((cmsFloat64Number*)output)[(i + start) * Stride] = v; + else + ((cmsFloat64Number*)output)[i + start] = v; + } - if (!ExtraFirst) { - output += Extra * sizeof(cmsFloat64Number); - } + if (Extra == 0 && SwapFirst) { - if (Extra == 0 && SwapFirst) { + memmove(swap1 + 1, swap1, (nChan - 1)* sizeof(cmsFloat64Number)); + *swap1 = v; + } - memmove(swap1 + 1, swap1, (nChan-1)* sizeof(cmsFloat64Number)); - *swap1 = v; - } - - if (T_PLANAR(info -> OutputFormat)) - return output + sizeof(cmsFloat64Number); - else - return output + nChan * sizeof(cmsFloat64Number); + if (T_PLANAR(info->OutputFormat)) + return output + sizeof(cmsFloat64Number); + else + return output + (nChan + Extra) * sizeof(cmsFloat64Number); } @@ -2820,50 +2808,47 @@ cmsUInt8Number* PackHalfFrom16(register _cmsTRANSFORM* info, register cmsUInt8Number* output, register cmsUInt32Number Stride) { - int nChan = T_CHANNELS(info -> OutputFormat); - int DoSwap = T_DOSWAP(info ->OutputFormat); - int Reverse = T_FLAVOR(info ->OutputFormat); - int Extra = T_EXTRA(info -> OutputFormat); - int SwapFirst = T_SWAPFIRST(info -> OutputFormat); - int Planar = T_PLANAR(info -> OutputFormat); - int ExtraFirst = DoSwap ^ SwapFirst; - cmsFloat32Number maximum = IsInkSpace(info ->OutputFormat) ? 655.35F : 65535.0F; - cmsFloat32Number v = 0; - cmsUInt16Number* swap1 = (cmsUInt16Number*) output; - int i, start = 0; + int nChan = T_CHANNELS(info->OutputFormat); + int DoSwap = T_DOSWAP(info->OutputFormat); + int Reverse = T_FLAVOR(info->OutputFormat); + int Extra = T_EXTRA(info->OutputFormat); + int SwapFirst = T_SWAPFIRST(info->OutputFormat); + int Planar = T_PLANAR(info->OutputFormat); + int ExtraFirst = DoSwap ^ SwapFirst; + cmsFloat32Number maximum = IsInkSpace(info->OutputFormat) ? 655.35F : 65535.0F; + cmsFloat32Number v = 0; + cmsUInt16Number* swap1 = (cmsUInt16Number*)output; + int i, start = 0; - if (ExtraFirst) - start = Extra; + if (ExtraFirst) + start = Extra; - for (i=0; i < nChan; i++) { + for (i = 0; i < nChan; i++) { - int index = DoSwap ? (nChan - i - 1) : i; + int index = DoSwap ? (nChan - i - 1) : i; - v = (cmsFloat32Number) wOut[index] / maximum; + v = (cmsFloat32Number)wOut[index] / maximum; - if (Reverse) - v = maximum - v; + if (Reverse) + v = maximum - v; - if (Planar) - ((cmsUInt16Number*) output)[(i + start ) * Stride]= _cmsFloat2Half(v); - else - ((cmsUInt16Number*) output)[i + start] = _cmsFloat2Half(v); - } + if (Planar) + ((cmsUInt16Number*)output)[(i + start) * Stride] = _cmsFloat2Half(v); + else + ((cmsUInt16Number*)output)[i + start] = _cmsFloat2Half(v); + } - if (!ExtraFirst) { - output += Extra * sizeof(cmsUInt16Number); - } - if (Extra == 0 && SwapFirst) { + if (Extra == 0 && SwapFirst) { - memmove(swap1 + 1, swap1, (nChan-1)* sizeof(cmsUInt16Number)); - *swap1 = _cmsFloat2Half(v); - } + memmove(swap1 + 1, swap1, (nChan - 1)* sizeof(cmsUInt16Number)); + *swap1 = _cmsFloat2Half(v); + } - if (T_PLANAR(info -> OutputFormat)) - return output + sizeof(cmsUInt16Number); - else - return output + nChan * sizeof(cmsUInt16Number); + if (T_PLANAR(info->OutputFormat)) + return output + sizeof(cmsUInt16Number); + else + return output + (nChan + Extra) * sizeof(cmsUInt16Number); } @@ -2874,50 +2859,47 @@ cmsUInt8Number* PackHalfFromFloat(_cmsTRANSFORM* info, cmsUInt8Number* output, cmsUInt32Number Stride) { - int nChan = T_CHANNELS(info -> OutputFormat); - int DoSwap = T_DOSWAP(info ->OutputFormat); - int Reverse = T_FLAVOR(info ->OutputFormat); - int Extra = T_EXTRA(info -> OutputFormat); - int SwapFirst = T_SWAPFIRST(info -> OutputFormat); - int Planar = T_PLANAR(info -> OutputFormat); - int ExtraFirst = DoSwap ^ SwapFirst; - cmsFloat32Number maximum = IsInkSpace(info ->OutputFormat) ? 100.0F : 1.0F; - cmsUInt16Number* swap1 = (cmsUInt16Number*) output; - cmsFloat32Number v = 0; - int i, start = 0; + int nChan = T_CHANNELS(info->OutputFormat); + int DoSwap = T_DOSWAP(info->OutputFormat); + int Reverse = T_FLAVOR(info->OutputFormat); + int Extra = T_EXTRA(info->OutputFormat); + int SwapFirst = T_SWAPFIRST(info->OutputFormat); + int Planar = T_PLANAR(info->OutputFormat); + int ExtraFirst = DoSwap ^ SwapFirst; + cmsFloat32Number maximum = IsInkSpace(info->OutputFormat) ? 100.0F : 1.0F; + cmsUInt16Number* swap1 = (cmsUInt16Number*)output; + cmsFloat32Number v = 0; + int i, start = 0; - if (ExtraFirst) - start = Extra; + if (ExtraFirst) + start = Extra; - for (i=0; i < nChan; i++) { + for (i = 0; i < nChan; i++) { - int index = DoSwap ? (nChan - i - 1) : i; + int index = DoSwap ? (nChan - i - 1) : i; - v = wOut[index] * maximum; + v = wOut[index] * maximum; - if (Reverse) - v = maximum - v; + if (Reverse) + v = maximum - v; - if (Planar) - ((cmsUInt16Number*) output)[(i + start)* Stride]= _cmsFloat2Half( v ); - else - ((cmsUInt16Number*) output)[i + start] = _cmsFloat2Half( v ); - } + if (Planar) + ((cmsUInt16Number*)output)[(i + start)* Stride] = _cmsFloat2Half(v); + else + ((cmsUInt16Number*)output)[i + start] = _cmsFloat2Half(v); + } - if (!ExtraFirst) { - output += Extra * sizeof(cmsUInt16Number); - } - if (Extra == 0 && SwapFirst) { + if (Extra == 0 && SwapFirst) { - memmove(swap1 + 1, swap1, (nChan-1)* sizeof(cmsUInt16Number)); - *swap1 = (cmsUInt16Number) _cmsFloat2Half( v ); - } + memmove(swap1 + 1, swap1, (nChan - 1)* sizeof(cmsUInt16Number)); + *swap1 = (cmsUInt16Number)_cmsFloat2Half(v); + } - if (T_PLANAR(info -> OutputFormat)) - return output + sizeof(cmsUInt16Number); - else - return output + nChan * sizeof(cmsUInt16Number); + if (T_PLANAR(info->OutputFormat)) + return output + sizeof(cmsUInt16Number); + else + return output + (nChan + Extra)* sizeof(cmsUInt16Number); } #endif @@ -3177,6 +3159,8 @@ cmsFormatter _cmsGetStockOutputFormatter(cmsUInt32Number dwInput, cmsUInt32Numbe cmsUInt32Number i; cmsFormatter fr; + // Optimization is only a hint + dwInput &= ~OPTIMIZED_SH(1); switch (dwFlags) { @@ -3367,3 +3351,4 @@ cmsUInt32Number CMSEXPORT cmsFormatterForPCSOfProfile(cmsHPROFILE hProfile, cmsU // Create a fake formatter for result return FLOAT_SH(Float) | COLORSPACE_SH(ColorSpaceBits) | BYTES_SH(nBytes) | CHANNELS_SH(nOutputChans); } + diff --git a/third_party/lcms/src/cmspcs.c b/third_party/lcms/src/cmspcs.c index 102cd7d21e..0cd8ecbf69 100644 --- a/third_party/lcms/src/cmspcs.c +++ b/third_party/lcms/src/cmspcs.c @@ -1,7 +1,7 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2010 Marti Maria Saguer +// Copyright (c) 1998-2016 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"), @@ -106,6 +106,15 @@ void CMSEXPORT cmsxyY2XYZ(cmsCIEXYZ* Dest, const cmsCIExyY* Source) Dest -> Z = ((1 - Source -> x - Source -> y) / Source -> y) * Source -> Y; } +/* + The break point (24/116)^3 = (6/29)^3 is a very small amount of tristimulus + primary (0.008856). Generally, this only happens for + nearly ideal blacks and for some orange / amber colors in transmission mode. + For example, the Z value of the orange turn indicator lamp lens on an + automobile will often be below this value. But the Z does not + contribute to the perceived color directly. +*/ + static cmsFloat64Number f(cmsFloat64Number t) { @@ -299,7 +308,7 @@ void CMSEXPORT cmsFloat2LabEncoded(cmsUInt16Number wLab[3], const cmsCIELab* fLa wLab[2] = ab2Fix4(Lab.b); } -// Auxiliar: convert to Radians +// Auxiliary: convert to Radians static cmsFloat64Number RADIANS(cmsFloat64Number deg) { @@ -307,7 +316,7 @@ cmsFloat64Number RADIANS(cmsFloat64Number deg) } -// Auxiliar: atan2 but operating in degrees and returning 0 if a==b==0 +// Auxiliary: atan2 but operating in degrees and returning 0 if a==b==0 static cmsFloat64Number atan2deg(cmsFloat64Number a, cmsFloat64Number b) { @@ -330,7 +339,7 @@ cmsFloat64Number atan2deg(cmsFloat64Number a, cmsFloat64Number b) } -// Auxiliar: Square +// Auxiliary: Square static cmsFloat64Number Sqr(cmsFloat64Number v) { diff --git a/third_party/lcms/src/cmsplugin.c b/third_party/lcms/src/cmsplugin.c index 42c4002b55..80dd8d48c1 100644 --- a/third_party/lcms/src/cmsplugin.c +++ b/third_party/lcms/src/cmsplugin.c @@ -1,7 +1,7 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2010 Marti Maria Saguer +// Copyright (c) 1998-2016 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"), @@ -107,7 +107,7 @@ void CMSEXPORT _cmsAdjustEndianess64(cmsUInt64Number* Result, cmsUInt64Number* #endif } -// Auxiliar -- read 8, 16 and 32-bit numbers +// Auxiliary -- read 8, 16 and 32-bit numbers cmsBool CMSEXPORT _cmsReadUInt8Number(cmsIOHANDLER* io, cmsUInt8Number* n) { cmsUInt8Number tmp; @@ -172,13 +172,13 @@ cmsBool CMSEXPORT _cmsReadFloat32Number(cmsIOHANDLER* io, cmsFloat32Number* n) _cmsAssert(io != NULL); - if (io -> Read(io, &tmp, sizeof(cmsFloat32Number), 1) != 1) + if (io -> Read(io, &tmp, sizeof(cmsUInt32Number), 1) != 1) return FALSE; if (n != NULL) { tmp = _cmsAdjustEndianess32(tmp); - *n = *(cmsFloat32Number*) &tmp; + *n = *(cmsFloat32Number*) (void*) &tmp; if (isnan(*n)) return FALSE; } @@ -219,22 +219,6 @@ cmsBool CMSEXPORT _cmsRead15Fixed16Number(cmsIOHANDLER* io, cmsFloat64Number* n } -// Jun-21-2000: Some profiles (those that comes with W2K) comes -// with the media white (media black?) x 100. Add a sanity check - -static -void NormalizeXYZ(cmsCIEXYZ* Dest) -{ - while (Dest -> X > 2. && - Dest -> Y > 2. && - Dest -> Z > 2.) { - - Dest -> X /= 10.; - Dest -> Y /= 10.; - Dest -> Z /= 10.; - } -} - cmsBool CMSEXPORT _cmsReadXYZNumber(cmsIOHANDLER* io, cmsCIEXYZ* XYZ) { cmsEncodedXYZNumber xyz; @@ -248,8 +232,6 @@ cmsBool CMSEXPORT _cmsReadXYZNumber(cmsIOHANDLER* io, cmsCIEXYZ* XYZ) XYZ->X = _cms15Fixed16toDouble(_cmsAdjustEndianess32(xyz.X)); XYZ->Y = _cms15Fixed16toDouble(_cmsAdjustEndianess32(xyz.Y)); XYZ->Z = _cms15Fixed16toDouble(_cmsAdjustEndianess32(xyz.Z)); - - NormalizeXYZ(XYZ); } return TRUE; } @@ -311,7 +293,7 @@ cmsBool CMSEXPORT _cmsWriteFloat32Number(cmsIOHANDLER* io, cmsFloat32Number n) _cmsAssert(io != NULL); - tmp = *(cmsUInt32Number*) &n; + tmp = *(cmsUInt32Number*) (void*) &n; tmp = _cmsAdjustEndianess32(tmp); if (io -> Write(io, sizeof(cmsUInt32Number), &tmp) != 1) return FALSE; @@ -507,7 +489,10 @@ cmsBool CMSEXPORT _cmsIOPrintf(cmsIOHANDLER* io, const char* frm, ...) va_start(args, frm); len = vsnprintf((char*) Buffer, 2047, frm, args); - if (len < 0) return FALSE; // Truncated, which is a fatal error for us + if (len < 0) { + va_end(args); + return FALSE; // Truncated, which is a fatal error for us + } rc = io ->Write(io, len, Buffer); @@ -529,6 +514,7 @@ void* _cmsPluginMalloc(cmsContext ContextID, cmsUInt32Number size) if (ContextID == NULL) { ctx->MemPool = _cmsCreateSubAlloc(0, 2*1024); + if (ctx->MemPool == NULL) return NULL; } else { cmsSignalError(ContextID, cmsERROR_CORRUPTION_DETECTED, "NULL memory pool on context"); @@ -687,15 +673,21 @@ struct _cmsContext_struct* _cmsGetContext(cmsContext ContextID) // Internal: get the memory area associanted with each context client -// Returns the block assigned to the specific zone. +// Returns the block assigned to the specific zone. Never return NULL. void* _cmsContextGetClientChunk(cmsContext ContextID, _cmsMemoryClient mc) { struct _cmsContext_struct* ctx; void *ptr; - if (mc >= MemoryClientMax) { - cmsSignalError(ContextID, cmsERROR_RANGE, "Bad context client"); - return NULL; + if ((int) mc < 0 || mc >= MemoryClientMax) { + + cmsSignalError(ContextID, cmsERROR_INTERNAL, "Bad context client -- possible corruption"); + + // This is catastrophic. Should never reach here + _cmsAssert(0); + + // Reverts to global context + return globalContext.chunks[UserPtr]; } ctx = _cmsGetContext(ContextID); @@ -884,7 +876,7 @@ cmsContext CMSEXPORT cmsDupContext(cmsContext ContextID, void* NewUserData) } - +/* static struct _cmsContext_struct* FindPrev(struct _cmsContext_struct* id) { @@ -901,6 +893,7 @@ struct _cmsContext_struct* FindPrev(struct _cmsContext_struct* id) return NULL; // List is empty or only one element! } +*/ // Frees any resources associated with the given context, // and destroys the context placeholder. @@ -936,8 +929,8 @@ void CMSEXPORT cmsDeleteContext(cmsContext ContextID) // Search for previous for (prev = _cmsContextPoolHead; - prev != NULL; - prev = prev ->Next) + prev != NULL; + prev = prev ->Next) { if (prev -> Next == ctx) { prev -> Next = ctx ->Next; @@ -957,3 +950,5 @@ void* CMSEXPORT cmsGetContextUserData(cmsContext ContextID) { return _cmsContextGetClientChunk(ContextID, UserPtr); } + + diff --git a/third_party/lcms/src/cmsps2.c b/third_party/lcms/src/cmsps2.c index 224b44b542..9635eaf8c0 100644 --- a/third_party/lcms/src/cmsps2.c +++ b/third_party/lcms/src/cmsps2.c @@ -1,7 +1,7 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2011 Marti Maria Saguer +// Copyright (c) 1998-2016 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"), @@ -579,7 +579,7 @@ void EmitNGamma(cmsIOHANDLER* m, int n, cmsToneCurve* g[]) // // Each row contains Pipeline values for all but first component. So, I // detect row changing by keeping a copy of last value of first -// component. -1 is used to mark begining of whole block. +// component. -1 is used to mark beginning of whole block. static int OutputValueSampler(register const cmsUInt16Number In[], register cmsUInt16Number Out[], register void* Cargo) @@ -1393,14 +1393,15 @@ void BuildColorantList(char *Colorant, int nColorant, cmsUInt16Number Out[]) if (nColorant > cmsMAXCHANNELS) nColorant = cmsMAXCHANNELS; - for (j=0; j < nColorant; j++) { + for (j = 0; j < nColorant; j++) { - sprintf(Buff, "%.3f", Out[j] / 65535.0); - strcat(Colorant, Buff); - if (j < nColorant -1) - strcat(Colorant, " "); + snprintf(Buff, 31, "%.3f", Out[j] / 65535.0); + Buff[31] = 0; + strcat(Colorant, Buff); + if (j < nColorant - 1) + strcat(Colorant, " "); - } + } } diff --git a/third_party/lcms/src/cmssamp.c b/third_party/lcms/src/cmssamp.c index 70e469161f..a9997fa8ee 100644 --- a/third_party/lcms/src/cmssamp.c +++ b/third_party/lcms/src/cmssamp.c @@ -1,7 +1,7 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2010 Marti Maria Saguer +// Copyright (c) 1998-2016 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"), @@ -340,28 +340,7 @@ cmsFloat64Number RootOfLeastSquaresFitQuadraticCurve(int n, cmsFloat64Number x[] } -/* -static -cmsBool IsMonotonic(int n, const cmsFloat64Number Table[]) -{ - int i; - cmsFloat64Number last; - - last = Table[n-1]; - - for (i = n-2; i >= 0; --i) { - - if (Table[i] > last) - - return FALSE; - else - last = Table[i]; - } - - return TRUE; -} -*/ // Calculates the black point of a destination profile. // This algorithm comes from the Adobe paper disclosing its black point compensation method. @@ -486,7 +465,6 @@ cmsBool CMSEXPORT cmsDetectDestinationBlackPoint(cmsCIEXYZ* BlackPoint, cmsHPROF // Test for mid range straight (only on relative colorimetric) - NearlyStraightMidrange = TRUE; MinL = outRamp[0]; MaxL = outRamp[255]; if (Intent == INTENT_RELATIVE_COLORIMETRIC) { @@ -502,7 +480,6 @@ cmsBool CMSEXPORT cmsDetectDestinationBlackPoint(cmsCIEXYZ* BlackPoint, cmsHPROF // DestinationBlackPoint shall be the same as initialLab. // Otherwise, the DestinationBlackPoint shall be determined // using curve fitting. - if (NearlyStraightMidrange) { cmsLab2XYZ(NULL, BlackPoint, &InitialLab); @@ -513,15 +490,13 @@ cmsBool CMSEXPORT cmsDetectDestinationBlackPoint(cmsCIEXYZ* BlackPoint, cmsHPROF // curve fitting: The round-trip curve normally looks like a nearly constant section at the black point, - // with a corner and a nearly straight line to the white point. - + // with a corner and a nearly straight line to the white point. for (l=0; l < 256; l++) { yRamp[l] = (outRamp[l] - MinL) / (MaxL - MinL); } // find the black point using the least squares error quadratic curve fitting - if (Intent == INTENT_RELATIVE_COLORIMETRIC) { lo = 0.1; hi = 0.5; diff --git a/third_party/lcms/src/cmssm.c b/third_party/lcms/src/cmssm.c index 5836e15506..0f7cb7f637 100644 --- a/third_party/lcms/src/cmssm.c +++ b/third_party/lcms/src/cmssm.c @@ -1,7 +1,7 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2011 Marti Maria Saguer +// Copyright (c) 1998-2016 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"), @@ -218,7 +218,8 @@ cmsBool ClosestLineToLine(cmsVEC3* r, const cmsLine* line1, const cmsLine* line2 { cmsFloat64Number a, b, c, d, e, D; cmsFloat64Number sc, sN, sD; - cmsFloat64Number tc, tN, tD; + //cmsFloat64Number tc; // left for future use + cmsFloat64Number tN, tD; cmsVEC3 w0; _cmsVEC3minus(&w0, &line1 ->a, &line2 ->a); @@ -286,7 +287,7 @@ cmsBool ClosestLineToLine(cmsVEC3* r, const cmsLine* line1, const cmsLine* line2 } // finally do the division to get sc and tc sc = (fabs(sN) < MATRIX_DET_TOLERANCE ? 0.0 : sN / sD); - tc = (fabs(tN) < MATRIX_DET_TOLERANCE ? 0.0 : tN / tD); + //tc = (fabs(tN) < MATRIX_DET_TOLERANCE ? 0.0 : tN / tD); // left for future use. GetPointOfLine(r, line1, sc); return TRUE; @@ -317,7 +318,7 @@ void CMSEXPORT cmsGBDFree(cmsHANDLE hGBD) } -// Auxiliar to retrieve a pointer to the segmentr containing the Lab value +// Auxiliary to retrieve a pointer to the segmentr containing the Lab value static cmsGDBPoint* GetPoint(cmsGDB* gbd, const cmsCIELab* Lab, cmsSpherical* sp) { @@ -329,7 +330,7 @@ cmsGDBPoint* GetPoint(cmsGDB* gbd, const cmsCIELab* Lab, cmsSpherical* sp) _cmsAssert(Lab != NULL); _cmsAssert(sp != NULL); - // Center L* by substracting half of its domain, that's 50 + // Center L* by subtracting half of its domain, that's 50 _cmsVEC3init(&v, Lab ->L - 50.0, Lab ->a, Lab ->b); // Convert to spherical coordinates @@ -732,3 +733,4 @@ cmsBool cmsGBDdumpVRML(cmsHANDLE hGBD, const char* fname) return TRUE; } #endif + diff --git a/third_party/lcms/src/cmstypes.c b/third_party/lcms/src/cmstypes.c index 29806fb194..8b02f86ca5 100644 --- a/third_party/lcms/src/cmstypes.c +++ b/third_party/lcms/src/cmstypes.c @@ -1,7 +1,7 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2014 Marti Maria Saguer +// Copyright (c) 1998-2016 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"), @@ -30,7 +30,7 @@ // This file implements every single tag and tag type as described in the ICC spec. Some types // have been deprecated, like ncl and Data. There is no implementation for those types as there // are no profiles holding them. The programmer can also extend this list by defining his own types -// by using the appropiate plug-in. There are three types of plug ins regarding that. First type +// by using the appropriate plug-in. There are three types of plug ins regarding that. First type // allows to define new tags using any existing type. Next plug-in type allows to define new types // and the third one is very specific: allows to extend the number of elements in the multiprocessing // elements special type. @@ -113,7 +113,7 @@ cmsTagTypeHandler* GetHandler(cmsTagTypeSignature sig, _cmsTagTypeLinkedList* Pl } -// Auxiliar to convert UTF-32 to UTF-16 in some cases +// Auxiliary to convert UTF-32 to UTF-16 in some cases static cmsBool _cmsWriteWCharArray(cmsIOHANDLER* io, cmsUInt32Number n, const wchar_t* Array) { @@ -129,7 +129,7 @@ cmsBool _cmsWriteWCharArray(cmsIOHANDLER* io, cmsUInt32Number n, const wchar_t* return TRUE; } -// Auxiliar to read an array of wchar_t +// Auxiliary to read an array of wchar_t static cmsBool _cmsReadWCharArray(cmsIOHANDLER* io, cmsUInt32Number n, wchar_t* Array) { @@ -160,7 +160,7 @@ typedef cmsBool (* PositionTableEntryFn)(struct _cms_typehandler_struct* self, cmsUInt32Number n, cmsUInt32Number SizeOfTag); -// Helper function to deal with position tables as decribed in ICC spec 4.3 +// Helper function to deal with position tables as described in ICC spec 4.3 // A table of n elements is readed, where first comes n records containing offsets and sizes and // then a block containing the data itself. This allows to reuse same data in more than one entry static @@ -957,7 +957,7 @@ cmsBool Type_Text_Description_Write(struct _cms_typehandler_struct* self, cmsIO cmsMLU* mlu = (cmsMLU*) Ptr; char *Text = NULL; wchar_t *Wide = NULL; - cmsUInt32Number len, len_aligned, len_filler_alignment; + cmsUInt32Number len, len_text, len_tag_requirement, len_aligned; cmsBool rc = FALSE; char Filler[68]; @@ -967,17 +967,18 @@ cmsBool Type_Text_Description_Write(struct _cms_typehandler_struct* self, cmsIO // Get the len of string len = cmsMLUgetASCII(mlu, cmsNoLanguage, cmsNoCountry, NULL, 0); - // From ICC3.4: It has been found that textDescriptionType can contain misaligned data + // Specification ICC.1:2001-04 (v2.4.0): It has been found that textDescriptionType can contain misaligned data //(see clause 4.1 for the definition of 'aligned'. Because the Unicode language // code and Unicode count immediately follow the ASCII description, their // alignment is not correct if the ASCII count is not a multiple of four. The // ScriptCode code is misaligned when the ASCII count is odd. Profile reading and // writing software must be written carefully in order to handle these alignment // problems. - - // Compute an aligned size - len_aligned = _cmsALIGNLONG(len); - len_filler_alignment = len_aligned - len; + // + // The above last sentence suggest to handle alignment issues in the + // parser. The provided example (Table 69 on Page 60) makes this clear. + // The padding only in the ASCII count is not sufficient for a aligned tag + // size, with the same text size in ASCII and Unicode. // Null strings if (len <= 0) { @@ -998,6 +999,12 @@ cmsBool Type_Text_Description_Write(struct _cms_typehandler_struct* self, cmsIO cmsMLUgetWide(mlu, cmsNoLanguage, cmsNoCountry, Wide, len * sizeof(wchar_t)); } + // Tell the real text len including the null terminator and padding + len_text = (cmsUInt32Number) strlen(Text) + 1; + // Compute an total tag size requirement + len_tag_requirement = (8+4+len_text+4+4+2*len_text+2+1+67); + len_aligned = _cmsALIGNLONG(len_tag_requirement); + // * cmsUInt32Number count; * Description length // * cmsInt8Number desc[count] * NULL terminated ascii string // * cmsUInt32Number ucLangCode; * UniCode language code @@ -1007,20 +1014,14 @@ cmsBool Type_Text_Description_Write(struct _cms_typehandler_struct* self, cmsIO // * cmsUInt8Number scCount; * ScriptCode count // * cmsInt8Number scDesc[67]; * ScriptCode Description - if (!_cmsWriteUInt32Number(io, len_aligned)) goto Error; - if (!io ->Write(io, len, Text)) goto Error; - if (!io ->Write(io, len_filler_alignment, Filler)) goto Error; + if (!_cmsWriteUInt32Number(io, len_text)) goto Error; + if (!io ->Write(io, len_text, Text)) goto Error; if (!_cmsWriteUInt32Number(io, 0)) goto Error; // ucLanguageCode - // This part is tricky: we need an aligned tag size, and the ScriptCode part - // takes 70 bytes, so we need 2 extra bytes to do the alignment - - if (!_cmsWriteUInt32Number(io, len_aligned+1)) goto Error; - + if (!_cmsWriteUInt32Number(io, len_text)) goto Error; // Note that in some compilers sizeof(cmsUInt16Number) != sizeof(wchar_t) - if (!_cmsWriteWCharArray(io, len, Wide)) goto Error; - if (!_cmsWriteUInt16Array(io, len_filler_alignment+1, (cmsUInt16Number*) Filler)) goto Error; + if (!_cmsWriteWCharArray(io, len_text, Wide)) goto Error; // ScriptCode Code & count (unused) if (!_cmsWriteUInt16Number(io, 0)) goto Error; @@ -1028,6 +1029,10 @@ cmsBool Type_Text_Description_Write(struct _cms_typehandler_struct* self, cmsIO if (!io ->Write(io, 67, Filler)) goto Error; + // possibly add pad at the end of tag + if(len_aligned - len_tag_requirement > 0) + if (!io ->Write(io, len_aligned - len_tag_requirement, Filler)) goto Error; + rc = TRUE; Error: @@ -1478,7 +1483,7 @@ void *Type_MLU_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsU LargestPosition = EndOfThisString; } - // Now read the remaining of tag and fill all strings. Substract the directory + // Now read the remaining of tag and fill all strings. Subtract the directory SizeOfTag = (LargestPosition * sizeof(wchar_t)) / sizeof(cmsUInt16Number); if (SizeOfTag == 0) { @@ -1512,7 +1517,7 @@ cmsBool Type_MLU_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsMLU* mlu =(cmsMLU*) Ptr; cmsUInt32Number HeaderSize; cmsUInt32Number Len, Offset; - int i; + cmsUInt32Number i; if (Ptr == NULL) { @@ -1698,10 +1703,7 @@ cmsBool Write8bitTables(cmsContext ContextID, cmsIOHANDLER* io, cmsUInt32Number else for (j=0; j < 256; j++) { - if (Tables != NULL) - val = (cmsUInt8Number) FROM_16_TO_8(Tables->TheCurves[i]->Table16[j]); - else - val = (cmsUInt8Number) j; + val = (cmsUInt8Number) FROM_16_TO_8(Tables->TheCurves[i]->Table16[j]); if (!_cmsWriteUInt8Number(io, val)) return FALSE; } @@ -3125,7 +3127,8 @@ void *Type_NamedColor_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* i memset(Colorant, 0, sizeof(Colorant)); if (io -> Read(io, Root, 32, 1) != 1) goto Error; - Root[32] = 0; + Root[32] = 0; // To prevent exploits + if (!_cmsReadUInt16Array(io, 3, PCS)) goto Error; if (!_cmsReadUInt16Array(io, nDeviceCoords, Colorant)) goto Error; @@ -3148,8 +3151,8 @@ static cmsBool Type_NamedColor_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems) { cmsNAMEDCOLORLIST* NamedColorList = (cmsNAMEDCOLORLIST*) Ptr; - char prefix[32]; // Prefix for each color name - char suffix[32]; // Suffix for each color name + char prefix[33]; // Prefix for each color name + char suffix[33]; // Suffix for each color name int i, nColors; nColors = cmsNamedColorCount(NamedColorList); @@ -3161,7 +3164,7 @@ cmsBool Type_NamedColor_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER strncpy(prefix, (const char*) NamedColorList->Prefix, 32); strncpy(suffix, (const char*) NamedColorList->Suffix, 32); - suffix[31] = prefix[31] = 0; + suffix[32] = prefix[32] = 0; if (!io ->Write(io, 32, prefix)) return FALSE; if (!io ->Write(io, 32, suffix)) return FALSE; @@ -3173,6 +3176,7 @@ cmsBool Type_NamedColor_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER char Root[33]; if (!cmsNamedColorInfo(NamedColorList, i, Root, NULL, NULL, PCS, Colorant)) return 0; + Root[32] = 0; if (!io ->Write(io, 32 , Root)) return FALSE; if (!_cmsWriteUInt16Array(io, 3, PCS)) return FALSE; if (!_cmsWriteUInt16Array(io, NamedColorList ->ColorantCount, Colorant)) return FALSE; @@ -3623,7 +3627,7 @@ country varies for each element: -// Auxiliar, read an string specified as count + string +// Auxiliary, read an string specified as count + string static cmsBool ReadCountAndSting(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsMLU* mlu, cmsUInt32Number* SizeOfTag, const char* Section) { @@ -3872,7 +3876,7 @@ cmsBool Type_ViewingConditions_Write(struct _cms_typehandler_struct* self, cmsIO static void* Type_ViewingConditions_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n) { - return _cmsDupMem(self ->ContextID, Ptr, sizeof(cmsScreening)); + return _cmsDupMem(self->ContextID, Ptr, sizeof(cmsICCViewingConditions)); cmsUNUSED_PARAMETER(n); } @@ -4190,7 +4194,7 @@ cmsBool Type_MPEcurve_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* // The matrix is organized as an array of PxQ+Q elements, where P is the number of input channels to the // matrix, and Q is the number of output channels. The matrix elements are each float32Numbers. The array // is organized as follows: -// array = [e11, e12, ? e1P, e21, e22, ? e2P, ? eQ1, eQ2, ? eQP, e1, e2, ? eQ] +// array = [e11, e12, ..., e1P, e21, e22, ..., e2P, ..., eQ1, eQ2, ..., eQP, e1, e2, ..., eQ] static void *Type_MPEmatrix_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag) @@ -4320,7 +4324,7 @@ void *Type_MPEclut_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, if (Dimensions8[i] == 1) goto Error; // Impossible value, 0 for no CLUT and then 2 at least GridPoints[i] = (cmsUInt32Number)Dimensions8[i]; } - + // Allocate the true CLUT mpe = cmsStageAllocCLutFloatGranular(self ->ContextID, GridPoints, InputChans, OutputChans, NULL); if (mpe == NULL) goto Error; @@ -4347,13 +4351,13 @@ Error: static cmsBool Type_MPEclut_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems) { - cmsUInt8Number Dimensions8[16]; + cmsUInt8Number Dimensions8[16]; // 16 because the spec says 16 and not max number of channels cmsUInt32Number i; cmsStage* mpe = (cmsStage*) Ptr; _cmsStageCLutData* clut = (_cmsStageCLutData*) mpe ->Data; - // Check for maximum number of channels - if (mpe -> InputChannels > 15) return FALSE; + // Check for maximum number of channels supported by lcms + if (mpe -> InputChannels > MAX_INPUT_DIMENSIONS) return FALSE; // Only floats are supported in MPE if (clut ->HasFloatValues == FALSE) return FALSE; @@ -4709,10 +4713,10 @@ void *Type_vcgt_Read(struct _cms_typehandler_struct* self, // Y = cX + f | X < d // vcgt formula is: - // Y = (Max ?Min) * (X ^ Gamma) + Min + // Y = (Max - Min) * (X ^ Gamma) + Min // So, the translation is - // a = (Max ?Min) ^ ( 1 / Gamma) + // a = (Max - Min) ^ ( 1 / Gamma) // e = Min // b=c=d=f=0 @@ -5495,8 +5499,9 @@ static _cmsTagLinkedList SupportedTags[] = { { cmsSigScreeningTag, { 1, 1, { cmsSigScreeningType}, NULL }, &SupportedTags[59]}, { cmsSigVcgtTag, { 1, 1, { cmsSigVcgtType}, NULL }, &SupportedTags[60]}, { cmsSigMetaTag, { 1, 1, { cmsSigDictType}, NULL }, &SupportedTags[61]}, - { cmsSigProfileSequenceIdTag, { 1, 1, { cmsSigProfileSequenceIdType}, NULL }, &SupportedTags[62]}, - { cmsSigProfileDescriptionMLTag,{ 1, 1, { cmsSigMultiLocalizedUnicodeType}, NULL}, NULL} + { cmsSigProfileSequenceIdTag, { 1, 1, { cmsSigProfileSequenceIdType}, NULL }, &SupportedTags[62]}, + { cmsSigProfileDescriptionMLTag,{ 1, 1, { cmsSigMultiLocalizedUnicodeType}, NULL}, &SupportedTags[63]}, + { cmsSigArgyllArtsTag, { 9, 1, { cmsSigS15Fixed16ArrayType}, NULL}, NULL} }; @@ -5608,3 +5613,4 @@ cmsTagDescriptor* _cmsGetTagDescriptor(cmsContext ContextID, cmsTagSignature sig return NULL; } + diff --git a/third_party/lcms/src/cmsvirt.c b/third_party/lcms/src/cmsvirt.c index d19ace1651..9eff1f7bed 100644 --- a/third_party/lcms/src/cmsvirt.c +++ b/third_party/lcms/src/cmsvirt.c @@ -1,7 +1,7 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2014 Marti Maria Saguer +// Copyright (c) 1998-2016 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"), @@ -642,7 +642,7 @@ cmsToneCurve* Build_sRGBGamma(cmsContext ContextID) // Create the ICC virtual profile for sRGB space cmsHPROFILE CMSEXPORT cmsCreate_sRGBProfileTHR(cmsContext ContextID) { - cmsCIExyY D65; + cmsCIExyY D65 = { 0.3127, 0.3290, 1.0 }; cmsCIExyYTRIPLE Rec709Primaries = { {0.6400, 0.3300, 1.0}, {0.3000, 0.6000, 1.0}, @@ -651,7 +651,7 @@ cmsHPROFILE CMSEXPORT cmsCreate_sRGBProfileTHR(cmsContext ContextID) cmsToneCurve* Gamma22[3]; cmsHPROFILE hsRGB; - cmsWhitePointFromTemp(&D65, 6504); + // cmsWhitePointFromTemp(&D65, 6504); Gamma22[0] = Gamma22[1] = Gamma22[2] = Build_sRGBGamma(ContextID); if (Gamma22[0] == NULL) return NULL; @@ -679,6 +679,7 @@ typedef struct { cmsFloat64Number Contrast; cmsFloat64Number Hue; cmsFloat64Number Saturation; + cmsBool lAdjustWP; cmsCIEXYZ WPsrc, WPdest; } BCHSWADJUSTS, *LPBCHSWADJUSTS; @@ -708,9 +709,10 @@ int bchswSampler(register const cmsUInt16Number In[], register cmsUInt16Number O cmsLCh2Lab(&LabOut, &LChOut); // Move white point in Lab - - cmsLab2XYZ(&bchsw ->WPsrc, &XYZ, &LabOut); - cmsXYZ2Lab(&bchsw ->WPdest, &LabOut, &XYZ); + if (bchsw->lAdjustWP) { + cmsLab2XYZ(&bchsw->WPsrc, &XYZ, &LabOut); + cmsXYZ2Lab(&bchsw->WPdest, &LabOut, &XYZ); + } // Back to encoded @@ -744,18 +746,23 @@ cmsHPROFILE CMSEXPORT cmsCreateBCHSWabstractProfileTHR(cmsContext ContextID, bchsw.Contrast = Contrast; bchsw.Hue = Hue; bchsw.Saturation = Saturation; + if (TempSrc == TempDest) { - cmsWhitePointFromTemp(&WhitePnt, TempSrc ); - cmsxyY2XYZ(&bchsw.WPsrc, &WhitePnt); - - cmsWhitePointFromTemp(&WhitePnt, TempDest); - cmsxyY2XYZ(&bchsw.WPdest, &WhitePnt); + bchsw.lAdjustWP = FALSE; + } + else { + bchsw.lAdjustWP = TRUE; + cmsWhitePointFromTemp(&WhitePnt, TempSrc); + cmsxyY2XYZ(&bchsw.WPsrc, &WhitePnt); + cmsWhitePointFromTemp(&WhitePnt, TempDest); + cmsxyY2XYZ(&bchsw.WPdest, &WhitePnt); + + } hICC = cmsCreateProfilePlaceholder(ContextID); if (!hICC) // can't allocate return NULL; - cmsSetDeviceClass(hICC, cmsSigAbstractClass); cmsSetColorSpace(hICC, cmsSigLabData); cmsSetPCS(hICC, cmsSigLabData); @@ -988,12 +995,14 @@ typedef struct { } cmsAllowedLUT; +#define cmsSig0 ((cmsTagSignature) 0) + static const cmsAllowedLUT AllowedLUTTypes[] = { - { 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 }}, + { FALSE, cmsSig0, cmsSigLut16Type, 4, { cmsSigMatrixElemType, cmsSigCurveSetElemType, cmsSigCLutElemType, cmsSigCurveSetElemType } }, + { FALSE, cmsSig0, cmsSigLut16Type, 3, { cmsSigCurveSetElemType, cmsSigCLutElemType, cmsSigCurveSetElemType } }, + { FALSE, cmsSig0, cmsSigLut16Type, 2, { cmsSigCurveSetElemType, cmsSigCLutElemType } }, + { TRUE, cmsSig0, cmsSigLutAtoBType, 1, { cmsSigCurveSetElemType } }, { TRUE , cmsSigAToB0Tag, cmsSigLutAtoBType, 3, { cmsSigCurveSetElemType, cmsSigMatrixElemType, cmsSigCurveSetElemType } }, { TRUE , cmsSigAToB0Tag, cmsSigLutAtoBType, 3, { cmsSigCurveSetElemType, cmsSigCLutElemType, cmsSigCurveSetElemType } }, { TRUE , cmsSigAToB0Tag, cmsSigLutAtoBType, 5, { cmsSigCurveSetElemType, cmsSigCLutElemType, cmsSigCurveSetElemType, cmsSigMatrixElemType, cmsSigCurveSetElemType }}, @@ -1129,15 +1138,20 @@ cmsHPROFILE CMSEXPORT cmsTransform2DeviceLink(cmsHTRANSFORM hTransform, cmsFloat // If no way, then force CLUT that for sure can be written if (AllowedLUT == NULL) { + cmsStage* FirstStage; + cmsStage* LastStage; + dwFlags |= cmsFLAGS_FORCE_CLUT; _cmsOptimizePipeline(ContextID, &LUT, xform ->RenderingIntent, &FrmIn, &FrmOut, &dwFlags); // Put identity curves if needed - if (cmsPipelineGetPtrToFirstStage(LUT) ->Type != cmsSigCurveSetElemType) + FirstStage = cmsPipelineGetPtrToFirstStage(LUT); + if (FirstStage != NULL && FirstStage ->Type != cmsSigCurveSetElemType) if (!cmsPipelineInsertStage(LUT, cmsAT_BEGIN, _cmsStageAllocIdentityCurves(ContextID, ChansIn))) goto Error; - if (cmsPipelineGetPtrToLastStage(LUT) ->Type != cmsSigCurveSetElemType) + LastStage = cmsPipelineGetPtrToLastStage(LUT); + if (LastStage != NULL && LastStage ->Type != cmsSigCurveSetElemType) if (!cmsPipelineInsertStage(LUT, cmsAT_END, _cmsStageAllocIdentityCurves(ContextID, ChansOut))) goto Error; diff --git a/third_party/lcms/src/cmswtpnt.c b/third_party/lcms/src/cmswtpnt.c index 903fdd7497..c6b612584b 100644 --- a/third_party/lcms/src/cmswtpnt.c +++ b/third_party/lcms/src/cmswtpnt.c @@ -1,7 +1,7 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2014 Marti Maria Saguer +// Copyright (c) 1998-2016 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"), @@ -347,3 +347,5 @@ cmsBool CMSEXPORT cmsAdaptToIlluminant(cmsCIEXYZ* Result, return TRUE; } + + diff --git a/third_party/lcms/src/cmsxform.c b/third_party/lcms/src/cmsxform.c index dffe6b2fb7..b3802f0d57 100644 --- a/third_party/lcms/src/cmsxform.c +++ b/third_party/lcms/src/cmsxform.c @@ -1,7 +1,7 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2014 Marti Maria Saguer +// Copyright (c) 1998-2016 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"), @@ -179,12 +179,18 @@ void CMSEXPORT cmsDoTransform(cmsHTRANSFORM Transform, { _cmsTRANSFORM* p = (_cmsTRANSFORM*) Transform; - - p -> xform(p, InputBuffer, OutputBuffer, Size, Size); + cmsStride stride; + + stride.BytesPerLineIn = 0; // Not used + stride.BytesPerLineOut = 0; + stride.BytesPerPlaneIn = Size; + stride.BytesPerPlaneOut = Size; + + p -> xform(p, InputBuffer, OutputBuffer, Size, 1, &stride); } -// Apply transform. +// This is a legacy stride for planar void CMSEXPORT cmsDoTransformStride(cmsHTRANSFORM Transform, const void* InputBuffer, void* OutputBuffer, @@ -192,10 +198,40 @@ void CMSEXPORT cmsDoTransformStride(cmsHTRANSFORM Transform, { _cmsTRANSFORM* p = (_cmsTRANSFORM*) Transform; + cmsStride stride; - p -> xform(p, InputBuffer, OutputBuffer, Size, Stride); + stride.BytesPerLineIn = 0; + stride.BytesPerLineOut = 0; + stride.BytesPerPlaneIn = Stride; + stride.BytesPerPlaneOut = Stride; + + p -> xform(p, InputBuffer, OutputBuffer, Size, 1, &stride); } +// This is the "fast" function for plugins +void CMSEXPORT cmsDoTransformLineStride(cmsHTRANSFORM Transform, + const void* InputBuffer, + void* OutputBuffer, + cmsUInt32Number PixelsPerLine, + cmsUInt32Number LineCount, + cmsUInt32Number BytesPerLineIn, + cmsUInt32Number BytesPerLineOut, + cmsUInt32Number BytesPerPlaneIn, + cmsUInt32Number BytesPerPlaneOut) + +{ + _cmsTRANSFORM* p = (_cmsTRANSFORM*) Transform; + cmsStride stride; + + stride.BytesPerLineIn = BytesPerLineIn; + stride.BytesPerLineOut = BytesPerLineOut; + stride.BytesPerPlaneIn = BytesPerPlaneIn; + stride.BytesPerPlaneOut = BytesPerPlaneOut; + + p->xform(p, InputBuffer, OutputBuffer, PixelsPerLine, LineCount, &stride); +} + + // Transform routines ---------------------------------------------------------------------------------------------------------- @@ -204,49 +240,64 @@ void CMSEXPORT cmsDoTransformStride(cmsHTRANSFORM Transform, static void FloatXFORM(_cmsTRANSFORM* p, const void* in, - void* out, cmsUInt32Number Size, cmsUInt32Number Stride) + void* out, + cmsUInt32Number PixelsPerLine, + cmsUInt32Number LineCount, + const cmsStride* Stride) { cmsUInt8Number* accum; cmsUInt8Number* output; cmsFloat32Number fIn[cmsMAXCHANNELS], fOut[cmsMAXCHANNELS]; cmsFloat32Number OutOfGamut; - cmsUInt32Number i, j; + cmsUInt32Number i, j, c, strideIn, strideOut; - accum = (cmsUInt8Number*) in; - output = (cmsUInt8Number*) out; + _cmsHandleExtraChannels(p, in, out, PixelsPerLine, LineCount, Stride); - for (i=0; i < Size; i++) { + strideIn = 0; + strideOut = 0; - accum = p -> FromInputFloat(p, fIn, accum, Stride); + for (i = 0; i < LineCount; i++) { - // Any gamut chack to do? - if (p ->GamutCheck != NULL) { + accum = (cmsUInt8Number*)in + strideIn; + output = (cmsUInt8Number*)out + strideOut; - // Evaluate gamut marker. - cmsPipelineEvalFloat( fIn, &OutOfGamut, p ->GamutCheck); + for (j = 0; j < PixelsPerLine; j++) { - // Is current color out of gamut? - if (OutOfGamut > 0.0) { + accum = p->FromInputFloat(p, fIn, accum, Stride->BytesPerPlaneIn); - // Certainly, out of gamut - for (j=0; j < cmsMAXCHANNELS; j++) - fOut[j] = -1.0; + // Any gamut chack to do? + if (p->GamutCheck != NULL) { + // Evaluate gamut marker. + cmsPipelineEvalFloat(fIn, &OutOfGamut, p->GamutCheck); + + // Is current color out of gamut? + if (OutOfGamut > 0.0) { + + // Certainly, out of gamut + for (c = 0; c < cmsMAXCHANNELS; c++) + fOut[c] = -1.0; + + } + else { + // No, proceed normally + cmsPipelineEvalFloat(fIn, fOut, p->Lut); + } } else { - // No, proceed normally - cmsPipelineEvalFloat(fIn, fOut, p -> Lut); + + // No gamut check at all + cmsPipelineEvalFloat(fIn, fOut, p->Lut); } - } - else { - // No gamut check at all - cmsPipelineEvalFloat(fIn, fOut, p -> Lut); + + output = p->ToOutputFloat(p, fOut, output, Stride->BytesPerPlaneOut); } - // Back to asked representation - output = p -> ToOutputFloat(p, fOut, output, Stride); + strideIn += Stride->BytesPerLineIn; + strideOut += Stride->BytesPerLineOut; } + } @@ -254,47 +305,73 @@ static void NullFloatXFORM(_cmsTRANSFORM* p, const void* in, void* out, - cmsUInt32Number Size, - cmsUInt32Number Stride) + cmsUInt32Number PixelsPerLine, + cmsUInt32Number LineCount, + const cmsStride* Stride) + { cmsUInt8Number* accum; cmsUInt8Number* output; cmsFloat32Number fIn[cmsMAXCHANNELS]; - cmsUInt32Number i, n; + cmsUInt32Number i, j, strideIn, strideOut; + + _cmsHandleExtraChannels(p, in, out, PixelsPerLine, LineCount, Stride); + + strideIn = 0; + strideOut = 0; + + for (i = 0; i < LineCount; i++) { + + accum = (cmsUInt8Number*) in + strideIn; + output = (cmsUInt8Number*) out + strideOut; - accum = (cmsUInt8Number*) in; - output = (cmsUInt8Number*) out; - n = Size; + for (j = 0; j < PixelsPerLine; j++) { - for (i=0; i < n; i++) { + accum = p->FromInputFloat(p, fIn, accum, Stride ->BytesPerPlaneIn); + output = p->ToOutputFloat(p, fIn, output, Stride->BytesPerPlaneOut); + } - accum = p -> FromInputFloat(p, fIn, accum, Stride); - output = p -> ToOutputFloat(p, fIn, output, Stride); + strideIn += Stride->BytesPerLineIn; + strideOut += Stride->BytesPerLineOut; } } // 16 bit precision ----------------------------------------------------------------------------------------------------------- -// Null transformation, only applies formatters. No cach?static +// Null transformation, only applies formatters. No cache +static void NullXFORM(_cmsTRANSFORM* p, const void* in, - void* out, cmsUInt32Number Size, - cmsUInt32Number Stride) + void* out, + cmsUInt32Number PixelsPerLine, + cmsUInt32Number LineCount, + const cmsStride* Stride) { cmsUInt8Number* accum; cmsUInt8Number* output; cmsUInt16Number wIn[cmsMAXCHANNELS]; - cmsUInt32Number i, n; + cmsUInt32Number i, j, strideIn, strideOut; + + _cmsHandleExtraChannels(p, in, out, PixelsPerLine, LineCount, Stride); + + strideIn = 0; + strideOut = 0; + + for (i = 0; i < LineCount; i++) { - accum = (cmsUInt8Number*) in; - output = (cmsUInt8Number*) out; - n = Size; // Buffer len + accum = (cmsUInt8Number*)in + strideIn; + output = (cmsUInt8Number*)out + strideOut; - for (i=0; i < n; i++) { + for (j = 0; j < PixelsPerLine; j++) { - accum = p -> FromInput(p, wIn, accum, Stride); - output = p -> ToOutput(p, wIn, output, Stride); + accum = p->FromInput(p, wIn, accum, Stride->BytesPerPlaneIn); + output = p->ToOutput(p, wIn, output, Stride->BytesPerPlaneOut); } + + strideIn += Stride->BytesPerLineIn; + strideOut += Stride->BytesPerLineOut; + } + } @@ -302,27 +379,41 @@ void NullXFORM(_cmsTRANSFORM* p, static void PrecalculatedXFORM(_cmsTRANSFORM* p, const void* in, - void* out, cmsUInt32Number Size, cmsUInt32Number Stride) + void* out, + cmsUInt32Number PixelsPerLine, + cmsUInt32Number LineCount, + const cmsStride* Stride) { register cmsUInt8Number* accum; register cmsUInt8Number* output; cmsUInt16Number wIn[cmsMAXCHANNELS], wOut[cmsMAXCHANNELS]; - cmsUInt32Number i, n; + cmsUInt32Number i, j, strideIn, strideOut; - accum = (cmsUInt8Number*) in; - output = (cmsUInt8Number*) out; - n = Size; + _cmsHandleExtraChannels(p, in, out, PixelsPerLine, LineCount, Stride); - for (i=0; i < n; i++) { + strideIn = 0; + strideOut = 0; - accum = p -> FromInput(p, wIn, accum, Stride); - p ->Lut ->Eval16Fn(wIn, wOut, p -> Lut->Data); - output = p -> ToOutput(p, wOut, output, Stride); + for (i = 0; i < LineCount; i++) { + + accum = (cmsUInt8Number*)in + strideIn; + output = (cmsUInt8Number*)out + strideOut; + + for (j = 0; j < PixelsPerLine; j++) { + + accum = p->FromInput(p, wIn, accum, Stride->BytesPerPlaneIn); + p->Lut->Eval16Fn(wIn, wOut, p->Lut->Data); + output = p->ToOutput(p, wOut, output, Stride->BytesPerPlaneOut); + } + + strideIn += Stride->BytesPerLineIn; + strideOut += Stride->BytesPerLineOut; } + } -// Auxiliar: Handle precalculated gamut check. The retrieval of context may be alittle bit slow, but this function is not critical. +// Auxiliary: 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[], @@ -345,122 +436,161 @@ void TransformOnePixelWithGamutCheck(_cmsTRANSFORM* p, p ->Lut ->Eval16Fn(wIn, wOut, p -> Lut->Data); } -// Gamut check, No cach? 16 bits. +// Gamut check, No cache, 16 bits. static void PrecalculatedXFORMGamutCheck(_cmsTRANSFORM* p, const void* in, - void* out, cmsUInt32Number Size, cmsUInt32Number Stride) + void* out, + cmsUInt32Number PixelsPerLine, + cmsUInt32Number LineCount, + const cmsStride* Stride) { cmsUInt8Number* accum; cmsUInt8Number* output; cmsUInt16Number wIn[cmsMAXCHANNELS], wOut[cmsMAXCHANNELS]; - cmsUInt32Number i, n; + cmsUInt32Number i, j, strideIn, strideOut; + + _cmsHandleExtraChannels(p, in, out, PixelsPerLine, LineCount, Stride); + + strideIn = 0; + strideOut = 0; + + for (i = 0; i < LineCount; i++) { - accum = (cmsUInt8Number*) in; - output = (cmsUInt8Number*) out; - n = Size; // Buffer len + accum = (cmsUInt8Number*)in + strideIn; + output = (cmsUInt8Number*)out + strideOut; - for (i=0; i < n; i++) { + for (j = 0; j < PixelsPerLine; j++) { - accum = p -> FromInput(p, wIn, accum, Stride); - TransformOnePixelWithGamutCheck(p, wIn, wOut); - output = p -> ToOutput(p, wOut, output, Stride); + accum = p->FromInput(p, wIn, accum, Stride->BytesPerPlaneIn); + TransformOnePixelWithGamutCheck(p, wIn, wOut); + output = p->ToOutput(p, wOut, output, Stride->BytesPerPlaneOut); + } + + strideIn += Stride->BytesPerLineIn; + strideOut += Stride->BytesPerLineOut; } } -// No gamut check, Cach? 16 bits, +// No gamut check, Cache, 16 bits, static void CachedXFORM(_cmsTRANSFORM* p, const void* in, - void* out, cmsUInt32Number Size, cmsUInt32Number Stride) + void* out, + cmsUInt32Number PixelsPerLine, + cmsUInt32Number LineCount, + const cmsStride* Stride) { cmsUInt8Number* accum; cmsUInt8Number* output; cmsUInt16Number wIn[cmsMAXCHANNELS], wOut[cmsMAXCHANNELS]; - cmsUInt32Number i, n; _cmsCACHE Cache; + cmsUInt32Number i, j, strideIn, strideOut; - accum = (cmsUInt8Number*) in; - output = (cmsUInt8Number*) out; - n = Size; // Buffer len + _cmsHandleExtraChannels(p, in, out, PixelsPerLine, LineCount, Stride); // Empty buffers for quick memcmp - memset(wIn, 0, sizeof(wIn)); + memset(wIn, 0, sizeof(wIn)); memset(wOut, 0, sizeof(wOut)); // Get copy of zero cache - memcpy(&Cache, &p ->Cache, sizeof(Cache)); + memcpy(&Cache, &p->Cache, sizeof(Cache)); - for (i=0; i < n; i++) { + strideIn = 0; + strideOut = 0; - accum = p -> FromInput(p, wIn, accum, Stride); + for (i = 0; i < LineCount; i++) { - if (memcmp(wIn, Cache.CacheIn, sizeof(Cache.CacheIn)) == 0) { + accum = (cmsUInt8Number*)in + strideIn; + output = (cmsUInt8Number*)out + strideOut; - memcpy(wOut, Cache.CacheOut, sizeof(Cache.CacheOut)); - } - else { + for (j = 0; j < PixelsPerLine; j++) { - p ->Lut ->Eval16Fn(wIn, wOut, p -> Lut->Data); + accum = p->FromInput(p, wIn, accum, Stride->BytesPerPlaneIn); - memcpy(Cache.CacheIn, wIn, sizeof(Cache.CacheIn)); - memcpy(Cache.CacheOut, wOut, sizeof(Cache.CacheOut)); + if (memcmp(wIn, Cache.CacheIn, sizeof(Cache.CacheIn)) == 0) { + + memcpy(wOut, Cache.CacheOut, sizeof(Cache.CacheOut)); + } + else { + p->Lut->Eval16Fn(wIn, wOut, p->Lut->Data); + + memcpy(Cache.CacheIn, wIn, sizeof(Cache.CacheIn)); + memcpy(Cache.CacheOut, wOut, sizeof(Cache.CacheOut)); + } + + output = p->ToOutput(p, wOut, output, Stride->BytesPerPlaneOut); } - output = p -> ToOutput(p, wOut, output, Stride); + strideIn += Stride->BytesPerLineIn; + strideOut += Stride->BytesPerLineOut; } - } - // All those nice features together static void CachedXFORMGamutCheck(_cmsTRANSFORM* p, const void* in, - void* out, cmsUInt32Number Size, cmsUInt32Number Stride) + void* out, + cmsUInt32Number PixelsPerLine, + cmsUInt32Number LineCount, + const cmsStride* Stride) { - cmsUInt8Number* accum; - cmsUInt8Number* output; - cmsUInt16Number wIn[cmsMAXCHANNELS], wOut[cmsMAXCHANNELS]; - cmsUInt32Number i, n; - _cmsCACHE Cache; + cmsUInt8Number* accum; + cmsUInt8Number* output; + cmsUInt16Number wIn[cmsMAXCHANNELS], wOut[cmsMAXCHANNELS]; + _cmsCACHE Cache; + cmsUInt32Number i, j, strideIn, strideOut; + + _cmsHandleExtraChannels(p, in, out, PixelsPerLine, LineCount, Stride); + + // Empty buffers for quick memcmp + memset(wIn, 0, sizeof(wIn)); + memset(wOut, 0, sizeof(wOut)); + + // Get copy of zero cache + memcpy(&Cache, &p->Cache, sizeof(Cache)); - accum = (cmsUInt8Number*) in; - output = (cmsUInt8Number*) out; - n = Size; // Buffer len + strideIn = 0; + strideOut = 0; - // Empty buffers for quick memcmp - memset(wIn, 0, sizeof(cmsUInt16Number) * cmsMAXCHANNELS); - memset(wOut, 0, sizeof(cmsUInt16Number) * cmsMAXCHANNELS); + for (i = 0; i < LineCount; i++) { - // Get copy of zero cache - memcpy(&Cache, &p ->Cache, sizeof(Cache)); + accum = (cmsUInt8Number*)in + strideIn; + output = (cmsUInt8Number*)out + strideOut; - for (i=0; i < n; i++) { + for (j = 0; j < PixelsPerLine; j++) { - accum = p -> FromInput(p, wIn, accum, Stride); + accum = p->FromInput(p, wIn, accum, Stride->BytesPerPlaneIn); if (memcmp(wIn, Cache.CacheIn, sizeof(Cache.CacheIn)) == 0) { - memcpy(wOut, Cache.CacheOut, sizeof(Cache.CacheOut)); + + memcpy(wOut, Cache.CacheOut, sizeof(Cache.CacheOut)); } else { - TransformOnePixelWithGamutCheck(p, wIn, wOut); - memcpy(Cache.CacheIn, wIn, sizeof(Cache.CacheIn)); - memcpy(Cache.CacheOut, wOut, sizeof(Cache.CacheOut)); + TransformOnePixelWithGamutCheck(p, wIn, wOut); + + memcpy(Cache.CacheIn, wIn, sizeof(Cache.CacheIn)); + memcpy(Cache.CacheOut, wOut, sizeof(Cache.CacheOut)); } - output = p -> ToOutput(p, wOut, output, Stride); - } + output = p->ToOutput(p, wOut, output, Stride->BytesPerPlaneOut); + } + strideIn += Stride->BytesPerLineIn; + strideOut += Stride->BytesPerLineOut; + } } -// ------------------------------------------------------------------------------------------------------------- +// Transform plug-ins ---------------------------------------------------------------------------------------------------- // List of used-defined transform factories typedef struct _cmsTransformCollection_st { - _cmsTransformFactory Factory; + _cmsTransform2Factory Factory; + cmsBool OldXform; // Factory returns xform function in the old style + struct _cmsTransformCollection_st *Next; } _cmsTransformCollection; @@ -503,6 +633,7 @@ void DupPluginTransformList(struct _cmsContext_struct* ctx, ctx ->chunks[TransformPlugin] = _cmsSubAllocDup(ctx->MemPool, &newHead, sizeof(_cmsTransformPluginChunkType)); } +// Allocates memory for transform plugin factory void _cmsAllocTransformPluginChunk(struct _cmsContext_struct* ctx, const struct _cmsContext_struct* src) { @@ -517,6 +648,35 @@ void _cmsAllocTransformPluginChunk(struct _cmsContext_struct* ctx, } } +// Adaptor for old versions of plug-in +static +void _cmsTransform2toTransformAdaptor(struct _cmstransform_struct *CMMcargo, + const void* InputBuffer, + void* OutputBuffer, + cmsUInt32Number PixelsPerLine, + cmsUInt32Number LineCount, + const cmsStride* Stride) +{ + + cmsUInt32Number i, strideIn, strideOut; + + _cmsHandleExtraChannels(CMMcargo, InputBuffer, OutputBuffer, PixelsPerLine, LineCount, Stride); + + strideIn = 0; + strideOut = 0; + + for (i = 0; i < LineCount; i++) { + + void *accum = (cmsUInt8Number*)InputBuffer + strideIn; + void *output = (cmsUInt8Number*)OutputBuffer + strideOut; + + CMMcargo->OldXform(CMMcargo, accum, output, PixelsPerLine, Stride->BytesPerPlaneIn); + + strideIn += Stride->BytesPerLineIn; + strideOut += Stride->BytesPerLineOut; + } +} + // Register new ways to transform @@ -534,14 +694,22 @@ cmsBool _cmsRegisterTransformPlugin(cmsContext ContextID, cmsPluginBase* Data) } // Factory callback is required - if (Plugin ->Factory == NULL) return FALSE; + if (Plugin->factories.xform == NULL) return FALSE; fl = (_cmsTransformCollection*) _cmsPluginMalloc(ContextID, sizeof(_cmsTransformCollection)); if (fl == NULL) return FALSE; + // Check for full xform plug-ins previous to 2.8, we would need an adapter in that case + if (Plugin->base.ExpectedVersion < 2080) { + + fl->OldXform = TRUE; + } + else + fl->OldXform = FALSE; + // Copy the parameters - fl ->Factory = Plugin ->Factory; + fl->Factory = Plugin->factories.xform; // Keep linked list fl ->Next = ctx->TransformCollection; @@ -591,49 +759,57 @@ _cmsTRANSFORM* AllocEmptyTransform(cmsContext ContextID, cmsPipeline* lut, _cmsTransformPluginChunkType* ctx = ( _cmsTransformPluginChunkType*) _cmsContextGetClientChunk(ContextID, TransformPlugin); _cmsTransformCollection* Plugin; - // Allocate needed memory - _cmsTRANSFORM* p = (_cmsTRANSFORM*) _cmsMallocZero(ContextID, sizeof(_cmsTRANSFORM)); - if (!p) { - cmsPipelineFree(lut); - return NULL; - } - - // Store the proposed pipeline - p ->Lut = lut; - - // Let's see if any plug-in want to do the transform by itself - for (Plugin = ctx ->TransformCollection; - Plugin != NULL; - Plugin = Plugin ->Next) { - - if (Plugin ->Factory(&p->xform, &p->UserData, &p ->FreeUserData, &p ->Lut, InputFormat, OutputFormat, dwFlags)) { - - // Last plugin in the declaration order takes control. We just keep - // the original parameters as a logging. - // Note that cmsFLAGS_CAN_CHANGE_FORMATTER is not set, so by default - // an optimized transform is not reusable. The plug-in can, however, change - // the flags and make it suitable. - - p ->ContextID = ContextID; - p ->InputFormat = *InputFormat; - p ->OutputFormat = *OutputFormat; - p ->dwOriginalFlags = *dwFlags; - - // 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(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; - } - } - - // Not suitable for the transform plug-in, let's check the pipeline plug-in - if (p ->Lut != NULL) - _cmsOptimizePipeline(ContextID, &p->Lut, Intent, InputFormat, OutputFormat, dwFlags); + // Allocate needed memory + _cmsTRANSFORM* p = (_cmsTRANSFORM*)_cmsMallocZero(ContextID, sizeof(_cmsTRANSFORM)); + if (!p) { + cmsPipelineFree(lut); + return NULL; + } + + // Store the proposed pipeline + p->Lut = lut; + + // Let's see if any plug-in want to do the transform by itself + if (p->Lut != NULL) { + + for (Plugin = ctx->TransformCollection; + Plugin != NULL; + Plugin = Plugin->Next) { + + if (Plugin->Factory(&p->xform, &p->UserData, &p->FreeUserData, &p->Lut, InputFormat, OutputFormat, dwFlags)) { + + // Last plugin in the declaration order takes control. We just keep + // the original parameters as a logging. + // Note that cmsFLAGS_CAN_CHANGE_FORMATTER is not set, so by default + // an optimized transform is not reusable. The plug-in can, however, change + // the flags and make it suitable. + + p->ContextID = ContextID; + p->InputFormat = *InputFormat; + p->OutputFormat = *OutputFormat; + p->dwOriginalFlags = *dwFlags; + + // 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(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; + + // Save the day? + if (Plugin->OldXform) { + p->OldXform = (_cmsTransformFn) p->xform; + p->xform = _cmsTransform2toTransformAdaptor; + } + + return p; + } + } + + // Not suitable for the transform plug-in, let's check the pipeline plug-in + _cmsOptimizePipeline(ContextID, &p->Lut, Intent, InputFormat, OutputFormat, dwFlags); + } // Check whatever this is a true floating point transform if (_cmsFormatterIsFloat(*InputFormat) && _cmsFormatterIsFloat(*OutputFormat)) { @@ -655,7 +831,7 @@ _cmsTRANSFORM* AllocEmptyTransform(cmsContext ContextID, cmsPipeline* lut, p ->xform = NullFloatXFORM; } else { - // Float transforms don't use cach? always are non-NULL + // Float transforms don't use cache, always are non-NULL p ->xform = FloatXFORM; } @@ -694,16 +870,17 @@ _cmsTRANSFORM* AllocEmptyTransform(cmsContext ContextID, cmsPipeline* lut, if (*dwFlags & cmsFLAGS_NOCACHE) { if (*dwFlags & cmsFLAGS_GAMUTCHECK) - p ->xform = PrecalculatedXFORMGamutCheck; // Gamut check, no cach? + p ->xform = PrecalculatedXFORMGamutCheck; // Gamut check, no cache else - p ->xform = PrecalculatedXFORM; // No cach? no gamut check + p ->xform = PrecalculatedXFORM; // No cache, no gamut check } else { if (*dwFlags & cmsFLAGS_GAMUTCHECK) - p ->xform = CachedXFORMGamutCheck; // Gamut check, cach? + p ->xform = CachedXFORMGamutCheck; // Gamut check, cache else - p ->xform = CachedXFORM; // No gamut check, cach? + p ->xform = CachedXFORM; // No gamut check, cache + } } } @@ -786,6 +963,22 @@ cmsBool IsProperColorSpace(cmsColorSpaceSignature Check, cmsUInt32Number dwForm // ---------------------------------------------------------------------------------------------------------------- +// Jun-21-2000: Some profiles (those that comes with W2K) comes +// with the media white (media black?) x 100. Add a sanity check + +static +void NormalizeXYZ(cmsCIEXYZ* Dest) +{ + while (Dest -> X > 2. && + Dest -> Y > 2. && + Dest -> Z > 2.) { + + Dest -> X /= 10.; + Dest -> Y /= 10.; + Dest -> Z /= 10.; + } +} + static void SetWhitePoint(cmsCIEXYZ* wtPt, const cmsCIEXYZ* src) { @@ -798,6 +991,8 @@ void SetWhitePoint(cmsCIEXYZ* wtPt, const cmsCIEXYZ* src) wtPt ->X = src->X; wtPt ->Y = src->Y; wtPt ->Z = src->Z; + + NormalizeXYZ(wtPt); } } @@ -1108,7 +1303,6 @@ cmsBool CMSEXPORT cmsChangeBuffersFormat(cmsHTRANSFORM hTransform, cmsUInt32Number InputFormat, cmsUInt32Number OutputFormat) { - _cmsTRANSFORM* xform = (_cmsTRANSFORM*) hTransform; cmsFormatter16 FromInput, ToOutput; diff --git a/third_party/lcms/src/lcms2_internal.h b/third_party/lcms/src/lcms2_internal.h index 1dedf16b8d..115ac59701 100644 --- a/third_party/lcms/src/lcms2_internal.h +++ b/third_party/lcms/src/lcms2_internal.h @@ -1,8 +1,7 @@ -//<<<+++OPENSOURCE -//<<<+++OPENSOURCE_MUST_BEGIN COMMENT==TRUE + // // Little Color Management System -// Copyright (c) 1998-2014 Marti Maria Saguer +// Copyright (c) 1998-2016 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"), @@ -29,7 +28,7 @@ // Include plug-in foundation #ifndef _lcms_plugin_H -#include "third_party/lcms/include/lcms2_plugin.h" +# include "third_party/lcms/include/lcms2_plugin.h" #endif // ctype is part of C99 as per 7.1.2 @@ -58,7 +57,15 @@ #define _cmsALIGNLONG(x) (((x)+(sizeof(cmsUInt32Number)-1)) & ~(sizeof(cmsUInt32Number)-1)) // Alignment to memory pointer -#define _cmsALIGNMEM(x) (((x)+(sizeof(void *) - 1)) & ~(sizeof(void *) - 1)) + +// (Ultra)SPARC with gcc requires ptr alignment of 8 bytes +// even though sizeof(void *) is only four: for greatest flexibility +// allow the build to specify ptr alignment. +#ifndef CMS_PTR_ALIGNMENT +# define CMS_PTR_ALIGNMENT sizeof(void *) +#endif + +#define _cmsALIGNMEM(x) (((x)+(CMS_PTR_ALIGNMENT - 1)) & ~(CMS_PTR_ALIGNMENT - 1)) // Maximum encodeable values in floating point #define MAX_ENCODEABLE_XYZ (1.0 + 32767.0/32768.0) @@ -195,11 +202,17 @@ cmsINLINE cmsUInt16Number _cmsQuickSaturateWord(cmsFloat64Number d) // Microsoft felt that it was necessary to keep it set at -1 for an unlocked critical // section, even when they changed the underlying algorithm to be more scalable. // The final parts of the critical section object are unimportant, and can be set -// to zero for their defaults. This yields an initialization macro: +// to zero for their defaults. This yields to an initialization macro: typedef CRITICAL_SECTION _cmsMutex; -#define CMS_MUTEX_INITIALIZER {(void*) -1,-1,0,0,0,0} +#define CMS_MUTEX_INITIALIZER {(PRTL_CRITICAL_SECTION_DEBUG) -1,-1,0,0,0,0} + +#ifdef _MSC_VER +# if (_MSC_VER >= 1800) +# pragma warning(disable : 26135) +# endif +#endif cmsINLINE int _cmsLockPrimitive(_cmsMutex *m) { @@ -285,38 +298,38 @@ typedef int _cmsMutex; cmsINLINE int _cmsLockPrimitive(_cmsMutex *m) { - return 0; cmsUNUSED_PARAMETER(m); + return 0; } cmsINLINE int _cmsUnlockPrimitive(_cmsMutex *m) { - return 0; cmsUNUSED_PARAMETER(m); + return 0; } cmsINLINE int _cmsInitMutexPrimitive(_cmsMutex *m) { - return 0; cmsUNUSED_PARAMETER(m); + return 0; } cmsINLINE int _cmsDestroyMutexPrimitive(_cmsMutex *m) { - return 0; cmsUNUSED_PARAMETER(m); + return 0; } cmsINLINE int _cmsEnterCriticalSectionPrimitive(_cmsMutex *m) { - return 0; cmsUNUSED_PARAMETER(m); + return 0; } cmsINLINE int _cmsLeaveCriticalSectionPrimitive(_cmsMutex *m) { - return 0; cmsUNUSED_PARAMETER(m); + return 0; } #endif @@ -657,8 +670,8 @@ struct _cms_MLU_struct { cmsContext ContextID; // The directory - int AllocatedEntries; - int UsedEntries; + cmsUInt32Number AllocatedEntries; + cmsUInt32Number UsedEntries; _cmsMLUentry* Entries; // Array of pointers to strings allocated in MemPool // The Pool @@ -726,7 +739,7 @@ typedef struct _cms_iccprofile_struct { // Dictionary cmsUInt32Number TagCount; cmsTagSignature TagNames[MAX_TABLE_TAG]; - cmsTagSignature TagLinked[MAX_TABLE_TAG]; // The tag to wich is linked (0=none) + cmsTagSignature TagLinked[MAX_TABLE_TAG]; // The tag to which is linked (0=none) cmsUInt32Number TagSizes[MAX_TABLE_TAG]; // Size on disk cmsUInt32Number TagOffsets[MAX_TABLE_TAG]; cmsBool TagSaveAsRaw[MAX_TABLE_TAG]; // True to write uncooked @@ -824,6 +837,8 @@ cmsStage* _cmsStageNormalizeFromLabFloat(cmsContext ContextID); cmsStage* _cmsStageNormalizeFromXyzFloat(cmsContext ContextID); cmsStage* _cmsStageNormalizeToLabFloat(cmsContext ContextID); cmsStage* _cmsStageNormalizeToXyzFloat(cmsContext ContextID); +cmsStage* _cmsStageClipNegatives(cmsContext ContextID, int nChannels); + // For curve set only cmsToneCurve** _cmsStageGetPtrToCurveSet(const cmsStage* mpe); @@ -952,7 +967,7 @@ typedef struct _cmstransform_struct { cmsUInt32Number InputFormat, OutputFormat; // Keep formats for further reference // Points to transform code - _cmsTransformFn xform; + _cmsTransform2Fn xform; // Formatters, cannot be embedded into LUT because cache cmsFormatter16 FromInput; @@ -998,9 +1013,20 @@ typedef struct _cmstransform_struct { void* UserData; _cmsFreeUserDataFn FreeUserData; + // A way to provide backwards compatibility with full xform plugins + _cmsTransformFn OldXform; + } _cmsTRANSFORM; -// -------------------------------------------------------------------------------------------------- +// Copies extra channels from input to output if the original flags in the transform structure +// instructs to do so. This function is called on all standard transform functions. +void _cmsHandleExtraChannels(_cmsTRANSFORM* p, const void* in, + void* out, + cmsUInt32Number PixelsPerLine, + cmsUInt32Number LineCount, + const cmsStride* Stride); + +// ----------------------------------------------------------------------------------------------------------------------- cmsHTRANSFORM _cmsChain2Lab(cmsContext ContextID, cmsUInt32Number nProfiles, @@ -1029,4 +1055,3 @@ cmsBool _cmsBuildRGB2XYZtransferMatrix(cmsMAT3* r, const cmsCIExyY* WhitePoint #define _lcms_internal_H #endif -//<<<+++OPENSOURCE_MUST_END -- cgit v1.2.3