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