jdk

Форк
0
4084 строки · 132.3 Кб
1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
3
 *
4
 * This code is free software; you can redistribute it and/or modify it
5
 * under the terms of the GNU General Public License version 2 only, as
6
 * published by the Free Software Foundation.  Oracle designates this
7
 * particular file as subject to the "Classpath" exception as provided
8
 * by Oracle in the LICENSE file that accompanied this code.
9
 *
10
 * This code is distributed in the hope that it will be useful, but WITHOUT
11
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
13
 * version 2 for more details (a copy is included in the LICENSE file that
14
 * accompanied this code).
15
 *
16
 * You should have received a copy of the GNU General Public License version
17
 * 2 along with this work; if not, write to the Free Software Foundation,
18
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
19
 *
20
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
21
 * or visit www.oracle.com if you need additional information or have any
22
 * questions.
23
 */
24

25
// This file is available under and governed by the GNU General Public
26
// License version 2 only, as published by the Free Software Foundation.
27
// However, the following notice accompanied the original version of this
28
// file:
29
//
30
//---------------------------------------------------------------------------------
31
//
32
//  Little Color Management System
33
//  Copyright (c) 1998-2023 Marti Maria Saguer
34
//
35
// Permission is hereby granted, free of charge, to any person obtaining
36
// a copy of this software and associated documentation files (the "Software"),
37
// to deal in the Software without restriction, including without limitation
38
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
39
// and/or sell copies of the Software, and to permit persons to whom the Software
40
// is furnished to do so, subject to the following conditions:
41
//
42
// The above copyright notice and this permission notice shall be included in
43
// all copies or substantial portions of the Software.
44
//
45
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
46
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
47
// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
48
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
49
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
50
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
51
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
52
//
53
//---------------------------------------------------------------------------------
54
//
55

56
#include "lcms2_internal.h"
57

58
// This module handles all formats supported by lcms. There are two flavors, 16 bits and
59
// floating point. Floating point is supported only in a subset, those formats holding
60
// cmsFloat32Number (4 bytes per component) and double (marked as 0 bytes per component
61
// as special case)
62

63
// ---------------------------------------------------------------------------
64

65

66
// This macro return words stored as big endian
67
#define CHANGE_ENDIAN(w)    (cmsUInt16Number) ((cmsUInt16Number) ((w)<<8)|((w)>>8))
68

69
// These macros handles reversing (negative)
70
#define REVERSE_FLAVOR_8(x)     ((cmsUInt8Number) (0xff-(x)))
71
#define REVERSE_FLAVOR_16(x)    ((cmsUInt16Number)(0xffff-(x)))
72

73
// * 0xffff / 0xff00 = (255 * 257) / (255 * 256) = 257 / 256
74
cmsINLINE cmsUInt16Number FomLabV2ToLabV4(cmsUInt16Number x)
75
{
76
    int a = (x << 8 | x) >> 8;  // * 257 / 256
77
    if ( a > 0xffff) return 0xffff;
78
    return (cmsUInt16Number) a;
79
}
80

81
// * 0xf00 / 0xffff = * 256 / 257
82
cmsINLINE cmsUInt16Number FomLabV4ToLabV2(cmsUInt16Number x)
83
{
84
    return (cmsUInt16Number) (((x << 8) + 0x80) / 257);
85
}
86

87

88
typedef struct {
89
    cmsUInt32Number Type;
90
    cmsUInt32Number Mask;
91
    cmsFormatter16  Frm;
92

93
} cmsFormatters16;
94

95
typedef struct {
96
    cmsUInt32Number    Type;
97
    cmsUInt32Number    Mask;
98
    cmsFormatterFloat  Frm;
99

100
} cmsFormattersFloat;
101

102

103
#define ANYSPACE        COLORSPACE_SH(31)
104
#define ANYCHANNELS     CHANNELS_SH(15)
105
#define ANYEXTRA        EXTRA_SH(7)
106
#define ANYPLANAR       PLANAR_SH(1)
107
#define ANYENDIAN       ENDIAN16_SH(1)
108
#define ANYSWAP         DOSWAP_SH(1)
109
#define ANYSWAPFIRST    SWAPFIRST_SH(1)
110
#define ANYFLAVOR       FLAVOR_SH(1)
111
#define ANYPREMUL       PREMUL_SH(1)
112

113

114
// Suppress waning about info never being used
115

116
#ifdef _MSC_VER
117
#pragma warning(disable : 4100)
118
#endif
119

120
// Unpacking routines (16 bits) ----------------------------------------------------------------------------------------
121

122

123
// Does almost everything but is slow
124
static
125
cmsUInt8Number* UnrollChunkyBytes(CMSREGISTER _cmsTRANSFORM* info,
126
                                  CMSREGISTER cmsUInt16Number wIn[],
127
                                  CMSREGISTER cmsUInt8Number* accum,
128
                                  CMSREGISTER cmsUInt32Number Stride)
129
{
130
    cmsUInt32Number nChan      = T_CHANNELS(info -> InputFormat);
131
    cmsUInt32Number DoSwap     = T_DOSWAP(info ->InputFormat);
132
    cmsUInt32Number Reverse    = T_FLAVOR(info ->InputFormat);
133
    cmsUInt32Number SwapFirst  = T_SWAPFIRST(info -> InputFormat);
134
    cmsUInt32Number Extra      = T_EXTRA(info -> InputFormat);
135
    cmsUInt32Number Premul     = T_PREMUL(info->InputFormat);
136

137
    cmsUInt32Number ExtraFirst = DoSwap ^ SwapFirst;
138
    cmsUInt32Number v;
139
    cmsUInt32Number i;
140
    cmsUInt32Number alpha_factor = 1;
141

142
    if (ExtraFirst) {
143

144
        if (Premul && Extra)
145
            alpha_factor = _cmsToFixedDomain(FROM_8_TO_16(accum[0]));
146

147
        accum += Extra;
148
    }
149
    else
150
    {
151
        if (Premul && Extra)
152
            alpha_factor = _cmsToFixedDomain(FROM_8_TO_16(accum[nChan]));
153
    }
154

155
    for (i=0; i < nChan; i++) {
156

157
        cmsUInt32Number index = DoSwap ? (nChan - i - 1) : i;
158

159
        v = FROM_8_TO_16(*accum);
160
        v = Reverse ? REVERSE_FLAVOR_16(v) : v;
161

162
        if (Premul && alpha_factor > 0)
163
        {
164
            v = ((cmsUInt32Number)((cmsUInt32Number)v << 16) / alpha_factor);
165
            if (v > 0xffff) v = 0xffff;
166
        }
167

168
        wIn[index] = (cmsUInt16Number) v;
169
        accum++;
170
    }
171

172
    if (!ExtraFirst) {
173
        accum += Extra;
174
    }
175

176
    if (Extra == 0 && SwapFirst) {
177
        cmsUInt16Number tmp = wIn[0];
178

179
        memmove(&wIn[0], &wIn[1], (nChan-1) * sizeof(cmsUInt16Number));
180
        wIn[nChan-1] = tmp;
181
    }
182

183
    return accum;
184

185
    cmsUNUSED_PARAMETER(info);
186
    cmsUNUSED_PARAMETER(Stride);
187

188
}
189

190

191
// Extra channels are just ignored because come in the next planes
192
static
193
cmsUInt8Number* UnrollPlanarBytes(CMSREGISTER _cmsTRANSFORM* info,
194
                                  CMSREGISTER cmsUInt16Number wIn[],
195
                                  CMSREGISTER cmsUInt8Number* accum,
196
                                  CMSREGISTER cmsUInt32Number Stride)
197
{
198
    cmsUInt32Number nChan     = T_CHANNELS(info -> InputFormat);
199
    cmsUInt32Number DoSwap    = T_DOSWAP(info ->InputFormat);
200
    cmsUInt32Number SwapFirst = T_SWAPFIRST(info ->InputFormat);
201
    cmsUInt32Number Reverse   = T_FLAVOR(info ->InputFormat);
202
    cmsUInt32Number i;
203
    cmsUInt32Number ExtraFirst = DoSwap ^ SwapFirst;
204
    cmsUInt32Number Extra = T_EXTRA(info->InputFormat);
205
    cmsUInt32Number Premul = T_PREMUL(info->InputFormat);
206
    cmsUInt8Number* Init = accum;
207
    cmsUInt32Number alpha_factor = 1;
208

209
    if (ExtraFirst) {
210

211
        if (Premul && Extra)
212
            alpha_factor = _cmsToFixedDomain(FROM_8_TO_16(accum[0]));
213

214

215
        accum += Extra * Stride;
216
    }
217
    else
218
    {
219
        if (Premul && Extra)
220
            alpha_factor = _cmsToFixedDomain(FROM_8_TO_16(accum[(nChan) * Stride]));
221
    }
222

223
    for (i=0; i < nChan; i++) {
224

225
        cmsUInt32Number index = DoSwap ? (nChan - i - 1) : i;
226
        cmsUInt32Number v = FROM_8_TO_16(*accum);
227

228
        v = Reverse ? REVERSE_FLAVOR_16(v) : v;
229

230
        if (Premul && alpha_factor > 0)
231
        {
232
            v = ((cmsUInt32Number)((cmsUInt32Number)v << 16) / alpha_factor);
233
            if (v > 0xffff) v = 0xffff;
234
        }
235

236
        wIn[index] = (cmsUInt16Number) v;
237
        accum += Stride;
238
    }
239

240
    return (Init + 1);
241
}
242

243

244
// Special cases, provided for performance
245
static
246
cmsUInt8Number* Unroll4Bytes(CMSREGISTER _cmsTRANSFORM* info,
247
                             CMSREGISTER cmsUInt16Number wIn[],
248
                             CMSREGISTER cmsUInt8Number* accum,
249
                             CMSREGISTER cmsUInt32Number Stride)
250
{
251
    wIn[0] = FROM_8_TO_16(*accum); accum++; // C
252
    wIn[1] = FROM_8_TO_16(*accum); accum++; // M
253
    wIn[2] = FROM_8_TO_16(*accum); accum++; // Y
254
    wIn[3] = FROM_8_TO_16(*accum); accum++; // K
255

256
    return accum;
257

258
    cmsUNUSED_PARAMETER(info);
259
    cmsUNUSED_PARAMETER(Stride);
260
}
261

262
static
263
cmsUInt8Number* Unroll4BytesReverse(CMSREGISTER _cmsTRANSFORM* info,
264
                                    CMSREGISTER cmsUInt16Number wIn[],
265
                                    CMSREGISTER cmsUInt8Number* accum,
266
                                    CMSREGISTER cmsUInt32Number Stride)
267
{
268
    wIn[0] = FROM_8_TO_16(REVERSE_FLAVOR_8(*accum)); accum++; // C
269
    wIn[1] = FROM_8_TO_16(REVERSE_FLAVOR_8(*accum)); accum++; // M
270
    wIn[2] = FROM_8_TO_16(REVERSE_FLAVOR_8(*accum)); accum++; // Y
271
    wIn[3] = FROM_8_TO_16(REVERSE_FLAVOR_8(*accum)); accum++; // K
272

273
    return accum;
274

275
    cmsUNUSED_PARAMETER(info);
276
    cmsUNUSED_PARAMETER(Stride);
277
}
278

279
static
280
cmsUInt8Number* Unroll4BytesSwapFirst(CMSREGISTER _cmsTRANSFORM* info,
281
                                      CMSREGISTER cmsUInt16Number wIn[],
282
                                      CMSREGISTER cmsUInt8Number* accum,
283
                                      CMSREGISTER cmsUInt32Number Stride)
284
{
285
    wIn[3] = FROM_8_TO_16(*accum); accum++; // K
286
    wIn[0] = FROM_8_TO_16(*accum); accum++; // C
287
    wIn[1] = FROM_8_TO_16(*accum); accum++; // M
288
    wIn[2] = FROM_8_TO_16(*accum); accum++; // Y
289

290
    return accum;
291

292
    cmsUNUSED_PARAMETER(info);
293
    cmsUNUSED_PARAMETER(Stride);
294
}
295

296
// KYMC
297
static
298
cmsUInt8Number* Unroll4BytesSwap(CMSREGISTER _cmsTRANSFORM* info,
299
                                 CMSREGISTER cmsUInt16Number wIn[],
300
                                 CMSREGISTER cmsUInt8Number* accum,
301
                                 CMSREGISTER cmsUInt32Number Stride)
302
{
303
    wIn[3] = FROM_8_TO_16(*accum); accum++;  // K
304
    wIn[2] = FROM_8_TO_16(*accum); accum++;  // Y
305
    wIn[1] = FROM_8_TO_16(*accum); accum++;  // M
306
    wIn[0] = FROM_8_TO_16(*accum); accum++;  // C
307

308
    return accum;
309

310
    cmsUNUSED_PARAMETER(info);
311
    cmsUNUSED_PARAMETER(Stride);
312
}
313

314
static
315
cmsUInt8Number* Unroll4BytesSwapSwapFirst(CMSREGISTER _cmsTRANSFORM* info,
316
                                          CMSREGISTER cmsUInt16Number wIn[],
317
                                          CMSREGISTER cmsUInt8Number* accum,
318
                                          CMSREGISTER cmsUInt32Number Stride)
319
{
320
    wIn[2] = FROM_8_TO_16(*accum); accum++;  // K
321
    wIn[1] = FROM_8_TO_16(*accum); accum++;  // Y
322
    wIn[0] = FROM_8_TO_16(*accum); accum++;  // M
323
    wIn[3] = FROM_8_TO_16(*accum); accum++;  // C
324

325
    return accum;
326

327
    cmsUNUSED_PARAMETER(info);
328
    cmsUNUSED_PARAMETER(Stride);
329
}
330

331
static
332
cmsUInt8Number* Unroll3Bytes(CMSREGISTER _cmsTRANSFORM* info,
333
                             CMSREGISTER cmsUInt16Number wIn[],
334
                             CMSREGISTER cmsUInt8Number* accum,
335
                             CMSREGISTER cmsUInt32Number Stride)
336
{
337
    wIn[0] = FROM_8_TO_16(*accum); accum++;     // R
338
    wIn[1] = FROM_8_TO_16(*accum); accum++;     // G
339
    wIn[2] = FROM_8_TO_16(*accum); accum++;     // B
340

341
    return accum;
342

343
    cmsUNUSED_PARAMETER(info);
344
    cmsUNUSED_PARAMETER(Stride);
345
}
346

347
static
348
cmsUInt8Number* Unroll3BytesSkip1Swap(CMSREGISTER _cmsTRANSFORM* info,
349
                                      CMSREGISTER cmsUInt16Number wIn[],
350
                                      CMSREGISTER cmsUInt8Number* accum,
351
                                      CMSREGISTER cmsUInt32Number Stride)
352
{
353
    accum++; // A
354
    wIn[2] = FROM_8_TO_16(*accum); accum++; // B
355
    wIn[1] = FROM_8_TO_16(*accum); accum++; // G
356
    wIn[0] = FROM_8_TO_16(*accum); accum++; // R
357

358
    return accum;
359

360
    cmsUNUSED_PARAMETER(info);
361
    cmsUNUSED_PARAMETER(Stride);
362
}
363

364
static
365
cmsUInt8Number* Unroll3BytesSkip1SwapSwapFirst(CMSREGISTER _cmsTRANSFORM* info,
366
                                              CMSREGISTER cmsUInt16Number wIn[],
367
                                              CMSREGISTER cmsUInt8Number* accum,
368
                                              CMSREGISTER cmsUInt32Number Stride)
369
{
370
    wIn[2] = FROM_8_TO_16(*accum); accum++; // B
371
    wIn[1] = FROM_8_TO_16(*accum); accum++; // G
372
    wIn[0] = FROM_8_TO_16(*accum); accum++; // R
373
    accum++; // A
374

375
    return accum;
376

377
    cmsUNUSED_PARAMETER(info);
378
    cmsUNUSED_PARAMETER(Stride);
379
}
380

381
static
382
cmsUInt8Number* Unroll3BytesSkip1SwapFirst(CMSREGISTER _cmsTRANSFORM* info,
383
                                           CMSREGISTER cmsUInt16Number wIn[],
384
                                           CMSREGISTER cmsUInt8Number* accum,
385
                                           CMSREGISTER cmsUInt32Number Stride)
386
{
387
    accum++; // A
388
    wIn[0] = FROM_8_TO_16(*accum); accum++; // R
389
    wIn[1] = FROM_8_TO_16(*accum); accum++; // G
390
    wIn[2] = FROM_8_TO_16(*accum); accum++; // B
391

392
    return accum;
393

394
    cmsUNUSED_PARAMETER(info);
395
    cmsUNUSED_PARAMETER(Stride);
396
}
397

398

399
// BRG
400
static
401
cmsUInt8Number* Unroll3BytesSwap(CMSREGISTER _cmsTRANSFORM* info,
402
                                 CMSREGISTER cmsUInt16Number wIn[],
403
                                 CMSREGISTER cmsUInt8Number* accum,
404
                                 CMSREGISTER cmsUInt32Number Stride)
405
{
406
    wIn[2] = FROM_8_TO_16(*accum); accum++;     // B
407
    wIn[1] = FROM_8_TO_16(*accum); accum++;     // G
408
    wIn[0] = FROM_8_TO_16(*accum); accum++;     // R
409

410
    return accum;
411

412
    cmsUNUSED_PARAMETER(info);
413
    cmsUNUSED_PARAMETER(Stride);
414
}
415

416
static
417
cmsUInt8Number* UnrollLabV2_8(CMSREGISTER _cmsTRANSFORM* info,
418
                              CMSREGISTER cmsUInt16Number wIn[],
419
                              CMSREGISTER cmsUInt8Number* accum,
420
                              CMSREGISTER cmsUInt32Number Stride)
421
{
422
    wIn[0] = FomLabV2ToLabV4(FROM_8_TO_16(*accum)); accum++;     // L
423
    wIn[1] = FomLabV2ToLabV4(FROM_8_TO_16(*accum)); accum++;     // a
424
    wIn[2] = FomLabV2ToLabV4(FROM_8_TO_16(*accum)); accum++;     // b
425

426
    return accum;
427

428
    cmsUNUSED_PARAMETER(info);
429
    cmsUNUSED_PARAMETER(Stride);
430
}
431

432
static
433
cmsUInt8Number* UnrollALabV2_8(CMSREGISTER _cmsTRANSFORM* info,
434
                               CMSREGISTER cmsUInt16Number wIn[],
435
                               CMSREGISTER cmsUInt8Number* accum,
436
                               CMSREGISTER cmsUInt32Number Stride)
437
{
438
    accum++;  // A
439
    wIn[0] = FomLabV2ToLabV4(FROM_8_TO_16(*accum)); accum++;     // L
440
    wIn[1] = FomLabV2ToLabV4(FROM_8_TO_16(*accum)); accum++;     // a
441
    wIn[2] = FomLabV2ToLabV4(FROM_8_TO_16(*accum)); accum++;     // b
442

443
    return accum;
444

445
    cmsUNUSED_PARAMETER(info);
446
    cmsUNUSED_PARAMETER(Stride);
447
}
448

449
static
450
cmsUInt8Number* UnrollLabV2_16(CMSREGISTER _cmsTRANSFORM* info,
451
                               CMSREGISTER cmsUInt16Number wIn[],
452
                               CMSREGISTER cmsUInt8Number* accum,
453
                               CMSREGISTER cmsUInt32Number Stride)
454
{
455
    wIn[0] = FomLabV2ToLabV4(*(cmsUInt16Number*) accum); accum += 2;     // L
456
    wIn[1] = FomLabV2ToLabV4(*(cmsUInt16Number*) accum); accum += 2;     // a
457
    wIn[2] = FomLabV2ToLabV4(*(cmsUInt16Number*) accum); accum += 2;     // b
458

459
    return accum;
460

461
    cmsUNUSED_PARAMETER(info);
462
    cmsUNUSED_PARAMETER(Stride);
463
}
464

465
// for duplex
466
static
467
cmsUInt8Number* Unroll2Bytes(CMSREGISTER _cmsTRANSFORM* info,
468
                                     CMSREGISTER cmsUInt16Number wIn[],
469
                                     CMSREGISTER cmsUInt8Number* accum,
470
                                     CMSREGISTER cmsUInt32Number Stride)
471
{
472
    wIn[0] = FROM_8_TO_16(*accum); accum++;     // ch1
473
    wIn[1] = FROM_8_TO_16(*accum); accum++;     // ch2
474

475
    return accum;
476

477
    cmsUNUSED_PARAMETER(info);
478
    cmsUNUSED_PARAMETER(Stride);
479
}
480

481

482

483

484
// Monochrome duplicates L into RGB for null-transforms
485
static
486
cmsUInt8Number* Unroll1Byte(CMSREGISTER _cmsTRANSFORM* info,
487
                            CMSREGISTER cmsUInt16Number wIn[],
488
                            CMSREGISTER cmsUInt8Number* accum,
489
                            CMSREGISTER cmsUInt32Number Stride)
490
{
491
    wIn[0] = wIn[1] = wIn[2] = FROM_8_TO_16(*accum); accum++;     // L
492

493
    return accum;
494

495
    cmsUNUSED_PARAMETER(info);
496
    cmsUNUSED_PARAMETER(Stride);
497
}
498

499

500
static
501
cmsUInt8Number* Unroll1ByteSkip1(CMSREGISTER _cmsTRANSFORM* info,
502
                                 CMSREGISTER cmsUInt16Number wIn[],
503
                                 CMSREGISTER cmsUInt8Number* accum,
504
                                 CMSREGISTER cmsUInt32Number Stride)
505
{
506
    wIn[0] = wIn[1] = wIn[2] = FROM_8_TO_16(*accum); accum++;     // L
507
    accum += 1;
508

509
    return accum;
510

511
    cmsUNUSED_PARAMETER(info);
512
    cmsUNUSED_PARAMETER(Stride);
513
}
514

515
static
516
cmsUInt8Number* Unroll1ByteSkip2(CMSREGISTER _cmsTRANSFORM* info,
517
                                 CMSREGISTER cmsUInt16Number wIn[],
518
                                 CMSREGISTER cmsUInt8Number* accum,
519
                                 CMSREGISTER cmsUInt32Number Stride)
520
{
521
    wIn[0] = wIn[1] = wIn[2] = FROM_8_TO_16(*accum); accum++;     // L
522
    accum += 2;
523

524
    return accum;
525

526
    cmsUNUSED_PARAMETER(info);
527
    cmsUNUSED_PARAMETER(Stride);
528
}
529

530
static
531
cmsUInt8Number* Unroll1ByteReversed(CMSREGISTER _cmsTRANSFORM* info,
532
                                    CMSREGISTER cmsUInt16Number wIn[],
533
                                    CMSREGISTER cmsUInt8Number* accum,
534
                                    CMSREGISTER cmsUInt32Number Stride)
535
{
536
    wIn[0] = wIn[1] = wIn[2] = REVERSE_FLAVOR_16(FROM_8_TO_16(*accum)); accum++;     // L
537

538
    return accum;
539

540
    cmsUNUSED_PARAMETER(info);
541
    cmsUNUSED_PARAMETER(Stride);
542
}
543

544

545
static
546
cmsUInt8Number* UnrollAnyWords(CMSREGISTER _cmsTRANSFORM* info,
547
                               CMSREGISTER cmsUInt16Number wIn[],
548
                               CMSREGISTER cmsUInt8Number* accum,
549
                               CMSREGISTER cmsUInt32Number Stride)
550
{
551
   cmsUInt32Number nChan       = T_CHANNELS(info -> InputFormat);
552
   cmsUInt32Number SwapEndian  = T_ENDIAN16(info -> InputFormat);
553
   cmsUInt32Number DoSwap      = T_DOSWAP(info ->InputFormat);
554
   cmsUInt32Number Reverse     = T_FLAVOR(info ->InputFormat);
555
   cmsUInt32Number SwapFirst   = T_SWAPFIRST(info -> InputFormat);
556
   cmsUInt32Number Extra       = T_EXTRA(info -> InputFormat);
557
   cmsUInt32Number ExtraFirst  = DoSwap ^ SwapFirst;
558
   cmsUInt32Number i;
559

560
    if (ExtraFirst) {
561
        accum += Extra * sizeof(cmsUInt16Number);
562
    }
563

564
    for (i=0; i < nChan; i++) {
565

566
        cmsUInt32Number index = DoSwap ? (nChan - i - 1) : i;
567
        cmsUInt16Number v = *(cmsUInt16Number*) accum;
568

569
        if (SwapEndian)
570
            v = CHANGE_ENDIAN(v);
571

572
        wIn[index] = Reverse ? REVERSE_FLAVOR_16(v) : v;
573

574
        accum += sizeof(cmsUInt16Number);
575
    }
576

577
    if (!ExtraFirst) {
578
        accum += Extra * sizeof(cmsUInt16Number);
579
    }
580

581
    if (Extra == 0 && SwapFirst) {
582

583
        cmsUInt16Number tmp = wIn[0];
584

585
        memmove(&wIn[0], &wIn[1], (nChan-1) * sizeof(cmsUInt16Number));
586
        wIn[nChan-1] = tmp;
587
    }
588

589
    return accum;
590

591
    cmsUNUSED_PARAMETER(Stride);
592
}
593

594

595
static
596
cmsUInt8Number* UnrollAnyWordsPremul(CMSREGISTER _cmsTRANSFORM* info,
597
                                     CMSREGISTER cmsUInt16Number wIn[],
598
                                     CMSREGISTER cmsUInt8Number* accum,
599
                                     CMSREGISTER cmsUInt32Number Stride)
600
{
601
   cmsUInt32Number nChan       = T_CHANNELS(info -> InputFormat);
602
   cmsUInt32Number SwapEndian  = T_ENDIAN16(info -> InputFormat);
603
   cmsUInt32Number DoSwap      = T_DOSWAP(info ->InputFormat);
604
   cmsUInt32Number Reverse     = T_FLAVOR(info ->InputFormat);
605
   cmsUInt32Number SwapFirst   = T_SWAPFIRST(info -> InputFormat);
606
   cmsUInt32Number ExtraFirst  = DoSwap ^ SwapFirst;
607
   cmsUInt32Number i;
608

609
   cmsUInt16Number alpha = (ExtraFirst ? accum[0] : accum[nChan - 1]);
610
   cmsUInt32Number alpha_factor = _cmsToFixedDomain(FROM_8_TO_16(alpha));
611

612
    if (ExtraFirst) {
613
        accum += sizeof(cmsUInt16Number);
614
    }
615

616
    for (i=0; i < nChan; i++) {
617

618
        cmsUInt32Number index = DoSwap ? (nChan - i - 1) : i;
619
        cmsUInt32Number v = *(cmsUInt16Number*) accum;
620

621
        if (SwapEndian)
622
            v = CHANGE_ENDIAN(v);
623

624
        if (alpha_factor > 0) {
625

626
            v = (v << 16) / alpha_factor;
627
            if (v > 0xffff) v = 0xffff;
628
        }
629

630
        wIn[index] = (cmsUInt16Number) (Reverse ? REVERSE_FLAVOR_16(v) : v);
631

632
        accum += sizeof(cmsUInt16Number);
633
    }
634

635
    if (!ExtraFirst) {
636
        accum += sizeof(cmsUInt16Number);
637
    }
638

639
    return accum;
640

641
    cmsUNUSED_PARAMETER(Stride);
642
}
643

644

645

646
static
647
cmsUInt8Number* UnrollPlanarWords(CMSREGISTER _cmsTRANSFORM* info,
648
                                  CMSREGISTER cmsUInt16Number wIn[],
649
                                  CMSREGISTER cmsUInt8Number* accum,
650
                                  CMSREGISTER cmsUInt32Number Stride)
651
{
652
    cmsUInt32Number nChan = T_CHANNELS(info -> InputFormat);
653
    cmsUInt32Number DoSwap= T_DOSWAP(info ->InputFormat);
654
    cmsUInt32Number Reverse= T_FLAVOR(info ->InputFormat);
655
    cmsUInt32Number SwapEndian = T_ENDIAN16(info -> InputFormat);
656
    cmsUInt32Number i;
657
    cmsUInt8Number* Init = accum;
658

659
    if (DoSwap) {
660
        accum += T_EXTRA(info -> InputFormat) * Stride;
661
    }
662

663
    for (i=0; i < nChan; i++) {
664

665
        cmsUInt32Number index = DoSwap ? (nChan - i - 1) : i;
666
        cmsUInt16Number v = *(cmsUInt16Number*) accum;
667

668
        if (SwapEndian)
669
            v = CHANGE_ENDIAN(v);
670

671
        wIn[index] = Reverse ? REVERSE_FLAVOR_16(v) : v;
672

673
        accum +=  Stride;
674
    }
675

676
    return (Init + sizeof(cmsUInt16Number));
677
}
678

679
static
680
cmsUInt8Number* UnrollPlanarWordsPremul(CMSREGISTER _cmsTRANSFORM* info,
681
                                        CMSREGISTER cmsUInt16Number wIn[],
682
                                        CMSREGISTER cmsUInt8Number* accum,
683
                                        CMSREGISTER cmsUInt32Number Stride)
684
{
685
    cmsUInt32Number nChan = T_CHANNELS(info -> InputFormat);
686
    cmsUInt32Number DoSwap= T_DOSWAP(info ->InputFormat);
687
    cmsUInt32Number SwapFirst = T_SWAPFIRST(info->InputFormat);
688
    cmsUInt32Number Reverse= T_FLAVOR(info ->InputFormat);
689
    cmsUInt32Number SwapEndian = T_ENDIAN16(info -> InputFormat);
690
    cmsUInt32Number i;
691
    cmsUInt32Number ExtraFirst = DoSwap ^ SwapFirst;
692
    cmsUInt8Number* Init = accum;
693

694
    cmsUInt16Number  alpha = (ExtraFirst ? accum[0] : accum[(nChan - 1) * Stride]);
695
    cmsUInt32Number alpha_factor = _cmsToFixedDomain(FROM_8_TO_16(alpha));
696

697
    if (ExtraFirst) {
698
        accum += Stride;
699
    }
700

701
    for (i=0; i < nChan; i++) {
702

703
        cmsUInt32Number index = DoSwap ? (nChan - i - 1) : i;
704
        cmsUInt32Number v = (cmsUInt32Number) *(cmsUInt16Number*) accum;
705

706
        if (SwapEndian)
707
            v = CHANGE_ENDIAN(v);
708

709
        if (alpha_factor > 0) {
710

711
            v = (v << 16) / alpha_factor;
712
            if (v > 0xffff) v = 0xffff;
713
        }
714

715
        wIn[index] = (cmsUInt16Number) (Reverse ? REVERSE_FLAVOR_16(v) : v);
716

717
        accum +=  Stride;
718
    }
719

720
    return (Init + sizeof(cmsUInt16Number));
721
}
722

723
static
724
cmsUInt8Number* Unroll4Words(CMSREGISTER _cmsTRANSFORM* info,
725
                             CMSREGISTER cmsUInt16Number wIn[],
726
                             CMSREGISTER cmsUInt8Number* accum,
727
                             CMSREGISTER cmsUInt32Number Stride)
728
{
729
    wIn[0] = *(cmsUInt16Number*) accum; accum+= 2; // C
730
    wIn[1] = *(cmsUInt16Number*) accum; accum+= 2; // M
731
    wIn[2] = *(cmsUInt16Number*) accum; accum+= 2; // Y
732
    wIn[3] = *(cmsUInt16Number*) accum; accum+= 2; // K
733

734
    return accum;
735

736
    cmsUNUSED_PARAMETER(info);
737
    cmsUNUSED_PARAMETER(Stride);
738
}
739

740
static
741
cmsUInt8Number* Unroll4WordsReverse(CMSREGISTER _cmsTRANSFORM* info,
742
                                    CMSREGISTER cmsUInt16Number wIn[],
743
                                    CMSREGISTER cmsUInt8Number* accum,
744
                                    CMSREGISTER cmsUInt32Number Stride)
745
{
746
    wIn[0] = REVERSE_FLAVOR_16(*(cmsUInt16Number*) accum); accum+= 2; // C
747
    wIn[1] = REVERSE_FLAVOR_16(*(cmsUInt16Number*) accum); accum+= 2; // M
748
    wIn[2] = REVERSE_FLAVOR_16(*(cmsUInt16Number*) accum); accum+= 2; // Y
749
    wIn[3] = REVERSE_FLAVOR_16(*(cmsUInt16Number*) accum); accum+= 2; // K
750

751
    return accum;
752

753
    cmsUNUSED_PARAMETER(info);
754
    cmsUNUSED_PARAMETER(Stride);
755
}
756

757
static
758
cmsUInt8Number* Unroll4WordsSwapFirst(CMSREGISTER _cmsTRANSFORM* info,
759
                                      CMSREGISTER cmsUInt16Number wIn[],
760
                                      CMSREGISTER cmsUInt8Number* accum,
761
                                      CMSREGISTER cmsUInt32Number Stride)
762
{
763
    wIn[3] = *(cmsUInt16Number*) accum; accum+= 2; // K
764
    wIn[0] = *(cmsUInt16Number*) accum; accum+= 2; // C
765
    wIn[1] = *(cmsUInt16Number*) accum; accum+= 2; // M
766
    wIn[2] = *(cmsUInt16Number*) accum; accum+= 2; // Y
767

768
    return accum;
769

770
    cmsUNUSED_PARAMETER(info);
771
    cmsUNUSED_PARAMETER(Stride);
772
}
773

774
// KYMC
775
static
776
cmsUInt8Number* Unroll4WordsSwap(CMSREGISTER _cmsTRANSFORM* info,
777
                                 CMSREGISTER cmsUInt16Number wIn[],
778
                                 CMSREGISTER cmsUInt8Number* accum,
779
                                 CMSREGISTER cmsUInt32Number Stride)
780
{
781
    wIn[3] = *(cmsUInt16Number*) accum; accum+= 2; // K
782
    wIn[2] = *(cmsUInt16Number*) accum; accum+= 2; // Y
783
    wIn[1] = *(cmsUInt16Number*) accum; accum+= 2; // M
784
    wIn[0] = *(cmsUInt16Number*) accum; accum+= 2; // C
785

786
    return accum;
787

788
    cmsUNUSED_PARAMETER(info);
789
    cmsUNUSED_PARAMETER(Stride);
790
}
791

792
static
793
cmsUInt8Number* Unroll4WordsSwapSwapFirst(CMSREGISTER _cmsTRANSFORM* info,
794
                                          CMSREGISTER cmsUInt16Number wIn[],
795
                                          CMSREGISTER cmsUInt8Number* accum,
796
                                          CMSREGISTER cmsUInt32Number Stride)
797
{
798
    wIn[2] = *(cmsUInt16Number*) accum; accum+= 2; // K
799
    wIn[1] = *(cmsUInt16Number*) accum; accum+= 2; // Y
800
    wIn[0] = *(cmsUInt16Number*) accum; accum+= 2; // M
801
    wIn[3] = *(cmsUInt16Number*) accum; accum+= 2; // C
802

803
    return accum;
804

805
    cmsUNUSED_PARAMETER(info);
806
    cmsUNUSED_PARAMETER(Stride);
807
}
808

809
static
810
cmsUInt8Number* Unroll3Words(CMSREGISTER _cmsTRANSFORM* info,
811
                             CMSREGISTER cmsUInt16Number wIn[],
812
                             CMSREGISTER cmsUInt8Number* accum,
813
                             CMSREGISTER cmsUInt32Number Stride)
814
{
815
    wIn[0] = *(cmsUInt16Number*) accum; accum+= 2;  // C R
816
    wIn[1] = *(cmsUInt16Number*) accum; accum+= 2;  // M G
817
    wIn[2] = *(cmsUInt16Number*) accum; accum+= 2;  // Y B
818

819
    return accum;
820

821
    cmsUNUSED_PARAMETER(info);
822
    cmsUNUSED_PARAMETER(Stride);
823
}
824

825
static
826
cmsUInt8Number* Unroll3WordsSwap(CMSREGISTER _cmsTRANSFORM* info,
827
                                 CMSREGISTER cmsUInt16Number wIn[],
828
                                 CMSREGISTER cmsUInt8Number* accum,
829
                                 CMSREGISTER cmsUInt32Number Stride)
830
{
831
    wIn[2] = *(cmsUInt16Number*) accum; accum+= 2;  // C R
832
    wIn[1] = *(cmsUInt16Number*) accum; accum+= 2;  // M G
833
    wIn[0] = *(cmsUInt16Number*) accum; accum+= 2;  // Y B
834

835
    return accum;
836

837
    cmsUNUSED_PARAMETER(info);
838
    cmsUNUSED_PARAMETER(Stride);
839
}
840

841
static
842
cmsUInt8Number* Unroll3WordsSkip1Swap(CMSREGISTER _cmsTRANSFORM* info,
843
                                      CMSREGISTER cmsUInt16Number wIn[],
844
                                      CMSREGISTER cmsUInt8Number* accum,
845
                                      CMSREGISTER cmsUInt32Number Stride)
846
{
847
    accum += 2; // A
848
    wIn[2] = *(cmsUInt16Number*) accum; accum += 2; // R
849
    wIn[1] = *(cmsUInt16Number*) accum; accum += 2; // G
850
    wIn[0] = *(cmsUInt16Number*) accum; accum += 2; // B
851

852
    return accum;
853

854
    cmsUNUSED_PARAMETER(info);
855
    cmsUNUSED_PARAMETER(Stride);
856
}
857

858
static
859
cmsUInt8Number* Unroll3WordsSkip1SwapFirst(CMSREGISTER _cmsTRANSFORM* info,
860
                                           CMSREGISTER cmsUInt16Number wIn[],
861
                                           CMSREGISTER cmsUInt8Number* accum,
862
                                           CMSREGISTER cmsUInt32Number Stride)
863
{
864
    accum += 2; // A
865
    wIn[0] = *(cmsUInt16Number*) accum; accum += 2; // R
866
    wIn[1] = *(cmsUInt16Number*) accum; accum += 2; // G
867
    wIn[2] = *(cmsUInt16Number*) accum; accum += 2; // B
868

869
    return accum;
870

871
    cmsUNUSED_PARAMETER(info);
872
    cmsUNUSED_PARAMETER(Stride);
873
}
874

875
static
876
cmsUInt8Number* Unroll1Word(CMSREGISTER _cmsTRANSFORM* info,
877
                            CMSREGISTER cmsUInt16Number wIn[],
878
                            CMSREGISTER cmsUInt8Number* accum,
879
                            CMSREGISTER cmsUInt32Number Stride)
880
{
881
    wIn[0] = wIn[1] = wIn[2] = *(cmsUInt16Number*) accum; accum+= 2;   // L
882

883
    return accum;
884

885
    cmsUNUSED_PARAMETER(info);
886
    cmsUNUSED_PARAMETER(Stride);
887
}
888

889
static
890
cmsUInt8Number* Unroll1WordReversed(CMSREGISTER _cmsTRANSFORM* info,
891
                                    CMSREGISTER cmsUInt16Number wIn[],
892
                                    CMSREGISTER cmsUInt8Number* accum,
893
                                    CMSREGISTER cmsUInt32Number Stride)
894
{
895
    wIn[0] = wIn[1] = wIn[2] = REVERSE_FLAVOR_16(*(cmsUInt16Number*) accum); accum+= 2;
896

897
    return accum;
898

899
    cmsUNUSED_PARAMETER(info);
900
    cmsUNUSED_PARAMETER(Stride);
901
}
902

903
static
904
cmsUInt8Number* Unroll1WordSkip3(CMSREGISTER _cmsTRANSFORM* info,
905
                                 CMSREGISTER cmsUInt16Number wIn[],
906
                                 CMSREGISTER cmsUInt8Number* accum,
907
                                 CMSREGISTER cmsUInt32Number Stride)
908
{
909
    wIn[0] = wIn[1] = wIn[2] = *(cmsUInt16Number*) accum;
910

911
    accum += 8;
912

913
    return accum;
914

915
    cmsUNUSED_PARAMETER(info);
916
    cmsUNUSED_PARAMETER(Stride);
917
}
918

919
static
920
cmsUInt8Number* Unroll2Words(CMSREGISTER _cmsTRANSFORM* info,
921
                                     CMSREGISTER cmsUInt16Number wIn[],
922
                                     CMSREGISTER cmsUInt8Number* accum,
923
                                     CMSREGISTER cmsUInt32Number Stride)
924
{
925
    wIn[0] = *(cmsUInt16Number*) accum; accum += 2;    // ch1
926
    wIn[1] = *(cmsUInt16Number*) accum; accum += 2;    // ch2
927

928
    return accum;
929

930
    cmsUNUSED_PARAMETER(info);
931
    cmsUNUSED_PARAMETER(Stride);
932
}
933

934

935
// This is a conversion of Lab double to 16 bits
936
static
937
cmsUInt8Number* UnrollLabDoubleTo16(CMSREGISTER _cmsTRANSFORM* info,
938
                                    CMSREGISTER cmsUInt16Number wIn[],
939
                                    CMSREGISTER cmsUInt8Number* accum,
940
                                    CMSREGISTER cmsUInt32Number  Stride)
941
{
942
    if (T_PLANAR(info -> InputFormat)) {
943

944
        cmsCIELab Lab;
945
        cmsUInt8Number* pos_L;
946
        cmsUInt8Number* pos_a;
947
        cmsUInt8Number* pos_b;
948

949
        pos_L = accum;
950
        pos_a = accum + Stride;
951
        pos_b = accum + Stride * 2;
952

953
        Lab.L = *(cmsFloat64Number*) pos_L;
954
        Lab.a = *(cmsFloat64Number*) pos_a;
955
        Lab.b = *(cmsFloat64Number*) pos_b;
956

957
        cmsFloat2LabEncoded(wIn, &Lab);
958
        return accum + sizeof(cmsFloat64Number);
959
    }
960
    else {
961

962
        cmsFloat2LabEncoded(wIn, (cmsCIELab*) accum);
963
        accum += sizeof(cmsCIELab) + T_EXTRA(info ->InputFormat) * sizeof(cmsFloat64Number);
964
        return accum;
965
    }
966
}
967

968

969
// This is a conversion of Lab float to 16 bits
970
static
971
cmsUInt8Number* UnrollLabFloatTo16(CMSREGISTER _cmsTRANSFORM* info,
972
                                    CMSREGISTER cmsUInt16Number wIn[],
973
                                    CMSREGISTER cmsUInt8Number* accum,
974
                                    CMSREGISTER cmsUInt32Number  Stride)
975
{
976
    cmsCIELab Lab;
977

978
    if (T_PLANAR(info -> InputFormat)) {
979

980
        cmsUInt8Number* pos_L;
981
        cmsUInt8Number* pos_a;
982
        cmsUInt8Number* pos_b;
983

984
        pos_L = accum;
985
        pos_a = accum + Stride;
986
        pos_b = accum + Stride * 2;
987

988
        Lab.L = *(cmsFloat32Number*)pos_L;
989
        Lab.a = *(cmsFloat32Number*)pos_a;
990
        Lab.b = *(cmsFloat32Number*)pos_b;
991

992
        cmsFloat2LabEncoded(wIn, &Lab);
993
        return accum + sizeof(cmsFloat32Number);
994
    }
995
    else {
996

997
        Lab.L = ((cmsFloat32Number*) accum)[0];
998
        Lab.a = ((cmsFloat32Number*) accum)[1];
999
        Lab.b = ((cmsFloat32Number*) accum)[2];
1000

1001
        cmsFloat2LabEncoded(wIn, &Lab);
1002
        accum += (3 + T_EXTRA(info ->InputFormat)) * sizeof(cmsFloat32Number);
1003
        return accum;
1004
    }
1005
}
1006

1007
// This is a conversion of XYZ double to 16 bits
1008
static
1009
cmsUInt8Number* UnrollXYZDoubleTo16(CMSREGISTER _cmsTRANSFORM* info,
1010
                                    CMSREGISTER cmsUInt16Number wIn[],
1011
                                    CMSREGISTER cmsUInt8Number* accum,
1012
                                    CMSREGISTER cmsUInt32Number Stride)
1013
{
1014
    if (T_PLANAR(info -> InputFormat)) {
1015

1016
        cmsCIEXYZ XYZ;
1017
        cmsUInt8Number* pos_X;
1018
        cmsUInt8Number* pos_Y;
1019
        cmsUInt8Number* pos_Z;
1020

1021
        pos_X = accum;
1022
        pos_Y = accum + Stride;
1023
        pos_Z = accum + Stride * 2;
1024

1025
        XYZ.X = *(cmsFloat64Number*)pos_X;
1026
        XYZ.Y = *(cmsFloat64Number*)pos_Y;
1027
        XYZ.Z = *(cmsFloat64Number*)pos_Z;
1028

1029
        cmsFloat2XYZEncoded(wIn, &XYZ);
1030

1031
        return accum + sizeof(cmsFloat64Number);
1032

1033
    }
1034

1035
    else {
1036
        cmsFloat2XYZEncoded(wIn, (cmsCIEXYZ*) accum);
1037
        accum += sizeof(cmsCIEXYZ) + T_EXTRA(info ->InputFormat) * sizeof(cmsFloat64Number);
1038

1039
        return accum;
1040
    }
1041
}
1042

1043
// This is a conversion of XYZ float to 16 bits
1044
static
1045
cmsUInt8Number* UnrollXYZFloatTo16(CMSREGISTER _cmsTRANSFORM* info,
1046
                                   CMSREGISTER cmsUInt16Number wIn[],
1047
                                   CMSREGISTER cmsUInt8Number* accum,
1048
                                   CMSREGISTER cmsUInt32Number Stride)
1049
{
1050
    if (T_PLANAR(info -> InputFormat)) {
1051

1052
        cmsCIEXYZ XYZ;
1053
        cmsUInt8Number* pos_X;
1054
        cmsUInt8Number* pos_Y;
1055
        cmsUInt8Number* pos_Z;
1056

1057
        pos_X = accum;
1058
        pos_Y = accum + Stride;
1059
        pos_Z = accum + Stride * 2;
1060

1061
        XYZ.X = *(cmsFloat32Number*)pos_X;
1062
        XYZ.Y = *(cmsFloat32Number*)pos_Y;
1063
        XYZ.Z = *(cmsFloat32Number*)pos_Z;
1064

1065
        cmsFloat2XYZEncoded(wIn, &XYZ);
1066

1067
        return accum + sizeof(cmsFloat32Number);
1068

1069
    }
1070

1071
    else {
1072
        cmsFloat32Number* Pt = (cmsFloat32Number*) accum;
1073
        cmsCIEXYZ XYZ;
1074

1075
        XYZ.X = Pt[0];
1076
        XYZ.Y = Pt[1];
1077
        XYZ.Z = Pt[2];
1078
        cmsFloat2XYZEncoded(wIn, &XYZ);
1079

1080
        accum += 3 * sizeof(cmsFloat32Number) + T_EXTRA(info ->InputFormat) * sizeof(cmsFloat32Number);
1081

1082
        return accum;
1083
    }
1084
}
1085

1086
// Check if space is marked as ink
1087
cmsINLINE cmsBool IsInkSpace(cmsUInt32Number Type)
1088
{
1089
    switch (T_COLORSPACE(Type)) {
1090

1091
     case PT_CMY:
1092
     case PT_CMYK:
1093
     case PT_MCH5:
1094
     case PT_MCH6:
1095
     case PT_MCH7:
1096
     case PT_MCH8:
1097
     case PT_MCH9:
1098
     case PT_MCH10:
1099
     case PT_MCH11:
1100
     case PT_MCH12:
1101
     case PT_MCH13:
1102
     case PT_MCH14:
1103
     case PT_MCH15: return TRUE;
1104

1105
     default: return FALSE;
1106
    }
1107
}
1108

1109
// Return the size in bytes of a given formatter
1110
static
1111
cmsUInt32Number PixelSize(cmsUInt32Number Format)
1112
{
1113
    cmsUInt32Number fmt_bytes = T_BYTES(Format);
1114

1115
    // For double, the T_BYTES field is zero
1116
    if (fmt_bytes == 0)
1117
        return sizeof(cmsUInt64Number);
1118

1119
    // Otherwise, it is already correct for all formats
1120
    return fmt_bytes;
1121
}
1122

1123
// Inks does come in percentage, remaining cases are between 0..1.0, again to 16 bits
1124
static
1125
cmsUInt8Number* UnrollDoubleTo16(CMSREGISTER _cmsTRANSFORM* info,
1126
                                CMSREGISTER cmsUInt16Number wIn[],
1127
                                CMSREGISTER cmsUInt8Number* accum,
1128
                                CMSREGISTER cmsUInt32Number Stride)
1129
{
1130

1131
    cmsUInt32Number nChan      = T_CHANNELS(info -> InputFormat);
1132
    cmsUInt32Number DoSwap     = T_DOSWAP(info ->InputFormat);
1133
    cmsUInt32Number Reverse    = T_FLAVOR(info ->InputFormat);
1134
    cmsUInt32Number SwapFirst  = T_SWAPFIRST(info -> InputFormat);
1135
    cmsUInt32Number Extra      = T_EXTRA(info -> InputFormat);
1136
    cmsUInt32Number ExtraFirst = DoSwap ^ SwapFirst;
1137
    cmsUInt32Number Planar     = T_PLANAR(info -> InputFormat);
1138
    cmsFloat64Number v;
1139
    cmsUInt16Number  vi;
1140
    cmsUInt32Number i, start = 0;
1141
    cmsFloat64Number maximum = IsInkSpace(info ->InputFormat) ? 655.35 : 65535.0;
1142

1143

1144
    Stride /= PixelSize(info->InputFormat);
1145

1146
    if (ExtraFirst)
1147
            start = Extra;
1148

1149
    for (i=0; i < nChan; i++) {
1150

1151
        cmsUInt32Number index = DoSwap ? (nChan - i - 1) : i;
1152

1153
        if (Planar)
1154
            v = (cmsFloat32Number) ((cmsFloat64Number*) accum)[(i + start) * Stride];
1155
        else
1156
            v = (cmsFloat32Number) ((cmsFloat64Number*) accum)[i + start];
1157

1158
        vi = _cmsQuickSaturateWord(v * maximum);
1159

1160
        if (Reverse)
1161
            vi = REVERSE_FLAVOR_16(vi);
1162

1163
        wIn[index] = vi;
1164
    }
1165

1166

1167
    if (Extra == 0 && SwapFirst) {
1168
        cmsUInt16Number tmp = wIn[0];
1169

1170
        memmove(&wIn[0], &wIn[1], (nChan-1) * sizeof(cmsUInt16Number));
1171
        wIn[nChan-1] = tmp;
1172
    }
1173

1174
    if (T_PLANAR(info -> InputFormat))
1175
        return accum + sizeof(cmsFloat64Number);
1176
    else
1177
        return accum + (nChan + Extra) * sizeof(cmsFloat64Number);
1178
}
1179

1180

1181

1182
static
1183
cmsUInt8Number* UnrollFloatTo16(CMSREGISTER _cmsTRANSFORM* info,
1184
                                CMSREGISTER cmsUInt16Number wIn[],
1185
                                CMSREGISTER cmsUInt8Number* accum,
1186
                                CMSREGISTER cmsUInt32Number Stride)
1187
{
1188

1189
    cmsUInt32Number nChan  = T_CHANNELS(info -> InputFormat);
1190
    cmsUInt32Number DoSwap   = T_DOSWAP(info ->InputFormat);
1191
    cmsUInt32Number Reverse    = T_FLAVOR(info ->InputFormat);
1192
    cmsUInt32Number SwapFirst  = T_SWAPFIRST(info -> InputFormat);
1193
    cmsUInt32Number Extra   = T_EXTRA(info -> InputFormat);
1194
    cmsUInt32Number ExtraFirst = DoSwap ^ SwapFirst;
1195
    cmsUInt32Number Planar     = T_PLANAR(info -> InputFormat);
1196
    cmsFloat32Number v;
1197
    cmsUInt16Number  vi;
1198
    cmsUInt32Number i, start = 0;
1199
    cmsFloat64Number maximum = IsInkSpace(info ->InputFormat) ? 655.35 : 65535.0;
1200

1201
    Stride /= PixelSize(info->InputFormat);
1202

1203
    if (ExtraFirst)
1204
            start = Extra;
1205

1206
    for (i=0; i < nChan; i++) {
1207

1208
        cmsUInt32Number index = DoSwap ? (nChan - i - 1) : i;
1209

1210
        if (Planar)
1211
            v = (cmsFloat32Number) ((cmsFloat32Number*) accum)[(i + start) * Stride];
1212
        else
1213
            v = (cmsFloat32Number) ((cmsFloat32Number*) accum)[i + start];
1214

1215
        vi = _cmsQuickSaturateWord(v * maximum);
1216

1217
        if (Reverse)
1218
            vi = REVERSE_FLAVOR_16(vi);
1219

1220
        wIn[index] = vi;
1221
    }
1222

1223

1224
    if (Extra == 0 && SwapFirst) {
1225
        cmsUInt16Number tmp = wIn[0];
1226

1227
        memmove(&wIn[0], &wIn[1], (nChan-1) * sizeof(cmsUInt16Number));
1228
        wIn[nChan-1] = tmp;
1229
    }
1230

1231
    if (T_PLANAR(info -> InputFormat))
1232
        return accum + sizeof(cmsFloat32Number);
1233
    else
1234
        return accum + (nChan + Extra) * sizeof(cmsFloat32Number);
1235
}
1236

1237

1238

1239

1240
// For 1 channel, we need to duplicate data (it comes in 0..1.0 range)
1241
static
1242
cmsUInt8Number* UnrollDouble1Chan(CMSREGISTER _cmsTRANSFORM* info,
1243
                                  CMSREGISTER cmsUInt16Number wIn[],
1244
                                  CMSREGISTER cmsUInt8Number* accum,
1245
                                  CMSREGISTER cmsUInt32Number Stride)
1246
{
1247
    cmsFloat64Number* Inks = (cmsFloat64Number*) accum;
1248

1249
    wIn[0] = wIn[1] = wIn[2] = _cmsQuickSaturateWord(Inks[0] * 65535.0);
1250

1251
    return accum + sizeof(cmsFloat64Number);
1252

1253
    cmsUNUSED_PARAMETER(info);
1254
    cmsUNUSED_PARAMETER(Stride);
1255
}
1256

1257
//-------------------------------------------------------------------------------------------------------------------
1258

1259
// For anything going from cmsUInt8Number
1260
static
1261
cmsUInt8Number* Unroll8ToFloat(_cmsTRANSFORM* info,
1262
                               cmsFloat32Number wIn[],
1263
                               cmsUInt8Number* accum,
1264
                               cmsUInt32Number Stride)
1265
{
1266

1267
    cmsUInt32Number nChan = T_CHANNELS(info->InputFormat);
1268
    cmsUInt32Number DoSwap = T_DOSWAP(info->InputFormat);
1269
    cmsUInt32Number Reverse = T_FLAVOR(info->InputFormat);
1270
    cmsUInt32Number SwapFirst = T_SWAPFIRST(info->InputFormat);
1271
    cmsUInt32Number Extra = T_EXTRA(info->InputFormat);
1272
    cmsUInt32Number ExtraFirst = DoSwap ^ SwapFirst;
1273
    cmsUInt32Number Planar = T_PLANAR(info->InputFormat);
1274
    cmsFloat32Number v;
1275
    cmsUInt32Number i, start = 0;
1276

1277
    Stride /= PixelSize(info->InputFormat);
1278

1279
    if (ExtraFirst)
1280
        start = Extra;
1281

1282
    for (i = 0; i < nChan; i++) {
1283

1284
        cmsUInt32Number index = DoSwap ? (nChan - i - 1) : i;
1285

1286
        if (Planar)
1287
            v = (cmsFloat32Number) ((cmsUInt8Number *)accum)[(i + start) * Stride];
1288
        else
1289
            v = (cmsFloat32Number) ((cmsUInt8Number *)accum)[i + start];
1290

1291
        v /= 255.0F;
1292

1293
        wIn[index] = Reverse ? 1 - v : v;
1294
    }
1295

1296

1297
    if (Extra == 0 && SwapFirst) {
1298
        cmsFloat32Number tmp = wIn[0];
1299

1300
        memmove(&wIn[0], &wIn[1], (nChan - 1) * sizeof(cmsFloat32Number));
1301
        wIn[nChan - 1] = tmp;
1302
    }
1303

1304
    if (T_PLANAR(info->InputFormat))
1305
        return accum + sizeof(cmsUInt8Number);
1306
    else
1307
        return accum + (nChan + Extra) * sizeof(cmsUInt8Number);
1308
}
1309

1310

1311
// For anything going from cmsUInt16Number
1312
static
1313
cmsUInt8Number* Unroll16ToFloat(_cmsTRANSFORM* info,
1314
                                cmsFloat32Number wIn[],
1315
                                cmsUInt8Number* accum,
1316
                                cmsUInt32Number Stride)
1317
{
1318

1319
    cmsUInt32Number nChan = T_CHANNELS(info->InputFormat);
1320
    cmsUInt32Number DoSwap = T_DOSWAP(info->InputFormat);
1321
    cmsUInt32Number Reverse = T_FLAVOR(info->InputFormat);
1322
    cmsUInt32Number SwapFirst = T_SWAPFIRST(info->InputFormat);
1323
    cmsUInt32Number Extra = T_EXTRA(info->InputFormat);
1324
    cmsUInt32Number ExtraFirst = DoSwap ^ SwapFirst;
1325
    cmsUInt32Number Planar = T_PLANAR(info->InputFormat);
1326
    cmsFloat32Number v;
1327
    cmsUInt32Number i, start = 0;
1328

1329
    Stride /= PixelSize(info->InputFormat);
1330

1331
    if (ExtraFirst)
1332
        start = Extra;
1333

1334
    for (i = 0; i < nChan; i++) {
1335

1336
        cmsUInt32Number index = DoSwap ? (nChan - i - 1) : i;
1337

1338
        if (Planar)
1339
            v = (cmsFloat32Number)((cmsUInt16Number*)accum)[(i + start) * Stride];
1340
        else
1341
            v = (cmsFloat32Number)((cmsUInt16Number*)accum)[i + start];
1342

1343
        v /= 65535.0F;
1344

1345
        wIn[index] = Reverse ? 1 - v : v;
1346
    }
1347

1348

1349
    if (Extra == 0 && SwapFirst) {
1350
        cmsFloat32Number tmp = wIn[0];
1351

1352
        memmove(&wIn[0], &wIn[1], (nChan - 1) * sizeof(cmsFloat32Number));
1353
        wIn[nChan - 1] = tmp;
1354
    }
1355

1356
    if (T_PLANAR(info->InputFormat))
1357
        return accum + sizeof(cmsUInt16Number);
1358
    else
1359
        return accum + (nChan + Extra) * sizeof(cmsUInt16Number);
1360
}
1361

1362

1363
// For anything going from cmsFloat32Number
1364
static
1365
cmsUInt8Number* UnrollFloatsToFloat(_cmsTRANSFORM* info,
1366
                                    cmsFloat32Number wIn[],
1367
                                    cmsUInt8Number* accum,
1368
                                    cmsUInt32Number Stride)
1369
{
1370

1371
    cmsUInt32Number nChan = T_CHANNELS(info->InputFormat);
1372
    cmsUInt32Number DoSwap = T_DOSWAP(info->InputFormat);
1373
    cmsUInt32Number Reverse = T_FLAVOR(info->InputFormat);
1374
    cmsUInt32Number SwapFirst = T_SWAPFIRST(info->InputFormat);
1375
    cmsUInt32Number Extra = T_EXTRA(info->InputFormat);
1376
    cmsUInt32Number ExtraFirst = DoSwap ^ SwapFirst;
1377
    cmsUInt32Number Planar = T_PLANAR(info->InputFormat);
1378
    cmsUInt32Number Premul = T_PREMUL(info->InputFormat);
1379
    cmsFloat32Number v;
1380
    cmsUInt32Number i, start = 0;
1381
    cmsFloat32Number maximum = IsInkSpace(info->InputFormat) ? 100.0F : 1.0F;
1382
    cmsFloat32Number alpha_factor = 1.0f;
1383
    cmsFloat32Number* ptr = (cmsFloat32Number*)accum;
1384

1385
    Stride /= PixelSize(info->InputFormat);
1386

1387
    if (Premul && Extra)
1388
    {
1389
        if (Planar)
1390
            alpha_factor = (ExtraFirst ? ptr[0] : ptr[nChan * Stride]) / maximum;
1391
        else
1392
            alpha_factor = (ExtraFirst ? ptr[0] : ptr[nChan]) / maximum;
1393
    }
1394

1395
    if (ExtraFirst)
1396
            start = Extra;
1397

1398
    for (i=0; i < nChan; i++) {
1399

1400
        cmsUInt32Number index = DoSwap ? (nChan - i - 1) : i;
1401

1402
        if (Planar)
1403
            v = ptr[(i + start) * Stride];
1404
        else
1405
            v = ptr[i + start];
1406

1407
        if (Premul && alpha_factor > 0)
1408
            v /= alpha_factor;
1409

1410
        v /= maximum;
1411

1412
        wIn[index] = Reverse ? 1 - v : v;
1413
    }
1414

1415

1416
    if (Extra == 0 && SwapFirst) {
1417
        cmsFloat32Number tmp = wIn[0];
1418

1419
        memmove(&wIn[0], &wIn[1], (nChan-1) * sizeof(cmsFloat32Number));
1420
        wIn[nChan-1] = tmp;
1421
    }
1422

1423
    if (T_PLANAR(info -> InputFormat))
1424
        return accum + sizeof(cmsFloat32Number);
1425
    else
1426
        return accum + (nChan + Extra) * sizeof(cmsFloat32Number);
1427
}
1428

1429
// For anything going from double
1430

1431
static
1432
cmsUInt8Number* UnrollDoublesToFloat(_cmsTRANSFORM* info,
1433
                                    cmsFloat32Number wIn[],
1434
                                    cmsUInt8Number* accum,
1435
                                    cmsUInt32Number Stride)
1436
{
1437

1438
    cmsUInt32Number nChan = T_CHANNELS(info->InputFormat);
1439
    cmsUInt32Number DoSwap = T_DOSWAP(info->InputFormat);
1440
    cmsUInt32Number Reverse = T_FLAVOR(info->InputFormat);
1441
    cmsUInt32Number SwapFirst = T_SWAPFIRST(info->InputFormat);
1442
    cmsUInt32Number Extra = T_EXTRA(info->InputFormat);
1443
    cmsUInt32Number ExtraFirst = DoSwap ^ SwapFirst;
1444
    cmsUInt32Number Planar = T_PLANAR(info->InputFormat);
1445
    cmsUInt32Number Premul = T_PREMUL(info->InputFormat);
1446
    cmsFloat64Number v;
1447
    cmsUInt32Number i, start = 0;
1448
    cmsFloat64Number maximum = IsInkSpace(info ->InputFormat) ? 100.0 : 1.0;
1449
    cmsFloat64Number alpha_factor = 1.0;
1450
    cmsFloat64Number* ptr = (cmsFloat64Number*)accum;
1451

1452
    Stride /= PixelSize(info->InputFormat);
1453

1454
    if (Premul && Extra)
1455
    {
1456
        if (Planar)
1457
            alpha_factor = (ExtraFirst ? ptr[0] : ptr[(nChan) * Stride]) / maximum;
1458
        else
1459
            alpha_factor = (ExtraFirst ? ptr[0] : ptr[nChan]) / maximum;
1460
    }
1461

1462
    if (ExtraFirst)
1463
            start = Extra;
1464

1465
    for (i=0; i < nChan; i++) {
1466

1467
        cmsUInt32Number index = DoSwap ? (nChan - i - 1) : i;
1468

1469
        if (Planar)
1470
            v = (cmsFloat64Number) ((cmsFloat64Number*) accum)[(i + start)  * Stride];
1471
        else
1472
            v = (cmsFloat64Number) ((cmsFloat64Number*) accum)[i + start];
1473

1474

1475
        if (Premul && alpha_factor > 0)
1476
            v /= alpha_factor;
1477

1478
        v /= maximum;
1479

1480
        wIn[index] = (cmsFloat32Number) (Reverse ? 1.0 - v : v);
1481
    }
1482

1483

1484
    if (Extra == 0 && SwapFirst) {
1485
        cmsFloat32Number tmp = wIn[0];
1486

1487
        memmove(&wIn[0], &wIn[1], (nChan-1) * sizeof(cmsFloat32Number));
1488
        wIn[nChan-1] = tmp;
1489
    }
1490

1491
    if (T_PLANAR(info -> InputFormat))
1492
        return accum + sizeof(cmsFloat64Number);
1493
    else
1494
        return accum + (nChan + Extra) * sizeof(cmsFloat64Number);
1495
}
1496

1497

1498

1499
// From Lab double to cmsFloat32Number
1500
static
1501
cmsUInt8Number* UnrollLabDoubleToFloat(_cmsTRANSFORM* info,
1502
                                       cmsFloat32Number wIn[],
1503
                                       cmsUInt8Number* accum,
1504
                                       cmsUInt32Number Stride)
1505
{
1506
    cmsFloat64Number* Pt = (cmsFloat64Number*) accum;
1507

1508
    if (T_PLANAR(info -> InputFormat)) {
1509

1510
        Stride /= PixelSize(info->InputFormat);
1511

1512
        wIn[0] = (cmsFloat32Number) (Pt[0] / 100.0);                 // from 0..100 to 0..1
1513
        wIn[1] = (cmsFloat32Number) ((Pt[Stride] + 128) / 255.0);    // form -128..+127 to 0..1
1514
        wIn[2] = (cmsFloat32Number) ((Pt[Stride*2] + 128) / 255.0);
1515

1516
        return accum + sizeof(cmsFloat64Number);
1517
    }
1518
    else {
1519

1520
        wIn[0] = (cmsFloat32Number) (Pt[0] / 100.0);            // from 0..100 to 0..1
1521
        wIn[1] = (cmsFloat32Number) ((Pt[1] + 128) / 255.0);    // form -128..+127 to 0..1
1522
        wIn[2] = (cmsFloat32Number) ((Pt[2] + 128) / 255.0);
1523

1524
        accum += sizeof(cmsFloat64Number)*(3 + T_EXTRA(info ->InputFormat));
1525
        return accum;
1526
    }
1527
}
1528

1529
// From Lab double to cmsFloat32Number
1530
static
1531
cmsUInt8Number* UnrollLabFloatToFloat(_cmsTRANSFORM* info,
1532
                                      cmsFloat32Number wIn[],
1533
                                      cmsUInt8Number* accum,
1534
                                      cmsUInt32Number Stride)
1535
{
1536
    cmsFloat32Number* Pt = (cmsFloat32Number*) accum;
1537

1538
    if (T_PLANAR(info -> InputFormat)) {
1539

1540
        Stride /= PixelSize(info->InputFormat);
1541

1542
        wIn[0] = (cmsFloat32Number) (Pt[0] / 100.0);                 // from 0..100 to 0..1
1543
        wIn[1] = (cmsFloat32Number) ((Pt[Stride] + 128) / 255.0);    // form -128..+127 to 0..1
1544
        wIn[2] = (cmsFloat32Number) ((Pt[Stride*2] + 128) / 255.0);
1545

1546
        return accum + sizeof(cmsFloat32Number);
1547
    }
1548
    else {
1549

1550
        wIn[0] = (cmsFloat32Number) (Pt[0] / 100.0);            // from 0..100 to 0..1
1551
        wIn[1] = (cmsFloat32Number) ((Pt[1] + 128) / 255.0);    // form -128..+127 to 0..1
1552
        wIn[2] = (cmsFloat32Number) ((Pt[2] + 128) / 255.0);
1553

1554
        accum += sizeof(cmsFloat32Number)*(3 + T_EXTRA(info ->InputFormat));
1555
        return accum;
1556
    }
1557
}
1558

1559
// 1.15 fixed point, that means maximum value is MAX_ENCODEABLE_XYZ (0xFFFF)
1560
static
1561
cmsUInt8Number* UnrollXYZDoubleToFloat(_cmsTRANSFORM* info,
1562
                                       cmsFloat32Number wIn[],
1563
                                       cmsUInt8Number* accum,
1564
                                       cmsUInt32Number Stride)
1565
{
1566
    cmsFloat64Number* Pt = (cmsFloat64Number*) accum;
1567

1568
    if (T_PLANAR(info -> InputFormat)) {
1569

1570
        Stride /= PixelSize(info->InputFormat);
1571

1572
        wIn[0] = (cmsFloat32Number) (Pt[0] / MAX_ENCODEABLE_XYZ);
1573
        wIn[1] = (cmsFloat32Number) (Pt[Stride] / MAX_ENCODEABLE_XYZ);
1574
        wIn[2] = (cmsFloat32Number) (Pt[Stride*2] / MAX_ENCODEABLE_XYZ);
1575

1576
        return accum + sizeof(cmsFloat64Number);
1577
    }
1578
    else {
1579

1580
        wIn[0] = (cmsFloat32Number) (Pt[0] / MAX_ENCODEABLE_XYZ);
1581
        wIn[1] = (cmsFloat32Number) (Pt[1] / MAX_ENCODEABLE_XYZ);
1582
        wIn[2] = (cmsFloat32Number) (Pt[2] / MAX_ENCODEABLE_XYZ);
1583

1584
        accum += sizeof(cmsFloat64Number)*(3 + T_EXTRA(info ->InputFormat));
1585
        return accum;
1586
    }
1587
}
1588

1589
static
1590
cmsUInt8Number* UnrollXYZFloatToFloat(_cmsTRANSFORM* info,
1591
                                      cmsFloat32Number wIn[],
1592
                                      cmsUInt8Number* accum,
1593
                                      cmsUInt32Number Stride)
1594
{
1595
    cmsFloat32Number* Pt = (cmsFloat32Number*) accum;
1596

1597
    if (T_PLANAR(info -> InputFormat)) {
1598

1599
        Stride /= PixelSize(info->InputFormat);
1600

1601
        wIn[0] = (cmsFloat32Number) (Pt[0] / MAX_ENCODEABLE_XYZ);
1602
        wIn[1] = (cmsFloat32Number) (Pt[Stride] / MAX_ENCODEABLE_XYZ);
1603
        wIn[2] = (cmsFloat32Number) (Pt[Stride*2] / MAX_ENCODEABLE_XYZ);
1604

1605
        return accum + sizeof(cmsFloat32Number);
1606
    }
1607
    else {
1608

1609
        wIn[0] = (cmsFloat32Number) (Pt[0] / MAX_ENCODEABLE_XYZ);
1610
        wIn[1] = (cmsFloat32Number) (Pt[1] / MAX_ENCODEABLE_XYZ);
1611
        wIn[2] = (cmsFloat32Number) (Pt[2] / MAX_ENCODEABLE_XYZ);
1612

1613
        accum += sizeof(cmsFloat32Number)*(3 + T_EXTRA(info ->InputFormat));
1614
        return accum;
1615
    }
1616
}
1617

1618

1619
cmsINLINE void lab4toFloat(cmsFloat32Number wIn[], cmsUInt16Number lab4[3])
1620
{
1621
    cmsFloat32Number L = (cmsFloat32Number) lab4[0] / 655.35F;
1622
    cmsFloat32Number a = ((cmsFloat32Number) lab4[1] / 257.0F) - 128.0F;
1623
    cmsFloat32Number b = ((cmsFloat32Number) lab4[2] / 257.0F) - 128.0F;
1624

1625
    wIn[0] = (L / 100.0F);                    // from 0..100 to 0..1
1626
    wIn[1] = ((a + 128.0F) / 255.0F);         // form -128..+127 to 0..1
1627
    wIn[2] = ((b + 128.0F) / 255.0F);
1628

1629
}
1630

1631
static
1632
cmsUInt8Number* UnrollLabV2_8ToFloat(_cmsTRANSFORM* info,
1633
                                      cmsFloat32Number wIn[],
1634
                                      cmsUInt8Number* accum,
1635
                                      cmsUInt32Number Stride)
1636
{
1637
    cmsUInt16Number lab4[3];
1638

1639
    lab4[0] = FomLabV2ToLabV4(FROM_8_TO_16(*accum)); accum++;     // L
1640
    lab4[1] = FomLabV2ToLabV4(FROM_8_TO_16(*accum)); accum++;     // a
1641
    lab4[2] = FomLabV2ToLabV4(FROM_8_TO_16(*accum)); accum++;     // b
1642

1643
    lab4toFloat(wIn, lab4);
1644

1645
    return accum;
1646

1647
    cmsUNUSED_PARAMETER(info);
1648
    cmsUNUSED_PARAMETER(Stride);
1649
}
1650

1651
static
1652
cmsUInt8Number* UnrollALabV2_8ToFloat(_cmsTRANSFORM* info,
1653
                                      cmsFloat32Number wIn[],
1654
                                      cmsUInt8Number* accum,
1655
                                      cmsUInt32Number Stride)
1656
{
1657
    cmsUInt16Number lab4[3];
1658

1659
    accum++;  // A
1660
    lab4[0] = FomLabV2ToLabV4(FROM_8_TO_16(*accum)); accum++;     // L
1661
    lab4[1] = FomLabV2ToLabV4(FROM_8_TO_16(*accum)); accum++;     // a
1662
    lab4[2] = FomLabV2ToLabV4(FROM_8_TO_16(*accum)); accum++;     // b
1663

1664
    lab4toFloat(wIn, lab4);
1665

1666
    return accum;
1667

1668
    cmsUNUSED_PARAMETER(info);
1669
    cmsUNUSED_PARAMETER(Stride);
1670
}
1671

1672
static
1673
cmsUInt8Number* UnrollLabV2_16ToFloat(_cmsTRANSFORM* info,
1674
                                      cmsFloat32Number wIn[],
1675
                                      cmsUInt8Number* accum,
1676
                                      cmsUInt32Number Stride)
1677
{
1678
    cmsUInt16Number lab4[3];
1679

1680
    lab4[0] = FomLabV2ToLabV4(*(cmsUInt16Number*) accum); accum += 2;     // L
1681
    lab4[1] = FomLabV2ToLabV4(*(cmsUInt16Number*) accum); accum += 2;     // a
1682
    lab4[2] = FomLabV2ToLabV4(*(cmsUInt16Number*) accum); accum += 2;     // b
1683

1684
    lab4toFloat(wIn, lab4);
1685

1686
    return accum;
1687

1688
    cmsUNUSED_PARAMETER(info);
1689
    cmsUNUSED_PARAMETER(Stride);
1690
}
1691

1692

1693
// Packing routines -----------------------------------------------------------------------------------------------------------
1694

1695

1696
// Generic chunky for byte
1697
static
1698
cmsUInt8Number* PackChunkyBytes(CMSREGISTER _cmsTRANSFORM* info,
1699
                                CMSREGISTER cmsUInt16Number wOut[],
1700
                                CMSREGISTER cmsUInt8Number* output,
1701
                                CMSREGISTER cmsUInt32Number Stride)
1702
{
1703
    cmsUInt32Number nChan = T_CHANNELS(info->OutputFormat);
1704
    cmsUInt32Number DoSwap = T_DOSWAP(info->OutputFormat);
1705
    cmsUInt32Number Reverse = T_FLAVOR(info->OutputFormat);
1706
    cmsUInt32Number Extra = T_EXTRA(info->OutputFormat);
1707
    cmsUInt32Number SwapFirst = T_SWAPFIRST(info->OutputFormat);
1708
    cmsUInt32Number Premul = T_PREMUL(info->OutputFormat);
1709
    cmsUInt32Number ExtraFirst = DoSwap ^ SwapFirst;
1710
    cmsUInt8Number* swap1;
1711
    cmsUInt16Number v = 0;
1712
    cmsUInt32Number i;
1713
    cmsUInt32Number alpha_factor = 0;
1714

1715
    swap1 = output;
1716

1717
    if (ExtraFirst) {
1718

1719
        if (Premul && Extra)
1720
            alpha_factor = _cmsToFixedDomain(FROM_8_TO_16(output[0]));
1721

1722
        output += Extra;
1723
    }
1724
    else
1725
    {
1726
        if (Premul && Extra)
1727
            alpha_factor = _cmsToFixedDomain(FROM_8_TO_16(output[nChan]));
1728
    }
1729

1730
    for (i=0; i < nChan; i++) {
1731

1732
        cmsUInt32Number index = DoSwap ? (nChan - i - 1) : i;
1733

1734
        v = wOut[index];
1735

1736
        if (Reverse)
1737
            v = REVERSE_FLAVOR_16(v);
1738

1739
        if (Premul)
1740
        {
1741
            v = (cmsUInt16Number)((cmsUInt32Number)((cmsUInt32Number)v * alpha_factor + 0x8000) >> 16);
1742
        }
1743

1744
        *output++ = FROM_16_TO_8(v);
1745
    }
1746

1747
    if (!ExtraFirst) {
1748
        output += Extra;
1749
    }
1750

1751
    if (Extra == 0 && SwapFirst) {
1752

1753
        memmove(swap1 + 1, swap1, nChan-1);
1754
        *swap1 = FROM_16_TO_8(v);
1755
    }
1756

1757
    return output;
1758

1759
    cmsUNUSED_PARAMETER(Stride);
1760
}
1761

1762
static
1763
cmsUInt8Number* PackChunkyWords(CMSREGISTER _cmsTRANSFORM* info,
1764
                                CMSREGISTER cmsUInt16Number wOut[],
1765
                                CMSREGISTER cmsUInt8Number* output,
1766
                                CMSREGISTER cmsUInt32Number Stride)
1767
{
1768
    cmsUInt32Number nChan = T_CHANNELS(info->OutputFormat);
1769
    cmsUInt32Number SwapEndian = T_ENDIAN16(info->OutputFormat);
1770
    cmsUInt32Number DoSwap = T_DOSWAP(info->OutputFormat);
1771
    cmsUInt32Number Reverse = T_FLAVOR(info->OutputFormat);
1772
    cmsUInt32Number Extra = T_EXTRA(info->OutputFormat);
1773
    cmsUInt32Number SwapFirst = T_SWAPFIRST(info->OutputFormat);
1774
    cmsUInt32Number Premul = T_PREMUL(info->OutputFormat);
1775
    cmsUInt32Number ExtraFirst = DoSwap ^ SwapFirst;
1776
    cmsUInt16Number* swap1;
1777
    cmsUInt16Number v = 0;
1778
    cmsUInt32Number i;
1779
    cmsUInt32Number alpha_factor = 0;
1780

1781
    swap1 = (cmsUInt16Number*) output;
1782

1783
    if (ExtraFirst) {
1784

1785
        if (Premul && Extra)
1786
            alpha_factor = _cmsToFixedDomain(*(cmsUInt16Number*) output);
1787

1788
        output += Extra * sizeof(cmsUInt16Number);
1789
    }
1790
    else
1791
    {
1792
        if (Premul && Extra)
1793
            alpha_factor = _cmsToFixedDomain(((cmsUInt16Number*) output)[nChan]);
1794
    }
1795

1796
    for (i=0; i < nChan; i++) {
1797

1798
        cmsUInt32Number index = DoSwap ? (nChan - i - 1) : i;
1799

1800
        v = wOut[index];
1801

1802
        if (SwapEndian)
1803
            v = CHANGE_ENDIAN(v);
1804

1805
        if (Reverse)
1806
            v = REVERSE_FLAVOR_16(v);
1807

1808
        if (Premul)
1809
        {
1810
            v = (cmsUInt16Number)((cmsUInt32Number)((cmsUInt32Number)v * alpha_factor + 0x8000) >> 16);
1811
        }
1812

1813
        *(cmsUInt16Number*) output = v;
1814

1815
        output += sizeof(cmsUInt16Number);
1816
    }
1817

1818
    if (!ExtraFirst) {
1819
        output += Extra * sizeof(cmsUInt16Number);
1820
    }
1821

1822
    if (Extra == 0 && SwapFirst) {
1823

1824
        memmove(swap1 + 1, swap1, (nChan-1)* sizeof(cmsUInt16Number));
1825
        *swap1 = v;
1826
    }
1827

1828
    return output;
1829

1830
    cmsUNUSED_PARAMETER(Stride);
1831
}
1832

1833

1834

1835
static
1836
cmsUInt8Number* PackPlanarBytes(CMSREGISTER _cmsTRANSFORM* info,
1837
                                CMSREGISTER cmsUInt16Number wOut[],
1838
                                CMSREGISTER cmsUInt8Number* output,
1839
                                CMSREGISTER cmsUInt32Number Stride)
1840
{
1841
    cmsUInt32Number nChan = T_CHANNELS(info->OutputFormat);
1842
    cmsUInt32Number DoSwap = T_DOSWAP(info->OutputFormat);
1843
    cmsUInt32Number SwapFirst = T_SWAPFIRST(info->OutputFormat);
1844
    cmsUInt32Number Reverse = T_FLAVOR(info->OutputFormat);
1845
    cmsUInt32Number Extra = T_EXTRA(info->OutputFormat);
1846
    cmsUInt32Number ExtraFirst = DoSwap ^ SwapFirst;
1847
    cmsUInt32Number Premul = T_PREMUL(info->OutputFormat);
1848
    cmsUInt32Number i;
1849
    cmsUInt8Number* Init = output;
1850
    cmsUInt32Number alpha_factor = 0;
1851

1852

1853
    if (ExtraFirst) {
1854

1855
        if (Premul && Extra)
1856
            alpha_factor = _cmsToFixedDomain(FROM_8_TO_16(output[0]));
1857

1858
        output += Extra * Stride;
1859
    }
1860
    else
1861
    {
1862
        if (Premul && Extra)
1863
            alpha_factor = _cmsToFixedDomain(FROM_8_TO_16(output[nChan * Stride]));
1864
    }
1865

1866

1867
    for (i=0; i < nChan; i++) {
1868

1869
        cmsUInt32Number index = DoSwap ? (nChan - i - 1) : i;
1870
        cmsUInt16Number v = wOut[index];
1871

1872
        if (Reverse)
1873
            v = REVERSE_FLAVOR_16(v);
1874

1875
        if (Premul)
1876
        {
1877
            v = (cmsUInt16Number)((cmsUInt32Number)((cmsUInt32Number)v * alpha_factor + 0x8000) >> 16);
1878
        }
1879

1880
        *(cmsUInt8Number*)output = FROM_16_TO_8(v);
1881

1882
        output += Stride;
1883
    }
1884

1885
    return (Init + 1);
1886

1887
    cmsUNUSED_PARAMETER(Stride);
1888
}
1889

1890

1891
static
1892
cmsUInt8Number* PackPlanarWords(CMSREGISTER _cmsTRANSFORM* info,
1893
                                CMSREGISTER cmsUInt16Number wOut[],
1894
                                CMSREGISTER cmsUInt8Number* output,
1895
                                CMSREGISTER cmsUInt32Number Stride)
1896
{
1897
    cmsUInt32Number nChan = T_CHANNELS(info->OutputFormat);
1898
    cmsUInt32Number DoSwap = T_DOSWAP(info->OutputFormat);
1899
    cmsUInt32Number SwapFirst = T_SWAPFIRST(info->OutputFormat);
1900
    cmsUInt32Number Reverse = T_FLAVOR(info->OutputFormat);
1901
    cmsUInt32Number Extra = T_EXTRA(info->OutputFormat);
1902
    cmsUInt32Number ExtraFirst = DoSwap ^ SwapFirst;
1903
    cmsUInt32Number Premul = T_PREMUL(info->OutputFormat);
1904
    cmsUInt32Number SwapEndian = T_ENDIAN16(info->OutputFormat);
1905
    cmsUInt32Number i;
1906
    cmsUInt8Number* Init = output;
1907
    cmsUInt16Number v;
1908
    cmsUInt32Number alpha_factor = 0;
1909

1910
    if (ExtraFirst) {
1911

1912
        if (Premul && Extra)
1913
            alpha_factor = _cmsToFixedDomain(((cmsUInt16Number*) output)[0]);
1914

1915
        output += Extra * Stride;
1916
    }
1917
    else
1918
    {
1919
        if (Premul && Extra)
1920
            alpha_factor = _cmsToFixedDomain(((cmsUInt16Number*)output)[nChan * Stride]);
1921
    }
1922

1923
    for (i=0; i < nChan; i++) {
1924

1925
        cmsUInt32Number index = DoSwap ? (nChan - i - 1) : i;
1926

1927
        v = wOut[index];
1928

1929
        if (SwapEndian)
1930
            v = CHANGE_ENDIAN(v);
1931

1932
        if (Reverse)
1933
            v =  REVERSE_FLAVOR_16(v);
1934

1935
        if (Premul)
1936
        {
1937
            v = (cmsUInt16Number)((cmsUInt32Number)((cmsUInt32Number)v * alpha_factor + 0x8000) >> 16);
1938
        }
1939

1940
        *(cmsUInt16Number*) output = v;
1941
        output += Stride;
1942
    }
1943

1944
    return (Init + sizeof(cmsUInt16Number));
1945
}
1946

1947
// CMYKcm (unrolled for speed)
1948

1949
static
1950
cmsUInt8Number* Pack6Bytes(CMSREGISTER _cmsTRANSFORM* info,
1951
                           CMSREGISTER cmsUInt16Number wOut[],
1952
                           CMSREGISTER cmsUInt8Number* output,
1953
                           CMSREGISTER cmsUInt32Number Stride)
1954
{
1955
    *output++ = FROM_16_TO_8(wOut[0]);
1956
    *output++ = FROM_16_TO_8(wOut[1]);
1957
    *output++ = FROM_16_TO_8(wOut[2]);
1958
    *output++ = FROM_16_TO_8(wOut[3]);
1959
    *output++ = FROM_16_TO_8(wOut[4]);
1960
    *output++ = FROM_16_TO_8(wOut[5]);
1961

1962
    return output;
1963

1964
    cmsUNUSED_PARAMETER(info);
1965
    cmsUNUSED_PARAMETER(Stride);
1966
}
1967

1968
// KCMYcm
1969

1970
static
1971
cmsUInt8Number* Pack6BytesSwap(CMSREGISTER _cmsTRANSFORM* info,
1972
                               CMSREGISTER cmsUInt16Number wOut[],
1973
                               CMSREGISTER cmsUInt8Number* output,
1974
                               CMSREGISTER cmsUInt32Number Stride)
1975
{
1976
    *output++ = FROM_16_TO_8(wOut[5]);
1977
    *output++ = FROM_16_TO_8(wOut[4]);
1978
    *output++ = FROM_16_TO_8(wOut[3]);
1979
    *output++ = FROM_16_TO_8(wOut[2]);
1980
    *output++ = FROM_16_TO_8(wOut[1]);
1981
    *output++ = FROM_16_TO_8(wOut[0]);
1982

1983
    return output;
1984

1985
    cmsUNUSED_PARAMETER(info);
1986
    cmsUNUSED_PARAMETER(Stride);
1987
}
1988

1989
// CMYKcm
1990
static
1991
cmsUInt8Number* Pack6Words(CMSREGISTER _cmsTRANSFORM* info,
1992
                           CMSREGISTER cmsUInt16Number wOut[],
1993
                           CMSREGISTER cmsUInt8Number* output,
1994
                           CMSREGISTER cmsUInt32Number Stride)
1995
{
1996
    *(cmsUInt16Number*) output = wOut[0];
1997
    output+= 2;
1998
    *(cmsUInt16Number*) output = wOut[1];
1999
    output+= 2;
2000
    *(cmsUInt16Number*) output = wOut[2];
2001
    output+= 2;
2002
    *(cmsUInt16Number*) output = wOut[3];
2003
    output+= 2;
2004
    *(cmsUInt16Number*) output = wOut[4];
2005
    output+= 2;
2006
    *(cmsUInt16Number*) output = wOut[5];
2007
    output+= 2;
2008

2009
    return output;
2010

2011
    cmsUNUSED_PARAMETER(info);
2012
    cmsUNUSED_PARAMETER(Stride);
2013
}
2014

2015
// KCMYcm
2016
static
2017
cmsUInt8Number* Pack6WordsSwap(CMSREGISTER _cmsTRANSFORM* info,
2018
                               CMSREGISTER cmsUInt16Number wOut[],
2019
                               CMSREGISTER cmsUInt8Number* output,
2020
                               CMSREGISTER cmsUInt32Number Stride)
2021
{
2022
    *(cmsUInt16Number*) output = wOut[5];
2023
    output+= 2;
2024
    *(cmsUInt16Number*) output = wOut[4];
2025
    output+= 2;
2026
    *(cmsUInt16Number*) output = wOut[3];
2027
    output+= 2;
2028
    *(cmsUInt16Number*) output = wOut[2];
2029
    output+= 2;
2030
    *(cmsUInt16Number*) output = wOut[1];
2031
    output+= 2;
2032
    *(cmsUInt16Number*) output = wOut[0];
2033
    output+= 2;
2034

2035
    return output;
2036

2037
    cmsUNUSED_PARAMETER(info);
2038
    cmsUNUSED_PARAMETER(Stride);
2039
}
2040

2041

2042
static
2043
cmsUInt8Number* Pack4Bytes(CMSREGISTER _cmsTRANSFORM* info,
2044
                           CMSREGISTER cmsUInt16Number wOut[],
2045
                           CMSREGISTER cmsUInt8Number* output,
2046
                           CMSREGISTER cmsUInt32Number Stride)
2047
{
2048
    *output++ = FROM_16_TO_8(wOut[0]);
2049
    *output++ = FROM_16_TO_8(wOut[1]);
2050
    *output++ = FROM_16_TO_8(wOut[2]);
2051
    *output++ = FROM_16_TO_8(wOut[3]);
2052

2053
    return output;
2054

2055
    cmsUNUSED_PARAMETER(info);
2056
    cmsUNUSED_PARAMETER(Stride);
2057
}
2058

2059
static
2060
cmsUInt8Number* Pack4BytesReverse(CMSREGISTER _cmsTRANSFORM* info,
2061
                                  CMSREGISTER cmsUInt16Number wOut[],
2062
                                  CMSREGISTER cmsUInt8Number* output,
2063
                                  CMSREGISTER cmsUInt32Number Stride)
2064
{
2065
    *output++ = REVERSE_FLAVOR_8(FROM_16_TO_8(wOut[0]));
2066
    *output++ = REVERSE_FLAVOR_8(FROM_16_TO_8(wOut[1]));
2067
    *output++ = REVERSE_FLAVOR_8(FROM_16_TO_8(wOut[2]));
2068
    *output++ = REVERSE_FLAVOR_8(FROM_16_TO_8(wOut[3]));
2069

2070
    return output;
2071

2072
    cmsUNUSED_PARAMETER(info);
2073
    cmsUNUSED_PARAMETER(Stride);
2074
}
2075

2076

2077
static
2078
cmsUInt8Number* Pack4BytesSwapFirst(CMSREGISTER _cmsTRANSFORM* info,
2079
                                    CMSREGISTER cmsUInt16Number wOut[],
2080
                                    CMSREGISTER cmsUInt8Number* output,
2081
                                    CMSREGISTER cmsUInt32Number Stride)
2082
{
2083
    *output++ = FROM_16_TO_8(wOut[3]);
2084
    *output++ = FROM_16_TO_8(wOut[0]);
2085
    *output++ = FROM_16_TO_8(wOut[1]);
2086
    *output++ = FROM_16_TO_8(wOut[2]);
2087

2088
    return output;
2089

2090
    cmsUNUSED_PARAMETER(info);
2091
    cmsUNUSED_PARAMETER(Stride);
2092
}
2093

2094
// ABGR
2095
static
2096
cmsUInt8Number* Pack4BytesSwap(CMSREGISTER _cmsTRANSFORM* info,
2097
                               CMSREGISTER cmsUInt16Number wOut[],
2098
                               CMSREGISTER cmsUInt8Number* output,
2099
                               CMSREGISTER cmsUInt32Number Stride)
2100
{
2101
    *output++ = FROM_16_TO_8(wOut[3]);
2102
    *output++ = FROM_16_TO_8(wOut[2]);
2103
    *output++ = FROM_16_TO_8(wOut[1]);
2104
    *output++ = FROM_16_TO_8(wOut[0]);
2105

2106
    return output;
2107

2108
    cmsUNUSED_PARAMETER(info);
2109
    cmsUNUSED_PARAMETER(Stride);
2110
}
2111

2112
static
2113
cmsUInt8Number* Pack4BytesSwapSwapFirst(CMSREGISTER _cmsTRANSFORM* info,
2114
                                        CMSREGISTER cmsUInt16Number wOut[],
2115
                                        CMSREGISTER cmsUInt8Number* output,
2116
                                        CMSREGISTER cmsUInt32Number Stride)
2117
{
2118
    *output++ = FROM_16_TO_8(wOut[2]);
2119
    *output++ = FROM_16_TO_8(wOut[1]);
2120
    *output++ = FROM_16_TO_8(wOut[0]);
2121
    *output++ = FROM_16_TO_8(wOut[3]);
2122

2123
    return output;
2124

2125
    cmsUNUSED_PARAMETER(info);
2126
    cmsUNUSED_PARAMETER(Stride);
2127
}
2128

2129
static
2130
cmsUInt8Number* Pack4Words(CMSREGISTER _cmsTRANSFORM* info,
2131
                           CMSREGISTER cmsUInt16Number wOut[],
2132
                           CMSREGISTER cmsUInt8Number* output,
2133
                           CMSREGISTER cmsUInt32Number Stride)
2134
{
2135
    *(cmsUInt16Number*) output = wOut[0];
2136
    output+= 2;
2137
    *(cmsUInt16Number*) output = wOut[1];
2138
    output+= 2;
2139
    *(cmsUInt16Number*) output = wOut[2];
2140
    output+= 2;
2141
    *(cmsUInt16Number*) output = wOut[3];
2142
    output+= 2;
2143

2144
    return output;
2145

2146
    cmsUNUSED_PARAMETER(info);
2147
    cmsUNUSED_PARAMETER(Stride);
2148
}
2149

2150
static
2151
cmsUInt8Number* Pack4WordsReverse(CMSREGISTER _cmsTRANSFORM* info,
2152
                                  CMSREGISTER cmsUInt16Number wOut[],
2153
                                  CMSREGISTER cmsUInt8Number* output,
2154
                                  CMSREGISTER cmsUInt32Number Stride)
2155
{
2156
    *(cmsUInt16Number*) output = REVERSE_FLAVOR_16(wOut[0]);
2157
    output+= 2;
2158
    *(cmsUInt16Number*) output = REVERSE_FLAVOR_16(wOut[1]);
2159
    output+= 2;
2160
    *(cmsUInt16Number*) output = REVERSE_FLAVOR_16(wOut[2]);
2161
    output+= 2;
2162
    *(cmsUInt16Number*) output = REVERSE_FLAVOR_16(wOut[3]);
2163
    output+= 2;
2164

2165
    return output;
2166

2167
    cmsUNUSED_PARAMETER(info);
2168
    cmsUNUSED_PARAMETER(Stride);
2169
}
2170

2171
// ABGR
2172
static
2173
cmsUInt8Number* Pack4WordsSwap(CMSREGISTER _cmsTRANSFORM* info,
2174
                               CMSREGISTER cmsUInt16Number wOut[],
2175
                               CMSREGISTER cmsUInt8Number* output,
2176
                               CMSREGISTER cmsUInt32Number Stride)
2177
{
2178
    *(cmsUInt16Number*) output = wOut[3];
2179
    output+= 2;
2180
    *(cmsUInt16Number*) output = wOut[2];
2181
    output+= 2;
2182
    *(cmsUInt16Number*) output = wOut[1];
2183
    output+= 2;
2184
    *(cmsUInt16Number*) output = wOut[0];
2185
    output+= 2;
2186

2187
    return output;
2188

2189
    cmsUNUSED_PARAMETER(info);
2190
    cmsUNUSED_PARAMETER(Stride);
2191
}
2192

2193
// CMYK
2194
static
2195
cmsUInt8Number* Pack4WordsBigEndian(CMSREGISTER _cmsTRANSFORM* info,
2196
                                    CMSREGISTER cmsUInt16Number wOut[],
2197
                                    CMSREGISTER cmsUInt8Number* output,
2198
                                    CMSREGISTER cmsUInt32Number Stride)
2199
{
2200
    *(cmsUInt16Number*) output = CHANGE_ENDIAN(wOut[0]);
2201
    output+= 2;
2202
    *(cmsUInt16Number*) output = CHANGE_ENDIAN(wOut[1]);
2203
    output+= 2;
2204
    *(cmsUInt16Number*) output = CHANGE_ENDIAN(wOut[2]);
2205
    output+= 2;
2206
    *(cmsUInt16Number*) output = CHANGE_ENDIAN(wOut[3]);
2207
    output+= 2;
2208

2209
    return output;
2210

2211
    cmsUNUSED_PARAMETER(info);
2212
    cmsUNUSED_PARAMETER(Stride);
2213
}
2214

2215

2216
static
2217
cmsUInt8Number* PackLabV2_8(CMSREGISTER _cmsTRANSFORM* info,
2218
                            CMSREGISTER cmsUInt16Number wOut[],
2219
                            CMSREGISTER cmsUInt8Number* output,
2220
                            CMSREGISTER cmsUInt32Number Stride)
2221
{
2222
    *output++ = FROM_16_TO_8(FomLabV4ToLabV2(wOut[0]));
2223
    *output++ = FROM_16_TO_8(FomLabV4ToLabV2(wOut[1]));
2224
    *output++ = FROM_16_TO_8(FomLabV4ToLabV2(wOut[2]));
2225

2226
    return output;
2227

2228
    cmsUNUSED_PARAMETER(info);
2229
    cmsUNUSED_PARAMETER(Stride);
2230
}
2231

2232
static
2233
cmsUInt8Number* PackALabV2_8(CMSREGISTER _cmsTRANSFORM* info,
2234
                             CMSREGISTER cmsUInt16Number wOut[],
2235
                             CMSREGISTER cmsUInt8Number* output,
2236
                             CMSREGISTER cmsUInt32Number Stride)
2237
{
2238
    output++;
2239
    *output++ = FROM_16_TO_8(FomLabV4ToLabV2(wOut[0]));
2240
    *output++ = FROM_16_TO_8(FomLabV4ToLabV2(wOut[1]));
2241
    *output++ = FROM_16_TO_8(FomLabV4ToLabV2(wOut[2]));
2242

2243
    return output;
2244

2245
    cmsUNUSED_PARAMETER(info);
2246
    cmsUNUSED_PARAMETER(Stride);
2247
}
2248

2249
static
2250
cmsUInt8Number* PackLabV2_16(CMSREGISTER _cmsTRANSFORM* info,
2251
                             CMSREGISTER cmsUInt16Number wOut[],
2252
                             CMSREGISTER cmsUInt8Number* output,
2253
                             CMSREGISTER cmsUInt32Number Stride)
2254
{
2255
    *(cmsUInt16Number*) output = FomLabV4ToLabV2(wOut[0]);
2256
    output += 2;
2257
    *(cmsUInt16Number*) output = FomLabV4ToLabV2(wOut[1]);
2258
    output += 2;
2259
    *(cmsUInt16Number*) output = FomLabV4ToLabV2(wOut[2]);
2260
    output += 2;
2261

2262
    return output;
2263

2264
    cmsUNUSED_PARAMETER(info);
2265
    cmsUNUSED_PARAMETER(Stride);
2266
}
2267

2268
static
2269
cmsUInt8Number* Pack3Bytes(CMSREGISTER _cmsTRANSFORM* info,
2270
                           CMSREGISTER cmsUInt16Number wOut[],
2271
                           CMSREGISTER cmsUInt8Number* output,
2272
                           CMSREGISTER cmsUInt32Number Stride)
2273
{
2274
    *output++ = FROM_16_TO_8(wOut[0]);
2275
    *output++ = FROM_16_TO_8(wOut[1]);
2276
    *output++ = FROM_16_TO_8(wOut[2]);
2277

2278
    return output;
2279

2280
    cmsUNUSED_PARAMETER(info);
2281
    cmsUNUSED_PARAMETER(Stride);
2282
}
2283

2284
static
2285
cmsUInt8Number* Pack3BytesOptimized(CMSREGISTER _cmsTRANSFORM* info,
2286
                                    CMSREGISTER cmsUInt16Number wOut[],
2287
                                    CMSREGISTER cmsUInt8Number* output,
2288
                                    CMSREGISTER cmsUInt32Number Stride)
2289
{
2290
    *output++ = (wOut[0] & 0xFFU);
2291
    *output++ = (wOut[1] & 0xFFU);
2292
    *output++ = (wOut[2] & 0xFFU);
2293

2294
    return output;
2295

2296
    cmsUNUSED_PARAMETER(info);
2297
    cmsUNUSED_PARAMETER(Stride);
2298
}
2299

2300
static
2301
cmsUInt8Number* Pack3BytesSwap(CMSREGISTER _cmsTRANSFORM* info,
2302
                               CMSREGISTER cmsUInt16Number wOut[],
2303
                               CMSREGISTER cmsUInt8Number* output,
2304
                               CMSREGISTER cmsUInt32Number Stride)
2305
{
2306
    *output++ = FROM_16_TO_8(wOut[2]);
2307
    *output++ = FROM_16_TO_8(wOut[1]);
2308
    *output++ = FROM_16_TO_8(wOut[0]);
2309

2310
    return output;
2311

2312
    cmsUNUSED_PARAMETER(info);
2313
    cmsUNUSED_PARAMETER(Stride);
2314
}
2315

2316
static
2317
cmsUInt8Number* Pack3BytesSwapOptimized(CMSREGISTER _cmsTRANSFORM* info,
2318
                                        CMSREGISTER cmsUInt16Number wOut[],
2319
                                        CMSREGISTER cmsUInt8Number* output,
2320
                                        CMSREGISTER cmsUInt32Number Stride)
2321
{
2322
    *output++ = (wOut[2] & 0xFFU);
2323
    *output++ = (wOut[1] & 0xFFU);
2324
    *output++ = (wOut[0] & 0xFFU);
2325

2326
    return output;
2327

2328
    cmsUNUSED_PARAMETER(info);
2329
    cmsUNUSED_PARAMETER(Stride);
2330
}
2331

2332

2333
static
2334
cmsUInt8Number* Pack3Words(CMSREGISTER _cmsTRANSFORM* info,
2335
                           CMSREGISTER cmsUInt16Number wOut[],
2336
                           CMSREGISTER cmsUInt8Number* output,
2337
                           CMSREGISTER cmsUInt32Number Stride)
2338
{
2339
    *(cmsUInt16Number*) output = wOut[0];
2340
    output+= 2;
2341
    *(cmsUInt16Number*) output = wOut[1];
2342
    output+= 2;
2343
    *(cmsUInt16Number*) output = wOut[2];
2344
    output+= 2;
2345

2346
    return output;
2347

2348
    cmsUNUSED_PARAMETER(info);
2349
    cmsUNUSED_PARAMETER(Stride);
2350
}
2351

2352
static
2353
cmsUInt8Number* Pack3WordsSwap(CMSREGISTER _cmsTRANSFORM* info,
2354
                               CMSREGISTER cmsUInt16Number wOut[],
2355
                               CMSREGISTER cmsUInt8Number* output,
2356
                               CMSREGISTER cmsUInt32Number Stride)
2357
{
2358
    *(cmsUInt16Number*) output = wOut[2];
2359
    output+= 2;
2360
    *(cmsUInt16Number*) output = wOut[1];
2361
    output+= 2;
2362
    *(cmsUInt16Number*) output = wOut[0];
2363
    output+= 2;
2364

2365
    return output;
2366

2367
    cmsUNUSED_PARAMETER(info);
2368
    cmsUNUSED_PARAMETER(Stride);
2369
}
2370

2371
static
2372
cmsUInt8Number* Pack3WordsBigEndian(CMSREGISTER _cmsTRANSFORM* info,
2373
                                    CMSREGISTER cmsUInt16Number wOut[],
2374
                                    CMSREGISTER cmsUInt8Number* output,
2375
                                    CMSREGISTER cmsUInt32Number Stride)
2376
{
2377
    *(cmsUInt16Number*) output = CHANGE_ENDIAN(wOut[0]);
2378
    output+= 2;
2379
    *(cmsUInt16Number*) output = CHANGE_ENDIAN(wOut[1]);
2380
    output+= 2;
2381
    *(cmsUInt16Number*) output = CHANGE_ENDIAN(wOut[2]);
2382
    output+= 2;
2383

2384
    return output;
2385

2386
    cmsUNUSED_PARAMETER(info);
2387
    cmsUNUSED_PARAMETER(Stride);
2388
}
2389

2390
static
2391
cmsUInt8Number* Pack3BytesAndSkip1(CMSREGISTER _cmsTRANSFORM* info,
2392
                                   CMSREGISTER cmsUInt16Number wOut[],
2393
                                   CMSREGISTER cmsUInt8Number* output,
2394
                                   CMSREGISTER cmsUInt32Number Stride)
2395
{
2396
    *output++ = FROM_16_TO_8(wOut[0]);
2397
    *output++ = FROM_16_TO_8(wOut[1]);
2398
    *output++ = FROM_16_TO_8(wOut[2]);
2399
    output++;
2400

2401
    return output;
2402

2403
    cmsUNUSED_PARAMETER(info);
2404
    cmsUNUSED_PARAMETER(Stride);
2405
}
2406

2407
static
2408
cmsUInt8Number* Pack3BytesAndSkip1Optimized(CMSREGISTER _cmsTRANSFORM* info,
2409
                                            CMSREGISTER cmsUInt16Number wOut[],
2410
                                            CMSREGISTER cmsUInt8Number* output,
2411
                                            CMSREGISTER cmsUInt32Number Stride)
2412
{
2413
    *output++ = (wOut[0] & 0xFFU);
2414
    *output++ = (wOut[1] & 0xFFU);
2415
    *output++ = (wOut[2] & 0xFFU);
2416
    output++;
2417

2418
    return output;
2419

2420
    cmsUNUSED_PARAMETER(info);
2421
    cmsUNUSED_PARAMETER(Stride);
2422
}
2423

2424

2425
static
2426
cmsUInt8Number* Pack3BytesAndSkip1SwapFirst(CMSREGISTER _cmsTRANSFORM* info,
2427
                                            CMSREGISTER cmsUInt16Number wOut[],
2428
                                            CMSREGISTER cmsUInt8Number* output,
2429
                                            CMSREGISTER cmsUInt32Number Stride)
2430
{
2431
    output++;
2432
    *output++ = FROM_16_TO_8(wOut[0]);
2433
    *output++ = FROM_16_TO_8(wOut[1]);
2434
    *output++ = FROM_16_TO_8(wOut[2]);
2435

2436
    return output;
2437

2438
    cmsUNUSED_PARAMETER(info);
2439
    cmsUNUSED_PARAMETER(Stride);
2440
}
2441

2442
static
2443
cmsUInt8Number* Pack3BytesAndSkip1SwapFirstOptimized(CMSREGISTER _cmsTRANSFORM* info,
2444
                                                     CMSREGISTER cmsUInt16Number wOut[],
2445
                                                     CMSREGISTER cmsUInt8Number* output,
2446
                                                     CMSREGISTER cmsUInt32Number Stride)
2447
{
2448
    output++;
2449
    *output++ = (wOut[0] & 0xFFU);
2450
    *output++ = (wOut[1] & 0xFFU);
2451
    *output++ = (wOut[2] & 0xFFU);
2452

2453
    return output;
2454

2455
    cmsUNUSED_PARAMETER(info);
2456
    cmsUNUSED_PARAMETER(Stride);
2457
}
2458

2459
static
2460
cmsUInt8Number* Pack3BytesAndSkip1Swap(CMSREGISTER _cmsTRANSFORM* info,
2461
                                       CMSREGISTER cmsUInt16Number wOut[],
2462
                                       CMSREGISTER cmsUInt8Number* output,
2463
                                       CMSREGISTER cmsUInt32Number Stride)
2464
{
2465
    output++;
2466
    *output++ = FROM_16_TO_8(wOut[2]);
2467
    *output++ = FROM_16_TO_8(wOut[1]);
2468
    *output++ = FROM_16_TO_8(wOut[0]);
2469

2470
    return output;
2471

2472
    cmsUNUSED_PARAMETER(info);
2473
    cmsUNUSED_PARAMETER(Stride);
2474
}
2475

2476
static
2477
cmsUInt8Number* Pack3BytesAndSkip1SwapOptimized(CMSREGISTER _cmsTRANSFORM* info,
2478
                                                CMSREGISTER cmsUInt16Number wOut[],
2479
                                                CMSREGISTER cmsUInt8Number* output,
2480
                                                CMSREGISTER cmsUInt32Number Stride)
2481
{
2482
    output++;
2483
    *output++ = (wOut[2] & 0xFFU);
2484
    *output++ = (wOut[1] & 0xFFU);
2485
    *output++ = (wOut[0] & 0xFFU);
2486

2487
    return output;
2488

2489
    cmsUNUSED_PARAMETER(info);
2490
    cmsUNUSED_PARAMETER(Stride);
2491
}
2492

2493

2494
static
2495
cmsUInt8Number* Pack3BytesAndSkip1SwapSwapFirst(CMSREGISTER _cmsTRANSFORM* info,
2496
                                                CMSREGISTER cmsUInt16Number wOut[],
2497
                                                CMSREGISTER cmsUInt8Number* output,
2498
                                                CMSREGISTER cmsUInt32Number Stride)
2499
{
2500
    *output++ = FROM_16_TO_8(wOut[2]);
2501
    *output++ = FROM_16_TO_8(wOut[1]);
2502
    *output++ = FROM_16_TO_8(wOut[0]);
2503
    output++;
2504

2505
    return output;
2506

2507
    cmsUNUSED_PARAMETER(info);
2508
    cmsUNUSED_PARAMETER(Stride);
2509
}
2510

2511
static
2512
cmsUInt8Number* Pack3BytesAndSkip1SwapSwapFirstOptimized(CMSREGISTER _cmsTRANSFORM* info,
2513
                                                         CMSREGISTER cmsUInt16Number wOut[],
2514
                                                         CMSREGISTER cmsUInt8Number* output,
2515
                                                         CMSREGISTER cmsUInt32Number Stride)
2516
{
2517
    *output++ = (wOut[2] & 0xFFU);
2518
    *output++ = (wOut[1] & 0xFFU);
2519
    *output++ = (wOut[0] & 0xFFU);
2520
    output++;
2521

2522
    return output;
2523

2524
    cmsUNUSED_PARAMETER(info);
2525
    cmsUNUSED_PARAMETER(Stride);
2526
}
2527

2528
static
2529
cmsUInt8Number* Pack3WordsAndSkip1(CMSREGISTER _cmsTRANSFORM* info,
2530
                                   CMSREGISTER cmsUInt16Number wOut[],
2531
                                   CMSREGISTER cmsUInt8Number* output,
2532
                                   CMSREGISTER cmsUInt32Number Stride)
2533
{
2534
    *(cmsUInt16Number*) output = wOut[0];
2535
    output+= 2;
2536
    *(cmsUInt16Number*) output = wOut[1];
2537
    output+= 2;
2538
    *(cmsUInt16Number*) output = wOut[2];
2539
    output+= 2;
2540
    output+= 2;
2541

2542
    return output;
2543

2544
    cmsUNUSED_PARAMETER(info);
2545
    cmsUNUSED_PARAMETER(Stride);
2546
}
2547

2548
static
2549
cmsUInt8Number* Pack3WordsAndSkip1Swap(CMSREGISTER _cmsTRANSFORM* info,
2550
                                       CMSREGISTER cmsUInt16Number wOut[],
2551
                                       CMSREGISTER cmsUInt8Number* output,
2552
                                       CMSREGISTER cmsUInt32Number Stride)
2553
{
2554
    output+= 2;
2555
    *(cmsUInt16Number*) output = wOut[2];
2556
    output+= 2;
2557
    *(cmsUInt16Number*) output = wOut[1];
2558
    output+= 2;
2559
    *(cmsUInt16Number*) output = wOut[0];
2560
    output+= 2;
2561

2562
    return output;
2563

2564
    cmsUNUSED_PARAMETER(info);
2565
    cmsUNUSED_PARAMETER(Stride);
2566
}
2567

2568

2569
static
2570
cmsUInt8Number* Pack3WordsAndSkip1SwapFirst(CMSREGISTER _cmsTRANSFORM* info,
2571
                                            CMSREGISTER cmsUInt16Number wOut[],
2572
                                            CMSREGISTER cmsUInt8Number* output,
2573
                                            CMSREGISTER cmsUInt32Number Stride)
2574
{
2575
    output+= 2;
2576
    *(cmsUInt16Number*) output = wOut[0];
2577
    output+= 2;
2578
    *(cmsUInt16Number*) output = wOut[1];
2579
    output+= 2;
2580
    *(cmsUInt16Number*) output = wOut[2];
2581
    output+= 2;
2582

2583
    return output;
2584

2585
    cmsUNUSED_PARAMETER(info);
2586
    cmsUNUSED_PARAMETER(Stride);
2587
}
2588

2589

2590
static
2591
cmsUInt8Number* Pack3WordsAndSkip1SwapSwapFirst(CMSREGISTER _cmsTRANSFORM* info,
2592
                                                CMSREGISTER cmsUInt16Number wOut[],
2593
                                                CMSREGISTER cmsUInt8Number* output,
2594
                                                CMSREGISTER cmsUInt32Number Stride)
2595
{
2596
    *(cmsUInt16Number*) output = wOut[2];
2597
    output+= 2;
2598
    *(cmsUInt16Number*) output = wOut[1];
2599
    output+= 2;
2600
    *(cmsUInt16Number*) output = wOut[0];
2601
    output+= 2;
2602
    output+= 2;
2603

2604
    return output;
2605

2606
    cmsUNUSED_PARAMETER(info);
2607
    cmsUNUSED_PARAMETER(Stride);
2608
}
2609

2610

2611

2612
static
2613
cmsUInt8Number* Pack1Byte(CMSREGISTER _cmsTRANSFORM* info,
2614
                          CMSREGISTER cmsUInt16Number wOut[],
2615
                          CMSREGISTER cmsUInt8Number* output,
2616
                          CMSREGISTER cmsUInt32Number Stride)
2617
{
2618
    *output++ = FROM_16_TO_8(wOut[0]);
2619

2620
    return output;
2621

2622
    cmsUNUSED_PARAMETER(info);
2623
    cmsUNUSED_PARAMETER(Stride);
2624
}
2625

2626

2627
static
2628
cmsUInt8Number* Pack1ByteReversed(CMSREGISTER _cmsTRANSFORM* info,
2629
                                  CMSREGISTER cmsUInt16Number wOut[],
2630
                                  CMSREGISTER cmsUInt8Number* output,
2631
                                  CMSREGISTER cmsUInt32Number Stride)
2632
{
2633
    *output++ = FROM_16_TO_8(REVERSE_FLAVOR_16(wOut[0]));
2634

2635
    return output;
2636

2637
    cmsUNUSED_PARAMETER(info);
2638
    cmsUNUSED_PARAMETER(Stride);
2639
}
2640

2641

2642
static
2643
cmsUInt8Number* Pack1ByteSkip1(CMSREGISTER _cmsTRANSFORM* info,
2644
                               CMSREGISTER cmsUInt16Number wOut[],
2645
                               CMSREGISTER cmsUInt8Number* output,
2646
                               CMSREGISTER cmsUInt32Number Stride)
2647
{
2648
    *output++ = FROM_16_TO_8(wOut[0]);
2649
    output++;
2650

2651
    return output;
2652

2653
    cmsUNUSED_PARAMETER(info);
2654
    cmsUNUSED_PARAMETER(Stride);
2655
}
2656

2657

2658
static
2659
cmsUInt8Number* Pack1ByteSkip1SwapFirst(CMSREGISTER _cmsTRANSFORM* info,
2660
                                        CMSREGISTER cmsUInt16Number wOut[],
2661
                                        CMSREGISTER cmsUInt8Number* output,
2662
                                        CMSREGISTER cmsUInt32Number Stride)
2663
{
2664
    output++;
2665
    *output++ = FROM_16_TO_8(wOut[0]);
2666

2667
    return output;
2668

2669
    cmsUNUSED_PARAMETER(info);
2670
    cmsUNUSED_PARAMETER(Stride);
2671
}
2672

2673
static
2674
cmsUInt8Number* Pack1Word(CMSREGISTER _cmsTRANSFORM* info,
2675
                          CMSREGISTER cmsUInt16Number wOut[],
2676
                          CMSREGISTER cmsUInt8Number* output,
2677
                          CMSREGISTER cmsUInt32Number Stride)
2678
{
2679
    *(cmsUInt16Number*) output = wOut[0];
2680
    output+= 2;
2681

2682
    return output;
2683

2684
    cmsUNUSED_PARAMETER(info);
2685
    cmsUNUSED_PARAMETER(Stride);
2686
}
2687

2688

2689
static
2690
cmsUInt8Number* Pack1WordReversed(CMSREGISTER _cmsTRANSFORM* info,
2691
                                  CMSREGISTER cmsUInt16Number wOut[],
2692
                                  CMSREGISTER cmsUInt8Number* output,
2693
                                  CMSREGISTER cmsUInt32Number Stride)
2694
{
2695
    *(cmsUInt16Number*) output = REVERSE_FLAVOR_16(wOut[0]);
2696
    output+= 2;
2697

2698
    return output;
2699

2700
    cmsUNUSED_PARAMETER(info);
2701
    cmsUNUSED_PARAMETER(Stride);
2702
}
2703

2704
static
2705
cmsUInt8Number* Pack1WordBigEndian(CMSREGISTER _cmsTRANSFORM* info,
2706
                                   CMSREGISTER cmsUInt16Number wOut[],
2707
                                   CMSREGISTER cmsUInt8Number* output,
2708
                                   CMSREGISTER cmsUInt32Number Stride)
2709
{
2710
    *(cmsUInt16Number*) output = CHANGE_ENDIAN(wOut[0]);
2711
    output+= 2;
2712

2713
    return output;
2714

2715
    cmsUNUSED_PARAMETER(info);
2716
    cmsUNUSED_PARAMETER(Stride);
2717
}
2718

2719

2720
static
2721
cmsUInt8Number* Pack1WordSkip1(CMSREGISTER _cmsTRANSFORM* info,
2722
                               CMSREGISTER cmsUInt16Number wOut[],
2723
                               CMSREGISTER cmsUInt8Number* output,
2724
                               CMSREGISTER cmsUInt32Number Stride)
2725
{
2726
    *(cmsUInt16Number*) output = wOut[0];
2727
    output+= 4;
2728

2729
    return output;
2730

2731
    cmsUNUSED_PARAMETER(info);
2732
    cmsUNUSED_PARAMETER(Stride);
2733
}
2734

2735
static
2736
cmsUInt8Number* Pack1WordSkip1SwapFirst(CMSREGISTER _cmsTRANSFORM* info,
2737
                                        CMSREGISTER cmsUInt16Number wOut[],
2738
                                        CMSREGISTER cmsUInt8Number* output,
2739
                                        CMSREGISTER cmsUInt32Number Stride)
2740
{
2741
    output += 2;
2742
    *(cmsUInt16Number*) output = wOut[0];
2743
    output+= 2;
2744

2745
    return output;
2746

2747
    cmsUNUSED_PARAMETER(info);
2748
    cmsUNUSED_PARAMETER(Stride);
2749
}
2750

2751

2752
// Unencoded Float values -- don't try optimize speed
2753
static
2754
cmsUInt8Number* PackLabDoubleFrom16(CMSREGISTER _cmsTRANSFORM* info,
2755
                                    CMSREGISTER cmsUInt16Number wOut[],
2756
                                    CMSREGISTER cmsUInt8Number* output,
2757
                                    CMSREGISTER cmsUInt32Number Stride)
2758
{
2759

2760
    if (T_PLANAR(info -> OutputFormat)) {
2761

2762
        cmsCIELab  Lab;
2763
        cmsFloat64Number* Out = (cmsFloat64Number*) output;
2764
        cmsLabEncoded2Float(&Lab, wOut);
2765

2766
        Out[0]        = Lab.L;
2767
        Out[Stride]   = Lab.a;
2768
        Out[Stride*2] = Lab.b;
2769

2770
        return output + sizeof(cmsFloat64Number);
2771
    }
2772
    else {
2773

2774
        cmsLabEncoded2Float((cmsCIELab*) output, wOut);
2775
        return output + (sizeof(cmsCIELab) + T_EXTRA(info ->OutputFormat) * sizeof(cmsFloat64Number));
2776
    }
2777
}
2778

2779

2780
static
2781
cmsUInt8Number* PackLabFloatFrom16(CMSREGISTER _cmsTRANSFORM* info,
2782
                                    CMSREGISTER cmsUInt16Number wOut[],
2783
                                    CMSREGISTER cmsUInt8Number* output,
2784
                                    CMSREGISTER cmsUInt32Number Stride)
2785
{
2786
    cmsCIELab  Lab;
2787
    cmsLabEncoded2Float(&Lab, wOut);
2788

2789
    if (T_PLANAR(info -> OutputFormat)) {
2790

2791
        cmsFloat32Number* Out = (cmsFloat32Number*) output;
2792

2793
        Stride /= PixelSize(info->OutputFormat);
2794

2795
        Out[0]        = (cmsFloat32Number)Lab.L;
2796
        Out[Stride]   = (cmsFloat32Number)Lab.a;
2797
        Out[Stride*2] = (cmsFloat32Number)Lab.b;
2798

2799
        return output + sizeof(cmsFloat32Number);
2800
    }
2801
    else {
2802

2803
       ((cmsFloat32Number*) output)[0] = (cmsFloat32Number) Lab.L;
2804
       ((cmsFloat32Number*) output)[1] = (cmsFloat32Number) Lab.a;
2805
       ((cmsFloat32Number*) output)[2] = (cmsFloat32Number) Lab.b;
2806

2807
        return output + (3 + T_EXTRA(info ->OutputFormat)) * sizeof(cmsFloat32Number);
2808
    }
2809
}
2810

2811
static
2812
cmsUInt8Number* PackXYZDoubleFrom16(CMSREGISTER _cmsTRANSFORM* Info,
2813
                                    CMSREGISTER cmsUInt16Number wOut[],
2814
                                    CMSREGISTER cmsUInt8Number* output,
2815
                                    CMSREGISTER cmsUInt32Number Stride)
2816
{
2817
    if (T_PLANAR(Info -> OutputFormat)) {
2818

2819
        cmsCIEXYZ XYZ;
2820
        cmsFloat64Number* Out = (cmsFloat64Number*) output;
2821
        cmsXYZEncoded2Float(&XYZ, wOut);
2822

2823
        Stride /= PixelSize(Info->OutputFormat);
2824

2825
        Out[0]        = XYZ.X;
2826
        Out[Stride]   = XYZ.Y;
2827
        Out[Stride*2] = XYZ.Z;
2828

2829
        return output + sizeof(cmsFloat64Number);
2830

2831
    }
2832
    else {
2833

2834
        cmsXYZEncoded2Float((cmsCIEXYZ*) output, wOut);
2835

2836
        return output + (sizeof(cmsCIEXYZ) + T_EXTRA(Info ->OutputFormat) * sizeof(cmsFloat64Number));
2837
    }
2838
}
2839

2840
static
2841
cmsUInt8Number* PackXYZFloatFrom16(CMSREGISTER _cmsTRANSFORM* Info,
2842
                                   CMSREGISTER cmsUInt16Number wOut[],
2843
                                   CMSREGISTER cmsUInt8Number* output,
2844
                                   CMSREGISTER cmsUInt32Number Stride)
2845
{
2846
    if (T_PLANAR(Info -> OutputFormat)) {
2847

2848
        cmsCIEXYZ XYZ;
2849
        cmsFloat32Number* Out = (cmsFloat32Number*) output;
2850
        cmsXYZEncoded2Float(&XYZ, wOut);
2851

2852
        Stride /= PixelSize(Info->OutputFormat);
2853

2854
        Out[0]        = (cmsFloat32Number) XYZ.X;
2855
        Out[Stride]   = (cmsFloat32Number) XYZ.Y;
2856
        Out[Stride*2] = (cmsFloat32Number) XYZ.Z;
2857

2858
        return output + sizeof(cmsFloat32Number);
2859

2860
    }
2861
    else {
2862

2863
        cmsCIEXYZ XYZ;
2864
        cmsFloat32Number* Out = (cmsFloat32Number*) output;
2865
        cmsXYZEncoded2Float(&XYZ, wOut);
2866

2867
        Out[0] = (cmsFloat32Number) XYZ.X;
2868
        Out[1] = (cmsFloat32Number) XYZ.Y;
2869
        Out[2] = (cmsFloat32Number) XYZ.Z;
2870

2871
        return output + (3 * sizeof(cmsFloat32Number) + T_EXTRA(Info ->OutputFormat) * sizeof(cmsFloat32Number));
2872
    }
2873
}
2874

2875
static
2876
cmsUInt8Number* PackDoubleFrom16(CMSREGISTER _cmsTRANSFORM* info,
2877
                                CMSREGISTER cmsUInt16Number wOut[],
2878
                                CMSREGISTER cmsUInt8Number* output,
2879
                                CMSREGISTER cmsUInt32Number Stride)
2880
{
2881
    cmsUInt32Number nChan      = T_CHANNELS(info -> OutputFormat);
2882
    cmsUInt32Number DoSwap     = T_DOSWAP(info ->OutputFormat);
2883
    cmsUInt32Number Reverse    = T_FLAVOR(info ->OutputFormat);
2884
    cmsUInt32Number Extra      = T_EXTRA(info -> OutputFormat);
2885
    cmsUInt32Number SwapFirst  = T_SWAPFIRST(info -> OutputFormat);
2886
    cmsUInt32Number Planar     = T_PLANAR(info -> OutputFormat);
2887
    cmsUInt32Number ExtraFirst = DoSwap ^ SwapFirst;
2888
    cmsFloat64Number maximum = IsInkSpace(info ->OutputFormat) ? 655.35 : 65535.0;
2889
    cmsFloat64Number v = 0;
2890
    cmsFloat64Number* swap1 = (cmsFloat64Number*) output;
2891
    cmsUInt32Number i, start = 0;
2892

2893
    Stride /= PixelSize(info->OutputFormat);
2894

2895
    if (ExtraFirst)
2896
        start = Extra;
2897

2898
    for (i=0; i < nChan; i++) {
2899

2900
        cmsUInt32Number index = DoSwap ? (nChan - i - 1) : i;
2901

2902
        v = (cmsFloat64Number) wOut[index] / maximum;
2903

2904
        if (Reverse)
2905
            v = maximum - v;
2906

2907
        if (Planar)
2908
            ((cmsFloat64Number*) output)[(i + start)  * Stride]= v;
2909
        else
2910
            ((cmsFloat64Number*) output)[i + start] = v;
2911
    }
2912

2913

2914
    if (Extra == 0 && SwapFirst) {
2915

2916
         memmove(swap1 + 1, swap1, (nChan-1)* sizeof(cmsFloat64Number));
2917
        *swap1 = v;
2918
    }
2919

2920
    if (T_PLANAR(info -> OutputFormat))
2921
        return output + sizeof(cmsFloat64Number);
2922
    else
2923
        return output + (nChan + Extra) * sizeof(cmsFloat64Number);
2924

2925
}
2926

2927

2928
static
2929
cmsUInt8Number* PackFloatFrom16(CMSREGISTER _cmsTRANSFORM* info,
2930
                                CMSREGISTER cmsUInt16Number wOut[],
2931
                                CMSREGISTER cmsUInt8Number* output,
2932
                                CMSREGISTER cmsUInt32Number Stride)
2933
{
2934
       cmsUInt32Number nChan      = T_CHANNELS(info->OutputFormat);
2935
       cmsUInt32Number DoSwap     = T_DOSWAP(info->OutputFormat);
2936
       cmsUInt32Number Reverse    = T_FLAVOR(info->OutputFormat);
2937
       cmsUInt32Number Extra      = T_EXTRA(info->OutputFormat);
2938
       cmsUInt32Number SwapFirst  = T_SWAPFIRST(info->OutputFormat);
2939
       cmsUInt32Number Planar     = T_PLANAR(info->OutputFormat);
2940
       cmsUInt32Number ExtraFirst = DoSwap ^ SwapFirst;
2941
       cmsFloat64Number maximum = IsInkSpace(info->OutputFormat) ? 655.35 : 65535.0;
2942
       cmsFloat64Number v = 0;
2943
       cmsFloat32Number* swap1 = (cmsFloat32Number*)output;
2944
       cmsUInt32Number i, start = 0;
2945

2946
       Stride /= PixelSize(info->OutputFormat);
2947

2948
       if (ExtraFirst)
2949
              start = Extra;
2950

2951
       for (i = 0; i < nChan; i++) {
2952

2953
              cmsUInt32Number index = DoSwap ? (nChan - i - 1) : i;
2954

2955
              v = (cmsFloat64Number)wOut[index] / maximum;
2956

2957
              if (Reverse)
2958
                     v = maximum - v;
2959

2960
              if (Planar)
2961
                     ((cmsFloat32Number*)output)[(i + start) * Stride] = (cmsFloat32Number)v;
2962
              else
2963
                     ((cmsFloat32Number*)output)[i + start] = (cmsFloat32Number)v;
2964
       }
2965

2966

2967
       if (Extra == 0 && SwapFirst) {
2968

2969
              memmove(swap1 + 1, swap1, (nChan - 1)* sizeof(cmsFloat32Number));
2970
              *swap1 = (cmsFloat32Number)v;
2971
       }
2972

2973
       if (T_PLANAR(info->OutputFormat))
2974
              return output + sizeof(cmsFloat32Number);
2975
       else
2976
              return output + (nChan + Extra) * sizeof(cmsFloat32Number);
2977
}
2978

2979

2980

2981
// --------------------------------------------------------------------------------------------------------
2982

2983
static
2984
cmsUInt8Number* PackBytesFromFloat(_cmsTRANSFORM* info,
2985
                                    cmsFloat32Number wOut[],
2986
                                    cmsUInt8Number* output,
2987
                                    cmsUInt32Number Stride)
2988
{
2989
    cmsUInt32Number nChan = T_CHANNELS(info->OutputFormat);
2990
    cmsUInt32Number DoSwap = T_DOSWAP(info->OutputFormat);
2991
    cmsUInt32Number Reverse = T_FLAVOR(info->OutputFormat);
2992
    cmsUInt32Number Extra = T_EXTRA(info->OutputFormat);
2993
    cmsUInt32Number SwapFirst = T_SWAPFIRST(info->OutputFormat);
2994
    cmsUInt32Number Planar = T_PLANAR(info->OutputFormat);
2995
    cmsUInt32Number ExtraFirst = DoSwap ^ SwapFirst;
2996
    cmsUInt8Number* swap1 = (cmsUInt8Number*)output;
2997
    cmsFloat64Number v = 0;
2998
    cmsUInt8Number vv = 0;
2999
    cmsUInt32Number i, start = 0;
3000

3001
    if (ExtraFirst)
3002
        start = Extra;
3003

3004
    for (i = 0; i < nChan; i++) {
3005

3006
        cmsUInt32Number index = DoSwap ? (nChan - i - 1) : i;
3007

3008
        v = wOut[index] * 65535.0;
3009

3010
        if (Reverse)
3011
            v = 65535.0 - v;
3012

3013
        vv =  FROM_16_TO_8(_cmsQuickSaturateWord(v));
3014

3015
        if (Planar)
3016
            ((cmsUInt8Number*)output)[(i + start) * Stride] = vv;
3017
        else
3018
            ((cmsUInt8Number*)output)[i + start] = vv;
3019
    }
3020

3021

3022
    if (Extra == 0 && SwapFirst) {
3023

3024
        memmove(swap1 + 1, swap1, (nChan - 1) * sizeof(cmsUInt8Number));
3025
        *swap1 = vv;
3026
    }
3027

3028
    if (T_PLANAR(info->OutputFormat))
3029
        return output + sizeof(cmsUInt8Number);
3030
    else
3031
        return output + (nChan + Extra) * sizeof(cmsUInt8Number);
3032
}
3033

3034
static
3035
cmsUInt8Number* PackWordsFromFloat(_cmsTRANSFORM* info,
3036
                                    cmsFloat32Number wOut[],
3037
                                    cmsUInt8Number* output,
3038
                                    cmsUInt32Number Stride)
3039
{
3040
    cmsUInt32Number nChan = T_CHANNELS(info->OutputFormat);
3041
    cmsUInt32Number DoSwap = T_DOSWAP(info->OutputFormat);
3042
    cmsUInt32Number Reverse = T_FLAVOR(info->OutputFormat);
3043
    cmsUInt32Number Extra = T_EXTRA(info->OutputFormat);
3044
    cmsUInt32Number SwapFirst = T_SWAPFIRST(info->OutputFormat);
3045
    cmsUInt32Number Planar = T_PLANAR(info->OutputFormat);
3046
    cmsUInt32Number ExtraFirst = DoSwap ^ SwapFirst;
3047
    cmsUInt16Number* swap1 = (cmsUInt16Number*)output;
3048
    cmsFloat64Number v = 0;
3049
    cmsUInt16Number vv = 0;
3050
    cmsUInt32Number i, start = 0;
3051

3052
    if (ExtraFirst)
3053
        start = Extra;
3054

3055
    for (i = 0; i < nChan; i++) {
3056

3057
        cmsUInt32Number index = DoSwap ? (nChan - i - 1) : i;
3058

3059
        v = wOut[index] * 65535.0;
3060

3061
        if (Reverse)
3062
            v = 65535.0 - v;
3063

3064
        vv = _cmsQuickSaturateWord(v);
3065

3066
        if (Planar)
3067
            ((cmsUInt16Number*)output)[(i + start) * Stride] = vv;
3068
        else
3069
            ((cmsUInt16Number*)output)[i + start] = vv;
3070
    }
3071

3072
    if (Extra == 0 && SwapFirst) {
3073

3074
        memmove(swap1 + 1, swap1, (nChan - 1) * sizeof(cmsUInt16Number));
3075
        *swap1 = vv;
3076
    }
3077

3078
    if (T_PLANAR(info->OutputFormat))
3079
        return output + sizeof(cmsUInt16Number);
3080
    else
3081
        return output + (nChan + Extra) * sizeof(cmsUInt16Number);
3082
}
3083

3084

3085
static
3086
cmsUInt8Number* PackFloatsFromFloat(_cmsTRANSFORM* info,
3087
                                    cmsFloat32Number wOut[],
3088
                                    cmsUInt8Number* output,
3089
                                    cmsUInt32Number Stride)
3090
{
3091
       cmsUInt32Number nChan = T_CHANNELS(info->OutputFormat);
3092
       cmsUInt32Number DoSwap = T_DOSWAP(info->OutputFormat);
3093
       cmsUInt32Number Reverse = T_FLAVOR(info->OutputFormat);
3094
       cmsUInt32Number Extra = T_EXTRA(info->OutputFormat);
3095
       cmsUInt32Number SwapFirst = T_SWAPFIRST(info->OutputFormat);
3096
       cmsUInt32Number Planar = T_PLANAR(info->OutputFormat);
3097
       cmsUInt32Number ExtraFirst = DoSwap ^ SwapFirst;
3098
       cmsFloat64Number maximum = IsInkSpace(info->OutputFormat) ? 100.0 : 1.0;
3099
       cmsFloat32Number* swap1 = (cmsFloat32Number*)output;
3100
       cmsFloat64Number v = 0;
3101
       cmsUInt32Number i, start = 0;
3102

3103
       Stride /= PixelSize(info->OutputFormat);
3104

3105
       if (ExtraFirst)
3106
              start = Extra;
3107

3108
       for (i = 0; i < nChan; i++) {
3109

3110
              cmsUInt32Number index = DoSwap ? (nChan - i - 1) : i;
3111

3112
              v = wOut[index] * maximum;
3113

3114
              if (Reverse)
3115
                     v = maximum - v;
3116

3117
              if (Planar)
3118
                     ((cmsFloat32Number*)output)[(i + start)* Stride] = (cmsFloat32Number)v;
3119
              else
3120
                     ((cmsFloat32Number*)output)[i + start] = (cmsFloat32Number)v;
3121
       }
3122

3123

3124
       if (Extra == 0 && SwapFirst) {
3125

3126
              memmove(swap1 + 1, swap1, (nChan - 1)* sizeof(cmsFloat32Number));
3127
              *swap1 = (cmsFloat32Number)v;
3128
       }
3129

3130
       if (T_PLANAR(info->OutputFormat))
3131
              return output + sizeof(cmsFloat32Number);
3132
       else
3133
              return output + (nChan + Extra) * sizeof(cmsFloat32Number);
3134
}
3135

3136
static
3137
cmsUInt8Number* PackDoublesFromFloat(_cmsTRANSFORM* info,
3138
                                    cmsFloat32Number wOut[],
3139
                                    cmsUInt8Number* output,
3140
                                    cmsUInt32Number Stride)
3141
{
3142
       cmsUInt32Number nChan      = T_CHANNELS(info->OutputFormat);
3143
       cmsUInt32Number DoSwap     = T_DOSWAP(info->OutputFormat);
3144
       cmsUInt32Number Reverse    = T_FLAVOR(info->OutputFormat);
3145
       cmsUInt32Number Extra      = T_EXTRA(info->OutputFormat);
3146
       cmsUInt32Number SwapFirst  = T_SWAPFIRST(info->OutputFormat);
3147
       cmsUInt32Number Planar     = T_PLANAR(info->OutputFormat);
3148
       cmsUInt32Number ExtraFirst = DoSwap ^ SwapFirst;
3149
       cmsFloat64Number maximum = IsInkSpace(info->OutputFormat) ? 100.0 : 1.0;
3150
       cmsFloat64Number v = 0;
3151
       cmsFloat64Number* swap1 = (cmsFloat64Number*)output;
3152
       cmsUInt32Number i, start = 0;
3153

3154
       Stride /= PixelSize(info->OutputFormat);
3155

3156
       if (ExtraFirst)
3157
              start = Extra;
3158

3159
       for (i = 0; i < nChan; i++) {
3160

3161
              cmsUInt32Number index = DoSwap ? (nChan - i - 1) : i;
3162

3163
              v = wOut[index] * maximum;
3164

3165
              if (Reverse)
3166
                     v = maximum - v;
3167

3168
              if (Planar)
3169
                     ((cmsFloat64Number*)output)[(i + start) * Stride] = v;
3170
              else
3171
                     ((cmsFloat64Number*)output)[i + start] = v;
3172
       }
3173

3174
       if (Extra == 0 && SwapFirst) {
3175

3176
              memmove(swap1 + 1, swap1, (nChan - 1)* sizeof(cmsFloat64Number));
3177
              *swap1 = v;
3178
       }
3179

3180

3181
       if (T_PLANAR(info->OutputFormat))
3182
              return output + sizeof(cmsFloat64Number);
3183
       else
3184
              return output + (nChan + Extra) * sizeof(cmsFloat64Number);
3185

3186
}
3187

3188
static
3189
cmsUInt8Number* PackLabFloatFromFloat(_cmsTRANSFORM* Info,
3190
                                      cmsFloat32Number wOut[],
3191
                                      cmsUInt8Number* output,
3192
                                      cmsUInt32Number Stride)
3193
{
3194
    cmsFloat32Number* Out = (cmsFloat32Number*) output;
3195

3196
    if (T_PLANAR(Info -> OutputFormat)) {
3197

3198
        Stride /= PixelSize(Info->OutputFormat);
3199

3200
        Out[0]        = (cmsFloat32Number) (wOut[0] * 100.0);
3201
        Out[Stride]   = (cmsFloat32Number) (wOut[1] * 255.0 - 128.0);
3202
        Out[Stride*2] = (cmsFloat32Number) (wOut[2] * 255.0 - 128.0);
3203

3204
        return output + sizeof(cmsFloat32Number);
3205
    }
3206
    else {
3207

3208
        Out[0] = (cmsFloat32Number) (wOut[0] * 100.0);
3209
        Out[1] = (cmsFloat32Number) (wOut[1] * 255.0 - 128.0);
3210
        Out[2] = (cmsFloat32Number) (wOut[2] * 255.0 - 128.0);
3211

3212
        return output + (sizeof(cmsFloat32Number)*3 + T_EXTRA(Info ->OutputFormat) * sizeof(cmsFloat32Number));
3213
    }
3214

3215
}
3216

3217

3218
static
3219
cmsUInt8Number* PackLabDoubleFromFloat(_cmsTRANSFORM* Info,
3220
                                       cmsFloat32Number wOut[],
3221
                                       cmsUInt8Number* output,
3222
                                       cmsUInt32Number Stride)
3223
{
3224
    cmsFloat64Number* Out = (cmsFloat64Number*) output;
3225

3226
    if (T_PLANAR(Info -> OutputFormat)) {
3227

3228
        Stride /= PixelSize(Info->OutputFormat);
3229

3230
        Out[0]        = (cmsFloat64Number) (wOut[0] * 100.0);
3231
        Out[Stride]   = (cmsFloat64Number) (wOut[1] * 255.0 - 128.0);
3232
        Out[Stride*2] = (cmsFloat64Number) (wOut[2] * 255.0 - 128.0);
3233

3234
        return output + sizeof(cmsFloat64Number);
3235
    }
3236
    else {
3237

3238
        Out[0] = (cmsFloat64Number) (wOut[0] * 100.0);
3239
        Out[1] = (cmsFloat64Number) (wOut[1] * 255.0 - 128.0);
3240
        Out[2] = (cmsFloat64Number) (wOut[2] * 255.0 - 128.0);
3241

3242
        return output + (sizeof(cmsFloat64Number)*3 + T_EXTRA(Info ->OutputFormat) * sizeof(cmsFloat64Number));
3243
    }
3244

3245
}
3246

3247

3248
static
3249
cmsUInt8Number* PackEncodedBytesLabV2FromFloat(_cmsTRANSFORM* Info,
3250
                                           cmsFloat32Number wOut[],
3251
                                           cmsUInt8Number* output,
3252
                                           cmsUInt32Number Stride)
3253
{
3254
    cmsCIELab Lab;
3255
    cmsUInt16Number wlab[3];
3256

3257
    Lab.L = (cmsFloat64Number)(wOut[0] * 100.0);
3258
    Lab.a = (cmsFloat64Number)(wOut[1] * 255.0 - 128.0);
3259
    Lab.b = (cmsFloat64Number)(wOut[2] * 255.0 - 128.0);
3260

3261
    cmsFloat2LabEncoded(wlab, &Lab);
3262

3263
    if (T_PLANAR(Info -> OutputFormat)) {
3264

3265
        Stride /= PixelSize(Info->OutputFormat);
3266

3267
        output[0]        = wlab[0] >> 8;
3268
        output[Stride]   = wlab[1] >> 8;
3269
        output[Stride*2] = wlab[2] >> 8;
3270

3271
        return output + 1;
3272
    }
3273
    else {
3274

3275
        output[0] = wlab[0] >> 8;
3276
        output[1] = wlab[1] >> 8;
3277
        output[2] = wlab[2] >> 8;
3278

3279
        return output + (3 + T_EXTRA(Info ->OutputFormat));
3280
    }
3281
}
3282

3283
static
3284
cmsUInt8Number* PackEncodedWordsLabV2FromFloat(_cmsTRANSFORM* Info,
3285
                                           cmsFloat32Number wOut[],
3286
                                           cmsUInt8Number* output,
3287
                                           cmsUInt32Number Stride)
3288
{
3289
    cmsCIELab Lab;
3290
    cmsUInt16Number wlab[3];
3291

3292
    Lab.L = (cmsFloat64Number)(wOut[0] * 100.0);
3293
    Lab.a = (cmsFloat64Number)(wOut[1] * 255.0 - 128.0);
3294
    Lab.b = (cmsFloat64Number)(wOut[2] * 255.0 - 128.0);
3295

3296
    cmsFloat2LabEncodedV2(wlab, &Lab);
3297

3298
    if (T_PLANAR(Info -> OutputFormat)) {
3299

3300
        Stride /= PixelSize(Info->OutputFormat);
3301

3302
        ((cmsUInt16Number*) output)[0]        = wlab[0];
3303
        ((cmsUInt16Number*) output)[Stride]   = wlab[1];
3304
        ((cmsUInt16Number*) output)[Stride*2] = wlab[2];
3305

3306
        return output + sizeof(cmsUInt16Number);
3307
    }
3308
    else {
3309

3310
         ((cmsUInt16Number*) output)[0] = wlab[0];
3311
         ((cmsUInt16Number*) output)[1] = wlab[1];
3312
         ((cmsUInt16Number*) output)[2] = wlab[2];
3313

3314
        return output + (3 + T_EXTRA(Info ->OutputFormat)) * sizeof(cmsUInt16Number);
3315
    }
3316
}
3317

3318

3319
// From 0..1 range to 0..MAX_ENCODEABLE_XYZ
3320
static
3321
cmsUInt8Number* PackXYZFloatFromFloat(_cmsTRANSFORM* Info,
3322
                                      cmsFloat32Number wOut[],
3323
                                      cmsUInt8Number* output,
3324
                                      cmsUInt32Number Stride)
3325
{
3326
    cmsFloat32Number* Out = (cmsFloat32Number*) output;
3327

3328
    if (T_PLANAR(Info -> OutputFormat)) {
3329

3330
        Stride /= PixelSize(Info->OutputFormat);
3331

3332
        Out[0]        = (cmsFloat32Number) (wOut[0] * MAX_ENCODEABLE_XYZ);
3333
        Out[Stride]   = (cmsFloat32Number) (wOut[1] * MAX_ENCODEABLE_XYZ);
3334
        Out[Stride*2] = (cmsFloat32Number) (wOut[2] * MAX_ENCODEABLE_XYZ);
3335

3336
        return output + sizeof(cmsFloat32Number);
3337
    }
3338
    else {
3339

3340
        Out[0] = (cmsFloat32Number) (wOut[0] * MAX_ENCODEABLE_XYZ);
3341
        Out[1] = (cmsFloat32Number) (wOut[1] * MAX_ENCODEABLE_XYZ);
3342
        Out[2] = (cmsFloat32Number) (wOut[2] * MAX_ENCODEABLE_XYZ);
3343

3344
        return output + (sizeof(cmsFloat32Number)*3 + T_EXTRA(Info ->OutputFormat) * sizeof(cmsFloat32Number));
3345
    }
3346

3347
}
3348

3349
// Same, but convert to double
3350
static
3351
cmsUInt8Number* PackXYZDoubleFromFloat(_cmsTRANSFORM* Info,
3352
                                       cmsFloat32Number wOut[],
3353
                                       cmsUInt8Number* output,
3354
                                       cmsUInt32Number Stride)
3355
{
3356
    cmsFloat64Number* Out = (cmsFloat64Number*) output;
3357

3358
    if (T_PLANAR(Info -> OutputFormat)) {
3359

3360
        Stride /= PixelSize(Info->OutputFormat);
3361

3362
        Out[0]        = (cmsFloat64Number) (wOut[0] * MAX_ENCODEABLE_XYZ);
3363
        Out[Stride]   = (cmsFloat64Number) (wOut[1] * MAX_ENCODEABLE_XYZ);
3364
        Out[Stride*2] = (cmsFloat64Number) (wOut[2] * MAX_ENCODEABLE_XYZ);
3365

3366
        return output + sizeof(cmsFloat64Number);
3367
    }
3368
    else {
3369

3370
        Out[0] = (cmsFloat64Number) (wOut[0] * MAX_ENCODEABLE_XYZ);
3371
        Out[1] = (cmsFloat64Number) (wOut[1] * MAX_ENCODEABLE_XYZ);
3372
        Out[2] = (cmsFloat64Number) (wOut[2] * MAX_ENCODEABLE_XYZ);
3373

3374
        return output + (sizeof(cmsFloat64Number)*3 + T_EXTRA(Info ->OutputFormat) * sizeof(cmsFloat64Number));
3375
    }
3376

3377
}
3378

3379

3380
// ----------------------------------------------------------------------------------------------------------------
3381

3382
#ifndef CMS_NO_HALF_SUPPORT
3383

3384
// Decodes an stream of half floats to wIn[] described by input format
3385

3386
static
3387
cmsUInt8Number* UnrollHalfTo16(CMSREGISTER _cmsTRANSFORM* info,
3388
                                CMSREGISTER cmsUInt16Number wIn[],
3389
                                CMSREGISTER cmsUInt8Number* accum,
3390
                                CMSREGISTER cmsUInt32Number Stride)
3391
{
3392

3393
    cmsUInt32Number nChan      = T_CHANNELS(info -> InputFormat);
3394
    cmsUInt32Number DoSwap     = T_DOSWAP(info ->InputFormat);
3395
    cmsUInt32Number Reverse    = T_FLAVOR(info ->InputFormat);
3396
    cmsUInt32Number SwapFirst  = T_SWAPFIRST(info -> InputFormat);
3397
    cmsUInt32Number Extra      = T_EXTRA(info -> InputFormat);
3398
    cmsUInt32Number ExtraFirst = DoSwap ^ SwapFirst;
3399
    cmsUInt32Number Planar     = T_PLANAR(info -> InputFormat);
3400
    cmsFloat32Number v;
3401
    cmsUInt32Number i, start = 0;
3402
    cmsFloat32Number maximum = IsInkSpace(info ->InputFormat) ? 655.35F : 65535.0F;
3403

3404

3405
    Stride /= PixelSize(info->OutputFormat);
3406

3407
    if (ExtraFirst)
3408
            start = Extra;
3409

3410
    for (i=0; i < nChan; i++) {
3411

3412
        cmsUInt32Number index = DoSwap ? (nChan - i - 1) : i;
3413

3414
        if (Planar)
3415
            v = _cmsHalf2Float ( ((cmsUInt16Number*) accum)[(i + start) * Stride] );
3416
        else
3417
            v = _cmsHalf2Float ( ((cmsUInt16Number*) accum)[i + start] ) ;
3418

3419
        if (Reverse) v = maximum - v;
3420

3421
        wIn[index] = _cmsQuickSaturateWord((cmsFloat64Number) v * maximum);
3422
    }
3423

3424

3425
    if (Extra == 0 && SwapFirst) {
3426
        cmsUInt16Number tmp = wIn[0];
3427

3428
        memmove(&wIn[0], &wIn[1], (nChan-1) * sizeof(cmsUInt16Number));
3429
        wIn[nChan-1] = tmp;
3430
    }
3431

3432
    if (T_PLANAR(info -> InputFormat))
3433
        return accum + sizeof(cmsUInt16Number);
3434
    else
3435
        return accum + (nChan + Extra) * sizeof(cmsUInt16Number);
3436
}
3437

3438
// Decodes an stream of half floats to wIn[] described by input format
3439

3440
static
3441
cmsUInt8Number* UnrollHalfToFloat(_cmsTRANSFORM* info,
3442
                                    cmsFloat32Number wIn[],
3443
                                    cmsUInt8Number* accum,
3444
                                    cmsUInt32Number Stride)
3445
{
3446

3447
    cmsUInt32Number nChan      = T_CHANNELS(info -> InputFormat);
3448
    cmsUInt32Number DoSwap     = T_DOSWAP(info ->InputFormat);
3449
    cmsUInt32Number Reverse    = T_FLAVOR(info ->InputFormat);
3450
    cmsUInt32Number SwapFirst  = T_SWAPFIRST(info -> InputFormat);
3451
    cmsUInt32Number Extra      = T_EXTRA(info -> InputFormat);
3452
    cmsUInt32Number ExtraFirst = DoSwap ^ SwapFirst;
3453
    cmsUInt32Number Planar     = T_PLANAR(info -> InputFormat);
3454
    cmsFloat32Number v;
3455
    cmsUInt32Number i, start = 0;
3456
    cmsFloat32Number maximum = IsInkSpace(info ->InputFormat) ? 100.0F : 1.0F;
3457

3458
    Stride /= PixelSize(info->OutputFormat);
3459

3460
    if (ExtraFirst)
3461
            start = Extra;
3462

3463
    for (i=0; i < nChan; i++) {
3464

3465
        cmsUInt32Number index = DoSwap ? (nChan - i - 1) : i;
3466

3467
        if (Planar)
3468
            v =  _cmsHalf2Float ( ((cmsUInt16Number*) accum)[(i + start) * Stride] );
3469
        else
3470
            v =  _cmsHalf2Float ( ((cmsUInt16Number*) accum)[i + start] ) ;
3471

3472
        v /= maximum;
3473

3474
        wIn[index] = Reverse ? 1 - v : v;
3475
    }
3476

3477

3478
    if (Extra == 0 && SwapFirst) {
3479
        cmsFloat32Number tmp = wIn[0];
3480

3481
        memmove(&wIn[0], &wIn[1], (nChan-1) * sizeof(cmsFloat32Number));
3482
        wIn[nChan-1] = tmp;
3483
    }
3484

3485
    if (T_PLANAR(info -> InputFormat))
3486
        return accum + sizeof(cmsUInt16Number);
3487
    else
3488
        return accum + (nChan + Extra) * sizeof(cmsUInt16Number);
3489
}
3490

3491

3492
static
3493
cmsUInt8Number* PackHalfFrom16(CMSREGISTER _cmsTRANSFORM* info,
3494
                                CMSREGISTER cmsUInt16Number wOut[],
3495
                                CMSREGISTER cmsUInt8Number* output,
3496
                                CMSREGISTER cmsUInt32Number Stride)
3497
{
3498
       cmsUInt32Number nChan      = T_CHANNELS(info->OutputFormat);
3499
       cmsUInt32Number DoSwap     = T_DOSWAP(info->OutputFormat);
3500
       cmsUInt32Number Reverse    = T_FLAVOR(info->OutputFormat);
3501
       cmsUInt32Number Extra      = T_EXTRA(info->OutputFormat);
3502
       cmsUInt32Number SwapFirst  = T_SWAPFIRST(info->OutputFormat);
3503
       cmsUInt32Number Planar     = T_PLANAR(info->OutputFormat);
3504
       cmsUInt32Number ExtraFirst = DoSwap ^ SwapFirst;
3505
       cmsFloat32Number maximum = IsInkSpace(info->OutputFormat) ? 655.35F : 65535.0F;
3506
       cmsFloat32Number v = 0;
3507
       cmsUInt16Number* swap1 = (cmsUInt16Number*)output;
3508
       cmsUInt32Number i, start = 0;
3509

3510
       Stride /= PixelSize(info->OutputFormat);
3511

3512
       if (ExtraFirst)
3513
              start = Extra;
3514

3515
       for (i = 0; i < nChan; i++) {
3516

3517
              cmsUInt32Number index = DoSwap ? (nChan - i - 1) : i;
3518

3519
              v = (cmsFloat32Number)wOut[index] / maximum;
3520

3521
              if (Reverse)
3522
                     v = maximum - v;
3523

3524
              if (Planar)
3525
                     ((cmsUInt16Number*)output)[(i + start) * Stride] = _cmsFloat2Half(v);
3526
              else
3527
                     ((cmsUInt16Number*)output)[i + start] = _cmsFloat2Half(v);
3528
       }
3529

3530

3531
       if (Extra == 0 && SwapFirst) {
3532

3533
              memmove(swap1 + 1, swap1, (nChan - 1)* sizeof(cmsUInt16Number));
3534
              *swap1 = _cmsFloat2Half(v);
3535
       }
3536

3537
       if (T_PLANAR(info->OutputFormat))
3538
              return output + sizeof(cmsUInt16Number);
3539
       else
3540
              return output + (nChan + Extra) * sizeof(cmsUInt16Number);
3541
}
3542

3543

3544

3545
static
3546
cmsUInt8Number* PackHalfFromFloat(_cmsTRANSFORM* info,
3547
                                    cmsFloat32Number wOut[],
3548
                                    cmsUInt8Number* output,
3549
                                    cmsUInt32Number Stride)
3550
{
3551
       cmsUInt32Number nChan      = T_CHANNELS(info->OutputFormat);
3552
       cmsUInt32Number DoSwap     = T_DOSWAP(info->OutputFormat);
3553
       cmsUInt32Number Reverse    = T_FLAVOR(info->OutputFormat);
3554
       cmsUInt32Number Extra      = T_EXTRA(info->OutputFormat);
3555
       cmsUInt32Number SwapFirst  = T_SWAPFIRST(info->OutputFormat);
3556
       cmsUInt32Number Planar     = T_PLANAR(info->OutputFormat);
3557
       cmsUInt32Number ExtraFirst = DoSwap ^ SwapFirst;
3558
       cmsFloat32Number maximum = IsInkSpace(info->OutputFormat) ? 100.0F : 1.0F;
3559
       cmsUInt16Number* swap1 = (cmsUInt16Number*)output;
3560
       cmsFloat32Number v = 0;
3561
       cmsUInt32Number i, start = 0;
3562

3563
       Stride /= PixelSize(info->OutputFormat);
3564

3565
       if (ExtraFirst)
3566
              start = Extra;
3567

3568
       for (i = 0; i < nChan; i++) {
3569

3570
           cmsUInt32Number index = DoSwap ? (nChan - i - 1) : i;
3571

3572
              v = wOut[index] * maximum;
3573

3574
              if (Reverse)
3575
                     v = maximum - v;
3576

3577
              if (Planar)
3578
                     ((cmsUInt16Number*)output)[(i + start)* Stride] = _cmsFloat2Half(v);
3579
              else
3580
                     ((cmsUInt16Number*)output)[i + start] = _cmsFloat2Half(v);
3581
       }
3582

3583

3584
       if (Extra == 0 && SwapFirst) {
3585

3586
              memmove(swap1 + 1, swap1, (nChan - 1)* sizeof(cmsUInt16Number));
3587
              *swap1 = (cmsUInt16Number)_cmsFloat2Half(v);
3588
       }
3589

3590
       if (T_PLANAR(info->OutputFormat))
3591
              return output + sizeof(cmsUInt16Number);
3592
       else
3593
              return output + (nChan + Extra)* sizeof(cmsUInt16Number);
3594
}
3595

3596
#endif
3597

3598
// ----------------------------------------------------------------------------------------------------------------
3599

3600

3601
static const cmsFormatters16 InputFormatters16[] = {
3602

3603
    //    Type                                          Mask                  Function
3604
    //  ----------------------------   ------------------------------------  ----------------------------
3605
    { TYPE_Lab_DBL,                                 ANYPLANAR|ANYEXTRA,   UnrollLabDoubleTo16},
3606
    { TYPE_XYZ_DBL,                                 ANYPLANAR|ANYEXTRA,   UnrollXYZDoubleTo16},
3607
    { TYPE_Lab_FLT,                                 ANYPLANAR|ANYEXTRA,   UnrollLabFloatTo16},
3608
    { TYPE_XYZ_FLT,                                 ANYPLANAR|ANYEXTRA,   UnrollXYZFloatTo16},
3609
    { TYPE_GRAY_DBL,                                                 0,   UnrollDouble1Chan},
3610
    { FLOAT_SH(1)|BYTES_SH(0), ANYCHANNELS|ANYPLANAR|ANYSWAPFIRST|ANYFLAVOR|
3611
                                             ANYSWAP|ANYEXTRA|ANYSPACE,   UnrollDoubleTo16},
3612
    { FLOAT_SH(1)|BYTES_SH(4), ANYCHANNELS|ANYPLANAR|ANYSWAPFIRST|ANYFLAVOR|
3613
                                             ANYSWAP|ANYEXTRA|ANYSPACE,   UnrollFloatTo16},
3614
#ifndef CMS_NO_HALF_SUPPORT
3615
    { FLOAT_SH(1)|BYTES_SH(2), ANYCHANNELS|ANYPLANAR|ANYSWAPFIRST|ANYFLAVOR|
3616
                                            ANYEXTRA|ANYSWAP|ANYSPACE,   UnrollHalfTo16},
3617
#endif
3618

3619
    { CHANNELS_SH(1)|BYTES_SH(1),                              ANYSPACE,  Unroll1Byte},
3620
    { CHANNELS_SH(1)|BYTES_SH(1)|EXTRA_SH(1),                  ANYSPACE,  Unroll1ByteSkip1},
3621
    { CHANNELS_SH(1)|BYTES_SH(1)|EXTRA_SH(2),                  ANYSPACE,  Unroll1ByteSkip2},
3622
    { CHANNELS_SH(1)|BYTES_SH(1)|FLAVOR_SH(1),                 ANYSPACE,  Unroll1ByteReversed},
3623
    { COLORSPACE_SH(PT_MCH2)|CHANNELS_SH(2)|BYTES_SH(1),              0,  Unroll2Bytes},
3624

3625
    { TYPE_LabV2_8,                                                   0,  UnrollLabV2_8 },
3626
    { TYPE_ALabV2_8,                                                  0,  UnrollALabV2_8 },
3627
    { TYPE_LabV2_16,                                                  0,  UnrollLabV2_16 },
3628

3629
    { CHANNELS_SH(3)|BYTES_SH(1),                              ANYSPACE,  Unroll3Bytes},
3630
    { CHANNELS_SH(3)|BYTES_SH(1)|DOSWAP_SH(1),                 ANYSPACE,  Unroll3BytesSwap},
3631
    { CHANNELS_SH(3)|EXTRA_SH(1)|BYTES_SH(1)|DOSWAP_SH(1),     ANYSPACE,  Unroll3BytesSkip1Swap},
3632
    { CHANNELS_SH(3)|EXTRA_SH(1)|BYTES_SH(1)|SWAPFIRST_SH(1),  ANYSPACE,  Unroll3BytesSkip1SwapFirst},
3633

3634
    { CHANNELS_SH(3)|EXTRA_SH(1)|BYTES_SH(1)|DOSWAP_SH(1)|SWAPFIRST_SH(1),
3635
                                                               ANYSPACE,  Unroll3BytesSkip1SwapSwapFirst},
3636

3637
    { CHANNELS_SH(4)|BYTES_SH(1),                              ANYSPACE,  Unroll4Bytes},
3638
    { CHANNELS_SH(4)|BYTES_SH(1)|FLAVOR_SH(1),                 ANYSPACE,  Unroll4BytesReverse},
3639
    { CHANNELS_SH(4)|BYTES_SH(1)|SWAPFIRST_SH(1),              ANYSPACE,  Unroll4BytesSwapFirst},
3640
    { CHANNELS_SH(4)|BYTES_SH(1)|DOSWAP_SH(1),                 ANYSPACE,  Unroll4BytesSwap},
3641
    { CHANNELS_SH(4)|BYTES_SH(1)|DOSWAP_SH(1)|SWAPFIRST_SH(1), ANYSPACE,  Unroll4BytesSwapSwapFirst},
3642

3643
    { BYTES_SH(1)|PLANAR_SH(1), ANYFLAVOR|ANYSWAPFIRST|ANYPREMUL|
3644
                                   ANYSWAP|ANYEXTRA|ANYCHANNELS|ANYSPACE, UnrollPlanarBytes},
3645

3646
    { BYTES_SH(1),    ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|ANYPREMUL|
3647
                                           ANYEXTRA|ANYCHANNELS|ANYSPACE, UnrollChunkyBytes},
3648

3649
    { CHANNELS_SH(1)|BYTES_SH(2),                              ANYSPACE,  Unroll1Word},
3650
    { CHANNELS_SH(1)|BYTES_SH(2)|FLAVOR_SH(1),                 ANYSPACE,  Unroll1WordReversed},
3651
    { CHANNELS_SH(1)|BYTES_SH(2)|EXTRA_SH(3),                  ANYSPACE,  Unroll1WordSkip3},
3652

3653
    { CHANNELS_SH(2)|BYTES_SH(2),                              ANYSPACE,  Unroll2Words},
3654
    { CHANNELS_SH(3)|BYTES_SH(2),                              ANYSPACE,  Unroll3Words},
3655
    { CHANNELS_SH(4)|BYTES_SH(2),                              ANYSPACE,  Unroll4Words},
3656

3657
    { CHANNELS_SH(3)|BYTES_SH(2)|DOSWAP_SH(1),                 ANYSPACE,  Unroll3WordsSwap},
3658
    { CHANNELS_SH(3)|BYTES_SH(2)|EXTRA_SH(1)|SWAPFIRST_SH(1),  ANYSPACE,  Unroll3WordsSkip1SwapFirst},
3659
    { CHANNELS_SH(3)|BYTES_SH(2)|EXTRA_SH(1)|DOSWAP_SH(1),     ANYSPACE,  Unroll3WordsSkip1Swap},
3660
    { CHANNELS_SH(4)|BYTES_SH(2)|FLAVOR_SH(1),                 ANYSPACE,  Unroll4WordsReverse},
3661
    { CHANNELS_SH(4)|BYTES_SH(2)|SWAPFIRST_SH(1),              ANYSPACE,  Unroll4WordsSwapFirst},
3662
    { CHANNELS_SH(4)|BYTES_SH(2)|DOSWAP_SH(1),                 ANYSPACE,  Unroll4WordsSwap},
3663
    { CHANNELS_SH(4)|BYTES_SH(2)|DOSWAP_SH(1)|SWAPFIRST_SH(1), ANYSPACE,  Unroll4WordsSwapSwapFirst},
3664

3665

3666
    { BYTES_SH(2)|PLANAR_SH(1),  ANYFLAVOR|ANYSWAP|ANYENDIAN|ANYEXTRA|ANYCHANNELS|ANYSPACE,  UnrollPlanarWords},
3667
    { BYTES_SH(2),  ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|ANYENDIAN|ANYEXTRA|ANYCHANNELS|ANYSPACE,  UnrollAnyWords},
3668

3669
    { BYTES_SH(2)|PLANAR_SH(1),  ANYFLAVOR|ANYSWAP|ANYENDIAN|ANYEXTRA|ANYCHANNELS|ANYSPACE|PREMUL_SH(1),  UnrollPlanarWordsPremul},
3670
    { BYTES_SH(2),  ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|ANYENDIAN|ANYEXTRA|ANYCHANNELS|ANYSPACE|PREMUL_SH(1),  UnrollAnyWordsPremul}
3671

3672
};
3673

3674

3675

3676
static const cmsFormattersFloat InputFormattersFloat[] = {
3677

3678
    //    Type                                          Mask                  Function
3679
    //  ----------------------------   ------------------------------------  ----------------------------
3680
    {     TYPE_Lab_DBL,                                ANYPLANAR|ANYEXTRA,   UnrollLabDoubleToFloat},
3681
    {     TYPE_Lab_FLT,                                ANYPLANAR|ANYEXTRA,   UnrollLabFloatToFloat},
3682

3683
    {     TYPE_XYZ_DBL,                                ANYPLANAR|ANYEXTRA,   UnrollXYZDoubleToFloat},
3684
    {     TYPE_XYZ_FLT,                                ANYPLANAR|ANYEXTRA,   UnrollXYZFloatToFloat},
3685

3686
    {     FLOAT_SH(1)|BYTES_SH(4), ANYPLANAR|ANYSWAPFIRST|ANYSWAP|ANYEXTRA|
3687
                                            ANYPREMUL|ANYCHANNELS|ANYSPACE,  UnrollFloatsToFloat},
3688

3689
    {     FLOAT_SH(1)|BYTES_SH(0), ANYPLANAR|ANYSWAPFIRST|ANYSWAP|ANYEXTRA|
3690
                                              ANYCHANNELS|ANYSPACE|ANYPREMUL, UnrollDoublesToFloat},
3691

3692
    {     TYPE_LabV2_8,                                                   0,  UnrollLabV2_8ToFloat },
3693
    {     TYPE_ALabV2_8,                                                  0,  UnrollALabV2_8ToFloat },
3694
    {     TYPE_LabV2_16,                                                  0,  UnrollLabV2_16ToFloat },
3695

3696
    {     BYTES_SH(1),              ANYPLANAR|ANYSWAPFIRST|ANYSWAP|ANYEXTRA|
3697
                                                        ANYCHANNELS|ANYSPACE, Unroll8ToFloat},
3698

3699
    {     BYTES_SH(2),              ANYPLANAR|ANYSWAPFIRST|ANYSWAP|ANYEXTRA|
3700
                                                        ANYCHANNELS|ANYSPACE, Unroll16ToFloat},
3701
#ifndef CMS_NO_HALF_SUPPORT
3702
    {     FLOAT_SH(1)|BYTES_SH(2), ANYPLANAR|ANYSWAPFIRST|ANYSWAP|ANYEXTRA|
3703
                                                        ANYCHANNELS|ANYSPACE, UnrollHalfToFloat},
3704
#endif
3705
};
3706

3707

3708
// Bit fields set to one in the mask are not compared
3709
static
3710
cmsFormatter _cmsGetStockInputFormatter(cmsUInt32Number dwInput, cmsUInt32Number dwFlags)
3711
{
3712
    cmsUInt32Number i;
3713
    cmsFormatter fr;
3714

3715
    switch (dwFlags) {
3716

3717
    case CMS_PACK_FLAGS_16BITS: {
3718
        for (i=0; i < sizeof(InputFormatters16) / sizeof(cmsFormatters16); i++) {
3719
            const cmsFormatters16* f = InputFormatters16 + i;
3720

3721
            if ((dwInput & ~f ->Mask) == f ->Type) {
3722
                fr.Fmt16 = f ->Frm;
3723
                return fr;
3724
            }
3725
        }
3726
    }
3727
    break;
3728

3729
    case CMS_PACK_FLAGS_FLOAT: {
3730
        for (i=0; i < sizeof(InputFormattersFloat) / sizeof(cmsFormattersFloat); i++) {
3731
            const cmsFormattersFloat* f = InputFormattersFloat + i;
3732

3733
            if ((dwInput & ~f ->Mask) == f ->Type) {
3734
                fr.FmtFloat = f ->Frm;
3735
                return fr;
3736
            }
3737
        }
3738
    }
3739
    break;
3740

3741
    default:;
3742

3743
    }
3744

3745
    fr.Fmt16 = NULL;
3746
    return fr;
3747
}
3748

3749
static const cmsFormatters16 OutputFormatters16[] = {
3750
    //    Type                                          Mask                  Function
3751
    //  ----------------------------   ------------------------------------  ----------------------------
3752

3753
    { TYPE_Lab_DBL,                                      ANYPLANAR|ANYEXTRA,  PackLabDoubleFrom16},
3754
    { TYPE_XYZ_DBL,                                      ANYPLANAR|ANYEXTRA,  PackXYZDoubleFrom16},
3755

3756
    { TYPE_Lab_FLT,                                      ANYPLANAR|ANYEXTRA,  PackLabFloatFrom16},
3757
    { TYPE_XYZ_FLT,                                      ANYPLANAR|ANYEXTRA,  PackXYZFloatFrom16},
3758

3759
    { FLOAT_SH(1)|BYTES_SH(0),      ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|
3760
                                    ANYCHANNELS|ANYPLANAR|ANYEXTRA|ANYSPACE,  PackDoubleFrom16},
3761
    { FLOAT_SH(1)|BYTES_SH(4),      ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|
3762
                                    ANYCHANNELS|ANYPLANAR|ANYEXTRA|ANYSPACE,  PackFloatFrom16},
3763
#ifndef CMS_NO_HALF_SUPPORT
3764
    { FLOAT_SH(1)|BYTES_SH(2),      ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|
3765
                                    ANYCHANNELS|ANYPLANAR|ANYEXTRA|ANYSPACE,  PackHalfFrom16},
3766
#endif
3767

3768
    { CHANNELS_SH(1)|BYTES_SH(1),                                  ANYSPACE,  Pack1Byte},
3769
    { CHANNELS_SH(1)|BYTES_SH(1)|EXTRA_SH(1),                      ANYSPACE,  Pack1ByteSkip1},
3770
    { CHANNELS_SH(1)|BYTES_SH(1)|EXTRA_SH(1)|SWAPFIRST_SH(1),      ANYSPACE,  Pack1ByteSkip1SwapFirst},
3771

3772
    { CHANNELS_SH(1)|BYTES_SH(1)|FLAVOR_SH(1),                     ANYSPACE,  Pack1ByteReversed},
3773

3774
    { TYPE_LabV2_8,                                                       0,  PackLabV2_8 },
3775
    { TYPE_ALabV2_8,                                                      0,  PackALabV2_8 },
3776
    { TYPE_LabV2_16,                                                      0,  PackLabV2_16 },
3777

3778
    { CHANNELS_SH(3)|BYTES_SH(1)|OPTIMIZED_SH(1),                  ANYSPACE,  Pack3BytesOptimized},
3779
    { CHANNELS_SH(3)|BYTES_SH(1)|EXTRA_SH(1)|OPTIMIZED_SH(1),      ANYSPACE,  Pack3BytesAndSkip1Optimized},
3780
    { CHANNELS_SH(3)|BYTES_SH(1)|EXTRA_SH(1)|SWAPFIRST_SH(1)|OPTIMIZED_SH(1),
3781
                                                                   ANYSPACE,  Pack3BytesAndSkip1SwapFirstOptimized},
3782
    { CHANNELS_SH(3)|BYTES_SH(1)|EXTRA_SH(1)|DOSWAP_SH(1)|SWAPFIRST_SH(1)|OPTIMIZED_SH(1),
3783
                                                                   ANYSPACE,  Pack3BytesAndSkip1SwapSwapFirstOptimized},
3784
    { CHANNELS_SH(3)|BYTES_SH(1)|DOSWAP_SH(1)|EXTRA_SH(1)|OPTIMIZED_SH(1),
3785
                                                                   ANYSPACE,  Pack3BytesAndSkip1SwapOptimized},
3786
    { CHANNELS_SH(3)|BYTES_SH(1)|DOSWAP_SH(1)|OPTIMIZED_SH(1),     ANYSPACE,  Pack3BytesSwapOptimized},
3787

3788

3789

3790
    { CHANNELS_SH(3)|BYTES_SH(1),                                  ANYSPACE,  Pack3Bytes},
3791
    { CHANNELS_SH(3)|BYTES_SH(1)|EXTRA_SH(1),                      ANYSPACE,  Pack3BytesAndSkip1},
3792
    { CHANNELS_SH(3)|BYTES_SH(1)|EXTRA_SH(1)|SWAPFIRST_SH(1),      ANYSPACE,  Pack3BytesAndSkip1SwapFirst},
3793
    { CHANNELS_SH(3)|BYTES_SH(1)|EXTRA_SH(1)|DOSWAP_SH(1)|SWAPFIRST_SH(1),
3794
                                                                   ANYSPACE,  Pack3BytesAndSkip1SwapSwapFirst},
3795
    { CHANNELS_SH(3)|BYTES_SH(1)|DOSWAP_SH(1)|EXTRA_SH(1),         ANYSPACE,  Pack3BytesAndSkip1Swap},
3796
    { CHANNELS_SH(3)|BYTES_SH(1)|DOSWAP_SH(1),                     ANYSPACE,  Pack3BytesSwap},
3797
    { CHANNELS_SH(4)|BYTES_SH(1),                                  ANYSPACE,  Pack4Bytes},
3798
    { CHANNELS_SH(4)|BYTES_SH(1)|FLAVOR_SH(1),                     ANYSPACE,  Pack4BytesReverse},
3799
    { CHANNELS_SH(4)|BYTES_SH(1)|SWAPFIRST_SH(1),                  ANYSPACE,  Pack4BytesSwapFirst},
3800
    { CHANNELS_SH(4)|BYTES_SH(1)|DOSWAP_SH(1),                     ANYSPACE,  Pack4BytesSwap},
3801
    { CHANNELS_SH(4)|BYTES_SH(1)|DOSWAP_SH(1)|SWAPFIRST_SH(1),     ANYSPACE,  Pack4BytesSwapSwapFirst},
3802
    { CHANNELS_SH(6)|BYTES_SH(1),                                  ANYSPACE,  Pack6Bytes},
3803
    { CHANNELS_SH(6)|BYTES_SH(1)|DOSWAP_SH(1),                     ANYSPACE,  Pack6BytesSwap},
3804

3805
    { BYTES_SH(1),    ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|ANYEXTRA|ANYCHANNELS|
3806
                                                          ANYSPACE|ANYPREMUL, PackChunkyBytes},
3807

3808
    { BYTES_SH(1)|PLANAR_SH(1),    ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|ANYEXTRA|
3809
                                              ANYCHANNELS|ANYSPACE|ANYPREMUL, PackPlanarBytes},
3810

3811

3812
    { CHANNELS_SH(1)|BYTES_SH(2),                                  ANYSPACE,  Pack1Word},
3813
    { CHANNELS_SH(1)|BYTES_SH(2)|EXTRA_SH(1),                      ANYSPACE,  Pack1WordSkip1},
3814
    { CHANNELS_SH(1)|BYTES_SH(2)|EXTRA_SH(1)|SWAPFIRST_SH(1),      ANYSPACE,  Pack1WordSkip1SwapFirst},
3815
    { CHANNELS_SH(1)|BYTES_SH(2)|FLAVOR_SH(1),                     ANYSPACE,  Pack1WordReversed},
3816
    { CHANNELS_SH(1)|BYTES_SH(2)|ENDIAN16_SH(1),                   ANYSPACE,  Pack1WordBigEndian},
3817
    { CHANNELS_SH(3)|BYTES_SH(2),                                  ANYSPACE,  Pack3Words},
3818
    { CHANNELS_SH(3)|BYTES_SH(2)|DOSWAP_SH(1),                     ANYSPACE,  Pack3WordsSwap},
3819
    { CHANNELS_SH(3)|BYTES_SH(2)|ENDIAN16_SH(1),                   ANYSPACE,  Pack3WordsBigEndian},
3820
    { CHANNELS_SH(3)|BYTES_SH(2)|EXTRA_SH(1),                      ANYSPACE,  Pack3WordsAndSkip1},
3821
    { CHANNELS_SH(3)|BYTES_SH(2)|EXTRA_SH(1)|DOSWAP_SH(1),         ANYSPACE,  Pack3WordsAndSkip1Swap},
3822
    { CHANNELS_SH(3)|BYTES_SH(2)|EXTRA_SH(1)|SWAPFIRST_SH(1),      ANYSPACE,  Pack3WordsAndSkip1SwapFirst},
3823

3824
    { CHANNELS_SH(3)|BYTES_SH(2)|EXTRA_SH(1)|DOSWAP_SH(1)|SWAPFIRST_SH(1),
3825
                                                                   ANYSPACE,  Pack3WordsAndSkip1SwapSwapFirst},
3826

3827
    { CHANNELS_SH(4)|BYTES_SH(2),                                  ANYSPACE,  Pack4Words},
3828
    { CHANNELS_SH(4)|BYTES_SH(2)|FLAVOR_SH(1),                     ANYSPACE,  Pack4WordsReverse},
3829
    { CHANNELS_SH(4)|BYTES_SH(2)|DOSWAP_SH(1),                     ANYSPACE,  Pack4WordsSwap},
3830
    { CHANNELS_SH(4)|BYTES_SH(2)|ENDIAN16_SH(1),                   ANYSPACE,  Pack4WordsBigEndian},
3831

3832
    { CHANNELS_SH(6)|BYTES_SH(2),                                  ANYSPACE,  Pack6Words},
3833
    { CHANNELS_SH(6)|BYTES_SH(2)|DOSWAP_SH(1),                     ANYSPACE,  Pack6WordsSwap},
3834

3835
    { BYTES_SH(2),                  ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|ANYENDIAN|
3836
                                     ANYEXTRA|ANYCHANNELS|ANYSPACE|ANYPREMUL, PackChunkyWords},
3837
    { BYTES_SH(2)|PLANAR_SH(1),     ANYFLAVOR|ANYENDIAN|ANYSWAP|ANYEXTRA|
3838
                                     ANYCHANNELS|ANYSPACE|ANYPREMUL,          PackPlanarWords}
3839

3840
};
3841

3842

3843
static const cmsFormattersFloat OutputFormattersFloat[] = {
3844
    //    Type                                          Mask                                 Function
3845
    //  ----------------------------   ---------------------------------------------------  ----------------------------
3846
    {     TYPE_Lab_FLT,                                                ANYPLANAR|ANYEXTRA,   PackLabFloatFromFloat},
3847
    {     TYPE_XYZ_FLT,                                                ANYPLANAR|ANYEXTRA,   PackXYZFloatFromFloat},
3848

3849
    {     TYPE_Lab_DBL,                                                ANYPLANAR|ANYEXTRA,   PackLabDoubleFromFloat},
3850
    {     TYPE_XYZ_DBL,                                                ANYPLANAR|ANYEXTRA,   PackXYZDoubleFromFloat},
3851

3852
    {     TYPE_LabV2_8,                                                ANYPLANAR|ANYEXTRA,   PackEncodedBytesLabV2FromFloat},
3853
    {     TYPE_LabV2_16,                                               ANYPLANAR|ANYEXTRA,   PackEncodedWordsLabV2FromFloat},
3854

3855
    {     FLOAT_SH(1)|BYTES_SH(4), ANYPLANAR|
3856
                             ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|ANYEXTRA|ANYCHANNELS|ANYSPACE,   PackFloatsFromFloat },
3857
    {     FLOAT_SH(1)|BYTES_SH(0), ANYPLANAR|
3858
                             ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|ANYEXTRA|ANYCHANNELS|ANYSPACE,   PackDoublesFromFloat },
3859

3860
    {     BYTES_SH(2), ANYPLANAR|
3861
                             ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|ANYEXTRA|ANYCHANNELS|ANYSPACE,   PackWordsFromFloat },
3862

3863
    {     BYTES_SH(1), ANYPLANAR|
3864
                             ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|ANYEXTRA|ANYCHANNELS|ANYSPACE,   PackBytesFromFloat },
3865

3866
#ifndef CMS_NO_HALF_SUPPORT
3867
    {     FLOAT_SH(1)|BYTES_SH(2),
3868
                             ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|ANYEXTRA|ANYCHANNELS|ANYSPACE,   PackHalfFromFloat },
3869
#endif
3870

3871
};
3872

3873

3874
// Bit fields set to one in the mask are not compared
3875
static
3876
cmsFormatter _cmsGetStockOutputFormatter(cmsUInt32Number dwInput, cmsUInt32Number dwFlags)
3877
{
3878
    cmsUInt32Number i;
3879
    cmsFormatter fr;
3880

3881
    // Optimization is only a hint
3882
    dwInput &= ~OPTIMIZED_SH(1);
3883

3884
    switch (dwFlags)
3885
    {
3886

3887
     case CMS_PACK_FLAGS_16BITS: {
3888

3889
        for (i=0; i < sizeof(OutputFormatters16) / sizeof(cmsFormatters16); i++) {
3890
            const cmsFormatters16* f = OutputFormatters16 + i;
3891

3892
            if ((dwInput & ~f ->Mask) == f ->Type) {
3893
                fr.Fmt16 = f ->Frm;
3894
                return fr;
3895
            }
3896
        }
3897
        }
3898
        break;
3899

3900
    case CMS_PACK_FLAGS_FLOAT: {
3901

3902
        for (i=0; i < sizeof(OutputFormattersFloat) / sizeof(cmsFormattersFloat); i++) {
3903
            const cmsFormattersFloat* f = OutputFormattersFloat + i;
3904

3905
            if ((dwInput & ~f ->Mask) == f ->Type) {
3906
                fr.FmtFloat = f ->Frm;
3907
                return fr;
3908
            }
3909
        }
3910
        }
3911
        break;
3912

3913
    default:;
3914

3915
    }
3916

3917
    fr.Fmt16 = NULL;
3918
    return fr;
3919
}
3920

3921

3922
typedef struct _cms_formatters_factory_list {
3923

3924
    cmsFormatterFactory Factory;
3925
    struct _cms_formatters_factory_list *Next;
3926

3927
} cmsFormattersFactoryList;
3928

3929
_cmsFormattersPluginChunkType _cmsFormattersPluginChunk = { NULL };
3930

3931

3932
// Duplicates the zone of memory used by the plug-in in the new context
3933
static
3934
void DupFormatterFactoryList(struct _cmsContext_struct* ctx,
3935
                                               const struct _cmsContext_struct* src)
3936
{
3937
   _cmsFormattersPluginChunkType newHead = { NULL };
3938
   cmsFormattersFactoryList*  entry;
3939
   cmsFormattersFactoryList*  Anterior = NULL;
3940
   _cmsFormattersPluginChunkType* head = (_cmsFormattersPluginChunkType*) src->chunks[FormattersPlugin];
3941

3942
     _cmsAssert(head != NULL);
3943

3944
   // Walk the list copying all nodes
3945
   for (entry = head->FactoryList;
3946
       entry != NULL;
3947
       entry = entry ->Next) {
3948

3949
           cmsFormattersFactoryList *newEntry = ( cmsFormattersFactoryList *) _cmsSubAllocDup(ctx ->MemPool, entry, sizeof(cmsFormattersFactoryList));
3950

3951
           if (newEntry == NULL)
3952
               return;
3953

3954
           // We want to keep the linked list order, so this is a little bit tricky
3955
           newEntry -> Next = NULL;
3956
           if (Anterior)
3957
               Anterior -> Next = newEntry;
3958

3959
           Anterior = newEntry;
3960

3961
           if (newHead.FactoryList == NULL)
3962
               newHead.FactoryList = newEntry;
3963
   }
3964

3965
   ctx ->chunks[FormattersPlugin] = _cmsSubAllocDup(ctx->MemPool, &newHead, sizeof(_cmsFormattersPluginChunkType));
3966
}
3967

3968
// The interpolation plug-in memory chunk allocator/dup
3969
void _cmsAllocFormattersPluginChunk(struct _cmsContext_struct* ctx,
3970
                                    const struct _cmsContext_struct* src)
3971
{
3972
      _cmsAssert(ctx != NULL);
3973

3974
     if (src != NULL) {
3975

3976
         // Duplicate the LIST
3977
         DupFormatterFactoryList(ctx, src);
3978
     }
3979
     else {
3980
          static _cmsFormattersPluginChunkType FormattersPluginChunk = { NULL };
3981
          ctx ->chunks[FormattersPlugin] = _cmsSubAllocDup(ctx ->MemPool, &FormattersPluginChunk, sizeof(_cmsFormattersPluginChunkType));
3982
     }
3983
}
3984

3985

3986

3987
// Formatters management
3988
cmsBool  _cmsRegisterFormattersPlugin(cmsContext ContextID, cmsPluginBase* Data)
3989
{
3990
    _cmsFormattersPluginChunkType* ctx = ( _cmsFormattersPluginChunkType*) _cmsContextGetClientChunk(ContextID, FormattersPlugin);
3991
    cmsPluginFormatters* Plugin = (cmsPluginFormatters*) Data;
3992
    cmsFormattersFactoryList* fl ;
3993

3994
    // Reset to built-in defaults
3995
    if (Data == NULL) {
3996

3997
          ctx ->FactoryList = NULL;
3998
          return TRUE;
3999
    }
4000

4001
    fl = (cmsFormattersFactoryList*) _cmsPluginMalloc(ContextID, sizeof(cmsFormattersFactoryList));
4002
    if (fl == NULL) return FALSE;
4003

4004
    fl ->Factory    = Plugin ->FormattersFactory;
4005

4006
    fl ->Next = ctx -> FactoryList;
4007
    ctx ->FactoryList = fl;
4008

4009
    return TRUE;
4010
}
4011

4012
cmsFormatter CMSEXPORT _cmsGetFormatter(cmsContext ContextID,
4013
                                        cmsUInt32Number Type,         // Specific type, i.e. TYPE_RGB_8
4014
                                        cmsFormatterDirection Dir,
4015
                                        cmsUInt32Number dwFlags)
4016
{
4017
    _cmsFormattersPluginChunkType* ctx = ( _cmsFormattersPluginChunkType*) _cmsContextGetClientChunk(ContextID, FormattersPlugin);
4018
    cmsFormattersFactoryList* f;
4019

4020
    if (T_CHANNELS(Type) == 0) {
4021
        static const cmsFormatter nullFormatter = { 0 };
4022
        return nullFormatter;
4023
    }
4024

4025
    for (f =ctx->FactoryList; f != NULL; f = f ->Next) {
4026

4027
        cmsFormatter fn = f ->Factory(Type, Dir, dwFlags);
4028
        if (fn.Fmt16 != NULL) return fn;
4029
    }
4030

4031
    // Revert to default
4032
    if (Dir == cmsFormatterInput)
4033
        return _cmsGetStockInputFormatter(Type, dwFlags);
4034
    else
4035
        return _cmsGetStockOutputFormatter(Type, dwFlags);
4036
}
4037

4038

4039
// Return whatever given formatter refers to float values
4040
cmsBool  _cmsFormatterIsFloat(cmsUInt32Number Type)
4041
{
4042
    return T_FLOAT(Type) ? TRUE : FALSE;
4043
}
4044

4045
// Return whatever given formatter refers to 8 bits
4046
cmsBool  _cmsFormatterIs8bit(cmsUInt32Number Type)
4047
{
4048
    cmsUInt32Number Bytes = T_BYTES(Type);
4049

4050
    return (Bytes == 1);
4051
}
4052

4053
// Build a suitable formatter for the colorspace of this profile
4054
cmsUInt32Number CMSEXPORT cmsFormatterForColorspaceOfProfile(cmsHPROFILE hProfile, cmsUInt32Number nBytes, cmsBool lIsFloat)
4055
{
4056

4057
    cmsColorSpaceSignature ColorSpace      = cmsGetColorSpace(hProfile);
4058
    cmsUInt32Number        ColorSpaceBits  = (cmsUInt32Number) _cmsLCMScolorSpace(ColorSpace);
4059
    cmsInt32Number         nOutputChans    = cmsChannelsOfColorSpace(ColorSpace);
4060
    cmsUInt32Number        Float           = lIsFloat ? 1U : 0;
4061

4062
    // Unsupported color space?
4063
    if (nOutputChans < 0) return 0;
4064

4065
    // Create a fake formatter for result
4066
    return FLOAT_SH(Float) | COLORSPACE_SH(ColorSpaceBits) | BYTES_SH(nBytes) | CHANNELS_SH(nOutputChans);
4067
}
4068

4069
// Build a suitable formatter for the colorspace of this profile
4070
cmsUInt32Number CMSEXPORT cmsFormatterForPCSOfProfile(cmsHPROFILE hProfile, cmsUInt32Number nBytes, cmsBool lIsFloat)
4071
{
4072

4073
    cmsColorSpaceSignature ColorSpace = cmsGetPCS(hProfile);
4074

4075
    cmsUInt32Number ColorSpaceBits = (cmsUInt32Number) _cmsLCMScolorSpace(ColorSpace);
4076
    cmsInt32Number  nOutputChans = cmsChannelsOfColorSpace(ColorSpace);
4077
    cmsUInt32Number Float = lIsFloat ? 1U : 0;
4078

4079
    // Unsupported color space?
4080
    if (nOutputChans < 0) return 0;
4081

4082
    // Create a fake formatter for result
4083
    return FLOAT_SH(Float) | COLORSPACE_SH(ColorSpaceBits) | BYTES_SH(nBytes) | CHANNELS_SH(nOutputChans);
4084
}
4085

4086

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.