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