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