Commit 95ef954f authored by Alexandre Julliard's avatar Alexandre Julliard

lcms: Import upstream release 2.13.1.

parent b0c9a28e
//--------------------------------------------------------------------------------- //---------------------------------------------------------------------------------
// //
// Little Color Management System // Little Color Management System
// Copyright (c) 1998-2020 Marti Maria Saguer // Copyright (c) 1998-2022 Marti Maria Saguer
// //
// Permission is hereby granted, free of charge, to any person obtaining // Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the "Software"), // a copy of this software and associated documentation files (the "Software"),
...@@ -24,7 +24,7 @@ ...@@ -24,7 +24,7 @@
//--------------------------------------------------------------------------------- //---------------------------------------------------------------------------------
// //
// This is the plug-in header file. Normal LittleCMS clients should not use it. // This is the plug-in header file. Normal LittleCMS clients should not use it.
// It is provided for plug-in writters that may want to access the support // It is provided for plug-in writers that may want to access the support
// functions to do low level operations. All plug-in related structures // functions to do low level operations. All plug-in related structures
// are defined here. Including this file forces to include the standard API too. // are defined here. Including this file forces to include the standard API too.
......
//--------------------------------------------------------------------------------- //---------------------------------------------------------------------------------
// //
// Little Color Management System // Little Color Management System
// Copyright (c) 1998-2020 Marti Maria Saguer // Copyright (c) 1998-2022 Marti Maria Saguer
// //
// Permission is hereby granted, free of charge, to any person obtaining // Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the "Software"), // a copy of this software and associated documentation files (the "Software"),
...@@ -191,21 +191,21 @@ static ...@@ -191,21 +191,21 @@ static
void fromFLTto8(void* dst, const void* src) void fromFLTto8(void* dst, const void* src)
{ {
cmsFloat32Number n = *(cmsFloat32Number*)src; cmsFloat32Number n = *(cmsFloat32Number*)src;
*(cmsUInt8Number*)dst = _cmsQuickSaturateByte(n * 255.0f); *(cmsUInt8Number*)dst = _cmsQuickSaturateByte(n * 255.0);
} }
static static
void fromFLTto16(void* dst, const void* src) void fromFLTto16(void* dst, const void* src)
{ {
cmsFloat32Number n = *(cmsFloat32Number*)src; cmsFloat32Number n = *(cmsFloat32Number*)src;
*(cmsUInt16Number*)dst = _cmsQuickSaturateWord(n * 65535.0f); *(cmsUInt16Number*)dst = _cmsQuickSaturateWord(n * 65535.0);
} }
static static
void fromFLTto16SE(void* dst, const void* src) void fromFLTto16SE(void* dst, const void* src)
{ {
cmsFloat32Number n = *(cmsFloat32Number*)src; cmsFloat32Number n = *(cmsFloat32Number*)src;
cmsUInt16Number i = _cmsQuickSaturateWord(n * 65535.0f); cmsUInt16Number i = _cmsQuickSaturateWord(n * 65535.0);
*(cmsUInt16Number*)dst = CHANGE_ENDIAN(i); *(cmsUInt16Number*)dst = CHANGE_ENDIAN(i);
} }
...@@ -243,7 +243,7 @@ void fromHLFto8(void* dst, const void* src) ...@@ -243,7 +243,7 @@ void fromHLFto8(void* dst, const void* src)
{ {
#ifndef CMS_NO_HALF_SUPPORT #ifndef CMS_NO_HALF_SUPPORT
cmsFloat32Number n = _cmsHalf2Float(*(cmsUInt16Number*)src); cmsFloat32Number n = _cmsHalf2Float(*(cmsUInt16Number*)src);
*(cmsUInt8Number*)dst = _cmsQuickSaturateByte(n * 255.0f); *(cmsUInt8Number*)dst = _cmsQuickSaturateByte(n * 255.0);
#else #else
cmsUNUSED_PARAMETER(dst); cmsUNUSED_PARAMETER(dst);
cmsUNUSED_PARAMETER(src); cmsUNUSED_PARAMETER(src);
...@@ -256,7 +256,7 @@ void fromHLFto16(void* dst, const void* src) ...@@ -256,7 +256,7 @@ void fromHLFto16(void* dst, const void* src)
{ {
#ifndef CMS_NO_HALF_SUPPORT #ifndef CMS_NO_HALF_SUPPORT
cmsFloat32Number n = _cmsHalf2Float(*(cmsUInt16Number*)src); cmsFloat32Number n = _cmsHalf2Float(*(cmsUInt16Number*)src);
*(cmsUInt16Number*)dst = _cmsQuickSaturateWord(n * 65535.0f); *(cmsUInt16Number*)dst = _cmsQuickSaturateWord(n * 65535.0);
#else #else
cmsUNUSED_PARAMETER(dst); cmsUNUSED_PARAMETER(dst);
cmsUNUSED_PARAMETER(src); cmsUNUSED_PARAMETER(src);
...@@ -268,7 +268,7 @@ void fromHLFto16SE(void* dst, const void* src) ...@@ -268,7 +268,7 @@ void fromHLFto16SE(void* dst, const void* src)
{ {
#ifndef CMS_NO_HALF_SUPPORT #ifndef CMS_NO_HALF_SUPPORT
cmsFloat32Number n = _cmsHalf2Float(*(cmsUInt16Number*)src); cmsFloat32Number n = _cmsHalf2Float(*(cmsUInt16Number*)src);
cmsUInt16Number i = _cmsQuickSaturateWord(n * 65535.0f); cmsUInt16Number i = _cmsQuickSaturateWord(n * 65535.0);
*(cmsUInt16Number*)dst = CHANGE_ENDIAN(i); *(cmsUInt16Number*)dst = CHANGE_ENDIAN(i);
#else #else
cmsUNUSED_PARAMETER(dst); cmsUNUSED_PARAMETER(dst);
...@@ -414,9 +414,9 @@ void ComputeIncrementsForChunky(cmsUInt32Number Format, ...@@ -414,9 +414,9 @@ void ComputeIncrementsForChunky(cmsUInt32Number Format,
cmsUInt32Number channelSize = trueBytesSize(Format); cmsUInt32Number channelSize = trueBytesSize(Format);
cmsUInt32Number pixelSize = channelSize * total_chans; cmsUInt32Number pixelSize = channelSize * total_chans;
// Sanity check // Sanity check
if (total_chans <= 0 || total_chans >= cmsMAXCHANNELS) if (total_chans <= 0 || total_chans >= cmsMAXCHANNELS)
return; return;
memset(channels, 0, sizeof(channels)); memset(channels, 0, sizeof(channels));
......
//--------------------------------------------------------------------------------- //---------------------------------------------------------------------------------
// //
// Little Color Management System // Little Color Management System
// Copyright (c) 1998-2020 Marti Maria Saguer // Copyright (c) 1998-2022 Marti Maria Saguer
// //
// Permission is hereby granted, free of charge, to any person obtaining // Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the "Software"), // a copy of this software and associated documentation files (the "Software"),
......
//--------------------------------------------------------------------------------- //---------------------------------------------------------------------------------
// //
// Little Color Management System // Little Color Management System
// Copyright (c) 1998-2020 Marti Maria Saguer // Copyright (c) 1998-2022 Marti Maria Saguer
// //
// Permission is hereby granted, free of charge, to any person obtaining // Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the "Software"), // a copy of this software and associated documentation files (the "Software"),
...@@ -79,7 +79,7 @@ long int CMSEXPORT cmsfilelength(FILE* f) ...@@ -79,7 +79,7 @@ long int CMSEXPORT cmsfilelength(FILE* f)
// User may override this behaviour by using a memory plug-in, which basically replaces // User may override this behaviour by using a memory plug-in, which basically replaces
// the default memory management functions. In this case, no check is performed and it // the default memory management functions. In this case, no check is performed and it
// is up to the plug-in writter to keep in the safe side. There are only three functions // is up to the plug-in writer to keep in the safe side. There are only three functions
// required to be implemented: malloc, realloc and free, although the user may want to // required to be implemented: malloc, realloc and free, although the user may want to
// replace the optional mallocZero, calloc and dup as well. // replace the optional mallocZero, calloc and dup as well.
...@@ -308,7 +308,7 @@ void* CMSEXPORT _cmsDupMem(cmsContext ContextID, const void* Org, cmsUInt32Numbe ...@@ -308,7 +308,7 @@ void* CMSEXPORT _cmsDupMem(cmsContext ContextID, const void* Org, cmsUInt32Numbe
// Sub allocation takes care of many pointers of small size. The memory allocated in // Sub allocation takes care of many pointers of small size. The memory allocated in
// this way have be freed at once. Next function allocates a single chunk for linked list // this way have be freed at once. Next function allocates a single chunk for linked list
// I prefer this method over realloc due to the big inpact on xput realloc may have if // I prefer this method over realloc due to the big impact on xput realloc may have if
// memory is being swapped to disk. This approach is safer (although that may not be true on all platforms) // memory is being swapped to disk. This approach is safer (although that may not be true on all platforms)
static static
_cmsSubAllocator_chunk* _cmsCreateSubAllocChunk(cmsContext ContextID, cmsUInt32Number Initial) _cmsSubAllocator_chunk* _cmsCreateSubAllocChunk(cmsContext ContextID, cmsUInt32Number Initial)
......
//--------------------------------------------------------------------------------- //---------------------------------------------------------------------------------
// //
// Little Color Management System // Little Color Management System
// Copyright (c) 1998-2020 Marti Maria Saguer // Copyright (c) 1998-2022 Marti Maria Saguer
// //
// Permission is hereby granted, free of charge, to any person obtaining // Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the "Software"), // a copy of this software and associated documentation files (the "Software"),
...@@ -207,7 +207,7 @@ _cmsParametricCurvesCollection *GetParametricCurveByType(cmsContext ContextID, i ...@@ -207,7 +207,7 @@ _cmsParametricCurvesCollection *GetParametricCurveByType(cmsContext ContextID, i
} }
// Low level allocate, which takes care of memory details. nEntries may be zero, and in this case // Low level allocate, which takes care of memory details. nEntries may be zero, and in this case
// no optimation curve is computed. nSegments may also be zero in the inverse case, where only the // no optimization curve is computed. nSegments may also be zero in the inverse case, where only the
// optimization curve is given. Both features simultaneously is an error // optimization curve is given. Both features simultaneously is an error
static static
cmsToneCurve* AllocateToneCurveStruct(cmsContext ContextID, cmsUInt32Number nEntries, cmsToneCurve* AllocateToneCurveStruct(cmsContext ContextID, cmsUInt32Number nEntries,
...@@ -507,28 +507,31 @@ cmsFloat64Number DefaultEvalParametricFn(cmsInt32Number Type, const cmsFloat64Nu ...@@ -507,28 +507,31 @@ cmsFloat64Number DefaultEvalParametricFn(cmsInt32Number Type, const cmsFloat64Nu
// X=Y/c | Y< (ad+b)^g // X=Y/c | Y< (ad+b)^g
case -4: case -4:
{ {
if (fabs(Params[0]) < MATRIX_DET_TOLERANCE ||
fabs(Params[1]) < MATRIX_DET_TOLERANCE || e = Params[1] * Params[4] + Params[2];
fabs(Params[3]) < MATRIX_DET_TOLERANCE) if (e < 0)
{ disc = 0;
Val = 0;
}
else else
{ disc = pow(e, Params[0]);
e = Params[1] * Params[4] + Params[2];
if (e < 0)
disc = 0;
else
disc = pow(e, Params[0]);
if (R >= disc) { if (R >= disc) {
if (fabs(Params[0]) < MATRIX_DET_TOLERANCE ||
fabs(Params[1]) < MATRIX_DET_TOLERANCE)
Val = 0;
else
Val = (pow(R, 1.0 / Params[0]) - Params[2]) / Params[1]; Val = (pow(R, 1.0 / Params[0]) - Params[2]) / Params[1];
} }
else { else {
if (fabs(Params[3]) < MATRIX_DET_TOLERANCE)
Val = 0;
else
Val = R / Params[3]; Val = R / Params[3];
}
} }
} }
break; break;
...@@ -555,26 +558,29 @@ cmsFloat64Number DefaultEvalParametricFn(cmsInt32Number Type, const cmsFloat64Nu ...@@ -555,26 +558,29 @@ cmsFloat64Number DefaultEvalParametricFn(cmsInt32Number Type, const cmsFloat64Nu
// X=(Y-f)/c | else // X=(Y-f)/c | else
case -5: case -5:
{ {
if (fabs(Params[1]) < MATRIX_DET_TOLERANCE || disc = Params[3] * Params[4] + Params[6];
fabs(Params[3]) < MATRIX_DET_TOLERANCE) if (R >= disc) {
{
Val = 0; e = R - Params[5];
} if (e < 0)
else Val = 0;
{ else
disc = Params[3] * Params[4] + Params[6]; {
if (R >= disc) { if (fabs(Params[0]) < MATRIX_DET_TOLERANCE ||
fabs(Params[1]) < MATRIX_DET_TOLERANCE)
e = R - Params[5];
if (e < 0)
Val = 0; Val = 0;
else else
Val = (pow(e, 1.0 / Params[0]) - Params[2]) / Params[1]; Val = (pow(e, 1.0 / Params[0]) - Params[2]) / Params[1];
} }
else { }
else {
if (fabs(Params[3]) < MATRIX_DET_TOLERANCE)
Val = 0;
else
Val = (R - Params[6]) / Params[3]; Val = (R - Params[6]) / Params[3];
}
} }
} }
break; break;
......
//--------------------------------------------------------------------------------- //---------------------------------------------------------------------------------
// //
// Little Color Management System // Little Color Management System
// Copyright (c) 1998-2020 Marti Maria Saguer // Copyright (c) 1998-2021 Marti Maria Saguer
// //
// Permission is hereby granted, free of charge, to any person obtaining // Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the "Software"), // a copy of this software and associated documentation files (the "Software"),
...@@ -199,15 +199,15 @@ typedef struct { ...@@ -199,15 +199,15 @@ typedef struct {
cmsHTRANSFORM hInput; // From whatever input color space. 16 bits to DBL cmsHTRANSFORM hInput; // From whatever input color space. 16 bits to DBL
cmsHTRANSFORM hForward, hReverse; // Transforms going from Lab to colorant and back cmsHTRANSFORM hForward, hReverse; // Transforms going from Lab to colorant and back
cmsFloat64Number Thereshold; // The thereshold after which is considered out of gamut cmsFloat64Number Threshold; // The threshold after which is considered out of gamut
} GAMUTCHAIN; } GAMUTCHAIN;
// This sampler does compute gamut boundaries by comparing original // This sampler does compute gamut boundaries by comparing original
// values with a transform going back and forth. Values above ERR_THERESHOLD // values with a transform going back and forth. Values above ERR_THRESHOLD
// of maximum are considered out of gamut. // of maximum are considered out of gamut.
#define ERR_THERESHOLD 5 #define ERR_THRESHOLD 5
static static
...@@ -246,17 +246,17 @@ int GamutSampler(CMSREGISTER const cmsUInt16Number In[], CMSREGISTER cmsUInt16Nu ...@@ -246,17 +246,17 @@ int GamutSampler(CMSREGISTER const cmsUInt16Number In[], CMSREGISTER cmsUInt16Nu
// if dE1 is small and dE2 is small, value is likely to be in gamut // if dE1 is small and dE2 is small, value is likely to be in gamut
if (dE1 < t->Thereshold && dE2 < t->Thereshold) if (dE1 < t->Threshold && dE2 < t->Threshold)
Out[0] = 0; Out[0] = 0;
else { else {
// if dE1 is small and dE2 is big, undefined. Assume in gamut // if dE1 is small and dE2 is big, undefined. Assume in gamut
if (dE1 < t->Thereshold && dE2 > t->Thereshold) if (dE1 < t->Threshold && dE2 > t->Threshold)
Out[0] = 0; Out[0] = 0;
else else
// dE1 is big and dE2 is small, clearly out of gamut // dE1 is big and dE2 is small, clearly out of gamut
if (dE1 > t->Thereshold && dE2 < t->Thereshold) if (dE1 > t->Threshold && dE2 < t->Threshold)
Out[0] = (cmsUInt16Number) _cmsQuickFloor((dE1 - t->Thereshold) + .5); Out[0] = (cmsUInt16Number) _cmsQuickFloor((dE1 - t->Threshold) + .5);
else { else {
// dE1 is big and dE2 is also big, could be due to perceptual mapping // dE1 is big and dE2 is also big, could be due to perceptual mapping
...@@ -266,8 +266,8 @@ int GamutSampler(CMSREGISTER const cmsUInt16Number In[], CMSREGISTER cmsUInt16Nu ...@@ -266,8 +266,8 @@ int GamutSampler(CMSREGISTER const cmsUInt16Number In[], CMSREGISTER cmsUInt16Nu
else else
ErrorRatio = dE1 / dE2; ErrorRatio = dE1 / dE2;
if (ErrorRatio > t->Thereshold) if (ErrorRatio > t->Threshold)
Out[0] = (cmsUInt16Number) _cmsQuickFloor((ErrorRatio - t->Thereshold) + .5); Out[0] = (cmsUInt16Number) _cmsQuickFloor((ErrorRatio - t->Threshold) + .5);
else else
Out[0] = 0; Out[0] = 0;
} }
...@@ -323,10 +323,10 @@ cmsPipeline* _cmsCreateGamutCheckPipeline(cmsContext ContextID, ...@@ -323,10 +323,10 @@ cmsPipeline* _cmsCreateGamutCheckPipeline(cmsContext ContextID,
if (cmsIsMatrixShaper(hGamut)) { if (cmsIsMatrixShaper(hGamut)) {
Chain.Thereshold = 1.0; Chain.Threshold = 1.0;
} }
else { else {
Chain.Thereshold = ERR_THERESHOLD; Chain.Threshold = ERR_THRESHOLD;
} }
...@@ -588,3 +588,67 @@ cmsBool CMSEXPORT cmsDesaturateLab(cmsCIELab* Lab, ...@@ -588,3 +588,67 @@ cmsBool CMSEXPORT cmsDesaturateLab(cmsCIELab* Lab,
return TRUE; return TRUE;
} }
// Detect whatever a given ICC profile works in linear (gamma 1.0) space
// Actually, doing that "well" is quite hard, since every component may behave completely different.
// Since the true point of this function is to detect suitable optimizations, I am imposing some requirements
// that simplifies things: only RGB, and only profiles that can got in both directions.
// The algorithm obtains Y from a syntetical gray R=G=B. Then least squares fitting is used to estimate gamma.
// For gamma close to 1.0, RGB is linear. On profiles not supported, -1 is returned.
cmsFloat64Number CMSEXPORT cmsDetectRGBProfileGamma(cmsHPROFILE hProfile, cmsFloat64Number threshold)
{
cmsContext ContextID;
cmsHPROFILE hXYZ;
cmsHTRANSFORM xform;
cmsToneCurve* Y_curve;
cmsUInt16Number rgb[256][3];
cmsCIEXYZ XYZ[256];
cmsFloat32Number Y_normalized[256];
cmsFloat64Number gamma;
cmsProfileClassSignature cl;
int i;
if (cmsGetColorSpace(hProfile) != cmsSigRgbData)
return -1;
cl = cmsGetDeviceClass(hProfile);
if (cl != cmsSigInputClass && cl != cmsSigDisplayClass &&
cl != cmsSigOutputClass && cl != cmsSigColorSpaceClass)
return -1;
ContextID = cmsGetProfileContextID(hProfile);
hXYZ = cmsCreateXYZProfileTHR(ContextID);
xform = cmsCreateTransformTHR(ContextID, hProfile, TYPE_RGB_16, hXYZ, TYPE_XYZ_DBL,
INTENT_RELATIVE_COLORIMETRIC, cmsFLAGS_NOOPTIMIZE);
if (xform == NULL) { // If not RGB or forward direction is not supported, regret with the previous error
cmsCloseProfile(hXYZ);
return -1;
}
for (i = 0; i < 256; i++) {
rgb[i][0] = rgb[i][1] = rgb[i][2] = FROM_8_TO_16(i);
}
cmsDoTransform(xform, rgb, XYZ, 256);
cmsDeleteTransform(xform);
cmsCloseProfile(hXYZ);
for (i = 0; i < 256; i++) {
Y_normalized[i] = (cmsFloat32Number) XYZ[i].Y;
}
Y_curve = cmsBuildTabulatedToneCurveFloat(ContextID, 256, Y_normalized);
if (Y_curve == NULL)
return -1;
gamma = cmsEstimateGamma(Y_curve, threshold);
cmsFreeToneCurve(Y_curve);
return gamma;
}
//--------------------------------------------------------------------------------- //---------------------------------------------------------------------------------
// //
// Little Color Management System // Little Color Management System
// Copyright (c) 1998-2020 Marti Maria Saguer // Copyright (c) 1998-2022 Marti Maria Saguer
// //
// Permission is hereby granted, free of charge, to any person obtaining // Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the "Software"), // a copy of this software and associated documentation files (the "Software"),
......
//--------------------------------------------------------------------------------- //---------------------------------------------------------------------------------
// //
// Little Color Management System // Little Color Management System
// Copyright (c) 1998-2020 Marti Maria Saguer // Copyright (c) 1998-2022 Marti Maria Saguer
// //
// Permission is hereby granted, free of charge, to any person obtaining // Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the "Software"), // a copy of this software and associated documentation files (the "Software"),
...@@ -200,8 +200,8 @@ void LinLerp1D(CMSREGISTER const cmsUInt16Number Value[], ...@@ -200,8 +200,8 @@ void LinLerp1D(CMSREGISTER const cmsUInt16Number Value[],
int val3; int val3;
const cmsUInt16Number* LutTable = (cmsUInt16Number*) p ->Table; const cmsUInt16Number* LutTable = (cmsUInt16Number*) p ->Table;
// if last value... // if last value or just one point
if (Value[0] == 0xffff) { if (Value[0] == 0xffff || p->Domain[0] == 0) {
Output[0] = LutTable[p -> Domain[0]]; Output[0] = LutTable[p -> Domain[0]];
} }
...@@ -240,7 +240,7 @@ void LinLerp1Dfloat(const cmsFloat32Number Value[], ...@@ -240,7 +240,7 @@ void LinLerp1Dfloat(const cmsFloat32Number Value[],
val2 = fclamp(Value[0]); val2 = fclamp(Value[0]);
// if last value... // if last value...
if (val2 == 1.0) { if (val2 == 1.0 || p->Domain[0] == 0) {
Output[0] = LutTable[p -> Domain[0]]; Output[0] = LutTable[p -> Domain[0]];
} }
else else
...@@ -274,20 +274,34 @@ void Eval1Input(CMSREGISTER const cmsUInt16Number Input[], ...@@ -274,20 +274,34 @@ void Eval1Input(CMSREGISTER const cmsUInt16Number Input[],
cmsUInt32Number OutChan; cmsUInt32Number OutChan;
const cmsUInt16Number* LutTable = (cmsUInt16Number*) p16 -> Table; const cmsUInt16Number* LutTable = (cmsUInt16Number*) p16 -> Table;
v = Input[0] * p16 -> Domain[0];
fk = _cmsToFixedDomain(v);
k0 = FIXED_TO_INT(fk); // if last value...
rk = (cmsUInt16Number) FIXED_REST_TO_INT(fk); if (Input[0] == 0xffff || p16->Domain[0] == 0) {
cmsUInt32Number y0 = p16->Domain[0] * p16->opta[0];
for (OutChan = 0; OutChan < p16->nOutputs; OutChan++) {
Output[OutChan] = LutTable[y0 + OutChan];
}
}
else
{
v = Input[0] * p16->Domain[0];
fk = _cmsToFixedDomain(v);
k0 = FIXED_TO_INT(fk);
rk = (cmsUInt16Number)FIXED_REST_TO_INT(fk);
k1 = k0 + (Input[0] != 0xFFFFU ? 1 : 0); k1 = k0 + (Input[0] != 0xFFFFU ? 1 : 0);
K0 = p16 -> opta[0] * k0; K0 = p16->opta[0] * k0;
K1 = p16 -> opta[0] * k1; K1 = p16->opta[0] * k1;
for (OutChan=0; OutChan < p16->nOutputs; OutChan++) { for (OutChan = 0; OutChan < p16->nOutputs; OutChan++) {
Output[OutChan] = LinearInterp(rk, LutTable[K0+OutChan], LutTable[K1+OutChan]); Output[OutChan] = LinearInterp(rk, LutTable[K0 + OutChan], LutTable[K1 + OutChan]);
}
} }
} }
...@@ -308,12 +322,12 @@ void Eval1InputFloat(const cmsFloat32Number Value[], ...@@ -308,12 +322,12 @@ void Eval1InputFloat(const cmsFloat32Number Value[],
val2 = fclamp(Value[0]); val2 = fclamp(Value[0]);
// if last value... // if last value...
if (val2 == 1.0) { if (val2 == 1.0 || p->Domain[0] == 0) {
y0 = LutTable[p->Domain[0]]; cmsUInt32Number start = p->Domain[0] * p->opta[0];
for (OutChan = 0; OutChan < p->nOutputs; OutChan++) { for (OutChan = 0; OutChan < p->nOutputs; OutChan++) {
Output[OutChan] = y0; Output[OutChan] = LutTable[start + OutChan];
} }
} }
else else
......
//--------------------------------------------------------------------------------- //---------------------------------------------------------------------------------
// //
// Little Color Management System // Little Color Management System
// Copyright (c) 1998-2020 Marti Maria Saguer // Copyright (c) 1998-2022 Marti Maria Saguer
// //
// Permission is hereby granted, free of charge, to any person obtaining // Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the "Software"), // a copy of this software and associated documentation files (the "Software"),
...@@ -479,16 +479,15 @@ cmsBool CMSEXPORT cmsCloseIOhandler(cmsIOHANDLER* io) ...@@ -479,16 +479,15 @@ cmsBool CMSEXPORT cmsCloseIOhandler(cmsIOHANDLER* io)
cmsIOHANDLER* CMSEXPORT cmsGetProfileIOhandler(cmsHPROFILE hProfile) cmsIOHANDLER* CMSEXPORT cmsGetProfileIOhandler(cmsHPROFILE hProfile)
{ {
_cmsICCPROFILE* Icc = (_cmsICCPROFILE*)hProfile; _cmsICCPROFILE* Icc = (_cmsICCPROFILE*)hProfile;
if (Icc == NULL) return NULL; if (Icc == NULL) return NULL;
return Icc->IOhandler; return Icc->IOhandler;
} }
// Creates an empty structure holding all required parameters // Creates an empty structure holding all required parameters
cmsHPROFILE CMSEXPORT cmsCreateProfilePlaceholder(cmsContext ContextID) cmsHPROFILE CMSEXPORT cmsCreateProfilePlaceholder(cmsContext ContextID)
{ {
time_t now = time(NULL);
_cmsICCPROFILE* Icc = (_cmsICCPROFILE*) _cmsMallocZero(ContextID, sizeof(_cmsICCPROFILE)); _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) _cmsMallocZero(ContextID, sizeof(_cmsICCPROFILE));
if (Icc == NULL) return NULL; if (Icc == NULL) return NULL;
...@@ -499,15 +498,20 @@ cmsHPROFILE CMSEXPORT cmsCreateProfilePlaceholder(cmsContext ContextID) ...@@ -499,15 +498,20 @@ cmsHPROFILE CMSEXPORT cmsCreateProfilePlaceholder(cmsContext ContextID)
// Set default version // Set default version
Icc ->Version = 0x02100000; Icc ->Version = 0x02100000;
// Set creation date/time // Set creation date/time
memmove(&Icc ->Created, gmtime(&now), sizeof(Icc ->Created)); if (!_cmsGetTime(&Icc->Created))
goto Error;
// Create a mutex if the user provided proper plugin. NULL otherwise // Create a mutex if the user provided proper plugin. NULL otherwise
Icc ->UsrMutex = _cmsCreateMutex(ContextID); Icc ->UsrMutex = _cmsCreateMutex(ContextID);
// Return the handle // Return the handle
return (cmsHPROFILE) Icc; return (cmsHPROFILE) Icc;
Error:
_cmsFree(ContextID, Icc);
return NULL;
} }
cmsContext CMSEXPORT cmsGetProfileContextID(cmsHPROFILE hProfile) cmsContext CMSEXPORT cmsGetProfileContextID(cmsHPROFILE hProfile)
...@@ -1430,7 +1434,25 @@ cmsBool CMSEXPORT cmsSaveProfileToMem(cmsHPROFILE hProfile, void *MemPtr, cmsUIn ...@@ -1430,7 +1434,25 @@ cmsBool CMSEXPORT cmsSaveProfileToMem(cmsHPROFILE hProfile, void *MemPtr, cmsUIn
return rc; return rc;
} }
// Free one tag contents
static
void freeOneTag(_cmsICCPROFILE* Icc, cmsUInt32Number i)
{
if (Icc->TagPtrs[i]) {
cmsTagTypeHandler* TypeHandler = Icc->TagTypeHandlers[i];
if (TypeHandler != NULL) {
cmsTagTypeHandler LocalTypeHandler = *TypeHandler;
LocalTypeHandler.ContextID = Icc->ContextID;
LocalTypeHandler.ICCVersion = Icc->Version;
LocalTypeHandler.FreePtr(&LocalTypeHandler, Icc->TagPtrs[i]);
}
else
_cmsFree(Icc->ContextID, Icc->TagPtrs[i]);
}
}
// Closes a profile freeing any involved resources // Closes a profile freeing any involved resources
cmsBool CMSEXPORT cmsCloseProfile(cmsHPROFILE hProfile) cmsBool CMSEXPORT cmsCloseProfile(cmsHPROFILE hProfile)
...@@ -1450,20 +1472,7 @@ cmsBool CMSEXPORT cmsCloseProfile(cmsHPROFILE hProfile) ...@@ -1450,20 +1472,7 @@ cmsBool CMSEXPORT cmsCloseProfile(cmsHPROFILE hProfile)
for (i=0; i < Icc -> TagCount; i++) { for (i=0; i < Icc -> TagCount; i++) {
if (Icc -> TagPtrs[i]) { freeOneTag(Icc, i);
cmsTagTypeHandler* TypeHandler = Icc ->TagTypeHandlers[i];
if (TypeHandler != NULL) {
cmsTagTypeHandler LocalTypeHandler = *TypeHandler;
LocalTypeHandler.ContextID = Icc ->ContextID; // As an additional parameters
LocalTypeHandler.ICCVersion = Icc ->Version;
LocalTypeHandler.FreePtr(&LocalTypeHandler, Icc -> TagPtrs[i]);
}
else
_cmsFree(Icc ->ContextID, Icc ->TagPtrs[i]);
}
} }
if (Icc ->IOhandler != NULL) { if (Icc ->IOhandler != NULL) {
...@@ -1503,7 +1512,7 @@ cmsBool IsTypeSupported(cmsTagDescriptor* TagDescriptor, cmsTagTypeSignature Typ ...@@ -1503,7 +1512,7 @@ cmsBool IsTypeSupported(cmsTagDescriptor* TagDescriptor, cmsTagTypeSignature Typ
void* CMSEXPORT cmsReadTag(cmsHPROFILE hProfile, cmsTagSignature sig) void* CMSEXPORT cmsReadTag(cmsHPROFILE hProfile, cmsTagSignature sig)
{ {
_cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile;
cmsIOHANDLER* io = Icc ->IOhandler; cmsIOHANDLER* io;
cmsTagTypeHandler* TypeHandler; cmsTagTypeHandler* TypeHandler;
cmsTagTypeHandler LocalTypeHandler; cmsTagTypeHandler LocalTypeHandler;
cmsTagDescriptor* TagDescriptor; cmsTagDescriptor* TagDescriptor;
...@@ -1515,8 +1524,12 @@ void* CMSEXPORT cmsReadTag(cmsHPROFILE hProfile, cmsTagSignature sig) ...@@ -1515,8 +1524,12 @@ void* CMSEXPORT cmsReadTag(cmsHPROFILE hProfile, cmsTagSignature sig)
if (!_cmsLockMutex(Icc->ContextID, Icc ->UsrMutex)) return NULL; if (!_cmsLockMutex(Icc->ContextID, Icc ->UsrMutex)) return NULL;
n = _cmsSearchTag(Icc, sig, TRUE); n = _cmsSearchTag(Icc, sig, TRUE);
if (n < 0) goto Error; // Not found, return NULL if (n < 0)
{
// Not found, return NULL
_cmsUnlockMutex(Icc->ContextID, Icc->UsrMutex);
return NULL;
}
// If the element is already in memory, return the pointer // If the element is already in memory, return the pointer
if (Icc -> TagPtrs[n]) { if (Icc -> TagPtrs[n]) {
...@@ -1544,6 +1557,7 @@ void* CMSEXPORT cmsReadTag(cmsHPROFILE hProfile, cmsTagSignature sig) ...@@ -1544,6 +1557,7 @@ void* CMSEXPORT cmsReadTag(cmsHPROFILE hProfile, cmsTagSignature sig)
if (TagSize < 8) goto Error; if (TagSize < 8) goto Error;
io = Icc ->IOhandler;
// Seek to its location // Seek to its location
if (!io -> Seek(io, Offset)) if (!io -> Seek(io, Offset))
goto Error; goto Error;
...@@ -1611,8 +1625,12 @@ void* CMSEXPORT cmsReadTag(cmsHPROFILE hProfile, cmsTagSignature sig) ...@@ -1611,8 +1625,12 @@ void* CMSEXPORT cmsReadTag(cmsHPROFILE hProfile, cmsTagSignature sig)
return Icc -> TagPtrs[n]; return Icc -> TagPtrs[n];
// Return error and unlock tha data // Return error and unlock the data
Error: Error:
freeOneTag(Icc, n);
Icc->TagPtrs[n] = NULL;
_cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex); _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex);
return NULL; return NULL;
} }
...@@ -1778,7 +1796,7 @@ cmsUInt32Number CMSEXPORT cmsReadRawTag(cmsHPROFILE hProfile, cmsTagSignature si ...@@ -1778,7 +1796,7 @@ cmsUInt32Number CMSEXPORT cmsReadRawTag(cmsHPROFILE hProfile, cmsTagSignature si
// It is already read? // It is already read?
if (Icc -> TagPtrs[i] == NULL) { if (Icc -> TagPtrs[i] == NULL) {
// No yet, get original position // Not yet, get original position
Offset = Icc ->TagOffsets[i]; Offset = Icc ->TagOffsets[i];
TagSize = Icc ->TagSizes[i]; TagSize = Icc ->TagSizes[i];
......
//--------------------------------------------------------------------------------- //---------------------------------------------------------------------------------
// //
// Little Color Management System // Little Color Management System
// Copyright (c) 1998-2020 Marti Maria Saguer // Copyright (c) 1998-2022 Marti Maria Saguer
// //
// Permission is hereby granted, free of charge, to any person obtaining // Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the "Software"), // a copy of this software and associated documentation files (the "Software"),
...@@ -260,7 +260,7 @@ Error: ...@@ -260,7 +260,7 @@ Error:
// Read the DToAX tag, adjusting the encoding of Lab or XYZ if neded // Read the DToAX tag, adjusting the encoding of Lab or XYZ if needed
static static
cmsPipeline* _cmsReadFloatInputTag(cmsHPROFILE hProfile, cmsTagSignature tagFloat) cmsPipeline* _cmsReadFloatInputTag(cmsHPROFILE hProfile, cmsTagSignature tagFloat)
{ {
...@@ -536,7 +536,7 @@ void ChangeInterpolationToTrilinear(cmsPipeline* Lut) ...@@ -536,7 +536,7 @@ void ChangeInterpolationToTrilinear(cmsPipeline* Lut)
} }
// Read the DToAX tag, adjusting the encoding of Lab or XYZ if neded // Read the DToAX tag, adjusting the encoding of Lab or XYZ if needed
static static
cmsPipeline* _cmsReadFloatOutputTag(cmsHPROFILE hProfile, cmsTagSignature tagFloat) cmsPipeline* _cmsReadFloatOutputTag(cmsHPROFILE hProfile, cmsTagSignature tagFloat)
{ {
...@@ -661,7 +661,7 @@ Error: ...@@ -661,7 +661,7 @@ Error:
// --------------------------------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------------------------------
// Read the AToD0 tag, adjusting the encoding of Lab or XYZ if neded // Read the AToD0 tag, adjusting the encoding of Lab or XYZ if needed
static static
cmsPipeline* _cmsReadFloatDevicelinkTag(cmsHPROFILE hProfile, cmsTagSignature tagFloat) cmsPipeline* _cmsReadFloatDevicelinkTag(cmsHPROFILE hProfile, cmsTagSignature tagFloat)
{ {
......
//--------------------------------------------------------------------------------- //---------------------------------------------------------------------------------
// //
// Little Color Management System // Little Color Management System
// Copyright (c) 1998-2020 Marti Maria Saguer // Copyright (c) 1998-2022 Marti Maria Saguer
// //
// Permission is hereby granted, free of charge, to any person obtaining // Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the "Software"), // a copy of this software and associated documentation files (the "Software"),
...@@ -1226,6 +1226,11 @@ void* CMSEXPORT cmsStageData(const cmsStage* mpe) ...@@ -1226,6 +1226,11 @@ void* CMSEXPORT cmsStageData(const cmsStage* mpe)
return mpe -> Data; return mpe -> Data;
} }
cmsContext CMSEXPORT cmsGetStageContextID(const cmsStage* mpe)
{
return mpe -> ContextID;
}
cmsStage* CMSEXPORT cmsStageNext(const cmsStage* mpe) cmsStage* CMSEXPORT cmsStageNext(const cmsStage* mpe)
{ {
return mpe -> Next; return mpe -> Next;
......
//--------------------------------------------------------------------------------- //---------------------------------------------------------------------------------
// //
// Little Color Management System // Little Color Management System
// Copyright (c) 1998-2020 Marti Maria Saguer // Copyright (c) 1998-2022 Marti Maria Saguer
// //
// Permission is hereby granted, free of charge, to any person obtaining // Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the "Software"), // a copy of this software and associated documentation files (the "Software"),
......
//--------------------------------------------------------------------------------- //---------------------------------------------------------------------------------
// //
// Little Color Management System // Little Color Management System
// Copyright (c) 1998-2020 Marti Maria Saguer // Copyright (c) 1998-2022 Marti Maria Saguer
// //
// Permission is hereby granted, free of charge, to any person obtaining // Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the "Software"), // a copy of this software and associated documentation files (the "Software"),
...@@ -204,7 +204,7 @@ void strFrom16(char str[3], cmsUInt16Number n) ...@@ -204,7 +204,7 @@ void strFrom16(char str[3], cmsUInt16Number n)
} }
// Add an ASCII entry. Do not add any \0 termination (ICC1v43_2010-12.pdf page 61) // Add an ASCII entry. Do not add any \0 termination (ICC1v43_2010-12.pdf page 61)
// In the case the user explicitely sets an empty string, we force a \0 // In the case the user explicitly sets an empty string, we force a \0
cmsBool CMSEXPORT cmsMLUsetASCII(cmsMLU* mlu, const char LanguageCode[3], const char CountryCode[3], const char* ASCIIString) cmsBool CMSEXPORT cmsMLUsetASCII(cmsMLU* mlu, const char LanguageCode[3], const char CountryCode[3], const char* ASCIIString)
{ {
cmsUInt32Number i, len = (cmsUInt32Number) strlen(ASCIIString); cmsUInt32Number i, len = (cmsUInt32Number) strlen(ASCIIString);
...@@ -641,7 +641,7 @@ cmsUInt32Number CMSEXPORT cmsNamedColorCount(const cmsNAMEDCOLORLIST* NamedColor ...@@ -641,7 +641,7 @@ cmsUInt32Number CMSEXPORT cmsNamedColorCount(const cmsNAMEDCOLORLIST* NamedColor
return NamedColorList ->nColors; return NamedColorList ->nColors;
} }
// Info aboout a given color // Info about a given color
cmsBool CMSEXPORT cmsNamedColorInfo(const cmsNAMEDCOLORLIST* NamedColorList, cmsUInt32Number nColor, cmsBool CMSEXPORT cmsNamedColorInfo(const cmsNAMEDCOLORLIST* NamedColorList, cmsUInt32Number nColor,
char* Name, char* Name,
char* Prefix, char* Prefix,
......
//--------------------------------------------------------------------------------- //---------------------------------------------------------------------------------
// //
// Little Color Management System // Little Color Management System
// Copyright (c) 1998-2020 Marti Maria Saguer // Copyright (c) 1998-2022 Marti Maria Saguer
// //
// Permission is hereby granted, free of charge, to any person obtaining // Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the "Software"), // a copy of this software and associated documentation files (the "Software"),
...@@ -647,7 +647,6 @@ cmsBool OptimizeByResampling(cmsPipeline** Lut, cmsUInt32Number Intent, cmsUInt3 ...@@ -647,7 +647,6 @@ cmsBool OptimizeByResampling(cmsPipeline** Lut, cmsUInt32Number Intent, cmsUInt3
{ {
cmsPipeline* Src = NULL; cmsPipeline* Src = NULL;
cmsPipeline* Dest = NULL; cmsPipeline* Dest = NULL;
cmsStage* mpe;
cmsStage* CLUT; cmsStage* CLUT;
cmsStage *KeepPreLin = NULL, *KeepPostLin = NULL; cmsStage *KeepPreLin = NULL, *KeepPostLin = NULL;
cmsUInt32Number nGridPoints; cmsUInt32Number nGridPoints;
...@@ -669,7 +668,7 @@ cmsBool OptimizeByResampling(cmsPipeline** Lut, cmsUInt32Number Intent, cmsUInt3 ...@@ -669,7 +668,7 @@ cmsBool OptimizeByResampling(cmsPipeline** Lut, cmsUInt32Number Intent, cmsUInt3
if (ColorSpace == (cmsColorSpaceSignature)0 || if (ColorSpace == (cmsColorSpaceSignature)0 ||
OutputColorSpace == (cmsColorSpaceSignature)0) return FALSE; OutputColorSpace == (cmsColorSpaceSignature)0) return FALSE;
nGridPoints = _cmsReasonableGridpointsByColorspace(ColorSpace, *dwFlags); nGridPoints = _cmsReasonableGridpointsByColorspace(ColorSpace, *dwFlags);
// For empty LUTs, 2 points are enough // For empty LUTs, 2 points are enough
if (cmsPipelineStageCount(*Lut) == 0) if (cmsPipelineStageCount(*Lut) == 0)
...@@ -677,13 +676,6 @@ cmsBool OptimizeByResampling(cmsPipeline** Lut, cmsUInt32Number Intent, cmsUInt3 ...@@ -677,13 +676,6 @@ cmsBool OptimizeByResampling(cmsPipeline** Lut, cmsUInt32Number Intent, cmsUInt3
Src = *Lut; Src = *Lut;
// Named color pipelines cannot be optimized either
for (mpe = cmsPipelineGetPtrToFirstStage(Src);
mpe != NULL;
mpe = cmsStageNext(mpe)) {
if (cmsStageType(mpe) == cmsSigNamedColorElemType) return FALSE;
}
// Allocate an empty LUT // Allocate an empty LUT
Dest = cmsPipelineAlloc(Src ->ContextID, Src ->InputChannels, Src ->OutputChannels); Dest = cmsPipelineAlloc(Src ->ContextID, Src ->InputChannels, Src ->OutputChannels);
if (!Dest) return FALSE; if (!Dest) return FALSE;
...@@ -1051,7 +1043,6 @@ cmsBool OptimizeByComputingLinearization(cmsPipeline** Lut, cmsUInt32Number Inte ...@@ -1051,7 +1043,6 @@ cmsBool OptimizeByComputingLinearization(cmsPipeline** Lut, cmsUInt32Number Inte
cmsStage* OptimizedCLUTmpe; cmsStage* OptimizedCLUTmpe;
cmsColorSpaceSignature ColorSpace, OutputColorSpace; cmsColorSpaceSignature ColorSpace, OutputColorSpace;
cmsStage* OptimizedPrelinMpe; cmsStage* OptimizedPrelinMpe;
cmsStage* mpe;
cmsToneCurve** OptimizedPrelinCurves; cmsToneCurve** OptimizedPrelinCurves;
_cmsStageCLutData* OptimizedPrelinCLUT; _cmsStageCLutData* OptimizedPrelinCLUT;
...@@ -1072,14 +1063,7 @@ cmsBool OptimizeByComputingLinearization(cmsPipeline** Lut, cmsUInt32Number Inte ...@@ -1072,14 +1063,7 @@ cmsBool OptimizeByComputingLinearization(cmsPipeline** Lut, cmsUInt32Number Inte
} }
OriginalLut = *Lut; OriginalLut = *Lut;
// Named color pipelines cannot be optimized either
for (mpe = cmsPipelineGetPtrToFirstStage(OriginalLut);
mpe != NULL;
mpe = cmsStageNext(mpe)) {
if (cmsStageType(mpe) == cmsSigNamedColorElemType) return FALSE;
}
ColorSpace = _cmsICCcolorSpace((int) T_COLORSPACE(*InputFormat)); ColorSpace = _cmsICCcolorSpace((int) T_COLORSPACE(*InputFormat));
OutputColorSpace = _cmsICCcolorSpace((int) T_COLORSPACE(*OutputFormat)); OutputColorSpace = _cmsICCcolorSpace((int) T_COLORSPACE(*OutputFormat));
...@@ -1918,6 +1902,7 @@ cmsBool CMSEXPORT _cmsOptimizePipeline(cmsContext ContextID, ...@@ -1918,6 +1902,7 @@ cmsBool CMSEXPORT _cmsOptimizePipeline(cmsContext ContextID,
_cmsOptimizationPluginChunkType* ctx = ( _cmsOptimizationPluginChunkType*) _cmsContextGetClientChunk(ContextID, OptimizationPlugin); _cmsOptimizationPluginChunkType* ctx = ( _cmsOptimizationPluginChunkType*) _cmsContextGetClientChunk(ContextID, OptimizationPlugin);
_cmsOptimizationCollection* Opts; _cmsOptimizationCollection* Opts;
cmsBool AnySuccess = FALSE; cmsBool AnySuccess = FALSE;
cmsStage* mpe;
// A CLUT is being asked, so force this specific optimization // A CLUT is being asked, so force this specific optimization
if (*dwFlags & cmsFLAGS_FORCE_CLUT) { if (*dwFlags & cmsFLAGS_FORCE_CLUT) {
...@@ -1932,6 +1917,13 @@ cmsBool CMSEXPORT _cmsOptimizePipeline(cmsContext ContextID, ...@@ -1932,6 +1917,13 @@ cmsBool CMSEXPORT _cmsOptimizePipeline(cmsContext ContextID,
return TRUE; return TRUE;
} }
// Named color pipelines cannot be optimized
for (mpe = cmsPipelineGetPtrToFirstStage(*PtrLut);
mpe != NULL;
mpe = cmsStageNext(mpe)) {
if (cmsStageType(mpe) == cmsSigNamedColorElemType) return FALSE;
}
// Try to get rid of identities and trivial conversions. // Try to get rid of identities and trivial conversions.
AnySuccess = PreOptimize(*PtrLut); AnySuccess = PreOptimize(*PtrLut);
......
//--------------------------------------------------------------------------------- //---------------------------------------------------------------------------------
// //
// Little Color Management System // Little Color Management System
// Copyright (c) 1998-2020 Marti Maria Saguer // Copyright (c) 1998-2022 Marti Maria Saguer
// //
// Permission is hereby granted, free of charge, to any person obtaining // Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the "Software"), // a copy of this software and associated documentation files (the "Software"),
......
//--------------------------------------------------------------------------------- //---------------------------------------------------------------------------------
// //
// Little Color Management System // Little Color Management System
// Copyright (c) 1998-2020 Marti Maria Saguer // Copyright (c) 1998-2022 Marti Maria Saguer
// //
// Permission is hereby granted, free of charge, to any person obtaining // Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the "Software"), // a copy of this software and associated documentation files (the "Software"),
...@@ -671,17 +671,65 @@ static struct _cmsContext_struct globalContext = { ...@@ -671,17 +671,65 @@ static struct _cmsContext_struct globalContext = {
static _cmsMutex _cmsContextPoolHeadMutex = CMS_MUTEX_INITIALIZER; static _cmsMutex _cmsContextPoolHeadMutex = CMS_MUTEX_INITIALIZER;
static struct _cmsContext_struct* _cmsContextPoolHead = NULL; static struct _cmsContext_struct* _cmsContextPoolHead = NULL;
// Make sure context is initialized (needed on windows)
static
cmsBool InitContextMutex(void)
{
// See the comments regarding locking in lcms2_internal.h
// for an explanation of why we need the following code.
#ifndef CMS_NO_PTHREADS
#ifdef CMS_IS_WINDOWS_
#ifndef CMS_RELY_ON_WINDOWS_STATIC_MUTEX_INIT
static cmsBool already_initialized = FALSE;
if (!already_initialized)
{
static HANDLE _cmsWindowsInitMutex = NULL;
static volatile HANDLE* mutex = &_cmsWindowsInitMutex;
if (*mutex == NULL)
{
HANDLE p = CreateMutex(NULL, FALSE, NULL);
if (p && InterlockedCompareExchangePointer((void**)mutex, (void*)p, NULL) != NULL)
CloseHandle(p);
}
if (*mutex == NULL || WaitForSingleObject(*mutex, INFINITE) == WAIT_FAILED)
{
cmsSignalError(0, cmsERROR_INTERNAL, "Mutex lock failed");
return FALSE;
}
if (((void**)&_cmsContextPoolHeadMutex)[0] == NULL)
InitializeCriticalSection(&_cmsContextPoolHeadMutex);
if (*mutex == NULL || !ReleaseMutex(*mutex))
{
cmsSignalError(0, cmsERROR_INTERNAL, "Mutex unlock failed");
return FALSE;
}
already_initialized = TRUE;
}
#endif
#endif
#endif
return TRUE;
}
// Internal, get associated pointer, with guessing. Never returns NULL. // Internal, get associated pointer, with guessing. Never returns NULL.
struct _cmsContext_struct* _cmsGetContext(cmsContext ContextID) struct _cmsContext_struct* _cmsGetContext(cmsContext ContextID)
{ {
struct _cmsContext_struct* id = (struct _cmsContext_struct*) ContextID; struct _cmsContext_struct* id = (struct _cmsContext_struct*) ContextID;
struct _cmsContext_struct* ctx; struct _cmsContext_struct* ctx;
// On 0, use global settings // On 0, use global settings
if (id == NULL) if (id == NULL)
return &globalContext; return &globalContext;
InitContextMutex();
// Search // Search
_cmsEnterCriticalSectionPrimitive(&_cmsContextPoolHeadMutex); _cmsEnterCriticalSectionPrimitive(&_cmsContextPoolHeadMutex);
...@@ -784,31 +832,7 @@ cmsContext CMSEXPORT cmsCreateContext(void* Plugin, void* UserData) ...@@ -784,31 +832,7 @@ cmsContext CMSEXPORT cmsCreateContext(void* Plugin, void* UserData)
struct _cmsContext_struct* ctx; struct _cmsContext_struct* ctx;
struct _cmsContext_struct fakeContext; struct _cmsContext_struct fakeContext;
// See the comments regarding locking in lcms2_internal.h if (!InitContextMutex()) return NULL;
// for an explanation of why we need the following code.
#ifndef CMS_NO_PTHREADS
#ifdef CMS_IS_WINDOWS_
#ifndef CMS_RELY_ON_WINDOWS_STATIC_MUTEX_INIT
{
static HANDLE _cmsWindowsInitMutex = NULL;
static volatile HANDLE* mutex = &_cmsWindowsInitMutex;
if (*mutex == NULL)
{
HANDLE p = CreateMutex(NULL, FALSE, NULL);
if (p && InterlockedCompareExchangePointer((void **)mutex, (void*)p, NULL) != NULL)
CloseHandle(p);
}
if (*mutex == NULL || WaitForSingleObject(*mutex, INFINITE) == WAIT_FAILED)
return NULL;
if (((void **)&_cmsContextPoolHeadMutex)[0] == NULL)
InitializeCriticalSection(&_cmsContextPoolHeadMutex);
if (*mutex == NULL || !ReleaseMutex(*mutex))
return NULL;
}
#endif
#endif
#endif
_cmsInstallAllocFunctions(_cmsFindMemoryPlugin(Plugin), &fakeContext.DefaultMemoryManager); _cmsInstallAllocFunctions(_cmsFindMemoryPlugin(Plugin), &fakeContext.DefaultMemoryManager);
...@@ -884,6 +908,8 @@ cmsContext CMSEXPORT cmsDupContext(cmsContext ContextID, void* NewUserData) ...@@ -884,6 +908,8 @@ cmsContext CMSEXPORT cmsDupContext(cmsContext ContextID, void* NewUserData)
if (ctx == NULL) if (ctx == NULL)
return NULL; // Something very wrong happened return NULL; // Something very wrong happened
if (!InitContextMutex()) return NULL;
// Setup default memory allocators // Setup default memory allocators
memcpy(&ctx->DefaultMemoryManager, &src->DefaultMemoryManager, sizeof(ctx->DefaultMemoryManager)); memcpy(&ctx->DefaultMemoryManager, &src->DefaultMemoryManager, sizeof(ctx->DefaultMemoryManager));
...@@ -943,6 +969,9 @@ void CMSEXPORT cmsDeleteContext(cmsContext ContextID) ...@@ -943,6 +969,9 @@ void CMSEXPORT cmsDeleteContext(cmsContext ContextID)
struct _cmsContext_struct fakeContext; struct _cmsContext_struct fakeContext;
struct _cmsContext_struct* prev; struct _cmsContext_struct* prev;
InitContextMutex();
memcpy(&fakeContext.DefaultMemoryManager, &ctx->DefaultMemoryManager, sizeof(ctx->DefaultMemoryManager)); memcpy(&fakeContext.DefaultMemoryManager, &ctx->DefaultMemoryManager, sizeof(ctx->DefaultMemoryManager));
fakeContext.chunks[UserPtr] = ctx ->chunks[UserPtr]; fakeContext.chunks[UserPtr] = ctx ->chunks[UserPtr];
...@@ -989,3 +1018,32 @@ void* CMSEXPORT cmsGetContextUserData(cmsContext ContextID) ...@@ -989,3 +1018,32 @@ void* CMSEXPORT cmsGetContextUserData(cmsContext ContextID)
} }
// Use context mutex to provide thread-safe time
cmsBool _cmsGetTime(struct tm* ptr_time)
{
struct tm* t;
#if defined(HAVE_GMTIME_R) || defined(HAVE_GMTIME_S)
struct tm tm;
#endif
time_t now = time(NULL);
#ifdef HAVE_GMTIME_R
t = gmtime_r(&now, &tm);
#elif defined(HAVE_GMTIME_S)
t = gmtime_s(&tm, &now) == 0 ? &tm : NULL;
#else
if (!InitContextMutex()) return FALSE;
_cmsEnterCriticalSectionPrimitive(&_cmsContextPoolHeadMutex);
t = gmtime(&now);
_cmsLeaveCriticalSectionPrimitive(&_cmsContextPoolHeadMutex);
#endif
if (t == NULL)
return FALSE;
else {
*ptr_time = *t;
return TRUE;
}
}
//--------------------------------------------------------------------------------- //---------------------------------------------------------------------------------
// //
// Little Color Management System // Little Color Management System
// Copyright (c) 1998-2020 Marti Maria Saguer // Copyright (c) 1998-2022 Marti Maria Saguer
// //
// Permission is hereby granted, free of charge, to any person obtaining // Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the "Software"), // a copy of this software and associated documentation files (the "Software"),
......
//--------------------------------------------------------------------------------- //---------------------------------------------------------------------------------
// //
// Little Color Management System // Little Color Management System
// Copyright (c) 1998-2020 Marti Maria Saguer // Copyright (c) 1998-2022 Marti Maria Saguer
// //
// Permission is hereby granted, free of charge, to any person obtaining // Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the "Software"), // a copy of this software and associated documentation files (the "Software"),
...@@ -368,7 +368,7 @@ int InkLimitingSampler(CMSREGISTER const cmsUInt16Number In[], CMSREGISTER cmsUI ...@@ -368,7 +368,7 @@ int InkLimitingSampler(CMSREGISTER const cmsUInt16Number In[], CMSREGISTER cmsUI
InkLimit = (InkLimit * 655.35); InkLimit = (InkLimit * 655.35);
SumCMY = In[0] + In[1] + In[2]; SumCMY = (cmsFloat64Number) In[0] + In[1] + In[2];
SumCMYK = SumCMY + In[3]; SumCMYK = SumCMY + In[3];
if (SumCMYK > InkLimit) { if (SumCMYK > InkLimit) {
......
//--------------------------------------------------------------------------------- //---------------------------------------------------------------------------------
// //
// Little Color Management System // Little Color Management System
// Copyright (c) 1998-2020 Marti Maria Saguer // Copyright (c) 1998-2022 Marti Maria Saguer
// //
// Permission is hereby granted, free of charge, to any person obtaining // Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the "Software"), // a copy of this software and associated documentation files (the "Software"),
...@@ -264,16 +264,16 @@ cmsBool _cmsAdaptMatrixToD50(cmsMAT3* r, const cmsCIExyY* SourceWhitePt) ...@@ -264,16 +264,16 @@ cmsBool _cmsAdaptMatrixToD50(cmsMAT3* r, const cmsCIExyY* SourceWhitePt)
// Build a White point, primary chromas transfer matrix from RGB to CIE XYZ // Build a White point, primary chromas transfer matrix from RGB to CIE XYZ
// This is just an approximation, I am not handling all the non-linear // This is just an approximation, I am not handling all the non-linear
// aspects of the RGB to XYZ process, and assumming that the gamma correction // aspects of the RGB to XYZ process, and assuming that the gamma correction
// has transitive property in the transformation chain. // has transitive property in the transformation chain.
// //
// the alghoritm: // the algorithm:
// //
// - First I build the absolute conversion matrix using // - First I build the absolute conversion matrix using
// primaries in XYZ. This matrix is next inverted // primaries in XYZ. This matrix is next inverted
// - Then I eval the source white point across this matrix // - Then I eval the source white point across this matrix
// obtaining the coeficients of the transformation // obtaining the coefficients of the transformation
// - Then, I apply these coeficients to the original matrix // - Then, I apply these coefficients to the original matrix
// //
cmsBool _cmsBuildRGB2XYZtransferMatrix(cmsMAT3* r, const cmsCIExyY* WhitePt, const cmsCIExyYTRIPLE* Primrs) cmsBool _cmsBuildRGB2XYZtransferMatrix(cmsMAT3* r, const cmsCIExyY* WhitePt, const cmsCIExyYTRIPLE* Primrs)
{ {
......
//--------------------------------------------------------------------------------- //---------------------------------------------------------------------------------
// //
// Little Color Management System // Little Color Management System
// Copyright (c) 1998-2020 Marti Maria Saguer // Copyright (c) 1998-2022 Marti Maria Saguer
// //
// Permission is hereby granted, free of charge, to any person obtaining // Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the "Software"), // a copy of this software and associated documentation files (the "Software"),
...@@ -284,7 +284,7 @@ void FloatXFORM(_cmsTRANSFORM* p, ...@@ -284,7 +284,7 @@ void FloatXFORM(_cmsTRANSFORM* p,
accum = p->FromInputFloat(p, fIn, accum, Stride->BytesPerPlaneIn); accum = p->FromInputFloat(p, fIn, accum, Stride->BytesPerPlaneIn);
// Any gamut chack to do? // Any gamut check to do?
if (p->GamutCheck != NULL) { if (p->GamutCheck != NULL) {
// Evaluate gamut marker. // Evaluate gamut marker.
...@@ -846,7 +846,7 @@ _cmsTRANSFORM* AllocEmptyTransform(cmsContext ContextID, cmsPipeline* lut, ...@@ -846,7 +846,7 @@ _cmsTRANSFORM* AllocEmptyTransform(cmsContext ContextID, cmsPipeline* lut,
} }
// Check whatever this is a true floating point transform // Check whatever this is a true floating point transform
if (_cmsFormatterIsFloat(*InputFormat) && _cmsFormatterIsFloat(*OutputFormat)) { if (_cmsFormatterIsFloat(*OutputFormat)) {
// Get formatter function always return a valid union, but the contents of this union may be NULL. // Get formatter function always return a valid union, but the contents of this union may be NULL.
p ->FromInputFloat = _cmsGetFormatter(ContextID, *InputFormat, cmsFormatterInput, CMS_PACK_FLAGS_FLOAT).FmtFloat; p ->FromInputFloat = _cmsGetFormatter(ContextID, *InputFormat, cmsFormatterInput, CMS_PACK_FLAGS_FLOAT).FmtFloat;
...@@ -1081,6 +1081,15 @@ cmsHTRANSFORM CMSEXPORT cmsCreateExtendedTransform(cmsContext ContextID, ...@@ -1081,6 +1081,15 @@ cmsHTRANSFORM CMSEXPORT cmsCreateExtendedTransform(cmsContext ContextID,
return NULL; return NULL;
} }
// Check whatever the transform is 16 bits and involves linear RGB in first profile. If so, disable optimizations
if (EntryColorSpace == cmsSigRgbData && T_BYTES(InputFormat) == 2 && !(dwFlags & cmsFLAGS_NOOPTIMIZE))
{
cmsFloat64Number gamma = cmsDetectRGBProfileGamma(hProfiles[0], 0.1);
if (gamma > 0 && gamma < 1.6)
dwFlags |= cmsFLAGS_NOOPTIMIZE;
}
// Create a pipeline with all transformations // Create a pipeline with all transformations
Lut = _cmsLinkProfiles(ContextID, nProfiles, Intents, hProfiles, BPC, AdaptationStates, dwFlags); Lut = _cmsLinkProfiles(ContextID, nProfiles, Intents, hProfiles, BPC, AdaptationStates, dwFlags);
if (Lut == NULL) { if (Lut == NULL) {
......
// //
// Little Color Management System // Little Color Management System
// Copyright (c) 1998-2020 Marti Maria Saguer // Copyright (c) 1998-2022 Marti Maria Saguer
// //
// Permission is hereby granted, free of charge, to any person obtaining // Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the "Software"), // a copy of this software and associated documentation files (the "Software"),
...@@ -1118,5 +1118,8 @@ cmsBool _cmsAdaptationMatrix(cmsMAT3* r, const cmsMAT3* ConeMatrix, const cmsC ...@@ -1118,5 +1118,8 @@ cmsBool _cmsAdaptationMatrix(cmsMAT3* r, const cmsMAT3* ConeMatrix, const cmsC
cmsBool _cmsBuildRGB2XYZtransferMatrix(cmsMAT3* r, const cmsCIExyY* WhitePoint, const cmsCIExyYTRIPLE* Primaries); cmsBool _cmsBuildRGB2XYZtransferMatrix(cmsMAT3* r, const cmsCIExyY* WhitePoint, const cmsCIExyYTRIPLE* Primaries);
// thread-safe gettime
cmsBool _cmsGetTime(struct tm* ptr_time);
#define _lcms_internal_H #define _lcms_internal_H
#endif #endif
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment