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