提交 1ce44c68 编写于 作者: P prr

8029750: Enhance LCMS color processing

Reviewed-by: bae, vadim, mschoene
上级 f91f21c6
...@@ -81,7 +81,7 @@ typedef struct { ...@@ -81,7 +81,7 @@ typedef struct {
cmsUInt32Number surround; cmsUInt32Number surround;
cmsFloat64Number n, Nbb, Ncb, z, FL, D; cmsFloat64Number n, Nbb, Ncb, z, FL, D;
cmsContext ContextID; cmsContext ContextID;
} cmsCIECAM02; } cmsCIECAM02;
...@@ -467,6 +467,7 @@ void CMSEXPORT cmsCIECAM02Forward(cmsHANDLE hModel, const cmsCIEXYZ* pIn, cmsJCh ...@@ -467,6 +467,7 @@ void CMSEXPORT cmsCIECAM02Forward(cmsHANDLE hModel, const cmsCIEXYZ* pIn, cmsJCh
CAM02COLOR clr; CAM02COLOR clr;
cmsCIECAM02* lpMod = (cmsCIECAM02*) hModel; cmsCIECAM02* lpMod = (cmsCIECAM02*) hModel;
memset(&clr, 0, sizeof(clr));
_cmsAssert(lpMod != NULL); _cmsAssert(lpMod != NULL);
_cmsAssert(pIn != NULL); _cmsAssert(pIn != NULL);
_cmsAssert(pOut != NULL); _cmsAssert(pOut != NULL);
...@@ -491,6 +492,7 @@ void CMSEXPORT cmsCIECAM02Reverse(cmsHANDLE hModel, const cmsJCh* pIn, cmsCIEXYZ ...@@ -491,6 +492,7 @@ void CMSEXPORT cmsCIECAM02Reverse(cmsHANDLE hModel, const cmsJCh* pIn, cmsCIEXYZ
CAM02COLOR clr; CAM02COLOR clr;
cmsCIECAM02* lpMod = (cmsCIECAM02*) hModel; cmsCIECAM02* lpMod = (cmsCIECAM02*) hModel;
memset(&clr, 0, sizeof(clr));
_cmsAssert(lpMod != NULL); _cmsAssert(lpMod != NULL);
_cmsAssert(pIn != NULL); _cmsAssert(pIn != NULL);
_cmsAssert(pOut != NULL); _cmsAssert(pOut != NULL);
......
...@@ -59,8 +59,8 @@ ...@@ -59,8 +59,8 @@
// IT8.7 / CGATS.17-200x handling ----------------------------------------------------------------------------- // IT8.7 / CGATS.17-200x handling -----------------------------------------------------------------------------
#define MAXID 128 // Max lenght of identifier #define MAXID 128 // Max length of identifier
#define MAXSTR 1024 // Max lenght of string #define MAXSTR 1024 // Max length of string
#define MAXTABLES 255 // Max Number of tables in a single stream #define MAXTABLES 255 // Max Number of tables in a single stream
#define MAXINCLUDE 20 // Max number of nested includes #define MAXINCLUDE 20 // Max number of nested includes
...@@ -383,28 +383,28 @@ static const char* PredefinedSampleID[] = { ...@@ -383,28 +383,28 @@ static const char* PredefinedSampleID[] = {
//Forward declaration of some internal functions //Forward declaration of some internal functions
static void* AllocChunk(cmsIT8* it8, cmsUInt32Number size); static void* AllocChunk(cmsIT8* it8, cmsUInt32Number size);
// Checks if c is a separator // Checks whatever c is a separator
static static
cmsBool isseparator(int c) cmsBool isseparator(int c)
{ {
return (c == ' ') || (c == '\t') || (c == '\r'); return (c == ' ') || (c == '\t') ;
} }
// Checks whatever if c is a valid identifier char // Checks whatever c is a valid identifier char
static static
cmsBool ismiddle(int c) cmsBool ismiddle(int c)
{ {
return (!isseparator(c) && (c != '#') && (c !='\"') && (c != '\'') && (c > 32) && (c < 127)); return (!isseparator(c) && (c != '#') && (c !='\"') && (c != '\'') && (c > 32) && (c < 127));
} }
// Checks whatsever if c is a valid identifier middle char. // Checks whatsever c is a valid identifier middle char.
static static
cmsBool isidchar(int c) cmsBool isidchar(int c)
{ {
return isalnum(c) || ismiddle(c); return isalnum(c) || ismiddle(c);
} }
// Checks whatsever if c is a valid identifier first char. // Checks whatsever c is a valid identifier first char.
static static
cmsBool isfirstidchar(int c) cmsBool isfirstidchar(int c)
{ {
...@@ -436,7 +436,6 @@ cmsBool isabsolutepath(const char *path) ...@@ -436,7 +436,6 @@ cmsBool isabsolutepath(const char *path)
} }
// Makes a file path based on a given reference path // Makes a file path based on a given reference path
// NOTE: this function doesn't check if the path exists or even if it's legal // NOTE: this function doesn't check if the path exists or even if it's legal
static static
...@@ -634,6 +633,7 @@ cmsFloat64Number ParseFloatNumber(const char *Buffer) ...@@ -634,6 +633,7 @@ cmsFloat64Number ParseFloatNumber(const char *Buffer)
cmsFloat64Number dnum = 0.0; cmsFloat64Number dnum = 0.0;
int sign = 1; int sign = 1;
// keep safe
if (Buffer == NULL) return 0.0; if (Buffer == NULL) return 0.0;
if (*Buffer == '-' || *Buffer == '+') { if (*Buffer == '-' || *Buffer == '+') {
...@@ -869,6 +869,14 @@ void InSymbol(cmsIT8* it8) ...@@ -869,6 +869,14 @@ void InSymbol(cmsIT8* it8)
// Next line // Next line
case '\r':
NextCh(it8);
if (it8 ->ch == '\n')
NextCh(it8);
it8->sy = SEOLN;
it8->lineno++;
break;
case '\n': case '\n':
NextCh(it8); NextCh(it8);
it8->sy = SEOLN; it8->sy = SEOLN;
...@@ -878,7 +886,7 @@ void InSymbol(cmsIT8* it8) ...@@ -878,7 +886,7 @@ void InSymbol(cmsIT8* it8)
// Comment // Comment
case '#': case '#':
NextCh(it8); NextCh(it8);
while (it8->ch && it8->ch != '\n') while (it8->ch && it8->ch != '\n' && it8->ch != '\r')
NextCh(it8); NextCh(it8);
it8->sy = SCOMMENT; it8->sy = SCOMMENT;
...@@ -996,6 +1004,9 @@ cmsBool GetVal(cmsIT8* it8, char* Buffer, cmsUInt32Number max, const char* Error ...@@ -996,6 +1004,9 @@ cmsBool GetVal(cmsIT8* it8, char* Buffer, cmsUInt32Number max, const char* Error
{ {
switch (it8->sy) { switch (it8->sy) {
case SEOLN: // Empty value
Buffer[0]=0;
break;
case SIDENT: strncpy(Buffer, it8->id, max); case SIDENT: strncpy(Buffer, it8->id, max);
Buffer[max-1]=0; Buffer[max-1]=0;
break; break;
...@@ -1145,9 +1156,9 @@ cmsBool IsAvailableOnList(KEYVALUE* p, const char* Key, const char* Subkey, KEYV ...@@ -1145,9 +1156,9 @@ cmsBool IsAvailableOnList(KEYVALUE* p, const char* Key, const char* Subkey, KEYV
if (*Key != '#') { // Comments are ignored if (*Key != '#') { // Comments are ignored
if (cmsstrcasecmp(Key, p->Keyword) == 0) if (cmsstrcasecmp(Key, p->Keyword) == 0)
break; break;
}
} }
}
if (p == NULL) if (p == NULL)
return FALSE; return FALSE;
...@@ -1157,11 +1168,13 @@ cmsBool IsAvailableOnList(KEYVALUE* p, const char* Key, const char* Subkey, KEYV ...@@ -1157,11 +1168,13 @@ cmsBool IsAvailableOnList(KEYVALUE* p, const char* Key, const char* Subkey, KEYV
for (; p != NULL; p = p->NextSubkey) { for (; p != NULL; p = p->NextSubkey) {
if (p ->Subkey == NULL) continue;
if (LastPtr) *LastPtr = p; if (LastPtr) *LastPtr = p;
if (cmsstrcasecmp(Subkey, p->Subkey) == 0) if (cmsstrcasecmp(Subkey, p->Subkey) == 0)
return TRUE; return TRUE;
} }
return FALSE; return FALSE;
} }
...@@ -1284,7 +1297,7 @@ cmsInt32Number CMSEXPORT cmsIT8SetTable(cmsHANDLE IT8, cmsUInt32Number nTable) ...@@ -1284,7 +1297,7 @@ cmsInt32Number CMSEXPORT cmsIT8SetTable(cmsHANDLE IT8, cmsUInt32Number nTable)
it8 ->nTable = nTable; it8 ->nTable = nTable;
return nTable; return (cmsInt32Number) nTable;
} }
...@@ -1389,7 +1402,7 @@ cmsBool CMSEXPORT cmsIT8SetPropertyHex(cmsHANDLE hIT8, const char* cProp, cmsUIn ...@@ -1389,7 +1402,7 @@ cmsBool CMSEXPORT cmsIT8SetPropertyHex(cmsHANDLE hIT8, const char* cProp, cmsUIn
cmsIT8* it8 = (cmsIT8*) hIT8; cmsIT8* it8 = (cmsIT8*) hIT8;
char Buffer[1024]; char Buffer[1024];
sprintf(Buffer, "%d", Val); sprintf(Buffer, "%u", Val);
return AddToList(it8, &GetTable(it8)->HeaderList, cProp, NULL, Buffer, WRITE_HEXADECIMAL) != NULL; return AddToList(it8, &GetTable(it8)->HeaderList, cProp, NULL, Buffer, WRITE_HEXADECIMAL) != NULL;
} }
...@@ -1426,6 +1439,8 @@ cmsFloat64Number CMSEXPORT cmsIT8GetPropertyDbl(cmsHANDLE hIT8, const char* cPro ...@@ -1426,6 +1439,8 @@ cmsFloat64Number CMSEXPORT cmsIT8GetPropertyDbl(cmsHANDLE hIT8, const char* cPro
{ {
const char *v = cmsIT8GetProperty(hIT8, cProp); const char *v = cmsIT8GetProperty(hIT8, cProp);
if (v == NULL) return 0.0;
return ParseFloatNumber(v); return ParseFloatNumber(v);
} }
...@@ -1458,7 +1473,7 @@ void AllocateDataFormat(cmsIT8* it8) ...@@ -1458,7 +1473,7 @@ void AllocateDataFormat(cmsIT8* it8)
t -> nSamples = 10; t -> nSamples = 10;
} }
t -> DataFormat = (char**) AllocChunk (it8, (t->nSamples + 1) * sizeof(char *)); t -> DataFormat = (char**) AllocChunk (it8, ((cmsUInt32Number) t->nSamples + 1) * sizeof(char *));
if (t->DataFormat == NULL) { if (t->DataFormat == NULL) {
SynError(it8, "AllocateDataFormat: Unable to allocate dataFormat array"); SynError(it8, "AllocateDataFormat: Unable to allocate dataFormat array");
...@@ -1514,7 +1529,7 @@ void AllocateDataSet(cmsIT8* it8) ...@@ -1514,7 +1529,7 @@ void AllocateDataSet(cmsIT8* it8)
t-> nSamples = atoi(cmsIT8GetProperty(it8, "NUMBER_OF_FIELDS")); t-> nSamples = atoi(cmsIT8GetProperty(it8, "NUMBER_OF_FIELDS"));
t-> nPatches = atoi(cmsIT8GetProperty(it8, "NUMBER_OF_SETS")); t-> nPatches = atoi(cmsIT8GetProperty(it8, "NUMBER_OF_SETS"));
t-> Data = (char**)AllocChunk (it8, (t->nSamples + 1) * (t->nPatches + 1) *sizeof (char*)); t-> Data = (char**)AllocChunk (it8, ((cmsUInt32Number) t->nSamples + 1) * ((cmsUInt32Number) t->nPatches + 1) *sizeof (char*));
if (t->Data == NULL) { if (t->Data == NULL) {
SynError(it8, "AllocateDataSet: Unable to allocate data array"); SynError(it8, "AllocateDataSet: Unable to allocate data array");
...@@ -1573,7 +1588,7 @@ void WriteStr(SAVESTREAM* f, const char *str) ...@@ -1573,7 +1588,7 @@ void WriteStr(SAVESTREAM* f, const char *str)
if (str == NULL) if (str == NULL)
str = " "; str = " ";
// Lenghth to write // Length to write
len = (cmsUInt32Number) strlen(str); len = (cmsUInt32Number) strlen(str);
f ->Used += len; f ->Used += len;
...@@ -2097,7 +2112,7 @@ cmsBool ParseIT8(cmsIT8* it8, cmsBool nosheet) ...@@ -2097,7 +2112,7 @@ cmsBool ParseIT8(cmsIT8* it8, cmsBool nosheet)
NextCh(it8); NextCh(it8);
// If a newline is found, then this is a type string // If a newline is found, then this is a type string
if (it8 ->ch == '\n') { if (it8 ->ch == '\n' || it8->ch == '\r') {
cmsIT8SetSheetType(it8, it8 ->id); cmsIT8SetSheetType(it8, it8 ->id);
InSymbol(it8); InSymbol(it8);
...@@ -2212,7 +2227,7 @@ void CookPointers(cmsIT8* it8) ...@@ -2212,7 +2227,7 @@ void CookPointers(cmsIT8* it8)
char Buffer[256]; char Buffer[256];
char *Type = p ->Value; char *Type = p ->Value;
int nTable = k; int nTable = (int) k;
snprintf(Buffer, 255, "%s %d %s", Label, nTable, Type ); snprintf(Buffer, 255, "%s %d %s", Label, nTable, Type );
...@@ -2566,6 +2581,8 @@ cmsFloat64Number CMSEXPORT cmsIT8GetDataRowColDbl(cmsHANDLE hIT8, int row, int c ...@@ -2566,6 +2581,8 @@ cmsFloat64Number CMSEXPORT cmsIT8GetDataRowColDbl(cmsHANDLE hIT8, int row, int c
Buffer = cmsIT8GetDataRowCol(hIT8, row, col); Buffer = cmsIT8GetDataRowCol(hIT8, row, col);
if (Buffer == NULL) return 0.0;
return ParseFloatNumber(Buffer); return ParseFloatNumber(Buffer);
} }
...@@ -2778,7 +2795,7 @@ void CMSEXPORT cmsIT8DefineDblFormat(cmsHANDLE hIT8, const char* Formatter) ...@@ -2778,7 +2795,7 @@ void CMSEXPORT cmsIT8DefineDblFormat(cmsHANDLE hIT8, const char* Formatter)
if (Formatter == NULL) if (Formatter == NULL)
strcpy(it8->DoubleFormatter, DEFAULT_DBL_FORMAT); strcpy(it8->DoubleFormatter, DEFAULT_DBL_FORMAT);
else else
strcpy(it8->DoubleFormatter, Formatter); strncpy(it8->DoubleFormatter, Formatter, sizeof(it8->DoubleFormatter));
it8 ->DoubleFormatter[sizeof(it8 ->DoubleFormatter)-1] = 0; it8 ->DoubleFormatter[sizeof(it8 ->DoubleFormatter)-1] = 0;
} }
......
...@@ -270,7 +270,7 @@ cmsBool ComputeAbsoluteIntent(cmsFloat64Number AdaptationState, ...@@ -270,7 +270,7 @@ cmsBool ComputeAbsoluteIntent(cmsFloat64Number AdaptationState,
// m2 holds CHAD from output white to D50 times abs. col. scaling // m2 holds CHAD from output white to D50 times abs. col. scaling
// Observer is not adapted, undo the chromatic adaptation // Observer is not adapted, undo the chromatic adaptation
_cmsMAT3per(m, &m3, ChromaticAdaptationMatrixOut); _cmsMAT3per(m, &m2, ChromaticAdaptationMatrixOut);
m3 = *ChromaticAdaptationMatrixIn; m3 = *ChromaticAdaptationMatrixIn;
if (!_cmsMAT3inverse(&m3, &m4)) return FALSE; if (!_cmsMAT3inverse(&m3, &m4)) return FALSE;
...@@ -411,57 +411,61 @@ cmsBool AddConversion(cmsPipeline* Result, cmsColorSpaceSignature InPCS, cmsColo ...@@ -411,57 +411,61 @@ cmsBool AddConversion(cmsPipeline* Result, cmsColorSpaceSignature InPCS, cmsColo
// Handle PCS mismatches. A specialized stage is added to the LUT in such case // Handle PCS mismatches. A specialized stage is added to the LUT in such case
switch (InPCS) { switch (InPCS) {
case cmsSigXYZData: // Input profile operates in XYZ case cmsSigXYZData: // Input profile operates in XYZ
switch (OutPCS) { switch (OutPCS) {
case cmsSigXYZData: // XYZ -> XYZ case cmsSigXYZData: // XYZ -> XYZ
if (!IsEmptyLayer(m, off)) if (!IsEmptyLayer(m, off) &&
cmsPipelineInsertStage(Result, cmsAT_END, cmsStageAllocMatrix(Result ->ContextID, 3, 3, m_as_dbl, off_as_dbl)); !cmsPipelineInsertStage(Result, cmsAT_END, cmsStageAllocMatrix(Result ->ContextID, 3, 3, m_as_dbl, off_as_dbl)))
break; return FALSE;
break;
case cmsSigLabData: // XYZ -> Lab
if (!IsEmptyLayer(m, off))
cmsPipelineInsertStage(Result, cmsAT_END, cmsStageAllocMatrix(Result ->ContextID, 3, 3, m_as_dbl, off_as_dbl));
cmsPipelineInsertStage(Result, cmsAT_END, _cmsStageAllocXYZ2Lab(Result ->ContextID));
break;
default:
return FALSE; // Colorspace mismatch
}
break;
case cmsSigLabData: // XYZ -> Lab
if (!IsEmptyLayer(m, off) &&
!cmsPipelineInsertStage(Result, cmsAT_END, cmsStageAllocMatrix(Result ->ContextID, 3, 3, m_as_dbl, off_as_dbl)))
return FALSE;
if (!cmsPipelineInsertStage(Result, cmsAT_END, _cmsStageAllocXYZ2Lab(Result ->ContextID)))
return FALSE;
break;
case cmsSigLabData: // Input profile operates in Lab default:
return FALSE; // Colorspace mismatch
}
break;
switch (OutPCS) { case cmsSigLabData: // Input profile operates in Lab
case cmsSigXYZData: // Lab -> XYZ switch (OutPCS) {
cmsPipelineInsertStage(Result, cmsAT_END, _cmsStageAllocLab2XYZ(Result ->ContextID)); case cmsSigXYZData: // Lab -> XYZ
if (!IsEmptyLayer(m, off))
cmsPipelineInsertStage(Result, cmsAT_END, cmsStageAllocMatrix(Result ->ContextID, 3, 3, m_as_dbl, off_as_dbl));
break;
case cmsSigLabData: // Lab -> Lab if (!cmsPipelineInsertStage(Result, cmsAT_END, _cmsStageAllocLab2XYZ(Result ->ContextID)))
return FALSE;
if (!IsEmptyLayer(m, off) &&
!cmsPipelineInsertStage(Result, cmsAT_END, cmsStageAllocMatrix(Result ->ContextID, 3, 3, m_as_dbl, off_as_dbl)))
return FALSE;
break;
if (!IsEmptyLayer(m, off)) { case cmsSigLabData: // Lab -> Lab
cmsPipelineInsertStage(Result, cmsAT_END, _cmsStageAllocLab2XYZ(Result ->ContextID));
cmsPipelineInsertStage(Result, cmsAT_END, cmsStageAllocMatrix(Result ->ContextID, 3, 3, m_as_dbl, off_as_dbl));
cmsPipelineInsertStage(Result, cmsAT_END, _cmsStageAllocXYZ2Lab(Result ->ContextID));
}
break;
default: if (!IsEmptyLayer(m, off)) {
return FALSE; // Mismatch if (!cmsPipelineInsertStage(Result, cmsAT_END, _cmsStageAllocLab2XYZ(Result ->ContextID)) ||
!cmsPipelineInsertStage(Result, cmsAT_END, cmsStageAllocMatrix(Result ->ContextID, 3, 3, m_as_dbl, off_as_dbl)) ||
!cmsPipelineInsertStage(Result, cmsAT_END, _cmsStageAllocXYZ2Lab(Result ->ContextID)))
return FALSE;
} }
break; break;
// On colorspaces other than PCS, check for same space
default: default:
if (InPCS != OutPCS) return FALSE; return FALSE; // Mismatch
break; }
break;
// On colorspaces other than PCS, check for same space
default:
if (InPCS != OutPCS) return FALSE;
break;
} }
return TRUE; return TRUE;
...@@ -497,7 +501,8 @@ cmsPipeline* DefaultICCintents(cmsContext ContextID, ...@@ -497,7 +501,8 @@ cmsPipeline* DefaultICCintents(cmsContext ContextID,
cmsFloat64Number AdaptationStates[], cmsFloat64Number AdaptationStates[],
cmsUInt32Number dwFlags) cmsUInt32Number dwFlags)
{ {
cmsPipeline* Lut, *Result; cmsPipeline* Lut = NULL;
cmsPipeline* Result;
cmsHPROFILE hProfile; cmsHPROFILE hProfile;
cmsMAT3 m; cmsMAT3 m;
cmsVEC3 off; cmsVEC3 off;
...@@ -593,8 +598,11 @@ cmsPipeline* DefaultICCintents(cmsContext ContextID, ...@@ -593,8 +598,11 @@ cmsPipeline* DefaultICCintents(cmsContext ContextID,
} }
// Concatenate to the output LUT // Concatenate to the output LUT
cmsPipelineCat(Result, Lut); if (!cmsPipelineCat(Result, Lut))
goto Error;
cmsPipelineFree(Lut); cmsPipelineFree(Lut);
Lut = NULL;
// Update current space // Update current space
CurrentColorSpace = ColorSpaceOut; CurrentColorSpace = ColorSpaceOut;
...@@ -604,6 +612,7 @@ cmsPipeline* DefaultICCintents(cmsContext ContextID, ...@@ -604,6 +612,7 @@ cmsPipeline* DefaultICCintents(cmsContext ContextID,
Error: Error:
if (Lut != NULL) cmsPipelineFree(Lut);
if (Result != NULL) cmsPipelineFree(Result); if (Result != NULL) cmsPipelineFree(Result);
return NULL; return NULL;
...@@ -742,7 +751,8 @@ cmsPipeline* BlackPreservingKOnlyIntents(cmsContext ContextID, ...@@ -742,7 +751,8 @@ cmsPipeline* BlackPreservingKOnlyIntents(cmsContext ContextID,
if (CLUT == NULL) goto Error; if (CLUT == NULL) goto Error;
// This is the one and only MPE in this LUT // This is the one and only MPE in this LUT
cmsPipelineInsertStage(Result, cmsAT_BEGIN, CLUT); if (!cmsPipelineInsertStage(Result, cmsAT_BEGIN, CLUT))
goto Error;
// Sample it. We cannot afford pre/post linearization this time. // Sample it. We cannot afford pre/post linearization this time.
if (!cmsStageSampleCLut16bit(CLUT, BlackPreservingGrayOnlySampler, (void*) &bp, 0)) if (!cmsStageSampleCLut16bit(CLUT, BlackPreservingGrayOnlySampler, (void*) &bp, 0))
...@@ -959,7 +969,8 @@ cmsPipeline* BlackPreservingKPlaneIntents(cmsContext ContextID, ...@@ -959,7 +969,8 @@ cmsPipeline* BlackPreservingKPlaneIntents(cmsContext ContextID,
CLUT = cmsStageAllocCLut16bit(ContextID, nGridPoints, 4, 4, NULL); CLUT = cmsStageAllocCLut16bit(ContextID, nGridPoints, 4, 4, NULL);
if (CLUT == NULL) goto Cleanup; if (CLUT == NULL) goto Cleanup;
cmsPipelineInsertStage(Result, cmsAT_BEGIN, CLUT); if (!cmsPipelineInsertStage(Result, cmsAT_BEGIN, CLUT))
goto Cleanup;
cmsStageSampleCLut16bit(CLUT, BlackPreservingSampler, (void*) &bp, 0); cmsStageSampleCLut16bit(CLUT, BlackPreservingSampler, (void*) &bp, 0);
...@@ -1057,7 +1068,7 @@ cmsUInt32Number CMSEXPORT cmsGetSupportedIntents(cmsUInt32Number nMax, cmsUInt32 ...@@ -1057,7 +1068,7 @@ cmsUInt32Number CMSEXPORT cmsGetSupportedIntents(cmsUInt32Number nMax, cmsUInt32
} }
// The plug-in registration. User can add new intents or override default routines // The plug-in registration. User can add new intents or override default routines
cmsBool _cmsRegisterRenderingIntentPlugin(cmsPluginBase* Data) cmsBool _cmsRegisterRenderingIntentPlugin(cmsContext id, cmsPluginBase* Data)
{ {
cmsPluginRenderingIntent* Plugin = (cmsPluginRenderingIntent*) Data; cmsPluginRenderingIntent* Plugin = (cmsPluginRenderingIntent*) Data;
cmsIntentsList* fl; cmsIntentsList* fl;
...@@ -1072,7 +1083,7 @@ cmsBool _cmsRegisterRenderingIntentPlugin(cmsPluginBase* Data) ...@@ -1072,7 +1083,7 @@ cmsBool _cmsRegisterRenderingIntentPlugin(cmsPluginBase* Data)
fl = SearchIntent(Plugin ->Intent); fl = SearchIntent(Plugin ->Intent);
if (fl == NULL) { if (fl == NULL) {
fl = (cmsIntentsList*) _cmsPluginMalloc(sizeof(cmsIntentsList)); fl = (cmsIntentsList*) _cmsPluginMalloc(id, sizeof(cmsIntentsList));
if (fl == NULL) return FALSE; if (fl == NULL) return FALSE;
} }
......
...@@ -302,8 +302,6 @@ _cmsSubAllocator_chunk* _cmsCreateSubAllocChunk(cmsContext ContextID, cmsUInt32N ...@@ -302,8 +302,6 @@ _cmsSubAllocator_chunk* _cmsCreateSubAllocChunk(cmsContext ContextID, cmsUInt32N
return NULL; return NULL;
} }
chunk ->BlockSize = Initial; chunk ->BlockSize = Initial;
chunk ->Used = 0; chunk ->Used = 0;
chunk ->next = NULL; chunk ->next = NULL;
......
...@@ -30,7 +30,7 @@ ...@@ -30,7 +30,7 @@
//--------------------------------------------------------------------------------- //---------------------------------------------------------------------------------
// //
// Little Color Management System // Little Color Management System
// Copyright (c) 1998-2012 Marti Maria Saguer // Copyright (c) 1998-2013 Marti Maria Saguer
// //
// Permission is hereby granted, free of charge, to any person obtaining // Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the "Software"), // a copy of this software and associated documentation files (the "Software"),
...@@ -99,7 +99,7 @@ static _cmsParametricCurvesCollection DefaultCurves = { ...@@ -99,7 +99,7 @@ static _cmsParametricCurvesCollection DefaultCurves = {
static _cmsParametricCurvesCollection* ParametricCurves = &DefaultCurves; static _cmsParametricCurvesCollection* ParametricCurves = &DefaultCurves;
// As a way to install new parametric curves // As a way to install new parametric curves
cmsBool _cmsRegisterParametricCurvesPlugin(cmsPluginBase* Data) cmsBool _cmsRegisterParametricCurvesPlugin(cmsContext id, cmsPluginBase* Data)
{ {
cmsPluginParametricCurves* Plugin = (cmsPluginParametricCurves*) Data; cmsPluginParametricCurves* Plugin = (cmsPluginParametricCurves*) Data;
_cmsParametricCurvesCollection* fl; _cmsParametricCurvesCollection* fl;
...@@ -110,7 +110,7 @@ cmsBool _cmsRegisterParametricCurvesPlugin(cmsPluginBase* Data) ...@@ -110,7 +110,7 @@ cmsBool _cmsRegisterParametricCurvesPlugin(cmsPluginBase* Data)
return TRUE; return TRUE;
} }
fl = (_cmsParametricCurvesCollection*) _cmsPluginMalloc(sizeof(_cmsParametricCurvesCollection)); fl = (_cmsParametricCurvesCollection*) _cmsPluginMalloc(id, sizeof(_cmsParametricCurvesCollection));
if (fl == NULL) return FALSE; if (fl == NULL) return FALSE;
// Copy the parameters // Copy the parameters
...@@ -258,7 +258,8 @@ cmsToneCurve* AllocateToneCurveStruct(cmsContext ContextID, cmsInt32Number nEntr ...@@ -258,7 +258,8 @@ cmsToneCurve* AllocateToneCurveStruct(cmsContext ContextID, cmsInt32Number nEntr
} }
p ->InterpParams = _cmsComputeInterpParams(ContextID, p ->nEntries, 1, 1, p->Table16, CMS_LERP_FLAGS_16BITS); p ->InterpParams = _cmsComputeInterpParams(ContextID, p ->nEntries, 1, 1, p->Table16, CMS_LERP_FLAGS_16BITS);
return p; if (p->InterpParams != NULL)
return p;
Error: Error:
if (p -> Segments) _cmsFree(ContextID, p ->Segments); if (p -> Segments) _cmsFree(ContextID, p ->Segments);
...@@ -423,7 +424,7 @@ cmsFloat64Number DefaultEvalParametricFn(cmsInt32Number Type, const cmsFloat64Nu ...@@ -423,7 +424,7 @@ cmsFloat64Number DefaultEvalParametricFn(cmsInt32Number Type, const cmsFloat64Nu
if (e > 0) if (e > 0)
Val = pow(e, Params[0]) + Params[5]; Val = pow(e, Params[0]) + Params[5];
else else
Val = 0; Val = Params[5];
} }
else else
Val = R*Params[3] + Params[6]; Val = R*Params[3] + Params[6];
...@@ -458,7 +459,7 @@ cmsFloat64Number DefaultEvalParametricFn(cmsInt32Number Type, const cmsFloat64Nu ...@@ -458,7 +459,7 @@ cmsFloat64Number DefaultEvalParametricFn(cmsInt32Number Type, const cmsFloat64Nu
e = Params[1]*R + Params[2]; e = Params[1]*R + Params[2];
if (e < 0) if (e < 0)
Val = 0; Val = Params[3];
else else
Val = pow(e, Params[0]) + Params[3]; Val = pow(e, Params[0]) + Params[3];
break; break;
...@@ -478,7 +479,7 @@ cmsFloat64Number DefaultEvalParametricFn(cmsInt32Number Type, const cmsFloat64Nu ...@@ -478,7 +479,7 @@ cmsFloat64Number DefaultEvalParametricFn(cmsInt32Number Type, const cmsFloat64Nu
e = Params[2] * pow(R, Params[0]) + Params[3]; e = Params[2] * pow(R, Params[0]) + Params[3];
if (e <= 0) if (e <= 0)
Val = 0; Val = Params[4];
else else
Val = Params[1]*log10(e) + Params[4]; Val = Params[1]*log10(e) + Params[4];
break; break;
...@@ -544,7 +545,7 @@ cmsFloat64Number EvalSegmentedFn(const cmsToneCurve *g, cmsFloat64Number R) ...@@ -544,7 +545,7 @@ cmsFloat64Number EvalSegmentedFn(const cmsToneCurve *g, cmsFloat64Number R)
// Type == 0 means segment is sampled // Type == 0 means segment is sampled
if (g ->Segments[i].Type == 0) { if (g ->Segments[i].Type == 0) {
cmsFloat32Number R1 = (cmsFloat32Number) (R - g ->Segments[i].x0); cmsFloat32Number R1 = (cmsFloat32Number) (R - g ->Segments[i].x0) / (g ->Segments[i].x1 - g ->Segments[i].x0);
cmsFloat32Number Out; cmsFloat32Number Out;
// Setup the table (TODO: clean that) // Setup the table (TODO: clean that)
...@@ -629,20 +630,21 @@ cmsToneCurve* CMSEXPORT cmsBuildSegmentedToneCurve(cmsContext ContextID, ...@@ -629,20 +630,21 @@ cmsToneCurve* CMSEXPORT cmsBuildSegmentedToneCurve(cmsContext ContextID,
// Use a segmented curve to store the floating point table // Use a segmented curve to store the floating point table
cmsToneCurve* CMSEXPORT cmsBuildTabulatedToneCurveFloat(cmsContext ContextID, cmsUInt32Number nEntries, const cmsFloat32Number values[]) cmsToneCurve* CMSEXPORT cmsBuildTabulatedToneCurveFloat(cmsContext ContextID, cmsUInt32Number nEntries, const cmsFloat32Number values[])
{ {
cmsCurveSegment Seg[2]; cmsCurveSegment Seg[3];
// Initialize segmented curve part up to 0 // A segmented tone curve should have function segments in the first and last positions
Seg[0].x0 = -1; // Initialize segmented curve part up to 0 to constant value = samples[0]
Seg[0].x0 = MINUS_INF;
Seg[0].x1 = 0; Seg[0].x1 = 0;
Seg[0].Type = 6; Seg[0].Type = 6;
Seg[0].Params[0] = 1; Seg[0].Params[0] = 1;
Seg[0].Params[1] = 0; Seg[0].Params[1] = 0;
Seg[0].Params[2] = 0; Seg[0].Params[2] = 0;
Seg[0].Params[3] = 0; Seg[0].Params[3] = values[0];
Seg[0].Params[4] = 0; Seg[0].Params[4] = 0;
// From zero to any // From zero to 1
Seg[1].x0 = 0; Seg[1].x0 = 0;
Seg[1].x1 = 1.0; Seg[1].x1 = 1.0;
Seg[1].Type = 0; Seg[1].Type = 0;
...@@ -650,7 +652,19 @@ cmsToneCurve* CMSEXPORT cmsBuildTabulatedToneCurveFloat(cmsContext ContextID, cm ...@@ -650,7 +652,19 @@ cmsToneCurve* CMSEXPORT cmsBuildTabulatedToneCurveFloat(cmsContext ContextID, cm
Seg[1].nGridPoints = nEntries; Seg[1].nGridPoints = nEntries;
Seg[1].SampledPoints = (cmsFloat32Number*) values; Seg[1].SampledPoints = (cmsFloat32Number*) values;
return cmsBuildSegmentedToneCurve(ContextID, 2, Seg); // Final segment is constant = lastsample
Seg[2].x0 = 1.0;
Seg[2].x1 = PLUS_INF;
Seg[2].Type = 6;
Seg[2].Params[0] = 1;
Seg[2].Params[1] = 0;
Seg[2].Params[2] = 0;
Seg[2].Params[3] = values[nEntries-1];
Seg[2].Params[4] = 0;
return cmsBuildSegmentedToneCurve(ContextID, 3, Seg);
} }
// Parametric curves // Parametric curves
...@@ -993,7 +1007,7 @@ cmsBool CMSEXPORT cmsSmoothToneCurve(cmsToneCurve* Tab, cmsFloat64Number lambda ...@@ -993,7 +1007,7 @@ cmsBool CMSEXPORT cmsSmoothToneCurve(cmsToneCurve* Tab, cmsFloat64Number lambda
if (Tab == NULL) return FALSE; if (Tab == NULL) return FALSE;
if (cmsIsToneCurveLinear(Tab)) return FALSE; // Nothing to do if (cmsIsToneCurveLinear(Tab)) return TRUE; // Nothing to do
nItems = Tab -> nEntries; nItems = Tab -> nEntries;
...@@ -1020,11 +1034,20 @@ cmsBool CMSEXPORT cmsSmoothToneCurve(cmsToneCurve* Tab, cmsFloat64Number lambda ...@@ -1020,11 +1034,20 @@ cmsBool CMSEXPORT cmsSmoothToneCurve(cmsToneCurve* Tab, cmsFloat64Number lambda
if (z[i] == 0.) Zeros++; if (z[i] == 0.) Zeros++;
if (z[i] >= 65535.) Poles++; if (z[i] >= 65535.) Poles++;
if (z[i] < z[i-1]) return FALSE; // Non-Monotonic if (z[i] < z[i-1]) {
cmsSignalError(Tab ->InterpParams->ContextID, cmsERROR_RANGE, "cmsSmoothToneCurve: Non-Monotonic.");
return FALSE;
}
} }
if (Zeros > (nItems / 3)) return FALSE; // Degenerated, mostly zeros if (Zeros > (nItems / 3)) {
if (Poles > (nItems / 3)) return FALSE; // Degenerated, mostly poles cmsSignalError(Tab ->InterpParams->ContextID, cmsERROR_RANGE, "cmsSmoothToneCurve: Degenerated, mostly zeros.");
return FALSE;
}
if (Poles > (nItems / 3)) {
cmsSignalError(Tab ->InterpParams->ContextID, cmsERROR_RANGE, "cmsSmoothToneCurve: Degenerated, mostly poles.");
return FALSE;
}
// Seems ok // Seems ok
for (i=0; i < nItems; i++) { for (i=0; i < nItems; i++) {
......
...@@ -249,13 +249,10 @@ int GamutSampler(register const cmsUInt16Number In[], register cmsUInt16Number O ...@@ -249,13 +249,10 @@ int GamutSampler(register const cmsUInt16Number In[], register cmsUInt16Number O
cmsFloat64Number dE1, dE2, ErrorRatio; cmsFloat64Number dE1, dE2, ErrorRatio;
// Assume in-gamut by default. // Assume in-gamut by default.
dE1 = 0.;
dE2 = 0;
ErrorRatio = 1.0; ErrorRatio = 1.0;
// Convert input to Lab // Convert input to Lab
if (t -> hInput != NULL) cmsDoTransform(t -> hInput, In, &LabIn1, 1);
cmsDoTransform(t -> hInput, In, &LabIn1, 1);
// converts from PCS to colorant. This always // converts from PCS to colorant. This always
// does return in-gamut values, // does return in-gamut values,
...@@ -267,7 +264,7 @@ int GamutSampler(register const cmsUInt16Number In[], register cmsUInt16Number O ...@@ -267,7 +264,7 @@ int GamutSampler(register const cmsUInt16Number In[], register cmsUInt16Number O
memmove(&LabIn2, &LabOut1, sizeof(cmsCIELab)); memmove(&LabIn2, &LabOut1, sizeof(cmsCIELab));
// Try again, but this time taking Check as input // Try again, but this time taking Check as input
cmsDoTransform(t -> hForward, &LabOut1, Proof2, 1); cmsDoTransform(t -> hForward, &LabOut1, Proof2, 1);
cmsDoTransform(t -> hReverse, Proof2, &LabOut2, 1); cmsDoTransform(t -> hReverse, Proof2, &LabOut2, 1);
// Take difference of direct value // Take difference of direct value
...@@ -374,7 +371,7 @@ cmsPipeline* _cmsCreateGamutCheckPipeline(cmsContext ContextID, ...@@ -374,7 +371,7 @@ cmsPipeline* _cmsCreateGamutCheckPipeline(cmsContext ContextID,
ProfileList[nGamutPCSposition] = hLab; ProfileList[nGamutPCSposition] = hLab;
BPCList[nGamutPCSposition] = 0; BPCList[nGamutPCSposition] = 0;
AdaptationList[nGamutPCSposition] = 1.0; AdaptationList[nGamutPCSposition] = 1.0;
Intents[nGamutPCSposition] = INTENT_RELATIVE_COLORIMETRIC; IntentList[nGamutPCSposition] = INTENT_RELATIVE_COLORIMETRIC;
ColorSpace = cmsGetColorSpace(hGamut); ColorSpace = cmsGetColorSpace(hGamut);
...@@ -385,45 +382,48 @@ cmsPipeline* _cmsCreateGamutCheckPipeline(cmsContext ContextID, ...@@ -385,45 +382,48 @@ cmsPipeline* _cmsCreateGamutCheckPipeline(cmsContext ContextID,
// 16 bits to Lab double // 16 bits to Lab double
Chain.hInput = cmsCreateExtendedTransform(ContextID, Chain.hInput = cmsCreateExtendedTransform(ContextID,
nGamutPCSposition + 1, nGamutPCSposition + 1,
ProfileList, ProfileList,
BPCList, BPCList,
Intents, IntentList,
AdaptationList, AdaptationList,
NULL, 0, NULL, 0,
dwFormat, TYPE_Lab_DBL, dwFormat, TYPE_Lab_DBL,
cmsFLAGS_NOCACHE); cmsFLAGS_NOCACHE);
// Does create the forward step. Lab double to device // Does create the forward step. Lab double to device
dwFormat = (CHANNELS_SH(nChannels)|BYTES_SH(2)); dwFormat = (CHANNELS_SH(nChannels)|BYTES_SH(2));
Chain.hForward = cmsCreateTransformTHR(ContextID, Chain.hForward = cmsCreateTransformTHR(ContextID,
hLab, TYPE_Lab_DBL, hLab, TYPE_Lab_DBL,
hGamut, dwFormat, hGamut, dwFormat,
INTENT_RELATIVE_COLORIMETRIC, INTENT_RELATIVE_COLORIMETRIC,
cmsFLAGS_NOCACHE); cmsFLAGS_NOCACHE);
// Does create the backwards step // Does create the backwards step
Chain.hReverse = cmsCreateTransformTHR(ContextID, hGamut, dwFormat, Chain.hReverse = cmsCreateTransformTHR(ContextID, hGamut, dwFormat,
hLab, TYPE_Lab_DBL, hLab, TYPE_Lab_DBL,
INTENT_RELATIVE_COLORIMETRIC, INTENT_RELATIVE_COLORIMETRIC,
cmsFLAGS_NOCACHE); cmsFLAGS_NOCACHE);
// All ok? // All ok?
if (Chain.hForward && Chain.hReverse) { if (Chain.hInput && Chain.hForward && Chain.hReverse) {
// Go on, try to compute gamut LUT from PCS. This consist on a single channel containing // Go on, try to compute gamut LUT from PCS. This consist on a single channel containing
// dE when doing a transform back and forth on the colorimetric intent. // dE when doing a transform back and forth on the colorimetric intent.
Gamut = cmsPipelineAlloc(ContextID, 3, 1); Gamut = cmsPipelineAlloc(ContextID, 3, 1);
if (Gamut != NULL) { if (Gamut != NULL) {
CLUT = cmsStageAllocCLut16bit(ContextID, nGridpoints, nChannels, 1, NULL); CLUT = cmsStageAllocCLut16bit(ContextID, nGridpoints, nChannels, 1, NULL);
cmsPipelineInsertStage(Gamut, cmsAT_BEGIN, CLUT); if (!cmsPipelineInsertStage(Gamut, cmsAT_BEGIN, CLUT)) {
cmsPipelineFree(Gamut);
cmsStageSampleCLut16bit(CLUT, GamutSampler, (void*) &Chain, 0); Gamut = NULL;
}
else {
cmsStageSampleCLut16bit(CLUT, GamutSampler, (void*) &Chain, 0);
}
} }
} }
else else
......
...@@ -83,7 +83,6 @@ cmsBool _cmsRegisterInterpPlugin(cmsPluginBase* Data) ...@@ -83,7 +83,6 @@ cmsBool _cmsRegisterInterpPlugin(cmsPluginBase* Data)
// Set the interpolation method // Set the interpolation method
cmsBool _cmsSetInterpolationRoutine(cmsInterpParams* p) cmsBool _cmsSetInterpolationRoutine(cmsInterpParams* p)
{ {
// Invoke factory, possibly in the Plug-in // Invoke factory, possibly in the Plug-in
...@@ -831,7 +830,7 @@ void Eval4Inputs(register const cmsUInt16Number Input[], ...@@ -831,7 +830,7 @@ void Eval4Inputs(register const cmsUInt16Number Input[],
register cmsUInt16Number Output[], register cmsUInt16Number Output[],
register const cmsInterpParams* p16) register const cmsInterpParams* p16)
{ {
const cmsUInt16Number* LutTable = (cmsUInt16Number*) p16 -> Table; const cmsUInt16Number* LutTable;
cmsS15Fixed16Number fk; cmsS15Fixed16Number fk;
cmsS15Fixed16Number k0, rk; cmsS15Fixed16Number k0, rk;
int K0, K1; int K0, K1;
......
...@@ -154,7 +154,6 @@ cmsIOHANDLER* CMSEXPORT cmsOpenIOhandlerFromNULL(cmsContext ContextID) ...@@ -154,7 +154,6 @@ cmsIOHANDLER* CMSEXPORT cmsOpenIOhandlerFromNULL(cmsContext ContextID)
return iohandler; return iohandler;
Error: Error:
if (fm) _cmsFree(ContextID, fm);
if (iohandler) _cmsFree(ContextID, iohandler); if (iohandler) _cmsFree(ContextID, iohandler);
return NULL; return NULL;
...@@ -223,12 +222,17 @@ cmsUInt32Number MemoryTell(struct _cms_io_handler* iohandler) ...@@ -223,12 +222,17 @@ cmsUInt32Number MemoryTell(struct _cms_io_handler* iohandler)
// Writes data to memory, also keeps used space for further reference. // Writes data to memory, also keeps used space for further reference.
static static
cmsBool MemoryWrite(struct _cms_io_handler* iohandler, cmsUInt32Number size, const void *Ptr) cmsBool MemoryWrite(struct _cms_io_handler* iohandler, cmsUInt32Number size, const void *Ptr)
{ {
FILEMEM* ResData = (FILEMEM*) iohandler ->stream; FILEMEM* ResData = (FILEMEM*) iohandler ->stream;
if (ResData == NULL) return FALSE; // Housekeeping if (ResData == NULL) return FALSE; // Housekeeping
// Check for available space. Clip.
if (iohandler ->UsedSpace + size > ResData->Size) {
size = ResData ->Size - iohandler ->UsedSpace;
}
if (size == 0) return TRUE; // Write zero bytes is ok, but does nothing if (size == 0) return TRUE; // Write zero bytes is ok, but does nothing
memmove(ResData ->Block + ResData ->Pointer, Ptr, size); memmove(ResData ->Block + ResData ->Pointer, Ptr, size);
...@@ -350,7 +354,7 @@ cmsUInt32Number FileRead(cmsIOHANDLER* iohandler, void *Buffer, cmsUInt32Number ...@@ -350,7 +354,7 @@ cmsUInt32Number FileRead(cmsIOHANDLER* iohandler, void *Buffer, cmsUInt32Number
return nReaded; return nReaded;
} }
// Position file pointer in the file // Postion file pointer in the file
static static
cmsBool FileSeek(cmsIOHANDLER* iohandler, cmsUInt32Number offset) cmsBool FileSeek(cmsIOHANDLER* iohandler, cmsUInt32Number offset)
{ {
...@@ -389,13 +393,15 @@ cmsBool FileClose(cmsIOHANDLER* iohandler) ...@@ -389,13 +393,15 @@ cmsBool FileClose(cmsIOHANDLER* iohandler)
return TRUE; return TRUE;
} }
// Create a iohandler for disk based files. if FileName is NULL, then 'stream' member is also set // Create a iohandler for disk based files.
// to NULL and no real writting is performed. This only happens in writting access mode
cmsIOHANDLER* CMSEXPORT cmsOpenIOhandlerFromFile(cmsContext ContextID, const char* FileName, const char* AccessMode) cmsIOHANDLER* CMSEXPORT cmsOpenIOhandlerFromFile(cmsContext ContextID, const char* FileName, const char* AccessMode)
{ {
cmsIOHANDLER* iohandler = NULL; cmsIOHANDLER* iohandler = NULL;
FILE* fm = NULL; FILE* fm = NULL;
_cmsAssert(FileName != NULL);
_cmsAssert(AccessMode != NULL);
iohandler = (cmsIOHANDLER*) _cmsMallocZero(ContextID, sizeof(cmsIOHANDLER)); iohandler = (cmsIOHANDLER*) _cmsMallocZero(ContextID, sizeof(cmsIOHANDLER));
if (iohandler == NULL) return NULL; if (iohandler == NULL) return NULL;
...@@ -432,11 +438,8 @@ cmsIOHANDLER* CMSEXPORT cmsOpenIOhandlerFromFile(cmsContext ContextID, const cha ...@@ -432,11 +438,8 @@ cmsIOHANDLER* CMSEXPORT cmsOpenIOhandlerFromFile(cmsContext ContextID, const cha
iohandler ->UsedSpace = 0; iohandler ->UsedSpace = 0;
// Keep track of the original file // Keep track of the original file
if (FileName != NULL) { strncpy(iohandler -> PhysicalFile, FileName, sizeof(iohandler -> PhysicalFile)-1);
iohandler -> PhysicalFile[sizeof(iohandler -> PhysicalFile)-1] = 0;
strncpy(iohandler -> PhysicalFile, FileName, sizeof(iohandler -> PhysicalFile)-1);
iohandler -> PhysicalFile[sizeof(iohandler -> PhysicalFile)-1] = 0;
}
iohandler ->Read = FileRead; iohandler ->Read = FileRead;
iohandler ->Seek = FileSeek; iohandler ->Seek = FileSeek;
...@@ -643,10 +646,13 @@ cmsBool _cmsReadHeader(_cmsICCPROFILE* Icc) ...@@ -643,10 +646,13 @@ cmsBool _cmsReadHeader(_cmsICCPROFILE* Icc)
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 -> 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);
Icc -> creator = _cmsAdjustEndianess32(Header.creator);
_cmsAdjustEndianess64(&Icc -> attributes, &Header.attributes); _cmsAdjustEndianess64(&Icc -> attributes, &Header.attributes);
Icc -> Version = _cmsAdjustEndianess32(Header.version); Icc -> Version = _cmsAdjustEndianess32(Header.version);
...@@ -815,28 +821,33 @@ void CMSEXPORT cmsSetHeaderFlags(cmsHPROFILE hProfile, cmsUInt32Number Flags) ...@@ -815,28 +821,33 @@ void CMSEXPORT cmsSetHeaderFlags(cmsHPROFILE hProfile, cmsUInt32Number Flags)
cmsUInt32Number CMSEXPORT cmsGetHeaderManufacturer(cmsHPROFILE hProfile) cmsUInt32Number CMSEXPORT cmsGetHeaderManufacturer(cmsHPROFILE hProfile)
{ {
_cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile;
return (cmsUInt32Number) Icc ->manufacturer; return Icc ->manufacturer;
} }
void CMSEXPORT cmsSetHeaderManufacturer(cmsHPROFILE hProfile, cmsUInt32Number manufacturer) void CMSEXPORT cmsSetHeaderManufacturer(cmsHPROFILE hProfile, cmsUInt32Number manufacturer)
{ {
_cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile;
Icc -> manufacturer = (cmsUInt32Number) manufacturer; Icc -> manufacturer = manufacturer;
}
cmsUInt32Number CMSEXPORT cmsGetHeaderCreator(cmsHPROFILE hProfile)
{
_cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile;
return Icc ->creator;
} }
cmsUInt32Number CMSEXPORT cmsGetHeaderModel(cmsHPROFILE hProfile) cmsUInt32Number CMSEXPORT cmsGetHeaderModel(cmsHPROFILE hProfile)
{ {
_cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile;
return (cmsUInt32Number) Icc ->model; return Icc ->model;
} }
void CMSEXPORT cmsSetHeaderModel(cmsHPROFILE hProfile, cmsUInt32Number model) void CMSEXPORT cmsSetHeaderModel(cmsHPROFILE hProfile, cmsUInt32Number model)
{ {
_cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile;
Icc -> model = (cmsUInt32Number) model; Icc -> model = model;
} }
void CMSEXPORT cmsGetHeaderAttributes(cmsHPROFILE hProfile, cmsUInt64Number* Flags) void CMSEXPORT cmsGetHeaderAttributes(cmsHPROFILE hProfile, cmsUInt64Number* Flags)
{ {
_cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile;
...@@ -1073,7 +1084,6 @@ cmsHPROFILE CMSEXPORT cmsOpenProfileFromMem(const void* MemPtr, cmsUInt32Number ...@@ -1073,7 +1084,6 @@ cmsHPROFILE CMSEXPORT cmsOpenProfileFromMem(const void* MemPtr, cmsUInt32Number
return cmsOpenProfileFromMemTHR(NULL, MemPtr, dwSize); return cmsOpenProfileFromMemTHR(NULL, MemPtr, dwSize);
} }
static static
cmsBool SanityCheck(_cmsICCPROFILE* profile) cmsBool SanityCheck(_cmsICCPROFILE* profile)
{ {
...@@ -1112,11 +1122,13 @@ cmsBool SaveTags(_cmsICCPROFILE* Icc, _cmsICCPROFILE* FileOrig) ...@@ -1112,11 +1122,13 @@ cmsBool SaveTags(_cmsICCPROFILE* Icc, _cmsICCPROFILE* FileOrig)
cmsIOHANDLER* io = Icc ->IOhandler; cmsIOHANDLER* io = Icc ->IOhandler;
cmsTagDescriptor* TagDescriptor; cmsTagDescriptor* TagDescriptor;
cmsTagTypeSignature TypeBase; cmsTagTypeSignature TypeBase;
cmsTagTypeSignature Type;
cmsTagTypeHandler* TypeHandler; cmsTagTypeHandler* TypeHandler;
cmsFloat64Number Version = cmsGetProfileVersion((cmsHPROFILE) Icc);
cmsTagTypeHandler LocalTypeHandler;
for (i=0; i < Icc -> TagCount; i++) { for (i=0; i < Icc -> TagCount; i++) {
if (Icc ->TagNames[i] == 0) continue; if (Icc ->TagNames[i] == 0) continue;
// Linked tags are not written // Linked tags are not written
...@@ -1168,7 +1180,16 @@ cmsBool SaveTags(_cmsICCPROFILE* Icc, _cmsICCPROFILE* FileOrig) ...@@ -1168,7 +1180,16 @@ cmsBool SaveTags(_cmsICCPROFILE* Icc, _cmsICCPROFILE* FileOrig)
TagDescriptor = _cmsGetTagDescriptor(Icc -> TagNames[i]); TagDescriptor = _cmsGetTagDescriptor(Icc -> TagNames[i]);
if (TagDescriptor == NULL) continue; // Unsupported, ignore it if (TagDescriptor == NULL) continue; // Unsupported, ignore it
TypeHandler = Icc ->TagTypeHandlers[i]; if (TagDescriptor ->DecideType != NULL) {
Type = TagDescriptor ->DecideType(Version, Data);
}
else {
Type = TagDescriptor ->SupportedTypes[0];
}
TypeHandler = _cmsGetTagTypeHandler(Type);
if (TypeHandler == NULL) { if (TypeHandler == NULL) {
cmsSignalError(Icc ->ContextID, cmsERROR_INTERNAL, "(Internal) no handler for tag %x", Icc -> TagNames[i]); cmsSignalError(Icc ->ContextID, cmsERROR_INTERNAL, "(Internal) no handler for tag %x", Icc -> TagNames[i]);
...@@ -1179,9 +1200,10 @@ cmsBool SaveTags(_cmsICCPROFILE* Icc, _cmsICCPROFILE* FileOrig) ...@@ -1179,9 +1200,10 @@ cmsBool SaveTags(_cmsICCPROFILE* Icc, _cmsICCPROFILE* FileOrig)
if (!_cmsWriteTypeBase(io, TypeBase)) if (!_cmsWriteTypeBase(io, TypeBase))
return FALSE; return FALSE;
TypeHandler ->ContextID = Icc ->ContextID; LocalTypeHandler = *TypeHandler;
TypeHandler ->ICCVersion = Icc ->Version; LocalTypeHandler.ContextID = Icc ->ContextID;
if (!TypeHandler ->WritePtr(TypeHandler, io, Data, TagDescriptor ->ElemCount)) { LocalTypeHandler.ICCVersion = Icc ->Version;
if (!LocalTypeHandler.WritePtr(&LocalTypeHandler, io, Data, TagDescriptor ->ElemCount)) {
char String[5]; char String[5];
...@@ -1318,8 +1340,8 @@ cmsBool CMSEXPORT cmsSaveProfileToMem(cmsHPROFILE hProfile, void *MemPtr, cmsUIn ...@@ -1318,8 +1340,8 @@ cmsBool CMSEXPORT cmsSaveProfileToMem(cmsHPROFILE hProfile, void *MemPtr, cmsUIn
// Should we just calculate the needed space? // Should we just calculate the needed space?
if (MemPtr == NULL) { if (MemPtr == NULL) {
*BytesNeeded = cmsSaveProfileToIOhandler(hProfile, NULL); *BytesNeeded = cmsSaveProfileToIOhandler(hProfile, NULL);
return (*BytesNeeded == 0 ? FALSE : TRUE); return (*BytesNeeded == 0 ? FALSE : TRUE);
} }
// That is a real write operation // That is a real write operation
...@@ -1357,10 +1379,11 @@ cmsBool CMSEXPORT cmsCloseProfile(cmsHPROFILE hProfile) ...@@ -1357,10 +1379,11 @@ cmsBool CMSEXPORT cmsCloseProfile(cmsHPROFILE hProfile)
cmsTagTypeHandler* TypeHandler = Icc ->TagTypeHandlers[i]; cmsTagTypeHandler* TypeHandler = Icc ->TagTypeHandlers[i];
if (TypeHandler != NULL) { if (TypeHandler != NULL) {
cmsTagTypeHandler LocalTypeHandler = *TypeHandler;
TypeHandler ->ContextID = Icc ->ContextID; // As an additional parameters LocalTypeHandler.ContextID = Icc ->ContextID; // As an additional parameters
TypeHandler ->ICCVersion = Icc ->Version; LocalTypeHandler.ICCVersion = Icc ->Version;
TypeHandler ->FreePtr(TypeHandler, Icc -> TagPtrs[i]); LocalTypeHandler.FreePtr(&LocalTypeHandler, Icc -> TagPtrs[i]);
} }
else else
_cmsFree(Icc ->ContextID, Icc ->TagPtrs[i]); _cmsFree(Icc ->ContextID, Icc ->TagPtrs[i]);
...@@ -1404,6 +1427,7 @@ void* CMSEXPORT cmsReadTag(cmsHPROFILE hProfile, cmsTagSignature sig) ...@@ -1404,6 +1427,7 @@ void* CMSEXPORT cmsReadTag(cmsHPROFILE hProfile, cmsTagSignature sig)
_cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile;
cmsIOHANDLER* io = Icc ->IOhandler; cmsIOHANDLER* io = Icc ->IOhandler;
cmsTagTypeHandler* TypeHandler; cmsTagTypeHandler* TypeHandler;
cmsTagTypeHandler LocalTypeHandler;
cmsTagDescriptor* TagDescriptor; cmsTagDescriptor* TagDescriptor;
cmsTagTypeSignature BaseType; cmsTagTypeSignature BaseType;
cmsUInt32Number Offset, TagSize; cmsUInt32Number Offset, TagSize;
...@@ -1427,7 +1451,7 @@ void* CMSEXPORT cmsReadTag(cmsHPROFILE hProfile, cmsTagSignature sig) ...@@ -1427,7 +1451,7 @@ void* CMSEXPORT cmsReadTag(cmsHPROFILE hProfile, cmsTagSignature sig)
// Seek to its location // Seek to its location
if (!io -> Seek(io, Offset)) if (!io -> Seek(io, Offset))
return NULL; return NULL;
// Search for support on this tag // Search for support on this tag
TagDescriptor = _cmsGetTagDescriptor(sig); TagDescriptor = _cmsGetTagDescriptor(sig);
...@@ -1444,14 +1468,15 @@ void* CMSEXPORT cmsReadTag(cmsHPROFILE hProfile, cmsTagSignature sig) ...@@ -1444,14 +1468,15 @@ void* CMSEXPORT cmsReadTag(cmsHPROFILE hProfile, cmsTagSignature sig)
// Get type handler // Get type handler
TypeHandler = _cmsGetTagTypeHandler(BaseType); TypeHandler = _cmsGetTagTypeHandler(BaseType);
if (TypeHandler == NULL) return NULL; if (TypeHandler == NULL) return NULL;
LocalTypeHandler = *TypeHandler;
// Read the tag // Read the tag
Icc -> TagTypeHandlers[n] = TypeHandler; Icc -> TagTypeHandlers[n] = TypeHandler;
TypeHandler ->ContextID = Icc ->ContextID; LocalTypeHandler.ContextID = Icc ->ContextID;
TypeHandler ->ICCVersion = Icc ->Version; LocalTypeHandler.ICCVersion = Icc ->Version;
Icc -> TagPtrs[n] = TypeHandler ->ReadPtr(TypeHandler, io, &ElemCount, TagSize); Icc -> TagPtrs[n] = LocalTypeHandler.ReadPtr(&LocalTypeHandler, io, &ElemCount, TagSize);
// The tag type is supported, but something wrong happend and we cannot read the tag. // The tag type is supported, but something wrong happend and we cannot read the tag.
// let know the user about this (although it is just a warning) // let know the user about this (although it is just a warning)
...@@ -1472,7 +1497,7 @@ void* CMSEXPORT cmsReadTag(cmsHPROFILE hProfile, cmsTagSignature sig) ...@@ -1472,7 +1497,7 @@ void* CMSEXPORT cmsReadTag(cmsHPROFILE hProfile, cmsTagSignature sig)
_cmsTagSignature2String(String, sig); _cmsTagSignature2String(String, sig);
cmsSignalError(Icc ->ContextID, cmsERROR_CORRUPTION_DETECTED, "'%s' Inconsistent number of items: expected %d, got %d", cmsSignalError(Icc ->ContextID, cmsERROR_CORRUPTION_DETECTED, "'%s' Inconsistent number of items: expected %d, got %d",
String, TagDescriptor ->ElemCount, ElemCount); String, TagDescriptor ->ElemCount, ElemCount);
} }
...@@ -1504,6 +1529,7 @@ cmsBool CMSEXPORT cmsWriteTag(cmsHPROFILE hProfile, cmsTagSignature sig, const v ...@@ -1504,6 +1529,7 @@ cmsBool CMSEXPORT cmsWriteTag(cmsHPROFILE hProfile, cmsTagSignature sig, const v
{ {
_cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile;
cmsTagTypeHandler* TypeHandler = NULL; cmsTagTypeHandler* TypeHandler = NULL;
cmsTagTypeHandler LocalTypeHandler;
cmsTagDescriptor* TagDescriptor = NULL; cmsTagDescriptor* TagDescriptor = NULL;
cmsTagTypeSignature Type; cmsTagTypeSignature Type;
int i; int i;
...@@ -1534,9 +1560,10 @@ cmsBool CMSEXPORT cmsWriteTag(cmsHPROFILE hProfile, cmsTagSignature sig, const v ...@@ -1534,9 +1560,10 @@ cmsBool CMSEXPORT cmsWriteTag(cmsHPROFILE hProfile, cmsTagSignature sig, const v
if (TypeHandler != NULL) { if (TypeHandler != NULL) {
TypeHandler ->ContextID = Icc ->ContextID; // As an additional parameter LocalTypeHandler = *TypeHandler;
TypeHandler ->ICCVersion = Icc ->Version; LocalTypeHandler.ContextID = Icc ->ContextID; // As an additional parameter
TypeHandler->FreePtr(TypeHandler, Icc -> TagPtrs[i]); LocalTypeHandler.ICCVersion = Icc ->Version;
LocalTypeHandler.FreePtr(&LocalTypeHandler, Icc -> TagPtrs[i]);
} }
} }
} }
...@@ -1575,7 +1602,7 @@ cmsBool CMSEXPORT cmsWriteTag(cmsHPROFILE hProfile, cmsTagSignature sig, const v ...@@ -1575,7 +1602,7 @@ cmsBool CMSEXPORT cmsWriteTag(cmsHPROFILE hProfile, cmsTagSignature sig, const v
// Let the tag descriptor to decide the type base on depending on // Let the tag descriptor to decide the type base on depending on
// the data. This is useful for example on parametric curves, where // the data. This is useful for example on parametric curves, where
// curves specified by a table cannot be saved as parametric and needs // curves specified by a table cannot be saved as parametric and needs
// to be revented to single v2-curves, even on v4 profiles. // to be casted to single v2-curves, even on v4 profiles.
Type = TagDescriptor ->DecideType(Version, data); Type = TagDescriptor ->DecideType(Version, data);
} }
...@@ -1613,9 +1640,10 @@ cmsBool CMSEXPORT cmsWriteTag(cmsHPROFILE hProfile, cmsTagSignature sig, const v ...@@ -1613,9 +1640,10 @@ cmsBool CMSEXPORT cmsWriteTag(cmsHPROFILE hProfile, cmsTagSignature sig, const v
Icc ->TagSizes[i] = 0; Icc ->TagSizes[i] = 0;
Icc ->TagOffsets[i] = 0; Icc ->TagOffsets[i] = 0;
TypeHandler ->ContextID = Icc ->ContextID; LocalTypeHandler = *TypeHandler;
TypeHandler ->ICCVersion = Icc ->Version; LocalTypeHandler.ContextID = Icc ->ContextID;
Icc ->TagPtrs[i] = TypeHandler ->DupPtr(TypeHandler, data, TagDescriptor ->ElemCount); LocalTypeHandler.ICCVersion = Icc ->Version;
Icc ->TagPtrs[i] = LocalTypeHandler.DupPtr(&LocalTypeHandler, data, TagDescriptor ->ElemCount);
if (Icc ->TagPtrs[i] == NULL) { if (Icc ->TagPtrs[i] == NULL) {
...@@ -1642,6 +1670,7 @@ cmsInt32Number CMSEXPORT cmsReadRawTag(cmsHPROFILE hProfile, cmsTagSignature sig ...@@ -1642,6 +1670,7 @@ cmsInt32Number CMSEXPORT cmsReadRawTag(cmsHPROFILE hProfile, cmsTagSignature sig
int i; int i;
cmsIOHANDLER* MemIO; cmsIOHANDLER* MemIO;
cmsTagTypeHandler* TypeHandler = NULL; cmsTagTypeHandler* TypeHandler = NULL;
cmsTagTypeHandler LocalTypeHandler;
cmsTagDescriptor* TagDescriptor = NULL; cmsTagDescriptor* TagDescriptor = NULL;
cmsUInt32Number rc; cmsUInt32Number rc;
cmsUInt32Number Offset, TagSize; cmsUInt32Number Offset, TagSize;
...@@ -1657,15 +1686,16 @@ cmsInt32Number CMSEXPORT cmsReadRawTag(cmsHPROFILE hProfile, cmsTagSignature sig ...@@ -1657,15 +1686,16 @@ cmsInt32Number CMSEXPORT cmsReadRawTag(cmsHPROFILE hProfile, cmsTagSignature sig
Offset = Icc ->TagOffsets[i]; Offset = Icc ->TagOffsets[i];
TagSize = Icc ->TagSizes[i]; TagSize = Icc ->TagSizes[i];
// read the data directly, don't keep copy // read the data directly, don't keep copy
if (data != NULL) { if (data != NULL) {
if (BufferSize < TagSize) if (BufferSize < TagSize)
TagSize = BufferSize; TagSize = BufferSize;
if (!Icc ->IOhandler ->Seek(Icc ->IOhandler, Offset)) return 0; if (!Icc ->IOhandler ->Seek(Icc ->IOhandler, Offset)) return 0;
if (!Icc ->IOhandler ->Read(Icc ->IOhandler, data, 1, TagSize)) return 0; if (!Icc ->IOhandler ->Read(Icc ->IOhandler, data, 1, TagSize)) return 0;
return TagSize;
} }
return Icc ->TagSizes[i]; return Icc ->TagSizes[i];
...@@ -1679,9 +1709,11 @@ cmsInt32Number CMSEXPORT cmsReadRawTag(cmsHPROFILE hProfile, cmsTagSignature sig ...@@ -1679,9 +1709,11 @@ cmsInt32Number CMSEXPORT cmsReadRawTag(cmsHPROFILE hProfile, cmsTagSignature sig
TagSize = Icc ->TagSizes[i]; TagSize = Icc ->TagSizes[i];
if (BufferSize < TagSize) if (BufferSize < TagSize)
TagSize = BufferSize; TagSize = BufferSize;
memmove(data, Icc ->TagPtrs[i], TagSize); memmove(data, Icc ->TagPtrs[i], TagSize);
return TagSize;
} }
return Icc ->TagSizes[i]; return Icc ->TagSizes[i];
...@@ -1697,7 +1729,7 @@ cmsInt32Number CMSEXPORT cmsReadRawTag(cmsHPROFILE hProfile, cmsTagSignature sig ...@@ -1697,7 +1729,7 @@ cmsInt32Number CMSEXPORT cmsReadRawTag(cmsHPROFILE hProfile, cmsTagSignature sig
if (data == NULL) { if (data == NULL) {
MemIO = cmsOpenIOhandlerFromNULL(cmsGetProfileContextID(hProfile)); MemIO = cmsOpenIOhandlerFromNULL(cmsGetProfileContextID(hProfile));
} else{ } else{
MemIO = cmsOpenIOhandlerFromMem(cmsGetProfileContextID(hProfile), data, BufferSize, "w"); MemIO = cmsOpenIOhandlerFromMem(cmsGetProfileContextID(hProfile), data, BufferSize, "w");
} }
if (MemIO == NULL) return 0; if (MemIO == NULL) return 0;
...@@ -1705,20 +1737,22 @@ cmsInt32Number CMSEXPORT cmsReadRawTag(cmsHPROFILE hProfile, cmsTagSignature sig ...@@ -1705,20 +1737,22 @@ cmsInt32Number CMSEXPORT cmsReadRawTag(cmsHPROFILE hProfile, cmsTagSignature sig
TypeHandler = Icc ->TagTypeHandlers[i]; TypeHandler = Icc ->TagTypeHandlers[i];
TagDescriptor = _cmsGetTagDescriptor(sig); TagDescriptor = _cmsGetTagDescriptor(sig);
if (TagDescriptor == NULL) { if (TagDescriptor == NULL) {
cmsCloseIOhandler(MemIO); cmsCloseIOhandler(MemIO);
return 0; return 0;
} }
// FIXME: No handling for TypeHandler == NULL here?
// Serialize // Serialize
TypeHandler ->ContextID = Icc ->ContextID; LocalTypeHandler = *TypeHandler;
TypeHandler ->ICCVersion = Icc ->Version; LocalTypeHandler.ContextID = Icc ->ContextID;
LocalTypeHandler.ICCVersion = Icc ->Version;
if (!_cmsWriteTypeBase(MemIO, TypeHandler ->Signature)) { if (!_cmsWriteTypeBase(MemIO, TypeHandler ->Signature)) {
cmsCloseIOhandler(MemIO); cmsCloseIOhandler(MemIO);
return 0; return 0;
} }
if (!TypeHandler ->WritePtr(TypeHandler, MemIO, Object, TagDescriptor ->ElemCount)) { if (!LocalTypeHandler.WritePtr(&LocalTypeHandler, MemIO, Object, TagDescriptor ->ElemCount)) {
cmsCloseIOhandler(MemIO); cmsCloseIOhandler(MemIO);
return 0; return 0;
} }
...@@ -1756,7 +1790,7 @@ cmsBool CMSEXPORT cmsWriteRawTag(cmsHPROFILE hProfile, cmsTagSignature sig, cons ...@@ -1756,7 +1790,7 @@ cmsBool CMSEXPORT cmsWriteRawTag(cmsHPROFILE hProfile, cmsTagSignature sig, cons
// Using this function you can collapse several tag entries to the same block in the profile // Using this function you can collapse several tag entries to the same block in the profile
cmsBool CMSEXPORT cmsLinkTag(cmsHPROFILE hProfile, cmsTagSignature sig, cmsTagSignature dest) cmsBool CMSEXPORT cmsLinkTag(cmsHPROFILE hProfile, cmsTagSignature sig, cmsTagSignature dest)
{ {
_cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile;
int i; int i;
if (!_cmsNewTag(Icc, sig, &i)) return FALSE; if (!_cmsNewTag(Icc, sig, &i)) return FALSE;
......
...@@ -129,7 +129,6 @@ cmsBool _cmsReadCHAD(cmsMAT3* Dest, cmsHPROFILE hProfile) ...@@ -129,7 +129,6 @@ cmsBool _cmsReadCHAD(cmsMAT3* Dest, cmsHPROFILE hProfile)
Tag = (cmsMAT3*) cmsReadTag(hProfile, cmsSigChromaticAdaptationTag); Tag = (cmsMAT3*) cmsReadTag(hProfile, cmsSigChromaticAdaptationTag);
if (Tag != NULL) { if (Tag != NULL) {
*Dest = *Tag; *Dest = *Tag;
return TRUE; return TRUE;
} }
...@@ -193,7 +192,8 @@ cmsPipeline* BuildGrayInputMatrixPipeline(cmsHPROFILE hProfile) ...@@ -193,7 +192,8 @@ cmsPipeline* BuildGrayInputMatrixPipeline(cmsHPROFILE hProfile)
if (GrayTRC == NULL) return NULL; if (GrayTRC == NULL) return NULL;
Lut = cmsPipelineAlloc(ContextID, 1, 3); Lut = cmsPipelineAlloc(ContextID, 1, 3);
if (Lut == NULL) return NULL; if (Lut == NULL)
goto Error;
if (cmsGetPCS(hProfile) == cmsSigLabData) { if (cmsGetPCS(hProfile) == cmsSigLabData) {
...@@ -204,28 +204,35 @@ cmsPipeline* BuildGrayInputMatrixPipeline(cmsHPROFILE hProfile) ...@@ -204,28 +204,35 @@ cmsPipeline* BuildGrayInputMatrixPipeline(cmsHPROFILE hProfile)
EmptyTab = cmsBuildTabulatedToneCurve16(ContextID, 2, Zero); EmptyTab = cmsBuildTabulatedToneCurve16(ContextID, 2, Zero);
if (EmptyTab == NULL) { if (EmptyTab == NULL)
goto Error;
cmsPipelineFree(Lut);
return NULL;
}
LabCurves[0] = GrayTRC; LabCurves[0] = GrayTRC;
LabCurves[1] = EmptyTab; LabCurves[1] = EmptyTab;
LabCurves[2] = EmptyTab; LabCurves[2] = EmptyTab;
cmsPipelineInsertStage(Lut, cmsAT_END, cmsStageAllocMatrix(ContextID, 3, 1, OneToThreeInputMatrix, NULL)); if (!cmsPipelineInsertStage(Lut, cmsAT_END, cmsStageAllocMatrix(ContextID, 3, 1, OneToThreeInputMatrix, NULL)) ||
cmsPipelineInsertStage(Lut, cmsAT_END, cmsStageAllocToneCurves(ContextID, 3, LabCurves)); !cmsPipelineInsertStage(Lut, cmsAT_END, cmsStageAllocToneCurves(ContextID, 3, LabCurves))) {
cmsFreeToneCurve(EmptyTab);
goto Error;
}
cmsFreeToneCurve(EmptyTab); cmsFreeToneCurve(EmptyTab);
} }
else { else {
cmsPipelineInsertStage(Lut, cmsAT_END, cmsStageAllocToneCurves(ContextID, 1, &GrayTRC));
cmsPipelineInsertStage(Lut, cmsAT_END, cmsStageAllocMatrix(ContextID, 3, 1, GrayInputMatrix, NULL)); if (!cmsPipelineInsertStage(Lut, cmsAT_END, cmsStageAllocToneCurves(ContextID, 1, &GrayTRC)) ||
!cmsPipelineInsertStage(Lut, cmsAT_END, cmsStageAllocMatrix(ContextID, 3, 1, GrayInputMatrix, NULL)))
goto Error;
} }
return Lut; return Lut;
Error:
cmsFreeToneCurve(GrayTRC);
cmsPipelineFree(Lut);
return NULL;
} }
// RGB Matrix shaper // RGB Matrix shaper
...@@ -259,49 +266,31 @@ cmsPipeline* BuildRGBInputMatrixShaper(cmsHPROFILE hProfile) ...@@ -259,49 +266,31 @@ cmsPipeline* BuildRGBInputMatrixShaper(cmsHPROFILE hProfile)
Lut = cmsPipelineAlloc(ContextID, 3, 3); Lut = cmsPipelineAlloc(ContextID, 3, 3);
if (Lut != NULL) { if (Lut != NULL) {
cmsPipelineInsertStage(Lut, cmsAT_END, cmsStageAllocToneCurves(ContextID, 3, Shapes)); if (!cmsPipelineInsertStage(Lut, cmsAT_END, cmsStageAllocToneCurves(ContextID, 3, Shapes)) ||
cmsPipelineInsertStage(Lut, cmsAT_END, cmsStageAllocMatrix(ContextID, 3, 3, (cmsFloat64Number*) &Mat, NULL)); !cmsPipelineInsertStage(Lut, cmsAT_END, cmsStageAllocMatrix(ContextID, 3, 3, (cmsFloat64Number*) &Mat, NULL)))
goto Error;
// Note that it is certainly possible a single profile would have a LUT based // Note that it is certainly possible a single profile would have a LUT based
// tag for output working in lab and a matrix-shaper for the fallback cases. // tag for output working in lab and a matrix-shaper for the fallback cases.
// This is not allowed by the spec, but this code is tolerant to those cases // This is not allowed by the spec, but this code is tolerant to those cases
if (cmsGetPCS(hProfile) == cmsSigLabData) { if (cmsGetPCS(hProfile) == cmsSigLabData) {
cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageAllocXYZ2Lab(ContextID)); if (!cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageAllocXYZ2Lab(ContextID)))
goto Error;
} }
} }
return Lut; return Lut;
Error:
cmsPipelineFree(Lut);
return NULL;
} }
// 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 neded
/*static
cmsPipeline* _cmsReadFloatInputTag(cmsHPROFILE hProfile, cmsTagSignature tagFloat)
{
cmsContext ContextID = cmsGetProfileContextID(hProfile);
cmsPipeline* Lut = cmsPipelineDup((cmsPipeline*) cmsReadTag(hProfile, tagFloat));
cmsColorSpaceSignature spc = cmsGetColorSpace(hProfile);
if (Lut == NULL) return NULL;
// If PCS is Lab or XYZ, the floating point tag is accepting data in the space encoding,
// and since the formatter has already accomodated to 0..1.0, we should undo this change
if ( spc == cmsSigLabData)
{
cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageNormalizeFromLabFloat(ContextID));
}
else
if (spc == cmsSigXYZData)
{
cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageNormalizeFromXyzFloat(ContextID));
}
return Lut;
}
*/
static static
cmsPipeline* _cmsReadFloatInputTag(cmsHPROFILE hProfile, cmsTagSignature tagFloat) cmsPipeline* _cmsReadFloatInputTag(cmsHPROFILE hProfile, cmsTagSignature tagFloat)
{ {
...@@ -316,23 +305,31 @@ cmsPipeline* _cmsReadFloatInputTag(cmsHPROFILE hProfile, cmsTagSignature tagFloa ...@@ -316,23 +305,31 @@ cmsPipeline* _cmsReadFloatInputTag(cmsHPROFILE hProfile, cmsTagSignature tagFloa
// these need to be normalized into the appropriate ranges (Lab = 100,0,0, XYZ=1.0,1.0,1.0) // these need to be normalized into the appropriate ranges (Lab = 100,0,0, XYZ=1.0,1.0,1.0)
if ( spc == cmsSigLabData) if ( spc == cmsSigLabData)
{ {
cmsPipelineInsertStage(Lut, cmsAT_BEGIN, _cmsStageNormalizeToLabFloat(ContextID)); if (!cmsPipelineInsertStage(Lut, cmsAT_BEGIN, _cmsStageNormalizeToLabFloat(ContextID)))
goto Error;
} }
else if (spc == cmsSigXYZData) else if (spc == cmsSigXYZData)
{ {
cmsPipelineInsertStage(Lut, cmsAT_BEGIN, _cmsStageNormalizeToXyzFloat(ContextID)); if (!cmsPipelineInsertStage(Lut, cmsAT_BEGIN, _cmsStageNormalizeToXyzFloat(ContextID)))
goto Error;
} }
if ( PCS == cmsSigLabData) if ( PCS == cmsSigLabData)
{ {
cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageNormalizeFromLabFloat(ContextID)); if (!cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageNormalizeFromLabFloat(ContextID)))
goto Error;
} }
else if( PCS == cmsSigXYZData) else if( PCS == cmsSigXYZData)
{ {
cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageNormalizeFromXyzFloat(ContextID)); if (!cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageNormalizeFromXyzFloat(ContextID)))
goto Error;
} }
return Lut; return Lut;
Error:
cmsPipelineFree(Lut);
return NULL;
} }
...@@ -359,8 +356,11 @@ cmsPipeline* _cmsReadInputLUT(cmsHPROFILE hProfile, int Intent) ...@@ -359,8 +356,11 @@ cmsPipeline* _cmsReadInputLUT(cmsHPROFILE hProfile, int Intent)
return NULL; return NULL;
} }
cmsPipelineInsertStage(Lut, cmsAT_BEGIN, _cmsStageAllocNamedColor(nc, TRUE)); if (!cmsPipelineInsertStage(Lut, cmsAT_BEGIN, _cmsStageAllocNamedColor(nc, TRUE)) ||
cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageAllocLabV2ToV4(ContextID)); !cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageAllocLabV2ToV4(ContextID))) {
cmsPipelineFree(Lut);
return NULL;
}
return Lut; return Lut;
} }
...@@ -395,12 +395,18 @@ cmsPipeline* _cmsReadInputLUT(cmsHPROFILE hProfile, int Intent) ...@@ -395,12 +395,18 @@ cmsPipeline* _cmsReadInputLUT(cmsHPROFILE hProfile, int Intent)
return Lut; return Lut;
// If the input is Lab, add also a conversion at the begin // If the input is Lab, add also a conversion at the begin
if (cmsGetColorSpace(hProfile) == cmsSigLabData) if (cmsGetColorSpace(hProfile) == cmsSigLabData &&
cmsPipelineInsertStage(Lut, cmsAT_BEGIN, _cmsStageAllocLabV4ToV2(ContextID)); !cmsPipelineInsertStage(Lut, cmsAT_BEGIN, _cmsStageAllocLabV4ToV2(ContextID)))
goto Error;
// Add a matrix for conversion V2 to V4 Lab PCS // Add a matrix for conversion V2 to V4 Lab PCS
cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageAllocLabV2ToV4(ContextID)); if (!cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageAllocLabV2ToV4(ContextID)))
goto Error;
return Lut; return Lut;
Error:
cmsPipelineFree(Lut);
return NULL;
} }
// Lut was not found, try to create a matrix-shaper // Lut was not found, try to create a matrix-shaper
...@@ -445,19 +451,25 @@ cmsPipeline* BuildGrayOutputPipeline(cmsHPROFILE hProfile) ...@@ -445,19 +451,25 @@ cmsPipeline* BuildGrayOutputPipeline(cmsHPROFILE hProfile)
if (cmsGetPCS(hProfile) == cmsSigLabData) { if (cmsGetPCS(hProfile) == cmsSigLabData) {
cmsPipelineInsertStage(Lut, cmsAT_END, cmsStageAllocMatrix(ContextID, 1, 3, PickLstarMatrix, NULL)); if (!cmsPipelineInsertStage(Lut, cmsAT_END, cmsStageAllocMatrix(ContextID, 1, 3, PickLstarMatrix, NULL)))
goto Error;
} }
else { else {
cmsPipelineInsertStage(Lut, cmsAT_END, cmsStageAllocMatrix(ContextID, 1, 3, PickYMatrix, NULL)); if (!cmsPipelineInsertStage(Lut, cmsAT_END, cmsStageAllocMatrix(ContextID, 1, 3, PickYMatrix, NULL)))
goto Error;
} }
cmsPipelineInsertStage(Lut, cmsAT_END, cmsStageAllocToneCurves(ContextID, 1, &RevGrayTRC)); if (!cmsPipelineInsertStage(Lut, cmsAT_END, cmsStageAllocToneCurves(ContextID, 1, &RevGrayTRC)))
cmsFreeToneCurve(RevGrayTRC); goto Error;
cmsFreeToneCurve(RevGrayTRC);
return Lut; return Lut;
}
Error:
cmsFreeToneCurve(RevGrayTRC);
cmsPipelineFree(Lut);
return NULL;
}
static static
...@@ -506,15 +518,21 @@ cmsPipeline* BuildRGBOutputMatrixShaper(cmsHPROFILE hProfile) ...@@ -506,15 +518,21 @@ cmsPipeline* BuildRGBOutputMatrixShaper(cmsHPROFILE hProfile)
// This is not allowed by the spec, but this code is tolerant to those cases // This is not allowed by the spec, but this code is tolerant to those cases
if (cmsGetPCS(hProfile) == cmsSigLabData) { if (cmsGetPCS(hProfile) == cmsSigLabData) {
cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageAllocLab2XYZ(ContextID)); if (!cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageAllocLab2XYZ(ContextID)))
goto Error;
} }
cmsPipelineInsertStage(Lut, cmsAT_END, cmsStageAllocMatrix(ContextID, 3, 3, (cmsFloat64Number*) &Inv, NULL)); if (!cmsPipelineInsertStage(Lut, cmsAT_END, cmsStageAllocMatrix(ContextID, 3, 3, (cmsFloat64Number*) &Inv, NULL)) ||
cmsPipelineInsertStage(Lut, cmsAT_END, cmsStageAllocToneCurves(ContextID, 3, InvShapes)); !cmsPipelineInsertStage(Lut, cmsAT_END, cmsStageAllocToneCurves(ContextID, 3, InvShapes)))
goto Error;
} }
cmsFreeToneCurveTriple(InvShapes); cmsFreeToneCurveTriple(InvShapes);
return Lut; return Lut;
Error:
cmsFreeToneCurveTriple(InvShapes);
cmsPipelineFree(Lut);
return NULL;
} }
...@@ -540,30 +558,6 @@ void ChangeInterpolationToTrilinear(cmsPipeline* Lut) ...@@ -540,30 +558,6 @@ void ChangeInterpolationToTrilinear(cmsPipeline* Lut)
// 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 neded
/*static
cmsPipeline* _cmsReadFloatOutputTag(cmsHPROFILE hProfile, cmsTagSignature tagFloat)
{
cmsContext ContextID = cmsGetProfileContextID(hProfile);
cmsPipeline* Lut = cmsPipelineDup((cmsPipeline*) cmsReadTag(hProfile, tagFloat));
cmsColorSpaceSignature PCS = cmsGetPCS(hProfile);
if (Lut == NULL) return NULL;
// If PCS is Lab or XYZ, the floating point tag is accepting data in the space encoding,
// and since the formatter has already accomodated to 0..1.0, we should undo this change
if ( PCS == cmsSigLabData)
{
cmsPipelineInsertStage(Lut, cmsAT_BEGIN, _cmsStageNormalizeToLabFloat(ContextID));
}
else
if (PCS == cmsSigXYZData)
{
cmsPipelineInsertStage(Lut, cmsAT_BEGIN, _cmsStageNormalizeToXyzFloat(ContextID));
}
return Lut;
}*/
static static
cmsPipeline* _cmsReadFloatOutputTag(cmsHPROFILE hProfile, cmsTagSignature tagFloat) cmsPipeline* _cmsReadFloatOutputTag(cmsHPROFILE hProfile, cmsTagSignature tagFloat)
{ {
...@@ -578,25 +572,33 @@ cmsPipeline* _cmsReadFloatOutputTag(cmsHPROFILE hProfile, cmsTagSignature tagFlo ...@@ -578,25 +572,33 @@ cmsPipeline* _cmsReadFloatOutputTag(cmsHPROFILE hProfile, cmsTagSignature tagFlo
// and since the formatter has already accomodated to 0..1.0, we should undo this change // and since the formatter has already accomodated to 0..1.0, we should undo this change
if ( PCS == cmsSigLabData) if ( PCS == cmsSigLabData)
{ {
cmsPipelineInsertStage(Lut, cmsAT_BEGIN, _cmsStageNormalizeToLabFloat(ContextID)); if (!cmsPipelineInsertStage(Lut, cmsAT_BEGIN, _cmsStageNormalizeToLabFloat(ContextID)))
goto Error;
} }
else else
if (PCS == cmsSigXYZData) if (PCS == cmsSigXYZData)
{ {
cmsPipelineInsertStage(Lut, cmsAT_BEGIN, _cmsStageNormalizeToXyzFloat(ContextID)); if (!cmsPipelineInsertStage(Lut, cmsAT_BEGIN, _cmsStageNormalizeToXyzFloat(ContextID)))
goto Error;
} }
// the output can be Lab or XYZ, in which case normalisation is needed on the end of the pipeline // the output can be Lab or XYZ, in which case normalisation is needed on the end of the pipeline
if ( dataSpace == cmsSigLabData) if ( dataSpace == cmsSigLabData)
{ {
cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageNormalizeFromLabFloat(ContextID)); if (!cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageNormalizeFromLabFloat(ContextID)))
goto Error;
} }
else if ( dataSpace == cmsSigXYZData) else if (dataSpace == cmsSigXYZData)
{ {
cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageNormalizeFromXyzFloat(ContextID)); if (!cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageNormalizeFromXyzFloat(ContextID)))
goto Error;
} }
return Lut; return Lut;
Error:
cmsPipelineFree(Lut);
return NULL;
} }
// Create an output MPE LUT from agiven profile. Version mismatches are handled here // Create an output MPE LUT from agiven profile. Version mismatches are handled here
...@@ -636,30 +638,35 @@ cmsPipeline* _cmsReadOutputLUT(cmsHPROFILE hProfile, int Intent) ...@@ -636,30 +638,35 @@ cmsPipeline* _cmsReadOutputLUT(cmsHPROFILE hProfile, int Intent)
// Now it is time for a controversial stuff. I found that for 3D LUTS using // Now it is time for a controversial stuff. I found that for 3D LUTS using
// Lab used as indexer space, trilinear interpolation should be used // Lab used as indexer space, trilinear interpolation should be used
if (cmsGetPCS(hProfile) == cmsSigLabData) if (cmsGetPCS(hProfile) == cmsSigLabData)
ChangeInterpolationToTrilinear(Lut); ChangeInterpolationToTrilinear(Lut);
// We need to adjust data only for Lab and Lut16 type // We need to adjust data only for Lab and Lut16 type
if (OriginalType != cmsSigLut16Type || cmsGetPCS(hProfile) != cmsSigLabData) if (OriginalType != cmsSigLut16Type || cmsGetPCS(hProfile) != cmsSigLabData)
return Lut; return Lut;
// Add a matrix for conversion V4 to V2 Lab PCS // Add a matrix for conversion V4 to V2 Lab PCS
cmsPipelineInsertStage(Lut, cmsAT_BEGIN, _cmsStageAllocLabV4ToV2(ContextID)); if (!cmsPipelineInsertStage(Lut, cmsAT_BEGIN, _cmsStageAllocLabV4ToV2(ContextID)))
goto Error;
// If the output is Lab, add also a conversion at the end // If the output is Lab, add also a conversion at the end
if (cmsGetColorSpace(hProfile) == cmsSigLabData) if (cmsGetColorSpace(hProfile) == cmsSigLabData)
cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageAllocLabV2ToV4(ContextID)); if (!cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageAllocLabV2ToV4(ContextID)))
goto Error;
return Lut; return Lut;
Error:
cmsPipelineFree(Lut);
return NULL;
} }
// Lut not found, try to create a matrix-shaper // Lut not found, try to create a matrix-shaper
// Check if this is a grayscale profile. // Check if this is a grayscale profile.
if (cmsGetColorSpace(hProfile) == cmsSigGrayData) { if (cmsGetColorSpace(hProfile) == cmsSigGrayData) {
// if so, build appropiate conversion tables. // if so, build appropiate conversion tables.
// The tables are the PCS iluminant, scaled across GrayTRC // The tables are the PCS iluminant, scaled across GrayTRC
return BuildGrayOutputPipeline(hProfile); return BuildGrayOutputPipeline(hProfile);
} }
// Not gray, create a normal matrix-shaper, which only operates in XYZ space // Not gray, create a normal matrix-shaper, which only operates in XYZ space
...@@ -681,25 +688,32 @@ cmsPipeline* _cmsReadFloatDevicelinkTag(cmsHPROFILE hProfile, cmsTagSignature ta ...@@ -681,25 +688,32 @@ cmsPipeline* _cmsReadFloatDevicelinkTag(cmsHPROFILE hProfile, cmsTagSignature ta
if (spc == cmsSigLabData) if (spc == cmsSigLabData)
{ {
cmsPipelineInsertStage(Lut, cmsAT_BEGIN, _cmsStageNormalizeToLabFloat(ContextID)); if (!cmsPipelineInsertStage(Lut, cmsAT_BEGIN, _cmsStageNormalizeToLabFloat(ContextID)))
goto Error;
} }
else else
if (spc == cmsSigXYZData) if (spc == cmsSigXYZData)
{ {
cmsPipelineInsertStage(Lut, cmsAT_BEGIN, _cmsStageNormalizeToXyzFloat(ContextID)); if (!cmsPipelineInsertStage(Lut, cmsAT_BEGIN, _cmsStageNormalizeToXyzFloat(ContextID)))
goto Error;
} }
if (PCS == cmsSigLabData) if (PCS == cmsSigLabData)
{ {
cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageNormalizeFromLabFloat(ContextID)); if (!cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageNormalizeFromLabFloat(ContextID)))
goto Error;
} }
else else
if (PCS == cmsSigXYZData) if (PCS == cmsSigXYZData)
{ {
cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageNormalizeFromXyzFloat(ContextID)); if (!cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageNormalizeFromXyzFloat(ContextID)))
goto Error;
} }
return Lut; return Lut;
Error:
cmsPipelineFree(Lut);
return NULL;
} }
// This one includes abstract profiles as well. Matrix-shaper cannot be obtained on that device class. The // This one includes abstract profiles as well. Matrix-shaper cannot be obtained on that device class. The
...@@ -721,15 +735,21 @@ cmsPipeline* _cmsReadDevicelinkLUT(cmsHPROFILE hProfile, int Intent) ...@@ -721,15 +735,21 @@ cmsPipeline* _cmsReadDevicelinkLUT(cmsHPROFILE hProfile, int Intent)
if (nc == NULL) return NULL; if (nc == NULL) return NULL;
Lut = cmsPipelineAlloc(ContextID, 0, 0); Lut = cmsPipelineAlloc(ContextID, 0, 0);
if (Lut == NULL) { if (Lut == NULL)
cmsFreeNamedColorList(nc); goto Error;
return NULL;
} if (!cmsPipelineInsertStage(Lut, cmsAT_BEGIN, _cmsStageAllocNamedColor(nc, FALSE)))
goto Error;
cmsPipelineInsertStage(Lut, cmsAT_BEGIN, _cmsStageAllocNamedColor(nc, FALSE));
if (cmsGetColorSpace(hProfile) == cmsSigLabData) if (cmsGetColorSpace(hProfile) == cmsSigLabData)
cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageAllocLabV2ToV4(ContextID)); if (!cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageAllocLabV2ToV4(ContextID)))
goto Error;
return Lut; return Lut;
Error:
cmsPipelineFree(Lut);
cmsFreeNamedColorList(nc);
return NULL;
} }
if (cmsIsTag(hProfile, tagFloat)) { // Float tag takes precedence if (cmsIsTag(hProfile, tagFloat)) { // Float tag takes precedence
...@@ -760,10 +780,10 @@ cmsPipeline* _cmsReadDevicelinkLUT(cmsHPROFILE hProfile, int Intent) ...@@ -760,10 +780,10 @@ cmsPipeline* _cmsReadDevicelinkLUT(cmsHPROFILE hProfile, int Intent)
Lut = cmsPipelineDup(Lut); Lut = cmsPipelineDup(Lut);
if (Lut == NULL) return NULL; if (Lut == NULL) return NULL;
// Now it is time for a controversial stuff. I found that for 3D LUTS using // Now it is time for a controversial stuff. I found that for 3D LUTS using
// Lab used as indexer space, trilinear interpolation should be used // Lab used as indexer space, trilinear interpolation should be used
if (cmsGetColorSpace(hProfile) == cmsSigLabData) if (cmsGetColorSpace(hProfile) == cmsSigLabData)
ChangeInterpolationToTrilinear(Lut); ChangeInterpolationToTrilinear(Lut);
// After reading it, we have info about the original type // After reading it, we have info about the original type
OriginalType = _cmsGetTagTrueType(hProfile, tag16); OriginalType = _cmsGetTagTrueType(hProfile, tag16);
...@@ -774,16 +794,20 @@ cmsPipeline* _cmsReadDevicelinkLUT(cmsHPROFILE hProfile, int Intent) ...@@ -774,16 +794,20 @@ cmsPipeline* _cmsReadDevicelinkLUT(cmsHPROFILE hProfile, int Intent)
// Here it is possible to get Lab on both sides // Here it is possible to get Lab on both sides
if (cmsGetPCS(hProfile) == cmsSigLabData) { if (cmsGetPCS(hProfile) == cmsSigLabData) {
cmsPipelineInsertStage(Lut, cmsAT_BEGIN, _cmsStageAllocLabV4ToV2(ContextID)); if(!cmsPipelineInsertStage(Lut, cmsAT_BEGIN, _cmsStageAllocLabV4ToV2(ContextID)))
goto Error2;
} }
if (cmsGetColorSpace(hProfile) == cmsSigLabData) { if (cmsGetColorSpace(hProfile) == cmsSigLabData) {
cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageAllocLabV2ToV4(ContextID)); if(!cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageAllocLabV2ToV4(ContextID)))
goto Error2;
} }
return Lut; return Lut;
Error2:
cmsPipelineFree(Lut);
return NULL;
} }
// --------------------------------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------------------------------
......
...@@ -264,10 +264,10 @@ Error: ...@@ -264,10 +264,10 @@ Error:
if (NewElem ->TheCurves != NULL) { if (NewElem ->TheCurves != NULL) {
for (i=0; i < NewElem ->nCurves; i++) { for (i=0; i < NewElem ->nCurves; i++) {
if (NewElem ->TheCurves[i]) if (NewElem ->TheCurves[i])
cmsFreeToneCurve(Data ->TheCurves[i]); cmsFreeToneCurve(NewElem ->TheCurves[i]);
} }
} }
_cmsFree(mpe ->ContextID, Data ->TheCurves); _cmsFree(mpe ->ContextID, NewElem ->TheCurves);
_cmsFree(mpe ->ContextID, NewElem); _cmsFree(mpe ->ContextID, NewElem);
return NULL; return NULL;
} }
...@@ -392,6 +392,8 @@ static ...@@ -392,6 +392,8 @@ static
void MatrixElemTypeFree(cmsStage* mpe) void MatrixElemTypeFree(cmsStage* mpe)
{ {
_cmsStageMatrixData* Data = (_cmsStageMatrixData*) mpe ->Data; _cmsStageMatrixData* Data = (_cmsStageMatrixData*) mpe ->Data;
if (Data == NULL)
return;
if (Data ->Double) if (Data ->Double)
_cmsFree(mpe ->ContextID, Data ->Double); _cmsFree(mpe ->ContextID, Data ->Double);
...@@ -526,10 +528,15 @@ void* CLUTElemDup(cmsStage* mpe) ...@@ -526,10 +528,15 @@ void* CLUTElemDup(cmsStage* mpe)
if (Data ->Tab.T) { if (Data ->Tab.T) {
if (Data ->HasFloatValues) if (Data ->HasFloatValues) {
NewElem ->Tab.TFloat = (cmsFloat32Number*) _cmsDupMem(mpe ->ContextID, Data ->Tab.TFloat, Data ->nEntries * sizeof (cmsFloat32Number)); NewElem ->Tab.TFloat = (cmsFloat32Number*) _cmsDupMem(mpe ->ContextID, Data ->Tab.TFloat, Data ->nEntries * sizeof (cmsFloat32Number));
else if (NewElem ->Tab.TFloat == NULL)
goto Error;
} else {
NewElem ->Tab.T = (cmsUInt16Number*) _cmsDupMem(mpe ->ContextID, Data ->Tab.T, Data ->nEntries * sizeof (cmsUInt16Number)); NewElem ->Tab.T = (cmsUInt16Number*) _cmsDupMem(mpe ->ContextID, Data ->Tab.T, Data ->nEntries * sizeof (cmsUInt16Number));
if (NewElem ->Tab.TFloat == NULL)
goto Error;
}
} }
NewElem ->Params = _cmsComputeInterpParamsEx(mpe ->ContextID, NewElem ->Params = _cmsComputeInterpParamsEx(mpe ->ContextID,
...@@ -538,8 +545,14 @@ void* CLUTElemDup(cmsStage* mpe) ...@@ -538,8 +545,14 @@ void* CLUTElemDup(cmsStage* mpe)
Data ->Params ->nOutputs, Data ->Params ->nOutputs,
NewElem ->Tab.T, NewElem ->Tab.T,
Data ->Params ->dwFlags); Data ->Params ->dwFlags);
if (NewElem->Params != NULL)
return (void*) NewElem; return (void*) NewElem;
Error:
if (NewElem->Tab.T)
// This works for both types
_cmsFree(mpe ->ContextID, NewElem -> Tab.T);
_cmsFree(mpe ->ContextID, NewElem);
return NULL;
} }
...@@ -636,7 +649,6 @@ cmsStage* CMSEXPORT cmsStageAllocCLut16bit(cmsContext ContextID, ...@@ -636,7 +649,6 @@ cmsStage* CMSEXPORT cmsStageAllocCLut16bit(cmsContext ContextID,
for (i=0; i < MAX_INPUT_DIMENSIONS; i++) for (i=0; i < MAX_INPUT_DIMENSIONS; i++)
Dimensions[i] = nGridPoints; Dimensions[i] = nGridPoints;
return cmsStageAllocCLut16bitGranular(ContextID, Dimensions, inputChan, outputChan, Table); return cmsStageAllocCLut16bitGranular(ContextID, Dimensions, inputChan, outputChan, Table);
} }
...@@ -706,15 +718,12 @@ cmsStage* CMSEXPORT cmsStageAllocCLutFloatGranular(cmsContext ContextID, const c ...@@ -706,15 +718,12 @@ cmsStage* CMSEXPORT cmsStageAllocCLutFloatGranular(cmsContext ContextID, const c
} }
} }
NewElem ->Params = _cmsComputeInterpParamsEx(ContextID, clutPoints, inputChan, outputChan, NewElem ->Tab.TFloat, CMS_LERP_FLAGS_FLOAT); NewElem ->Params = _cmsComputeInterpParamsEx(ContextID, clutPoints, inputChan, outputChan, NewElem ->Tab.TFloat, CMS_LERP_FLAGS_FLOAT);
if (NewElem ->Params == NULL) { if (NewElem ->Params == NULL) {
cmsStageFree(NewMPE); cmsStageFree(NewMPE);
return NULL; return NULL;
} }
return NewMPE; return NewMPE;
} }
...@@ -772,7 +781,7 @@ cmsBool CMSEXPORT cmsStageSampleCLut16bit(cmsStage* mpe, cmsSAMPLER16 Sampler, v ...@@ -772,7 +781,7 @@ cmsBool CMSEXPORT cmsStageSampleCLut16bit(cmsStage* mpe, cmsSAMPLER16 Sampler, v
int i, t, nTotalPoints, index, rest; int i, t, nTotalPoints, index, rest;
int nInputs, nOutputs; int nInputs, nOutputs;
cmsUInt32Number* nSamples; cmsUInt32Number* nSamples;
cmsUInt16Number In[cmsMAXCHANNELS], Out[MAX_STAGE_CHANNELS]; cmsUInt16Number In[MAX_INPUT_DIMENSIONS+1], Out[MAX_STAGE_CHANNELS];
_cmsStageCLutData* clut; _cmsStageCLutData* clut;
if (mpe == NULL) return FALSE; if (mpe == NULL) return FALSE;
...@@ -785,7 +794,9 @@ cmsBool CMSEXPORT cmsStageSampleCLut16bit(cmsStage* mpe, cmsSAMPLER16 Sampler, v ...@@ -785,7 +794,9 @@ cmsBool CMSEXPORT cmsStageSampleCLut16bit(cmsStage* mpe, cmsSAMPLER16 Sampler, v
nInputs = clut->Params ->nInputs; nInputs = clut->Params ->nInputs;
nOutputs = clut->Params ->nOutputs; nOutputs = clut->Params ->nOutputs;
if (nInputs >= cmsMAXCHANNELS) return FALSE; if (nInputs <= 0) return FALSE;
if (nOutputs <= 0) return FALSE;
if (nInputs > MAX_INPUT_DIMENSIONS) return FALSE;
if (nOutputs >= MAX_STAGE_CHANNELS) return FALSE; if (nOutputs >= MAX_STAGE_CHANNELS) return FALSE;
nTotalPoints = CubeSize(nSamples, nInputs); nTotalPoints = CubeSize(nSamples, nInputs);
...@@ -832,14 +843,16 @@ cmsBool CMSEXPORT cmsStageSampleCLutFloat(cmsStage* mpe, cmsSAMPLERFLOAT Sampler ...@@ -832,14 +843,16 @@ cmsBool CMSEXPORT cmsStageSampleCLutFloat(cmsStage* mpe, cmsSAMPLERFLOAT Sampler
int i, t, nTotalPoints, index, rest; int i, t, nTotalPoints, index, rest;
int nInputs, nOutputs; int nInputs, nOutputs;
cmsUInt32Number* nSamples; cmsUInt32Number* nSamples;
cmsFloat32Number In[cmsMAXCHANNELS], Out[MAX_STAGE_CHANNELS]; cmsFloat32Number In[MAX_INPUT_DIMENSIONS+1], Out[MAX_STAGE_CHANNELS];
_cmsStageCLutData* clut = (_cmsStageCLutData*) mpe->Data; _cmsStageCLutData* clut = (_cmsStageCLutData*) mpe->Data;
nSamples = clut->Params ->nSamples; nSamples = clut->Params ->nSamples;
nInputs = clut->Params ->nInputs; nInputs = clut->Params ->nInputs;
nOutputs = clut->Params ->nOutputs; nOutputs = clut->Params ->nOutputs;
if (nInputs >= cmsMAXCHANNELS) return FALSE; if (nInputs <= 0) return FALSE;
if (nOutputs <= 0) return FALSE;
if (nInputs > MAX_INPUT_DIMENSIONS) return FALSE;
if (nOutputs >= MAX_STAGE_CHANNELS) return FALSE; if (nOutputs >= MAX_STAGE_CHANNELS) return FALSE;
nTotalPoints = CubeSize(nSamples, nInputs); nTotalPoints = CubeSize(nSamples, nInputs);
...@@ -1021,8 +1034,7 @@ cmsStage* _cmsStageAllocLabV2ToV4curves(cmsContext ContextID) ...@@ -1021,8 +1034,7 @@ cmsStage* _cmsStageAllocLabV2ToV4curves(cmsContext ContextID)
mpe = cmsStageAllocToneCurves(ContextID, 3, LabTable); mpe = cmsStageAllocToneCurves(ContextID, 3, LabTable);
cmsFreeToneCurveTriple(LabTable); cmsFreeToneCurveTriple(LabTable);
if (mpe == NULL) return mpe; if (mpe == NULL) return NULL;
mpe ->Implements = cmsSigLabV2toV4; mpe ->Implements = cmsSigLabV2toV4;
return mpe; return mpe;
} }
...@@ -1248,12 +1260,22 @@ cmsStage* CMSEXPORT cmsStageDup(cmsStage* mpe) ...@@ -1248,12 +1260,22 @@ cmsStage* CMSEXPORT cmsStageDup(cmsStage* mpe)
NULL); NULL);
if (NewMPE == NULL) return NULL; if (NewMPE == NULL) return NULL;
NewMPE ->Implements = mpe ->Implements; NewMPE ->Implements = mpe ->Implements;
if (mpe ->DupElemPtr) {
NewMPE ->Data = mpe ->DupElemPtr(mpe);
if (NewMPE->Data == NULL) {
cmsStageFree(NewMPE);
return NULL;
}
} else {
if (mpe ->DupElemPtr)
NewMPE ->Data = mpe ->DupElemPtr(mpe);
else
NewMPE ->Data = NULL; NewMPE ->Data = NULL;
}
return NewMPE; return NewMPE;
} }
...@@ -1266,7 +1288,7 @@ cmsStage* CMSEXPORT cmsStageDup(cmsStage* mpe) ...@@ -1266,7 +1288,7 @@ cmsStage* CMSEXPORT cmsStageDup(cmsStage* mpe)
static static
void BlessLUT(cmsPipeline* lut) void BlessLUT(cmsPipeline* lut)
{ {
// We can set the input/output channels only if we have elements. // We can set the input/ouput channels only if we have elements.
if (lut ->Elements != NULL) { if (lut ->Elements != NULL) {
cmsStage *First, *Last; cmsStage *First, *Last;
...@@ -1466,12 +1488,12 @@ cmsPipeline* CMSEXPORT cmsPipelineDup(const cmsPipeline* lut) ...@@ -1466,12 +1488,12 @@ cmsPipeline* CMSEXPORT cmsPipelineDup(const cmsPipeline* lut)
} }
void CMSEXPORT cmsPipelineInsertStage(cmsPipeline* lut, cmsStageLoc loc, cmsStage* mpe) int CMSEXPORT cmsPipelineInsertStage(cmsPipeline* lut, cmsStageLoc loc, cmsStage* mpe)
{ {
cmsStage* Anterior = NULL, *pt; cmsStage* Anterior = NULL, *pt;
_cmsAssert(lut != NULL); if (lut == NULL || mpe == NULL)
_cmsAssert(mpe != NULL); return FALSE;
switch (loc) { switch (loc) {
...@@ -1495,9 +1517,11 @@ void CMSEXPORT cmsPipelineInsertStage(cmsPipeline* lut, cmsStageLoc loc, cmsStag ...@@ -1495,9 +1517,11 @@ void CMSEXPORT cmsPipelineInsertStage(cmsPipeline* lut, cmsStageLoc loc, cmsStag
} }
break; break;
default:; default:;
return FALSE;
} }
BlessLUT(lut); BlessLUT(lut);
return TRUE;
} }
// Unlink an element and return the pointer to it // Unlink an element and return the pointer to it
...@@ -1559,7 +1583,7 @@ void CMSEXPORT cmsPipelineUnlinkStage(cmsPipeline* lut, cmsStageLoc loc, cmsStag ...@@ -1559,7 +1583,7 @@ void CMSEXPORT cmsPipelineUnlinkStage(cmsPipeline* lut, cmsStageLoc loc, cmsStag
// Concatenate two LUT into a new single one // Concatenate two LUT into a new single one
cmsBool CMSEXPORT cmsPipelineCat(cmsPipeline* l1, const cmsPipeline* l2) cmsBool CMSEXPORT cmsPipelineCat(cmsPipeline* l1, const cmsPipeline* l2)
{ {
cmsStage* mpe, *NewMPE; cmsStage* mpe;
// If both LUTS does not have elements, we need to inherit // If both LUTS does not have elements, we need to inherit
// the number of channels // the number of channels
...@@ -1574,17 +1598,12 @@ cmsBool CMSEXPORT cmsPipelineCat(cmsPipeline* l1, const cmsPipeline* l2) ...@@ -1574,17 +1598,12 @@ cmsBool CMSEXPORT cmsPipelineCat(cmsPipeline* l1, const cmsPipeline* l2)
mpe = mpe ->Next) { mpe = mpe ->Next) {
// We have to dup each element // We have to dup each element
NewMPE = cmsStageDup(mpe); if (!cmsPipelineInsertStage(l1, cmsAT_END, cmsStageDup(mpe)))
return FALSE;
if (NewMPE == NULL) {
return FALSE;
}
cmsPipelineInsertStage(l1, cmsAT_END, NewMPE);
} }
BlessLUT(l1); BlessLUT(l1);
return TRUE; return TRUE;
} }
...@@ -1714,16 +1733,11 @@ cmsBool CMSEXPORT cmsPipelineEvalReverseFloat(cmsFloat32Number Target[], ...@@ -1714,16 +1733,11 @@ cmsBool CMSEXPORT cmsPipelineEvalReverseFloat(cmsFloat32Number Target[],
cmsFloat32Number fx[4], x[4], xd[4], fxd[4]; cmsFloat32Number fx[4], x[4], xd[4], fxd[4];
cmsVEC3 tmp, tmp2; cmsVEC3 tmp, tmp2;
cmsMAT3 Jacobian; cmsMAT3 Jacobian;
cmsFloat64Number LastResult[4];
// Only 3->3 and 4->3 are supported // Only 3->3 and 4->3 are supported
if (lut ->InputChannels != 3 && lut ->InputChannels != 4) return FALSE; if (lut ->InputChannels != 3 && lut ->InputChannels != 4) return FALSE;
if (lut ->OutputChannels != 3) return FALSE; if (lut ->OutputChannels != 3) return FALSE;
// Mark result of -1
LastResult[0] = LastResult[1] = LastResult[2] = -1.0f;
// Take the hint as starting point if specified // Take the hint as starting point if specified
if (Hint == NULL) { if (Hint == NULL) {
......
...@@ -338,7 +338,7 @@ cmsBool CMSEXPORT cmsMD5computeID(cmsHPROFILE hProfile) ...@@ -338,7 +338,7 @@ cmsBool CMSEXPORT cmsMD5computeID(cmsHPROFILE hProfile)
Error: Error:
// Free resources as something went wrong // Free resources as something went wrong
if (MD5 != NULL) _cmsFree(ContextID, MD5); // "MD5" cannot be other than NULL here, so no need to free it
if (Mem != NULL) _cmsFree(ContextID, Mem); if (Mem != NULL) _cmsFree(ContextID, Mem);
memmove(Icc, &Keep, sizeof(_cmsICCPROFILE)); memmove(Icc, &Keep, sizeof(_cmsICCPROFILE));
return FALSE; return FALSE;
......
...@@ -359,9 +359,9 @@ const wchar_t* _cmsMLUgetWide(const cmsMLU* mlu, ...@@ -359,9 +359,9 @@ const wchar_t* _cmsMLUgetWide(const cmsMLU* mlu,
if (Best == -1) if (Best == -1)
Best = 0; Best = 0;
v = mlu ->Entries + Best; v = mlu ->Entries + Best;
if (UsedLanguageCode != NULL) *UsedLanguageCode = v ->Language; if (UsedLanguageCode != NULL) *UsedLanguageCode = v ->Language;
if (UsedCountryCode != NULL) *UsedCountryCode = v ->Country; if (UsedCountryCode != NULL) *UsedCountryCode = v ->Country;
if (len != NULL) *len = v ->Len; if (len != NULL) *len = v ->Len;
...@@ -475,6 +475,35 @@ CMSAPI cmsBool CMSEXPORT cmsMLUgetTranslation(const cmsMLU* mlu, ...@@ -475,6 +475,35 @@ CMSAPI cmsBool CMSEXPORT cmsMLUgetTranslation(const cmsMLU* mlu,
} }
// Get the number of translations in the MLU object
cmsUInt32Number CMSEXPORT cmsMLUtranslationsCount(const cmsMLU* mlu)
{
if (mlu == NULL) return 0;
return mlu->UsedEntries;
}
// Get the language and country codes for a specific MLU index
cmsBool CMSEXPORT cmsMLUtranslationsCodes(const cmsMLU* mlu,
cmsUInt32Number idx,
char LanguageCode[3],
char CountryCode[3])
{
_cmsMLUentry *entry;
if (mlu == NULL) return FALSE;
if (idx >= (cmsUInt32Number) mlu->UsedEntries) return FALSE;
entry = &mlu->Entries[idx];
*(cmsUInt16Number *)LanguageCode = _cmsAdjustEndianess16(entry->Language);
*(cmsUInt16Number *)CountryCode = _cmsAdjustEndianess16(entry->Country);
return TRUE;
}
// Named color lists -------------------------------------------------------------------------------------------- // Named color lists --------------------------------------------------------------------------------------------
// Grow the list to keep at least NumElements // Grow the list to keep at least NumElements
...@@ -517,9 +546,9 @@ cmsNAMEDCOLORLIST* CMSEXPORT cmsAllocNamedColorList(cmsContext ContextID, cmsUIn ...@@ -517,9 +546,9 @@ cmsNAMEDCOLORLIST* CMSEXPORT cmsAllocNamedColorList(cmsContext ContextID, cmsUIn
while (v -> Allocated < n) while (v -> Allocated < n)
GrowNamedColorList(v); GrowNamedColorList(v);
strncpy(v ->Prefix, Prefix, sizeof(v ->Prefix) - 1); strncpy(v ->Prefix, Prefix, sizeof(v ->Prefix)-1);
strncpy(v ->Suffix, Suffix, sizeof(v ->Suffix) - 1); strncpy(v ->Suffix, Suffix, sizeof(v ->Suffix)-1);
v->Prefix[sizeof(v ->Prefix) - 1] = v->Suffix[sizeof(v ->Suffix) - 1] = 0; v->Prefix[32] = v->Suffix[32] = 0;
v -> ColorantCount = ColorantCount; v -> ColorantCount = ColorantCount;
...@@ -529,8 +558,9 @@ cmsNAMEDCOLORLIST* CMSEXPORT cmsAllocNamedColorList(cmsContext ContextID, cmsUIn ...@@ -529,8 +558,9 @@ cmsNAMEDCOLORLIST* CMSEXPORT cmsAllocNamedColorList(cmsContext ContextID, cmsUIn
// Free a list // Free a list
void CMSEXPORT cmsFreeNamedColorList(cmsNAMEDCOLORLIST* v) void CMSEXPORT cmsFreeNamedColorList(cmsNAMEDCOLORLIST* v)
{ {
if (v == NULL) return;
if (v ->List) _cmsFree(v ->ContextID, v ->List); if (v ->List) _cmsFree(v ->ContextID, v ->List);
if (v) _cmsFree(v ->ContextID, v); _cmsFree(v ->ContextID, v);
} }
cmsNAMEDCOLORLIST* CMSEXPORT cmsDupNamedColorList(const cmsNAMEDCOLORLIST* v) cmsNAMEDCOLORLIST* CMSEXPORT cmsDupNamedColorList(const cmsNAMEDCOLORLIST* v)
...@@ -576,11 +606,8 @@ cmsBool CMSEXPORT cmsAppendNamedColor(cmsNAMEDCOLORLIST* NamedColorList, ...@@ -576,11 +606,8 @@ cmsBool CMSEXPORT cmsAppendNamedColor(cmsNAMEDCOLORLIST* NamedColorList,
if (Name != NULL) { if (Name != NULL) {
strncpy(NamedColorList ->List[NamedColorList ->nColors].Name, Name, strncpy(NamedColorList ->List[NamedColorList ->nColors].Name, Name, cmsMAX_PATH-1);
sizeof(NamedColorList ->List[NamedColorList ->nColors].Name) - 1); NamedColorList ->List[NamedColorList ->nColors].Name[cmsMAX_PATH-1] = 0;
NamedColorList ->List[NamedColorList ->nColors].
Name[sizeof(NamedColorList ->List[NamedColorList ->nColors].Name) - 1] = 0;
} }
else else
...@@ -891,7 +918,6 @@ cmsHANDLE CMSEXPORT cmsDictDup(cmsHANDLE hDict) ...@@ -891,7 +918,6 @@ cmsHANDLE CMSEXPORT cmsDictDup(cmsHANDLE hDict)
{ {
_cmsDICT* old_dict = (_cmsDICT*) hDict; _cmsDICT* old_dict = (_cmsDICT*) hDict;
cmsHANDLE hNew; cmsHANDLE hNew;
_cmsDICT* new_dict;
cmsDICTentry *entry; cmsDICTentry *entry;
_cmsAssert(old_dict != NULL); _cmsAssert(old_dict != NULL);
...@@ -899,8 +925,6 @@ cmsHANDLE CMSEXPORT cmsDictDup(cmsHANDLE hDict) ...@@ -899,8 +925,6 @@ cmsHANDLE CMSEXPORT cmsDictDup(cmsHANDLE hDict)
hNew = cmsDictAlloc(old_dict ->ContextID); hNew = cmsDictAlloc(old_dict ->ContextID);
if (hNew == NULL) return NULL; if (hNew == NULL) return NULL;
new_dict = (_cmsDICT*) hNew;
// Walk the list freeing all nodes // Walk the list freeing all nodes
entry = old_dict ->head; entry = old_dict ->head;
while (entry != NULL) { while (entry != NULL) {
......
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
// However, the following notice accompanied the original version of this // However, the following notice accompanied the original version of this
// file: // file:
// //
//--------------------------------------------------------------------------------- //---------------------------------------------------------------------------------
// //
// Little Color Management System // Little Color Management System
...@@ -81,10 +82,6 @@ typedef struct { ...@@ -81,10 +82,6 @@ typedef struct {
int nInputs; int nInputs;
int nOutputs; int nOutputs;
// Since there is no limitation of the output number of channels, this buffer holding the connexion CLUT-shaper
// has to be dynamically allocated. This is not the case of first step shaper-CLUT, which is limited to max inputs
cmsUInt16Number* StageDEF;
_cmsInterpFn16 EvalCurveIn16[MAX_INPUT_DIMENSIONS]; // The maximum number of input channels is known in advance _cmsInterpFn16 EvalCurveIn16[MAX_INPUT_DIMENSIONS]; // The maximum number of input channels is known in advance
cmsInterpParams* ParamsCurveIn16[MAX_INPUT_DIMENSIONS]; cmsInterpParams* ParamsCurveIn16[MAX_INPUT_DIMENSIONS];
...@@ -202,8 +199,6 @@ cmsBool PreOptimize(cmsPipeline* Lut) ...@@ -202,8 +199,6 @@ cmsBool PreOptimize(cmsPipeline* Lut)
{ {
cmsBool AnyOpt = FALSE, Opt; cmsBool AnyOpt = FALSE, Opt;
AnyOpt = FALSE;
do { do {
Opt = FALSE; Opt = FALSE;
...@@ -253,6 +248,7 @@ void PrelinEval16(register const cmsUInt16Number Input[], ...@@ -253,6 +248,7 @@ void PrelinEval16(register const cmsUInt16Number Input[],
{ {
Prelin16Data* p16 = (Prelin16Data*) D; Prelin16Data* p16 = (Prelin16Data*) D;
cmsUInt16Number StageABC[MAX_INPUT_DIMENSIONS]; cmsUInt16Number StageABC[MAX_INPUT_DIMENSIONS];
cmsUInt16Number StageDEF[cmsMAXCHANNELS];
int i; int i;
for (i=0; i < p16 ->nInputs; i++) { for (i=0; i < p16 ->nInputs; i++) {
...@@ -260,11 +256,11 @@ void PrelinEval16(register const cmsUInt16Number Input[], ...@@ -260,11 +256,11 @@ void PrelinEval16(register const cmsUInt16Number Input[],
p16 ->EvalCurveIn16[i](&Input[i], &StageABC[i], p16 ->ParamsCurveIn16[i]); p16 ->EvalCurveIn16[i](&Input[i], &StageABC[i], p16 ->ParamsCurveIn16[i]);
} }
p16 ->EvalCLUT(StageABC, p16 ->StageDEF, p16 ->CLUTparams); p16 ->EvalCLUT(StageABC, StageDEF, p16 ->CLUTparams);
for (i=0; i < p16 ->nOutputs; i++) { for (i=0; i < p16 ->nOutputs; i++) {
p16 ->EvalCurveOut16[i](&p16->StageDEF[i], &Output[i], p16 ->ParamsCurveOut16[i]); p16 ->EvalCurveOut16[i](&StageDEF[i], &Output[i], p16 ->ParamsCurveOut16[i]);
} }
} }
...@@ -274,7 +270,6 @@ void PrelinOpt16free(cmsContext ContextID, void* ptr) ...@@ -274,7 +270,6 @@ void PrelinOpt16free(cmsContext ContextID, void* ptr)
{ {
Prelin16Data* p16 = (Prelin16Data*) ptr; Prelin16Data* p16 = (Prelin16Data*) ptr;
_cmsFree(ContextID, p16 ->StageDEF);
_cmsFree(ContextID, p16 ->EvalCurveOut16); _cmsFree(ContextID, p16 ->EvalCurveOut16);
_cmsFree(ContextID, p16 ->ParamsCurveOut16); _cmsFree(ContextID, p16 ->ParamsCurveOut16);
...@@ -289,7 +284,6 @@ void* Prelin16dup(cmsContext ContextID, const void* ptr) ...@@ -289,7 +284,6 @@ void* Prelin16dup(cmsContext ContextID, const void* ptr)
if (Duped == NULL) return NULL; if (Duped == NULL) return NULL;
Duped ->StageDEF = _cmsCalloc(ContextID, p16 ->nOutputs, sizeof(cmsUInt16Number));
Duped ->EvalCurveOut16 = _cmsDupMem(ContextID, p16 ->EvalCurveOut16, p16 ->nOutputs * sizeof(_cmsInterpFn16)); Duped ->EvalCurveOut16 = _cmsDupMem(ContextID, p16 ->EvalCurveOut16, p16 ->nOutputs * sizeof(_cmsInterpFn16));
Duped ->ParamsCurveOut16 = _cmsDupMem(ContextID, p16 ->ParamsCurveOut16, p16 ->nOutputs * sizeof(cmsInterpParams* )); Duped ->ParamsCurveOut16 = _cmsDupMem(ContextID, p16 ->ParamsCurveOut16, p16 ->nOutputs * sizeof(cmsInterpParams* ));
...@@ -328,7 +322,6 @@ Prelin16Data* PrelinOpt16alloc(cmsContext ContextID, ...@@ -328,7 +322,6 @@ Prelin16Data* PrelinOpt16alloc(cmsContext ContextID,
p16 ->EvalCLUT = ColorMap ->Interpolation.Lerp16; p16 ->EvalCLUT = ColorMap ->Interpolation.Lerp16;
p16 -> StageDEF = _cmsCalloc(ContextID, p16 ->nOutputs, sizeof(cmsUInt16Number));
p16 -> EvalCurveOut16 = (_cmsInterpFn16*) _cmsCalloc(ContextID, nOutputs, sizeof(_cmsInterpFn16)); p16 -> EvalCurveOut16 = (_cmsInterpFn16*) _cmsCalloc(ContextID, nOutputs, sizeof(_cmsInterpFn16));
p16 -> ParamsCurveOut16 = (cmsInterpParams**) _cmsCalloc(ContextID, nOutputs, sizeof(cmsInterpParams* )); p16 -> ParamsCurveOut16 = (cmsInterpParams**) _cmsCalloc(ContextID, nOutputs, sizeof(cmsInterpParams* ));
...@@ -413,7 +406,7 @@ cmsBool PatchLUT(cmsStage* CLUT, cmsUInt16Number At[], cmsUInt16Number Value[], ...@@ -413,7 +406,7 @@ cmsBool PatchLUT(cmsStage* CLUT, cmsUInt16Number At[], cmsUInt16Number Value[],
int i, index; int i, index;
if (CLUT -> Type != cmsSigCLutElemType) { if (CLUT -> Type != cmsSigCLutElemType) {
cmsSignalError(CLUT->ContextID, cmsERROR_INTERNAL, "(internal) Attempt to PatchLUT on non-lut MPE"); cmsSignalError(CLUT->ContextID, cmsERROR_INTERNAL, "(internal) Attempt to PatchLUT on non-lut stage");
return FALSE; return FALSE;
} }
...@@ -579,8 +572,8 @@ cmsBool FixWhiteMisalignment(cmsPipeline* Lut, cmsColorSpaceSignature EntryColor ...@@ -579,8 +572,8 @@ cmsBool FixWhiteMisalignment(cmsPipeline* Lut, cmsColorSpaceSignature EntryColor
static static
cmsBool OptimizeByResampling(cmsPipeline** Lut, cmsUInt32Number Intent, cmsUInt32Number* InputFormat, cmsUInt32Number* OutputFormat, cmsUInt32Number* dwFlags) cmsBool OptimizeByResampling(cmsPipeline** Lut, cmsUInt32Number Intent, cmsUInt32Number* InputFormat, cmsUInt32Number* OutputFormat, cmsUInt32Number* dwFlags)
{ {
cmsPipeline* Src; cmsPipeline* Src = NULL;
cmsPipeline* Dest; cmsPipeline* Dest = NULL;
cmsStage* mpe; cmsStage* mpe;
cmsStage* CLUT; cmsStage* CLUT;
cmsStage *KeepPreLin = NULL, *KeepPostLin = NULL; cmsStage *KeepPreLin = NULL, *KeepPostLin = NULL;
...@@ -593,7 +586,6 @@ cmsBool OptimizeByResampling(cmsPipeline** Lut, cmsUInt32Number Intent, cmsUInt3 ...@@ -593,7 +586,6 @@ cmsBool OptimizeByResampling(cmsPipeline** Lut, cmsUInt32Number Intent, cmsUInt3
cmsToneCurve** DataSetOut; cmsToneCurve** DataSetOut;
Prelin16Data* p16; Prelin16Data* p16;
// This is a loosy optimization! does not apply in floating-point cases // This is a loosy optimization! does not apply in floating-point cases
if (_cmsFormatterIsFloat(*InputFormat) || _cmsFormatterIsFloat(*OutputFormat)) return FALSE; if (_cmsFormatterIsFloat(*InputFormat) || _cmsFormatterIsFloat(*OutputFormat)) return FALSE;
...@@ -607,10 +599,10 @@ cmsBool OptimizeByResampling(cmsPipeline** Lut, cmsUInt32Number Intent, cmsUInt3 ...@@ -607,10 +599,10 @@ cmsBool OptimizeByResampling(cmsPipeline** Lut, cmsUInt32Number Intent, cmsUInt3
Src = *Lut; Src = *Lut;
// Named color pipelines cannot be optimized either // Named color pipelines cannot be optimized either
for (mpe = cmsPipelineGetPtrToFirstStage(Src); for (mpe = cmsPipelineGetPtrToFirstStage(Src);
mpe != NULL; mpe != NULL;
mpe = cmsStageNext(mpe)) { mpe = cmsStageNext(mpe)) {
if (cmsStageType(mpe) == cmsSigNamedColorElemType) return FALSE; if (cmsStageType(mpe) == cmsSigNamedColorElemType) return FALSE;
} }
...@@ -632,7 +624,8 @@ cmsBool OptimizeByResampling(cmsPipeline** Lut, cmsUInt32Number Intent, cmsUInt3 ...@@ -632,7 +624,8 @@ cmsBool OptimizeByResampling(cmsPipeline** Lut, cmsUInt32Number Intent, cmsUInt3
// All seems ok, proceed. // All seems ok, proceed.
NewPreLin = cmsStageDup(PreLin); NewPreLin = cmsStageDup(PreLin);
cmsPipelineInsertStage(Dest, cmsAT_BEGIN, NewPreLin); if(!cmsPipelineInsertStage(Dest, cmsAT_BEGIN, NewPreLin))
goto Error;
// Remove prelinearization. Since we have duplicated the curve // Remove prelinearization. Since we have duplicated the curve
// in destination LUT, the sampling shoud be applied after this stage. // in destination LUT, the sampling shoud be applied after this stage.
...@@ -646,7 +639,9 @@ cmsBool OptimizeByResampling(cmsPipeline** Lut, cmsUInt32Number Intent, cmsUInt3 ...@@ -646,7 +639,9 @@ cmsBool OptimizeByResampling(cmsPipeline** Lut, cmsUInt32Number Intent, cmsUInt3
if (CLUT == NULL) return FALSE; if (CLUT == NULL) return FALSE;
// Add the CLUT to the destination LUT // Add the CLUT to the destination LUT
cmsPipelineInsertStage(Dest, cmsAT_END, CLUT); if (!cmsPipelineInsertStage(Dest, cmsAT_END, CLUT)) {
goto Error;
}
// Postlinearization tables are kept unless indicated by flags // Postlinearization tables are kept unless indicated by flags
if (*dwFlags & cmsFLAGS_CLUT_POST_LINEARIZATION) { if (*dwFlags & cmsFLAGS_CLUT_POST_LINEARIZATION) {
...@@ -662,7 +657,8 @@ cmsBool OptimizeByResampling(cmsPipeline** Lut, cmsUInt32Number Intent, cmsUInt3 ...@@ -662,7 +657,8 @@ cmsBool OptimizeByResampling(cmsPipeline** Lut, cmsUInt32Number Intent, cmsUInt3
// All seems ok, proceed. // All seems ok, proceed.
NewPostLin = cmsStageDup(PostLin); NewPostLin = cmsStageDup(PostLin);
cmsPipelineInsertStage(Dest, cmsAT_END, NewPostLin); if (!cmsPipelineInsertStage(Dest, cmsAT_END, NewPostLin))
goto Error;
// In destination LUT, the sampling shoud be applied after this stage. // In destination LUT, the sampling shoud be applied after this stage.
cmsPipelineUnlinkStage(Src, cmsAT_END, &KeepPostLin); cmsPipelineUnlinkStage(Src, cmsAT_END, &KeepPostLin);
...@@ -673,10 +669,18 @@ cmsBool OptimizeByResampling(cmsPipeline** Lut, cmsUInt32Number Intent, cmsUInt3 ...@@ -673,10 +669,18 @@ cmsBool OptimizeByResampling(cmsPipeline** Lut, cmsUInt32Number Intent, cmsUInt3
// Now its time to do the sampling. We have to ignore pre/post linearization // Now its time to do the sampling. We have to ignore pre/post linearization
// The source LUT whithout pre/post curves is passed as parameter. // The source LUT whithout pre/post curves is passed as parameter.
if (!cmsStageSampleCLut16bit(CLUT, XFormSampler16, (void*) Src, 0)) { if (!cmsStageSampleCLut16bit(CLUT, XFormSampler16, (void*) Src, 0)) {
Error:
// Ops, something went wrong, Restore stages // Ops, something went wrong, Restore stages
if (KeepPreLin != NULL) cmsPipelineInsertStage(Src, cmsAT_BEGIN, KeepPreLin); if (KeepPreLin != NULL) {
if (KeepPostLin != NULL) cmsPipelineInsertStage(Src, cmsAT_END, KeepPostLin); if (!cmsPipelineInsertStage(Src, cmsAT_BEGIN, KeepPreLin)) {
_cmsAssert(0); // This never happens
}
}
if (KeepPostLin != NULL) {
if (!cmsPipelineInsertStage(Src, cmsAT_END, KeepPostLin)) {
_cmsAssert(0); // This never happens
}
}
cmsPipelineFree(Dest); cmsPipelineFree(Dest);
return FALSE; return FALSE;
} }
...@@ -703,12 +707,11 @@ cmsBool OptimizeByResampling(cmsPipeline** Lut, cmsUInt32Number Intent, cmsUInt3 ...@@ -703,12 +707,11 @@ cmsBool OptimizeByResampling(cmsPipeline** Lut, cmsUInt32Number Intent, cmsUInt3
else { else {
p16 = PrelinOpt16alloc(Dest ->ContextID, p16 = PrelinOpt16alloc(Dest ->ContextID,
DataCLUT ->Params, DataCLUT ->Params,
Dest ->InputChannels, Dest ->InputChannels,
DataSetIn, DataSetIn,
Dest ->OutputChannels, Dest ->OutputChannels,
DataSetOut); DataSetOut);
_cmsPipelineSetOptimizationParameters(Dest, PrelinEval16, (void*) p16, PrelinOpt16free, Prelin16dup); _cmsPipelineSetOptimizationParameters(Dest, PrelinEval16, (void*) p16, PrelinOpt16free, Prelin16dup);
} }
...@@ -1062,7 +1065,8 @@ cmsBool OptimizeByComputingLinearization(cmsPipeline** Lut, cmsUInt32Number Inte ...@@ -1062,7 +1065,8 @@ cmsBool OptimizeByComputingLinearization(cmsPipeline** Lut, cmsUInt32Number Inte
LutPlusCurves = cmsPipelineDup(OriginalLut); LutPlusCurves = cmsPipelineDup(OriginalLut);
if (LutPlusCurves == NULL) goto Error; if (LutPlusCurves == NULL) goto Error;
cmsPipelineInsertStage(LutPlusCurves, cmsAT_BEGIN, cmsStageAllocToneCurves(OriginalLut ->ContextID, OriginalLut ->InputChannels, TransReverse)); if (!cmsPipelineInsertStage(LutPlusCurves, cmsAT_BEGIN, cmsStageAllocToneCurves(OriginalLut ->ContextID, OriginalLut ->InputChannels, TransReverse)))
goto Error;
// Create the result LUT // Create the result LUT
OptimizedLUT = cmsPipelineAlloc(OriginalLut ->ContextID, OriginalLut ->InputChannels, OriginalLut ->OutputChannels); OptimizedLUT = cmsPipelineAlloc(OriginalLut ->ContextID, OriginalLut ->InputChannels, OriginalLut ->OutputChannels);
...@@ -1071,13 +1075,15 @@ cmsBool OptimizeByComputingLinearization(cmsPipeline** Lut, cmsUInt32Number Inte ...@@ -1071,13 +1075,15 @@ cmsBool OptimizeByComputingLinearization(cmsPipeline** Lut, cmsUInt32Number Inte
OptimizedPrelinMpe = cmsStageAllocToneCurves(OriginalLut ->ContextID, OriginalLut ->InputChannels, Trans); OptimizedPrelinMpe = cmsStageAllocToneCurves(OriginalLut ->ContextID, OriginalLut ->InputChannels, Trans);
// Create and insert the curves at the beginning // Create and insert the curves at the beginning
cmsPipelineInsertStage(OptimizedLUT, cmsAT_BEGIN, OptimizedPrelinMpe); if (!cmsPipelineInsertStage(OptimizedLUT, cmsAT_BEGIN, OptimizedPrelinMpe))
goto Error;
// Allocate the CLUT for result // Allocate the CLUT for result
OptimizedCLUTmpe = cmsStageAllocCLut16bit(OriginalLut ->ContextID, nGridPoints, OriginalLut ->InputChannels, OriginalLut ->OutputChannels, NULL); OptimizedCLUTmpe = cmsStageAllocCLut16bit(OriginalLut ->ContextID, nGridPoints, OriginalLut ->InputChannels, OriginalLut ->OutputChannels, NULL);
// Add the CLUT to the destination LUT // Add the CLUT to the destination LUT
cmsPipelineInsertStage(OptimizedLUT, cmsAT_END, OptimizedCLUTmpe); if (!cmsPipelineInsertStage(OptimizedLUT, cmsAT_END, OptimizedCLUTmpe))
goto Error;
// Resample the LUT // Resample the LUT
if (!cmsStageSampleCLut16bit(OptimizedCLUTmpe, XFormSampler16, (void*) LutPlusCurves, 0)) goto Error; if (!cmsStageSampleCLut16bit(OptimizedCLUTmpe, XFormSampler16, (void*) LutPlusCurves, 0)) goto Error;
...@@ -1205,13 +1211,14 @@ Curves16Data* CurvesAlloc(cmsContext ContextID, int nCurves, int nElements, cmsT ...@@ -1205,13 +1211,14 @@ Curves16Data* CurvesAlloc(cmsContext ContextID, int nCurves, int nElements, cmsT
for (i=0; i < nCurves; i++) { for (i=0; i < nCurves; i++) {
c16->Curves[i] = _cmsCalloc(ContextID, nElements, sizeof(cmsUInt16Number)); c16->Curves[i] = _cmsCalloc(ContextID, nElements, sizeof(cmsUInt16Number));
if (c16->Curves[i] == NULL) { if (c16->Curves[i] == NULL) {
for (j=0; j < i; j++) { for (j=0; j < i; j++) {
_cmsFree(ContextID, c16->Curves[j]); _cmsFree(ContextID, c16->Curves[j]);
} }
_cmsFree(ContextID, c16->Curves); _cmsFree(ContextID, c16->Curves);
_cmsFree(ContextID, c16); _cmsFree(ContextID, c16);
return NULL; return NULL;
} }
...@@ -1340,7 +1347,8 @@ cmsBool OptimizeByJoiningCurves(cmsPipeline** Lut, cmsUInt32Number Intent, cmsUI ...@@ -1340,7 +1347,8 @@ cmsBool OptimizeByJoiningCurves(cmsPipeline** Lut, cmsUInt32Number Intent, cmsUI
// Maybe the curves are linear at the end // Maybe the curves are linear at the end
if (!AllCurvesAreLinear(ObtainedCurves)) { if (!AllCurvesAreLinear(ObtainedCurves)) {
cmsPipelineInsertStage(Dest, cmsAT_BEGIN, ObtainedCurves); if (!cmsPipelineInsertStage(Dest, cmsAT_BEGIN, ObtainedCurves))
goto Error;
// If the curves are to be applied in 8 bits, we can save memory // If the curves are to be applied in 8 bits, we can save memory
if (_cmsFormatterIs8bit(*InputFormat)) { if (_cmsFormatterIs8bit(*InputFormat)) {
...@@ -1348,6 +1356,7 @@ cmsBool OptimizeByJoiningCurves(cmsPipeline** Lut, cmsUInt32Number Intent, cmsUI ...@@ -1348,6 +1356,7 @@ cmsBool OptimizeByJoiningCurves(cmsPipeline** Lut, cmsUInt32Number Intent, cmsUI
_cmsStageToneCurvesData* Data = (_cmsStageToneCurvesData*) ObtainedCurves ->Data; _cmsStageToneCurvesData* Data = (_cmsStageToneCurvesData*) ObtainedCurves ->Data;
Curves16Data* c16 = CurvesAlloc(Dest ->ContextID, Data ->nCurves, 256, Data ->TheCurves); Curves16Data* c16 = CurvesAlloc(Dest ->ContextID, Data ->nCurves, 256, Data ->TheCurves);
if (c16 == NULL) goto Error;
*dwFlags |= cmsFLAGS_NOCACHE; *dwFlags |= cmsFLAGS_NOCACHE;
_cmsPipelineSetOptimizationParameters(Dest, FastEvaluateCurves8, c16, CurvesFree, CurvesDup); _cmsPipelineSetOptimizationParameters(Dest, FastEvaluateCurves8, c16, CurvesFree, CurvesDup);
...@@ -1357,6 +1366,7 @@ cmsBool OptimizeByJoiningCurves(cmsPipeline** Lut, cmsUInt32Number Intent, cmsUI ...@@ -1357,6 +1366,7 @@ cmsBool OptimizeByJoiningCurves(cmsPipeline** Lut, cmsUInt32Number Intent, cmsUI
_cmsStageToneCurvesData* Data = (_cmsStageToneCurvesData*) cmsStageData(ObtainedCurves); _cmsStageToneCurvesData* Data = (_cmsStageToneCurvesData*) cmsStageData(ObtainedCurves);
Curves16Data* c16 = CurvesAlloc(Dest ->ContextID, Data ->nCurves, 65536, Data ->TheCurves); Curves16Data* c16 = CurvesAlloc(Dest ->ContextID, Data ->nCurves, 65536, Data ->TheCurves);
if (c16 == NULL) goto Error;
*dwFlags |= cmsFLAGS_NOCACHE; *dwFlags |= cmsFLAGS_NOCACHE;
_cmsPipelineSetOptimizationParameters(Dest, FastEvaluateCurves16, c16, CurvesFree, CurvesDup); _cmsPipelineSetOptimizationParameters(Dest, FastEvaluateCurves16, c16, CurvesFree, CurvesDup);
} }
...@@ -1366,7 +1376,8 @@ cmsBool OptimizeByJoiningCurves(cmsPipeline** Lut, cmsUInt32Number Intent, cmsUI ...@@ -1366,7 +1376,8 @@ cmsBool OptimizeByJoiningCurves(cmsPipeline** Lut, cmsUInt32Number Intent, cmsUI
// LUT optimizes to nothing. Set the identity LUT // LUT optimizes to nothing. Set the identity LUT
cmsStageFree(ObtainedCurves); cmsStageFree(ObtainedCurves);
cmsPipelineInsertStage(Dest, cmsAT_BEGIN, cmsStageAllocIdentity(Dest ->ContextID, Src ->InputChannels)); if (!cmsPipelineInsertStage(Dest, cmsAT_BEGIN, cmsStageAllocIdentity(Dest ->ContextID, Src ->InputChannels)))
goto Error;
*dwFlags |= cmsFLAGS_NOCACHE; *dwFlags |= cmsFLAGS_NOCACHE;
_cmsPipelineSetOptimizationParameters(Dest, FastIdentity16, (void*) Dest, NULL, NULL); _cmsPipelineSetOptimizationParameters(Dest, FastIdentity16, (void*) Dest, NULL, NULL);
...@@ -1596,10 +1607,14 @@ cmsBool OptimizeMatrixShaper(cmsPipeline** Lut, cmsUInt32Number Intent, cmsUInt3 ...@@ -1596,10 +1607,14 @@ cmsBool OptimizeMatrixShaper(cmsPipeline** Lut, cmsUInt32Number Intent, cmsUInt3
if (!Dest) return FALSE; if (!Dest) return FALSE;
// Assamble the new LUT // Assamble the new LUT
cmsPipelineInsertStage(Dest, cmsAT_BEGIN, cmsStageDup(Curve1)); if (!cmsPipelineInsertStage(Dest, cmsAT_BEGIN, cmsStageDup(Curve1)))
goto Error;
if (!IdentityMat) if (!IdentityMat)
cmsPipelineInsertStage(Dest, cmsAT_END, cmsStageAllocMatrix(Dest ->ContextID, 3, 3, (const cmsFloat64Number*) &res, Data2 ->Offset)); if (!cmsPipelineInsertStage(Dest, cmsAT_END, cmsStageAllocMatrix(Dest ->ContextID, 3, 3, (const cmsFloat64Number*) &res, Data2 ->Offset)))
cmsPipelineInsertStage(Dest, cmsAT_END, cmsStageDup(Curve2)); goto Error;
if (!cmsPipelineInsertStage(Dest, cmsAT_END, cmsStageDup(Curve2)))
goto Error;
// If identity on matrix, we can further optimize the curves, so call the join curves routine // If identity on matrix, we can further optimize the curves, so call the join curves routine
if (IdentityMat) { if (IdentityMat) {
...@@ -1621,6 +1636,10 @@ cmsBool OptimizeMatrixShaper(cmsPipeline** Lut, cmsUInt32Number Intent, cmsUInt3 ...@@ -1621,6 +1636,10 @@ cmsBool OptimizeMatrixShaper(cmsPipeline** Lut, cmsUInt32Number Intent, cmsUInt3
cmsPipelineFree(Src); cmsPipelineFree(Src);
*Lut = Dest; *Lut = Dest;
return TRUE; return TRUE;
Error:
// Leave Src unchanged
cmsPipelineFree(Dest);
return FALSE;
} }
...@@ -1650,7 +1669,7 @@ static _cmsOptimizationCollection DefaultOptimization[] = { ...@@ -1650,7 +1669,7 @@ static _cmsOptimizationCollection DefaultOptimization[] = {
static _cmsOptimizationCollection* OptimizationCollection = DefaultOptimization; static _cmsOptimizationCollection* OptimizationCollection = DefaultOptimization;
// Register new ways to optimize // Register new ways to optimize
cmsBool _cmsRegisterOptimizationPlugin(cmsPluginBase* Data) cmsBool _cmsRegisterOptimizationPlugin(cmsContext id, cmsPluginBase* Data)
{ {
cmsPluginOptimization* Plugin = (cmsPluginOptimization*) Data; cmsPluginOptimization* Plugin = (cmsPluginOptimization*) Data;
_cmsOptimizationCollection* fl; _cmsOptimizationCollection* fl;
...@@ -1664,7 +1683,7 @@ cmsBool _cmsRegisterOptimizationPlugin(cmsPluginBase* Data) ...@@ -1664,7 +1683,7 @@ cmsBool _cmsRegisterOptimizationPlugin(cmsPluginBase* Data)
// Optimizer callback is required // Optimizer callback is required
if (Plugin ->OptimizePtr == NULL) return FALSE; if (Plugin ->OptimizePtr == NULL) return FALSE;
fl = (_cmsOptimizationCollection*) _cmsPluginMalloc(sizeof(_cmsOptimizationCollection)); fl = (_cmsOptimizationCollection*) _cmsPluginMalloc(id, sizeof(_cmsOptimizationCollection));
if (fl == NULL) return FALSE; if (fl == NULL) return FALSE;
// Copy the parameters // Copy the parameters
......
...@@ -316,6 +316,23 @@ cmsUInt8Number* Unroll3BytesSkip1Swap(register _cmsTRANSFORM* info, ...@@ -316,6 +316,23 @@ cmsUInt8Number* Unroll3BytesSkip1Swap(register _cmsTRANSFORM* info,
cmsUNUSED_PARAMETER(Stride); cmsUNUSED_PARAMETER(Stride);
} }
static
cmsUInt8Number* Unroll3BytesSkip1SwapSwapFirst(register _cmsTRANSFORM* info,
register cmsUInt16Number wIn[],
register cmsUInt8Number* accum,
register cmsUInt32Number Stride)
{
wIn[2] = FROM_8_TO_16(*accum); accum++; // B
wIn[1] = FROM_8_TO_16(*accum); accum++; // G
wIn[0] = FROM_8_TO_16(*accum); accum++; // R
accum++; // A
return accum;
cmsUNUSED_PARAMETER(info);
cmsUNUSED_PARAMETER(Stride);
}
static static
cmsUInt8Number* Unroll3BytesSkip1SwapFirst(register _cmsTRANSFORM* info, cmsUInt8Number* Unroll3BytesSkip1SwapFirst(register _cmsTRANSFORM* info,
register cmsUInt16Number wIn[], register cmsUInt16Number wIn[],
...@@ -2901,6 +2918,9 @@ static cmsFormatters16 InputFormatters16[] = { ...@@ -2901,6 +2918,9 @@ static cmsFormatters16 InputFormatters16[] = {
{ CHANNELS_SH(3)|EXTRA_SH(1)|BYTES_SH(1)|DOSWAP_SH(1), ANYSPACE, Unroll3BytesSkip1Swap}, { CHANNELS_SH(3)|EXTRA_SH(1)|BYTES_SH(1)|DOSWAP_SH(1), ANYSPACE, Unroll3BytesSkip1Swap},
{ CHANNELS_SH(3)|EXTRA_SH(1)|BYTES_SH(1)|SWAPFIRST_SH(1), ANYSPACE, Unroll3BytesSkip1SwapFirst}, { CHANNELS_SH(3)|EXTRA_SH(1)|BYTES_SH(1)|SWAPFIRST_SH(1), ANYSPACE, Unroll3BytesSkip1SwapFirst},
{ CHANNELS_SH(3)|EXTRA_SH(1)|BYTES_SH(1)|DOSWAP_SH(1)|SWAPFIRST_SH(1),
ANYSPACE, Unroll3BytesSkip1SwapSwapFirst},
{ CHANNELS_SH(4)|BYTES_SH(1), ANYSPACE, Unroll4Bytes}, { CHANNELS_SH(4)|BYTES_SH(1), ANYSPACE, Unroll4Bytes},
{ CHANNELS_SH(4)|BYTES_SH(1)|FLAVOR_SH(1), ANYSPACE, Unroll4BytesReverse}, { CHANNELS_SH(4)|BYTES_SH(1)|FLAVOR_SH(1), ANYSPACE, Unroll4BytesReverse},
{ CHANNELS_SH(4)|BYTES_SH(1)|SWAPFIRST_SH(1), ANYSPACE, Unroll4BytesSwapFirst}, { CHANNELS_SH(4)|BYTES_SH(1)|SWAPFIRST_SH(1), ANYSPACE, Unroll4BytesSwapFirst},
...@@ -3166,7 +3186,7 @@ static cmsFormattersFactoryList* FactoryList = NULL; ...@@ -3166,7 +3186,7 @@ static cmsFormattersFactoryList* FactoryList = NULL;
// Formatters management // Formatters management
cmsBool _cmsRegisterFormattersPlugin(cmsPluginBase* Data) cmsBool _cmsRegisterFormattersPlugin(cmsContext id, cmsPluginBase* Data)
{ {
cmsPluginFormatters* Plugin = (cmsPluginFormatters*) Data; cmsPluginFormatters* Plugin = (cmsPluginFormatters*) Data;
cmsFormattersFactoryList* fl ; cmsFormattersFactoryList* fl ;
...@@ -3178,7 +3198,7 @@ cmsBool _cmsRegisterFormattersPlugin(cmsPluginBase* Data) ...@@ -3178,7 +3198,7 @@ cmsBool _cmsRegisterFormattersPlugin(cmsPluginBase* Data)
return TRUE; return TRUE;
} }
fl = (cmsFormattersFactoryList*) _cmsPluginMalloc(sizeof(cmsFormattersFactoryList)); fl = (cmsFormattersFactoryList*) _cmsPluginMalloc(id, sizeof(cmsFormattersFactoryList));
if (fl == NULL) return FALSE; if (fl == NULL) return FALSE;
fl ->Factory = Plugin ->FormattersFactory; fl ->Factory = Plugin ->FormattersFactory;
......
...@@ -898,9 +898,11 @@ cmsUInt32Number CMSEXPORT cmsChannelsOf(cmsColorSpaceSignature ColorSpace) ...@@ -898,9 +898,11 @@ cmsUInt32Number CMSEXPORT cmsChannelsOf(cmsColorSpaceSignature ColorSpace)
{ {
switch (ColorSpace) { switch (ColorSpace) {
case cmsSigMCH1Data:
case cmsSig1colorData: case cmsSig1colorData:
case cmsSigGrayData: return 1; case cmsSigGrayData: return 1;
case cmsSigMCH2Data:
case cmsSig2colorData: return 2; case cmsSig2colorData: return 2;
case cmsSigXYZData: case cmsSigXYZData:
...@@ -912,10 +914,12 @@ cmsUInt32Number CMSEXPORT cmsChannelsOf(cmsColorSpaceSignature ColorSpace) ...@@ -912,10 +914,12 @@ cmsUInt32Number CMSEXPORT cmsChannelsOf(cmsColorSpaceSignature ColorSpace)
case cmsSigHsvData: case cmsSigHsvData:
case cmsSigHlsData: case cmsSigHlsData:
case cmsSigCmyData: case cmsSigCmyData:
case cmsSigMCH3Data:
case cmsSig3colorData: return 3; case cmsSig3colorData: return 3;
case cmsSigLuvKData: case cmsSigLuvKData:
case cmsSigCmykData: case cmsSigCmykData:
case cmsSigMCH4Data:
case cmsSig4colorData: return 4; case cmsSig4colorData: return 4;
case cmsSigMCH5Data: case cmsSigMCH5Data:
......
...@@ -125,10 +125,14 @@ void CMSEXPORT _cmsAdjustEndianess64(cmsUInt64Number* Result, cmsUInt64Number* ...@@ -125,10 +125,14 @@ void CMSEXPORT _cmsAdjustEndianess64(cmsUInt64Number* Result, cmsUInt64Number*
pOut[0] = pIn[7]; pOut[0] = pIn[7];
#else #else
_cmsAssert(Result != NULL); _cmsAssert(Result != NULL);
# ifdef CMS_DONT_USE_INT64
(*Result)[0] = QWord[0];
(*Result)[1] = QWord[1];
# else
*Result = *QWord; *Result = *QWord;
# endif
#endif #endif
} }
...@@ -543,10 +547,10 @@ cmsBool CMSEXPORT _cmsIOPrintf(cmsIOHANDLER* io, const char* frm, ...) ...@@ -543,10 +547,10 @@ cmsBool CMSEXPORT _cmsIOPrintf(cmsIOHANDLER* io, const char* frm, ...)
static _cmsSubAllocator* PluginPool = NULL; static _cmsSubAllocator* PluginPool = NULL;
// Specialized malloc for plug-ins, that is freed upon exit. // Specialized malloc for plug-ins, that is freed upon exit.
void* _cmsPluginMalloc(cmsUInt32Number size) void* _cmsPluginMalloc(cmsContext id, cmsUInt32Number size)
{ {
if (PluginPool == NULL) if (PluginPool == NULL)
PluginPool = _cmsCreateSubAlloc(0, 4*1024); PluginPool = _cmsCreateSubAlloc(id, 4*1024);
return _cmsSubAlloc(PluginPool, size); return _cmsSubAlloc(PluginPool, size);
} }
...@@ -554,6 +558,11 @@ void* _cmsPluginMalloc(cmsUInt32Number size) ...@@ -554,6 +558,11 @@ void* _cmsPluginMalloc(cmsUInt32Number size)
// Main plug-in dispatcher // Main plug-in dispatcher
cmsBool CMSEXPORT cmsPlugin(void* Plug_in) cmsBool CMSEXPORT cmsPlugin(void* Plug_in)
{
return cmsPluginTHR(NULL, Plug_in);
}
cmsBool CMSEXPORT cmsPluginTHR(cmsContext id, void* Plug_in)
{ {
cmsPluginBase* Plugin; cmsPluginBase* Plugin;
...@@ -583,35 +592,35 @@ cmsBool CMSEXPORT cmsPlugin(void* Plug_in) ...@@ -583,35 +592,35 @@ cmsBool CMSEXPORT cmsPlugin(void* Plug_in)
break; break;
case cmsPluginTagTypeSig: case cmsPluginTagTypeSig:
if (!_cmsRegisterTagTypePlugin(Plugin)) return FALSE; if (!_cmsRegisterTagTypePlugin(id, Plugin)) return FALSE;
break; break;
case cmsPluginTagSig: case cmsPluginTagSig:
if (!_cmsRegisterTagPlugin(Plugin)) return FALSE; if (!_cmsRegisterTagPlugin(id, Plugin)) return FALSE;
break; break;
case cmsPluginFormattersSig: case cmsPluginFormattersSig:
if (!_cmsRegisterFormattersPlugin(Plugin)) return FALSE; if (!_cmsRegisterFormattersPlugin(id, Plugin)) return FALSE;
break; break;
case cmsPluginRenderingIntentSig: case cmsPluginRenderingIntentSig:
if (!_cmsRegisterRenderingIntentPlugin(Plugin)) return FALSE; if (!_cmsRegisterRenderingIntentPlugin(id, Plugin)) return FALSE;
break; break;
case cmsPluginParametricCurveSig: case cmsPluginParametricCurveSig:
if (!_cmsRegisterParametricCurvesPlugin(Plugin)) return FALSE; if (!_cmsRegisterParametricCurvesPlugin(id, Plugin)) return FALSE;
break; break;
case cmsPluginMultiProcessElementSig: case cmsPluginMultiProcessElementSig:
if (!_cmsRegisterMultiProcessElementPlugin(Plugin)) return FALSE; if (!_cmsRegisterMultiProcessElementPlugin(id, Plugin)) return FALSE;
break; break;
case cmsPluginOptimizationSig: case cmsPluginOptimizationSig:
if (!_cmsRegisterOptimizationPlugin(Plugin)) return FALSE; if (!_cmsRegisterOptimizationPlugin(id, Plugin)) return FALSE;
break; break;
case cmsPluginTransformSig: case cmsPluginTransformSig:
if (!_cmsRegisterTransformPlugin(Plugin)) return FALSE; if (!_cmsRegisterTransformPlugin(id, Plugin)) return FALSE;
break; break;
default: default:
...@@ -630,14 +639,14 @@ void CMSEXPORT cmsUnregisterPlugins(void) ...@@ -630,14 +639,14 @@ void CMSEXPORT cmsUnregisterPlugins(void)
{ {
_cmsRegisterMemHandlerPlugin(NULL); _cmsRegisterMemHandlerPlugin(NULL);
_cmsRegisterInterpPlugin(NULL); _cmsRegisterInterpPlugin(NULL);
_cmsRegisterTagTypePlugin(NULL); _cmsRegisterTagTypePlugin(NULL, NULL);
_cmsRegisterTagPlugin(NULL); _cmsRegisterTagPlugin(NULL, NULL);
_cmsRegisterFormattersPlugin(NULL); _cmsRegisterFormattersPlugin(NULL, NULL);
_cmsRegisterRenderingIntentPlugin(NULL); _cmsRegisterRenderingIntentPlugin(NULL, NULL);
_cmsRegisterParametricCurvesPlugin(NULL); _cmsRegisterParametricCurvesPlugin(NULL, NULL);
_cmsRegisterMultiProcessElementPlugin(NULL); _cmsRegisterMultiProcessElementPlugin(NULL, NULL);
_cmsRegisterOptimizationPlugin(NULL); _cmsRegisterOptimizationPlugin(NULL, NULL);
_cmsRegisterTransformPlugin(NULL); _cmsRegisterTransformPlugin(NULL, NULL);
if (PluginPool != NULL) if (PluginPool != NULL)
_cmsSubAllocDestroy(PluginPool); _cmsSubAllocDestroy(PluginPool);
......
...@@ -806,7 +806,6 @@ int EmitCIEBasedDEF(cmsIOHANDLER* m, cmsPipeline* Pipeline, int Intent, cmsCIEXY ...@@ -806,7 +806,6 @@ int EmitCIEBasedDEF(cmsIOHANDLER* m, cmsPipeline* Pipeline, int Intent, cmsCIEXY
mpe = Pipeline ->Elements; mpe = Pipeline ->Elements;
switch (cmsStageInputChannels(mpe)) { switch (cmsStageInputChannels(mpe)) {
case 3: case 3:
...@@ -838,8 +837,6 @@ int EmitCIEBasedDEF(cmsIOHANDLER* m, cmsPipeline* Pipeline, int Intent, cmsCIEXY ...@@ -838,8 +837,6 @@ int EmitCIEBasedDEF(cmsIOHANDLER* m, cmsPipeline* Pipeline, int Intent, cmsCIEXY
mpe = mpe ->Next; mpe = mpe ->Next;
} }
if (cmsStageType(mpe) == cmsSigCLutElemType) { if (cmsStageType(mpe) == cmsSigCLutElemType) {
_cmsIOPrintf(m, "/Table "); _cmsIOPrintf(m, "/Table ");
...@@ -854,7 +851,6 @@ int EmitCIEBasedDEF(cmsIOHANDLER* m, cmsPipeline* Pipeline, int Intent, cmsCIEXY ...@@ -854,7 +851,6 @@ int EmitCIEBasedDEF(cmsIOHANDLER* m, cmsPipeline* Pipeline, int Intent, cmsCIEXY
_cmsIOPrintf(m, " >>\n"); _cmsIOPrintf(m, " >>\n");
_cmsIOPrintf(m, "]\n"); _cmsIOPrintf(m, "]\n");
return 1; return 1;
} }
...@@ -950,6 +946,7 @@ int WriteInputLUT(cmsIOHANDLER* m, cmsHPROFILE hProfile, int Intent, cmsUInt32Nu ...@@ -950,6 +946,7 @@ int WriteInputLUT(cmsIOHANDLER* m, cmsHPROFILE hProfile, int Intent, cmsUInt32Nu
rc = EmitCIEBasedDEF(m, DeviceLink, Intent, &BlackPointAdaptedToD50); rc = EmitCIEBasedDEF(m, DeviceLink, Intent, &BlackPointAdaptedToD50);
cmsPipelineFree(DeviceLink); cmsPipelineFree(DeviceLink);
if (rc == 0) return 0;
} }
break; break;
......
...@@ -56,6 +56,8 @@ ...@@ -56,6 +56,8 @@
#include "lcms2_internal.h" #include "lcms2_internal.h"
#define cmsmin(a, b) (((a) < (b)) ? (a) : (b))
#define cmsmax(a, b) (((a) > (b)) ? (a) : (b))
// This file contains routines for resampling and LUT optimization, black point detection // This file contains routines for resampling and LUT optimization, black point detection
// and black preservation. // and black preservation.
...@@ -67,13 +69,13 @@ ...@@ -67,13 +69,13 @@
static static
cmsHTRANSFORM CreateRoundtripXForm(cmsHPROFILE hProfile, cmsUInt32Number nIntent) cmsHTRANSFORM CreateRoundtripXForm(cmsHPROFILE hProfile, cmsUInt32Number nIntent)
{ {
cmsHPROFILE hLab = cmsCreateLab4Profile(NULL); cmsContext ContextID = cmsGetProfileContextID(hProfile);
cmsHPROFILE hLab = cmsCreateLab4ProfileTHR(ContextID, NULL);
cmsHTRANSFORM xform; cmsHTRANSFORM xform;
cmsBool BPC[4] = { FALSE, FALSE, FALSE, FALSE }; cmsBool BPC[4] = { FALSE, FALSE, FALSE, FALSE };
cmsFloat64Number States[4] = { 1.0, 1.0, 1.0, 1.0 }; cmsFloat64Number States[4] = { 1.0, 1.0, 1.0, 1.0 };
cmsHPROFILE hProfiles[4]; cmsHPROFILE hProfiles[4];
cmsUInt32Number Intents[4]; cmsUInt32Number Intents[4];
cmsContext ContextID = cmsGetProfileContextID(hProfile);
hProfiles[0] = hLab; hProfiles[1] = hProfile; hProfiles[2] = hProfile; hProfiles[3] = hLab; hProfiles[0] = hLab; hProfiles[1] = hProfile; hProfiles[2] = hProfile; hProfiles[3] = hLab;
Intents[0] = INTENT_RELATIVE_COLORIMETRIC; Intents[1] = nIntent; Intents[2] = INTENT_RELATIVE_COLORIMETRIC; Intents[3] = INTENT_RELATIVE_COLORIMETRIC; Intents[0] = INTENT_RELATIVE_COLORIMETRIC; Intents[1] = nIntent; Intents[2] = INTENT_RELATIVE_COLORIMETRIC; Intents[3] = INTENT_RELATIVE_COLORIMETRIC;
...@@ -141,8 +143,8 @@ cmsBool BlackPointAsDarkerColorant(cmsHPROFILE hInput, ...@@ -141,8 +143,8 @@ cmsBool BlackPointAsDarkerColorant(cmsHPROFILE hInput,
cmsCloseProfile(hLab); cmsCloseProfile(hLab);
if (xform == NULL) { if (xform == NULL) {
// Something went wrong. Get rid of open resources and return zero as black
// Something went wrong. Get rid of open resources and return zero as black
BlackPoint -> X = BlackPoint ->Y = BlackPoint -> Z = 0.0; BlackPoint -> X = BlackPoint ->Y = BlackPoint -> Z = 0.0;
return FALSE; return FALSE;
} }
...@@ -173,7 +175,6 @@ cmsBool BlackPointAsDarkerColorant(cmsHPROFILE hInput, ...@@ -173,7 +175,6 @@ cmsBool BlackPointAsDarkerColorant(cmsHPROFILE hInput,
// Lab (0, 0, 0) -> [Perceptual] Profile -> CMYK -> [Rel. colorimetric] Profile -> Lab // Lab (0, 0, 0) -> [Perceptual] Profile -> CMYK -> [Rel. colorimetric] Profile -> Lab
static static
cmsBool BlackPointUsingPerceptualBlack(cmsCIEXYZ* BlackPoint, cmsHPROFILE hProfile) cmsBool BlackPointUsingPerceptualBlack(cmsCIEXYZ* BlackPoint, cmsHPROFILE hProfile)
{ {
cmsHTRANSFORM hRoundTrip; cmsHTRANSFORM hRoundTrip;
cmsCIELab LabIn, LabOut; cmsCIELab LabIn, LabOut;
...@@ -218,17 +219,27 @@ cmsBool BlackPointUsingPerceptualBlack(cmsCIEXYZ* BlackPoint, cmsHPROFILE hProfi ...@@ -218,17 +219,27 @@ cmsBool BlackPointUsingPerceptualBlack(cmsCIEXYZ* BlackPoint, cmsHPROFILE hProfi
// involves to turn BP to neutral and to use only L component. // involves to turn BP to neutral and to use only L component.
cmsBool CMSEXPORT cmsDetectBlackPoint(cmsCIEXYZ* BlackPoint, cmsHPROFILE hProfile, cmsUInt32Number Intent, cmsUInt32Number dwFlags) cmsBool CMSEXPORT cmsDetectBlackPoint(cmsCIEXYZ* BlackPoint, cmsHPROFILE hProfile, cmsUInt32Number Intent, cmsUInt32Number dwFlags)
{ {
cmsProfileClassSignature devClass;
// Make sure the device class is adequate
devClass = cmsGetDeviceClass(hProfile);
if (devClass == cmsSigLinkClass ||
devClass == cmsSigAbstractClass ||
devClass == cmsSigNamedColorClass) {
BlackPoint -> X = BlackPoint ->Y = BlackPoint -> Z = 0.0;
return FALSE;
}
// Zero for black point // Make sure intent is adequate
if (cmsGetDeviceClass(hProfile) == cmsSigLinkClass) { if (Intent != INTENT_PERCEPTUAL &&
Intent != INTENT_RELATIVE_COLORIMETRIC &&
BlackPoint -> X = BlackPoint ->Y = BlackPoint -> Z = 0.0; Intent != INTENT_SATURATION) {
return FALSE; BlackPoint -> X = BlackPoint ->Y = BlackPoint -> Z = 0.0;
return FALSE;
} }
// v4 + perceptual & saturation intents does have its own black point, and it is // v4 + perceptual & saturation intents does have its own black point, and it is
// well specified enough to use it. Black point tag is deprecated in V4. // well specified enough to use it. Black point tag is deprecated in V4.
if ((cmsGetEncodedICCversion(hProfile) >= 0x4000000) && if ((cmsGetEncodedICCversion(hProfile) >= 0x4000000) &&
(Intent == INTENT_PERCEPTUAL || Intent == INTENT_SATURATION)) { (Intent == INTENT_PERCEPTUAL || Intent == INTENT_SATURATION)) {
...@@ -303,7 +314,7 @@ cmsFloat64Number RootOfLeastSquaresFitQuadraticCurve(int n, cmsFloat64Number x[] ...@@ -303,7 +314,7 @@ cmsFloat64Number RootOfLeastSquaresFitQuadraticCurve(int n, cmsFloat64Number x[]
{ {
double sum_x = 0, sum_x2 = 0, sum_x3 = 0, sum_x4 = 0; double sum_x = 0, sum_x2 = 0, sum_x3 = 0, sum_x4 = 0;
double sum_y = 0, sum_yx = 0, sum_yx2 = 0; double sum_y = 0, sum_yx = 0, sum_yx2 = 0;
double disc; double d, a, b, c;
int i; int i;
cmsMAT3 m; cmsMAT3 m;
cmsVEC3 v, res; cmsVEC3 v, res;
...@@ -333,14 +344,32 @@ cmsFloat64Number RootOfLeastSquaresFitQuadraticCurve(int n, cmsFloat64Number x[] ...@@ -333,14 +344,32 @@ cmsFloat64Number RootOfLeastSquaresFitQuadraticCurve(int n, cmsFloat64Number x[]
if (!_cmsMAT3solve(&res, &m, &v)) return 0; if (!_cmsMAT3solve(&res, &m, &v)) return 0;
// y = t x2 + u x + c
// x = ( - u + Sqrt( u^2 - 4 t c ) ) / ( 2 t )
disc = res.n[1]*res.n[1] - 4.0 * res.n[0] * res.n[2];
if (disc < 0) return -1;
return ( -1.0 * res.n[1] + sqrt( disc )) / (2.0 * res.n[0]); a = res.n[2];
b = res.n[1];
c = res.n[0];
if (fabs(a) < 1.0E-10) {
return cmsmin(0, cmsmax(50, -c/b ));
}
else {
d = b*b - 4.0 * a * c;
if (d <= 0) {
return 0;
}
else {
double rt = (-b + sqrt(d)) / (2.0 * a);
return cmsmax(0, cmsmin(50, rt));
}
}
} }
/*
static static
cmsBool IsMonotonic(int n, const cmsFloat64Number Table[]) cmsBool IsMonotonic(int n, const cmsFloat64Number Table[])
{ {
...@@ -361,6 +390,7 @@ cmsBool IsMonotonic(int n, const cmsFloat64Number Table[]) ...@@ -361,6 +390,7 @@ cmsBool IsMonotonic(int n, const cmsFloat64Number Table[])
return TRUE; return TRUE;
} }
*/
// Calculates the black point of a destination profile. // Calculates the black point of a destination profile.
// This algorithm comes from the Adobe paper disclosing its black point compensation method. // This algorithm comes from the Adobe paper disclosing its black point compensation method.
...@@ -369,21 +399,30 @@ cmsBool CMSEXPORT cmsDetectDestinationBlackPoint(cmsCIEXYZ* BlackPoint, cmsHPROF ...@@ -369,21 +399,30 @@ cmsBool CMSEXPORT cmsDetectDestinationBlackPoint(cmsCIEXYZ* BlackPoint, cmsHPROF
cmsColorSpaceSignature ColorSpace; cmsColorSpaceSignature ColorSpace;
cmsHTRANSFORM hRoundTrip = NULL; cmsHTRANSFORM hRoundTrip = NULL;
cmsCIELab InitialLab, destLab, Lab; cmsCIELab InitialLab, destLab, Lab;
cmsFloat64Number inRamp[256], outRamp[256];
cmsFloat64Number MinL, MaxL; cmsFloat64Number MinL, MaxL;
cmsBool NearlyStraightMidRange = FALSE; cmsBool NearlyStraightMidrange = TRUE;
cmsFloat64Number L; cmsFloat64Number yRamp[256];
cmsFloat64Number x[101], y[101]; cmsFloat64Number x[256], y[256];
cmsFloat64Number lo, hi, NonMonoMin; cmsFloat64Number lo, hi;
int n, l, i, NonMonoIndx; int n, l;
cmsProfileClassSignature devClass;
// Make sure the device class is adequate
devClass = cmsGetDeviceClass(hProfile);
if (devClass == cmsSigLinkClass ||
devClass == cmsSigAbstractClass ||
devClass == cmsSigNamedColorClass) {
BlackPoint -> X = BlackPoint ->Y = BlackPoint -> Z = 0.0;
return FALSE;
}
// Make sure intent is adequate // Make sure intent is adequate
if (Intent != INTENT_PERCEPTUAL && if (Intent != INTENT_PERCEPTUAL &&
Intent != INTENT_RELATIVE_COLORIMETRIC && Intent != INTENT_RELATIVE_COLORIMETRIC &&
Intent != INTENT_SATURATION) { Intent != INTENT_SATURATION) {
BlackPoint -> X = BlackPoint ->Y = BlackPoint -> Z = 0.0; BlackPoint -> X = BlackPoint ->Y = BlackPoint -> Z = 0.0;
return FALSE; return FALSE;
} }
...@@ -415,10 +454,8 @@ cmsBool CMSEXPORT cmsDetectDestinationBlackPoint(cmsCIEXYZ* BlackPoint, cmsHPROF ...@@ -415,10 +454,8 @@ cmsBool CMSEXPORT cmsDetectDestinationBlackPoint(cmsCIEXYZ* BlackPoint, cmsHPROF
return cmsDetectBlackPoint(BlackPoint, hProfile, Intent, dwFlags); return cmsDetectBlackPoint(BlackPoint, hProfile, Intent, dwFlags);
} }
// It is one of the valid cases!, presto chargo hocus pocus, go for the Adobe magic // It is one of the valid cases!, use Adobe algorithm
// Step 1
// ======
// Set a first guess, that should work on good profiles. // Set a first guess, that should work on good profiles.
if (Intent == INTENT_RELATIVE_COLORIMETRIC) { if (Intent == INTENT_RELATIVE_COLORIMETRIC) {
...@@ -449,71 +486,68 @@ cmsBool CMSEXPORT cmsDetectDestinationBlackPoint(cmsCIEXYZ* BlackPoint, cmsHPROF ...@@ -449,71 +486,68 @@ cmsBool CMSEXPORT cmsDetectDestinationBlackPoint(cmsCIEXYZ* BlackPoint, cmsHPROF
hRoundTrip = CreateRoundtripXForm(hProfile, Intent); hRoundTrip = CreateRoundtripXForm(hProfile, Intent);
if (hRoundTrip == NULL) return FALSE; if (hRoundTrip == NULL) return FALSE;
// Calculate Min L* // Compute ramps
Lab = InitialLab;
Lab.L = 0;
cmsDoTransform(hRoundTrip, &Lab, &destLab, 1);
MinL = destLab.L;
// Calculate Max L* for (l=0; l < 256; l++) {
Lab = InitialLab;
Lab.L = 100;
cmsDoTransform(hRoundTrip, &Lab, &destLab, 1);
MaxL = destLab.L;
// Step 3 Lab.L = (cmsFloat64Number) (l * 100.0) / 255.0;
// ====== Lab.a = cmsmin(50, cmsmax(-50, InitialLab.a));
Lab.b = cmsmin(50, cmsmax(-50, InitialLab.b));
// check if quadratic estimation needs to be done. cmsDoTransform(hRoundTrip, &Lab, &destLab, 1);
if (Intent == INTENT_RELATIVE_COLORIMETRIC) {
// Conceptually, this code tests how close the source l and converted L are to one another in the mid-range inRamp[l] = Lab.L;
// of the values. If the converted ramp of L values is close enough to a straight line y=x, then InitialLab outRamp[l] = destLab.L;
// is good enough to be the DestinationBlackPoint, }
NearlyStraightMidRange = TRUE;
for (l=0; l <= 100; l++) { // Make monotonic
for (l = 254; l > 0; --l) {
outRamp[l] = cmsmin(outRamp[l], outRamp[l+1]);
}
Lab.L = l; // Check
Lab.a = InitialLab.a; if (! (outRamp[0] < outRamp[255])) {
Lab.b = InitialLab.b;
cmsDeleteTransform(hRoundTrip);
BlackPoint -> X = BlackPoint ->Y = BlackPoint -> Z = 0.0;
return FALSE;
}
cmsDoTransform(hRoundTrip, &Lab, &destLab, 1);
L = destLab.L; // Test for mid range straight (only on relative colorimetric)
// Check the mid range in 20% after MinL NearlyStraightMidrange = TRUE;
if (L > (MinL + 0.2 * (MaxL - MinL))) { MinL = outRamp[0]; MaxL = outRamp[255];
if (Intent == INTENT_RELATIVE_COLORIMETRIC) {
// Is close enough? for (l=0; l < 256; l++) {
if (fabs(L - l) > 4.0) {
// Too far away, profile is buggy! if (! ((inRamp[l] <= MinL + 0.2 * (MaxL - MinL) ) ||
NearlyStraightMidRange = FALSE; (fabs(inRamp[l] - outRamp[l]) < 4.0 )))
break; NearlyStraightMidrange = FALSE;
}
}
} }
}
else {
// Check is always performed for perceptual and saturation intents
NearlyStraightMidRange = FALSE;
}
// If the mid range is straight (as determined above) then the
// DestinationBlackPoint shall be the same as initialLab.
// Otherwise, the DestinationBlackPoint shall be determined
// using curve fitting.
// If no furter checking is needed, we are done if (NearlyStraightMidrange) {
if (NearlyStraightMidRange) {
cmsLab2XYZ(NULL, BlackPoint, &InitialLab); cmsLab2XYZ(NULL, BlackPoint, &InitialLab);
cmsDeleteTransform(hRoundTrip); cmsDeleteTransform(hRoundTrip);
return TRUE; return TRUE;
}
} }
// The round-trip curve normally looks like a nearly constant section at the black point,
// curve fitting: The round-trip curve normally looks like a nearly constant section at the black point,
// with a corner and a nearly straight line to the white point. // with a corner and a nearly straight line to the white point.
// STEP 4 for (l=0; l < 256; l++) {
// =======
yRamp[l] = (outRamp[l] - MinL) / (MaxL - MinL);
}
// find the black point using the least squares error quadratic curve fitting // find the black point using the least squares error quadratic curve fitting
...@@ -528,62 +562,32 @@ cmsBool CMSEXPORT cmsDetectDestinationBlackPoint(cmsCIEXYZ* BlackPoint, cmsHPROF ...@@ -528,62 +562,32 @@ cmsBool CMSEXPORT cmsDetectDestinationBlackPoint(cmsCIEXYZ* BlackPoint, cmsHPROF
hi = 0.25; hi = 0.25;
} }
// Capture points for the fitting. // Capture shadow points for the fitting.
n = 0; n = 0;
for (l=0; l <= 100; l++) { for (l=0; l < 256; l++) {
cmsFloat64Number ff; cmsFloat64Number ff = yRamp[l];
Lab.L = (cmsFloat64Number) l;
Lab.a = InitialLab.a;
Lab.b = InitialLab.b;
cmsDoTransform(hRoundTrip, &Lab, &destLab, 1);
ff = (destLab.L - MinL)/(MaxL - MinL);
if (ff >= lo && ff < hi) { if (ff >= lo && ff < hi) {
x[n] = inRamp[l];
x[n] = Lab.L; y[n] = yRamp[l];
y[n] = ff;
n++; n++;
} }
} }
// This part is not on the Adobe paper, but I found is necessary for getting any result.
if (IsMonotonic(n, y)) {
// Monotonic means lower point is stil valid
cmsLab2XYZ(NULL, BlackPoint, &InitialLab);
cmsDeleteTransform(hRoundTrip);
return TRUE;
}
// No suitable points, regret and use safer algorithm // No suitable points
if (n == 0) { if (n < 3 ) {
cmsDeleteTransform(hRoundTrip); cmsDeleteTransform(hRoundTrip);
return cmsDetectBlackPoint(BlackPoint, hProfile, Intent, dwFlags); BlackPoint -> X = BlackPoint ->Y = BlackPoint -> Z = 0.0;
} return FALSE;
NonMonoMin = 100;
NonMonoIndx = 0;
for (i=0; i < n; i++) {
if (y[i] < NonMonoMin) {
NonMonoIndx = i;
NonMonoMin = y[i];
}
} }
Lab.L = x[NonMonoIndx];
// fit and get the vertex of quadratic curve // fit and get the vertex of quadratic curve
Lab.L = RootOfLeastSquaresFitQuadraticCurve(n, x, y); Lab.L = RootOfLeastSquaresFitQuadraticCurve(n, x, y);
if (Lab.L < 0.0 || Lab.L > 50.0) { // clip to zero L* if the vertex is negative if (Lab.L < 0.0) { // clip to zero L* if the vertex is negative
Lab.L = 0; Lab.L = 0;
} }
......
...@@ -208,9 +208,26 @@ cmsHPROFILE CMSEXPORT cmsCreateRGBProfileTHR(cmsContext ContextID, ...@@ -208,9 +208,26 @@ cmsHPROFILE CMSEXPORT cmsCreateRGBProfileTHR(cmsContext ContextID,
if (TransferFunction) { if (TransferFunction) {
// Tries to minimize space. Thanks to Richard Hughes for this nice idea
if (!cmsWriteTag(hICC, cmsSigRedTRCTag, (void*) TransferFunction[0])) goto Error; if (!cmsWriteTag(hICC, cmsSigRedTRCTag, (void*) TransferFunction[0])) goto Error;
if (!cmsWriteTag(hICC, cmsSigGreenTRCTag, (void*) TransferFunction[1])) goto Error;
if (!cmsWriteTag(hICC, cmsSigBlueTRCTag, (void*) TransferFunction[2])) goto Error; if (TransferFunction[1] == TransferFunction[0]) {
if (!cmsLinkTag (hICC, cmsSigGreenTRCTag, cmsSigRedTRCTag)) goto Error;
} else {
if (!cmsWriteTag(hICC, cmsSigGreenTRCTag, (void*) TransferFunction[1])) goto Error;
}
if (TransferFunction[2] == TransferFunction[0]) {
if (!cmsLinkTag (hICC, cmsSigBlueTRCTag, cmsSigRedTRCTag)) goto Error;
} else {
if (!cmsWriteTag(hICC, cmsSigBlueTRCTag, (void*) TransferFunction[2])) goto Error;
}
} }
if (Primaries) { if (Primaries) {
...@@ -303,7 +320,6 @@ cmsHPROFILE CMSEXPORT cmsCreateLinearizationDeviceLinkTHR(cmsContext ContextID, ...@@ -303,7 +320,6 @@ cmsHPROFILE CMSEXPORT cmsCreateLinearizationDeviceLinkTHR(cmsContext ContextID,
{ {
cmsHPROFILE hICC; cmsHPROFILE hICC;
cmsPipeline* Pipeline; cmsPipeline* Pipeline;
cmsStage* Lin;
int nChannels; int nChannels;
hICC = cmsCreateProfilePlaceholder(ContextID); hICC = cmsCreateProfilePlaceholder(ContextID);
...@@ -327,10 +343,8 @@ cmsHPROFILE CMSEXPORT cmsCreateLinearizationDeviceLinkTHR(cmsContext ContextID, ...@@ -327,10 +343,8 @@ cmsHPROFILE CMSEXPORT cmsCreateLinearizationDeviceLinkTHR(cmsContext ContextID,
// Copy tables to Pipeline // Copy tables to Pipeline
Lin = cmsStageAllocToneCurves(ContextID, nChannels, TransferFunctions); if (!cmsPipelineInsertStage(Pipeline, cmsAT_BEGIN, cmsStageAllocToneCurves(ContextID, nChannels, TransferFunctions)))
if (Lin == NULL) goto Error; goto Error;
cmsPipelineInsertStage(Pipeline, cmsAT_BEGIN, Lin);
// Create tags // Create tags
if (!SetTextTags(hICC, L"Linearization built-in")) goto Error; if (!SetTextTags(hICC, L"Linearization built-in")) goto Error;
...@@ -344,6 +358,7 @@ cmsHPROFILE CMSEXPORT cmsCreateLinearizationDeviceLinkTHR(cmsContext ContextID, ...@@ -344,6 +358,7 @@ cmsHPROFILE CMSEXPORT cmsCreateLinearizationDeviceLinkTHR(cmsContext ContextID,
return hICC; return hICC;
Error: Error:
cmsPipelineFree(Pipeline);
if (hICC) if (hICC)
cmsCloseProfile(hICC); cmsCloseProfile(hICC);
...@@ -451,9 +466,10 @@ cmsHPROFILE CMSEXPORT cmsCreateInkLimitingDeviceLinkTHR(cmsContext ContextID, ...@@ -451,9 +466,10 @@ cmsHPROFILE CMSEXPORT cmsCreateInkLimitingDeviceLinkTHR(cmsContext ContextID,
if (!cmsStageSampleCLut16bit(CLUT, InkLimitingSampler, (void*) &Limit, 0)) goto Error; if (!cmsStageSampleCLut16bit(CLUT, InkLimitingSampler, (void*) &Limit, 0)) goto Error;
cmsPipelineInsertStage(LUT, cmsAT_BEGIN, _cmsStageAllocIdentityCurves(ContextID, nChannels)); if (!cmsPipelineInsertStage(LUT, cmsAT_BEGIN, _cmsStageAllocIdentityCurves(ContextID, nChannels)) ||
cmsPipelineInsertStage(LUT, cmsAT_END, CLUT); !cmsPipelineInsertStage(LUT, cmsAT_END, CLUT) ||
cmsPipelineInsertStage(LUT, cmsAT_END, _cmsStageAllocIdentityCurves(ContextID, nChannels)); !cmsPipelineInsertStage(LUT, cmsAT_END, _cmsStageAllocIdentityCurves(ContextID, nChannels)))
goto Error;
// Create tags // Create tags
if (!SetTextTags(hICC, L"ink-limiting built-in")) goto Error; if (!SetTextTags(hICC, L"ink-limiting built-in")) goto Error;
...@@ -504,7 +520,8 @@ cmsHPROFILE CMSEXPORT cmsCreateLab2ProfileTHR(cmsContext ContextID, const cmsCIE ...@@ -504,7 +520,8 @@ cmsHPROFILE CMSEXPORT cmsCreateLab2ProfileTHR(cmsContext ContextID, const cmsCIE
LUT = cmsPipelineAlloc(ContextID, 3, 3); LUT = cmsPipelineAlloc(ContextID, 3, 3);
if (LUT == NULL) goto Error; if (LUT == NULL) goto Error;
cmsPipelineInsertStage(LUT, cmsAT_BEGIN, _cmsStageAllocIdentityCLut(ContextID, 3)); if (!cmsPipelineInsertStage(LUT, cmsAT_BEGIN, _cmsStageAllocIdentityCLut(ContextID, 3)))
goto Error;
if (!cmsWriteTag(hProfile, cmsSigAToB0Tag, LUT)) goto Error; if (!cmsWriteTag(hProfile, cmsSigAToB0Tag, LUT)) goto Error;
cmsPipelineFree(LUT); cmsPipelineFree(LUT);
...@@ -550,7 +567,8 @@ cmsHPROFILE CMSEXPORT cmsCreateLab4ProfileTHR(cmsContext ContextID, const cmsCIE ...@@ -550,7 +567,8 @@ cmsHPROFILE CMSEXPORT cmsCreateLab4ProfileTHR(cmsContext ContextID, const cmsCIE
LUT = cmsPipelineAlloc(ContextID, 3, 3); LUT = cmsPipelineAlloc(ContextID, 3, 3);
if (LUT == NULL) goto Error; if (LUT == NULL) goto Error;
cmsPipelineInsertStage(LUT, cmsAT_BEGIN, _cmsStageAllocIdentityCurves(ContextID, 3)); if (!cmsPipelineInsertStage(LUT, cmsAT_BEGIN, _cmsStageAllocIdentityCurves(ContextID, 3)))
goto Error;
if (!cmsWriteTag(hProfile, cmsSigAToB0Tag, LUT)) goto Error; if (!cmsWriteTag(hProfile, cmsSigAToB0Tag, LUT)) goto Error;
cmsPipelineFree(LUT); cmsPipelineFree(LUT);
...@@ -595,7 +613,8 @@ cmsHPROFILE CMSEXPORT cmsCreateXYZProfileTHR(cmsContext ContextID) ...@@ -595,7 +613,8 @@ cmsHPROFILE CMSEXPORT cmsCreateXYZProfileTHR(cmsContext ContextID)
LUT = cmsPipelineAlloc(ContextID, 3, 3); LUT = cmsPipelineAlloc(ContextID, 3, 3);
if (LUT == NULL) goto Error; if (LUT == NULL) goto Error;
cmsPipelineInsertStage(LUT, cmsAT_BEGIN, _cmsStageAllocIdentityCurves(ContextID, 3)); if (!cmsPipelineInsertStage(LUT, cmsAT_BEGIN, _cmsStageAllocIdentityCurves(ContextID, 3)))
goto Error;
if (!cmsWriteTag(hProfile, cmsSigAToB0Tag, LUT)) goto Error; if (!cmsWriteTag(hProfile, cmsSigAToB0Tag, LUT)) goto Error;
cmsPipelineFree(LUT); cmsPipelineFree(LUT);
...@@ -734,81 +753,83 @@ int bchswSampler(register const cmsUInt16Number In[], register cmsUInt16Number O ...@@ -734,81 +753,83 @@ int bchswSampler(register const cmsUInt16Number In[], register cmsUInt16Number O
// contrast, Saturation and white point displacement // contrast, Saturation and white point displacement
cmsHPROFILE CMSEXPORT cmsCreateBCHSWabstractProfileTHR(cmsContext ContextID, cmsHPROFILE CMSEXPORT cmsCreateBCHSWabstractProfileTHR(cmsContext ContextID,
int nLUTPoints, int nLUTPoints,
cmsFloat64Number Bright, cmsFloat64Number Bright,
cmsFloat64Number Contrast, cmsFloat64Number Contrast,
cmsFloat64Number Hue, cmsFloat64Number Hue,
cmsFloat64Number Saturation, cmsFloat64Number Saturation,
int TempSrc, int TempSrc,
int TempDest) int TempDest)
{ {
cmsHPROFILE hICC; cmsHPROFILE hICC;
cmsPipeline* Pipeline; cmsPipeline* Pipeline;
BCHSWADJUSTS bchsw; BCHSWADJUSTS bchsw;
cmsCIExyY WhitePnt; cmsCIExyY WhitePnt;
cmsStage* CLUT; cmsStage* CLUT;
cmsUInt32Number Dimensions[MAX_INPUT_DIMENSIONS]; cmsUInt32Number Dimensions[MAX_INPUT_DIMENSIONS];
int i; int i;
bchsw.Brightness = Bright;
bchsw.Contrast = Contrast;
bchsw.Hue = Hue;
bchsw.Saturation = Saturation;
cmsWhitePointFromTemp(&WhitePnt, TempSrc ); bchsw.Brightness = Bright;
cmsxyY2XYZ(&bchsw.WPsrc, &WhitePnt); bchsw.Contrast = Contrast;
bchsw.Hue = Hue;
bchsw.Saturation = Saturation;
cmsWhitePointFromTemp(&WhitePnt, TempDest); cmsWhitePointFromTemp(&WhitePnt, TempSrc );
cmsxyY2XYZ(&bchsw.WPdest, &WhitePnt); cmsxyY2XYZ(&bchsw.WPsrc, &WhitePnt);
hICC = cmsCreateProfilePlaceholder(ContextID); cmsWhitePointFromTemp(&WhitePnt, TempDest);
if (!hICC) // can't allocate cmsxyY2XYZ(&bchsw.WPdest, &WhitePnt);
return NULL;
hICC = cmsCreateProfilePlaceholder(ContextID);
if (!hICC) // can't allocate
return NULL;
cmsSetDeviceClass(hICC, cmsSigAbstractClass);
cmsSetColorSpace(hICC, cmsSigLabData);
cmsSetPCS(hICC, cmsSigLabData);
cmsSetHeaderRenderingIntent(hICC, INTENT_PERCEPTUAL); cmsSetDeviceClass(hICC, cmsSigAbstractClass);
cmsSetColorSpace(hICC, cmsSigLabData);
cmsSetPCS(hICC, cmsSigLabData);
cmsSetHeaderRenderingIntent(hICC, INTENT_PERCEPTUAL);
// Creates a Pipeline with 3D grid only // Creates a Pipeline with 3D grid only
Pipeline = cmsPipelineAlloc(ContextID, 3, 3); Pipeline = cmsPipelineAlloc(ContextID, 3, 3);
if (Pipeline == NULL) { if (Pipeline == NULL) {
cmsCloseProfile(hICC); cmsCloseProfile(hICC);
return NULL; return NULL;
} }
for (i=0; i < MAX_INPUT_DIMENSIONS; i++) Dimensions[i] = nLUTPoints; for (i=0; i < MAX_INPUT_DIMENSIONS; i++) Dimensions[i] = nLUTPoints;
CLUT = cmsStageAllocCLut16bitGranular(ContextID, Dimensions, 3, 3, NULL); CLUT = cmsStageAllocCLut16bitGranular(ContextID, Dimensions, 3, 3, NULL);
if (CLUT == NULL) return NULL; if (CLUT == NULL) return NULL;
if (!cmsStageSampleCLut16bit(CLUT, bchswSampler, (void*) &bchsw, 0)) { if (!cmsStageSampleCLut16bit(CLUT, bchswSampler, (void*) &bchsw, 0)) {
// Shouldn't reach here // Shouldn't reach here
cmsPipelineFree(Pipeline); goto Error;
cmsCloseProfile(hICC); }
return NULL;
}
cmsPipelineInsertStage(Pipeline, cmsAT_END, CLUT); if (!cmsPipelineInsertStage(Pipeline, cmsAT_END, CLUT)) {
goto Error;
}
// Create tags // Create tags
if (!SetTextTags(hICC, L"BCHS built-in")) return NULL;
if (!SetTextTags(hICC, L"BCHS built-in")) return NULL; cmsWriteTag(hICC, cmsSigMediaWhitePointTag, (void*) cmsD50_XYZ());
cmsWriteTag(hICC, cmsSigMediaWhitePointTag, (void*) cmsD50_XYZ()); cmsWriteTag(hICC, cmsSigAToB0Tag, (void*) Pipeline);
cmsWriteTag(hICC, cmsSigAToB0Tag, (void*) Pipeline); // Pipeline is already on virtual profile
cmsPipelineFree(Pipeline);
// Pipeline is already on virtual profile // Ok, done
cmsPipelineFree(Pipeline); return hICC;
// Ok, done Error:
return hICC; cmsPipelineFree(Pipeline);
cmsCloseProfile(hICC);
return NULL;
} }
...@@ -856,7 +877,8 @@ cmsHPROFILE CMSEXPORT cmsCreateNULLProfileTHR(cmsContext ContextID) ...@@ -856,7 +877,8 @@ cmsHPROFILE CMSEXPORT cmsCreateNULLProfileTHR(cmsContext ContextID)
PostLin = cmsStageAllocToneCurves(ContextID, 1, &EmptyTab); PostLin = cmsStageAllocToneCurves(ContextID, 1, &EmptyTab);
cmsFreeToneCurve(EmptyTab); cmsFreeToneCurve(EmptyTab);
cmsPipelineInsertStage(LUT, cmsAT_END, PostLin); if (!cmsPipelineInsertStage(LUT, cmsAT_END, PostLin))
goto Error;
if (!cmsWriteTag(hProfile, cmsSigBToA0Tag, (void*) LUT)) goto Error; if (!cmsWriteTag(hProfile, cmsSigBToA0Tag, (void*) LUT)) goto Error;
if (!cmsWriteTag(hProfile, cmsSigMediaWhitePointTag, cmsD50_XYZ())) goto Error; if (!cmsWriteTag(hProfile, cmsSigMediaWhitePointTag, cmsD50_XYZ())) goto Error;
...@@ -999,6 +1021,7 @@ static const cmsAllowedLUT AllowedLUTTypes[] = { ...@@ -999,6 +1021,7 @@ static const cmsAllowedLUT AllowedLUTTypes[] = {
{ FALSE, 0, cmsSigLut16Type, 4, { cmsSigMatrixElemType, cmsSigCurveSetElemType, cmsSigCLutElemType, cmsSigCurveSetElemType}}, { FALSE, 0, cmsSigLut16Type, 4, { cmsSigMatrixElemType, cmsSigCurveSetElemType, cmsSigCLutElemType, cmsSigCurveSetElemType}},
{ FALSE, 0, cmsSigLut16Type, 3, { cmsSigCurveSetElemType, cmsSigCLutElemType, cmsSigCurveSetElemType}}, { FALSE, 0, cmsSigLut16Type, 3, { cmsSigCurveSetElemType, cmsSigCLutElemType, cmsSigCurveSetElemType}},
{ FALSE, 0, cmsSigLut16Type, 2, { cmsSigCurveSetElemType, cmsSigCLutElemType}},
{ TRUE , 0, cmsSigLutAtoBType, 1, { cmsSigCurveSetElemType }}, { TRUE , 0, cmsSigLutAtoBType, 1, { cmsSigCurveSetElemType }},
{ TRUE , cmsSigAToB0Tag, cmsSigLutAtoBType, 3, { cmsSigCurveSetElemType, cmsSigMatrixElemType, cmsSigCurveSetElemType } }, { TRUE , cmsSigAToB0Tag, cmsSigLutAtoBType, 3, { cmsSigCurveSetElemType, cmsSigMatrixElemType, cmsSigCurveSetElemType } },
{ TRUE , cmsSigAToB0Tag, cmsSigLutAtoBType, 3, { cmsSigCurveSetElemType, cmsSigCLutElemType, cmsSigCurveSetElemType } }, { TRUE , cmsSigAToB0Tag, cmsSigLutAtoBType, 3, { cmsSigCurveSetElemType, cmsSigCLutElemType, cmsSigCurveSetElemType } },
...@@ -1059,6 +1082,7 @@ cmsHPROFILE CMSEXPORT cmsTransform2DeviceLink(cmsHTRANSFORM hTransform, cmsFloat ...@@ -1059,6 +1082,7 @@ cmsHPROFILE CMSEXPORT cmsTransform2DeviceLink(cmsHTRANSFORM hTransform, cmsFloat
cmsContext ContextID = cmsGetTransformContextID(hTransform); cmsContext ContextID = cmsGetTransformContextID(hTransform);
const cmsAllowedLUT* AllowedLUT; const cmsAllowedLUT* AllowedLUT;
cmsTagSignature DestinationTag; cmsTagSignature DestinationTag;
cmsProfileClassSignature deviceClass;
_cmsAssert(hTransform != NULL); _cmsAssert(hTransform != NULL);
...@@ -1080,13 +1104,15 @@ cmsHPROFILE CMSEXPORT cmsTransform2DeviceLink(cmsHTRANSFORM hTransform, cmsFloat ...@@ -1080,13 +1104,15 @@ cmsHPROFILE CMSEXPORT cmsTransform2DeviceLink(cmsHTRANSFORM hTransform, cmsFloat
// Time to fix the Lab2/Lab4 issue. // Time to fix the Lab2/Lab4 issue.
if ((xform ->EntryColorSpace == cmsSigLabData) && (Version < 4.0)) { if ((xform ->EntryColorSpace == cmsSigLabData) && (Version < 4.0)) {
cmsPipelineInsertStage(LUT, cmsAT_BEGIN, _cmsStageAllocLabV2ToV4curves(ContextID)); if (!cmsPipelineInsertStage(LUT, cmsAT_BEGIN, _cmsStageAllocLabV2ToV4curves(ContextID)))
goto Error;
} }
// On the output side too // On the output side too
if ((xform ->ExitColorSpace) == cmsSigLabData && (Version < 4.0)) { if ((xform ->ExitColorSpace) == cmsSigLabData && (Version < 4.0)) {
cmsPipelineInsertStage(LUT, cmsAT_END, _cmsStageAllocLabV4ToV2(ContextID)); if (!cmsPipelineInsertStage(LUT, cmsAT_END, _cmsStageAllocLabV4ToV2(ContextID)))
goto Error;
} }
...@@ -1108,8 +1134,9 @@ cmsHPROFILE CMSEXPORT cmsTransform2DeviceLink(cmsHTRANSFORM hTransform, cmsFloat ...@@ -1108,8 +1134,9 @@ cmsHPROFILE CMSEXPORT cmsTransform2DeviceLink(cmsHTRANSFORM hTransform, cmsFloat
FrmIn = COLORSPACE_SH(ColorSpaceBitsIn) | CHANNELS_SH(ChansIn)|BYTES_SH(2); FrmIn = COLORSPACE_SH(ColorSpaceBitsIn) | CHANNELS_SH(ChansIn)|BYTES_SH(2);
FrmOut = COLORSPACE_SH(ColorSpaceBitsOut) | CHANNELS_SH(ChansOut)|BYTES_SH(2); FrmOut = COLORSPACE_SH(ColorSpaceBitsOut) | CHANNELS_SH(ChansOut)|BYTES_SH(2);
deviceClass = cmsGetDeviceClass(hProfile);
if (cmsGetDeviceClass(hProfile) == cmsSigOutputClass) if (deviceClass == cmsSigOutputClass)
DestinationTag = cmsSigBToA0Tag; DestinationTag = cmsSigBToA0Tag;
else else
DestinationTag = cmsSigAToB0Tag; DestinationTag = cmsSigAToB0Tag;
...@@ -1136,10 +1163,12 @@ cmsHPROFILE CMSEXPORT cmsTransform2DeviceLink(cmsHTRANSFORM hTransform, cmsFloat ...@@ -1136,10 +1163,12 @@ cmsHPROFILE CMSEXPORT cmsTransform2DeviceLink(cmsHTRANSFORM hTransform, cmsFloat
// Put identity curves if needed // Put identity curves if needed
if (cmsPipelineGetPtrToFirstStage(LUT) ->Type != cmsSigCurveSetElemType) if (cmsPipelineGetPtrToFirstStage(LUT) ->Type != cmsSigCurveSetElemType)
cmsPipelineInsertStage(LUT, cmsAT_BEGIN, _cmsStageAllocIdentityCurves(ContextID, ChansIn)); if (!cmsPipelineInsertStage(LUT, cmsAT_BEGIN, _cmsStageAllocIdentityCurves(ContextID, ChansIn)))
goto Error;
if (cmsPipelineGetPtrToLastStage(LUT) ->Type != cmsSigCurveSetElemType) if (cmsPipelineGetPtrToLastStage(LUT) ->Type != cmsSigCurveSetElemType)
cmsPipelineInsertStage(LUT, cmsAT_END, _cmsStageAllocIdentityCurves(ContextID, ChansOut)); if (!cmsPipelineInsertStage(LUT, cmsAT_END, _cmsStageAllocIdentityCurves(ContextID, ChansOut)))
goto Error;
AllowedLUT = FindCombination(LUT, Version >= 4.0, DestinationTag); AllowedLUT = FindCombination(LUT, Version >= 4.0, DestinationTag);
} }
...@@ -1168,10 +1197,22 @@ cmsHPROFILE CMSEXPORT cmsTransform2DeviceLink(cmsHTRANSFORM hTransform, cmsFloat ...@@ -1168,10 +1197,22 @@ cmsHPROFILE CMSEXPORT cmsTransform2DeviceLink(cmsHTRANSFORM hTransform, cmsFloat
if (!cmsWriteTag(hProfile, cmsSigColorantTableOutTag, xform->OutputColorant)) goto Error; if (!cmsWriteTag(hProfile, cmsSigColorantTableOutTag, xform->OutputColorant)) goto Error;
} }
if (xform ->Sequence != NULL) { if ((deviceClass == cmsSigLinkClass) && (xform ->Sequence != NULL)) {
if (!_cmsWriteProfileSequence(hProfile, xform ->Sequence)) goto Error; if (!_cmsWriteProfileSequence(hProfile, xform ->Sequence)) goto Error;
} }
// Set the white point
if (deviceClass == cmsSigInputClass) {
if (!cmsWriteTag(hProfile, cmsSigMediaWhitePointTag, &xform ->EntryWhitePoint)) goto Error;
}
else {
if (!cmsWriteTag(hProfile, cmsSigMediaWhitePointTag, &xform ->ExitWhitePoint)) goto Error;
}
// Per 7.2.15 in spec 4.3
cmsSetHeaderRenderingIntent(hProfile, xform ->RenderingIntent);
cmsPipelineFree(LUT); cmsPipelineFree(LUT);
return hProfile; return hProfile;
......
...@@ -30,7 +30,7 @@ ...@@ -30,7 +30,7 @@
//--------------------------------------------------------------------------------- //---------------------------------------------------------------------------------
// //
// Little Color Management System // Little Color Management System
// Copyright (c) 1998-2010 Marti Maria Saguer // Copyright (c) 1998-2012 Marti Maria Saguer
// //
// Permission is hereby granted, free of charge, to any person obtaining // Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the "Software"), // a copy of this software and associated documentation files (the "Software"),
...@@ -76,48 +76,48 @@ const cmsCIExyY* CMSEXPORT cmsD50_xyY(void) ...@@ -76,48 +76,48 @@ const cmsCIExyY* CMSEXPORT cmsD50_xyY(void)
// Obtains WhitePoint from Temperature // Obtains WhitePoint from Temperature
cmsBool CMSEXPORT cmsWhitePointFromTemp(cmsCIExyY* WhitePoint, cmsFloat64Number TempK) cmsBool CMSEXPORT cmsWhitePointFromTemp(cmsCIExyY* WhitePoint, cmsFloat64Number TempK)
{ {
cmsFloat64Number x, y; cmsFloat64Number x, y;
cmsFloat64Number T, T2, T3; cmsFloat64Number T, T2, T3;
// cmsFloat64Number M1, M2; // cmsFloat64Number M1, M2;
_cmsAssert(WhitePoint != NULL); _cmsAssert(WhitePoint != NULL);
T = TempK; T = TempK;
T2 = T*T; // Square T2 = T*T; // Square
T3 = T2*T; // Cube T3 = T2*T; // Cube
// For correlated color temperature (T) between 4000K and 7000K: // For correlated color temperature (T) between 4000K and 7000K:
if (T >= 4000. && T <= 7000.) if (T >= 4000. && T <= 7000.)
{ {
x = -4.6070*(1E9/T3) + 2.9678*(1E6/T2) + 0.09911*(1E3/T) + 0.244063; x = -4.6070*(1E9/T3) + 2.9678*(1E6/T2) + 0.09911*(1E3/T) + 0.244063;
} }
else else
// or for correlated color temperature (T) between 7000K and 25000K: // or for correlated color temperature (T) between 7000K and 25000K:
if (T > 7000.0 && T <= 25000.0) if (T > 7000.0 && T <= 25000.0)
{ {
x = -2.0064*(1E9/T3) + 1.9018*(1E6/T2) + 0.24748*(1E3/T) + 0.237040; x = -2.0064*(1E9/T3) + 1.9018*(1E6/T2) + 0.24748*(1E3/T) + 0.237040;
} }
else { else {
cmsSignalError(0, cmsERROR_RANGE, "cmsWhitePointFromTemp: invalid temp"); cmsSignalError(0, cmsERROR_RANGE, "cmsWhitePointFromTemp: invalid temp");
return FALSE; return FALSE;
} }
// Obtain y(x) // Obtain y(x)
y = -3.000*(x*x) + 2.870*x - 0.275; y = -3.000*(x*x) + 2.870*x - 0.275;
// wave factors (not used, but here for futures extensions) // wave factors (not used, but here for futures extensions)
// M1 = (-1.3515 - 1.7703*x + 5.9114 *y)/(0.0241 + 0.2562*x - 0.7341*y); // M1 = (-1.3515 - 1.7703*x + 5.9114 *y)/(0.0241 + 0.2562*x - 0.7341*y);
// M2 = (0.0300 - 31.4424*x + 30.0717*y)/(0.0241 + 0.2562*x - 0.7341*y); // M2 = (0.0300 - 31.4424*x + 30.0717*y)/(0.0241 + 0.2562*x - 0.7341*y);
WhitePoint -> x = x; WhitePoint -> x = x;
WhitePoint -> y = y; WhitePoint -> y = y;
WhitePoint -> Y = 1.0; WhitePoint -> Y = 1.0;
return TRUE; return TRUE;
} }
...@@ -266,7 +266,7 @@ cmsBool _cmsAdaptationMatrix(cmsMAT3* r, const cmsMAT3* ConeMatrix, const cmsCI ...@@ -266,7 +266,7 @@ cmsBool _cmsAdaptationMatrix(cmsMAT3* r, const cmsMAT3* ConeMatrix, const cmsCI
{{ 0.8951, 0.2664, -0.1614 }}, {{ 0.8951, 0.2664, -0.1614 }},
{{ -0.7502, 1.7135, 0.0367 }}, {{ -0.7502, 1.7135, 0.0367 }},
{{ 0.0389, -0.0685, 1.0296 }} {{ 0.0389, -0.0685, 1.0296 }}
}}; }};
if (ConeMatrix == NULL) if (ConeMatrix == NULL)
ConeMatrix = &LamRigg; ConeMatrix = &LamRigg;
......
...@@ -396,7 +396,7 @@ typedef struct _cmsTransformCollection_st { ...@@ -396,7 +396,7 @@ typedef struct _cmsTransformCollection_st {
static _cmsTransformCollection* TransformCollection = NULL; static _cmsTransformCollection* TransformCollection = NULL;
// Register new ways to transform // Register new ways to transform
cmsBool _cmsRegisterTransformPlugin(cmsPluginBase* Data) cmsBool _cmsRegisterTransformPlugin(cmsContext id, cmsPluginBase* Data)
{ {
cmsPluginTransform* Plugin = (cmsPluginTransform*) Data; cmsPluginTransform* Plugin = (cmsPluginTransform*) Data;
_cmsTransformCollection* fl; _cmsTransformCollection* fl;
...@@ -412,7 +412,7 @@ cmsBool _cmsRegisterTransformPlugin(cmsPluginBase* Data) ...@@ -412,7 +412,7 @@ cmsBool _cmsRegisterTransformPlugin(cmsPluginBase* Data)
if (Plugin ->Factory == NULL) return FALSE; if (Plugin ->Factory == NULL) return FALSE;
fl = (_cmsTransformCollection*) _cmsPluginMalloc(sizeof(_cmsTransformCollection)); fl = (_cmsTransformCollection*) _cmsPluginMalloc(id, sizeof(_cmsTransformCollection));
if (fl == NULL) return FALSE; if (fl == NULL) return FALSE;
// Copy the parameters // Copy the parameters
...@@ -651,6 +651,22 @@ cmsBool IsProperColorSpace(cmsColorSpaceSignature Check, cmsUInt32Number dwForm ...@@ -651,6 +651,22 @@ cmsBool IsProperColorSpace(cmsColorSpaceSignature Check, cmsUInt32Number dwForm
// ---------------------------------------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------------------------------------
static
void SetWhitePoint(cmsCIEXYZ* wtPt, const cmsCIEXYZ* src)
{
if (src == NULL) {
wtPt ->X = cmsD50X;
wtPt ->Y = cmsD50Y;
wtPt ->Z = cmsD50Z;
}
else {
wtPt ->X = src->X;
wtPt ->Y = src->Y;
wtPt ->Z = src->Z;
}
}
// New to lcms 2.0 -- have all parameters available. // New to lcms 2.0 -- have all parameters available.
cmsHTRANSFORM CMSEXPORT cmsCreateExtendedTransform(cmsContext ContextID, cmsHTRANSFORM CMSEXPORT cmsCreateExtendedTransform(cmsContext ContextID,
cmsUInt32Number nProfiles, cmsHPROFILE hProfiles[], cmsUInt32Number nProfiles, cmsHPROFILE hProfiles[],
...@@ -664,7 +680,6 @@ cmsHTRANSFORM CMSEXPORT cmsCreateExtendedTransform(cmsContext ContextID, ...@@ -664,7 +680,6 @@ cmsHTRANSFORM CMSEXPORT cmsCreateExtendedTransform(cmsContext ContextID,
cmsUInt32Number dwFlags) cmsUInt32Number dwFlags)
{ {
_cmsTRANSFORM* xform; _cmsTRANSFORM* xform;
cmsBool FloatTransform;
cmsColorSpaceSignature EntryColorSpace; cmsColorSpaceSignature EntryColorSpace;
cmsColorSpaceSignature ExitColorSpace; cmsColorSpaceSignature ExitColorSpace;
cmsPipeline* Lut; cmsPipeline* Lut;
...@@ -681,9 +696,7 @@ cmsHTRANSFORM CMSEXPORT cmsCreateExtendedTransform(cmsContext ContextID, ...@@ -681,9 +696,7 @@ cmsHTRANSFORM CMSEXPORT cmsCreateExtendedTransform(cmsContext ContextID,
if (hGamutProfile == NULL) dwFlags &= ~cmsFLAGS_GAMUTCHECK; if (hGamutProfile == NULL) dwFlags &= ~cmsFLAGS_GAMUTCHECK;
} }
// On floating point transforms, inhibit optimizations // On floating point transforms, inhibit cache
FloatTransform = (_cmsFormatterIsFloat(InputFormat) && _cmsFormatterIsFloat(OutputFormat));
if (_cmsFormatterIsFloat(InputFormat) || _cmsFormatterIsFloat(OutputFormat)) if (_cmsFormatterIsFloat(InputFormat) || _cmsFormatterIsFloat(OutputFormat))
dwFlags |= cmsFLAGS_NOCACHE; dwFlags |= cmsFLAGS_NOCACHE;
...@@ -730,6 +743,10 @@ cmsHTRANSFORM CMSEXPORT cmsCreateExtendedTransform(cmsContext ContextID, ...@@ -730,6 +743,10 @@ cmsHTRANSFORM CMSEXPORT cmsCreateExtendedTransform(cmsContext ContextID,
xform ->ExitColorSpace = ExitColorSpace; xform ->ExitColorSpace = ExitColorSpace;
xform ->RenderingIntent = Intents[nProfiles-1]; xform ->RenderingIntent = Intents[nProfiles-1];
// Take white points
SetWhitePoint(&xform->EntryWhitePoint, (cmsCIEXYZ*) cmsReadTag(hProfiles[0], cmsSigMediaWhitePointTag));
SetWhitePoint(&xform->ExitWhitePoint, (cmsCIEXYZ*) cmsReadTag(hProfiles[nProfiles-1], cmsSigMediaWhitePointTag));
// Create a gamut check LUT if requested // Create a gamut check LUT if requested
if (hGamutProfile != NULL && (dwFlags & cmsFLAGS_GAMUTCHECK)) if (hGamutProfile != NULL && (dwFlags & cmsFLAGS_GAMUTCHECK))
......
...@@ -30,7 +30,7 @@ ...@@ -30,7 +30,7 @@
//--------------------------------------------------------------------------------- //---------------------------------------------------------------------------------
// //
// Little Color Management System // Little Color Management System
// Copyright (c) 1998-2011 Marti Maria Saguer // Copyright (c) 1998-2013 Marti Maria Saguer
// //
// Permission is hereby granted, free of charge, to any person obtaining // Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the "Software"), // a copy of this software and associated documentation files (the "Software"),
...@@ -52,7 +52,7 @@ ...@@ -52,7 +52,7 @@
// //
//--------------------------------------------------------------------------------- //---------------------------------------------------------------------------------
// //
// Version 2.4 // Version 2.5
// //
#ifndef _lcms2_H #ifndef _lcms2_H
...@@ -101,7 +101,7 @@ extern "C" { ...@@ -101,7 +101,7 @@ extern "C" {
#endif #endif
// Version/release // Version/release
#define LCMS_VERSION 2040 #define LCMS_VERSION 2050
// 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
...@@ -367,6 +367,7 @@ typedef enum { ...@@ -367,6 +367,7 @@ typedef enum {
cmsSigPreview1Tag = 0x70726531, // 'pre1' cmsSigPreview1Tag = 0x70726531, // 'pre1'
cmsSigPreview2Tag = 0x70726532, // 'pre2' cmsSigPreview2Tag = 0x70726532, // 'pre2'
cmsSigProfileDescriptionTag = 0x64657363, // 'desc' cmsSigProfileDescriptionTag = 0x64657363, // 'desc'
cmsSigProfileDescriptionMLTag = 0x6473636d, // 'dscm'
cmsSigProfileSequenceDescTag = 0x70736571, // 'pseq' cmsSigProfileSequenceDescTag = 0x70736571, // 'pseq'
cmsSigProfileSequenceIdTag = 0x70736964, // 'psid' cmsSigProfileSequenceIdTag = 0x70736964, // 'psid'
cmsSigPs2CRD0Tag = 0x70736430, // 'psd0' cmsSigPs2CRD0Tag = 0x70736430, // 'psd0'
...@@ -1014,6 +1015,7 @@ CMSAPI long int CMSEXPORT cmsfilelength(FILE* f); ...@@ -1014,6 +1015,7 @@ CMSAPI long int CMSEXPORT cmsfilelength(FILE* f);
// Plug-In registering --------------------------------------------------------------------------------------------------- // Plug-In registering ---------------------------------------------------------------------------------------------------
CMSAPI cmsBool CMSEXPORT cmsPlugin(void* Plugin); CMSAPI cmsBool CMSEXPORT cmsPlugin(void* Plugin);
CMSAPI cmsBool CMSEXPORT cmsPluginTHR(cmsContext ContextID, void* Plugin);
CMSAPI void CMSEXPORT cmsUnregisterPlugins(void); CMSAPI void CMSEXPORT cmsUnregisterPlugins(void);
// Error logging ---------------------------------------------------------------------------------------------------------- // Error logging ----------------------------------------------------------------------------------------------------------
...@@ -1190,7 +1192,7 @@ CMSAPI cmsBool CMSEXPORT cmsPipelineSetSaveAs8bitsFlag(cmsPipeline* lu ...@@ -1190,7 +1192,7 @@ CMSAPI cmsBool CMSEXPORT cmsPipelineSetSaveAs8bitsFlag(cmsPipeline* lu
// Where to place/locate the stages in the pipeline chain // Where to place/locate the stages in the pipeline chain
typedef enum { cmsAT_BEGIN, cmsAT_END } cmsStageLoc; typedef enum { cmsAT_BEGIN, cmsAT_END } cmsStageLoc;
CMSAPI void CMSEXPORT cmsPipelineInsertStage(cmsPipeline* lut, cmsStageLoc loc, cmsStage* mpe); CMSAPI int CMSEXPORT cmsPipelineInsertStage(cmsPipeline* lut, cmsStageLoc loc, cmsStage* mpe);
CMSAPI void CMSEXPORT cmsPipelineUnlinkStage(cmsPipeline* lut, cmsStageLoc loc, cmsStage** mpe); CMSAPI void CMSEXPORT cmsPipelineUnlinkStage(cmsPipeline* lut, cmsStageLoc loc, cmsStage** mpe);
// This function is quite useful to analyze the structure of a Pipeline and retrieve the Stage elements // This function is quite useful to analyze the structure of a Pipeline and retrieve the Stage elements
...@@ -1274,6 +1276,13 @@ CMSAPI cmsBool CMSEXPORT cmsMLUgetTranslation(const cmsMLU* mlu, ...@@ -1274,6 +1276,13 @@ CMSAPI cmsBool CMSEXPORT cmsMLUgetTranslation(const cmsMLU* mlu,
const char LanguageCode[3], const char CountryCode[3], const char LanguageCode[3], const char CountryCode[3],
char ObtainedLanguage[3], char ObtainedCountry[3]); char ObtainedLanguage[3], char ObtainedCountry[3]);
CMSAPI cmsUInt32Number CMSEXPORT cmsMLUtranslationsCount(const cmsMLU* mlu);
CMSAPI cmsBool CMSEXPORT cmsMLUtranslationsCodes(const cmsMLU* mlu,
cmsUInt32Number idx,
char LanguageCode[3],
char CountryCode[3]);
// Undercolorremoval & black generation ------------------------------------------------------------------------------------- // Undercolorremoval & black generation -------------------------------------------------------------------------------------
typedef struct { typedef struct {
...@@ -1424,6 +1433,7 @@ CMSAPI cmsUInt32Number CMSEXPORT cmsGetHeaderRenderingIntent(cmsHPROFILE hProf ...@@ -1424,6 +1433,7 @@ CMSAPI cmsUInt32Number CMSEXPORT cmsGetHeaderRenderingIntent(cmsHPROFILE hProf
CMSAPI void CMSEXPORT cmsSetHeaderFlags(cmsHPROFILE hProfile, cmsUInt32Number Flags); CMSAPI void CMSEXPORT cmsSetHeaderFlags(cmsHPROFILE hProfile, cmsUInt32Number Flags);
CMSAPI cmsUInt32Number CMSEXPORT cmsGetHeaderManufacturer(cmsHPROFILE hProfile); CMSAPI cmsUInt32Number CMSEXPORT cmsGetHeaderManufacturer(cmsHPROFILE hProfile);
CMSAPI void CMSEXPORT cmsSetHeaderManufacturer(cmsHPROFILE hProfile, cmsUInt32Number manufacturer); CMSAPI void CMSEXPORT cmsSetHeaderManufacturer(cmsHPROFILE hProfile, cmsUInt32Number manufacturer);
CMSAPI cmsUInt32Number CMSEXPORT cmsGetHeaderCreator(cmsHPROFILE hProfile);
CMSAPI cmsUInt32Number CMSEXPORT cmsGetHeaderModel(cmsHPROFILE hProfile); CMSAPI cmsUInt32Number CMSEXPORT cmsGetHeaderModel(cmsHPROFILE hProfile);
CMSAPI void CMSEXPORT cmsSetHeaderModel(cmsHPROFILE hProfile, cmsUInt32Number model); CMSAPI void CMSEXPORT cmsSetHeaderModel(cmsHPROFILE hProfile, cmsUInt32Number model);
CMSAPI void CMSEXPORT cmsSetHeaderAttributes(cmsHPROFILE hProfile, cmsUInt64Number Flags); CMSAPI void CMSEXPORT cmsSetHeaderAttributes(cmsHPROFILE hProfile, cmsUInt64Number Flags);
......
...@@ -27,7 +27,7 @@ ...@@ -27,7 +27,7 @@
// However, the following notice accompanied the original version of this // However, the following notice accompanied the original version of this
// file: // file:
// //
//---------------------------------------------------------------------------------
// //
// Little Color Management System // Little Color Management System
// Copyright (c) 1998-2011 Marti Maria Saguer // Copyright (c) 1998-2011 Marti Maria Saguer
...@@ -196,7 +196,7 @@ cmsINLINE cmsUInt16Number _cmsQuickSaturateWord(cmsFloat64Number d) ...@@ -196,7 +196,7 @@ cmsINLINE cmsUInt16Number _cmsQuickSaturateWord(cmsFloat64Number d)
// Plug-In registering --------------------------------------------------------------- // Plug-In registering ---------------------------------------------------------------
// Specialized function for plug-in memory management. No pairing free() since whole pool is freed at once. // Specialized function for plug-in memory management. No pairing free() since whole pool is freed at once.
void* _cmsPluginMalloc(cmsUInt32Number size); void* _cmsPluginMalloc(cmsContext ContextID, cmsUInt32Number size);
// Memory management // Memory management
cmsBool _cmsRegisterMemHandlerPlugin(cmsPluginBase* Plugin); cmsBool _cmsRegisterMemHandlerPlugin(cmsPluginBase* Plugin);
...@@ -205,28 +205,28 @@ cmsBool _cmsRegisterMemHandlerPlugin(cmsPluginBase* Plugin); ...@@ -205,28 +205,28 @@ cmsBool _cmsRegisterMemHandlerPlugin(cmsPluginBase* Plugin);
cmsBool _cmsRegisterInterpPlugin(cmsPluginBase* Plugin); cmsBool _cmsRegisterInterpPlugin(cmsPluginBase* Plugin);
// Parametric curves // Parametric curves
cmsBool _cmsRegisterParametricCurvesPlugin(cmsPluginBase* Plugin); cmsBool _cmsRegisterParametricCurvesPlugin(cmsContext ContextID, cmsPluginBase* Plugin);
// Formatters management // Formatters management
cmsBool _cmsRegisterFormattersPlugin(cmsPluginBase* Plugin); cmsBool _cmsRegisterFormattersPlugin(cmsContext ContextID, cmsPluginBase* Plugin);
// Tag type management // Tag type management
cmsBool _cmsRegisterTagTypePlugin(cmsPluginBase* Plugin); cmsBool _cmsRegisterTagTypePlugin(cmsContext ContextID, cmsPluginBase* Plugin);
// Tag management // Tag management
cmsBool _cmsRegisterTagPlugin(cmsPluginBase* Plugin); cmsBool _cmsRegisterTagPlugin(cmsContext ContextID, cmsPluginBase* Plugin);
// Intent management // Intent management
cmsBool _cmsRegisterRenderingIntentPlugin(cmsPluginBase* Plugin); cmsBool _cmsRegisterRenderingIntentPlugin(cmsContext ContextID, cmsPluginBase* Plugin);
// Multi Process elements // Multi Process elements
cmsBool _cmsRegisterMultiProcessElementPlugin(cmsPluginBase* Plugin); cmsBool _cmsRegisterMultiProcessElementPlugin(cmsContext ContextID, cmsPluginBase* Plugin);
// Optimization // Optimization
cmsBool _cmsRegisterOptimizationPlugin(cmsPluginBase* Plugin); cmsBool _cmsRegisterOptimizationPlugin(cmsContext ContextID, cmsPluginBase* Plugin);
// Transform // Transform
cmsBool _cmsRegisterTransformPlugin(cmsPluginBase* Plugin); cmsBool _cmsRegisterTransformPlugin(cmsContext ContextID, cmsPluginBase* Plugin);
// --------------------------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------------------------
...@@ -263,7 +263,7 @@ typedef struct { ...@@ -263,7 +263,7 @@ typedef struct {
cmsUInt16Number Country; cmsUInt16Number Country;
cmsUInt32Number StrW; // Offset to current unicode string cmsUInt32Number StrW; // Offset to current unicode string
cmsUInt32Number Len; // Lenght in bytes cmsUInt32Number Len; // Length in bytes
} _cmsMLUentry; } _cmsMLUentry;
...@@ -330,9 +330,11 @@ typedef struct _cms_iccprofile_struct { ...@@ -330,9 +330,11 @@ typedef struct _cms_iccprofile_struct {
cmsColorSpaceSignature ColorSpace; cmsColorSpaceSignature ColorSpace;
cmsColorSpaceSignature PCS; cmsColorSpaceSignature PCS;
cmsUInt32Number RenderingIntent; cmsUInt32Number RenderingIntent;
cmsUInt32Number flags; cmsUInt32Number flags;
cmsUInt32Number manufacturer, model; cmsUInt32Number manufacturer, model;
cmsUInt64Number attributes; cmsUInt64Number attributes;
cmsUInt32Number creator;
cmsProfileID ProfileID; cmsProfileID ProfileID;
...@@ -585,6 +587,10 @@ typedef struct _cmstransform_struct { ...@@ -585,6 +587,10 @@ typedef struct _cmstransform_struct {
cmsColorSpaceSignature EntryColorSpace; cmsColorSpaceSignature EntryColorSpace;
cmsColorSpaceSignature ExitColorSpace; cmsColorSpaceSignature ExitColorSpace;
// White points (informative only)
cmsCIEXYZ EntryWhitePoint;
cmsCIEXYZ ExitWhitePoint;
// Profiles used to create the transform // Profiles used to create the transform
cmsSEQ* Sequence; cmsSEQ* Sequence;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册