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