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

8029750: Enhance LCMS color processing

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