diff options
author | Robin Watts <robin@ghostscript.com> | 2011-05-11 16:17:05 +0000 |
---|---|---|
committer | Robin Watts <robin@ghostscript.com> | 2011-05-11 16:20:10 +0000 |
commit | 6469f738123e0c212473f11d38e88bb3650a9087 (patch) | |
tree | c2236b37bc148d7bfcbb4f3dd32a46e1296bcff0 | |
parent | 1d07f53add51362ce5887b599f2dcb360f9cf348 (diff) | |
download | ghostpdl-6469f738123e0c212473f11d38e88bb3650a9087.tar.gz |
LCMS (v1) optimisations for CachedXFORM etc.
Optimise CachedXFORM (and related functions) by using a 'template' header
file and repeatedly including it with different options to generate
different specific versions of the code.
This gives a 10% improvement on 568.40345_VO_nr_3_vpeSR18.xl (a file where
most of the time is spent in clipping).
No expected cluster differences.
-rw-r--r-- | gs/base/lcms.mak | 2 | ||||
-rw-r--r-- | gs/lcms/include/lcms.h | 2 | ||||
-rw-r--r-- | gs/lcms/src/cmspack.c | 109 | ||||
-rw-r--r-- | gs/lcms/src/cmsxform.c | 667 | ||||
-rw-r--r-- | gs/lcms/src/cmsxform.h | 230 |
5 files changed, 553 insertions, 457 deletions
diff --git a/gs/base/lcms.mak b/gs/base/lcms.mak index c7e8e6e71..5014c0ada 100644 --- a/gs/base/lcms.mak +++ b/gs/base/lcms.mak @@ -125,7 +125,7 @@ $(LCMSOBJ)cmsmatsh.$(OBJ) : $(LCMSSRC)cmsmatsh.c $(lcms_HDRS) $(LCMSOBJ)cmsmtrx.$(OBJ) : $(LCMSSRC)cmsmtrx.c $(lcms_HDRS) $(LCMS_CC) $(LCMSO_)cmsmtrx.$(OBJ) $(C_) $(LCMSSRC)cmsmtrx.c -$(LCMSOBJ)cmspack.$(OBJ) : $(LCMSSRC)cmspack.c $(lcms_HDRS) +$(LCMSOBJ)cmspack.$(OBJ) : $(LCMSSRC)cmspack.c $(LCMSSRC)cmsxform.h $(lcms_HDRS) $(LCMS_CC) $(LCMSO_)cmspack.$(OBJ) $(C_) $(LCMSSRC)cmspack.c $(LCMSOBJ)cmspcs.$(OBJ) : $(LCMSSRC)cmspcs.c $(lcms_HDRS) diff --git a/gs/lcms/include/lcms.h b/gs/lcms/include/lcms.h index 7a061e6a1..269299425 100644 --- a/gs/lcms/include/lcms.h +++ b/gs/lcms/include/lcms.h @@ -2056,6 +2056,8 @@ LPGAMMATABLE _cmsBuildKToneCurve(cmsHTRANSFORM hCMYK2CMYK, int nPoints); // Validates a LUT LCMSBOOL cdecl _cmsValidateLUT(LPLUT NewLUT); +// Choose the transform function to use +void _cmsSetPrecalculatedTransform(_LPcmsTRANSFORM p); // These are two VITAL macros, from converting between 8 and 16 bit // representation. diff --git a/gs/lcms/src/cmspack.c b/gs/lcms/src/cmspack.c index c4c16f9d4..5c409b372 100644 --- a/gs/lcms/src/cmspack.c +++ b/gs/lcms/src/cmspack.c @@ -2135,6 +2135,113 @@ void LCMSEXPORT cmsGetUserFormatters(cmsHTRANSFORM hTransform, } +extern WORD _cmsAlarmR, _cmsAlarmG, _cmsAlarmB; + +// RJW: Move the core transform routines in here, so they can benefit from +// being in the same compilation unit as the pack/unpack routines. +#define FUNCTION_NAME PrecalculatedXFORM +#include "cmsxform.h" + +#define FUNCTION_NAME PrecalculatedXFORMGamutCheck +#define GAMUTCHECK +#include "cmsxform.h" + +#define FUNCTION_NAME CachedXFORM +#define CACHED +#include "cmsxform.h" + +#define FUNCTION_NAME CachedXFORM4 +#define CACHED +#define INBYTES 4 +#include "cmsxform.h" + +#define FUNCTION_NAME CachedXFORM8 +#define CACHED +#define INBYTES 8 +#include "cmsxform.h" + +#define FUNCTION_NAME CachedXFORMGamutCheck +#define CACHED +#define GAMUTCHECK +#include "cmsxform.h" + +#define FUNCTION_NAME CachedXFORM3to1 +#define CACHED +#define INBYTES 6 +#define UNPACK(T,D,S) \ +do { \ + (D)[0] = RGB_8_TO_16(*(S)); (S)++; /* R */ \ + (D)[1] = RGB_8_TO_16(*(S)); (S)++; /* G */ \ + (D)[2] = RGB_8_TO_16(*(S)); (S)++; /* B */ \ +} while (0) +#define PACKFN Pack1Byte +#include "cmsxform.h" + +// Auxiliar: Handle precalculated gamut check + +void TransformOnePixelWithGamutCheck(_LPcmsTRANSFORM p, WORD wIn[], WORD wOut[]) +{ + WORD wOutOfGamut; + + cmsEvalLUT(p ->GamutCheck, wIn, &wOutOfGamut); + + if (wOutOfGamut >= 1) { + + ZeroMemory(wOut, sizeof(WORD) * MAXCHANNELS); + + wOut[0] = _cmsAlarmR; + wOut[1] = _cmsAlarmG; + wOut[2] = _cmsAlarmB; + + } + else + cmsEvalLUT(p -> DeviceLink, wIn, wOut); + +} + +// Identify whatever a transform is to be cached + +void _cmsSetPrecalculatedTransform(_LPcmsTRANSFORM p) +{ + if ((p->dwOriginalFlags & cmsFLAGS_GAMUTCHECK) && p ->GamutCheck != NULL) { + + p -> xform = PrecalculatedXFORMGamutCheck; + + if (!(p->dwOriginalFlags & cmsFLAGS_NOTCACHE)) { + + ZeroMemory(p ->CacheIn, sizeof(WORD) * MAXCHANNELS); + TransformOnePixelWithGamutCheck(p, p->CacheIn, p ->CacheOut); + p ->xform = CachedXFORMGamutCheck; + } + + } + else { + + p -> xform = PrecalculatedXFORM; + + if (!(p->dwOriginalFlags & cmsFLAGS_NOTCACHE)) { + + ZeroMemory(p ->CacheIn, sizeof(WORD) * MAXCHANNELS); + cmsEvalLUT(p ->DeviceLink, p->CacheIn, p ->CacheOut); + if ((p->FromInput == Unroll3Bytes) && + (p->ToOutput == Pack1Byte)) + { + p->xform = CachedXFORM3to1; + } else { + int inbytes = (T_CHANNELS(p->InputFormat) * + T_BYTES(p->InputFormat)); + if (inbytes <= 4) + p->xform = CachedXFORM4; + else if (inbytes <= 8) + p->xform = CachedXFORM8; + else + p->xform = CachedXFORM; + } + } + } +} + + // Change format of yet existing transform. No colorspace checking is performed void LCMSEXPORT cmsChangeBuffersFormat(cmsHTRANSFORM hTransform, @@ -2147,4 +2254,6 @@ void LCMSEXPORT cmsChangeBuffersFormat(cmsHTRANSFORM hTransform, (cmsFORMATTER) _cmsIdentifyInputFormat((_LPcmsTRANSFORM) hTransform, dwInputFormat), dwOutputFormat, (cmsFORMATTER) _cmsIdentifyOutputFormat((_LPcmsTRANSFORM) hTransform, dwOutputFormat)); + + _cmsSetPrecalculatedTransform((_LPcmsTRANSFORM) hTransform); } diff --git a/gs/lcms/src/cmsxform.c b/gs/lcms/src/cmsxform.c index 8977c9347..0ca889dde 100644 --- a/gs/lcms/src/cmsxform.c +++ b/gs/lcms/src/cmsxform.c @@ -2,22 +2,22 @@ // Little cms // Copyright (C) 1998-2007 Marti Maria // -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the Software +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the Software // is furnished to do so, subject to the following conditions: // -// The above copyright notice and this permission notice shall be included in +// The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO -// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. @@ -63,7 +63,7 @@ LCMSBOOL LCMSEXPORT cmsIsIntentSupported(cmsHPROFILE hProfile, // Alarm RGB codes -static WORD AlarmR = 0x8fff, AlarmG = 0x8fff, AlarmB = 0x8fff; +WORD _cmsAlarmR = 0x8fff, _cmsAlarmG = 0x8fff, _cmsAlarmB = 0x8fff; // Tag tables, soted by intents @@ -91,7 +91,7 @@ static volatile double GlobalAdaptationState = 0; // --------------------------------Stages-------------------------------------- -// Following routines does implement several kind of steps inside +// Following routines does implement several kind of steps inside // transform. On building the transform, code chooses adequate. @@ -113,7 +113,7 @@ void LUTtoPCS(struct _cmstransform_struct *p, cmsEvalLUT(p -> Device2PCS, In, Out); } -// From indexed named color to PCS +// From indexed named color to PCS static void NC2toPCS(struct _cmstransform_struct *p, @@ -234,12 +234,12 @@ void NormalXFORM(_LPcmsTRANSFORM p, // Gamut check, enabled across CLUT cmsEvalLUT(p -> Gamut, wPCS, wGamut); - - if (wGamut[0] >= 1) { - - wOut[0] = AlarmR; // Gamut alarm - wOut[1] = AlarmG; - wOut[2] = AlarmB; + + if (wGamut[0] >= 1) { + + wOut[0] = _cmsAlarmR; // Gamut alarm + wOut[1] = _cmsAlarmG; + wOut[2] = _cmsAlarmB; wOut[3] = 0; output = p -> ToOutput((_LPcmsTRANSFORM)p, wOut, output); @@ -258,7 +258,7 @@ void NormalXFORM(_LPcmsTRANSFORM p, if (p -> Stage2) { p -> Stage2(wPCS, wStageLMN, &p->m2, &p->of2); - + if (wPCS[0] == 0xFFFF && wPCS[1] == 0xFFFF && wPCS[2] == 0xFFFF) { @@ -284,219 +284,6 @@ void NormalXFORM(_LPcmsTRANSFORM p, } } -// Using precalculated LUT - -static -void PrecalculatedXFORM(_LPcmsTRANSFORM p, - LPVOID in, - LPVOID out, unsigned int Size) -{ - register LPBYTE accum; - register LPBYTE output; - WORD wIn[MAXCHANNELS], wOut[MAXCHANNELS]; - unsigned int i, n; - - - accum = (LPBYTE) in; - output = (LPBYTE) out; - n = Size; // Buffer len - - - for (i=0; i < n; i++) { - - accum = p -> FromInput(p, wIn, accum); - - // Try to speedup things on plain devicelinks - - if (p ->DeviceLink ->wFlags == LUT_HAS3DGRID) { - - p ->DeviceLink ->CLut16params.Interp3D(wIn, wOut, - p ->DeviceLink -> T, - &p ->DeviceLink -> CLut16params); - } - else - cmsEvalLUT(p -> DeviceLink, wIn, wOut); - - - output = p -> ToOutput(p, wOut, output); - } -} - -// Auxiliar: Handle precalculated gamut check - -static -void TransformOnePixelWithGamutCheck(_LPcmsTRANSFORM p, WORD wIn[], WORD wOut[]) -{ - WORD wOutOfGamut; - - cmsEvalLUT(p ->GamutCheck, wIn, &wOutOfGamut); - - if (wOutOfGamut >= 1) { - - ZeroMemory(wOut, sizeof(WORD) * MAXCHANNELS); - - wOut[0] = AlarmR; - wOut[1] = AlarmG; - wOut[2] = AlarmB; - - } - else - cmsEvalLUT(p -> DeviceLink, wIn, wOut); - -} - - -static -void PrecalculatedXFORMGamutCheck(_LPcmsTRANSFORM p, - LPVOID in, - LPVOID out, unsigned int Size) -{ - register LPBYTE accum; - register LPBYTE output; - WORD wIn[MAXCHANNELS], wOut[MAXCHANNELS]; - register unsigned int i, n; - - - accum = (LPBYTE) in; - output = (LPBYTE) out; - n = Size; // Buffer len - - for (i=0; i < n; i++) { - - accum = p -> FromInput(p, wIn, accum); - - TransformOnePixelWithGamutCheck(p, wIn, wOut); - - output = p -> ToOutput(p, wOut, output); - } -} - - - -// Using precalculated LUT + Cache - -static -void CachedXFORM(_LPcmsTRANSFORM p, - LPVOID in, - LPVOID out, unsigned int Size) -{ - register LPBYTE accum; - register LPBYTE output; - WORD wIn[MAXCHANNELS], wOut[MAXCHANNELS]; - register unsigned int i, n; - WORD CacheIn[MAXCHANNELS], CacheOut[MAXCHANNELS]; - - - accum = (LPBYTE) in; - output = (LPBYTE) out; - n = Size; // Buffer len - - // Empty buffers for quick memcmp - - ZeroMemory(wIn, sizeof(WORD) * MAXCHANNELS); - ZeroMemory(wOut, sizeof(WORD) * MAXCHANNELS); - - - LCMS_READ_LOCK(&p ->rwlock); - CopyMemory(CacheIn, p ->CacheIn, sizeof(WORD) * MAXCHANNELS); - CopyMemory(CacheOut, p ->CacheOut, sizeof(WORD) * MAXCHANNELS); - LCMS_UNLOCK(&p ->rwlock); - - for (i=0; i < n; i++) { - - accum = p -> FromInput(p, wIn, accum); - - - if (memcmp(wIn, CacheIn, sizeof(WORD) * MAXCHANNELS) == 0) { - - CopyMemory(wOut, CacheOut, sizeof(WORD) * MAXCHANNELS); - } - else { - - // Try to speedup things on plain devicelinks - - if (p ->DeviceLink ->wFlags == LUT_HAS3DGRID) { - - p ->DeviceLink ->CLut16params.Interp3D(wIn, wOut, - p ->DeviceLink -> T, - &p ->DeviceLink -> CLut16params); - } - else - cmsEvalLUT(p -> DeviceLink, wIn, wOut); - - - CopyMemory(CacheIn, wIn, sizeof(WORD) * MAXCHANNELS); - CopyMemory(CacheOut, wOut, sizeof(WORD) * MAXCHANNELS); - } - - output = p -> ToOutput(p, wOut, output); - } - - - LCMS_WRITE_LOCK(&p ->rwlock); - CopyMemory(p->CacheIn, CacheIn, sizeof(WORD) * MAXCHANNELS); - CopyMemory(p->CacheOut, CacheOut, sizeof(WORD) * MAXCHANNELS); - LCMS_UNLOCK(&p ->rwlock); - -} - - - -// Using precalculated LUT + Cache - -static -void CachedXFORMGamutCheck(_LPcmsTRANSFORM p, - LPVOID in, - LPVOID out, unsigned int Size) -{ - register LPBYTE accum; - register LPBYTE output; - WORD wIn[MAXCHANNELS], wOut[MAXCHANNELS]; - register unsigned int i, n; - WORD CacheIn[MAXCHANNELS], CacheOut[MAXCHANNELS]; - - - accum = (LPBYTE) in; - output = (LPBYTE) out; - n = Size; // Buffer len - - // Empty buffers for quick memcmp - - ZeroMemory(wIn, sizeof(WORD) * MAXCHANNELS); - ZeroMemory(wOut, sizeof(WORD) * MAXCHANNELS); - - LCMS_READ_LOCK(&p ->rwlock); - CopyMemory(CacheIn, p ->CacheIn, sizeof(WORD) * MAXCHANNELS); - CopyMemory(CacheOut, p ->CacheOut, sizeof(WORD) * MAXCHANNELS); - LCMS_UNLOCK(&p ->rwlock); - - - for (i=0; i < n; i++) { - - accum = p -> FromInput(p, wIn, accum); - - if (memcmp(wIn, CacheIn, sizeof(WORD) * MAXCHANNELS) == 0) { - - CopyMemory(wOut, CacheOut, sizeof(WORD) * MAXCHANNELS); - } - else { - - TransformOnePixelWithGamutCheck(p, wIn, wOut); - - CopyMemory(CacheIn, wIn, sizeof(WORD) * MAXCHANNELS); - CopyMemory(CacheOut, wOut, sizeof(WORD) * MAXCHANNELS); - } - - output = p -> ToOutput(p, wOut, output); - } - - LCMS_WRITE_LOCK(&p ->rwlock); - CopyMemory(p->CacheIn, CacheIn, sizeof(WORD) * MAXCHANNELS); - CopyMemory(p->CacheOut, CacheOut, sizeof(WORD) * MAXCHANNELS); - LCMS_UNLOCK(&p ->rwlock); -} - - // Using smelted Matrix/Shaper static @@ -542,11 +329,11 @@ void NC2deviceXform(_LPcmsTRANSFORM p, for (i=0; i < Size; i++) { - accum = p -> FromInput(p, wIn, accum); + accum = p -> FromInput(p, wIn, accum); CopyMemory(wOut, p ->NamedColorList->List[wIn[0]].DeviceColorant, sizeof(WORD) * MAXCHANNELS); output = p -> ToOutput(p, wOut, output); } - + } @@ -617,12 +404,12 @@ LPMATSHAPER cmsBuildGrayInputMatrixShaper(cmsHPROFILE hProfile) else { Shapes[0] = cmsDupGamma(GrayTRC); Shapes[1] = cmsDupGamma(GrayTRC); - Shapes[2] = cmsDupGamma(GrayTRC); + Shapes[2] = cmsDupGamma(GrayTRC); } - + if (!Shapes[0] || !Shapes[1] || !Shapes[2]) return NULL; - + cmsFreeGamma(GrayTRC); // R=G=B as precondition @@ -630,8 +417,8 @@ LPMATSHAPER cmsBuildGrayInputMatrixShaper(cmsHPROFILE hProfile) VEC3init(&Scale.v[0], Illuminant.X/3, Illuminant.X/3, Illuminant.X/3); VEC3init(&Scale.v[1], Illuminant.Y/3, Illuminant.Y/3, Illuminant.Y/3); VEC3init(&Scale.v[2], Illuminant.Z/3, Illuminant.Z/3, Illuminant.Z/3); - - + + MatShaper = cmsAllocMatShaper(&Scale, Shapes, MATSHAPER_INPUT); cmsFreeGammaTriple(Shapes); return MatShaper; @@ -648,27 +435,27 @@ LPMATSHAPER cmsBuildGrayOutputMatrixShaper(cmsHPROFILE hProfile) LPGAMMATABLE GrayTRC, Shapes[3]; LPMATSHAPER MatShaper; MAT3 Scale; - + cmsTakeIluminant(&Illuminant, hProfile); - // That is a special case for non-compliant profiles. + // That is a special case for non-compliant profiles. if (cmsGetPCS(hProfile) == icSigLabData) { - + LPGAMMATABLE Shapes1[3]; GrayTRC = cmsReadICCGamma(hProfile, icSigGrayTRCTag); FromLstarToXYZ(GrayTRC, Shapes1); - if (GrayTRC == NULL) - return NULL; + if (GrayTRC == NULL) + return NULL; // Reversing must be done after curve translation Shapes[0] = cmsReverseGamma(Shapes1[0]->nEntries, Shapes1[0]); Shapes[1] = cmsReverseGamma(Shapes1[1]->nEntries, Shapes1[1]); Shapes[2] = cmsReverseGamma(Shapes1[2]->nEntries, Shapes1[2]); - + cmsFreeGammaTriple(Shapes1); } @@ -678,24 +465,24 @@ LPMATSHAPER cmsBuildGrayOutputMatrixShaper(cmsHPROFILE hProfile) GrayTRC = cmsReadICCGammaReversed(hProfile, icSigGrayTRCTag); // Y - if (GrayTRC == NULL) - return NULL; + if (GrayTRC == NULL) + return NULL; Shapes[0] = cmsDupGamma(GrayTRC); Shapes[1] = cmsDupGamma(GrayTRC); - Shapes[2] = cmsDupGamma(GrayTRC); + Shapes[2] = cmsDupGamma(GrayTRC); } - + if (!Shapes[0] || !Shapes[1] || !Shapes[2]) return NULL; - + cmsFreeGamma(GrayTRC); VEC3init(&Scale.v[0], 0, 1.0/Illuminant.Y, 0); VEC3init(&Scale.v[1], 0, 1.0/Illuminant.Y, 0); VEC3init(&Scale.v[2], 0, 1.0/Illuminant.Y, 0); - - + + MatShaper = cmsAllocMatShaper(&Scale, Shapes, MATSHAPER_OUTPUT); cmsFreeGammaTriple(Shapes); return MatShaper; @@ -717,8 +504,8 @@ LPMATSHAPER cmsBuildInputMatrixShaper(cmsHPROFILE InputProfile) // iluminant, scaled across GrayTRC if (cmsGetColorSpace(InputProfile) == icSigGrayData) - { - return cmsBuildGrayInputMatrixShaper(InputProfile); + { + return cmsBuildGrayInputMatrixShaper(InputProfile); } if (!cmsReadICCMatrixRGB2XYZ(&DoubleMat, InputProfile)) @@ -734,7 +521,7 @@ LPMATSHAPER cmsBuildInputMatrixShaper(cmsHPROFILE InputProfile) InMatSh = cmsAllocMatShaper(&DoubleMat, Shapes, MATSHAPER_INPUT); cmsFreeGammaTriple(Shapes); - + return InMatSh; } @@ -748,11 +535,11 @@ LPMATSHAPER cmsBuildOutputMatrixShaper(cmsHPROFILE OutputProfile) LPGAMMATABLE InverseShapes[3]; LPMATSHAPER OutMatSh; - + if (cmsGetColorSpace(OutputProfile) == icSigGrayData) - { - return cmsBuildGrayOutputMatrixShaper(OutputProfile); + { + return cmsBuildGrayOutputMatrixShaper(OutputProfile); } @@ -762,11 +549,11 @@ LPMATSHAPER cmsBuildOutputMatrixShaper(cmsHPROFILE OutputProfile) if (MAT3inverse(&DoubleMat, &DoubleInv) < 0) return NULL; - + InverseShapes[0] = cmsReadICCGammaReversed(OutputProfile, icSigRedTRCTag); InverseShapes[1] = cmsReadICCGammaReversed(OutputProfile, icSigGreenTRCTag); InverseShapes[2] = cmsReadICCGammaReversed(OutputProfile, icSigBlueTRCTag); - + if (InverseShapes[0] == NULL || InverseShapes[1] == NULL || InverseShapes[2] == NULL) return NULL; @@ -774,7 +561,7 @@ LPMATSHAPER cmsBuildOutputMatrixShaper(cmsHPROFILE OutputProfile) OutMatSh = cmsAllocMatShaper(&DoubleInv, InverseShapes, MATSHAPER_OUTPUT); cmsFreeGammaTriple(InverseShapes); - + return OutMatSh; } @@ -787,8 +574,8 @@ LCMSBOOL cmsBuildSmeltMatShaper(_LPcmsTRANSFORM p) { MAT3 From, To, ToInv, Transfer; LPGAMMATABLE In[3], InverseOut[3]; - - + + if (!cmsReadICCMatrixRGB2XYZ(&From, p -> InputProfile)) return FALSE; @@ -797,14 +584,14 @@ LCMSBOOL cmsBuildSmeltMatShaper(_LPcmsTRANSFORM p) return FALSE; // invert dest - + if (MAT3inverse(&To, &ToInv) < 0) return FALSE; // Multiply - MAT3per(&Transfer, &ToInv, &From); - - + MAT3per(&Transfer, &ToInv, &From); + + // Read gamma curves In[0] = cmsReadICCGamma(p -> InputProfile, icSigRedTRCTag); @@ -813,14 +600,14 @@ LCMSBOOL cmsBuildSmeltMatShaper(_LPcmsTRANSFORM p) if (!In[0] || !In[1] || !In[2]) return FALSE; - + InverseOut[0] = cmsReadICCGammaReversed(p -> OutputProfile, icSigRedTRCTag); InverseOut[1] = cmsReadICCGammaReversed(p -> OutputProfile, icSigGreenTRCTag); InverseOut[2] = cmsReadICCGammaReversed(p -> OutputProfile, icSigBlueTRCTag); if (!InverseOut[0] || !InverseOut[1] || !InverseOut[2]) { - cmsFreeGammaTriple(In); + cmsFreeGammaTriple(In); return FALSE; } @@ -828,7 +615,7 @@ LCMSBOOL cmsBuildSmeltMatShaper(_LPcmsTRANSFORM p) cmsFreeGammaTriple(In); cmsFreeGammaTriple(InverseOut); - + return (p -> SmeltMatShaper != NULL); } @@ -841,7 +628,7 @@ LCMSBOOL cmsBuildSmeltMatShaper(_LPcmsTRANSFORM p) static int GetPhase(cmsHPROFILE hProfile) -{ +{ switch (cmsGetPCS(hProfile)) { case icSigXYZData: return XYZRel; @@ -877,9 +664,9 @@ void TakeConversionRoutines(_LPcmsTRANSFORM p, int DoBPC) cmsTakeMediaBlackPoint(&BlackPointOut, p -> OutputProfile); cmsReadChromaticAdaptationMatrix(&ChromaticAdaptationMatrixOut, p -> OutputProfile); - + if (p -> Preview == NULL && p ->Gamut == NULL) // Non-proofing - { + { if (p ->Intent == INTENT_PERCEPTUAL || p ->Intent == INTENT_SATURATION) { @@ -896,34 +683,34 @@ void TakeConversionRoutines(_LPcmsTRANSFORM p, int DoBPC) // Black point compensation does not apply to absolute intent - if (p ->Intent == INTENT_ABSOLUTE_COLORIMETRIC) + if (p ->Intent == INTENT_ABSOLUTE_COLORIMETRIC) DoBPC = FALSE; // Black point compensation does not apply to devicelink profiles - + if (cmsGetDeviceClass(p ->InputProfile) == icSigLinkClass) DoBPC = FALSE; if (cmsGetDeviceClass(p ->OutputProfile) == icSigLinkClass) DoBPC = FALSE; - + if (DoBPC) { - + // Detect Black points cmsDetectBlackPoint(&BlackPointIn, p->InputProfile, p->Intent, 0); - cmsDetectBlackPoint(&BlackPointOut, p->OutputProfile, p->Intent, 0); + cmsDetectBlackPoint(&BlackPointOut, p->OutputProfile, p->Intent, 0); // If equal black points, then do nothing. This often applies to BP=0 if (BlackPointIn.X == BlackPointOut.X && BlackPointIn.Y == BlackPointOut.Y && - BlackPointIn.Z == BlackPointOut.Z) + BlackPointIn.Z == BlackPointOut.Z) DoBPC = FALSE; } - + cmsChooseCnvrt(p -> Intent == INTENT_ABSOLUTE_COLORIMETRIC, p -> Phase1, @@ -947,7 +734,7 @@ void TakeConversionRoutines(_LPcmsTRANSFORM p, int DoBPC) else // Proofing { - + cmsTakeIluminant(&IlluminantProof, p -> PreviewProfile); cmsTakeMediaWhitePoint(&WhitePointProof, p -> PreviewProfile); cmsTakeMediaBlackPoint(&BlackPointProof, p -> PreviewProfile); @@ -957,19 +744,19 @@ void TakeConversionRoutines(_LPcmsTRANSFORM p, int DoBPC) cmsDetectBlackPoint(&BlackPointProof, p->PreviewProfile, p->Intent, 0); cmsDetectBlackPoint(&BlackPointIn, p->InputProfile, p->Intent, 0); - cmsDetectBlackPoint(&BlackPointOut, p->OutputProfile, p->Intent, 0); - + cmsDetectBlackPoint(&BlackPointOut, p->OutputProfile, p->Intent, 0); + // Reality check if (BlackPointIn.X == BlackPointProof.X && BlackPointIn.Y == BlackPointProof.Y && - BlackPointIn.Z == BlackPointProof.Z) + BlackPointIn.Z == BlackPointProof.Z) DoBPC = FALSE; } - + cmsChooseCnvrt(p -> Intent == INTENT_ABSOLUTE_COLORIMETRIC, @@ -1068,43 +855,11 @@ _LPcmsTRANSFORM AllocEmptyTransform(void) return p; } - -// Identify whatever a transform is to be cached - -static -void SetPrecalculatedTransform(_LPcmsTRANSFORM p) -{ - if ((p->dwOriginalFlags & cmsFLAGS_GAMUTCHECK) && p ->GamutCheck != NULL) { - - p -> xform = PrecalculatedXFORMGamutCheck; - - if (!(p->dwOriginalFlags & cmsFLAGS_NOTCACHE)) { - - ZeroMemory(p ->CacheIn, sizeof(WORD) * MAXCHANNELS); - TransformOnePixelWithGamutCheck(p, p->CacheIn, p ->CacheOut); - p ->xform = CachedXFORMGamutCheck; - } - - } - else { - - p -> xform = PrecalculatedXFORM; - - if (!(p->dwOriginalFlags & cmsFLAGS_NOTCACHE)) { - - ZeroMemory(p ->CacheIn, sizeof(WORD) * MAXCHANNELS); - cmsEvalLUT(p ->DeviceLink, p->CacheIn, p ->CacheOut); - p ->xform = CachedXFORM; - } - } -} - - // Transform is identified as device-link -static +static cmsHPROFILE CreateDeviceLinkTransform(_LPcmsTRANSFORM p) { - + if (!IsProperColorSpace(p->InputProfile, p->InputFormat, FALSE)) { cmsSignalError(LCMS_ERRC_ABORTED, "Device link is operating on wrong colorspace on input"); return NULL; @@ -1138,17 +893,17 @@ cmsHPROFILE CreateDeviceLinkTransform(_LPcmsTRANSFORM p) p -> Phase2 = -1; p -> Phase3 = -1; - SetPrecalculatedTransform(p); - + _cmsSetPrecalculatedTransform(p); + p -> EntryColorSpace = cmsGetColorSpace(p -> InputProfile); p -> ExitColorSpace = cmsGetPCS(p -> InputProfile); - + if (p ->EntryColorSpace == icSigRgbData || p ->EntryColorSpace == icSigCmyData) { - + p->DeviceLink -> CLut16params.Interp3D = cmsTetrahedralInterp16; } - + // Precalculated device-link profile is ready return (cmsHTRANSFORM) p; } @@ -1160,13 +915,13 @@ void CreateProof(_LPcmsTRANSFORM p, icTagSignature *ToTagPtr) { icTagSignature ProofTag; - + if (p -> dwOriginalFlags & cmsFLAGS_SOFTPROOFING) { // Apr-15, 2002 - Too much profiles does have bogus content // on preview tag, so I do compute it by my own. - p -> Preview = _cmsComputeSoftProofLUT(p ->PreviewProfile, p ->Intent); + p -> Preview = _cmsComputeSoftProofLUT(p ->PreviewProfile, p ->Intent); p -> Phase2 = LabRel; // That's a proofing transfor, so use second intent for output. @@ -1174,7 +929,7 @@ void CreateProof(_LPcmsTRANSFORM p, icTagSignature *ToTagPtr) *ToTagPtr = PCS2Device[p->ProofIntent]; if (p -> Preview == NULL) { - + ProofTag = Preview[p -> Intent]; if (!cmsIsTag(p ->PreviewProfile, ProofTag)) { @@ -1188,7 +943,7 @@ void CreateProof(_LPcmsTRANSFORM p, icTagSignature *ToTagPtr) p -> Preview = cmsReadICCLut(p ->PreviewProfile, ProofTag); p -> Phase2 = GetPhase(p ->PreviewProfile); - + } else { @@ -1197,7 +952,7 @@ void CreateProof(_LPcmsTRANSFORM p, icTagSignature *ToTagPtr) cmsSignalError(LCMS_ERRC_WARNING, "Sorry, the proof profile has not previewing capabilities"); } } - + } @@ -1206,23 +961,23 @@ void CreateProof(_LPcmsTRANSFORM p, icTagSignature *ToTagPtr) if ((p -> dwOriginalFlags & cmsFLAGS_GAMUTCHECK) && (p -> dwOriginalFlags & cmsFLAGS_NOTPRECALC)) { - - p -> Gamut = _cmsComputeGamutLUT(p->PreviewProfile, p ->Intent); + + p -> Gamut = _cmsComputeGamutLUT(p->PreviewProfile, p ->Intent); p -> Phase2 = LabRel; if (p -> Gamut == NULL) { - // Profile goes only in one direction... try to see + // Profile goes only in one direction... try to see // if profile has the tag, and use it, no matter it // could be bogus. This is the last chance! if (cmsIsTag(p ->PreviewProfile, icSigGamutTag)) { p -> Gamut = cmsReadICCLut(p ->PreviewProfile, icSigGamutTag); - + } else { - + // Nope, cannot be done. cmsSignalError(LCMS_ERRC_WARNING, "Sorry, the proof profile has not gamut checking capabilities"); @@ -1237,13 +992,13 @@ void CreateProof(_LPcmsTRANSFORM p, icTagSignature *ToTagPtr) // Choose the adequate transform routine static -_LPcmsTRANSFORM PickTransformRoutine(_LPcmsTRANSFORM p, +_LPcmsTRANSFORM PickTransformRoutine(_LPcmsTRANSFORM p, icTagSignature *FromTagPtr, icTagSignature *ToTagPtr) { - - + + // Is a named color profile? if (cmsGetDeviceClass(p->InputProfile) == icSigNamedColorClass) { @@ -1254,11 +1009,11 @@ _LPcmsTRANSFORM PickTransformRoutine(_LPcmsTRANSFORM p, else { // Can we optimize matrix-shaper only transform? - if ((*FromTagPtr == 0) && - (*ToTagPtr == 0) && - (!p->PreviewProfile) && - (p -> Intent != INTENT_ABSOLUTE_COLORIMETRIC) && - (p -> EntryColorSpace == icSigRgbData) && + if ((*FromTagPtr == 0) && + (*ToTagPtr == 0) && + (!p->PreviewProfile) && + (p -> Intent != INTENT_ABSOLUTE_COLORIMETRIC) && + (p -> EntryColorSpace == icSigRgbData) && (p -> ExitColorSpace == icSigRgbData) && !(p -> dwOriginalFlags & cmsFLAGS_BLACKPOINTCOMPENSATION)) { @@ -1268,7 +1023,7 @@ _LPcmsTRANSFORM PickTransformRoutine(_LPcmsTRANSFORM p, if (!cmsBuildSmeltMatShaper(p)) { - cmsSignalError(LCMS_ERRC_ABORTED, "unable to smelt shaper-matrix, required tags missing"); + cmsSignalError(LCMS_ERRC_ABORTED, "unable to smelt shaper-matrix, required tags missing"); return NULL; } @@ -1285,7 +1040,7 @@ _LPcmsTRANSFORM PickTransformRoutine(_LPcmsTRANSFORM p, p -> Device2PCS = cmsReadICCLut(p -> InputProfile, *FromTagPtr); if (!p -> Device2PCS) { - cmsSignalError(LCMS_ERRC_ABORTED, "profile is unsuitable for input"); + cmsSignalError(LCMS_ERRC_ABORTED, "profile is unsuitable for input"); return NULL; } @@ -1296,7 +1051,7 @@ _LPcmsTRANSFORM PickTransformRoutine(_LPcmsTRANSFORM p, p -> InMatShaper = cmsBuildInputMatrixShaper(p -> InputProfile); if (!p ->InMatShaper) { - cmsSignalError(LCMS_ERRC_ABORTED, "profile is unsuitable for input"); + cmsSignalError(LCMS_ERRC_ABORTED, "profile is unsuitable for input"); return NULL; } @@ -1310,7 +1065,7 @@ _LPcmsTRANSFORM PickTransformRoutine(_LPcmsTRANSFORM p, p -> ToDevice = PCStoLUT; p -> PCS2Device = cmsReadICCLut(p -> OutputProfile, *ToTagPtr); if (!p -> PCS2Device) { - cmsSignalError(LCMS_ERRC_ABORTED, "profile is unsuitable for output"); + cmsSignalError(LCMS_ERRC_ABORTED, "profile is unsuitable for output"); return NULL; } @@ -1321,13 +1076,13 @@ _LPcmsTRANSFORM PickTransformRoutine(_LPcmsTRANSFORM p, p -> OutMatShaper = cmsBuildOutputMatrixShaper(p->OutputProfile); if (!p -> OutMatShaper) { - cmsSignalError(LCMS_ERRC_ABORTED, "profile is unsuitable for output"); + cmsSignalError(LCMS_ERRC_ABORTED, "profile is unsuitable for output"); return NULL; } p -> Phase3 = XYZRel; - + } - + return p; } @@ -1350,7 +1105,7 @@ cmsHTRANSFORM LCMSEXPORT cmsCreateProofingTransform(cmsHPROFILE InputProfile, _LPcmsTRANSFORM p; icTagSignature FromTag; icTagSignature ToTag; - + if (nIntent < 0 || nIntent > 3 || ProofingIntent < 0 || ProofingIntent > 3) { @@ -1367,7 +1122,7 @@ cmsHTRANSFORM LCMSEXPORT cmsCreateProofingTransform(cmsHPROFILE InputProfile, p -> DoGamutCheck = FALSE; p -> InputProfile = InputProfile; p -> OutputProfile = OutputProfile; - p -> PreviewProfile = ProofingProfile; + p -> PreviewProfile = ProofingProfile; p -> InputFormat = InputFormat; p -> OutputFormat = OutputFormat; p -> dwOriginalFlags = dwFlags; @@ -1389,7 +1144,7 @@ cmsHTRANSFORM LCMSEXPORT cmsCreateProofingTransform(cmsHPROFILE InputProfile, // From here we need at least one input profile if (InputProfile == NULL) { - + cmsSignalError(LCMS_ERRC_ABORTED, "Input profile cannot be NULL!"); cmsDeleteTransform((cmsHTRANSFORM) p); return NULL; @@ -1401,7 +1156,7 @@ cmsHTRANSFORM LCMSEXPORT cmsCreateProofingTransform(cmsHPROFILE InputProfile, return CreateDeviceLinkTransform(p); } - + if (!IsProperColorSpace(InputProfile, InputFormat, FALSE)) { cmsSignalError(LCMS_ERRC_ABORTED, "Input profile is operating on wrong colorspace"); @@ -1418,7 +1173,7 @@ cmsHTRANSFORM LCMSEXPORT cmsCreateProofingTransform(cmsHPROFILE InputProfile, p ->NamedColorList = cmsAllocNamedColorList(0); cmsReadICCnamedColorList(p, InputProfile, icSigNamedColor2Tag); - + // Special case. If output profile == NULL, then the transform gives // device values from named colors. @@ -1433,18 +1188,18 @@ cmsHTRANSFORM LCMSEXPORT cmsCreateProofingTransform(cmsHPROFILE InputProfile, p -> dwOriginalFlags |= cmsFLAGS_NOTPRECALC; } - + // From here we need also output profile. - if (OutputProfile == NULL) { + if (OutputProfile == NULL) { cmsSignalError(LCMS_ERRC_ABORTED, "Output profile cannot be NULL!"); cmsDeleteTransform((cmsHTRANSFORM) p); return NULL; } - + if (!IsProperColorSpace(OutputProfile, OutputFormat, FALSE)) { cmsSignalError(LCMS_ERRC_ABORTED, "Output profile is operating on wrong colorspace"); - cmsDeleteTransform((cmsHTRANSFORM) p); + cmsDeleteTransform((cmsHTRANSFORM) p); return NULL; } @@ -1477,22 +1232,22 @@ cmsHTRANSFORM LCMSEXPORT cmsCreateProofingTransform(cmsHPROFILE InputProfile, } // If proofing is needed, add required tags/parameters - if (ProofingProfile) - CreateProof(p, &ToTag); - + if (ProofingProfile) + CreateProof(p, &ToTag); + if (!cmsIsTag(OutputProfile, ToTag)) { ToTag = PCS2Device[0]; - // 12-Dec-2003, Abstract profiles can be placed as output and still using AToB0 + // 12-Dec-2003, Abstract profiles can be placed as output and still using AToB0 if (cmsGetDeviceClass(OutputProfile) == icSigAbstractClass) { - + if (!cmsIsTag(OutputProfile, ToTag)) { ToTag = (icTagSignature) icSigAToB0Tag; - } + } } - + if (!cmsIsTag(OutputProfile, ToTag)) ToTag = (icTagSignature)0; } @@ -1504,8 +1259,8 @@ cmsHTRANSFORM LCMSEXPORT cmsCreateProofingTransform(cmsHPROFILE InputProfile, if (p -> dwOriginalFlags & cmsFLAGS_MATRIXOUTPUT) ToTag = (icTagSignature)0; - - + + if (PickTransformRoutine(p, &FromTag, &ToTag) == NULL) { cmsDeleteTransform((cmsHTRANSFORM) p); @@ -1517,9 +1272,9 @@ cmsHTRANSFORM LCMSEXPORT cmsCreateProofingTransform(cmsHPROFILE InputProfile, if (!(p -> dwOriginalFlags & cmsFLAGS_NOTPRECALC)) { - LPLUT DeviceLink; + LPLUT DeviceLink; LPLUT GamutCheck = NULL; - + if (p ->EntryColorSpace == icSigCmykData && p ->ExitColorSpace == icSigCmykData && @@ -1528,44 +1283,44 @@ cmsHTRANSFORM LCMSEXPORT cmsCreateProofingTransform(cmsHPROFILE InputProfile, DeviceLink = _cmsPrecalculateBlackPreservingDeviceLink((cmsHTRANSFORM) p, dwFlags); // Cannot be done at all? - if (DeviceLink == NULL) + if (DeviceLink == NULL) DeviceLink = _cmsPrecalculateDeviceLink((cmsHTRANSFORM) p, dwFlags); - } + } else { DeviceLink = _cmsPrecalculateDeviceLink((cmsHTRANSFORM) p, dwFlags); } - - // Allow to specify cmsFLAGS_GAMUTCHECK, even if no proofing profile is given + + // Allow to specify cmsFLAGS_GAMUTCHECK, even if no proofing profile is given if ((p ->PreviewProfile != NULL) && (p -> dwOriginalFlags & cmsFLAGS_GAMUTCHECK)) { GamutCheck = _cmsPrecalculateGamutCheck((cmsHTRANSFORM) p); } // If input colorspace is Rgb, Cmy, then use tetrahedral interpolation - // for speed reasons (it only works well on spaces on Luma is diagonal, and + // for speed reasons (it only works well on spaces on Luma is diagonal, and // not if luma is in separate channel) if (p ->EntryColorSpace == icSigRgbData || p ->EntryColorSpace == icSigCmyData) { - - + + cmsCalcCLUT16ParamsEx(DeviceLink->CLut16params.nSamples, DeviceLink->CLut16params.nInputs, - DeviceLink->CLut16params.nOutputs, + DeviceLink->CLut16params.nOutputs, TRUE, &DeviceLink->CLut16params); - + } - + // If this is a 8-bit transform, optimize LUT further. - + if ((T_BYTES(InputFormat) == 1) && (T_CHANNELS(InputFormat) == 3)) { DeviceLink = _cmsBlessLUT8(DeviceLink); if (DeviceLink == NULL) return NULL; } - + p ->GamutCheck = GamutCheck; @@ -1573,7 +1328,7 @@ cmsHTRANSFORM LCMSEXPORT cmsCreateProofingTransform(cmsHPROFILE InputProfile, p ->DeviceLink = DeviceLink; - if ((nIntent != INTENT_ABSOLUTE_COLORIMETRIC) && + if ((nIntent != INTENT_ABSOLUTE_COLORIMETRIC) && !(p -> dwOriginalFlags & cmsFLAGS_NOWHITEONWHITEFIXUP)) _cmsFixWhiteMisalignment(p); @@ -1591,8 +1346,8 @@ cmsHTRANSFORM LCMSEXPORT cmsCreateProofingTransform(cmsHPROFILE InputProfile, } - SetPrecalculatedTransform(p); - + _cmsSetPrecalculatedTransform(p); + } @@ -1600,7 +1355,7 @@ cmsHTRANSFORM LCMSEXPORT cmsCreateProofingTransform(cmsHPROFILE InputProfile, p -> FromInput = _cmsIdentifyInputFormat(p, InputFormat); p -> ToOutput = _cmsIdentifyOutputFormat(p, OutputFormat); - + return p; } @@ -1648,7 +1403,7 @@ void LCMSEXPORT cmsDeleteTransform(cmsHTRANSFORM hTransform) if (p ->NamedColorList) cmsFreeNamedColorList(p ->NamedColorList); if (p -> GamutCheck) - cmsFreeLUT(p -> GamutCheck); + cmsFreeLUT(p -> GamutCheck); LCMS_FREE_LOCK(&p->rwlock); @@ -1666,7 +1421,7 @@ void LCMSEXPORT cmsDoTransform(cmsHTRANSFORM Transform, _LPcmsTRANSFORM p = (_LPcmsTRANSFORM) (LPSTR) Transform; p -> StrideIn = p -> StrideOut = Size; - + p -> xform(p, InputBuffer, OutputBuffer, Size); } @@ -1674,26 +1429,26 @@ void LCMSEXPORT cmsDoTransform(cmsHTRANSFORM Transform, void LCMSEXPORT cmsSetAlarmCodes(int r, int g, int b) { - AlarmR = RGB_8_TO_16(r); - AlarmG = RGB_8_TO_16(g); - AlarmB = RGB_8_TO_16(b); + _cmsAlarmR = RGB_8_TO_16(r); + _cmsAlarmG = RGB_8_TO_16(g); + _cmsAlarmB = RGB_8_TO_16(b); } void LCMSEXPORT cmsGetAlarmCodes(int *r, int *g, int *b) { - *r = RGB_16_TO_8(AlarmR); - *g = RGB_16_TO_8(AlarmG); - *b = RGB_16_TO_8(AlarmB); + *r = RGB_16_TO_8(_cmsAlarmR); + *g = RGB_16_TO_8(_cmsAlarmG); + *b = RGB_16_TO_8(_cmsAlarmB); } // Returns TRUE if the profile is implemented as matrix-shaper LCMSBOOL LCMSEXPORT _cmsIsMatrixShaper(cmsHPROFILE hProfile) -{ +{ switch (cmsGetColorSpace(hProfile)) { case icSigGrayData: - + return cmsIsTag(hProfile, icSigGrayTRCTag); case icSigRgbData: @@ -1740,20 +1495,20 @@ LCMSBOOL LCMSEXPORT cmsIsIntentSupported(cmsHPROFILE hProfile, return (cmsTakeRenderingIntent(hProfile) == Intent); } -// Multiple profile transform. +// Multiple profile transform. static int MultiprofileSampler(register WORD In[], register WORD Out[], register LPVOID Cargo) { cmsHTRANSFORM* Transforms = (cmsHTRANSFORM*) Cargo; int i; - + cmsDoTransform(Transforms[0], In, Out, 1); for (i=1; Transforms[i]; i++) cmsDoTransform(Transforms[i], Out, Out, 1); - + return TRUE; } @@ -1783,14 +1538,14 @@ cmsHTRANSFORM LCMSEXPORT cmsCreateMultiprofileTransform(cmsHPROFILE hProfiles[], cmsHTRANSFORM Transforms[257]; DWORD dwPrecalcFlags = (dwFlags|cmsFLAGS_NOTPRECALC|cmsFLAGS_NOTCACHE); DWORD FormatInput, FormatOutput; - cmsHPROFILE hLab, hXYZ, hProfile; + cmsHPROFILE hLab, hXYZ, hProfile; icColorSpaceSignature ColorSpace, CurrentColorSpace; - icColorSpaceSignature ColorSpaceIn, ColorSpaceOut; + icColorSpaceSignature ColorSpaceIn, ColorSpaceOut; LPLUT Grid; - int nGridPoints, ChannelsInput, ChannelsOutput = 3, i; - _LPcmsTRANSFORM p; + int nGridPoints, ChannelsInput, ChannelsOutput = 3, i; + _LPcmsTRANSFORM p; int nNamedColor; - + if (nProfiles > 255) { cmsSignalError(LCMS_ERRC_ABORTED, "What are you trying to do with more that 255 profiles?!?, of course aborted"); return NULL; @@ -1799,7 +1554,7 @@ cmsHTRANSFORM LCMSEXPORT cmsCreateMultiprofileTransform(cmsHPROFILE hProfiles[], // There is a simple case with just two profiles, try to catch it in order of getting // black preservation to work on this function, at least with two profiles. - + if (nProfiles == 2) { icProfileClassSignature Class1 = cmsGetDeviceClass(hProfiles[0]); @@ -1807,20 +1562,20 @@ cmsHTRANSFORM LCMSEXPORT cmsCreateMultiprofileTransform(cmsHPROFILE hProfiles[], // Only input, output and display are allowed - if (IsAllowedInSingleXform(Class1) && - IsAllowedInSingleXform(Class2)) + if (IsAllowedInSingleXform(Class1) && + IsAllowedInSingleXform(Class2)) return cmsCreateTransform(hProfiles[0], dwInput, hProfiles[1], dwOutput, Intent, dwFlags); } - + // Creates a phantom transform for latter filling - p = (_LPcmsTRANSFORM) cmsCreateTransform(NULL, dwInput, + p = (_LPcmsTRANSFORM) cmsCreateTransform(NULL, dwInput, NULL, dwOutput, Intent, cmsFLAGS_NULLTRANSFORM); // If user wants null one, give it if (dwFlags & cmsFLAGS_NULLTRANSFORM) return (cmsHPROFILE) p; - // Is a bunch of named color profiles? + // Is a bunch of named color profiles? nNamedColor = 0; for (i=0; i < nProfiles; i++) { if (cmsGetDeviceClass(hProfiles[i]) == icSigNamedColorClass) @@ -1863,8 +1618,8 @@ cmsHTRANSFORM LCMSEXPORT cmsCreateMultiprofileTransform(cmsHPROFILE hProfiles[], // Take some info.... - p ->EntryColorSpace = CurrentColorSpace = cmsGetColorSpace(hProfiles[0]); - + p ->EntryColorSpace = CurrentColorSpace = cmsGetColorSpace(hProfiles[0]); + for (i=0; i < nProfiles; i++) { @@ -1884,99 +1639,99 @@ cmsHTRANSFORM LCMSEXPORT cmsCreateMultiprofileTransform(cmsHPROFILE hProfiles[], } else { - + ColorSpaceIn = cmsGetPCS(hProfile); ColorSpaceOut = cmsGetColorSpace(hProfile); } ChannelsInput = _cmsChannelsOf(ColorSpaceIn); ChannelsOutput = _cmsChannelsOf(ColorSpaceOut); - + FormatInput = BYTES_SH(2)|CHANNELS_SH(ChannelsInput); FormatOutput = BYTES_SH(2)|CHANNELS_SH(ChannelsOutput); - + ColorSpace = ColorSpaceIn; - + if (ColorSpace == CurrentColorSpace) { - + if (lIsDeviceLink) { - Transforms[i] = cmsCreateTransform(hProfile, FormatInput, - NULL, FormatOutput, - Intent, dwPrecalcFlags); + Transforms[i] = cmsCreateTransform(hProfile, FormatInput, + NULL, FormatOutput, + Intent, dwPrecalcFlags); } else { if (lIsInput) { - Transforms[i] = cmsCreateTransform(hProfile, FormatInput, - (ColorSpaceOut == icSigLabData ? hLab : hXYZ), FormatOutput, - Intent, dwPrecalcFlags); + Transforms[i] = cmsCreateTransform(hProfile, FormatInput, + (ColorSpaceOut == icSigLabData ? hLab : hXYZ), FormatOutput, + Intent, dwPrecalcFlags); } else { - Transforms[i] = cmsCreateTransform((ColorSpaceIn == icSigLabData ? hLab : hXYZ), FormatInput, - hProfile, FormatOutput, - Intent, dwPrecalcFlags); - + Transforms[i] = cmsCreateTransform((ColorSpaceIn == icSigLabData ? hLab : hXYZ), FormatInput, + hProfile, FormatOutput, + Intent, dwPrecalcFlags); + } - } - - + } + + } else // Can come from pcs? if (CurrentColorSpace == icSigXYZData) { - Transforms[i] = cmsCreateTransform(hXYZ, FormatInput, - hProfile, FormatOutput, - Intent, dwPrecalcFlags); - + Transforms[i] = cmsCreateTransform(hXYZ, FormatInput, + hProfile, FormatOutput, + Intent, dwPrecalcFlags); + } else if (CurrentColorSpace == icSigLabData) { - Transforms[i] = cmsCreateTransform(hLab, FormatInput, - hProfile, FormatOutput, + Transforms[i] = cmsCreateTransform(hLab, FormatInput, + hProfile, FormatOutput, Intent, dwPrecalcFlags); - - } + + } else { cmsSignalError(LCMS_ERRC_ABORTED, "cmsCreateMultiprofileTransform: ColorSpace mismatch"); goto ErrorCleanup; } CurrentColorSpace = ColorSpaceOut; - + } p ->ExitColorSpace = CurrentColorSpace; - Transforms[i] = NULL; // End marker + Transforms[i] = NULL; // End marker p ->InputProfile = hProfiles[0]; p ->OutputProfile = hProfiles[nProfiles - 1]; nGridPoints = _cmsReasonableGridpointsByColorspace(p ->EntryColorSpace, dwFlags); - + ChannelsInput = _cmsChannelsOf(cmsGetColorSpace(p ->InputProfile)); - + Grid = cmsAlloc3DGrid(Grid, nGridPoints, ChannelsInput, ChannelsOutput); if (!(dwFlags & cmsFLAGS_NOPRELINEARIZATION)) _cmsComputePrelinearizationTablesFromXFORM(Transforms, nProfiles, Grid); - - // Compute device link on 16-bit basis + + // Compute device link on 16-bit basis if (!cmsSample3DGrid(Grid, MultiprofileSampler, (LPVOID) Transforms, Grid -> wFlags)) { cmsFreeLUT(Grid); goto ErrorCleanup; } - // All ok, store the newly created LUT + // All ok, store the newly created LUT p -> DeviceLink = Grid; - SetPrecalculatedTransform(p); - + _cmsSetPrecalculatedTransform(p); + for (i=nProfiles-1; i >= 0; --i) cmsDeleteTransform(Transforms[i]); @@ -1984,15 +1739,15 @@ cmsHTRANSFORM LCMSEXPORT cmsCreateMultiprofileTransform(cmsHPROFILE hProfiles[], if (hLab) cmsCloseProfile(hLab); if (hXYZ) cmsCloseProfile(hXYZ); - + if (p ->EntryColorSpace == icSigRgbData || p ->EntryColorSpace == icSigCmyData) { - + p->DeviceLink -> CLut16params.Interp3D = cmsTetrahedralInterp16; } - - if ((Intent != INTENT_ABSOLUTE_COLORIMETRIC) && + + if ((Intent != INTENT_ABSOLUTE_COLORIMETRIC) && !(dwFlags & cmsFLAGS_NOWHITEONWHITEFIXUP)) _cmsFixWhiteMisalignment(p); @@ -2007,14 +1762,14 @@ ErrorCleanup: } - + double LCMSEXPORT cmsSetAdaptationState(double d) { double OldVal = GlobalAdaptationState; - if (d >= 0) + if (d >= 0) GlobalAdaptationState = d; return OldVal; - + } diff --git a/gs/lcms/src/cmsxform.h b/gs/lcms/src/cmsxform.h new file mode 100644 index 000000000..bf958cd91 --- /dev/null +++ b/gs/lcms/src/cmsxform.h @@ -0,0 +1,230 @@ +// +// Little cms + +// Chameleonic header file to instantiate different versions of the +// transform routines. +// +// As a bare minimum the following must be defined on entry: +// FUNCTION_NAME the name of the function +// +// In addition, a range of other symbols can be optionally defined on entry +// to make the generated code more efficient. All these symbols (and +// FUNCTION_NAME) will be automatically undefined at the end of the file so +// that repeated #includes of this file are made simple. +// +// If caching is wanted, define CACHED. (INBYTES will only have an effect +// if CACHED is defined). +// +// To reduce the amount of surplus memory checking done, set INBYTES to the +// number of bytes in an unpacked data chunk. +// +// If you know the code to be used to unpack (or pack, or both) data to/from +// the simple 16 bit transform input/output format, then you can choose +// to this directly by defining UNPACK/PACK macros as follows: +// UNPACK(T,TO,FROM) (Opt) code to unpack input data (T = Transform +// TO = buffer to unpack into, FROM = data) +// PACK(T,FROM,TO) (Opt) code to pack transformed input data +// (T = Transform, FROM = transformed data, +// TO = output buffer to pack into) +// +// As an alternative to the above, if you know the function name that would +// be called, supply that in UNPACKFN and PACKFN and inlining compilers +// should hopefully do the hard work for you. +// UNPACKFN (Opt) function to unpack input data +// PACKFN (Opt) function to pack input data +// +// Finally, GAMUTCHECK can be predefined if a gamut check needs to be done. + +#ifndef CACHED +#undef INBYTES +#endif + +#ifdef INBYTES +#if INBYTES <= 4 +#define COMPARE(A,B) (*((int *)(A)) != *((int *)(B))) +#elif INBYTES <= 8 +#define COMPARE(A,B) (*((LCMSULONGLONG *)(A)) != *((LCMSULONGLONG *)(B))) +/* Or we could use #define COMPARE(A,B) ((((int *)(A))[0] != ((int *)(B))[0]) || (((int *)(A))[1] != ((int *)(B))[1])) */ +#else +#undef INBYTES +#endif +#endif + +#ifndef COMPARE +#define COMPARE(A,B) memcmp((A),(B), (sizeof(WORD)*MAXCHANNELS)) +#endif + +#ifndef UNPACK +#ifdef UNPACKFN +#define UNPACK(T,TO,FROM) \ + do { (FROM) = UNPACKFN((T),(TO),(FROM)); } while (0) +#else +#define UNPACK(T,TO,FROM) \ + do { (FROM) = (T)->FromInput((T),(TO),(FROM)); } while (0) +#endif +#endif + +#ifndef PACK +#ifdef PACKFN +#define PACK(T,FROM,TO) \ + do { (TO) = PACKFN((T),(FROM),(TO)); } while (0) +#else +#define PACK(T,FROM,TO) \ + do { (TO) = (T)->ToOutput((T),(FROM),(TO)); } while (0) +#endif +#endif + +static +void FUNCTION_NAME(_LPcmsTRANSFORM p, + LPVOID in, + LPVOID out, + unsigned int n) +{ + register LPBYTE accum; + register LPBYTE output; + LCMSULONGLONG wIn[sizeof(WORD)*MAXCHANNELS*2/sizeof(LCMSULONGLONG)]; +#define wIn0 (&((WORD *)wIn)[0]) +#define wIn1 (&((WORD *)wIn)[MAXCHANNELS]) + WORD *currIn; +#ifdef CACHED + WORD *prevIn; +#ifdef INBYTES + int cacheValid = 1; +#endif /* INBYTES */ +#endif /* CACHED */ + WORD wOut[MAXCHANNELS]; + LPLUT devLink = p->DeviceLink; + accum = (LPBYTE) in; + output = (LPBYTE) out; + + if (n == 0) + return; + +#ifdef CACHED + // Empty buffers for quick memcmp + ZeroMemory(wIn1, sizeof(WORD) * MAXCHANNELS); + + LCMS_READ_LOCK(&p ->rwlock); + CopyMemory(wIn0, p ->CacheIn, sizeof(WORD) * MAXCHANNELS); + CopyMemory(wOut, p ->CacheOut, sizeof(WORD) * MAXCHANNELS); + LCMS_UNLOCK(&p ->rwlock); + +#ifdef INBYTES + /* We only check the first 'inBytes' of the cached version in the loop, + * and the cached version might differ after that point. So check the + * rest of the bytes now. */ + if (memcmp(((LPBYTE)wIn0)+INBYTES, wIn1, + sizeof(WORD) * MAXCHANNELS - INBYTES) != 0) + { + cacheValid = 0; + /* Zero the rest of the cached bytes to ensure what we copy back is + * correct. */ + ZeroMemory(((LPBYTE)wIn0)+INBYTES, + sizeof(WORD) * MAXCHANNELS - INBYTES); + } +#endif /* INBYTES */ + + prevIn = wIn0; +#endif /* CACHED */ + currIn = wIn1; + + // Try to speedup things on plain devicelinks +#ifdef INBYTES + UNPACK(p,currIn,accum); +#endif +#ifndef GAMUTCHECK + if (devLink->wFlags == LUT_HAS3DGRID) { +#ifdef INBYTES + if (cacheValid) + goto enterCacheValid3d; + else + goto enterCacheInvalid3d; +#endif + do { + UNPACK(p,currIn,accum); +#ifdef INBYTES + enterCacheValid3d: +#endif /* INBYTES */ +#ifdef CACHED + if (COMPARE(currIn, prevIn)) +#endif /* CACHED */ + { +#ifdef INBYTES + enterCacheInvalid3d: +#endif /* INBYTES */ + devLink->CLut16params.Interp3D(currIn, wOut, + devLink -> T, + &devLink -> CLut16params); +#ifdef CACHED + {WORD *tmp = currIn; currIn = prevIn; prevIn = tmp;} +#endif /* CACHED */ + } + PACK(p,wOut,output); + } while (--n); + } + else +#endif /* GAMUTCHECK */ + { +#ifdef INBYTES + if (cacheValid) + goto enterCacheValid; + else + goto enterCacheInvalid; +#endif /* INBYTES */ + do { + UNPACK(p,currIn,accum); +#ifdef INBYTES + enterCacheValid: +#endif +#ifdef CACHED + if (COMPARE(currIn, prevIn)) +#endif /* CACHED */ + { +#ifdef INBYTES + enterCacheInvalid: +#endif /* INBYTES */ +#ifdef GAMUTCHECK + { + WORD wOutOfGamut; + + cmsEvalLUT(p->GamutCheck, currIn, &wOutOfGamut); + if (wOutOfGamut >= 1) { + ZeroMemory(wOut, sizeof(WORD) * MAXCHANNELS); + + wOut[0] = _cmsAlarmR; + wOut[1] = _cmsAlarmG; + wOut[2] = _cmsAlarmB; + } else { +#endif /* GAMUTCHECK */ + cmsEvalLUT(devLink, currIn, wOut); +#ifdef GAMUTCHECK + } + } +#endif /* GAMUTCHECK */ +#ifdef CACHED + {WORD *tmp = currIn; currIn = prevIn; prevIn = tmp;} +#endif /* CACHED */ + } + PACK(p,wOut,output); + } while (--n); + } +#ifdef CACHED + LCMS_WRITE_LOCK(&p ->rwlock); + CopyMemory(p->CacheIn, prevIn, sizeof(WORD) * MAXCHANNELS); + CopyMemory(p->CacheOut, wOut, sizeof(WORD) * MAXCHANNELS); + LCMS_UNLOCK(&p ->rwlock); +#endif /* CACHED */ +} + +#undef wIn0 +#undef wIn1 + +#undef FUNCTION_NAME +#undef COMPARE +#undef INBYTES +#undef UNPACK +#undef PACK +#undef UNPACKFN +#undef PACKFN +#undef GAMUTCHECK +#undef CACHED |