Switch to libcms2-2.6
[openjpeg.git] / thirdparty / liblcms2 / src / cmspack.c
1 //---------------------------------------------------------------------------------
2 //
3 //  Little Color Management System
4 //  Copyright (c) 1998-2010 Marti Maria Saguer
5 //
6 // Permission is hereby granted, free of charge, to any person obtaining
7 // a copy of this software and associated documentation files (the "Software"),
8 // to deal in the Software without restriction, including without limitation
9 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 // and/or sell copies of the Software, and to permit persons to whom the Software
11 // is furnished to do so, subject to the following conditions:
12 //
13 // The above copyright notice and this permission notice shall be included in
14 // all copies or substantial portions of the Software.
15 //
16 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
18 // THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 //
24 //---------------------------------------------------------------------------------
25 //
26
27 #include "lcms2_internal.h"
28
29 // This module handles all formats supported by lcms. There are two flavors, 16 bits and
30 // floating point. Floating point is supported only in a subset, those formats holding
31 // cmsFloat32Number (4 bytes per component) and double (marked as 0 bytes per component
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 // Supress 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     if (!ExtraFirst) {
2413         output += Extra * sizeof(cmsFloat64Number);
2414     }
2415
2416     if (Extra == 0 && SwapFirst) {
2417
2418          memmove(swap1 + 1, swap1, (nChan-1)* sizeof(cmsFloat64Number));
2419         *swap1 = v;
2420     }
2421
2422     if (T_PLANAR(info -> OutputFormat))
2423         return output + sizeof(cmsFloat64Number);
2424     else
2425         return output + nChan * sizeof(cmsFloat64Number);
2426
2427 }
2428
2429
2430 static
2431 cmsUInt8Number* PackFloatFrom16(register _cmsTRANSFORM* info,
2432                                 register cmsUInt16Number wOut[],
2433                                 register cmsUInt8Number* output,
2434                                 register cmsUInt32Number Stride)
2435 {
2436     int nChan      = T_CHANNELS(info -> OutputFormat);
2437     int DoSwap     = T_DOSWAP(info ->OutputFormat);
2438     int Reverse    = T_FLAVOR(info ->OutputFormat);
2439     int Extra      = T_EXTRA(info -> OutputFormat);
2440     int SwapFirst  = T_SWAPFIRST(info -> OutputFormat);
2441     int Planar     = T_PLANAR(info -> OutputFormat);
2442     int ExtraFirst = DoSwap ^ SwapFirst;
2443     cmsFloat64Number maximum = IsInkSpace(info ->OutputFormat) ? 655.35 : 65535.0;
2444     cmsFloat64Number v = 0;
2445     cmsFloat32Number* swap1 = (cmsFloat32Number*) output;
2446     int i, start = 0;
2447
2448     if (ExtraFirst)
2449         start = Extra;
2450
2451     for (i=0; i < nChan; i++) {
2452
2453         int index = DoSwap ? (nChan - i - 1) : i;
2454
2455         v = (cmsFloat64Number) wOut[index] / maximum;
2456
2457         if (Reverse)
2458             v = maximum - v;
2459
2460         if (Planar)
2461             ((cmsFloat32Number*) output)[(i + start ) * Stride]= (cmsFloat32Number) v;
2462         else
2463             ((cmsFloat32Number*) output)[i + start] = (cmsFloat32Number) v;
2464     }
2465
2466     if (!ExtraFirst) {
2467         output += Extra * sizeof(cmsFloat32Number);
2468     }
2469
2470   if (Extra == 0 && SwapFirst) {
2471
2472          memmove(swap1 + 1, swap1, (nChan-1)* sizeof(cmsFloat32Number));
2473         *swap1 = (cmsFloat32Number) v;
2474     }
2475
2476     if (T_PLANAR(info -> OutputFormat))
2477         return output + sizeof(cmsFloat32Number);
2478     else
2479         return output + nChan * sizeof(cmsFloat32Number);
2480 }
2481
2482
2483
2484 // --------------------------------------------------------------------------------------------------------
2485
2486 static
2487 cmsUInt8Number* PackFloatsFromFloat(_cmsTRANSFORM* info,
2488                                     cmsFloat32Number wOut[],
2489                                     cmsUInt8Number* output,
2490                                     cmsUInt32Number Stride)
2491 {
2492     int nChan      = T_CHANNELS(info -> OutputFormat);
2493     int DoSwap     = T_DOSWAP(info ->OutputFormat);
2494     int Reverse    = T_FLAVOR(info ->OutputFormat);
2495     int Extra      = T_EXTRA(info -> OutputFormat);
2496     int SwapFirst  = T_SWAPFIRST(info -> OutputFormat);
2497     int Planar     = T_PLANAR(info -> OutputFormat);
2498     int ExtraFirst = DoSwap ^ SwapFirst;
2499     cmsFloat64Number maximum = IsInkSpace(info ->OutputFormat) ? 100.0 : 1.0;
2500     cmsFloat32Number* swap1 = (cmsFloat32Number*) output;
2501     cmsFloat64Number v = 0;
2502     int i, start = 0;
2503
2504     if (ExtraFirst)
2505         start = Extra;
2506
2507     for (i=0; i < nChan; i++) {
2508
2509         int index = DoSwap ? (nChan - i - 1) : i;
2510
2511         v = wOut[index] * maximum;
2512
2513         if (Reverse)
2514             v = maximum - v;
2515
2516         if (Planar)
2517             ((cmsFloat32Number*) output)[(i + start)* Stride]= (cmsFloat32Number) v;
2518         else
2519             ((cmsFloat32Number*) output)[i + start] = (cmsFloat32Number) v;
2520     }
2521
2522     if (!ExtraFirst) {
2523         output += Extra * sizeof(cmsFloat32Number);
2524     }
2525
2526    if (Extra == 0 && SwapFirst) {
2527
2528          memmove(swap1 + 1, swap1, (nChan-1)* sizeof(cmsFloat32Number));
2529         *swap1 = (cmsFloat32Number) v;
2530     }
2531
2532     if (T_PLANAR(info -> OutputFormat))
2533         return output + sizeof(cmsFloat32Number);
2534     else
2535         return output + nChan * sizeof(cmsFloat32Number);
2536 }
2537
2538 static
2539 cmsUInt8Number* PackDoublesFromFloat(_cmsTRANSFORM* info,
2540                                     cmsFloat32Number wOut[],
2541                                     cmsUInt8Number* output,
2542                                     cmsUInt32Number Stride)
2543 {
2544     int nChan      = T_CHANNELS(info -> OutputFormat);
2545     int DoSwap     = T_DOSWAP(info ->OutputFormat);
2546     int Reverse    = T_FLAVOR(info ->OutputFormat);
2547     int Extra      = T_EXTRA(info -> OutputFormat);
2548     int SwapFirst  = T_SWAPFIRST(info -> OutputFormat);
2549     int Planar     = T_PLANAR(info -> OutputFormat);
2550     int ExtraFirst = DoSwap ^ SwapFirst;
2551     cmsFloat64Number maximum = IsInkSpace(info ->OutputFormat) ? 100.0 : 1.0;
2552     cmsFloat64Number v = 0;
2553     cmsFloat64Number* swap1 = (cmsFloat64Number*) output;
2554     int i, start = 0;
2555
2556     if (ExtraFirst)
2557         start = Extra;
2558
2559     for (i=0; i < nChan; i++) {
2560
2561         int index = DoSwap ? (nChan - i - 1) : i;
2562
2563         v = wOut[index] * maximum;
2564
2565         if (Reverse)
2566             v = maximum - v;
2567
2568         if (Planar)
2569             ((cmsFloat64Number*) output)[(i + start) * Stride] =  v;
2570         else
2571             ((cmsFloat64Number*) output)[i + start] =  v;
2572     }
2573
2574     if (!ExtraFirst) {
2575         output += Extra * sizeof(cmsFloat64Number);
2576     }
2577
2578    if (Extra == 0 && SwapFirst) {
2579
2580          memmove(swap1 + 1, swap1, (nChan-1)* sizeof(cmsFloat64Number));
2581         *swap1 = v;
2582     }
2583
2584
2585     if (T_PLANAR(info -> OutputFormat))
2586         return output + sizeof(cmsFloat64Number);
2587     else
2588         return output + nChan * sizeof(cmsFloat64Number);
2589
2590 }
2591
2592
2593
2594
2595
2596 static
2597 cmsUInt8Number* PackLabFloatFromFloat(_cmsTRANSFORM* Info,
2598                                       cmsFloat32Number wOut[],
2599                                       cmsUInt8Number* output,
2600                                       cmsUInt32Number Stride)
2601 {
2602     cmsFloat32Number* Out = (cmsFloat32Number*) output;
2603
2604     if (T_PLANAR(Info -> OutputFormat)) {
2605
2606         Out[0]        = (cmsFloat32Number) (wOut[0] * 100.0);
2607         Out[Stride]   = (cmsFloat32Number) (wOut[1] * 255.0 - 128.0);
2608         Out[Stride*2] = (cmsFloat32Number) (wOut[2] * 255.0 - 128.0);
2609
2610         return output + sizeof(cmsFloat32Number);
2611     }
2612     else {
2613
2614         Out[0] = (cmsFloat32Number) (wOut[0] * 100.0);
2615         Out[1] = (cmsFloat32Number) (wOut[1] * 255.0 - 128.0);
2616         Out[2] = (cmsFloat32Number) (wOut[2] * 255.0 - 128.0);
2617
2618         return output + (sizeof(cmsFloat32Number)*3 + T_EXTRA(Info ->OutputFormat) * sizeof(cmsFloat32Number));
2619     }
2620
2621 }
2622
2623
2624 static
2625 cmsUInt8Number* PackLabDoubleFromFloat(_cmsTRANSFORM* Info,
2626                                        cmsFloat32Number wOut[],
2627                                        cmsUInt8Number* output,
2628                                        cmsUInt32Number Stride)
2629 {
2630     cmsFloat64Number* Out = (cmsFloat64Number*) output;
2631
2632     if (T_PLANAR(Info -> OutputFormat)) {
2633
2634         Out[0]        = (cmsFloat64Number) (wOut[0] * 100.0);
2635         Out[Stride]   = (cmsFloat64Number) (wOut[1] * 255.0 - 128.0);
2636         Out[Stride*2] = (cmsFloat64Number) (wOut[2] * 255.0 - 128.0);
2637
2638         return output + sizeof(cmsFloat64Number);
2639     }
2640     else {
2641
2642         Out[0] = (cmsFloat64Number) (wOut[0] * 100.0);
2643         Out[1] = (cmsFloat64Number) (wOut[1] * 255.0 - 128.0);
2644         Out[2] = (cmsFloat64Number) (wOut[2] * 255.0 - 128.0);
2645
2646         return output + (sizeof(cmsFloat64Number)*3 + T_EXTRA(Info ->OutputFormat) * sizeof(cmsFloat64Number));
2647     }
2648
2649 }
2650
2651
2652 // From 0..1 range to 0..MAX_ENCODEABLE_XYZ
2653 static
2654 cmsUInt8Number* PackXYZFloatFromFloat(_cmsTRANSFORM* Info,
2655                                       cmsFloat32Number wOut[],
2656                                       cmsUInt8Number* output,
2657                                       cmsUInt32Number Stride)
2658 {
2659     cmsFloat32Number* Out = (cmsFloat32Number*) output;
2660
2661     if (T_PLANAR(Info -> OutputFormat)) {
2662
2663         Out[0]        = (cmsFloat32Number) (wOut[0] * MAX_ENCODEABLE_XYZ);
2664         Out[Stride]   = (cmsFloat32Number) (wOut[1] * MAX_ENCODEABLE_XYZ);
2665         Out[Stride*2] = (cmsFloat32Number) (wOut[2] * MAX_ENCODEABLE_XYZ);
2666
2667         return output + sizeof(cmsFloat32Number);
2668     }
2669     else {
2670
2671         Out[0] = (cmsFloat32Number) (wOut[0] * MAX_ENCODEABLE_XYZ);
2672         Out[1] = (cmsFloat32Number) (wOut[1] * MAX_ENCODEABLE_XYZ);
2673         Out[2] = (cmsFloat32Number) (wOut[2] * MAX_ENCODEABLE_XYZ);
2674
2675         return output + (sizeof(cmsFloat32Number)*3 + T_EXTRA(Info ->OutputFormat) * sizeof(cmsFloat32Number));
2676     }
2677
2678 }
2679
2680 // Same, but convert to double
2681 static
2682 cmsUInt8Number* PackXYZDoubleFromFloat(_cmsTRANSFORM* Info,
2683                                        cmsFloat32Number wOut[],
2684                                        cmsUInt8Number* output,
2685                                        cmsUInt32Number Stride)
2686 {
2687     cmsFloat64Number* Out = (cmsFloat64Number*) output;
2688
2689     if (T_PLANAR(Info -> OutputFormat)) {
2690
2691         Out[0]        = (cmsFloat64Number) (wOut[0] * MAX_ENCODEABLE_XYZ);
2692         Out[Stride]   = (cmsFloat64Number) (wOut[1] * MAX_ENCODEABLE_XYZ);
2693         Out[Stride*2] = (cmsFloat64Number) (wOut[2] * MAX_ENCODEABLE_XYZ);
2694
2695         return output + sizeof(cmsFloat64Number);
2696     }
2697     else {
2698
2699         Out[0] = (cmsFloat64Number) (wOut[0] * MAX_ENCODEABLE_XYZ);
2700         Out[1] = (cmsFloat64Number) (wOut[1] * MAX_ENCODEABLE_XYZ);
2701         Out[2] = (cmsFloat64Number) (wOut[2] * MAX_ENCODEABLE_XYZ);
2702
2703         return output + (sizeof(cmsFloat64Number)*3 + T_EXTRA(Info ->OutputFormat) * sizeof(cmsFloat64Number));
2704     }
2705
2706 }
2707
2708
2709 // ----------------------------------------------------------------------------------------------------------------
2710
2711 #ifndef CMS_NO_HALF_SUPPORT 
2712
2713 // Decodes an stream of half floats to wIn[] described by input format
2714
2715 static
2716 cmsUInt8Number* UnrollHalfTo16(register _cmsTRANSFORM* info,
2717                                 register cmsUInt16Number wIn[],
2718                                 register cmsUInt8Number* accum,
2719                                 register cmsUInt32Number Stride)
2720 {
2721
2722     int nChan      = T_CHANNELS(info -> InputFormat);
2723     int DoSwap     = T_DOSWAP(info ->InputFormat);
2724     int Reverse    = T_FLAVOR(info ->InputFormat);
2725     int SwapFirst  = T_SWAPFIRST(info -> InputFormat);
2726     int Extra      = T_EXTRA(info -> InputFormat);
2727     int ExtraFirst = DoSwap ^ SwapFirst;
2728     int Planar     = T_PLANAR(info -> InputFormat);
2729     cmsFloat32Number v;
2730     int i, start = 0;
2731     cmsFloat32Number maximum = IsInkSpace(info ->InputFormat) ? 655.35F : 65535.0F;
2732
2733
2734     if (ExtraFirst)
2735             start = Extra;
2736
2737     for (i=0; i < nChan; i++) {
2738
2739         int index = DoSwap ? (nChan - i - 1) : i;
2740
2741         if (Planar)
2742             v = _cmsHalf2Float ( ((cmsUInt16Number*) accum)[(i + start) * Stride] );
2743         else
2744             v = _cmsHalf2Float ( ((cmsUInt16Number*) accum)[i + start] ) ;
2745
2746         if (Reverse) v = maximum - v;
2747
2748         wIn[index] = _cmsQuickSaturateWord(v * maximum);
2749     }
2750
2751
2752     if (Extra == 0 && SwapFirst) {
2753         cmsUInt16Number tmp = wIn[0];
2754
2755         memmove(&wIn[0], &wIn[1], (nChan-1) * sizeof(cmsUInt16Number));
2756         wIn[nChan-1] = tmp;
2757     }
2758
2759     if (T_PLANAR(info -> InputFormat))
2760         return accum + sizeof(cmsUInt16Number);
2761     else
2762         return accum + (nChan + Extra) * sizeof(cmsUInt16Number);
2763 }
2764
2765 // Decodes an stream of half floats to wIn[] described by input format
2766
2767 static
2768 cmsUInt8Number* UnrollHalfToFloat(_cmsTRANSFORM* info,
2769                                     cmsFloat32Number wIn[],
2770                                     cmsUInt8Number* accum,
2771                                     cmsUInt32Number Stride)
2772 {
2773
2774     int nChan      = T_CHANNELS(info -> InputFormat);
2775     int DoSwap     = T_DOSWAP(info ->InputFormat);
2776     int Reverse    = T_FLAVOR(info ->InputFormat);
2777     int SwapFirst  = T_SWAPFIRST(info -> InputFormat);
2778     int Extra      = T_EXTRA(info -> InputFormat);
2779     int ExtraFirst = DoSwap ^ SwapFirst;
2780     int Planar     = T_PLANAR(info -> InputFormat);
2781     cmsFloat32Number v;
2782     int i, start = 0;
2783     cmsFloat32Number maximum = IsInkSpace(info ->InputFormat) ? 100.0F : 1.0F;
2784
2785
2786     if (ExtraFirst)
2787             start = Extra;
2788
2789     for (i=0; i < nChan; i++) {
2790
2791         int index = DoSwap ? (nChan - i - 1) : i;
2792
2793         if (Planar)
2794             v =  _cmsHalf2Float ( ((cmsUInt16Number*) accum)[(i + start) * Stride] );
2795         else
2796             v =  _cmsHalf2Float ( ((cmsUInt16Number*) accum)[i + start] ) ;
2797
2798         v /= maximum;
2799
2800         wIn[index] = Reverse ? 1 - v : v;
2801     }
2802
2803
2804     if (Extra == 0 && SwapFirst) {
2805         cmsFloat32Number tmp = wIn[0];
2806
2807         memmove(&wIn[0], &wIn[1], (nChan-1) * sizeof(cmsFloat32Number));
2808         wIn[nChan-1] = tmp;
2809     }
2810
2811     if (T_PLANAR(info -> InputFormat))
2812         return accum + sizeof(cmsUInt16Number);
2813     else
2814         return accum + (nChan + Extra) * sizeof(cmsUInt16Number);
2815 }
2816
2817
2818 static
2819 cmsUInt8Number* PackHalfFrom16(register _cmsTRANSFORM* info,
2820                                 register cmsUInt16Number wOut[],
2821                                 register cmsUInt8Number* output,
2822                                 register cmsUInt32Number Stride)
2823 {
2824     int nChan      = T_CHANNELS(info -> OutputFormat);
2825     int DoSwap     = T_DOSWAP(info ->OutputFormat);
2826     int Reverse    = T_FLAVOR(info ->OutputFormat);
2827     int Extra      = T_EXTRA(info -> OutputFormat);
2828     int SwapFirst  = T_SWAPFIRST(info -> OutputFormat);
2829     int Planar     = T_PLANAR(info -> OutputFormat);
2830     int ExtraFirst = DoSwap ^ SwapFirst;
2831     cmsFloat32Number maximum = IsInkSpace(info ->OutputFormat) ? 655.35F : 65535.0F;
2832     cmsFloat32Number v = 0;
2833     cmsUInt16Number* swap1 = (cmsUInt16Number*) output;
2834     int i, start = 0;
2835
2836     if (ExtraFirst)
2837         start = Extra;
2838
2839     for (i=0; i < nChan; i++) {
2840
2841         int index = DoSwap ? (nChan - i - 1) : i;
2842
2843         v = (cmsFloat32Number) wOut[index] / maximum;
2844
2845         if (Reverse)
2846             v = maximum - v;
2847
2848         if (Planar)
2849             ((cmsUInt16Number*) output)[(i + start ) * Stride]= _cmsFloat2Half(v);
2850         else
2851             ((cmsUInt16Number*) output)[i + start] =  _cmsFloat2Half(v);
2852     }
2853
2854     if (!ExtraFirst) {
2855         output += Extra * sizeof(cmsUInt16Number);
2856     }
2857
2858   if (Extra == 0 && SwapFirst) {
2859
2860          memmove(swap1 + 1, swap1, (nChan-1)* sizeof(cmsUInt16Number));
2861         *swap1 = _cmsFloat2Half(v);
2862     }
2863
2864     if (T_PLANAR(info -> OutputFormat))
2865         return output + sizeof(cmsUInt16Number);
2866     else
2867         return output + nChan * sizeof(cmsUInt16Number);
2868 }
2869
2870
2871
2872 static
2873 cmsUInt8Number* PackHalfFromFloat(_cmsTRANSFORM* info,
2874                                     cmsFloat32Number wOut[],
2875                                     cmsUInt8Number* output,
2876                                     cmsUInt32Number Stride)
2877 {
2878     int nChan      = T_CHANNELS(info -> OutputFormat);
2879     int DoSwap     = T_DOSWAP(info ->OutputFormat);
2880     int Reverse    = T_FLAVOR(info ->OutputFormat);
2881     int Extra      = T_EXTRA(info -> OutputFormat);
2882     int SwapFirst  = T_SWAPFIRST(info -> OutputFormat);
2883     int Planar     = T_PLANAR(info -> OutputFormat);
2884     int ExtraFirst = DoSwap ^ SwapFirst;
2885     cmsFloat32Number maximum = IsInkSpace(info ->OutputFormat) ? 100.0F : 1.0F;
2886     cmsUInt16Number* swap1 = (cmsUInt16Number*) output;
2887     cmsFloat32Number v = 0;
2888     int i, start = 0;
2889
2890     if (ExtraFirst)
2891         start = Extra;
2892
2893     for (i=0; i < nChan; i++) {
2894
2895         int index = DoSwap ? (nChan - i - 1) : i;
2896
2897         v = wOut[index] * maximum;
2898
2899         if (Reverse)
2900             v = maximum - v;
2901
2902         if (Planar)
2903             ((cmsUInt16Number*) output)[(i + start)* Stride]= _cmsFloat2Half( v );
2904         else
2905             ((cmsUInt16Number*) output)[i + start] = _cmsFloat2Half( v );
2906     }
2907
2908     if (!ExtraFirst) {
2909         output += Extra * sizeof(cmsUInt16Number);
2910     }
2911
2912    if (Extra == 0 && SwapFirst) {
2913
2914          memmove(swap1 + 1, swap1, (nChan-1)* sizeof(cmsUInt16Number));
2915         *swap1 = (cmsUInt16Number)  _cmsFloat2Half( v );
2916     }
2917
2918     if (T_PLANAR(info -> OutputFormat))
2919         return output + sizeof(cmsUInt16Number);
2920     else
2921         return output + nChan * sizeof(cmsUInt16Number);
2922 }
2923
2924 #endif
2925
2926 // ----------------------------------------------------------------------------------------------------------------
2927
2928
2929 static cmsFormatters16 InputFormatters16[] = {
2930
2931     //    Type                                          Mask                  Function
2932     //  ----------------------------   ------------------------------------  ----------------------------
2933     { TYPE_Lab_DBL,                                 ANYPLANAR|ANYEXTRA,   UnrollLabDoubleTo16},
2934     { TYPE_XYZ_DBL,                                 ANYPLANAR|ANYEXTRA,   UnrollXYZDoubleTo16},
2935     { TYPE_Lab_FLT,                                 ANYPLANAR|ANYEXTRA,   UnrollLabFloatTo16},
2936     { TYPE_XYZ_FLT,                                 ANYPLANAR|ANYEXTRA,   UnrollXYZFloatTo16},
2937     { TYPE_GRAY_DBL,                                                 0,   UnrollDouble1Chan},
2938     { FLOAT_SH(1)|BYTES_SH(0), ANYCHANNELS|ANYPLANAR|ANYSWAPFIRST|ANYFLAVOR|
2939                                              ANYSWAP|ANYEXTRA|ANYSPACE,   UnrollDoubleTo16},
2940     { FLOAT_SH(1)|BYTES_SH(4), ANYCHANNELS|ANYPLANAR|ANYSWAPFIRST|ANYFLAVOR|
2941                                              ANYSWAP|ANYEXTRA|ANYSPACE,   UnrollFloatTo16},
2942 #ifndef CMS_NO_HALF_SUPPORT 
2943     { FLOAT_SH(1)|BYTES_SH(2), ANYCHANNELS|ANYPLANAR|ANYSWAPFIRST|ANYFLAVOR|
2944                                             ANYEXTRA|ANYSWAP|ANYSPACE,   UnrollHalfTo16},
2945 #endif
2946
2947     { CHANNELS_SH(1)|BYTES_SH(1),                              ANYSPACE,  Unroll1Byte},
2948     { CHANNELS_SH(1)|BYTES_SH(1)|EXTRA_SH(1),                  ANYSPACE,  Unroll1ByteSkip1},
2949     { CHANNELS_SH(1)|BYTES_SH(1)|EXTRA_SH(2),                  ANYSPACE,  Unroll1ByteSkip2},
2950     { CHANNELS_SH(1)|BYTES_SH(1)|FLAVOR_SH(1),                 ANYSPACE,  Unroll1ByteReversed},
2951     { COLORSPACE_SH(PT_MCH2)|CHANNELS_SH(2)|BYTES_SH(1),              0,  Unroll2Bytes},
2952
2953     { TYPE_LabV2_8,                                                   0,  UnrollLabV2_8 },
2954     { TYPE_ALabV2_8,                                                  0,  UnrollALabV2_8 },
2955     { TYPE_LabV2_16,                                                  0,  UnrollLabV2_16 },
2956
2957     { CHANNELS_SH(3)|BYTES_SH(1),                              ANYSPACE,  Unroll3Bytes},
2958     { CHANNELS_SH(3)|BYTES_SH(1)|DOSWAP_SH(1),                 ANYSPACE,  Unroll3BytesSwap},
2959     { CHANNELS_SH(3)|EXTRA_SH(1)|BYTES_SH(1)|DOSWAP_SH(1),     ANYSPACE,  Unroll3BytesSkip1Swap},
2960     { CHANNELS_SH(3)|EXTRA_SH(1)|BYTES_SH(1)|SWAPFIRST_SH(1),  ANYSPACE,  Unroll3BytesSkip1SwapFirst},
2961
2962     { CHANNELS_SH(3)|EXTRA_SH(1)|BYTES_SH(1)|DOSWAP_SH(1)|SWAPFIRST_SH(1),  
2963                                                                ANYSPACE,  Unroll3BytesSkip1SwapSwapFirst},
2964
2965     { CHANNELS_SH(4)|BYTES_SH(1),                              ANYSPACE,  Unroll4Bytes},
2966     { CHANNELS_SH(4)|BYTES_SH(1)|FLAVOR_SH(1),                 ANYSPACE,  Unroll4BytesReverse},
2967     { CHANNELS_SH(4)|BYTES_SH(1)|SWAPFIRST_SH(1),              ANYSPACE,  Unroll4BytesSwapFirst},
2968     { CHANNELS_SH(4)|BYTES_SH(1)|DOSWAP_SH(1),                 ANYSPACE,  Unroll4BytesSwap},
2969     { CHANNELS_SH(4)|BYTES_SH(1)|DOSWAP_SH(1)|SWAPFIRST_SH(1), ANYSPACE,  Unroll4BytesSwapSwapFirst},
2970
2971     { BYTES_SH(1)|PLANAR_SH(1), ANYFLAVOR|ANYSWAPFIRST|
2972                                    ANYSWAP|ANYEXTRA|ANYCHANNELS|ANYSPACE, UnrollPlanarBytes},
2973
2974     { BYTES_SH(1),    ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|
2975                                            ANYEXTRA|ANYCHANNELS|ANYSPACE, UnrollChunkyBytes},
2976
2977     { CHANNELS_SH(1)|BYTES_SH(2),                              ANYSPACE,  Unroll1Word},
2978     { CHANNELS_SH(1)|BYTES_SH(2)|FLAVOR_SH(1),                 ANYSPACE,  Unroll1WordReversed},
2979     { CHANNELS_SH(1)|BYTES_SH(2)|EXTRA_SH(3),                  ANYSPACE,  Unroll1WordSkip3},
2980
2981     { CHANNELS_SH(2)|BYTES_SH(2),                              ANYSPACE,  Unroll2Words},
2982     { CHANNELS_SH(3)|BYTES_SH(2),                              ANYSPACE,  Unroll3Words},
2983     { CHANNELS_SH(4)|BYTES_SH(2),                              ANYSPACE,  Unroll4Words},
2984
2985     { CHANNELS_SH(3)|BYTES_SH(2)|DOSWAP_SH(1),                 ANYSPACE,  Unroll3WordsSwap},
2986     { CHANNELS_SH(3)|BYTES_SH(2)|EXTRA_SH(1)|SWAPFIRST_SH(1),  ANYSPACE,  Unroll3WordsSkip1SwapFirst},
2987     { CHANNELS_SH(3)|BYTES_SH(2)|EXTRA_SH(1)|DOSWAP_SH(1),     ANYSPACE,  Unroll3WordsSkip1Swap},
2988     { CHANNELS_SH(4)|BYTES_SH(2)|FLAVOR_SH(1),                 ANYSPACE,  Unroll4WordsReverse},
2989     { CHANNELS_SH(4)|BYTES_SH(2)|SWAPFIRST_SH(1),              ANYSPACE,  Unroll4WordsSwapFirst},
2990     { CHANNELS_SH(4)|BYTES_SH(2)|DOSWAP_SH(1),                 ANYSPACE,  Unroll4WordsSwap},
2991     { CHANNELS_SH(4)|BYTES_SH(2)|DOSWAP_SH(1)|SWAPFIRST_SH(1), ANYSPACE,  Unroll4WordsSwapSwapFirst},
2992
2993
2994     { BYTES_SH(2)|PLANAR_SH(1),  ANYFLAVOR|ANYSWAP|ANYENDIAN|ANYEXTRA|ANYCHANNELS|ANYSPACE,  UnrollPlanarWords},
2995     { BYTES_SH(2),  ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|ANYENDIAN|ANYEXTRA|ANYCHANNELS|ANYSPACE,  UnrollAnyWords},
2996 };
2997
2998
2999
3000 static cmsFormattersFloat InputFormattersFloat[] = {
3001
3002     //    Type                                          Mask                  Function
3003     //  ----------------------------   ------------------------------------  ----------------------------
3004     {     TYPE_Lab_DBL,                                ANYPLANAR|ANYEXTRA,   UnrollLabDoubleToFloat},
3005     {     TYPE_Lab_FLT,                                ANYPLANAR|ANYEXTRA,   UnrollLabFloatToFloat},
3006
3007     {     TYPE_XYZ_DBL,                                ANYPLANAR|ANYEXTRA,   UnrollXYZDoubleToFloat},
3008     {     TYPE_XYZ_FLT,                                ANYPLANAR|ANYEXTRA,   UnrollXYZFloatToFloat},
3009
3010     {     FLOAT_SH(1)|BYTES_SH(4), ANYPLANAR|ANYSWAPFIRST|ANYSWAP|ANYEXTRA|
3011                                                       ANYCHANNELS|ANYSPACE,  UnrollFloatsToFloat},
3012
3013     {     FLOAT_SH(1)|BYTES_SH(0), ANYPLANAR|ANYSWAPFIRST|ANYSWAP|ANYEXTRA|
3014                                                         ANYCHANNELS|ANYSPACE,  UnrollDoublesToFloat},
3015 #ifndef CMS_NO_HALF_SUPPORT 
3016     {     FLOAT_SH(1)|BYTES_SH(2), ANYPLANAR|ANYSWAPFIRST|ANYSWAP|ANYEXTRA|
3017                                                         ANYCHANNELS|ANYSPACE,  UnrollHalfToFloat},
3018 #endif
3019 };
3020
3021
3022 // Bit fields set to one in the mask are not compared
3023 static
3024 cmsFormatter _cmsGetStockInputFormatter(cmsUInt32Number dwInput, cmsUInt32Number dwFlags)
3025 {
3026     cmsUInt32Number i;
3027     cmsFormatter fr;
3028
3029     switch (dwFlags) {
3030
3031     case CMS_PACK_FLAGS_16BITS: {
3032         for (i=0; i < sizeof(InputFormatters16) / sizeof(cmsFormatters16); i++) {
3033             cmsFormatters16* f = InputFormatters16 + i;
3034
3035             if ((dwInput & ~f ->Mask) == f ->Type) {
3036                 fr.Fmt16 = f ->Frm;
3037                 return fr;
3038             }
3039         }
3040     }
3041     break;
3042
3043     case CMS_PACK_FLAGS_FLOAT: {
3044         for (i=0; i < sizeof(InputFormattersFloat) / sizeof(cmsFormattersFloat); i++) {
3045             cmsFormattersFloat* f = InputFormattersFloat + i;
3046
3047             if ((dwInput & ~f ->Mask) == f ->Type) {
3048                 fr.FmtFloat = f ->Frm;
3049                 return fr;
3050             }
3051         }
3052     }
3053     break;
3054
3055     default:;
3056
3057     }
3058
3059     fr.Fmt16 = NULL;
3060     return fr;
3061 }
3062
3063 static cmsFormatters16 OutputFormatters16[] = {
3064     //    Type                                          Mask                  Function
3065     //  ----------------------------   ------------------------------------  ----------------------------
3066
3067     { TYPE_Lab_DBL,                                      ANYPLANAR|ANYEXTRA,  PackLabDoubleFrom16},
3068     { TYPE_XYZ_DBL,                                      ANYPLANAR|ANYEXTRA,  PackXYZDoubleFrom16},
3069
3070     { TYPE_Lab_FLT,                                      ANYPLANAR|ANYEXTRA,  PackLabFloatFrom16},
3071     { TYPE_XYZ_FLT,                                      ANYPLANAR|ANYEXTRA,  PackXYZFloatFrom16},
3072     
3073     { FLOAT_SH(1)|BYTES_SH(0),      ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|
3074                                     ANYCHANNELS|ANYPLANAR|ANYEXTRA|ANYSPACE,  PackDoubleFrom16},
3075     { FLOAT_SH(1)|BYTES_SH(4),      ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|
3076                                     ANYCHANNELS|ANYPLANAR|ANYEXTRA|ANYSPACE,  PackFloatFrom16},
3077 #ifndef CMS_NO_HALF_SUPPORT 
3078     { FLOAT_SH(1)|BYTES_SH(2),      ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|
3079                                     ANYCHANNELS|ANYPLANAR|ANYEXTRA|ANYSPACE,  PackHalfFrom16},
3080 #endif
3081
3082     { CHANNELS_SH(1)|BYTES_SH(1),                                  ANYSPACE,  Pack1Byte},
3083     { CHANNELS_SH(1)|BYTES_SH(1)|EXTRA_SH(1),                      ANYSPACE,  Pack1ByteSkip1},
3084     { CHANNELS_SH(1)|BYTES_SH(1)|EXTRA_SH(1)|SWAPFIRST_SH(1),      ANYSPACE,  Pack1ByteSkip1SwapFirst},
3085
3086     { CHANNELS_SH(1)|BYTES_SH(1)|FLAVOR_SH(1),                     ANYSPACE,  Pack1ByteReversed},
3087
3088     { TYPE_LabV2_8,                                                       0,  PackLabV2_8 },
3089     { TYPE_ALabV2_8,                                                      0,  PackALabV2_8 },
3090     { TYPE_LabV2_16,                                                      0,  PackLabV2_16 },
3091
3092     { CHANNELS_SH(3)|BYTES_SH(1)|OPTIMIZED_SH(1),                  ANYSPACE,  Pack3BytesOptimized},
3093     { CHANNELS_SH(3)|BYTES_SH(1)|EXTRA_SH(1)|OPTIMIZED_SH(1),      ANYSPACE,  Pack3BytesAndSkip1Optimized},
3094     { CHANNELS_SH(3)|BYTES_SH(1)|EXTRA_SH(1)|SWAPFIRST_SH(1)|OPTIMIZED_SH(1),
3095                                                                    ANYSPACE,  Pack3BytesAndSkip1SwapFirstOptimized},
3096     { CHANNELS_SH(3)|BYTES_SH(1)|EXTRA_SH(1)|DOSWAP_SH(1)|SWAPFIRST_SH(1)|OPTIMIZED_SH(1),
3097                                                                    ANYSPACE,  Pack3BytesAndSkip1SwapSwapFirstOptimized},
3098     { CHANNELS_SH(3)|BYTES_SH(1)|DOSWAP_SH(1)|EXTRA_SH(1)|OPTIMIZED_SH(1),
3099                                                                    ANYSPACE,  Pack3BytesAndSkip1SwapOptimized},
3100     { CHANNELS_SH(3)|BYTES_SH(1)|DOSWAP_SH(1)|OPTIMIZED_SH(1),     ANYSPACE,  Pack3BytesSwapOptimized},
3101
3102
3103
3104     { CHANNELS_SH(3)|BYTES_SH(1),                                  ANYSPACE,  Pack3Bytes},
3105     { CHANNELS_SH(3)|BYTES_SH(1)|EXTRA_SH(1),                      ANYSPACE,  Pack3BytesAndSkip1},
3106     { CHANNELS_SH(3)|BYTES_SH(1)|EXTRA_SH(1)|SWAPFIRST_SH(1),      ANYSPACE,  Pack3BytesAndSkip1SwapFirst},
3107     { CHANNELS_SH(3)|BYTES_SH(1)|EXTRA_SH(1)|DOSWAP_SH(1)|SWAPFIRST_SH(1),
3108                                                                    ANYSPACE,  Pack3BytesAndSkip1SwapSwapFirst},
3109     { CHANNELS_SH(3)|BYTES_SH(1)|DOSWAP_SH(1)|EXTRA_SH(1),         ANYSPACE,  Pack3BytesAndSkip1Swap},
3110     { CHANNELS_SH(3)|BYTES_SH(1)|DOSWAP_SH(1),                     ANYSPACE,  Pack3BytesSwap},
3111     { CHANNELS_SH(6)|BYTES_SH(1),                                  ANYSPACE,  Pack6Bytes},
3112     { CHANNELS_SH(6)|BYTES_SH(1)|DOSWAP_SH(1),                     ANYSPACE,  Pack6BytesSwap},
3113     { CHANNELS_SH(4)|BYTES_SH(1),                                  ANYSPACE,  Pack4Bytes},
3114     { CHANNELS_SH(4)|BYTES_SH(1)|FLAVOR_SH(1),                     ANYSPACE,  Pack4BytesReverse},
3115     { CHANNELS_SH(4)|BYTES_SH(1)|SWAPFIRST_SH(1),                  ANYSPACE,  Pack4BytesSwapFirst},
3116     { CHANNELS_SH(4)|BYTES_SH(1)|DOSWAP_SH(1),                     ANYSPACE,  Pack4BytesSwap},
3117     { CHANNELS_SH(4)|BYTES_SH(1)|DOSWAP_SH(1)|SWAPFIRST_SH(1),     ANYSPACE,  Pack4BytesSwapSwapFirst},
3118
3119     { BYTES_SH(1),                 ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|ANYEXTRA|ANYCHANNELS|ANYSPACE, PackAnyBytes},
3120     { BYTES_SH(1)|PLANAR_SH(1),    ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|ANYEXTRA|ANYCHANNELS|ANYSPACE, PackPlanarBytes},
3121
3122     { CHANNELS_SH(1)|BYTES_SH(2),                                  ANYSPACE,  Pack1Word},
3123     { CHANNELS_SH(1)|BYTES_SH(2)|EXTRA_SH(1),                      ANYSPACE,  Pack1WordSkip1},
3124     { CHANNELS_SH(1)|BYTES_SH(2)|EXTRA_SH(1)|SWAPFIRST_SH(1),      ANYSPACE,  Pack1WordSkip1SwapFirst},
3125     { CHANNELS_SH(1)|BYTES_SH(2)|FLAVOR_SH(1),                     ANYSPACE,  Pack1WordReversed},
3126     { CHANNELS_SH(1)|BYTES_SH(2)|ENDIAN16_SH(1),                   ANYSPACE,  Pack1WordBigEndian},
3127     { CHANNELS_SH(3)|BYTES_SH(2),                                  ANYSPACE,  Pack3Words},
3128     { CHANNELS_SH(3)|BYTES_SH(2)|DOSWAP_SH(1),                     ANYSPACE,  Pack3WordsSwap},
3129     { CHANNELS_SH(3)|BYTES_SH(2)|ENDIAN16_SH(1),                   ANYSPACE,  Pack3WordsBigEndian},
3130     { CHANNELS_SH(3)|BYTES_SH(2)|EXTRA_SH(1),                      ANYSPACE,  Pack3WordsAndSkip1},
3131     { CHANNELS_SH(3)|BYTES_SH(2)|EXTRA_SH(1)|DOSWAP_SH(1),         ANYSPACE,  Pack3WordsAndSkip1Swap},
3132     { CHANNELS_SH(3)|BYTES_SH(2)|EXTRA_SH(1)|SWAPFIRST_SH(1),      ANYSPACE,  Pack3WordsAndSkip1SwapFirst},
3133
3134     { CHANNELS_SH(3)|BYTES_SH(2)|EXTRA_SH(1)|DOSWAP_SH(1)|SWAPFIRST_SH(1),
3135                                                                    ANYSPACE,  Pack3WordsAndSkip1SwapSwapFirst},
3136
3137     { CHANNELS_SH(4)|BYTES_SH(2),                                  ANYSPACE,  Pack4Words},
3138     { CHANNELS_SH(4)|BYTES_SH(2)|FLAVOR_SH(1),                     ANYSPACE,  Pack4WordsReverse},
3139     { CHANNELS_SH(4)|BYTES_SH(2)|DOSWAP_SH(1),                     ANYSPACE,  Pack4WordsSwap},
3140     { CHANNELS_SH(4)|BYTES_SH(2)|ENDIAN16_SH(1),                   ANYSPACE,  Pack4WordsBigEndian},
3141
3142     { CHANNELS_SH(6)|BYTES_SH(2),                                  ANYSPACE,  Pack6Words},
3143     { CHANNELS_SH(6)|BYTES_SH(2)|DOSWAP_SH(1),                     ANYSPACE,  Pack6WordsSwap},
3144
3145     { BYTES_SH(2)|PLANAR_SH(1),     ANYFLAVOR|ANYENDIAN|ANYSWAP|ANYEXTRA|ANYCHANNELS|ANYSPACE, PackPlanarWords},
3146     { BYTES_SH(2),                  ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|ANYENDIAN|ANYEXTRA|ANYCHANNELS|ANYSPACE, PackAnyWords}
3147
3148 };
3149
3150
3151 static cmsFormattersFloat OutputFormattersFloat[] = {
3152     //    Type                                          Mask                                 Function
3153     //  ----------------------------   ---------------------------------------------------  ----------------------------
3154     {     TYPE_Lab_FLT,                                                ANYPLANAR|ANYEXTRA,   PackLabFloatFromFloat},
3155     {     TYPE_XYZ_FLT,                                                ANYPLANAR|ANYEXTRA,   PackXYZFloatFromFloat},
3156
3157     {     TYPE_Lab_DBL,                                                ANYPLANAR|ANYEXTRA,   PackLabDoubleFromFloat},
3158     {     TYPE_XYZ_DBL,                                                ANYPLANAR|ANYEXTRA,   PackXYZDoubleFromFloat},
3159
3160     {     FLOAT_SH(1)|BYTES_SH(4), ANYPLANAR|
3161                              ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|ANYEXTRA|ANYCHANNELS|ANYSPACE,   PackFloatsFromFloat },
3162     {     FLOAT_SH(1)|BYTES_SH(0), ANYPLANAR|
3163                              ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|ANYEXTRA|ANYCHANNELS|ANYSPACE,   PackDoublesFromFloat },
3164 #ifndef CMS_NO_HALF_SUPPORT 
3165     {     FLOAT_SH(1)|BYTES_SH(2),                                   
3166                              ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|ANYEXTRA|ANYCHANNELS|ANYSPACE,   PackHalfFromFloat },
3167 #endif
3168
3169
3170
3171 };
3172
3173
3174 // Bit fields set to one in the mask are not compared
3175 static
3176 cmsFormatter _cmsGetStockOutputFormatter(cmsUInt32Number dwInput, cmsUInt32Number dwFlags)
3177 {
3178     cmsUInt32Number i;
3179     cmsFormatter fr;
3180
3181
3182     switch (dwFlags)
3183     {
3184
3185      case CMS_PACK_FLAGS_16BITS: {
3186
3187         for (i=0; i < sizeof(OutputFormatters16) / sizeof(cmsFormatters16); i++) {
3188             cmsFormatters16* f = OutputFormatters16 + i;
3189
3190             if ((dwInput & ~f ->Mask) == f ->Type) {
3191                 fr.Fmt16 = f ->Frm;
3192                 return fr;
3193             }
3194         }
3195         }
3196         break;
3197
3198     case CMS_PACK_FLAGS_FLOAT: {
3199
3200         for (i=0; i < sizeof(OutputFormattersFloat) / sizeof(cmsFormattersFloat); i++) {
3201             cmsFormattersFloat* f = OutputFormattersFloat + i;
3202
3203             if ((dwInput & ~f ->Mask) == f ->Type) {
3204                 fr.FmtFloat = f ->Frm;
3205                 return fr;
3206             }
3207         }
3208         }
3209         break;
3210
3211     default:;
3212
3213     }
3214
3215     fr.Fmt16 = NULL;
3216     return fr;
3217 }
3218
3219
3220 typedef struct _cms_formatters_factory_list {
3221
3222     cmsFormatterFactory Factory;
3223     struct _cms_formatters_factory_list *Next;
3224
3225 } cmsFormattersFactoryList;
3226
3227 _cmsFormattersPluginChunkType _cmsFormattersPluginChunk = { NULL };
3228
3229
3230 // Duplicates the zone of memory used by the plug-in in the new context
3231 static
3232 void DupFormatterFactoryList(struct _cmsContext_struct* ctx, 
3233                                                const struct _cmsContext_struct* src)
3234 {
3235    _cmsFormattersPluginChunkType newHead = { NULL };
3236    cmsFormattersFactoryList*  entry;
3237    cmsFormattersFactoryList*  Anterior = NULL;
3238    _cmsFormattersPluginChunkType* head = (_cmsFormattersPluginChunkType*) src->chunks[FormattersPlugin];
3239
3240      _cmsAssert(head != NULL);
3241
3242    // Walk the list copying all nodes
3243    for (entry = head->FactoryList;
3244        entry != NULL;
3245        entry = entry ->Next) {
3246
3247            cmsFormattersFactoryList *newEntry = ( cmsFormattersFactoryList *) _cmsSubAllocDup(ctx ->MemPool, entry, sizeof(cmsFormattersFactoryList));
3248
3249            if (newEntry == NULL) 
3250                return;
3251
3252            // We want to keep the linked list order, so this is a little bit tricky
3253            newEntry -> Next = NULL;
3254            if (Anterior)
3255                Anterior -> Next = newEntry;
3256
3257            Anterior = newEntry;
3258
3259            if (newHead.FactoryList == NULL)
3260                newHead.FactoryList = newEntry;
3261    }
3262
3263    ctx ->chunks[FormattersPlugin] = _cmsSubAllocDup(ctx->MemPool, &newHead, sizeof(_cmsFormattersPluginChunkType));
3264 }
3265
3266 // The interpolation plug-in memory chunk allocator/dup
3267 void _cmsAllocFormattersPluginChunk(struct _cmsContext_struct* ctx, 
3268                                     const struct _cmsContext_struct* src)
3269 {
3270       _cmsAssert(ctx != NULL);
3271
3272      if (src != NULL) {
3273         
3274          // Duplicate the LIST
3275          DupFormatterFactoryList(ctx, src);
3276      }
3277      else {
3278           static _cmsFormattersPluginChunkType FormattersPluginChunk = { NULL };
3279           ctx ->chunks[FormattersPlugin] = _cmsSubAllocDup(ctx ->MemPool, &FormattersPluginChunk, sizeof(_cmsFormattersPluginChunkType));
3280      }
3281 }
3282
3283
3284
3285 // Formatters management
3286 cmsBool  _cmsRegisterFormattersPlugin(cmsContext ContextID, cmsPluginBase* Data)
3287 {
3288     _cmsFormattersPluginChunkType* ctx = ( _cmsFormattersPluginChunkType*) _cmsContextGetClientChunk(ContextID, FormattersPlugin);
3289     cmsPluginFormatters* Plugin = (cmsPluginFormatters*) Data;
3290     cmsFormattersFactoryList* fl ;
3291
3292     // Reset to built-in defaults
3293     if (Data == NULL) {
3294
3295           ctx ->FactoryList = NULL;
3296           return TRUE;
3297     }
3298
3299     fl = (cmsFormattersFactoryList*) _cmsPluginMalloc(ContextID, sizeof(cmsFormattersFactoryList));
3300     if (fl == NULL) return FALSE;
3301
3302     fl ->Factory    = Plugin ->FormattersFactory;
3303
3304     fl ->Next = ctx -> FactoryList;
3305     ctx ->FactoryList = fl;
3306
3307     return TRUE;
3308 }
3309
3310 cmsFormatter _cmsGetFormatter(cmsContext ContextID,
3311                              cmsUInt32Number Type,         // Specific type, i.e. TYPE_RGB_8
3312                              cmsFormatterDirection Dir,
3313                              cmsUInt32Number dwFlags)
3314 {
3315     _cmsFormattersPluginChunkType* ctx = ( _cmsFormattersPluginChunkType*) _cmsContextGetClientChunk(ContextID, FormattersPlugin);
3316     cmsFormattersFactoryList* f;
3317
3318     for (f =ctx->FactoryList; f != NULL; f = f ->Next) {
3319
3320         cmsFormatter fn = f ->Factory(Type, Dir, dwFlags);
3321         if (fn.Fmt16 != NULL) return fn;
3322     }
3323
3324     // Revert to default
3325     if (Dir == cmsFormatterInput)
3326         return _cmsGetStockInputFormatter(Type, dwFlags);
3327     else
3328         return _cmsGetStockOutputFormatter(Type, dwFlags);
3329 }
3330
3331
3332 // Return whatever given formatter refers to float values
3333 cmsBool  _cmsFormatterIsFloat(cmsUInt32Number Type)
3334 {
3335     return T_FLOAT(Type) ? TRUE : FALSE;
3336 }
3337
3338 // Return whatever given formatter refers to 8 bits
3339 cmsBool  _cmsFormatterIs8bit(cmsUInt32Number Type)
3340 {
3341     int Bytes = T_BYTES(Type);
3342
3343     return (Bytes == 1);
3344 }
3345
3346 // Build a suitable formatter for the colorspace of this profile
3347 cmsUInt32Number CMSEXPORT cmsFormatterForColorspaceOfProfile(cmsHPROFILE hProfile, cmsUInt32Number nBytes, cmsBool lIsFloat)
3348 {
3349
3350     cmsColorSpaceSignature ColorSpace      = cmsGetColorSpace(hProfile);
3351     cmsUInt32Number        ColorSpaceBits  = _cmsLCMScolorSpace(ColorSpace);
3352     cmsUInt32Number        nOutputChans    = cmsChannelsOf(ColorSpace);
3353     cmsUInt32Number        Float           = lIsFloat ? 1 : 0;
3354
3355     // Create a fake formatter for result
3356     return FLOAT_SH(Float) | COLORSPACE_SH(ColorSpaceBits) | BYTES_SH(nBytes) | CHANNELS_SH(nOutputChans);
3357 }
3358
3359 // Build a suitable formatter for the colorspace of this profile
3360 cmsUInt32Number CMSEXPORT cmsFormatterForPCSOfProfile(cmsHPROFILE hProfile, cmsUInt32Number nBytes, cmsBool lIsFloat)
3361 {
3362
3363     cmsColorSpaceSignature ColorSpace      = cmsGetPCS(hProfile);
3364     int                    ColorSpaceBits  = _cmsLCMScolorSpace(ColorSpace);
3365     cmsUInt32Number        nOutputChans    = cmsChannelsOf(ColorSpace);
3366     cmsUInt32Number        Float           = lIsFloat ? 1 : 0;
3367
3368     // Create a fake formatter for result
3369     return FLOAT_SH(Float) | COLORSPACE_SH(ColorSpaceBits) | BYTES_SH(nBytes) | CHANNELS_SH(nOutputChans);
3370 }
3371