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

lcms: Import upstream release 2.13.1.

parent b0c9a28e
//---------------------------------------------------------------------------------
//
// 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
// a copy of this software and associated documentation files (the "Software"),
......@@ -24,7 +24,7 @@
//---------------------------------------------------------------------------------
//
// 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
// are defined here. Including this file forces to include the standard API too.
......
//---------------------------------------------------------------------------------
//
// 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
// a copy of this software and associated documentation files (the "Software"),
......@@ -191,21 +191,21 @@ static
void fromFLTto8(void* dst, const void* src)
{
cmsFloat32Number n = *(cmsFloat32Number*)src;
*(cmsUInt8Number*)dst = _cmsQuickSaturateByte(n * 255.0f);
*(cmsUInt8Number*)dst = _cmsQuickSaturateByte(n * 255.0);
}
static
void fromFLTto16(void* dst, const void* src)
{
cmsFloat32Number n = *(cmsFloat32Number*)src;
*(cmsUInt16Number*)dst = _cmsQuickSaturateWord(n * 65535.0f);
*(cmsUInt16Number*)dst = _cmsQuickSaturateWord(n * 65535.0);
}
static
void fromFLTto16SE(void* dst, const void* src)
{
cmsFloat32Number n = *(cmsFloat32Number*)src;
cmsUInt16Number i = _cmsQuickSaturateWord(n * 65535.0f);
cmsUInt16Number i = _cmsQuickSaturateWord(n * 65535.0);
*(cmsUInt16Number*)dst = CHANGE_ENDIAN(i);
}
......@@ -243,7 +243,7 @@ void fromHLFto8(void* dst, const void* src)
{
#ifndef CMS_NO_HALF_SUPPORT
cmsFloat32Number n = _cmsHalf2Float(*(cmsUInt16Number*)src);
*(cmsUInt8Number*)dst = _cmsQuickSaturateByte(n * 255.0f);
*(cmsUInt8Number*)dst = _cmsQuickSaturateByte(n * 255.0);
#else
cmsUNUSED_PARAMETER(dst);
cmsUNUSED_PARAMETER(src);
......@@ -256,7 +256,7 @@ void fromHLFto16(void* dst, const void* src)
{
#ifndef CMS_NO_HALF_SUPPORT
cmsFloat32Number n = _cmsHalf2Float(*(cmsUInt16Number*)src);
*(cmsUInt16Number*)dst = _cmsQuickSaturateWord(n * 65535.0f);
*(cmsUInt16Number*)dst = _cmsQuickSaturateWord(n * 65535.0);
#else
cmsUNUSED_PARAMETER(dst);
cmsUNUSED_PARAMETER(src);
......@@ -268,7 +268,7 @@ void fromHLFto16SE(void* dst, const void* src)
{
#ifndef CMS_NO_HALF_SUPPORT
cmsFloat32Number n = _cmsHalf2Float(*(cmsUInt16Number*)src);
cmsUInt16Number i = _cmsQuickSaturateWord(n * 65535.0f);
cmsUInt16Number i = _cmsQuickSaturateWord(n * 65535.0);
*(cmsUInt16Number*)dst = CHANGE_ENDIAN(i);
#else
cmsUNUSED_PARAMETER(dst);
......@@ -414,9 +414,9 @@ void ComputeIncrementsForChunky(cmsUInt32Number Format,
cmsUInt32Number channelSize = trueBytesSize(Format);
cmsUInt32Number pixelSize = channelSize * total_chans;
// Sanity check
if (total_chans <= 0 || total_chans >= cmsMAXCHANNELS)
return;
// Sanity check
if (total_chans <= 0 || total_chans >= cmsMAXCHANNELS)
return;
memset(channels, 0, sizeof(channels));
......
//---------------------------------------------------------------------------------
//
// 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
// a copy of this software and associated documentation files (the "Software"),
......
//---------------------------------------------------------------------------------
//
// 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
// a copy of this software and associated documentation files (the "Software"),
......@@ -79,7 +79,7 @@ long int CMSEXPORT cmsfilelength(FILE* f)
// 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
// 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
// replace the optional mallocZero, calloc and dup as well.
......@@ -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
// 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)
static
_cmsSubAllocator_chunk* _cmsCreateSubAllocChunk(cmsContext ContextID, cmsUInt32Number Initial)
......
//---------------------------------------------------------------------------------
//
// 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
// a copy of this software and associated documentation files (the "Software"),
......@@ -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
// 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
static
cmsToneCurve* AllocateToneCurveStruct(cmsContext ContextID, cmsUInt32Number nEntries,
......@@ -507,28 +507,31 @@ cmsFloat64Number DefaultEvalParametricFn(cmsInt32Number Type, const cmsFloat64Nu
// X=Y/c | Y< (ad+b)^g
case -4:
{
if (fabs(Params[0]) < MATRIX_DET_TOLERANCE ||
fabs(Params[1]) < MATRIX_DET_TOLERANCE ||
fabs(Params[3]) < MATRIX_DET_TOLERANCE)
{
Val = 0;
}
e = Params[1] * Params[4] + Params[2];
if (e < 0)
disc = 0;
else
{
e = Params[1] * Params[4] + Params[2];
if (e < 0)
disc = 0;
else
disc = pow(e, Params[0]);
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];
}
else {
}
else {
if (fabs(Params[3]) < MATRIX_DET_TOLERANCE)
Val = 0;
else
Val = R / Params[3];
}
}
}
break;
......@@ -555,26 +558,29 @@ cmsFloat64Number DefaultEvalParametricFn(cmsInt32Number Type, const cmsFloat64Nu
// X=(Y-f)/c | else
case -5:
{
if (fabs(Params[1]) < MATRIX_DET_TOLERANCE ||
fabs(Params[3]) < MATRIX_DET_TOLERANCE)
{
Val = 0;
}
else
{
disc = Params[3] * Params[4] + Params[6];
if (R >= disc) {
disc = Params[3] * Params[4] + Params[6];
if (R >= disc) {
e = R - Params[5];
if (e < 0)
Val = 0;
else
{
if (fabs(Params[0]) < MATRIX_DET_TOLERANCE ||
fabs(Params[1]) < MATRIX_DET_TOLERANCE)
e = R - Params[5];
if (e < 0)
Val = 0;
else
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];
}
}
}
break;
......
//---------------------------------------------------------------------------------
//
// 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
// a copy of this software and associated documentation files (the "Software"),
......@@ -199,15 +199,15 @@ typedef struct {
cmsHTRANSFORM hInput; // From whatever input color space. 16 bits to DBL
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;
// 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.
#define ERR_THERESHOLD 5
#define ERR_THRESHOLD 5
static
......@@ -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 < t->Thereshold && dE2 < t->Thereshold)
if (dE1 < t->Threshold && dE2 < t->Threshold)
Out[0] = 0;
else {
// 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;
else
// dE1 is big and dE2 is small, clearly out of gamut
if (dE1 > t->Thereshold && dE2 < t->Thereshold)
Out[0] = (cmsUInt16Number) _cmsQuickFloor((dE1 - t->Thereshold) + .5);
if (dE1 > t->Threshold && dE2 < t->Threshold)
Out[0] = (cmsUInt16Number) _cmsQuickFloor((dE1 - t->Threshold) + .5);
else {
// 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
else
ErrorRatio = dE1 / dE2;
if (ErrorRatio > t->Thereshold)
Out[0] = (cmsUInt16Number) _cmsQuickFloor((ErrorRatio - t->Thereshold) + .5);
if (ErrorRatio > t->Threshold)
Out[0] = (cmsUInt16Number) _cmsQuickFloor((ErrorRatio - t->Threshold) + .5);
else
Out[0] = 0;
}
......@@ -323,10 +323,10 @@ cmsPipeline* _cmsCreateGamutCheckPipeline(cmsContext ContextID,
if (cmsIsMatrixShaper(hGamut)) {
Chain.Thereshold = 1.0;
Chain.Threshold = 1.0;
}
else {
Chain.Thereshold = ERR_THERESHOLD;
Chain.Threshold = ERR_THRESHOLD;
}
......@@ -588,3 +588,67 @@ cmsBool CMSEXPORT cmsDesaturateLab(cmsCIELab* Lab,
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
// 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
// a copy of this software and associated documentation files (the "Software"),
......
//---------------------------------------------------------------------------------
//
// 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
// a copy of this software and associated documentation files (the "Software"),
......@@ -200,8 +200,8 @@ void LinLerp1D(CMSREGISTER const cmsUInt16Number Value[],
int val3;
const cmsUInt16Number* LutTable = (cmsUInt16Number*) p ->Table;
// if last value...
if (Value[0] == 0xffff) {
// if last value or just one point
if (Value[0] == 0xffff || p->Domain[0] == 0) {
Output[0] = LutTable[p -> Domain[0]];
}
......@@ -240,7 +240,7 @@ void LinLerp1Dfloat(const cmsFloat32Number Value[],
val2 = fclamp(Value[0]);
// if last value...
if (val2 == 1.0) {
if (val2 == 1.0 || p->Domain[0] == 0) {
Output[0] = LutTable[p -> Domain[0]];
}
else
......@@ -274,20 +274,34 @@ void Eval1Input(CMSREGISTER const cmsUInt16Number Input[],
cmsUInt32Number OutChan;
const cmsUInt16Number* LutTable = (cmsUInt16Number*) p16 -> Table;
v = Input[0] * p16 -> Domain[0];
fk = _cmsToFixedDomain(v);
k0 = FIXED_TO_INT(fk);
rk = (cmsUInt16Number) FIXED_REST_TO_INT(fk);
// if last value...
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;
K1 = p16 -> opta[0] * k1;
K0 = p16->opta[0] * k0;
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[],
val2 = fclamp(Value[0]);
// 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++) {
Output[OutChan] = y0;
Output[OutChan] = LutTable[start + OutChan];
}
}
else
......
//---------------------------------------------------------------------------------
//
// 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
// a copy of this software and associated documentation files (the "Software"),
......@@ -479,16 +479,15 @@ cmsBool CMSEXPORT cmsCloseIOhandler(cmsIOHANDLER* io)
cmsIOHANDLER* CMSEXPORT cmsGetProfileIOhandler(cmsHPROFILE hProfile)
{
_cmsICCPROFILE* Icc = (_cmsICCPROFILE*)hProfile;
_cmsICCPROFILE* Icc = (_cmsICCPROFILE*)hProfile;
if (Icc == NULL) return NULL;
return Icc->IOhandler;
if (Icc == NULL) return NULL;
return Icc->IOhandler;
}
// Creates an empty structure holding all required parameters
cmsHPROFILE CMSEXPORT cmsCreateProfilePlaceholder(cmsContext ContextID)
{
time_t now = time(NULL);
_cmsICCPROFILE* Icc = (_cmsICCPROFILE*) _cmsMallocZero(ContextID, sizeof(_cmsICCPROFILE));
if (Icc == NULL) return NULL;
......@@ -499,15 +498,20 @@ cmsHPROFILE CMSEXPORT cmsCreateProfilePlaceholder(cmsContext ContextID)
// Set default version
Icc ->Version = 0x02100000;
// 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
Icc ->UsrMutex = _cmsCreateMutex(ContextID);
// Return the handle
return (cmsHPROFILE) Icc;
Error:
_cmsFree(ContextID, Icc);
return NULL;
}
cmsContext CMSEXPORT cmsGetProfileContextID(cmsHPROFILE hProfile)
......@@ -1430,7 +1434,25 @@ cmsBool CMSEXPORT cmsSaveProfileToMem(cmsHPROFILE hProfile, void *MemPtr, cmsUIn
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
cmsBool CMSEXPORT cmsCloseProfile(cmsHPROFILE hProfile)
......@@ -1450,20 +1472,7 @@ cmsBool CMSEXPORT cmsCloseProfile(cmsHPROFILE hProfile)
for (i=0; i < Icc -> TagCount; i++) {
if (Icc -> TagPtrs[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]);
}
freeOneTag(Icc, i);
}
if (Icc ->IOhandler != NULL) {
......@@ -1503,7 +1512,7 @@ cmsBool IsTypeSupported(cmsTagDescriptor* TagDescriptor, cmsTagTypeSignature Typ
void* CMSEXPORT cmsReadTag(cmsHPROFILE hProfile, cmsTagSignature sig)
{
_cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile;
cmsIOHANDLER* io = Icc ->IOhandler;
cmsIOHANDLER* io;
cmsTagTypeHandler* TypeHandler;
cmsTagTypeHandler LocalTypeHandler;
cmsTagDescriptor* TagDescriptor;
......@@ -1515,8 +1524,12 @@ void* CMSEXPORT cmsReadTag(cmsHPROFILE hProfile, cmsTagSignature sig)
if (!_cmsLockMutex(Icc->ContextID, Icc ->UsrMutex)) return NULL;
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 (Icc -> TagPtrs[n]) {
......@@ -1544,6 +1557,7 @@ void* CMSEXPORT cmsReadTag(cmsHPROFILE hProfile, cmsTagSignature sig)
if (TagSize < 8) goto Error;
io = Icc ->IOhandler;
// Seek to its location
if (!io -> Seek(io, Offset))
goto Error;
......@@ -1611,8 +1625,12 @@ void* CMSEXPORT cmsReadTag(cmsHPROFILE hProfile, cmsTagSignature sig)
return Icc -> TagPtrs[n];
// Return error and unlock tha data
// Return error and unlock the data
Error:
freeOneTag(Icc, n);
Icc->TagPtrs[n] = NULL;
_cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex);
return NULL;
}
......@@ -1778,7 +1796,7 @@ cmsUInt32Number CMSEXPORT cmsReadRawTag(cmsHPROFILE hProfile, cmsTagSignature si
// It is already read?
if (Icc -> TagPtrs[i] == NULL) {
// No yet, get original position
// Not yet, get original position
Offset = Icc ->TagOffsets[i];
TagSize = Icc ->TagSizes[i];
......
//---------------------------------------------------------------------------------
//
// 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
// a copy of this software and associated documentation files (the "Software"),
......@@ -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
cmsPipeline* _cmsReadFloatInputTag(cmsHPROFILE hProfile, cmsTagSignature tagFloat)
{
......@@ -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
cmsPipeline* _cmsReadFloatOutputTag(cmsHPROFILE hProfile, cmsTagSignature tagFloat)
{
......@@ -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
cmsPipeline* _cmsReadFloatDevicelinkTag(cmsHPROFILE hProfile, cmsTagSignature tagFloat)
{
......
//---------------------------------------------------------------------------------
//
// 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
// a copy of this software and associated documentation files (the "Software"),
......@@ -1226,6 +1226,11 @@ void* CMSEXPORT cmsStageData(const cmsStage* mpe)
return mpe -> Data;
}
cmsContext CMSEXPORT cmsGetStageContextID(const cmsStage* mpe)
{
return mpe -> ContextID;
}
cmsStage* CMSEXPORT cmsStageNext(const cmsStage* mpe)
{
return mpe -> Next;
......
//---------------------------------------------------------------------------------
//
// 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
// a copy of this software and associated documentation files (the "Software"),
......
//---------------------------------------------------------------------------------
//
// 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
// a copy of this software and associated documentation files (the "Software"),
......@@ -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)
// 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)
{
cmsUInt32Number i, len = (cmsUInt32Number) strlen(ASCIIString);
......@@ -641,7 +641,7 @@ cmsUInt32Number CMSEXPORT cmsNamedColorCount(const cmsNAMEDCOLORLIST* NamedColor
return NamedColorList ->nColors;
}
// Info aboout a given color
// Info about a given color
cmsBool CMSEXPORT cmsNamedColorInfo(const cmsNAMEDCOLORLIST* NamedColorList, cmsUInt32Number nColor,
char* Name,
char* Prefix,
......
//---------------------------------------------------------------------------------
//
// 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
// a copy of this software and associated documentation files (the "Software"),
......@@ -647,7 +647,6 @@ cmsBool OptimizeByResampling(cmsPipeline** Lut, cmsUInt32Number Intent, cmsUInt3
{
cmsPipeline* Src = NULL;
cmsPipeline* Dest = NULL;
cmsStage* mpe;
cmsStage* CLUT;
cmsStage *KeepPreLin = NULL, *KeepPostLin = NULL;
cmsUInt32Number nGridPoints;
......@@ -669,7 +668,7 @@ cmsBool OptimizeByResampling(cmsPipeline** Lut, cmsUInt32Number Intent, cmsUInt3
if (ColorSpace == (cmsColorSpaceSignature)0 ||
OutputColorSpace == (cmsColorSpaceSignature)0) return FALSE;
nGridPoints = _cmsReasonableGridpointsByColorspace(ColorSpace, *dwFlags);
nGridPoints = _cmsReasonableGridpointsByColorspace(ColorSpace, *dwFlags);
// For empty LUTs, 2 points are enough
if (cmsPipelineStageCount(*Lut) == 0)
......@@ -677,13 +676,6 @@ cmsBool OptimizeByResampling(cmsPipeline** Lut, cmsUInt32Number Intent, cmsUInt3
Src = *Lut;
// Named color pipelines cannot be optimized either
for (mpe = cmsPipelineGetPtrToFirstStage(Src);
mpe != NULL;
mpe = cmsStageNext(mpe)) {
if (cmsStageType(mpe) == cmsSigNamedColorElemType) return FALSE;
}
// Allocate an empty LUT
Dest = cmsPipelineAlloc(Src ->ContextID, Src ->InputChannels, Src ->OutputChannels);
if (!Dest) return FALSE;
......@@ -1051,7 +1043,6 @@ cmsBool OptimizeByComputingLinearization(cmsPipeline** Lut, cmsUInt32Number Inte
cmsStage* OptimizedCLUTmpe;
cmsColorSpaceSignature ColorSpace, OutputColorSpace;
cmsStage* OptimizedPrelinMpe;
cmsStage* mpe;
cmsToneCurve** OptimizedPrelinCurves;
_cmsStageCLutData* OptimizedPrelinCLUT;
......@@ -1072,14 +1063,7 @@ cmsBool OptimizeByComputingLinearization(cmsPipeline** Lut, cmsUInt32Number Inte
}
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));
OutputColorSpace = _cmsICCcolorSpace((int) T_COLORSPACE(*OutputFormat));
......@@ -1918,6 +1902,7 @@ cmsBool CMSEXPORT _cmsOptimizePipeline(cmsContext ContextID,
_cmsOptimizationPluginChunkType* ctx = ( _cmsOptimizationPluginChunkType*) _cmsContextGetClientChunk(ContextID, OptimizationPlugin);
_cmsOptimizationCollection* Opts;
cmsBool AnySuccess = FALSE;
cmsStage* mpe;
// A CLUT is being asked, so force this specific optimization
if (*dwFlags & cmsFLAGS_FORCE_CLUT) {
......@@ -1932,6 +1917,13 @@ cmsBool CMSEXPORT _cmsOptimizePipeline(cmsContext ContextID,
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.
AnySuccess = PreOptimize(*PtrLut);
......
//---------------------------------------------------------------------------------
//
// 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
// a copy of this software and associated documentation files (the "Software"),
......
//---------------------------------------------------------------------------------
//
// 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
// a copy of this software and associated documentation files (the "Software"),
......@@ -671,17 +671,65 @@ static struct _cmsContext_struct globalContext = {
static _cmsMutex _cmsContextPoolHeadMutex = CMS_MUTEX_INITIALIZER;
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.
struct _cmsContext_struct* _cmsGetContext(cmsContext ContextID)
{
struct _cmsContext_struct* id = (struct _cmsContext_struct*) ContextID;
struct _cmsContext_struct* ctx;
// On 0, use global settings
if (id == NULL)
return &globalContext;
InitContextMutex();
// Search
_cmsEnterCriticalSectionPrimitive(&_cmsContextPoolHeadMutex);
......@@ -784,31 +832,7 @@ cmsContext CMSEXPORT cmsCreateContext(void* Plugin, void* UserData)
struct _cmsContext_struct* ctx;
struct _cmsContext_struct fakeContext;
// 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 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
if (!InitContextMutex()) return NULL;
_cmsInstallAllocFunctions(_cmsFindMemoryPlugin(Plugin), &fakeContext.DefaultMemoryManager);
......@@ -884,6 +908,8 @@ cmsContext CMSEXPORT cmsDupContext(cmsContext ContextID, void* NewUserData)
if (ctx == NULL)
return NULL; // Something very wrong happened
if (!InitContextMutex()) return NULL;
// Setup default memory allocators
memcpy(&ctx->DefaultMemoryManager, &src->DefaultMemoryManager, sizeof(ctx->DefaultMemoryManager));
......@@ -943,6 +969,9 @@ void CMSEXPORT cmsDeleteContext(cmsContext ContextID)
struct _cmsContext_struct fakeContext;
struct _cmsContext_struct* prev;
InitContextMutex();
memcpy(&fakeContext.DefaultMemoryManager, &ctx->DefaultMemoryManager, sizeof(ctx->DefaultMemoryManager));
fakeContext.chunks[UserPtr] = ctx ->chunks[UserPtr];
......@@ -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
// 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
// a copy of this software and associated documentation files (the "Software"),
......
//---------------------------------------------------------------------------------
//
// 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
// a copy of this software and associated documentation files (the "Software"),
......@@ -368,7 +368,7 @@ int InkLimitingSampler(CMSREGISTER const cmsUInt16Number In[], CMSREGISTER cmsUI
InkLimit = (InkLimit * 655.35);
SumCMY = In[0] + In[1] + In[2];
SumCMY = (cmsFloat64Number) In[0] + In[1] + In[2];
SumCMYK = SumCMY + In[3];
if (SumCMYK > InkLimit) {
......
//---------------------------------------------------------------------------------
//
// 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
// a copy of this software and associated documentation files (the "Software"),
......@@ -264,16 +264,16 @@ cmsBool _cmsAdaptMatrixToD50(cmsMAT3* r, const cmsCIExyY* SourceWhitePt)
// 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
// 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.
//
// the alghoritm:
// the algorithm:
//
// - First I build the absolute conversion matrix using
// primaries in XYZ. This matrix is next inverted
// - Then I eval the source white point across this matrix
// obtaining the coeficients of the transformation
// - Then, I apply these coeficients to the original matrix
// obtaining the coefficients of the transformation
// - Then, I apply these coefficients to the original matrix
//
cmsBool _cmsBuildRGB2XYZtransferMatrix(cmsMAT3* r, const cmsCIExyY* WhitePt, const cmsCIExyYTRIPLE* Primrs)
{
......
//---------------------------------------------------------------------------------
//
// 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
// a copy of this software and associated documentation files (the "Software"),
......@@ -284,7 +284,7 @@ void FloatXFORM(_cmsTRANSFORM* p,
accum = p->FromInputFloat(p, fIn, accum, Stride->BytesPerPlaneIn);
// Any gamut chack to do?
// Any gamut check to do?
if (p->GamutCheck != NULL) {
// Evaluate gamut marker.
......@@ -846,7 +846,7 @@ _cmsTRANSFORM* AllocEmptyTransform(cmsContext ContextID, cmsPipeline* lut,
}
// 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.
p ->FromInputFloat = _cmsGetFormatter(ContextID, *InputFormat, cmsFormatterInput, CMS_PACK_FLAGS_FLOAT).FmtFloat;
......@@ -1081,6 +1081,15 @@ cmsHTRANSFORM CMSEXPORT cmsCreateExtendedTransform(cmsContext ContextID,
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
Lut = _cmsLinkProfiles(ContextID, nProfiles, Intents, hProfiles, BPC, AdaptationStates, dwFlags);
if (Lut == NULL) {
......
//
// 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
// a copy of this software and associated documentation files (the "Software"),
......@@ -1118,5 +1118,8 @@ cmsBool _cmsAdaptationMatrix(cmsMAT3* r, const cmsMAT3* ConeMatrix, const cmsC
cmsBool _cmsBuildRGB2XYZtransferMatrix(cmsMAT3* r, const cmsCIExyY* WhitePoint, const cmsCIExyYTRIPLE* Primaries);
// thread-safe gettime
cmsBool _cmsGetTime(struct tm* ptr_time);
#define _lcms_internal_H
#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