comparison 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
comparison
equal deleted inserted replaced
1:1d09e1dec1d9 2:b50eed0cc0ef
1 //
2 // Little cms
3
4 // Chameleonic header file to instantiate different versions of the
5 // transform routines.
6 //
7 // As a bare minimum the following must be defined on entry:
8 // FUNCTION_NAME the name of the function
9 //
10 // In addition, a range of other symbols can be optionally defined on entry
11 // to make the generated code more efficient. All these symbols (and
12 // FUNCTION_NAME) will be automatically undefined at the end of the file so
13 // that repeated #includes of this file are made simple.
14 //
15 // If caching is wanted, define CACHED.
16 //
17 // If the representation/calculations are to be done using floating point
18 // define XFORM_FLOAT. In the absence of this it is assumed that the
19 // calculations will be done in 16 bit with appropriate unpacking/repacking.
20 //
21 // If you know the number of input/output channels, define NUMINCHANNELS and
22 // NUMOUTCHANNELS.
23 //
24 // If you know the number of bytes used for the packed version of input and/or
25 // output, define INPACKEDSAMPLESIZE and OUTPACKEDSAMPLESIZE.
26 //
27 // If you do not know the number of channels and/or the sample size, but you
28 // do know a maximum bound on the number of bytes used to represent the
29 // unpacked samples, then operation with CACHE can be accelerated by defining
30 // CMPBYTES to the number of bytes that should be compared to the cached result.
31 // Usually that is calculated from NUMINCHANNELS and INPACKEDSAMPLESIZE, so
32 // specifying it directly is only useful if either (or both) of those is not
33 // known in advance.
34 //
35 // For Premultiplied Alpha modes, you must define PREMULT. We only support
36 // premultiplied alpha where the alpha is the last 'extra' channel, and
37 // where both source and destination are packed in the same way.
38 //
39 // If you know the code to be used to unpack (or pack, or both) data to/from
40 // the simple 16 bit transform input/output format, then you can choose
41 // to this directly by defining UNPACK/PACK macros as follows:
42 // UNPACK(T,TO,FROM,SIZE,AL) (Opt) code to unpack input data (T = Transform
43 // TO = buffer to unpack into, FROM = data,
44 // SIZE = size of data, AL = Alpha)
45 // PACK(T,FROM,TO,SIZE,AL) (Opt) code to pack transformed input data
46 // (T = Transform, FROM = transformed data,
47 // TO = output buffer to pack into,
48 // SIZE = size of data, AL = Alpha)
49 //
50 // Ignore AL unless PREMULT is defined, in which case it will be in the packed
51 // format. AL is guaranteed to be non-zero.
52 //
53 // If UNPACKINCLUDESPREALPHA is defined, then UNPACK should undo the
54 // premultiplication by AL (i.e. divide by AL). Otherwise AL should be ignored
55 // and this routine will do it for you.
56 //
57 // If PACKINCLUDESPREALPHA is defined, then PACK should apply AL (i.e. multiply
58 // by AL). Otherwise AL should be ignored and this routine will do it for you.
59 //
60 // As an alternative to the above, if you know the function name that would
61 // be called, supply that in UNPACKFN and PACKFN and inlining compilers
62 // should hopefully do the hard work for you.
63 // UNPACKFN (Opt) function to unpack input data
64 // PACKFN (Opt) function to pack input data
65 //
66 // If the data happens to be in the correct input format anyway, we can skip
67 // unpacking it entirely and just use it direct.
68 // NO_UNPACK (Opt) if defined, transform direct from the input
69 // data.
70 //
71 // UNPACK/PACK/UNPACKFN/PACKFN/NO_UNPACK are all expected to update their
72 // TO pointer to point to the next pixels data. This means for cases where
73 // we have extra bytes, they should skip the extra bytes too!
74 //
75 // If the data happens to be in the correct output format anyway, we can skip
76 // packing it entirely and just transform it direct into the buffer.
77 // NO_PACK (Opt) if defined, transform direct to the output
78 // data.
79 // COPY_MATCHED(FROM,TO)(Opt)if defined, copy output values from FROM to
80 // TO. Used in the case CACHED case where the
81 // cache matches and we have to copy forwards.
82 //
83 // GAMUTCHECK can be predefined if a gamut check needs to be done.
84 //
85 // If there are a known number of extra bytes to be dealt with, define EXTRABYTES
86 // to that number (such as 0 for none).
87 // If you want to provide your own code for copying from input to output, define
88 // COPY_EXTRAS(TRANS,FROM,TO) to do so.
89 // If none of these are defined, we call cmsHandleExtraChannels.
90
91 #ifndef CMPBYTES
92 #ifdef NUMINCHANNELS
93 #ifdef XFORM_FLOAT
94 #define CMPBYTES (NUMINCHANNELS*4)
95 #else
96 #define CMPBYTES (NUMINCHANNELS*2)
97 #endif
98 #endif
99 #endif
100
101 #ifdef CMPBYTES
102 // Previously, we've attempted to do 'int' based checks here, but this falls
103 // foul of some compilers with their strict pointer aliasing. We have the
104 // choice of calling memcmp (which tests using chars, so is safe), or of
105 // testing using the actual type.
106 #ifdef XFORM_FLOAT
107 #if CMPBYTES == 4
108 #define COMPARE(A,B) ((A)[0] != (B)[0])
109 #elif CMPBYTES == 8
110 #define COMPARE(A,B) (((A)[0] != (B)[0]) || ((A)[1] != (B)[1]))
111 #elif CMPBYTES == 12
112 #define COMPARE(A,B) (((A)[0] != (B)[0]) || ((A)[1] != (B)[1]) || ((A)[2] != (B)[2]))
113 #elif CMPBYTES == 16
114 #define COMPARE(A,B) (((A)[0] != (B)[0]) || ((A)[1] != (B)[1]) || ((A)[2] != (B)[2]) || ((A)[3] != (B)[3]))
115 #endif
116 #else
117 #if CMPBYTES == 2
118 #define COMPARE(A,B) ((A)[0] != (B)[0])
119 #elif CMPBYTES == 4
120 #define COMPARE(A,B) (((A)[0] != (B)[0]) || ((A)[1] != (B)[1]))
121 #elif CMPBYTES == 6
122 #define COMPARE(A,B) (((A)[0] != (B)[0]) || ((A)[1] != (B)[1]) || ((A)[2] != (B)[2]))
123 #elif CMPBYTES == 8
124 #define COMPARE(A,B) (((A)[0] != (B)[0]) || ((A)[1] != (B)[1]) || ((A)[2] != (B)[2]) || ((A)[3] != (B)[3]))
125 #endif
126 #endif
127 #else
128 // Otherwise, set INBYTES to be the maximum size it could possibly be.
129 #ifdef XFORM_FLOAT
130 #define CMPBYTES (sizeof(cmsFloat32Number)*cmsMAXCHANNELS)
131 #else
132 #define CMPBYTES (sizeof(cmsUInt16Number)*cmsMAXCHANNELS)
133 #endif
134 #endif
135
136 #ifndef COMPARE
137 #define COMPARE(A,B) memcmp((A),(B), CMPBYTES)
138 #endif
139
140 #if defined(UNPACK)
141 // Nothing to do, UNPACK is already defined
142 #elif defined(NO_UNPACK)
143 #define UNPACK(CTX,T,TO,FROM,STRIDE,AL) do { } while (0)
144 #elif defined(UNPACKFN)
145 #define UNPACK(CTX,T,TO,FROM,STRIDE,AL) \
146 do { (FROM) = UNPACKFN((CTX),(T),(TO),(FROM),(STRIDE),(AL)); } while (0)
147 #elif defined(XFORM_FLOAT)
148 #define UNPACK(CTX,T,TO,FROM,STRIDE,AL) \
149 do { (FROM) = (T)->FromInputFloat((CTX),(T),(TO),(FROM),(STRIDE)); } while (0)
150 #else
151 #define UNPACK(CTX,T,TO,FROM,STRIDE,AL) \
152 do { (FROM) = (T)->FromInput((CTX),(T),(TO),(FROM),(STRIDE)); } while (0)
153 #endif
154
155 #if defined(PACK)
156 // Nothing to do, PACK is already defined
157 #elif defined(NO_PACK)
158 #define PACK(CTX,T,FROM,TO,STRIDE,AL) \
159 do { (FROM) += (totaloutbytes/sizeof(XFORM_TYPE)); } while (0)
160 #elif defined(PACKFN)
161 #define PACK(CTX,T,FROM,TO,STRIDE,AL) \
162 do { (TO) = PACKFN((CTX),(T),(FROM),(TO),(STRIDE)); } while (0)
163 #elif defined(XFORM_FLOAT)
164 #define PACK(CTX,T,FROM,TO,STRIDE,AL) \
165 do { (TO) = (T)->ToOutputFloat((CTX),(T),(FROM),(TO),(STRIDE)); } while (0)
166 #else
167 #define PACK(CTX,T,FROM,TO,STRIDE,AL) \
168 do { (TO) = (T)->ToOutput((CTX),(T),(FROM),(TO),(STRIDE)); } while (0)
169 #endif
170
171 #ifndef ZEROPACK
172 /* The 'default' definition of ZEROPACK only works when
173 * inpackedsamplesize == outpackedsamplesize. */
174 #define ZEROPACK(CTX,T,TO,FROM) do { \
175 memset((TO),0,numoutchannels*outpackedsamplesize);\
176 if (numextras != 0) memcpy((TO)+numoutchannels*outpackedsamplesize,\
177 (FROM)+numinchannels*inpackedsamplesize,\
178 numextras*outpackedsamplesize);\
179 (TO)+=(1+prealphaindexout)*outpackedsamplesize; } while (0)
180 #endif
181
182 #ifndef UNPRE
183 #ifdef PREALPHA
184 #else
185 #define UNPRE(CTX,T,S,A) do {} while (0)
186 #endif
187 #endif
188
189 #ifndef REPRE
190 #ifdef PREALPHA
191 #define REPRE(CTX,T,S,A) do { int i; for (i = 0; i < numoutchannels; i++) \
192 (S)[i] = mul65535((S)[i],A); } while (0)
193 #else
194 #define REPRE(CTX,T,S,A) do {} while (0)
195 #endif
196 #endif
197
198 #ifndef XFORMVARS
199 #define XFORMVARS(p) do { } while (0)
200 #endif
201
202 #if defined(NUMOUTCHANNELS)
203 #ifdef XFORM_FLOAT
204 #define OUTBYTES (sizeof(cmsFloat32Number)*NUMOUTCHANNELS)
205 #else
206 #define OUTBYTES (sizeof(cmsUInt16Number)*NUMOUTCHANNELS)
207 #endif
208 #endif
209
210 #if defined(NO_PACK) && !defined(COPY_MATCHED) && defined(OUTBYTES)
211 #if (defined(XFORM_FLOAT) && OUTBYTES == 4) || OUTBYTES == 2
212 #define COPY_MATCHED(FROM,TO) ((TO)[0] = (FROM)[0])
213 #elif (defined(XFORM_FLOAT) && OUTBYTES == 8) || OUTBYTES == 4
214 #define COPY_MATCHED(FROM,TO) ((TO)[0] = (FROM)[0],(TO)[1] = (FROM)[1])
215 #elif (defined(XFORM_FLOAT) && OUTBYTES == 12) || OUTBYTES == 6
216 #define COPY_MATCHED(FROM,TO) ((TO)[0] = (FROM)[0],(TO)[1] = (FROM)[1],(TO)[2] = (FROM)[2])
217 #elif (defined(XFORM_FLOAT) && OUTBYTES == 16) || OUTBYTES == 8
218 #define COPY_MATCHED(FROM,TO) ((TO)[0] = (FROM)[0],(TO)[1] = (FROM)[1],(TO)[2] = (FROM)[2],(TO)[3] = (FROM)[3])
219 #else
220 #define COPY_MATCHED(FROM,TO) memcpy((TO),(FROM),(OUTBYTES))
221 #endif
222 #endif
223
224 #ifdef XFORM_FLOAT
225 #define XFORM_TYPE cmsFloat32Number
226 #else
227 #define XFORM_TYPE cmsUInt16Number
228 #endif
229
230 #ifndef COPY_EXTRAS
231 #ifdef NUMEXTRAS
232 #if NUMEXTRAS == 0
233 #define COPY_EXTRAS(TRANS,FROM,TO) do { } while (0)
234 #else
235 #define COPY_EXTRAS(TRANS,FROM,TO) \
236 do { memcpy((TO),(FROM),(NUMEXTRAS)*inpackedsamplesize); \
237 (TO) += (NUMEXTRAS)*inpackedsamplesize; \
238 (FROM) += (NUMEXTRAS)*inpackedsamplesize; \
239 } while (0)
240 #endif
241 #else
242 #define BULK_COPY_EXTRAS
243 #define COPY_EXTRAS(TRANS,FROM,TO) do { } while (0)
244 #endif
245 #endif
246
247 static
248 void FUNCTION_NAME(cmsContext ContextID,
249 _cmsTRANSFORM* p,
250 const void* in,
251 void* out,
252 cmsUInt32Number PixelsPerLine,
253 cmsUInt32Number LineCount,
254 const cmsStride* Stride)
255 {
256 _cmsTRANSFORMCORE *core = p->core;
257 #ifndef NO_UNPACK
258 #ifdef XFORM_FLOAT
259 cmsFloat32Number wIn[cmsMAXCHANNELS*2];
260 #else
261 cmsUInt16Number wIn[cmsMAXCHANNELS*2];
262 #endif
263 #define wIn0 (&wIn[0])
264 #define wIn1 (&wIn[cmsMAXCHANNELS])
265 #endif
266 XFORM_TYPE *currIn;
267 #ifdef CACHED
268 XFORM_TYPE *prevIn;
269 #endif /* CACHED */
270 #ifdef NO_PACK
271 XFORM_TYPE *wOut = (XFORM_TYPE *)out;
272 XFORM_TYPE *prevOut = (XFORM_TYPE *)p->Cache.CacheOut;
273 #else
274 XFORM_TYPE wOut[cmsMAXCHANNELS];
275 #endif
276 #if defined(PREALPHA) && !defined(PACKINCLUDESPREALPHA)
277 XFORM_TYPE wScaled[cmsMAXCHANNELS];
278 #endif
279 #ifdef GAMUTCHECK
280 _cmsPipelineEval16Fn evalGamut = core->GamutCheck->Eval16Fn;
281 #endif /* GAMUTCHECK */
282 #ifdef XFORM_FLOAT
283 _cmsPipelineEvalFloatFn eval = core->Lut->EvalFloatFn;
284 const cmsPipeline *data = core->Lut;
285 #else
286 _cmsPipelineEval16Fn eval = core->Lut->Eval16Fn;
287 void *data = core->Lut->Data;
288 #endif
289 cmsUInt32Number bppi = Stride->BytesPerPlaneIn;
290 cmsUInt32Number bppo = Stride->BytesPerPlaneOut;
291 #ifdef NUMINCHANNELS
292 int numinchannels = NUMINCHANNELS;
293 #else
294 int numinchannels = T_CHANNELS(p->InputFormat);
295 #endif
296 #ifdef NUMOUTCHANNELS
297 int numoutchannels = NUMOUTCHANNELS;
298 #else
299 int numoutchannels = T_CHANNELS(p->OutputFormat);
300 #endif
301 #ifdef NUMEXTRAS
302 int numextras = NUMEXTRAS;
303 #else
304 int numextras = T_EXTRA(p->InputFormat);
305 #endif
306 #ifdef INPACKEDSAMPLESIZE
307 int inpackedsamplesize = INPACKEDSAMPLESIZE;
308 #else
309 int inpackedsamplesize = T_BYTES(p->InputFormat);
310 #endif
311 #ifdef OUTPACKEDSAMPLESIZE
312 int outpackedsamplesize = OUTPACKEDSAMPLESIZE;
313 #else
314 int outpackedsamplesize = T_BYTES(p->OutputFormat);
315 #endif
316 int prealphaindexin = numinchannels + numextras - 1;
317 int prealphaindexout = numoutchannels + numextras - 1;
318 int totalinbytes = (numinchannels + numextras)*inpackedsamplesize;
319 int totaloutbytes = (numoutchannels + numextras)*outpackedsamplesize;
320
321 /* Silence some warnings */
322 (void)bppi;
323 (void)bppo;
324 (void)prealphaindexin;
325 (void)numextras;
326 (void)prealphaindexout;
327 (void)inpackedsamplesize;
328 (void)outpackedsamplesize;
329 (void)totalinbytes;
330 (void)totaloutbytes;
331
332 #ifdef BULK_COPY_EXTRAS
333 if (core->dwOriginalFlags & cmsFLAGS_COPY_ALPHA)
334 _cmsHandleExtraChannels(ContextID, p, in, out, PixelsPerLine, LineCount, Stride);
335 #endif
336
337 if (PixelsPerLine == 0)
338 return;
339
340 #ifdef NO_UNPACK
341 prevIn = (XFORM_TYPE *)p->Cache.CacheIn;
342 #else
343 #ifdef CACHED
344 // Empty buffers for quick memcmp
345 memset(wIn1, 0, sizeof(XFORM_TYPE) * cmsMAXCHANNELS);
346
347 // Get copy of zero cache
348 memcpy(wIn0, p->Cache.CacheIn, sizeof(XFORM_TYPE) * cmsMAXCHANNELS);
349 memcpy(wOut, p->Cache.CacheOut, sizeof(XFORM_TYPE) * cmsMAXCHANNELS);
350
351 // The caller guarantees us that the cache is always valid on entry; if
352 // the representation is changed, the cache is reset.
353 prevIn = wIn0;
354 #endif /* CACHED */
355 currIn = wIn1;
356 #endif
357
358 while (LineCount-- > 0)
359 {
360 cmsUInt32Number n = PixelsPerLine;
361 cmsUInt8Number* accum = (cmsUInt8Number*) in;
362 cmsUInt8Number* output = (cmsUInt8Number*) out;
363 #ifdef NO_UNPACK
364 currIn = (XFORM_TYPE *)accum;
365 #endif
366 while (n-- > 0) { // prevIn == CacheIn, wOut = CacheOut
367 #ifdef PREALPHA
368 #ifdef XFORM_FLOAT
369 cmsFloat32Number alpha = ((cmsFloat32Number *)accum)[prealphaindexin];
370 #else
371 cmsUInt32Number alpha = inpackedsamplesize == 2 ?
372 ((cmsUInt16Number *)accum)[prealphaindexin] :
373 (accum[prealphaindexin]);
374 #endif
375 if (alpha == 0) {
376 ZEROPACK(ContextID,p,output,accum);
377 accum += inpackedsamplesize*(prealphaindexin+1);
378 } else {
379 #endif
380 UNPACK(ContextID,p,currIn,accum,bppi,alpha);
381 #ifdef PREALPHA
382 #ifndef UNPACKINCLUDESPREALPHA
383 #ifdef XFORM_FLOAT
384 {
385 int i;
386 cmsFloat32Number inva = 1.0f / alpha;
387 for (i = 0; i < numinchannels; i++)
388 currIn[i] *= inva;
389 }
390 #else
391 {
392 int i;
393 cmsUInt32Number al = inpackedsamplesize == 1 ? alpha*0x101 : alpha;
394 cmsUInt32Number inva = 0xffff0000U / al;
395 for (i = 0; i < numinchannels; i++)
396 currIn[i] = ((currIn[i] * inva)>>16);
397 }
398 #endif
399 #endif
400 #endif
401 #ifdef CACHED
402 if (COMPARE(currIn, prevIn))
403 #endif /* CACHED */
404 {
405 #ifdef GAMUTCHECK
406 #ifdef XFORM_FLOAT
407 cmsFloat32Number OutOfGamut;
408
409 // Evaluate gamut marker.
410 cmsPipelineEvalFloat(currIn, &OutOfGamut, core->GamutCheck);
411
412 // Is current color out of gamut?
413 if (OutOfGamut > 0.0)
414 // Certainly, out of gamut
415 for (j=0; j < cmsMAXCHANNELS; j++)
416 fOut[j] = -1.0;
417 else
418 #else
419 cmsUInt16Number wOutOfGamut;
420
421 evalGamut(ContextID, currIn, &wOutOfGamut, core->GamutCheck->Data);
422 if (wOutOfGamut >= 1)
423 /* RJW: Could be faster? copy once to a local buffer? */
424 cmsGetAlarmCodes(ContextID, wOut);
425 else
426 #endif /* FLOAT_XFORM */
427 #endif /* GAMUTCHECK */
428 eval(ContextID, currIn, wOut, data);
429 #ifdef NO_UNPACK
430 #ifdef CACHED
431 prevIn = currIn;
432 #endif
433 currIn = (XFORM_TYPE *)(((char *)currIn) + totalinbytes);
434 #else
435 #ifdef CACHED
436 {XFORM_TYPE *tmp = currIn; currIn = prevIn; prevIn = tmp;} // SWAP
437 #endif /* CACHED */
438 #endif /* NO_UNPACK */
439 }
440 #ifdef NO_PACK
441 else
442 COPY_MATCHED(prevOut,wOut);
443 prevOut = wOut;
444 #endif
445 #ifdef PREALPHA
446 #ifndef PACKINCLUDESPREALPHA
447 #ifdef XFORM_FLOAT
448 {
449 int i;
450 for (i = 0; i < numoutchannels; i++)
451 wScaled = wOut[i] * alpha;
452 }
453 #else
454 {
455 int i;
456 cmsUInt32Number al = inpackedsamplesize == 1 ? alpha*0x101 : alpha;
457 for (i = 0; i < numoutchannels; i++)
458 wScaled[i] = mul65535(wOut[i],al);
459 }
460 #endif
461 PACK(ContextID,p,wScaled,output,bppo,alpha);
462 #else
463 PACK(ContextID,p,wOut,output,bppo,alpha);
464 #endif
465 #else
466 PACK(ContextID,p,wOut,output,bppo,alpha);
467 #endif
468 COPY_EXTRAS(p,accum,output);
469 #ifdef PREALPHA
470 }
471 #endif
472 } /* End x loop */
473 in = (void *)((cmsUInt8Number *)in + Stride->BytesPerLineIn);
474 out = (void *)((cmsUInt8Number *)out + Stride->BytesPerLineOut);
475 } /* End y loop */
476 /* The following code is only safe if we know that a given transform is
477 * called on one thread a time. */
478 #if 0
479 #ifdef CACHED
480 #ifdef NO_UNPACK
481 memcpy(p->Cache.CacheIn,prevIn, CMPBYTES);
482 #else
483 memcpy(p->Cache.CacheIn, prevIn, sizeof(XFORM_TYPE) * cmsMAXCHANNELS);
484 #endif
485 #ifdef NO_PACK
486 COPY_MATCHED(prevOut,p->Cache.CacheOut);
487 #else
488 memcpy(p->Cache.CacheOut, wOut, sizeof(XFORM_TYPE) * cmsMAXCHANNELS);
489 #endif /* NO_PACK */
490 #endif /* CACHED */
491 #endif
492 }
493
494 #undef wIn0
495 #undef wIn1
496 #undef XFORM_TYPE
497 #undef XFORM_FLOAT
498
499 #undef FUNCTION_NAME
500 #undef COMPARE
501 #undef CMPBYTES
502 #undef OUTBYTES
503 #undef UNPACK
504 #undef NO_UNPACK
505 #undef PACK
506 #undef NO_PACK
507 #undef UNPACKFN
508 #undef PACKFN
509 #undef GAMUTCHECK
510 #undef CACHED
511 #undef COPY_MATCHED
512 #undef EXTRABYTES
513 #undef COPY_EXTRAS
514 #undef BULK_COPY_EXTRAS
515 #undef PREALPHA
516 #undef ZEROPACK
517 #undef XFORMVARS
518 #undef UNPRE
519 #undef REPRE
520 #undef INPACKEDSAMPLESIZE
521 #undef OUTPACKEDSAMPLESIZE
522 #undef NUMINCHANNELS
523 #undef NUMOUTCHANNELS
524 #undef NUMEXTRAS