diff options
Diffstat (limited to 'lcms2mt/src/extra_xform.h')
-rw-r--r-- | lcms2mt/src/extra_xform.h | 326 |
1 files changed, 259 insertions, 67 deletions
diff --git a/lcms2mt/src/extra_xform.h b/lcms2mt/src/extra_xform.h index 51dd0e05..3f8a75f7 100644 --- a/lcms2mt/src/extra_xform.h +++ b/lcms2mt/src/extra_xform.h @@ -14,20 +14,48 @@ // // If caching is wanted, define CACHED. // -// To reduce the amount of surplus memory checking done, set INBYTES to the -// number of bytes in an unpacked data chunk. INBYTES will only have an -// effect if CACHED or NO_UNPACK +// If the representation/calculations are to be done using floating point +// define XFORM_FLOAT. In the absence of this it is assumed that the +// calculations will be done in 16 bit with appropriate unpacking/repacking. +// +// If you know the number of input/output channels, define NUMINCHANNELS and +// NUMOUTCHANNELS. +// +// If you know the number of bytes used for the packed version of input and/or +// output, define INPACKEDSAMPLESIZE and OUTPACKEDSAMPLESIZE. +// +// If you do not know the number of channels and/or the sample size, but you +// do know a maximum bound on the number of bytes used to represent the +// unpacked samples, then operation with CACHE can be accelerated by defining +// CMPBYTES to the number of bytes that should be compared to the cached result. +// Usually that is calculated from NUMINCHANNELS and INPACKEDSAMPLESIZE, so +// specifying it directly is only useful if either (or both) of those is not +// known in advance. +// +// For Premultiplied Alpha modes, you must define PREMULT. We only support +// premultiplied alpha where the alpha is the last 'extra' channel, and +// where both source and destination are packed in the same way. // // 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,SIZE) (Opt) code to unpack input data (T = Transform -// TO = buffer to unpack into, FROM = data, -// SIZE = size of data) -// PACK(T,FROM,TO,SIZE) (Opt) code to pack transformed input data -// (T = Transform, FROM = transformed data, -// TO = output buffer to pack into, -// SIZE = size of data) +// UNPACK(T,TO,FROM,SIZE,AL) (Opt) code to unpack input data (T = Transform +// TO = buffer to unpack into, FROM = data, +// SIZE = size of data, AL = Alpha) +// PACK(T,FROM,TO,SIZE,AL) (Opt) code to pack transformed input data +// (T = Transform, FROM = transformed data, +// TO = output buffer to pack into, +// SIZE = size of data, AL = Alpha) +// +// Ignore AL unless PREMULT is defined, in which case it will be in the packed +// format. AL is guaranteed to be non-zero. +// +// If UNPACKINCLUDESPREALPHA is defined, then UNPACK should undo the +// premultiplication by AL (i.e. divide by AL). Otherwise AL should be ignored +// and this routine will do it for you. +// +// If PACKINCLUDESPREALPHA is defined, then PACK should apply AL (i.e. multiply +// by AL). Otherwise AL should be ignored and this routine will do it for you. // // 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 @@ -38,7 +66,7 @@ // If the data happens to be in the correct input format anyway, we can skip // unpacking it entirely and just use it direct. // NO_UNPACK (Opt) if defined, transform direct from the input -// data. INBYTES must be defined. +// data. // // UNPACK/PACK/UNPACKFN/PACKFN/NO_UNPACK are all expected to update their // TO pointer to point to the next pixels data. This means for cases where @@ -47,7 +75,7 @@ // If the data happens to be in the correct output format anyway, we can skip // packing it entirely and just transform it direct into the buffer. // NO_PACK (Opt) if defined, transform direct to the output -// data. OUTBYTES must be defined. +// data. // COPY_MATCHED(FROM,TO)(Opt)if defined, copy output values from FROM to // TO. Used in the case CACHED case where the // cache matches and we have to copy forwards. @@ -60,73 +88,126 @@ // COPY_EXTRAS(TRANS,FROM,TO) to do so. // If none of these are defined, we call cmsHandleExtraChannels. -#ifdef INBYTES +#ifndef CMPBYTES +#ifdef NUMINCHANNELS +#ifdef XFORM_FLOAT +#define CMPBYTES (NUMINCHANNELS*4) +#else +#define CMPBYTES (NUMINCHANNELS*2) +#endif +#endif +#endif + +#ifdef CMPBYTES // Previously, we've attempted to do 'int' based checks here, but this falls // foul of some compilers with their strict pointer aliasing. We have the // choice of calling memcmp (which tests using chars, so is safe), or of // testing using the actual type. #ifdef XFORM_FLOAT - #if INBYTES == 4 + #if CMPBYTES == 4 #define COMPARE(A,B) ((A)[0] != (B)[0]) - #elif INBYTES == 8 + #elif CMPBYTES == 8 #define COMPARE(A,B) (((A)[0] != (B)[0]) || ((A)[1] != (B)[1])) - #elif INBYTES == 12 + #elif CMPBYTES == 12 #define COMPARE(A,B) (((A)[0] != (B)[0]) || ((A)[1] != (B)[1]) || ((A)[2] != (B)[2])) - #elif INBYTES == 16 + #elif CMPBYTES == 16 #define COMPARE(A,B) (((A)[0] != (B)[0]) || ((A)[1] != (B)[1]) || ((A)[2] != (B)[2]) || ((A)[3] != (B)[3])) #endif #else - #if INBYTES == 2 + #if CMPBYTES == 2 #define COMPARE(A,B) ((A)[0] != (B)[0]) - #elif INBYTES == 4 + #elif CMPBYTES == 4 #define COMPARE(A,B) (((A)[0] != (B)[0]) || ((A)[1] != (B)[1])) - #elif INBYTES == 6 + #elif CMPBYTES == 6 #define COMPARE(A,B) (((A)[0] != (B)[0]) || ((A)[1] != (B)[1]) || ((A)[2] != (B)[2])) - #elif INBYTES == 8 + #elif CMPBYTES == 8 #define COMPARE(A,B) (((A)[0] != (B)[0]) || ((A)[1] != (B)[1]) || ((A)[2] != (B)[2]) || ((A)[3] != (B)[3])) #endif #endif #else // Otherwise, set INBYTES to be the maximum size it could possibly be. - #define INBYTES (sizeof(cmsUInt16Number)*cmsMAXCHANNELS) + #ifdef XFORM_FLOAT + #define CMPBYTES (sizeof(cmsFloat32Number)*cmsMAXCHANNELS) + #else + #define CMPBYTES (sizeof(cmsUInt16Number)*cmsMAXCHANNELS) + #endif #endif #ifndef COMPARE - #define COMPARE(A,B) memcmp((A),(B), INBYTES) + #define COMPARE(A,B) memcmp((A),(B), CMPBYTES) #endif #if defined(UNPACK) // Nothing to do, UNPACK is already defined #elif defined(NO_UNPACK) - #define UNPACK(CTX,T,TO,FROM,STRIDE) do { } while (0) + #define UNPACK(CTX,T,TO,FROM,STRIDE,AL) do { } while (0) #elif defined(UNPACKFN) - #define UNPACK(CTX,T,TO,FROM,STRIDE) \ - do { (FROM) = UNPACKFN((CTX),(T),(TO),(FROM),(STRIDE)); } while (0) + #define UNPACK(CTX,T,TO,FROM,STRIDE,AL) \ + do { (FROM) = UNPACKFN((CTX),(T),(TO),(FROM),(STRIDE),(AL)); } while (0) #elif defined(XFORM_FLOAT) - #define UNPACK(CTX,T,TO,FROM,STRIDE) \ + #define UNPACK(CTX,T,TO,FROM,STRIDE,AL) \ do { (FROM) = (T)->FromInputFloat((CTX),(T),(TO),(FROM),(STRIDE)); } while (0) #else - #define UNPACK(CTX,T,TO,FROM,STRIDE) \ + #define UNPACK(CTX,T,TO,FROM,STRIDE,AL) \ do { (FROM) = (T)->FromInput((CTX),(T),(TO),(FROM),(STRIDE)); } while (0) #endif #if defined(PACK) // Nothing to do, PACK is already defined #elif defined(NO_PACK) - #define PACK(CTX,T,FROM,TO,STRIDE) \ - do { (FROM) += ((OUTBYTES)/sizeof(XFORM_TYPE)); } while (0) + #define PACK(CTX,T,FROM,TO,STRIDE,AL) \ + do { (FROM) += (totaloutbytes/sizeof(XFORM_TYPE)); } while (0) #elif defined(PACKFN) - #define PACK(CTX,T,FROM,TO,STRIDE) \ + #define PACK(CTX,T,FROM,TO,STRIDE,AL) \ do { (TO) = PACKFN((CTX),(T),(FROM),(TO),(STRIDE)); } while (0) #elif defined(XFORM_FLOAT) - #define PACK(CTX,T,FROM,TO,STRIDE) \ + #define PACK(CTX,T,FROM,TO,STRIDE,AL) \ do { (TO) = (T)->ToOutputFloat((CTX),(T),(FROM),(TO),(STRIDE)); } while (0) #else - #define PACK(CTX,T,FROM,TO,STRIDE) \ + #define PACK(CTX,T,FROM,TO,STRIDE,AL) \ do { (TO) = (T)->ToOutput((CTX),(T),(FROM),(TO),(STRIDE)); } while (0) #endif -#if defined(NO_PACK) && !defined(COPY_MATCHED) +#ifndef ZEROPACK +/* The 'default' definition of ZEROPACK only works when + * inpackedsamplesize == outpackedsamplesize. */ +#define ZEROPACK(CTX,T,TO,FROM) do { \ + memset((TO),0,numoutchannels*outpackedsamplesize);\ + if (numextras != 0) memcpy((TO)+numoutchannels*outpackedsamplesize,\ + (FROM)+numinchannels*inpackedsamplesize,\ + numextras*outpackedsamplesize);\ + (TO)+=(1+prealphaindexout)*outpackedsamplesize; } while (0) +#endif + +#ifndef UNPRE +#ifdef PREALPHA +#else +#define UNPRE(CTX,T,S,A) do {} while (0) +#endif +#endif + +#ifndef REPRE +#ifdef PREALPHA +#define REPRE(CTX,T,S,A) do { int i; for (i = 0; i < numoutchannels; i++) \ + (S)[i] = mul65535((S)[i],A); } while (0) +#else +#define REPRE(CTX,T,S,A) do {} while (0) +#endif +#endif + +#ifndef XFORMVARS +#define XFORMVARS(p) do { } while (0) +#endif + +#if defined(NUMOUTCHANNELS) + #ifdef XFORM_FLOAT + #define OUTBYTES (sizeof(cmsFloat32Number)*NUMOUTCHANNELS) + #else + #define OUTBYTES (sizeof(cmsUInt16Number)*NUMOUTCHANNELS) + #endif +#endif + +#if defined(NO_PACK) && !defined(COPY_MATCHED) && defined(OUTBYTES) #if (defined(XFORM_FLOAT) && OUTBYTES == 4) || OUTBYTES == 2 #define COPY_MATCHED(FROM,TO) ((TO)[0] = (FROM)[0]) #elif (defined(XFORM_FLOAT) && OUTBYTES == 8) || OUTBYTES == 4 @@ -147,11 +228,15 @@ #endif #ifndef COPY_EXTRAS - #ifdef EXTRABYTES - #if EXTRABYTES == 0 + #ifdef NUMEXTRAS + #if NUMEXTRAS == 0 #define COPY_EXTRAS(TRANS,FROM,TO) do { } while (0) #else - #define COPY_EXTRAS(TRANS,FROM,TO) memcpy((TO),(FROM),(EXTRABYTES)) + #define COPY_EXTRAS(TRANS,FROM,TO) \ + do { memcpy((TO),(FROM),(NUMEXTRAS)*inpackedsamplesize); \ + (TO) += (NUMEXTRAS)*inpackedsamplesize; \ + (FROM) += (NUMEXTRAS)*inpackedsamplesize; \ + } while (0) #endif #else #define BULK_COPY_EXTRAS @@ -188,6 +273,9 @@ void FUNCTION_NAME(cmsContext ContextID, #else XFORM_TYPE wOut[cmsMAXCHANNELS]; #endif +#if defined(PREALPHA) && !defined(PACKINCLUDESPREALPHA) + XFORM_TYPE wScaled[cmsMAXCHANNELS]; +#endif #ifdef GAMUTCHECK _cmsPipelineEval16Fn evalGamut = core->GamutCheck->Eval16Fn; #endif /* GAMUTCHECK */ @@ -200,10 +288,46 @@ void FUNCTION_NAME(cmsContext ContextID, #endif cmsUInt32Number bppi = Stride->BytesPerPlaneIn; cmsUInt32Number bppo = Stride->BytesPerPlaneOut; +#ifdef NUMINCHANNELS + int numinchannels = NUMINCHANNELS; +#else + int numinchannels = T_CHANNELS(p->InputFormat); +#endif +#ifdef NUMOUTCHANNELS + int numoutchannels = NUMOUTCHANNELS; +#else + int numoutchannels = T_CHANNELS(p->OutputFormat); +#endif +#ifdef NUMEXTRAS + int numextras = NUMEXTRAS; +#else + int numextras = T_EXTRA(p->InputFormat); +#endif +#ifdef INPACKEDSAMPLESIZE + int inpackedsamplesize = INPACKEDSAMPLESIZE; +#else + int inpackedsamplesize = T_BYTES(p->InputFormat); +#endif +#ifdef OUTPACKEDSAMPLESIZE + int outpackedsamplesize = OUTPACKEDSAMPLESIZE; +#else + int outpackedsamplesize = T_BYTES(p->OutputFormat); +#endif + int prealphaindexin = numinchannels + numextras - 1; + int prealphaindexout = numoutchannels + numextras - 1; + int totalinbytes = (numinchannels + numextras)*inpackedsamplesize; + int totaloutbytes = (numoutchannels + numextras)*outpackedsamplesize; /* Silence some warnings */ (void)bppi; (void)bppo; + (void)prealphaindexin; + (void)numextras; + (void)prealphaindexout; + (void)inpackedsamplesize; + (void)outpackedsamplesize; + (void)totalinbytes; + (void)totaloutbytes; #ifdef BULK_COPY_EXTRAS if (core->dwOriginalFlags & cmsFLAGS_COPY_ALPHA) @@ -240,53 +364,111 @@ void FUNCTION_NAME(cmsContext ContextID, currIn = (XFORM_TYPE *)accum; #endif while (n-- > 0) { // prevIn == CacheIn, wOut = CacheOut - UNPACK(ContextID,p,currIn,accum,bppi); +#ifdef PREALPHA + #ifdef XFORM_FLOAT + cmsFloat32Number alpha = ((cmsFloat32Number *)accum)[prealphaindexin]; + #else + cmsUInt32Number alpha = inpackedsamplesize == 2 ? + ((cmsUInt16Number *)accum)[prealphaindexin] : + (accum[prealphaindexin]); + #endif + if (alpha == 0) { + ZEROPACK(ContextID,p,output,accum); + accum += inpackedsamplesize*(prealphaindexin+1); + } else { +#endif + UNPACK(ContextID,p,currIn,accum,bppi,alpha); +#ifdef PREALPHA + #ifndef UNPACKINCLUDESPREALPHA + #ifdef XFORM_FLOAT + { + int i; + cmsFloat32Number inva = 1.0f / alpha; + for (i = 0; i < numinchannels; i++) + currIn[i] *= inva; + } + #else + { + int i; + cmsUInt32Number al = inpackedsamplesize == 1 ? alpha*0x101 : alpha; + cmsUInt32Number inva = 0xffff0000U / al; + for (i = 0; i < numinchannels; i++) + currIn[i] = ((currIn[i] * inva)>>16); + } + #endif + #endif +#endif #ifdef CACHED - if (COMPARE(currIn, prevIn)) + if (COMPARE(currIn, prevIn)) #endif /* CACHED */ - { + { #ifdef GAMUTCHECK #ifdef XFORM_FLOAT - cmsFloat32Number OutOfGamut; + cmsFloat32Number OutOfGamut; - // Evaluate gamut marker. - cmsPipelineEvalFloat(currIn, &OutOfGamut, core->GamutCheck); + // Evaluate gamut marker. + cmsPipelineEvalFloat(currIn, &OutOfGamut, core->GamutCheck); - // Is current color out of gamut? - if (OutOfGamut > 0.0) - // Certainly, out of gamut - for (j=0; j < cmsMAXCHANNELS; j++) - fOut[j] = -1.0; - else + // Is current color out of gamut? + if (OutOfGamut > 0.0) + // Certainly, out of gamut + for (j=0; j < cmsMAXCHANNELS; j++) + fOut[j] = -1.0; + else #else - cmsUInt16Number wOutOfGamut; + cmsUInt16Number wOutOfGamut; - evalGamut(ContextID, currIn, &wOutOfGamut, core->GamutCheck->Data); - if (wOutOfGamut >= 1) - /* RJW: Could be faster? copy once to a local buffer? */ - cmsGetAlarmCodes(ContextID, wOut); - else + evalGamut(ContextID, currIn, &wOutOfGamut, core->GamutCheck->Data); + if (wOutOfGamut >= 1) + /* RJW: Could be faster? copy once to a local buffer? */ + cmsGetAlarmCodes(ContextID, wOut); + else #endif /* FLOAT_XFORM */ #endif /* GAMUTCHECK */ - eval(ContextID, currIn, wOut, data); + eval(ContextID, currIn, wOut, data); #ifdef NO_UNPACK #ifdef CACHED - prevIn = currIn; + prevIn = currIn; #endif - currIn = (XFORM_TYPE *)(((char *)currIn) + INBYTES); + currIn = (XFORM_TYPE *)(((char *)currIn) + totalinbytes); #else #ifdef CACHED - {XFORM_TYPE *tmp = currIn; currIn = prevIn; prevIn = tmp;} // SWAP + {XFORM_TYPE *tmp = currIn; currIn = prevIn; prevIn = tmp;} // SWAP #endif /* CACHED */ #endif /* NO_UNPACK */ - } + } #ifdef NO_PACK - else - COPY_MATCHED(prevOut,wOut); - prevOut = wOut; + else + COPY_MATCHED(prevOut,wOut); + prevOut = wOut; +#endif +#ifdef PREALPHA + #ifndef PACKINCLUDESPREALPHA + #ifdef XFORM_FLOAT + { + int i; + for (i = 0; i < numoutchannels; i++) + wScaled = wOut[i] * alpha; + } + #else + { + int i; + cmsUInt32Number al = inpackedsamplesize == 1 ? alpha*0x101 : alpha; + for (i = 0; i < numoutchannels; i++) + wScaled[i] = mul65535(wOut[i],al); + } + #endif + PACK(ContextID,p,wScaled,output,bppo,alpha); + #else + PACK(ContextID,p,wOut,output,bppo,alpha); + #endif +#else + PACK(ContextID,p,wOut,output,bppo,alpha); +#endif + COPY_EXTRAS(p,accum,output); +#ifdef PREALPHA + } #endif - PACK(ContextID,p,wOut,output,bppo); - COPY_EXTRAS(p,accum,output); } /* End x loop */ in = (void *)((cmsUInt8Number *)in + Stride->BytesPerLineIn); out = (void *)((cmsUInt8Number *)out + Stride->BytesPerLineOut); @@ -296,7 +478,7 @@ void FUNCTION_NAME(cmsContext ContextID, #if 0 #ifdef CACHED #ifdef NO_UNPACK - memcpy(p->Cache.CacheIn,prevIn,INBYTES); + memcpy(p->Cache.CacheIn,prevIn, CMPBYTES); #else memcpy(p->Cache.CacheIn, prevIn, sizeof(XFORM_TYPE) * cmsMAXCHANNELS); #endif @@ -316,7 +498,7 @@ void FUNCTION_NAME(cmsContext ContextID, #undef FUNCTION_NAME #undef COMPARE -#undef INBYTES +#undef CMPBYTES #undef OUTBYTES #undef UNPACK #undef NO_UNPACK @@ -330,3 +512,13 @@ void FUNCTION_NAME(cmsContext ContextID, #undef EXTRABYTES #undef COPY_EXTRAS #undef BULK_COPY_EXTRAS +#undef PREALPHA +#undef ZEROPACK +#undef XFORMVARS +#undef UNPRE +#undef REPRE +#undef INPACKEDSAMPLESIZE +#undef OUTPACKEDSAMPLESIZE +#undef NUMINCHANNELS +#undef NUMOUTCHANNELS +#undef NUMEXTRAS |