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