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