Tizen 2.0 Release
[external/lcms.git] / src / cmspack.c
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
27 #include "lcms2_internal.h"
28
29 // This module handles all formats supported by lcms. There are two flavors, 16 bits and 
30 // floating point. Floating point is supported only in a subset, those formats holding
31 // cmsFloat32Number (4 bytes per component) and double (marked as 0 bytes per component as special 
32 // case)
33
34 // ---------------------------------------------------------------------------
35
36
37 // This macro return words stored as big endian
38 #define CHANGE_ENDIAN(w)    (cmsUInt16Number) ((cmsUInt16Number) ((w)<<8)|((w)>>8))
39
40 // These macros handles reversing (negative)
41 #define REVERSE_FLAVOR_8(x)     ((cmsUInt8Number) (0xff-(x)))
42 #define REVERSE_FLAVOR_16(x)    ((cmsUInt16Number)(0xffff-(x)))
43
44 // * 0xffff / 0xff00 = (255 * 257) / (255 * 256) = 257 / 256
45 cmsINLINE cmsUInt16Number FomLabV2ToLabV4(cmsUInt16Number x) 
46 {
47     int a;
48
49     a = (x << 8 | x) >> 8;  // * 257 / 256
50     if ( a > 0xffff) return 0xffff;
51     return (cmsUInt16Number) a;
52 }
53
54 // * 0xf00 / 0xffff = * 256 / 257
55 cmsINLINE cmsUInt16Number FomLabV4ToLabV2(cmsUInt16Number x) 
56 {
57     return (cmsUInt16Number) (((x << 8) + 0x80) / 257);
58 }
59
60
61 typedef struct {
62     cmsUInt32Number Type;
63     cmsUInt32Number Mask;
64     cmsFormatter16 Frm;
65
66 } cmsFormatters16;
67
68 typedef struct {
69     cmsUInt32Number    Type;
70     cmsUInt32Number    Mask;
71     cmsFormatterFloat Frm;
72
73 } cmsFormattersFloat;
74
75 #define ANYSPACE        COLORSPACE_SH(31)
76 #define ANYCHANNELS     CHANNELS_SH(15)
77 #define ANYEXTRA        EXTRA_SH(7)
78 #define ANYPLANAR       PLANAR_SH(1)
79 #define ANYENDIAN       ENDIAN16_SH(1)
80 #define ANYSWAP         DOSWAP_SH(1)
81 #define ANYSWAPFIRST    SWAPFIRST_SH(1) 
82 #define ANYFLAVOR       FLAVOR_SH(1)
83
84
85 // Supress waning about info never being used
86
87 #ifdef _MSC_VER
88 #pragma warning(disable : 4100)
89 #endif
90
91 // Unpacking routines (16 bits) ---------------------------------------------------------------------------------------- 
92
93 // Does almost everything but is slow
94 static
95 cmsUInt8Number* UnrollChunkyBytes(register _cmsTRANSFORM* info, 
96                                   register cmsUInt16Number wIn[], 
97                                   register cmsUInt8Number* accum,
98                                   register cmsUInt32Number Stride)
99 {
100     int nChan      = T_CHANNELS(info -> InputFormat);
101     int DoSwap     = T_DOSWAP(info ->InputFormat);
102     int Reverse    = T_FLAVOR(info ->InputFormat);
103     int SwapFirst  = T_SWAPFIRST(info -> InputFormat);
104     int Extra      = T_EXTRA(info -> InputFormat);
105     int ExtraFirst = DoSwap && !SwapFirst;
106     cmsUInt16Number v;
107     int i;
108
109     if (ExtraFirst) {
110         accum += Extra;
111     }
112
113     for (i=0; i < nChan; i++) {
114         int index = DoSwap ? (nChan - i - 1) : i;
115
116         v = FROM_8_TO_16(*accum); 
117         v = Reverse ? REVERSE_FLAVOR_16(v) : v;
118         wIn[index] = v;
119         accum++;              
120     }
121
122     if (!ExtraFirst) {
123         accum += Extra;
124     }
125
126     if (Extra == 0 && SwapFirst) {
127         cmsUInt16Number tmp = wIn[0];
128
129         memmove(&wIn[0], &wIn[1], (nChan-1) * sizeof(cmsUInt16Number));
130         wIn[nChan-1] = tmp;
131     }
132
133     return accum;
134
135     cmsUNUSED_PARAMETER(info);
136     cmsUNUSED_PARAMETER(Stride);
137
138 }
139
140 // Extra channels are just ignored because come in the next planes
141 static
142 cmsUInt8Number* UnrollPlanarBytes(register _cmsTRANSFORM* info, 
143                                   register cmsUInt16Number wIn[], 
144                                   register cmsUInt8Number* accum,
145                                   register cmsUInt32Number Stride)
146 {
147     int nChan = T_CHANNELS(info -> InputFormat);
148     int DoSwap= T_DOSWAP(info ->InputFormat);
149     int Reverse= T_FLAVOR(info ->InputFormat);
150     int i;
151     cmsUInt8Number* Init = accum;
152
153     if (DoSwap) {
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
170 static
171 cmsUInt8Number* 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
187 static
188 cmsUInt8Number* 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
204 static
205 cmsUInt8Number* 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
222 static
223 cmsUInt8Number* 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
239 static
240 cmsUInt8Number* 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
256 static
257 cmsUInt8Number* 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
272 static
273 cmsUInt8Number* 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
289 static
290 cmsUInt8Number* Unroll3BytesSkip1SwapFirst(register _cmsTRANSFORM* info, 
291                                            register cmsUInt16Number wIn[], 
292                                            register cmsUInt8Number* accum,
293                                            register cmsUInt32Number Stride)
294 {
295     accum++; // A
296     wIn[0] = FROM_8_TO_16(*accum); accum++; // R
297     wIn[1] = FROM_8_TO_16(*accum); accum++; // G
298     wIn[2] = FROM_8_TO_16(*accum); accum++; // B
299
300     return accum;
301
302     cmsUNUSED_PARAMETER(info);
303     cmsUNUSED_PARAMETER(Stride);
304 }
305
306
307 // BRG
308 static
309 cmsUInt8Number* Unroll3BytesSwap(register _cmsTRANSFORM* info, 
310                                  register cmsUInt16Number wIn[], 
311                                  register cmsUInt8Number* accum,
312                                  register cmsUInt32Number Stride)
313 {
314     wIn[2] = FROM_8_TO_16(*accum); accum++;     // B
315     wIn[1] = FROM_8_TO_16(*accum); accum++;     // G
316     wIn[0] = FROM_8_TO_16(*accum); accum++;     // R
317
318     return accum;
319
320     cmsUNUSED_PARAMETER(info);
321     cmsUNUSED_PARAMETER(Stride);
322 }
323
324 static
325 cmsUInt8Number* UnrollLabV2_8(register _cmsTRANSFORM* info, 
326                               register cmsUInt16Number wIn[], 
327                               register cmsUInt8Number* accum,
328                               register cmsUInt32Number Stride)
329 {
330     wIn[0] = FomLabV2ToLabV4(FROM_8_TO_16(*accum)); accum++;     // L
331     wIn[1] = FomLabV2ToLabV4(FROM_8_TO_16(*accum)); accum++;     // a
332     wIn[2] = FomLabV2ToLabV4(FROM_8_TO_16(*accum)); accum++;     // b
333
334     return accum;
335
336     cmsUNUSED_PARAMETER(info);
337     cmsUNUSED_PARAMETER(Stride);
338 }
339
340 static
341 cmsUInt8Number* UnrollALabV2_8(register _cmsTRANSFORM* info, 
342                                register cmsUInt16Number wIn[], 
343                                register cmsUInt8Number* accum,
344                                register cmsUInt32Number Stride)
345 {
346     accum++;  // A
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
357 static
358 cmsUInt8Number* UnrollLabV2_16(register _cmsTRANSFORM* info, 
359                                register cmsUInt16Number wIn[], 
360                                register cmsUInt8Number* accum,
361                                register cmsUInt32Number Stride)
362 {
363     wIn[0] = FomLabV2ToLabV4(*(cmsUInt16Number*) accum); accum += 2;     // L
364     wIn[1] = FomLabV2ToLabV4(*(cmsUInt16Number*) accum); accum += 2;     // a
365     wIn[2] = FomLabV2ToLabV4(*(cmsUInt16Number*) accum); accum += 2;     // b
366
367     return accum;
368
369     cmsUNUSED_PARAMETER(info);
370     cmsUNUSED_PARAMETER(Stride);
371 }
372
373 // for duplex
374 static
375 cmsUInt8Number* Unroll2Bytes(register _cmsTRANSFORM* info, 
376                                      register cmsUInt16Number wIn[], 
377                                      register cmsUInt8Number* accum,
378                                      register cmsUInt32Number Stride)
379 {
380     wIn[0] = FROM_8_TO_16(*accum); accum++;     // ch1
381     wIn[1] = FROM_8_TO_16(*accum); accum++;     // ch2
382
383     return accum;
384
385     cmsUNUSED_PARAMETER(info);
386     cmsUNUSED_PARAMETER(Stride);
387 }
388
389
390
391
392 // Monochrome duplicates L into RGB for null-transforms
393 static
394 cmsUInt8Number* Unroll1Byte(register _cmsTRANSFORM* info, 
395                             register cmsUInt16Number wIn[], 
396                             register cmsUInt8Number* accum,
397                             register cmsUInt32Number Stride)
398 {
399     wIn[0] = wIn[1] = wIn[2] = FROM_8_TO_16(*accum); accum++;     // L
400
401     return accum;
402
403     cmsUNUSED_PARAMETER(info);
404     cmsUNUSED_PARAMETER(Stride);
405 }
406
407
408 static
409 cmsUInt8Number* Unroll1ByteSkip1(register _cmsTRANSFORM* info, 
410                                  register cmsUInt16Number wIn[], 
411                                  register cmsUInt8Number* accum,
412                                  register cmsUInt32Number Stride)
413 {
414     wIn[0] = wIn[1] = wIn[2] = FROM_8_TO_16(*accum); accum++;     // L
415     accum += 1;
416
417     return accum;
418
419     cmsUNUSED_PARAMETER(info);
420     cmsUNUSED_PARAMETER(Stride);
421 }
422
423 static
424 cmsUInt8Number* Unroll1ByteSkip2(register _cmsTRANSFORM* info, 
425                                  register cmsUInt16Number wIn[], 
426                                  register cmsUInt8Number* accum,
427                                  register cmsUInt32Number Stride)
428 {
429     wIn[0] = wIn[1] = wIn[2] = FROM_8_TO_16(*accum); accum++;     // L
430     accum += 2;
431
432     return accum;
433
434     cmsUNUSED_PARAMETER(info);
435     cmsUNUSED_PARAMETER(Stride);
436 }
437
438 static
439 cmsUInt8Number* Unroll1ByteReversed(register _cmsTRANSFORM* info, 
440                                     register cmsUInt16Number wIn[], 
441                                     register cmsUInt8Number* accum,
442                                     register cmsUInt32Number Stride)
443 {
444     wIn[0] = wIn[1] = wIn[2] = REVERSE_FLAVOR_16(FROM_8_TO_16(*accum)); accum++;     // L
445
446     return accum;
447
448     cmsUNUSED_PARAMETER(info);
449     cmsUNUSED_PARAMETER(Stride);
450 }
451
452
453 static
454 cmsUInt8Number* UnrollAnyWords(register _cmsTRANSFORM* info, 
455                                register cmsUInt16Number wIn[], 
456                                register cmsUInt8Number* accum,
457                                register cmsUInt32Number Stride)
458 {
459     int nChan       = T_CHANNELS(info -> InputFormat);
460     int SwapEndian  = T_ENDIAN16(info -> InputFormat);
461     int DoSwap      = T_DOSWAP(info ->InputFormat);
462     int Reverse     = T_FLAVOR(info ->InputFormat);
463     int SwapFirst   = T_SWAPFIRST(info -> InputFormat);
464     int Extra       = T_EXTRA(info -> InputFormat);
465     int ExtraFirst  = DoSwap && !SwapFirst;
466     int i;
467
468     if (ExtraFirst) {
469         accum += Extra * sizeof(cmsUInt16Number);
470     }
471
472     for (i=0; i < nChan; i++) {
473
474         int index = DoSwap ? (nChan - i - 1) : i;
475         cmsUInt16Number v = *(cmsUInt16Number*) accum; 
476
477         if (SwapEndian)
478             v = CHANGE_ENDIAN(v);
479
480         wIn[index] = Reverse ? REVERSE_FLAVOR_16(v) : v;
481
482         accum += sizeof(cmsUInt16Number);              
483     }
484
485     if (!ExtraFirst) {
486         accum += Extra * sizeof(cmsUInt16Number);
487     }
488
489     if (Extra == 0 && SwapFirst) {
490
491         cmsUInt16Number tmp = wIn[0];
492
493         memmove(&wIn[0], &wIn[1], (nChan-1) * sizeof(cmsUInt16Number));
494         wIn[nChan-1] = tmp;
495     }
496
497     return accum;
498
499     cmsUNUSED_PARAMETER(Stride);
500 }
501
502 static
503 cmsUInt8Number* UnrollPlanarWords(register _cmsTRANSFORM* info, 
504                                   register cmsUInt16Number wIn[], 
505                                   register cmsUInt8Number* accum,
506                                   register cmsUInt32Number Stride)
507 {
508     int nChan = T_CHANNELS(info -> InputFormat);
509     int DoSwap= T_DOSWAP(info ->InputFormat);
510     int Reverse= T_FLAVOR(info ->InputFormat);
511     int SwapEndian = T_ENDIAN16(info -> InputFormat);
512     int i;
513     cmsUInt8Number* Init = accum;
514
515     if (DoSwap) {
516         accum += T_EXTRA(info -> InputFormat) * Stride * sizeof(cmsUInt16Number);
517     }
518
519     for (i=0; i < nChan; i++) {
520
521         int index = DoSwap ? (nChan - i - 1) : i;
522         cmsUInt16Number v = *(cmsUInt16Number*) accum; 
523
524         if (SwapEndian)
525             v = CHANGE_ENDIAN(v);
526
527         wIn[index] = Reverse ? REVERSE_FLAVOR_16(v) : v;
528
529         accum +=  Stride * sizeof(cmsUInt16Number);           
530     }
531
532     return (Init + sizeof(cmsUInt16Number));
533 }
534
535
536 static
537 cmsUInt8Number* Unroll4Words(register _cmsTRANSFORM* info, 
538                              register cmsUInt16Number wIn[], 
539                              register cmsUInt8Number* accum,
540                              register cmsUInt32Number Stride)
541 {
542     wIn[0] = *(cmsUInt16Number*) accum; accum+= 2; // C
543     wIn[1] = *(cmsUInt16Number*) accum; accum+= 2; // M
544     wIn[2] = *(cmsUInt16Number*) accum; accum+= 2; // Y
545     wIn[3] = *(cmsUInt16Number*) accum; accum+= 2; // K
546
547     return accum;
548
549     cmsUNUSED_PARAMETER(info);
550     cmsUNUSED_PARAMETER(Stride);
551 }
552
553 static
554 cmsUInt8Number* Unroll4WordsReverse(register _cmsTRANSFORM* info, 
555                                     register cmsUInt16Number wIn[], 
556                                     register cmsUInt8Number* accum,
557                                     register cmsUInt32Number Stride)
558 {
559     wIn[0] = REVERSE_FLAVOR_16(*(cmsUInt16Number*) accum); accum+= 2; // C
560     wIn[1] = REVERSE_FLAVOR_16(*(cmsUInt16Number*) accum); accum+= 2; // M
561     wIn[2] = REVERSE_FLAVOR_16(*(cmsUInt16Number*) accum); accum+= 2; // Y
562     wIn[3] = REVERSE_FLAVOR_16(*(cmsUInt16Number*) accum); accum+= 2; // K
563
564     return accum;
565
566     cmsUNUSED_PARAMETER(info);
567     cmsUNUSED_PARAMETER(Stride);
568 }
569
570 static
571 cmsUInt8Number* Unroll4WordsSwapFirst(register _cmsTRANSFORM* info, 
572                                       register cmsUInt16Number wIn[], 
573                                       register cmsUInt8Number* accum,
574                                       register cmsUInt32Number Stride)
575 {
576     wIn[3] = *(cmsUInt16Number*) accum; accum+= 2; // K
577     wIn[0] = *(cmsUInt16Number*) accum; accum+= 2; // C
578     wIn[1] = *(cmsUInt16Number*) accum; accum+= 2; // M
579     wIn[2] = *(cmsUInt16Number*) accum; accum+= 2; // Y
580
581     return accum;
582
583     cmsUNUSED_PARAMETER(info);
584     cmsUNUSED_PARAMETER(Stride);
585 }
586
587 // KYMC
588 static
589 cmsUInt8Number* Unroll4WordsSwap(register _cmsTRANSFORM* info, 
590                                  register cmsUInt16Number wIn[], 
591                                  register cmsUInt8Number* accum,
592                                  register cmsUInt32Number Stride)
593 {
594     wIn[3] = *(cmsUInt16Number*) accum; accum+= 2; // K
595     wIn[2] = *(cmsUInt16Number*) accum; accum+= 2; // Y
596     wIn[1] = *(cmsUInt16Number*) accum; accum+= 2; // M
597     wIn[0] = *(cmsUInt16Number*) accum; accum+= 2; // C
598
599     return accum;
600
601     cmsUNUSED_PARAMETER(info);
602     cmsUNUSED_PARAMETER(Stride);
603 }
604
605 static
606 cmsUInt8Number* Unroll4WordsSwapSwapFirst(register _cmsTRANSFORM* info, 
607                                           register cmsUInt16Number wIn[], 
608                                           register cmsUInt8Number* accum,
609                                           register cmsUInt32Number Stride)
610 {
611     wIn[2] = *(cmsUInt16Number*) accum; accum+= 2; // K
612     wIn[1] = *(cmsUInt16Number*) accum; accum+= 2; // Y
613     wIn[0] = *(cmsUInt16Number*) accum; accum+= 2; // M
614     wIn[3] = *(cmsUInt16Number*) accum; accum+= 2; // C
615
616     return accum;
617
618     cmsUNUSED_PARAMETER(info);
619     cmsUNUSED_PARAMETER(Stride);
620 }
621
622 static
623 cmsUInt8Number* Unroll3Words(register _cmsTRANSFORM* info, 
624                              register cmsUInt16Number wIn[], 
625                              register cmsUInt8Number* accum,
626                              register cmsUInt32Number Stride)
627 {
628     wIn[0] = *(cmsUInt16Number*) accum; accum+= 2;  // C R
629     wIn[1] = *(cmsUInt16Number*) accum; accum+= 2;  // M G
630     wIn[2] = *(cmsUInt16Number*) accum; accum+= 2;  // Y B
631
632     return accum;
633
634     cmsUNUSED_PARAMETER(info);
635     cmsUNUSED_PARAMETER(Stride);
636 }
637
638 static
639 cmsUInt8Number* Unroll3WordsSwap(register _cmsTRANSFORM* info, 
640                                  register cmsUInt16Number wIn[], 
641                                  register cmsUInt8Number* accum,
642                                  register cmsUInt32Number Stride)
643 {
644     wIn[2] = *(cmsUInt16Number*) accum; accum+= 2;  // C R
645     wIn[1] = *(cmsUInt16Number*) accum; accum+= 2;  // M G
646     wIn[0] = *(cmsUInt16Number*) accum; accum+= 2;  // Y B
647
648     return accum;
649
650     cmsUNUSED_PARAMETER(info);
651     cmsUNUSED_PARAMETER(Stride);
652 }
653
654 static
655 cmsUInt8Number* Unroll3WordsSkip1Swap(register _cmsTRANSFORM* info, 
656                                       register cmsUInt16Number wIn[], 
657                                       register cmsUInt8Number* accum,
658                                       register cmsUInt32Number Stride)
659 {
660     accum += 2; // A
661     wIn[2] = *(cmsUInt16Number*) accum; accum += 2; // R
662     wIn[1] = *(cmsUInt16Number*) accum; accum += 2; // G
663     wIn[0] = *(cmsUInt16Number*) accum; accum += 2; // B
664
665     return accum;
666
667     cmsUNUSED_PARAMETER(info);
668     cmsUNUSED_PARAMETER(Stride);
669 }
670
671 static
672 cmsUInt8Number* Unroll3WordsSkip1SwapFirst(register _cmsTRANSFORM* info, 
673                                            register cmsUInt16Number wIn[], 
674                                            register cmsUInt8Number* accum,
675                                            register cmsUInt32Number Stride)
676 {
677     accum += 2; // A
678     wIn[0] = *(cmsUInt16Number*) accum; accum += 2; // R
679     wIn[1] = *(cmsUInt16Number*) accum; accum += 2; // G
680     wIn[2] = *(cmsUInt16Number*) accum; accum += 2; // B
681
682     return accum;
683
684     cmsUNUSED_PARAMETER(info);
685     cmsUNUSED_PARAMETER(Stride);
686 }
687
688 static
689 cmsUInt8Number* Unroll1Word(register _cmsTRANSFORM* info, 
690                             register cmsUInt16Number wIn[], 
691                             register cmsUInt8Number* accum,
692                             register cmsUInt32Number Stride)
693 {
694     wIn[0] = wIn[1] = wIn[2] = *(cmsUInt16Number*) accum; accum+= 2;   // L
695
696     return accum;
697
698     cmsUNUSED_PARAMETER(info);
699     cmsUNUSED_PARAMETER(Stride);
700 }
701
702 static
703 cmsUInt8Number* Unroll1WordReversed(register _cmsTRANSFORM* info, 
704                                     register cmsUInt16Number wIn[], 
705                                     register cmsUInt8Number* accum,
706                                     register cmsUInt32Number Stride)
707 {
708     wIn[0] = wIn[1] = wIn[2] = REVERSE_FLAVOR_16(*(cmsUInt16Number*) accum); accum+= 2;
709
710     return accum;
711
712     cmsUNUSED_PARAMETER(info);
713     cmsUNUSED_PARAMETER(Stride);
714 }
715
716 static
717 cmsUInt8Number* Unroll1WordSkip3(register _cmsTRANSFORM* info, 
718                                  register cmsUInt16Number wIn[], 
719                                  register cmsUInt8Number* accum,
720                                  register cmsUInt32Number Stride)
721 {
722     wIn[0] = wIn[1] = wIn[2] = *(cmsUInt16Number*) accum; 
723
724     accum += 8;
725
726     return accum;
727
728     cmsUNUSED_PARAMETER(info);
729     cmsUNUSED_PARAMETER(Stride);
730 }
731
732 static
733 cmsUInt8Number* Unroll2Words(register _cmsTRANSFORM* info, 
734                                      register cmsUInt16Number wIn[], 
735                                      register cmsUInt8Number* accum,
736                                      register cmsUInt32Number Stride)
737 {
738     wIn[0] = *(cmsUInt16Number*) accum; accum += 2;    // ch1
739     wIn[1] = *(cmsUInt16Number*) accum; accum += 2;    // ch2
740
741     return accum;
742
743     cmsUNUSED_PARAMETER(info);
744     cmsUNUSED_PARAMETER(Stride);
745 }
746
747
748 // This is a conversion of Lab double to 16 bits
749 static
750 cmsUInt8Number* UnrollLabDoubleTo16(register _cmsTRANSFORM* info, 
751                                     register cmsUInt16Number wIn[], 
752                                     register cmsUInt8Number* accum,
753                                     register cmsUInt32Number  Stride)
754 {       
755     if (T_PLANAR(info -> InputFormat)) {
756
757         cmsFloat64Number* Pt = (cmsFloat64Number*) accum;
758
759         cmsCIELab Lab;
760
761         Lab.L = Pt[0];
762         Lab.a = Pt[Stride];
763         Lab.b = Pt[Stride*2];
764
765         cmsFloat2LabEncoded(wIn, &Lab);
766         return accum + sizeof(cmsFloat64Number);
767     }
768     else {
769
770         cmsFloat2LabEncoded(wIn, (cmsCIELab*) accum);
771         accum += sizeof(cmsCIELab) + T_EXTRA(info ->InputFormat) * sizeof(cmsFloat64Number);
772         return accum;
773     }
774 }
775
776 // This is a conversion of XYZ double to 16 bits
777 static
778 cmsUInt8Number* UnrollXYZDoubleTo16(register _cmsTRANSFORM* info, 
779                                     register cmsUInt16Number wIn[], 
780                                     register cmsUInt8Number* accum,
781                                     register cmsUInt32Number Stride)
782 {   
783     if (T_PLANAR(info -> InputFormat)) {
784
785         cmsFloat64Number* Pt = (cmsFloat64Number*) accum;
786         cmsCIEXYZ XYZ;
787
788         XYZ.X = Pt[0];
789         XYZ.Y = Pt[Stride];
790         XYZ.Z = Pt[Stride*2];
791         cmsFloat2XYZEncoded(wIn, &XYZ);
792
793         return accum + sizeof(cmsFloat64Number);
794
795     }
796
797     else {
798         cmsFloat2XYZEncoded(wIn, (cmsCIEXYZ*) accum);
799         accum += sizeof(cmsCIEXYZ) + T_EXTRA(info ->InputFormat) * sizeof(cmsFloat64Number);
800
801         return accum;
802     }
803 }
804
805 // Check if space is marked as ink
806 cmsINLINE cmsBool IsInkSpace(cmsUInt32Number Type)
807 {
808     switch (T_COLORSPACE(Type)) {
809
810      case PT_CMY:       
811      case PT_CMYK:      
812      case PT_MCH5:      
813      case PT_MCH6:
814      case PT_MCH7:     
815      case PT_MCH8:     
816      case PT_MCH9:     
817      case PT_MCH10:    
818      case PT_MCH11:    
819      case PT_MCH12:    
820      case PT_MCH13:    
821      case PT_MCH14:    
822      case PT_MCH15: return TRUE;
823
824      default: return FALSE;
825     }
826 }
827
828 // Inks does come in percentage, remaining cases are between 0..1.0, again to 16 bits
829 static
830 cmsUInt8Number* UnrollDoubleTo16(register _cmsTRANSFORM* info, 
831                                  register cmsUInt16Number wIn[], 
832                                  register cmsUInt8Number* accum,
833                                  register cmsUInt32Number Stride)
834 {
835     cmsFloat64Number* Inks = (cmsFloat64Number*) accum;
836     int nChan  = T_CHANNELS(info -> InputFormat);
837     int Planar = T_PLANAR(info -> InputFormat);
838     int i;
839     cmsFloat64Number v;
840     cmsFloat64Number maximum = IsInkSpace(info ->InputFormat) ? 655.35 : 65535.0;
841
842     for (i=0; i < nChan; i++) {
843
844         if (Planar)
845
846             v = Inks[i * Stride];
847         else
848             v = Inks[i];
849
850         wIn[i] = _cmsQuickSaturateWord(v * maximum);
851     }
852
853     if (T_PLANAR(info -> InputFormat))
854         return accum + sizeof(cmsFloat64Number);
855     else
856         return accum + (nChan + T_EXTRA(info ->InputFormat)) * sizeof(cmsFloat64Number);
857 }
858
859 static
860 cmsUInt8Number* UnrollFloatTo16(register _cmsTRANSFORM* info, 
861                                 register cmsUInt16Number wIn[], 
862                                 register cmsUInt8Number* accum,
863                                 register cmsUInt32Number Stride)
864 {
865     cmsFloat32Number* Inks = (cmsFloat32Number*) accum;
866     int nChan  = T_CHANNELS(info -> InputFormat);
867     int Planar = T_PLANAR(info -> InputFormat);
868     int i;
869     cmsFloat32Number v;
870     cmsFloat64Number maximum = IsInkSpace(info ->InputFormat) ? 655.35 : 65535.0;
871
872     for (i=0; i < nChan; i++) {
873
874         if (Planar)
875
876             v = Inks[i * Stride];
877         else
878             v = Inks[i];
879
880         wIn[i] = _cmsQuickSaturateWord(v * maximum);
881     }
882
883     if (T_PLANAR(info -> InputFormat))
884         return accum + sizeof(cmsFloat32Number);
885     else
886         return accum + (nChan + T_EXTRA(info ->InputFormat)) * sizeof(cmsFloat32Number);
887 }
888
889
890 // For 1 channel, we need to duplicate data (it comes in 0..1.0 range)
891 static
892 cmsUInt8Number* UnrollDouble1Chan(register _cmsTRANSFORM* info, 
893                                   register cmsUInt16Number wIn[], 
894                                   register cmsUInt8Number* accum,
895                                   register cmsUInt32Number Stride)
896 {
897     cmsFloat64Number* Inks = (cmsFloat64Number*) accum;
898
899     wIn[0] = wIn[1] = wIn[2] = _cmsQuickSaturateWord(Inks[0] * 65535.0);
900
901     return accum + sizeof(cmsFloat64Number);    
902
903     cmsUNUSED_PARAMETER(info);
904     cmsUNUSED_PARAMETER(Stride);
905 }
906
907 //-------------------------------------------------------------------------------------------------------------------
908
909 // True float transformation. 
910
911 // For anything going from cmsFloat32Number 
912 static
913 cmsUInt8Number* UnrollFloatsToFloat(_cmsTRANSFORM* info, 
914                                     cmsFloat32Number wIn[], 
915                                     cmsUInt8Number* accum,
916                                     cmsUInt32Number Stride)
917 {
918     cmsFloat32Number* Inks = (cmsFloat32Number*) accum;
919     int nChan  = T_CHANNELS(info -> InputFormat);
920     int Planar = T_PLANAR(info -> InputFormat);
921     int i;
922     cmsFloat64Number maximum = IsInkSpace(info ->InputFormat) ? 100.0 : 1.0;
923
924
925     for (i=0; i <  nChan; i++) {
926
927         if (Planar)
928             wIn[i] = (cmsFloat32Number) (Inks[i * Stride] / maximum);
929         else
930             wIn[i] = (cmsFloat32Number) (Inks[i] / maximum);                            
931     }
932
933     if (T_PLANAR(info -> InputFormat))
934         return accum + sizeof(cmsFloat32Number);
935     else
936         return accum + (nChan + T_EXTRA(info ->InputFormat)) * sizeof(cmsFloat32Number);
937 }
938
939 // For anything going from double
940 static
941 cmsUInt8Number* UnrollDoublesToFloat(_cmsTRANSFORM* info, 
942                                      cmsFloat32Number wIn[], 
943                                      cmsUInt8Number* accum,
944                                      cmsUInt32Number Stride)
945 {
946     cmsFloat64Number* Inks = (cmsFloat64Number*) accum;
947     int nChan  = T_CHANNELS(info -> InputFormat);
948     int Planar = T_PLANAR(info -> InputFormat);
949     int i;
950     cmsFloat64Number maximum = IsInkSpace(info ->InputFormat) ? 100.0 : 1.0;
951
952     for (i=0; i <  nChan; i++) {
953
954         if (Planar)
955             wIn[i] = (cmsFloat32Number) (Inks[i * Stride] / maximum);
956         else
957             wIn[i] = (cmsFloat32Number) (Inks[i] / maximum);                            
958     }
959
960     if (T_PLANAR(info -> InputFormat))
961         return accum + sizeof(cmsFloat64Number);
962     else
963         return accum + (nChan + T_EXTRA(info ->InputFormat)) * sizeof(cmsFloat64Number);
964 }
965
966
967 // From Lab double to cmsFloat32Number
968 static
969 cmsUInt8Number* UnrollLabDoubleToFloat(_cmsTRANSFORM* info,  
970                                        cmsFloat32Number wIn[], 
971                                        cmsUInt8Number* accum,
972                                        cmsUInt32Number Stride)
973 {  
974     cmsFloat64Number* Pt = (cmsFloat64Number*) accum;
975
976     if (T_PLANAR(info -> InputFormat)) {
977
978         wIn[0] = (cmsFloat32Number) (Pt[0] / 100.0);                            // from 0..100 to 0..1 
979         wIn[1] = (cmsFloat32Number) ((Pt[Stride] + 128) / 255.0);    // form -128..+127 to 0..1
980         wIn[2] = (cmsFloat32Number) ((Pt[Stride*2] + 128) / 255.0);
981
982         return accum + sizeof(cmsFloat64Number);
983     }
984     else {
985
986         wIn[0] = (cmsFloat32Number) (Pt[0] / 100.0);            // from 0..100 to 0..1 
987         wIn[1] = (cmsFloat32Number) ((Pt[1] + 128) / 255.0);    // form -128..+127 to 0..1
988         wIn[2] = (cmsFloat32Number) ((Pt[2] + 128) / 255.0);
989
990         accum += sizeof(cmsFloat64Number)*(3 + T_EXTRA(info ->InputFormat));
991         return accum;
992     }
993 }
994
995 // From Lab double to cmsFloat32Number
996 static
997 cmsUInt8Number* UnrollLabFloatToFloat(_cmsTRANSFORM* info, 
998                                       cmsFloat32Number wIn[], 
999                                       cmsUInt8Number* accum,
1000                                       cmsUInt32Number Stride)
1001 {  
1002     cmsFloat32Number* Pt = (cmsFloat32Number*) accum;
1003
1004     if (T_PLANAR(info -> InputFormat)) {
1005
1006         wIn[0] = (cmsFloat32Number) (Pt[0] / 100.0);                 // from 0..100 to 0..1 
1007         wIn[1] = (cmsFloat32Number) ((Pt[Stride] + 128) / 255.0);    // form -128..+127 to 0..1
1008         wIn[2] = (cmsFloat32Number) ((Pt[Stride*2] + 128) / 255.0);
1009
1010         return accum + sizeof(cmsFloat32Number);
1011     }
1012     else {
1013
1014         wIn[0] = (cmsFloat32Number) (Pt[0] / 100.0);            // from 0..100 to 0..1 
1015         wIn[1] = (cmsFloat32Number) ((Pt[1] + 128) / 255.0);    // form -128..+127 to 0..1
1016         wIn[2] = (cmsFloat32Number) ((Pt[2] + 128) / 255.0);
1017
1018         accum += sizeof(cmsFloat32Number)*(3 + T_EXTRA(info ->InputFormat));
1019         return accum;
1020     }
1021 }
1022
1023
1024 // 1.15 fixed point, that means maximum value is MAX_ENCODEABLE_XYZ (0xFFFF)
1025 static
1026 cmsUInt8Number* UnrollXYZDoubleToFloat(_cmsTRANSFORM* info,  
1027                                        cmsFloat32Number wIn[], 
1028                                        cmsUInt8Number* accum,
1029                                        cmsUInt32Number Stride)
1030 {  
1031     cmsFloat64Number* Pt = (cmsFloat64Number*) accum;
1032
1033     if (T_PLANAR(info -> InputFormat)) {
1034
1035         wIn[0] = (cmsFloat32Number) (Pt[0] / MAX_ENCODEABLE_XYZ);                   
1036         wIn[1] = (cmsFloat32Number) (Pt[Stride] / MAX_ENCODEABLE_XYZ);    
1037         wIn[2] = (cmsFloat32Number) (Pt[Stride*2] / MAX_ENCODEABLE_XYZ);
1038
1039         return accum + sizeof(cmsFloat64Number);
1040     }
1041     else {
1042
1043         wIn[0] = (cmsFloat32Number) (Pt[0] / MAX_ENCODEABLE_XYZ);            
1044         wIn[1] = (cmsFloat32Number) (Pt[1] / MAX_ENCODEABLE_XYZ);    
1045         wIn[2] = (cmsFloat32Number) (Pt[2] / MAX_ENCODEABLE_XYZ);
1046
1047         accum += sizeof(cmsFloat64Number)*(3 + T_EXTRA(info ->InputFormat));
1048         return accum;
1049     }
1050 }
1051
1052 static
1053 cmsUInt8Number* UnrollXYZFloatToFloat(_cmsTRANSFORM* info,  
1054                                       cmsFloat32Number wIn[], 
1055                                       cmsUInt8Number* accum,
1056                                       cmsUInt32Number Stride)
1057 {  
1058     cmsFloat32Number* Pt = (cmsFloat32Number*) accum;
1059
1060     if (T_PLANAR(info -> InputFormat)) {
1061
1062         wIn[0] = (cmsFloat32Number) (Pt[0] / MAX_ENCODEABLE_XYZ);                   
1063         wIn[1] = (cmsFloat32Number) (Pt[Stride] / MAX_ENCODEABLE_XYZ);    
1064         wIn[2] = (cmsFloat32Number) (Pt[Stride*2] / MAX_ENCODEABLE_XYZ);
1065
1066         return accum + sizeof(cmsFloat32Number);
1067     }
1068     else {
1069
1070         wIn[0] = (cmsFloat32Number) (Pt[0] / MAX_ENCODEABLE_XYZ);            
1071         wIn[1] = (cmsFloat32Number) (Pt[1] / MAX_ENCODEABLE_XYZ);    
1072         wIn[2] = (cmsFloat32Number) (Pt[2] / MAX_ENCODEABLE_XYZ);
1073
1074         accum += sizeof(cmsFloat32Number)*(3 + T_EXTRA(info ->InputFormat));
1075         return accum;
1076     }
1077 }
1078
1079 // Packing routines -----------------------------------------------------------------------------------------------------------
1080
1081
1082 // Generic chunky for byte
1083
1084 static
1085 cmsUInt8Number* PackAnyBytes(register _cmsTRANSFORM* info, 
1086                              register cmsUInt16Number wOut[], 
1087                              register cmsUInt8Number* output,
1088                              register cmsUInt32Number Stride)
1089 {
1090     int nChan      = T_CHANNELS(info -> OutputFormat);
1091     int DoSwap     = T_DOSWAP(info ->OutputFormat);
1092     int Reverse    = T_FLAVOR(info ->OutputFormat);
1093     int Extra      = T_EXTRA(info -> OutputFormat);
1094     int SwapFirst  = T_SWAPFIRST(info -> OutputFormat);
1095     int ExtraFirst = DoSwap && !SwapFirst;
1096     cmsUInt8Number* swap1;
1097     cmsUInt8Number v = 0;
1098     int i;
1099
1100     swap1 = output;
1101
1102     if (ExtraFirst) {
1103         output += Extra;
1104     }
1105
1106     for (i=0; i < nChan; i++) {
1107
1108         int index = DoSwap ? (nChan - i - 1) : i;
1109
1110         v = FROM_16_TO_8(wOut[index]);
1111
1112         if (Reverse)
1113             v = REVERSE_FLAVOR_8(v);
1114
1115         *output++ = v;
1116     }
1117
1118     if (!ExtraFirst) {
1119         output += Extra;
1120     }
1121
1122     if (Extra == 0 && SwapFirst) {
1123
1124         memmove(swap1 + 1, swap1, nChan-1);
1125         *swap1 = v;
1126     }
1127
1128
1129     return output;
1130
1131     cmsUNUSED_PARAMETER(Stride);
1132 }
1133
1134
1135
1136 static
1137 cmsUInt8Number* PackAnyWords(register _cmsTRANSFORM* info, 
1138                              register cmsUInt16Number wOut[], 
1139                              register cmsUInt8Number* output,
1140                              register cmsUInt32Number Stride)
1141 {
1142     int nChan      = T_CHANNELS(info -> OutputFormat);
1143     int SwapEndian = T_ENDIAN16(info -> InputFormat);
1144     int DoSwap     = T_DOSWAP(info ->OutputFormat);
1145     int Reverse    = T_FLAVOR(info ->OutputFormat);
1146     int Extra      = T_EXTRA(info -> OutputFormat);
1147     int SwapFirst  = T_SWAPFIRST(info -> OutputFormat);
1148     int ExtraFirst = DoSwap && !SwapFirst;
1149     cmsUInt16Number* swap1;
1150     cmsUInt16Number v = 0;
1151     int i;
1152
1153     swap1 = (cmsUInt16Number*) output;
1154
1155     if (ExtraFirst) {
1156         output += Extra * sizeof(cmsUInt16Number);
1157     }
1158
1159     for (i=0; i < nChan; i++) {
1160
1161         int index = DoSwap ? (nChan - i - 1) : i;
1162
1163         v = wOut[index];
1164
1165         if (SwapEndian)
1166             v = CHANGE_ENDIAN(v);
1167
1168         if (Reverse)
1169             v = REVERSE_FLAVOR_16(v);
1170
1171         *(cmsUInt16Number*) output = v;
1172
1173         output += sizeof(cmsUInt16Number);
1174     }
1175
1176     if (!ExtraFirst) {
1177         output += Extra * sizeof(cmsUInt16Number);
1178     }
1179
1180     if (Extra == 0 && SwapFirst) {
1181
1182         memmove(swap1 + 1, swap1, (nChan-1)* sizeof(cmsUInt16Number));
1183         *swap1 = v;
1184     }
1185
1186
1187     return output;
1188
1189     cmsUNUSED_PARAMETER(Stride);
1190 }
1191
1192
1193 static
1194 cmsUInt8Number* PackPlanarBytes(register _cmsTRANSFORM* info, 
1195                                 register cmsUInt16Number wOut[], 
1196                                 register cmsUInt8Number* output,
1197                                 register cmsUInt32Number Stride)
1198 {
1199     int nChan = T_CHANNELS(info -> OutputFormat);
1200     int DoSwap = T_DOSWAP(info ->OutputFormat);
1201     int Reverse= T_FLAVOR(info ->OutputFormat);
1202     int i;
1203     cmsUInt8Number* Init = output;
1204
1205     for (i=0; i < nChan; i++) {
1206
1207         int index = DoSwap ? (nChan - i - 1) : i;
1208         cmsUInt8Number v = FROM_16_TO_8(wOut[index]);
1209
1210         *(cmsUInt8Number*)  output = (cmsUInt8Number) (Reverse ? REVERSE_FLAVOR_8(v) : v);
1211         output += Stride;
1212     }
1213
1214     return (Init + 1);
1215
1216     cmsUNUSED_PARAMETER(Stride);
1217 }
1218
1219
1220 static
1221 cmsUInt8Number* PackPlanarWords(register _cmsTRANSFORM* info, 
1222                                 register cmsUInt16Number wOut[], 
1223                                 register cmsUInt8Number* output,
1224                                 register cmsUInt32Number Stride)
1225 {
1226     int nChan = T_CHANNELS(info -> OutputFormat);
1227     int DoSwap = T_DOSWAP(info ->OutputFormat);
1228     int Reverse= T_FLAVOR(info ->OutputFormat);
1229     int SwapEndian = T_ENDIAN16(info -> OutputFormat);
1230     int i;
1231     cmsUInt8Number* Init = output;
1232     cmsUInt16Number v;
1233
1234     if (DoSwap) {
1235         output += T_EXTRA(info -> OutputFormat) * Stride * sizeof(cmsUInt16Number);
1236     }
1237
1238     for (i=0; i < nChan; i++) {
1239
1240         int index = DoSwap ? (nChan - i - 1) : i;
1241
1242         v = wOut[index];
1243
1244         if (SwapEndian)
1245             v = CHANGE_ENDIAN(v);
1246
1247         if (Reverse) 
1248             v =  REVERSE_FLAVOR_16(v);
1249
1250         *(cmsUInt16Number*) output = v;
1251         output += (Stride * sizeof(cmsUInt16Number));
1252     }
1253
1254     return (Init + sizeof(cmsUInt16Number));
1255 }
1256
1257 // CMYKcm (unrolled for speed)
1258
1259 static
1260 cmsUInt8Number* Pack6Bytes(register _cmsTRANSFORM* info, 
1261                            register cmsUInt16Number wOut[], 
1262                            register cmsUInt8Number* output,
1263                            register cmsUInt32Number Stride)
1264 {
1265     *output++ = FROM_16_TO_8(wOut[0]);
1266     *output++ = FROM_16_TO_8(wOut[1]);
1267     *output++ = FROM_16_TO_8(wOut[2]);
1268     *output++ = FROM_16_TO_8(wOut[3]);
1269     *output++ = FROM_16_TO_8(wOut[4]);
1270     *output++ = FROM_16_TO_8(wOut[5]);
1271
1272     return output;
1273
1274     cmsUNUSED_PARAMETER(info);
1275     cmsUNUSED_PARAMETER(Stride);
1276 }
1277
1278 // KCMYcm
1279
1280 static
1281 cmsUInt8Number* Pack6BytesSwap(register _cmsTRANSFORM* info, 
1282                                register cmsUInt16Number wOut[], 
1283                                register cmsUInt8Number* output,
1284                                register cmsUInt32Number Stride)
1285 {
1286     *output++ = FROM_16_TO_8(wOut[5]);
1287     *output++ = FROM_16_TO_8(wOut[4]);
1288     *output++ = FROM_16_TO_8(wOut[3]);
1289     *output++ = FROM_16_TO_8(wOut[2]);
1290     *output++ = FROM_16_TO_8(wOut[1]);
1291     *output++ = FROM_16_TO_8(wOut[0]);
1292
1293     return output;
1294
1295     cmsUNUSED_PARAMETER(info);
1296     cmsUNUSED_PARAMETER(Stride);
1297 }
1298
1299 // CMYKcm
1300 static
1301 cmsUInt8Number* Pack6Words(register _cmsTRANSFORM* info, 
1302                            register cmsUInt16Number wOut[], 
1303                            register cmsUInt8Number* output,
1304                            register cmsUInt32Number Stride)
1305 {
1306     *(cmsUInt16Number*) output = wOut[0];
1307     output+= 2;
1308     *(cmsUInt16Number*) output = wOut[1];
1309     output+= 2;
1310     *(cmsUInt16Number*) output = wOut[2];
1311     output+= 2;
1312     *(cmsUInt16Number*) output = wOut[3];
1313     output+= 2;
1314     *(cmsUInt16Number*) output = wOut[4];
1315     output+= 2;
1316     *(cmsUInt16Number*) output = wOut[5];
1317     output+= 2;
1318
1319     return output;
1320
1321     cmsUNUSED_PARAMETER(info);
1322     cmsUNUSED_PARAMETER(Stride);
1323 }
1324
1325 // KCMYcm
1326 static
1327 cmsUInt8Number* Pack6WordsSwap(register _cmsTRANSFORM* info, 
1328                                register cmsUInt16Number wOut[], 
1329                                register cmsUInt8Number* output,
1330                                register cmsUInt32Number Stride)
1331 {
1332     *(cmsUInt16Number*) output = wOut[5];
1333     output+= 2;
1334     *(cmsUInt16Number*) output = wOut[4];
1335     output+= 2;
1336     *(cmsUInt16Number*) output = wOut[3];
1337     output+= 2;
1338     *(cmsUInt16Number*) output = wOut[2];
1339     output+= 2;
1340     *(cmsUInt16Number*) output = wOut[1];
1341     output+= 2;
1342     *(cmsUInt16Number*) output = wOut[0];
1343     output+= 2;
1344
1345     return output;
1346
1347     cmsUNUSED_PARAMETER(info);
1348     cmsUNUSED_PARAMETER(Stride);
1349 }
1350
1351
1352 static
1353 cmsUInt8Number* Pack4Bytes(register _cmsTRANSFORM* info, 
1354                            register cmsUInt16Number wOut[], 
1355                            register cmsUInt8Number* output,
1356                            register cmsUInt32Number Stride)
1357 {
1358     *output++ = FROM_16_TO_8(wOut[0]);
1359     *output++ = FROM_16_TO_8(wOut[1]);
1360     *output++ = FROM_16_TO_8(wOut[2]);
1361     *output++ = FROM_16_TO_8(wOut[3]);
1362
1363     return output;
1364
1365     cmsUNUSED_PARAMETER(info);
1366     cmsUNUSED_PARAMETER(Stride);
1367 }
1368
1369 static
1370 cmsUInt8Number* Pack4BytesReverse(register _cmsTRANSFORM* info, 
1371                                   register cmsUInt16Number wOut[], 
1372                                   register cmsUInt8Number* output,
1373                                   register cmsUInt32Number Stride)
1374 {
1375     *output++ = REVERSE_FLAVOR_8(FROM_16_TO_8(wOut[0]));
1376     *output++ = REVERSE_FLAVOR_8(FROM_16_TO_8(wOut[1]));
1377     *output++ = REVERSE_FLAVOR_8(FROM_16_TO_8(wOut[2]));
1378     *output++ = REVERSE_FLAVOR_8(FROM_16_TO_8(wOut[3]));
1379
1380     return output;
1381
1382     cmsUNUSED_PARAMETER(info);
1383     cmsUNUSED_PARAMETER(Stride);
1384 }
1385
1386
1387 static
1388 cmsUInt8Number* Pack4BytesSwapFirst(register _cmsTRANSFORM* info, 
1389                                     register cmsUInt16Number wOut[], 
1390                                     register cmsUInt8Number* output,
1391                                     register cmsUInt32Number Stride)
1392 {
1393     *output++ = FROM_16_TO_8(wOut[3]);
1394     *output++ = FROM_16_TO_8(wOut[0]);
1395     *output++ = FROM_16_TO_8(wOut[1]);
1396     *output++ = FROM_16_TO_8(wOut[2]);
1397
1398     return output;
1399
1400     cmsUNUSED_PARAMETER(info);
1401     cmsUNUSED_PARAMETER(Stride);
1402 }
1403
1404 // ABGR
1405 static
1406 cmsUInt8Number* Pack4BytesSwap(register _cmsTRANSFORM* info, 
1407                                register cmsUInt16Number wOut[], 
1408                                register cmsUInt8Number* output,
1409                                register cmsUInt32Number Stride)
1410 {
1411     *output++ = FROM_16_TO_8(wOut[3]);
1412     *output++ = FROM_16_TO_8(wOut[2]);
1413     *output++ = FROM_16_TO_8(wOut[1]);
1414     *output++ = FROM_16_TO_8(wOut[0]);
1415
1416     return output;
1417
1418     cmsUNUSED_PARAMETER(info);
1419     cmsUNUSED_PARAMETER(Stride);
1420 }
1421
1422 static
1423 cmsUInt8Number* Pack4BytesSwapSwapFirst(register _cmsTRANSFORM* info, 
1424                                         register cmsUInt16Number wOut[], 
1425                                         register cmsUInt8Number* output,
1426                                         register cmsUInt32Number Stride)
1427 {
1428     *output++ = FROM_16_TO_8(wOut[2]);
1429     *output++ = FROM_16_TO_8(wOut[1]);
1430     *output++ = FROM_16_TO_8(wOut[0]);
1431     *output++ = FROM_16_TO_8(wOut[3]);
1432
1433     return output;
1434
1435     cmsUNUSED_PARAMETER(info);
1436     cmsUNUSED_PARAMETER(Stride);
1437 }
1438
1439 static
1440 cmsUInt8Number* Pack4Words(register _cmsTRANSFORM* info, 
1441                            register cmsUInt16Number wOut[], 
1442                            register cmsUInt8Number* output,
1443                            register cmsUInt32Number Stride)
1444 {
1445     *(cmsUInt16Number*) output = wOut[0];
1446     output+= 2;
1447     *(cmsUInt16Number*) output = wOut[1];
1448     output+= 2;
1449     *(cmsUInt16Number*) output = wOut[2];
1450     output+= 2;
1451     *(cmsUInt16Number*) output = wOut[3];
1452     output+= 2;
1453
1454     return output;
1455
1456     cmsUNUSED_PARAMETER(info);
1457     cmsUNUSED_PARAMETER(Stride);
1458 }
1459
1460 static
1461 cmsUInt8Number* Pack4WordsReverse(register _cmsTRANSFORM* info, 
1462                                   register cmsUInt16Number wOut[], 
1463                                   register cmsUInt8Number* output,
1464                                   register cmsUInt32Number Stride)
1465 {
1466     *(cmsUInt16Number*) output = REVERSE_FLAVOR_16(wOut[0]);
1467     output+= 2;
1468     *(cmsUInt16Number*) output = REVERSE_FLAVOR_16(wOut[1]);
1469     output+= 2;
1470     *(cmsUInt16Number*) output = REVERSE_FLAVOR_16(wOut[2]);
1471     output+= 2;
1472     *(cmsUInt16Number*) output = REVERSE_FLAVOR_16(wOut[3]);
1473     output+= 2;
1474
1475     return output;
1476
1477     cmsUNUSED_PARAMETER(info);
1478     cmsUNUSED_PARAMETER(Stride);
1479 }
1480
1481 // ABGR
1482 static
1483 cmsUInt8Number* Pack4WordsSwap(register _cmsTRANSFORM* info, 
1484                                register cmsUInt16Number wOut[], 
1485                                register cmsUInt8Number* output,
1486                                register cmsUInt32Number Stride)
1487 {
1488     *(cmsUInt16Number*) output = wOut[3];
1489     output+= 2;
1490     *(cmsUInt16Number*) output = wOut[2];
1491     output+= 2;
1492     *(cmsUInt16Number*) output = wOut[1];
1493     output+= 2;
1494     *(cmsUInt16Number*) output = wOut[0];
1495     output+= 2;
1496
1497     return output;
1498
1499     cmsUNUSED_PARAMETER(info);
1500     cmsUNUSED_PARAMETER(Stride);
1501 }
1502
1503 // CMYK
1504 static
1505 cmsUInt8Number* Pack4WordsBigEndian(register _cmsTRANSFORM* info, 
1506                                     register cmsUInt16Number wOut[], 
1507                                     register cmsUInt8Number* output,
1508                                     register cmsUInt32Number Stride)
1509 {
1510     *(cmsUInt16Number*) output = CHANGE_ENDIAN(wOut[0]);
1511     output+= 2;
1512     *(cmsUInt16Number*) output = CHANGE_ENDIAN(wOut[1]);
1513     output+= 2;
1514     *(cmsUInt16Number*) output = CHANGE_ENDIAN(wOut[2]);
1515     output+= 2;
1516     *(cmsUInt16Number*) output = CHANGE_ENDIAN(wOut[3]);
1517     output+= 2;
1518
1519     return output;
1520
1521     cmsUNUSED_PARAMETER(info);
1522     cmsUNUSED_PARAMETER(Stride);
1523 }
1524
1525
1526 static
1527 cmsUInt8Number* PackLabV2_8(register _cmsTRANSFORM* info, 
1528                             register cmsUInt16Number wOut[], 
1529                             register cmsUInt8Number* output,
1530                             register cmsUInt32Number Stride)
1531 {
1532     *output++ = FROM_16_TO_8(FomLabV4ToLabV2(wOut[0]));
1533     *output++ = FROM_16_TO_8(FomLabV4ToLabV2(wOut[1]));
1534     *output++ = FROM_16_TO_8(FomLabV4ToLabV2(wOut[2]));
1535
1536     return output;
1537
1538     cmsUNUSED_PARAMETER(info);
1539     cmsUNUSED_PARAMETER(Stride);
1540 }
1541
1542 static
1543 cmsUInt8Number* PackALabV2_8(register _cmsTRANSFORM* info, 
1544                              register cmsUInt16Number wOut[], 
1545                              register cmsUInt8Number* output,
1546                              register cmsUInt32Number Stride)
1547 {
1548     output++;
1549     *output++ = FROM_16_TO_8(FomLabV4ToLabV2(wOut[0]));
1550     *output++ = FROM_16_TO_8(FomLabV4ToLabV2(wOut[1]));
1551     *output++ = FROM_16_TO_8(FomLabV4ToLabV2(wOut[2]));
1552
1553     return output;
1554
1555     cmsUNUSED_PARAMETER(info);
1556     cmsUNUSED_PARAMETER(Stride);
1557 }
1558
1559 static
1560 cmsUInt8Number* PackLabV2_16(register _cmsTRANSFORM* info, 
1561                              register cmsUInt16Number wOut[], 
1562                              register cmsUInt8Number* output,
1563                              register cmsUInt32Number Stride)
1564 {
1565     *(cmsUInt16Number*) output = FomLabV4ToLabV2(wOut[0]);
1566     output += 2;
1567     *(cmsUInt16Number*) output = FomLabV4ToLabV2(wOut[1]);
1568     output += 2;
1569     *(cmsUInt16Number*) output = FomLabV4ToLabV2(wOut[2]);
1570     output += 2;
1571
1572     return output;
1573
1574     cmsUNUSED_PARAMETER(info);
1575     cmsUNUSED_PARAMETER(Stride);
1576 }
1577
1578 static
1579 cmsUInt8Number* Pack3Bytes(register _cmsTRANSFORM* info, 
1580                            register cmsUInt16Number wOut[], 
1581                            register cmsUInt8Number* output,
1582                            register cmsUInt32Number Stride)
1583 {
1584     *output++ = FROM_16_TO_8(wOut[0]);
1585     *output++ = FROM_16_TO_8(wOut[1]);
1586     *output++ = FROM_16_TO_8(wOut[2]);
1587
1588     return output;
1589
1590     cmsUNUSED_PARAMETER(info);
1591     cmsUNUSED_PARAMETER(Stride);
1592 }
1593
1594 static
1595 cmsUInt8Number* Pack3BytesOptimized(register _cmsTRANSFORM* info, 
1596                                     register cmsUInt16Number wOut[], 
1597                                     register cmsUInt8Number* output,
1598                                     register cmsUInt32Number Stride)
1599 {
1600     *output++ = (wOut[0] & 0xFF);
1601     *output++ = (wOut[1] & 0xFF);
1602     *output++ = (wOut[2] & 0xFF);
1603
1604     return output;
1605
1606     cmsUNUSED_PARAMETER(info);
1607     cmsUNUSED_PARAMETER(Stride);
1608 }
1609
1610 static
1611 cmsUInt8Number* Pack3BytesSwap(register _cmsTRANSFORM* info, 
1612                                register cmsUInt16Number wOut[], 
1613                                register cmsUInt8Number* output,
1614                                register cmsUInt32Number Stride)
1615 {
1616     *output++ = FROM_16_TO_8(wOut[2]);
1617     *output++ = FROM_16_TO_8(wOut[1]);
1618     *output++ = FROM_16_TO_8(wOut[0]);
1619
1620     return output;
1621
1622     cmsUNUSED_PARAMETER(info);
1623     cmsUNUSED_PARAMETER(Stride);
1624 }
1625
1626 static
1627 cmsUInt8Number* Pack3BytesSwapOptimized(register _cmsTRANSFORM* info, 
1628                                         register cmsUInt16Number wOut[], 
1629                                         register cmsUInt8Number* output,
1630                                         register cmsUInt32Number Stride)
1631 {
1632     *output++ = (wOut[2] & 0xFF);
1633     *output++ = (wOut[1] & 0xFF);
1634     *output++ = (wOut[0] & 0xFF);
1635
1636     return output;
1637
1638     cmsUNUSED_PARAMETER(info);
1639     cmsUNUSED_PARAMETER(Stride);
1640 }
1641
1642
1643 static
1644 cmsUInt8Number* Pack3Words(register _cmsTRANSFORM* info, 
1645                            register cmsUInt16Number wOut[], 
1646                            register cmsUInt8Number* output,
1647                            register cmsUInt32Number Stride)
1648 {
1649     *(cmsUInt16Number*) output = wOut[0];
1650     output+= 2;
1651     *(cmsUInt16Number*) output = wOut[1];
1652     output+= 2;
1653     *(cmsUInt16Number*) output = wOut[2];
1654     output+= 2;
1655
1656     return output;
1657
1658     cmsUNUSED_PARAMETER(info);
1659     cmsUNUSED_PARAMETER(Stride);
1660 }
1661
1662 static
1663 cmsUInt8Number* Pack3WordsSwap(register _cmsTRANSFORM* info, 
1664                                register cmsUInt16Number wOut[], 
1665                                register cmsUInt8Number* output,
1666                                register cmsUInt32Number Stride)
1667 {
1668     *(cmsUInt16Number*) output = wOut[2];
1669     output+= 2;
1670     *(cmsUInt16Number*) output = wOut[1];
1671     output+= 2;
1672     *(cmsUInt16Number*) output = wOut[0];
1673     output+= 2;
1674
1675     return output;
1676
1677     cmsUNUSED_PARAMETER(info);
1678     cmsUNUSED_PARAMETER(Stride);
1679 }
1680
1681 static
1682 cmsUInt8Number* Pack3WordsBigEndian(register _cmsTRANSFORM* info, 
1683                                     register cmsUInt16Number wOut[], 
1684                                     register cmsUInt8Number* output,
1685                                     register cmsUInt32Number Stride)
1686 {
1687     *(cmsUInt16Number*) output = CHANGE_ENDIAN(wOut[0]);
1688     output+= 2;
1689     *(cmsUInt16Number*) output = CHANGE_ENDIAN(wOut[1]);
1690     output+= 2;
1691     *(cmsUInt16Number*) output = CHANGE_ENDIAN(wOut[2]);
1692     output+= 2;
1693
1694     return output;
1695
1696     cmsUNUSED_PARAMETER(info);
1697     cmsUNUSED_PARAMETER(Stride);
1698 }
1699
1700 static
1701 cmsUInt8Number* Pack3BytesAndSkip1(register _cmsTRANSFORM* info, 
1702                                    register cmsUInt16Number wOut[], 
1703                                    register cmsUInt8Number* output,
1704                                    register cmsUInt32Number Stride)
1705 {
1706     *output++ = FROM_16_TO_8(wOut[0]);
1707     *output++ = FROM_16_TO_8(wOut[1]);
1708     *output++ = FROM_16_TO_8(wOut[2]);
1709     output++;
1710
1711     return output;
1712
1713     cmsUNUSED_PARAMETER(info);
1714     cmsUNUSED_PARAMETER(Stride);
1715 }
1716
1717 static
1718 cmsUInt8Number* Pack3BytesAndSkip1Optimized(register _cmsTRANSFORM* info, 
1719                                             register cmsUInt16Number wOut[], 
1720                                             register cmsUInt8Number* output,
1721                                             register cmsUInt32Number Stride)
1722 {
1723     *output++ = (wOut[0] & 0xFF);
1724     *output++ = (wOut[1] & 0xFF);
1725     *output++ = (wOut[2] & 0xFF);
1726     output++;
1727
1728     return output;
1729
1730     cmsUNUSED_PARAMETER(info);
1731     cmsUNUSED_PARAMETER(Stride);
1732 }
1733
1734
1735 static
1736 cmsUInt8Number* Pack3BytesAndSkip1SwapFirst(register _cmsTRANSFORM* info, 
1737                                             register cmsUInt16Number wOut[], 
1738                                             register cmsUInt8Number* output,
1739                                             register cmsUInt32Number Stride)
1740 {
1741     output++;
1742     *output++ = FROM_16_TO_8(wOut[0]);
1743     *output++ = FROM_16_TO_8(wOut[1]);
1744     *output++ = FROM_16_TO_8(wOut[2]);
1745
1746     return output;
1747
1748     cmsUNUSED_PARAMETER(info);
1749     cmsUNUSED_PARAMETER(Stride);
1750 }
1751
1752 static
1753 cmsUInt8Number* Pack3BytesAndSkip1SwapFirstOptimized(register _cmsTRANSFORM* info, 
1754                                                      register cmsUInt16Number wOut[], 
1755                                                      register cmsUInt8Number* output,
1756                                                      register cmsUInt32Number Stride)
1757 {
1758     output++;
1759     *output++ = (wOut[0] & 0xFF);
1760     *output++ = (wOut[1] & 0xFF);
1761     *output++ = (wOut[2] & 0xFF);
1762
1763     return output;
1764
1765     cmsUNUSED_PARAMETER(info);
1766     cmsUNUSED_PARAMETER(Stride);
1767 }
1768
1769 static
1770 cmsUInt8Number* Pack3BytesAndSkip1Swap(register _cmsTRANSFORM* info, 
1771                                        register cmsUInt16Number wOut[], 
1772                                        register cmsUInt8Number* output,
1773                                        register cmsUInt32Number Stride)
1774 {
1775     output++;
1776     *output++ = FROM_16_TO_8(wOut[2]);
1777     *output++ = FROM_16_TO_8(wOut[1]);
1778     *output++ = FROM_16_TO_8(wOut[0]);
1779
1780     return output;
1781
1782     cmsUNUSED_PARAMETER(info);
1783     cmsUNUSED_PARAMETER(Stride);
1784 }
1785
1786 static
1787 cmsUInt8Number* Pack3BytesAndSkip1SwapOptimized(register _cmsTRANSFORM* info, 
1788                                                 register cmsUInt16Number wOut[], 
1789                                                 register cmsUInt8Number* output,
1790                                                 register cmsUInt32Number Stride)
1791 {
1792     output++;
1793     *output++ = (wOut[2] & 0xFF);
1794     *output++ = (wOut[1] & 0xFF);
1795     *output++ = (wOut[0] & 0xFF);
1796
1797     return output;
1798
1799     cmsUNUSED_PARAMETER(info);
1800     cmsUNUSED_PARAMETER(Stride);
1801 }
1802
1803
1804 static
1805 cmsUInt8Number* Pack3BytesAndSkip1SwapSwapFirst(register _cmsTRANSFORM* info, 
1806                                                 register cmsUInt16Number wOut[], 
1807                                                 register cmsUInt8Number* output,
1808                                                 register cmsUInt32Number Stride)
1809 {       
1810     *output++ = FROM_16_TO_8(wOut[2]);
1811     *output++ = FROM_16_TO_8(wOut[1]);
1812     *output++ = FROM_16_TO_8(wOut[0]);
1813     output++;
1814
1815     return output;
1816
1817     cmsUNUSED_PARAMETER(info);
1818     cmsUNUSED_PARAMETER(Stride);
1819 }
1820
1821 static
1822 cmsUInt8Number* Pack3BytesAndSkip1SwapSwapFirstOptimized(register _cmsTRANSFORM* info, 
1823                                                          register cmsUInt16Number wOut[], 
1824                                                          register cmsUInt8Number* output,
1825                                                          register cmsUInt32Number Stride)
1826 {       
1827     *output++ = (wOut[2] & 0xFF);
1828     *output++ = (wOut[1] & 0xFF);
1829     *output++ = (wOut[0] & 0xFF);
1830     output++;
1831
1832     return output;
1833
1834     cmsUNUSED_PARAMETER(info);
1835     cmsUNUSED_PARAMETER(Stride);
1836 }
1837
1838 static
1839 cmsUInt8Number* Pack3WordsAndSkip1(register _cmsTRANSFORM* info, 
1840                                    register cmsUInt16Number wOut[], 
1841                                    register cmsUInt8Number* output,
1842                                    register cmsUInt32Number Stride)
1843 {
1844     *(cmsUInt16Number*) output = wOut[0];
1845     output+= 2;
1846     *(cmsUInt16Number*) output = wOut[1];
1847     output+= 2;
1848     *(cmsUInt16Number*) output = wOut[2];
1849     output+= 2;
1850     output+= 2;
1851
1852     return output;
1853
1854     cmsUNUSED_PARAMETER(info);
1855     cmsUNUSED_PARAMETER(Stride);
1856 }
1857
1858 static
1859 cmsUInt8Number* Pack3WordsAndSkip1Swap(register _cmsTRANSFORM* info, 
1860                                        register cmsUInt16Number wOut[], 
1861                                        register cmsUInt8Number* output,
1862                                        register cmsUInt32Number Stride)
1863 {
1864     output+= 2;
1865     *(cmsUInt16Number*) output = wOut[2];
1866     output+= 2;
1867     *(cmsUInt16Number*) output = wOut[1];
1868     output+= 2;
1869     *(cmsUInt16Number*) output = wOut[0];
1870     output+= 2;
1871
1872     return output;
1873
1874     cmsUNUSED_PARAMETER(info);
1875     cmsUNUSED_PARAMETER(Stride);
1876 }
1877
1878
1879 static
1880 cmsUInt8Number* Pack3WordsAndSkip1SwapFirst(register _cmsTRANSFORM* info, 
1881                                             register cmsUInt16Number wOut[], 
1882                                             register cmsUInt8Number* output,
1883                                             register cmsUInt32Number Stride)
1884 {   
1885     output+= 2;
1886     *(cmsUInt16Number*) output = wOut[0];
1887     output+= 2;
1888     *(cmsUInt16Number*) output = wOut[1];
1889     output+= 2;
1890     *(cmsUInt16Number*) output = wOut[2];
1891     output+= 2;
1892
1893     return output;
1894
1895     cmsUNUSED_PARAMETER(info);
1896     cmsUNUSED_PARAMETER(Stride);
1897 }
1898
1899
1900 static
1901 cmsUInt8Number* Pack3WordsAndSkip1SwapSwapFirst(register _cmsTRANSFORM* info, 
1902                                                 register cmsUInt16Number wOut[], 
1903                                                 register cmsUInt8Number* output,
1904                                                 register cmsUInt32Number Stride)
1905 {      
1906     *(cmsUInt16Number*) output = wOut[2];
1907     output+= 2;
1908     *(cmsUInt16Number*) output = wOut[1];
1909     output+= 2;
1910     *(cmsUInt16Number*) output = wOut[0];
1911     output+= 2;
1912     output+= 2;
1913
1914     return output;
1915
1916     cmsUNUSED_PARAMETER(info);
1917     cmsUNUSED_PARAMETER(Stride);
1918 }
1919
1920
1921
1922 static
1923 cmsUInt8Number* Pack1Byte(register _cmsTRANSFORM* info, 
1924                           register cmsUInt16Number wOut[], 
1925                           register cmsUInt8Number* output,
1926                           register cmsUInt32Number Stride)
1927 {
1928     *output++ = FROM_16_TO_8(wOut[0]);
1929
1930     return output;
1931
1932     cmsUNUSED_PARAMETER(info);
1933     cmsUNUSED_PARAMETER(Stride);
1934 }
1935
1936
1937 static
1938 cmsUInt8Number* Pack1ByteReversed(register _cmsTRANSFORM* info, 
1939                                   register cmsUInt16Number wOut[], 
1940                                   register cmsUInt8Number* output,
1941                                   register cmsUInt32Number Stride)
1942 {
1943     *output++ = FROM_16_TO_8(REVERSE_FLAVOR_16(wOut[0]));
1944
1945     return output;
1946
1947     cmsUNUSED_PARAMETER(info);
1948     cmsUNUSED_PARAMETER(Stride);
1949 }
1950
1951
1952 static
1953 cmsUInt8Number* Pack1ByteSkip1(register _cmsTRANSFORM* info, 
1954                                register cmsUInt16Number wOut[], 
1955                                register cmsUInt8Number* output,
1956                                register cmsUInt32Number Stride)
1957 {
1958     *output++ = FROM_16_TO_8(wOut[0]);
1959     output++;
1960
1961     return output;
1962
1963     cmsUNUSED_PARAMETER(info);
1964     cmsUNUSED_PARAMETER(Stride);
1965 }
1966
1967
1968 static
1969 cmsUInt8Number* Pack1ByteSkip1SwapFirst(register _cmsTRANSFORM* info, 
1970                                         register cmsUInt16Number wOut[], 
1971                                         register cmsUInt8Number* output,
1972                                         register cmsUInt32Number Stride)
1973 {
1974     output++;
1975     *output++ = FROM_16_TO_8(wOut[0]);
1976
1977     return output;
1978
1979     cmsUNUSED_PARAMETER(info);
1980     cmsUNUSED_PARAMETER(Stride);
1981 }
1982
1983 static
1984 cmsUInt8Number* Pack1Word(register _cmsTRANSFORM* info, 
1985                           register cmsUInt16Number wOut[], 
1986                           register cmsUInt8Number* output,
1987                           register cmsUInt32Number Stride)
1988 {
1989     *(cmsUInt16Number*) output = wOut[0];
1990     output+= 2;
1991
1992     return output;
1993
1994     cmsUNUSED_PARAMETER(info);
1995     cmsUNUSED_PARAMETER(Stride);
1996 }
1997
1998
1999 static
2000 cmsUInt8Number* Pack1WordReversed(register _cmsTRANSFORM* info, 
2001                                   register cmsUInt16Number wOut[], 
2002                                   register cmsUInt8Number* output,
2003                                   register cmsUInt32Number Stride)
2004 {
2005     *(cmsUInt16Number*) output = REVERSE_FLAVOR_16(wOut[0]);
2006     output+= 2;
2007
2008     return output;
2009
2010     cmsUNUSED_PARAMETER(info);
2011     cmsUNUSED_PARAMETER(Stride);
2012 }
2013
2014 static
2015 cmsUInt8Number* Pack1WordBigEndian(register _cmsTRANSFORM* info, 
2016                                    register cmsUInt16Number wOut[], 
2017                                    register cmsUInt8Number* output,
2018                                    register cmsUInt32Number Stride)
2019 {
2020     *(cmsUInt16Number*) output = CHANGE_ENDIAN(wOut[0]);
2021     output+= 2;
2022
2023     return output;
2024
2025     cmsUNUSED_PARAMETER(info);
2026     cmsUNUSED_PARAMETER(Stride);
2027 }
2028
2029
2030 static
2031 cmsUInt8Number* Pack1WordSkip1(register _cmsTRANSFORM* info, 
2032                                register cmsUInt16Number wOut[], 
2033                                register cmsUInt8Number* output,
2034                                register cmsUInt32Number Stride)
2035 {
2036     *(cmsUInt16Number*) output = wOut[0];
2037     output+= 4;
2038
2039     return output;
2040
2041     cmsUNUSED_PARAMETER(info);
2042     cmsUNUSED_PARAMETER(Stride);
2043 }
2044
2045 static
2046 cmsUInt8Number* Pack1WordSkip1SwapFirst(register _cmsTRANSFORM* info, 
2047                                         register cmsUInt16Number wOut[], 
2048                                         register cmsUInt8Number* output,
2049                                         register cmsUInt32Number Stride)
2050 {
2051     output += 2; 
2052     *(cmsUInt16Number*) output = wOut[0];
2053     output+= 2;
2054
2055     return output;
2056
2057     cmsUNUSED_PARAMETER(info);
2058     cmsUNUSED_PARAMETER(Stride);
2059 }
2060
2061
2062 // Unencoded Float values -- don't try optimize speed
2063 static
2064 cmsUInt8Number* PackLabDoubleFrom16(register _cmsTRANSFORM* info, 
2065                                     register cmsUInt16Number wOut[], 
2066                                     register cmsUInt8Number* output, 
2067                                     register cmsUInt32Number Stride)
2068 {
2069
2070     if (T_PLANAR(info -> OutputFormat)) {
2071
2072         cmsCIELab  Lab;
2073         cmsFloat64Number* Out = (cmsFloat64Number*) output;
2074         cmsLabEncoded2Float(&Lab, wOut);
2075
2076         Out[0]        = Lab.L;
2077         Out[Stride]   = Lab.a;
2078         Out[Stride*2] = Lab.b;
2079
2080         return output + sizeof(cmsFloat64Number);
2081     }
2082     else {
2083
2084         cmsLabEncoded2Float((cmsCIELab*) output, wOut);
2085         return output + (sizeof(cmsCIELab) + T_EXTRA(info ->OutputFormat) * sizeof(cmsFloat64Number));            
2086     }
2087
2088 }
2089
2090 static
2091 cmsUInt8Number* PackXYZDoubleFrom16(register _cmsTRANSFORM* Info, 
2092                                     register cmsUInt16Number wOut[], 
2093                                     register cmsUInt8Number* output,
2094                                     register cmsUInt32Number Stride)
2095 {
2096     if (T_PLANAR(Info -> OutputFormat)) {
2097
2098         cmsCIEXYZ XYZ;
2099         cmsFloat64Number* Out = (cmsFloat64Number*) output;
2100         cmsXYZEncoded2Float(&XYZ, wOut);
2101
2102         Out[0]                  = XYZ.X;
2103         Out[Stride]   = XYZ.Y;
2104         Out[Stride*2] = XYZ.Z;
2105
2106         return output + sizeof(cmsFloat64Number);
2107
2108     }
2109     else {
2110
2111         cmsXYZEncoded2Float((cmsCIEXYZ*) output, wOut);
2112
2113         return output + (sizeof(cmsCIEXYZ) + T_EXTRA(Info ->OutputFormat) * sizeof(cmsFloat64Number));
2114     }
2115 }
2116
2117 static
2118 cmsUInt8Number* PackDoubleFrom16(register _cmsTRANSFORM* Info, 
2119                                  register cmsUInt16Number wOut[], 
2120                                  register cmsUInt8Number* output,
2121                                  register cmsUInt32Number Stride)
2122 {
2123     cmsFloat64Number* Inks = (cmsFloat64Number*) output;
2124     int nChan = T_CHANNELS(Info -> OutputFormat);
2125     int i;
2126     cmsFloat64Number maximum = IsInkSpace(Info ->OutputFormat) ? 655.35 : 65535.0;
2127
2128     if (T_PLANAR(Info -> OutputFormat)) {
2129
2130         for (i=0; i <  nChan; i++) {
2131
2132             Inks[i*Stride] = wOut[i] / maximum;
2133         }
2134
2135         return output + sizeof(cmsFloat64Number);
2136     } 
2137     else {
2138
2139         for (i=0; i <  nChan; i++) {
2140
2141             Inks[i] = wOut[i] /  maximum;
2142         }
2143
2144
2145         return output + (nChan + T_EXTRA(Info ->OutputFormat)) * sizeof(cmsFloat64Number);
2146     }
2147
2148 }
2149
2150 static
2151 cmsUInt8Number* PackFloatFrom16(register _cmsTRANSFORM* Info, 
2152                                 register cmsUInt16Number wOut[], 
2153                                 register cmsUInt8Number* output,
2154                                 register cmsUInt32Number Stride)
2155 {
2156     cmsFloat32Number* Inks = (cmsFloat32Number*) output;
2157     int nChan = T_CHANNELS(Info -> OutputFormat);
2158     int i;
2159     cmsFloat64Number maximum = IsInkSpace(Info ->OutputFormat) ? 655.35 : 65535.0;
2160
2161     if (T_PLANAR(Info -> OutputFormat)) {
2162
2163         for (i=0; i <  nChan; i++) {
2164
2165             Inks[i*Stride] = (cmsFloat32Number) (wOut[i] / maximum);
2166         }
2167
2168         return output + sizeof(cmsFloat32Number);
2169     } 
2170     else {
2171
2172         for (i=0; i <  nChan; i++) {
2173
2174             Inks[i] = (cmsFloat32Number) (wOut[i] /  maximum);
2175         }
2176
2177
2178         return output + (nChan + T_EXTRA(Info ->OutputFormat)) * sizeof(cmsFloat32Number);
2179     }
2180
2181 }
2182
2183
2184 // --------------------------------------------------------------------------------------------------------
2185
2186 static
2187 cmsUInt8Number* PackChunkyFloatsFromFloat(_cmsTRANSFORM* info, 
2188                                           cmsFloat32Number wOut[], 
2189                                           cmsUInt8Number* output,
2190                                           cmsUInt32Number Stride)
2191 {
2192     int nChan      = T_CHANNELS(info -> OutputFormat);
2193     int DoSwap     = T_DOSWAP(info ->OutputFormat);
2194     int Reverse    = T_FLAVOR(info ->OutputFormat);
2195     int Extra      = T_EXTRA(info -> OutputFormat);
2196     int SwapFirst  = T_SWAPFIRST(info -> OutputFormat);
2197     int ExtraFirst = DoSwap && !SwapFirst;
2198     cmsFloat64Number maximum = IsInkSpace(info ->OutputFormat) ? 100.0 : 1.0;
2199     cmsFloat32Number* swap1;
2200     cmsFloat64Number v = 0;
2201     int i;
2202
2203     swap1 = (cmsFloat32Number*) output;
2204
2205     if (ExtraFirst) {
2206         output += Extra * sizeof(cmsFloat32Number);
2207     }
2208
2209     for (i=0; i < nChan; i++) {
2210
2211         int index = DoSwap ? (nChan - i - 1) : i;
2212
2213         v = wOut[index] * maximum;
2214
2215         if (Reverse)
2216             v = maximum - v;
2217
2218         *(cmsFloat32Number*) output = (cmsFloat32Number) v;
2219
2220         output += sizeof(cmsFloat32Number);
2221     }
2222
2223     if (!ExtraFirst) {
2224         output += Extra * sizeof(cmsFloat32Number);
2225     }
2226
2227     if (Extra == 0 && SwapFirst) {
2228
2229         memmove(swap1 + 1, swap1, (nChan-1)* sizeof(cmsFloat32Number));
2230         *swap1 = (cmsFloat32Number) v;
2231     }
2232
2233
2234     return output;
2235
2236     cmsUNUSED_PARAMETER(Stride);
2237 }
2238
2239 static
2240 cmsUInt8Number* PackPlanarFloatsFromFloat(_cmsTRANSFORM* info, 
2241                                           cmsFloat32Number wOut[], 
2242                                           cmsUInt8Number* output,
2243                                           cmsUInt32Number Stride)
2244 {
2245     int nChan = T_CHANNELS(info -> OutputFormat);
2246     int DoSwap = T_DOSWAP(info ->OutputFormat);
2247     int Reverse= T_FLAVOR(info ->OutputFormat);
2248     int i;
2249     cmsUInt8Number* Init = output;
2250     cmsFloat64Number maximum = IsInkSpace(info ->OutputFormat) ? 100.0 : 1.0;
2251     cmsFloat64Number v;
2252
2253     if (DoSwap) {
2254         output += T_EXTRA(info -> OutputFormat) * Stride * sizeof(cmsFloat32Number);
2255     }
2256
2257     for (i=0; i < nChan; i++) {
2258
2259         int index = DoSwap ? (nChan - i - 1) : i;
2260
2261         v = wOut[index] * maximum;
2262
2263         if (Reverse) 
2264             v =  maximum - v;
2265
2266         *(cmsFloat32Number*) output = (cmsFloat32Number) v;
2267         output += (Stride * sizeof(cmsFloat32Number));
2268     }
2269
2270     return (Init + sizeof(cmsFloat32Number));
2271
2272 }
2273
2274
2275 static
2276 cmsUInt8Number* PackChunkyDoublesFromFloat(_cmsTRANSFORM* info, 
2277                                            cmsFloat32Number wOut[], 
2278                                            cmsUInt8Number* output,
2279                                            cmsUInt32Number Stride)
2280 {
2281     int nChan      = T_CHANNELS(info -> OutputFormat);
2282     int DoSwap     = T_DOSWAP(info ->OutputFormat);
2283     int Reverse    = T_FLAVOR(info ->OutputFormat);
2284     int Extra      = T_EXTRA(info -> OutputFormat);
2285     int SwapFirst  = T_SWAPFIRST(info -> OutputFormat);
2286     int ExtraFirst = DoSwap && !SwapFirst;
2287     cmsFloat64Number* swap1;
2288     cmsFloat64Number maximum = IsInkSpace(info ->OutputFormat) ? 100.0 : 1.0;
2289     cmsFloat64Number v = 0;
2290     int i;
2291
2292     swap1 = (cmsFloat64Number*) output;
2293
2294     if (ExtraFirst) {
2295         output += Extra * sizeof(cmsFloat64Number);
2296     }
2297
2298     for (i=0; i < nChan; i++) {
2299
2300         int index = DoSwap ? (nChan - i - 1) : i;
2301
2302         v = (cmsFloat64Number) wOut[index] * maximum;
2303
2304         if (Reverse)
2305             v = maximum - v;
2306
2307         *(cmsFloat64Number*) output = v;
2308
2309         output += sizeof(cmsFloat64Number);
2310     }
2311
2312     if (!ExtraFirst) {
2313         output += Extra * sizeof(cmsFloat64Number);
2314     }
2315
2316     if (Extra == 0 && SwapFirst) {
2317
2318         memmove(swap1 + 1, swap1, (nChan-1)* sizeof(cmsFloat64Number));
2319         *swap1 = v;
2320     }
2321
2322
2323     return output;
2324
2325     cmsUNUSED_PARAMETER(Stride);
2326 }
2327
2328 static
2329 cmsUInt8Number* PackPlanarDoublesFromFloat(_cmsTRANSFORM* info, 
2330                                            cmsFloat32Number wOut[], 
2331                                            cmsUInt8Number* output,
2332                                            cmsUInt32Number Stride)
2333 {
2334     int nChan = T_CHANNELS(info -> OutputFormat);
2335     int DoSwap = T_DOSWAP(info ->OutputFormat);
2336     int Reverse= T_FLAVOR(info ->OutputFormat);
2337     int i;
2338     cmsUInt8Number* Init = output;
2339     cmsFloat64Number maximum = IsInkSpace(info ->OutputFormat) ? 100.0 : 1.0;
2340     cmsFloat64Number v;
2341
2342     if (DoSwap) {
2343         output += T_EXTRA(info -> OutputFormat) * Stride * sizeof(cmsFloat64Number);
2344     }
2345
2346     for (i=0; i < nChan; i++) {
2347
2348         int index = DoSwap ? (nChan - i - 1) : i;
2349
2350         v = (cmsFloat64Number) wOut[index] * maximum;
2351
2352         if (Reverse) 
2353             v =  maximum - v;
2354
2355         *(cmsFloat64Number*) output = v;
2356         output += (Stride * sizeof(cmsFloat64Number));
2357     }
2358
2359     return (Init + sizeof(cmsFloat64Number));
2360 }
2361
2362
2363
2364
2365 static
2366 cmsUInt8Number* PackLabFloatFromFloat(_cmsTRANSFORM* Info, 
2367                                       cmsFloat32Number wOut[], 
2368                                       cmsUInt8Number* output,
2369                                       cmsUInt32Number Stride)
2370 {        
2371     cmsFloat32Number* Out = (cmsFloat32Number*) output;
2372
2373     if (T_PLANAR(Info -> OutputFormat)) {
2374
2375         Out[0]        = (cmsFloat32Number) (wOut[0] * 100.0);
2376         Out[Stride]   = (cmsFloat32Number) (wOut[1] * 255.0 - 128.0);
2377         Out[Stride*2] = (cmsFloat32Number) (wOut[2] * 255.0 - 128.0);
2378
2379         return output + sizeof(cmsFloat32Number);
2380     }
2381     else {
2382
2383         Out[0] = (cmsFloat32Number) (wOut[0] * 100.0);
2384         Out[1] = (cmsFloat32Number) (wOut[1] * 255.0 - 128.0);
2385         Out[2] = (cmsFloat32Number) (wOut[2] * 255.0 - 128.0);
2386
2387         return output + (sizeof(cmsFloat32Number)*3 + T_EXTRA(Info ->OutputFormat) * sizeof(cmsFloat32Number));            
2388     }
2389
2390 }
2391
2392 static
2393 cmsUInt8Number* PackLabDoubleFromFloat(_cmsTRANSFORM* Info, 
2394                                        cmsFloat32Number wOut[], 
2395                                        cmsUInt8Number* output,
2396                                        cmsUInt32Number Stride)
2397 {        
2398     cmsFloat64Number* Out = (cmsFloat64Number*) output;
2399
2400     if (T_PLANAR(Info -> OutputFormat)) {
2401
2402         Out[0]        = (cmsFloat64Number) (wOut[0] * 100.0);
2403         Out[Stride]   = (cmsFloat64Number) (wOut[1] * 255.0 - 128.0);
2404         Out[Stride*2] = (cmsFloat64Number) (wOut[2] * 255.0 - 128.0);
2405
2406         return output + sizeof(cmsFloat64Number);
2407     }
2408     else {
2409
2410         Out[0] = (cmsFloat64Number) (wOut[0] * 100.0);
2411         Out[1] = (cmsFloat64Number) (wOut[1] * 255.0 - 128.0);
2412         Out[2] = (cmsFloat64Number) (wOut[2] * 255.0 - 128.0);
2413
2414         return output + (sizeof(cmsFloat64Number)*3 + T_EXTRA(Info ->OutputFormat) * sizeof(cmsFloat64Number));            
2415     }
2416
2417 }
2418
2419
2420 // From 0..1 range to 0..MAX_ENCODEABLE_XYZ
2421 static
2422 cmsUInt8Number* PackXYZFloatFromFloat(_cmsTRANSFORM* Info, 
2423                                       cmsFloat32Number wOut[], 
2424                                       cmsUInt8Number* output,
2425                                       cmsUInt32Number Stride)
2426 {        
2427     cmsFloat32Number* Out = (cmsFloat32Number*) output;
2428
2429     if (T_PLANAR(Info -> OutputFormat)) {
2430
2431         Out[0]        = (cmsFloat32Number) (wOut[0] * MAX_ENCODEABLE_XYZ);
2432         Out[Stride]   = (cmsFloat32Number) (wOut[1] * MAX_ENCODEABLE_XYZ);
2433         Out[Stride*2] = (cmsFloat32Number) (wOut[2] * MAX_ENCODEABLE_XYZ);
2434
2435         return output + sizeof(cmsFloat32Number);
2436     }
2437     else {
2438
2439         Out[0] = (cmsFloat32Number) (wOut[0] * MAX_ENCODEABLE_XYZ);
2440         Out[1] = (cmsFloat32Number) (wOut[1] * MAX_ENCODEABLE_XYZ);
2441         Out[2] = (cmsFloat32Number) (wOut[2] * MAX_ENCODEABLE_XYZ);
2442
2443         return output + (sizeof(cmsFloat32Number)*3 + T_EXTRA(Info ->OutputFormat) * sizeof(cmsFloat32Number));            
2444     }
2445
2446 }
2447
2448
2449 // Same, but convert to double
2450 static
2451 cmsUInt8Number* PackXYZDoubleFromFloat(_cmsTRANSFORM* Info, 
2452                                        cmsFloat32Number wOut[], 
2453                                        cmsUInt8Number* output,
2454                                        cmsUInt32Number Stride)
2455 {        
2456     cmsFloat64Number* Out = (cmsFloat64Number*) output;
2457
2458     if (T_PLANAR(Info -> OutputFormat)) {
2459
2460         Out[0]        = (cmsFloat64Number) (wOut[0] * MAX_ENCODEABLE_XYZ);
2461         Out[Stride]   = (cmsFloat64Number) (wOut[1] * MAX_ENCODEABLE_XYZ);
2462         Out[Stride*2] = (cmsFloat64Number) (wOut[2] * MAX_ENCODEABLE_XYZ);
2463
2464         return output + sizeof(cmsFloat64Number);
2465     }
2466     else {
2467
2468         Out[0] = (cmsFloat64Number) (wOut[0] * MAX_ENCODEABLE_XYZ);
2469         Out[1] = (cmsFloat64Number) (wOut[1] * MAX_ENCODEABLE_XYZ);
2470         Out[2] = (cmsFloat64Number) (wOut[2] * MAX_ENCODEABLE_XYZ);
2471
2472         return output + (sizeof(cmsFloat64Number)*3 + T_EXTRA(Info ->OutputFormat) * sizeof(cmsFloat64Number));            
2473     }
2474
2475 }
2476
2477
2478 // ----------------------------------------------------------------------------------------------------------------
2479
2480
2481 static cmsFormatters16 InputFormatters16[] = {
2482
2483     //    Type                                          Mask                  Function
2484     //  ----------------------------   ------------------------------------  ----------------------------
2485     { TYPE_Lab_DBL,                                 ANYPLANAR|ANYEXTRA,   UnrollLabDoubleTo16},
2486     { TYPE_XYZ_DBL,                                 ANYPLANAR|ANYEXTRA,   UnrollXYZDoubleTo16},
2487     { TYPE_GRAY_DBL,                                                 0,   UnrollDouble1Chan},
2488     { FLOAT_SH(1)|BYTES_SH(0), ANYCHANNELS|ANYPLANAR|ANYEXTRA|ANYSPACE,   UnrollDoubleTo16},
2489     { FLOAT_SH(1)|BYTES_SH(4), ANYCHANNELS|ANYPLANAR|ANYEXTRA|ANYSPACE,   UnrollFloatTo16},
2490
2491
2492     { CHANNELS_SH(1)|BYTES_SH(1),                              ANYSPACE,  Unroll1Byte}, 
2493     { CHANNELS_SH(1)|BYTES_SH(1)|EXTRA_SH(1),                  ANYSPACE,  Unroll1ByteSkip1},
2494     { CHANNELS_SH(1)|BYTES_SH(1)|EXTRA_SH(2),                  ANYSPACE,  Unroll1ByteSkip2},
2495     { CHANNELS_SH(1)|BYTES_SH(1)|FLAVOR_SH(1),                 ANYSPACE,  Unroll1ByteReversed},
2496     { COLORSPACE_SH(PT_MCH2)|CHANNELS_SH(2)|BYTES_SH(1),              0,  Unroll2Bytes},
2497    
2498     { TYPE_LabV2_8,                                                   0,  UnrollLabV2_8 },
2499     { TYPE_ALabV2_8,                                                  0,  UnrollALabV2_8 },
2500     { TYPE_LabV2_16,                                                  0,  UnrollLabV2_16 },
2501
2502     { CHANNELS_SH(3)|BYTES_SH(1),                              ANYSPACE,  Unroll3Bytes},
2503     { CHANNELS_SH(3)|BYTES_SH(1)|DOSWAP_SH(1),                 ANYSPACE,  Unroll3BytesSwap},
2504     { CHANNELS_SH(3)|EXTRA_SH(1)|BYTES_SH(1)|DOSWAP_SH(1),     ANYSPACE,  Unroll3BytesSkip1Swap},
2505     { CHANNELS_SH(3)|EXTRA_SH(1)|BYTES_SH(1)|SWAPFIRST_SH(1),  ANYSPACE,  Unroll3BytesSkip1SwapFirst},
2506
2507     { CHANNELS_SH(4)|BYTES_SH(1),                              ANYSPACE,  Unroll4Bytes},
2508     { CHANNELS_SH(4)|BYTES_SH(1)|FLAVOR_SH(1),                 ANYSPACE,  Unroll4BytesReverse},
2509     { CHANNELS_SH(4)|BYTES_SH(1)|SWAPFIRST_SH(1),              ANYSPACE,  Unroll4BytesSwapFirst}, 
2510     { CHANNELS_SH(4)|BYTES_SH(1)|DOSWAP_SH(1),                 ANYSPACE,  Unroll4BytesSwap}, 
2511     { CHANNELS_SH(4)|BYTES_SH(1)|DOSWAP_SH(1)|SWAPFIRST_SH(1), ANYSPACE,  Unroll4BytesSwapSwapFirst}, 
2512
2513     { BYTES_SH(1)|PLANAR_SH(1),    ANYFLAVOR|ANYSWAP|ANYEXTRA|ANYCHANNELS|ANYSPACE, UnrollPlanarBytes},
2514     { BYTES_SH(1),    ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|ANYEXTRA|ANYCHANNELS|ANYSPACE, UnrollChunkyBytes},     
2515
2516
2517     { CHANNELS_SH(1)|BYTES_SH(2),                              ANYSPACE,  Unroll1Word},
2518     { CHANNELS_SH(1)|BYTES_SH(2)|FLAVOR_SH(1),                 ANYSPACE,  Unroll1WordReversed},
2519     { CHANNELS_SH(1)|BYTES_SH(2)|EXTRA_SH(3),                  ANYSPACE,  Unroll1WordSkip3},
2520
2521     { CHANNELS_SH(2)|BYTES_SH(2),                              ANYSPACE,  Unroll2Words},
2522     { CHANNELS_SH(3)|BYTES_SH(2),                              ANYSPACE,  Unroll3Words},
2523     { CHANNELS_SH(4)|BYTES_SH(2),                              ANYSPACE,  Unroll4Words},
2524
2525     { CHANNELS_SH(3)|BYTES_SH(2)|DOSWAP_SH(1),                 ANYSPACE,  Unroll3WordsSwap},
2526     { CHANNELS_SH(3)|BYTES_SH(2)|EXTRA_SH(1)|SWAPFIRST_SH(1),  ANYSPACE,  Unroll3WordsSkip1SwapFirst},
2527     { CHANNELS_SH(3)|BYTES_SH(2)|EXTRA_SH(1)|DOSWAP_SH(1),     ANYSPACE,  Unroll3WordsSkip1Swap},
2528     { CHANNELS_SH(4)|BYTES_SH(2)|FLAVOR_SH(1),                 ANYSPACE,  Unroll4WordsReverse},
2529     { CHANNELS_SH(4)|BYTES_SH(2)|SWAPFIRST_SH(1),              ANYSPACE,  Unroll4WordsSwapFirst}, 
2530     { CHANNELS_SH(4)|BYTES_SH(2)|DOSWAP_SH(1),                 ANYSPACE,  Unroll4WordsSwap}, 
2531     { CHANNELS_SH(4)|BYTES_SH(2)|DOSWAP_SH(1)|SWAPFIRST_SH(1), ANYSPACE,  Unroll4WordsSwapSwapFirst}, 
2532
2533
2534     { BYTES_SH(2)|PLANAR_SH(1),  ANYFLAVOR|ANYSWAP|ANYENDIAN|ANYEXTRA|ANYCHANNELS|ANYSPACE,  UnrollPlanarWords },
2535     { BYTES_SH(2),  ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|ANYENDIAN|ANYEXTRA|ANYCHANNELS|ANYSPACE,  UnrollAnyWords}, 
2536 };
2537
2538
2539
2540 static cmsFormattersFloat InputFormattersFloat[] = {
2541
2542     //    Type                                          Mask                  Function
2543     //  ----------------------------   ------------------------------------  ----------------------------
2544     {     TYPE_Lab_DBL,                                ANYPLANAR|ANYEXTRA,   UnrollLabDoubleToFloat},
2545     {     TYPE_Lab_FLT,                                ANYPLANAR|ANYEXTRA,   UnrollLabFloatToFloat},
2546     {     TYPE_XYZ_DBL,                                ANYPLANAR|ANYEXTRA,   UnrollXYZDoubleToFloat},
2547     {     TYPE_XYZ_FLT,                                ANYPLANAR|ANYEXTRA,   UnrollXYZFloatToFloat},
2548
2549     {     FLOAT_SH(1)|BYTES_SH(4), ANYPLANAR|ANYEXTRA|ANYCHANNELS|ANYSPACE,  UnrollFloatsToFloat},
2550     {     FLOAT_SH(1)|BYTES_SH(0), ANYPLANAR|ANYEXTRA|ANYCHANNELS|ANYSPACE,  UnrollDoublesToFloat},
2551 };
2552
2553
2554 // Bit fields set to one in the mask are not compared
2555 static
2556 cmsFormatter _cmsGetStockInputFormatter(cmsUInt32Number dwInput, cmsUInt32Number dwFlags)
2557 {
2558     cmsUInt32Number i;
2559     cmsFormatter fr;
2560
2561
2562     if (!(dwFlags & CMS_PACK_FLAGS_FLOAT)) {
2563
2564         for (i=0; i < sizeof(InputFormatters16) / sizeof(cmsFormatters16); i++) {
2565             cmsFormatters16* f = InputFormatters16 + i;
2566
2567             if ((dwInput & ~f ->Mask) == f ->Type) {
2568                 fr.Fmt16 = f ->Frm;
2569                 return fr;
2570             }
2571         }
2572     }
2573     else {
2574         for (i=0; i < sizeof(InputFormattersFloat) / sizeof(cmsFormattersFloat); i++) {
2575             cmsFormattersFloat* f = InputFormattersFloat + i;
2576
2577             if ((dwInput & ~f ->Mask) == f ->Type) {
2578                 fr.FmtFloat = f ->Frm;
2579                 return fr;
2580             }
2581         }
2582     }
2583
2584     fr.Fmt16 = NULL;
2585     return fr;
2586 }
2587
2588 static cmsFormatters16 OutputFormatters16[] = {
2589     //    Type                                          Mask                  Function
2590     //  ----------------------------   ------------------------------------  ----------------------------
2591
2592     { TYPE_Lab_DBL,                                      ANYPLANAR|ANYEXTRA,  PackLabDoubleFrom16},
2593     { TYPE_XYZ_DBL,                                      ANYPLANAR|ANYEXTRA,  PackXYZDoubleFrom16},
2594     { FLOAT_SH(1)|BYTES_SH(0),      ANYCHANNELS|ANYPLANAR|ANYEXTRA|ANYSPACE,  PackDoubleFrom16},
2595     { FLOAT_SH(1)|BYTES_SH(4),      ANYCHANNELS|ANYPLANAR|ANYEXTRA|ANYSPACE,  PackFloatFrom16},
2596
2597     { CHANNELS_SH(1)|BYTES_SH(1),                                  ANYSPACE,  Pack1Byte},   
2598     { CHANNELS_SH(1)|BYTES_SH(1)|EXTRA_SH(1),                      ANYSPACE,  Pack1ByteSkip1},
2599     { CHANNELS_SH(1)|BYTES_SH(1)|EXTRA_SH(1)|SWAPFIRST_SH(1),      ANYSPACE,  Pack1ByteSkip1SwapFirst},
2600
2601     { CHANNELS_SH(1)|BYTES_SH(1)|FLAVOR_SH(1),                     ANYSPACE,  Pack1ByteReversed},
2602
2603     { TYPE_LabV2_8,                                                       0,  PackLabV2_8 },
2604     { TYPE_ALabV2_8,                                                      0,  PackALabV2_8 },
2605     { TYPE_LabV2_16,                                                      0,  PackLabV2_16 },
2606
2607     { CHANNELS_SH(3)|BYTES_SH(1)|OPTIMIZED_SH(1),                  ANYSPACE,  Pack3BytesOptimized},
2608     { CHANNELS_SH(3)|BYTES_SH(1)|EXTRA_SH(1)|OPTIMIZED_SH(1),      ANYSPACE,  Pack3BytesAndSkip1Optimized},
2609     { CHANNELS_SH(3)|BYTES_SH(1)|EXTRA_SH(1)|SWAPFIRST_SH(1)|OPTIMIZED_SH(1),
2610                                                                    ANYSPACE,  Pack3BytesAndSkip1SwapFirstOptimized},
2611     { CHANNELS_SH(3)|BYTES_SH(1)|EXTRA_SH(1)|DOSWAP_SH(1)|SWAPFIRST_SH(1)|OPTIMIZED_SH(1),  
2612                                                                    ANYSPACE,  Pack3BytesAndSkip1SwapSwapFirstOptimized},
2613     { CHANNELS_SH(3)|BYTES_SH(1)|DOSWAP_SH(1)|EXTRA_SH(1)|OPTIMIZED_SH(1),         
2614                                                                    ANYSPACE,  Pack3BytesAndSkip1SwapOptimized},
2615     { CHANNELS_SH(3)|BYTES_SH(1)|DOSWAP_SH(1)|OPTIMIZED_SH(1),     ANYSPACE,  Pack3BytesSwapOptimized},
2616
2617
2618
2619     { CHANNELS_SH(3)|BYTES_SH(1),                                  ANYSPACE,  Pack3Bytes},
2620     { CHANNELS_SH(3)|BYTES_SH(1)|EXTRA_SH(1),                      ANYSPACE,  Pack3BytesAndSkip1},
2621     { CHANNELS_SH(3)|BYTES_SH(1)|EXTRA_SH(1)|SWAPFIRST_SH(1),      ANYSPACE,  Pack3BytesAndSkip1SwapFirst},
2622     { CHANNELS_SH(3)|BYTES_SH(1)|EXTRA_SH(1)|DOSWAP_SH(1)|SWAPFIRST_SH(1),  
2623                                                                    ANYSPACE,  Pack3BytesAndSkip1SwapSwapFirst},
2624     { CHANNELS_SH(3)|BYTES_SH(1)|DOSWAP_SH(1)|EXTRA_SH(1),         ANYSPACE,  Pack3BytesAndSkip1Swap},
2625     { CHANNELS_SH(3)|BYTES_SH(1)|DOSWAP_SH(1),                     ANYSPACE,  Pack3BytesSwap},
2626     { CHANNELS_SH(6)|BYTES_SH(1),                                  ANYSPACE,  Pack6Bytes},
2627     { CHANNELS_SH(6)|BYTES_SH(1)|DOSWAP_SH(1),                     ANYSPACE,  Pack6BytesSwap},
2628     { CHANNELS_SH(4)|BYTES_SH(1),                                  ANYSPACE,  Pack4Bytes},
2629     { CHANNELS_SH(4)|BYTES_SH(1)|FLAVOR_SH(1),                     ANYSPACE,  Pack4BytesReverse},
2630     { CHANNELS_SH(4)|BYTES_SH(1)|SWAPFIRST_SH(1),                  ANYSPACE,  Pack4BytesSwapFirst}, 
2631     { CHANNELS_SH(4)|BYTES_SH(1)|DOSWAP_SH(1),                     ANYSPACE,  Pack4BytesSwap}, 
2632     { CHANNELS_SH(4)|BYTES_SH(1)|DOSWAP_SH(1)|SWAPFIRST_SH(1),     ANYSPACE,  Pack4BytesSwapSwapFirst}, 
2633
2634     { BYTES_SH(1),                 ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|ANYEXTRA|ANYCHANNELS|ANYSPACE, PackAnyBytes},     
2635     { BYTES_SH(1)|PLANAR_SH(1),    ANYFLAVOR|ANYSWAP|ANYEXTRA|ANYCHANNELS|ANYSPACE, PackPlanarBytes},   
2636
2637     { CHANNELS_SH(1)|BYTES_SH(2),                                  ANYSPACE,  Pack1Word},
2638     { CHANNELS_SH(1)|BYTES_SH(2)|EXTRA_SH(1),                      ANYSPACE,  Pack1WordSkip1},
2639     { CHANNELS_SH(1)|BYTES_SH(2)|EXTRA_SH(1)|SWAPFIRST_SH(1),      ANYSPACE,  Pack1WordSkip1SwapFirst},
2640     { CHANNELS_SH(1)|BYTES_SH(2)|FLAVOR_SH(1),                     ANYSPACE,  Pack1WordReversed},
2641     { CHANNELS_SH(1)|BYTES_SH(2)|ENDIAN16_SH(1),                   ANYSPACE,  Pack1WordBigEndian},
2642     { CHANNELS_SH(3)|BYTES_SH(2),                                  ANYSPACE,  Pack3Words},
2643     { CHANNELS_SH(3)|BYTES_SH(2)|DOSWAP_SH(1),                     ANYSPACE,  Pack3WordsSwap},
2644     { CHANNELS_SH(3)|BYTES_SH(2)|ENDIAN16_SH(1),                   ANYSPACE,  Pack3WordsBigEndian},
2645     { CHANNELS_SH(3)|BYTES_SH(2)|EXTRA_SH(1),                      ANYSPACE,  Pack3WordsAndSkip1},
2646     { CHANNELS_SH(3)|BYTES_SH(2)|EXTRA_SH(1)|DOSWAP_SH(1),         ANYSPACE,  Pack3WordsAndSkip1Swap},
2647     { CHANNELS_SH(3)|BYTES_SH(2)|EXTRA_SH(1)|SWAPFIRST_SH(1),      ANYSPACE,  Pack3WordsAndSkip1SwapFirst},
2648
2649     { CHANNELS_SH(3)|BYTES_SH(2)|EXTRA_SH(1)|DOSWAP_SH(1)|SWAPFIRST_SH(1),             
2650                                                                    ANYSPACE,  Pack3WordsAndSkip1SwapSwapFirst},
2651
2652     { CHANNELS_SH(4)|BYTES_SH(2),                                  ANYSPACE,  Pack4Words},
2653     { CHANNELS_SH(4)|BYTES_SH(2)|FLAVOR_SH(1),                     ANYSPACE,  Pack4WordsReverse},
2654     { CHANNELS_SH(4)|BYTES_SH(2)|DOSWAP_SH(1),                     ANYSPACE,  Pack4WordsSwap}, 
2655     { CHANNELS_SH(4)|BYTES_SH(2)|ENDIAN16_SH(1),                   ANYSPACE,  Pack4WordsBigEndian},
2656
2657     { CHANNELS_SH(6)|BYTES_SH(2),                                  ANYSPACE,  Pack6Words},
2658     { CHANNELS_SH(6)|BYTES_SH(2)|DOSWAP_SH(1),                     ANYSPACE,  Pack6WordsSwap},
2659
2660     { BYTES_SH(2)|PLANAR_SH(1),     ANYFLAVOR|ANYENDIAN|ANYSWAP|ANYEXTRA|ANYCHANNELS|ANYSPACE, PackPlanarWords}, 
2661     { BYTES_SH(2),                  ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|ANYENDIAN|ANYEXTRA|ANYCHANNELS|ANYSPACE, PackAnyWords}
2662
2663 };
2664
2665
2666 static cmsFormattersFloat OutputFormattersFloat[] = {
2667     //    Type                                          Mask                                 Function
2668     //  ----------------------------   ---------------------------------------------------  ----------------------------
2669     {     TYPE_Lab_FLT,                                                ANYPLANAR|ANYEXTRA,   PackLabFloatFromFloat},
2670     {     TYPE_XYZ_FLT,                                                ANYPLANAR|ANYEXTRA,   PackXYZFloatFromFloat},
2671     {     TYPE_Lab_DBL,                                                ANYPLANAR|ANYEXTRA,   PackLabDoubleFromFloat},
2672     {     TYPE_XYZ_DBL,                                                ANYPLANAR|ANYEXTRA,   PackXYZDoubleFromFloat},
2673     {     FLOAT_SH(1)|BYTES_SH(4), 
2674                              ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|ANYEXTRA|ANYCHANNELS|ANYSPACE,   PackChunkyFloatsFromFloat }, 
2675     {     FLOAT_SH(1)|BYTES_SH(4)|PLANAR_SH(1),             ANYEXTRA|ANYCHANNELS|ANYSPACE,   PackPlanarFloatsFromFloat},
2676     {     FLOAT_SH(1)|BYTES_SH(0),
2677                              ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|ANYEXTRA|ANYCHANNELS|ANYSPACE,   PackChunkyDoublesFromFloat }, 
2678     {     FLOAT_SH(1)|BYTES_SH(0)|PLANAR_SH(1),             ANYEXTRA|ANYCHANNELS|ANYSPACE,   PackPlanarDoublesFromFloat},
2679
2680
2681 };
2682
2683
2684 // Bit fields set to one in the mask are not compared
2685 cmsFormatter _cmsGetStockOutputFormatter(cmsUInt32Number dwInput, cmsUInt32Number dwFlags)
2686 {
2687     cmsUInt32Number i;
2688     cmsFormatter fr;
2689
2690
2691     if (dwFlags & CMS_PACK_FLAGS_FLOAT) {
2692
2693         for (i=0; i < sizeof(OutputFormattersFloat) / sizeof(cmsFormattersFloat); i++) {
2694             cmsFormattersFloat* f = OutputFormattersFloat + i;
2695
2696             if ((dwInput & ~f ->Mask) == f ->Type) {
2697                 fr.FmtFloat = f ->Frm;
2698                 return fr;
2699             }
2700         }
2701
2702     }
2703     else {
2704
2705         for (i=0; i < sizeof(OutputFormatters16) / sizeof(cmsFormatters16); i++) {
2706             cmsFormatters16* f = OutputFormatters16 + i;
2707
2708             if ((dwInput & ~f ->Mask) == f ->Type) {
2709                 fr.Fmt16 = f ->Frm;
2710                 return fr;
2711             }
2712         }
2713     }
2714
2715     fr.Fmt16 = NULL;
2716     return fr;
2717 }
2718
2719
2720 typedef struct _cms_formatters_factory_list {
2721
2722     cmsFormatterFactory Factory;
2723     struct _cms_formatters_factory_list *Next;
2724
2725 } cmsFormattersFactoryList;
2726
2727 static cmsFormattersFactoryList* FactoryList = NULL;
2728
2729
2730 // Formatters management
2731 cmsBool  _cmsRegisterFormattersPlugin(cmsPluginBase* Data)
2732 {
2733     cmsPluginFormatters* Plugin = (cmsPluginFormatters*) Data;
2734     cmsFormattersFactoryList* fl ;
2735
2736     // Reset
2737     if (Data == NULL) {
2738
2739           FactoryList = NULL;
2740           return TRUE;
2741     }
2742     
2743     fl = (cmsFormattersFactoryList*) _cmsPluginMalloc(sizeof(cmsFormattersFactoryList));
2744     if (fl == NULL) return FALSE;
2745
2746     fl ->Factory    = Plugin ->FormattersFactory;
2747
2748     fl ->Next = FactoryList;
2749     FactoryList = fl;
2750
2751     return TRUE;
2752 }
2753
2754 cmsFormatter _cmsGetFormatter(cmsUInt32Number Type,         // Specific type, i.e. TYPE_RGB_8
2755                              cmsFormatterDirection Dir, 
2756                              cmsUInt32Number dwFlags)       // Float or 16 bits
2757 {
2758     cmsFormattersFactoryList* f;
2759
2760     for (f = FactoryList; f != NULL; f = f ->Next) {
2761
2762         cmsFormatter fn = f ->Factory(Type, Dir, dwFlags);
2763         if (fn.Fmt16 != NULL) return fn;
2764     }
2765
2766     // Revert to default
2767     if (Dir == cmsFormatterInput) 
2768         return _cmsGetStockInputFormatter(Type, dwFlags);
2769     else 
2770         return _cmsGetStockOutputFormatter(Type, dwFlags);
2771 }
2772
2773
2774 // Return whatever given formatter refers to float values
2775 cmsBool  _cmsFormatterIsFloat(cmsUInt32Number Type)
2776 {
2777     return T_FLOAT(Type) ? TRUE : FALSE;
2778 }
2779
2780 // Return whatever given formatter refers to 8 bits
2781 cmsBool  _cmsFormatterIs8bit(cmsUInt32Number Type)
2782 {
2783     int Bytes = T_BYTES(Type);
2784
2785     return (Bytes == 1);
2786 }
2787
2788 // Build a suitable formatter for the colorspace of this profile
2789 cmsUInt32Number CMSEXPORT cmsFormatterForColorspaceOfProfile(cmsHPROFILE hProfile, cmsUInt32Number nBytes, cmsBool lIsFloat)
2790 {
2791  
2792     cmsColorSpaceSignature ColorSpace      = cmsGetColorSpace(hProfile);
2793     cmsUInt32Number        ColorSpaceBits  = _cmsLCMScolorSpace(ColorSpace);
2794     cmsUInt32Number        nOutputChans    = cmsChannelsOf(ColorSpace);
2795     cmsUInt32Number        Float           = lIsFloat ? 1 : 0;
2796
2797     // Create a fake formatter for result
2798     return FLOAT_SH(Float) | COLORSPACE_SH(ColorSpaceBits) | BYTES_SH(nBytes) | CHANNELS_SH(nOutputChans);
2799 }
2800
2801 // Build a suitable formatter for the colorspace of this profile
2802 cmsUInt32Number CMSEXPORT cmsFormatterForPCSOfProfile(cmsHPROFILE hProfile, cmsUInt32Number nBytes, cmsBool lIsFloat)
2803 {
2804  
2805     cmsColorSpaceSignature ColorSpace      = cmsGetPCS(hProfile);
2806     int                    ColorSpaceBits  = _cmsLCMScolorSpace(ColorSpace);
2807     cmsUInt32Number        nOutputChans    = cmsChannelsOf(ColorSpace);
2808     cmsUInt32Number        Float           = lIsFloat ? 1 : 0;
2809
2810     // Create a fake formatter for result
2811     return FLOAT_SH(Float) | COLORSPACE_SH(ColorSpaceBits) | BYTES_SH(nBytes) | CHANNELS_SH(nOutputChans);
2812 }
2813