diff options
60 files changed, 3219 insertions, 1769 deletions
@@ -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 |