Commit b15d0120 authored by Alexandre Julliard's avatar Alexandre Julliard

lcms2: Import upstream release 2.16.

parent 041167b2
...@@ -42,6 +42,7 @@ Philipp Knechtges ...@@ -42,6 +42,7 @@ Philipp Knechtges
Amyspark Amyspark
Lovell Fuller Lovell Fuller
Eli Schwartz Eli Schwartz
Diogo Teles Sant'Anna
Special Thanks Special Thanks
-------------- --------------
......
...@@ -23,7 +23,7 @@ ...@@ -23,7 +23,7 @@
// //
//--------------------------------------------------------------------------------- //---------------------------------------------------------------------------------
// //
// Version 2.15 // Version 2.16
// //
#ifndef _lcms2_H #ifndef _lcms2_H
...@@ -76,12 +76,15 @@ ...@@ -76,12 +76,15 @@
#ifndef CMS_USE_CPP_API #ifndef CMS_USE_CPP_API
# ifdef __cplusplus # ifdef __cplusplus
# if __cplusplus >= 201703L
# define CMS_NO_REGISTER_KEYWORD 1
# endif
extern "C" { extern "C" {
# endif # endif
#endif #endif
// Version/release // Version/release
#define LCMS_VERSION 2150 #define LCMS_VERSION 2160
// I will give the chance of redefining basic types for compilers that are not fully C99 compliant // I will give the chance of redefining basic types for compilers that are not fully C99 compliant
#ifndef CMS_BASIC_TYPES_ALREADY_DEFINED #ifndef CMS_BASIC_TYPES_ALREADY_DEFINED
...@@ -325,7 +328,8 @@ typedef enum { ...@@ -325,7 +328,8 @@ typedef enum {
cmsSigUInt8ArrayType = 0x75693038, // 'ui08' cmsSigUInt8ArrayType = 0x75693038, // 'ui08'
cmsSigVcgtType = 0x76636774, // 'vcgt' cmsSigVcgtType = 0x76636774, // 'vcgt'
cmsSigViewingConditionsType = 0x76696577, // 'view' cmsSigViewingConditionsType = 0x76696577, // 'view'
cmsSigXYZType = 0x58595A20 // 'XYZ ' cmsSigXYZType = 0x58595A20, // 'XYZ '
cmsSigMHC2Type = 0x4D484332 // 'MHC2'
} cmsTagTypeSignature; } cmsTagTypeSignature;
...@@ -403,7 +407,8 @@ typedef enum { ...@@ -403,7 +407,8 @@ typedef enum {
cmsSigVcgtTag = 0x76636774, // 'vcgt' cmsSigVcgtTag = 0x76636774, // 'vcgt'
cmsSigMetaTag = 0x6D657461, // 'meta' cmsSigMetaTag = 0x6D657461, // 'meta'
cmsSigcicpTag = 0x63696370, // 'cicp' cmsSigcicpTag = 0x63696370, // 'cicp'
cmsSigArgyllArtsTag = 0x61727473 // 'arts' cmsSigArgyllArtsTag = 0x61727473, // 'arts'
cmsSigMHC2Tag = 0x4D484332 // 'MHC2'
} cmsTagSignature; } cmsTagSignature;
...@@ -948,6 +953,7 @@ typedef void* cmsHTRANSFORM; ...@@ -948,6 +953,7 @@ typedef void* cmsHTRANSFORM;
#define TYPE_RGB_DBL (FLOAT_SH(1)|COLORSPACE_SH(PT_RGB)|CHANNELS_SH(3)|BYTES_SH(0)) #define TYPE_RGB_DBL (FLOAT_SH(1)|COLORSPACE_SH(PT_RGB)|CHANNELS_SH(3)|BYTES_SH(0))
#define TYPE_BGR_DBL (FLOAT_SH(1)|COLORSPACE_SH(PT_RGB)|CHANNELS_SH(3)|BYTES_SH(0)|DOSWAP_SH(1)) #define TYPE_BGR_DBL (FLOAT_SH(1)|COLORSPACE_SH(PT_RGB)|CHANNELS_SH(3)|BYTES_SH(0)|DOSWAP_SH(1))
#define TYPE_CMYK_DBL (FLOAT_SH(1)|COLORSPACE_SH(PT_CMYK)|CHANNELS_SH(4)|BYTES_SH(0)) #define TYPE_CMYK_DBL (FLOAT_SH(1)|COLORSPACE_SH(PT_CMYK)|CHANNELS_SH(4)|BYTES_SH(0))
#define TYPE_OKLAB_DBL (FLOAT_SH(1)|COLORSPACE_SH(PT_MCH3)|CHANNELS_SH(3)|BYTES_SH(0))
// IEEE 754-2008 "half" // IEEE 754-2008 "half"
#define TYPE_GRAY_HALF_FLT (FLOAT_SH(1)|COLORSPACE_SH(PT_GRAY)|CHANNELS_SH(1)|BYTES_SH(2)) #define TYPE_GRAY_HALF_FLT (FLOAT_SH(1)|COLORSPACE_SH(PT_GRAY)|CHANNELS_SH(1)|BYTES_SH(2))
...@@ -1048,6 +1054,19 @@ typedef struct { ...@@ -1048,6 +1054,19 @@ typedef struct {
} cmsVideoSignalType; } cmsVideoSignalType;
typedef struct {
cmsUInt32Number CurveEntries;
cmsFloat64Number* RedCurve;
cmsFloat64Number* GreenCurve;
cmsFloat64Number* BlueCurve;
cmsFloat64Number MinLuminance; // ST.2086 min luminance in nits
cmsFloat64Number PeakLuminance; // ST.2086 peak luminance in nits
cmsFloat64Number XYZ2XYZmatrix[3][4];
} cmsMHC2Type;
// Get LittleCMS version (for shared objects) ----------------------------------------------------------------------------- // Get LittleCMS version (for shared objects) -----------------------------------------------------------------------------
...@@ -1220,7 +1239,8 @@ CMSAPI cmsBool CMSEXPORT cmsIsToneCurveMonotonic(const cmsToneCurve* t ...@@ -1220,7 +1239,8 @@ CMSAPI cmsBool CMSEXPORT cmsIsToneCurveMonotonic(const cmsToneCurve* t
CMSAPI cmsBool CMSEXPORT cmsIsToneCurveDescending(const cmsToneCurve* t); CMSAPI cmsBool CMSEXPORT cmsIsToneCurveDescending(const cmsToneCurve* t);
CMSAPI cmsInt32Number CMSEXPORT cmsGetToneCurveParametricType(const cmsToneCurve* t); CMSAPI cmsInt32Number CMSEXPORT cmsGetToneCurveParametricType(const cmsToneCurve* t);
CMSAPI cmsFloat64Number CMSEXPORT cmsEstimateGamma(const cmsToneCurve* t, cmsFloat64Number Precision); CMSAPI cmsFloat64Number CMSEXPORT cmsEstimateGamma(const cmsToneCurve* t, cmsFloat64Number Precision);
CMSAPI cmsFloat64Number* CMSEXPORT cmsGetToneCurveParams(const cmsToneCurve* t);
CMSAPI const cmsCurveSegment* CMSEXPORT cmsGetToneCurveSegment(cmsInt32Number n, const cmsToneCurve* t);
// Tone curve tabular estimation // Tone curve tabular estimation
CMSAPI cmsUInt32Number CMSEXPORT cmsGetToneCurveEstimatedTableEntries(const cmsToneCurve* t); CMSAPI cmsUInt32Number CMSEXPORT cmsGetToneCurveEstimatedTableEntries(const cmsToneCurve* t);
...@@ -1317,6 +1337,9 @@ typedef struct _cms_MLU_struct cmsMLU; ...@@ -1317,6 +1337,9 @@ typedef struct _cms_MLU_struct cmsMLU;
#define cmsNoLanguage "\0\0" #define cmsNoLanguage "\0\0"
#define cmsNoCountry "\0\0" #define cmsNoCountry "\0\0"
// Special language/country to retrieve unicode field for description in V2 profiles. Use with care.
#define cmsV2Unicode "\xff\xff"
CMSAPI cmsMLU* CMSEXPORT cmsMLUalloc(cmsContext ContextID, cmsUInt32Number nItems); CMSAPI cmsMLU* CMSEXPORT cmsMLUalloc(cmsContext ContextID, cmsUInt32Number nItems);
CMSAPI void CMSEXPORT cmsMLUfree(cmsMLU* mlu); CMSAPI void CMSEXPORT cmsMLUfree(cmsMLU* mlu);
CMSAPI cmsMLU* CMSEXPORT cmsMLUdup(const cmsMLU* mlu); CMSAPI cmsMLU* CMSEXPORT cmsMLUdup(const cmsMLU* mlu);
...@@ -1327,6 +1350,9 @@ CMSAPI cmsBool CMSEXPORT cmsMLUsetASCII(cmsMLU* mlu, ...@@ -1327,6 +1350,9 @@ CMSAPI cmsBool CMSEXPORT cmsMLUsetASCII(cmsMLU* mlu,
CMSAPI cmsBool CMSEXPORT cmsMLUsetWide(cmsMLU* mlu, CMSAPI cmsBool CMSEXPORT cmsMLUsetWide(cmsMLU* mlu,
const char LanguageCode[3], const char CountryCode[3], const char LanguageCode[3], const char CountryCode[3],
const wchar_t* WideString); const wchar_t* WideString);
CMSAPI cmsBool CMSEXPORT cmsMLUsetUTF8(cmsMLU* mlu,
const char LanguageCode[3], const char CountryCode[3],
const char* UTF8String);
CMSAPI cmsUInt32Number CMSEXPORT cmsMLUgetASCII(const cmsMLU* mlu, CMSAPI cmsUInt32Number CMSEXPORT cmsMLUgetASCII(const cmsMLU* mlu,
const char LanguageCode[3], const char CountryCode[3], const char LanguageCode[3], const char CountryCode[3],
...@@ -1335,6 +1361,10 @@ CMSAPI cmsUInt32Number CMSEXPORT cmsMLUgetASCII(const cmsMLU* mlu, ...@@ -1335,6 +1361,10 @@ CMSAPI cmsUInt32Number CMSEXPORT cmsMLUgetASCII(const cmsMLU* mlu,
CMSAPI cmsUInt32Number CMSEXPORT cmsMLUgetWide(const cmsMLU* mlu, CMSAPI cmsUInt32Number CMSEXPORT cmsMLUgetWide(const cmsMLU* mlu,
const char LanguageCode[3], const char CountryCode[3], const char LanguageCode[3], const char CountryCode[3],
wchar_t* Buffer, cmsUInt32Number BufferSize); wchar_t* Buffer, cmsUInt32Number BufferSize);
CMSAPI cmsUInt32Number CMSEXPORT cmsMLUgetUTF8(const cmsMLU* mlu,
const char LanguageCode[3], const char CountryCode[3],
char* Buffer, cmsUInt32Number BufferSize);
CMSAPI cmsBool CMSEXPORT cmsMLUgetTranslation(const cmsMLU* mlu, CMSAPI cmsBool CMSEXPORT cmsMLUgetTranslation(const cmsMLU* mlu,
const char LanguageCode[3], const char CountryCode[3], const char LanguageCode[3], const char CountryCode[3],
...@@ -1559,6 +1589,10 @@ CMSAPI cmsUInt32Number CMSEXPORT cmsGetProfileInfoASCII(cmsHPROFILE hProfile, ...@@ -1559,6 +1589,10 @@ CMSAPI cmsUInt32Number CMSEXPORT cmsGetProfileInfoASCII(cmsHPROFILE hProfile,
const char LanguageCode[3], const char CountryCode[3], const char LanguageCode[3], const char CountryCode[3],
char* Buffer, cmsUInt32Number BufferSize); char* Buffer, cmsUInt32Number BufferSize);
CMSAPI cmsUInt32Number CMSEXPORT cmsGetProfileInfoUTF8(cmsHPROFILE hProfile, cmsInfoType Info,
const char LanguageCode[3], const char CountryCode[3],
char* Buffer, cmsUInt32Number BufferSize);
// IO handlers ---------------------------------------------------------------------------------------------------------- // IO handlers ----------------------------------------------------------------------------------------------------------
typedef struct _cms_io_handler cmsIOHANDLER; typedef struct _cms_io_handler cmsIOHANDLER;
...@@ -1621,6 +1655,9 @@ CMSAPI cmsHPROFILE CMSEXPORT cmsCreateInkLimitingDeviceLinkTHR(cmsContext C ...@@ -1621,6 +1655,9 @@ CMSAPI cmsHPROFILE CMSEXPORT cmsCreateInkLimitingDeviceLinkTHR(cmsContext C
CMSAPI cmsHPROFILE CMSEXPORT cmsCreateInkLimitingDeviceLink(cmsColorSpaceSignature ColorSpace, cmsFloat64Number Limit); CMSAPI cmsHPROFILE CMSEXPORT cmsCreateInkLimitingDeviceLink(cmsColorSpaceSignature ColorSpace, cmsFloat64Number Limit);
CMSAPI cmsHPROFILE CMSEXPORT cmsCreateDeviceLinkFromCubeFile(const char* cFileName);
CMSAPI cmsHPROFILE CMSEXPORT cmsCreateDeviceLinkFromCubeFileTHR(cmsContext ContextID, const char* cFileName);
CMSAPI cmsHPROFILE CMSEXPORT cmsCreateLab2ProfileTHR(cmsContext ContextID, const cmsCIExyY* WhitePoint); CMSAPI cmsHPROFILE CMSEXPORT cmsCreateLab2ProfileTHR(cmsContext ContextID, const cmsCIExyY* WhitePoint);
CMSAPI cmsHPROFILE CMSEXPORT cmsCreateLab2Profile(const cmsCIExyY* WhitePoint); CMSAPI cmsHPROFILE CMSEXPORT cmsCreateLab2Profile(const cmsCIExyY* WhitePoint);
...@@ -1633,6 +1670,8 @@ CMSAPI cmsHPROFILE CMSEXPORT cmsCreateXYZProfile(void); ...@@ -1633,6 +1670,8 @@ CMSAPI cmsHPROFILE CMSEXPORT cmsCreateXYZProfile(void);
CMSAPI cmsHPROFILE CMSEXPORT cmsCreate_sRGBProfileTHR(cmsContext ContextID); CMSAPI cmsHPROFILE CMSEXPORT cmsCreate_sRGBProfileTHR(cmsContext ContextID);
CMSAPI cmsHPROFILE CMSEXPORT cmsCreate_sRGBProfile(void); CMSAPI cmsHPROFILE CMSEXPORT cmsCreate_sRGBProfile(void);
CMSAPI cmsHPROFILE CMSEXPORT cmsCreate_OkLabProfile(cmsContext ctx);
CMSAPI cmsHPROFILE CMSEXPORT cmsCreateBCHSWabstractProfileTHR(cmsContext ContextID, CMSAPI cmsHPROFILE CMSEXPORT cmsCreateBCHSWabstractProfileTHR(cmsContext ContextID,
cmsUInt32Number nLUTPoints, cmsUInt32Number nLUTPoints,
cmsFloat64Number Bright, cmsFloat64Number Bright,
......
...@@ -402,7 +402,7 @@ static cmsFormatterAlphaFn FormattersAlpha[6][6] = { ...@@ -402,7 +402,7 @@ static cmsFormatterAlphaFn FormattersAlpha[6][6] = {
// This function computes the distance from each component to the next one in bytes. // This function computes the distance from each component to the next one in bytes.
static static
void ComputeIncrementsForChunky(cmsUInt32Number Format, cmsBool ComputeIncrementsForChunky(cmsUInt32Number Format,
cmsUInt32Number ComponentStartingOrder[], cmsUInt32Number ComponentStartingOrder[],
cmsUInt32Number ComponentPointerIncrements[]) cmsUInt32Number ComponentPointerIncrements[])
{ {
...@@ -416,7 +416,7 @@ void ComputeIncrementsForChunky(cmsUInt32Number Format, ...@@ -416,7 +416,7 @@ void ComputeIncrementsForChunky(cmsUInt32Number Format,
// Sanity check // Sanity check
if (total_chans <= 0 || total_chans >= cmsMAXCHANNELS) if (total_chans <= 0 || total_chans >= cmsMAXCHANNELS)
return; return FALSE;
memset(channels, 0, sizeof(channels)); memset(channels, 0, sizeof(channels));
...@@ -453,13 +453,15 @@ void ComputeIncrementsForChunky(cmsUInt32Number Format, ...@@ -453,13 +453,15 @@ void ComputeIncrementsForChunky(cmsUInt32Number Format,
for (i = 0; i < extra; i++) for (i = 0; i < extra; i++)
ComponentStartingOrder[i] = channels[i + nchannels]; ComponentStartingOrder[i] = channels[i + nchannels];
return TRUE;
} }
// On planar configurations, the distance is the stride added to any non-negative // On planar configurations, the distance is the stride added to any non-negative
static static
void ComputeIncrementsForPlanar(cmsUInt32Number Format, cmsBool ComputeIncrementsForPlanar(cmsUInt32Number Format,
cmsUInt32Number BytesPerPlane, cmsUInt32Number BytesPerPlane,
cmsUInt32Number ComponentStartingOrder[], cmsUInt32Number ComponentStartingOrder[],
cmsUInt32Number ComponentPointerIncrements[]) cmsUInt32Number ComponentPointerIncrements[])
...@@ -473,7 +475,7 @@ void ComputeIncrementsForPlanar(cmsUInt32Number Format, ...@@ -473,7 +475,7 @@ void ComputeIncrementsForPlanar(cmsUInt32Number Format,
// Sanity check // Sanity check
if (total_chans <= 0 || total_chans >= cmsMAXCHANNELS) if (total_chans <= 0 || total_chans >= cmsMAXCHANNELS)
return; return FALSE;
memset(channels, 0, sizeof(channels)); memset(channels, 0, sizeof(channels));
...@@ -509,29 +511,29 @@ void ComputeIncrementsForPlanar(cmsUInt32Number Format, ...@@ -509,29 +511,29 @@ void ComputeIncrementsForPlanar(cmsUInt32Number Format,
for (i = 0; i < extra; i++) for (i = 0; i < extra; i++)
ComponentStartingOrder[i] = channels[i + nchannels]; ComponentStartingOrder[i] = channels[i + nchannels];
return TRUE;
} }
// Dispatcher por chunky and planar RGB // Dispatcher por chunky and planar RGB
static static
void ComputeComponentIncrements(cmsUInt32Number Format, cmsBool ComputeComponentIncrements(cmsUInt32Number Format,
cmsUInt32Number BytesPerPlane, cmsUInt32Number BytesPerPlane,
cmsUInt32Number ComponentStartingOrder[], cmsUInt32Number ComponentStartingOrder[],
cmsUInt32Number ComponentPointerIncrements[]) cmsUInt32Number ComponentPointerIncrements[])
{ {
if (T_PLANAR(Format)) { if (T_PLANAR(Format)) {
ComputeIncrementsForPlanar(Format, BytesPerPlane, ComponentStartingOrder, ComponentPointerIncrements); return ComputeIncrementsForPlanar(Format, BytesPerPlane, ComponentStartingOrder, ComponentPointerIncrements);
} }
else { else {
ComputeIncrementsForChunky(Format, ComponentStartingOrder, ComponentPointerIncrements); return ComputeIncrementsForChunky(Format, ComponentStartingOrder, ComponentPointerIncrements);
} }
} }
// Handles extra channels copying alpha if requested by the flags // Handles extra channels copying alpha if requested by the flags
void _cmsHandleExtraChannels(_cmsTRANSFORM* p, const void* in, void _cmsHandleExtraChannels(_cmsTRANSFORM* p, const void* in,
void* out, void* out,
...@@ -566,8 +568,10 @@ void _cmsHandleExtraChannels(_cmsTRANSFORM* p, const void* in, ...@@ -566,8 +568,10 @@ void _cmsHandleExtraChannels(_cmsTRANSFORM* p, const void* in,
return; return;
// Compute the increments // Compute the increments
ComputeComponentIncrements(p->InputFormat, Stride->BytesPerPlaneIn, SourceStartingOrder, SourceIncrements); if (!ComputeComponentIncrements(p->InputFormat, Stride->BytesPerPlaneIn, SourceStartingOrder, SourceIncrements))
ComputeComponentIncrements(p->OutputFormat, Stride->BytesPerPlaneOut, DestStartingOrder, DestIncrements); return;
if (!ComputeComponentIncrements(p->OutputFormat, Stride->BytesPerPlaneOut, DestStartingOrder, DestIncrements))
return;
// Check for conversions 8, 16, half, float, dbl // Check for conversions 8, 16, half, float, dbl
copyValueFn = _cmsGetFormatterAlpha(p->ContextID, p->InputFormat, p->OutputFormat); copyValueFn = _cmsGetFormatterAlpha(p->ContextID, p->InputFormat, p->OutputFormat);
...@@ -642,5 +646,3 @@ void _cmsHandleExtraChannels(_cmsTRANSFORM* p, const void* in, ...@@ -642,5 +646,3 @@ void _cmsHandleExtraChannels(_cmsTRANSFORM* p, const void* in,
} }
} }
} }
...@@ -715,6 +715,16 @@ int BlackPreservingGrayOnlySampler(CMSREGISTER const cmsUInt16Number In[], CMSRE ...@@ -715,6 +715,16 @@ int BlackPreservingGrayOnlySampler(CMSREGISTER const cmsUInt16Number In[], CMSRE
return TRUE; return TRUE;
} }
// Check whatever the profile is a CMYK->CMYK devicelink
static
cmsBool is_cmyk_devicelink(cmsHPROFILE hProfile)
{
return cmsGetDeviceClass(hProfile) == cmsSigLinkClass &&
cmsGetColorSpace(hProfile) == cmsSigCmykData &&
cmsGetColorSpace(hProfile) == cmsSigCmykData;
}
// This is the entry for black-preserving K-only intents, which are non-ICC // This is the entry for black-preserving K-only intents, which are non-ICC
static static
cmsPipeline* BlackPreservingKOnlyIntents(cmsContext ContextID, cmsPipeline* BlackPreservingKOnlyIntents(cmsContext ContextID,
...@@ -747,14 +757,16 @@ cmsPipeline* BlackPreservingKOnlyIntents(cmsContext ContextID, ...@@ -747,14 +757,16 @@ cmsPipeline* BlackPreservingKOnlyIntents(cmsContext ContextID,
lastProfilePos = nProfiles - 1; lastProfilePos = nProfiles - 1;
hLastProfile = hProfiles[lastProfilePos]; hLastProfile = hProfiles[lastProfilePos];
while (lastProfilePos > 1) // Skip CMYK->CMYK devicelinks on ending
while (is_cmyk_devicelink(hLastProfile))
{ {
hLastProfile = hProfiles[--lastProfilePos]; if (lastProfilePos < 2)
if (cmsGetColorSpace(hLastProfile) != cmsSigCmykData ||
cmsGetDeviceClass(hLastProfile) != cmsSigLinkClass)
break; break;
hLastProfile = hProfiles[--lastProfilePos];
} }
preservationProfilesCount = lastProfilePos + 1; preservationProfilesCount = lastProfilePos + 1;
// Check for non-cmyk profiles // Check for non-cmyk profiles
...@@ -973,12 +985,13 @@ cmsPipeline* BlackPreservingKPlaneIntents(cmsContext ContextID, ...@@ -973,12 +985,13 @@ cmsPipeline* BlackPreservingKPlaneIntents(cmsContext ContextID,
lastProfilePos = nProfiles - 1; lastProfilePos = nProfiles - 1;
hLastProfile = hProfiles[lastProfilePos]; hLastProfile = hProfiles[lastProfilePos];
while (lastProfilePos > 1) // Skip CMYK->CMYK devicelinks on ending
while (is_cmyk_devicelink(hLastProfile))
{ {
hLastProfile = hProfiles[--lastProfilePos]; if (lastProfilePos < 2)
if (cmsGetColorSpace(hLastProfile) != cmsSigCmykData ||
cmsGetDeviceClass(hLastProfile) != cmsSigLinkClass)
break; break;
hLastProfile = hProfiles[--lastProfilePos];
} }
preservationProfilesCount = lastProfilePos + 1; preservationProfilesCount = lastProfilePos + 1;
...@@ -1148,8 +1161,7 @@ cmsUInt32Number CMSEXPORT cmsGetSupportedIntentsTHR(cmsContext ContextID, cmsUIn ...@@ -1148,8 +1161,7 @@ cmsUInt32Number CMSEXPORT cmsGetSupportedIntentsTHR(cmsContext ContextID, cmsUIn
cmsIntentsList* pt; cmsIntentsList* pt;
cmsUInt32Number nIntents; cmsUInt32Number nIntents;
for (nIntents=0, pt = DefaultIntents; pt != NULL; pt = pt -> Next)
for (nIntents=0, pt = ctx->Intents; pt != NULL; pt = pt -> Next)
{ {
if (nIntents < nMax) { if (nIntents < nMax) {
if (Codes != NULL) if (Codes != NULL)
...@@ -1162,7 +1174,7 @@ cmsUInt32Number CMSEXPORT cmsGetSupportedIntentsTHR(cmsContext ContextID, cmsUIn ...@@ -1162,7 +1174,7 @@ cmsUInt32Number CMSEXPORT cmsGetSupportedIntentsTHR(cmsContext ContextID, cmsUIn
nIntents++; nIntents++;
} }
for (nIntents=0, pt = DefaultIntents; pt != NULL; pt = pt -> Next) for (pt = ctx->Intents; pt != NULL; pt = pt -> Next)
{ {
if (nIntents < nMax) { if (nIntents < nMax) {
if (Codes != NULL) if (Codes != NULL)
...@@ -1174,6 +1186,7 @@ cmsUInt32Number CMSEXPORT cmsGetSupportedIntentsTHR(cmsContext ContextID, cmsUIn ...@@ -1174,6 +1186,7 @@ cmsUInt32Number CMSEXPORT cmsGetSupportedIntentsTHR(cmsContext ContextID, cmsUIn
nIntents++; nIntents++;
} }
return nIntents; return nIntents;
} }
...@@ -1211,4 +1224,3 @@ cmsBool _cmsRegisterRenderingIntentPlugin(cmsContext id, cmsPluginBase* Data) ...@@ -1211,4 +1224,3 @@ cmsBool _cmsRegisterRenderingIntentPlugin(cmsContext id, cmsPluginBase* Data)
return TRUE; return TRUE;
} }
...@@ -72,7 +72,7 @@ long int CMSEXPORT cmsfilelength(FILE* f) ...@@ -72,7 +72,7 @@ long int CMSEXPORT cmsfilelength(FILE* f)
// //
// This is the interface to low-level memory management routines. By default a simple // This is the interface to low-level memory management routines. By default a simple
// wrapping to malloc/free/realloc is provided, although there is a limit on the max // wrapping to malloc/free/realloc is provided, although there is a limit on the max
// amount of memoy that can be reclaimed. This is mostly as a safety feature to prevent // amount of memory that can be reclaimed. This is mostly as a safety feature to prevent
// bogus or evil code to allocate huge blocks that otherwise lcms would never need. // bogus or evil code to allocate huge blocks that otherwise lcms would never need.
#define MAX_MEMORY_FOR_ALLOC ((cmsUInt32Number)(1024U*1024U*512U)) #define MAX_MEMORY_FOR_ALLOC ((cmsUInt32Number)(1024U*1024U*512U))
...@@ -92,7 +92,8 @@ cmsBool _cmsRegisterMemHandlerPlugin(cmsContext ContextID, cmsPluginBase* Plug ...@@ -92,7 +92,8 @@ cmsBool _cmsRegisterMemHandlerPlugin(cmsContext ContextID, cmsPluginBase* Plug
static static
void* _cmsMallocDefaultFn(cmsContext ContextID, cmsUInt32Number size) void* _cmsMallocDefaultFn(cmsContext ContextID, cmsUInt32Number size)
{ {
if (size > MAX_MEMORY_FOR_ALLOC) return NULL; // Never allow over maximum // Never allow 0 or over maximum
if (size == 0 || size > MAX_MEMORY_FOR_ALLOC) return NULL;
return (void*) malloc(size); return (void*) malloc(size);
...@@ -234,7 +235,7 @@ cmsBool _cmsRegisterMemHandlerPlugin(cmsContext ContextID, cmsPluginBase *Data) ...@@ -234,7 +235,7 @@ cmsBool _cmsRegisterMemHandlerPlugin(cmsContext ContextID, cmsPluginBase *Data)
// NULL forces to reset to defaults. In this special case, the defaults are stored in the context structure. // NULL forces to reset to defaults. In this special case, the defaults are stored in the context structure.
// Remaining plug-ins does NOT have any copy in the context structure, but this is somehow special as the // Remaining plug-ins does NOT have any copy in the context structure, but this is somehow special as the
// context internal data should be malloce'd by using those functions. // context internal data should be malloc'ed by using those functions.
if (Data == NULL) { if (Data == NULL) {
struct _cmsContext_struct* ctx = ( struct _cmsContext_struct*) ContextID; struct _cmsContext_struct* ctx = ( struct _cmsContext_struct*) ContextID;
......
...@@ -300,6 +300,10 @@ cmsToneCurve* AllocateToneCurveStruct(cmsContext ContextID, cmsUInt32Number nEnt ...@@ -300,6 +300,10 @@ cmsToneCurve* AllocateToneCurveStruct(cmsContext ContextID, cmsUInt32Number nEnt
return p; return p;
Error: Error:
for (i=0; i < nSegments; i++) {
if (p ->Segments && p ->Segments[i].SampledPoints) _cmsFree(ContextID, p ->Segments[i].SampledPoints);
if (p ->SegInterp && p ->SegInterp[i]) _cmsFree(ContextID, p ->SegInterp[i]);
}
if (p -> SegInterp) _cmsFree(ContextID, p -> SegInterp); if (p -> SegInterp) _cmsFree(ContextID, p -> SegInterp);
if (p -> Segments) _cmsFree(ContextID, p -> Segments); if (p -> Segments) _cmsFree(ContextID, p -> Segments);
if (p -> Evals) _cmsFree(ContextID, p -> Evals); if (p -> Evals) _cmsFree(ContextID, p -> Evals);
...@@ -593,10 +597,16 @@ cmsFloat64Number DefaultEvalParametricFn(cmsInt32Number Type, const cmsFloat64Nu ...@@ -593,10 +597,16 @@ cmsFloat64Number DefaultEvalParametricFn(cmsInt32Number Type, const cmsFloat64Nu
case 6: case 6:
e = Params[1]*R + Params[2]; e = Params[1]*R + Params[2];
// On gamma 1.0, don't clamp
if (Params[0] == 1.0) {
Val = e + Params[3];
}
else {
if (e < 0) if (e < 0)
Val = Params[3]; Val = Params[3];
else else
Val = pow(e, Params[0]) + Params[3]; Val = pow(e, Params[0]) + Params[3];
}
break; break;
// ((Y - c) ^1/Gamma - b) / a // ((Y - c) ^1/Gamma - b) / a
...@@ -1491,13 +1501,12 @@ cmsFloat64Number CMSEXPORT cmsEstimateGamma(const cmsToneCurve* t, cmsFloat64Num ...@@ -1491,13 +1501,12 @@ cmsFloat64Number CMSEXPORT cmsEstimateGamma(const cmsToneCurve* t, cmsFloat64Num
return (sum / n); // The mean return (sum / n); // The mean
} }
// Retrieve segments on tone curves
// Retrieve parameters on one-segment tone curves const cmsCurveSegment* CMSEXPORT cmsGetToneCurveSegment(cmsInt32Number n, const cmsToneCurve* t)
cmsFloat64Number* CMSEXPORT cmsGetToneCurveParams(const cmsToneCurve* t)
{ {
_cmsAssert(t != NULL); _cmsAssert(t != NULL);
if (t->nSegments != 1) return NULL; if (n < 0 || n >= (cmsInt32Number) t->nSegments) return NULL;
return t->Segments[0].Params; return t->Segments + n;
} }
...@@ -219,7 +219,7 @@ int GamutSampler(CMSREGISTER const cmsUInt16Number In[], CMSREGISTER cmsUInt16Nu ...@@ -219,7 +219,7 @@ int GamutSampler(CMSREGISTER const cmsUInt16Number In[], CMSREGISTER cmsUInt16Nu
cmsUInt16Number Proof[cmsMAXCHANNELS], Proof2[cmsMAXCHANNELS]; cmsUInt16Number Proof[cmsMAXCHANNELS], Proof2[cmsMAXCHANNELS];
cmsFloat64Number dE1, dE2, ErrorRatio; cmsFloat64Number dE1, dE2, ErrorRatio;
// Assume in-gamut by default. // Assume in-gamut by default. NEVER READ, USED FOR DEBUG PURPOSES.
ErrorRatio = 1.0; ErrorRatio = 1.0;
// Convert input to Lab // Convert input to Lab
...@@ -596,7 +596,7 @@ cmsBool CMSEXPORT cmsDesaturateLab(cmsCIELab* Lab, ...@@ -596,7 +596,7 @@ cmsBool CMSEXPORT cmsDesaturateLab(cmsCIELab* Lab,
// Actually, doing that "well" is quite hard, since every component may behave completely different. // 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 // 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. // 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. // The algorithm obtains Y from a synthetical 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. // For gamma close to 1.0, RGB is linear. On profiles not supported, -1 is returned.
cmsFloat64Number CMSEXPORT cmsDetectRGBProfileGamma(cmsHPROFILE hProfile, cmsFloat64Number threshold) cmsFloat64Number CMSEXPORT cmsDetectRGBProfileGamma(cmsHPROFILE hProfile, cmsFloat64Number threshold)
...@@ -656,4 +656,3 @@ cmsFloat64Number CMSEXPORT cmsDetectRGBProfileGamma(cmsHPROFILE hProfile, cmsFlo ...@@ -656,4 +656,3 @@ cmsFloat64Number CMSEXPORT cmsDetectRGBProfileGamma(cmsHPROFILE hProfile, cmsFlo
return gamma; return gamma;
} }
...@@ -531,6 +531,20 @@ cmsHPROFILE CMSEXPORT cmsCreateProfilePlaceholder(cmsContext ContextID) ...@@ -531,6 +531,20 @@ cmsHPROFILE CMSEXPORT cmsCreateProfilePlaceholder(cmsContext ContextID)
// Set default version // Set default version
Icc ->Version = 0x02100000; Icc ->Version = 0x02100000;
// Set default CMM (that's me!)
Icc ->CMM = lcmsSignature;
// Set default creator
// Created by LittleCMS (that's me!)
Icc ->creator = lcmsSignature;
// Set default platform
#ifdef CMS_IS_WINDOWS_
Icc ->platform = cmsSigMicrosoft;
#else
Icc ->platform = cmsSigMacintosh;
#endif
// Set default device class // Set default device class
Icc->DeviceClass = cmsSigDisplayClass; Icc->DeviceClass = cmsSigDisplayClass;
...@@ -784,11 +798,13 @@ cmsBool _cmsReadHeader(_cmsICCPROFILE* Icc) ...@@ -784,11 +798,13 @@ cmsBool _cmsReadHeader(_cmsICCPROFILE* Icc)
} }
// Adjust endianness of the used parameters // Adjust endianness of the used parameters
Icc -> CMM = _cmsAdjustEndianess32(Header.cmmId);
Icc -> DeviceClass = (cmsProfileClassSignature) _cmsAdjustEndianess32(Header.deviceClass); Icc -> DeviceClass = (cmsProfileClassSignature) _cmsAdjustEndianess32(Header.deviceClass);
Icc -> ColorSpace = (cmsColorSpaceSignature) _cmsAdjustEndianess32(Header.colorSpace); Icc -> ColorSpace = (cmsColorSpaceSignature) _cmsAdjustEndianess32(Header.colorSpace);
Icc -> PCS = (cmsColorSpaceSignature) _cmsAdjustEndianess32(Header.pcs); Icc -> PCS = (cmsColorSpaceSignature) _cmsAdjustEndianess32(Header.pcs);
Icc -> RenderingIntent = _cmsAdjustEndianess32(Header.renderingIntent); Icc -> RenderingIntent = _cmsAdjustEndianess32(Header.renderingIntent);
Icc -> platform = (cmsPlatformSignature)_cmsAdjustEndianess32(Header.platform);
Icc -> flags = _cmsAdjustEndianess32(Header.flags); Icc -> flags = _cmsAdjustEndianess32(Header.flags);
Icc -> manufacturer = _cmsAdjustEndianess32(Header.manufacturer); Icc -> manufacturer = _cmsAdjustEndianess32(Header.manufacturer);
Icc -> model = _cmsAdjustEndianess32(Header.model); Icc -> model = _cmsAdjustEndianess32(Header.model);
...@@ -893,7 +909,7 @@ cmsBool _cmsWriteHeader(_cmsICCPROFILE* Icc, cmsUInt32Number UsedSpace) ...@@ -893,7 +909,7 @@ cmsBool _cmsWriteHeader(_cmsICCPROFILE* Icc, cmsUInt32Number UsedSpace)
cmsUInt32Number Count; cmsUInt32Number Count;
Header.size = _cmsAdjustEndianess32(UsedSpace); Header.size = _cmsAdjustEndianess32(UsedSpace);
Header.cmmId = _cmsAdjustEndianess32(lcmsSignature); Header.cmmId = _cmsAdjustEndianess32(Icc ->CMM);
Header.version = _cmsAdjustEndianess32(Icc ->Version); Header.version = _cmsAdjustEndianess32(Icc ->Version);
Header.deviceClass = (cmsProfileClassSignature) _cmsAdjustEndianess32(Icc -> DeviceClass); Header.deviceClass = (cmsProfileClassSignature) _cmsAdjustEndianess32(Icc -> DeviceClass);
...@@ -905,11 +921,7 @@ cmsBool _cmsWriteHeader(_cmsICCPROFILE* Icc, cmsUInt32Number UsedSpace) ...@@ -905,11 +921,7 @@ cmsBool _cmsWriteHeader(_cmsICCPROFILE* Icc, cmsUInt32Number UsedSpace)
Header.magic = _cmsAdjustEndianess32(cmsMagicNumber); Header.magic = _cmsAdjustEndianess32(cmsMagicNumber);
#ifdef CMS_IS_WINDOWS_ Header.platform = (cmsPlatformSignature) _cmsAdjustEndianess32(Icc -> platform);
Header.platform = (cmsPlatformSignature) _cmsAdjustEndianess32(cmsSigMicrosoft);
#else
Header.platform = (cmsPlatformSignature) _cmsAdjustEndianess32(cmsSigMacintosh);
#endif
Header.flags = _cmsAdjustEndianess32(Icc -> flags); Header.flags = _cmsAdjustEndianess32(Icc -> flags);
Header.manufacturer = _cmsAdjustEndianess32(Icc -> manufacturer); Header.manufacturer = _cmsAdjustEndianess32(Icc -> manufacturer);
...@@ -925,8 +937,7 @@ cmsBool _cmsWriteHeader(_cmsICCPROFILE* Icc, cmsUInt32Number UsedSpace) ...@@ -925,8 +937,7 @@ cmsBool _cmsWriteHeader(_cmsICCPROFILE* Icc, cmsUInt32Number UsedSpace)
Header.illuminant.Y = (cmsS15Fixed16Number) _cmsAdjustEndianess32((cmsUInt32Number) _cmsDoubleTo15Fixed16(cmsD50_XYZ()->Y)); Header.illuminant.Y = (cmsS15Fixed16Number) _cmsAdjustEndianess32((cmsUInt32Number) _cmsDoubleTo15Fixed16(cmsD50_XYZ()->Y));
Header.illuminant.Z = (cmsS15Fixed16Number) _cmsAdjustEndianess32((cmsUInt32Number) _cmsDoubleTo15Fixed16(cmsD50_XYZ()->Z)); Header.illuminant.Z = (cmsS15Fixed16Number) _cmsAdjustEndianess32((cmsUInt32Number) _cmsDoubleTo15Fixed16(cmsD50_XYZ()->Z));
// Created by LittleCMS (that's me!) Header.creator = _cmsAdjustEndianess32(Icc ->creator);
Header.creator = _cmsAdjustEndianess32(lcmsSignature);
memset(&Header.reserved, 0, sizeof(Header.reserved)); memset(&Header.reserved, 0, sizeof(Header.reserved));
......
...@@ -578,7 +578,7 @@ Error: ...@@ -578,7 +578,7 @@ Error:
return NULL; return NULL;
} }
// Create an output MPE LUT from agiven profile. Version mismatches are handled here // Create an output MPE LUT from a given profile. Version mismatches are handled here
cmsPipeline* CMSEXPORT _cmsReadOutputLUT(cmsHPROFILE hProfile, cmsUInt32Number Intent) cmsPipeline* CMSEXPORT _cmsReadOutputLUT(cmsHPROFILE hProfile, cmsUInt32Number Intent)
{ {
cmsTagTypeSignature OriginalType; cmsTagTypeSignature OriginalType;
...@@ -1027,3 +1027,13 @@ cmsUInt32Number CMSEXPORT cmsGetProfileInfoASCII(cmsHPROFILE hProfile, cmsInfoT ...@@ -1027,3 +1027,13 @@ cmsUInt32Number CMSEXPORT cmsGetProfileInfoASCII(cmsHPROFILE hProfile, cmsInfoT
return cmsMLUgetASCII(mlu, LanguageCode, CountryCode, Buffer, BufferSize); return cmsMLUgetASCII(mlu, LanguageCode, CountryCode, Buffer, BufferSize);
} }
cmsUInt32Number CMSEXPORT cmsGetProfileInfoUTF8(cmsHPROFILE hProfile, cmsInfoType Info,
const char LanguageCode[3], const char CountryCode[3],
char* Buffer, cmsUInt32Number BufferSize)
{
const cmsMLU* mlu = GetInfo(hProfile, Info);
if (mlu == NULL) return 0;
return cmsMLUgetUTF8(mlu, LanguageCode, CountryCode, Buffer, BufferSize);
}
...@@ -475,6 +475,9 @@ cmsUInt32Number CubeSize(const cmsUInt32Number Dims[], cmsUInt32Number b) ...@@ -475,6 +475,9 @@ cmsUInt32Number CubeSize(const cmsUInt32Number Dims[], cmsUInt32Number b)
if (rv > UINT_MAX / dim) return 0; if (rv > UINT_MAX / dim) return 0;
} }
// Again, prevent overflow
if (rv > UINT_MAX / 15) return 0;
return rv; return rv;
} }
...@@ -814,7 +817,13 @@ cmsBool CMSEXPORT cmsStageSampleCLutFloat(cmsStage* mpe, cmsSAMPLERFLOAT Sampler ...@@ -814,7 +817,13 @@ cmsBool CMSEXPORT cmsStageSampleCLutFloat(cmsStage* mpe, cmsSAMPLERFLOAT Sampler
cmsUInt32Number nInputs, nOutputs; cmsUInt32Number nInputs, nOutputs;
cmsUInt32Number* nSamples; cmsUInt32Number* nSamples;
cmsFloat32Number In[MAX_INPUT_DIMENSIONS+1], Out[MAX_STAGE_CHANNELS]; cmsFloat32Number In[MAX_INPUT_DIMENSIONS+1], Out[MAX_STAGE_CHANNELS];
_cmsStageCLutData* clut = (_cmsStageCLutData*) mpe->Data; _cmsStageCLutData* clut;
if (mpe == NULL) return FALSE;
clut = (_cmsStageCLutData*)mpe->Data;
if (clut == NULL) return FALSE;
nSamples = clut->Params ->nSamples; nSamples = clut->Params ->nSamples;
nInputs = clut->Params ->nInputs; nInputs = clut->Params ->nInputs;
...@@ -1838,5 +1847,3 @@ cmsBool CMSEXPORT cmsPipelineEvalReverseFloat(cmsFloat32Number Target[], ...@@ -1838,5 +1847,3 @@ cmsBool CMSEXPORT cmsPipelineEvalReverseFloat(cmsFloat32Number Target[],
return TRUE; return TRUE;
} }
...@@ -200,14 +200,142 @@ void strFrom16(char str[3], cmsUInt16Number n) ...@@ -200,14 +200,142 @@ void strFrom16(char str[3], cmsUInt16Number n)
str[0] = (char)(n >> 8); str[0] = (char)(n >> 8);
str[1] = (char)n; str[1] = (char)n;
str[2] = (char)0; str[2] = (char)0;
}
// Convert from UTF8 to wchar, returns len.
static
cmsUInt32Number decodeUTF8(wchar_t* out, const char* in)
{
cmsUInt32Number codepoint = 0;
cmsUInt32Number size = 0;
while (*in)
{
cmsUInt8Number ch = (cmsUInt8Number) *in;
if (ch <= 0x7f)
{
codepoint = ch;
}
else if (ch <= 0xbf)
{
codepoint = (codepoint << 6) | (ch & 0x3f);
}
else if (ch <= 0xdf)
{
codepoint = ch & 0x1f;
}
else if (ch <= 0xef)
{
codepoint = ch & 0x0f;
}
else
{
codepoint = ch & 0x07;
}
in++;
if (((*in & 0xc0) != 0x80) && (codepoint <= 0x10ffff))
{
if (sizeof(wchar_t) > 2)
{
if (out) *out++ = (wchar_t) codepoint;
size++;
}
else
if (codepoint > 0xffff)
{
if (out)
{
*out++ = (wchar_t)(0xd800 + (codepoint >> 10));
*out++ = (wchar_t)(0xdc00 + (codepoint & 0x03ff));
size += 2;
}
}
else
if (codepoint < 0xd800 || codepoint >= 0xe000)
{
if (out) *out++ = (wchar_t) codepoint;
size++;
}
}
}
return size;
}
// Convert from wchar_t to UTF8
static
cmsUInt32Number encodeUTF8(char* out, const wchar_t* in, cmsUInt32Number max_wchars, cmsUInt32Number max_chars)
{
cmsUInt32Number codepoint = 0;
cmsUInt32Number size = 0;
cmsUInt32Number len_w = 0;
while (*in && len_w < max_wchars)
{
if (*in >= 0xd800 && *in <= 0xdbff)
codepoint = ((*in - 0xd800) << 10) + 0x10000;
else
{
if (*in >= 0xdc00 && *in <= 0xdfff)
codepoint |= *in - 0xdc00;
else
codepoint = *in;
if (codepoint <= 0x7f)
{
if (out && (size + 1 < max_chars)) *out++ = (char)codepoint;
size++;
}
else if (codepoint <= 0x7ff)
{
if (out && (max_chars > 0) && (size + 2 < max_chars))
{
*out++ = (char)(cmsUInt32Number)(0xc0 | ((codepoint >> 6) & 0x1f));
*out++ = (char)(cmsUInt32Number)(0x80 | (codepoint & 0x3f));
}
size += 2;
}
else if (codepoint <= 0xffff)
{
if (out && (max_chars > 0) && (size + 3 < max_chars))
{
*out++ = (char)(cmsUInt32Number)(0xe0 | ((codepoint >> 12) & 0x0f));
*out++ = (char)(cmsUInt32Number)(0x80 | ((codepoint >> 6) & 0x3f));
*out++ = (char)(cmsUInt32Number)(0x80 | (codepoint & 0x3f));
}
size += 3;
}
else
{
if (out && (max_chars > 0) && (size + 4 < max_chars))
{
*out++ = (char)(cmsUInt32Number)(0xf0 | ((codepoint >> 18) & 0x07));
*out++ = (char)(cmsUInt32Number)(0x80 | ((codepoint >> 12) & 0x3f));
*out++ = (char)(cmsUInt32Number)(0x80 | ((codepoint >> 6) & 0x3f));
*out++ = (char)(cmsUInt32Number)(0x80 | (codepoint & 0x3f));
}
size += 4;
}
codepoint = 0;
}
in++; len_w++;
}
return size;
} }
// Add an ASCII entry. Do not add any \0 termination (ICC1v43_2010-12.pdf page 61) // Add an ASCII entry. Do not add any \0 termination (ICC1v43_2010-12.pdf page 61)
// In the case the user explicitly 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) cmsBool CMSEXPORT cmsMLUsetASCII(cmsMLU* mlu, const char LanguageCode[3], const char CountryCode[3], const char* ASCIIString)
{ {
cmsUInt32Number i, len = (cmsUInt32Number) strlen(ASCIIString); cmsUInt32Number i, len = (cmsUInt32Number)strlen(ASCIIString);
wchar_t* WStr; wchar_t* WStr;
cmsBool rc; cmsBool rc;
cmsUInt16Number Lang = strTo16(LanguageCode); cmsUInt16Number Lang = strTo16(LanguageCode);
...@@ -218,22 +346,56 @@ cmsBool CMSEXPORT cmsMLUsetASCII(cmsMLU* mlu, const char LanguageCode[3], const ...@@ -218,22 +346,56 @@ cmsBool CMSEXPORT cmsMLUsetASCII(cmsMLU* mlu, const char LanguageCode[3], const
// len == 0 would prevent operation, so we set a empty string pointing to zero // len == 0 would prevent operation, so we set a empty string pointing to zero
if (len == 0) if (len == 0)
{ {
len = 1; wchar_t empty = 0;
return AddMLUBlock(mlu, sizeof(wchar_t), &empty, Lang, Cntry);
} }
WStr = (wchar_t*) _cmsCalloc(mlu ->ContextID, len, sizeof(wchar_t)); WStr = (wchar_t*)_cmsCalloc(mlu->ContextID, len, sizeof(wchar_t));
if (WStr == NULL) return FALSE; if (WStr == NULL) return FALSE;
for (i=0; i < len; i++) for (i = 0; i < len; i++)
WStr[i] = (wchar_t) ASCIIString[i]; WStr[i] = (wchar_t)ASCIIString[i];
rc = AddMLUBlock(mlu, len * sizeof(wchar_t), WStr, Lang, Cntry); rc = AddMLUBlock(mlu, len * sizeof(wchar_t), WStr, Lang, Cntry);
_cmsFree(mlu ->ContextID, WStr); _cmsFree(mlu->ContextID, WStr);
return rc; return rc;
} }
// Add an UTF8 entry. Do not add any \0 termination (ICC1v43_2010-12.pdf page 61)
// In the case the user explicitly sets an empty string, we force a \0
cmsBool CMSEXPORT cmsMLUsetUTF8(cmsMLU* mlu, const char LanguageCode[3], const char CountryCode[3], const char* UTF8String)
{
cmsUInt32Number UTF8len;
wchar_t* WStr;
cmsBool rc;
cmsUInt16Number Lang = strTo16(LanguageCode);
cmsUInt16Number Cntry = strTo16(CountryCode);
if (mlu == NULL) return FALSE;
if (*UTF8String == '\0')
{
wchar_t empty = 0;
return AddMLUBlock(mlu, sizeof(wchar_t), &empty, Lang, Cntry);
}
// Len excluding terminator 0
UTF8len = decodeUTF8(NULL, UTF8String);
// Get space for dest
WStr = (wchar_t*) _cmsCalloc(mlu ->ContextID, UTF8len, sizeof(wchar_t));
if (WStr == NULL) return FALSE;
decodeUTF8(WStr, UTF8String);
rc = AddMLUBlock(mlu, UTF8len * sizeof(wchar_t), WStr, Lang, Cntry);
_cmsFree(mlu ->ContextID, WStr);
return rc;
}
// We don't need any wcs support library // We don't need any wcs support library
static static
cmsUInt32Number mywcslen(const wchar_t *s) cmsUInt32Number mywcslen(const wchar_t *s)
...@@ -372,7 +534,7 @@ const wchar_t* _cmsMLUgetWide(const cmsMLU* mlu, ...@@ -372,7 +534,7 @@ const wchar_t* _cmsMLUgetWide(const cmsMLU* mlu,
if (v->StrW + v->Len > mlu->PoolSize) return NULL; if (v->StrW + v->Len > mlu->PoolSize) return NULL;
return(wchar_t*) ((cmsUInt8Number*) mlu ->MemPool + v ->StrW); return (wchar_t*) ((cmsUInt8Number*) mlu ->MemPool + v ->StrW);
} }
...@@ -410,10 +572,12 @@ cmsUInt32Number CMSEXPORT cmsMLUgetASCII(const cmsMLU* mlu, ...@@ -410,10 +572,12 @@ cmsUInt32Number CMSEXPORT cmsMLUgetASCII(const cmsMLU* mlu,
// Precess each character // Precess each character
for (i=0; i < ASCIIlen; i++) { for (i=0; i < ASCIIlen; i++) {
if (Wide[i] == 0) wchar_t wc = Wide[i];
Buffer[i] = 0;
if (wc < 0xff)
Buffer[i] = (char)wc;
else else
Buffer[i] = (char) Wide[i]; Buffer[i] = '?';
} }
// We put a termination "\0" // We put a termination "\0"
...@@ -421,6 +585,46 @@ cmsUInt32Number CMSEXPORT cmsMLUgetASCII(const cmsMLU* mlu, ...@@ -421,6 +585,46 @@ cmsUInt32Number CMSEXPORT cmsMLUgetASCII(const cmsMLU* mlu,
return ASCIIlen + 1; return ASCIIlen + 1;
} }
// Obtain a UTF8 representation of the wide string. Setting buffer to NULL returns the len
cmsUInt32Number CMSEXPORT cmsMLUgetUTF8(const cmsMLU* mlu,
const char LanguageCode[3], const char CountryCode[3],
char* Buffer, cmsUInt32Number BufferSize)
{
const wchar_t *Wide;
cmsUInt32Number StrLen = 0;
cmsUInt32Number UTF8len;
cmsUInt16Number Lang = strTo16(LanguageCode);
cmsUInt16Number Cntry = strTo16(CountryCode);
// Sanitize
if (mlu == NULL) return 0;
// Get WideChar
Wide = _cmsMLUgetWide(mlu, &StrLen, Lang, Cntry, NULL, NULL);
if (Wide == NULL) return 0;
UTF8len = encodeUTF8(NULL, Wide, StrLen / sizeof(wchar_t), BufferSize);
// Maybe we want only to know the len?
if (Buffer == NULL) return UTF8len + 1; // Note the zero at the end
// No buffer size means no data
if (BufferSize <= 0) return 0;
// Some clipping may be required
if (BufferSize < UTF8len + 1)
UTF8len = BufferSize - 1;
// Process it
encodeUTF8(Buffer, Wide, StrLen / sizeof(wchar_t), BufferSize);
// We put a termination "\0"
Buffer[UTF8len] = 0;
return UTF8len + 1;
}
// Obtain a wide representation of the MLU, on depending on current locale settings // Obtain a wide representation of the MLU, on depending on current locale settings
cmsUInt32Number CMSEXPORT cmsMLUgetWide(const cmsMLU* mlu, cmsUInt32Number CMSEXPORT cmsMLUgetWide(const cmsMLU* mlu,
const char LanguageCode[3], const char CountryCode[3], const char LanguageCode[3], const char CountryCode[3],
...@@ -441,12 +645,12 @@ cmsUInt32Number CMSEXPORT cmsMLUgetWide(const cmsMLU* mlu, ...@@ -441,12 +645,12 @@ cmsUInt32Number CMSEXPORT cmsMLUgetWide(const cmsMLU* mlu,
// Maybe we want only to know the len? // Maybe we want only to know the len?
if (Buffer == NULL) return StrLen + sizeof(wchar_t); if (Buffer == NULL) return StrLen + sizeof(wchar_t);
// No buffer size means no data // Invalid buffer size means no data
if (BufferSize <= 0) return 0; if (BufferSize < sizeof(wchar_t)) return 0;
// Some clipping may be required // Some clipping may be required
if (BufferSize < StrLen + sizeof(wchar_t)) if (BufferSize < StrLen + sizeof(wchar_t))
StrLen = BufferSize - + sizeof(wchar_t); StrLen = BufferSize - sizeof(wchar_t);
memmove(Buffer, Wide, StrLen); memmove(Buffer, Wide, StrLen);
Buffer[StrLen / sizeof(wchar_t)] = 0; Buffer[StrLen / sizeof(wchar_t)] = 0;
...@@ -814,13 +1018,19 @@ void CMSEXPORT cmsFreeProfileSequenceDescription(cmsSEQ* pseq) ...@@ -814,13 +1018,19 @@ void CMSEXPORT cmsFreeProfileSequenceDescription(cmsSEQ* pseq)
{ {
cmsUInt32Number i; cmsUInt32Number i;
if (pseq == NULL)
return;
if (pseq ->seq != NULL) {
for (i=0; i < pseq ->n; i++) { for (i=0; i < pseq ->n; i++) {
if (pseq ->seq[i].Manufacturer != NULL) cmsMLUfree(pseq ->seq[i].Manufacturer); if (pseq ->seq[i].Manufacturer != NULL) cmsMLUfree(pseq ->seq[i].Manufacturer);
if (pseq ->seq[i].Model != NULL) cmsMLUfree(pseq ->seq[i].Model); if (pseq ->seq[i].Model != NULL) cmsMLUfree(pseq ->seq[i].Model);
if (pseq ->seq[i].Description != NULL) cmsMLUfree(pseq ->seq[i].Description); if (pseq ->seq[i].Description != NULL) cmsMLUfree(pseq ->seq[i].Description);
} }
if (pseq ->seq != NULL) _cmsFree(pseq ->ContextID, pseq ->seq); _cmsFree(pseq ->ContextID, pseq ->seq);
}
_cmsFree(pseq -> ContextID, pseq); _cmsFree(pseq -> ContextID, pseq);
} }
......
...@@ -183,6 +183,7 @@ cmsBool isFloatMatrixIdentity(const cmsMAT3* a) ...@@ -183,6 +183,7 @@ cmsBool isFloatMatrixIdentity(const cmsMAT3* a)
return TRUE; return TRUE;
} }
// if two adjacent matrices are found, multiply them. // if two adjacent matrices are found, multiply them.
static static
cmsBool _MultiplyMatrix(cmsPipeline* Lut) cmsBool _MultiplyMatrix(cmsPipeline* Lut)
...@@ -1113,14 +1114,17 @@ cmsBool OptimizeByComputingLinearization(cmsPipeline** Lut, cmsUInt32Number Inte ...@@ -1113,14 +1114,17 @@ cmsBool OptimizeByComputingLinearization(cmsPipeline** Lut, cmsUInt32Number Inte
// Store result in curve // Store result in curve
for (t=0; t < OriginalLut ->InputChannels; t++) for (t=0; t < OriginalLut ->InputChannels; t++)
{
if (Trans[t]->Table16 != NULL)
Trans[t] ->Table16[i] = _cmsQuickSaturateWord(Out[t] * 65535.0); Trans[t] ->Table16[i] = _cmsQuickSaturateWord(Out[t] * 65535.0);
} }
}
// Slope-limit the obtained curves // Slope-limit the obtained curves
for (t = 0; t < OriginalLut ->InputChannels; t++) for (t = 0; t < OriginalLut ->InputChannels; t++)
SlopeLimiting(Trans[t]); SlopeLimiting(Trans[t]);
// Check for validity // Check for validity. lIsLinear is here for debug purposes
lIsSuitable = TRUE; lIsSuitable = TRUE;
lIsLinear = TRUE; lIsLinear = TRUE;
for (t=0; (lIsSuitable && (t < OriginalLut ->InputChannels)); t++) { for (t=0; (lIsSuitable && (t < OriginalLut ->InputChannels)); t++) {
...@@ -1724,6 +1728,8 @@ cmsBool OptimizeMatrixShaper(cmsPipeline** Lut, cmsUInt32Number Intent, cmsUInt3 ...@@ -1724,6 +1728,8 @@ cmsBool OptimizeMatrixShaper(cmsPipeline** Lut, cmsUInt32Number Intent, cmsUInt3
_cmsStageMatrixData* Data = (_cmsStageMatrixData*)cmsStageData(Matrix1); _cmsStageMatrixData* Data = (_cmsStageMatrixData*)cmsStageData(Matrix1);
if (Matrix1->InputChannels != 3 || Matrix1->OutputChannels != 3) return FALSE;
// Copy the matrix to our result // Copy the matrix to our result
memcpy(&res, Data->Double, sizeof(res)); memcpy(&res, Data->Double, sizeof(res));
...@@ -1768,7 +1774,7 @@ cmsBool OptimizeMatrixShaper(cmsPipeline** Lut, cmsUInt32Number Intent, cmsUInt3 ...@@ -1768,7 +1774,7 @@ cmsBool OptimizeMatrixShaper(cmsPipeline** Lut, cmsUInt32Number Intent, cmsUInt3
_cmsStageToneCurvesData* mpeC2 = (_cmsStageToneCurvesData*) cmsStageData(Curve2); _cmsStageToneCurvesData* mpeC2 = (_cmsStageToneCurvesData*) cmsStageData(Curve2);
// In this particular optimization, cache does not help as it takes more time to deal with // In this particular optimization, cache does not help as it takes more time to deal with
// the cache that with the pixel handling // the cache than with the pixel handling
*dwFlags |= cmsFLAGS_NOCACHE; *dwFlags |= cmsFLAGS_NOCACHE;
// Setup the optimizarion routines // Setup the optimizarion routines
...@@ -1967,6 +1973,3 @@ cmsBool CMSEXPORT _cmsOptimizePipeline(cmsContext ContextID, ...@@ -1967,6 +1973,3 @@ cmsBool CMSEXPORT _cmsOptimizePipeline(cmsContext ContextID,
// Only simple optimizations succeeded // Only simple optimizations succeeded
return AnySuccess; return AnySuccess;
} }
...@@ -2952,6 +2952,108 @@ cmsUInt8Number* PackFloatFrom16(CMSREGISTER _cmsTRANSFORM* info, ...@@ -2952,6 +2952,108 @@ cmsUInt8Number* PackFloatFrom16(CMSREGISTER _cmsTRANSFORM* info,
// -------------------------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------------------------
static static
cmsUInt8Number* PackBytesFromFloat(_cmsTRANSFORM* info,
cmsFloat32Number wOut[],
cmsUInt8Number* output,
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 Planar = T_PLANAR(info->OutputFormat);
cmsUInt32Number ExtraFirst = DoSwap ^ SwapFirst;
cmsUInt8Number* swap1 = (cmsUInt8Number*)output;
cmsFloat64Number v = 0;
cmsUInt8Number vv = 0;
cmsUInt32Number i, start = 0;
if (ExtraFirst)
start = Extra;
for (i = 0; i < nChan; i++) {
cmsUInt32Number index = DoSwap ? (nChan - i - 1) : i;
v = wOut[index] * 65535.0;
if (Reverse)
v = 65535.0 - v;
vv = FROM_16_TO_8(_cmsQuickSaturateWord(v));
if (Planar)
((cmsUInt8Number*)output)[(i + start) * Stride] = vv;
else
((cmsUInt8Number*)output)[i + start] = vv;
}
if (Extra == 0 && SwapFirst) {
memmove(swap1 + 1, swap1, (nChan - 1) * sizeof(cmsUInt8Number));
*swap1 = vv;
}
if (T_PLANAR(info->OutputFormat))
return output + sizeof(cmsUInt8Number);
else
return output + (nChan + Extra) * sizeof(cmsUInt8Number);
}
static
cmsUInt8Number* PackWordsFromFloat(_cmsTRANSFORM* info,
cmsFloat32Number wOut[],
cmsUInt8Number* output,
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 Planar = T_PLANAR(info->OutputFormat);
cmsUInt32Number ExtraFirst = DoSwap ^ SwapFirst;
cmsUInt16Number* swap1 = (cmsUInt16Number*)output;
cmsFloat64Number v = 0;
cmsUInt16Number vv = 0;
cmsUInt32Number i, start = 0;
if (ExtraFirst)
start = Extra;
for (i = 0; i < nChan; i++) {
cmsUInt32Number index = DoSwap ? (nChan - i - 1) : i;
v = wOut[index] * 65535.0;
if (Reverse)
v = 65535.0 - v;
vv = _cmsQuickSaturateWord(v);
if (Planar)
((cmsUInt16Number*)output)[(i + start) * Stride] = vv;
else
((cmsUInt16Number*)output)[i + start] = vv;
}
if (Extra == 0 && SwapFirst) {
memmove(swap1 + 1, swap1, (nChan - 1) * sizeof(cmsUInt16Number));
*swap1 = vv;
}
if (T_PLANAR(info->OutputFormat))
return output + sizeof(cmsUInt16Number);
else
return output + (nChan + Extra) * sizeof(cmsUInt16Number);
}
static
cmsUInt8Number* PackFloatsFromFloat(_cmsTRANSFORM* info, cmsUInt8Number* PackFloatsFromFloat(_cmsTRANSFORM* info,
cmsFloat32Number wOut[], cmsFloat32Number wOut[],
cmsUInt8Number* output, cmsUInt8Number* output,
...@@ -3114,6 +3216,77 @@ cmsUInt8Number* PackLabDoubleFromFloat(_cmsTRANSFORM* Info, ...@@ -3114,6 +3216,77 @@ cmsUInt8Number* PackLabDoubleFromFloat(_cmsTRANSFORM* Info,
} }
static
cmsUInt8Number* PackEncodedBytesLabV2FromFloat(_cmsTRANSFORM* Info,
cmsFloat32Number wOut[],
cmsUInt8Number* output,
cmsUInt32Number Stride)
{
cmsCIELab Lab;
cmsUInt16Number wlab[3];
Lab.L = (cmsFloat64Number)(wOut[0] * 100.0);
Lab.a = (cmsFloat64Number)(wOut[1] * 255.0 - 128.0);
Lab.b = (cmsFloat64Number)(wOut[2] * 255.0 - 128.0);
cmsFloat2LabEncoded(wlab, &Lab);
if (T_PLANAR(Info -> OutputFormat)) {
Stride /= PixelSize(Info->OutputFormat);
output[0] = wlab[0] >> 8;
output[Stride] = wlab[1] >> 8;
output[Stride*2] = wlab[2] >> 8;
return output + 1;
}
else {
output[0] = wlab[0] >> 8;
output[1] = wlab[1] >> 8;
output[2] = wlab[2] >> 8;
return output + (3 + T_EXTRA(Info ->OutputFormat));
}
}
static
cmsUInt8Number* PackEncodedWordsLabV2FromFloat(_cmsTRANSFORM* Info,
cmsFloat32Number wOut[],
cmsUInt8Number* output,
cmsUInt32Number Stride)
{
cmsCIELab Lab;
cmsUInt16Number wlab[3];
Lab.L = (cmsFloat64Number)(wOut[0] * 100.0);
Lab.a = (cmsFloat64Number)(wOut[1] * 255.0 - 128.0);
Lab.b = (cmsFloat64Number)(wOut[2] * 255.0 - 128.0);
cmsFloat2LabEncodedV2(wlab, &Lab);
if (T_PLANAR(Info -> OutputFormat)) {
Stride /= PixelSize(Info->OutputFormat);
((cmsUInt16Number*) output)[0] = wlab[0];
((cmsUInt16Number*) output)[Stride] = wlab[1];
((cmsUInt16Number*) output)[Stride*2] = wlab[2];
return output + sizeof(cmsUInt16Number);
}
else {
((cmsUInt16Number*) output)[0] = wlab[0];
((cmsUInt16Number*) output)[1] = wlab[1];
((cmsUInt16Number*) output)[2] = wlab[2];
return output + (3 + T_EXTRA(Info ->OutputFormat)) * sizeof(cmsUInt16Number);
}
}
// From 0..1 range to 0..MAX_ENCODEABLE_XYZ // From 0..1 range to 0..MAX_ENCODEABLE_XYZ
static static
cmsUInt8Number* PackXYZFloatFromFloat(_cmsTRANSFORM* Info, cmsUInt8Number* PackXYZFloatFromFloat(_cmsTRANSFORM* Info,
...@@ -3647,10 +3820,20 @@ static const cmsFormattersFloat OutputFormattersFloat[] = { ...@@ -3647,10 +3820,20 @@ static const cmsFormattersFloat OutputFormattersFloat[] = {
{ TYPE_Lab_DBL, ANYPLANAR|ANYEXTRA, PackLabDoubleFromFloat}, { TYPE_Lab_DBL, ANYPLANAR|ANYEXTRA, PackLabDoubleFromFloat},
{ TYPE_XYZ_DBL, ANYPLANAR|ANYEXTRA, PackXYZDoubleFromFloat}, { TYPE_XYZ_DBL, ANYPLANAR|ANYEXTRA, PackXYZDoubleFromFloat},
{ TYPE_LabV2_8, ANYPLANAR|ANYEXTRA, PackEncodedBytesLabV2FromFloat},
{ TYPE_LabV2_16, ANYPLANAR|ANYEXTRA, PackEncodedWordsLabV2FromFloat},
{ FLOAT_SH(1)|BYTES_SH(4), ANYPLANAR| { FLOAT_SH(1)|BYTES_SH(4), ANYPLANAR|
ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|ANYEXTRA|ANYCHANNELS|ANYSPACE, PackFloatsFromFloat }, ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|ANYEXTRA|ANYCHANNELS|ANYSPACE, PackFloatsFromFloat },
{ FLOAT_SH(1)|BYTES_SH(0), ANYPLANAR| { FLOAT_SH(1)|BYTES_SH(0), ANYPLANAR|
ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|ANYEXTRA|ANYCHANNELS|ANYSPACE, PackDoublesFromFloat }, ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|ANYEXTRA|ANYCHANNELS|ANYSPACE, PackDoublesFromFloat },
{ BYTES_SH(2), ANYPLANAR|
ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|ANYEXTRA|ANYCHANNELS|ANYSPACE, PackWordsFromFloat },
{ BYTES_SH(1), ANYPLANAR|
ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|ANYEXTRA|ANYCHANNELS|ANYSPACE, PackBytesFromFloat },
#ifndef CMS_NO_HALF_SUPPORT #ifndef CMS_NO_HALF_SUPPORT
{ FLOAT_SH(1)|BYTES_SH(2), { FLOAT_SH(1)|BYTES_SH(2),
ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|ANYEXTRA|ANYCHANNELS|ANYSPACE, PackHalfFromFloat }, ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|ANYEXTRA|ANYCHANNELS|ANYSPACE, PackHalfFromFloat },
...@@ -3861,7 +4044,7 @@ cmsUInt32Number CMSEXPORT cmsFormatterForPCSOfProfile(cmsHPROFILE hProfile, cmsU ...@@ -3861,7 +4044,7 @@ cmsUInt32Number CMSEXPORT cmsFormatterForPCSOfProfile(cmsHPROFILE hProfile, cmsU
cmsColorSpaceSignature ColorSpace = cmsGetPCS(hProfile); cmsColorSpaceSignature ColorSpace = cmsGetPCS(hProfile);
cmsUInt32Number ColorSpaceBits = (cmsUInt32Number) _cmsLCMScolorSpace(ColorSpace); cmsUInt32Number ColorSpaceBits = (cmsUInt32Number) _cmsLCMScolorSpace(ColorSpace);
cmsUInt32Number nOutputChans = cmsChannelsOf(ColorSpace); cmsInt32Number nOutputChans = cmsChannelsOfColorSpace(ColorSpace);
cmsUInt32Number Float = lIsFloat ? 1U : 0; cmsUInt32Number Float = lIsFloat ? 1U : 0;
// Unsupported color space? // Unsupported color space?
...@@ -3870,4 +4053,3 @@ cmsUInt32Number CMSEXPORT cmsFormatterForPCSOfProfile(cmsHPROFILE hProfile, cmsU ...@@ -3870,4 +4053,3 @@ cmsUInt32Number CMSEXPORT cmsFormatterForPCSOfProfile(cmsHPROFILE hProfile, cmsU
// Create a fake formatter for result // Create a fake formatter for result
return FLOAT_SH(Float) | COLORSPACE_SH(ColorSpaceBits) | BYTES_SH(nBytes) | CHANNELS_SH(nOutputChans); return FLOAT_SH(Float) | COLORSPACE_SH(ColorSpaceBits) | BYTES_SH(nBytes) | CHANNELS_SH(nOutputChans);
} }
...@@ -364,12 +364,7 @@ cmsBool CMSEXPORT _cmsWriteXYZNumber(cmsIOHANDLER* io, const cmsCIEXYZ* XYZ) ...@@ -364,12 +364,7 @@ cmsBool CMSEXPORT _cmsWriteXYZNumber(cmsIOHANDLER* io, const cmsCIEXYZ* XYZ)
// from Fixed point 8.8 to double // from Fixed point 8.8 to double
cmsFloat64Number CMSEXPORT _cms8Fixed8toDouble(cmsUInt16Number fixed8) cmsFloat64Number CMSEXPORT _cms8Fixed8toDouble(cmsUInt16Number fixed8)
{ {
cmsUInt8Number msb, lsb; return fixed8 / 256.0;
lsb = (cmsUInt8Number) (fixed8 & 0xff);
msb = (cmsUInt8Number) (((cmsUInt16Number) fixed8 >> 8) & 0xff);
return (cmsFloat64Number) ((cmsFloat64Number) msb + ((cmsFloat64Number) lsb / 256.0));
} }
cmsUInt16Number CMSEXPORT _cmsDoubleTo8Fixed8(cmsFloat64Number val) cmsUInt16Number CMSEXPORT _cmsDoubleTo8Fixed8(cmsFloat64Number val)
...@@ -381,19 +376,7 @@ cmsUInt16Number CMSEXPORT _cmsDoubleTo8Fixed8(cmsFloat64Number val) ...@@ -381,19 +376,7 @@ cmsUInt16Number CMSEXPORT _cmsDoubleTo8Fixed8(cmsFloat64Number val)
// from Fixed point 15.16 to double // from Fixed point 15.16 to double
cmsFloat64Number CMSEXPORT _cms15Fixed16toDouble(cmsS15Fixed16Number fix32) cmsFloat64Number CMSEXPORT _cms15Fixed16toDouble(cmsS15Fixed16Number fix32)
{ {
cmsFloat64Number floater, sign, mid; return fix32 / 65536.0;
int Whole, FracPart;
sign = (fix32 < 0 ? -1 : 1);
fix32 = abs(fix32);
Whole = (cmsUInt16Number)(fix32 >> 16) & 0xffff;
FracPart = (cmsUInt16Number)(fix32 & 0xffff);
mid = (cmsFloat64Number) FracPart / 65536.0;
floater = (cmsFloat64Number) Whole + mid;
return sign * floater;
} }
// from double to Fixed point 15.16 // from double to Fixed point 15.16
......
...@@ -123,7 +123,7 @@ cmsBool BlackPointAsDarkerColorant(cmsHPROFILE hInput, ...@@ -123,7 +123,7 @@ cmsBool BlackPointAsDarkerColorant(cmsHPROFILE hInput,
// Convert black to Lab // Convert black to Lab
cmsDoTransform(xform, Black, &Lab, 1); cmsDoTransform(xform, Black, &Lab, 1);
// Force it to be neutral, check for inconsistences // Force it to be neutral, check for inconsistencies
Lab.a = Lab.b = 0; Lab.a = Lab.b = 0;
if (Lab.L > 50 || Lab.L < 0) Lab.L = 0; if (Lab.L > 50 || Lab.L < 0) Lab.L = 0;
......
...@@ -406,10 +406,9 @@ cmsHPROFILE CMSEXPORT cmsCreateInkLimitingDeviceLinkTHR(cmsContext ContextID, ...@@ -406,10 +406,9 @@ cmsHPROFILE CMSEXPORT cmsCreateInkLimitingDeviceLinkTHR(cmsContext ContextID,
if (Limit < 0.0 || Limit > 400) { if (Limit < 0.0 || Limit > 400) {
cmsSignalError(ContextID, cmsERROR_RANGE, "InkLimiting: Limit should be between 0..400"); cmsSignalError(ContextID, cmsERROR_RANGE, "InkLimiting: Limit should be between 1..400");
if (Limit < 0) Limit = 0; if (Limit < 1) Limit = 1;
if (Limit > 400) Limit = 400; if (Limit > 400) Limit = 400;
} }
hICC = cmsCreateProfilePlaceholder(ContextID); hICC = cmsCreateProfilePlaceholder(ContextID);
...@@ -672,6 +671,127 @@ cmsHPROFILE CMSEXPORT cmsCreate_sRGBProfile(void) ...@@ -672,6 +671,127 @@ cmsHPROFILE CMSEXPORT cmsCreate_sRGBProfile(void)
return cmsCreate_sRGBProfileTHR(NULL); return cmsCreate_sRGBProfileTHR(NULL);
} }
/**
* Oklab colorspace profile (experimental)
*
* This virtual profile cannot be saved as an ICC file
*/
cmsHPROFILE cmsCreate_OkLabProfile(cmsContext ctx)
{
cmsStage* XYZPCS = _cmsStageNormalizeFromXyzFloat(ctx);
cmsStage* PCSXYZ = _cmsStageNormalizeToXyzFloat(ctx);
const double M_D65_D50[] =
{
1.047886, 0.022919, -0.050216,
0.029582, 0.990484, -0.017079,
-0.009252, 0.015073, 0.751678
};
const double M_D50_D65[] =
{
0.955512609517083, -0.023073214184645, 0.063308961782107,
-0.028324949364887, 1.009942432477107, 0.021054814890112,
0.012328875695483, -0.020535835374141, 1.330713916450354
};
cmsStage* D65toD50 = cmsStageAllocMatrix(ctx, 3, 3, M_D65_D50, NULL);
cmsStage* D50toD65 = cmsStageAllocMatrix(ctx, 3, 3, M_D50_D65, NULL);
const double M_D65_LMS[] =
{
0.8189330101, 0.3618667424, -0.1288597137,
0.0329845436, 0.9293118715, 0.0361456387,
0.0482003018, 0.2643662691, 0.6338517070
};
const double M_LMS_D65[] =
{
1.227013851103521, -0.557799980651822, 0.281256148966468,
-0.040580178423281, 1.112256869616830, -0.071676678665601,
-0.076381284505707, -0.421481978418013, 1.586163220440795
};
cmsStage* D65toLMS = cmsStageAllocMatrix(ctx, 3, 3, M_D65_LMS, NULL);
cmsStage* LMStoD65 = cmsStageAllocMatrix(ctx, 3, 3, M_LMS_D65, NULL);
cmsToneCurve* CubeRoot = cmsBuildGamma(ctx, 1.0 / 3.0);
cmsToneCurve* Cube = cmsBuildGamma(ctx, 3.0);
cmsToneCurve* Roots[3] = { CubeRoot, CubeRoot, CubeRoot };
cmsToneCurve* Cubes[3] = { Cube, Cube, Cube };
cmsStage* NonLinearityFw = cmsStageAllocToneCurves(ctx, 3, Roots);
cmsStage* NonLinearityRv = cmsStageAllocToneCurves(ctx, 3, Cubes);
const double M_LMSprime_OkLab[] =
{
0.2104542553, 0.7936177850, -0.0040720468,
1.9779984951, -2.4285922050, 0.4505937099,
0.0259040371, 0.7827717662, -0.8086757660
};
const double M_OkLab_LMSprime[] =
{
0.999999998450520, 0.396337792173768, 0.215803758060759,
1.000000008881761, -0.105561342323656, -0.063854174771706,
1.000000054672411, -0.089484182094966, -1.291485537864092
};
cmsStage* LMSprime_OkLab = cmsStageAllocMatrix(ctx, 3, 3, M_LMSprime_OkLab, NULL);
cmsStage* OkLab_LMSprime = cmsStageAllocMatrix(ctx, 3, 3, M_OkLab_LMSprime, NULL);
cmsPipeline* AToB = cmsPipelineAlloc(ctx, 3, 3);
cmsPipeline* BToA = cmsPipelineAlloc(ctx, 3, 3);
cmsHPROFILE hProfile = cmsCreateProfilePlaceholder(ctx);
cmsSetProfileVersion(hProfile, 4.4);
cmsSetDeviceClass(hProfile, cmsSigColorSpaceClass);
cmsSetColorSpace(hProfile, cmsSig3colorData);
cmsSetPCS(hProfile, cmsSigXYZData);
cmsSetHeaderRenderingIntent(hProfile, INTENT_RELATIVE_COLORIMETRIC);
/**
* Conversion PCS (XYZ/D50) to OkLab
*/
if (!cmsPipelineInsertStage(BToA, cmsAT_END, PCSXYZ)) goto error;
if (!cmsPipelineInsertStage(BToA, cmsAT_END, D50toD65)) goto error;
if (!cmsPipelineInsertStage(BToA, cmsAT_END, D65toLMS)) goto error;
if (!cmsPipelineInsertStage(BToA, cmsAT_END, NonLinearityFw)) goto error;
if (!cmsPipelineInsertStage(BToA, cmsAT_END, LMSprime_OkLab)) goto error;
if (!cmsWriteTag(hProfile, cmsSigBToA0Tag, BToA)) goto error;
if (!cmsPipelineInsertStage(AToB, cmsAT_END, OkLab_LMSprime)) goto error;
if (!cmsPipelineInsertStage(AToB, cmsAT_END, NonLinearityRv)) goto error;
if (!cmsPipelineInsertStage(AToB, cmsAT_END, LMStoD65)) goto error;
if (!cmsPipelineInsertStage(AToB, cmsAT_END, D65toD50)) goto error;
if (!cmsPipelineInsertStage(AToB, cmsAT_END, XYZPCS)) goto error;
if (!cmsWriteTag(hProfile, cmsSigAToB0Tag, AToB)) goto error;
cmsPipelineFree(BToA);
cmsPipelineFree(AToB);
cmsFreeToneCurve(CubeRoot);
cmsFreeToneCurve(Cube);
return hProfile;
error:
cmsPipelineFree(BToA);
cmsPipelineFree(AToB);
cmsFreeToneCurve(CubeRoot);
cmsFreeToneCurve(Cube);
cmsCloseProfile(hProfile);
return NULL;
}
typedef struct { typedef struct {
...@@ -1031,7 +1151,7 @@ cmsBool CheckOne(const cmsAllowedLUT* Tab, const cmsPipeline* Lut) ...@@ -1031,7 +1151,7 @@ cmsBool CheckOne(const cmsAllowedLUT* Tab, const cmsPipeline* Lut)
for (n=0, mpe = Lut ->Elements; mpe != NULL; mpe = mpe ->Next, n++) { for (n=0, mpe = Lut ->Elements; mpe != NULL; mpe = mpe ->Next, n++) {
if (n > Tab ->nTypes) return FALSE; if (n >= Tab ->nTypes) return FALSE;
if (cmsStageType(mpe) != Tab ->MpeTypes[n]) return FALSE; if (cmsStageType(mpe) != Tab ->MpeTypes[n]) return FALSE;
} }
...@@ -1075,6 +1195,9 @@ cmsHPROFILE CMSEXPORT cmsTransform2DeviceLink(cmsHTRANSFORM hTransform, cmsFloat ...@@ -1075,6 +1195,9 @@ cmsHPROFILE CMSEXPORT cmsTransform2DeviceLink(cmsHTRANSFORM hTransform, cmsFloat
_cmsAssert(hTransform != NULL); _cmsAssert(hTransform != NULL);
// Check if the pipeline holding is valid
if (xform -> Lut == NULL) return NULL;
// Get the first mpe to check for named color // Get the first mpe to check for named color
mpe = cmsPipelineGetPtrToFirstStage(xform ->Lut); mpe = cmsPipelineGetPtrToFirstStage(xform ->Lut);
......
...@@ -914,7 +914,7 @@ _cmsTRANSFORM* AllocEmptyTransform(cmsContext ContextID, cmsPipeline* lut, ...@@ -914,7 +914,7 @@ _cmsTRANSFORM* AllocEmptyTransform(cmsContext ContextID, cmsPipeline* lut,
} }
// Check whatever this is a true floating point transform // Check whatever this is a true floating point transform
if (_cmsFormatterIsFloat(*OutputFormat)) { if (_cmsFormatterIsFloat(*InputFormat) || _cmsFormatterIsFloat(*OutputFormat)) {
// Get formatter function always return a valid union, but the contents of this union may be NULL. // 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; p ->FromInputFloat = _cmsGetFormatter(ContextID, *InputFormat, cmsFormatterInput, CMS_PACK_FLAGS_FLOAT).FmtFloat;
...@@ -989,6 +989,19 @@ _cmsTRANSFORM* AllocEmptyTransform(cmsContext ContextID, cmsPipeline* lut, ...@@ -989,6 +989,19 @@ _cmsTRANSFORM* AllocEmptyTransform(cmsContext ContextID, cmsPipeline* lut,
} }
} }
/**
* Check consistency for alpha channel copy
*/
if (*dwFlags & cmsFLAGS_COPY_ALPHA)
{
if (T_EXTRA(*InputFormat) != T_EXTRA(*OutputFormat))
{
cmsSignalError(ContextID, cmsERROR_NOT_SUITABLE, "Mismatched alpha channels");
cmsDeleteTransform(p);
return NULL;
}
}
p ->InputFormat = *InputFormat; p ->InputFormat = *InputFormat;
p ->OutputFormat = *OutputFormat; p ->OutputFormat = *OutputFormat;
p ->dwOriginalFlags = *dwFlags; p ->dwOriginalFlags = *dwFlags;
......
...@@ -260,6 +260,7 @@ typedef CRITICAL_SECTION _cmsMutex; ...@@ -260,6 +260,7 @@ typedef CRITICAL_SECTION _cmsMutex;
#ifdef _MSC_VER #ifdef _MSC_VER
# if (_MSC_VER >= 1800) # if (_MSC_VER >= 1800)
# pragma warning(disable : 26135) # pragma warning(disable : 26135)
# pragma warning(disable : 4127)
# endif # endif
#endif #endif
...@@ -517,7 +518,7 @@ struct _cmsContext_struct { ...@@ -517,7 +518,7 @@ struct _cmsContext_struct {
struct _cmsContext_struct* Next; // Points to next context in the new style struct _cmsContext_struct* Next; // Points to next context in the new style
_cmsSubAllocator* MemPool; // The memory pool that stores context data _cmsSubAllocator* MemPool; // The memory pool that stores context data
void* chunks[MemoryClientMax]; // array of pointers to client chunks. Memory itself is hold in the suballocator. void* chunks[MemoryClientMax]; // array of pointers to client chunks. Memory itself is held in the suballocator.
// If NULL, then it reverts to global Context0 // If NULL, then it reverts to global Context0
_cmsMemPluginChunkType DefaultMemoryManager; // The allocators used for creating the context itself. Cannot be overridden _cmsMemPluginChunkType DefaultMemoryManager; // The allocators used for creating the context itself. Cannot be overridden
...@@ -811,6 +812,9 @@ typedef struct _cms_iccprofile_struct { ...@@ -811,6 +812,9 @@ typedef struct _cms_iccprofile_struct {
// Creation time // Creation time
struct tm Created; struct tm Created;
// Color management module identification
cmsUInt32Number CMM;
// Only most important items found in ICC profiles // Only most important items found in ICC profiles
cmsUInt32Number Version; cmsUInt32Number Version;
cmsProfileClassSignature DeviceClass; cmsProfileClassSignature DeviceClass;
...@@ -818,6 +822,7 @@ typedef struct _cms_iccprofile_struct { ...@@ -818,6 +822,7 @@ typedef struct _cms_iccprofile_struct {
cmsColorSpaceSignature PCS; cmsColorSpaceSignature PCS;
cmsUInt32Number RenderingIntent; cmsUInt32Number RenderingIntent;
cmsPlatformSignature platform;
cmsUInt32Number flags; cmsUInt32Number flags;
cmsUInt32Number manufacturer, model; cmsUInt32Number manufacturer, model;
cmsUInt64Number attributes; cmsUInt64Number attributes;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment