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 | // To reduce the amount of surplus memory checking done, set INBYTES to the |
18 | // number of bytes in an unpacked data chunk. INBYTES will only have an |
19 | // effect if CACHED or NO_UNPACK |
20 | // |
21 | // If you know the code to be used to unpack (or pack, or both) data to/from |
22 | // the simple 16 bit transform input/output format, then you can choose |
23 | // to this directly by defining UNPACK/PACK macros as follows: |
24 | // UNPACK(T,TO,FROM,SIZE) (Opt) code to unpack input data (T = Transform |
25 | // TO = buffer to unpack into, FROM = data, |
26 | // SIZE = size of data) |
27 | // PACK(T,FROM,TO,SIZE) (Opt) code to pack transformed input data |
28 | // (T = Transform, FROM = transformed data, |
29 | // TO = output buffer to pack into, |
30 | // SIZE = size of data) |
31 | // |
32 | // As an alternative to the above, if you know the function name that would |
33 | // be called, supply that in UNPACKFN and PACKFN and inlining compilers |
34 | // should hopefully do the hard work for you. |
35 | // UNPACKFN (Opt) function to unpack input data |
36 | // PACKFN (Opt) function to pack input data |
37 | // |
38 | // If the data happens to be in the correct input format anyway, we can skip |
39 | // unpacking it entirely and just use it direct. |
40 | // NO_UNPACK (Opt) if defined, transform direct from the input |
41 | // data. INBYTES must be defined. |
42 | // |
43 | // UNPACK/PACK/UNPACKFN/PACKFN/NO_UNPACK are all expected to update their |
44 | // TO pointer to point to the next pixels data. This means for cases where |
45 | // we have extra bytes, they should skip the extra bytes too! |
46 | // |
47 | // If the data happens to be in the correct output format anyway, we can skip |
48 | // packing it entirely and just transform it direct into the buffer. |
49 | // NO_PACK (Opt) if defined, transform direct to the output |
50 | // data. OUTBYTES must be defined. |
51 | // COPY_MATCHED(FROM,TO)(Opt)if defined, copy output values from FROM to |
52 | // TO. Used in the case CACHED case where the |
53 | // cache matches and we have to copy forwards. |
54 | // |
55 | // GAMUTCHECK can be predefined if a gamut check needs to be done. |
56 | // |
57 | // If there are a known number of extra bytes to be dealt with, define EXTRABYTES |
58 | // to that number (such as 0 for none). |
59 | // If you want to provide your own code for copying from input to output, define |
60 | // COPY_EXTRAS(TRANS,FROM,TO) to do so. |
61 | // If none of these are defined, we call cmsHandleExtraChannels. |
62 | |
63 | #ifdef INBYTES |
64 | // Previously, we've attempted to do 'int' based checks here, but this falls |
65 | // foul of some compilers with their strict pointer aliasing. We have the |
66 | // choice of calling memcmp (which tests using chars, so is safe), or of |
67 | // testing using the actual type. |
68 | #ifdef XFORM_FLOAT |
69 | #if INBYTES == 4 |
70 | #define COMPARE(A,B) ((A)[0] != (B)[0]) |
71 | #elif INBYTES == 8 |
72 | #define COMPARE(A,B) (((A)[0] != (B)[0]) || ((A)[1] != (B)[1])) |
73 | #elif INBYTES == 12 |
74 | #define COMPARE(A,B) (((A)[0] != (B)[0]) || ((A)[1] != (B)[1]) || ((A)[2] != (B)[2])) |
75 | #elif INBYTES == 16 |
76 | #define COMPARE(A,B) (((A)[0] != (B)[0]) || ((A)[1] != (B)[1]) || ((A)[2] != (B)[2]) || ((A)[3] != (B)[3])) |
77 | #endif |
78 | #else |
79 | #if INBYTES == 2 |
80 | #define COMPARE(A,B) ((A)[0] != (B)[0]) |
81 | #elif INBYTES == 4 |
82 | #define COMPARE(A,B) (((A)[0] != (B)[0]) || ((A)[1] != (B)[1])) |
83 | #elif INBYTES == 6 |
84 | #define COMPARE(A,B) (((A)[0] != (B)[0]) || ((A)[1] != (B)[1]) || ((A)[2] != (B)[2])) |
85 | #elif INBYTES == 8 |
86 | #define COMPARE(A,B) (((A)[0] != (B)[0]) || ((A)[1] != (B)[1]) || ((A)[2] != (B)[2]) || ((A)[3] != (B)[3])) |
87 | #endif |
88 | #endif |
89 | #else |
90 | // Otherwise, set INBYTES to be the maximum size it could possibly be. |
91 | #define INBYTES (sizeof(cmsUInt16Number)*cmsMAXCHANNELS) |
92 | #endif |
93 | |
94 | #ifndef COMPARE |
95 | #define COMPARE(A,B) memcmp((A),(B), INBYTES) |
96 | #endif |
97 | |
98 | #if defined(UNPACK) |
99 | // Nothing to do, UNPACK is already defined |
100 | #elif defined(NO_UNPACK) |
101 | #define UNPACK(CTX,T,TO,FROM,STRIDE) do { } while (0) |
102 | #elif defined(UNPACKFN) |
103 | #define UNPACK(CTX,T,TO,FROM,STRIDE) \ |
104 | do { (FROM) = UNPACKFN((CTX),(T),(TO),(FROM),(STRIDE)); } while (0) |
105 | #elif defined(XFORM_FLOAT) |
106 | #define UNPACK(CTX,T,TO,FROM,STRIDE) \ |
107 | do { (FROM) = (T)->FromInputFloat((CTX),(T),(TO),(FROM),(STRIDE)); } while (0) |
108 | #else |
109 | #define UNPACK(CTX,T,TO,FROM,STRIDE) \ |
110 | do { (FROM) = (T)->FromInput((CTX),(T),(TO),(FROM),(STRIDE)); } while (0) |
111 | #endif |
112 | |
113 | #if defined(PACK) |
114 | // Nothing to do, PACK is already defined |
115 | #elif defined(NO_PACK) |
116 | #define PACK(CTX,T,FROM,TO,STRIDE) \ |
117 | do { (FROM) += ((OUTBYTES)/sizeof(XFORM_TYPE)); } while (0) |
118 | #elif defined(PACKFN) |
119 | #define PACK(CTX,T,FROM,TO,STRIDE) \ |
120 | do { (TO) = PACKFN((CTX),(T),(FROM),(TO),(STRIDE)); } while (0) |
121 | #elif defined(XFORM_FLOAT) |
122 | #define PACK(CTX,T,FROM,TO,STRIDE) \ |
123 | do { (TO) = (T)->ToOutputFloat((CTX),(T),(FROM),(TO),(STRIDE)); } while (0) |
124 | #else |
125 | #define PACK(CTX,T,FROM,TO,STRIDE) \ |
126 | do { (TO) = (T)->ToOutput((CTX),(T),(FROM),(TO),(STRIDE)); } while (0) |
127 | #endif |
128 | |
129 | #if defined(NO_PACK) && !defined(COPY_MATCHED) |
130 | #if (defined(XFORM_FLOAT) && OUTBYTES == 4) || OUTBYTES == 2 |
131 | #define COPY_MATCHED(FROM,TO) ((TO)[0] = (FROM)[0]) |
132 | #elif (defined(XFORM_FLOAT) && OUTBYTES == 8) || OUTBYTES == 4 |
133 | #define COPY_MATCHED(FROM,TO) ((TO)[0] = (FROM)[0],(TO)[1] = (FROM)[1]) |
134 | #elif (defined(XFORM_FLOAT) && OUTBYTES == 12) || OUTBYTES == 6 |
135 | #define COPY_MATCHED(FROM,TO) ((TO)[0] = (FROM)[0],(TO)[1] = (FROM)[1],(TO)[2] = (FROM)[2]) |
136 | #elif (defined(XFORM_FLOAT) && OUTBYTES == 16) || OUTBYTES == 8 |
137 | #define COPY_MATCHED(FROM,TO) ((TO)[0] = (FROM)[0],(TO)[1] = (FROM)[1],(TO)[2] = (FROM)[2],(TO)[3] = (FROM)[3]) |
138 | #else |
139 | #define COPY_MATCHED(FROM,TO) memcpy((TO),(FROM),(OUTBYTES)) |
140 | #endif |
141 | #endif |
142 | |
143 | #ifdef XFORM_FLOAT |
144 | #define XFORM_TYPE cmsFloat32Number |
145 | #else |
146 | #define XFORM_TYPE cmsUInt16Number |
147 | #endif |
148 | |
149 | #ifndef COPY_EXTRAS |
150 | #ifdef EXTRABYTES |
151 | #if EXTRABYTES == 0 |
152 | #define COPY_EXTRAS(TRANS,FROM,TO) do { } while (0) |
153 | #else |
154 | #define COPY_EXTRAS(TRANS,FROM,TO) memcpy((TO),(FROM),(EXTRABYTES)) |
155 | #endif |
156 | #else |
157 | #define |
158 | #define (TRANS,FROM,TO) do { } while (0) |
159 | #endif |
160 | #endif |
161 | |
162 | static |
163 | void FUNCTION_NAME(cmsContext ContextID, |
164 | _cmsTRANSFORM* p, |
165 | const void* in, |
166 | void* out, |
167 | cmsUInt32Number PixelsPerLine, |
168 | cmsUInt32Number LineCount, |
169 | const cmsStride* Stride) |
170 | { |
171 | _cmsTRANSFORMCORE *core = p->core; |
172 | #ifndef NO_UNPACK |
173 | #ifdef XFORM_FLOAT |
174 | cmsFloat32Number wIn[cmsMAXCHANNELS*2]; |
175 | #else |
176 | cmsUInt16Number wIn[cmsMAXCHANNELS*2]; |
177 | #endif |
178 | #define wIn0 (&wIn[0]) |
179 | #define wIn1 (&wIn[cmsMAXCHANNELS]) |
180 | #endif |
181 | XFORM_TYPE *currIn; |
182 | #ifdef CACHED |
183 | XFORM_TYPE *prevIn; |
184 | #endif /* CACHED */ |
185 | #ifdef NO_PACK |
186 | XFORM_TYPE *wOut = (XFORM_TYPE *)out; |
187 | XFORM_TYPE *prevOut = (XFORM_TYPE *)p->Cache.CacheOut; |
188 | #else |
189 | XFORM_TYPE wOut[cmsMAXCHANNELS]; |
190 | #endif |
191 | #ifdef GAMUTCHECK |
192 | _cmsOPTeval16Fn evalGamut = core->GamutCheck->Eval16Fn; |
193 | #endif /* GAMUTCHECK */ |
194 | #ifdef XFORM_FLOAT |
195 | _cmsPipelineEvalFloatFn eval = core->Lut->EvalFloatFn; |
196 | const cmsPipeline *data = core->Lut; |
197 | #else |
198 | _cmsOPTeval16Fn eval = core->Lut->Eval16Fn; |
199 | void *data = core->Lut->Data; |
200 | #endif |
201 | cmsUInt32Number bppi = Stride->BytesPerPlaneIn; |
202 | cmsUInt32Number bppo = Stride->BytesPerPlaneOut; |
203 | |
204 | /* Silence some warnings */ |
205 | (void)bppi; |
206 | (void)bppo; |
207 | |
208 | #ifdef BULK_COPY_EXTRAS |
209 | if (core->dwOriginalFlags & cmsFLAGS_COPY_ALPHA) |
210 | _cmsHandleExtraChannels(ContextID, p, in, out, PixelsPerLine, LineCount, Stride); |
211 | #endif |
212 | |
213 | if (PixelsPerLine == 0) |
214 | return; |
215 | |
216 | #ifdef NO_UNPACK |
217 | prevIn = (XFORM_TYPE *)p->Cache.CacheIn; |
218 | #else |
219 | #ifdef CACHED |
220 | // Empty buffers for quick memcmp |
221 | memset(wIn1, 0, sizeof(XFORM_TYPE) * cmsMAXCHANNELS); |
222 | |
223 | // Get copy of zero cache |
224 | memcpy(wIn0, p->Cache.CacheIn, sizeof(XFORM_TYPE) * cmsMAXCHANNELS); |
225 | memcpy(wOut, p->Cache.CacheOut, sizeof(XFORM_TYPE) * cmsMAXCHANNELS); |
226 | |
227 | // The caller guarantees us that the cache is always valid on entry; if |
228 | // the representation is changed, the cache is reset. |
229 | prevIn = wIn0; |
230 | #endif /* CACHED */ |
231 | currIn = wIn1; |
232 | #endif |
233 | |
234 | while (LineCount-- > 0) |
235 | { |
236 | cmsUInt32Number n = PixelsPerLine; |
237 | cmsUInt8Number* accum = (cmsUInt8Number*) in; |
238 | cmsUInt8Number* output = (cmsUInt8Number*) out; |
239 | #ifdef NO_UNPACK |
240 | currIn = (XFORM_TYPE *)accum; |
241 | #endif |
242 | while (n-- > 0) { // prevIn == CacheIn, wOut = CacheOut |
243 | UNPACK(ContextID,p,currIn,accum,bppi); |
244 | #ifdef CACHED |
245 | if (COMPARE(currIn, prevIn)) |
246 | #endif /* CACHED */ |
247 | { |
248 | #ifdef GAMUTCHECK |
249 | #ifdef XFORM_FLOAT |
250 | cmsFloat32Number OutOfGamut; |
251 | |
252 | // Evaluate gamut marker. |
253 | cmsPipelineEvalFloat(currIn, &OutOfGamut, core->GamutCheck); |
254 | |
255 | // Is current color out of gamut? |
256 | if (OutOfGamut > 0.0) |
257 | // Certainly, out of gamut |
258 | for (j=0; j < cmsMAXCHANNELS; j++) |
259 | fOut[j] = -1.0; |
260 | else |
261 | #else |
262 | cmsUInt16Number wOutOfGamut; |
263 | |
264 | evalGamut(ContextID, currIn, &wOutOfGamut, core->GamutCheck->Data); |
265 | if (wOutOfGamut >= 1) |
266 | /* RJW: Could be faster? copy once to a local buffer? */ |
267 | cmsGetAlarmCodes(ContextID, wOut); |
268 | else |
269 | #endif /* FLOAT_XFORM */ |
270 | #endif /* GAMUTCHECK */ |
271 | eval(ContextID, currIn, wOut, data); |
272 | #ifdef NO_UNPACK |
273 | #ifdef CACHED |
274 | prevIn = currIn; |
275 | #endif |
276 | currIn = (XFORM_TYPE *)(((char *)currIn) + INBYTES); |
277 | #else |
278 | #ifdef CACHED |
279 | {XFORM_TYPE *tmp = currIn; currIn = prevIn; prevIn = tmp;} // SWAP |
280 | #endif /* CACHED */ |
281 | #endif /* NO_UNPACK */ |
282 | } |
283 | #ifdef NO_PACK |
284 | else |
285 | COPY_MATCHED(prevOut,wOut); |
286 | prevOut = wOut; |
287 | #endif |
288 | PACK(ContextID,p,wOut,output,bppo); |
289 | COPY_EXTRAS(p,accum,output); |
290 | } /* End x loop */ |
291 | in = (void *)((cmsUInt8Number *)in + Stride->BytesPerLineIn); |
292 | out = (void *)((cmsUInt8Number *)out + Stride->BytesPerLineOut); |
293 | } /* End y loop */ |
294 | /* The following code is only safe if we know that a given transform is |
295 | * called on one thread a time. */ |
296 | #if 0 |
297 | #ifdef CACHED |
298 | #ifdef NO_UNPACK |
299 | memcpy(p->Cache.CacheIn,prevIn,INBYTES); |
300 | #else |
301 | memcpy(p->Cache.CacheIn, prevIn, sizeof(XFORM_TYPE) * cmsMAXCHANNELS); |
302 | #endif |
303 | #ifdef NO_PACK |
304 | COPY_MATCHED(prevOut,p->Cache.CacheOut); |
305 | #else |
306 | memcpy(p->Cache.CacheOut, wOut, sizeof(XFORM_TYPE) * cmsMAXCHANNELS); |
307 | #endif /* NO_PACK */ |
308 | #endif /* CACHED */ |
309 | #endif |
310 | } |
311 | |
312 | #undef wIn0 |
313 | #undef wIn1 |
314 | #undef XFORM_TYPE |
315 | #undef XFORM_FLOAT |
316 | |
317 | #undef FUNCTION_NAME |
318 | #undef COMPARE |
319 | #undef INBYTES |
320 | #undef OUTBYTES |
321 | #undef UNPACK |
322 | #undef NO_UNPACK |
323 | #undef PACK |
324 | #undef NO_PACK |
325 | #undef UNPACKFN |
326 | #undef PACKFN |
327 | #undef GAMUTCHECK |
328 | #undef CACHED |
329 | #undef COPY_MATCHED |
330 | #undef EXTRABYTES |
331 | #undef COPY_EXTRAS |
332 | #undef BULK_COPY_EXTRAS |
333 | |