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-2016 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// This module handles all formats supported by lcms. There are two flavors, 16 bits and
59// floating point. Floating point is supported only in a subset, those formats holding
60// cmsFloat32Number (4 bytes per component) and double (marked as 0 bytes per component
61// as special case)
62
63// ---------------------------------------------------------------------------
64
65
66// This macro return words stored as big endian
67#define CHANGE_ENDIAN(w)    (cmsUInt16Number) ((cmsUInt16Number) ((w)<<8)|((w)>>8))
68
69// These macros handles reversing (negative)
70#define REVERSE_FLAVOR_8(x)     ((cmsUInt8Number) (0xff-(x)))
71#define REVERSE_FLAVOR_16(x)    ((cmsUInt16Number)(0xffff-(x)))
72
73// * 0xffff / 0xff00 = (255 * 257) / (255 * 256) = 257 / 256
74cmsINLINE cmsUInt16Number FomLabV2ToLabV4(cmsUInt16Number x)
75{
76    int a = (x << 8 | x) >> 8;  // * 257 / 256
77    if ( a > 0xffff) return 0xffff;
78    return (cmsUInt16Number) a;
79}
80
81// * 0xf00 / 0xffff = * 256 / 257
82cmsINLINE cmsUInt16Number FomLabV4ToLabV2(cmsUInt16Number x)
83{
84    return (cmsUInt16Number) (((x << 8) + 0x80) / 257);
85}
86
87
88typedef struct {
89    cmsUInt32Number Type;
90    cmsUInt32Number Mask;
91    cmsFormatter16  Frm;
92
93} cmsFormatters16;
94
95typedef struct {
96    cmsUInt32Number    Type;
97    cmsUInt32Number    Mask;
98    cmsFormatterFloat  Frm;
99
100} cmsFormattersFloat;
101
102
103#define ANYSPACE        COLORSPACE_SH(31)
104#define ANYCHANNELS     CHANNELS_SH(15)
105#define ANYEXTRA        EXTRA_SH(7)
106#define ANYPLANAR       PLANAR_SH(1)
107#define ANYENDIAN       ENDIAN16_SH(1)
108#define ANYSWAP         DOSWAP_SH(1)
109#define ANYSWAPFIRST    SWAPFIRST_SH(1)
110#define ANYFLAVOR       FLAVOR_SH(1)
111
112
113// Suppress waning about info never being used
114
115#ifdef _MSC_VER
116#pragma warning(disable : 4100)
117#endif
118
119// Unpacking routines (16 bits) ----------------------------------------------------------------------------------------
120
121
122// Does almost everything but is slow
123static
124cmsUInt8Number* UnrollChunkyBytes(register _cmsTRANSFORM* info,
125                                  register cmsUInt16Number wIn[],
126                                  register cmsUInt8Number* accum,
127                                  register cmsUInt32Number Stride)
128{
129    int nChan      = T_CHANNELS(info -> InputFormat);
130    int DoSwap     = T_DOSWAP(info ->InputFormat);
131    int Reverse    = T_FLAVOR(info ->InputFormat);
132    int SwapFirst  = T_SWAPFIRST(info -> InputFormat);
133    int Extra      = T_EXTRA(info -> InputFormat);
134    int ExtraFirst = DoSwap ^ SwapFirst;
135    cmsUInt16Number v;
136    int i;
137
138    if (ExtraFirst) {
139        accum += Extra;
140    }
141
142    for (i=0; i < nChan; i++) {
143        int index = DoSwap ? (nChan - i - 1) : i;
144
145        v = FROM_8_TO_16(*accum);
146        v = Reverse ? REVERSE_FLAVOR_16(v) : v;
147        wIn[index] = v;
148        accum++;
149    }
150
151    if (!ExtraFirst) {
152        accum += Extra;
153    }
154
155    if (Extra == 0 && SwapFirst) {
156        cmsUInt16Number tmp = wIn[0];
157
158        memmove(&wIn[0], &wIn[1], (nChan-1) * sizeof(cmsUInt16Number));
159        wIn[nChan-1] = tmp;
160    }
161
162    return accum;
163
164    cmsUNUSED_PARAMETER(info);
165    cmsUNUSED_PARAMETER(Stride);
166
167}
168
169// Extra channels are just ignored because come in the next planes
170static
171cmsUInt8Number* UnrollPlanarBytes(register _cmsTRANSFORM* info,
172                                  register cmsUInt16Number wIn[],
173                                  register cmsUInt8Number* accum,
174                                  register cmsUInt32Number Stride)
175{
176    int nChan     = T_CHANNELS(info -> InputFormat);
177    int DoSwap    = T_DOSWAP(info ->InputFormat);
178    int SwapFirst = T_SWAPFIRST(info ->InputFormat);
179    int Reverse   = T_FLAVOR(info ->InputFormat);
180    int i;
181    cmsUInt8Number* Init = accum;
182
183    if (DoSwap ^ SwapFirst) {
184        accum += T_EXTRA(info -> InputFormat) * Stride;
185    }
186
187    for (i=0; i < nChan; i++) {
188
189        int index = DoSwap ? (nChan - i - 1) : i;
190        cmsUInt16Number v = FROM_8_TO_16(*accum);
191
192        wIn[index] = Reverse ? REVERSE_FLAVOR_16(v) : v;
193        accum += Stride;
194    }
195
196    return (Init + 1);
197}
198
199// Special cases, provided for performance
200static
201cmsUInt8Number* Unroll4Bytes(register _cmsTRANSFORM* info,
202                             register cmsUInt16Number wIn[],
203                             register cmsUInt8Number* accum,
204                             register cmsUInt32Number Stride)
205{
206    wIn[0] = FROM_8_TO_16(*accum); accum++; // C
207    wIn[1] = FROM_8_TO_16(*accum); accum++; // M
208    wIn[2] = FROM_8_TO_16(*accum); accum++; // Y
209    wIn[3] = FROM_8_TO_16(*accum); accum++; // K
210
211    return accum;
212
213    cmsUNUSED_PARAMETER(info);
214    cmsUNUSED_PARAMETER(Stride);
215}
216
217static
218cmsUInt8Number* Unroll4BytesReverse(register _cmsTRANSFORM* info,
219                                    register cmsUInt16Number wIn[],
220                                    register cmsUInt8Number* accum,
221                                    register cmsUInt32Number Stride)
222{
223    wIn[0] = FROM_8_TO_16(REVERSE_FLAVOR_8(*accum)); accum++; // C
224    wIn[1] = FROM_8_TO_16(REVERSE_FLAVOR_8(*accum)); accum++; // M
225    wIn[2] = FROM_8_TO_16(REVERSE_FLAVOR_8(*accum)); accum++; // Y
226    wIn[3] = FROM_8_TO_16(REVERSE_FLAVOR_8(*accum)); accum++; // K
227
228    return accum;
229
230    cmsUNUSED_PARAMETER(info);
231    cmsUNUSED_PARAMETER(Stride);
232}
233
234static
235cmsUInt8Number* Unroll4BytesSwapFirst(register _cmsTRANSFORM* info,
236                                      register cmsUInt16Number wIn[],
237                                      register cmsUInt8Number* accum,
238                                      register cmsUInt32Number Stride)
239{
240    wIn[3] = FROM_8_TO_16(*accum); accum++; // K
241    wIn[0] = FROM_8_TO_16(*accum); accum++; // C
242    wIn[1] = FROM_8_TO_16(*accum); accum++; // M
243    wIn[2] = FROM_8_TO_16(*accum); accum++; // Y
244
245    return accum;
246
247    cmsUNUSED_PARAMETER(info);
248    cmsUNUSED_PARAMETER(Stride);
249}
250
251// KYMC
252static
253cmsUInt8Number* Unroll4BytesSwap(register _cmsTRANSFORM* info,
254                                 register cmsUInt16Number wIn[],
255                                 register cmsUInt8Number* accum,
256                                 register cmsUInt32Number Stride)
257{
258    wIn[3] = FROM_8_TO_16(*accum); accum++;  // K
259    wIn[2] = FROM_8_TO_16(*accum); accum++;  // Y
260    wIn[1] = FROM_8_TO_16(*accum); accum++;  // M
261    wIn[0] = FROM_8_TO_16(*accum); accum++;  // C
262
263    return accum;
264
265    cmsUNUSED_PARAMETER(info);
266    cmsUNUSED_PARAMETER(Stride);
267}
268
269static
270cmsUInt8Number* Unroll4BytesSwapSwapFirst(register _cmsTRANSFORM* info,
271                                          register cmsUInt16Number wIn[],
272                                          register cmsUInt8Number* accum,
273                                          register cmsUInt32Number Stride)
274{
275    wIn[2] = FROM_8_TO_16(*accum); accum++;  // K
276    wIn[1] = FROM_8_TO_16(*accum); accum++;  // Y
277    wIn[0] = FROM_8_TO_16(*accum); accum++;  // M
278    wIn[3] = FROM_8_TO_16(*accum); accum++;  // C
279
280    return accum;
281
282    cmsUNUSED_PARAMETER(info);
283    cmsUNUSED_PARAMETER(Stride);
284}
285
286static
287cmsUInt8Number* Unroll3Bytes(register _cmsTRANSFORM* info,
288                             register cmsUInt16Number wIn[],
289                             register cmsUInt8Number* accum,
290                             register cmsUInt32Number Stride)
291{
292    wIn[0] = FROM_8_TO_16(*accum); accum++;     // R
293    wIn[1] = FROM_8_TO_16(*accum); accum++;     // G
294    wIn[2] = FROM_8_TO_16(*accum); accum++;     // B
295
296    return accum;
297
298    cmsUNUSED_PARAMETER(info);
299    cmsUNUSED_PARAMETER(Stride);
300}
301
302static
303cmsUInt8Number* Unroll3BytesSkip1Swap(register _cmsTRANSFORM* info,
304                                      register cmsUInt16Number wIn[],
305                                      register cmsUInt8Number* accum,
306                                      register cmsUInt32Number Stride)
307{
308    accum++; // A
309    wIn[2] = FROM_8_TO_16(*accum); accum++; // B
310    wIn[1] = FROM_8_TO_16(*accum); accum++; // G
311    wIn[0] = FROM_8_TO_16(*accum); accum++; // R
312
313    return accum;
314
315    cmsUNUSED_PARAMETER(info);
316    cmsUNUSED_PARAMETER(Stride);
317}
318
319static
320cmsUInt8Number* Unroll3BytesSkip1SwapSwapFirst(register _cmsTRANSFORM* info,
321                                              register cmsUInt16Number wIn[],
322                                              register cmsUInt8Number* accum,
323                                              register cmsUInt32Number Stride)
324{
325    wIn[2] = FROM_8_TO_16(*accum); accum++; // B
326    wIn[1] = FROM_8_TO_16(*accum); accum++; // G
327    wIn[0] = FROM_8_TO_16(*accum); accum++; // R
328    accum++; // A
329
330    return accum;
331
332    cmsUNUSED_PARAMETER(info);
333    cmsUNUSED_PARAMETER(Stride);
334}
335
336static
337cmsUInt8Number* Unroll3BytesSkip1SwapFirst(register _cmsTRANSFORM* info,
338                                           register cmsUInt16Number wIn[],
339                                           register cmsUInt8Number* accum,
340                                           register cmsUInt32Number Stride)
341{
342    accum++; // A
343    wIn[0] = FROM_8_TO_16(*accum); accum++; // R
344    wIn[1] = FROM_8_TO_16(*accum); accum++; // G
345    wIn[2] = FROM_8_TO_16(*accum); accum++; // B
346
347    return accum;
348
349    cmsUNUSED_PARAMETER(info);
350    cmsUNUSED_PARAMETER(Stride);
351}
352
353
354// BRG
355static
356cmsUInt8Number* Unroll3BytesSwap(register _cmsTRANSFORM* info,
357                                 register cmsUInt16Number wIn[],
358                                 register cmsUInt8Number* accum,
359                                 register cmsUInt32Number Stride)
360{
361    wIn[2] = FROM_8_TO_16(*accum); accum++;     // B
362    wIn[1] = FROM_8_TO_16(*accum); accum++;     // G
363    wIn[0] = FROM_8_TO_16(*accum); accum++;     // R
364
365    return accum;
366
367    cmsUNUSED_PARAMETER(info);
368    cmsUNUSED_PARAMETER(Stride);
369}
370
371static
372cmsUInt8Number* UnrollLabV2_8(register _cmsTRANSFORM* info,
373                              register cmsUInt16Number wIn[],
374                              register cmsUInt8Number* accum,
375                              register cmsUInt32Number Stride)
376{
377    wIn[0] = FomLabV2ToLabV4(FROM_8_TO_16(*accum)); accum++;     // L
378    wIn[1] = FomLabV2ToLabV4(FROM_8_TO_16(*accum)); accum++;     // a
379    wIn[2] = FomLabV2ToLabV4(FROM_8_TO_16(*accum)); accum++;     // b
380
381    return accum;
382
383    cmsUNUSED_PARAMETER(info);
384    cmsUNUSED_PARAMETER(Stride);
385}
386
387static
388cmsUInt8Number* UnrollALabV2_8(register _cmsTRANSFORM* info,
389                               register cmsUInt16Number wIn[],
390                               register cmsUInt8Number* accum,
391                               register cmsUInt32Number Stride)
392{
393    accum++;  // A
394    wIn[0] = FomLabV2ToLabV4(FROM_8_TO_16(*accum)); accum++;     // L
395    wIn[1] = FomLabV2ToLabV4(FROM_8_TO_16(*accum)); accum++;     // a
396    wIn[2] = FomLabV2ToLabV4(FROM_8_TO_16(*accum)); accum++;     // b
397
398    return accum;
399
400    cmsUNUSED_PARAMETER(info);
401    cmsUNUSED_PARAMETER(Stride);
402}
403
404static
405cmsUInt8Number* UnrollLabV2_16(register _cmsTRANSFORM* info,
406                               register cmsUInt16Number wIn[],
407                               register cmsUInt8Number* accum,
408                               register cmsUInt32Number Stride)
409{
410    wIn[0] = FomLabV2ToLabV4(*(cmsUInt16Number*) accum); accum += 2;     // L
411    wIn[1] = FomLabV2ToLabV4(*(cmsUInt16Number*) accum); accum += 2;     // a
412    wIn[2] = FomLabV2ToLabV4(*(cmsUInt16Number*) accum); accum += 2;     // b
413
414    return accum;
415
416    cmsUNUSED_PARAMETER(info);
417    cmsUNUSED_PARAMETER(Stride);
418}
419
420// for duplex
421static
422cmsUInt8Number* Unroll2Bytes(register _cmsTRANSFORM* info,
423                                     register cmsUInt16Number wIn[],
424                                     register cmsUInt8Number* accum,
425                                     register cmsUInt32Number Stride)
426{
427    wIn[0] = FROM_8_TO_16(*accum); accum++;     // ch1
428    wIn[1] = FROM_8_TO_16(*accum); accum++;     // ch2
429
430    return accum;
431
432    cmsUNUSED_PARAMETER(info);
433    cmsUNUSED_PARAMETER(Stride);
434}
435
436
437
438
439// Monochrome duplicates L into RGB for null-transforms
440static
441cmsUInt8Number* Unroll1Byte(register _cmsTRANSFORM* info,
442                            register cmsUInt16Number wIn[],
443                            register cmsUInt8Number* accum,
444                            register cmsUInt32Number Stride)
445{
446    wIn[0] = wIn[1] = wIn[2] = FROM_8_TO_16(*accum); accum++;     // L
447
448    return accum;
449
450    cmsUNUSED_PARAMETER(info);
451    cmsUNUSED_PARAMETER(Stride);
452}
453
454
455static
456cmsUInt8Number* Unroll1ByteSkip1(register _cmsTRANSFORM* info,
457                                 register cmsUInt16Number wIn[],
458                                 register cmsUInt8Number* accum,
459                                 register cmsUInt32Number Stride)
460{
461    wIn[0] = wIn[1] = wIn[2] = FROM_8_TO_16(*accum); accum++;     // L
462    accum += 1;
463
464    return accum;
465
466    cmsUNUSED_PARAMETER(info);
467    cmsUNUSED_PARAMETER(Stride);
468}
469
470static
471cmsUInt8Number* Unroll1ByteSkip2(register _cmsTRANSFORM* info,
472                                 register cmsUInt16Number wIn[],
473                                 register cmsUInt8Number* accum,
474                                 register cmsUInt32Number Stride)
475{
476    wIn[0] = wIn[1] = wIn[2] = FROM_8_TO_16(*accum); accum++;     // L
477    accum += 2;
478
479    return accum;
480
481    cmsUNUSED_PARAMETER(info);
482    cmsUNUSED_PARAMETER(Stride);
483}
484
485static
486cmsUInt8Number* Unroll1ByteReversed(register _cmsTRANSFORM* info,
487                                    register cmsUInt16Number wIn[],
488                                    register cmsUInt8Number* accum,
489                                    register cmsUInt32Number Stride)
490{
491    wIn[0] = wIn[1] = wIn[2] = REVERSE_FLAVOR_16(FROM_8_TO_16(*accum)); accum++;     // L
492
493    return accum;
494
495    cmsUNUSED_PARAMETER(info);
496    cmsUNUSED_PARAMETER(Stride);
497}
498
499
500static
501cmsUInt8Number* UnrollAnyWords(register _cmsTRANSFORM* info,
502                               register cmsUInt16Number wIn[],
503                               register cmsUInt8Number* accum,
504                               register cmsUInt32Number Stride)
505{
506    int nChan       = T_CHANNELS(info -> InputFormat);
507    int SwapEndian  = T_ENDIAN16(info -> InputFormat);
508    int DoSwap      = T_DOSWAP(info ->InputFormat);
509    int Reverse     = T_FLAVOR(info ->InputFormat);
510    int SwapFirst   = T_SWAPFIRST(info -> InputFormat);
511    int Extra       = T_EXTRA(info -> InputFormat);
512    int ExtraFirst  = DoSwap ^ SwapFirst;
513    int i;
514
515    if (ExtraFirst) {
516        accum += Extra * sizeof(cmsUInt16Number);
517    }
518
519    for (i=0; i < nChan; i++) {
520
521        int index = DoSwap ? (nChan - i - 1) : i;
522        cmsUInt16Number v = *(cmsUInt16Number*) accum;
523
524        if (SwapEndian)
525            v = CHANGE_ENDIAN(v);
526
527        wIn[index] = Reverse ? REVERSE_FLAVOR_16(v) : v;
528
529        accum += sizeof(cmsUInt16Number);
530    }
531
532    if (!ExtraFirst) {
533        accum += Extra * sizeof(cmsUInt16Number);
534    }
535
536    if (Extra == 0 && SwapFirst) {
537
538        cmsUInt16Number tmp = wIn[0];
539
540        memmove(&wIn[0], &wIn[1], (nChan-1) * sizeof(cmsUInt16Number));
541        wIn[nChan-1] = tmp;
542    }
543
544    return accum;
545
546    cmsUNUSED_PARAMETER(Stride);
547}
548
549static
550cmsUInt8Number* UnrollPlanarWords(register _cmsTRANSFORM* info,
551                                  register cmsUInt16Number wIn[],
552                                  register cmsUInt8Number* accum,
553                                  register cmsUInt32Number Stride)
554{
555    int nChan = T_CHANNELS(info -> InputFormat);
556    int DoSwap= T_DOSWAP(info ->InputFormat);
557    int Reverse= T_FLAVOR(info ->InputFormat);
558    int SwapEndian = T_ENDIAN16(info -> InputFormat);
559    int i;
560    cmsUInt8Number* Init = accum;
561
562    if (DoSwap) {
563        accum += T_EXTRA(info -> InputFormat) * Stride * sizeof(cmsUInt16Number);
564    }
565
566    for (i=0; i < nChan; i++) {
567
568        int index = DoSwap ? (nChan - i - 1) : i;
569        cmsUInt16Number v = *(cmsUInt16Number*) accum;
570
571        if (SwapEndian)
572            v = CHANGE_ENDIAN(v);
573
574        wIn[index] = Reverse ? REVERSE_FLAVOR_16(v) : v;
575
576        accum +=  Stride * sizeof(cmsUInt16Number);
577    }
578
579    return (Init + sizeof(cmsUInt16Number));
580}
581
582
583static
584cmsUInt8Number* Unroll4Words(register _cmsTRANSFORM* info,
585                             register cmsUInt16Number wIn[],
586                             register cmsUInt8Number* accum,
587                             register cmsUInt32Number Stride)
588{
589    wIn[0] = *(cmsUInt16Number*) accum; accum+= 2; // C
590    wIn[1] = *(cmsUInt16Number*) accum; accum+= 2; // M
591    wIn[2] = *(cmsUInt16Number*) accum; accum+= 2; // Y
592    wIn[3] = *(cmsUInt16Number*) accum; accum+= 2; // K
593
594    return accum;
595
596    cmsUNUSED_PARAMETER(info);
597    cmsUNUSED_PARAMETER(Stride);
598}
599
600static
601cmsUInt8Number* Unroll4WordsReverse(register _cmsTRANSFORM* info,
602                                    register cmsUInt16Number wIn[],
603                                    register cmsUInt8Number* accum,
604                                    register cmsUInt32Number Stride)
605{
606    wIn[0] = REVERSE_FLAVOR_16(*(cmsUInt16Number*) accum); accum+= 2; // C
607    wIn[1] = REVERSE_FLAVOR_16(*(cmsUInt16Number*) accum); accum+= 2; // M
608    wIn[2] = REVERSE_FLAVOR_16(*(cmsUInt16Number*) accum); accum+= 2; // Y
609    wIn[3] = REVERSE_FLAVOR_16(*(cmsUInt16Number*) accum); accum+= 2; // K
610
611    return accum;
612
613    cmsUNUSED_PARAMETER(info);
614    cmsUNUSED_PARAMETER(Stride);
615}
616
617static
618cmsUInt8Number* Unroll4WordsSwapFirst(register _cmsTRANSFORM* info,
619                                      register cmsUInt16Number wIn[],
620                                      register cmsUInt8Number* accum,
621                                      register cmsUInt32Number Stride)
622{
623    wIn[3] = *(cmsUInt16Number*) accum; accum+= 2; // K
624    wIn[0] = *(cmsUInt16Number*) accum; accum+= 2; // C
625    wIn[1] = *(cmsUInt16Number*) accum; accum+= 2; // M
626    wIn[2] = *(cmsUInt16Number*) accum; accum+= 2; // Y
627
628    return accum;
629
630    cmsUNUSED_PARAMETER(info);
631    cmsUNUSED_PARAMETER(Stride);
632}
633
634// KYMC
635static
636cmsUInt8Number* Unroll4WordsSwap(register _cmsTRANSFORM* info,
637                                 register cmsUInt16Number wIn[],
638                                 register cmsUInt8Number* accum,
639                                 register cmsUInt32Number Stride)
640{
641    wIn[3] = *(cmsUInt16Number*) accum; accum+= 2; // K
642    wIn[2] = *(cmsUInt16Number*) accum; accum+= 2; // Y
643    wIn[1] = *(cmsUInt16Number*) accum; accum+= 2; // M
644    wIn[0] = *(cmsUInt16Number*) accum; accum+= 2; // C
645
646    return accum;
647
648    cmsUNUSED_PARAMETER(info);
649    cmsUNUSED_PARAMETER(Stride);
650}
651
652static
653cmsUInt8Number* Unroll4WordsSwapSwapFirst(register _cmsTRANSFORM* info,
654                                          register cmsUInt16Number wIn[],
655                                          register cmsUInt8Number* accum,
656                                          register cmsUInt32Number Stride)
657{
658    wIn[2] = *(cmsUInt16Number*) accum; accum+= 2; // K
659    wIn[1] = *(cmsUInt16Number*) accum; accum+= 2; // Y
660    wIn[0] = *(cmsUInt16Number*) accum; accum+= 2; // M
661    wIn[3] = *(cmsUInt16Number*) accum; accum+= 2; // C
662
663    return accum;
664
665    cmsUNUSED_PARAMETER(info);
666    cmsUNUSED_PARAMETER(Stride);
667}
668
669static
670cmsUInt8Number* Unroll3Words(register _cmsTRANSFORM* info,
671                             register cmsUInt16Number wIn[],
672                             register cmsUInt8Number* accum,
673                             register cmsUInt32Number Stride)
674{
675    wIn[0] = *(cmsUInt16Number*) accum; accum+= 2;  // C R
676    wIn[1] = *(cmsUInt16Number*) accum; accum+= 2;  // M G
677    wIn[2] = *(cmsUInt16Number*) accum; accum+= 2;  // Y B
678
679    return accum;
680
681    cmsUNUSED_PARAMETER(info);
682    cmsUNUSED_PARAMETER(Stride);
683}
684
685static
686cmsUInt8Number* Unroll3WordsSwap(register _cmsTRANSFORM* info,
687                                 register cmsUInt16Number wIn[],
688                                 register cmsUInt8Number* accum,
689                                 register cmsUInt32Number Stride)
690{
691    wIn[2] = *(cmsUInt16Number*) accum; accum+= 2;  // C R
692    wIn[1] = *(cmsUInt16Number*) accum; accum+= 2;  // M G
693    wIn[0] = *(cmsUInt16Number*) accum; accum+= 2;  // Y B
694
695    return accum;
696
697    cmsUNUSED_PARAMETER(info);
698    cmsUNUSED_PARAMETER(Stride);
699}
700
701static
702cmsUInt8Number* Unroll3WordsSkip1Swap(register _cmsTRANSFORM* info,
703                                      register cmsUInt16Number wIn[],
704                                      register cmsUInt8Number* accum,
705                                      register cmsUInt32Number Stride)
706{
707    accum += 2; // A
708    wIn[2] = *(cmsUInt16Number*) accum; accum += 2; // R
709    wIn[1] = *(cmsUInt16Number*) accum; accum += 2; // G
710    wIn[0] = *(cmsUInt16Number*) accum; accum += 2; // B
711
712    return accum;
713
714    cmsUNUSED_PARAMETER(info);
715    cmsUNUSED_PARAMETER(Stride);
716}
717
718static
719cmsUInt8Number* Unroll3WordsSkip1SwapFirst(register _cmsTRANSFORM* info,
720                                           register cmsUInt16Number wIn[],
721                                           register cmsUInt8Number* accum,
722                                           register cmsUInt32Number Stride)
723{
724    accum += 2; // A
725    wIn[0] = *(cmsUInt16Number*) accum; accum += 2; // R
726    wIn[1] = *(cmsUInt16Number*) accum; accum += 2; // G
727    wIn[2] = *(cmsUInt16Number*) accum; accum += 2; // B
728
729    return accum;
730
731    cmsUNUSED_PARAMETER(info);
732    cmsUNUSED_PARAMETER(Stride);
733}
734
735static
736cmsUInt8Number* Unroll1Word(register _cmsTRANSFORM* info,
737                            register cmsUInt16Number wIn[],
738                            register cmsUInt8Number* accum,
739                            register cmsUInt32Number Stride)
740{
741    wIn[0] = wIn[1] = wIn[2] = *(cmsUInt16Number*) accum; accum+= 2;   // L
742
743    return accum;
744
745    cmsUNUSED_PARAMETER(info);
746    cmsUNUSED_PARAMETER(Stride);
747}
748
749static
750cmsUInt8Number* Unroll1WordReversed(register _cmsTRANSFORM* info,
751                                    register cmsUInt16Number wIn[],
752                                    register cmsUInt8Number* accum,
753                                    register cmsUInt32Number Stride)
754{
755    wIn[0] = wIn[1] = wIn[2] = REVERSE_FLAVOR_16(*(cmsUInt16Number*) accum); accum+= 2;
756
757    return accum;
758
759    cmsUNUSED_PARAMETER(info);
760    cmsUNUSED_PARAMETER(Stride);
761}
762
763static
764cmsUInt8Number* Unroll1WordSkip3(register _cmsTRANSFORM* info,
765                                 register cmsUInt16Number wIn[],
766                                 register cmsUInt8Number* accum,
767                                 register cmsUInt32Number Stride)
768{
769    wIn[0] = wIn[1] = wIn[2] = *(cmsUInt16Number*) accum;
770
771    accum += 8;
772
773    return accum;
774
775    cmsUNUSED_PARAMETER(info);
776    cmsUNUSED_PARAMETER(Stride);
777}
778
779static
780cmsUInt8Number* Unroll2Words(register _cmsTRANSFORM* info,
781                                     register cmsUInt16Number wIn[],
782                                     register cmsUInt8Number* accum,
783                                     register cmsUInt32Number Stride)
784{
785    wIn[0] = *(cmsUInt16Number*) accum; accum += 2;    // ch1
786    wIn[1] = *(cmsUInt16Number*) accum; accum += 2;    // ch2
787
788    return accum;
789
790    cmsUNUSED_PARAMETER(info);
791    cmsUNUSED_PARAMETER(Stride);
792}
793
794
795// This is a conversion of Lab double to 16 bits
796static
797cmsUInt8Number* UnrollLabDoubleTo16(register _cmsTRANSFORM* info,
798                                    register cmsUInt16Number wIn[],
799                                    register cmsUInt8Number* accum,
800                                    register cmsUInt32Number  Stride)
801{
802    if (T_PLANAR(info -> InputFormat)) {
803
804        cmsFloat64Number* Pt = (cmsFloat64Number*) accum;
805
806        cmsCIELab Lab;
807
808        Lab.L = Pt[0];
809        Lab.a = Pt[Stride];
810        Lab.b = Pt[Stride*2];
811
812        cmsFloat2LabEncoded(wIn, &Lab);
813        return accum + sizeof(cmsFloat64Number);
814    }
815    else {
816
817        cmsFloat2LabEncoded(wIn, (cmsCIELab*) accum);
818        accum += sizeof(cmsCIELab) + T_EXTRA(info ->InputFormat) * sizeof(cmsFloat64Number);
819        return accum;
820    }
821}
822
823
824// This is a conversion of Lab float to 16 bits
825static
826cmsUInt8Number* UnrollLabFloatTo16(register _cmsTRANSFORM* info,
827                                    register cmsUInt16Number wIn[],
828                                    register cmsUInt8Number* accum,
829                                    register cmsUInt32Number  Stride)
830{
831    cmsCIELab Lab;
832
833    if (T_PLANAR(info -> InputFormat)) {
834
835        cmsFloat32Number* Pt = (cmsFloat32Number*) accum;
836
837
838        Lab.L = Pt[0];
839        Lab.a = Pt[Stride];
840        Lab.b = Pt[Stride*2];
841
842        cmsFloat2LabEncoded(wIn, &Lab);
843        return accum + sizeof(cmsFloat32Number);
844    }
845    else {
846
847        Lab.L = ((cmsFloat32Number*) accum)[0];
848        Lab.a = ((cmsFloat32Number*) accum)[1];
849        Lab.b = ((cmsFloat32Number*) accum)[2];
850
851        cmsFloat2LabEncoded(wIn, &Lab);
852        accum += (3 + T_EXTRA(info ->InputFormat)) * sizeof(cmsFloat32Number);
853        return accum;
854    }
855}
856
857// This is a conversion of XYZ double to 16 bits
858static
859cmsUInt8Number* UnrollXYZDoubleTo16(register _cmsTRANSFORM* info,
860                                    register cmsUInt16Number wIn[],
861                                    register cmsUInt8Number* accum,
862                                    register cmsUInt32Number Stride)
863{
864    if (T_PLANAR(info -> InputFormat)) {
865
866        cmsFloat64Number* Pt = (cmsFloat64Number*) accum;
867        cmsCIEXYZ XYZ;
868
869        XYZ.X = Pt[0];
870        XYZ.Y = Pt[Stride];
871        XYZ.Z = Pt[Stride*2];
872        cmsFloat2XYZEncoded(wIn, &XYZ);
873
874        return accum + sizeof(cmsFloat64Number);
875
876    }
877
878    else {
879        cmsFloat2XYZEncoded(wIn, (cmsCIEXYZ*) accum);
880        accum += sizeof(cmsCIEXYZ) + T_EXTRA(info ->InputFormat) * sizeof(cmsFloat64Number);
881
882        return accum;
883    }
884}
885
886// This is a conversion of XYZ float to 16 bits
887static
888cmsUInt8Number* UnrollXYZFloatTo16(register _cmsTRANSFORM* info,
889                                   register cmsUInt16Number wIn[],
890                                   register cmsUInt8Number* accum,
891                                   register cmsUInt32Number Stride)
892{
893    if (T_PLANAR(info -> InputFormat)) {
894
895        cmsFloat32Number* Pt = (cmsFloat32Number*) accum;
896        cmsCIEXYZ XYZ;
897
898        XYZ.X = Pt[0];
899        XYZ.Y = Pt[Stride];
900        XYZ.Z = Pt[Stride*2];
901        cmsFloat2XYZEncoded(wIn, &XYZ);
902
903        return accum + sizeof(cmsFloat32Number);
904
905    }
906
907    else {
908        cmsFloat32Number* Pt = (cmsFloat32Number*) accum;
909        cmsCIEXYZ XYZ;
910
911        XYZ.X = Pt[0];
912        XYZ.Y = Pt[1];
913        XYZ.Z = Pt[2];
914        cmsFloat2XYZEncoded(wIn, &XYZ);
915
916        accum += 3 * sizeof(cmsFloat32Number) + T_EXTRA(info ->InputFormat) * sizeof(cmsFloat32Number);
917
918        return accum;
919    }
920}
921
922// Check if space is marked as ink
923cmsINLINE cmsBool IsInkSpace(cmsUInt32Number Type)
924{
925    switch (T_COLORSPACE(Type)) {
926
927     case PT_CMY:
928     case PT_CMYK:
929     case PT_MCH5:
930     case PT_MCH6:
931     case PT_MCH7:
932     case PT_MCH8:
933     case PT_MCH9:
934     case PT_MCH10:
935     case PT_MCH11:
936     case PT_MCH12:
937     case PT_MCH13:
938     case PT_MCH14:
939     case PT_MCH15: return TRUE;
940
941     default: return FALSE;
942    }
943}
944
945// Inks does come in percentage, remaining cases are between 0..1.0, again to 16 bits
946static
947cmsUInt8Number* UnrollDoubleTo16(register _cmsTRANSFORM* info,
948                                register cmsUInt16Number wIn[],
949                                register cmsUInt8Number* accum,
950                                register cmsUInt32Number Stride)
951{
952
953    int nChan      = T_CHANNELS(info -> InputFormat);
954    int DoSwap     = T_DOSWAP(info ->InputFormat);
955    int Reverse    = T_FLAVOR(info ->InputFormat);
956    int SwapFirst  = T_SWAPFIRST(info -> InputFormat);
957    int Extra      = T_EXTRA(info -> InputFormat);
958    int ExtraFirst = DoSwap ^ SwapFirst;
959    int Planar     = T_PLANAR(info -> InputFormat);
960    cmsFloat64Number v;
961    cmsUInt16Number  vi;
962    int i, start = 0;
963   cmsFloat64Number maximum = IsInkSpace(info ->InputFormat) ? 655.35 : 65535.0;
964
965
966    if (ExtraFirst)
967            start = Extra;
968
969    for (i=0; i < nChan; i++) {
970
971        int index = DoSwap ? (nChan - i - 1) : i;
972
973        if (Planar)
974            v = (cmsFloat32Number) ((cmsFloat64Number*) accum)[(i + start) * Stride];
975        else
976            v = (cmsFloat32Number) ((cmsFloat64Number*) accum)[i + start];
977
978        vi = _cmsQuickSaturateWord(v * maximum);
979
980        if (Reverse)
981            vi = REVERSE_FLAVOR_16(vi);
982
983        wIn[index] = vi;
984    }
985
986
987    if (Extra == 0 && SwapFirst) {
988        cmsUInt16Number tmp = wIn[0];
989
990        memmove(&wIn[0], &wIn[1], (nChan-1) * sizeof(cmsUInt16Number));
991        wIn[nChan-1] = tmp;
992    }
993
994    if (T_PLANAR(info -> InputFormat))
995        return accum + sizeof(cmsFloat64Number);
996    else
997        return accum + (nChan + Extra) * sizeof(cmsFloat64Number);
998}
999
1000
1001
1002static
1003cmsUInt8Number* UnrollFloatTo16(register _cmsTRANSFORM* info,
1004                                register cmsUInt16Number wIn[],
1005                                register cmsUInt8Number* accum,
1006                                register cmsUInt32Number Stride)
1007{
1008
1009    int nChan      = T_CHANNELS(info -> InputFormat);
1010    int DoSwap     = T_DOSWAP(info ->InputFormat);
1011    int Reverse    = T_FLAVOR(info ->InputFormat);
1012    int SwapFirst  = T_SWAPFIRST(info -> InputFormat);
1013    int Extra      = T_EXTRA(info -> InputFormat);
1014    int ExtraFirst = DoSwap ^ SwapFirst;
1015    int Planar     = T_PLANAR(info -> InputFormat);
1016    cmsFloat32Number v;
1017    cmsUInt16Number  vi;
1018    int i, start = 0;
1019   cmsFloat64Number maximum = IsInkSpace(info ->InputFormat) ? 655.35 : 65535.0;
1020
1021
1022    if (ExtraFirst)
1023            start = Extra;
1024
1025    for (i=0; i < nChan; i++) {
1026
1027        int index = DoSwap ? (nChan - i - 1) : i;
1028
1029        if (Planar)
1030            v = (cmsFloat32Number) ((cmsFloat32Number*) accum)[(i + start) * Stride];
1031        else
1032            v = (cmsFloat32Number) ((cmsFloat32Number*) accum)[i + start];
1033
1034        vi = _cmsQuickSaturateWord(v * maximum);
1035
1036        if (Reverse)
1037            vi = REVERSE_FLAVOR_16(vi);
1038
1039        wIn[index] = vi;
1040    }
1041
1042
1043    if (Extra == 0 && SwapFirst) {
1044        cmsUInt16Number tmp = wIn[0];
1045
1046        memmove(&wIn[0], &wIn[1], (nChan-1) * sizeof(cmsUInt16Number));
1047        wIn[nChan-1] = tmp;
1048    }
1049
1050    if (T_PLANAR(info -> InputFormat))
1051        return accum + sizeof(cmsFloat32Number);
1052    else
1053        return accum + (nChan + Extra) * sizeof(cmsFloat32Number);
1054}
1055
1056
1057
1058
1059// For 1 channel, we need to duplicate data (it comes in 0..1.0 range)
1060static
1061cmsUInt8Number* UnrollDouble1Chan(register _cmsTRANSFORM* info,
1062                                  register cmsUInt16Number wIn[],
1063                                  register cmsUInt8Number* accum,
1064                                  register cmsUInt32Number Stride)
1065{
1066    cmsFloat64Number* Inks = (cmsFloat64Number*) accum;
1067
1068    wIn[0] = wIn[1] = wIn[2] = _cmsQuickSaturateWord(Inks[0] * 65535.0);
1069
1070    return accum + sizeof(cmsFloat64Number);
1071
1072    cmsUNUSED_PARAMETER(info);
1073    cmsUNUSED_PARAMETER(Stride);
1074}
1075
1076//-------------------------------------------------------------------------------------------------------------------
1077
1078// For anything going from cmsFloat32Number
1079static
1080cmsUInt8Number* UnrollFloatsToFloat(_cmsTRANSFORM* info,
1081                                    cmsFloat32Number wIn[],
1082                                    cmsUInt8Number* accum,
1083                                    cmsUInt32Number Stride)
1084{
1085
1086    int nChan      = T_CHANNELS(info -> InputFormat);
1087    int DoSwap     = T_DOSWAP(info ->InputFormat);
1088    int Reverse    = T_FLAVOR(info ->InputFormat);
1089    int SwapFirst  = T_SWAPFIRST(info -> InputFormat);
1090    int Extra      = T_EXTRA(info -> InputFormat);
1091    int ExtraFirst = DoSwap ^ SwapFirst;
1092    int Planar     = T_PLANAR(info -> InputFormat);
1093    cmsFloat32Number v;
1094    int i, start = 0;
1095    cmsFloat32Number maximum = IsInkSpace(info ->InputFormat) ? 100.0F : 1.0F;
1096
1097
1098    if (ExtraFirst)
1099            start = Extra;
1100
1101    for (i=0; i < nChan; i++) {
1102
1103        int index = DoSwap ? (nChan - i - 1) : i;
1104
1105        if (Planar)
1106            v = (cmsFloat32Number) ((cmsFloat32Number*) accum)[(i + start) * Stride];
1107        else
1108            v = (cmsFloat32Number) ((cmsFloat32Number*) accum)[i + start];
1109
1110        v /= maximum;
1111
1112        wIn[index] = Reverse ? 1 - v : v;
1113    }
1114
1115
1116    if (Extra == 0 && SwapFirst) {
1117        cmsFloat32Number tmp = wIn[0];
1118
1119        memmove(&wIn[0], &wIn[1], (nChan-1) * sizeof(cmsFloat32Number));
1120        wIn[nChan-1] = tmp;
1121    }
1122
1123    if (T_PLANAR(info -> InputFormat))
1124        return accum + sizeof(cmsFloat32Number);
1125    else
1126        return accum + (nChan + Extra) * sizeof(cmsFloat32Number);
1127}
1128
1129// For anything going from double
1130
1131static
1132cmsUInt8Number* UnrollDoublesToFloat(_cmsTRANSFORM* info,
1133                                    cmsFloat32Number wIn[],
1134                                    cmsUInt8Number* accum,
1135                                    cmsUInt32Number Stride)
1136{
1137
1138    int nChan      = T_CHANNELS(info -> InputFormat);
1139    int DoSwap     = T_DOSWAP(info ->InputFormat);
1140    int Reverse    = T_FLAVOR(info ->InputFormat);
1141    int SwapFirst  = T_SWAPFIRST(info -> InputFormat);
1142    int Extra      = T_EXTRA(info -> InputFormat);
1143    int ExtraFirst = DoSwap ^ SwapFirst;
1144    int Planar     = T_PLANAR(info -> InputFormat);
1145    cmsFloat64Number v;
1146    int i, start = 0;
1147    cmsFloat64Number maximum = IsInkSpace(info ->InputFormat) ? 100.0 : 1.0;
1148
1149
1150    if (ExtraFirst)
1151            start = Extra;
1152
1153    for (i=0; i < nChan; i++) {
1154
1155        int index = DoSwap ? (nChan - i - 1) : i;
1156
1157        if (Planar)
1158            v = (cmsFloat64Number) ((cmsFloat64Number*) accum)[(i + start)  * Stride];
1159        else
1160            v = (cmsFloat64Number) ((cmsFloat64Number*) accum)[i + start];
1161
1162        v /= maximum;
1163
1164        wIn[index] = (cmsFloat32Number) (Reverse ? 1.0 - v : v);
1165    }
1166
1167
1168    if (Extra == 0 && SwapFirst) {
1169        cmsFloat32Number tmp = wIn[0];
1170
1171        memmove(&wIn[0], &wIn[1], (nChan-1) * sizeof(cmsFloat32Number));
1172        wIn[nChan-1] = tmp;
1173    }
1174
1175    if (T_PLANAR(info -> InputFormat))
1176        return accum + sizeof(cmsFloat64Number);
1177    else
1178        return accum + (nChan + Extra) * sizeof(cmsFloat64Number);
1179}
1180
1181
1182
1183// From Lab double to cmsFloat32Number
1184static
1185cmsUInt8Number* UnrollLabDoubleToFloat(_cmsTRANSFORM* info,
1186                                       cmsFloat32Number wIn[],
1187                                       cmsUInt8Number* accum,
1188                                       cmsUInt32Number Stride)
1189{
1190    cmsFloat64Number* Pt = (cmsFloat64Number*) accum;
1191
1192    if (T_PLANAR(info -> InputFormat)) {
1193
1194        wIn[0] = (cmsFloat32Number) (Pt[0] / 100.0);                            // from 0..100 to 0..1
1195        wIn[1] = (cmsFloat32Number) ((Pt[Stride] + 128) / 255.0);    // form -128..+127 to 0..1
1196        wIn[2] = (cmsFloat32Number) ((Pt[Stride*2] + 128) / 255.0);
1197
1198        return accum + sizeof(cmsFloat64Number);
1199    }
1200    else {
1201
1202        wIn[0] = (cmsFloat32Number) (Pt[0] / 100.0);            // from 0..100 to 0..1
1203        wIn[1] = (cmsFloat32Number) ((Pt[1] + 128) / 255.0);    // form -128..+127 to 0..1
1204        wIn[2] = (cmsFloat32Number) ((Pt[2] + 128) / 255.0);
1205
1206        accum += sizeof(cmsFloat64Number)*(3 + T_EXTRA(info ->InputFormat));
1207        return accum;
1208    }
1209}
1210
1211// From Lab double to cmsFloat32Number
1212static
1213cmsUInt8Number* UnrollLabFloatToFloat(_cmsTRANSFORM* info,
1214                                      cmsFloat32Number wIn[],
1215                                      cmsUInt8Number* accum,
1216                                      cmsUInt32Number Stride)
1217{
1218    cmsFloat32Number* Pt = (cmsFloat32Number*) accum;
1219
1220    if (T_PLANAR(info -> InputFormat)) {
1221
1222        wIn[0] = (cmsFloat32Number) (Pt[0] / 100.0);                 // from 0..100 to 0..1
1223        wIn[1] = (cmsFloat32Number) ((Pt[Stride] + 128) / 255.0);    // form -128..+127 to 0..1
1224        wIn[2] = (cmsFloat32Number) ((Pt[Stride*2] + 128) / 255.0);
1225
1226        return accum + sizeof(cmsFloat32Number);
1227    }
1228    else {
1229
1230        wIn[0] = (cmsFloat32Number) (Pt[0] / 100.0);            // from 0..100 to 0..1
1231        wIn[1] = (cmsFloat32Number) ((Pt[1] + 128) / 255.0);    // form -128..+127 to 0..1
1232        wIn[2] = (cmsFloat32Number) ((Pt[2] + 128) / 255.0);
1233
1234        accum += sizeof(cmsFloat32Number)*(3 + T_EXTRA(info ->InputFormat));
1235        return accum;
1236    }
1237}
1238
1239
1240
1241// 1.15 fixed point, that means maximum value is MAX_ENCODEABLE_XYZ (0xFFFF)
1242static
1243cmsUInt8Number* UnrollXYZDoubleToFloat(_cmsTRANSFORM* info,
1244                                       cmsFloat32Number wIn[],
1245                                       cmsUInt8Number* accum,
1246                                       cmsUInt32Number Stride)
1247{
1248    cmsFloat64Number* Pt = (cmsFloat64Number*) accum;
1249
1250    if (T_PLANAR(info -> InputFormat)) {
1251
1252        wIn[0] = (cmsFloat32Number) (Pt[0] / MAX_ENCODEABLE_XYZ);
1253        wIn[1] = (cmsFloat32Number) (Pt[Stride] / MAX_ENCODEABLE_XYZ);
1254        wIn[2] = (cmsFloat32Number) (Pt[Stride*2] / MAX_ENCODEABLE_XYZ);
1255
1256        return accum + sizeof(cmsFloat64Number);
1257    }
1258    else {
1259
1260        wIn[0] = (cmsFloat32Number) (Pt[0] / MAX_ENCODEABLE_XYZ);
1261        wIn[1] = (cmsFloat32Number) (Pt[1] / MAX_ENCODEABLE_XYZ);
1262        wIn[2] = (cmsFloat32Number) (Pt[2] / MAX_ENCODEABLE_XYZ);
1263
1264        accum += sizeof(cmsFloat64Number)*(3 + T_EXTRA(info ->InputFormat));
1265        return accum;
1266    }
1267}
1268
1269static
1270cmsUInt8Number* UnrollXYZFloatToFloat(_cmsTRANSFORM* info,
1271                                      cmsFloat32Number wIn[],
1272                                      cmsUInt8Number* accum,
1273                                      cmsUInt32Number Stride)
1274{
1275    cmsFloat32Number* Pt = (cmsFloat32Number*) accum;
1276
1277    if (T_PLANAR(info -> InputFormat)) {
1278
1279        wIn[0] = (cmsFloat32Number) (Pt[0] / MAX_ENCODEABLE_XYZ);
1280        wIn[1] = (cmsFloat32Number) (Pt[Stride] / MAX_ENCODEABLE_XYZ);
1281        wIn[2] = (cmsFloat32Number) (Pt[Stride*2] / MAX_ENCODEABLE_XYZ);
1282
1283        return accum + sizeof(cmsFloat32Number);
1284    }
1285    else {
1286
1287        wIn[0] = (cmsFloat32Number) (Pt[0] / MAX_ENCODEABLE_XYZ);
1288        wIn[1] = (cmsFloat32Number) (Pt[1] / MAX_ENCODEABLE_XYZ);
1289        wIn[2] = (cmsFloat32Number) (Pt[2] / MAX_ENCODEABLE_XYZ);
1290
1291        accum += sizeof(cmsFloat32Number)*(3 + T_EXTRA(info ->InputFormat));
1292        return accum;
1293    }
1294}
1295
1296
1297
1298// Packing routines -----------------------------------------------------------------------------------------------------------
1299
1300
1301// Generic chunky for byte
1302
1303static
1304cmsUInt8Number* PackAnyBytes(register _cmsTRANSFORM* info,
1305                             register cmsUInt16Number wOut[],
1306                             register cmsUInt8Number* output,
1307                             register cmsUInt32Number Stride)
1308{
1309    int nChan      = T_CHANNELS(info -> OutputFormat);
1310    int DoSwap     = T_DOSWAP(info ->OutputFormat);
1311    int Reverse    = T_FLAVOR(info ->OutputFormat);
1312    int Extra      = T_EXTRA(info -> OutputFormat);
1313    int SwapFirst  = T_SWAPFIRST(info -> OutputFormat);
1314    int ExtraFirst = DoSwap ^ SwapFirst;
1315    cmsUInt8Number* swap1;
1316    cmsUInt8Number v = 0;
1317    int i;
1318
1319    swap1 = output;
1320
1321    if (ExtraFirst) {
1322        output += Extra;
1323    }
1324
1325    for (i=0; i < nChan; i++) {
1326
1327        int index = DoSwap ? (nChan - i - 1) : i;
1328
1329        v = FROM_16_TO_8(wOut[index]);
1330
1331        if (Reverse)
1332            v = REVERSE_FLAVOR_8(v);
1333
1334        *output++ = v;
1335    }
1336
1337    if (!ExtraFirst) {
1338        output += Extra;
1339    }
1340
1341    if (Extra == 0 && SwapFirst) {
1342
1343        memmove(swap1 + 1, swap1, nChan-1);
1344        *swap1 = v;
1345    }
1346
1347
1348    return output;
1349
1350    cmsUNUSED_PARAMETER(Stride);
1351}
1352
1353
1354
1355static
1356cmsUInt8Number* PackAnyWords(register _cmsTRANSFORM* info,
1357                             register cmsUInt16Number wOut[],
1358                             register cmsUInt8Number* output,
1359                             register cmsUInt32Number Stride)
1360{
1361    int nChan      = T_CHANNELS(info -> OutputFormat);
1362    int SwapEndian = T_ENDIAN16(info -> InputFormat);
1363    int DoSwap     = T_DOSWAP(info ->OutputFormat);
1364    int Reverse    = T_FLAVOR(info ->OutputFormat);
1365    int Extra      = T_EXTRA(info -> OutputFormat);
1366    int SwapFirst  = T_SWAPFIRST(info -> OutputFormat);
1367    int ExtraFirst = DoSwap ^ SwapFirst;
1368    cmsUInt16Number* swap1;
1369    cmsUInt16Number v = 0;
1370    int i;
1371
1372    swap1 = (cmsUInt16Number*) output;
1373
1374    if (ExtraFirst) {
1375        output += Extra * sizeof(cmsUInt16Number);
1376    }
1377
1378    for (i=0; i < nChan; i++) {
1379
1380        int index = DoSwap ? (nChan - i - 1) : i;
1381
1382        v = wOut[index];
1383
1384        if (SwapEndian)
1385            v = CHANGE_ENDIAN(v);
1386
1387        if (Reverse)
1388            v = REVERSE_FLAVOR_16(v);
1389
1390        *(cmsUInt16Number*) output = v;
1391
1392        output += sizeof(cmsUInt16Number);
1393    }
1394
1395    if (!ExtraFirst) {
1396        output += Extra * sizeof(cmsUInt16Number);
1397    }
1398
1399    if (Extra == 0 && SwapFirst) {
1400
1401        memmove(swap1 + 1, swap1, (nChan-1)* sizeof(cmsUInt16Number));
1402        *swap1 = v;
1403    }
1404
1405
1406    return output;
1407
1408    cmsUNUSED_PARAMETER(Stride);
1409}
1410
1411
1412static
1413cmsUInt8Number* PackPlanarBytes(register _cmsTRANSFORM* info,
1414                                register cmsUInt16Number wOut[],
1415                                register cmsUInt8Number* output,
1416                                register cmsUInt32Number Stride)
1417{
1418    int nChan     = T_CHANNELS(info -> OutputFormat);
1419    int DoSwap    = T_DOSWAP(info ->OutputFormat);
1420    int SwapFirst = T_SWAPFIRST(info ->OutputFormat);
1421    int Reverse   = T_FLAVOR(info ->OutputFormat);
1422    int i;
1423    cmsUInt8Number* Init = output;
1424
1425
1426    if (DoSwap ^ SwapFirst) {
1427        output += T_EXTRA(info -> OutputFormat) * Stride;
1428    }
1429
1430
1431    for (i=0; i < nChan; i++) {
1432
1433        int index = DoSwap ? (nChan - i - 1) : i;
1434        cmsUInt8Number v = FROM_16_TO_8(wOut[index]);
1435
1436        *(cmsUInt8Number*)  output = (cmsUInt8Number) (Reverse ? REVERSE_FLAVOR_8(v) : v);
1437        output += Stride;
1438    }
1439
1440    return (Init + 1);
1441
1442    cmsUNUSED_PARAMETER(Stride);
1443}
1444
1445
1446static
1447cmsUInt8Number* PackPlanarWords(register _cmsTRANSFORM* info,
1448                                register cmsUInt16Number wOut[],
1449                                register cmsUInt8Number* output,
1450                                register cmsUInt32Number Stride)
1451{
1452    int nChan = T_CHANNELS(info -> OutputFormat);
1453    int DoSwap = T_DOSWAP(info ->OutputFormat);
1454    int Reverse= T_FLAVOR(info ->OutputFormat);
1455    int SwapEndian = T_ENDIAN16(info -> OutputFormat);
1456    int i;
1457    cmsUInt8Number* Init = output;
1458    cmsUInt16Number v;
1459
1460    if (DoSwap) {
1461        output += T_EXTRA(info -> OutputFormat) * Stride * sizeof(cmsUInt16Number);
1462    }
1463
1464    for (i=0; i < nChan; i++) {
1465
1466        int index = DoSwap ? (nChan - i - 1) : i;
1467
1468        v = wOut[index];
1469
1470        if (SwapEndian)
1471            v = CHANGE_ENDIAN(v);
1472
1473        if (Reverse)
1474            v =  REVERSE_FLAVOR_16(v);
1475
1476        *(cmsUInt16Number*) output = v;
1477        output += (Stride * sizeof(cmsUInt16Number));
1478    }
1479
1480    return (Init + sizeof(cmsUInt16Number));
1481}
1482
1483// CMYKcm (unrolled for speed)
1484
1485static
1486cmsUInt8Number* Pack6Bytes(register _cmsTRANSFORM* info,
1487                           register cmsUInt16Number wOut[],
1488                           register cmsUInt8Number* output,
1489                           register cmsUInt32Number Stride)
1490{
1491    *output++ = FROM_16_TO_8(wOut[0]);
1492    *output++ = FROM_16_TO_8(wOut[1]);
1493    *output++ = FROM_16_TO_8(wOut[2]);
1494    *output++ = FROM_16_TO_8(wOut[3]);
1495    *output++ = FROM_16_TO_8(wOut[4]);
1496    *output++ = FROM_16_TO_8(wOut[5]);
1497
1498    return output;
1499
1500    cmsUNUSED_PARAMETER(info);
1501    cmsUNUSED_PARAMETER(Stride);
1502}
1503
1504// KCMYcm
1505
1506static
1507cmsUInt8Number* Pack6BytesSwap(register _cmsTRANSFORM* info,
1508                               register cmsUInt16Number wOut[],
1509                               register cmsUInt8Number* output,
1510                               register cmsUInt32Number Stride)
1511{
1512    *output++ = FROM_16_TO_8(wOut[5]);
1513    *output++ = FROM_16_TO_8(wOut[4]);
1514    *output++ = FROM_16_TO_8(wOut[3]);
1515    *output++ = FROM_16_TO_8(wOut[2]);
1516    *output++ = FROM_16_TO_8(wOut[1]);
1517    *output++ = FROM_16_TO_8(wOut[0]);
1518
1519    return output;
1520
1521    cmsUNUSED_PARAMETER(info);
1522    cmsUNUSED_PARAMETER(Stride);
1523}
1524
1525// CMYKcm
1526static
1527cmsUInt8Number* Pack6Words(register _cmsTRANSFORM* info,
1528                           register cmsUInt16Number wOut[],
1529                           register cmsUInt8Number* output,
1530                           register cmsUInt32Number Stride)
1531{
1532    *(cmsUInt16Number*) output = wOut[0];
1533    output+= 2;
1534    *(cmsUInt16Number*) output = wOut[1];
1535    output+= 2;
1536    *(cmsUInt16Number*) output = wOut[2];
1537    output+= 2;
1538    *(cmsUInt16Number*) output = wOut[3];
1539    output+= 2;
1540    *(cmsUInt16Number*) output = wOut[4];
1541    output+= 2;
1542    *(cmsUInt16Number*) output = wOut[5];
1543    output+= 2;
1544
1545    return output;
1546
1547    cmsUNUSED_PARAMETER(info);
1548    cmsUNUSED_PARAMETER(Stride);
1549}
1550
1551// KCMYcm
1552static
1553cmsUInt8Number* Pack6WordsSwap(register _cmsTRANSFORM* info,
1554                               register cmsUInt16Number wOut[],
1555                               register cmsUInt8Number* output,
1556                               register cmsUInt32Number Stride)
1557{
1558    *(cmsUInt16Number*) output = wOut[5];
1559    output+= 2;
1560    *(cmsUInt16Number*) output = wOut[4];
1561    output+= 2;
1562    *(cmsUInt16Number*) output = wOut[3];
1563    output+= 2;
1564    *(cmsUInt16Number*) output = wOut[2];
1565    output+= 2;
1566    *(cmsUInt16Number*) output = wOut[1];
1567    output+= 2;
1568    *(cmsUInt16Number*) output = wOut[0];
1569    output+= 2;
1570
1571    return output;
1572
1573    cmsUNUSED_PARAMETER(info);
1574    cmsUNUSED_PARAMETER(Stride);
1575}
1576
1577
1578static
1579cmsUInt8Number* Pack4Bytes(register _cmsTRANSFORM* info,
1580                           register cmsUInt16Number wOut[],
1581                           register cmsUInt8Number* output,
1582                           register cmsUInt32Number Stride)
1583{
1584    *output++ = FROM_16_TO_8(wOut[0]);
1585    *output++ = FROM_16_TO_8(wOut[1]);
1586    *output++ = FROM_16_TO_8(wOut[2]);
1587    *output++ = FROM_16_TO_8(wOut[3]);
1588
1589    return output;
1590
1591    cmsUNUSED_PARAMETER(info);
1592    cmsUNUSED_PARAMETER(Stride);
1593}
1594
1595static
1596cmsUInt8Number* Pack4BytesReverse(register _cmsTRANSFORM* info,
1597                                  register cmsUInt16Number wOut[],
1598                                  register cmsUInt8Number* output,
1599                                  register cmsUInt32Number Stride)
1600{
1601    *output++ = REVERSE_FLAVOR_8(FROM_16_TO_8(wOut[0]));
1602    *output++ = REVERSE_FLAVOR_8(FROM_16_TO_8(wOut[1]));
1603    *output++ = REVERSE_FLAVOR_8(FROM_16_TO_8(wOut[2]));
1604    *output++ = REVERSE_FLAVOR_8(FROM_16_TO_8(wOut[3]));
1605
1606    return output;
1607
1608    cmsUNUSED_PARAMETER(info);
1609    cmsUNUSED_PARAMETER(Stride);
1610}
1611
1612
1613static
1614cmsUInt8Number* Pack4BytesSwapFirst(register _cmsTRANSFORM* info,
1615                                    register cmsUInt16Number wOut[],
1616                                    register cmsUInt8Number* output,
1617                                    register cmsUInt32Number Stride)
1618{
1619    *output++ = FROM_16_TO_8(wOut[3]);
1620    *output++ = FROM_16_TO_8(wOut[0]);
1621    *output++ = FROM_16_TO_8(wOut[1]);
1622    *output++ = FROM_16_TO_8(wOut[2]);
1623
1624    return output;
1625
1626    cmsUNUSED_PARAMETER(info);
1627    cmsUNUSED_PARAMETER(Stride);
1628}
1629
1630// ABGR
1631static
1632cmsUInt8Number* Pack4BytesSwap(register _cmsTRANSFORM* info,
1633                               register cmsUInt16Number wOut[],
1634                               register cmsUInt8Number* output,
1635                               register cmsUInt32Number Stride)
1636{
1637    *output++ = FROM_16_TO_8(wOut[3]);
1638    *output++ = FROM_16_TO_8(wOut[2]);
1639    *output++ = FROM_16_TO_8(wOut[1]);
1640    *output++ = FROM_16_TO_8(wOut[0]);
1641
1642    return output;
1643
1644    cmsUNUSED_PARAMETER(info);
1645    cmsUNUSED_PARAMETER(Stride);
1646}
1647
1648static
1649cmsUInt8Number* Pack4BytesSwapSwapFirst(register _cmsTRANSFORM* info,
1650                                        register cmsUInt16Number wOut[],
1651                                        register cmsUInt8Number* output,
1652                                        register cmsUInt32Number Stride)
1653{
1654    *output++ = FROM_16_TO_8(wOut[2]);
1655    *output++ = FROM_16_TO_8(wOut[1]);
1656    *output++ = FROM_16_TO_8(wOut[0]);
1657    *output++ = FROM_16_TO_8(wOut[3]);
1658
1659    return output;
1660
1661    cmsUNUSED_PARAMETER(info);
1662    cmsUNUSED_PARAMETER(Stride);
1663}
1664
1665static
1666cmsUInt8Number* Pack4Words(register _cmsTRANSFORM* info,
1667                           register cmsUInt16Number wOut[],
1668                           register cmsUInt8Number* output,
1669                           register cmsUInt32Number Stride)
1670{
1671    *(cmsUInt16Number*) output = wOut[0];
1672    output+= 2;
1673    *(cmsUInt16Number*) output = wOut[1];
1674    output+= 2;
1675    *(cmsUInt16Number*) output = wOut[2];
1676    output+= 2;
1677    *(cmsUInt16Number*) output = wOut[3];
1678    output+= 2;
1679
1680    return output;
1681
1682    cmsUNUSED_PARAMETER(info);
1683    cmsUNUSED_PARAMETER(Stride);
1684}
1685
1686static
1687cmsUInt8Number* Pack4WordsReverse(register _cmsTRANSFORM* info,
1688                                  register cmsUInt16Number wOut[],
1689                                  register cmsUInt8Number* output,
1690                                  register cmsUInt32Number Stride)
1691{
1692    *(cmsUInt16Number*) output = REVERSE_FLAVOR_16(wOut[0]);
1693    output+= 2;
1694    *(cmsUInt16Number*) output = REVERSE_FLAVOR_16(wOut[1]);
1695    output+= 2;
1696    *(cmsUInt16Number*) output = REVERSE_FLAVOR_16(wOut[2]);
1697    output+= 2;
1698    *(cmsUInt16Number*) output = REVERSE_FLAVOR_16(wOut[3]);
1699    output+= 2;
1700
1701    return output;
1702
1703    cmsUNUSED_PARAMETER(info);
1704    cmsUNUSED_PARAMETER(Stride);
1705}
1706
1707// ABGR
1708static
1709cmsUInt8Number* Pack4WordsSwap(register _cmsTRANSFORM* info,
1710                               register cmsUInt16Number wOut[],
1711                               register cmsUInt8Number* output,
1712                               register cmsUInt32Number Stride)
1713{
1714    *(cmsUInt16Number*) output = wOut[3];
1715    output+= 2;
1716    *(cmsUInt16Number*) output = wOut[2];
1717    output+= 2;
1718    *(cmsUInt16Number*) output = wOut[1];
1719    output+= 2;
1720    *(cmsUInt16Number*) output = wOut[0];
1721    output+= 2;
1722
1723    return output;
1724
1725    cmsUNUSED_PARAMETER(info);
1726    cmsUNUSED_PARAMETER(Stride);
1727}
1728
1729// CMYK
1730static
1731cmsUInt8Number* Pack4WordsBigEndian(register _cmsTRANSFORM* info,
1732                                    register cmsUInt16Number wOut[],
1733                                    register cmsUInt8Number* output,
1734                                    register cmsUInt32Number Stride)
1735{
1736    *(cmsUInt16Number*) output = CHANGE_ENDIAN(wOut[0]);
1737    output+= 2;
1738    *(cmsUInt16Number*) output = CHANGE_ENDIAN(wOut[1]);
1739    output+= 2;
1740    *(cmsUInt16Number*) output = CHANGE_ENDIAN(wOut[2]);
1741    output+= 2;
1742    *(cmsUInt16Number*) output = CHANGE_ENDIAN(wOut[3]);
1743    output+= 2;
1744
1745    return output;
1746
1747    cmsUNUSED_PARAMETER(info);
1748    cmsUNUSED_PARAMETER(Stride);
1749}
1750
1751
1752static
1753cmsUInt8Number* PackLabV2_8(register _cmsTRANSFORM* info,
1754                            register cmsUInt16Number wOut[],
1755                            register cmsUInt8Number* output,
1756                            register cmsUInt32Number Stride)
1757{
1758    *output++ = FROM_16_TO_8(FomLabV4ToLabV2(wOut[0]));
1759    *output++ = FROM_16_TO_8(FomLabV4ToLabV2(wOut[1]));
1760    *output++ = FROM_16_TO_8(FomLabV4ToLabV2(wOut[2]));
1761
1762    return output;
1763
1764    cmsUNUSED_PARAMETER(info);
1765    cmsUNUSED_PARAMETER(Stride);
1766}
1767
1768static
1769cmsUInt8Number* PackALabV2_8(register _cmsTRANSFORM* info,
1770                             register cmsUInt16Number wOut[],
1771                             register cmsUInt8Number* output,
1772                             register cmsUInt32Number Stride)
1773{
1774    output++;
1775    *output++ = FROM_16_TO_8(FomLabV4ToLabV2(wOut[0]));
1776    *output++ = FROM_16_TO_8(FomLabV4ToLabV2(wOut[1]));
1777    *output++ = FROM_16_TO_8(FomLabV4ToLabV2(wOut[2]));
1778
1779    return output;
1780
1781    cmsUNUSED_PARAMETER(info);
1782    cmsUNUSED_PARAMETER(Stride);
1783}
1784
1785static
1786cmsUInt8Number* PackLabV2_16(register _cmsTRANSFORM* info,
1787                             register cmsUInt16Number wOut[],
1788                             register cmsUInt8Number* output,
1789                             register cmsUInt32Number Stride)
1790{
1791    *(cmsUInt16Number*) output = FomLabV4ToLabV2(wOut[0]);
1792    output += 2;
1793    *(cmsUInt16Number*) output = FomLabV4ToLabV2(wOut[1]);
1794    output += 2;
1795    *(cmsUInt16Number*) output = FomLabV4ToLabV2(wOut[2]);
1796    output += 2;
1797
1798    return output;
1799
1800    cmsUNUSED_PARAMETER(info);
1801    cmsUNUSED_PARAMETER(Stride);
1802}
1803
1804static
1805cmsUInt8Number* Pack3Bytes(register _cmsTRANSFORM* info,
1806                           register cmsUInt16Number wOut[],
1807                           register cmsUInt8Number* output,
1808                           register cmsUInt32Number Stride)
1809{
1810    *output++ = FROM_16_TO_8(wOut[0]);
1811    *output++ = FROM_16_TO_8(wOut[1]);
1812    *output++ = FROM_16_TO_8(wOut[2]);
1813
1814    return output;
1815
1816    cmsUNUSED_PARAMETER(info);
1817    cmsUNUSED_PARAMETER(Stride);
1818}
1819
1820static
1821cmsUInt8Number* Pack3BytesOptimized(register _cmsTRANSFORM* info,
1822                                    register cmsUInt16Number wOut[],
1823                                    register cmsUInt8Number* output,
1824                                    register cmsUInt32Number Stride)
1825{
1826    *output++ = (wOut[0] & 0xFF);
1827    *output++ = (wOut[1] & 0xFF);
1828    *output++ = (wOut[2] & 0xFF);
1829
1830    return output;
1831
1832    cmsUNUSED_PARAMETER(info);
1833    cmsUNUSED_PARAMETER(Stride);
1834}
1835
1836static
1837cmsUInt8Number* Pack3BytesSwap(register _cmsTRANSFORM* info,
1838                               register cmsUInt16Number wOut[],
1839                               register cmsUInt8Number* output,
1840                               register cmsUInt32Number Stride)
1841{
1842    *output++ = FROM_16_TO_8(wOut[2]);
1843    *output++ = FROM_16_TO_8(wOut[1]);
1844    *output++ = FROM_16_TO_8(wOut[0]);
1845
1846    return output;
1847
1848    cmsUNUSED_PARAMETER(info);
1849    cmsUNUSED_PARAMETER(Stride);
1850}
1851
1852static
1853cmsUInt8Number* Pack3BytesSwapOptimized(register _cmsTRANSFORM* info,
1854                                        register cmsUInt16Number wOut[],
1855                                        register cmsUInt8Number* output,
1856                                        register cmsUInt32Number Stride)
1857{
1858    *output++ = (wOut[2] & 0xFF);
1859    *output++ = (wOut[1] & 0xFF);
1860    *output++ = (wOut[0] & 0xFF);
1861
1862    return output;
1863
1864    cmsUNUSED_PARAMETER(info);
1865    cmsUNUSED_PARAMETER(Stride);
1866}
1867
1868
1869static
1870cmsUInt8Number* Pack3Words(register _cmsTRANSFORM* info,
1871                           register cmsUInt16Number wOut[],
1872                           register cmsUInt8Number* output,
1873                           register cmsUInt32Number Stride)
1874{
1875    *(cmsUInt16Number*) output = wOut[0];
1876    output+= 2;
1877    *(cmsUInt16Number*) output = wOut[1];
1878    output+= 2;
1879    *(cmsUInt16Number*) output = wOut[2];
1880    output+= 2;
1881
1882    return output;
1883
1884    cmsUNUSED_PARAMETER(info);
1885    cmsUNUSED_PARAMETER(Stride);
1886}
1887
1888static
1889cmsUInt8Number* Pack3WordsSwap(register _cmsTRANSFORM* info,
1890                               register cmsUInt16Number wOut[],
1891                               register cmsUInt8Number* output,
1892                               register cmsUInt32Number Stride)
1893{
1894    *(cmsUInt16Number*) output = wOut[2];
1895    output+= 2;
1896    *(cmsUInt16Number*) output = wOut[1];
1897    output+= 2;
1898    *(cmsUInt16Number*) output = wOut[0];
1899    output+= 2;
1900
1901    return output;
1902
1903    cmsUNUSED_PARAMETER(info);
1904    cmsUNUSED_PARAMETER(Stride);
1905}
1906
1907static
1908cmsUInt8Number* Pack3WordsBigEndian(register _cmsTRANSFORM* info,
1909                                    register cmsUInt16Number wOut[],
1910                                    register cmsUInt8Number* output,
1911                                    register cmsUInt32Number Stride)
1912{
1913    *(cmsUInt16Number*) output = CHANGE_ENDIAN(wOut[0]);
1914    output+= 2;
1915    *(cmsUInt16Number*) output = CHANGE_ENDIAN(wOut[1]);
1916    output+= 2;
1917    *(cmsUInt16Number*) output = CHANGE_ENDIAN(wOut[2]);
1918    output+= 2;
1919
1920    return output;
1921
1922    cmsUNUSED_PARAMETER(info);
1923    cmsUNUSED_PARAMETER(Stride);
1924}
1925
1926static
1927cmsUInt8Number* Pack3BytesAndSkip1(register _cmsTRANSFORM* info,
1928                                   register cmsUInt16Number wOut[],
1929                                   register cmsUInt8Number* output,
1930                                   register cmsUInt32Number Stride)
1931{
1932    *output++ = FROM_16_TO_8(wOut[0]);
1933    *output++ = FROM_16_TO_8(wOut[1]);
1934    *output++ = FROM_16_TO_8(wOut[2]);
1935    output++;
1936
1937    return output;
1938
1939    cmsUNUSED_PARAMETER(info);
1940    cmsUNUSED_PARAMETER(Stride);
1941}
1942
1943static
1944cmsUInt8Number* Pack3BytesAndSkip1Optimized(register _cmsTRANSFORM* info,
1945                                            register cmsUInt16Number wOut[],
1946                                            register cmsUInt8Number* output,
1947                                            register cmsUInt32Number Stride)
1948{
1949    *output++ = (wOut[0] & 0xFF);
1950    *output++ = (wOut[1] & 0xFF);
1951    *output++ = (wOut[2] & 0xFF);
1952    output++;
1953
1954    return output;
1955
1956    cmsUNUSED_PARAMETER(info);
1957    cmsUNUSED_PARAMETER(Stride);
1958}
1959
1960
1961static
1962cmsUInt8Number* Pack3BytesAndSkip1SwapFirst(register _cmsTRANSFORM* info,
1963                                            register cmsUInt16Number wOut[],
1964                                            register cmsUInt8Number* output,
1965                                            register cmsUInt32Number Stride)
1966{
1967    output++;
1968    *output++ = FROM_16_TO_8(wOut[0]);
1969    *output++ = FROM_16_TO_8(wOut[1]);
1970    *output++ = FROM_16_TO_8(wOut[2]);
1971
1972    return output;
1973
1974    cmsUNUSED_PARAMETER(info);
1975    cmsUNUSED_PARAMETER(Stride);
1976}
1977
1978static
1979cmsUInt8Number* Pack3BytesAndSkip1SwapFirstOptimized(register _cmsTRANSFORM* info,
1980                                                     register cmsUInt16Number wOut[],
1981                                                     register cmsUInt8Number* output,
1982                                                     register cmsUInt32Number Stride)
1983{
1984    output++;
1985    *output++ = (wOut[0] & 0xFF);
1986    *output++ = (wOut[1] & 0xFF);
1987    *output++ = (wOut[2] & 0xFF);
1988
1989    return output;
1990
1991    cmsUNUSED_PARAMETER(info);
1992    cmsUNUSED_PARAMETER(Stride);
1993}
1994
1995static
1996cmsUInt8Number* Pack3BytesAndSkip1Swap(register _cmsTRANSFORM* info,
1997                                       register cmsUInt16Number wOut[],
1998                                       register cmsUInt8Number* output,
1999                                       register cmsUInt32Number Stride)
2000{
2001    output++;
2002    *output++ = FROM_16_TO_8(wOut[2]);
2003    *output++ = FROM_16_TO_8(wOut[1]);
2004    *output++ = FROM_16_TO_8(wOut[0]);
2005
2006    return output;
2007
2008    cmsUNUSED_PARAMETER(info);
2009    cmsUNUSED_PARAMETER(Stride);
2010}
2011
2012static
2013cmsUInt8Number* Pack3BytesAndSkip1SwapOptimized(register _cmsTRANSFORM* info,
2014                                                register cmsUInt16Number wOut[],
2015                                                register cmsUInt8Number* output,
2016                                                register cmsUInt32Number Stride)
2017{
2018    output++;
2019    *output++ = (wOut[2] & 0xFF);
2020    *output++ = (wOut[1] & 0xFF);
2021    *output++ = (wOut[0] & 0xFF);
2022
2023    return output;
2024
2025    cmsUNUSED_PARAMETER(info);
2026    cmsUNUSED_PARAMETER(Stride);
2027}
2028
2029
2030static
2031cmsUInt8Number* Pack3BytesAndSkip1SwapSwapFirst(register _cmsTRANSFORM* info,
2032                                                register cmsUInt16Number wOut[],
2033                                                register cmsUInt8Number* output,
2034                                                register cmsUInt32Number Stride)
2035{
2036    *output++ = FROM_16_TO_8(wOut[2]);
2037    *output++ = FROM_16_TO_8(wOut[1]);
2038    *output++ = FROM_16_TO_8(wOut[0]);
2039    output++;
2040
2041    return output;
2042
2043    cmsUNUSED_PARAMETER(info);
2044    cmsUNUSED_PARAMETER(Stride);
2045}
2046
2047static
2048cmsUInt8Number* Pack3BytesAndSkip1SwapSwapFirstOptimized(register _cmsTRANSFORM* info,
2049                                                         register cmsUInt16Number wOut[],
2050                                                         register cmsUInt8Number* output,
2051                                                         register cmsUInt32Number Stride)
2052{
2053    *output++ = (wOut[2] & 0xFF);
2054    *output++ = (wOut[1] & 0xFF);
2055    *output++ = (wOut[0] & 0xFF);
2056    output++;
2057
2058    return output;
2059
2060    cmsUNUSED_PARAMETER(info);
2061    cmsUNUSED_PARAMETER(Stride);
2062}
2063
2064static
2065cmsUInt8Number* Pack3WordsAndSkip1(register _cmsTRANSFORM* info,
2066                                   register cmsUInt16Number wOut[],
2067                                   register cmsUInt8Number* output,
2068                                   register cmsUInt32Number Stride)
2069{
2070    *(cmsUInt16Number*) output = wOut[0];
2071    output+= 2;
2072    *(cmsUInt16Number*) output = wOut[1];
2073    output+= 2;
2074    *(cmsUInt16Number*) output = wOut[2];
2075    output+= 2;
2076    output+= 2;
2077
2078    return output;
2079
2080    cmsUNUSED_PARAMETER(info);
2081    cmsUNUSED_PARAMETER(Stride);
2082}
2083
2084static
2085cmsUInt8Number* Pack3WordsAndSkip1Swap(register _cmsTRANSFORM* info,
2086                                       register cmsUInt16Number wOut[],
2087                                       register cmsUInt8Number* output,
2088                                       register cmsUInt32Number Stride)
2089{
2090    output+= 2;
2091    *(cmsUInt16Number*) output = wOut[2];
2092    output+= 2;
2093    *(cmsUInt16Number*) output = wOut[1];
2094    output+= 2;
2095    *(cmsUInt16Number*) output = wOut[0];
2096    output+= 2;
2097
2098    return output;
2099
2100    cmsUNUSED_PARAMETER(info);
2101    cmsUNUSED_PARAMETER(Stride);
2102}
2103
2104
2105static
2106cmsUInt8Number* Pack3WordsAndSkip1SwapFirst(register _cmsTRANSFORM* info,
2107                                            register cmsUInt16Number wOut[],
2108                                            register cmsUInt8Number* output,
2109                                            register cmsUInt32Number Stride)
2110{
2111    output+= 2;
2112    *(cmsUInt16Number*) output = wOut[0];
2113    output+= 2;
2114    *(cmsUInt16Number*) output = wOut[1];
2115    output+= 2;
2116    *(cmsUInt16Number*) output = wOut[2];
2117    output+= 2;
2118
2119    return output;
2120
2121    cmsUNUSED_PARAMETER(info);
2122    cmsUNUSED_PARAMETER(Stride);
2123}
2124
2125
2126static
2127cmsUInt8Number* Pack3WordsAndSkip1SwapSwapFirst(register _cmsTRANSFORM* info,
2128                                                register cmsUInt16Number wOut[],
2129                                                register cmsUInt8Number* output,
2130                                                register cmsUInt32Number Stride)
2131{
2132    *(cmsUInt16Number*) output = wOut[2];
2133    output+= 2;
2134    *(cmsUInt16Number*) output = wOut[1];
2135    output+= 2;
2136    *(cmsUInt16Number*) output = wOut[0];
2137    output+= 2;
2138    output+= 2;
2139
2140    return output;
2141
2142    cmsUNUSED_PARAMETER(info);
2143    cmsUNUSED_PARAMETER(Stride);
2144}
2145
2146
2147
2148static
2149cmsUInt8Number* Pack1Byte(register _cmsTRANSFORM* info,
2150                          register cmsUInt16Number wOut[],
2151                          register cmsUInt8Number* output,
2152                          register cmsUInt32Number Stride)
2153{
2154    *output++ = FROM_16_TO_8(wOut[0]);
2155
2156    return output;
2157
2158    cmsUNUSED_PARAMETER(info);
2159    cmsUNUSED_PARAMETER(Stride);
2160}
2161
2162
2163static
2164cmsUInt8Number* Pack1ByteReversed(register _cmsTRANSFORM* info,
2165                                  register cmsUInt16Number wOut[],
2166                                  register cmsUInt8Number* output,
2167                                  register cmsUInt32Number Stride)
2168{
2169    *output++ = FROM_16_TO_8(REVERSE_FLAVOR_16(wOut[0]));
2170
2171    return output;
2172
2173    cmsUNUSED_PARAMETER(info);
2174    cmsUNUSED_PARAMETER(Stride);
2175}
2176
2177
2178static
2179cmsUInt8Number* Pack1ByteSkip1(register _cmsTRANSFORM* info,
2180                               register cmsUInt16Number wOut[],
2181                               register cmsUInt8Number* output,
2182                               register cmsUInt32Number Stride)
2183{
2184    *output++ = FROM_16_TO_8(wOut[0]);
2185    output++;
2186
2187    return output;
2188
2189    cmsUNUSED_PARAMETER(info);
2190    cmsUNUSED_PARAMETER(Stride);
2191}
2192
2193
2194static
2195cmsUInt8Number* Pack1ByteSkip1SwapFirst(register _cmsTRANSFORM* info,
2196                                        register cmsUInt16Number wOut[],
2197                                        register cmsUInt8Number* output,
2198                                        register cmsUInt32Number Stride)
2199{
2200    output++;
2201    *output++ = FROM_16_TO_8(wOut[0]);
2202
2203    return output;
2204
2205    cmsUNUSED_PARAMETER(info);
2206    cmsUNUSED_PARAMETER(Stride);
2207}
2208
2209static
2210cmsUInt8Number* Pack1Word(register _cmsTRANSFORM* info,
2211                          register cmsUInt16Number wOut[],
2212                          register cmsUInt8Number* output,
2213                          register cmsUInt32Number Stride)
2214{
2215    *(cmsUInt16Number*) output = wOut[0];
2216    output+= 2;
2217
2218    return output;
2219
2220    cmsUNUSED_PARAMETER(info);
2221    cmsUNUSED_PARAMETER(Stride);
2222}
2223
2224
2225static
2226cmsUInt8Number* Pack1WordReversed(register _cmsTRANSFORM* info,
2227                                  register cmsUInt16Number wOut[],
2228                                  register cmsUInt8Number* output,
2229                                  register cmsUInt32Number Stride)
2230{
2231    *(cmsUInt16Number*) output = REVERSE_FLAVOR_16(wOut[0]);
2232    output+= 2;
2233
2234    return output;
2235
2236    cmsUNUSED_PARAMETER(info);
2237    cmsUNUSED_PARAMETER(Stride);
2238}
2239
2240static
2241cmsUInt8Number* Pack1WordBigEndian(register _cmsTRANSFORM* info,
2242                                   register cmsUInt16Number wOut[],
2243                                   register cmsUInt8Number* output,
2244                                   register cmsUInt32Number Stride)
2245{
2246    *(cmsUInt16Number*) output = CHANGE_ENDIAN(wOut[0]);
2247    output+= 2;
2248
2249    return output;
2250
2251    cmsUNUSED_PARAMETER(info);
2252    cmsUNUSED_PARAMETER(Stride);
2253}
2254
2255
2256static
2257cmsUInt8Number* Pack1WordSkip1(register _cmsTRANSFORM* info,
2258                               register cmsUInt16Number wOut[],
2259                               register cmsUInt8Number* output,
2260                               register cmsUInt32Number Stride)
2261{
2262    *(cmsUInt16Number*) output = wOut[0];
2263    output+= 4;
2264
2265    return output;
2266
2267    cmsUNUSED_PARAMETER(info);
2268    cmsUNUSED_PARAMETER(Stride);
2269}
2270
2271static
2272cmsUInt8Number* Pack1WordSkip1SwapFirst(register _cmsTRANSFORM* info,
2273                                        register cmsUInt16Number wOut[],
2274                                        register cmsUInt8Number* output,
2275                                        register cmsUInt32Number Stride)
2276{
2277    output += 2;
2278    *(cmsUInt16Number*) output = wOut[0];
2279    output+= 2;
2280
2281    return output;
2282
2283    cmsUNUSED_PARAMETER(info);
2284    cmsUNUSED_PARAMETER(Stride);
2285}
2286
2287
2288// Unencoded Float values -- don't try optimize speed
2289static
2290cmsUInt8Number* PackLabDoubleFrom16(register _cmsTRANSFORM* info,
2291                                    register cmsUInt16Number wOut[],
2292                                    register cmsUInt8Number* output,
2293                                    register cmsUInt32Number Stride)
2294{
2295
2296    if (T_PLANAR(info -> OutputFormat)) {
2297
2298        cmsCIELab  Lab;
2299        cmsFloat64Number* Out = (cmsFloat64Number*) output;
2300        cmsLabEncoded2Float(&Lab, wOut);
2301
2302        Out[0]        = Lab.L;
2303        Out[Stride]   = Lab.a;
2304        Out[Stride*2] = Lab.b;
2305
2306        return output + sizeof(cmsFloat64Number);
2307    }
2308    else {
2309
2310        cmsLabEncoded2Float((cmsCIELab*) output, wOut);
2311        return output + (sizeof(cmsCIELab) + T_EXTRA(info ->OutputFormat) * sizeof(cmsFloat64Number));
2312    }
2313}
2314
2315
2316static
2317cmsUInt8Number* PackLabFloatFrom16(register _cmsTRANSFORM* info,
2318                                    register cmsUInt16Number wOut[],
2319                                    register cmsUInt8Number* output,
2320                                    register cmsUInt32Number Stride)
2321{
2322    cmsCIELab  Lab;
2323    cmsLabEncoded2Float(&Lab, wOut);
2324
2325    if (T_PLANAR(info -> OutputFormat)) {
2326
2327        cmsFloat32Number* Out = (cmsFloat32Number*) output;
2328
2329        Out[0]        = (cmsFloat32Number)Lab.L;
2330        Out[Stride]   = (cmsFloat32Number)Lab.a;
2331        Out[Stride*2] = (cmsFloat32Number)Lab.b;
2332
2333        return output + sizeof(cmsFloat32Number);
2334    }
2335    else {
2336
2337       ((cmsFloat32Number*) output)[0] = (cmsFloat32Number) Lab.L;
2338       ((cmsFloat32Number*) output)[1] = (cmsFloat32Number) Lab.a;
2339       ((cmsFloat32Number*) output)[2] = (cmsFloat32Number) Lab.b;
2340
2341        return output + (3 + T_EXTRA(info ->OutputFormat)) * sizeof(cmsFloat32Number);
2342    }
2343}
2344
2345static
2346cmsUInt8Number* PackXYZDoubleFrom16(register _cmsTRANSFORM* Info,
2347                                    register cmsUInt16Number wOut[],
2348                                    register cmsUInt8Number* output,
2349                                    register cmsUInt32Number Stride)
2350{
2351    if (T_PLANAR(Info -> OutputFormat)) {
2352
2353        cmsCIEXYZ XYZ;
2354        cmsFloat64Number* Out = (cmsFloat64Number*) output;
2355        cmsXYZEncoded2Float(&XYZ, wOut);
2356
2357        Out[0]        = XYZ.X;
2358        Out[Stride]   = XYZ.Y;
2359        Out[Stride*2] = XYZ.Z;
2360
2361        return output + sizeof(cmsFloat64Number);
2362
2363    }
2364    else {
2365
2366        cmsXYZEncoded2Float((cmsCIEXYZ*) output, wOut);
2367
2368        return output + (sizeof(cmsCIEXYZ) + T_EXTRA(Info ->OutputFormat) * sizeof(cmsFloat64Number));
2369    }
2370}
2371
2372static
2373cmsUInt8Number* PackXYZFloatFrom16(register _cmsTRANSFORM* Info,
2374                                   register cmsUInt16Number wOut[],
2375                                   register cmsUInt8Number* output,
2376                                   register cmsUInt32Number Stride)
2377{
2378    if (T_PLANAR(Info -> OutputFormat)) {
2379
2380        cmsCIEXYZ XYZ;
2381        cmsFloat32Number* Out = (cmsFloat32Number*) output;
2382        cmsXYZEncoded2Float(&XYZ, wOut);
2383
2384        Out[0]        = (cmsFloat32Number) XYZ.X;
2385        Out[Stride]   = (cmsFloat32Number) XYZ.Y;
2386        Out[Stride*2] = (cmsFloat32Number) XYZ.Z;
2387
2388        return output + sizeof(cmsFloat32Number);
2389
2390    }
2391    else {
2392
2393        cmsCIEXYZ XYZ;
2394        cmsFloat32Number* Out = (cmsFloat32Number*) output;
2395        cmsXYZEncoded2Float(&XYZ, wOut);
2396
2397        Out[0] = (cmsFloat32Number) XYZ.X;
2398        Out[1] = (cmsFloat32Number) XYZ.Y;
2399        Out[2] = (cmsFloat32Number) XYZ.Z;
2400
2401        return output + (3 * sizeof(cmsFloat32Number) + T_EXTRA(Info ->OutputFormat) * sizeof(cmsFloat32Number));
2402    }
2403}
2404
2405static
2406cmsUInt8Number* PackDoubleFrom16(register _cmsTRANSFORM* info,
2407                                register cmsUInt16Number wOut[],
2408                                register cmsUInt8Number* output,
2409                                register cmsUInt32Number Stride)
2410{
2411    int nChan      = T_CHANNELS(info -> OutputFormat);
2412    int DoSwap     = T_DOSWAP(info ->OutputFormat);
2413    int Reverse    = T_FLAVOR(info ->OutputFormat);
2414    int Extra      = T_EXTRA(info -> OutputFormat);
2415    int SwapFirst  = T_SWAPFIRST(info -> OutputFormat);
2416    int Planar     = T_PLANAR(info -> OutputFormat);
2417    int ExtraFirst = DoSwap ^ SwapFirst;
2418    cmsFloat64Number maximum = IsInkSpace(info ->OutputFormat) ? 655.35 : 65535.0;
2419    cmsFloat64Number v = 0;
2420    cmsFloat64Number* swap1 = (cmsFloat64Number*) output;
2421    int i, start = 0;
2422
2423    if (ExtraFirst)
2424        start = Extra;
2425
2426    for (i=0; i < nChan; i++) {
2427
2428        int index = DoSwap ? (nChan - i - 1) : i;
2429
2430        v = (cmsFloat64Number) wOut[index] / maximum;
2431
2432        if (Reverse)
2433            v = maximum - v;
2434
2435        if (Planar)
2436            ((cmsFloat64Number*) output)[(i + start)  * Stride]= v;
2437        else
2438            ((cmsFloat64Number*) output)[i + start] = v;
2439    }
2440
2441
2442    if (Extra == 0 && SwapFirst) {
2443
2444         memmove(swap1 + 1, swap1, (nChan-1)* sizeof(cmsFloat64Number));
2445        *swap1 = v;
2446    }
2447
2448    if (T_PLANAR(info -> OutputFormat))
2449        return output + sizeof(cmsFloat64Number);
2450    else
2451        return output + (nChan + Extra) * sizeof(cmsFloat64Number);
2452
2453}
2454
2455
2456static
2457cmsUInt8Number* PackFloatFrom16(register _cmsTRANSFORM* info,
2458                                register cmsUInt16Number wOut[],
2459                                register cmsUInt8Number* output,
2460                                register cmsUInt32Number Stride)
2461{
2462       int nChan = T_CHANNELS(info->OutputFormat);
2463       int DoSwap = T_DOSWAP(info->OutputFormat);
2464       int Reverse = T_FLAVOR(info->OutputFormat);
2465       int Extra = T_EXTRA(info->OutputFormat);
2466       int SwapFirst = T_SWAPFIRST(info->OutputFormat);
2467       int Planar = T_PLANAR(info->OutputFormat);
2468       int ExtraFirst = DoSwap ^ SwapFirst;
2469       cmsFloat64Number maximum = IsInkSpace(info->OutputFormat) ? 655.35 : 65535.0;
2470       cmsFloat64Number v = 0;
2471       cmsFloat32Number* swap1 = (cmsFloat32Number*)output;
2472       int i, start = 0;
2473
2474       if (ExtraFirst)
2475              start = Extra;
2476
2477       for (i = 0; i < nChan; i++) {
2478
2479              int index = DoSwap ? (nChan - i - 1) : i;
2480
2481              v = (cmsFloat64Number)wOut[index] / maximum;
2482
2483              if (Reverse)
2484                     v = maximum - v;
2485
2486              if (Planar)
2487                     ((cmsFloat32Number*)output)[(i + start) * Stride] = (cmsFloat32Number)v;
2488              else
2489                     ((cmsFloat32Number*)output)[i + start] = (cmsFloat32Number)v;
2490       }
2491
2492
2493       if (Extra == 0 && SwapFirst) {
2494
2495              memmove(swap1 + 1, swap1, (nChan - 1)* sizeof(cmsFloat32Number));
2496              *swap1 = (cmsFloat32Number)v;
2497       }
2498
2499       if (T_PLANAR(info->OutputFormat))
2500              return output + sizeof(cmsFloat32Number);
2501       else
2502              return output + (nChan + Extra) * sizeof(cmsFloat32Number);
2503}
2504
2505
2506
2507// --------------------------------------------------------------------------------------------------------
2508
2509static
2510cmsUInt8Number* PackFloatsFromFloat(_cmsTRANSFORM* info,
2511                                    cmsFloat32Number wOut[],
2512                                    cmsUInt8Number* output,
2513                                    cmsUInt32Number Stride)
2514{
2515       int nChan = T_CHANNELS(info->OutputFormat);
2516       int DoSwap = T_DOSWAP(info->OutputFormat);
2517       int Reverse = T_FLAVOR(info->OutputFormat);
2518       int Extra = T_EXTRA(info->OutputFormat);
2519       int SwapFirst = T_SWAPFIRST(info->OutputFormat);
2520       int Planar = T_PLANAR(info->OutputFormat);
2521       int ExtraFirst = DoSwap ^ SwapFirst;
2522       cmsFloat64Number maximum = IsInkSpace(info->OutputFormat) ? 100.0 : 1.0;
2523       cmsFloat32Number* swap1 = (cmsFloat32Number*)output;
2524       cmsFloat64Number v = 0;
2525       int i, start = 0;
2526
2527       if (ExtraFirst)
2528              start = Extra;
2529
2530       for (i = 0; i < nChan; i++) {
2531
2532              int index = DoSwap ? (nChan - i - 1) : i;
2533
2534              v = wOut[index] * maximum;
2535
2536              if (Reverse)
2537                     v = maximum - v;
2538
2539              if (Planar)
2540                     ((cmsFloat32Number*)output)[(i + start)* Stride] = (cmsFloat32Number)v;
2541              else
2542                     ((cmsFloat32Number*)output)[i + start] = (cmsFloat32Number)v;
2543       }
2544
2545
2546       if (Extra == 0 && SwapFirst) {
2547
2548              memmove(swap1 + 1, swap1, (nChan - 1)* sizeof(cmsFloat32Number));
2549              *swap1 = (cmsFloat32Number)v;
2550       }
2551
2552       if (T_PLANAR(info->OutputFormat))
2553              return output + sizeof(cmsFloat32Number);
2554       else
2555              return output + (nChan + Extra) * sizeof(cmsFloat32Number);
2556}
2557
2558static
2559cmsUInt8Number* PackDoublesFromFloat(_cmsTRANSFORM* info,
2560                                    cmsFloat32Number wOut[],
2561                                    cmsUInt8Number* output,
2562                                    cmsUInt32Number Stride)
2563{
2564       int nChan = T_CHANNELS(info->OutputFormat);
2565       int DoSwap = T_DOSWAP(info->OutputFormat);
2566       int Reverse = T_FLAVOR(info->OutputFormat);
2567       int Extra = T_EXTRA(info->OutputFormat);
2568       int SwapFirst = T_SWAPFIRST(info->OutputFormat);
2569       int Planar = T_PLANAR(info->OutputFormat);
2570       int ExtraFirst = DoSwap ^ SwapFirst;
2571       cmsFloat64Number maximum = IsInkSpace(info->OutputFormat) ? 100.0 : 1.0;
2572       cmsFloat64Number v = 0;
2573       cmsFloat64Number* swap1 = (cmsFloat64Number*)output;
2574       int i, start = 0;
2575
2576       if (ExtraFirst)
2577              start = Extra;
2578
2579       for (i = 0; i < nChan; i++) {
2580
2581              int index = DoSwap ? (nChan - i - 1) : i;
2582
2583              v = wOut[index] * maximum;
2584
2585              if (Reverse)
2586                     v = maximum - v;
2587
2588              if (Planar)
2589                     ((cmsFloat64Number*)output)[(i + start) * Stride] = v;
2590              else
2591                     ((cmsFloat64Number*)output)[i + start] = v;
2592       }
2593
2594       if (Extra == 0 && SwapFirst) {
2595
2596              memmove(swap1 + 1, swap1, (nChan - 1)* sizeof(cmsFloat64Number));
2597              *swap1 = v;
2598       }
2599
2600
2601       if (T_PLANAR(info->OutputFormat))
2602              return output + sizeof(cmsFloat64Number);
2603       else
2604              return output + (nChan + Extra) * sizeof(cmsFloat64Number);
2605
2606}
2607
2608
2609
2610
2611
2612static
2613cmsUInt8Number* PackLabFloatFromFloat(_cmsTRANSFORM* Info,
2614                                      cmsFloat32Number wOut[],
2615                                      cmsUInt8Number* output,
2616                                      cmsUInt32Number Stride)
2617{
2618    cmsFloat32Number* Out = (cmsFloat32Number*) output;
2619
2620    if (T_PLANAR(Info -> OutputFormat)) {
2621
2622        Out[0]        = (cmsFloat32Number) (wOut[0] * 100.0);
2623        Out[Stride]   = (cmsFloat32Number) (wOut[1] * 255.0 - 128.0);
2624        Out[Stride*2] = (cmsFloat32Number) (wOut[2] * 255.0 - 128.0);
2625
2626        return output + sizeof(cmsFloat32Number);
2627    }
2628    else {
2629
2630        Out[0] = (cmsFloat32Number) (wOut[0] * 100.0);
2631        Out[1] = (cmsFloat32Number) (wOut[1] * 255.0 - 128.0);
2632        Out[2] = (cmsFloat32Number) (wOut[2] * 255.0 - 128.0);
2633
2634        return output + (sizeof(cmsFloat32Number)*3 + T_EXTRA(Info ->OutputFormat) * sizeof(cmsFloat32Number));
2635    }
2636
2637}
2638
2639
2640static
2641cmsUInt8Number* PackLabDoubleFromFloat(_cmsTRANSFORM* Info,
2642                                       cmsFloat32Number wOut[],
2643                                       cmsUInt8Number* output,
2644                                       cmsUInt32Number Stride)
2645{
2646    cmsFloat64Number* Out = (cmsFloat64Number*) output;
2647
2648    if (T_PLANAR(Info -> OutputFormat)) {
2649
2650        Out[0]        = (cmsFloat64Number) (wOut[0] * 100.0);
2651        Out[Stride]   = (cmsFloat64Number) (wOut[1] * 255.0 - 128.0);
2652        Out[Stride*2] = (cmsFloat64Number) (wOut[2] * 255.0 - 128.0);
2653
2654        return output + sizeof(cmsFloat64Number);
2655    }
2656    else {
2657
2658        Out[0] = (cmsFloat64Number) (wOut[0] * 100.0);
2659        Out[1] = (cmsFloat64Number) (wOut[1] * 255.0 - 128.0);
2660        Out[2] = (cmsFloat64Number) (wOut[2] * 255.0 - 128.0);
2661
2662        return output + (sizeof(cmsFloat64Number)*3 + T_EXTRA(Info ->OutputFormat) * sizeof(cmsFloat64Number));
2663    }
2664
2665}
2666
2667
2668// From 0..1 range to 0..MAX_ENCODEABLE_XYZ
2669static
2670cmsUInt8Number* PackXYZFloatFromFloat(_cmsTRANSFORM* Info,
2671                                      cmsFloat32Number wOut[],
2672                                      cmsUInt8Number* output,
2673                                      cmsUInt32Number Stride)
2674{
2675    cmsFloat32Number* Out = (cmsFloat32Number*) output;
2676
2677    if (T_PLANAR(Info -> OutputFormat)) {
2678
2679        Out[0]        = (cmsFloat32Number) (wOut[0] * MAX_ENCODEABLE_XYZ);
2680        Out[Stride]   = (cmsFloat32Number) (wOut[1] * MAX_ENCODEABLE_XYZ);
2681        Out[Stride*2] = (cmsFloat32Number) (wOut[2] * MAX_ENCODEABLE_XYZ);
2682
2683        return output + sizeof(cmsFloat32Number);
2684    }
2685    else {
2686
2687        Out[0] = (cmsFloat32Number) (wOut[0] * MAX_ENCODEABLE_XYZ);
2688        Out[1] = (cmsFloat32Number) (wOut[1] * MAX_ENCODEABLE_XYZ);
2689        Out[2] = (cmsFloat32Number) (wOut[2] * MAX_ENCODEABLE_XYZ);
2690
2691        return output + (sizeof(cmsFloat32Number)*3 + T_EXTRA(Info ->OutputFormat) * sizeof(cmsFloat32Number));
2692    }
2693
2694}
2695
2696// Same, but convert to double
2697static
2698cmsUInt8Number* PackXYZDoubleFromFloat(_cmsTRANSFORM* Info,
2699                                       cmsFloat32Number wOut[],
2700                                       cmsUInt8Number* output,
2701                                       cmsUInt32Number Stride)
2702{
2703    cmsFloat64Number* Out = (cmsFloat64Number*) output;
2704
2705    if (T_PLANAR(Info -> OutputFormat)) {
2706
2707        Out[0]        = (cmsFloat64Number) (wOut[0] * MAX_ENCODEABLE_XYZ);
2708        Out[Stride]   = (cmsFloat64Number) (wOut[1] * MAX_ENCODEABLE_XYZ);
2709        Out[Stride*2] = (cmsFloat64Number) (wOut[2] * MAX_ENCODEABLE_XYZ);
2710
2711        return output + sizeof(cmsFloat64Number);
2712    }
2713    else {
2714
2715        Out[0] = (cmsFloat64Number) (wOut[0] * MAX_ENCODEABLE_XYZ);
2716        Out[1] = (cmsFloat64Number) (wOut[1] * MAX_ENCODEABLE_XYZ);
2717        Out[2] = (cmsFloat64Number) (wOut[2] * MAX_ENCODEABLE_XYZ);
2718
2719        return output + (sizeof(cmsFloat64Number)*3 + T_EXTRA(Info ->OutputFormat) * sizeof(cmsFloat64Number));
2720    }
2721
2722}
2723
2724
2725// ----------------------------------------------------------------------------------------------------------------
2726
2727#ifndef CMS_NO_HALF_SUPPORT
2728
2729// Decodes an stream of half floats to wIn[] described by input format
2730
2731static
2732cmsUInt8Number* UnrollHalfTo16(register _cmsTRANSFORM* info,
2733                                register cmsUInt16Number wIn[],
2734                                register cmsUInt8Number* accum,
2735                                register cmsUInt32Number Stride)
2736{
2737
2738    int nChan      = T_CHANNELS(info -> InputFormat);
2739    int DoSwap     = T_DOSWAP(info ->InputFormat);
2740    int Reverse    = T_FLAVOR(info ->InputFormat);
2741    int SwapFirst  = T_SWAPFIRST(info -> InputFormat);
2742    int Extra      = T_EXTRA(info -> InputFormat);
2743    int ExtraFirst = DoSwap ^ SwapFirst;
2744    int Planar     = T_PLANAR(info -> InputFormat);
2745    cmsFloat32Number v;
2746    int i, start = 0;
2747    cmsFloat32Number maximum = IsInkSpace(info ->InputFormat) ? 655.35F : 65535.0F;
2748
2749
2750    if (ExtraFirst)
2751            start = Extra;
2752
2753    for (i=0; i < nChan; i++) {
2754
2755        int index = DoSwap ? (nChan - i - 1) : i;
2756
2757        if (Planar)
2758            v = _cmsHalf2Float ( ((cmsUInt16Number*) accum)[(i + start) * Stride] );
2759        else
2760            v = _cmsHalf2Float ( ((cmsUInt16Number*) accum)[i + start] ) ;
2761
2762        if (Reverse) v = maximum - v;
2763
2764        wIn[index] = _cmsQuickSaturateWord(v * maximum);
2765    }
2766
2767
2768    if (Extra == 0 && SwapFirst) {
2769        cmsUInt16Number tmp = wIn[0];
2770
2771        memmove(&wIn[0], &wIn[1], (nChan-1) * sizeof(cmsUInt16Number));
2772        wIn[nChan-1] = tmp;
2773    }
2774
2775    if (T_PLANAR(info -> InputFormat))
2776        return accum + sizeof(cmsUInt16Number);
2777    else
2778        return accum + (nChan + Extra) * sizeof(cmsUInt16Number);
2779}
2780
2781// Decodes an stream of half floats to wIn[] described by input format
2782
2783static
2784cmsUInt8Number* UnrollHalfToFloat(_cmsTRANSFORM* info,
2785                                    cmsFloat32Number wIn[],
2786                                    cmsUInt8Number* accum,
2787                                    cmsUInt32Number Stride)
2788{
2789
2790    int nChan      = T_CHANNELS(info -> InputFormat);
2791    int DoSwap     = T_DOSWAP(info ->InputFormat);
2792    int Reverse    = T_FLAVOR(info ->InputFormat);
2793    int SwapFirst  = T_SWAPFIRST(info -> InputFormat);
2794    int Extra      = T_EXTRA(info -> InputFormat);
2795    int ExtraFirst = DoSwap ^ SwapFirst;
2796    int Planar     = T_PLANAR(info -> InputFormat);
2797    cmsFloat32Number v;
2798    int i, start = 0;
2799    cmsFloat32Number maximum = IsInkSpace(info ->InputFormat) ? 100.0F : 1.0F;
2800
2801
2802    if (ExtraFirst)
2803            start = Extra;
2804
2805    for (i=0; i < nChan; i++) {
2806
2807        int index = DoSwap ? (nChan - i - 1) : i;
2808
2809        if (Planar)
2810            v =  _cmsHalf2Float ( ((cmsUInt16Number*) accum)[(i + start) * Stride] );
2811        else
2812            v =  _cmsHalf2Float ( ((cmsUInt16Number*) accum)[i + start] ) ;
2813
2814        v /= maximum;
2815
2816        wIn[index] = Reverse ? 1 - v : v;
2817    }
2818
2819
2820    if (Extra == 0 && SwapFirst) {
2821        cmsFloat32Number tmp = wIn[0];
2822
2823        memmove(&wIn[0], &wIn[1], (nChan-1) * sizeof(cmsFloat32Number));
2824        wIn[nChan-1] = tmp;
2825    }
2826
2827    if (T_PLANAR(info -> InputFormat))
2828        return accum + sizeof(cmsUInt16Number);
2829    else
2830        return accum + (nChan + Extra) * sizeof(cmsUInt16Number);
2831}
2832
2833
2834static
2835cmsUInt8Number* PackHalfFrom16(register _cmsTRANSFORM* info,
2836                                register cmsUInt16Number wOut[],
2837                                register cmsUInt8Number* output,
2838                                register cmsUInt32Number Stride)
2839{
2840       int nChan = T_CHANNELS(info->OutputFormat);
2841       int DoSwap = T_DOSWAP(info->OutputFormat);
2842       int Reverse = T_FLAVOR(info->OutputFormat);
2843       int Extra = T_EXTRA(info->OutputFormat);
2844       int SwapFirst = T_SWAPFIRST(info->OutputFormat);
2845       int Planar = T_PLANAR(info->OutputFormat);
2846       int ExtraFirst = DoSwap ^ SwapFirst;
2847       cmsFloat32Number maximum = IsInkSpace(info->OutputFormat) ? 655.35F : 65535.0F;
2848       cmsFloat32Number v = 0;
2849       cmsUInt16Number* swap1 = (cmsUInt16Number*)output;
2850       int i, start = 0;
2851
2852       if (ExtraFirst)
2853              start = Extra;
2854
2855       for (i = 0; i < nChan; i++) {
2856
2857              int index = DoSwap ? (nChan - i - 1) : i;
2858
2859              v = (cmsFloat32Number)wOut[index] / maximum;
2860
2861              if (Reverse)
2862                     v = maximum - v;
2863
2864              if (Planar)
2865                     ((cmsUInt16Number*)output)[(i + start) * Stride] = _cmsFloat2Half(v);
2866              else
2867                     ((cmsUInt16Number*)output)[i + start] = _cmsFloat2Half(v);
2868       }
2869
2870
2871       if (Extra == 0 && SwapFirst) {
2872
2873              memmove(swap1 + 1, swap1, (nChan - 1)* sizeof(cmsUInt16Number));
2874              *swap1 = _cmsFloat2Half(v);
2875       }
2876
2877       if (T_PLANAR(info->OutputFormat))
2878              return output + sizeof(cmsUInt16Number);
2879       else
2880              return output + (nChan + Extra) * sizeof(cmsUInt16Number);
2881}
2882
2883
2884
2885static
2886cmsUInt8Number* PackHalfFromFloat(_cmsTRANSFORM* info,
2887                                    cmsFloat32Number wOut[],
2888                                    cmsUInt8Number* output,
2889                                    cmsUInt32Number Stride)
2890{
2891       int nChan = T_CHANNELS(info->OutputFormat);
2892       int DoSwap = T_DOSWAP(info->OutputFormat);
2893       int Reverse = T_FLAVOR(info->OutputFormat);
2894       int Extra = T_EXTRA(info->OutputFormat);
2895       int SwapFirst = T_SWAPFIRST(info->OutputFormat);
2896       int Planar = T_PLANAR(info->OutputFormat);
2897       int ExtraFirst = DoSwap ^ SwapFirst;
2898       cmsFloat32Number maximum = IsInkSpace(info->OutputFormat) ? 100.0F : 1.0F;
2899       cmsUInt16Number* swap1 = (cmsUInt16Number*)output;
2900       cmsFloat32Number v = 0;
2901       int i, start = 0;
2902
2903       if (ExtraFirst)
2904              start = Extra;
2905
2906       for (i = 0; i < nChan; i++) {
2907
2908              int index = DoSwap ? (nChan - i - 1) : i;
2909
2910              v = wOut[index] * maximum;
2911
2912              if (Reverse)
2913                     v = maximum - v;
2914
2915              if (Planar)
2916                     ((cmsUInt16Number*)output)[(i + start)* Stride] = _cmsFloat2Half(v);
2917              else
2918                     ((cmsUInt16Number*)output)[i + start] = _cmsFloat2Half(v);
2919       }
2920
2921
2922       if (Extra == 0 && SwapFirst) {
2923
2924              memmove(swap1 + 1, swap1, (nChan - 1)* sizeof(cmsUInt16Number));
2925              *swap1 = (cmsUInt16Number)_cmsFloat2Half(v);
2926       }
2927
2928       if (T_PLANAR(info->OutputFormat))
2929              return output + sizeof(cmsUInt16Number);
2930       else
2931              return output + (nChan + Extra)* sizeof(cmsUInt16Number);
2932}
2933
2934#endif
2935
2936// ----------------------------------------------------------------------------------------------------------------
2937
2938
2939static cmsFormatters16 InputFormatters16[] = {
2940
2941    //    Type                                          Mask                  Function
2942    //  ----------------------------   ------------------------------------  ----------------------------
2943    { TYPE_Lab_DBL,                                 ANYPLANAR|ANYEXTRA,   UnrollLabDoubleTo16},
2944    { TYPE_XYZ_DBL,                                 ANYPLANAR|ANYEXTRA,   UnrollXYZDoubleTo16},
2945    { TYPE_Lab_FLT,                                 ANYPLANAR|ANYEXTRA,   UnrollLabFloatTo16},
2946    { TYPE_XYZ_FLT,                                 ANYPLANAR|ANYEXTRA,   UnrollXYZFloatTo16},
2947    { TYPE_GRAY_DBL,                                                 0,   UnrollDouble1Chan},
2948    { FLOAT_SH(1)|BYTES_SH(0), ANYCHANNELS|ANYPLANAR|ANYSWAPFIRST|ANYFLAVOR|
2949                                             ANYSWAP|ANYEXTRA|ANYSPACE,   UnrollDoubleTo16},
2950    { FLOAT_SH(1)|BYTES_SH(4), ANYCHANNELS|ANYPLANAR|ANYSWAPFIRST|ANYFLAVOR|
2951                                             ANYSWAP|ANYEXTRA|ANYSPACE,   UnrollFloatTo16},
2952#ifndef CMS_NO_HALF_SUPPORT
2953    { FLOAT_SH(1)|BYTES_SH(2), ANYCHANNELS|ANYPLANAR|ANYSWAPFIRST|ANYFLAVOR|
2954                                            ANYEXTRA|ANYSWAP|ANYSPACE,   UnrollHalfTo16},
2955#endif
2956
2957    { CHANNELS_SH(1)|BYTES_SH(1),                              ANYSPACE,  Unroll1Byte},
2958    { CHANNELS_SH(1)|BYTES_SH(1)|EXTRA_SH(1),                  ANYSPACE,  Unroll1ByteSkip1},
2959    { CHANNELS_SH(1)|BYTES_SH(1)|EXTRA_SH(2),                  ANYSPACE,  Unroll1ByteSkip2},
2960    { CHANNELS_SH(1)|BYTES_SH(1)|FLAVOR_SH(1),                 ANYSPACE,  Unroll1ByteReversed},
2961    { COLORSPACE_SH(PT_MCH2)|CHANNELS_SH(2)|BYTES_SH(1),              0,  Unroll2Bytes},
2962
2963    { TYPE_LabV2_8,                                                   0,  UnrollLabV2_8 },
2964    { TYPE_ALabV2_8,                                                  0,  UnrollALabV2_8 },
2965    { TYPE_LabV2_16,                                                  0,  UnrollLabV2_16 },
2966
2967    { CHANNELS_SH(3)|BYTES_SH(1),                              ANYSPACE,  Unroll3Bytes},
2968    { CHANNELS_SH(3)|BYTES_SH(1)|DOSWAP_SH(1),                 ANYSPACE,  Unroll3BytesSwap},
2969    { CHANNELS_SH(3)|EXTRA_SH(1)|BYTES_SH(1)|DOSWAP_SH(1),     ANYSPACE,  Unroll3BytesSkip1Swap},
2970    { CHANNELS_SH(3)|EXTRA_SH(1)|BYTES_SH(1)|SWAPFIRST_SH(1),  ANYSPACE,  Unroll3BytesSkip1SwapFirst},
2971
2972    { CHANNELS_SH(3)|EXTRA_SH(1)|BYTES_SH(1)|DOSWAP_SH(1)|SWAPFIRST_SH(1),
2973                                                               ANYSPACE,  Unroll3BytesSkip1SwapSwapFirst},
2974
2975    { CHANNELS_SH(4)|BYTES_SH(1),                              ANYSPACE,  Unroll4Bytes},
2976    { CHANNELS_SH(4)|BYTES_SH(1)|FLAVOR_SH(1),                 ANYSPACE,  Unroll4BytesReverse},
2977    { CHANNELS_SH(4)|BYTES_SH(1)|SWAPFIRST_SH(1),              ANYSPACE,  Unroll4BytesSwapFirst},
2978    { CHANNELS_SH(4)|BYTES_SH(1)|DOSWAP_SH(1),                 ANYSPACE,  Unroll4BytesSwap},
2979    { CHANNELS_SH(4)|BYTES_SH(1)|DOSWAP_SH(1)|SWAPFIRST_SH(1), ANYSPACE,  Unroll4BytesSwapSwapFirst},
2980
2981    { BYTES_SH(1)|PLANAR_SH(1), ANYFLAVOR|ANYSWAPFIRST|
2982                                   ANYSWAP|ANYEXTRA|ANYCHANNELS|ANYSPACE, UnrollPlanarBytes},
2983
2984    { BYTES_SH(1),    ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|
2985                                           ANYEXTRA|ANYCHANNELS|ANYSPACE, UnrollChunkyBytes},
2986
2987    { CHANNELS_SH(1)|BYTES_SH(2),                              ANYSPACE,  Unroll1Word},
2988    { CHANNELS_SH(1)|BYTES_SH(2)|FLAVOR_SH(1),                 ANYSPACE,  Unroll1WordReversed},
2989    { CHANNELS_SH(1)|BYTES_SH(2)|EXTRA_SH(3),                  ANYSPACE,  Unroll1WordSkip3},
2990
2991    { CHANNELS_SH(2)|BYTES_SH(2),                              ANYSPACE,  Unroll2Words},
2992    { CHANNELS_SH(3)|BYTES_SH(2),                              ANYSPACE,  Unroll3Words},
2993    { CHANNELS_SH(4)|BYTES_SH(2),                              ANYSPACE,  Unroll4Words},
2994
2995    { CHANNELS_SH(3)|BYTES_SH(2)|DOSWAP_SH(1),                 ANYSPACE,  Unroll3WordsSwap},
2996    { CHANNELS_SH(3)|BYTES_SH(2)|EXTRA_SH(1)|SWAPFIRST_SH(1),  ANYSPACE,  Unroll3WordsSkip1SwapFirst},
2997    { CHANNELS_SH(3)|BYTES_SH(2)|EXTRA_SH(1)|DOSWAP_SH(1),     ANYSPACE,  Unroll3WordsSkip1Swap},
2998    { CHANNELS_SH(4)|BYTES_SH(2)|FLAVOR_SH(1),                 ANYSPACE,  Unroll4WordsReverse},
2999    { CHANNELS_SH(4)|BYTES_SH(2)|SWAPFIRST_SH(1),              ANYSPACE,  Unroll4WordsSwapFirst},
3000    { CHANNELS_SH(4)|BYTES_SH(2)|DOSWAP_SH(1),                 ANYSPACE,  Unroll4WordsSwap},
3001    { CHANNELS_SH(4)|BYTES_SH(2)|DOSWAP_SH(1)|SWAPFIRST_SH(1), ANYSPACE,  Unroll4WordsSwapSwapFirst},
3002
3003
3004    { BYTES_SH(2)|PLANAR_SH(1),  ANYFLAVOR|ANYSWAP|ANYENDIAN|ANYEXTRA|ANYCHANNELS|ANYSPACE,  UnrollPlanarWords},
3005    { BYTES_SH(2),  ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|ANYENDIAN|ANYEXTRA|ANYCHANNELS|ANYSPACE,  UnrollAnyWords},
3006};
3007
3008
3009
3010static cmsFormattersFloat InputFormattersFloat[] = {
3011
3012    //    Type                                          Mask                  Function
3013    //  ----------------------------   ------------------------------------  ----------------------------
3014    {     TYPE_Lab_DBL,                                ANYPLANAR|ANYEXTRA,   UnrollLabDoubleToFloat},
3015    {     TYPE_Lab_FLT,                                ANYPLANAR|ANYEXTRA,   UnrollLabFloatToFloat},
3016
3017    {     TYPE_XYZ_DBL,                                ANYPLANAR|ANYEXTRA,   UnrollXYZDoubleToFloat},
3018    {     TYPE_XYZ_FLT,                                ANYPLANAR|ANYEXTRA,   UnrollXYZFloatToFloat},
3019
3020    {     FLOAT_SH(1)|BYTES_SH(4), ANYPLANAR|ANYSWAPFIRST|ANYSWAP|ANYEXTRA|
3021                                                      ANYCHANNELS|ANYSPACE,  UnrollFloatsToFloat},
3022
3023    {     FLOAT_SH(1)|BYTES_SH(0), ANYPLANAR|ANYSWAPFIRST|ANYSWAP|ANYEXTRA|
3024                                                        ANYCHANNELS|ANYSPACE,  UnrollDoublesToFloat},
3025#ifndef CMS_NO_HALF_SUPPORT
3026    {     FLOAT_SH(1)|BYTES_SH(2), ANYPLANAR|ANYSWAPFIRST|ANYSWAP|ANYEXTRA|
3027                                                        ANYCHANNELS|ANYSPACE,  UnrollHalfToFloat},
3028#endif
3029};
3030
3031
3032// Bit fields set to one in the mask are not compared
3033static
3034cmsFormatter _cmsGetStockInputFormatter(cmsUInt32Number dwInput, cmsUInt32Number dwFlags)
3035{
3036    cmsUInt32Number i;
3037    cmsFormatter fr;
3038
3039    switch (dwFlags) {
3040
3041    case CMS_PACK_FLAGS_16BITS: {
3042        for (i=0; i < sizeof(InputFormatters16) / sizeof(cmsFormatters16); i++) {
3043            cmsFormatters16* f = InputFormatters16 + i;
3044
3045            if ((dwInput & ~f ->Mask) == f ->Type) {
3046                fr.Fmt16 = f ->Frm;
3047                return fr;
3048            }
3049        }
3050    }
3051    break;
3052
3053    case CMS_PACK_FLAGS_FLOAT: {
3054        for (i=0; i < sizeof(InputFormattersFloat) / sizeof(cmsFormattersFloat); i++) {
3055            cmsFormattersFloat* f = InputFormattersFloat + i;
3056
3057            if ((dwInput & ~f ->Mask) == f ->Type) {
3058                fr.FmtFloat = f ->Frm;
3059                return fr;
3060            }
3061        }
3062    }
3063    break;
3064
3065    default:;
3066
3067    }
3068
3069    fr.Fmt16 = NULL;
3070    return fr;
3071}
3072
3073static cmsFormatters16 OutputFormatters16[] = {
3074    //    Type                                          Mask                  Function
3075    //  ----------------------------   ------------------------------------  ----------------------------
3076
3077    { TYPE_Lab_DBL,                                      ANYPLANAR|ANYEXTRA,  PackLabDoubleFrom16},
3078    { TYPE_XYZ_DBL,                                      ANYPLANAR|ANYEXTRA,  PackXYZDoubleFrom16},
3079
3080    { TYPE_Lab_FLT,                                      ANYPLANAR|ANYEXTRA,  PackLabFloatFrom16},
3081    { TYPE_XYZ_FLT,                                      ANYPLANAR|ANYEXTRA,  PackXYZFloatFrom16},
3082
3083    { FLOAT_SH(1)|BYTES_SH(0),      ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|
3084                                    ANYCHANNELS|ANYPLANAR|ANYEXTRA|ANYSPACE,  PackDoubleFrom16},
3085    { FLOAT_SH(1)|BYTES_SH(4),      ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|
3086                                    ANYCHANNELS|ANYPLANAR|ANYEXTRA|ANYSPACE,  PackFloatFrom16},
3087#ifndef CMS_NO_HALF_SUPPORT
3088    { FLOAT_SH(1)|BYTES_SH(2),      ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|
3089                                    ANYCHANNELS|ANYPLANAR|ANYEXTRA|ANYSPACE,  PackHalfFrom16},
3090#endif
3091
3092    { CHANNELS_SH(1)|BYTES_SH(1),                                  ANYSPACE,  Pack1Byte},
3093    { CHANNELS_SH(1)|BYTES_SH(1)|EXTRA_SH(1),                      ANYSPACE,  Pack1ByteSkip1},
3094    { CHANNELS_SH(1)|BYTES_SH(1)|EXTRA_SH(1)|SWAPFIRST_SH(1),      ANYSPACE,  Pack1ByteSkip1SwapFirst},
3095
3096    { CHANNELS_SH(1)|BYTES_SH(1)|FLAVOR_SH(1),                     ANYSPACE,  Pack1ByteReversed},
3097
3098    { TYPE_LabV2_8,                                                       0,  PackLabV2_8 },
3099    { TYPE_ALabV2_8,                                                      0,  PackALabV2_8 },
3100    { TYPE_LabV2_16,                                                      0,  PackLabV2_16 },
3101
3102    { CHANNELS_SH(3)|BYTES_SH(1)|OPTIMIZED_SH(1),                  ANYSPACE,  Pack3BytesOptimized},
3103    { CHANNELS_SH(3)|BYTES_SH(1)|EXTRA_SH(1)|OPTIMIZED_SH(1),      ANYSPACE,  Pack3BytesAndSkip1Optimized},
3104    { CHANNELS_SH(3)|BYTES_SH(1)|EXTRA_SH(1)|SWAPFIRST_SH(1)|OPTIMIZED_SH(1),
3105                                                                   ANYSPACE,  Pack3BytesAndSkip1SwapFirstOptimized},
3106    { CHANNELS_SH(3)|BYTES_SH(1)|EXTRA_SH(1)|DOSWAP_SH(1)|SWAPFIRST_SH(1)|OPTIMIZED_SH(1),
3107                                                                   ANYSPACE,  Pack3BytesAndSkip1SwapSwapFirstOptimized},
3108    { CHANNELS_SH(3)|BYTES_SH(1)|DOSWAP_SH(1)|EXTRA_SH(1)|OPTIMIZED_SH(1),
3109                                                                   ANYSPACE,  Pack3BytesAndSkip1SwapOptimized},
3110    { CHANNELS_SH(3)|BYTES_SH(1)|DOSWAP_SH(1)|OPTIMIZED_SH(1),     ANYSPACE,  Pack3BytesSwapOptimized},
3111
3112
3113
3114    { CHANNELS_SH(3)|BYTES_SH(1),                                  ANYSPACE,  Pack3Bytes},
3115    { CHANNELS_SH(3)|BYTES_SH(1)|EXTRA_SH(1),                      ANYSPACE,  Pack3BytesAndSkip1},
3116    { CHANNELS_SH(3)|BYTES_SH(1)|EXTRA_SH(1)|SWAPFIRST_SH(1),      ANYSPACE,  Pack3BytesAndSkip1SwapFirst},
3117    { CHANNELS_SH(3)|BYTES_SH(1)|EXTRA_SH(1)|DOSWAP_SH(1)|SWAPFIRST_SH(1),
3118                                                                   ANYSPACE,  Pack3BytesAndSkip1SwapSwapFirst},
3119    { CHANNELS_SH(3)|BYTES_SH(1)|DOSWAP_SH(1)|EXTRA_SH(1),         ANYSPACE,  Pack3BytesAndSkip1Swap},
3120    { CHANNELS_SH(3)|BYTES_SH(1)|DOSWAP_SH(1),                     ANYSPACE,  Pack3BytesSwap},
3121    { CHANNELS_SH(6)|BYTES_SH(1),                                  ANYSPACE,  Pack6Bytes},
3122    { CHANNELS_SH(6)|BYTES_SH(1)|DOSWAP_SH(1),                     ANYSPACE,  Pack6BytesSwap},
3123    { CHANNELS_SH(4)|BYTES_SH(1),                                  ANYSPACE,  Pack4Bytes},
3124    { CHANNELS_SH(4)|BYTES_SH(1)|FLAVOR_SH(1),                     ANYSPACE,  Pack4BytesReverse},
3125    { CHANNELS_SH(4)|BYTES_SH(1)|SWAPFIRST_SH(1),                  ANYSPACE,  Pack4BytesSwapFirst},
3126    { CHANNELS_SH(4)|BYTES_SH(1)|DOSWAP_SH(1),                     ANYSPACE,  Pack4BytesSwap},
3127    { CHANNELS_SH(4)|BYTES_SH(1)|DOSWAP_SH(1)|SWAPFIRST_SH(1),     ANYSPACE,  Pack4BytesSwapSwapFirst},
3128
3129    { BYTES_SH(1),                 ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|ANYEXTRA|ANYCHANNELS|ANYSPACE, PackAnyBytes},
3130    { BYTES_SH(1)|PLANAR_SH(1),    ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|ANYEXTRA|ANYCHANNELS|ANYSPACE, PackPlanarBytes},
3131
3132    { CHANNELS_SH(1)|BYTES_SH(2),                                  ANYSPACE,  Pack1Word},
3133    { CHANNELS_SH(1)|BYTES_SH(2)|EXTRA_SH(1),                      ANYSPACE,  Pack1WordSkip1},
3134    { CHANNELS_SH(1)|BYTES_SH(2)|EXTRA_SH(1)|SWAPFIRST_SH(1),      ANYSPACE,  Pack1WordSkip1SwapFirst},
3135    { CHANNELS_SH(1)|BYTES_SH(2)|FLAVOR_SH(1),                     ANYSPACE,  Pack1WordReversed},
3136    { CHANNELS_SH(1)|BYTES_SH(2)|ENDIAN16_SH(1),                   ANYSPACE,  Pack1WordBigEndian},
3137    { CHANNELS_SH(3)|BYTES_SH(2),                                  ANYSPACE,  Pack3Words},
3138    { CHANNELS_SH(3)|BYTES_SH(2)|DOSWAP_SH(1),                     ANYSPACE,  Pack3WordsSwap},
3139    { CHANNELS_SH(3)|BYTES_SH(2)|ENDIAN16_SH(1),                   ANYSPACE,  Pack3WordsBigEndian},
3140    { CHANNELS_SH(3)|BYTES_SH(2)|EXTRA_SH(1),                      ANYSPACE,  Pack3WordsAndSkip1},
3141    { CHANNELS_SH(3)|BYTES_SH(2)|EXTRA_SH(1)|DOSWAP_SH(1),         ANYSPACE,  Pack3WordsAndSkip1Swap},
3142    { CHANNELS_SH(3)|BYTES_SH(2)|EXTRA_SH(1)|SWAPFIRST_SH(1),      ANYSPACE,  Pack3WordsAndSkip1SwapFirst},
3143
3144    { CHANNELS_SH(3)|BYTES_SH(2)|EXTRA_SH(1)|DOSWAP_SH(1)|SWAPFIRST_SH(1),
3145                                                                   ANYSPACE,  Pack3WordsAndSkip1SwapSwapFirst},
3146
3147    { CHANNELS_SH(4)|BYTES_SH(2),                                  ANYSPACE,  Pack4Words},
3148    { CHANNELS_SH(4)|BYTES_SH(2)|FLAVOR_SH(1),                     ANYSPACE,  Pack4WordsReverse},
3149    { CHANNELS_SH(4)|BYTES_SH(2)|DOSWAP_SH(1),                     ANYSPACE,  Pack4WordsSwap},
3150    { CHANNELS_SH(4)|BYTES_SH(2)|ENDIAN16_SH(1),                   ANYSPACE,  Pack4WordsBigEndian},
3151
3152    { CHANNELS_SH(6)|BYTES_SH(2),                                  ANYSPACE,  Pack6Words},
3153    { CHANNELS_SH(6)|BYTES_SH(2)|DOSWAP_SH(1),                     ANYSPACE,  Pack6WordsSwap},
3154
3155    { BYTES_SH(2)|PLANAR_SH(1),     ANYFLAVOR|ANYENDIAN|ANYSWAP|ANYEXTRA|ANYCHANNELS|ANYSPACE, PackPlanarWords},
3156    { BYTES_SH(2),                  ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|ANYENDIAN|ANYEXTRA|ANYCHANNELS|ANYSPACE, PackAnyWords}
3157
3158};
3159
3160
3161static cmsFormattersFloat OutputFormattersFloat[] = {
3162    //    Type                                          Mask                                 Function
3163    //  ----------------------------   ---------------------------------------------------  ----------------------------
3164    {     TYPE_Lab_FLT,                                                ANYPLANAR|ANYEXTRA,   PackLabFloatFromFloat},
3165    {     TYPE_XYZ_FLT,                                                ANYPLANAR|ANYEXTRA,   PackXYZFloatFromFloat},
3166
3167    {     TYPE_Lab_DBL,                                                ANYPLANAR|ANYEXTRA,   PackLabDoubleFromFloat},
3168    {     TYPE_XYZ_DBL,                                                ANYPLANAR|ANYEXTRA,   PackXYZDoubleFromFloat},
3169
3170    {     FLOAT_SH(1)|BYTES_SH(4), ANYPLANAR|
3171                             ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|ANYEXTRA|ANYCHANNELS|ANYSPACE,   PackFloatsFromFloat },
3172    {     FLOAT_SH(1)|BYTES_SH(0), ANYPLANAR|
3173                             ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|ANYEXTRA|ANYCHANNELS|ANYSPACE,   PackDoublesFromFloat },
3174#ifndef CMS_NO_HALF_SUPPORT
3175    {     FLOAT_SH(1)|BYTES_SH(2),
3176                             ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|ANYEXTRA|ANYCHANNELS|ANYSPACE,   PackHalfFromFloat },
3177#endif
3178
3179
3180
3181};
3182
3183
3184// Bit fields set to one in the mask are not compared
3185static
3186cmsFormatter _cmsGetStockOutputFormatter(cmsUInt32Number dwInput, cmsUInt32Number dwFlags)
3187{
3188    cmsUInt32Number i;
3189    cmsFormatter fr;
3190
3191    // Optimization is only a hint
3192    dwInput &= ~OPTIMIZED_SH(1);
3193
3194    switch (dwFlags)
3195    {
3196
3197     case CMS_PACK_FLAGS_16BITS: {
3198
3199        for (i=0; i < sizeof(OutputFormatters16) / sizeof(cmsFormatters16); i++) {
3200            cmsFormatters16* f = OutputFormatters16 + i;
3201
3202            if ((dwInput & ~f ->Mask) == f ->Type) {
3203                fr.Fmt16 = f ->Frm;
3204                return fr;
3205            }
3206        }
3207        }
3208        break;
3209
3210    case CMS_PACK_FLAGS_FLOAT: {
3211
3212        for (i=0; i < sizeof(OutputFormattersFloat) / sizeof(cmsFormattersFloat); i++) {
3213            cmsFormattersFloat* f = OutputFormattersFloat + i;
3214
3215            if ((dwInput & ~f ->Mask) == f ->Type) {
3216                fr.FmtFloat = f ->Frm;
3217                return fr;
3218            }
3219        }
3220        }
3221        break;
3222
3223    default:;
3224
3225    }
3226
3227    fr.Fmt16 = NULL;
3228    return fr;
3229}
3230
3231
3232typedef struct _cms_formatters_factory_list {
3233
3234    cmsFormatterFactory Factory;
3235    struct _cms_formatters_factory_list *Next;
3236
3237} cmsFormattersFactoryList;
3238
3239_cmsFormattersPluginChunkType _cmsFormattersPluginChunk = { NULL };
3240
3241
3242// Duplicates the zone of memory used by the plug-in in the new context
3243static
3244void DupFormatterFactoryList(struct _cmsContext_struct* ctx,
3245                                               const struct _cmsContext_struct* src)
3246{
3247   _cmsFormattersPluginChunkType newHead = { NULL };
3248   cmsFormattersFactoryList*  entry;
3249   cmsFormattersFactoryList*  Anterior = NULL;
3250   _cmsFormattersPluginChunkType* head = (_cmsFormattersPluginChunkType*) src->chunks[FormattersPlugin];
3251
3252     _cmsAssert(head != NULL);
3253
3254   // Walk the list copying all nodes
3255   for (entry = head->FactoryList;
3256       entry != NULL;
3257       entry = entry ->Next) {
3258
3259           cmsFormattersFactoryList *newEntry = ( cmsFormattersFactoryList *) _cmsSubAllocDup(ctx ->MemPool, entry, sizeof(cmsFormattersFactoryList));
3260
3261           if (newEntry == NULL)
3262               return;
3263
3264           // We want to keep the linked list order, so this is a little bit tricky
3265           newEntry -> Next = NULL;
3266           if (Anterior)
3267               Anterior -> Next = newEntry;
3268
3269           Anterior = newEntry;
3270
3271           if (newHead.FactoryList == NULL)
3272               newHead.FactoryList = newEntry;
3273   }
3274
3275   ctx ->chunks[FormattersPlugin] = _cmsSubAllocDup(ctx->MemPool, &newHead, sizeof(_cmsFormattersPluginChunkType));
3276}
3277
3278// The interpolation plug-in memory chunk allocator/dup
3279void _cmsAllocFormattersPluginChunk(struct _cmsContext_struct* ctx,
3280                                    const struct _cmsContext_struct* src)
3281{
3282      _cmsAssert(ctx != NULL);
3283
3284     if (src != NULL) {
3285
3286         // Duplicate the LIST
3287         DupFormatterFactoryList(ctx, src);
3288     }
3289     else {
3290          static _cmsFormattersPluginChunkType FormattersPluginChunk = { NULL };
3291          ctx ->chunks[FormattersPlugin] = _cmsSubAllocDup(ctx ->MemPool, &FormattersPluginChunk, sizeof(_cmsFormattersPluginChunkType));
3292     }
3293}
3294
3295
3296
3297// Formatters management
3298cmsBool  _cmsRegisterFormattersPlugin(cmsContext ContextID, cmsPluginBase* Data)
3299{
3300    _cmsFormattersPluginChunkType* ctx = ( _cmsFormattersPluginChunkType*) _cmsContextGetClientChunk(ContextID, FormattersPlugin);
3301    cmsPluginFormatters* Plugin = (cmsPluginFormatters*) Data;
3302    cmsFormattersFactoryList* fl ;
3303
3304    // Reset to built-in defaults
3305    if (Data == NULL) {
3306
3307          ctx ->FactoryList = NULL;
3308          return TRUE;
3309    }
3310
3311    fl = (cmsFormattersFactoryList*) _cmsPluginMalloc(ContextID, sizeof(cmsFormattersFactoryList));
3312    if (fl == NULL) return FALSE;
3313
3314    fl ->Factory    = Plugin ->FormattersFactory;
3315
3316    fl ->Next = ctx -> FactoryList;
3317    ctx ->FactoryList = fl;
3318
3319    return TRUE;
3320}
3321
3322cmsFormatter _cmsGetFormatter(cmsContext ContextID,
3323                             cmsUInt32Number Type,         // Specific type, i.e. TYPE_RGB_8
3324                             cmsFormatterDirection Dir,
3325                             cmsUInt32Number dwFlags)
3326{
3327    _cmsFormattersPluginChunkType* ctx = ( _cmsFormattersPluginChunkType*) _cmsContextGetClientChunk(ContextID, FormattersPlugin);
3328    cmsFormattersFactoryList* f;
3329
3330    for (f =ctx->FactoryList; f != NULL; f = f ->Next) {
3331
3332        cmsFormatter fn = f ->Factory(Type, Dir, dwFlags);
3333        if (fn.Fmt16 != NULL) return fn;
3334    }
3335
3336    // Revert to default
3337    if (Dir == cmsFormatterInput)
3338        return _cmsGetStockInputFormatter(Type, dwFlags);
3339    else
3340        return _cmsGetStockOutputFormatter(Type, dwFlags);
3341}
3342
3343
3344// Return whatever given formatter refers to float values
3345cmsBool  _cmsFormatterIsFloat(cmsUInt32Number Type)
3346{
3347    return T_FLOAT(Type) ? TRUE : FALSE;
3348}
3349
3350// Return whatever given formatter refers to 8 bits
3351cmsBool  _cmsFormatterIs8bit(cmsUInt32Number Type)
3352{
3353    int Bytes = T_BYTES(Type);
3354
3355    return (Bytes == 1);
3356}
3357
3358// Build a suitable formatter for the colorspace of this profile
3359cmsUInt32Number CMSEXPORT cmsFormatterForColorspaceOfProfile(cmsHPROFILE hProfile, cmsUInt32Number nBytes, cmsBool lIsFloat)
3360{
3361
3362    cmsColorSpaceSignature ColorSpace      = cmsGetColorSpace(hProfile);
3363    cmsUInt32Number        ColorSpaceBits  = _cmsLCMScolorSpace(ColorSpace);
3364    cmsUInt32Number        nOutputChans    = cmsChannelsOf(ColorSpace);
3365    cmsUInt32Number        Float           = lIsFloat ? 1 : 0;
3366
3367    // Create a fake formatter for result
3368    return FLOAT_SH(Float) | COLORSPACE_SH(ColorSpaceBits) | BYTES_SH(nBytes) | CHANNELS_SH(nOutputChans);
3369}
3370
3371// Build a suitable formatter for the colorspace of this profile
3372cmsUInt32Number CMSEXPORT cmsFormatterForPCSOfProfile(cmsHPROFILE hProfile, cmsUInt32Number nBytes, cmsBool lIsFloat)
3373{
3374
3375    cmsColorSpaceSignature ColorSpace      = cmsGetPCS(hProfile);
3376    int                    ColorSpaceBits  = _cmsLCMScolorSpace(ColorSpace);
3377    cmsUInt32Number        nOutputChans    = cmsChannelsOf(ColorSpace);
3378    cmsUInt32Number        Float           = lIsFloat ? 1 : 0;
3379
3380    // Create a fake formatter for result
3381    return FLOAT_SH(Float) | COLORSPACE_SH(ColorSpaceBits) | BYTES_SH(nBytes) | CHANNELS_SH(nOutputChans);
3382}
3383
3384