1 | //--------------------------------------------------------------------------------- |
2 | // |
3 | // Little Color Management System |
4 | // Copyright (c) 1998-2017 Marti Maria Saguer |
5 | // |
6 | // Permission is hereby granted, free of charge, to any person obtaining |
7 | // a copy of this software and associated documentation files (the "Software"), |
8 | // to deal in the Software without restriction, including without limitation |
9 | // the rights to use, copy, modify, merge, publish, distribute, sublicense, |
10 | // and/or sell copies of the Software, and to permit persons to whom the Software |
11 | // is furnished to do so, subject to the following conditions: |
12 | // |
13 | // The above copyright notice and this permission notice shall be included in |
14 | // all copies or substantial portions of the Software. |
15 | // |
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
17 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO |
18 | // THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
19 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE |
20 | // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
21 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
22 | // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
23 | // |
24 | //--------------------------------------------------------------------------------- |
25 | // |
26 | |
27 | #include "lcms2_internal.h" |
28 | |
29 | // Alpha copy ------------------------------------------------------------------------------------------------------------------ |
30 | |
31 | // This macro return words stored as big endian |
32 | #define CHANGE_ENDIAN(w) (cmsUInt16Number) ((cmsUInt16Number) ((w)<<8)|((w)>>8)) |
33 | |
34 | |
35 | // Floor to byte, taking care of saturation |
36 | cmsINLINE cmsUInt8Number _cmsQuickSaturateByte(cmsFloat64Number d) |
37 | { |
38 | d += 0.5; |
39 | if (d <= 0) return 0; |
40 | if (d >= 255.0) return 255; |
41 | |
42 | return (cmsUInt8Number) _cmsQuickFloorWord(d); |
43 | } |
44 | |
45 | |
46 | // Return the size in bytes of a given formatter |
47 | static |
48 | cmsUInt32Number trueBytesSize(cmsUInt32Number Format) |
49 | { |
50 | cmsUInt32Number fmt_bytes = T_BYTES(Format); |
51 | |
52 | // For double, the T_BYTES field returns zero |
53 | if (fmt_bytes == 0) |
54 | return sizeof(double); |
55 | |
56 | // Otherwise, it is already correct for all formats |
57 | return fmt_bytes; |
58 | } |
59 | |
60 | |
61 | // Several format converters |
62 | |
63 | typedef void(*cmsFormatterAlphaFn)(void* dst, const void* src); |
64 | |
65 | |
66 | // From 8 |
67 | |
68 | static |
69 | void copy8(void* dst, const void* src) |
70 | { |
71 | memmove(dst, src, 1); |
72 | } |
73 | |
74 | static |
75 | void from8to16(void* dst, const void* src) |
76 | { |
77 | cmsUInt8Number n = *(cmsUInt8Number*)src; |
78 | *(cmsUInt16Number*) dst = FROM_8_TO_16(n); |
79 | } |
80 | |
81 | static |
82 | void from8to16SE(void* dst, const void* src) |
83 | { |
84 | cmsUInt8Number n = *(cmsUInt8Number*)src; |
85 | *(cmsUInt16Number*)dst = CHANGE_ENDIAN(FROM_8_TO_16(n)); |
86 | } |
87 | |
88 | static |
89 | void from8toFLT(void* dst, const void* src) |
90 | { |
91 | *(cmsFloat32Number*)dst = (*(cmsUInt8Number*)src) / 255.0f; |
92 | } |
93 | |
94 | static |
95 | void from8toDBL(void* dst, const void* src) |
96 | { |
97 | *(cmsFloat64Number*)dst = (*(cmsUInt8Number*)src) / 255.0; |
98 | } |
99 | |
100 | static |
101 | void from8toHLF(void* dst, const void* src) |
102 | { |
103 | #ifndef CMS_NO_HALF_SUPPORT |
104 | cmsFloat32Number n = (*(cmsUInt8Number*)src) / 255.0f; |
105 | *(cmsUInt16Number*)dst = _cmsFloat2Half(n); |
106 | #else |
107 | cmsUNUSED_PARAMETER(dst); |
108 | cmsUNUSED_PARAMETER(src); |
109 | #endif |
110 | } |
111 | |
112 | // From 16 |
113 | |
114 | static |
115 | void from16to8(void* dst, const void* src) |
116 | { |
117 | cmsUInt16Number n = *(cmsUInt16Number*)src; |
118 | *(cmsUInt8Number*) dst = FROM_16_TO_8(n); |
119 | } |
120 | |
121 | static |
122 | void from16SEto8(void* dst, const void* src) |
123 | { |
124 | cmsUInt16Number n = *(cmsUInt16Number*)src; |
125 | *(cmsUInt8Number*)dst = FROM_16_TO_8(CHANGE_ENDIAN(n)); |
126 | } |
127 | |
128 | static |
129 | void copy16(void* dst, const void* src) |
130 | { |
131 | memmove(dst, src, 2); |
132 | } |
133 | |
134 | static |
135 | void from16to16(void* dst, const void* src) |
136 | { |
137 | cmsUInt16Number n = *(cmsUInt16Number*)src; |
138 | *(cmsUInt16Number*)dst = CHANGE_ENDIAN(n); |
139 | } |
140 | |
141 | static |
142 | void from16toFLT(void* dst, const void* src) |
143 | { |
144 | *(cmsFloat32Number*)dst = (*(cmsUInt16Number*)src) / 65535.0f; |
145 | } |
146 | |
147 | static |
148 | void from16SEtoFLT(void* dst, const void* src) |
149 | { |
150 | *(cmsFloat32Number*)dst = (CHANGE_ENDIAN(*(cmsUInt16Number*)src)) / 65535.0f; |
151 | } |
152 | |
153 | static |
154 | void from16toDBL(void* dst, const void* src) |
155 | { |
156 | *(cmsFloat64Number*)dst = (*(cmsUInt16Number*)src) / 65535.0f; |
157 | } |
158 | |
159 | static |
160 | void from16SEtoDBL(void* dst, const void* src) |
161 | { |
162 | *(cmsFloat64Number*)dst = (CHANGE_ENDIAN(*(cmsUInt16Number*)src)) / 65535.0f; |
163 | } |
164 | |
165 | static |
166 | void from16toHLF(void* dst, const void* src) |
167 | { |
168 | #ifndef CMS_NO_HALF_SUPPORT |
169 | cmsFloat32Number n = (*(cmsUInt16Number*)src) / 65535.0f; |
170 | *(cmsUInt16Number*)dst = _cmsFloat2Half(n); |
171 | #else |
172 | cmsUNUSED_PARAMETER(dst); |
173 | cmsUNUSED_PARAMETER(src); |
174 | #endif |
175 | } |
176 | |
177 | static |
178 | void from16SEtoHLF(void* dst, const void* src) |
179 | { |
180 | #ifndef CMS_NO_HALF_SUPPORT |
181 | cmsFloat32Number n = (CHANGE_ENDIAN(*(cmsUInt16Number*)src)) / 65535.0f; |
182 | *(cmsUInt16Number*)dst = _cmsFloat2Half(n); |
183 | #else |
184 | cmsUNUSED_PARAMETER(dst); |
185 | cmsUNUSED_PARAMETER(src); |
186 | #endif |
187 | } |
188 | // From Float |
189 | |
190 | static |
191 | void fromFLTto8(void* dst, const void* src) |
192 | { |
193 | cmsFloat32Number n = *(cmsFloat32Number*)src; |
194 | *(cmsUInt8Number*)dst = _cmsQuickSaturateByte(n * 255.0f); |
195 | } |
196 | |
197 | static |
198 | void fromFLTto16(void* dst, const void* src) |
199 | { |
200 | cmsFloat32Number n = *(cmsFloat32Number*)src; |
201 | *(cmsUInt16Number*)dst = _cmsQuickSaturateWord(n * 65535.0f); |
202 | } |
203 | |
204 | static |
205 | void fromFLTto16SE(void* dst, const void* src) |
206 | { |
207 | cmsFloat32Number n = *(cmsFloat32Number*)src; |
208 | cmsUInt16Number i = _cmsQuickSaturateWord(n * 65535.0f); |
209 | |
210 | *(cmsUInt16Number*)dst = CHANGE_ENDIAN(i); |
211 | } |
212 | |
213 | static |
214 | void copy32(void* dst, const void* src) |
215 | { |
216 | memmove(dst, src, sizeof(cmsFloat32Number)); |
217 | } |
218 | |
219 | static |
220 | void fromFLTtoDBL(void* dst, const void* src) |
221 | { |
222 | cmsFloat32Number n = *(cmsFloat32Number*)src; |
223 | *(cmsFloat64Number*)dst = (cmsFloat64Number)n; |
224 | } |
225 | |
226 | static |
227 | void fromFLTtoHLF(void* dst, const void* src) |
228 | { |
229 | #ifndef CMS_NO_HALF_SUPPORT |
230 | cmsFloat32Number n = *(cmsFloat32Number*)src; |
231 | *(cmsUInt16Number*)dst = _cmsFloat2Half(n); |
232 | #else |
233 | cmsUNUSED_PARAMETER(dst); |
234 | cmsUNUSED_PARAMETER(src); |
235 | #endif |
236 | } |
237 | |
238 | |
239 | // From HALF |
240 | |
241 | static |
242 | void fromHLFto8(void* dst, const void* src) |
243 | { |
244 | #ifndef CMS_NO_HALF_SUPPORT |
245 | cmsFloat32Number n = _cmsHalf2Float(*(cmsUInt16Number*)src); |
246 | *(cmsUInt8Number*)dst = _cmsQuickSaturateByte(n * 255.0f); |
247 | #else |
248 | cmsUNUSED_PARAMETER(dst); |
249 | cmsUNUSED_PARAMETER(src); |
250 | #endif |
251 | |
252 | } |
253 | |
254 | static |
255 | void fromHLFto16(void* dst, const void* src) |
256 | { |
257 | #ifndef CMS_NO_HALF_SUPPORT |
258 | cmsFloat32Number n = _cmsHalf2Float(*(cmsUInt16Number*)src); |
259 | *(cmsUInt16Number*)dst = _cmsQuickSaturateWord(n * 65535.0f); |
260 | #else |
261 | cmsUNUSED_PARAMETER(dst); |
262 | cmsUNUSED_PARAMETER(src); |
263 | #endif |
264 | } |
265 | |
266 | static |
267 | void fromHLFto16SE(void* dst, const void* src) |
268 | { |
269 | #ifndef CMS_NO_HALF_SUPPORT |
270 | cmsFloat32Number n = _cmsHalf2Float(*(cmsUInt16Number*)src); |
271 | cmsUInt16Number i = _cmsQuickSaturateWord(n * 65535.0f); |
272 | *(cmsUInt16Number*)dst = CHANGE_ENDIAN(i); |
273 | #else |
274 | cmsUNUSED_PARAMETER(dst); |
275 | cmsUNUSED_PARAMETER(src); |
276 | #endif |
277 | } |
278 | static |
279 | void fromHLFtoFLT(void* dst, const void* src) |
280 | { |
281 | #ifndef CMS_NO_HALF_SUPPORT |
282 | *(cmsFloat32Number*)dst = _cmsHalf2Float(*(cmsUInt16Number*)src); |
283 | #else |
284 | cmsUNUSED_PARAMETER(dst); |
285 | cmsUNUSED_PARAMETER(src); |
286 | #endif |
287 | } |
288 | |
289 | static |
290 | void fromHLFtoDBL(void* dst, const void* src) |
291 | { |
292 | #ifndef CMS_NO_HALF_SUPPORT |
293 | *(cmsFloat64Number*)dst = (cmsFloat64Number)_cmsHalf2Float(*(cmsUInt16Number*)src); |
294 | #else |
295 | cmsUNUSED_PARAMETER(dst); |
296 | cmsUNUSED_PARAMETER(src); |
297 | #endif |
298 | } |
299 | |
300 | // From double |
301 | static |
302 | void fromDBLto8(void* dst, const void* src) |
303 | { |
304 | cmsFloat64Number n = *(cmsFloat64Number*)src; |
305 | *(cmsUInt8Number*)dst = _cmsQuickSaturateByte(n * 255.0); |
306 | } |
307 | |
308 | static |
309 | void fromDBLto16(void* dst, const void* src) |
310 | { |
311 | cmsFloat64Number n = *(cmsFloat64Number*)src; |
312 | *(cmsUInt16Number*)dst = _cmsQuickSaturateWord(n * 65535.0f); |
313 | } |
314 | |
315 | static |
316 | void fromDBLto16SE(void* dst, const void* src) |
317 | { |
318 | cmsFloat64Number n = *(cmsFloat64Number*)src; |
319 | cmsUInt16Number i = _cmsQuickSaturateWord(n * 65535.0f); |
320 | *(cmsUInt16Number*)dst = CHANGE_ENDIAN(i); |
321 | } |
322 | static |
323 | void fromDBLtoFLT(void* dst, const void* src) |
324 | { |
325 | cmsFloat64Number n = *(cmsFloat64Number*)src; |
326 | *(cmsFloat32Number*)dst = (cmsFloat32Number) n; |
327 | } |
328 | |
329 | static |
330 | void fromDBLtoHLF(void* dst, const void* src) |
331 | { |
332 | #ifndef CMS_NO_HALF_SUPPORT |
333 | cmsFloat32Number n = (cmsFloat32Number) *(cmsFloat64Number*)src; |
334 | *(cmsUInt16Number*)dst = _cmsFloat2Half(n); |
335 | #else |
336 | cmsUNUSED_PARAMETER(dst); |
337 | cmsUNUSED_PARAMETER(src); |
338 | #endif |
339 | } |
340 | |
341 | static |
342 | void copy64(void* dst, const void* src) |
343 | { |
344 | memmove(dst, src, sizeof(cmsFloat64Number)); |
345 | } |
346 | |
347 | |
348 | // Returns the position (x or y) of the formatter in the table of functions |
349 | static |
350 | int FormatterPos(cmsUInt32Number frm) |
351 | { |
352 | cmsUInt32Number b = T_BYTES(frm); |
353 | |
354 | if (b == 0 && T_FLOAT(frm)) |
355 | return 5; // DBL |
356 | #ifndef CMS_NO_HALF_SUPPORT |
357 | if (b == 2 && T_FLOAT(frm)) |
358 | return 3; // HLF |
359 | #endif |
360 | if (b == 4 && T_FLOAT(frm)) |
361 | return 4; // FLT |
362 | if (b == 2 && !T_FLOAT(frm)) |
363 | return 1; // 16 |
364 | if (b == 1 && !T_FLOAT(frm)) |
365 | return 0; // 8 |
366 | if (b == 2 && T_ENDIAN16(frm)) |
367 | return 3; |
368 | return -1; // not recognized |
369 | } |
370 | |
371 | // Obtains a alpha-to-alpha funmction formatter |
372 | static |
373 | cmsFormatterAlphaFn _cmsGetFormatterAlpha(cmsContext id, cmsUInt32Number in, cmsUInt32Number out) |
374 | { |
375 | static cmsFormatterAlphaFn FormattersAlpha[6][6] = { |
376 | |
377 | /* from 8 */ { copy8, from8to16, from8to16SE, from8toHLF, from8toFLT, from8toDBL }, |
378 | /* from 16*/ { from16to8, copy16, from16to16, from16toHLF, from16toFLT, from16toDBL }, |
379 | /* from 16SE*/{ from16SEto8, from16to16, copy16, from16SEtoHLF,from16SEtoFLT, from16SEtoDBL }, |
380 | /* from HLF*/ { fromHLFto8, fromHLFto16, fromHLFto16SE, copy16, fromHLFtoFLT, fromHLFtoDBL }, |
381 | /* from FLT*/ { fromFLTto8, fromFLTto16, fromFLTto16SE, fromFLTtoHLF, copy32, fromFLTtoDBL }, |
382 | /* from DBL*/ { fromDBLto8, fromDBLto16, fromDBLto16SE, fromDBLtoHLF, fromDBLtoFLT, copy64 }}; |
383 | |
384 | int in_n = FormatterPos(in); |
385 | int out_n = FormatterPos(out); |
386 | |
387 | if (in_n < 0 || out_n < 0 || in_n > 4 || out_n > 4) { |
388 | |
389 | cmsSignalError(id, cmsERROR_UNKNOWN_EXTENSION, "Unrecognized alpha channel width" ); |
390 | return NULL; |
391 | } |
392 | |
393 | return FormattersAlpha[in_n][out_n]; |
394 | } |
395 | |
396 | |
397 | |
398 | // This function computes the distance from each component to the next one in bytes. |
399 | static |
400 | void ComputeIncrementsForChunky(cmsUInt32Number Format, |
401 | cmsUInt32Number ComponentStartingOrder[], |
402 | cmsUInt32Number ComponentPointerIncrements[]) |
403 | { |
404 | cmsUInt32Number channels[cmsMAXEXTRACHANNELS]; |
405 | cmsUInt32Number = T_EXTRA(Format); |
406 | cmsUInt32Number nchannels = T_CHANNELS(Format); |
407 | cmsUInt32Number total_chans = nchannels + extra; |
408 | cmsUInt32Number i; |
409 | cmsUInt32Number channelSize = trueBytesSize(Format); |
410 | cmsUInt32Number pixelSize = channelSize * total_chans; |
411 | |
412 | // Sanity check |
413 | if (total_chans <= 0 || total_chans >= cmsMAXEXTRACHANNELS) |
414 | return; |
415 | |
416 | memset(channels, 0, sizeof(channels)); |
417 | |
418 | // Separation is independent of starting point and only depends on channel size |
419 | for (i = 0; i < extra; i++) |
420 | ComponentPointerIncrements[i] = pixelSize; |
421 | |
422 | // Handle do swap |
423 | for (i = 0; i < total_chans; i++) |
424 | { |
425 | if (T_DOSWAP(Format)) { |
426 | channels[i] = total_chans - i - 1; |
427 | } |
428 | else { |
429 | channels[i] = i; |
430 | } |
431 | } |
432 | |
433 | // Handle swap first (ROL of positions), example CMYK -> KCMY | 0123 -> 3012 |
434 | if (T_SWAPFIRST(Format) && total_chans > 1) { |
435 | |
436 | cmsUInt32Number tmp = channels[0]; |
437 | for (i = 0; i < total_chans-1; i++) |
438 | channels[i] = channels[i + 1]; |
439 | |
440 | channels[total_chans - 1] = tmp; |
441 | } |
442 | |
443 | // Handle size |
444 | if (channelSize > 1) |
445 | for (i = 0; i < total_chans; i++) { |
446 | channels[i] *= channelSize; |
447 | } |
448 | |
449 | for (i = 0; i < extra; i++) |
450 | ComponentStartingOrder[i] = channels[i + nchannels]; |
451 | } |
452 | |
453 | |
454 | |
455 | // On planar configurations, the distance is the stride added to any non-negative |
456 | static |
457 | void ComputeIncrementsForPlanar(cmsUInt32Number Format, |
458 | cmsUInt32Number BytesPerPlane, |
459 | cmsUInt32Number ComponentStartingOrder[], |
460 | cmsUInt32Number ComponentPointerIncrements[]) |
461 | { |
462 | cmsUInt32Number channels[cmsMAXEXTRACHANNELS]; |
463 | cmsUInt32Number = T_EXTRA(Format); |
464 | cmsUInt32Number nchannels = T_CHANNELS(Format); |
465 | cmsUInt32Number total_chans = nchannels + extra; |
466 | cmsUInt32Number i; |
467 | cmsUInt32Number channelSize = trueBytesSize(Format); |
468 | |
469 | // Sanity check |
470 | if (total_chans <= 0 || total_chans >= cmsMAXEXTRACHANNELS) |
471 | return; |
472 | |
473 | memset(channels, 0, sizeof(channels)); |
474 | |
475 | // Separation is independent of starting point and only depends on channel size |
476 | for (i = 0; i < extra; i++) |
477 | ComponentPointerIncrements[i] = channelSize; |
478 | |
479 | // Handle do swap |
480 | for (i = 0; i < total_chans; i++) |
481 | { |
482 | if (T_DOSWAP(Format)) { |
483 | channels[i] = total_chans - i - 1; |
484 | } |
485 | else { |
486 | channels[i] = i; |
487 | } |
488 | } |
489 | |
490 | // Handle swap first (ROL of positions), example CMYK -> KCMY | 0123 -> 3012 |
491 | if (T_SWAPFIRST(Format) && total_chans > 0) { |
492 | |
493 | cmsUInt32Number tmp = channels[0]; |
494 | for (i = 0; i < total_chans - 1; i++) |
495 | channels[i] = channels[i + 1]; |
496 | |
497 | channels[total_chans - 1] = tmp; |
498 | } |
499 | |
500 | // Handle size |
501 | for (i = 0; i < total_chans; i++) { |
502 | channels[i] *= BytesPerPlane; |
503 | } |
504 | |
505 | for (i = 0; i < extra; i++) |
506 | ComponentStartingOrder[i] = channels[i + nchannels]; |
507 | } |
508 | |
509 | |
510 | |
511 | // Dispatcher por chunky and planar RGB |
512 | static |
513 | void ComputeComponentIncrements(cmsUInt32Number Format, |
514 | cmsUInt32Number BytesPerPlane, |
515 | cmsUInt32Number ComponentStartingOrder[], |
516 | cmsUInt32Number ComponentPointerIncrements[]) |
517 | { |
518 | if (T_PLANAR(Format)) { |
519 | |
520 | ComputeIncrementsForPlanar(Format, BytesPerPlane, ComponentStartingOrder, ComponentPointerIncrements); |
521 | } |
522 | else { |
523 | ComputeIncrementsForChunky(Format, ComponentStartingOrder, ComponentPointerIncrements); |
524 | } |
525 | |
526 | } |
527 | |
528 | |
529 | |
530 | // Handles extra channels copying alpha if requested by the flags |
531 | void _cmsHandleExtraChannels(cmsContext ContextID, _cmsTRANSFORM* p, const void* in, |
532 | void* out, |
533 | cmsUInt32Number PixelsPerLine, |
534 | cmsUInt32Number LineCount, |
535 | const cmsStride* Stride) |
536 | { |
537 | cmsUInt32Number i, j, k; |
538 | cmsUInt32Number ; |
539 | cmsUInt32Number SourceStartingOrder[cmsMAXEXTRACHANNELS]; |
540 | cmsUInt32Number SourceIncrements[cmsMAXEXTRACHANNELS]; |
541 | cmsUInt32Number DestStartingOrder[cmsMAXEXTRACHANNELS]; |
542 | cmsUInt32Number DestIncrements[cmsMAXEXTRACHANNELS]; |
543 | |
544 | cmsFormatterAlphaFn copyValueFn; |
545 | |
546 | // Make sure we need some copy |
547 | if (!(p->core->dwOriginalFlags & cmsFLAGS_COPY_ALPHA)) |
548 | return; |
549 | |
550 | // Exit early if in-place color-management is occurring - no need to copy extra channels to themselves. |
551 | if (p->InputFormat == p->OutputFormat && in == out) |
552 | return; |
553 | |
554 | // Make sure we have same number of alpha channels. If not, just return as this should be checked at transform creation time. |
555 | nExtra = T_EXTRA(p->InputFormat); |
556 | if (nExtra != T_EXTRA(p->OutputFormat)) |
557 | return; |
558 | |
559 | // Anything to do? |
560 | if (nExtra == 0) |
561 | return; |
562 | |
563 | // Compute the increments |
564 | ComputeComponentIncrements(p->InputFormat, Stride->BytesPerPlaneIn, SourceStartingOrder, SourceIncrements); |
565 | ComputeComponentIncrements(p->OutputFormat, Stride->BytesPerPlaneOut, DestStartingOrder, DestIncrements); |
566 | |
567 | // Check for conversions 8, 16, half, float, dbl |
568 | copyValueFn = _cmsGetFormatterAlpha(ContextID, p->InputFormat, p->OutputFormat); |
569 | |
570 | if (nExtra == 1) { // Optimized routine for copying a single extra channel quickly |
571 | |
572 | cmsUInt8Number* SourcePtr; |
573 | cmsUInt8Number* DestPtr; |
574 | |
575 | cmsUInt32Number SourceStrideIncrement = 0; |
576 | cmsUInt32Number DestStrideIncrement = 0; |
577 | |
578 | // The loop itself |
579 | for (i = 0; i < LineCount; i++) { |
580 | |
581 | // Prepare pointers for the loop |
582 | SourcePtr = (cmsUInt8Number*)in + SourceStartingOrder[0] + SourceStrideIncrement; |
583 | DestPtr = (cmsUInt8Number*)out + DestStartingOrder[0] + DestStrideIncrement; |
584 | |
585 | for (j = 0; j < PixelsPerLine; j++) { |
586 | |
587 | copyValueFn(DestPtr, SourcePtr); |
588 | |
589 | SourcePtr += SourceIncrements[0]; |
590 | DestPtr += DestIncrements[0]; |
591 | } |
592 | |
593 | SourceStrideIncrement += Stride->BytesPerLineIn; |
594 | DestStrideIncrement += Stride->BytesPerLineOut; |
595 | } |
596 | |
597 | } |
598 | else { // General case with more than one extra channel |
599 | |
600 | cmsUInt8Number* SourcePtr[cmsMAXEXTRACHANNELS]; |
601 | cmsUInt8Number* DestPtr[cmsMAXEXTRACHANNELS]; |
602 | |
603 | cmsUInt32Number SourceStrideIncrements[cmsMAXEXTRACHANNELS]; |
604 | cmsUInt32Number DestStrideIncrements[cmsMAXEXTRACHANNELS]; |
605 | |
606 | memset(SourceStrideIncrements, 0, sizeof(SourceStrideIncrements)); |
607 | memset(DestStrideIncrements, 0, sizeof(DestStrideIncrements)); |
608 | |
609 | // The loop itself |
610 | for (i = 0; i < LineCount; i++) { |
611 | |
612 | // Prepare pointers for the loop |
613 | for (j = 0; j < nExtra; j++) { |
614 | |
615 | SourcePtr[j] = (cmsUInt8Number*)in + SourceStartingOrder[j] + SourceStrideIncrements[j]; |
616 | DestPtr[j] = (cmsUInt8Number*)out + DestStartingOrder[j] + DestStrideIncrements[j]; |
617 | } |
618 | |
619 | for (j = 0; j < PixelsPerLine; j++) { |
620 | |
621 | for (k = 0; k < nExtra; k++) { |
622 | |
623 | copyValueFn(DestPtr[k], SourcePtr[k]); |
624 | |
625 | SourcePtr[k] += SourceIncrements[k]; |
626 | DestPtr[k] += DestIncrements[k]; |
627 | } |
628 | } |
629 | |
630 | for (j = 0; j < nExtra; j++) { |
631 | |
632 | SourceStrideIncrements[j] += Stride->BytesPerLineIn; |
633 | DestStrideIncrements[j] += Stride->BytesPerLineOut; |
634 | } |
635 | } |
636 | } |
637 | } |
638 | |