Mercurial > hgrepos > Python2 > PyMuPDF
diff mupdf-source/thirdparty/lcms2/src/extra_xform.h @ 2:b50eed0cc0ef upstream
ADD: MuPDF v1.26.7: the MuPDF source as downloaded by a default build of PyMuPDF 1.26.4.
The directory name has changed: no version number in the expanded directory now.
| author | Franz Glasner <fzglas.hg@dom66.de> |
|---|---|
| date | Mon, 15 Sep 2025 11:43:07 +0200 |
| parents | |
| children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mupdf-source/thirdparty/lcms2/src/extra_xform.h Mon Sep 15 11:43:07 2025 +0200 @@ -0,0 +1,524 @@ +// +// 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. +// +// 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,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 +// should hopefully do the hard work for you. +// UNPACKFN (Opt) function to unpack input data +// PACKFN (Opt) function to pack input data +// +// 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. +// +// 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 +// we have extra bytes, they should skip the extra bytes too! +// +// 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. +// 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. +// +// GAMUTCHECK can be predefined if a gamut check needs to be done. +// +// If there are a known number of extra bytes to be dealt with, define EXTRABYTES +// to that number (such as 0 for none). +// If you want to provide your own code for copying from input to output, define +// COPY_EXTRAS(TRANS,FROM,TO) to do so. +// If none of these are defined, we call cmsHandleExtraChannels. + +#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 CMPBYTES == 4 + #define COMPARE(A,B) ((A)[0] != (B)[0]) + #elif CMPBYTES == 8 + #define COMPARE(A,B) (((A)[0] != (B)[0]) || ((A)[1] != (B)[1])) + #elif CMPBYTES == 12 + #define COMPARE(A,B) (((A)[0] != (B)[0]) || ((A)[1] != (B)[1]) || ((A)[2] != (B)[2])) + #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 CMPBYTES == 2 + #define COMPARE(A,B) ((A)[0] != (B)[0]) + #elif CMPBYTES == 4 + #define COMPARE(A,B) (((A)[0] != (B)[0]) || ((A)[1] != (B)[1])) + #elif CMPBYTES == 6 + #define COMPARE(A,B) (((A)[0] != (B)[0]) || ((A)[1] != (B)[1]) || ((A)[2] != (B)[2])) + #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. + #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), CMPBYTES) +#endif + +#if defined(UNPACK) + // Nothing to do, UNPACK is already defined +#elif defined(NO_UNPACK) + #define UNPACK(CTX,T,TO,FROM,STRIDE,AL) do { } while (0) +#elif defined(UNPACKFN) + #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,AL) \ + do { (FROM) = (T)->FromInputFloat((CTX),(T),(TO),(FROM),(STRIDE)); } while (0) +#else + #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,AL) \ + do { (FROM) += (totaloutbytes/sizeof(XFORM_TYPE)); } while (0) +#elif defined(PACKFN) + #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,AL) \ + do { (TO) = (T)->ToOutputFloat((CTX),(T),(FROM),(TO),(STRIDE)); } while (0) +#else + #define PACK(CTX,T,FROM,TO,STRIDE,AL) \ + do { (TO) = (T)->ToOutput((CTX),(T),(FROM),(TO),(STRIDE)); } while (0) +#endif + +#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 + #define COPY_MATCHED(FROM,TO) ((TO)[0] = (FROM)[0],(TO)[1] = (FROM)[1]) + #elif (defined(XFORM_FLOAT) && OUTBYTES == 12) || OUTBYTES == 6 + #define COPY_MATCHED(FROM,TO) ((TO)[0] = (FROM)[0],(TO)[1] = (FROM)[1],(TO)[2] = (FROM)[2]) + #elif (defined(XFORM_FLOAT) && OUTBYTES == 16) || OUTBYTES == 8 + #define COPY_MATCHED(FROM,TO) ((TO)[0] = (FROM)[0],(TO)[1] = (FROM)[1],(TO)[2] = (FROM)[2],(TO)[3] = (FROM)[3]) + #else + #define COPY_MATCHED(FROM,TO) memcpy((TO),(FROM),(OUTBYTES)) + #endif +#endif + +#ifdef XFORM_FLOAT + #define XFORM_TYPE cmsFloat32Number +#else + #define XFORM_TYPE cmsUInt16Number +#endif + +#ifndef COPY_EXTRAS + #ifdef NUMEXTRAS + #if NUMEXTRAS == 0 + #define COPY_EXTRAS(TRANS,FROM,TO) do { } while (0) + #else + #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 + #define COPY_EXTRAS(TRANS,FROM,TO) do { } while (0) + #endif +#endif + +static +void FUNCTION_NAME(cmsContext ContextID, + _cmsTRANSFORM* p, + const void* in, + void* out, + cmsUInt32Number PixelsPerLine, + cmsUInt32Number LineCount, + const cmsStride* Stride) +{ + _cmsTRANSFORMCORE *core = p->core; +#ifndef NO_UNPACK + #ifdef XFORM_FLOAT + cmsFloat32Number wIn[cmsMAXCHANNELS*2]; + #else + cmsUInt16Number wIn[cmsMAXCHANNELS*2]; + #endif + #define wIn0 (&wIn[0]) + #define wIn1 (&wIn[cmsMAXCHANNELS]) +#endif + XFORM_TYPE *currIn; +#ifdef CACHED + XFORM_TYPE *prevIn; +#endif /* CACHED */ +#ifdef NO_PACK + XFORM_TYPE *wOut = (XFORM_TYPE *)out; + XFORM_TYPE *prevOut = (XFORM_TYPE *)p->Cache.CacheOut; +#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 */ +#ifdef XFORM_FLOAT + _cmsPipelineEvalFloatFn eval = core->Lut->EvalFloatFn; + const cmsPipeline *data = core->Lut; +#else + _cmsPipelineEval16Fn eval = core->Lut->Eval16Fn; + void *data = core->Lut->Data; +#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) + _cmsHandleExtraChannels(ContextID, p, in, out, PixelsPerLine, LineCount, Stride); +#endif + + if (PixelsPerLine == 0) + return; + +#ifdef NO_UNPACK + prevIn = (XFORM_TYPE *)p->Cache.CacheIn; +#else + #ifdef CACHED + // Empty buffers for quick memcmp + memset(wIn1, 0, sizeof(XFORM_TYPE) * cmsMAXCHANNELS); + + // Get copy of zero cache + memcpy(wIn0, p->Cache.CacheIn, sizeof(XFORM_TYPE) * cmsMAXCHANNELS); + memcpy(wOut, p->Cache.CacheOut, sizeof(XFORM_TYPE) * cmsMAXCHANNELS); + + // The caller guarantees us that the cache is always valid on entry; if + // the representation is changed, the cache is reset. + prevIn = wIn0; + #endif /* CACHED */ + currIn = wIn1; +#endif + + while (LineCount-- > 0) + { + cmsUInt32Number n = PixelsPerLine; + cmsUInt8Number* accum = (cmsUInt8Number*) in; + cmsUInt8Number* output = (cmsUInt8Number*) out; +#ifdef NO_UNPACK + currIn = (XFORM_TYPE *)accum; +#endif + while (n-- > 0) { // prevIn == CacheIn, wOut = CacheOut +#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)) +#endif /* CACHED */ + { +#ifdef GAMUTCHECK + #ifdef XFORM_FLOAT + cmsFloat32Number OutOfGamut; + + // 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 + #else + 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 + #endif /* FLOAT_XFORM */ +#endif /* GAMUTCHECK */ + eval(ContextID, currIn, wOut, data); +#ifdef NO_UNPACK + #ifdef CACHED + prevIn = currIn; + #endif + currIn = (XFORM_TYPE *)(((char *)currIn) + totalinbytes); +#else + #ifdef CACHED + {XFORM_TYPE *tmp = currIn; currIn = prevIn; prevIn = tmp;} // SWAP + #endif /* CACHED */ +#endif /* NO_UNPACK */ + } +#ifdef NO_PACK + 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 + } /* End x loop */ + in = (void *)((cmsUInt8Number *)in + Stride->BytesPerLineIn); + out = (void *)((cmsUInt8Number *)out + Stride->BytesPerLineOut); + } /* End y loop */ + /* The following code is only safe if we know that a given transform is + * called on one thread a time. */ +#if 0 +#ifdef CACHED +#ifdef NO_UNPACK + memcpy(p->Cache.CacheIn,prevIn, CMPBYTES); +#else + memcpy(p->Cache.CacheIn, prevIn, sizeof(XFORM_TYPE) * cmsMAXCHANNELS); +#endif +#ifdef NO_PACK + COPY_MATCHED(prevOut,p->Cache.CacheOut); +#else + memcpy(p->Cache.CacheOut, wOut, sizeof(XFORM_TYPE) * cmsMAXCHANNELS); +#endif /* NO_PACK */ +#endif /* CACHED */ +#endif +} + +#undef wIn0 +#undef wIn1 +#undef XFORM_TYPE +#undef XFORM_FLOAT + +#undef FUNCTION_NAME +#undef COMPARE +#undef CMPBYTES +#undef OUTBYTES +#undef UNPACK +#undef NO_UNPACK +#undef PACK +#undef NO_PACK +#undef UNPACKFN +#undef PACKFN +#undef GAMUTCHECK +#undef CACHED +#undef COPY_MATCHED +#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
