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