summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNicolas Pena <npm@chromium.org>2017-08-14 10:36:01 -0400
committerChromium commit bot <commit-bot@chromium.org>2017-08-14 15:02:17 +0000
commit0bd847232a1f430c70dd9d8df177ce68a3cde010 (patch)
tree15cec8c11493549f1974ae2f6aeac58234c176d2
parentdff02cee2d2410d81a55c59345fb38b5aac8a457 (diff)
downloadpdfium-0bd847232a1f430c70dd9d8df177ce68a3cde010.tar.xz
LCMS: upgrade to 2.8
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 <npm@chromium.org> Reviewed-by: dsinclair <dsinclair@chromium.org>
-rw-r--r--DEPS2
-rw-r--r--third_party/BUILD.gn1
-rw-r--r--third_party/lcms/0000-cmserr-changes.patch285
-rw-r--r--third_party/lcms/0001-fix-include.patch13
-rw-r--r--third_party/lcms/0001-from16-to-8-overflow.patch13
-rw-r--r--third_party/lcms/0002-old-performance-fix.patch13
-rw-r--r--third_party/lcms/0003-old-uninitialized-in-LUTevalFloat.patch13
-rw-r--r--third_party/lcms/0004-old-uninitialized-in-LUTeval16.patch13
-rw-r--r--third_party/lcms/0005-old-fix-e-with-tilde.patch61
-rw-r--r--third_party/lcms/0006-tag-type-confusion.patch (renamed from third_party/lcms/0000-tag-type-confusion.patch)0
-rw-r--r--third_party/lcms/0008-infinite-loop-GrowNamedColorList.patch (renamed from third_party/lcms/0002-infinite-loop-GrowNamedColorList.patch)24
-rw-r--r--third_party/lcms/0009-uninit.patch (renamed from third_party/lcms/0003-uninit.patch)15
-rw-r--r--third_party/lcms/0010-memory-leak-Type_Curve_Read.patch (renamed from third_party/lcms/0004-memory-leak-Type_Curve_Read.patch)0
-rw-r--r--third_party/lcms/0011-memory-leak-AllocEmptyTransform.patch (renamed from third_party/lcms/0005-memory-leak-AllocEmptyTransform.patch)26
-rw-r--r--third_party/lcms/0012-memory-leak-Type_NamedColor_Read.patch (renamed from third_party/lcms/0006-memory-leak-Type_NamedColor_Read.patch)10
-rw-r--r--third_party/lcms/0013-memory-leak-OptimizeByResampling.patch (renamed from third_party/lcms/0007-memory-leak-OptimizeByResampling.patch)0
-rw-r--r--third_party/lcms/0014-memory-leak-Type_MPEmatrix_Read.patch (renamed from third_party/lcms/0008-memory-leak-Type_MPEmatrix_Read.patch)0
-rw-r--r--third_party/lcms/0015-cmsStageAllocMatrix-param-swap.patch (renamed from third_party/lcms/0009-cmsStageAllocMatrix-param-swap.patch)0
-rw-r--r--third_party/lcms/0016-reject-nan.patch (renamed from third_party/lcms/0010-reject-nan.patch)4
-rw-r--r--third_party/lcms/0017-memory-leak-ReadSegmentedCurve.patch (renamed from third_party/lcms/0011-memory-leak-ReadSegmentedCurve.patch)0
-rw-r--r--third_party/lcms/0018-backport-c0a98d86.patch (renamed from third_party/lcms/0012-backport-c0a98d86.patch)2
-rw-r--r--third_party/lcms/0019-utf8.patch (renamed from third_party/lcms/0013-utf8.patch)57
-rw-r--r--third_party/lcms/0020-avoid-fixed-inf.patch (renamed from third_party/lcms/0014-avoid-fixed-inf.patch)26
-rw-r--r--third_party/lcms/0021-sanitize-float-read.patch (renamed from third_party/lcms/0015-sanitize-float-read.patch)0
-rw-r--r--third_party/lcms/0022-check-LUT-and-MPE.patch (renamed from third_party/lcms/0016-check-LUT-and-MPE.patch)6
-rw-r--r--third_party/lcms/0023-upstream-integer-overflow-MPEmatrix_Read.patch (renamed from third_party/lcms/0017-upstream-integer-overflow-MPEmatrix_Read.patch)0
-rw-r--r--third_party/lcms/0024-verify-size-before-reading.patch (renamed from third_party/lcms/0018-verify-size-before-reading.patch)0
-rw-r--r--third_party/lcms/0025-upstream-direct-leak-Type_MPE_Read.patch (renamed from third_party/lcms/0019-upstream-direct-leak-Type_MPE_Read.patch)0
-rw-r--r--third_party/lcms/0026-more-unsupported-characters.patch73
-rw-r--r--third_party/lcms/0027-changes-from-beginning-of-time.patch152
-rw-r--r--third_party/lcms/README.pdfium50
-rw-r--r--third_party/lcms/include/lcms2.h113
-rw-r--r--third_party/lcms/include/lcms2_plugin.h42
-rw-r--r--third_party/lcms/src/cmsalpha.c518
-rw-r--r--third_party/lcms/src/cmscam02.c2
-rw-r--r--third_party/lcms/src/cmscgats.c43
-rw-r--r--third_party/lcms/src/cmscnvrt.c33
-rw-r--r--third_party/lcms/src/cmserr.c318
-rw-r--r--third_party/lcms/src/cmsgamma.c55
-rw-r--r--third_party/lcms/src/cmsgmt.c1180
-rw-r--r--third_party/lcms/src/cmshalf.c5
-rw-r--r--third_party/lcms/src/cmsintrp.c8
-rw-r--r--third_party/lcms/src/cmsio0.c117
-rw-r--r--third_party/lcms/src/cmsio1.c75
-rw-r--r--third_party/lcms/src/cmslut.c33
-rw-r--r--third_party/lcms/src/cmsmd5.c30
-rw-r--r--third_party/lcms/src/cmsmtrx.c5
-rw-r--r--third_party/lcms/src/cmsnamed.c81
-rw-r--r--third_party/lcms/src/cmsopt.c273
-rw-r--r--third_party/lcms/src/cmspack.c341
-rw-r--r--third_party/lcms/src/cmspcs.c17
-rw-r--r--third_party/lcms/src/cmsplugin.c57
-rw-r--r--third_party/lcms/src/cmsps2.c17
-rw-r--r--third_party/lcms/src/cmssamp.c29
-rw-r--r--third_party/lcms/src/cmssm.c12
-rw-r--r--third_party/lcms/src/cmstypes.c90
-rw-r--r--third_party/lcms/src/cmsvirt.c50
-rw-r--r--third_party/lcms/src/cmswtpnt.c4
-rw-r--r--third_party/lcms/src/cmsxform.c518
-rw-r--r--third_party/lcms/src/lcms2_internal.h63
60 files changed, 3219 insertions, 1769 deletions
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/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-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/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-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<E9>
++// 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<E9>, 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<E9>, 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<E9>, 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<E9>
++ p ->xform = PrecalculatedXFORMGamutCheck; // Gamut check, no cache
+ else
+- p ->xform = PrecalculatedXFORM; // No cach<E9>, no gamut check
++ p ->xform = PrecalculatedXFORM; // No cache, no gamut check
+ }
+ else {
+
+ if (*dwFlags & cmsFLAGS_GAMUTCHECK)
+- p ->xform = CachedXFORMGamutCheck; // Gamut check, cach<E9>
++ p ->xform = CachedXFORMGamutCheck; // Gamut check, cache
+ else
+- p ->xform = CachedXFORM; // No gamut check, cach<E9>
++ p ->xform = CachedXFORM; // No gamut check, cache
+
+ }
+ }
diff --git a/third_party/lcms/0000-tag-type-confusion.patch b/third_party/lcms/0006-tag-type-confusion.patch
index 97d3c7f4d9..97d3c7f4d9 100644
--- a/third_party/lcms/0000-tag-type-confusion.patch
+++ b/third_party/lcms/0006-tag-type-confusion.patch
diff --git a/third_party/lcms/0002-infinite-loop-GrowNamedColorList.patch b/third_party/lcms/0008-infinite-loop-GrowNamedColorList.patch
index 2a6f3df6c7..eabf6a938d 100644
--- a/third_party/lcms/0002-infinite-loop-GrowNamedColorList.patch
+++ b/third_party/lcms/0008-infinite-loop-GrowNamedColorList.patch
@@ -1,34 +1,28 @@
diff --git a/third_party/lcms/src/cmsnamed.c b/third_party/lcms/src/cmsnamed.c
-index acfd1c8..ef1eb30 100644
+index 9b27ca0cc..9ed4cad39 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;
+@@ -540,7 +540,10 @@ cmsNAMEDCOLORLIST* CMSEXPORT cmsAllocNamedColorList(cmsContext ContextID, cmsUIn
v ->ContextID = ContextID;
-- while (v -> Allocated < n)
-- GrowNamedColorList(v);
-+ while (v -> Allocated < n) {
+ while (v -> Allocated < n){
+- if (!GrowNamedColorList(v)) return NULL;
+ 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;
+@@ -571,7 +574,10 @@ cmsNAMEDCOLORLIST* CMSEXPORT cmsDupNamedColorList(const cmsNAMEDCOLORLIST* v)
// For really large tables we need this
-- while (NewNC ->Allocated < v ->Allocated)
-- GrowNamedColorList(NewNC);
-+ while (NewNC ->Allocated < v ->Allocated) {
+ 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));
- memmove(NewNC ->Suffix, v ->Suffix, sizeof(v ->Suffix));
diff --git a/third_party/lcms/0003-uninit.patch b/third_party/lcms/0009-uninit.patch
index 4017c0150b..e9538c1f22 100644
--- a/third_party/lcms/0003-uninit.patch
+++ b/third_party/lcms/0009-uninit.patch
@@ -1,8 +1,9 @@
+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 06742b5..44c5b87 100644
+index cb618600a..2a0ea9448 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
+@@ -2966,7 +2966,7 @@ void *Type_ColorantTable_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER
{
cmsUInt32Number i, Count;
cmsNAMEDCOLORLIST* List;
@@ -11,7 +12,7 @@ index 06742b5..44c5b87 100644
cmsUInt16Number PCS[3];
-@@ -2979,7 +2979,7 @@ void *Type_ColorantTable_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER
+@@ -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;
@@ -20,11 +21,3 @@ index 06742b5..44c5b87 100644
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/0010-memory-leak-Type_Curve_Read.patch
index 7edc7f9e0f..7edc7f9e0f 100644
--- a/third_party/lcms/0004-memory-leak-Type_Curve_Read.patch
+++ b/third_party/lcms/0010-memory-leak-Type_Curve_Read.patch
diff --git a/third_party/lcms/0005-memory-leak-AllocEmptyTransform.patch b/third_party/lcms/0011-memory-leak-AllocEmptyTransform.patch
index 481d421292..332519601e 100644
--- a/third_party/lcms/0005-memory-leak-AllocEmptyTransform.patch
+++ b/third_party/lcms/0011-memory-leak-AllocEmptyTransform.patch
@@ -1,20 +1,20 @@
diff --git a/third_party/lcms/src/cmsxform.c b/third_party/lcms/src/cmsxform.c
-index eddb9bd..6466d27 100644
+index 9c20c49b0..b3802f0d5 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,
+@@ -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;
-+ }
+ // 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,
+ // 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");
@@ -23,7 +23,7 @@ index eddb9bd..6466d27 100644
return NULL;
}
-@@ -673,7 +676,7 @@ _cmsTRANSFORM* AllocEmptyTransform(cmsContext ContextID, cmsPipeline* lut,
+@@ -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");
diff --git a/third_party/lcms/0006-memory-leak-Type_NamedColor_Read.patch b/third_party/lcms/0012-memory-leak-Type_NamedColor_Read.patch
index f6fa010357..ce9e1bf5b6 100644
--- a/third_party/lcms/0006-memory-leak-Type_NamedColor_Read.patch
+++ b/third_party/lcms/0012-memory-leak-Type_NamedColor_Read.patch
@@ -1,8 +1,8 @@
diff --git a/third_party/lcms/src/cmstypes.c b/third_party/lcms/src/cmstypes.c
-index feba387..4d24fc2 100644
+index 941107e1a..f2119ae0a 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
+@@ -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);
@@ -11,12 +11,12 @@ index feba387..4d24fc2 100644
}
for (i=0; i < count; i++) {
-@@ -3111,7 +3111,7 @@ void *Type_NamedColor_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* 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;
+ Root[32] = 0; // To prevent exploits
+
if (!_cmsReadUInt16Array(io, 3, PCS)) goto Error;
- if (!_cmsReadUInt16Array(io, nDeviceCoords, Colorant)) goto Error;
diff --git a/third_party/lcms/0007-memory-leak-OptimizeByResampling.patch b/third_party/lcms/0013-memory-leak-OptimizeByResampling.patch
index 48645d1f01..48645d1f01 100644
--- a/third_party/lcms/0007-memory-leak-OptimizeByResampling.patch
+++ b/third_party/lcms/0013-memory-leak-OptimizeByResampling.patch
diff --git a/third_party/lcms/0008-memory-leak-Type_MPEmatrix_Read.patch b/third_party/lcms/0014-memory-leak-Type_MPEmatrix_Read.patch
index 8cc477fb8e..8cc477fb8e 100644
--- a/third_party/lcms/0008-memory-leak-Type_MPEmatrix_Read.patch
+++ b/third_party/lcms/0014-memory-leak-Type_MPEmatrix_Read.patch
diff --git a/third_party/lcms/0009-cmsStageAllocMatrix-param-swap.patch b/third_party/lcms/0015-cmsStageAllocMatrix-param-swap.patch
index 04f854398c..04f854398c 100644
--- a/third_party/lcms/0009-cmsStageAllocMatrix-param-swap.patch
+++ b/third_party/lcms/0015-cmsStageAllocMatrix-param-swap.patch
diff --git a/third_party/lcms/0010-reject-nan.patch b/third_party/lcms/0016-reject-nan.patch
index 8aa325a749..c2b5068645 100644
--- a/third_party/lcms/0010-reject-nan.patch
+++ b/third_party/lcms/0016-reject-nan.patch
@@ -1,11 +1,11 @@
diff --git a/third_party/lcms/src/cmsplugin.c b/third_party/lcms/src/cmsplugin.c
-index 8903d2b..b95befb 100644
+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*) &tmp;
+ *n = *(cmsFloat32Number*) (void*) &tmp;
+ if (isnan(*n))
+ return FALSE;
}
diff --git a/third_party/lcms/0011-memory-leak-ReadSegmentedCurve.patch b/third_party/lcms/0017-memory-leak-ReadSegmentedCurve.patch
index 472bcadf05..472bcadf05 100644
--- a/third_party/lcms/0011-memory-leak-ReadSegmentedCurve.patch
+++ b/third_party/lcms/0017-memory-leak-ReadSegmentedCurve.patch
diff --git a/third_party/lcms/0012-backport-c0a98d86.patch b/third_party/lcms/0018-backport-c0a98d86.patch
index 3835b0d6cc..34b5477b34 100644
--- a/third_party/lcms/0012-backport-c0a98d86.patch
+++ b/third_party/lcms/0018-backport-c0a98d86.patch
@@ -47,7 +47,7 @@ index 04dd0c4..386439b 100644
+ 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/0013-utf8.patch b/third_party/lcms/0019-utf8.patch
index c143aa8793..351659d409 100644
--- a/third_party/lcms/0013-utf8.patch
+++ b/third_party/lcms/0019-utf8.patch
@@ -1,96 +1,95 @@
diff --git a/third_party/lcms/src/cmscgats.c b/third_party/lcms/src/cmscgats.c
-index 9017435..5720c66 100644
+index 6011fb201..d53360b1f 100644
--- a/third_party/lcms/src/cmscgats.c
+++ b/third_party/lcms/src/cmscgats.c
-@@ -258,7 +258,7 @@ static PROPERTY PredefinedProperties[] = {
+@@ -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 “black? “white? or {"na".
+- // 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
-@@ -274,7 +274,7 @@ static PROPERTY PredefinedProperties[] = {
+@@ -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? “white? “none?or “na?
-+ // values are "yes" "white" "none" or "na"
+- // 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 386439b..e5ed06c 100644
+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);
- // 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
+ // 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
-@@ -3064,9 +3064,10 @@ void Type_ColorantTable_Free(struct _cms_typehandler_struct* self, void* Ptr)
+@@ -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’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<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.
+ //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.
-@@ -3809,7 +3810,8 @@ void Type_Screening_Free(struct _cms_typehandler_struct* self, void* Ptr)
+@@ -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 ’absolute?illuminant white point tristimulus values and CIE ’absolute?//surround tristimulus values.
+-//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.
+ //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)
+@@ -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 –Infinity, and the last curve segment always ends at +Infinity. The
+-// 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 b324c99..d19ace1 100644
+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’sRGB,G’sRGB, B’sRGB < 0.04045
+-//If R<92>sRGB,G<92>sRGB, B<92>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<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’sRGB,G’sRGB, B’sRGB >= 0.04045
+-//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’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<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
diff --git a/third_party/lcms/0014-avoid-fixed-inf.patch b/third_party/lcms/0020-avoid-fixed-inf.patch
index b7960e6885..b2397d73f9 100644
--- a/third_party/lcms/0014-avoid-fixed-inf.patch
+++ b/third_party/lcms/0020-avoid-fixed-inf.patch
@@ -1,8 +1,8 @@
diff --git a/third_party/lcms/src/cmsopt.c b/third_party/lcms/src/cmsopt.c
-index 684910d..76de015 100644
+index e4a7e4521..23aa54402 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[],
+@@ -1546,7 +1546,7 @@ void MatShaperEval16(register const cmsUInt16Number In[],
// This table converts from 8 bits to 1.14 after applying the curve
static
@@ -11,7 +11,7 @@ index 684910d..76de015 100644
{
int i;
cmsFloat32Number R, y;
-@@ -1452,14 +1452,17 @@ void FillFirstShaper(cmsS1Fixed14Number* Table, cmsToneCurve* Curve)
+@@ -1555,14 +1555,17 @@ void FillFirstShaper(cmsS1Fixed14Number* Table, cmsToneCurve* Curve)
R = (cmsFloat32Number) (i / 255.0);
y = cmsEvalToneCurveFloat(Curve, R);
@@ -30,7 +30,7 @@ index 684910d..76de015 100644
{
int i;
cmsFloat32Number R, Val;
-@@ -1468,6 +1471,8 @@ void FillSecondShaper(cmsUInt16Number* Table, cmsToneCurve* Curve, cmsBool Is8Bi
+@@ -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
@@ -39,7 +39,7 @@ index 684910d..76de015 100644
if (Is8BitsOutput) {
-@@ -1482,6 +1487,7 @@ void FillSecondShaper(cmsUInt16Number* Table, cmsToneCurve* Curve, cmsBool Is8Bi
+@@ -1585,6 +1590,7 @@ void FillSecondShaper(cmsUInt16Number* Table, cmsToneCurve* Curve, cmsBool Is8Bi
}
else Table[i] = _cmsQuickSaturateWord(Val * 65535.0);
}
@@ -47,7 +47,7 @@ index 684910d..76de015 100644
}
// Compute the matrix-shaper structure
-@@ -1499,13 +1505,19 @@ cmsBool SetMatShaper(cmsPipeline* Dest, cmsToneCurve* Curve1[3], cmsMAT3* Mat, c
+@@ -1602,13 +1608,19 @@ cmsBool SetMatShaper(cmsPipeline* Dest, cmsToneCurve* Curve1[3], cmsMAT3* Mat, c
p -> ContextID = Dest -> ContextID;
// Precompute tables
@@ -73,22 +73,22 @@ index 684910d..76de015 100644
// 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
+@@ -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;
++ 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
+@@ -1746,7 +1761,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))
+- SetMatShaper(Dest, mpeC1 ->TheCurves, &res, (cmsVEC3*) Offset, mpeC2->TheCurves, OutputFormat);
++ if (!SetMatShaper(Dest, mpeC1 ->TheCurves, &res, (cmsVEC3*) Offset, mpeC2->TheCurves, OutputFormat))
+ goto Error;
}
diff --git a/third_party/lcms/0015-sanitize-float-read.patch b/third_party/lcms/0021-sanitize-float-read.patch
index 568fd0e112..568fd0e112 100644
--- a/third_party/lcms/0015-sanitize-float-read.patch
+++ b/third_party/lcms/0021-sanitize-float-read.patch
diff --git a/third_party/lcms/0016-check-LUT-and-MPE.patch b/third_party/lcms/0022-check-LUT-and-MPE.patch
index e2efe5a3a7..04ddac81ed 100644
--- a/third_party/lcms/0016-check-LUT-and-MPE.patch
+++ b/third_party/lcms/0022-check-LUT-and-MPE.patch
@@ -43,7 +43,7 @@ index 9b0eb4b54..19d43361f 100644
+ prev = prev->Next;
+ }
}
-+ return TRUE;
++ return TRUE;
}
@@ -88,7 +88,7 @@ index 9b0eb4b54..19d43361f 100644
- BlessLUT(lut);
- return TRUE;
-+ return BlessLUT(lut);
++ return BlessLUT(lut);
}
// Unlink an element and return the pointer to it
@@ -106,7 +106,7 @@ index 9b0eb4b54..19d43361f 100644
- BlessLUT(l1);
- return TRUE;
-+ return BlessLUT(l1);
++ return BlessLUT(l1);
}
diff --git a/third_party/lcms/0017-upstream-integer-overflow-MPEmatrix_Read.patch b/third_party/lcms/0023-upstream-integer-overflow-MPEmatrix_Read.patch
index 70a6bb9b20..70a6bb9b20 100644
--- a/third_party/lcms/0017-upstream-integer-overflow-MPEmatrix_Read.patch
+++ b/third_party/lcms/0023-upstream-integer-overflow-MPEmatrix_Read.patch
diff --git a/third_party/lcms/0018-verify-size-before-reading.patch b/third_party/lcms/0024-verify-size-before-reading.patch
index e72e310a1b..e72e310a1b 100644
--- a/third_party/lcms/0018-verify-size-before-reading.patch
+++ b/third_party/lcms/0024-verify-size-before-reading.patch
diff --git a/third_party/lcms/0019-upstream-direct-leak-Type_MPE_Read.patch b/third_party/lcms/0025-upstream-direct-leak-Type_MPE_Read.patch
index 339333188a..339333188a 100644
--- a/third_party/lcms/0019-upstream-direct-leak-Type_MPE_Read.patch
+++ b/third_party/lcms/0025-upstream-direct-leak-Type_MPE_Read.patch
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<E9> does not help as it takes more time to deal with
+- // the cach<E9> 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<E9> does not help as it takes more time to deal with
+- // the cach<E9> 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 <io.h>
++//sunliang.liu modified 2010426 for wince error
++# ifndef _WIN32_WCE
++# include <io.h>
++# 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 <io.h>
-# endif
+# ifndef _WIN32_WCE
+# include <io.h>
+# 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