Upgrade to lcms 2.13.
Update 0000-cmserr-changes.patch to patch cleanly since upstream fixed a
typo. Remove 0034-uninitialized-reads.patch as it was recently
cherry-picked from upstream just before the 2.13 release.
Change-Id: I10020318f40faa4ad048675f133a635e1880b305
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/90172
Reviewed-by: Tom Sepez <tsepez@chromium.org>
Commit-Queue: Lei Zhang <thestig@chromium.org>
diff --git a/third_party/lcms/0000-cmserr-changes.patch b/third_party/lcms/0000-cmserr-changes.patch
index 31f56fd..13a854a 100644
--- a/third_party/lcms/0000-cmserr-changes.patch
+++ b/third_party/lcms/0000-cmserr-changes.patch
@@ -27,7 +27,7 @@
-
-// 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
+-// is up to the plug-in writer 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.
-
diff --git a/third_party/lcms/0034-uninitialized-reads.patch b/third_party/lcms/0034-uninitialized-reads.patch
deleted file mode 100644
index 303266e..0000000
--- a/third_party/lcms/0034-uninitialized-reads.patch
+++ /dev/null
@@ -1,161 +0,0 @@
-diff --git a/third_party/lcms/src/cmsintrp.c b/third_party/lcms/src/cmsintrp.c
-index 3d9a40530..22de3e550 100644
---- a/third_party/lcms/src/cmsintrp.c
-+++ b/third_party/lcms/src/cmsintrp.c
-@@ -200,8 +200,8 @@ void LinLerp1D(CMSREGISTER const cmsUInt16Number Value[],
- int val3;
- const cmsUInt16Number* LutTable = (cmsUInt16Number*) p ->Table;
-
-- // if last value...
-- if (Value[0] == 0xffff) {
-+ // if last value or just one point
-+ if (Value[0] == 0xffff || p->Domain[0] == 0) {
-
- Output[0] = LutTable[p -> Domain[0]];
- }
-@@ -240,7 +240,7 @@ void LinLerp1Dfloat(const cmsFloat32Number Value[],
- val2 = fclamp(Value[0]);
-
- // if last value...
-- if (val2 == 1.0) {
-+ if (val2 == 1.0 || p->Domain[0] == 0) {
- Output[0] = LutTable[p -> Domain[0]];
- }
- else
-@@ -274,20 +274,34 @@ void Eval1Input(CMSREGISTER const cmsUInt16Number Input[],
- cmsUInt32Number OutChan;
- const cmsUInt16Number* LutTable = (cmsUInt16Number*) p16 -> Table;
-
-- v = Input[0] * p16 -> Domain[0];
-- fk = _cmsToFixedDomain(v);
-
-- k0 = FIXED_TO_INT(fk);
-- rk = (cmsUInt16Number) FIXED_REST_TO_INT(fk);
-+ // if last value...
-+ if (Input[0] == 0xffff || p16->Domain[0] == 0) {
-+
-+ cmsUInt16Number y0 = LutTable[p16->Domain[0]];
-+
-+ for (OutChan = 0; OutChan < p16->nOutputs; OutChan++) {
-+ Output[OutChan] = y0;
-+ }
-+ }
-+ else
-+ {
-+
-+ v = Input[0] * p16->Domain[0];
-+ fk = _cmsToFixedDomain(v);
-+
-+ k0 = FIXED_TO_INT(fk);
-+ rk = (cmsUInt16Number)FIXED_REST_TO_INT(fk);
-
-- k1 = k0 + (Input[0] != 0xFFFFU ? 1 : 0);
-+ k1 = k0 + (Input[0] != 0xFFFFU ? 1 : 0);
-
-- K0 = p16 -> opta[0] * k0;
-- K1 = p16 -> opta[0] * k1;
-+ K0 = p16->opta[0] * k0;
-+ K1 = p16->opta[0] * k1;
-
-- for (OutChan=0; OutChan < p16->nOutputs; OutChan++) {
-+ for (OutChan = 0; OutChan < p16->nOutputs; OutChan++) {
-
-- Output[OutChan] = LinearInterp(rk, LutTable[K0+OutChan], LutTable[K1+OutChan]);
-+ Output[OutChan] = LinearInterp(rk, LutTable[K0 + OutChan], LutTable[K1 + OutChan]);
-+ }
- }
- }
-
-@@ -308,7 +322,7 @@ void Eval1InputFloat(const cmsFloat32Number Value[],
- val2 = fclamp(Value[0]);
-
- // if last value...
-- if (val2 == 1.0) {
-+ if (val2 == 1.0 || p->Domain[0] == 0) {
-
- y0 = LutTable[p->Domain[0]];
-
-diff --git a/third_party/lcms/src/cmsio0.c b/third_party/lcms/src/cmsio0.c
-index 743b958df..ff8c464fc 100644
---- a/third_party/lcms/src/cmsio0.c
-+++ b/third_party/lcms/src/cmsio0.c
-@@ -1538,8 +1538,12 @@ void* CMSEXPORT cmsReadTag(cmsHPROFILE hProfile, cmsTagSignature sig)
- if (!_cmsLockMutex(Icc->ContextID, Icc ->UsrMutex)) return NULL;
-
- n = _cmsSearchTag(Icc, sig, TRUE);
-- if (n < 0) goto Error; // Not found, return NULL
--
-+ if (n < 0)
-+ {
-+ // Not found, return NULL
-+ _cmsUnlockMutex(Icc->ContextID, Icc->UsrMutex);
-+ return NULL;
-+ }
-
- // If the element is already in memory, return the pointer
- if (Icc -> TagPtrs[n]) {
-diff --git a/third_party/lcms/src/cmstypes.c b/third_party/lcms/src/cmstypes.c
-index 825b11eb1..49207735b 100644
---- a/third_party/lcms/src/cmstypes.c
-+++ b/third_party/lcms/src/cmstypes.c
-@@ -3515,42 +3515,48 @@ void *Type_UcrBg_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cm
- {
- cmsUcrBg* n = (cmsUcrBg*) _cmsMallocZero(self ->ContextID, sizeof(cmsUcrBg));
- cmsUInt32Number CountUcr, CountBg;
-+ cmsInt32Number SignedSizeOfTag = (cmsInt32Number)SizeOfTag;
- char* ASCIIString;
-
- *nItems = 0;
- if (n == NULL) return NULL;
-
- // First curve is Under color removal
-+
-+ if (SignedSizeOfTag < sizeof(cmsUInt32Number)) return NULL;
- if (!_cmsReadUInt32Number(io, &CountUcr)) return NULL;
-- if (SizeOfTag < sizeof(cmsUInt32Number)) return NULL;
-- SizeOfTag -= sizeof(cmsUInt32Number);
-+ SignedSizeOfTag -= sizeof(cmsUInt32Number);
-
- n ->Ucr = cmsBuildTabulatedToneCurve16(self ->ContextID, CountUcr, NULL);
- if (n ->Ucr == NULL) return NULL;
-
-+ if (SignedSizeOfTag < (cmsInt32Number)CountUcr * sizeof(cmsUInt16Number)) return NULL;
- if (!_cmsReadUInt16Array(io, CountUcr, n ->Ucr->Table16)) return NULL;
-- if (SizeOfTag < sizeof(cmsUInt32Number)) return NULL;
-- SizeOfTag -= CountUcr * sizeof(cmsUInt16Number);
-+
-+ SignedSizeOfTag -= CountUcr * sizeof(cmsUInt16Number);
-
- // Second curve is Black generation
-+
-+ if (SignedSizeOfTag < sizeof(cmsUInt32Number)) return NULL;
- if (!_cmsReadUInt32Number(io, &CountBg)) return NULL;
-- if (SizeOfTag < sizeof(cmsUInt32Number)) return NULL;
-- SizeOfTag -= sizeof(cmsUInt32Number);
-+ SignedSizeOfTag -= sizeof(cmsUInt32Number);
-
- n ->Bg = cmsBuildTabulatedToneCurve16(self ->ContextID, CountBg, NULL);
- if (n ->Bg == NULL) return NULL;
-+
-+ if (SignedSizeOfTag < (cmsInt32Number) CountBg * sizeof(cmsUInt16Number)) return NULL;
- if (!_cmsReadUInt16Array(io, CountBg, n ->Bg->Table16)) return NULL;
-- if (SizeOfTag < CountBg * sizeof(cmsUInt16Number)) return NULL;
-- SizeOfTag -= CountBg * sizeof(cmsUInt16Number);
-- if (SizeOfTag == UINT_MAX) return NULL;
-+ SignedSizeOfTag -= CountBg * sizeof(cmsUInt16Number);
-+
-+ if (SignedSizeOfTag < 0 || SignedSizeOfTag > 32000) return NULL;
-
- // Now comes the text. The length is specified by the tag size
- n ->Desc = cmsMLUalloc(self ->ContextID, 1);
- if (n ->Desc == NULL) return NULL;
-
-- ASCIIString = (char*) _cmsMalloc(self ->ContextID, SizeOfTag + 1);
-- if (io ->Read(io, ASCIIString, sizeof(char), SizeOfTag) != SizeOfTag) return NULL;
-- ASCIIString[SizeOfTag] = 0;
-+ ASCIIString = (char*) _cmsMalloc(self ->ContextID, SignedSizeOfTag + 1);
-+ if (io ->Read(io, ASCIIString, sizeof(char), SignedSizeOfTag) != (cmsUInt32Number) SignedSizeOfTag) return NULL;
-+ ASCIIString[SignedSizeOfTag] = 0;
- cmsMLUsetASCII(n ->Desc, cmsNoLanguage, cmsNoCountry, ASCIIString);
- _cmsFree(self ->ContextID, ASCIIString);
-
diff --git a/third_party/lcms/README.pdfium b/third_party/lcms/README.pdfium
index 8a0fafb..e5c3645 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.9
+Version: 2.13
Security Critical: yes
License: MIT License
@@ -20,4 +20,3 @@
0029-drop-register-keyword.patch: Remove deprecated 'register' keyword.
0030-const-data.patch: Mark many data structures as const.
0033-opt-integer-overflow.patch: Protect against integer overflow.
-0034-uninitialized-reads.patch: Protect against corrupt profiles.
diff --git a/third_party/lcms/include/lcms2.h b/third_party/lcms/include/lcms2.h
index f60f5f7..11d0c53 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-2021 Marti Maria Saguer
+// Copyright (c) 1998-2022 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.12
+// Version 2.13
//
#ifndef _lcms2_H
@@ -81,7 +81,7 @@
#endif
// Version/release
-#define LCMS_VERSION 2120
+#define LCMS_VERSION 2130
// I will give the chance of redefining basic types for compilers that are not fully C99 compliant
#ifndef CMS_BASIC_TYPES_ALREADY_DEFINED
@@ -666,9 +666,10 @@
// Format of pixel is defined by one cmsUInt32Number, using bit fields as follows
//
// 2 1 0
-// 3 2 10987 6 5 4 3 2 1 098 7654 321
-// A O TTTTT U Y F P X S EEE CCCC BBB
+// 4 3 2 10987 6 5 4 3 2 1 098 7654 321
+// M A O TTTTT U Y F P X S EEE CCCC BBB
//
+// M: Premultiplied alpha (only works when extra samples is 1)
// A: Floating point -- With this flag we can differentiate 16 bits as float and as int
// O: Optimized -- previous optimization already returns the final 8-bit value
// T: Pixeltype
@@ -681,6 +682,7 @@
// B: bytes per sample
// Y: Swap first - changes ABGR to BGRA and KCMY to CMYK
+#define PREMUL_SH(m) ((m) << 23)
#define FLOAT_SH(a) ((a) << 22)
#define OPTIMIZED_SH(s) ((s) << 21)
#define COLORSPACE_SH(s) ((s) << 16)
@@ -694,6 +696,7 @@
#define BYTES_SH(b) (b)
// These macros unpack format specifiers into integers
+#define T_PREMUL(m) (((m)>>23)&1)
#define T_FLOAT(a) (((a)>>22)&1)
#define T_OPTIMIZED(o) (((o)>>21)&1)
#define T_COLORSPACE(s) (((s)>>16)&31)
@@ -722,7 +725,6 @@
#define PT_HSV 12
#define PT_HLS 13
#define PT_Yxy 14
-
#define PT_MCH1 15
#define PT_MCH2 16
#define PT_MCH3 17
@@ -738,7 +740,6 @@
#define PT_MCH13 27
#define PT_MCH14 28
#define PT_MCH15 29
-
#define PT_LabV2 30 // Identical to PT_Lab, but using the V2 old encoding
// Some (not all!) representations
@@ -752,7 +753,9 @@
#define TYPE_GRAY_16_REV (COLORSPACE_SH(PT_GRAY)|CHANNELS_SH(1)|BYTES_SH(2)|FLAVOR_SH(1))
#define TYPE_GRAY_16_SE (COLORSPACE_SH(PT_GRAY)|CHANNELS_SH(1)|BYTES_SH(2)|ENDIAN16_SH(1))
#define TYPE_GRAYA_8 (COLORSPACE_SH(PT_GRAY)|EXTRA_SH(1)|CHANNELS_SH(1)|BYTES_SH(1))
+#define TYPE_GRAYA_8_PREMUL (COLORSPACE_SH(PT_GRAY)|EXTRA_SH(1)|CHANNELS_SH(1)|BYTES_SH(1)|PREMUL_SH(1))
#define TYPE_GRAYA_16 (COLORSPACE_SH(PT_GRAY)|EXTRA_SH(1)|CHANNELS_SH(1)|BYTES_SH(2))
+#define TYPE_GRAYA_16_PREMUL (COLORSPACE_SH(PT_GRAY)|EXTRA_SH(1)|CHANNELS_SH(1)|BYTES_SH(2)|PREMUL_SH(1))
#define TYPE_GRAYA_16_SE (COLORSPACE_SH(PT_GRAY)|EXTRA_SH(1)|CHANNELS_SH(1)|BYTES_SH(2)|ENDIAN16_SH(1))
#define TYPE_GRAYA_8_PLANAR (COLORSPACE_SH(PT_GRAY)|EXTRA_SH(1)|CHANNELS_SH(1)|BYTES_SH(1)|PLANAR_SH(1))
#define TYPE_GRAYA_16_PLANAR (COLORSPACE_SH(PT_GRAY)|EXTRA_SH(1)|CHANNELS_SH(1)|BYTES_SH(2)|PLANAR_SH(1))
@@ -769,24 +772,32 @@
#define TYPE_BGR_16_SE (COLORSPACE_SH(PT_RGB)|CHANNELS_SH(3)|BYTES_SH(2)|DOSWAP_SH(1)|ENDIAN16_SH(1))
#define TYPE_RGBA_8 (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(1))
+#define TYPE_RGBA_8_PREMUL (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(1)|PREMUL_SH(1))
#define TYPE_RGBA_8_PLANAR (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(1)|PLANAR_SH(1))
#define TYPE_RGBA_16 (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(2))
+#define TYPE_RGBA_16_PREMUL (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(2)|PREMUL_SH(1))
#define TYPE_RGBA_16_PLANAR (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(2)|PLANAR_SH(1))
#define TYPE_RGBA_16_SE (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(2)|ENDIAN16_SH(1))
#define TYPE_ARGB_8 (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(1)|SWAPFIRST_SH(1))
+#define TYPE_ARGB_8_PREMUL (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(1)|SWAPFIRST_SH(1)|PREMUL_SH(1))
#define TYPE_ARGB_8_PLANAR (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(1)|SWAPFIRST_SH(1)|PLANAR_SH(1))
#define TYPE_ARGB_16 (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(2)|SWAPFIRST_SH(1))
+#define TYPE_ARGB_16_PREMUL (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(2)|SWAPFIRST_SH(1)|PREMUL_SH(1))
#define TYPE_ABGR_8 (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(1)|DOSWAP_SH(1))
+#define TYPE_ABGR_8_PREMUL (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(1)|DOSWAP_SH(1)|PREMUL_SH(1))
#define TYPE_ABGR_8_PLANAR (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(1)|DOSWAP_SH(1)|PLANAR_SH(1))
#define TYPE_ABGR_16 (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(2)|DOSWAP_SH(1))
+#define TYPE_ABGR_16_PREMUL (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(2)|DOSWAP_SH(1)|PREMUL_SH(1))
#define TYPE_ABGR_16_PLANAR (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(2)|DOSWAP_SH(1)|PLANAR_SH(1))
#define TYPE_ABGR_16_SE (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(2)|DOSWAP_SH(1)|ENDIAN16_SH(1))
#define TYPE_BGRA_8 (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(1)|DOSWAP_SH(1)|SWAPFIRST_SH(1))
+#define TYPE_BGRA_8_PREMUL (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(1)|DOSWAP_SH(1)|SWAPFIRST_SH(1)|PREMUL_SH(1))
#define TYPE_BGRA_8_PLANAR (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(1)|DOSWAP_SH(1)|SWAPFIRST_SH(1)|PLANAR_SH(1))
#define TYPE_BGRA_16 (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(2)|DOSWAP_SH(1)|SWAPFIRST_SH(1))
+#define TYPE_BGRA_16_PREMUL (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(2)|DOSWAP_SH(1)|SWAPFIRST_SH(1)|PREMUL_SH(1))
#define TYPE_BGRA_16_SE (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(2)|ENDIAN16_SH(1)|DOSWAP_SH(1)|SWAPFIRST_SH(1))
#define TYPE_CMY_8 (COLORSPACE_SH(PT_CMY)|CHANNELS_SH(3)|BYTES_SH(1))
@@ -903,7 +914,7 @@
#define TYPE_HSV_16_PLANAR (COLORSPACE_SH(PT_HSV)|CHANNELS_SH(3)|BYTES_SH(2)|PLANAR_SH(1))
#define TYPE_HSV_16_SE (COLORSPACE_SH(PT_HSV)|CHANNELS_SH(3)|BYTES_SH(2)|ENDIAN16_SH(1))
-// Named color index. Only 16 bits allowed (don't check colorspace)
+// Named color index. Only 16 bits is allowed (don't check colorspace)
#define TYPE_NAMED_COLOR_INDEX (CHANNELS_SH(1)|BYTES_SH(2))
// Float formatters.
@@ -911,13 +922,19 @@
#define TYPE_Lab_FLT (FLOAT_SH(1)|COLORSPACE_SH(PT_Lab)|CHANNELS_SH(3)|BYTES_SH(4))
#define TYPE_LabA_FLT (FLOAT_SH(1)|COLORSPACE_SH(PT_Lab)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(4))
#define TYPE_GRAY_FLT (FLOAT_SH(1)|COLORSPACE_SH(PT_GRAY)|CHANNELS_SH(1)|BYTES_SH(4))
+#define TYPE_GRAYA_FLT (FLOAT_SH(1)|COLORSPACE_SH(PT_GRAY)|CHANNELS_SH(1)|BYTES_SH(4)|EXTRA_SH(1))
+#define TYPE_GRAYA_FLT_PREMUL (FLOAT_SH(1)|COLORSPACE_SH(PT_GRAY)|CHANNELS_SH(1)|BYTES_SH(4)|EXTRA_SH(1)|PREMUL_SH(1))
#define TYPE_RGB_FLT (FLOAT_SH(1)|COLORSPACE_SH(PT_RGB)|CHANNELS_SH(3)|BYTES_SH(4))
#define TYPE_RGBA_FLT (FLOAT_SH(1)|COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(4))
+#define TYPE_RGBA_FLT_PREMUL (FLOAT_SH(1)|COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(4)|PREMUL_SH(1))
#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_ARGB_FLT_PREMUL (FLOAT_SH(1)|COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(4)|SWAPFIRST_SH(1)|PREMUL_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_BGRA_FLT_PREMUL (FLOAT_SH(1)|COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(4)|DOSWAP_SH(1)|SWAPFIRST_SH(1)|PREMUL_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_ABGR_FLT_PREMUL (FLOAT_SH(1)|COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(4)|DOSWAP_SH(1)|PREMUL_SH(1))
#define TYPE_CMYK_FLT (FLOAT_SH(1)|COLORSPACE_SH(PT_CMYK)|CHANNELS_SH(4)|BYTES_SH(4))
@@ -1256,6 +1273,7 @@
CMSAPI cmsUInt32Number CMSEXPORT cmsStageOutputChannels(const cmsStage* mpe);
CMSAPI cmsStageSignature CMSEXPORT cmsStageType(const cmsStage* mpe);
CMSAPI void* CMSEXPORT cmsStageData(const cmsStage* mpe);
+CMSAPI cmsContext CMSEXPORT cmsGetStageContextID(const cmsStage* mpe);
// Sampling
typedef cmsInt32Number (* cmsSAMPLER16) (CMSREGISTER const cmsUInt16Number In[],
@@ -1906,6 +1924,8 @@
// Estimate total area coverage
CMSAPI cmsFloat64Number CMSEXPORT cmsDetectTAC(cmsHPROFILE hProfile);
+// Estimate gamma space, always positive. Returns -1 on error.
+CMSAPI cmsFloat64Number CMSEXPORT cmsDetectRGBProfileGamma(cmsHPROFILE hProfile, cmsFloat64Number threshold);
// Poor man's gamut mapping
CMSAPI cmsBool CMSEXPORT cmsDesaturateLab(cmsCIELab* Lab,
diff --git a/third_party/lcms/include/lcms2_plugin.h b/third_party/lcms/include/lcms2_plugin.h
index 5bc8227..27fdb6a 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-2020 Marti Maria Saguer
+// Copyright (c) 1998-2022 Marti Maria Saguer
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the "Software"),
@@ -24,7 +24,7 @@
//---------------------------------------------------------------------------------
//
// This is the plug-in header file. Normal LittleCMS clients should not use it.
-// It is provided for plug-in writters that may want to access the support
+// It is provided for plug-in writers that may want to access the support
// functions to do low level operations. All plug-in related structures
// are defined here. Including this file forces to include the standard API too.
diff --git a/third_party/lcms/src/cmsalpha.c b/third_party/lcms/src/cmsalpha.c
index 36fdc9c..b34d82b 100644
--- a/third_party/lcms/src/cmsalpha.c
+++ b/third_party/lcms/src/cmsalpha.c
@@ -1,7 +1,7 @@
//---------------------------------------------------------------------------------
//
// Little Color Management System
-// Copyright (c) 1998-2020 Marti Maria Saguer
+// Copyright (c) 1998-2022 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"),
@@ -191,21 +191,21 @@
void fromFLTto8(void* dst, const void* src)
{
cmsFloat32Number n = *(cmsFloat32Number*)src;
- *(cmsUInt8Number*)dst = _cmsQuickSaturateByte(n * 255.0f);
+ *(cmsUInt8Number*)dst = _cmsQuickSaturateByte(n * 255.0);
}
static
void fromFLTto16(void* dst, const void* src)
{
cmsFloat32Number n = *(cmsFloat32Number*)src;
- *(cmsUInt16Number*)dst = _cmsQuickSaturateWord(n * 65535.0f);
+ *(cmsUInt16Number*)dst = _cmsQuickSaturateWord(n * 65535.0);
}
static
void fromFLTto16SE(void* dst, const void* src)
{
cmsFloat32Number n = *(cmsFloat32Number*)src;
- cmsUInt16Number i = _cmsQuickSaturateWord(n * 65535.0f);
+ cmsUInt16Number i = _cmsQuickSaturateWord(n * 65535.0);
*(cmsUInt16Number*)dst = CHANGE_ENDIAN(i);
}
@@ -243,7 +243,7 @@
{
#ifndef CMS_NO_HALF_SUPPORT
cmsFloat32Number n = _cmsHalf2Float(*(cmsUInt16Number*)src);
- *(cmsUInt8Number*)dst = _cmsQuickSaturateByte(n * 255.0f);
+ *(cmsUInt8Number*)dst = _cmsQuickSaturateByte(n * 255.0);
#else
cmsUNUSED_PARAMETER(dst);
cmsUNUSED_PARAMETER(src);
@@ -256,7 +256,7 @@
{
#ifndef CMS_NO_HALF_SUPPORT
cmsFloat32Number n = _cmsHalf2Float(*(cmsUInt16Number*)src);
- *(cmsUInt16Number*)dst = _cmsQuickSaturateWord(n * 65535.0f);
+ *(cmsUInt16Number*)dst = _cmsQuickSaturateWord(n * 65535.0);
#else
cmsUNUSED_PARAMETER(dst);
cmsUNUSED_PARAMETER(src);
@@ -268,7 +268,7 @@
{
#ifndef CMS_NO_HALF_SUPPORT
cmsFloat32Number n = _cmsHalf2Float(*(cmsUInt16Number*)src);
- cmsUInt16Number i = _cmsQuickSaturateWord(n * 65535.0f);
+ cmsUInt16Number i = _cmsQuickSaturateWord(n * 65535.0);
*(cmsUInt16Number*)dst = CHANGE_ENDIAN(i);
#else
cmsUNUSED_PARAMETER(dst);
@@ -414,9 +414,9 @@
cmsUInt32Number channelSize = trueBytesSize(Format);
cmsUInt32Number pixelSize = channelSize * total_chans;
- // Sanity check
- if (total_chans <= 0 || total_chans >= cmsMAXCHANNELS)
- return;
+ // Sanity check
+ if (total_chans <= 0 || total_chans >= cmsMAXCHANNELS)
+ return;
memset(channels, 0, sizeof(channels));
diff --git a/third_party/lcms/src/cmscam02.c b/third_party/lcms/src/cmscam02.c
index 5444b38..f7838ee 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-2020 Marti Maria Saguer
+// Copyright (c) 1998-2022 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 e0d5c12..241a88f 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-2020 Marti Maria Saguer
+// Copyright (c) 1998-2022 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"),
@@ -136,9 +136,18 @@
FILE* Stream; // File stream or NULL if holded in memory
} FILECTX;
-// This struct hold all information about an open IT8 handler.
+//Very simple string
typedef struct {
+ struct struct_it8* it8;
+ cmsInt32Number max;
+ cmsInt32Number len;
+ char* begin;
+ } string;
+
+
+// This struct hold all information about an open IT8 handler.
+typedef struct struct_it8 {
cmsUInt32Number TablesCount; // How many tables in this stream
cmsUInt32Number nTable; // The actual table
@@ -156,8 +165,8 @@
cmsInt32Number inum; // integer value
cmsFloat64Number dnum; // real value
- char id[MAXID]; // identifier
- char str[MAXSTR]; // string
+ string* id; // identifier
+ string* str; // string
// Allowed keywords & datasets. They have visibility on whole stream
KEYVALUE* ValidKeywords;
@@ -242,7 +251,7 @@
{"MATERIAL", WRITE_STRINGIFY}, // Identifies the material on which the target was produced using a code
// uniquely identifying th e material. This is intend ed to be used for IT8.7
- // physical targets only (i.e . IT8.7/1 a nd IT8.7/2).
+ // physical targets only (i.e . IT8.7/1 and IT8.7/2).
{"INSTRUMENTATION", WRITE_STRINGIFY}, // Used to report the specific instrumentation used (manufacturer and
// model number) to generate the data reported. This data will often
@@ -357,6 +366,59 @@
//Forward declaration of some internal functions
static void* AllocChunk(cmsIT8* it8, cmsUInt32Number size);
+static
+string* StringAlloc(cmsIT8* it8, int max)
+{
+ string* s = (string*) AllocChunk(it8, sizeof(string));
+
+ s->it8 = it8;
+ s->max = max;
+ s->len = 0;
+ s->begin = (char*) AllocChunk(it8, s->max);
+
+ return s;
+}
+
+static
+void StringClear(string* s)
+{
+ s->len = 0;
+}
+
+static
+void StringAppend(string* s, char c)
+{
+ if (s->len + 1 >= s->max)
+ {
+ char* new_ptr;
+
+ s->max *= 10;
+ new_ptr = AllocChunk(s->it8, s->max);
+ memcpy(new_ptr, s->begin, s->len);
+ s->begin = new_ptr;
+ }
+
+ s->begin[s->len++] = c;
+ s->begin[s->len] = 0;
+}
+
+static
+char* StringPtr(string* s)
+{
+ return s->begin;
+}
+
+static
+void StringCat(string* s, const char* c)
+{
+ while (*c)
+ {
+ StringAppend(s, *c);
+ c++;
+ }
+}
+
+
// Checks whatever c is a separator
static
cmsBool isseparator(int c)
@@ -682,14 +744,44 @@
}
+// Reads a string, special case to avoid infinite resursion on .include
+static
+void InStringSymbol(cmsIT8* it8)
+{
+ while (isseparator(it8->ch))
+ NextCh(it8);
+
+ if (it8->ch == '\'' || it8->ch == '\"')
+ {
+ int sng;
+
+ sng = it8->ch;
+ StringClear(it8->str);
+
+ NextCh(it8);
+
+ while (it8->ch != sng) {
+
+ if (it8->ch == '\n' || it8->ch == '\r' || it8->ch == 0) break;
+ else {
+ StringAppend(it8->str, (char)it8->ch);
+ NextCh(it8);
+ }
+ }
+
+ it8->sy = SSTRING;
+ NextCh(it8);
+ }
+ else
+ SynError(it8, "String expected");
+
+}
+
// Reads next symbol
static
void InSymbol(cmsIT8* it8)
{
- CMSREGISTER char *idptr;
- CMSREGISTER int k;
SYMBOL key;
- int sng;
do {
@@ -698,21 +790,18 @@
if (isfirstidchar(it8->ch)) { // Identifier
- k = 0;
- idptr = it8->id;
+ StringClear(it8->id);
do {
- if (++k < MAXID) *idptr++ = (char) it8->ch;
+ StringAppend(it8->id, (char) it8->ch);
NextCh(it8);
} while (isidchar(it8->ch));
- *idptr = '\0';
-
- key = BinSrchKey(it8->id);
+ key = BinSrchKey(StringPtr(it8->id));
if (key == SUNDEFINED) it8->sy = SIDENT;
else it8->sy = key;
@@ -808,26 +897,27 @@
if (isidchar(it8 ->ch)) {
+ char buffer[127];
+
if (it8 ->sy == SINUM) {
- snprintf(it8->id, 127, "%d", it8->inum);
+ snprintf(buffer, sizeof(buffer), "%d", it8->inum);
}
else {
- snprintf(it8->id, 127, it8 ->DoubleFormatter, it8->dnum);
+ snprintf(buffer, sizeof(buffer), it8 ->DoubleFormatter, it8->dnum);
}
- k = (int) strlen(it8 ->id);
- idptr = it8 ->id + k;
+ StringCat(it8->id, buffer);
+
do {
- if (++k < MAXID) *idptr++ = (char) it8->ch;
+ StringAppend(it8->id, (char) it8->ch);
NextCh(it8);
} while (isidchar(it8->ch));
- *idptr = '\0';
it8->sy = SIDENT;
}
return;
@@ -875,24 +965,7 @@
// String.
case '\'':
case '\"':
- idptr = it8->str;
- sng = it8->ch;
- k = 0;
- NextCh(it8);
-
- while (k < (MAXSTR-1) && it8->ch != sng) {
-
- if (it8->ch == '\n'|| it8->ch == '\r') k = MAXSTR+1;
- else {
- *idptr++ = (char) it8->ch;
- NextCh(it8);
- k++;
- }
- }
-
- it8->sy = SSTRING;
- *idptr = '\0';
- NextCh(it8);
+ InStringSymbol(it8);
break;
@@ -915,7 +988,7 @@
return;
}
- InSymbol(it8);
+ InStringSymbol(it8);
if (!Check(it8, SSTRING, "Filename expected")) return;
FileNest = it8 -> FileStack[it8 -> IncludeSP + 1];
@@ -926,7 +999,7 @@
// TODO: how to manage out-of-memory conditions?
}
- if (BuildAbsolutePath(it8->str,
+ if (BuildAbsolutePath(StringPtr(it8->str),
it8->FileStack[it8->IncludeSP]->FileName,
FileNest->FileName, cmsMAX_PATH-1) == FALSE) {
SynError(it8, "File path too long");
@@ -987,12 +1060,12 @@
case SEOLN: // Empty value
Buffer[0]=0;
break;
- case SIDENT: strncpy(Buffer, it8->id, max);
+ case SIDENT: strncpy(Buffer, StringPtr(it8->id), max);
Buffer[max-1]=0;
break;
case SINUM: snprintf(Buffer, max, "%d", it8 -> inum); break;
case SDNUM: snprintf(Buffer, max, it8->DoubleFormatter, it8 -> dnum); break;
- case SSTRING: strncpy(Buffer, it8->str, max);
+ case SSTRING: strncpy(Buffer, StringPtr(it8->str), max);
Buffer[max-1] = 0;
break;
@@ -1117,7 +1190,7 @@
ptr = (char *) AllocChunk(it8, Size);
- if (ptr) strncpy (ptr, str, Size-1);
+ if (ptr) memcpy(ptr, str, Size-1);
return ptr;
}
@@ -1316,6 +1389,9 @@
it8->IncludeSP = 0;
it8 -> lineno = 1;
+ it8->id = StringAlloc(it8, MAXSTR);
+ it8->str = StringAlloc(it8, MAXSTR);
+
strcpy(it8->DoubleFormatter, DEFAULT_DBL_FORMAT);
cmsIT8SetSheetType((cmsHANDLE) it8, "CGATS.17");
@@ -1507,6 +1583,25 @@
return atoi(b);
}
+// Convert to binary
+static
+const char* satob(const char* v)
+{
+ cmsUInt32Number x;
+ static char buf[33];
+ char *s = buf + 33;
+
+ if (v == NULL) return "0";
+
+ x = atoi(v);
+ *--s = 0;
+ if (!x) *--s = '0';
+ for (; x; x /= 2) *--s = '0' + x%2;
+
+ return s;
+}
+
+
static
void AllocateDataSet(cmsIT8* it8)
{
@@ -1692,7 +1787,7 @@
break;
case WRITE_BINARY:
- Writef(fp, "\t0x%B", satoi(p ->Value));
+ Writef(fp, "\t0b%s", satob(p ->Value));
break;
case WRITE_PAIR:
@@ -1862,7 +1957,7 @@
return SynError(it8, "Sample type expected");
}
- if (!SetDataFormat(it8, iField, it8->id)) return FALSE;
+ if (!SetDataFormat(it8, iField, StringPtr(it8->id))) return FALSE;
iField++;
InSymbol(it8);
@@ -1908,11 +2003,28 @@
if (it8->sy != SEND_DATA && it8->sy != SEOF) {
+ switch (it8->sy)
+ {
+
+ // To keep very long data
+ case SIDENT:
+ if (!SetData(it8, iSet, iField, StringPtr(it8->id)))
+ return FALSE;
+ break;
+
+ case SSTRING:
+ if (!SetData(it8, iSet, iField, StringPtr(it8->str)))
+ return FALSE;
+ break;
+
+ default:
+
if (!GetVal(it8, Buffer, 255, "Sample data expected"))
return FALSE;
if (!SetData(it8, iSet, iField, Buffer))
return FALSE;
+ }
iField++;
@@ -1968,7 +2080,7 @@
case SIDENT:
- strncpy(VarName, it8->id, MAXID - 1);
+ strncpy(VarName, StringPtr(it8->id), MAXID - 1);
VarName[MAXID - 1] = 0;
if (!IsAvailableOnList(it8->ValidKeywords, VarName, NULL, &Key)) {
@@ -2112,7 +2224,7 @@
// If a newline is found, then this is a type string
if (it8 ->ch == '\n' || it8->ch == '\r') {
- cmsIT8SetSheetType(it8, it8 ->id);
+ cmsIT8SetSheetType(it8, StringPtr(it8 ->id));
InSymbol(it8);
}
else
@@ -2124,7 +2236,7 @@
else
// Validate quoted strings
if (it8 ->sy == SSTRING) {
- cmsIT8SetSheetType(it8, it8 ->str);
+ cmsIT8SetSheetType(it8, StringPtr(it8 ->str));
InSymbol(it8);
}
}
diff --git a/third_party/lcms/src/cmscnvrt.c b/third_party/lcms/src/cmscnvrt.c
index b471da7..fe25525 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-2020 Marti Maria Saguer
+// Copyright (c) 1998-2022 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/cmserr.c b/third_party/lcms/src/cmserr.c
index eb96d25..c65dce5 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-2020 Marti Maria Saguer
+// Copyright (c) 1998-2022 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"),
@@ -166,7 +166,7 @@
// Sub allocation takes care of many pointers of small size. The memory allocated in
// this way have be freed at once. Next function allocates a single chunk for linked list
-// I prefer this method over realloc due to the big inpact on xput realloc may have if
+// I prefer this method over realloc due to the big impact on xput realloc may have if
// memory is being swapped to disk. This approach is safer (although that may not be true on all platforms)
static
_cmsSubAllocator_chunk* _cmsCreateSubAllocChunk(cmsContext ContextID, cmsUInt32Number Initial)
diff --git a/third_party/lcms/src/cmsgamma.c b/third_party/lcms/src/cmsgamma.c
index 08a7c22..dee1b4b 100644
--- a/third_party/lcms/src/cmsgamma.c
+++ b/third_party/lcms/src/cmsgamma.c
@@ -1,7 +1,7 @@
//---------------------------------------------------------------------------------
//
// Little Color Management System
-// Copyright (c) 1998-2020 Marti Maria Saguer
+// Copyright (c) 1998-2022 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"),
@@ -207,7 +207,7 @@
}
// Low level allocate, which takes care of memory details. nEntries may be zero, and in this case
-// no optimation curve is computed. nSegments may also be zero in the inverse case, where only the
+// no optimization curve is computed. nSegments may also be zero in the inverse case, where only the
// optimization curve is given. Both features simultaneously is an error
static
cmsToneCurve* AllocateToneCurveStruct(cmsContext ContextID, cmsUInt32Number nEntries,
@@ -507,28 +507,31 @@
// X=Y/c | Y< (ad+b)^g
case -4:
{
- if (fabs(Params[0]) < MATRIX_DET_TOLERANCE ||
- fabs(Params[1]) < MATRIX_DET_TOLERANCE ||
- fabs(Params[3]) < MATRIX_DET_TOLERANCE)
- {
- Val = 0;
- }
+
+ e = Params[1] * Params[4] + Params[2];
+ if (e < 0)
+ disc = 0;
else
- {
- e = Params[1] * Params[4] + Params[2];
- if (e < 0)
- disc = 0;
+ disc = pow(e, Params[0]);
+
+ if (R >= disc) {
+
+ if (fabs(Params[0]) < MATRIX_DET_TOLERANCE ||
+ fabs(Params[1]) < MATRIX_DET_TOLERANCE)
+
+ Val = 0;
+
else
- disc = pow(e, Params[0]);
-
- if (R >= disc) {
-
Val = (pow(R, 1.0 / Params[0]) - Params[2]) / Params[1];
- }
- else {
- Val = R / Params[3];
- }
}
+ else {
+
+ if (fabs(Params[3]) < MATRIX_DET_TOLERANCE)
+ Val = 0;
+ else
+ Val = R / Params[3];
+ }
+
}
break;
@@ -555,26 +558,29 @@
// X=(Y-f)/c | else
case -5:
{
- if (fabs(Params[1]) < MATRIX_DET_TOLERANCE ||
- fabs(Params[3]) < MATRIX_DET_TOLERANCE)
- {
- Val = 0;
- }
- else
- {
- disc = Params[3] * Params[4] + Params[6];
- if (R >= disc) {
+ disc = Params[3] * Params[4] + Params[6];
+ if (R >= disc) {
- e = R - Params[5];
- if (e < 0)
+ e = R - Params[5];
+ if (e < 0)
+ Val = 0;
+ else
+ {
+ if (fabs(Params[0]) < MATRIX_DET_TOLERANCE ||
+ fabs(Params[1]) < MATRIX_DET_TOLERANCE)
+
Val = 0;
else
Val = (pow(e, 1.0 / Params[0]) - Params[2]) / Params[1];
}
- else {
- Val = (R - Params[6]) / Params[3];
- }
}
+ else {
+ if (fabs(Params[3]) < MATRIX_DET_TOLERANCE)
+ Val = 0;
+ else
+ Val = (R - Params[6]) / Params[3];
+ }
+
}
break;
diff --git a/third_party/lcms/src/cmsgmt.c b/third_party/lcms/src/cmsgmt.c
index 7432137..70f2803 100644
--- a/third_party/lcms/src/cmsgmt.c
+++ b/third_party/lcms/src/cmsgmt.c
@@ -1,7 +1,7 @@
//---------------------------------------------------------------------------------
//
// Little Color Management System
-// Copyright (c) 1998-2020 Marti Maria Saguer
+// Copyright (c) 1998-2021 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"),
@@ -199,15 +199,15 @@
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
+ cmsFloat64Number Threshold; // The threshold 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
+// values with a transform going back and forth. Values above ERR_THRESHOLD
// of maximum are considered out of gamut.
-#define ERR_THERESHOLD 5
+#define ERR_THRESHOLD 5
static
@@ -246,17 +246,17 @@
// if dE1 is small and dE2 is small, value is likely to be in gamut
- if (dE1 < t->Thereshold && dE2 < t->Thereshold)
+ if (dE1 < t->Threshold && dE2 < t->Threshold)
Out[0] = 0;
else {
// if dE1 is small and dE2 is big, undefined. Assume in gamut
- if (dE1 < t->Thereshold && dE2 > t->Thereshold)
+ if (dE1 < t->Threshold && dE2 > t->Threshold)
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);
+ if (dE1 > t->Threshold && dE2 < t->Threshold)
+ Out[0] = (cmsUInt16Number) _cmsQuickFloor((dE1 - t->Threshold) + .5);
else {
// dE1 is big and dE2 is also big, could be due to perceptual mapping
@@ -266,8 +266,8 @@
else
ErrorRatio = dE1 / dE2;
- if (ErrorRatio > t->Thereshold)
- Out[0] = (cmsUInt16Number) _cmsQuickFloor((ErrorRatio - t->Thereshold) + .5);
+ if (ErrorRatio > t->Threshold)
+ Out[0] = (cmsUInt16Number) _cmsQuickFloor((ErrorRatio - t->Threshold) + .5);
else
Out[0] = 0;
}
@@ -323,10 +323,10 @@
if (cmsIsMatrixShaper(hGamut)) {
- Chain.Thereshold = 1.0;
+ Chain.Threshold = 1.0;
}
else {
- Chain.Thereshold = ERR_THERESHOLD;
+ Chain.Threshold = ERR_THRESHOLD;
}
@@ -588,3 +588,67 @@
return TRUE;
}
+
+// Detect whatever a given ICC profile works in linear (gamma 1.0) space
+// Actually, doing that "well" is quite hard, since every component may behave completely different.
+// Since the true point of this function is to detect suitable optimizations, I am imposing some requirements
+// that simplifies things: only RGB, and only profiles that can got in both directions.
+// The algorithm obtains Y from a syntetical gray R=G=B. Then least squares fitting is used to estimate gamma.
+// For gamma close to 1.0, RGB is linear. On profiles not supported, -1 is returned.
+
+cmsFloat64Number CMSEXPORT cmsDetectRGBProfileGamma(cmsHPROFILE hProfile, cmsFloat64Number threshold)
+{
+ cmsContext ContextID;
+ cmsHPROFILE hXYZ;
+ cmsHTRANSFORM xform;
+ cmsToneCurve* Y_curve;
+ cmsUInt16Number rgb[256][3];
+ cmsCIEXYZ XYZ[256];
+ cmsFloat32Number Y_normalized[256];
+ cmsFloat64Number gamma;
+ cmsProfileClassSignature cl;
+ int i;
+
+ if (cmsGetColorSpace(hProfile) != cmsSigRgbData)
+ return -1;
+
+ cl = cmsGetDeviceClass(hProfile);
+ if (cl != cmsSigInputClass && cl != cmsSigDisplayClass &&
+ cl != cmsSigOutputClass && cl != cmsSigColorSpaceClass)
+ return -1;
+
+ ContextID = cmsGetProfileContextID(hProfile);
+ hXYZ = cmsCreateXYZProfileTHR(ContextID);
+ xform = cmsCreateTransformTHR(ContextID, hProfile, TYPE_RGB_16, hXYZ, TYPE_XYZ_DBL,
+ INTENT_RELATIVE_COLORIMETRIC, cmsFLAGS_NOOPTIMIZE);
+
+ if (xform == NULL) { // If not RGB or forward direction is not supported, regret with the previous error
+
+ cmsCloseProfile(hXYZ);
+ return -1;
+ }
+
+ for (i = 0; i < 256; i++) {
+ rgb[i][0] = rgb[i][1] = rgb[i][2] = FROM_8_TO_16(i);
+ }
+
+ cmsDoTransform(xform, rgb, XYZ, 256);
+
+ cmsDeleteTransform(xform);
+ cmsCloseProfile(hXYZ);
+
+ for (i = 0; i < 256; i++) {
+ Y_normalized[i] = (cmsFloat32Number) XYZ[i].Y;
+ }
+
+ Y_curve = cmsBuildTabulatedToneCurveFloat(ContextID, 256, Y_normalized);
+ if (Y_curve == NULL)
+ return -1;
+
+ gamma = cmsEstimateGamma(Y_curve, threshold);
+
+ cmsFreeToneCurve(Y_curve);
+
+ return gamma;
+}
+
diff --git a/third_party/lcms/src/cmshalf.c b/third_party/lcms/src/cmshalf.c
index 52c0a2a..57cb5b0 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-2020 Marti Maria Saguer
+// Copyright (c) 1998-2022 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/cmsintrp.c b/third_party/lcms/src/cmsintrp.c
index 22de3e5..5cd6d16 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-2020 Marti Maria Saguer
+// Copyright (c) 1998-2022 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/cmsio0.c b/third_party/lcms/src/cmsio0.c
index ff8c464..0724eaa 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-2020 Marti Maria Saguer
+// Copyright (c) 1998-2022 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"),
@@ -479,10 +479,10 @@
cmsIOHANDLER* CMSEXPORT cmsGetProfileIOhandler(cmsHPROFILE hProfile)
{
- _cmsICCPROFILE* Icc = (_cmsICCPROFILE*)hProfile;
+ _cmsICCPROFILE* Icc = (_cmsICCPROFILE*)hProfile;
- if (Icc == NULL) return NULL;
- return Icc->IOhandler;
+ if (Icc == NULL) return NULL;
+ return Icc->IOhandler;
}
#ifdef _WIN32_WCE
@@ -496,7 +496,6 @@
// Creates an empty structure holding all required parameters
cmsHPROFILE CMSEXPORT cmsCreateProfilePlaceholder(cmsContext ContextID)
{
- time_t now = time(NULL);
_cmsICCPROFILE* Icc = (_cmsICCPROFILE*) _cmsMallocZero(ContextID, sizeof(_cmsICCPROFILE));
if (Icc == NULL) return NULL;
@@ -507,15 +506,20 @@
// Set default version
Icc ->Version = 0x02100000;
-
+
// Set creation date/time
- memmove(&Icc ->Created, gmtime(&now), sizeof(Icc ->Created));
+ if (!_cmsGetTime(&Icc->Created))
+ goto Error;
// Create a mutex if the user provided proper plugin. NULL otherwise
Icc ->UsrMutex = _cmsCreateMutex(ContextID);
// Return the handle
return (cmsHPROFILE) Icc;
+
+Error:
+ _cmsFree(ContextID, Icc);
+ return NULL;
}
cmsContext CMSEXPORT cmsGetProfileContextID(cmsHPROFILE hProfile)
@@ -1453,7 +1457,25 @@
return rc;
}
+// Free one tag contents
+static
+void freeOneTag(_cmsICCPROFILE* Icc, cmsUInt32Number i)
+{
+ if (Icc->TagPtrs[i]) {
+ cmsTagTypeHandler* TypeHandler = Icc->TagTypeHandlers[i];
+
+ if (TypeHandler != NULL) {
+ cmsTagTypeHandler LocalTypeHandler = *TypeHandler;
+
+ LocalTypeHandler.ContextID = Icc->ContextID;
+ LocalTypeHandler.ICCVersion = Icc->Version;
+ LocalTypeHandler.FreePtr(&LocalTypeHandler, Icc->TagPtrs[i]);
+ }
+ else
+ _cmsFree(Icc->ContextID, Icc->TagPtrs[i]);
+ }
+}
// Closes a profile freeing any involved resources
cmsBool CMSEXPORT cmsCloseProfile(cmsHPROFILE hProfile)
@@ -1473,20 +1495,7 @@
for (i=0; i < Icc -> TagCount; i++) {
- if (Icc -> TagPtrs[i]) {
-
- cmsTagTypeHandler* TypeHandler = Icc ->TagTypeHandlers[i];
-
- if (TypeHandler != NULL) {
- cmsTagTypeHandler LocalTypeHandler = *TypeHandler;
-
- LocalTypeHandler.ContextID = Icc ->ContextID; // As an additional parameters
- LocalTypeHandler.ICCVersion = Icc ->Version;
- LocalTypeHandler.FreePtr(&LocalTypeHandler, Icc -> TagPtrs[i]);
- }
- else
- _cmsFree(Icc ->ContextID, Icc ->TagPtrs[i]);
- }
+ freeOneTag(Icc, i);
}
if (Icc ->IOhandler != NULL) {
@@ -1526,7 +1535,7 @@
void* CMSEXPORT cmsReadTag(cmsHPROFILE hProfile, cmsTagSignature sig)
{
_cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile;
- cmsIOHANDLER* io = Icc ->IOhandler;
+ cmsIOHANDLER* io;
cmsTagTypeHandler* TypeHandler;
cmsTagTypeHandler LocalTypeHandler;
cmsTagDescriptor* TagDescriptor;
@@ -1571,6 +1580,7 @@
if (TagSize < 8) goto Error;
+ io = Icc ->IOhandler;
// Seek to its location
if (!io -> Seek(io, Offset))
goto Error;
@@ -1638,8 +1648,12 @@
return Icc -> TagPtrs[n];
- // Return error and unlock tha data
+ // Return error and unlock the data
Error:
+
+ freeOneTag(Icc, n);
+ Icc->TagPtrs[n] = NULL;
+
_cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex);
return NULL;
}
@@ -1805,7 +1819,7 @@
// It is already read?
if (Icc -> TagPtrs[i] == NULL) {
- // No yet, get original position
+ // Not yet, get original position
Offset = Icc ->TagOffsets[i];
TagSize = Icc ->TagSizes[i];
diff --git a/third_party/lcms/src/cmsio1.c b/third_party/lcms/src/cmsio1.c
index f2a3970..db18b9f 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-2020 Marti Maria Saguer
+// Copyright (c) 1998-2022 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"),
@@ -260,7 +260,7 @@
-// Read the DToAX tag, adjusting the encoding of Lab or XYZ if neded
+// Read the DToAX tag, adjusting the encoding of Lab or XYZ if needed
static
cmsPipeline* _cmsReadFloatInputTag(cmsHPROFILE hProfile, cmsTagSignature tagFloat)
{
@@ -536,7 +536,7 @@
}
-// Read the DToAX tag, adjusting the encoding of Lab or XYZ if neded
+// Read the DToAX tag, adjusting the encoding of Lab or XYZ if needed
static
cmsPipeline* _cmsReadFloatOutputTag(cmsHPROFILE hProfile, cmsTagSignature tagFloat)
{
@@ -661,7 +661,7 @@
// ---------------------------------------------------------------------------------------------------------------
-// Read the AToD0 tag, adjusting the encoding of Lab or XYZ if neded
+// Read the AToD0 tag, adjusting the encoding of Lab or XYZ if needed
static
cmsPipeline* _cmsReadFloatDevicelinkTag(cmsHPROFILE hProfile, cmsTagSignature tagFloat)
{
diff --git a/third_party/lcms/src/cmslut.c b/third_party/lcms/src/cmslut.c
index 04ece7f..49cc63b 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-2020 Marti Maria Saguer
+// Copyright (c) 1998-2022 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"),
@@ -1226,6 +1226,11 @@
return mpe -> Data;
}
+cmsContext CMSEXPORT cmsGetStageContextID(const cmsStage* mpe)
+{
+ return mpe -> ContextID;
+}
+
cmsStage* CMSEXPORT cmsStageNext(const cmsStage* mpe)
{
return mpe -> Next;
diff --git a/third_party/lcms/src/cmsmd5.c b/third_party/lcms/src/cmsmd5.c
index 88b2d77..f0af214 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-2020 Marti Maria Saguer
+// Copyright (c) 1998-2022 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/cmsmtrx.c b/third_party/lcms/src/cmsmtrx.c
index 9e05355..86a66f7 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-2020 Marti Maria Saguer
+// Copyright (c) 1998-2022 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/cmsnamed.c b/third_party/lcms/src/cmsnamed.c
index c0595dd..28e67f2 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-2020 Marti Maria Saguer
+// Copyright (c) 1998-2022 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"),
@@ -204,7 +204,7 @@
}
// Add an ASCII entry. Do not add any \0 termination (ICC1v43_2010-12.pdf page 61)
-// In the case the user explicitely sets an empty string, we force a \0
+// In the case the user explicitly sets an empty string, we force a \0
cmsBool CMSEXPORT cmsMLUsetASCII(cmsMLU* mlu, const char LanguageCode[3], const char CountryCode[3], const char* ASCIIString)
{
cmsUInt32Number i, len = (cmsUInt32Number) strlen(ASCIIString);
@@ -641,7 +641,7 @@
return NamedColorList ->nColors;
}
-// Info aboout a given color
+// Info about a given color
cmsBool CMSEXPORT cmsNamedColorInfo(const cmsNAMEDCOLORLIST* NamedColorList, cmsUInt32Number nColor,
char* Name,
char* Prefix,
diff --git a/third_party/lcms/src/cmsopt.c b/third_party/lcms/src/cmsopt.c
index 1f1173f..3eb8f62 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-2020 Marti Maria Saguer
+// Copyright (c) 1998-2022 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"),
@@ -680,7 +680,6 @@
{
cmsPipeline* Src = NULL;
cmsPipeline* Dest = NULL;
- cmsStage* mpe;
cmsStage* CLUT;
cmsStage *KeepPreLin = NULL, *KeepPostLin = NULL;
cmsUInt32Number nGridPoints;
@@ -702,7 +701,7 @@
if (ColorSpace == (cmsColorSpaceSignature)0 ||
OutputColorSpace == (cmsColorSpaceSignature)0) return FALSE;
- nGridPoints = _cmsReasonableGridpointsByColorspace(ColorSpace, *dwFlags);
+ nGridPoints = _cmsReasonableGridpointsByColorspace(ColorSpace, *dwFlags);
// For empty LUTs, 2 points are enough
if (cmsPipelineStageCount(*Lut) == 0)
@@ -710,13 +709,6 @@
Src = *Lut;
- // Named color pipelines cannot be optimized either
- for (mpe = cmsPipelineGetPtrToFirstStage(Src);
- mpe != NULL;
- mpe = cmsStageNext(mpe)) {
- if (cmsStageType(mpe) == cmsSigNamedColorElemType) return FALSE;
- }
-
// Allocate an empty LUT
Dest = cmsPipelineAlloc(Src ->ContextID, Src ->InputChannels, Src ->OutputChannels);
if (!Dest) return FALSE;
@@ -1084,7 +1076,6 @@
cmsStage* OptimizedCLUTmpe;
cmsColorSpaceSignature ColorSpace, OutputColorSpace;
cmsStage* OptimizedPrelinMpe;
- cmsStage* mpe;
cmsToneCurve** OptimizedPrelinCurves;
_cmsStageCLutData* OptimizedPrelinCLUT;
@@ -1105,14 +1096,7 @@
}
OriginalLut = *Lut;
-
- // Named color pipelines cannot be optimized either
- for (mpe = cmsPipelineGetPtrToFirstStage(OriginalLut);
- mpe != NULL;
- mpe = cmsStageNext(mpe)) {
- if (cmsStageType(mpe) == cmsSigNamedColorElemType) return FALSE;
- }
-
+
ColorSpace = _cmsICCcolorSpace((int) T_COLORSPACE(*InputFormat));
OutputColorSpace = _cmsICCcolorSpace((int) T_COLORSPACE(*OutputFormat));
@@ -1952,6 +1936,7 @@
_cmsOptimizationPluginChunkType* ctx = ( _cmsOptimizationPluginChunkType*) _cmsContextGetClientChunk(ContextID, OptimizationPlugin);
_cmsOptimizationCollection* Opts;
cmsBool AnySuccess = FALSE;
+ cmsStage* mpe;
// A CLUT is being asked, so force this specific optimization
if (*dwFlags & cmsFLAGS_FORCE_CLUT) {
@@ -1966,6 +1951,13 @@
return TRUE;
}
+ // Named color pipelines cannot be optimized
+ for (mpe = cmsPipelineGetPtrToFirstStage(*PtrLut);
+ mpe != NULL;
+ mpe = cmsStageNext(mpe)) {
+ if (cmsStageType(mpe) == cmsSigNamedColorElemType) return FALSE;
+ }
+
// Try to get rid of identities and trivial conversions.
AnySuccess = PreOptimize(*PtrLut);
diff --git a/third_party/lcms/src/cmspack.c b/third_party/lcms/src/cmspack.c
index 9510802..955687c 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-2020 Marti Maria Saguer
+// Copyright (c) 1998-2022 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"),
@@ -79,6 +79,7 @@
#define ANYSWAP DOSWAP_SH(1)
#define ANYSWAPFIRST SWAPFIRST_SH(1)
#define ANYFLAVOR FLAVOR_SH(1)
+#define ANYPREMUL PREMUL_SH(1)
// Suppress waning about info never being used
@@ -102,20 +103,40 @@
cmsUInt32Number Reverse = T_FLAVOR(info ->InputFormat);
cmsUInt32Number SwapFirst = T_SWAPFIRST(info -> InputFormat);
cmsUInt32Number Extra = T_EXTRA(info -> InputFormat);
+ cmsUInt32Number Premul = T_PREMUL(info->InputFormat);
+
cmsUInt32Number ExtraFirst = DoSwap ^ SwapFirst;
- cmsUInt16Number v;
- cmsUInt32Number i;
+ cmsUInt32Number v;
+ cmsUInt32Number i;
+ cmsUInt32Number alpha_factor = 1;
if (ExtraFirst) {
+
+ if (Premul && Extra)
+ alpha_factor = _cmsToFixedDomain(FROM_8_TO_16(accum[0]));
+
accum += Extra;
}
+ else
+ {
+ if (Premul && Extra)
+ alpha_factor = _cmsToFixedDomain(FROM_8_TO_16(accum[nChan]));
+ }
for (i=0; i < nChan; i++) {
+
cmsUInt32Number index = DoSwap ? (nChan - i - 1) : i;
v = FROM_8_TO_16(*accum);
v = Reverse ? REVERSE_FLAVOR_16(v) : v;
- wIn[index] = v;
+
+ if (Premul && alpha_factor > 0)
+ {
+ v = ((cmsUInt32Number)((cmsUInt32Number)v << 16) / alpha_factor);
+ if (v > 0xffff) v = 0xffff;
+ }
+
+ wIn[index] = (cmsUInt16Number) v;
accum++;
}
@@ -137,6 +158,7 @@
}
+
// Extra channels are just ignored because come in the next planes
static
cmsUInt8Number* UnrollPlanarBytes(CMSREGISTER _cmsTRANSFORM* info,
@@ -149,24 +171,47 @@
cmsUInt32Number SwapFirst = T_SWAPFIRST(info ->InputFormat);
cmsUInt32Number Reverse = T_FLAVOR(info ->InputFormat);
cmsUInt32Number i;
+ cmsUInt32Number ExtraFirst = DoSwap ^ SwapFirst;
+ cmsUInt32Number Extra = T_EXTRA(info->InputFormat);
+ cmsUInt32Number Premul = T_PREMUL(info->InputFormat);
cmsUInt8Number* Init = accum;
+ cmsUInt32Number alpha_factor = 1;
- if (DoSwap ^ SwapFirst) {
- accum += T_EXTRA(info -> InputFormat) * Stride;
+ if (ExtraFirst) {
+
+ if (Premul && Extra)
+ alpha_factor = _cmsToFixedDomain(FROM_8_TO_16(accum[0]));
+
+
+ accum += Extra * Stride;
+ }
+ else
+ {
+ if (Premul && Extra)
+ alpha_factor = _cmsToFixedDomain(FROM_8_TO_16(accum[(nChan) * Stride]));
}
for (i=0; i < nChan; i++) {
cmsUInt32Number index = DoSwap ? (nChan - i - 1) : i;
- cmsUInt16Number v = FROM_8_TO_16(*accum);
+ cmsUInt32Number v = FROM_8_TO_16(*accum);
+
+ v = Reverse ? REVERSE_FLAVOR_16(v) : v;
- wIn[index] = Reverse ? REVERSE_FLAVOR_16(v) : v;
+ if (Premul && alpha_factor > 0)
+ {
+ v = ((cmsUInt32Number)((cmsUInt32Number)v << 16) / alpha_factor);
+ if (v > 0xffff) v = 0xffff;
+ }
+
+ wIn[index] = (cmsUInt16Number) v;
accum += Stride;
}
return (Init + 1);
}
+
// Special cases, provided for performance
static
cmsUInt8Number* Unroll4Bytes(CMSREGISTER _cmsTRANSFORM* info,
@@ -517,6 +562,55 @@
cmsUNUSED_PARAMETER(Stride);
}
+
+static
+cmsUInt8Number* UnrollAnyWordsPremul(CMSREGISTER _cmsTRANSFORM* info,
+ CMSREGISTER cmsUInt16Number wIn[],
+ CMSREGISTER cmsUInt8Number* accum,
+ CMSREGISTER cmsUInt32Number Stride)
+{
+ cmsUInt32Number nChan = T_CHANNELS(info -> InputFormat);
+ cmsUInt32Number SwapEndian = T_ENDIAN16(info -> InputFormat);
+ cmsUInt32Number DoSwap = T_DOSWAP(info ->InputFormat);
+ cmsUInt32Number Reverse = T_FLAVOR(info ->InputFormat);
+ cmsUInt32Number SwapFirst = T_SWAPFIRST(info -> InputFormat);
+ cmsUInt32Number ExtraFirst = DoSwap ^ SwapFirst;
+ cmsUInt32Number i;
+
+ cmsUInt16Number alpha = (ExtraFirst ? accum[0] : accum[nChan - 1]);
+ cmsUInt32Number alpha_factor = _cmsToFixedDomain(FROM_8_TO_16(alpha));
+
+ if (ExtraFirst) {
+ accum += sizeof(cmsUInt16Number);
+ }
+
+ for (i=0; i < nChan; i++) {
+
+ cmsUInt32Number index = DoSwap ? (nChan - i - 1) : i;
+ cmsUInt32Number v = *(cmsUInt16Number*) accum;
+
+ if (SwapEndian)
+ v = CHANGE_ENDIAN(v);
+
+ v = (v << 16) / alpha_factor;
+ if (v > 0xffff) v = 0xffff;
+
+ wIn[index] = (cmsUInt16Number) (Reverse ? REVERSE_FLAVOR_16(v) : v);
+
+ accum += sizeof(cmsUInt16Number);
+ }
+
+ if (!ExtraFirst) {
+ accum += sizeof(cmsUInt16Number);
+ }
+
+ return accum;
+
+ cmsUNUSED_PARAMETER(Stride);
+}
+
+
+
static
cmsUInt8Number* UnrollPlanarWords(CMSREGISTER _cmsTRANSFORM* info,
CMSREGISTER cmsUInt16Number wIn[],
@@ -550,6 +644,46 @@
return (Init + sizeof(cmsUInt16Number));
}
+static
+cmsUInt8Number* UnrollPlanarWordsPremul(CMSREGISTER _cmsTRANSFORM* info,
+ CMSREGISTER cmsUInt16Number wIn[],
+ CMSREGISTER cmsUInt8Number* accum,
+ CMSREGISTER cmsUInt32Number Stride)
+{
+ cmsUInt32Number nChan = T_CHANNELS(info -> InputFormat);
+ cmsUInt32Number DoSwap= T_DOSWAP(info ->InputFormat);
+ cmsUInt32Number SwapFirst = T_SWAPFIRST(info->InputFormat);
+ cmsUInt32Number Reverse= T_FLAVOR(info ->InputFormat);
+ cmsUInt32Number SwapEndian = T_ENDIAN16(info -> InputFormat);
+ cmsUInt32Number i;
+ cmsUInt32Number ExtraFirst = DoSwap ^ SwapFirst;
+ cmsUInt8Number* Init = accum;
+
+ cmsUInt16Number alpha = (ExtraFirst ? accum[0] : accum[(nChan - 1) * Stride]);
+ cmsUInt32Number alpha_factor = _cmsToFixedDomain(FROM_8_TO_16(alpha));
+
+ if (ExtraFirst) {
+ accum += Stride;
+ }
+
+ for (i=0; i < nChan; i++) {
+
+ cmsUInt32Number index = DoSwap ? (nChan - i - 1) : i;
+ cmsUInt32Number v = (cmsUInt32Number) *(cmsUInt16Number*) accum;
+
+ if (SwapEndian)
+ v = CHANGE_ENDIAN(v);
+
+ v = (v << 16) / alpha_factor;
+ if (v > 0xffff) v = 0xffff;
+
+ wIn[index] = (cmsUInt16Number) (Reverse ? REVERSE_FLAVOR_16(v) : v);
+
+ accum += Stride;
+ }
+
+ return (Init + sizeof(cmsUInt16Number));
+}
static
cmsUInt8Number* Unroll4Words(CMSREGISTER _cmsTRANSFORM* info,
@@ -1087,6 +1221,110 @@
//-------------------------------------------------------------------------------------------------------------------
+// For anything going from cmsUInt8Number
+static
+cmsUInt8Number* Unroll8ToFloat(_cmsTRANSFORM* info,
+ cmsFloat32Number wIn[],
+ cmsUInt8Number* accum,
+ cmsUInt32Number Stride)
+{
+
+ cmsUInt32Number nChan = T_CHANNELS(info->InputFormat);
+ cmsUInt32Number DoSwap = T_DOSWAP(info->InputFormat);
+ cmsUInt32Number Reverse = T_FLAVOR(info->InputFormat);
+ cmsUInt32Number SwapFirst = T_SWAPFIRST(info->InputFormat);
+ cmsUInt32Number Extra = T_EXTRA(info->InputFormat);
+ cmsUInt32Number ExtraFirst = DoSwap ^ SwapFirst;
+ cmsUInt32Number Planar = T_PLANAR(info->InputFormat);
+ cmsFloat32Number v;
+ cmsUInt32Number i, start = 0;
+
+ Stride /= PixelSize(info->InputFormat);
+
+ if (ExtraFirst)
+ start = Extra;
+
+ for (i = 0; i < nChan; i++) {
+
+ cmsUInt32Number index = DoSwap ? (nChan - i - 1) : i;
+
+ if (Planar)
+ v = (cmsFloat32Number) ((cmsUInt8Number *)accum)[(i + start) * Stride];
+ else
+ v = (cmsFloat32Number) ((cmsUInt8Number *)accum)[i + start];
+
+ v /= 255.0F;
+
+ wIn[index] = Reverse ? 1 - v : v;
+ }
+
+
+ if (Extra == 0 && SwapFirst) {
+ cmsFloat32Number tmp = wIn[0];
+
+ memmove(&wIn[0], &wIn[1], (nChan - 1) * sizeof(cmsFloat32Number));
+ wIn[nChan - 1] = tmp;
+ }
+
+ if (T_PLANAR(info->InputFormat))
+ return accum + sizeof(cmsUInt8Number);
+ else
+ return accum + (nChan + Extra) * sizeof(cmsUInt8Number);
+}
+
+
+// For anything going from cmsUInt16Number
+static
+cmsUInt8Number* Unroll16ToFloat(_cmsTRANSFORM* info,
+ cmsFloat32Number wIn[],
+ cmsUInt8Number* accum,
+ cmsUInt32Number Stride)
+{
+
+ cmsUInt32Number nChan = T_CHANNELS(info->InputFormat);
+ cmsUInt32Number DoSwap = T_DOSWAP(info->InputFormat);
+ cmsUInt32Number Reverse = T_FLAVOR(info->InputFormat);
+ cmsUInt32Number SwapFirst = T_SWAPFIRST(info->InputFormat);
+ cmsUInt32Number Extra = T_EXTRA(info->InputFormat);
+ cmsUInt32Number ExtraFirst = DoSwap ^ SwapFirst;
+ cmsUInt32Number Planar = T_PLANAR(info->InputFormat);
+ cmsFloat32Number v;
+ cmsUInt32Number i, start = 0;
+
+ Stride /= PixelSize(info->InputFormat);
+
+ if (ExtraFirst)
+ start = Extra;
+
+ for (i = 0; i < nChan; i++) {
+
+ cmsUInt32Number index = DoSwap ? (nChan - i - 1) : i;
+
+ if (Planar)
+ v = (cmsFloat32Number)((cmsUInt16Number*)accum)[(i + start) * Stride];
+ else
+ v = (cmsFloat32Number)((cmsUInt16Number*)accum)[i + start];
+
+ v /= 65535.0F;
+
+ wIn[index] = Reverse ? 1 - v : v;
+ }
+
+
+ if (Extra == 0 && SwapFirst) {
+ cmsFloat32Number tmp = wIn[0];
+
+ memmove(&wIn[0], &wIn[1], (nChan - 1) * sizeof(cmsFloat32Number));
+ wIn[nChan - 1] = tmp;
+ }
+
+ if (T_PLANAR(info->InputFormat))
+ return accum + sizeof(cmsUInt16Number);
+ else
+ return accum + (nChan + Extra) * sizeof(cmsUInt16Number);
+}
+
+
// For anything going from cmsFloat32Number
static
cmsUInt8Number* UnrollFloatsToFloat(_cmsTRANSFORM* info,
@@ -1095,19 +1333,30 @@
cmsUInt32Number Stride)
{
- cmsUInt32Number nChan = T_CHANNELS(info -> InputFormat);
- cmsUInt32Number DoSwap = T_DOSWAP(info ->InputFormat);
- cmsUInt32Number Reverse = T_FLAVOR(info ->InputFormat);
- cmsUInt32Number SwapFirst = T_SWAPFIRST(info -> InputFormat);
- cmsUInt32Number Extra = T_EXTRA(info -> InputFormat);
+ cmsUInt32Number nChan = T_CHANNELS(info->InputFormat);
+ cmsUInt32Number DoSwap = T_DOSWAP(info->InputFormat);
+ cmsUInt32Number Reverse = T_FLAVOR(info->InputFormat);
+ cmsUInt32Number SwapFirst = T_SWAPFIRST(info->InputFormat);
+ cmsUInt32Number Extra = T_EXTRA(info->InputFormat);
cmsUInt32Number ExtraFirst = DoSwap ^ SwapFirst;
- cmsUInt32Number Planar = T_PLANAR(info -> InputFormat);
+ cmsUInt32Number Planar = T_PLANAR(info->InputFormat);
+ cmsUInt32Number Premul = T_PREMUL(info->InputFormat);
cmsFloat32Number v;
cmsUInt32Number i, start = 0;
- cmsFloat32Number maximum = IsInkSpace(info ->InputFormat) ? 100.0F : 1.0F;
+ cmsFloat32Number maximum = IsInkSpace(info->InputFormat) ? 100.0F : 1.0F;
+ cmsFloat32Number alpha_factor = 1.0f;
+ cmsFloat32Number* ptr = (cmsFloat32Number*)accum;
Stride /= PixelSize(info->InputFormat);
+ if (Premul && Extra)
+ {
+ if (Planar)
+ alpha_factor = (ExtraFirst ? ptr[0] : ptr[nChan * Stride]) / maximum;
+ else
+ alpha_factor = (ExtraFirst ? ptr[0] : ptr[nChan]) / maximum;
+ }
+
if (ExtraFirst)
start = Extra;
@@ -1116,9 +1365,12 @@
cmsUInt32Number index = DoSwap ? (nChan - i - 1) : i;
if (Planar)
- v = (cmsFloat32Number) ((cmsFloat32Number*) accum)[(i + start) * Stride];
+ v = ptr[(i + start) * Stride];
else
- v = (cmsFloat32Number) ((cmsFloat32Number*) accum)[i + start];
+ v = ptr[i + start];
+
+ if (Premul && alpha_factor > 0)
+ v /= alpha_factor;
v /= maximum;
@@ -1148,19 +1400,30 @@
cmsUInt32Number Stride)
{
- cmsUInt32Number nChan = T_CHANNELS(info -> InputFormat);
- cmsUInt32Number DoSwap = T_DOSWAP(info ->InputFormat);
- cmsUInt32Number Reverse = T_FLAVOR(info ->InputFormat);
- cmsUInt32Number SwapFirst = T_SWAPFIRST(info -> InputFormat);
- cmsUInt32Number Extra = T_EXTRA(info -> InputFormat);
+ cmsUInt32Number nChan = T_CHANNELS(info->InputFormat);
+ cmsUInt32Number DoSwap = T_DOSWAP(info->InputFormat);
+ cmsUInt32Number Reverse = T_FLAVOR(info->InputFormat);
+ cmsUInt32Number SwapFirst = T_SWAPFIRST(info->InputFormat);
+ cmsUInt32Number Extra = T_EXTRA(info->InputFormat);
cmsUInt32Number ExtraFirst = DoSwap ^ SwapFirst;
- cmsUInt32Number Planar = T_PLANAR(info -> InputFormat);
+ cmsUInt32Number Planar = T_PLANAR(info->InputFormat);
+ cmsUInt32Number Premul = T_PREMUL(info->InputFormat);
cmsFloat64Number v;
cmsUInt32Number i, start = 0;
cmsFloat64Number maximum = IsInkSpace(info ->InputFormat) ? 100.0 : 1.0;
+ cmsFloat64Number alpha_factor = 1.0;
+ cmsFloat64Number* ptr = (cmsFloat64Number*)accum;
Stride /= PixelSize(info->InputFormat);
+ if (Premul && Extra)
+ {
+ if (Planar)
+ alpha_factor = (ExtraFirst ? ptr[0] : ptr[(nChan) * Stride]) / maximum;
+ else
+ alpha_factor = (ExtraFirst ? ptr[0] : ptr[nChan]) / maximum;
+ }
+
if (ExtraFirst)
start = Extra;
@@ -1173,6 +1436,10 @@
else
v = (cmsFloat64Number) ((cmsFloat64Number*) accum)[i + start];
+
+ if (Premul && alpha_factor > 0)
+ v /= alpha_factor;
+
v /= maximum;
wIn[index] = (cmsFloat32Number) (Reverse ? 1.0 - v : v);
@@ -1254,8 +1521,6 @@
}
}
-
-
// 1.15 fixed point, that means maximum value is MAX_ENCODEABLE_XYZ (0xFFFF)
static
cmsUInt8Number* UnrollXYZDoubleToFloat(_cmsTRANSFORM* info,
@@ -1316,44 +1581,132 @@
}
+cmsINLINE void lab4toFloat(cmsFloat32Number wIn[], cmsUInt16Number lab4[3])
+{
+ cmsFloat32Number L = (cmsFloat32Number) lab4[0] / 655.35F;
+ cmsFloat32Number a = ((cmsFloat32Number) lab4[1] / 257.0F) - 128.0F;
+ cmsFloat32Number b = ((cmsFloat32Number) lab4[2] / 257.0F) - 128.0F;
+
+ wIn[0] = (L / 100.0F); // from 0..100 to 0..1
+ wIn[1] = ((a + 128.0F) / 255.0F); // form -128..+127 to 0..1
+ wIn[2] = ((b + 128.0F) / 255.0F);
+
+}
+
+static
+cmsUInt8Number* UnrollLabV2_8ToFloat(_cmsTRANSFORM* info,
+ cmsFloat32Number wIn[],
+ cmsUInt8Number* accum,
+ cmsUInt32Number Stride)
+{
+ cmsUInt16Number lab4[3];
+
+ lab4[0] = FomLabV2ToLabV4(FROM_8_TO_16(*accum)); accum++; // L
+ lab4[1] = FomLabV2ToLabV4(FROM_8_TO_16(*accum)); accum++; // a
+ lab4[2] = FomLabV2ToLabV4(FROM_8_TO_16(*accum)); accum++; // b
+
+ lab4toFloat(wIn, lab4);
+
+ return accum;
+
+ cmsUNUSED_PARAMETER(info);
+ cmsUNUSED_PARAMETER(Stride);
+}
+
+static
+cmsUInt8Number* UnrollALabV2_8ToFloat(_cmsTRANSFORM* info,
+ cmsFloat32Number wIn[],
+ cmsUInt8Number* accum,
+ cmsUInt32Number Stride)
+{
+ cmsUInt16Number lab4[3];
+
+ accum++; // A
+ lab4[0] = FomLabV2ToLabV4(FROM_8_TO_16(*accum)); accum++; // L
+ lab4[1] = FomLabV2ToLabV4(FROM_8_TO_16(*accum)); accum++; // a
+ lab4[2] = FomLabV2ToLabV4(FROM_8_TO_16(*accum)); accum++; // b
+
+ lab4toFloat(wIn, lab4);
+
+ return accum;
+
+ cmsUNUSED_PARAMETER(info);
+ cmsUNUSED_PARAMETER(Stride);
+}
+
+static
+cmsUInt8Number* UnrollLabV2_16ToFloat(_cmsTRANSFORM* info,
+ cmsFloat32Number wIn[],
+ cmsUInt8Number* accum,
+ cmsUInt32Number Stride)
+{
+ cmsUInt16Number lab4[3];
+
+ lab4[0] = FomLabV2ToLabV4(*(cmsUInt16Number*) accum); accum += 2; // L
+ lab4[1] = FomLabV2ToLabV4(*(cmsUInt16Number*) accum); accum += 2; // a
+ lab4[2] = FomLabV2ToLabV4(*(cmsUInt16Number*) accum); accum += 2; // b
+
+ lab4toFloat(wIn, lab4);
+
+ return accum;
+
+ cmsUNUSED_PARAMETER(info);
+ cmsUNUSED_PARAMETER(Stride);
+}
+
// Packing routines -----------------------------------------------------------------------------------------------------------
// Generic chunky for byte
-
static
-cmsUInt8Number* PackAnyBytes(CMSREGISTER _cmsTRANSFORM* info,
- CMSREGISTER cmsUInt16Number wOut[],
- CMSREGISTER cmsUInt8Number* output,
- CMSREGISTER cmsUInt32Number Stride)
+cmsUInt8Number* PackChunkyBytes(CMSREGISTER _cmsTRANSFORM* info,
+ CMSREGISTER cmsUInt16Number wOut[],
+ CMSREGISTER cmsUInt8Number* output,
+ CMSREGISTER cmsUInt32Number Stride)
{
- cmsUInt32Number nChan = T_CHANNELS(info -> OutputFormat);
- cmsUInt32Number DoSwap = T_DOSWAP(info ->OutputFormat);
- cmsUInt32Number Reverse = T_FLAVOR(info ->OutputFormat);
- cmsUInt32Number Extra = T_EXTRA(info -> OutputFormat);
- cmsUInt32Number SwapFirst = T_SWAPFIRST(info -> OutputFormat);
+ cmsUInt32Number nChan = T_CHANNELS(info->OutputFormat);
+ cmsUInt32Number DoSwap = T_DOSWAP(info->OutputFormat);
+ cmsUInt32Number Reverse = T_FLAVOR(info->OutputFormat);
+ cmsUInt32Number Extra = T_EXTRA(info->OutputFormat);
+ cmsUInt32Number SwapFirst = T_SWAPFIRST(info->OutputFormat);
+ cmsUInt32Number Premul = T_PREMUL(info->OutputFormat);
cmsUInt32Number ExtraFirst = DoSwap ^ SwapFirst;
cmsUInt8Number* swap1;
- cmsUInt8Number v = 0;
+ cmsUInt16Number v = 0;
cmsUInt32Number i;
+ cmsUInt32Number alpha_factor = 0;
swap1 = output;
if (ExtraFirst) {
+
+ if (Premul && Extra)
+ alpha_factor = _cmsToFixedDomain(FROM_8_TO_16(output[0]));
+
output += Extra;
}
+ else
+ {
+ if (Premul && Extra)
+ alpha_factor = _cmsToFixedDomain(FROM_8_TO_16(output[nChan]));
+ }
for (i=0; i < nChan; i++) {
cmsUInt32Number index = DoSwap ? (nChan - i - 1) : i;
- v = FROM_16_TO_8(wOut[index]);
+ v = wOut[index];
if (Reverse)
- v = REVERSE_FLAVOR_8(v);
+ v = REVERSE_FLAVOR_16(v);
- *output++ = v;
+ if (Premul && alpha_factor != 0)
+ {
+ v = (cmsUInt16Number)((cmsUInt32Number)((cmsUInt32Number)v * alpha_factor + 0x8000) >> 16);
+ }
+
+ *output++ = FROM_16_TO_8(v);
}
if (!ExtraFirst) {
@@ -1363,39 +1716,47 @@
if (Extra == 0 && SwapFirst) {
memmove(swap1 + 1, swap1, nChan-1);
- *swap1 = v;
+ *swap1 = FROM_16_TO_8(v);
}
-
return output;
cmsUNUSED_PARAMETER(Stride);
}
-
-
static
-cmsUInt8Number* PackAnyWords(CMSREGISTER _cmsTRANSFORM* info,
- CMSREGISTER cmsUInt16Number wOut[],
- CMSREGISTER cmsUInt8Number* output,
- CMSREGISTER cmsUInt32Number Stride)
+cmsUInt8Number* PackChunkyWords(CMSREGISTER _cmsTRANSFORM* info,
+ CMSREGISTER cmsUInt16Number wOut[],
+ CMSREGISTER cmsUInt8Number* output,
+ CMSREGISTER cmsUInt32Number Stride)
{
- cmsUInt32Number nChan = T_CHANNELS(info -> OutputFormat);
- cmsUInt32Number SwapEndian = T_ENDIAN16(info -> OutputFormat);
- cmsUInt32Number DoSwap = T_DOSWAP(info ->OutputFormat);
- cmsUInt32Number Reverse = T_FLAVOR(info ->OutputFormat);
- cmsUInt32Number Extra = T_EXTRA(info -> OutputFormat);
- cmsUInt32Number SwapFirst = T_SWAPFIRST(info -> OutputFormat);
+ cmsUInt32Number nChan = T_CHANNELS(info->OutputFormat);
+ cmsUInt32Number SwapEndian = T_ENDIAN16(info->OutputFormat);
+ cmsUInt32Number DoSwap = T_DOSWAP(info->OutputFormat);
+ cmsUInt32Number Reverse = T_FLAVOR(info->OutputFormat);
+ cmsUInt32Number Extra = T_EXTRA(info->OutputFormat);
+ cmsUInt32Number SwapFirst = T_SWAPFIRST(info->OutputFormat);
+ cmsUInt32Number Premul = T_PREMUL(info->OutputFormat);
cmsUInt32Number ExtraFirst = DoSwap ^ SwapFirst;
cmsUInt16Number* swap1;
cmsUInt16Number v = 0;
cmsUInt32Number i;
-
+ cmsUInt32Number alpha_factor = 0;
+
swap1 = (cmsUInt16Number*) output;
if (ExtraFirst) {
+
+ if (Premul && Extra)
+ alpha_factor = _cmsToFixedDomain(*(cmsUInt16Number*) output);
+
output += Extra * sizeof(cmsUInt16Number);
}
+ else
+ {
+ if (Premul && Extra)
+ alpha_factor = _cmsToFixedDomain(((cmsUInt16Number*) output)[nChan]);
+ }
for (i=0; i < nChan; i++) {
@@ -1409,6 +1770,11 @@
if (Reverse)
v = REVERSE_FLAVOR_16(v);
+ if (Premul && alpha_factor != 0)
+ {
+ v = (cmsUInt16Number)((cmsUInt32Number)((cmsUInt32Number)v * alpha_factor + 0x8000) >> 16);
+ }
+
*(cmsUInt16Number*) output = v;
output += sizeof(cmsUInt16Number);
@@ -1424,38 +1790,60 @@
*swap1 = v;
}
-
return output;
cmsUNUSED_PARAMETER(Stride);
}
+
static
cmsUInt8Number* PackPlanarBytes(CMSREGISTER _cmsTRANSFORM* info,
CMSREGISTER cmsUInt16Number wOut[],
CMSREGISTER cmsUInt8Number* output,
CMSREGISTER cmsUInt32Number Stride)
{
- cmsUInt32Number nChan = T_CHANNELS(info -> OutputFormat);
- cmsUInt32Number DoSwap = T_DOSWAP(info ->OutputFormat);
- cmsUInt32Number SwapFirst = T_SWAPFIRST(info ->OutputFormat);
- cmsUInt32Number Reverse = T_FLAVOR(info ->OutputFormat);
+ cmsUInt32Number nChan = T_CHANNELS(info->OutputFormat);
+ cmsUInt32Number DoSwap = T_DOSWAP(info->OutputFormat);
+ cmsUInt32Number SwapFirst = T_SWAPFIRST(info->OutputFormat);
+ cmsUInt32Number Reverse = T_FLAVOR(info->OutputFormat);
+ cmsUInt32Number Extra = T_EXTRA(info->OutputFormat);
+ cmsUInt32Number ExtraFirst = DoSwap ^ SwapFirst;
+ cmsUInt32Number Premul = T_PREMUL(info->OutputFormat);
cmsUInt32Number i;
cmsUInt8Number* Init = output;
+ cmsUInt32Number alpha_factor = 0;
- if (DoSwap ^ SwapFirst) {
- output += T_EXTRA(info -> OutputFormat) * Stride;
+ if (ExtraFirst) {
+
+ if (Premul && Extra)
+ alpha_factor = _cmsToFixedDomain(FROM_8_TO_16(output[0]));
+
+ output += Extra * Stride;
+ }
+ else
+ {
+ if (Premul && Extra)
+ alpha_factor = _cmsToFixedDomain(FROM_8_TO_16(output[nChan * Stride]));
}
for (i=0; i < nChan; i++) {
cmsUInt32Number index = DoSwap ? (nChan - i - 1) : i;
- cmsUInt8Number v = FROM_16_TO_8(wOut[index]);
+ cmsUInt16Number v = wOut[index];
- *(cmsUInt8Number*) output = (cmsUInt8Number) (Reverse ? REVERSE_FLAVOR_8(v) : v);
+ if (Reverse)
+ v = REVERSE_FLAVOR_16(v);
+
+ if (Premul && alpha_factor != 0)
+ {
+ v = (cmsUInt16Number)((cmsUInt32Number)((cmsUInt32Number)v * alpha_factor + 0x8000) >> 16);
+ }
+
+ *(cmsUInt8Number*)output = FROM_16_TO_8(v);
+
output += Stride;
}
@@ -1471,16 +1859,30 @@
CMSREGISTER cmsUInt8Number* output,
CMSREGISTER cmsUInt32Number Stride)
{
- cmsUInt32Number nChan = T_CHANNELS(info -> OutputFormat);
- cmsUInt32Number DoSwap = T_DOSWAP(info ->OutputFormat);
- cmsUInt32Number Reverse = T_FLAVOR(info ->OutputFormat);
- cmsUInt32Number SwapEndian = T_ENDIAN16(info -> OutputFormat);
+ cmsUInt32Number nChan = T_CHANNELS(info->OutputFormat);
+ cmsUInt32Number DoSwap = T_DOSWAP(info->OutputFormat);
+ cmsUInt32Number SwapFirst = T_SWAPFIRST(info->OutputFormat);
+ cmsUInt32Number Reverse = T_FLAVOR(info->OutputFormat);
+ cmsUInt32Number Extra = T_EXTRA(info->OutputFormat);
+ cmsUInt32Number ExtraFirst = DoSwap ^ SwapFirst;
+ cmsUInt32Number Premul = T_PREMUL(info->OutputFormat);
+ cmsUInt32Number SwapEndian = T_ENDIAN16(info->OutputFormat);
cmsUInt32Number i;
cmsUInt8Number* Init = output;
cmsUInt16Number v;
+ cmsUInt32Number alpha_factor = 0;
- if (DoSwap) {
- output += T_EXTRA(info -> OutputFormat) * Stride;
+ if (ExtraFirst) {
+
+ if (Premul && Extra)
+ alpha_factor = _cmsToFixedDomain(((cmsUInt16Number*) output)[0]);
+
+ output += Extra * Stride;
+ }
+ else
+ {
+ if (Premul && Extra)
+ alpha_factor = _cmsToFixedDomain(((cmsUInt16Number*)output)[nChan * Stride]);
}
for (i=0; i < nChan; i++) {
@@ -1495,6 +1897,11 @@
if (Reverse)
v = REVERSE_FLAVOR_16(v);
+ if (Premul && alpha_factor != 0)
+ {
+ v = (cmsUInt16Number)((cmsUInt32Number)((cmsUInt32Number)v * alpha_factor + 0x8000) >> 16);
+ }
+
*(cmsUInt16Number*) output = v;
output += Stride;
}
@@ -2641,10 +3048,6 @@
}
-
-
-
-
static
cmsUInt8Number* PackLabFloatFromFloat(_cmsTRANSFORM* Info,
cmsFloat32Number wOut[],
@@ -3029,12 +3432,12 @@
{ CHANNELS_SH(4)|BYTES_SH(1)|DOSWAP_SH(1), ANYSPACE, Unroll4BytesSwap},
{ CHANNELS_SH(4)|BYTES_SH(1)|DOSWAP_SH(1)|SWAPFIRST_SH(1), ANYSPACE, Unroll4BytesSwapSwapFirst},
- { BYTES_SH(1)|PLANAR_SH(1), ANYFLAVOR|ANYSWAPFIRST|
+ { BYTES_SH(1)|PLANAR_SH(1), ANYFLAVOR|ANYSWAPFIRST|ANYPREMUL|
ANYSWAP|ANYEXTRA|ANYCHANNELS|ANYSPACE, UnrollPlanarBytes},
- { BYTES_SH(1), ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|
+ { BYTES_SH(1), ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|ANYPREMUL|
ANYEXTRA|ANYCHANNELS|ANYSPACE, UnrollChunkyBytes},
-
+
{ CHANNELS_SH(1)|BYTES_SH(2), ANYSPACE, Unroll1Word},
{ CHANNELS_SH(1)|BYTES_SH(2)|FLAVOR_SH(1), ANYSPACE, Unroll1WordReversed},
{ CHANNELS_SH(1)|BYTES_SH(2)|EXTRA_SH(3), ANYSPACE, Unroll1WordSkip3},
@@ -3054,6 +3457,10 @@
{ BYTES_SH(2)|PLANAR_SH(1), ANYFLAVOR|ANYSWAP|ANYENDIAN|ANYEXTRA|ANYCHANNELS|ANYSPACE, UnrollPlanarWords},
{ BYTES_SH(2), ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|ANYENDIAN|ANYEXTRA|ANYCHANNELS|ANYSPACE, UnrollAnyWords},
+
+ { BYTES_SH(2)|PLANAR_SH(1), ANYFLAVOR|ANYSWAP|ANYENDIAN|ANYEXTRA|ANYCHANNELS|ANYSPACE|PREMUL_SH(1), UnrollPlanarWordsPremul},
+ { BYTES_SH(2), ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|ANYENDIAN|ANYEXTRA|ANYCHANNELS|ANYSPACE|PREMUL_SH(1), UnrollAnyWordsPremul}
+
};
@@ -3069,13 +3476,23 @@
{ TYPE_XYZ_FLT, ANYPLANAR|ANYEXTRA, UnrollXYZFloatToFloat},
{ FLOAT_SH(1)|BYTES_SH(4), ANYPLANAR|ANYSWAPFIRST|ANYSWAP|ANYEXTRA|
- ANYCHANNELS|ANYSPACE, UnrollFloatsToFloat},
+ ANYPREMUL|ANYCHANNELS|ANYSPACE, UnrollFloatsToFloat},
{ FLOAT_SH(1)|BYTES_SH(0), ANYPLANAR|ANYSWAPFIRST|ANYSWAP|ANYEXTRA|
- ANYCHANNELS|ANYSPACE, UnrollDoublesToFloat},
+ ANYCHANNELS|ANYSPACE|ANYPREMUL, UnrollDoublesToFloat},
+
+ { TYPE_LabV2_8, 0, UnrollLabV2_8ToFloat },
+ { TYPE_ALabV2_8, 0, UnrollALabV2_8ToFloat },
+ { TYPE_LabV2_16, 0, UnrollLabV2_16ToFloat },
+
+ { BYTES_SH(1), ANYPLANAR|ANYSWAPFIRST|ANYSWAP|ANYEXTRA|
+ ANYCHANNELS|ANYSPACE, Unroll8ToFloat},
+
+ { BYTES_SH(2), ANYPLANAR|ANYSWAPFIRST|ANYSWAP|ANYEXTRA|
+ ANYCHANNELS|ANYSPACE, Unroll16ToFloat},
#ifndef CMS_NO_HALF_SUPPORT
{ FLOAT_SH(1)|BYTES_SH(2), ANYPLANAR|ANYSWAPFIRST|ANYSWAP|ANYEXTRA|
- ANYCHANNELS|ANYSPACE, UnrollHalfToFloat},
+ ANYCHANNELS|ANYSPACE, UnrollHalfToFloat},
#endif
};
@@ -3169,16 +3586,20 @@
ANYSPACE, Pack3BytesAndSkip1SwapSwapFirst},
{ CHANNELS_SH(3)|BYTES_SH(1)|DOSWAP_SH(1)|EXTRA_SH(1), ANYSPACE, Pack3BytesAndSkip1Swap},
{ CHANNELS_SH(3)|BYTES_SH(1)|DOSWAP_SH(1), ANYSPACE, Pack3BytesSwap},
- { CHANNELS_SH(6)|BYTES_SH(1), ANYSPACE, Pack6Bytes},
- { CHANNELS_SH(6)|BYTES_SH(1)|DOSWAP_SH(1), ANYSPACE, Pack6BytesSwap},
{ CHANNELS_SH(4)|BYTES_SH(1), ANYSPACE, Pack4Bytes},
{ CHANNELS_SH(4)|BYTES_SH(1)|FLAVOR_SH(1), ANYSPACE, Pack4BytesReverse},
{ CHANNELS_SH(4)|BYTES_SH(1)|SWAPFIRST_SH(1), ANYSPACE, Pack4BytesSwapFirst},
{ CHANNELS_SH(4)|BYTES_SH(1)|DOSWAP_SH(1), ANYSPACE, Pack4BytesSwap},
{ CHANNELS_SH(4)|BYTES_SH(1)|DOSWAP_SH(1)|SWAPFIRST_SH(1), ANYSPACE, Pack4BytesSwapSwapFirst},
+ { CHANNELS_SH(6)|BYTES_SH(1), ANYSPACE, Pack6Bytes},
+ { CHANNELS_SH(6)|BYTES_SH(1)|DOSWAP_SH(1), ANYSPACE, Pack6BytesSwap},
- { BYTES_SH(1), ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|ANYEXTRA|ANYCHANNELS|ANYSPACE, PackAnyBytes},
- { BYTES_SH(1)|PLANAR_SH(1), ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|ANYEXTRA|ANYCHANNELS|ANYSPACE, PackPlanarBytes},
+ { BYTES_SH(1), ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|ANYEXTRA|ANYCHANNELS|
+ ANYSPACE|ANYPREMUL, PackChunkyBytes},
+
+ { BYTES_SH(1)|PLANAR_SH(1), ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|ANYEXTRA|
+ ANYCHANNELS|ANYSPACE|ANYPREMUL, PackPlanarBytes},
+
{ CHANNELS_SH(1)|BYTES_SH(2), ANYSPACE, Pack1Word},
{ CHANNELS_SH(1)|BYTES_SH(2)|EXTRA_SH(1), ANYSPACE, Pack1WordSkip1},
@@ -3203,9 +3624,11 @@
{ CHANNELS_SH(6)|BYTES_SH(2), ANYSPACE, Pack6Words},
{ CHANNELS_SH(6)|BYTES_SH(2)|DOSWAP_SH(1), ANYSPACE, Pack6WordsSwap},
- { BYTES_SH(2)|PLANAR_SH(1), ANYFLAVOR|ANYENDIAN|ANYSWAP|ANYEXTRA|ANYCHANNELS|ANYSPACE, PackPlanarWords},
- { BYTES_SH(2), ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|ANYENDIAN|ANYEXTRA|ANYCHANNELS|ANYSPACE, PackAnyWords}
-
+ { BYTES_SH(2), ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|ANYENDIAN|
+ ANYEXTRA|ANYCHANNELS|ANYSPACE|ANYPREMUL, PackChunkyWords},
+ { BYTES_SH(2)|PLANAR_SH(1), ANYFLAVOR|ANYENDIAN|ANYSWAP|ANYEXTRA|
+ ANYCHANNELS|ANYSPACE|ANYPREMUL, PackPlanarWords}
+
};
diff --git a/third_party/lcms/src/cmspcs.c b/third_party/lcms/src/cmspcs.c
index 9f03fc5..3d6323a 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-2020 Marti Maria Saguer
+// Copyright (c) 1998-2022 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/cmsplugin.c b/third_party/lcms/src/cmsplugin.c
index 2b86b64..dbda3fd 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-2020 Marti Maria Saguer
+// Copyright (c) 1998-2022 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"),
@@ -671,17 +671,65 @@
static _cmsMutex _cmsContextPoolHeadMutex = CMS_MUTEX_INITIALIZER;
static struct _cmsContext_struct* _cmsContextPoolHead = NULL;
+
+// Make sure context is initialized (needed on windows)
+static
+cmsBool InitContextMutex(void)
+{
+ // See the comments regarding locking in lcms2_internal.h
+ // for an explanation of why we need the following code.
+#ifndef CMS_NO_PTHREADS
+#ifdef CMS_IS_WINDOWS_
+#ifndef CMS_RELY_ON_WINDOWS_STATIC_MUTEX_INIT
+
+ static cmsBool already_initialized = FALSE;
+
+ if (!already_initialized)
+ {
+ static HANDLE _cmsWindowsInitMutex = NULL;
+ static volatile HANDLE* mutex = &_cmsWindowsInitMutex;
+
+ if (*mutex == NULL)
+ {
+ HANDLE p = CreateMutex(NULL, FALSE, NULL);
+ if (p && InterlockedCompareExchangePointer((void**)mutex, (void*)p, NULL) != NULL)
+ CloseHandle(p);
+ }
+ if (*mutex == NULL || WaitForSingleObject(*mutex, INFINITE) == WAIT_FAILED)
+ {
+ cmsSignalError(0, cmsERROR_INTERNAL, "Mutex lock failed");
+ return FALSE;
+ }
+ if (((void**)&_cmsContextPoolHeadMutex)[0] == NULL)
+ InitializeCriticalSection(&_cmsContextPoolHeadMutex);
+ if (*mutex == NULL || !ReleaseMutex(*mutex))
+ {
+ cmsSignalError(0, cmsERROR_INTERNAL, "Mutex unlock failed");
+ return FALSE;
+ }
+ already_initialized = TRUE;
+ }
+#endif
+#endif
+#endif
+
+ return TRUE;
+}
+
+
+
// Internal, get associated pointer, with guessing. Never returns NULL.
struct _cmsContext_struct* _cmsGetContext(cmsContext ContextID)
{
struct _cmsContext_struct* id = (struct _cmsContext_struct*) ContextID;
struct _cmsContext_struct* ctx;
-
// On 0, use global settings
if (id == NULL)
return &globalContext;
+ InitContextMutex();
+
// Search
_cmsEnterCriticalSectionPrimitive(&_cmsContextPoolHeadMutex);
@@ -784,31 +832,7 @@
struct _cmsContext_struct* ctx;
struct _cmsContext_struct fakeContext;
- // See the comments regarding locking in lcms2_internal.h
- // for an explanation of why we need the following code.
-#ifndef CMS_NO_PTHREADS
-#ifdef CMS_IS_WINDOWS_
-#ifndef CMS_RELY_ON_WINDOWS_STATIC_MUTEX_INIT
- {
- static HANDLE _cmsWindowsInitMutex = NULL;
- static volatile HANDLE* mutex = &_cmsWindowsInitMutex;
-
- if (*mutex == NULL)
- {
- HANDLE p = CreateMutex(NULL, FALSE, NULL);
- if (p && InterlockedCompareExchangePointer((void **)mutex, (void*)p, NULL) != NULL)
- CloseHandle(p);
- }
- if (*mutex == NULL || WaitForSingleObject(*mutex, INFINITE) == WAIT_FAILED)
- return NULL;
- if (((void **)&_cmsContextPoolHeadMutex)[0] == NULL)
- InitializeCriticalSection(&_cmsContextPoolHeadMutex);
- if (*mutex == NULL || !ReleaseMutex(*mutex))
- return NULL;
- }
-#endif
-#endif
-#endif
+ if (!InitContextMutex()) return NULL;
_cmsInstallAllocFunctions(_cmsFindMemoryPlugin(Plugin), &fakeContext.DefaultMemoryManager);
@@ -884,6 +908,8 @@
if (ctx == NULL)
return NULL; // Something very wrong happened
+ if (!InitContextMutex()) return NULL;
+
// Setup default memory allocators
memcpy(&ctx->DefaultMemoryManager, &src->DefaultMemoryManager, sizeof(ctx->DefaultMemoryManager));
@@ -943,6 +969,9 @@
struct _cmsContext_struct fakeContext;
struct _cmsContext_struct* prev;
+
+ InitContextMutex();
+
memcpy(&fakeContext.DefaultMemoryManager, &ctx->DefaultMemoryManager, sizeof(ctx->DefaultMemoryManager));
fakeContext.chunks[UserPtr] = ctx ->chunks[UserPtr];
@@ -989,3 +1018,32 @@
}
+// Use context mutex to provide thread-safe time
+cmsBool _cmsGetTime(struct tm* ptr_time)
+{
+ struct tm* t;
+#if defined(HAVE_GMTIME_R) || defined(HAVE_GMTIME_S)
+ struct tm tm;
+#endif
+
+ time_t now = time(NULL);
+
+#ifdef HAVE_GMTIME_R
+ t = gmtime_r(&now, &tm);
+#elif defined(HAVE_GMTIME_S)
+ t = gmtime_s(&tm, &now) == 0 ? &tm : NULL;
+#else
+ if (!InitContextMutex()) return FALSE;
+
+ _cmsEnterCriticalSectionPrimitive(&_cmsContextPoolHeadMutex);
+ t = gmtime(&now);
+ _cmsLeaveCriticalSectionPrimitive(&_cmsContextPoolHeadMutex);
+#endif
+
+ if (t == NULL)
+ return FALSE;
+ else {
+ *ptr_time = *t;
+ return TRUE;
+ }
+}
diff --git a/third_party/lcms/src/cmsps2.c b/third_party/lcms/src/cmsps2.c
index 43c9f74..4bb17b0 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-2020 Marti Maria Saguer
+// Copyright (c) 1998-2022 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"),
@@ -475,7 +475,7 @@
_cmsIOPrintf(m, "/lcms2gammatable [");
for (i=0; i < Table->nEntries; i++) {
- if (i % 10 == 0)
+ if (i % 10 == 0)
_cmsIOPrintf(m, "\n ");
_cmsIOPrintf(m, "%d ", Table->Table16[i]);
}
@@ -487,7 +487,7 @@
// PostScript code Stack
// =============== ========================
- // v
+ // v
_cmsIOPrintf(m, "/%s {\n ", name);
// Bounds check
@@ -554,7 +554,7 @@
}
else {
snprintf(buffer, sizeof(buffer), "%s%d", nameprefix, (int) i);
- buffer[sizeof(buffer)-1] = '\0';
+ buffer[sizeof(buffer)-1] = '\0';
Emit1Gamma(m, g[i], buffer);
}
}
diff --git a/third_party/lcms/src/cmssamp.c b/third_party/lcms/src/cmssamp.c
index 6434d53..868664a 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-2020 Marti Maria Saguer
+// Copyright (c) 1998-2022 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/cmssm.c b/third_party/lcms/src/cmssm.c
index 284c77a..fb6965e 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-2020 Marti Maria Saguer
+// Copyright (c) 1998-2022 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/cmstypes.c b/third_party/lcms/src/cmstypes.c
index 4920773..c05a3ec 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-2020 Marti Maria Saguer
+// Copyright (c) 1998-2022 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"),
@@ -134,15 +134,62 @@
return TRUE;
}
+// Try to promote correctly to wchar_t when 32 bits
+cmsINLINE cmsBool is_surrogate(cmsUInt32Number uc) { return (uc - 0xd800u) < 2048u; }
+cmsINLINE cmsBool is_high_surrogate(cmsUInt32Number uc) { return (uc & 0xfffffc00) == 0xd800; }
+cmsINLINE cmsBool is_low_surrogate(cmsUInt32Number uc) { return (uc & 0xfffffc00) == 0xdc00; }
+
+cmsINLINE cmsUInt32Number surrogate_to_utf32(cmsUInt32Number high, cmsUInt32Number low)
+{
+ return (high << 10) + low - 0x35fdc00;
+}
+
+cmsINLINE cmsBool convert_utf16_to_utf32(cmsIOHANDLER* io, cmsInt32Number n, wchar_t* output)
+{
+ cmsUInt16Number uc;
+
+ while (n > 0)
+ {
+ if (!_cmsReadUInt16Number(io, &uc)) return FALSE;
+ n--;
+
+ if (!is_surrogate(uc))
+ {
+ *output++ = (wchar_t)uc;
+ }
+ else {
+
+ cmsUInt16Number low;
+
+ if (!_cmsReadUInt16Number(io, &low)) return FALSE;
+ n--;
+
+ if (is_high_surrogate(uc) && is_low_surrogate(low))
+ *output++ = (wchar_t)surrogate_to_utf32(uc, low);
+ else
+ return FALSE; // Corrupted string, just ignore
+ }
+ }
+
+ return TRUE;
+}
+
+
// Auxiliary to read an array of wchar_t
static
cmsBool _cmsReadWCharArray(cmsIOHANDLER* io, cmsUInt32Number n, wchar_t* Array)
{
cmsUInt32Number i;
cmsUInt16Number tmp;
+ cmsBool is32 = sizeof(wchar_t) > sizeof(cmsUInt16Number);
_cmsAssert(io != NULL);
+ if (is32 && Array != NULL)
+ {
+ return convert_utf16_to_utf32(io, n, Array);
+ }
+
for (i=0; i < n; i++) {
if (Array != NULL) {
@@ -1307,7 +1354,7 @@
//
// All the dateTimeNumber values in a profile shall be in Coordinated Universal Time
// (UTC, also known as GMT or ZULU Time). Profile writers are required to convert local
-// time to UTC when setting these values. Programmes that display these values may show
+// time to UTC when setting these values. Programs that display these values may show
// the dateTimeNumber as UTC, show the equivalent local time (at current locale), or
// display both UTC and local versions of the dateTimeNumber.
@@ -1746,7 +1793,7 @@
// That will create a MPE LUT with Matrix, pre tables, CLUT and post tables.
-// 8 bit lut may be scaled easely to v4 PCS, but we need also to properly adjust
+// 8 bit lut may be scaled easily to v4 PCS, but we need also to properly adjust
// PCS on BToAxx tags and AtoB if abstract. We need to fix input direction.
static
@@ -1853,7 +1900,7 @@
static
cmsBool Type_LUT8_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
{
- cmsUInt32Number j, nTabSize, i, n;
+ cmsUInt32Number j, nTabSize, i;
cmsUInt8Number val;
cmsPipeline* NewLUT = (cmsPipeline*) Ptr;
cmsStage* mpe;
@@ -1902,8 +1949,6 @@
if (!_cmsWriteUInt8Number(io, (cmsUInt8Number) clutPoints)) return FALSE;
if (!_cmsWriteUInt8Number(io, 0)) return FALSE; // Padding
- n = NewLUT->InputChannels * NewLUT->OutputChannels;
-
if (MatMPE != NULL) {
for (i = 0; i < 9; i++)
@@ -3168,8 +3213,8 @@
if (!_cmsWriteUInt32Number(io, nColors)) return FALSE;
if (!_cmsWriteUInt32Number(io, NamedColorList ->ColorantCount)) return FALSE;
- strncpy(prefix, (const char*) NamedColorList->Prefix, 32);
- strncpy(suffix, (const char*) NamedColorList->Suffix, 32);
+ memcpy(prefix, (const char*) NamedColorList->Prefix, sizeof(prefix));
+ memcpy(suffix, (const char*) NamedColorList->Suffix, sizeof(suffix));
suffix[32] = prefix[32] = 0;
@@ -3182,6 +3227,10 @@
cmsUInt16Number Colorant[cmsMAXCHANNELS];
char Root[cmsMAX_PATH];
+ memset(Root, 0, sizeof(Root));
+ memset(PCS, 0, sizeof(PCS));
+ memset(Colorant, 0, sizeof(Colorant));
+
if (!cmsNamedColorInfo(NamedColorList, i, Root, NULL, NULL, PCS, Colorant)) return 0;
Root[32] = 0;
if (!io ->Write(io, 32 , Root)) return FALSE;
@@ -3523,45 +3572,60 @@
// First curve is Under color removal
- if (SignedSizeOfTag < sizeof(cmsUInt32Number)) return NULL;
+ if (SignedSizeOfTag < (cmsInt32Number) sizeof(cmsUInt32Number)) return NULL;
if (!_cmsReadUInt32Number(io, &CountUcr)) return NULL;
SignedSizeOfTag -= sizeof(cmsUInt32Number);
n ->Ucr = cmsBuildTabulatedToneCurve16(self ->ContextID, CountUcr, NULL);
- if (n ->Ucr == NULL) return NULL;
+ if (n ->Ucr == NULL) goto error;
- if (SignedSizeOfTag < (cmsInt32Number)CountUcr * sizeof(cmsUInt16Number)) return NULL;
- if (!_cmsReadUInt16Array(io, CountUcr, n ->Ucr->Table16)) return NULL;
+ if (SignedSizeOfTag < (cmsInt32Number)(CountUcr * sizeof(cmsUInt16Number))) goto error;
+ if (!_cmsReadUInt16Array(io, CountUcr, n ->Ucr->Table16)) goto error;
SignedSizeOfTag -= CountUcr * sizeof(cmsUInt16Number);
// Second curve is Black generation
- if (SignedSizeOfTag < sizeof(cmsUInt32Number)) return NULL;
- if (!_cmsReadUInt32Number(io, &CountBg)) return NULL;
+ if (SignedSizeOfTag < (cmsInt32Number)sizeof(cmsUInt32Number)) goto error;
+ if (!_cmsReadUInt32Number(io, &CountBg)) goto error;
SignedSizeOfTag -= sizeof(cmsUInt32Number);
n ->Bg = cmsBuildTabulatedToneCurve16(self ->ContextID, CountBg, NULL);
- if (n ->Bg == NULL) return NULL;
+ if (n ->Bg == NULL) goto error;
- if (SignedSizeOfTag < (cmsInt32Number) CountBg * sizeof(cmsUInt16Number)) return NULL;
- if (!_cmsReadUInt16Array(io, CountBg, n ->Bg->Table16)) return NULL;
+ if (SignedSizeOfTag < (cmsInt32Number) (CountBg * sizeof(cmsUInt16Number))) goto error;
+ if (!_cmsReadUInt16Array(io, CountBg, n ->Bg->Table16)) goto error;
SignedSizeOfTag -= CountBg * sizeof(cmsUInt16Number);
- if (SignedSizeOfTag < 0 || SignedSizeOfTag > 32000) return NULL;
+ if (SignedSizeOfTag < 0 || SignedSizeOfTag > 32000) goto error;
// Now comes the text. The length is specified by the tag size
n ->Desc = cmsMLUalloc(self ->ContextID, 1);
- if (n ->Desc == NULL) return NULL;
+ if (n ->Desc == NULL) goto error;
ASCIIString = (char*) _cmsMalloc(self ->ContextID, SignedSizeOfTag + 1);
- if (io ->Read(io, ASCIIString, sizeof(char), SignedSizeOfTag) != (cmsUInt32Number) SignedSizeOfTag) return NULL;
+ if (io->Read(io, ASCIIString, sizeof(char), SignedSizeOfTag) != (cmsUInt32Number)SignedSizeOfTag)
+ {
+ _cmsFree(self->ContextID, ASCIIString);
+ goto error;
+ }
+
ASCIIString[SignedSizeOfTag] = 0;
cmsMLUsetASCII(n ->Desc, cmsNoLanguage, cmsNoCountry, ASCIIString);
_cmsFree(self ->ContextID, ASCIIString);
*nItems = 1;
return (void*) n;
+
+error:
+
+ if (n->Ucr) cmsFreeToneCurve(n->Ucr);
+ if (n->Bg) cmsFreeToneCurve(n->Bg);
+ if (n->Desc) cmsMLUfree(n->Desc);
+ _cmsFree(self->ContextID, n);
+ *nItems = 0;
+ return NULL;
+
}
static
@@ -3975,41 +4039,44 @@
switch (ElementSig) {
- case cmsSigFormulaCurveSeg: {
+ case cmsSigFormulaCurveSeg: {
- cmsUInt16Number Type;
- cmsUInt32Number ParamsByType[] = {4, 5, 5 };
+ cmsUInt16Number Type;
+ cmsUInt32Number ParamsByType[] = { 4, 5, 5 };
- if (!_cmsReadUInt16Number(io, &Type)) goto Error;
- if (!_cmsReadUInt16Number(io, NULL)) goto Error;
+ if (!_cmsReadUInt16Number(io, &Type)) goto Error;
+ if (!_cmsReadUInt16Number(io, NULL)) goto Error;
- Segments[i].Type = Type + 6;
- if (Type > 2) goto Error;
+ Segments[i].Type = Type + 6;
+ if (Type > 2) goto Error;
- for (j=0; j < ParamsByType[Type]; j++) {
+ for (j = 0; j < ParamsByType[Type]; j++) {
- cmsFloat32Number f;
- if (!_cmsReadFloat32Number(io, &f)) goto Error;
- Segments[i].Params[j] = f;
- }
- }
- break;
+ cmsFloat32Number f;
+ if (!_cmsReadFloat32Number(io, &f)) goto Error;
+ Segments[i].Params[j] = f;
+ }
+ }
+ break;
- case cmsSigSampledCurveSeg: {
- cmsUInt32Number Count;
+ case cmsSigSampledCurveSeg: {
+ cmsUInt32Number Count;
- if (!_cmsReadUInt32Number(io, &Count)) goto Error;
+ if (!_cmsReadUInt32Number(io, &Count)) goto Error;
- Segments[i].nGridPoints = Count;
- Segments[i].SampledPoints = (cmsFloat32Number*) _cmsCalloc(self ->ContextID, Count, sizeof(cmsFloat32Number));
- if (Segments[i].SampledPoints == NULL) goto Error;
+ // The first point is implicit in the last stage, we allocate an extra note to be populated latter on
+ Count++;
+ Segments[i].nGridPoints = Count;
+ Segments[i].SampledPoints = (cmsFloat32Number*)_cmsCalloc(self->ContextID, Count, sizeof(cmsFloat32Number));
+ if (Segments[i].SampledPoints == NULL) goto Error;
- for (j=0; j < Count; j++) {
- if (!_cmsReadFloat32Number(io, &Segments[i].SampledPoints[j])) goto Error;
- }
- }
- break;
+ Segments[i].SampledPoints[0] = 0;
+ for (j = 1; j < Count; j++) {
+ if (!_cmsReadFloat32Number(io, &Segments[i].SampledPoints[j])) goto Error;
+ }
+ }
+ break;
default:
{
@@ -4029,6 +4096,17 @@
if (Segments[i].SampledPoints) _cmsFree(self ->ContextID, Segments[i].SampledPoints);
}
_cmsFree(self ->ContextID, Segments);
+
+ // Explore for missing implicit points
+ for (i = 0; i < nSegments; i++) {
+
+ // If sampled curve, fix it
+ if (Curve->Segments[i].Type == 0) {
+
+ Curve->Segments[i].SampledPoints[0] = cmsEvalToneCurveFloat(Curve, Curve->Segments[i].x0);
+ }
+ }
+
return Curve;
Error:
@@ -4123,12 +4201,12 @@
if (ActualSeg -> Type == 0) {
- // This is a sampled curve
+ // This is a sampled curve. First point is implicit in the ICC format, but not in our representation
if (!_cmsWriteUInt32Number(io, (cmsUInt32Number) cmsSigSampledCurveSeg)) goto Error;
if (!_cmsWriteUInt32Number(io, 0)) goto Error;
- if (!_cmsWriteUInt32Number(io, ActualSeg -> nGridPoints)) goto Error;
+ if (!_cmsWriteUInt32Number(io, ActualSeg -> nGridPoints - 1)) goto Error;
- for (j=0; j < g ->Segments[i].nGridPoints; j++) {
+ for (j=1; j < g ->Segments[i].nGridPoints; j++) {
if (!_cmsWriteFloat32Number(io, ActualSeg -> SampledPoints[j])) goto Error;
}
@@ -4505,7 +4583,7 @@
-// This one is a liitle bit more complex, so we don't use position tables this time.
+// This one is a little bit more complex, so we don't use position tables this time.
static
cmsBool Type_MPE_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
{
@@ -4937,7 +5015,7 @@
if (!_cmsReadUInt32Number(io, &e->Offsets[i])) return FALSE;
if (!_cmsReadUInt32Number(io, &e ->Sizes[i])) return FALSE;
- // An offset of zero has special meaning and shal be preserved
+ // An offset of zero has special meaning and shall be preserved
if (e ->Offsets[i] > 0)
e ->Offsets[i] += BaseOffset;
return TRUE;
@@ -4945,27 +5023,41 @@
static
-cmsBool ReadOffsetArray(cmsIOHANDLER* io, _cmsDICarray* a, cmsUInt32Number Count, cmsUInt32Number Length, cmsUInt32Number BaseOffset)
+cmsBool ReadOffsetArray(cmsIOHANDLER* io, _cmsDICarray* a,
+ cmsUInt32Number Count, cmsUInt32Number Length, cmsUInt32Number BaseOffset,
+ cmsInt32Number* SignedSizeOfTagPtr)
{
cmsUInt32Number i;
+ cmsInt32Number SignedSizeOfTag = *SignedSizeOfTagPtr;
// Read column arrays
for (i=0; i < Count; i++) {
+ if (SignedSizeOfTag < 4 * (cmsInt32Number) sizeof(cmsUInt32Number)) return FALSE;
+ SignedSizeOfTag -= 4 * sizeof(cmsUInt32Number);
+
if (!ReadOneElem(io, &a -> Name, i, BaseOffset)) return FALSE;
if (!ReadOneElem(io, &a -> Value, i, BaseOffset)) return FALSE;
if (Length > 16) {
+ if (SignedSizeOfTag < 2 * (cmsInt32Number) sizeof(cmsUInt32Number)) return FALSE;
+ SignedSizeOfTag -= 2 * sizeof(cmsUInt32Number);
+
if (!ReadOneElem(io, &a ->DisplayName, i, BaseOffset)) return FALSE;
}
if (Length > 24) {
+ if (SignedSizeOfTag < 2 * (cmsInt32Number) sizeof(cmsUInt32Number)) return FALSE;
+ SignedSizeOfTag -= 2 * (cmsInt32Number) sizeof(cmsUInt32Number);
+
if (!ReadOneElem(io, & a -> DisplayValue, i, BaseOffset)) return FALSE;
}
}
+
+ *SignedSizeOfTagPtr = SignedSizeOfTag;
return TRUE;
}
@@ -5113,26 +5205,31 @@
static
void *Type_Dictionary_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
{
- cmsHANDLE hDict;
+ cmsHANDLE hDict = NULL;
cmsUInt32Number i, Count, Length;
cmsUInt32Number BaseOffset;
_cmsDICarray a;
wchar_t *NameWCS = NULL, *ValueWCS = NULL;
cmsMLU *DisplayNameMLU = NULL, *DisplayValueMLU=NULL;
cmsBool rc;
+ cmsInt32Number SignedSizeOfTag = (cmsInt32Number)SizeOfTag;
*nItems = 0;
+ memset(&a, 0, sizeof(a));
// Get actual position as a basis for element offsets
BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase);
// Get name-value record count
+ SignedSizeOfTag -= sizeof(cmsUInt32Number);
+ if (SignedSizeOfTag < 0) goto Error;
if (!_cmsReadUInt32Number(io, &Count)) return NULL;
- SizeOfTag -= sizeof(cmsUInt32Number);
-
+
// Get rec length
+ SignedSizeOfTag -= sizeof(cmsUInt32Number);
+ if (SignedSizeOfTag < 0) goto Error;
if (!_cmsReadUInt32Number(io, &Length)) return NULL;
- SizeOfTag -= sizeof(cmsUInt32Number);
+
// Check for valid lengths
if (Length != 16 && Length != 24 && Length != 32) {
@@ -5148,7 +5245,7 @@
if (!AllocArray(self -> ContextID, &a, Count, Length)) goto Error;
// Read column arrays
- if (!ReadOffsetArray(io, &a, Count, Length, BaseOffset)) goto Error;
+ if (!ReadOffsetArray(io, &a, Count, Length, BaseOffset, &SignedSizeOfTag)) goto Error;
// Seek to each element and read it
for (i=0; i < Count; i++) {
@@ -5188,7 +5285,7 @@
Error:
FreeArray(&a);
- cmsDictFree(hDict);
+ if (hDict != NULL) cmsDictFree(hDict);
return NULL;
}
diff --git a/third_party/lcms/src/cmsvirt.c b/third_party/lcms/src/cmsvirt.c
index 6ab820b..bffb88e 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-2020 Marti Maria Saguer
+// Copyright (c) 1998-2022 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"),
@@ -368,7 +368,7 @@
InkLimit = (InkLimit * 655.35);
- SumCMY = In[0] + In[1] + In[2];
+ SumCMY = (cmsFloat64Number) In[0] + In[1] + In[2];
SumCMYK = SumCMY + In[3];
if (SumCMYK > InkLimit) {
diff --git a/third_party/lcms/src/cmswtpnt.c b/third_party/lcms/src/cmswtpnt.c
index c7184c3..a8e41b2 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-2020 Marti Maria Saguer
+// Copyright (c) 1998-2022 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"),
@@ -264,16 +264,16 @@
// Build a White point, primary chromas transfer matrix from RGB to CIE XYZ
// This is just an approximation, I am not handling all the non-linear
-// aspects of the RGB to XYZ process, and assumming that the gamma correction
+// aspects of the RGB to XYZ process, and assuming that the gamma correction
// has transitive property in the transformation chain.
//
-// the alghoritm:
+// the algorithm:
//
// - First I build the absolute conversion matrix using
// primaries in XYZ. This matrix is next inverted
// - Then I eval the source white point across this matrix
-// obtaining the coeficients of the transformation
-// - Then, I apply these coeficients to the original matrix
+// obtaining the coefficients of the transformation
+// - Then, I apply these coefficients to the original matrix
//
cmsBool _cmsBuildRGB2XYZtransferMatrix(cmsMAT3* r, const cmsCIExyY* WhitePt, const cmsCIExyYTRIPLE* Primrs)
{
diff --git a/third_party/lcms/src/cmsxform.c b/third_party/lcms/src/cmsxform.c
index 9d182e1..c7183fc 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-2020 Marti Maria Saguer
+// Copyright (c) 1998-2022 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"),
@@ -284,7 +284,7 @@
accum = p->FromInputFloat(p, fIn, accum, Stride->BytesPerPlaneIn);
- // Any gamut chack to do?
+ // Any gamut check to do?
if (p->GamutCheck != NULL) {
// Evaluate gamut marker.
@@ -846,7 +846,7 @@
}
// Check whatever this is a true floating point transform
- if (_cmsFormatterIsFloat(*InputFormat) && _cmsFormatterIsFloat(*OutputFormat)) {
+ if (_cmsFormatterIsFloat(*OutputFormat)) {
// Get formatter function always return a valid union, but the contents of this union may be NULL.
p ->FromInputFloat = _cmsGetFormatter(ContextID, *InputFormat, cmsFormatterInput, CMS_PACK_FLAGS_FLOAT).FmtFloat;
@@ -1081,6 +1081,15 @@
return NULL;
}
+ // Check whatever the transform is 16 bits and involves linear RGB in first profile. If so, disable optimizations
+ if (EntryColorSpace == cmsSigRgbData && T_BYTES(InputFormat) == 2 && !(dwFlags & cmsFLAGS_NOOPTIMIZE))
+ {
+ cmsFloat64Number gamma = cmsDetectRGBProfileGamma(hProfiles[0], 0.1);
+
+ if (gamma > 0 && gamma < 1.6)
+ dwFlags |= cmsFLAGS_NOOPTIMIZE;
+ }
+
// Create a pipeline with all transformations
Lut = _cmsLinkProfiles(ContextID, nProfiles, Intents, hProfiles, BPC, AdaptationStates, dwFlags);
if (Lut == NULL) {
diff --git a/third_party/lcms/src/lcms2_internal.h b/third_party/lcms/src/lcms2_internal.h
index 9560fc4..9eecf6e 100644
--- a/third_party/lcms/src/lcms2_internal.h
+++ b/third_party/lcms/src/lcms2_internal.h
@@ -1,7 +1,7 @@
//
// Little Color Management System
-// Copyright (c) 1998-2020 Marti Maria Saguer
+// Copyright (c) 1998-2022 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"),
@@ -1118,5 +1118,8 @@
cmsBool _cmsBuildRGB2XYZtransferMatrix(cmsMAT3* r, const cmsCIExyY* WhitePoint, const cmsCIExyYTRIPLE* Primaries);
+// thread-safe gettime
+cmsBool _cmsGetTime(struct tm* ptr_time);
+
#define _lcms_internal_H
#endif