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