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

8029750: Enhance LCMS color processing

Reviewed-by: bae, vadim, mschoene
上级 f91f21c6
......@@ -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;
......@@ -1157,6 +1168,8 @@ 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)
......@@ -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;
......@@ -416,14 +416,17 @@ cmsBool AddConversion(cmsPipeline* Result, cmsColorSpaceSignature InPCS, cmsColo
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));
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));
cmsPipelineInsertStage(Result, cmsAT_END, _cmsStageAllocXYZ2Lab(Result ->ContextID));
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;
default:
......@@ -431,24 +434,26 @@ cmsBool AddConversion(cmsPipeline* Result, cmsColorSpaceSignature InPCS, cmsColo
}
break;
case cmsSigLabData: // Input profile operates in Lab
switch (OutPCS) {
case cmsSigXYZData: // Lab -> XYZ
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));
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;
case cmsSigLabData: // Lab -> Lab
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));
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;
......@@ -457,7 +462,6 @@ cmsBool AddConversion(cmsPipeline* Result, cmsColorSpaceSignature InPCS, cmsColo
}
break;
// On colorspaces other than PCS, check for same space
default:
if (InPCS != OutPCS) return FALSE;
......@@ -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,6 +258,7 @@ cmsToneCurve* AllocateToneCurveStruct(cmsContext ContextID, cmsInt32Number nEntr
}
p ->InterpParams = _cmsComputeInterpParams(ContextID, p ->nEntries, 1, 1, p->Table16, CMS_LERP_FLAGS_16BITS);
if (p->InterpParams != NULL)
return p;
Error:
......@@ -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,12 +249,9 @@ 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);
// converts from PCS to colorant. This always
......@@ -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);
......@@ -388,7 +385,7 @@ cmsPipeline* _cmsCreateGamutCheckPipeline(cmsContext ContextID,
nGamutPCSposition + 1,
ProfileList,
BPCList,
Intents,
IntentList,
AdaptationList,
NULL, 0,
dwFormat, TYPE_Lab_DBL,
......@@ -411,21 +408,24 @@ cmsPipeline* _cmsCreateGamutCheckPipeline(cmsContext ContextID,
// 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);
if (!cmsPipelineInsertStage(Gamut, cmsAT_BEGIN, CLUT)) {
cmsPipelineFree(Gamut);
Gamut = NULL;
}
else {
cmsStageSampleCLut16bit(CLUT, GamutSampler, (void*) &Chain, 0);
}
}
}
else
Gamut = NULL; // Didn't work...
......
......@@ -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;
......@@ -229,6 +228,11 @@ cmsBool MemoryWrite(struct _cms_io_handler* iohandler, cmsUInt32Number size, co
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;
}
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];
......@@ -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;
......@@ -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)
......@@ -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,7 +1686,6 @@ 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) {
......@@ -1666,6 +1694,8 @@ cmsInt32Number CMSEXPORT cmsReadRawTag(cmsHPROFILE hProfile, cmsTagSignature sig
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];
......@@ -1682,6 +1712,8 @@ cmsInt32Number CMSEXPORT cmsReadRawTag(cmsHPROFILE hProfile, cmsTagSignature sig
TagSize = BufferSize;
memmove(data, Icc ->TagPtrs[i], TagSize);
return TagSize;
}
return Icc ->TagSizes[i];
......@@ -1709,16 +1741,18 @@ cmsInt32Number CMSEXPORT cmsReadRawTag(cmsHPROFILE hProfile, cmsTagSignature sig
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;
}
......
......@@ -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
......@@ -643,13 +645,18 @@ cmsPipeline* _cmsReadOutputLUT(cmsHPROFILE hProfile, int Intent)
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
......@@ -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;
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
......@@ -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);
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;
}
......@@ -1250,10 +1262,20 @@ cmsStage* CMSEXPORT cmsStageDup(cmsStage* mpe)
NewMPE ->Implements = mpe ->Implements;
if (mpe ->DupElemPtr)
if (mpe ->DupElemPtr) {
NewMPE ->Data = mpe ->DupElemPtr(mpe);
else
if (NewMPE->Data == NULL) {
cmsStageFree(NewMPE);
return NULL;
}
} 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,15 +1598,10 @@ cmsBool CMSEXPORT cmsPipelineCat(cmsPipeline* l1, const cmsPipeline* l2)
mpe = mpe ->Next) {
// We have to dup each element
NewMPE = cmsStageDup(mpe);
if (NewMPE == NULL) {
if (!cmsPipelineInsertStage(l1, cmsAT_END, cmsStageDup(mpe)))
return FALSE;
}
cmsPipelineInsertStage(l1, cmsAT_END, NewMPE);
}
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;
......
......@@ -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;
......@@ -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;
}
......@@ -709,7 +713,6 @@ cmsBool OptimizeByResampling(cmsPipeline** Lut, cmsUInt32Number Intent, cmsUInt3
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;
// Zero for black point
if (cmsGetDeviceClass(hProfile) == cmsSigLinkClass) {
// 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;
}
// 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,14 +399,23 @@ 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 &&
......@@ -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])) {
cmsDoTransform(hRoundTrip, &Lab, &destLab, 1);
cmsDeleteTransform(hRoundTrip);
BlackPoint -> X = BlackPoint ->Y = BlackPoint -> Z = 0.0;
return FALSE;
}
L = destLab.L;
// Check the mid range in 20% after MinL
if (L > (MinL + 0.2 * (MaxL - MinL))) {
// Test for mid range straight (only on relative colorimetric)
// Is close enough?
if (fabs(L - l) > 4.0) {
NearlyStraightMidrange = TRUE;
MinL = outRamp[0]; MaxL = outRamp[255];
if (Intent == INTENT_RELATIVE_COLORIMETRIC) {
// Too far away, profile is buggy!
NearlyStraightMidRange = FALSE;
break;
}
}
}
}
else {
// Check is always performed for perceptual and saturation intents
NearlyStraightMidRange = FALSE;
for (l=0; l < 256; l++) {
if (! ((inRamp[l] <= MinL + 0.2 * (MaxL - MinL) ) ||
(fabs(inRamp[l] - outRamp[l]) < 4.0 )))
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;
}
}
// 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++) {
cmsFloat64Number ff;
Lab.L = (cmsFloat64Number) l;
Lab.a = InitialLab.a;
Lab.b = InitialLab.b;
cmsDoTransform(hRoundTrip, &Lab, &destLab, 1);
for (l=0; l < 256; l++) {
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;
}
......
......@@ -91,7 +91,7 @@ typedef struct _cmsTagTypeLinkedList_st {
// Register a new type handler. This routine is shared between normal types and MPE
static
cmsBool RegisterTypesPlugin(cmsPluginBase* Data, _cmsTagTypeLinkedList* LinkedList, cmsUInt32Number DefaultListCount)
cmsBool RegisterTypesPlugin(cmsContext id, cmsPluginBase* Data, _cmsTagTypeLinkedList* LinkedList, cmsUInt32Number DefaultListCount)
{
cmsPluginTagType* Plugin = (cmsPluginTagType*) Data;
_cmsTagTypeLinkedList *pt, *Anterior = NULL;
......@@ -118,7 +118,7 @@ cmsBool RegisterTypesPlugin(cmsPluginBase* Data, _cmsTagTypeLinkedList* LinkedLi
}
// Registering happens in plug-in memory pool
pt = (_cmsTagTypeLinkedList*) _cmsPluginMalloc(sizeof(_cmsTagTypeLinkedList));
pt = (_cmsTagTypeLinkedList*) _cmsPluginMalloc(id, sizeof(_cmsTagTypeLinkedList));
if (pt == NULL) return FALSE;
pt ->Handler = Plugin ->Handler;
......@@ -208,10 +208,10 @@ cmsBool ReadPositionTable(struct _cms_typehandler_struct* self,
cmsUInt32Number *ElementOffsets = NULL, *ElementSizes = NULL;
// Let's take the offsets to each element
ElementOffsets = (cmsUInt32Number *) _cmsCalloc(io ->ContextID, Count, sizeof(cmsUInt32Number *));
ElementOffsets = (cmsUInt32Number *) _cmsCalloc(io ->ContextID, Count, sizeof(cmsUInt32Number));
if (ElementOffsets == NULL) goto Error;
ElementSizes = (cmsUInt32Number *) _cmsCalloc(io ->ContextID, Count, sizeof(cmsUInt32Number *));
ElementSizes = (cmsUInt32Number *) _cmsCalloc(io ->ContextID, Count, sizeof(cmsUInt32Number));
if (ElementSizes == NULL) goto Error;
for (i=0; i < Count; i++) {
......@@ -257,10 +257,10 @@ cmsBool WritePositionTable(struct _cms_typehandler_struct* self,
cmsUInt32Number *ElementOffsets = NULL, *ElementSizes = NULL;
// Create table
ElementOffsets = (cmsUInt32Number *) _cmsCalloc(io ->ContextID, Count, sizeof(cmsUInt32Number *));
ElementOffsets = (cmsUInt32Number *) _cmsCalloc(io ->ContextID, Count, sizeof(cmsUInt32Number));
if (ElementOffsets == NULL) goto Error;
ElementSizes = (cmsUInt32Number *) _cmsCalloc(io ->ContextID, Count, sizeof(cmsUInt32Number *));
ElementSizes = (cmsUInt32Number *) _cmsCalloc(io ->ContextID, Count, sizeof(cmsUInt32Number));
if (ElementSizes == NULL) goto Error;
// Keep starting position of curve offsets
......@@ -456,6 +456,7 @@ static
void* Type_Chromaticity_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
{
return _cmsDupMem(self ->ContextID, Ptr, sizeof(cmsCIExyYTRIPLE));
cmsUNUSED_PARAMETER(n);
}
......@@ -1106,8 +1107,6 @@ void *Type_Curve_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cm
{
cmsUInt32Number Count;
cmsToneCurve* NewGamma;
cmsUInt16Number Linear[2] = { 0, 0xffff };
*nItems = 0;
if (!_cmsReadUInt32Number(io, &Count)) return NULL;
......@@ -1115,11 +1114,14 @@ void *Type_Curve_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cm
switch (Count) {
case 0: // Linear.
{
cmsFloat64Number SingleGamma = 1.0;
NewGamma = cmsBuildTabulatedToneCurve16(self ->ContextID, 2, Linear);
NewGamma = cmsBuildParametricToneCurve(self ->ContextID, 1, &SingleGamma);
if (!NewGamma) return NULL;
*nItems = 1;
return NewGamma;
}
case 1: // Specified as the exponent of gamma function
{
......@@ -1210,6 +1212,7 @@ cmsTagTypeSignature DecideCurveType(cmsFloat64Number ICCVersion, const void *Dat
if (ICCVersion < 4.0) return cmsSigCurveType;
if (Curve ->nSegments != 1) return cmsSigCurveType; // Only 1-segment curves can be saved as parametric
if (Curve ->Segments[0].Type < 0) return cmsSigCurveType; // Only non-inverted curves
if (Curve ->Segments[0].Type > 5) return cmsSigCurveType; // Only ICC parametric curves
return cmsSigParametricCurveType;
}
......@@ -1386,6 +1389,9 @@ void *Type_Measurement_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER*
{
cmsICCMeasurementConditions mc;
memset(&mc, 0, sizeof(mc));
if (!_cmsReadUInt32Number(io, &mc.Observer)) return NULL;
if (!_cmsReadXYZNumber(io, &mc.Backing)) return NULL;
if (!_cmsReadUInt32Number(io, &mc.Geometry)) return NULL;
......@@ -1640,7 +1646,6 @@ Byte Position Field Length (bytes) Content Encoded as...
static
cmsBool Read8bitTables(cmsContext ContextID, cmsIOHANDLER* io, cmsPipeline* lut, int nChannels)
{
cmsStage* mpe;
cmsUInt8Number* Temp = NULL;
int i, j;
cmsToneCurve* Tables[cmsMAXCHANNELS];
......@@ -1669,11 +1674,8 @@ cmsBool Read8bitTables(cmsContext ContextID, cmsIOHANDLER* io, cmsPipeline* lut
_cmsFree(ContextID, Temp);
Temp = NULL;
mpe = cmsStageAllocToneCurves(ContextID, nChannels, Tables);
if (mpe == NULL) goto Error;
cmsPipelineInsertStage(lut, cmsAT_END, mpe);
if (!cmsPipelineInsertStage(lut, cmsAT_END, cmsStageAllocToneCurves(ContextID, nChannels, Tables)))
goto Error;
for (i=0; i < nChannels; i++)
cmsFreeToneCurve(Tables[i]);
......@@ -1701,13 +1703,21 @@ cmsBool Write8bitTables(cmsContext ContextID, cmsIOHANDLER* io, cmsUInt32Number
if (Tables) {
// Usual case of identity curves
if ((Tables ->TheCurves[i]->nEntries == 2) &&
(Tables->TheCurves[i]->Table16[0] == 0) &&
(Tables->TheCurves[i]->Table16[1] == 65535)) {
for (j=0; j < 256; j++) {
if (!_cmsWriteUInt8Number(io, (cmsUInt8Number) j)) return FALSE;
}
}
else
if (Tables ->TheCurves[i]->nEntries != 256) {
cmsSignalError(ContextID, cmsERROR_RANGE, "LUT8 needs 256 entries on prelinearization");
return FALSE;
}
}
else
for (j=0; j < 256; j++) {
if (Tables != NULL)
......@@ -1718,13 +1728,14 @@ cmsBool Write8bitTables(cmsContext ContextID, cmsIOHANDLER* io, cmsUInt32Number
if (!_cmsWriteUInt8Number(io, val)) return FALSE;
}
}
}
return TRUE;
}
// Check overflow
static
size_t uipow(cmsUInt32Number n, cmsUInt32Number a, cmsUInt32Number b)
cmsUInt32Number uipow(cmsUInt32Number n, cmsUInt32Number a, cmsUInt32Number b)
{
cmsUInt32Number rv = 1, rc;
......@@ -1736,13 +1747,13 @@ size_t uipow(cmsUInt32Number n, cmsUInt32Number a, cmsUInt32Number b)
rv *= a;
// Check for overflow
if (rv > UINT_MAX / a) return (size_t) -1;
if (rv > UINT_MAX / a) return (cmsUInt32Number) -1;
}
rc = rv * n;
if (rv != rc / n) return (size_t) -1;
if (rv != rc / n) return (cmsUInt32Number) -1;
return rc;
}
......@@ -1757,7 +1768,6 @@ void *Type_LUT8_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cms
cmsUInt8Number InputChannels, OutputChannels, CLUTpoints;
cmsUInt8Number* Temp = NULL;
cmsPipeline* NewLUT = NULL;
cmsStage *mpemat, *mpeclut;
cmsUInt32Number nTabSize, i;
cmsFloat64Number Matrix[3*3];
......@@ -1796,9 +1806,8 @@ void *Type_LUT8_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cms
// Only operates if not identity...
if ((InputChannels == 3) && !_cmsMAT3isIdentity((cmsMAT3*) Matrix)) {
mpemat = cmsStageAllocMatrix(self ->ContextID, 3, 3, Matrix, NULL);
if (mpemat == NULL) goto Error;
cmsPipelineInsertStage(NewLUT, cmsAT_BEGIN, mpemat);
if (!cmsPipelineInsertStage(NewLUT, cmsAT_BEGIN, cmsStageAllocMatrix(self ->ContextID, 3, 3, Matrix, NULL)))
goto Error;
}
// Get input tables
......@@ -1806,13 +1815,10 @@ void *Type_LUT8_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cms
// Get 3D CLUT. Check the overflow....
nTabSize = uipow(OutputChannels, CLUTpoints, InputChannels);
if (nTabSize == (size_t) -1) goto Error;
if (nTabSize == (cmsUInt32Number) -1) goto Error;
if (nTabSize > 0) {
cmsUInt16Number *PtrW, *T;
cmsUInt32Number Tsize;
Tsize = (cmsUInt32Number) nTabSize * sizeof(cmsUInt16Number);
PtrW = T = (cmsUInt16Number*) _cmsCalloc(self ->ContextID, nTabSize, sizeof(cmsUInt16Number));
if (T == NULL) goto Error;
......@@ -1829,10 +1835,8 @@ void *Type_LUT8_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cms
_cmsFree(self ->ContextID, Temp);
Temp = NULL;
mpeclut = cmsStageAllocCLut16bit(self ->ContextID, CLUTpoints, InputChannels, OutputChannels, T);
if (mpeclut == NULL) goto Error;
cmsPipelineInsertStage(NewLUT, cmsAT_END, mpeclut);
if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, cmsStageAllocCLut16bit(self ->ContextID, CLUTpoints, InputChannels, OutputChannels, T)))
goto Error;
_cmsFree(self ->ContextID, T);
}
......@@ -1934,7 +1938,7 @@ cmsBool Type_LUT8_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io,
if (!Write8bitTables(self ->ContextID, io, NewLUT ->InputChannels, PreMPE)) return FALSE;
nTabSize = uipow(NewLUT->OutputChannels, clutPoints, NewLUT ->InputChannels);
if (nTabSize == (size_t) -1) return FALSE;
if (nTabSize == (cmsUInt32Number) -1) return FALSE;
if (nTabSize > 0) {
// The 3D CLUT.
......@@ -1983,7 +1987,6 @@ void Type_LUT8_Free(struct _cms_typehandler_struct* self, void* Ptr)
static
cmsBool Read16bitTables(cmsContext ContextID, cmsIOHANDLER* io, cmsPipeline* lut, int nChannels, int nEntries)
{
cmsStage* mpe;
int i;
cmsToneCurve* Tables[cmsMAXCHANNELS];
......@@ -2007,10 +2010,8 @@ cmsBool Read16bitTables(cmsContext ContextID, cmsIOHANDLER* io, cmsPipeline* lu
// Add the table (which may certainly be an identity, but this is up to the optimizer, not the reading code)
mpe = cmsStageAllocToneCurves(ContextID, nChannels, Tables);
if (mpe == NULL) goto Error;
cmsPipelineInsertStage(lut, cmsAT_END, mpe);
if (!cmsPipelineInsertStage(lut, cmsAT_END, cmsStageAllocToneCurves(ContextID, nChannels, Tables)))
goto Error;
for (i=0; i < nChannels; i++)
cmsFreeToneCurve(Tables[i]);
......@@ -2031,7 +2032,9 @@ cmsBool Write16bitTables(cmsContext ContextID, cmsIOHANDLER* io, _cmsStageToneCu
int j;
cmsUInt32Number i;
cmsUInt16Number val;
int nEntries = 256;
int nEntries;
_cmsAssert(Tables != NULL);
nEntries = Tables->TheCurves[0]->nEntries;
......@@ -2039,11 +2042,7 @@ cmsBool Write16bitTables(cmsContext ContextID, cmsIOHANDLER* io, _cmsStageToneCu
for (j=0; j < nEntries; j++) {
if (Tables != NULL)
val = Tables->TheCurves[i]->Table16[j];
else
val = _cmsQuantizeVal(j, nEntries);
if (!_cmsWriteUInt16Number(io, val)) return FALSE;
}
}
......@@ -2057,7 +2056,6 @@ void *Type_LUT16_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cm
{
cmsUInt8Number InputChannels, OutputChannels, CLUTpoints;
cmsPipeline* NewLUT = NULL;
cmsStage *mpemat, *mpeclut;
cmsUInt32Number nTabSize;
cmsFloat64Number Matrix[3*3];
cmsUInt16Number InputEntries, OutputEntries;
......@@ -2094,9 +2092,8 @@ void *Type_LUT16_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cm
// Only operates on 3 channels
if ((InputChannels == 3) && !_cmsMAT3isIdentity((cmsMAT3*) Matrix)) {
mpemat = cmsStageAllocMatrix(self ->ContextID, 3, 3, Matrix, NULL);
if (mpemat == NULL) goto Error;
cmsPipelineInsertStage(NewLUT, cmsAT_END, mpemat);
if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, cmsStageAllocMatrix(self ->ContextID, 3, 3, Matrix, NULL)))
goto Error;
}
if (!_cmsReadUInt16Number(io, &InputEntries)) goto Error;
......@@ -2110,7 +2107,7 @@ void *Type_LUT16_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cm
// Get 3D CLUT
nTabSize = uipow(OutputChannels, CLUTpoints, InputChannels);
if (nTabSize == (size_t) -1) goto Error;
if (nTabSize == (cmsUInt32Number) -1) goto Error;
if (nTabSize > 0) {
cmsUInt16Number *T;
......@@ -2123,13 +2120,10 @@ void *Type_LUT16_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cm
goto Error;
}
mpeclut = cmsStageAllocCLut16bit(self ->ContextID, CLUTpoints, InputChannels, OutputChannels, T);
if (mpeclut == NULL) {
if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, cmsStageAllocCLut16bit(self ->ContextID, CLUTpoints, InputChannels, OutputChannels, T))) {
_cmsFree(self ->ContextID, T);
goto Error;
}
cmsPipelineInsertStage(NewLUT, cmsAT_END, mpeclut);
_cmsFree(self ->ContextID, T);
}
......@@ -2159,7 +2153,7 @@ cmsBool Type_LUT16_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io
_cmsStageToneCurvesData* PreMPE = NULL, *PostMPE = NULL;
_cmsStageMatrixData* MatMPE = NULL;
_cmsStageCLutData* clut = NULL;
int InputChannels, OutputChannels, clutPoints;
int i, InputChannels, OutputChannels, clutPoints;
// Disassemble the LUT into components.
mpe = NewLUT -> Elements;
......@@ -2234,13 +2228,13 @@ cmsBool Type_LUT16_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io
if (PreMPE != NULL) {
if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) PreMPE ->TheCurves[0]->nEntries)) return FALSE;
} else {
if (!_cmsWriteUInt16Number(io, 0)) return FALSE;
if (!_cmsWriteUInt16Number(io, 2)) return FALSE;
}
if (PostMPE != NULL) {
if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) PostMPE ->TheCurves[0]->nEntries)) return FALSE;
} else {
if (!_cmsWriteUInt16Number(io, 0)) return FALSE;
if (!_cmsWriteUInt16Number(io, 2)) return FALSE;
}
......@@ -2249,9 +2243,16 @@ cmsBool Type_LUT16_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io
if (PreMPE != NULL) {
if (!Write16bitTables(self ->ContextID, io, PreMPE)) return FALSE;
}
else {
for (i=0; i < InputChannels; i++) {
if (!_cmsWriteUInt16Number(io, 0)) return FALSE;
if (!_cmsWriteUInt16Number(io, 0xffff)) return FALSE;
}
}
nTabSize = uipow(OutputChannels, clutPoints, InputChannels);
if (nTabSize == (size_t) -1) return FALSE;
if (nTabSize == (cmsUInt32Number) -1) return FALSE;
if (nTabSize > 0) {
// The 3D CLUT.
if (clut != NULL) {
......@@ -2263,7 +2264,13 @@ cmsBool Type_LUT16_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io
if (PostMPE != NULL) {
if (!Write16bitTables(self ->ContextID, io, PostMPE)) return FALSE;
}
else {
for (i=0; i < OutputChannels; i++) {
if (!_cmsWriteUInt16Number(io, 0)) return FALSE;
if (!_cmsWriteUInt16Number(io, 0xffff)) return FALSE;
}
}
return TRUE;
......@@ -2479,7 +2486,6 @@ void* Type_LUTA2B_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, c
cmsUInt32Number offsetM; // Offset to first "M" curve
cmsUInt32Number offsetC; // Offset to CLUT
cmsUInt32Number offsetA; // Offset to first "A" curve
cmsStage* mpe;
cmsPipeline* NewLUT = NULL;
......@@ -2501,37 +2507,35 @@ void* Type_LUTA2B_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, c
if (NewLUT == NULL) return NULL;
if (offsetA!= 0) {
mpe = ReadSetOfCurves(self, io, BaseOffset + offsetA, inputChan);
if (mpe == NULL) { cmsPipelineFree(NewLUT); return NULL; }
cmsPipelineInsertStage(NewLUT, cmsAT_END, mpe);
if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, ReadSetOfCurves(self, io, BaseOffset + offsetA, inputChan)))
goto Error;
}
if (offsetC != 0) {
mpe = ReadCLUT(self, io, BaseOffset + offsetC, inputChan, outputChan);
if (mpe == NULL) { cmsPipelineFree(NewLUT); return NULL; }
cmsPipelineInsertStage(NewLUT, cmsAT_END, mpe);
if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, ReadCLUT(self, io, BaseOffset + offsetC, inputChan, outputChan)))
goto Error;
}
if (offsetM != 0) {
mpe = ReadSetOfCurves(self, io, BaseOffset + offsetM, outputChan);
if (mpe == NULL) { cmsPipelineFree(NewLUT); return NULL; }
cmsPipelineInsertStage(NewLUT, cmsAT_END, mpe);
if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, ReadSetOfCurves(self, io, BaseOffset + offsetM, outputChan)))
goto Error;
}
if (offsetMat != 0) {
mpe = ReadMatrix(self, io, BaseOffset + offsetMat);
if (mpe == NULL) { cmsPipelineFree(NewLUT); return NULL; }
cmsPipelineInsertStage(NewLUT, cmsAT_END, mpe);
if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, ReadMatrix(self, io, BaseOffset + offsetMat)))
goto Error;
}
if (offsetB != 0) {
mpe = ReadSetOfCurves(self, io, BaseOffset + offsetB, outputChan);
if (mpe == NULL) { cmsPipelineFree(NewLUT); return NULL; }
cmsPipelineInsertStage(NewLUT, cmsAT_END, mpe);
if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, ReadSetOfCurves(self, io, BaseOffset + offsetB, outputChan)))
goto Error;
}
*nItems = 1;
return NewLUT;
Error:
cmsPipelineFree(NewLUT);
return NULL;
cmsUNUSED_PARAMETER(SizeOfTag);
}
......@@ -2798,7 +2802,6 @@ void* Type_LUTB2A_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, c
cmsUInt32Number offsetM; // Offset to first "M" curve
cmsUInt32Number offsetC; // Offset to CLUT
cmsUInt32Number offsetA; // Offset to first "A" curve
cmsStage* mpe;
cmsPipeline* NewLUT = NULL;
......@@ -2821,37 +2824,35 @@ void* Type_LUTB2A_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, c
if (NewLUT == NULL) return NULL;
if (offsetB != 0) {
mpe = ReadSetOfCurves(self, io, BaseOffset + offsetB, inputChan);
if (mpe == NULL) { cmsPipelineFree(NewLUT); return NULL; }
cmsPipelineInsertStage(NewLUT, cmsAT_END, mpe);
if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, ReadSetOfCurves(self, io, BaseOffset + offsetB, inputChan)))
goto Error;
}
if (offsetMat != 0) {
mpe = ReadMatrix(self, io, BaseOffset + offsetMat);
if (mpe == NULL) { cmsPipelineFree(NewLUT); return NULL; }
cmsPipelineInsertStage(NewLUT, cmsAT_END, mpe);
if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, ReadMatrix(self, io, BaseOffset + offsetMat)))
goto Error;
}
if (offsetM != 0) {
mpe = ReadSetOfCurves(self, io, BaseOffset + offsetM, inputChan);
if (mpe == NULL) { cmsPipelineFree(NewLUT); return NULL; }
cmsPipelineInsertStage(NewLUT, cmsAT_END, mpe);
if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, ReadSetOfCurves(self, io, BaseOffset + offsetM, inputChan)))
goto Error;
}
if (offsetC != 0) {
mpe = ReadCLUT(self, io, BaseOffset + offsetC, inputChan, outputChan);
if (mpe == NULL) { cmsPipelineFree(NewLUT); return NULL; }
cmsPipelineInsertStage(NewLUT, cmsAT_END, mpe);
if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, ReadCLUT(self, io, BaseOffset + offsetC, inputChan, outputChan)))
goto Error;
}
if (offsetA!= 0) {
mpe = ReadSetOfCurves(self, io, BaseOffset + offsetA, outputChan);
if (mpe == NULL) { cmsPipelineFree(NewLUT); return NULL; }
cmsPipelineInsertStage(NewLUT, cmsAT_END, mpe);
if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, ReadSetOfCurves(self, io, BaseOffset + offsetA, outputChan)))
goto Error;
}
*nItems = 1;
return NewLUT;
Error:
cmsPipelineFree(NewLUT);
return NULL;
cmsUNUSED_PARAMETER(SizeOfTag);
}
......@@ -3287,7 +3288,7 @@ void *Type_ProfileSequenceDesc_Read(struct _cms_typehandler_struct* self, cmsIOH
SizeOfTag -= sizeof(cmsUInt32Number);
if (!_cmsReadUInt64Number(io, &sec ->attributes)) goto Error;
if (SizeOfTag < sizeof(cmsUInt32Number)) goto Error;
if (SizeOfTag < sizeof(cmsUInt64Number)) goto Error;
SizeOfTag -= sizeof(cmsUInt64Number);
if (!_cmsReadUInt32Number(io, (cmsUInt32Number *)&sec ->technology)) goto Error;
......@@ -4292,6 +4293,9 @@ void *Type_MPEclut_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io,
if (!_cmsReadUInt16Number(io, &InputChans)) return NULL;
if (!_cmsReadUInt16Number(io, &OutputChans)) return NULL;
if (InputChans == 0) goto Error;
if (OutputChans == 0) goto Error;
if (io ->Read(io, Dimensions8, sizeof(cmsUInt8Number), 16) != 16)
goto Error;
......@@ -4381,7 +4385,6 @@ cmsBool ReadMPEElem(struct _cms_typehandler_struct* self,
{
cmsStageSignature ElementSig;
cmsTagTypeHandler* TypeHandler;
cmsStage *mpe = NULL;
cmsUInt32Number nItems;
cmsPipeline *NewLUT = (cmsPipeline *) Cargo;
......@@ -4409,11 +4412,8 @@ cmsBool ReadMPEElem(struct _cms_typehandler_struct* self,
if (TypeHandler ->ReadPtr != NULL) {
// This is a real element which should be read and processed
mpe = (cmsStage*) TypeHandler ->ReadPtr(self, io, &nItems, SizeOfTag);
if (mpe == NULL) return FALSE;
// All seems ok, insert element
cmsPipelineInsertStage(NewLUT, cmsAT_END, mpe);
if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, (cmsStage*) TypeHandler ->ReadPtr(self, io, &nItems, SizeOfTag)))
return FALSE;
}
return TRUE;
......@@ -4479,10 +4479,10 @@ cmsBool Type_MPE_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, v
outputChan = cmsPipelineOutputChannels(Lut);
ElemCount = cmsPipelineStageCount(Lut);
ElementOffsets = (cmsUInt32Number *) _cmsCalloc(self ->ContextID, ElemCount, sizeof(cmsUInt32Number *));
ElementOffsets = (cmsUInt32Number *) _cmsCalloc(self ->ContextID, ElemCount, sizeof(cmsUInt32Number));
if (ElementOffsets == NULL) goto Error;
ElementSizes = (cmsUInt32Number *) _cmsCalloc(self ->ContextID, ElemCount, sizeof(cmsUInt32Number *));
ElementSizes = (cmsUInt32Number *) _cmsCalloc(self ->ContextID, ElemCount, sizeof(cmsUInt32Number));
if (ElementSizes == NULL) goto Error;
// Write the head
......@@ -4825,10 +4825,10 @@ typedef struct {
static
cmsBool AllocElem(cmsContext ContextID, _cmsDICelem* e, cmsUInt32Number Count)
{
e->Offsets = (cmsUInt32Number *) _cmsCalloc(ContextID, Count, sizeof(cmsUInt32Number *));
e->Offsets = (cmsUInt32Number *) _cmsCalloc(ContextID, Count, sizeof(cmsUInt32Number));
if (e->Offsets == NULL) return FALSE;
e->Sizes = (cmsUInt32Number *) _cmsCalloc(ContextID, Count, sizeof(cmsUInt32Number *));
e->Sizes = (cmsUInt32Number *) _cmsCalloc(ContextID, Count, sizeof(cmsUInt32Number));
if (e->Sizes == NULL) {
_cmsFree(ContextID, e -> Offsets);
......@@ -4844,7 +4844,7 @@ static
void FreeElem(_cmsDICelem* e)
{
if (e ->Offsets != NULL) _cmsFree(e -> ContextID, e -> Offsets);
if (e ->Sizes != NULL) _cmsFree(e -> ContextID, e ->Sizes);
if (e ->Sizes != NULL) _cmsFree(e -> ContextID, e -> Sizes);
e->Offsets = e ->Sizes = NULL;
}
......@@ -5084,7 +5084,7 @@ void *Type_Dictionary_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* i
if (!_cmsReadUInt32Number(io, &Count)) return NULL;
SizeOfTag -= sizeof(cmsUInt32Number);
// Get rec lenghth
// Get rec length
if (!_cmsReadUInt32Number(io, &Length)) return NULL;
SizeOfTag -= sizeof(cmsUInt32Number);
......@@ -5118,14 +5118,22 @@ void *Type_Dictionary_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* i
if (!ReadOneMLUC(self, io, &a.DisplayValue, i, &DisplayValueMLU)) goto Error;
}
if (NameWCS == NULL || ValueWCS == NULL) {
cmsSignalError(self->ContextID, cmsERROR_CORRUPTION_DETECTED, "Bad dictionary Name/Value");
rc = FALSE;
}
else {
rc = cmsDictAddEntry(hDict, NameWCS, ValueWCS, DisplayNameMLU, DisplayValueMLU);
}
if (NameWCS != NULL) _cmsFree(self ->ContextID, NameWCS);
if (ValueWCS != NULL) _cmsFree(self ->ContextID, ValueWCS);
if (DisplayNameMLU != NULL) cmsMLUfree(DisplayNameMLU);
if (DisplayValueMLU != NULL) cmsMLUfree(DisplayValueMLU);
if (!rc) return FALSE;
if (!rc) goto Error;
}
FreeArray(&a);
......@@ -5277,14 +5285,14 @@ static _cmsTagTypeLinkedList SupportedTagTypes[] = {
#define DEFAULT_TAG_TYPE_COUNT (sizeof(SupportedTagTypes) / sizeof(_cmsTagTypeLinkedList))
// Both kind of plug-ins share same structure
cmsBool _cmsRegisterTagTypePlugin(cmsPluginBase* Data)
cmsBool _cmsRegisterTagTypePlugin(cmsContext id, cmsPluginBase* Data)
{
return RegisterTypesPlugin(Data, SupportedTagTypes, DEFAULT_TAG_TYPE_COUNT);
return RegisterTypesPlugin(id, Data, SupportedTagTypes, DEFAULT_TAG_TYPE_COUNT);
}
cmsBool _cmsRegisterMultiProcessElementPlugin(cmsPluginBase* Data)
cmsBool _cmsRegisterMultiProcessElementPlugin(cmsContext id, cmsPluginBase* Data)
{
return RegisterTypesPlugin(Data, SupportedMPEtypes, DEFAULT_MPE_TYPE_COUNT);
return RegisterTypesPlugin(id, Data, SupportedMPEtypes, DEFAULT_MPE_TYPE_COUNT);
}
......@@ -5391,7 +5399,9 @@ static _cmsTagLinkedList SupportedTags[] = {
{ cmsSigScreeningTag, { 1, 1, { cmsSigScreeningType}, NULL }, &SupportedTags[59]},
{ cmsSigVcgtTag, { 1, 1, { cmsSigVcgtType}, NULL }, &SupportedTags[60]},
{ cmsSigMetaTag, { 1, 1, { cmsSigDictType}, NULL }, &SupportedTags[61]},
{ cmsSigProfileSequenceIdTag, { 1, 1, { cmsSigProfileSequenceIdType}, NULL}, NULL}
{ cmsSigProfileSequenceIdTag, { 1, 1, { cmsSigProfileSequenceIdType}, NULL }, &SupportedTags[62]},
{ cmsSigProfileDescriptionMLTag,{ 1, 1, { cmsSigMultiLocalizedUnicodeType}, NULL}, NULL}
};
......@@ -5406,7 +5416,7 @@ static _cmsTagLinkedList SupportedTags[] = {
#define DEFAULT_TAG_COUNT (sizeof(SupportedTags) / sizeof(_cmsTagLinkedList))
cmsBool _cmsRegisterTagPlugin(cmsPluginBase* Data)
cmsBool _cmsRegisterTagPlugin(cmsContext id, cmsPluginBase* Data)
{
cmsPluginTag* Plugin = (cmsPluginTag*) Data;
_cmsTagLinkedList *pt, *Anterior;
......@@ -5430,7 +5440,7 @@ cmsBool _cmsRegisterTagPlugin(cmsPluginBase* Data)
pt = pt ->Next;
}
pt = (_cmsTagLinkedList*) _cmsPluginMalloc(sizeof(_cmsTagLinkedList));
pt = (_cmsTagLinkedList*) _cmsPluginMalloc(id, sizeof(_cmsTagLinkedList));
if (pt == NULL) return FALSE;
pt ->Signature = Plugin ->Signature;
......
......@@ -208,10 +208,27 @@ 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 (TransferFunction[1] == TransferFunction[0]) {
if (!cmsLinkTag (hICC, cmsSigGreenTRCTag, cmsSigRedTRCTag)) goto Error;
} else {
if (!cmsWriteTag(hICC, cmsSigGreenTRCTag, (void*) TransferFunction[1])) goto Error;
}
if (TransferFunction[2] == TransferFunction[0]) {
if (!cmsLinkTag (hICC, cmsSigBlueTRCTag, cmsSigRedTRCTag)) goto Error;
} else {
if (!cmsWriteTag(hICC, cmsSigBlueTRCTag, (void*) TransferFunction[2])) goto Error;
}
}
if (Primaries) {
if (!cmsWriteTag(hICC, cmsSigChromaticityTag, (void*) Primaries)) goto Error;
......@@ -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);
......@@ -750,7 +769,6 @@ cmsHPROFILE CMSEXPORT cmsCreateBCHSWabstractProfileTHR(cmsContext ContextID,
cmsUInt32Number Dimensions[MAX_INPUT_DIMENSIONS];
int i;
bchsw.Brightness = Bright;
bchsw.Contrast = Contrast;
bchsw.Hue = Hue;
......@@ -773,7 +791,6 @@ cmsHPROFILE CMSEXPORT cmsCreateBCHSWabstractProfileTHR(cmsContext ContextID,
cmsSetHeaderRenderingIntent(hICC, INTENT_PERCEPTUAL);
// Creates a Pipeline with 3D grid only
Pipeline = cmsPipelineAlloc(ContextID, 3, 3);
if (Pipeline == NULL) {
......@@ -789,15 +806,14 @@ cmsHPROFILE CMSEXPORT cmsCreateBCHSWabstractProfileTHR(cmsContext ContextID,
if (!cmsStageSampleCLut16bit(CLUT, bchswSampler, (void*) &bchsw, 0)) {
// Shouldn't reach here
cmsPipelineFree(Pipeline);
cmsCloseProfile(hICC);
return NULL;
goto Error;
}
cmsPipelineInsertStage(Pipeline, cmsAT_END, CLUT);
if (!cmsPipelineInsertStage(Pipeline, cmsAT_END, CLUT)) {
goto Error;
}
// Create tags
if (!SetTextTags(hICC, L"BCHS built-in")) return NULL;
cmsWriteTag(hICC, cmsSigMediaWhitePointTag, (void*) cmsD50_XYZ());
......@@ -809,6 +825,11 @@ cmsHPROFILE CMSEXPORT cmsCreateBCHSWabstractProfileTHR(cmsContext ContextID,
// 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"),
......
......@@ -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.
先完成此消息的编辑!
想要评论请 注册