diff options
author | Marti Maria <info@littlecms.com> | 2012-05-19 17:07:51 +0200 |
---|---|---|
committer | Marti Maria <info@littlecms.com> | 2012-05-19 17:07:51 +0200 |
commit | 9fc6a31f69d199fe57593927890ef0cb227d5e37 (patch) | |
tree | 91571ef58c54c7a7cc6922591f7cd4d3d6b1789a | |
parent | b6153c3b5b35db07243625933203566eb0b243fd (diff) | |
download | lcms2-9fc6a31f69d199fe57593927890ef0cb227d5e37.tar.gz |
Sync with development sources, See Change Log
-rw-r--r-- | ChangeLog | 12 | ||||
-rw-r--r-- | include/lcms2.h | 23 | ||||
-rw-r--r-- | include/lcms2_plugin.h | 66 | ||||
-rw-r--r-- | src/cmscgats.c | 33 | ||||
-rw-r--r-- | src/cmsgamma.c | 35 | ||||
-rw-r--r-- | src/cmslut.c | 15 | ||||
-rw-r--r-- | src/cmsopt.c | 10 | ||||
-rw-r--r-- | src/cmspack.c | 81 | ||||
-rw-r--r-- | src/cmsplugin.c | 5 | ||||
-rw-r--r-- | src/cmssamp.c | 4 | ||||
-rw-r--r-- | src/cmsvirt.c | 10 | ||||
-rw-r--r-- | src/cmsxform.c | 183 | ||||
-rw-r--r-- | src/lcms2.def | 10 | ||||
-rw-r--r-- | src/lcms2_internal.h | 53 | ||||
-rw-r--r-- | testbed/testcms2.c | 113 |
15 files changed, 471 insertions, 182 deletions
@@ -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[]) + |