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* PackBytesFromFloat(_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     cmsUInt8Number* swap1 = (cmsUInt8Number*)output;
2997     cmsFloat64Number v = 0;
2998     cmsUInt8Number vv = 0;
2999     cmsUInt32Number i, start = 0;
3000 
3001     if (ExtraFirst)
3002         start = Extra;
3003 
3004     for (i = 0; i < nChan; i++) {
3005 
3006         cmsUInt32Number index = DoSwap ? (nChan - i - 1) : i;
3007 
3008         v = wOut[index] * 65535.0;
3009 
3010         if (Reverse)
3011             v = 65535.0 - v;
3012 
3013         vv =  FROM_16_TO_8(_cmsQuickSaturateWord(v));
3014 
3015         if (Planar)
3016             ((cmsUInt8Number*)output)[(i + start) * Stride] = vv;
3017         else
3018             ((cmsUInt8Number*)output)[i + start] = vv;
3019     }
3020 
3021 
3022     if (Extra == 0 && SwapFirst) {
3023 
3024         memmove(swap1 + 1, swap1, (nChan - 1) * sizeof(cmsUInt8Number));
3025         *swap1 = vv;
3026     }
3027 
3028     if (T_PLANAR(info->OutputFormat))
3029         return output + sizeof(cmsUInt8Number);
3030     else
3031         return output + (nChan + Extra) * sizeof(cmsUInt8Number);
3032 }
3033 
3034 static
3035 cmsUInt8Number* PackWordsFromFloat(_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     cmsUInt16Number* swap1 = (cmsUInt16Number*)output;
3048     cmsFloat64Number v = 0;
3049     cmsUInt16Number vv = 0;
3050     cmsUInt32Number i, start = 0;
3051 
3052     if (ExtraFirst)
3053         start = Extra;
3054 
3055     for (i = 0; i < nChan; i++) {
3056 
3057         cmsUInt32Number index = DoSwap ? (nChan - i - 1) : i;
3058 
3059         v = wOut[index] * 65535.0;
3060 
3061         if (Reverse)
3062             v = 65535.0 - v;
3063 
3064         vv = _cmsQuickSaturateWord(v);
3065 
3066         if (Planar)
3067             ((cmsUInt16Number*)output)[(i + start) * Stride] = vv;
3068         else
3069             ((cmsUInt16Number*)output)[i + start] = vv;
3070     }
3071 
3072     if (Extra == 0 && SwapFirst) {
3073 
3074         memmove(swap1 + 1, swap1, (nChan - 1) * sizeof(cmsUInt16Number));
3075         *swap1 = vv;
3076     }
3077 
3078     if (T_PLANAR(info->OutputFormat))
3079         return output + sizeof(cmsUInt16Number);
3080     else
3081         return output + (nChan + Extra) * sizeof(cmsUInt16Number);
3082 }
3083 
3084 
3085 static
3086 cmsUInt8Number* PackFloatsFromFloat(_cmsTRANSFORM* info,
3087                                     cmsFloat32Number wOut[],
3088                                     cmsUInt8Number* output,
3089                                     cmsUInt32Number Stride)
3090 {
3091        cmsUInt32Number nChan = T_CHANNELS(info->OutputFormat);
3092        cmsUInt32Number DoSwap = T_DOSWAP(info->OutputFormat);
3093        cmsUInt32Number Reverse = T_FLAVOR(info->OutputFormat);
3094        cmsUInt32Number Extra = T_EXTRA(info->OutputFormat);
3095        cmsUInt32Number SwapFirst = T_SWAPFIRST(info->OutputFormat);
3096        cmsUInt32Number Planar = T_PLANAR(info->OutputFormat);
3097        cmsUInt32Number ExtraFirst = DoSwap ^ SwapFirst;
3098        cmsFloat64Number maximum = IsInkSpace(info->OutputFormat) ? 100.0 : 1.0;
3099        cmsFloat32Number* swap1 = (cmsFloat32Number*)output;
3100        cmsFloat64Number v = 0;
3101        cmsUInt32Number i, start = 0;
3102 
3103        Stride /= PixelSize(info->OutputFormat);
3104 
3105        if (ExtraFirst)
3106               start = Extra;
3107 
3108        for (i = 0; i < nChan; i++) {
3109 
3110               cmsUInt32Number index = DoSwap ? (nChan - i - 1) : i;
3111 
3112               v = wOut[index] * maximum;
3113 
3114               if (Reverse)
3115                      v = maximum - v;
3116 
3117               if (Planar)
3118                      ((cmsFloat32Number*)output)[(i + start)* Stride] = (cmsFloat32Number)v;
3119               else
3120                      ((cmsFloat32Number*)output)[i + start] = (cmsFloat32Number)v;
3121        }
3122 
3123 
3124        if (Extra == 0 && SwapFirst) {
3125 
3126               memmove(swap1 + 1, swap1, (nChan - 1)* sizeof(cmsFloat32Number));
3127               *swap1 = (cmsFloat32Number)v;
3128        }
3129 
3130        if (T_PLANAR(info->OutputFormat))
3131               return output + sizeof(cmsFloat32Number);
3132        else
3133               return output + (nChan + Extra) * sizeof(cmsFloat32Number);
3134 }
3135 
3136 static
3137 cmsUInt8Number* PackDoublesFromFloat(_cmsTRANSFORM* info,
3138                                     cmsFloat32Number wOut[],
3139                                     cmsUInt8Number* output,
3140                                     cmsUInt32Number Stride)
3141 {
3142        cmsUInt32Number nChan      = T_CHANNELS(info->OutputFormat);
3143        cmsUInt32Number DoSwap     = T_DOSWAP(info->OutputFormat);
3144        cmsUInt32Number Reverse    = T_FLAVOR(info->OutputFormat);
3145        cmsUInt32Number Extra      = T_EXTRA(info->OutputFormat);
3146        cmsUInt32Number SwapFirst  = T_SWAPFIRST(info->OutputFormat);
3147        cmsUInt32Number Planar     = T_PLANAR(info->OutputFormat);
3148        cmsUInt32Number ExtraFirst = DoSwap ^ SwapFirst;
3149        cmsFloat64Number maximum = IsInkSpace(info->OutputFormat) ? 100.0 : 1.0;
3150        cmsFloat64Number v = 0;
3151        cmsFloat64Number* swap1 = (cmsFloat64Number*)output;
3152        cmsUInt32Number i, start = 0;
3153 
3154        Stride /= PixelSize(info->OutputFormat);
3155 
3156        if (ExtraFirst)
3157               start = Extra;
3158 
3159        for (i = 0; i < nChan; i++) {
3160 
3161               cmsUInt32Number index = DoSwap ? (nChan - i - 1) : i;
3162 
3163               v = wOut[index] * maximum;
3164 
3165               if (Reverse)
3166                      v = maximum - v;
3167 
3168               if (Planar)
3169                      ((cmsFloat64Number*)output)[(i + start) * Stride] = v;
3170               else
3171                      ((cmsFloat64Number*)output)[i + start] = v;
3172        }
3173 
3174        if (Extra == 0 && SwapFirst) {
3175 
3176               memmove(swap1 + 1, swap1, (nChan - 1)* sizeof(cmsFloat64Number));
3177               *swap1 = v;
3178        }
3179 
3180 
3181        if (T_PLANAR(info->OutputFormat))
3182               return output + sizeof(cmsFloat64Number);
3183        else
3184               return output + (nChan + Extra) * sizeof(cmsFloat64Number);
3185 
3186 }
3187 
3188 static
3189 cmsUInt8Number* PackLabFloatFromFloat(_cmsTRANSFORM* Info,
3190                                       cmsFloat32Number wOut[],
3191                                       cmsUInt8Number* output,
3192                                       cmsUInt32Number Stride)
3193 {
3194     cmsFloat32Number* Out = (cmsFloat32Number*) output;
3195 
3196     if (T_PLANAR(Info -> OutputFormat)) {
3197 
3198         Stride /= PixelSize(Info->OutputFormat);
3199 
3200         Out[0]        = (cmsFloat32Number) (wOut[0] * 100.0);
3201         Out[Stride]   = (cmsFloat32Number) (wOut[1] * 255.0 - 128.0);
3202         Out[Stride*2] = (cmsFloat32Number) (wOut[2] * 255.0 - 128.0);
3203 
3204         return output + sizeof(cmsFloat32Number);
3205     }
3206     else {
3207 
3208         Out[0] = (cmsFloat32Number) (wOut[0] * 100.0);
3209         Out[1] = (cmsFloat32Number) (wOut[1] * 255.0 - 128.0);
3210         Out[2] = (cmsFloat32Number) (wOut[2] * 255.0 - 128.0);
3211 
3212         return output + (sizeof(cmsFloat32Number)*3 + T_EXTRA(Info ->OutputFormat) * sizeof(cmsFloat32Number));
3213     }
3214 
3215 }
3216 
3217 
3218 static
3219 cmsUInt8Number* PackLabDoubleFromFloat(_cmsTRANSFORM* Info,
3220                                        cmsFloat32Number wOut[],
3221                                        cmsUInt8Number* output,
3222                                        cmsUInt32Number Stride)
3223 {
3224     cmsFloat64Number* Out = (cmsFloat64Number*) output;
3225 
3226     if (T_PLANAR(Info -> OutputFormat)) {
3227 
3228         Stride /= PixelSize(Info->OutputFormat);
3229 
3230         Out[0]        = (cmsFloat64Number) (wOut[0] * 100.0);
3231         Out[Stride]   = (cmsFloat64Number) (wOut[1] * 255.0 - 128.0);
3232         Out[Stride*2] = (cmsFloat64Number) (wOut[2] * 255.0 - 128.0);
3233 
3234         return output + sizeof(cmsFloat64Number);
3235     }
3236     else {
3237 
3238         Out[0] = (cmsFloat64Number) (wOut[0] * 100.0);
3239         Out[1] = (cmsFloat64Number) (wOut[1] * 255.0 - 128.0);
3240         Out[2] = (cmsFloat64Number) (wOut[2] * 255.0 - 128.0);
3241 
3242         return output + (sizeof(cmsFloat64Number)*3 + T_EXTRA(Info ->OutputFormat) * sizeof(cmsFloat64Number));
3243     }
3244 
3245 }
3246 
3247 
3248 static
3249 cmsUInt8Number* PackEncodedBytesLabV2FromFloat(_cmsTRANSFORM* Info,
3250                                            cmsFloat32Number wOut[],
3251                                            cmsUInt8Number* output,
3252                                            cmsUInt32Number Stride)
3253 {
3254     cmsCIELab Lab;
3255     cmsUInt16Number wlab[3];
3256 
3257     Lab.L = (cmsFloat64Number)(wOut[0] * 100.0);
3258     Lab.a = (cmsFloat64Number)(wOut[1] * 255.0 - 128.0);
3259     Lab.b = (cmsFloat64Number)(wOut[2] * 255.0 - 128.0);
3260 
3261     cmsFloat2LabEncoded(wlab, &Lab);
3262 
3263     if (T_PLANAR(Info -> OutputFormat)) {
3264 
3265         Stride /= PixelSize(Info->OutputFormat);
3266 
3267         output[0]        = wlab[0] >> 8;
3268         output[Stride]   = wlab[1] >> 8;
3269         output[Stride*2] = wlab[2] >> 8;
3270 
3271         return output + 1;
3272     }
3273     else {
3274 
3275         output[0] = wlab[0] >> 8;
3276         output[1] = wlab[1] >> 8;
3277         output[2] = wlab[2] >> 8;
3278 
3279         return output + (3 + T_EXTRA(Info ->OutputFormat));
3280     }
3281 }
3282 
3283 static
3284 cmsUInt8Number* PackEncodedWordsLabV2FromFloat(_cmsTRANSFORM* Info,
3285                                            cmsFloat32Number wOut[],
3286                                            cmsUInt8Number* output,
3287                                            cmsUInt32Number Stride)
3288 {
3289     cmsCIELab Lab;
3290     cmsUInt16Number wlab[3];
3291 
3292     Lab.L = (cmsFloat64Number)(wOut[0] * 100.0);
3293     Lab.a = (cmsFloat64Number)(wOut[1] * 255.0 - 128.0);
3294     Lab.b = (cmsFloat64Number)(wOut[2] * 255.0 - 128.0);
3295 
3296     cmsFloat2LabEncodedV2(wlab, &Lab);
3297 
3298     if (T_PLANAR(Info -> OutputFormat)) {
3299 
3300         Stride /= PixelSize(Info->OutputFormat);
3301 
3302         ((cmsUInt16Number*) output)[0]        = wlab[0];
3303         ((cmsUInt16Number*) output)[Stride]   = wlab[1];
3304         ((cmsUInt16Number*) output)[Stride*2] = wlab[2];
3305 
3306         return output + sizeof(cmsUInt16Number);
3307     }
3308     else {
3309 
3310          ((cmsUInt16Number*) output)[0] = wlab[0];
3311          ((cmsUInt16Number*) output)[1] = wlab[1];
3312          ((cmsUInt16Number*) output)[2] = wlab[2];
3313 
3314         return output + (3 + T_EXTRA(Info ->OutputFormat)) * sizeof(cmsUInt16Number);
3315     }
3316 }
3317 
3318 
3319 // From 0..1 range to 0..MAX_ENCODEABLE_XYZ
3320 static
3321 cmsUInt8Number* PackXYZFloatFromFloat(_cmsTRANSFORM* Info,
3322                                       cmsFloat32Number wOut[],
3323                                       cmsUInt8Number* output,
3324                                       cmsUInt32Number Stride)
3325 {
3326     cmsFloat32Number* Out = (cmsFloat32Number*) output;
3327 
3328     if (T_PLANAR(Info -> OutputFormat)) {
3329 
3330         Stride /= PixelSize(Info->OutputFormat);
3331 
3332         Out[0]        = (cmsFloat32Number) (wOut[0] * MAX_ENCODEABLE_XYZ);
3333         Out[Stride]   = (cmsFloat32Number) (wOut[1] * MAX_ENCODEABLE_XYZ);
3334         Out[Stride*2] = (cmsFloat32Number) (wOut[2] * MAX_ENCODEABLE_XYZ);
3335 
3336         return output + sizeof(cmsFloat32Number);
3337     }
3338     else {
3339 
3340         Out[0] = (cmsFloat32Number) (wOut[0] * MAX_ENCODEABLE_XYZ);
3341         Out[1] = (cmsFloat32Number) (wOut[1] * MAX_ENCODEABLE_XYZ);
3342         Out[2] = (cmsFloat32Number) (wOut[2] * MAX_ENCODEABLE_XYZ);
3343 
3344         return output + (sizeof(cmsFloat32Number)*3 + T_EXTRA(Info ->OutputFormat) * sizeof(cmsFloat32Number));
3345     }
3346 
3347 }
3348 
3349 // Same, but convert to double
3350 static
3351 cmsUInt8Number* PackXYZDoubleFromFloat(_cmsTRANSFORM* Info,
3352                                        cmsFloat32Number wOut[],
3353                                        cmsUInt8Number* output,
3354                                        cmsUInt32Number Stride)
3355 {
3356     cmsFloat64Number* Out = (cmsFloat64Number*) output;
3357 
3358     if (T_PLANAR(Info -> OutputFormat)) {
3359 
3360         Stride /= PixelSize(Info->OutputFormat);
3361 
3362         Out[0]        = (cmsFloat64Number) (wOut[0] * MAX_ENCODEABLE_XYZ);
3363         Out[Stride]   = (cmsFloat64Number) (wOut[1] * MAX_ENCODEABLE_XYZ);
3364         Out[Stride*2] = (cmsFloat64Number) (wOut[2] * MAX_ENCODEABLE_XYZ);
3365 
3366         return output + sizeof(cmsFloat64Number);
3367     }
3368     else {
3369 
3370         Out[0] = (cmsFloat64Number) (wOut[0] * MAX_ENCODEABLE_XYZ);
3371         Out[1] = (cmsFloat64Number) (wOut[1] * MAX_ENCODEABLE_XYZ);
3372         Out[2] = (cmsFloat64Number) (wOut[2] * MAX_ENCODEABLE_XYZ);
3373 
3374         return output + (sizeof(cmsFloat64Number)*3 + T_EXTRA(Info ->OutputFormat) * sizeof(cmsFloat64Number));
3375     }
3376 
3377 }
3378 
3379 
3380 // ----------------------------------------------------------------------------------------------------------------
3381 
3382 #ifndef CMS_NO_HALF_SUPPORT
3383 
3384 // Decodes an stream of half floats to wIn[] described by input format
3385 
3386 static
3387 cmsUInt8Number* UnrollHalfTo16(CMSREGISTER _cmsTRANSFORM* info,
3388                                 CMSREGISTER cmsUInt16Number wIn[],
3389                                 CMSREGISTER cmsUInt8Number* accum,
3390                                 CMSREGISTER cmsUInt32Number Stride)
3391 {
3392 
3393     cmsUInt32Number nChan      = T_CHANNELS(info -> InputFormat);
3394     cmsUInt32Number DoSwap     = T_DOSWAP(info ->InputFormat);
3395     cmsUInt32Number Reverse    = T_FLAVOR(info ->InputFormat);
3396     cmsUInt32Number SwapFirst  = T_SWAPFIRST(info -> InputFormat);
3397     cmsUInt32Number Extra      = T_EXTRA(info -> InputFormat);
3398     cmsUInt32Number ExtraFirst = DoSwap ^ SwapFirst;
3399     cmsUInt32Number Planar     = T_PLANAR(info -> InputFormat);
3400     cmsFloat32Number v;
3401     cmsUInt32Number i, start = 0;
3402     cmsFloat32Number maximum = IsInkSpace(info ->InputFormat) ? 655.35F : 65535.0F;
3403 
3404 
3405     Stride /= PixelSize(info->OutputFormat);
3406 
3407     if (ExtraFirst)
3408             start = Extra;
3409 
3410     for (i=0; i < nChan; i++) {
3411 
3412         cmsUInt32Number index = DoSwap ? (nChan - i - 1) : i;
3413 
3414         if (Planar)
3415             v = _cmsHalf2Float ( ((cmsUInt16Number*) accum)[(i + start) * Stride] );
3416         else
3417             v = _cmsHalf2Float ( ((cmsUInt16Number*) accum)[i + start] ) ;
3418 
3419         if (Reverse) v = maximum - v;
3420 
3421         wIn[index] = _cmsQuickSaturateWord((cmsFloat64Number) v * maximum);
3422     }
3423 
3424 
3425     if (Extra == 0 && SwapFirst) {
3426         cmsUInt16Number tmp = wIn[0];
3427 
3428         memmove(&wIn[0], &wIn[1], (nChan-1) * sizeof(cmsUInt16Number));
3429         wIn[nChan-1] = tmp;
3430     }
3431 
3432     if (T_PLANAR(info -> InputFormat))
3433         return accum + sizeof(cmsUInt16Number);
3434     else
3435         return accum + (nChan + Extra) * sizeof(cmsUInt16Number);
3436 }
3437 
3438 // Decodes an stream of half floats to wIn[] described by input format
3439 
3440 static
3441 cmsUInt8Number* UnrollHalfToFloat(_cmsTRANSFORM* info,
3442                                     cmsFloat32Number wIn[],
3443                                     cmsUInt8Number* accum,
3444                                     cmsUInt32Number Stride)
3445 {
3446 
3447     cmsUInt32Number nChan      = T_CHANNELS(info -> InputFormat);
3448     cmsUInt32Number DoSwap     = T_DOSWAP(info ->InputFormat);
3449     cmsUInt32Number Reverse    = T_FLAVOR(info ->InputFormat);
3450     cmsUInt32Number SwapFirst  = T_SWAPFIRST(info -> InputFormat);
3451     cmsUInt32Number Extra      = T_EXTRA(info -> InputFormat);
3452     cmsUInt32Number ExtraFirst = DoSwap ^ SwapFirst;
3453     cmsUInt32Number Planar     = T_PLANAR(info -> InputFormat);
3454     cmsFloat32Number v;
3455     cmsUInt32Number i, start = 0;
3456     cmsFloat32Number maximum = IsInkSpace(info ->InputFormat) ? 100.0F : 1.0F;
3457 
3458     Stride /= PixelSize(info->OutputFormat);
3459 
3460     if (ExtraFirst)
3461             start = Extra;
3462 
3463     for (i=0; i < nChan; i++) {
3464 
3465         cmsUInt32Number index = DoSwap ? (nChan - i - 1) : i;
3466 
3467         if (Planar)
3468             v =  _cmsHalf2Float ( ((cmsUInt16Number*) accum)[(i + start) * Stride] );
3469         else
3470             v =  _cmsHalf2Float ( ((cmsUInt16Number*) accum)[i + start] ) ;
3471 
3472         v /= maximum;
3473 
3474         wIn[index] = Reverse ? 1 - v : v;
3475     }
3476 
3477 
3478     if (Extra == 0 && SwapFirst) {
3479         cmsFloat32Number tmp = wIn[0];
3480 
3481         memmove(&wIn[0], &wIn[1], (nChan-1) * sizeof(cmsFloat32Number));
3482         wIn[nChan-1] = tmp;
3483     }
3484 
3485     if (T_PLANAR(info -> InputFormat))
3486         return accum + sizeof(cmsUInt16Number);
3487     else
3488         return accum + (nChan + Extra) * sizeof(cmsUInt16Number);
3489 }
3490 
3491 
3492 static
3493 cmsUInt8Number* PackHalfFrom16(CMSREGISTER _cmsTRANSFORM* info,
3494                                 CMSREGISTER cmsUInt16Number wOut[],
3495                                 CMSREGISTER cmsUInt8Number* output,
3496                                 CMSREGISTER cmsUInt32Number Stride)
3497 {
3498        cmsUInt32Number nChan      = T_CHANNELS(info->OutputFormat);
3499        cmsUInt32Number DoSwap     = T_DOSWAP(info->OutputFormat);
3500        cmsUInt32Number Reverse    = T_FLAVOR(info->OutputFormat);
3501        cmsUInt32Number Extra      = T_EXTRA(info->OutputFormat);
3502        cmsUInt32Number SwapFirst  = T_SWAPFIRST(info->OutputFormat);
3503        cmsUInt32Number Planar     = T_PLANAR(info->OutputFormat);
3504        cmsUInt32Number ExtraFirst = DoSwap ^ SwapFirst;
3505        cmsFloat32Number maximum = IsInkSpace(info->OutputFormat) ? 655.35F : 65535.0F;
3506        cmsFloat32Number v = 0;
3507        cmsUInt16Number* swap1 = (cmsUInt16Number*)output;
3508        cmsUInt32Number i, start = 0;
3509 
3510        Stride /= PixelSize(info->OutputFormat);
3511 
3512        if (ExtraFirst)
3513               start = Extra;
3514 
3515        for (i = 0; i < nChan; i++) {
3516 
3517               cmsUInt32Number index = DoSwap ? (nChan - i - 1) : i;
3518 
3519               v = (cmsFloat32Number)wOut[index] / maximum;
3520 
3521               if (Reverse)
3522                      v = maximum - v;
3523 
3524               if (Planar)
3525                      ((cmsUInt16Number*)output)[(i + start) * Stride] = _cmsFloat2Half(v);
3526               else
3527                      ((cmsUInt16Number*)output)[i + start] = _cmsFloat2Half(v);
3528        }
3529 
3530 
3531        if (Extra == 0 && SwapFirst) {
3532 
3533               memmove(swap1 + 1, swap1, (nChan - 1)* sizeof(cmsUInt16Number));
3534               *swap1 = _cmsFloat2Half(v);
3535        }
3536 
3537        if (T_PLANAR(info->OutputFormat))
3538               return output + sizeof(cmsUInt16Number);
3539        else
3540               return output + (nChan + Extra) * sizeof(cmsUInt16Number);
3541 }
3542 
3543 
3544 
3545 static
3546 cmsUInt8Number* PackHalfFromFloat(_cmsTRANSFORM* info,
3547                                     cmsFloat32Number wOut[],
3548                                     cmsUInt8Number* output,
3549                                     cmsUInt32Number Stride)
3550 {
3551        cmsUInt32Number nChan      = T_CHANNELS(info->OutputFormat);
3552        cmsUInt32Number DoSwap     = T_DOSWAP(info->OutputFormat);
3553        cmsUInt32Number Reverse    = T_FLAVOR(info->OutputFormat);
3554        cmsUInt32Number Extra      = T_EXTRA(info->OutputFormat);
3555        cmsUInt32Number SwapFirst  = T_SWAPFIRST(info->OutputFormat);
3556        cmsUInt32Number Planar     = T_PLANAR(info->OutputFormat);
3557        cmsUInt32Number ExtraFirst = DoSwap ^ SwapFirst;
3558        cmsFloat32Number maximum = IsInkSpace(info->OutputFormat) ? 100.0F : 1.0F;
3559        cmsUInt16Number* swap1 = (cmsUInt16Number*)output;
3560        cmsFloat32Number v = 0;
3561        cmsUInt32Number i, start = 0;
3562 
3563        Stride /= PixelSize(info->OutputFormat);
3564 
3565        if (ExtraFirst)
3566               start = Extra;
3567 
3568        for (i = 0; i < nChan; i++) {
3569 
3570            cmsUInt32Number index = DoSwap ? (nChan - i - 1) : i;
3571 
3572               v = wOut[index] * maximum;
3573 
3574               if (Reverse)
3575                      v = maximum - v;
3576 
3577               if (Planar)
3578                      ((cmsUInt16Number*)output)[(i + start)* Stride] = _cmsFloat2Half(v);
3579               else
3580                      ((cmsUInt16Number*)output)[i + start] = _cmsFloat2Half(v);
3581        }
3582 
3583 
3584        if (Extra == 0 && SwapFirst) {
3585 
3586               memmove(swap1 + 1, swap1, (nChan - 1)* sizeof(cmsUInt16Number));
3587               *swap1 = (cmsUInt16Number)_cmsFloat2Half(v);
3588        }
3589 
3590        if (T_PLANAR(info->OutputFormat))
3591               return output + sizeof(cmsUInt16Number);
3592        else
3593               return output + (nChan + Extra)* sizeof(cmsUInt16Number);
3594 }
3595 
3596 #endif
3597 
3598 // ----------------------------------------------------------------------------------------------------------------
3599 
3600 
3601 static const cmsFormatters16 InputFormatters16[] = {
3602 
3603     //    Type                                          Mask                  Function
3604     //  ----------------------------   ------------------------------------  ----------------------------
3605     { TYPE_Lab_DBL,                                 ANYPLANAR|ANYEXTRA,   UnrollLabDoubleTo16},
3606     { TYPE_XYZ_DBL,                                 ANYPLANAR|ANYEXTRA,   UnrollXYZDoubleTo16},
3607     { TYPE_Lab_FLT,                                 ANYPLANAR|ANYEXTRA,   UnrollLabFloatTo16},
3608     { TYPE_XYZ_FLT,                                 ANYPLANAR|ANYEXTRA,   UnrollXYZFloatTo16},
3609     { TYPE_GRAY_DBL,                                                 0,   UnrollDouble1Chan},
3610     { FLOAT_SH(1)|BYTES_SH(0), ANYCHANNELS|ANYPLANAR|ANYSWAPFIRST|ANYFLAVOR|
3611                                              ANYSWAP|ANYEXTRA|ANYSPACE,   UnrollDoubleTo16},
3612     { FLOAT_SH(1)|BYTES_SH(4), ANYCHANNELS|ANYPLANAR|ANYSWAPFIRST|ANYFLAVOR|
3613                                              ANYSWAP|ANYEXTRA|ANYSPACE,   UnrollFloatTo16},
3614 #ifndef CMS_NO_HALF_SUPPORT
3615     { FLOAT_SH(1)|BYTES_SH(2), ANYCHANNELS|ANYPLANAR|ANYSWAPFIRST|ANYFLAVOR|
3616                                             ANYEXTRA|ANYSWAP|ANYSPACE,   UnrollHalfTo16},
3617 #endif
3618 
3619     { CHANNELS_SH(1)|BYTES_SH(1),                              ANYSPACE,  Unroll1Byte},
3620     { CHANNELS_SH(1)|BYTES_SH(1)|EXTRA_SH(1),                  ANYSPACE,  Unroll1ByteSkip1},
3621     { CHANNELS_SH(1)|BYTES_SH(1)|EXTRA_SH(2),                  ANYSPACE,  Unroll1ByteSkip2},
3622     { CHANNELS_SH(1)|BYTES_SH(1)|FLAVOR_SH(1),                 ANYSPACE,  Unroll1ByteReversed},
3623     { COLORSPACE_SH(PT_MCH2)|CHANNELS_SH(2)|BYTES_SH(1),              0,  Unroll2Bytes},
3624 
3625     { TYPE_LabV2_8,                                                   0,  UnrollLabV2_8 },
3626     { TYPE_ALabV2_8,                                                  0,  UnrollALabV2_8 },
3627     { TYPE_LabV2_16,                                                  0,  UnrollLabV2_16 },
3628 
3629     { CHANNELS_SH(3)|BYTES_SH(1),                              ANYSPACE,  Unroll3Bytes},
3630     { CHANNELS_SH(3)|BYTES_SH(1)|DOSWAP_SH(1),                 ANYSPACE,  Unroll3BytesSwap},
3631     { CHANNELS_SH(3)|EXTRA_SH(1)|BYTES_SH(1)|DOSWAP_SH(1),     ANYSPACE,  Unroll3BytesSkip1Swap},
3632     { CHANNELS_SH(3)|EXTRA_SH(1)|BYTES_SH(1)|SWAPFIRST_SH(1),  ANYSPACE,  Unroll3BytesSkip1SwapFirst},
3633 
3634     { CHANNELS_SH(3)|EXTRA_SH(1)|BYTES_SH(1)|DOSWAP_SH(1)|SWAPFIRST_SH(1),
3635                                                                ANYSPACE,  Unroll3BytesSkip1SwapSwapFirst},
3636 
3637     { CHANNELS_SH(4)|BYTES_SH(1),                              ANYSPACE,  Unroll4Bytes},
3638     { CHANNELS_SH(4)|BYTES_SH(1)|FLAVOR_SH(1),                 ANYSPACE,  Unroll4BytesReverse},
3639     { CHANNELS_SH(4)|BYTES_SH(1)|SWAPFIRST_SH(1),              ANYSPACE,  Unroll4BytesSwapFirst},
3640     { CHANNELS_SH(4)|BYTES_SH(1)|DOSWAP_SH(1),                 ANYSPACE,  Unroll4BytesSwap},
3641     { CHANNELS_SH(4)|BYTES_SH(1)|DOSWAP_SH(1)|SWAPFIRST_SH(1), ANYSPACE,  Unroll4BytesSwapSwapFirst},
3642 
3643     { BYTES_SH(1)|PLANAR_SH(1), ANYFLAVOR|ANYSWAPFIRST|ANYPREMUL|
3644                                    ANYSWAP|ANYEXTRA|ANYCHANNELS|ANYSPACE, UnrollPlanarBytes},
3645 
3646     { BYTES_SH(1),    ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|ANYPREMUL|
3647                                            ANYEXTRA|ANYCHANNELS|ANYSPACE, UnrollChunkyBytes},
3648 
3649     { CHANNELS_SH(1)|BYTES_SH(2),                              ANYSPACE,  Unroll1Word},
3650     { CHANNELS_SH(1)|BYTES_SH(2)|FLAVOR_SH(1),                 ANYSPACE,  Unroll1WordReversed},
3651     { CHANNELS_SH(1)|BYTES_SH(2)|EXTRA_SH(3),                  ANYSPACE,  Unroll1WordSkip3},
3652 
3653     { CHANNELS_SH(2)|BYTES_SH(2),                              ANYSPACE,  Unroll2Words},
3654     { CHANNELS_SH(3)|BYTES_SH(2),                              ANYSPACE,  Unroll3Words},
3655     { CHANNELS_SH(4)|BYTES_SH(2),                              ANYSPACE,  Unroll4Words},
3656 
3657     { CHANNELS_SH(3)|BYTES_SH(2)|DOSWAP_SH(1),                 ANYSPACE,  Unroll3WordsSwap},
3658     { CHANNELS_SH(3)|BYTES_SH(2)|EXTRA_SH(1)|SWAPFIRST_SH(1),  ANYSPACE,  Unroll3WordsSkip1SwapFirst},
3659     { CHANNELS_SH(3)|BYTES_SH(2)|EXTRA_SH(1)|DOSWAP_SH(1),     ANYSPACE,  Unroll3WordsSkip1Swap},
3660     { CHANNELS_SH(4)|BYTES_SH(2)|FLAVOR_SH(1),                 ANYSPACE,  Unroll4WordsReverse},
3661     { CHANNELS_SH(4)|BYTES_SH(2)|SWAPFIRST_SH(1),              ANYSPACE,  Unroll4WordsSwapFirst},
3662     { CHANNELS_SH(4)|BYTES_SH(2)|DOSWAP_SH(1),                 ANYSPACE,  Unroll4WordsSwap},
3663     { CHANNELS_SH(4)|BYTES_SH(2)|DOSWAP_SH(1)|SWAPFIRST_SH(1), ANYSPACE,  Unroll4WordsSwapSwapFirst},
3664 
3665 
3666     { BYTES_SH(2)|PLANAR_SH(1),  ANYFLAVOR|ANYSWAP|ANYENDIAN|ANYEXTRA|ANYCHANNELS|ANYSPACE,  UnrollPlanarWords},
3667     { BYTES_SH(2),  ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|ANYENDIAN|ANYEXTRA|ANYCHANNELS|ANYSPACE,  UnrollAnyWords},
3668 
3669     { BYTES_SH(2)|PLANAR_SH(1),  ANYFLAVOR|ANYSWAP|ANYENDIAN|ANYEXTRA|ANYCHANNELS|ANYSPACE|PREMUL_SH(1),  UnrollPlanarWordsPremul},
3670     { BYTES_SH(2),  ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|ANYENDIAN|ANYEXTRA|ANYCHANNELS|ANYSPACE|PREMUL_SH(1),  UnrollAnyWordsPremul}
3671 
3672 };
3673 
3674 
3675 
3676 static const cmsFormattersFloat InputFormattersFloat[] = {
3677 
3678     //    Type                                          Mask                  Function
3679     //  ----------------------------   ------------------------------------  ----------------------------
3680     {     TYPE_Lab_DBL,                                ANYPLANAR|ANYEXTRA,   UnrollLabDoubleToFloat},
3681     {     TYPE_Lab_FLT,                                ANYPLANAR|ANYEXTRA,   UnrollLabFloatToFloat},
3682 
3683     {     TYPE_XYZ_DBL,                                ANYPLANAR|ANYEXTRA,   UnrollXYZDoubleToFloat},
3684     {     TYPE_XYZ_FLT,                                ANYPLANAR|ANYEXTRA,   UnrollXYZFloatToFloat},
3685 
3686     {     FLOAT_SH(1)|BYTES_SH(4), ANYPLANAR|ANYSWAPFIRST|ANYSWAP|ANYEXTRA|
3687                                             ANYPREMUL|ANYCHANNELS|ANYSPACE,  UnrollFloatsToFloat},
3688 
3689     {     FLOAT_SH(1)|BYTES_SH(0), ANYPLANAR|ANYSWAPFIRST|ANYSWAP|ANYEXTRA|
3690                                               ANYCHANNELS|ANYSPACE|ANYPREMUL, UnrollDoublesToFloat},
3691 
3692     {     TYPE_LabV2_8,                                                   0,  UnrollLabV2_8ToFloat },
3693     {     TYPE_ALabV2_8,                                                  0,  UnrollALabV2_8ToFloat },
3694     {     TYPE_LabV2_16,                                                  0,  UnrollLabV2_16ToFloat },
3695 
3696     {     BYTES_SH(1),              ANYPLANAR|ANYSWAPFIRST|ANYSWAP|ANYEXTRA|
3697                                                         ANYCHANNELS|ANYSPACE, Unroll8ToFloat},
3698 
3699     {     BYTES_SH(2),              ANYPLANAR|ANYSWAPFIRST|ANYSWAP|ANYEXTRA|
3700                                                         ANYCHANNELS|ANYSPACE, Unroll16ToFloat},
3701 #ifndef CMS_NO_HALF_SUPPORT
3702     {     FLOAT_SH(1)|BYTES_SH(2), ANYPLANAR|ANYSWAPFIRST|ANYSWAP|ANYEXTRA|
3703                                                         ANYCHANNELS|ANYSPACE, UnrollHalfToFloat},
3704 #endif
3705 };
3706 
3707 
3708 // Bit fields set to one in the mask are not compared
3709 static
3710 cmsFormatter _cmsGetStockInputFormatter(cmsUInt32Number dwInput, cmsUInt32Number dwFlags)
3711 {
3712     cmsUInt32Number i;
3713     cmsFormatter fr;
3714 
3715     switch (dwFlags) {
3716 
3717     case CMS_PACK_FLAGS_16BITS: {
3718         for (i=0; i < sizeof(InputFormatters16) / sizeof(cmsFormatters16); i++) {
3719             const cmsFormatters16* f = InputFormatters16 + i;
3720 
3721             if ((dwInput & ~f ->Mask) == f ->Type) {
3722                 fr.Fmt16 = f ->Frm;
3723                 return fr;
3724             }
3725         }
3726     }
3727     break;
3728 
3729     case CMS_PACK_FLAGS_FLOAT: {
3730         for (i=0; i < sizeof(InputFormattersFloat) / sizeof(cmsFormattersFloat); i++) {
3731             const cmsFormattersFloat* f = InputFormattersFloat + i;
3732 
3733             if ((dwInput & ~f ->Mask) == f ->Type) {
3734                 fr.FmtFloat = f ->Frm;
3735                 return fr;
3736             }
3737         }
3738     }
3739     break;
3740 
3741     default:;
3742 
3743     }
3744 
3745     fr.Fmt16 = NULL;
3746     return fr;
3747 }
3748 
3749 static const cmsFormatters16 OutputFormatters16[] = {
3750     //    Type                                          Mask                  Function
3751     //  ----------------------------   ------------------------------------  ----------------------------
3752 
3753     { TYPE_Lab_DBL,                                      ANYPLANAR|ANYEXTRA,  PackLabDoubleFrom16},
3754     { TYPE_XYZ_DBL,                                      ANYPLANAR|ANYEXTRA,  PackXYZDoubleFrom16},
3755 
3756     { TYPE_Lab_FLT,                                      ANYPLANAR|ANYEXTRA,  PackLabFloatFrom16},
3757     { TYPE_XYZ_FLT,                                      ANYPLANAR|ANYEXTRA,  PackXYZFloatFrom16},
3758 
3759     { FLOAT_SH(1)|BYTES_SH(0),      ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|
3760                                     ANYCHANNELS|ANYPLANAR|ANYEXTRA|ANYSPACE,  PackDoubleFrom16},
3761     { FLOAT_SH(1)|BYTES_SH(4),      ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|
3762                                     ANYCHANNELS|ANYPLANAR|ANYEXTRA|ANYSPACE,  PackFloatFrom16},
3763 #ifndef CMS_NO_HALF_SUPPORT
3764     { FLOAT_SH(1)|BYTES_SH(2),      ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|
3765                                     ANYCHANNELS|ANYPLANAR|ANYEXTRA|ANYSPACE,  PackHalfFrom16},
3766 #endif
3767 
3768     { CHANNELS_SH(1)|BYTES_SH(1),                                  ANYSPACE,  Pack1Byte},
3769     { CHANNELS_SH(1)|BYTES_SH(1)|EXTRA_SH(1),                      ANYSPACE,  Pack1ByteSkip1},
3770     { CHANNELS_SH(1)|BYTES_SH(1)|EXTRA_SH(1)|SWAPFIRST_SH(1),      ANYSPACE,  Pack1ByteSkip1SwapFirst},
3771 
3772     { CHANNELS_SH(1)|BYTES_SH(1)|FLAVOR_SH(1),                     ANYSPACE,  Pack1ByteReversed},
3773 
3774     { TYPE_LabV2_8,                                                       0,  PackLabV2_8 },
3775     { TYPE_ALabV2_8,                                                      0,  PackALabV2_8 },
3776     { TYPE_LabV2_16,                                                      0,  PackLabV2_16 },
3777 
3778     { CHANNELS_SH(3)|BYTES_SH(1)|OPTIMIZED_SH(1),                  ANYSPACE,  Pack3BytesOptimized},
3779     { CHANNELS_SH(3)|BYTES_SH(1)|EXTRA_SH(1)|OPTIMIZED_SH(1),      ANYSPACE,  Pack3BytesAndSkip1Optimized},
3780     { CHANNELS_SH(3)|BYTES_SH(1)|EXTRA_SH(1)|SWAPFIRST_SH(1)|OPTIMIZED_SH(1),
3781                                                                    ANYSPACE,  Pack3BytesAndSkip1SwapFirstOptimized},
3782     { CHANNELS_SH(3)|BYTES_SH(1)|EXTRA_SH(1)|DOSWAP_SH(1)|SWAPFIRST_SH(1)|OPTIMIZED_SH(1),
3783                                                                    ANYSPACE,  Pack3BytesAndSkip1SwapSwapFirstOptimized},
3784     { CHANNELS_SH(3)|BYTES_SH(1)|DOSWAP_SH(1)|EXTRA_SH(1)|OPTIMIZED_SH(1),
3785                                                                    ANYSPACE,  Pack3BytesAndSkip1SwapOptimized},
3786     { CHANNELS_SH(3)|BYTES_SH(1)|DOSWAP_SH(1)|OPTIMIZED_SH(1),     ANYSPACE,  Pack3BytesSwapOptimized},
3787 
3788 
3789 
3790     { CHANNELS_SH(3)|BYTES_SH(1),                                  ANYSPACE,  Pack3Bytes},
3791     { CHANNELS_SH(3)|BYTES_SH(1)|EXTRA_SH(1),                      ANYSPACE,  Pack3BytesAndSkip1},
3792     { CHANNELS_SH(3)|BYTES_SH(1)|EXTRA_SH(1)|SWAPFIRST_SH(1),      ANYSPACE,  Pack3BytesAndSkip1SwapFirst},
3793     { CHANNELS_SH(3)|BYTES_SH(1)|EXTRA_SH(1)|DOSWAP_SH(1)|SWAPFIRST_SH(1),
3794                                                                    ANYSPACE,  Pack3BytesAndSkip1SwapSwapFirst},
3795     { CHANNELS_SH(3)|BYTES_SH(1)|DOSWAP_SH(1)|EXTRA_SH(1),         ANYSPACE,  Pack3BytesAndSkip1Swap},
3796     { CHANNELS_SH(3)|BYTES_SH(1)|DOSWAP_SH(1),                     ANYSPACE,  Pack3BytesSwap},
3797     { CHANNELS_SH(4)|BYTES_SH(1),                                  ANYSPACE,  Pack4Bytes},
3798     { CHANNELS_SH(4)|BYTES_SH(1)|FLAVOR_SH(1),                     ANYSPACE,  Pack4BytesReverse},
3799     { CHANNELS_SH(4)|BYTES_SH(1)|SWAPFIRST_SH(1),                  ANYSPACE,  Pack4BytesSwapFirst},
3800     { CHANNELS_SH(4)|BYTES_SH(1)|DOSWAP_SH(1),                     ANYSPACE,  Pack4BytesSwap},
3801     { CHANNELS_SH(4)|BYTES_SH(1)|DOSWAP_SH(1)|SWAPFIRST_SH(1),     ANYSPACE,  Pack4BytesSwapSwapFirst},
3802     { CHANNELS_SH(6)|BYTES_SH(1),                                  ANYSPACE,  Pack6Bytes},
3803     { CHANNELS_SH(6)|BYTES_SH(1)|DOSWAP_SH(1),                     ANYSPACE,  Pack6BytesSwap},
3804 
3805     { BYTES_SH(1),    ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|ANYEXTRA|ANYCHANNELS|
3806                                                           ANYSPACE|ANYPREMUL, PackChunkyBytes},
3807 
3808     { BYTES_SH(1)|PLANAR_SH(1),    ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|ANYEXTRA|
3809                                               ANYCHANNELS|ANYSPACE|ANYPREMUL, PackPlanarBytes},
3810 
3811 
3812     { CHANNELS_SH(1)|BYTES_SH(2),                                  ANYSPACE,  Pack1Word},
3813     { CHANNELS_SH(1)|BYTES_SH(2)|EXTRA_SH(1),                      ANYSPACE,  Pack1WordSkip1},
3814     { CHANNELS_SH(1)|BYTES_SH(2)|EXTRA_SH(1)|SWAPFIRST_SH(1),      ANYSPACE,  Pack1WordSkip1SwapFirst},
3815     { CHANNELS_SH(1)|BYTES_SH(2)|FLAVOR_SH(1),                     ANYSPACE,  Pack1WordReversed},
3816     { CHANNELS_SH(1)|BYTES_SH(2)|ENDIAN16_SH(1),                   ANYSPACE,  Pack1WordBigEndian},
3817     { CHANNELS_SH(3)|BYTES_SH(2),                                  ANYSPACE,  Pack3Words},
3818     { CHANNELS_SH(3)|BYTES_SH(2)|DOSWAP_SH(1),                     ANYSPACE,  Pack3WordsSwap},
3819     { CHANNELS_SH(3)|BYTES_SH(2)|ENDIAN16_SH(1),                   ANYSPACE,  Pack3WordsBigEndian},
3820     { CHANNELS_SH(3)|BYTES_SH(2)|EXTRA_SH(1),                      ANYSPACE,  Pack3WordsAndSkip1},
3821     { CHANNELS_SH(3)|BYTES_SH(2)|EXTRA_SH(1)|DOSWAP_SH(1),         ANYSPACE,  Pack3WordsAndSkip1Swap},
3822     { CHANNELS_SH(3)|BYTES_SH(2)|EXTRA_SH(1)|SWAPFIRST_SH(1),      ANYSPACE,  Pack3WordsAndSkip1SwapFirst},
3823 
3824     { CHANNELS_SH(3)|BYTES_SH(2)|EXTRA_SH(1)|DOSWAP_SH(1)|SWAPFIRST_SH(1),
3825                                                                    ANYSPACE,  Pack3WordsAndSkip1SwapSwapFirst},
3826 
3827     { CHANNELS_SH(4)|BYTES_SH(2),                                  ANYSPACE,  Pack4Words},
3828     { CHANNELS_SH(4)|BYTES_SH(2)|FLAVOR_SH(1),                     ANYSPACE,  Pack4WordsReverse},
3829     { CHANNELS_SH(4)|BYTES_SH(2)|DOSWAP_SH(1),                     ANYSPACE,  Pack4WordsSwap},
3830     { CHANNELS_SH(4)|BYTES_SH(2)|ENDIAN16_SH(1),                   ANYSPACE,  Pack4WordsBigEndian},
3831 
3832     { CHANNELS_SH(6)|BYTES_SH(2),                                  ANYSPACE,  Pack6Words},
3833     { CHANNELS_SH(6)|BYTES_SH(2)|DOSWAP_SH(1),                     ANYSPACE,  Pack6WordsSwap},
3834 
3835     { BYTES_SH(2),                  ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|ANYENDIAN|
3836                                      ANYEXTRA|ANYCHANNELS|ANYSPACE|ANYPREMUL, PackChunkyWords},
3837     { BYTES_SH(2)|PLANAR_SH(1),     ANYFLAVOR|ANYENDIAN|ANYSWAP|ANYEXTRA|
3838                                      ANYCHANNELS|ANYSPACE|ANYPREMUL,          PackPlanarWords}
3839 
3840 };
3841 
3842 
3843 static const cmsFormattersFloat OutputFormattersFloat[] = {
3844     //    Type                                          Mask                                 Function
3845     //  ----------------------------   ---------------------------------------------------  ----------------------------
3846     {     TYPE_Lab_FLT,                                                ANYPLANAR|ANYEXTRA,   PackLabFloatFromFloat},
3847     {     TYPE_XYZ_FLT,                                                ANYPLANAR|ANYEXTRA,   PackXYZFloatFromFloat},
3848 
3849     {     TYPE_Lab_DBL,                                                ANYPLANAR|ANYEXTRA,   PackLabDoubleFromFloat},
3850     {     TYPE_XYZ_DBL,                                                ANYPLANAR|ANYEXTRA,   PackXYZDoubleFromFloat},
3851 
3852     {     TYPE_LabV2_8,                                                ANYPLANAR|ANYEXTRA,   PackEncodedBytesLabV2FromFloat},
3853     {     TYPE_LabV2_16,                                               ANYPLANAR|ANYEXTRA,   PackEncodedWordsLabV2FromFloat},
3854 
3855     {     FLOAT_SH(1)|BYTES_SH(4), ANYPLANAR|
3856                              ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|ANYEXTRA|ANYCHANNELS|ANYSPACE,   PackFloatsFromFloat },
3857     {     FLOAT_SH(1)|BYTES_SH(0), ANYPLANAR|
3858                              ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|ANYEXTRA|ANYCHANNELS|ANYSPACE,   PackDoublesFromFloat },
3859 
3860     {     BYTES_SH(2), ANYPLANAR|
3861                              ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|ANYEXTRA|ANYCHANNELS|ANYSPACE,   PackWordsFromFloat },
3862 
3863     {     BYTES_SH(1), ANYPLANAR|
3864                              ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|ANYEXTRA|ANYCHANNELS|ANYSPACE,   PackBytesFromFloat },
3865 
3866 #ifndef CMS_NO_HALF_SUPPORT
3867     {     FLOAT_SH(1)|BYTES_SH(2),
3868                              ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|ANYEXTRA|ANYCHANNELS|ANYSPACE,   PackHalfFromFloat },
3869 #endif
3870 
3871 };
3872 
3873 
3874 // Bit fields set to one in the mask are not compared
3875 static
3876 cmsFormatter _cmsGetStockOutputFormatter(cmsUInt32Number dwInput, cmsUInt32Number dwFlags)
3877 {
3878     cmsUInt32Number i;
3879     cmsFormatter fr;
3880 
3881     // Optimization is only a hint
3882     dwInput &= ~OPTIMIZED_SH(1);
3883 
3884     switch (dwFlags)
3885     {
3886 
3887      case CMS_PACK_FLAGS_16BITS: {
3888 
3889         for (i=0; i < sizeof(OutputFormatters16) / sizeof(cmsFormatters16); i++) {
3890             const cmsFormatters16* f = OutputFormatters16 + i;
3891 
3892             if ((dwInput & ~f ->Mask) == f ->Type) {
3893                 fr.Fmt16 = f ->Frm;
3894                 return fr;
3895             }
3896         }
3897         }
3898         break;
3899 
3900     case CMS_PACK_FLAGS_FLOAT: {
3901 
3902         for (i=0; i < sizeof(OutputFormattersFloat) / sizeof(cmsFormattersFloat); i++) {
3903             const cmsFormattersFloat* f = OutputFormattersFloat + i;
3904 
3905             if ((dwInput & ~f ->Mask) == f ->Type) {
3906                 fr.FmtFloat = f ->Frm;
3907                 return fr;
3908             }
3909         }
3910         }
3911         break;
3912 
3913     default:;
3914 
3915     }
3916 
3917     fr.Fmt16 = NULL;
3918     return fr;
3919 }
3920 
3921 
3922 typedef struct _cms_formatters_factory_list {
3923 
3924     cmsFormatterFactory Factory;
3925     struct _cms_formatters_factory_list *Next;
3926 
3927 } cmsFormattersFactoryList;
3928 
3929 _cmsFormattersPluginChunkType _cmsFormattersPluginChunk = { NULL };
3930 
3931 
3932 // Duplicates the zone of memory used by the plug-in in the new context
3933 static
3934 void DupFormatterFactoryList(struct _cmsContext_struct* ctx,
3935                                                const struct _cmsContext_struct* src)
3936 {
3937    _cmsFormattersPluginChunkType newHead = { NULL };
3938    cmsFormattersFactoryList*  entry;
3939    cmsFormattersFactoryList*  Anterior = NULL;
3940    _cmsFormattersPluginChunkType* head = (_cmsFormattersPluginChunkType*) src->chunks[FormattersPlugin];
3941 
3942      _cmsAssert(head != NULL);
3943 
3944    // Walk the list copying all nodes
3945    for (entry = head->FactoryList;
3946        entry != NULL;
3947        entry = entry ->Next) {
3948 
3949            cmsFormattersFactoryList *newEntry = ( cmsFormattersFactoryList *) _cmsSubAllocDup(ctx ->MemPool, entry, sizeof(cmsFormattersFactoryList));
3950 
3951            if (newEntry == NULL)
3952                return;
3953 
3954            // We want to keep the linked list order, so this is a little bit tricky
3955            newEntry -> Next = NULL;
3956            if (Anterior)
3957                Anterior -> Next = newEntry;
3958 
3959            Anterior = newEntry;
3960 
3961            if (newHead.FactoryList == NULL)
3962                newHead.FactoryList = newEntry;
3963    }
3964 
3965    ctx ->chunks[FormattersPlugin] = _cmsSubAllocDup(ctx->MemPool, &newHead, sizeof(_cmsFormattersPluginChunkType));
3966 }
3967 
3968 // The interpolation plug-in memory chunk allocator/dup
3969 void _cmsAllocFormattersPluginChunk(struct _cmsContext_struct* ctx,
3970                                     const struct _cmsContext_struct* src)
3971 {
3972       _cmsAssert(ctx != NULL);
3973 
3974      if (src != NULL) {
3975 
3976          // Duplicate the LIST
3977          DupFormatterFactoryList(ctx, src);
3978      }
3979      else {
3980           static _cmsFormattersPluginChunkType FormattersPluginChunk = { NULL };
3981           ctx ->chunks[FormattersPlugin] = _cmsSubAllocDup(ctx ->MemPool, &FormattersPluginChunk, sizeof(_cmsFormattersPluginChunkType));
3982      }
3983 }
3984 
3985 
3986 
3987 // Formatters management
3988 cmsBool  _cmsRegisterFormattersPlugin(cmsContext ContextID, cmsPluginBase* Data)
3989 {
3990     _cmsFormattersPluginChunkType* ctx = ( _cmsFormattersPluginChunkType*) _cmsContextGetClientChunk(ContextID, FormattersPlugin);
3991     cmsPluginFormatters* Plugin = (cmsPluginFormatters*) Data;
3992     cmsFormattersFactoryList* fl ;
3993 
3994     // Reset to built-in defaults
3995     if (Data == NULL) {
3996 
3997           ctx ->FactoryList = NULL;
3998           return TRUE;
3999     }
4000 
4001     fl = (cmsFormattersFactoryList*) _cmsPluginMalloc(ContextID, sizeof(cmsFormattersFactoryList));
4002     if (fl == NULL) return FALSE;
4003 
4004     fl ->Factory    = Plugin ->FormattersFactory;
4005 
4006     fl ->Next = ctx -> FactoryList;
4007     ctx ->FactoryList = fl;
4008 
4009     return TRUE;
4010 }
4011 
4012 cmsFormatter CMSEXPORT _cmsGetFormatter(cmsContext ContextID,
4013                                         cmsUInt32Number Type,         // Specific type, i.e. TYPE_RGB_8
4014                                         cmsFormatterDirection Dir,
4015                                         cmsUInt32Number dwFlags)
4016 {
4017     _cmsFormattersPluginChunkType* ctx = ( _cmsFormattersPluginChunkType*) _cmsContextGetClientChunk(ContextID, FormattersPlugin);
4018     cmsFormattersFactoryList* f;
4019 
4020     if (T_CHANNELS(Type) == 0) {
4021         static const cmsFormatter nullFormatter = { 0 };
4022         return nullFormatter;
4023     }
4024 
4025     for (f =ctx->FactoryList; f != NULL; f = f ->Next) {
4026 
4027         cmsFormatter fn = f ->Factory(Type, Dir, dwFlags);
4028         if (fn.Fmt16 != NULL) return fn;
4029     }
4030 
4031     // Revert to default
4032     if (Dir == cmsFormatterInput)
4033         return _cmsGetStockInputFormatter(Type, dwFlags);
4034     else
4035         return _cmsGetStockOutputFormatter(Type, dwFlags);
4036 }
4037 
4038 
4039 // Return whatever given formatter refers to float values
4040 cmsBool  _cmsFormatterIsFloat(cmsUInt32Number Type)
4041 {
4042     return T_FLOAT(Type) ? TRUE : FALSE;
4043 }
4044 
4045 // Return whatever given formatter refers to 8 bits
4046 cmsBool  _cmsFormatterIs8bit(cmsUInt32Number Type)
4047 {
4048     cmsUInt32Number Bytes = T_BYTES(Type);
4049 
4050     return (Bytes == 1);
4051 }
4052 
4053 // Build a suitable formatter for the colorspace of this profile
4054 cmsUInt32Number CMSEXPORT cmsFormatterForColorspaceOfProfile(cmsHPROFILE hProfile, cmsUInt32Number nBytes, cmsBool lIsFloat)
4055 {
4056 
4057     cmsColorSpaceSignature ColorSpace      = cmsGetColorSpace(hProfile);
4058     cmsUInt32Number        ColorSpaceBits  = (cmsUInt32Number) _cmsLCMScolorSpace(ColorSpace);
4059     cmsInt32Number         nOutputChans    = cmsChannelsOfColorSpace(ColorSpace);
4060     cmsUInt32Number        Float           = lIsFloat ? 1U : 0;
4061 
4062     // Unsupported color space?
4063     if (nOutputChans < 0) return 0;
4064 
4065     // Create a fake formatter for result
4066     return FLOAT_SH(Float) | COLORSPACE_SH(ColorSpaceBits) | BYTES_SH(nBytes) | CHANNELS_SH(nOutputChans);
4067 }
4068 
4069 // Build a suitable formatter for the colorspace of this profile
4070 cmsUInt32Number CMSEXPORT cmsFormatterForPCSOfProfile(cmsHPROFILE hProfile, cmsUInt32Number nBytes, cmsBool lIsFloat)
4071 {
4072 
4073     cmsColorSpaceSignature ColorSpace = cmsGetPCS(hProfile);
4074 
4075     cmsUInt32Number ColorSpaceBits = (cmsUInt32Number) _cmsLCMScolorSpace(ColorSpace);
4076     cmsInt32Number  nOutputChans = cmsChannelsOfColorSpace(ColorSpace);
4077     cmsUInt32Number Float = lIsFloat ? 1U : 0;
4078 
4079     // Unsupported color space?
4080     if (nOutputChans < 0) return 0;
4081 
4082     // Create a fake formatter for result
4083     return FLOAT_SH(Float) | COLORSPACE_SH(ColorSpaceBits) | BYTES_SH(nBytes) | CHANNELS_SH(nOutputChans);
4084 }
4085