summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarti Maria <marti.maria@littlecms.com>2021-06-20 19:43:03 +0200
committerMarti Maria <marti.maria@littlecms.com>2021-06-20 19:43:03 +0200
commit6b04ee0bab3ebe6f2c487195bac7b86efadd58d3 (patch)
tree6361af079f5ebbebd5e0e8e6c19efa183e010b69
parent8564c9b4fbf07d23062bbbbd87d5eb10dd92073f (diff)
downloadlcms2-6b04ee0bab3ebe6f2c487195bac7b86efadd58d3.tar.gz
Add automatic linear space detection
- Added a function to estimate gamma space of RGB profiles (only a subset). This function is still undocumented. - Lcms now automatically turns off optimizations when 16-bit on RGB and input linear space is found.
-rw-r--r--include/lcms2.h2
-rw-r--r--plugins/fast_float/src/fast_16_tethra.c10
-rw-r--r--plugins/fast_float/src/fast_8_tethra.c10
-rw-r--r--plugins/fast_float/src/fast_float_cmyk.c10
-rw-r--r--plugins/fast_float/src/fast_float_lab.c10
-rw-r--r--plugins/fast_float/src/fast_float_tethra.c10
-rw-r--r--src/cmsgmt.c66
-rw-r--r--src/cmsopt.c28
-rw-r--r--src/cmsxform.c9
-rw-r--r--src/lcms2.def1
-rw-r--r--testbed/testcms2.c112
-rw-r--r--utils/delphi/lcms2dll.pas7
12 files changed, 207 insertions, 68 deletions
diff --git a/include/lcms2.h b/include/lcms2.h
index c748e51..61e2ab3 100644
--- a/include/lcms2.h
+++ b/include/lcms2.h
@@ -1907,6 +1907,8 @@ CMSAPI cmsBool CMSEXPORT cmsDetectDestinationBlackPoint(cmsCIEXYZ* Blac
// Estimate total area coverage
CMSAPI cmsFloat64Number CMSEXPORT cmsDetectTAC(cmsHPROFILE hProfile);
+// Estimate gamma space, alwasys positive. Returns -1 on error.
+CMSAPI cmsFloat64Number CMSEXPORT cmsDetectRGBProfileGamma(cmsHPROFILE hProfile, cmsFloat64Number thereshold);
// Poor man's gamut mapping
CMSAPI cmsBool CMSEXPORT cmsDesaturateLab(cmsCIELab* Lab,
diff --git a/plugins/fast_float/src/fast_16_tethra.c b/plugins/fast_float/src/fast_16_tethra.c
index aad207f..d76c65a 100644
--- a/plugins/fast_float/src/fast_16_tethra.c
+++ b/plugins/fast_float/src/fast_16_tethra.c
@@ -317,7 +317,6 @@ cmsBool Optimize16BitRGBTransform(_cmsTransform2Fn* TransformFn,
cmsUInt32Number* OutputFormat,
cmsUInt32Number* dwFlags)
{
- cmsStage* mpe;
Performance16Data* p16;
cmsContext ContextID;
_cmsStageCLutData* data;
@@ -353,14 +352,7 @@ cmsBool Optimize16BitRGBTransform(_cmsTransform2Fn* TransformFn,
cmsSigCurveSetElemType, cmsSigCurveSetElemType,
NULL, NULL)) return FALSE;
-
- // Named color pipelines cannot be optimized either
- for (mpe = cmsPipelineGetPtrToFirstStage(*Lut);
- mpe != NULL;
- mpe = cmsStageNext(mpe)) {
- if (cmsStageType(mpe) == cmsSigNamedColorElemType) return FALSE;
- }
-
+
ContextID = cmsGetPipelineContextID(*Lut);
newFlags = *dwFlags | cmsFLAGS_FORCE_CLUT;
diff --git a/plugins/fast_float/src/fast_8_tethra.c b/plugins/fast_float/src/fast_8_tethra.c
index 26a5a5d..9a724a6 100644
--- a/plugins/fast_float/src/fast_8_tethra.c
+++ b/plugins/fast_float/src/fast_8_tethra.c
@@ -346,7 +346,6 @@ cmsBool Optimize8BitRGBTransform(_cmsTransform2Fn* TransformFn,
cmsPipeline* OptimizedLUT = NULL, *LutPlusCurves = NULL;
cmsStage* OptimizedCLUTmpe;
cmsStage* OptimizedPrelinMpe;
- cmsStage* mpe;
Performance8Data* p8;
cmsUInt16Number* MyTable[3];
cmsContext ContextID;
@@ -365,14 +364,7 @@ cmsBool Optimize8BitRGBTransform(_cmsTransform2Fn* TransformFn,
if (T_COLORSPACE(*InputFormat) != PT_RGB) return FALSE;
OriginalLut = *Lut;
-
- // Named color pipelines cannot be optimized either
- for (mpe = cmsPipelineGetPtrToFirstStage(OriginalLut);
- mpe != NULL;
- mpe = cmsStageNext(mpe)) {
- if (cmsStageType(mpe) == cmsSigNamedColorElemType) return FALSE;
- }
-
+
ContextID = cmsGetPipelineContextID(OriginalLut);
nGridPoints = _cmsReasonableGridpointsByColorspace(cmsSigRgbData, *dwFlags);
diff --git a/plugins/fast_float/src/fast_float_cmyk.c b/plugins/fast_float/src/fast_float_cmyk.c
index d4a8261..a0a23de 100644
--- a/plugins/fast_float/src/fast_float_cmyk.c
+++ b/plugins/fast_float/src/fast_float_cmyk.c
@@ -331,7 +331,6 @@ cmsBool OptimizeCLUTCMYKTransform(_cmsTransform2Fn* TransformFn,
int nGridPoints;
cmsPipeline* OptimizedLUT = NULL;
cmsStage* OptimizedCLUTmpe;
- cmsStage* mpe;
FloatCMYKData* pcmyk;
cmsContext ContextID;
_cmsStageCLutData* data;
@@ -349,14 +348,7 @@ cmsBool OptimizeCLUTCMYKTransform(_cmsTransform2Fn* TransformFn,
if (T_COLORSPACE(*InputFormat) != PT_CMYK) return FALSE;
OriginalLut = *Lut;
-
- // Named color pipelines cannot be optimized either
- for (mpe = cmsPipelineGetPtrToFirstStage(OriginalLut);
- mpe != NULL;
- mpe = cmsStageNext(mpe)) {
- if (cmsStageType(mpe) == cmsSigNamedColorElemType) return FALSE;
- }
-
+
ContextID = cmsGetPipelineContextID(OriginalLut);
nGridPoints = _cmsReasonableGridpointsByColorspace(cmsSigRgbData, *dwFlags);
diff --git a/plugins/fast_float/src/fast_float_lab.c b/plugins/fast_float/src/fast_float_lab.c
index d392a84..2f31d7d 100644
--- a/plugins/fast_float/src/fast_float_lab.c
+++ b/plugins/fast_float/src/fast_float_lab.c
@@ -369,7 +369,6 @@ cmsBool OptimizeCLUTLabTransform(_cmsTransform2Fn* TransformFn,
int nGridPoints;
cmsPipeline* OptimizedLUT = NULL;
cmsStage* OptimizedCLUTmpe;
- cmsStage* mpe;
LabCLUTdata* pfloat;
cmsContext ContextID;
_cmsStageCLutData* data;
@@ -389,14 +388,7 @@ cmsBool OptimizeCLUTLabTransform(_cmsTransform2Fn* TransformFn,
if (T_COLORSPACE(*InputFormat) != PT_Lab) return FALSE;
OriginalLut = *Lut;
-
- // Named color pipelines cannot be optimized either
- for (mpe = cmsPipelineGetPtrToFirstStage(OriginalLut);
- mpe != NULL;
- mpe = cmsStageNext(mpe)) {
- if (cmsStageType(mpe) == cmsSigNamedColorElemType) return FALSE;
- }
-
+
ContextID = cmsGetPipelineContextID(OriginalLut);
nGridPoints = GetGridpoints(*dwFlags);
diff --git a/plugins/fast_float/src/fast_float_tethra.c b/plugins/fast_float/src/fast_float_tethra.c
index 0e3015a..29ebde5 100644
--- a/plugins/fast_float/src/fast_float_tethra.c
+++ b/plugins/fast_float/src/fast_float_tethra.c
@@ -239,7 +239,6 @@ cmsBool OptimizeCLUTRGBTransform(_cmsTransform2Fn* TransformFn,
int nGridPoints;
cmsPipeline* OptimizedLUT = NULL;
cmsStage* OptimizedCLUTmpe;
- cmsStage* mpe;
FloatCLUTData* pfloat;
cmsContext ContextID;
_cmsStageCLutData* data;
@@ -258,14 +257,7 @@ cmsBool OptimizeCLUTRGBTransform(_cmsTransform2Fn* TransformFn,
if (T_COLORSPACE(*InputFormat) != PT_RGB) return FALSE;
OriginalLut = *Lut;
-
- // Named color pipelines cannot be optimized either
- for (mpe = cmsPipelineGetPtrToFirstStage(OriginalLut);
- mpe != NULL;
- mpe = cmsStageNext(mpe)) {
- if (cmsStageType(mpe) == cmsSigNamedColorElemType) return FALSE;
- }
-
+
ContextID = cmsGetPipelineContextID(OriginalLut);
nGridPoints = _cmsReasonableGridpointsByColorspace(cmsSigRgbData, *dwFlags);
diff --git a/src/cmsgmt.c b/src/cmsgmt.c
index 75904e4..f28e251 100644
--- a/src/cmsgmt.c
+++ b/src/cmsgmt.c
@@ -1,7 +1,7 @@
//---------------------------------------------------------------------------------
//
// 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"),
@@ -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 algorith 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 thereshold)
+{
+ 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, thereshold);
+
+ cmsFreeToneCurve(Y_curve);
+
+ return gamma;
+}
+
diff --git a/src/cmsopt.c b/src/cmsopt.c
index c760551..56cdf29 100644
--- a/src/cmsopt.c
+++ b/src/cmsopt.c
@@ -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);
diff --git a/src/cmsxform.c b/src/cmsxform.c
index 9d182e1..ac7792a 100644
--- a/src/cmsxform.c
+++ b/src/cmsxform.c
@@ -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) {
diff --git a/src/lcms2.def b/src/lcms2.def
index a60f1b0..b03943c 100644
--- a/src/lcms2.def
+++ b/src/lcms2.def
@@ -364,4 +364,5 @@ cmsMD5alloc = cmsMD5alloc
cmsMD5finish = cmsMD5finish
_cmsComputeInterpParams = _cmsComputeInterpParams
cmsGetToneCurveParams = cmsGetToneCurveParams
+cmsDetectRGBProfileGamma = cmsDetectRGBProfileGamma
diff --git a/testbed/testcms2.c b/testbed/testcms2.c
index aad8656..0355fd5 100644
--- a/testbed/testcms2.c
+++ b/testbed/testcms2.c
@@ -1,7 +1,7 @@
//---------------------------------------------------------------------------------
//
// 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"),
@@ -8318,6 +8318,113 @@ int Check_sRGB_Rountrips(void)
return 1;
}
+static
+cmsHPROFILE createRgbGamma(cmsFloat64Number g)
+{
+ cmsCIExyY D65 = { 0.3127, 0.3290, 1.0 };
+ cmsCIExyYTRIPLE Rec709Primaries = {
+ {0.6400, 0.3300, 1.0},
+ {0.3000, 0.6000, 1.0},
+ {0.1500, 0.0600, 1.0}
+ };
+ cmsToneCurve* Gamma[3];
+ cmsHPROFILE hRGB;
+
+ Gamma[0] = Gamma[1] = Gamma[2] = cmsBuildGamma(0, g);
+ if (Gamma[0] == NULL) return NULL;
+
+ hRGB = cmsCreateRGBProfile(&D65, &Rec709Primaries, Gamma);
+ cmsFreeToneCurve(Gamma[0]);
+ return hRGB;
+}
+
+
+static
+int CheckGammaSpaceDetection(void)
+{
+ cmsFloat64Number i;
+
+ for (i = 0.5; i < 3; i += 0.1)
+ {
+ cmsHPROFILE hProfile = createRgbGamma(i);
+
+ cmsFloat64Number gamma = cmsDetectRGBProfileGamma(hProfile, 0.01);
+
+ cmsCloseProfile(hProfile);
+
+ if (fabs(gamma - i) > 0.1)
+ {
+ Fail("Failed profile gamma detection of %f (got %f)", i, gamma);
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+
+#if 0
+
+// You need to download folowing profilies to execute this test: sRGB-elle-V4-srgbtrc.icc, sRGB-elle-V4-g10.icc
+// The include this line in the checks list: Check("KInear spaces detection", CheckLinearSpacesOptimization);
+static
+void uint16toFloat(cmsUInt16Number* src, cmsFloat32Number* dst)
+{
+ for (int i = 0; i < 3; i++) {
+ dst[i] = src[i] / 65535.f;
+ }
+}
+
+static
+int CheckLinearSpacesOptimization(void)
+{
+ cmsHPROFILE lcms_sRGB = cmsCreate_sRGBProfile();
+ cmsHPROFILE elle_sRGB = cmsOpenProfileFromFile("sRGB-elle-V4-srgbtrc.icc", "r");
+ cmsHPROFILE elle_linear = cmsOpenProfileFromFile("sRGB-elle-V4-g10.icc", "r");
+ cmsHTRANSFORM transform1 = cmsCreateTransform(elle_sRGB, TYPE_RGB_16, elle_linear, TYPE_RGB_16, INTENT_RELATIVE_COLORIMETRIC, 0);
+ cmsHTRANSFORM transform2 = cmsCreateTransform(elle_linear, TYPE_RGB_16, lcms_sRGB, TYPE_RGB_16, INTENT_RELATIVE_COLORIMETRIC, 0);
+ cmsHTRANSFORM transform2a = cmsCreateTransform(elle_linear, TYPE_RGB_FLT, lcms_sRGB, TYPE_RGB_16, INTENT_RELATIVE_COLORIMETRIC, 0);
+
+ cmsUInt16Number sourceCol[3] = { 43 * 257, 27 * 257, 6 * 257 };
+ cmsUInt16Number linearCol[3] = { 0 };
+ float linearColF[3] = { 0 };
+ cmsUInt16Number finalCol[3] = { 0 };
+ int difR, difG, difB;
+ int difR2, difG2, difB2;
+
+ cmsDoTransform(transform1, sourceCol, linearCol, 1);
+ cmsDoTransform(transform2, linearCol, finalCol, 1);
+
+ cmsCloseProfile(lcms_sRGB); cmsCloseProfile(elle_sRGB); cmsCloseProfile(elle_linear);
+
+
+ difR = (int)sourceCol[0] - finalCol[0];
+ difG = (int)sourceCol[1] - finalCol[1];
+ difB = (int)sourceCol[2] - finalCol[2];
+
+
+ uint16toFloat(linearCol, linearColF);
+ cmsDoTransform(transform2a, linearColF, finalCol, 1);
+
+ difR2 = (int)sourceCol[0] - finalCol[0];
+ difG2 = (int)sourceCol[1] - finalCol[1];
+ difB2 = (int)sourceCol[2] - finalCol[2];
+
+ cmsDeleteTransform(transform1);
+ cmsDeleteTransform(transform2);
+ cmsDeleteTransform(transform2a);
+
+ if (abs(difR2 - difR) > 5 || abs(difG2 - difG) > 5 || abs(difB2 - difB) > 5)
+ {
+ Fail("Linear detection failed");
+ return 0;
+ }
+
+ return 1;
+}
+#endif
+
+
// --------------------------------------------------------------------------------------------------
// P E R F O R M A N C E C H E C K S
// --------------------------------------------------------------------------------------------------
@@ -9049,7 +9156,7 @@ int main(int argc, char* argv[])
printf("Installing error logger ... ");
cmsSetLogErrorHandler(FatalErrorQuit);
printf("done.\n");
-
+
PrintSupportedIntents();
Check("Base types", CheckBaseTypes);
@@ -9254,6 +9361,7 @@ int main(int argc, char* argv[])
Check("Proofing intersection", CheckProofingIntersection);
Check("Empty MLUC", CheckEmptyMLUC);
Check("sRGB round-trips", Check_sRGB_Rountrips);
+ Check("Gamma space detection", CheckGammaSpaceDetection);
}
if (DoPluginTests)
diff --git a/utils/delphi/lcms2dll.pas b/utils/delphi/lcms2dll.pas
index 9af7a0d..9368fc9 100644
--- a/utils/delphi/lcms2dll.pas
+++ b/utils/delphi/lcms2dll.pas
@@ -3,7 +3,7 @@
//---------------------------------------------------------------------------------
//
// Little Color Management System
-// Copyright (c) 1998-2014 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"),
@@ -25,7 +25,7 @@
//
//---------------------------------------------------------------------------------
//
-// Version 2.6
+// Version 2.13
//
UNIT lcms2dll;
@@ -1659,6 +1659,9 @@ FUNCTION cmsDetectDestinationBlackPoint( BlackPoint: LPcmsCIEXYZ; hProfile: cmsH
// Estimate total area coverage
FUNCTION cmsDetectTAC(hProfile: cmsHPROFILE): cmsFloat64Number; StdCall;
+// Estimate profile gamma
+FUNCTION cmsDetectRGBProfileGamma(hProfile: cmsHPROFILE): cmsFloat64Number; StdCall;
+
// Poor man's gamut mapping
FUNCTION cmsDesaturateLab(Lab: LPcmsCIELab; amax, amin, bmax, bmin: cmsFloat64Number): cmsBool; StdCall;