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