summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarti Maria <info@littlecms.com>2012-05-19 17:07:51 +0200
committerMarti Maria <info@littlecms.com>2012-05-19 17:07:51 +0200
commit9fc6a31f69d199fe57593927890ef0cb227d5e37 (patch)
tree91571ef58c54c7a7cc6922591f7cd4d3d6b1789a
parentb6153c3b5b35db07243625933203566eb0b243fd (diff)
downloadlcms2-9fc6a31f69d199fe57593927890ef0cb227d5e37.tar.gz
Sync with development sources, See Change Log
-rw-r--r--ChangeLog12
-rw-r--r--include/lcms2.h23
-rw-r--r--include/lcms2_plugin.h66
-rw-r--r--src/cmscgats.c33
-rw-r--r--src/cmsgamma.c35
-rw-r--r--src/cmslut.c15
-rw-r--r--src/cmsopt.c10
-rw-r--r--src/cmspack.c81
-rw-r--r--src/cmsplugin.c5
-rw-r--r--src/cmssamp.c4
-rw-r--r--src/cmsvirt.c10
-rw-r--r--src/cmsxform.c183
-rw-r--r--src/lcms2.def10
-rw-r--r--src/lcms2_internal.h53
-rw-r--r--testbed/testcms2.c113
15 files changed, 471 insertions, 182 deletions
diff --git a/ChangeLog b/ChangeLog
index 394a3b8..5fbcadf 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -59,6 +59,16 @@ Added compatibilty with Argyll's CGATS parser
Fixed a bug in the named color devicelink generation
Fixed uint64 to work in systems without long long native type
-Added performance improvements from several contributors, mostly artifex
+Added performance improvements from several contributors, mostly Artifex
Fixed a bug in black preservation checking
Added black point detection algorithm from Adobe paper
+Added support for transforms on planar data with different stride
+Added a new plug in entry for full transform
+Exposed internal overview table for tone curves
+gamma 1.0 can now operate in unbounded mode
+Fixed a bug in pipeline duplication
+Added getPipelineContextID
+Added a new plug-in type
+Internal stage structs are now accessible through plug-in API
+Fixed a bug on ending zero when saving a IT8 to memory
+Fixed a bug on IT8 reading of negative numbers.
diff --git a/include/lcms2.h b/include/lcms2.h
index 11965eb..f44c598 100644
--- a/include/lcms2.h
+++ b/include/lcms2.h
@@ -23,7 +23,7 @@
//
//---------------------------------------------------------------------------------
//
-// Version 2.3
+// Version 2.4
//
#ifndef _lcms2_H
@@ -69,7 +69,7 @@ extern "C" {
#endif
// Version/release
-#define LCMS_VERSION 2030
+#define LCMS_VERSION 2040
// I will give the chance of redefining basic types for compilers that are not fully C99 compliant
#ifndef CMS_BASIC_TYPES_ALREADY_DEFINED
@@ -722,14 +722,17 @@ typedef void* cmsHTRANSFORM;
#define TYPE_RGBA_16_SE (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(2)|ENDIAN16_SH(1))
#define TYPE_ARGB_8 (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(1)|SWAPFIRST_SH(1))
+#define TYPE_ARGB_8_PLANAR (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(1)|SWAPFIRST_SH(1)|PLANAR_SH(1))
#define TYPE_ARGB_16 (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(2)|SWAPFIRST_SH(1))
#define TYPE_ABGR_8 (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(1)|DOSWAP_SH(1))
+#define TYPE_ABGR_8_PLANAR (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(1)|DOSWAP_SH(1)|PLANAR_SH(1))
#define TYPE_ABGR_16 (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(2)|DOSWAP_SH(1))
#define TYPE_ABGR_16_PLANAR (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(2)|DOSWAP_SH(1)|PLANAR_SH(1))
#define TYPE_ABGR_16_SE (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(2)|DOSWAP_SH(1)|ENDIAN16_SH(1))
#define TYPE_BGRA_8 (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(1)|DOSWAP_SH(1)|SWAPFIRST_SH(1))
+#define TYPE_BGRA_8_PLANAR (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(1)|DOSWAP_SH(1)|SWAPFIRST_SH(1)|PLANAR_SH(1))
#define TYPE_BGRA_16 (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(2)|DOSWAP_SH(1)|SWAPFIRST_SH(1))
#define TYPE_BGRA_16_SE (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(2)|ENDIAN16_SH(1)|SWAPFIRST_SH(1))
@@ -1098,6 +1101,10 @@ CMSAPI cmsBool CMSEXPORT cmsIsToneCurveDescending(const cmsToneCurve*
CMSAPI cmsInt32Number CMSEXPORT cmsGetToneCurveParametricType(const cmsToneCurve* t);
CMSAPI cmsFloat64Number CMSEXPORT cmsEstimateGamma(const cmsToneCurve* t, cmsFloat64Number Precision);
+// Tone curve tabular estimation
+CMSAPI cmsUInt32Number CMSEXPORT cmsGetToneCurveEstimatedTableEntries(const cmsToneCurve* t);
+CMSAPI const cmsUInt16Number* CMSEXPORT cmsGetToneCurveEstimatedTable(const cmsToneCurve* t);
+
// Implements pipelines of multi-processing elements -------------------------------------------------------------
@@ -1110,6 +1117,7 @@ CMSAPI cmsPipeline* CMSEXPORT cmsPipelineAlloc(cmsContext ContextID, cmsUIn
CMSAPI void CMSEXPORT cmsPipelineFree(cmsPipeline* lut);
CMSAPI cmsPipeline* CMSEXPORT cmsPipelineDup(const cmsPipeline* Orig);
+CMSAPI cmsContext CMSEXPORT cmsGetPipelineContextID(const cmsPipeline* lut);
CMSAPI cmsUInt32Number CMSEXPORT cmsPipelineInputChannels(const cmsPipeline* lut);
CMSAPI cmsUInt32Number CMSEXPORT cmsPipelineOutputChannels(const cmsPipeline* lut);
@@ -1170,10 +1178,9 @@ typedef cmsInt32Number (* cmsSAMPLERFLOAT)(register const cmsFloat32Number In[],
#define SAMPLER_INSPECT 0x01000000
// For CLUT only
-CMSAPI cmsBool CMSEXPORT cmsStageSampleCLut16bit(cmsStage* mpe, cmsSAMPLER16 Sampler, void* Cargo, cmsUInt32Number dwFlags);
+CMSAPI cmsBool CMSEXPORT cmsStageSampleCLut16bit(cmsStage* mpe, cmsSAMPLER16 Sampler, void* Cargo, cmsUInt32Number dwFlags);
CMSAPI cmsBool CMSEXPORT cmsStageSampleCLutFloat(cmsStage* mpe, cmsSAMPLERFLOAT Sampler, void* Cargo, cmsUInt32Number dwFlags);
-
// Slicers
CMSAPI cmsBool CMSEXPORT cmsSliceSpace16(cmsUInt32Number nInputs, const cmsUInt32Number clutPoints[],
cmsSAMPLER16 Sampler, void * Cargo);
@@ -1283,6 +1290,7 @@ CMSAPI cmsNAMEDCOLORLIST* CMSEXPORT cmsGetNamedColorList(cmsHTRANSFORM xform);
// Profile sequence descriptor. Some fields come from profile sequence descriptor tag, others
// come from Profile Sequence Identifier Tag
typedef struct {
+
cmsSignature deviceMfg;
cmsSignature deviceModel;
cmsUInt64Number attributes;
@@ -1634,6 +1642,13 @@ CMSAPI void CMSEXPORT cmsDoTransform(cmsHTRANSFORM Transform,
void * OutputBuffer,
cmsUInt32Number Size);
+CMSAPI void CMSEXPORT cmsDoTransformStride(cmsHTRANSFORM Transform,
+ const void * InputBuffer,
+ void * OutputBuffer,
+ cmsUInt32Number Size,
+ cmsUInt32Number Stride);
+
+
CMSAPI void CMSEXPORT cmsSetAlarmCodes(cmsUInt16Number NewAlarm[cmsMAXCHANNELS]);
CMSAPI void CMSEXPORT cmsGetAlarmCodes(cmsUInt16Number NewAlarm[cmsMAXCHANNELS]);
diff --git a/include/lcms2_plugin.h b/include/lcms2_plugin.h
index 34e9af2..c2fa5bf 100644
--- a/include/lcms2_plugin.h
+++ b/include/lcms2_plugin.h
@@ -181,7 +181,6 @@ CMSAPI cmsS15Fixed16Number CMSEXPORT _cmsDoubleTo15Fixed16(cmsFloat64Number v);
CMSAPI void CMSEXPORT _cmsEncodeDateTimeNumber(cmsDateTimeNumber *Dest, const struct tm *Source);
CMSAPI void CMSEXPORT _cmsDecodeDateTimeNumber(const cmsDateTimeNumber *Source, struct tm *Dest);
-
//----------------------------------------------------------------------------------------------------------
// Plug-in foundation
@@ -196,6 +195,7 @@ CMSAPI void CMSEXPORT _cmsDecodeDateTimeNumber(const cmsDateTimeN
#define cmsPluginRenderingIntentSig 0x696E7448 // 'intH'
#define cmsPluginMultiProcessElementSig 0x6D706548 // 'mpeH'
#define cmsPluginOptimizationSig 0x6F707448 // 'optH'
+#define cmsPluginTransformSig 0x7A666D48 // 'xfmH'
typedef struct _cmsPluginBaseStruct {
@@ -486,6 +486,39 @@ typedef struct {
} cmsPluginMultiProcessElement;
+
+// Data kept in "Element" member of cmsStage
+
+// Curves
+typedef struct {
+ cmsUInt32Number nCurves;
+ cmsToneCurve** TheCurves;
+
+} _cmsStageToneCurvesData;
+
+// Matrix
+typedef struct {
+ cmsFloat64Number* Double; // floating point for the matrix
+ cmsFloat64Number* Offset; // The offset
+
+} _cmsStageMatrixData;
+
+// CLUT
+typedef struct {
+
+ union { // Can have only one of both representations at same time
+ cmsUInt16Number* T; // Points to the table 16 bits table
+ cmsFloat32Number* TFloat; // Points to the cmsFloat32Number table
+
+ } Tab;
+
+ cmsInterpParams* Params;
+ cmsUInt32Number nEntries;
+ cmsBool HasFloatValues;
+
+} _cmsStageCLutData;
+
+
//----------------------------------------------------------------------------------------------------------
// Optimization. Using this plug-in, additional optimization strategies may be implemented.
// The function should return TRUE if any optimization is done on the LUT, this terminates
@@ -524,6 +557,37 @@ typedef struct {
} cmsPluginOptimization;
//----------------------------------------------------------------------------------------------------------
+// Full xform
+typedef void (* _cmsTransformFn)(struct _cmstransform_struct *CMMcargo,
+ const void* InputBuffer,
+ void* OutputBuffer,
+ cmsUInt32Number Size,
+ cmsUInt32Number Stride);
+
+typedef cmsBool (* _cmsTranformFactory)(_cmsTransformFn* xform,
+ void** UserData,
+ _cmsOPTfreeDataFn* FreeUserData,
+ cmsPipeline** Lut,
+ cmsUInt32Number* InputFormat,
+ cmsUInt32Number* OutputFormat,
+ cmsUInt32Number* dwFlags);
+
+
+// Retrieve user data as specified by the factory
+CMSAPI void * CMSEXPORT _cmsGetTransformUserData(struct _cmstransform_struct *CMMcargo);
+
+
+// FIXME: Those are hacks that should be solved somehow.
+void* _cmsOPTgetTransformPipelinePrivateData(struct _cmstransform_struct *CMMcargo);
+
+typedef struct {
+ cmsPluginBase base;
+
+ // Transform entry point
+ _cmsTranformFactory Factory;
+
+} cmsPluginTransform;
+
#ifndef CMS_USE_CPP_API
# ifdef __cplusplus
diff --git a/src/cmscgats.c b/src/cmscgats.c
index 487c2c3..5f482a1 100644
--- a/src/cmscgats.c
+++ b/src/cmscgats.c
@@ -603,6 +603,14 @@ static
cmsFloat64Number ParseFloatNumber(const char *Buffer)
{
cmsFloat64Number dnum = 0.0;
+ int sign = 1;
+
+ if (*Buffer == '-' || *Buffer == '+') {
+
+ sign = (*Buffer == '-') ? -1 : 1;
+ Buffer++;
+ }
+
while (*Buffer && isdigit(*Buffer)) {
@@ -661,8 +669,7 @@ cmsFloat64Number ParseFloatNumber(const char *Buffer)
dnum = dnum * xpow10(e);
}
-
- return dnum;
+ return sign * dnum;
}
@@ -1773,19 +1780,19 @@ cmsBool CMSEXPORT cmsIT8SaveToMem(cmsHANDLE hIT8, void *MemPtr, cmsUInt32Number*
sd.Max = *BytesNeeded; // Write to memory?
else
sd.Max = 0; // Just counting the needed bytes
-
+
for (i=0; i < it8 ->TablesCount; i++) {
- cmsIT8SetTable(hIT8, i);
- WriteHeader(it8, &sd);
- WriteDataFormat(&sd, it8);
- WriteData(&sd, it8);
+ cmsIT8SetTable(hIT8, i);
+ WriteHeader(it8, &sd);
+ WriteDataFormat(&sd, it8);
+ WriteData(&sd, it8);
}
-
+
sd.Used++; // The \0 at the very end
if (sd.Base)
- sd.Ptr = 0;
+ *sd.Ptr = 0;
*BytesNeeded = sd.Used;
@@ -2198,11 +2205,11 @@ void CookPointers(cmsIT8* it8)
// Try to infere if the file is a CGATS/IT8 file at all. Read first line
// that should be something like some printable characters plus a \n
-// returns 0 if this is not like a CGATS, or an integer otherwise
+// returns 0 if this is not like a CGATS, or an integer otherwise. This integer is the number of words in first line?
static
int IsMyBlock(cmsUInt8Number* Buffer, int n)
{
- int cols = 1, space = 0, quot = 0;
+ int words = 1, space = 0, quot = 0;
int i;
if (n < 10) return 0; // Too small
@@ -2216,7 +2223,7 @@ int IsMyBlock(cmsUInt8Number* Buffer, int n)
{
case '\n':
case '\r':
- return ((quot == 1) || (cols > 2)) ? 0 : cols;
+ return ((quot == 1) || (words > 2)) ? 0 : words;
case '\t':
case ' ':
if(!quot && !space)
@@ -2228,7 +2235,7 @@ int IsMyBlock(cmsUInt8Number* Buffer, int n)
default:
if (Buffer[i] < 32) return 0;
if (Buffer[i] > 127) return 0;
- cols += space;
+ words += space;
space = 0;
break;
}
diff --git a/src/cmsgamma.c b/src/cmsgamma.c
index 02dc910..b546fd8 100644
--- a/src/cmsgamma.c
+++ b/src/cmsgamma.c
@@ -248,18 +248,28 @@ cmsFloat64Number DefaultEvalParametricFn(cmsInt32Number Type, const cmsFloat64Nu
switch (Type) {
- // X = Y ^ Gamma
- case 1:
- if (R < 0)
- Val = 0;
+ // X = Y ^ Gamma
+ case 1:
+ if (R < 0) {
+
+ if (fabs(Params[0] - 1.0) < MATRIX_DET_TOLERANCE)
+ Val = R;
+ else
+ Val = 0;
+ }
else
Val = pow(R, Params[0]);
break;
// Type 1 Reversed: X = Y ^1/gamma
case -1:
- if (R < 0)
- Val = 0;
+ if (R < 0) {
+
+ if (fabs(Params[0] - 1.0) < MATRIX_DET_TOLERANCE)
+ Val = R;
+ else
+ Val = 0;
+ }
else
Val = pow(R, 1/Params[0]);
break;
@@ -523,6 +533,19 @@ cmsFloat64Number EvalSegmentedFn(const cmsToneCurve *g, cmsFloat64Number R)
return MINUS_INF;
}
+// Access to estimated low-res table
+cmsUInt32Number CMSEXPORT cmsGetToneCurveEstimatedTableEntries(const cmsToneCurve* t)
+{
+ _cmsAssert(t != NULL);
+ return t ->nEntries;
+}
+
+const cmsUInt16Number* CMSEXPORT cmsGetToneCurveEstimatedTable(const cmsToneCurve* t)
+{
+ _cmsAssert(t != NULL);
+ return t ->Table16;
+}
+
// Create an empty gamma curve, by using tables. This specifies only the limited-precision part, and leaves the
// floating point description empty.
diff --git a/src/cmslut.c b/src/cmslut.c
index 52204be..8f1febf 100644
--- a/src/cmslut.c
+++ b/src/cmslut.c
@@ -1298,14 +1298,21 @@ cmsPipeline* CMSEXPORT cmsPipelineAlloc(cmsContext ContextID, cmsUInt32Number In
return NewLUT;
}
+cmsContext CMSEXPORT cmsGetPipelineContextID(const cmsPipeline* lut)
+{
+ _cmsAssert(lut != NULL);
+ return lut ->ContextID;
+}
cmsUInt32Number CMSEXPORT cmsPipelineInputChannels(const cmsPipeline* lut)
{
+ _cmsAssert(lut != NULL);
return lut ->InputChannels;
}
cmsUInt32Number CMSEXPORT cmsPipelineOutputChannels(const cmsPipeline* lut)
{
+ _cmsAssert(lut != NULL);
return lut ->OutputChannels;
}
@@ -1333,6 +1340,7 @@ void CMSEXPORT cmsPipelineFree(cmsPipeline* lut)
// Default to evaluate the LUT on 16 bit-basis.
void CMSEXPORT cmsPipelineEval16(const cmsUInt16Number In[], cmsUInt16Number Out[], const cmsPipeline* lut)
{
+ _cmsAssert(lut != NULL);
lut ->Eval16Fn(In, Out, lut->Data);
}
@@ -1340,6 +1348,7 @@ void CMSEXPORT cmsPipelineEval16(const cmsUInt16Number In[], cmsUInt16Number Out
// Does evaluate the LUT on cmsFloat32Number-basis.
void CMSEXPORT cmsPipelineEvalFloat(const cmsFloat32Number In[], cmsFloat32Number Out[], const cmsPipeline* lut)
{
+ _cmsAssert(lut != NULL);
lut ->EvalFloatFn(In, Out, lut);
}
@@ -1377,8 +1386,10 @@ cmsPipeline* CMSEXPORT cmsPipelineDup(const cmsPipeline* lut)
Anterior = NewMPE;
}
- NewLUT ->DupDataFn = lut ->DupDataFn;
- NewLUT ->FreeDataFn = lut ->FreeDataFn;
+ NewLUT ->Eval16Fn = lut ->Eval16Fn;
+ NewLUT ->EvalFloatFn = lut ->EvalFloatFn;
+ NewLUT ->DupDataFn = lut ->DupDataFn;
+ NewLUT ->FreeDataFn = lut ->FreeDataFn;
if (NewLUT ->DupDataFn != NULL)
NewLUT ->Data = NewLUT ->DupDataFn(lut ->ContextID, lut->Data);
diff --git a/src/cmsopt.c b/src/cmsopt.c
index 554f832..7b99c5e 100644
--- a/src/cmsopt.c
+++ b/src/cmsopt.c
@@ -270,7 +270,7 @@ Prelin16Data* PrelinOpt16alloc(cmsContext ContextID,
int nOutputs, cmsToneCurve** Out )
{
int i;
- Prelin16Data* p16 = (Prelin16Data*) _cmsMallocZero(ContextID, sizeof(Prelin16Data));
+ Prelin16Data* p16 = _cmsMallocZero(ContextID, sizeof(Prelin16Data));
if (p16 == NULL) return NULL;
p16 ->nInputs = nInputs;
@@ -802,8 +802,8 @@ void PrelinEval8(register const cmsUInt16Number Input[],
cmsUInt8Number r, g, b;
cmsS15Fixed16Number rx, ry, rz;
cmsS15Fixed16Number c0, c1, c2, c3, Rest;
- int OutChan;
- register cmsS15Fixed16Number X0, X1, Y0, Y1, Z0, Z1;
+ int OutChan;
+ register cmsS15Fixed16Number X0, X1, Y0, Y1, Z0, Z1;
Prelin8Data* p8 = (Prelin8Data*) D;
register const cmsInterpParams* p = p8 ->p;
int TotalOut = p -> nOutputs;
@@ -1430,12 +1430,12 @@ void FillSecondShaper(cmsUInt16Number* Table, cmsToneCurve* Curve, cmsBool Is8Bi
// first we compute the resulting byte and then we store the byte times
// 257. This quantization allows to round very quick by doing a >> 8, but
// since the low byte is always equal to msb, we can do a & 0xff and this works!
- cmsUInt16Number w = _cmsQuickSaturateWord(Val * 65535.0 + 0.5);
+ cmsUInt16Number w = _cmsQuickSaturateWord(Val * 65535.0);
cmsUInt8Number b = FROM_16_TO_8(w);
Table[i] = FROM_8_TO_16(b);
}
- else Table[i] = _cmsQuickSaturateWord(Val * 65535.0 + 0.5);
+ else Table[i] = _cmsQuickSaturateWord(Val * 65535.0);
}
}
diff --git a/src/cmspack.c b/src/cmspack.c
index 16be43d..6056878 100644
--- a/src/cmspack.c
+++ b/src/cmspack.c
@@ -28,8 +28,8 @@
// This module handles all formats supported by lcms. There are two flavors, 16 bits and
// floating point. Floating point is supported only in a subset, those formats holding
-// cmsFloat32Number (4 bytes per component) and double (marked as 0 bytes per component as special
-// case)
+// cmsFloat32Number (4 bytes per component) and double (marked as 0 bytes per component
+// as special case)
// ---------------------------------------------------------------------------
@@ -61,17 +61,18 @@ cmsINLINE cmsUInt16Number FomLabV4ToLabV2(cmsUInt16Number x)
typedef struct {
cmsUInt32Number Type;
cmsUInt32Number Mask;
- cmsFormatter16 Frm;
+ cmsFormatter16 Frm;
} cmsFormatters16;
typedef struct {
cmsUInt32Number Type;
cmsUInt32Number Mask;
- cmsFormatterFloat Frm;
+ cmsFormatterFloat Frm;
} cmsFormattersFloat;
+
#define ANYSPACE COLORSPACE_SH(31)
#define ANYCHANNELS CHANNELS_SH(15)
#define ANYEXTRA EXTRA_SH(7)
@@ -144,13 +145,14 @@ cmsUInt8Number* UnrollPlanarBytes(register _cmsTRANSFORM* info,
register cmsUInt8Number* accum,
register cmsUInt32Number Stride)
{
- int nChan = T_CHANNELS(info -> InputFormat);
- int DoSwap= T_DOSWAP(info ->InputFormat);
- int Reverse= T_FLAVOR(info ->InputFormat);
+ int nChan = T_CHANNELS(info -> InputFormat);
+ int DoSwap = T_DOSWAP(info ->InputFormat);
+ int SwapFirst = T_SWAPFIRST(info ->InputFormat);
+ int Reverse = T_FLAVOR(info ->InputFormat);
int i;
cmsUInt8Number* Init = accum;
- if (DoSwap) {
+ if (DoSwap ^ SwapFirst) {
accum += T_EXTRA(info -> InputFormat) * Stride;
}
@@ -1196,12 +1198,19 @@ cmsUInt8Number* PackPlanarBytes(register _cmsTRANSFORM* info,
register cmsUInt8Number* output,
register cmsUInt32Number Stride)
{
- int nChan = T_CHANNELS(info -> OutputFormat);
- int DoSwap = T_DOSWAP(info ->OutputFormat);
- int Reverse= T_FLAVOR(info ->OutputFormat);
+ int nChan = T_CHANNELS(info -> OutputFormat);
+ int DoSwap = T_DOSWAP(info ->OutputFormat);
+ int SwapFirst = T_SWAPFIRST(info ->OutputFormat);
+ int Reverse = T_FLAVOR(info ->OutputFormat);
int i;
cmsUInt8Number* Init = output;
+
+ if (DoSwap ^ SwapFirst) {
+ output += T_EXTRA(info -> OutputFormat) * Stride;
+ }
+
+
for (i=0; i < nChan; i++) {
int index = DoSwap ? (nChan - i - 1) : i;
@@ -2475,6 +2484,8 @@ cmsUInt8Number* PackXYZDoubleFromFloat(_cmsTRANSFORM* Info,
}
+
+
// ----------------------------------------------------------------------------------------------------------------
@@ -2510,7 +2521,7 @@ static cmsFormatters16 InputFormatters16[] = {
{ CHANNELS_SH(4)|BYTES_SH(1)|DOSWAP_SH(1), ANYSPACE, Unroll4BytesSwap},
{ CHANNELS_SH(4)|BYTES_SH(1)|DOSWAP_SH(1)|SWAPFIRST_SH(1), ANYSPACE, Unroll4BytesSwapSwapFirst},
- { BYTES_SH(1)|PLANAR_SH(1), ANYFLAVOR|ANYSWAP|ANYEXTRA|ANYCHANNELS|ANYSPACE, UnrollPlanarBytes},
+ { BYTES_SH(1)|PLANAR_SH(1), ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|ANYEXTRA|ANYCHANNELS|ANYSPACE, UnrollPlanarBytes},
{ BYTES_SH(1), ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|ANYEXTRA|ANYCHANNELS|ANYSPACE, UnrollChunkyBytes},
@@ -2531,7 +2542,7 @@ static cmsFormatters16 InputFormatters16[] = {
{ CHANNELS_SH(4)|BYTES_SH(2)|DOSWAP_SH(1)|SWAPFIRST_SH(1), ANYSPACE, Unroll4WordsSwapSwapFirst},
- { BYTES_SH(2)|PLANAR_SH(1), ANYFLAVOR|ANYSWAP|ANYENDIAN|ANYEXTRA|ANYCHANNELS|ANYSPACE, UnrollPlanarWords },
+ { BYTES_SH(2)|PLANAR_SH(1), ANYFLAVOR|ANYSWAP|ANYENDIAN|ANYEXTRA|ANYCHANNELS|ANYSPACE, UnrollPlanarWords},
{ BYTES_SH(2), ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|ANYENDIAN|ANYEXTRA|ANYCHANNELS|ANYSPACE, UnrollAnyWords},
};
@@ -2558,9 +2569,9 @@ cmsFormatter _cmsGetStockInputFormatter(cmsUInt32Number dwInput, cmsUInt32Number
cmsUInt32Number i;
cmsFormatter fr;
+ switch (dwFlags) {
- if (!(dwFlags & CMS_PACK_FLAGS_FLOAT)) {
-
+ case CMS_PACK_FLAGS_16BITS: {
for (i=0; i < sizeof(InputFormatters16) / sizeof(cmsFormatters16); i++) {
cmsFormatters16* f = InputFormatters16 + i;
@@ -2570,7 +2581,9 @@ cmsFormatter _cmsGetStockInputFormatter(cmsUInt32Number dwInput, cmsUInt32Number
}
}
}
- else {
+ break;
+
+ case CMS_PACK_FLAGS_FLOAT: {
for (i=0; i < sizeof(InputFormattersFloat) / sizeof(cmsFormattersFloat); i++) {
cmsFormattersFloat* f = InputFormattersFloat + i;
@@ -2580,7 +2593,12 @@ cmsFormatter _cmsGetStockInputFormatter(cmsUInt32Number dwInput, cmsUInt32Number
}
}
}
+ break;
+ default:;
+
+ }
+
fr.Fmt16 = NULL;
return fr;
}
@@ -2632,7 +2650,7 @@ static cmsFormatters16 OutputFormatters16[] = {
{ CHANNELS_SH(4)|BYTES_SH(1)|DOSWAP_SH(1)|SWAPFIRST_SH(1), ANYSPACE, Pack4BytesSwapSwapFirst},
{ BYTES_SH(1), ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|ANYEXTRA|ANYCHANNELS|ANYSPACE, PackAnyBytes},
- { BYTES_SH(1)|PLANAR_SH(1), ANYFLAVOR|ANYSWAP|ANYEXTRA|ANYCHANNELS|ANYSPACE, PackPlanarBytes},
+ { BYTES_SH(1)|PLANAR_SH(1), ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|ANYEXTRA|ANYCHANNELS|ANYSPACE, PackPlanarBytes},
{ CHANNELS_SH(1)|BYTES_SH(2), ANYSPACE, Pack1Word},
{ CHANNELS_SH(1)|BYTES_SH(2)|EXTRA_SH(1), ANYSPACE, Pack1WordSkip1},
@@ -2689,28 +2707,37 @@ cmsFormatter _cmsGetStockOutputFormatter(cmsUInt32Number dwInput, cmsUInt32Numbe
cmsFormatter fr;
- if (dwFlags & CMS_PACK_FLAGS_FLOAT) {
+ switch (dwFlags)
+ {
- for (i=0; i < sizeof(OutputFormattersFloat) / sizeof(cmsFormattersFloat); i++) {
- cmsFormattersFloat* f = OutputFormattersFloat + i;
+ case CMS_PACK_FLAGS_16BITS: {
+
+ for (i=0; i < sizeof(OutputFormatters16) / sizeof(cmsFormatters16); i++) {
+ cmsFormatters16* f = OutputFormatters16 + i;
if ((dwInput & ~f ->Mask) == f ->Type) {
- fr.FmtFloat = f ->Frm;
+ fr.Fmt16 = f ->Frm;
return fr;
}
}
+ }
+ break;
- }
- else {
+ case CMS_PACK_FLAGS_FLOAT: {
- for (i=0; i < sizeof(OutputFormatters16) / sizeof(cmsFormatters16); i++) {
- cmsFormatters16* f = OutputFormatters16 + i;
+ for (i=0; i < sizeof(OutputFormattersFloat) / sizeof(cmsFormattersFloat); i++) {
+ cmsFormattersFloat* f = OutputFormattersFloat + i;
if ((dwInput & ~f ->Mask) == f ->Type) {
- fr.Fmt16 = f ->Frm;
+ fr.FmtFloat = f ->Frm;
return fr;
}
}
+ }
+ break;
+
+ default:;
+
}
fr.Fmt16 = NULL;
@@ -2754,7 +2781,7 @@ cmsBool _cmsRegisterFormattersPlugin(cmsPluginBase* Data)
cmsFormatter _cmsGetFormatter(cmsUInt32Number Type, // Specific type, i.e. TYPE_RGB_8
cmsFormatterDirection Dir,
- cmsUInt32Number dwFlags) // Float or 16 bits
+ cmsUInt32Number dwFlags)
{
cmsFormattersFactoryList* f;
diff --git a/src/cmsplugin.c b/src/cmsplugin.c
index ca05ec0..58ce15d 100644
--- a/src/cmsplugin.c
+++ b/src/cmsplugin.c
@@ -581,6 +581,10 @@ cmsBool CMSEXPORT cmsPlugin(void* Plug_in)
if (!_cmsRegisterOptimizationPlugin(Plugin)) return FALSE;
break;
+ case cmsPluginTransformSig:
+ if (!_cmsRegisterTransformPlugin(Plugin)) return FALSE;
+ break;
+
default:
cmsSignalError(0, cmsERROR_UNKNOWN_EXTENSION, "Unrecognized plugin type '%X'", Plugin -> Type);
return FALSE;
@@ -604,6 +608,7 @@ void CMSEXPORT cmsUnregisterPlugins(void)
_cmsRegisterParametricCurvesPlugin(NULL);
_cmsRegisterMultiProcessElementPlugin(NULL);
_cmsRegisterOptimizationPlugin(NULL);
+ _cmsRegisterTransformPlugin(NULL);
if (PluginPool != NULL)
_cmsSubAllocDestroy(PluginPool);
diff --git a/src/cmssamp.c b/src/cmssamp.c
index a918c66..420003e 100644
--- a/src/cmssamp.c
+++ b/src/cmssamp.c
@@ -270,7 +270,7 @@ cmsBool CMSEXPORT cmsDetectBlackPoint(cmsCIEXYZ* BlackPoint, cmsHPROFILE hProfil
// http://www.personal.psu.edu/jhm/f90/lectures/lsq2.html
static
-cmsFloat64Number VertexOfLeastSquaresFitQuadraticCurve(int n, cmsFloat64Number x[], cmsFloat64Number y[])
+cmsFloat64Number RootOfLeastSquaresFitQuadraticCurve(int n, cmsFloat64Number x[], cmsFloat64Number y[])
{
double sum_x = 0, sum_x2 = 0, sum_x3 = 0, sum_x4 = 0;
double sum_y = 0, sum_yx = 0, sum_yx2 = 0;
@@ -552,7 +552,7 @@ cmsBool CMSEXPORT cmsDetectDestinationBlackPoint(cmsCIEXYZ* BlackPoint, cmsHPROF
Lab.L = x[NonMonoIndx];
// fit and get the vertex of quadratic curve
- Lab.L = VertexOfLeastSquaresFitQuadraticCurve(n, x, y);
+ Lab.L = RootOfLeastSquaresFitQuadraticCurve(n, x, y);
if (Lab.L < 0.0 || Lab.L > 50.0) { // clip to zero L* if the vertex is negative
Lab.L = 0;
diff --git a/src/cmsvirt.c b/src/cmsvirt.c
index eafa58b..c8be58c 100644
--- a/src/cmsvirt.c
+++ b/src/cmsvirt.c
@@ -1106,12 +1106,12 @@ cmsHPROFILE CMSEXPORT cmsTransform2DeviceLink(cmsHTRANSFORM hTransform, cmsFloat
_cmsOptimizePipeline(&LUT, xform ->RenderingIntent, &FrmIn, &FrmOut, &dwFlags);
// Put identity curves if needed
- if (cmsPipelineStageCount(LUT) == 1) {
-
- cmsPipelineInsertStage(LUT, cmsAT_BEGIN, _cmsStageAllocIdentityCurves(ContextID, ChansIn));
- cmsPipelineInsertStage(LUT, cmsAT_END, _cmsStageAllocIdentityCurves(ContextID, ChansOut));
- }
+ if (cmsPipelineGetPtrToFirstStage(LUT) ->Type != cmsSigCurveSetElemType)
+ cmsPipelineInsertStage(LUT, cmsAT_BEGIN, _cmsStageAllocIdentityCurves(ContextID, ChansIn));
+ if (cmsPipelineGetPtrToLastStage(LUT) ->Type != cmsSigCurveSetElemType)
+ cmsPipelineInsertStage(LUT, cmsAT_END, _cmsStageAllocIdentityCurves(ContextID, ChansOut));
+
AllowedLUT = FindCombination(LUT, Version >= 4.0, DestinationTag);
}
diff --git a/src/cmsxform.c b/src/cmsxform.c
index eef54e4..aa6b41c 100644
--- a/src/cmsxform.c
+++ b/src/cmsxform.c
@@ -89,6 +89,9 @@ void CMSEXPORT cmsDeleteTransform(cmsHTRANSFORM hTransform)
if (p ->Sequence)
cmsFreeProfileSequenceDescription(p ->Sequence);
+ if (p ->UserData)
+ p ->FreeUserData(p ->ContextID, p ->UserData);
+
_cmsFree(p ->ContextID, (void *) p);
}
@@ -101,7 +104,20 @@ void CMSEXPORT cmsDoTransform(cmsHTRANSFORM Transform,
{
_cmsTRANSFORM* p = (_cmsTRANSFORM*) Transform;
- p -> xform(p, InputBuffer, OutputBuffer, Size);
+ p -> xform(p, InputBuffer, OutputBuffer, Size, Size);
+}
+
+
+// Apply transform.
+void CMSEXPORT cmsDoTransformStride(cmsHTRANSFORM Transform,
+ const void* InputBuffer,
+ void* OutputBuffer,
+ cmsUInt32Number Size, cmsUInt32Number Stride)
+
+{
+ _cmsTRANSFORM* p = (_cmsTRANSFORM*) Transform;
+
+ p -> xform(p, InputBuffer, OutputBuffer, Size, Stride);
}
@@ -112,7 +128,7 @@ void CMSEXPORT cmsDoTransform(cmsHTRANSFORM Transform,
static
void FloatXFORM(_cmsTRANSFORM* p,
const void* in,
- void* out, cmsUInt32Number Size)
+ void* out, cmsUInt32Number Size, cmsUInt32Number Stride)
{
cmsUInt8Number* accum;
cmsUInt8Number* output;
@@ -125,7 +141,7 @@ void FloatXFORM(_cmsTRANSFORM* p,
for (i=0; i < Size; i++) {
- accum = p -> FromInputFloat(p, fIn, accum, Size);
+ accum = p -> FromInputFloat(p, fIn, accum, Stride);
// Any gamut chack to do?
if (p ->GamutCheck != NULL) {
@@ -153,7 +169,7 @@ void FloatXFORM(_cmsTRANSFORM* p,
}
// Back to asked representation
- output = p -> ToOutputFloat(p, fOut, output, Size);
+ output = p -> ToOutputFloat(p, fOut, output, Stride);
}
}
@@ -163,7 +179,8 @@ void FloatXFORM(_cmsTRANSFORM* p,
static
void NullXFORM(_cmsTRANSFORM* p,
const void* in,
- void* out, cmsUInt32Number Size)
+ void* out, cmsUInt32Number Size,
+ cmsUInt32Number Stride)
{
cmsUInt8Number* accum;
cmsUInt8Number* output;
@@ -176,8 +193,8 @@ void NullXFORM(_cmsTRANSFORM* p,
for (i=0; i < n; i++) {
- accum = p -> FromInput(p, wIn, accum, Size);
- output = p -> ToOutput(p, wIn, output, Size);
+ accum = p -> FromInput(p, wIn, accum, Stride);
+ output = p -> ToOutput(p, wIn, output, Stride);
}
}
@@ -186,7 +203,7 @@ void NullXFORM(_cmsTRANSFORM* p,
static
void PrecalculatedXFORM(_cmsTRANSFORM* p,
const void* in,
- void* out, cmsUInt32Number Size)
+ void* out, cmsUInt32Number Size, cmsUInt32Number Stride)
{
register cmsUInt8Number* accum;
register cmsUInt8Number* output;
@@ -199,9 +216,9 @@ void PrecalculatedXFORM(_cmsTRANSFORM* p,
for (i=0; i < n; i++) {
- accum = p -> FromInput(p, wIn, accum, Size);
+ accum = p -> FromInput(p, wIn, accum, Stride);
p ->Lut ->Eval16Fn(wIn, wOut, p -> Lut->Data);
- output = p -> ToOutput(p, wOut, output, Size);
+ output = p -> ToOutput(p, wOut, output, Stride);
}
}
@@ -230,7 +247,7 @@ void TransformOnePixelWithGamutCheck(_cmsTRANSFORM* p,
static
void PrecalculatedXFORMGamutCheck(_cmsTRANSFORM* p,
const void* in,
- void* out, cmsUInt32Number Size)
+ void* out, cmsUInt32Number Size, cmsUInt32Number Stride)
{
cmsUInt8Number* accum;
cmsUInt8Number* output;
@@ -243,9 +260,9 @@ void PrecalculatedXFORMGamutCheck(_cmsTRANSFORM* p,
for (i=0; i < n; i++) {
- accum = p -> FromInput(p, wIn, accum, Size);
+ accum = p -> FromInput(p, wIn, accum, Stride);
TransformOnePixelWithGamutCheck(p, wIn, wOut);
- output = p -> ToOutput(p, wOut, output, Size);
+ output = p -> ToOutput(p, wOut, output, Stride);
}
}
@@ -254,7 +271,7 @@ void PrecalculatedXFORMGamutCheck(_cmsTRANSFORM* p,
static
void CachedXFORM(_cmsTRANSFORM* p,
const void* in,
- void* out, cmsUInt32Number Size)
+ void* out, cmsUInt32Number Size, cmsUInt32Number Stride)
{
cmsUInt8Number* accum;
cmsUInt8Number* output;
@@ -275,7 +292,7 @@ void CachedXFORM(_cmsTRANSFORM* p,
for (i=0; i < n; i++) {
- accum = p -> FromInput(p, wIn, accum, Size);
+ accum = p -> FromInput(p, wIn, accum, Stride);
if (memcmp(wIn, Cache.CacheIn, sizeof(Cache.CacheIn)) == 0) {
@@ -289,7 +306,7 @@ void CachedXFORM(_cmsTRANSFORM* p,
memcpy(Cache.CacheOut, wOut, sizeof(Cache.CacheOut));
}
- output = p -> ToOutput(p, wOut, output, Size);
+ output = p -> ToOutput(p, wOut, output, Stride);
}
}
@@ -299,7 +316,7 @@ void CachedXFORM(_cmsTRANSFORM* p,
static
void CachedXFORMGamutCheck(_cmsTRANSFORM* p,
const void* in,
- void* out, cmsUInt32Number Size)
+ void* out, cmsUInt32Number Size, cmsUInt32Number Stride)
{
cmsUInt8Number* accum;
cmsUInt8Number* output;
@@ -320,7 +337,7 @@ void CachedXFORMGamutCheck(_cmsTRANSFORM* p,
for (i=0; i < n; i++) {
- accum = p -> FromInput(p, wIn, accum, Size);
+ accum = p -> FromInput(p, wIn, accum, Stride);
if (memcmp(wIn, Cache.CacheIn, sizeof(Cache.CacheIn)) == 0) {
memcpy(wOut, Cache.CacheOut, sizeof(Cache.CacheOut));
@@ -331,29 +348,106 @@ void CachedXFORMGamutCheck(_cmsTRANSFORM* p,
memcpy(Cache.CacheOut, wOut, sizeof(Cache.CacheOut));
}
- output = p -> ToOutput(p, wOut, output, Size);
+ output = p -> ToOutput(p, wOut, output, Stride);
}
}
+// -------------------------------------------------------------------------------------------------------------
+
+// List of used-defined transform factories
+typedef struct _cmsTransformCollection_st {
+
+ _cmsTranformFactory Factory;
+ struct _cmsTransformCollection_st *Next;
+
+} _cmsTransformCollection;
+
+// The linked list head
+static _cmsTransformCollection* TransformCollection = NULL;
+// Register new ways to transform
+cmsBool _cmsRegisterTransformPlugin(cmsPluginBase* Data)
+{
+ cmsPluginTransform* Plugin = (cmsPluginTransform*) Data;
+ _cmsTransformCollection* fl;
+
+ if (Data == NULL) {
+
+ // Free the chain. Memory is safely freed at exit
+ TransformCollection = NULL;
+ return TRUE;
+ }
+
+ // Factory callback is required
+ if (Plugin ->Factory == NULL) return FALSE;
-// Allocate transform struct and set it to defaults
+ fl = (_cmsTransformCollection*) _cmsPluginMalloc(sizeof(_cmsTransformCollection));
+ if (fl == NULL) return FALSE;
+
+ // Copy the parameters
+ fl ->Factory = Plugin ->Factory;
+
+ // Keep linked list
+ fl ->Next = TransformCollection;
+ TransformCollection = fl;
+
+ // All is ok
+ return TRUE;
+}
+
+
+// returns the pointer defined by the plug-in to store private data
+void * CMSEXPORT _cmsGetTransformUserData(struct _cmstransform_struct *CMMcargo)
+{
+ _cmsAssert(CMMcargo != NULL);
+ return CMMcargo ->UserData;
+}
+
+// Allocate transform struct and set it to defaults. Ask the optimization plug-in about if those formats are proper
+// for separated transforms. If this is the case,
static
-_cmsTRANSFORM* AllocEmptyTransform(cmsContext ContextID, cmsUInt32Number InputFormat, cmsUInt32Number OutputFormat, cmsUInt32Number dwFlags)
+_cmsTRANSFORM* AllocEmptyTransform(cmsContext ContextID, cmsPipeline* lut,
+ cmsUInt32Number Intent, cmsUInt32Number* InputFormat, cmsUInt32Number* OutputFormat, cmsUInt32Number* dwFlags)
{
+ _cmsTransformCollection* Plugin;
+
// Allocate needed memory
_cmsTRANSFORM* p = (_cmsTRANSFORM*) _cmsMallocZero(ContextID, sizeof(_cmsTRANSFORM));
if (!p) return NULL;
+ // Store the proposed pipeline
+ p ->Lut = lut;
+
+ // Let's see if any plug-in want to do the transform by itself
+ for (Plugin = TransformCollection;
+ Plugin != NULL;
+ Plugin = Plugin ->Next) {
+
+ if (Plugin ->Factory(&p->xform, &p->UserData, &p ->FreeUserData, &p ->Lut, InputFormat, OutputFormat, dwFlags))
+ {
+ // Last plugin in the declaration order takes control. We just keep
+ // the original parameters as a logging
+ p ->InputFormat = *InputFormat;
+ p ->OutputFormat = *OutputFormat;
+ p ->dwOriginalFlags = *dwFlags;
+ p ->ContextID = ContextID;
+ return p;
+ }
+ }
+
+ // Not suitable for the transform plug-in, let's check the pipeline plug-in
+ if (p ->Lut != NULL)
+ _cmsOptimizePipeline(&p->Lut, Intent, InputFormat, OutputFormat, dwFlags);
+
// Check whatever this is a true floating point transform
- if (_cmsFormatterIsFloat(InputFormat) && _cmsFormatterIsFloat(OutputFormat)) {
+ if (_cmsFormatterIsFloat(*InputFormat) && _cmsFormatterIsFloat(*OutputFormat)) {
// Get formatter function always return a valid union, but the contents of this union may be NULL.
- p ->FromInputFloat = _cmsGetFormatter(InputFormat, cmsFormatterInput, CMS_PACK_FLAGS_FLOAT).FmtFloat;
- p ->ToOutputFloat = _cmsGetFormatter(OutputFormat, cmsFormatterOutput, CMS_PACK_FLAGS_FLOAT).FmtFloat;
- dwFlags |= cmsFLAGS_CAN_CHANGE_FORMATTER;
+ p ->FromInputFloat = _cmsGetFormatter(*InputFormat, cmsFormatterInput, CMS_PACK_FLAGS_FLOAT).FmtFloat;
+ p ->ToOutputFloat = _cmsGetFormatter(*OutputFormat, cmsFormatterOutput, CMS_PACK_FLAGS_FLOAT).FmtFloat;
+ *dwFlags |= cmsFLAGS_CAN_CHANGE_FORMATTER;
if (p ->FromInputFloat == NULL || p ->ToOutputFloat == NULL) {
@@ -367,17 +461,16 @@ _cmsTRANSFORM* AllocEmptyTransform(cmsContext ContextID, cmsUInt32Number InputFo
}
else {
- if (InputFormat == 0 && OutputFormat == 0) {
+ if (*InputFormat == 0 && *OutputFormat == 0) {
p ->FromInput = p ->ToOutput = NULL;
- dwFlags |= cmsFLAGS_CAN_CHANGE_FORMATTER;
+ *dwFlags |= cmsFLAGS_CAN_CHANGE_FORMATTER;
}
else {
int BytesPerPixelInput;
- p ->FromInput = _cmsGetFormatter(InputFormat, cmsFormatterInput, CMS_PACK_FLAGS_16BITS).Fmt16;
- p ->ToOutput = _cmsGetFormatter(OutputFormat, cmsFormatterOutput, CMS_PACK_FLAGS_16BITS).Fmt16;
-
+ p ->FromInput = _cmsGetFormatter(*InputFormat, cmsFormatterInput, CMS_PACK_FLAGS_16BITS).Fmt16;
+ p ->ToOutput = _cmsGetFormatter(*OutputFormat, cmsFormatterOutput, CMS_PACK_FLAGS_16BITS).Fmt16;
if (p ->FromInput == NULL || p ->ToOutput == NULL) {
@@ -388,25 +481,25 @@ _cmsTRANSFORM* AllocEmptyTransform(cmsContext ContextID, cmsUInt32Number InputFo
BytesPerPixelInput = T_BYTES(p ->InputFormat);
if (BytesPerPixelInput == 0 || BytesPerPixelInput >= 2)
- dwFlags |= cmsFLAGS_CAN_CHANGE_FORMATTER;
+ *dwFlags |= cmsFLAGS_CAN_CHANGE_FORMATTER;
}
- if (dwFlags & cmsFLAGS_NULLTRANSFORM) {
+ if (*dwFlags & cmsFLAGS_NULLTRANSFORM) {
p ->xform = NullXFORM;
}
else {
- if (dwFlags & cmsFLAGS_NOCACHE) {
+ if (*dwFlags & cmsFLAGS_NOCACHE) {
- if (dwFlags & cmsFLAGS_GAMUTCHECK)
+ if (*dwFlags & cmsFLAGS_GAMUTCHECK)
p ->xform = PrecalculatedXFORMGamutCheck; // Gamut check, no caché
else
p ->xform = PrecalculatedXFORM; // No caché, no gamut check
}
else {
- if (dwFlags & cmsFLAGS_GAMUTCHECK)
+ if (*dwFlags & cmsFLAGS_GAMUTCHECK)
p ->xform = CachedXFORMGamutCheck; // Gamut check, caché
else
p ->xform = CachedXFORM; // No gamut check, caché
@@ -414,12 +507,12 @@ _cmsTRANSFORM* AllocEmptyTransform(cmsContext ContextID, cmsUInt32Number InputFo
}
}
}
-
- p ->InputFormat = InputFormat;
- p ->OutputFormat = OutputFormat;
- p ->dwOriginalFlags = dwFlags;
+ p ->InputFormat = *InputFormat;
+ p ->OutputFormat = *OutputFormat;
+ p ->dwOriginalFlags = *dwFlags;
p ->ContextID = ContextID;
+ p ->UserData = NULL;
return p;
}
@@ -513,7 +606,7 @@ cmsHTRANSFORM CMSEXPORT cmsCreateExtendedTransform(cmsContext ContextID,
// If it is a fake transform
if (dwFlags & cmsFLAGS_NULLTRANSFORM)
{
- return AllocEmptyTransform(ContextID, InputFormat, OutputFormat, dwFlags);
+ return AllocEmptyTransform(ContextID, NULL, INTENT_PERCEPTUAL, &InputFormat, &OutputFormat, &dwFlags);
}
// If gamut check is requested, make sure we have a gamut profile
@@ -551,14 +644,10 @@ cmsHTRANSFORM CMSEXPORT cmsCreateExtendedTransform(cmsContext ContextID,
return NULL;
}
- // Optimize the LUT if possible
- _cmsOptimizePipeline(&Lut, LastIntent, &InputFormat, &OutputFormat, &dwFlags);
-
-
+
// All seems ok
- xform = AllocEmptyTransform(ContextID, InputFormat, OutputFormat, dwFlags);
+ xform = AllocEmptyTransform(ContextID, Lut, LastIntent, &InputFormat, &OutputFormat, &dwFlags);
if (xform == NULL) {
- cmsPipelineFree(Lut);
return NULL;
}
@@ -566,7 +655,7 @@ cmsHTRANSFORM CMSEXPORT cmsCreateExtendedTransform(cmsContext ContextID,
xform ->EntryColorSpace = EntryColorSpace;
xform ->ExitColorSpace = ExitColorSpace;
xform ->RenderingIntent = Intents[nProfiles-1];
- xform ->Lut = Lut;
+
// Create a gamut check LUT if requested
if (hGamutProfile != NULL && (dwFlags & cmsFLAGS_GAMUTCHECK))
diff --git a/src/lcms2.def b/src/lcms2.def
index 64240fe..828fcd2 100644
--- a/src/lcms2.def
+++ b/src/lcms2.def
@@ -62,11 +62,12 @@ _cmsDecodeDateTimeNumber = _cmsDecodeDateTimeNumber
_cmsDefaultICCintents = _cmsDefaultICCintents
cmsDeleteTransform = cmsDeleteTransform
cmsDeltaE = cmsDeltaE
-cmsDetectBlackPoint = cmsDetectBlackPoint
+cmsDetectBlackPoint = cmsDetectBlackPoint
cmsDetectDestinationBlackPoint = cmsDetectDestinationBlackPoint
cmsDetectTAC = cmsDetectTAC
cmsDesaturateLab = cmsDesaturateLab
cmsDoTransform = cmsDoTransform
+cmsDoTransformStride = cmsDoTransformStride
_cmsDoubleTo15Fixed16 = _cmsDoubleTo15Fixed16
_cmsDoubleTo8Fixed8 = _cmsDoubleTo8Fixed8
_cmsDupMem = _cmsDupMem
@@ -75,6 +76,8 @@ cmsDupProfileSequenceDescription = cmsDupProfileSequenceDescription
cmsDupToneCurve = cmsDupToneCurve
_cmsEncodeDateTimeNumber = _cmsEncodeDateTimeNumber
cmsEstimateGamma = cmsEstimateGamma
+cmsGetToneCurveEstimatedTableEntries = cmsGetToneCurveEstimatedTableEntries
+cmsGetToneCurveEstimatedTable = cmsGetToneCurveEstimatedTable
cmsEvalToneCurve16 = cmsEvalToneCurve16
cmsEvalToneCurveFloat = cmsEvalToneCurveFloat
cmsfilelength = cmsfilelength
@@ -111,12 +114,12 @@ cmsGetPostScriptCRD = cmsGetPostScriptCRD
cmsGetPostScriptCSA = cmsGetPostScriptCSA
cmsGetProfileInfo = cmsGetProfileInfo
cmsGetProfileInfoASCII = cmsGetProfileInfoASCII
-cmsGetProfileContextID = cmsGetProfileContextID
+cmsGetProfileContextID = cmsGetProfileContextID
cmsGetProfileVersion = cmsGetProfileVersion
cmsGetSupportedIntents = cmsGetSupportedIntents
cmsGetTagCount = cmsGetTagCount
cmsGetTagSignature = cmsGetTagSignature
-cmsGetTransformContextID = cmsGetTransformContextID
+cmsGetTransformContextID = cmsGetTransformContextID
_cmsICCcolorSpace = _cmsICCcolorSpace
_cmsIOPrintf = _cmsIOPrintf
cmsIsCLUT = cmsIsCLUT
@@ -311,5 +314,6 @@ cmsDictDup = cmsDictDup
cmsDictAddEntry = cmsDictAddEntry
cmsDictGetEntryList = cmsDictGetEntryList
cmsDictNextEntry = cmsDictNextEntry
+_cmsGetTransformUserData = _cmsGetTransformUserData
\ No newline at end of file
diff --git a/src/lcms2_internal.h b/src/lcms2_internal.h
index 79dbc99..fb86d60 100644
--- a/src/lcms2_internal.h
+++ b/src/lcms2_internal.h
@@ -196,6 +196,8 @@ cmsBool _cmsRegisterMultiProcessElementPlugin(cmsPluginBase* Plugin);
// Optimization
cmsBool _cmsRegisterOptimizationPlugin(cmsPluginBase* Plugin);
+// Transform
+cmsBool _cmsRegisterTransformPlugin(cmsPluginBase* Plugin);
// ---------------------------------------------------------------------------------------------------------
@@ -387,37 +389,6 @@ struct _cmsStage_struct {
struct _cmsStage_struct* Next;
};
-// Data kept in "Element" member of cmsStage
-
-// Curves
-typedef struct {
- cmsUInt32Number nCurves;
- cmsToneCurve** TheCurves;
-
-} _cmsStageToneCurvesData;
-
-// Matrix
-typedef struct {
- cmsFloat64Number* Double; // floating point for the matrix
- cmsFloat64Number* Offset; // The offset
-
-} _cmsStageMatrixData;
-
-// CLUT
-typedef struct {
-
- union { // Can have only one of both representations at same time
- cmsUInt16Number* T; // Points to the table 16 bits table
- cmsFloat32Number* TFloat; // Points to the cmsFloat32Number table
-
- } Tab;
-
- cmsInterpParams* Params;
- cmsUInt32Number nEntries;
- cmsBool HasFloatValues;
-
-} _cmsStageCLutData;
-
// Special Stages (cannot be saved)
cmsStage* _cmsStageAllocLab2XYZ(cmsContext ContextID);
@@ -544,18 +515,6 @@ typedef struct {
} _cmsCACHE;
-// Full xform
-typedef void (* _cmsTransformFn)(struct _cmstransform_struct *Transform,
- const void* InputBuffer,
- void* OutputBuffer,
- cmsUInt32Number Size);
-
-typedef struct {
-
- cmsUInt32Number InputFormat, OutputFormat; // Keep formats for further reference
- cmsUInt32Number StrideIn, StrideOut; // Planar support
-
-} cmsFormatterInfo;
// Transformation
typedef struct _cmstransform_struct {
@@ -575,10 +534,10 @@ typedef struct _cmstransform_struct {
// 1-pixel cache seed for zero as input (16 bits, read only)
_cmsCACHE Cache;
- // A MPE LUT holding the full (optimized) transform
+ // A Pipeline holding the full (optimized) transform
cmsPipeline* Lut;
- // A MPE LUT holding the gamut check. It goes from the input space to bilevel
+ // A Pipeline holding the gamut check. It goes from the input space to bilevel
cmsPipeline* GamutCheck;
// Colorant tables
@@ -601,6 +560,10 @@ typedef struct _cmstransform_struct {
// An id that uniquely identifies the running context. May be null.
cmsContext ContextID;
+ // A user-defined pointer that can be used to store data for transform plug-ins
+ void* UserData;
+ _cmsOPTfreeDataFn FreeUserData;
+
} _cmsTRANSFORM;
// --------------------------------------------------------------------------------------------------
diff --git a/testbed/testcms2.c b/testbed/testcms2.c
index d928aee..2bc41d4 100644
--- a/testbed/testcms2.c
+++ b/testbed/testcms2.c
@@ -187,6 +187,10 @@ static
void FatalErrorQuit(cmsContext ContextID, cmsUInt32Number ErrorCode, const char *Text)
{
Die(Text);
+
+ cmsUNUSED_PARAMETER(ContextID);
+ cmsUNUSED_PARAMETER(ErrorCode);
+
}
// Print a dot for gauging
@@ -342,6 +346,20 @@ cmsHPROFILE Create_Gray22(void)
return hProfile;
}
+// A gamma-3.0 gray space
+static
+cmsHPROFILE Create_Gray30(void)
+{
+ cmsHPROFILE hProfile;
+ cmsToneCurve* Curve = cmsBuildGamma(DbgThread(), 3.0);
+ if (Curve == NULL) return NULL;
+
+ hProfile = cmsCreateGrayProfileTHR(DbgThread(), cmsD50_xyY(), Curve);
+ cmsFreeToneCurve(Curve);
+
+ return hProfile;
+}
+
static
cmsHPROFILE Create_GrayLab(void)
@@ -585,6 +603,11 @@ cmsInt32Number CreateTestProfiles(void)
// ----
+ h = Create_Gray30();
+ if (!OneVirtual(h, "Gray 3.0 profile", "gray3lcms2.icc")) return 0;
+
+ // ----
+
h = Create_GrayLab();
if (!OneVirtual(h, "Gray Lab profile", "glablcms2.icc")) return 0;
@@ -637,6 +660,7 @@ void RemoveTestProfiles(void)
remove("sRGBlcms2.icc");
remove("aRGBlcms2.icc");
remove("graylcms2.icc");
+ remove("gray3lcms2.icc");
remove("linlcms2.icc");
remove("limitlcms2.icc");
remove("labv2lcms2.icc");
@@ -654,6 +678,11 @@ void RemoveTestProfiles(void)
static
cmsInt32Number CheckBaseTypes(void)
{
+ // Ignore warnings about conditional expression
+#ifdef _MSC_VER
+#pragma warning(disable: 4127)
+#endif
+
if (sizeof(cmsUInt8Number) != 1) return 0;
if (sizeof(cmsInt8Number) != 1) return 0;
if (sizeof(cmsUInt16Number) != 2) return 0;
@@ -1603,6 +1632,9 @@ cmsInt32Number Sampler3D(register const cmsUInt16Number In[],
Out[2] = Fn8D3(In[0], In[1], In[2], 0, 0, 0, 0, 0, 3);
return 1;
+
+ cmsUNUSED_PARAMETER(Cargo);
+
}
static
@@ -1616,6 +1648,8 @@ cmsInt32Number Sampler4D(register const cmsUInt16Number In[],
Out[2] = Fn8D3(In[0], In[1], In[2], In[3], 0, 0, 0, 0, 4);
return 1;
+
+ cmsUNUSED_PARAMETER(Cargo);
}
static
@@ -1629,6 +1663,8 @@ cmsInt32Number Sampler5D(register const cmsUInt16Number In[],
Out[2] = Fn8D3(In[0], In[1], In[2], In[3], In[4], 0, 0, 0, 5);
return 1;
+
+ cmsUNUSED_PARAMETER(Cargo);
}
static
@@ -1642,6 +1678,8 @@ cmsInt32Number Sampler6D(register const cmsUInt16Number In[],
Out[2] = Fn8D3(In[0], In[1], In[2], In[3], In[4], In[5], 0, 0, 6);
return 1;
+
+ cmsUNUSED_PARAMETER(Cargo);
}
static
@@ -1655,6 +1693,8 @@ cmsInt32Number Sampler7D(register const cmsUInt16Number In[],
Out[2] = Fn8D3(In[0], In[1], In[2], In[3], In[4], In[5], In[6], 0, 7);
return 1;
+
+ cmsUNUSED_PARAMETER(Cargo);
}
static
@@ -1668,6 +1708,8 @@ cmsInt32Number Sampler8D(register const cmsUInt16Number In[],
Out[2] = Fn8D3(In[0], In[1], In[2], In[3], In[4], In[5], In[6], In[7], 8);
return 1;
+
+ cmsUNUSED_PARAMETER(Cargo);
}
static
@@ -3635,16 +3677,16 @@ void CheckSingleFormatter16(cmsUInt32Number Type, const char* Text)
info.OutputFormat = info.InputFormat = Type;
// Go forth and back
- f = _cmsGetFormatter(Type, cmsFormatterInput, 0);
- b = _cmsGetFormatter(Type, cmsFormatterOutput, 0);
+ f = _cmsGetFormatter(Type, cmsFormatterInput, CMS_PACK_FLAGS_16BITS);
+ b = _cmsGetFormatter(Type, cmsFormatterOutput, CMS_PACK_FLAGS_16BITS);
if (f.Fmt16 == NULL || b.Fmt16 == NULL) {
Fail("no formatter for %s", Text);
FormatterFailed = TRUE;
// Useful for debug
- f = _cmsGetFormatter(Type, cmsFormatterInput, 0);
- b = _cmsGetFormatter(Type, cmsFormatterOutput, 0);
+ f = _cmsGetFormatter(Type, cmsFormatterInput, CMS_PACK_FLAGS_16BITS);
+ b = _cmsGetFormatter(Type, cmsFormatterOutput, CMS_PACK_FLAGS_16BITS);
return;
}
@@ -3724,12 +3766,15 @@ cmsInt32Number CheckFormatters16(void)
C( TYPE_RGBA_16_PLANAR );
C( TYPE_RGBA_16_SE );
C( TYPE_ARGB_8 );
+ C( TYPE_ARGB_8_PLANAR );
C( TYPE_ARGB_16 );
C( TYPE_ABGR_8 );
+ C( TYPE_ABGR_8_PLANAR );
C( TYPE_ABGR_16 );
C( TYPE_ABGR_16_PLANAR );
C( TYPE_ABGR_16_SE );
C( TYPE_BGRA_8 );
+ C( TYPE_BGRA_8_PLANAR );
C( TYPE_BGRA_16 );
C( TYPE_BGRA_16_SE );
C( TYPE_CMY_8 );
@@ -3943,8 +3988,9 @@ cmsInt32Number CheckFormattersFloat(void)
#undef C
+
static
-cmsInt32Number CheckOneRGB(cmsHTRANSFORM xform, cmsUInt32Number R, cmsUInt32Number G, cmsUInt32Number B, cmsUInt32Number Ro, cmsUInt32Number Go, cmsUInt32Number Bo)
+cmsInt32Number CheckOneRGB(cmsHTRANSFORM xform, cmsUInt16Number R, cmsUInt16Number G, cmsUInt16Number B, cmsUInt16Number Ro, cmsUInt16Number Go, cmsUInt16Number Bo)
{
cmsUInt16Number RGB[3];
cmsUInt16Number Out[3];
@@ -5148,7 +5194,10 @@ void ErrorReportingFunction(cmsContext ContextID, cmsUInt32Number ErrorCode, con
{
TrappedError = TRUE;
SimultaneousErrors++;
- strncpy(ReasonToFailBuffer, Text, TEXT_ERROR_BUFFER_SIZE-1);
+ strncpy(ReasonToFailBuffer, Text, TEXT_ERROR_BUFFER_SIZE-1);
+
+ cmsUNUSED_PARAMETER(ContextID);
+ cmsUNUSED_PARAMETER(ErrorCode);
}
@@ -6365,27 +6414,27 @@ cmsInt32Number CheckBlackPoint(void)
cmsCIELab Lab;
hProfile = cmsOpenProfileFromFileTHR(DbgThread(), "test5.icc", "r");
- cmsDetectBlackPoint(&Black, hProfile, INTENT_RELATIVE_COLORIMETRIC, 0);
+ cmsDetectDestinationBlackPoint(&Black, hProfile, INTENT_RELATIVE_COLORIMETRIC, 0);
cmsCloseProfile(hProfile);
hProfile = cmsOpenProfileFromFileTHR(DbgThread(), "test1.icc", "r");
- cmsDetectBlackPoint(&Black, hProfile, INTENT_RELATIVE_COLORIMETRIC, 0);
+ cmsDetectDestinationBlackPoint(&Black, hProfile, INTENT_RELATIVE_COLORIMETRIC, 0);
cmsXYZ2Lab(NULL, &Lab, &Black);
cmsCloseProfile(hProfile);
hProfile = cmsOpenProfileFromFileTHR(DbgThread(), "lcms2cmyk.icc", "r");
- cmsDetectBlackPoint(&Black, hProfile, INTENT_RELATIVE_COLORIMETRIC, 0);
+ cmsDetectDestinationBlackPoint(&Black, hProfile, INTENT_RELATIVE_COLORIMETRIC, 0);
cmsXYZ2Lab(NULL, &Lab, &Black);
cmsCloseProfile(hProfile);
hProfile = cmsOpenProfileFromFileTHR(DbgThread(), "test2.icc", "r");
- cmsDetectBlackPoint(&Black, hProfile, INTENT_RELATIVE_COLORIMETRIC, 0);
+ cmsDetectDestinationBlackPoint(&Black, hProfile, INTENT_RELATIVE_COLORIMETRIC, 0);
cmsXYZ2Lab(NULL, &Lab, &Black);
cmsCloseProfile(hProfile);
hProfile = cmsOpenProfileFromFileTHR(DbgThread(), "test1.icc", "r");
- cmsDetectBlackPoint(&Black, hProfile, INTENT_PERCEPTUAL, 0);
+ cmsDetectDestinationBlackPoint(&Black, hProfile, INTENT_PERCEPTUAL, 0);
cmsXYZ2Lab(NULL, &Lab, &Black);
cmsCloseProfile(hProfile);
@@ -6438,7 +6487,7 @@ cmsInt32Number CheckCGATS(void)
cmsHANDLE it8;
cmsInt32Number i;
-
+ SubTest("IT8 creation");
it8 = cmsIT8Alloc(DbgThread());
if (it8 == NULL) return 0;
@@ -6458,6 +6507,7 @@ cmsInt32Number CheckCGATS(void)
cmsIT8SetDataFormat(it8, 2, "RGB_G");
cmsIT8SetDataFormat(it8, 3, "RGB_B");
+ SubTest("Table creation");
for (i=0; i < NPOINTS_IT8; i++) {
char Patch[20];
@@ -6470,18 +6520,25 @@ cmsInt32Number CheckCGATS(void)
cmsIT8SetDataRowColDbl(it8, i, 3, i);
}
+ SubTest("Save to file");
cmsIT8SaveToFile(it8, "TEST.IT8");
cmsIT8Free(it8);
-
+ SubTest("Load from file");
it8 = cmsIT8LoadFromFile(DbgThread(), "TEST.IT8");
+ if (it8 == NULL) return 0;
+
+ SubTest("Save again file");
cmsIT8SaveToFile(it8, "TEST.IT8");
cmsIT8Free(it8);
-
+ SubTest("Load from file (II)");
it8 = cmsIT8LoadFromFile(DbgThread(), "TEST.IT8");
+ if (it8 == NULL) return 0;
+
+ SubTest("Change prop value");
if (cmsIT8GetPropertyDbl(it8, "DESCRIPTOR") != 1234) {
return 0;
@@ -6489,24 +6546,26 @@ cmsInt32Number CheckCGATS(void)
cmsIT8SetPropertyDbl(it8, "DESCRIPTOR", 5678);
-
if (cmsIT8GetPropertyDbl(it8, "DESCRIPTOR") != 5678) {
return 0;
}
+ SubTest("Positive numbers");
if (cmsIT8GetDataDbl(it8, "P3", "RGB_G") != 3) {
return 0;
}
+ SubTest("Positive exponent numbers");
cmsIT8SetPropertyDbl(it8, "DBL_PROP", 123E+12);
if ((cmsIT8GetPropertyDbl(it8, "DBL_PROP") - 123E+12) > 1 ) {
return 0;
}
+ SubTest("Negative exponent numbers");
cmsIT8SetPropertyDbl(it8, "DBL_PROP_NEG", 123E-45);
if ((cmsIT8GetPropertyDbl(it8, "DBL_PROP_NEG") - 123E-45) > 1E-45 ) {
@@ -6514,6 +6573,13 @@ cmsInt32Number CheckCGATS(void)
}
+ SubTest("Negative numbers");
+ cmsIT8SetPropertyDbl(it8, "DBL_NEG_VAL", -123);
+ if ((cmsIT8GetPropertyDbl(it8, "DBL_NEG_VAL")) != -123 ) {
+
+ return 0;
+ }
+
cmsIT8Free(it8);
remove("TEST.IT8");
@@ -7289,7 +7355,11 @@ void SpeedTest(void)
cmsOpenProfileFromFile("test1.icc", "r"),
cmsOpenProfileFromFile("test2.icc", "r"));
- SpeedTest8bitsGray("8 bits on gray-to-gray",
+ SpeedTest8bitsGray("8 bits on gray-to gray",
+ cmsOpenProfileFromFile("gray3lcms2.icc", "r"),
+ cmsOpenProfileFromFile("graylcms2.icc", "r"), INTENT_RELATIVE_COLORIMETRIC);
+
+ SpeedTest8bitsGray("8 bits on gray-to-lab gray",
cmsOpenProfileFromFile("graylcms2.icc", "r"),
cmsOpenProfileFromFile("glablcms2.icc", "r"), INTENT_RELATIVE_COLORIMETRIC);
@@ -7435,10 +7505,10 @@ void ReadAllLUTS(cmsHPROFILE h)
if (a) cmsPipelineFree(a);
- cmsDetectBlackPoint(&Black, h, INTENT_PERCEPTUAL, 0);
- cmsDetectBlackPoint(&Black, h, INTENT_RELATIVE_COLORIMETRIC, 0);
- cmsDetectBlackPoint(&Black, h, INTENT_SATURATION, 0);
- cmsDetectBlackPoint(&Black, h, INTENT_ABSOLUTE_COLORIMETRIC, 0);
+ cmsDetectDestinationBlackPoint(&Black, h, INTENT_PERCEPTUAL, 0);
+ cmsDetectDestinationBlackPoint(&Black, h, INTENT_RELATIVE_COLORIMETRIC, 0);
+ cmsDetectDestinationBlackPoint(&Black, h, INTENT_SATURATION, 0);
+ cmsDetectDestinationBlackPoint(&Black, h, INTENT_ABSOLUTE_COLORIMETRIC, 0);
cmsDetectTAC(h);
}
@@ -7608,7 +7678,7 @@ int main(int argc, char* argv[])
printf("done.\n");
#ifdef CMS_IS_WINDOWS_
- // CheckProfileZOO();
+ // CheckProfileZOO();
#endif
PrintSupportedIntents();
@@ -7807,3 +7877,4 @@ int main(int argc, char* argv[])
+