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