1/*
2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
3 *
4 * This code is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 2 only, as
6 * published by the Free Software Foundation.  Oracle designates this
7 * particular file as subject to the "Classpath" exception as provided
8 * by Oracle in the LICENSE file that accompanied this code.
9 *
10 * This code is distributed in the hope that it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
13 * version 2 for more details (a copy is included in the LICENSE file that
14 * accompanied this code).
15 *
16 * You should have received a copy of the GNU General Public License version
17 * 2 along with this work; if not, write to the Free Software Foundation,
18 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
19 *
20 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
21 * or visit www.oracle.com if you need additional information or have any
22 * questions.
23 */
24
25// This file is available under and governed by the GNU General Public
26// License version 2 only, as published by the Free Software Foundation.
27// However, the following notice accompanied the original version of this
28// file:
29//
30//---------------------------------------------------------------------------------
31//
32//  Little Color Management System
33//  Copyright (c) 1998-2016 Marti Maria Saguer
34//
35// Permission is hereby granted, free of charge, to any person obtaining
36// a copy of this software and associated documentation files (the "Software"),
37// to deal in the Software without restriction, including without limitation
38// the rights to use, copy, modify, merge, publish, distribute, sublicense,
39// and/or sell copies of the Software, and to permit persons to whom the Software
40// is furnished to do so, subject to the following conditions:
41//
42// The above copyright notice and this permission notice shall be included in
43// all copies or substantial portions of the Software.
44//
45// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
46// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
47// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
48// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
49// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
50// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
51// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
52//
53//---------------------------------------------------------------------------------
54//
55
56#include "lcms2_internal.h"
57
58
59// Alpha copy ------------------------------------------------------------------------------------------------------------------
60
61// Floor to byte, taking care of saturation
62cmsINLINE cmsUInt8Number _cmsQuickSaturateByte(cmsFloat64Number d)
63{
64       d += 0.5;
65       if (d <= 0) return 0;
66       if (d >= 255.0) return 255;
67
68       return (cmsUInt8Number) _cmsQuickFloorWord(d);
69}
70
71
72// Return the size in bytes of a given formatter
73static
74int trueBytesSize(cmsUInt32Number Format)
75{
76       int fmt_bytes = T_BYTES(Format);
77
78       // For double, the T_BYTES field returns zero
79       if (fmt_bytes == 0)
80              return sizeof(double);
81
82       // Otherwise, it is already correct for all formats
83       return fmt_bytes;
84}
85
86
87// Several format converters
88
89typedef void(*cmsFormatterAlphaFn)(void* dst, const void* src);
90
91
92// From 8
93
94static
95void copy8(void* dst, const void* src)
96{
97       memmove(dst, src, 1);
98}
99
100static
101void from8to16(void* dst, const void* src)
102{
103       cmsUInt8Number n = *(cmsUInt8Number*)src;
104       *(cmsUInt16Number*) dst = FROM_8_TO_16(n);
105}
106
107static
108void from8toFLT(void* dst, const void* src)
109{
110       *(cmsFloat32Number*)dst = (*(cmsUInt8Number*)src) / 255.0f;
111}
112
113static
114void from8toDBL(void* dst, const void* src)
115{
116       *(cmsFloat64Number*)dst = (*(cmsUInt8Number*)src) / 255.0;
117}
118
119static
120void from8toHLF(void* dst, const void* src)
121{
122       cmsFloat32Number n = (*(cmsUInt8Number*)src) / 255.0f;
123       *(cmsUInt16Number*)dst = _cmsFloat2Half(n);
124}
125
126// From 16
127
128static
129void from16to8(void* dst, const void* src)
130{
131       cmsUInt16Number n = *(cmsUInt16Number*)src;
132       *(cmsUInt8Number*) dst = FROM_16_TO_8(n);
133}
134
135static
136void copy16(void* dst, const void* src)
137{
138       memmove(dst, src, 2);
139}
140
141void from16toFLT(void* dst, const void* src)
142{
143       *(cmsFloat32Number*)dst = (*(cmsUInt16Number*)src) / 65535.0f;
144}
145
146void from16toDBL(void* dst, const void* src)
147{
148       *(cmsFloat64Number*)dst = (*(cmsUInt16Number*)src) / 65535.0f;
149}
150
151static
152void from16toHLF(void* dst, const void* src)
153{
154       cmsFloat32Number n = (*(cmsUInt16Number*)src) / 65535.0f;
155       *(cmsUInt16Number*)dst = _cmsFloat2Half(n);
156}
157
158// From Float
159
160static
161void fromFLTto8(void* dst, const void* src)
162{
163       cmsFloat32Number n = *(cmsFloat32Number*)src;
164       *(cmsUInt8Number*)dst = _cmsQuickSaturateByte(n * 255.0f);
165}
166
167static
168void fromFLTto16(void* dst, const void* src)
169{
170       cmsFloat32Number n = *(cmsFloat32Number*)src;
171       *(cmsUInt16Number*)dst = _cmsQuickSaturateWord(n * 65535.0f);
172}
173
174static
175void copy32(void* dst, const void* src)
176{
177       memmove(dst, src, sizeof(cmsFloat32Number));
178}
179
180static
181void fromFLTtoDBL(void* dst, const void* src)
182{
183       cmsFloat32Number n = *(cmsFloat32Number*)src;
184       *(cmsFloat64Number*)dst = (cmsFloat64Number)n;
185}
186
187static
188void fromFLTtoHLF(void* dst, const void* src)
189{
190       cmsFloat32Number n = *(cmsFloat32Number*)src;
191       *(cmsUInt16Number*)dst = _cmsFloat2Half(n);
192}
193
194
195// From HALF
196
197static
198void fromHLFto8(void* dst, const void* src)
199{
200       cmsFloat32Number n = _cmsHalf2Float(*(cmsUInt16Number*)src);
201       *(cmsUInt8Number*)dst = _cmsQuickSaturateByte(n * 255.0f);
202}
203
204static
205void fromHLFto16(void* dst, const void* src)
206{
207       cmsFloat32Number n = _cmsHalf2Float(*(cmsUInt16Number*)src);
208       *(cmsUInt16Number*)dst = _cmsQuickSaturateWord(n * 65535.0f);
209}
210
211static
212void fromHLFtoFLT(void* dst, const void* src)
213{
214       *(cmsFloat32Number*)dst = _cmsHalf2Float(*(cmsUInt16Number*)src);
215}
216
217static
218void fromHLFtoDBL(void* dst, const void* src)
219{
220       *(cmsFloat64Number*)dst = (cmsFloat64Number)_cmsHalf2Float(*(cmsUInt16Number*)src);
221}
222
223// From double
224static
225void fromDBLto8(void* dst, const void* src)
226{
227       cmsFloat64Number n = *(cmsFloat64Number*)src;
228       *(cmsUInt8Number*)dst = _cmsQuickSaturateByte(n * 255.0);
229}
230
231static
232void fromDBLto16(void* dst, const void* src)
233{
234       cmsFloat64Number n = *(cmsFloat64Number*)src;
235       *(cmsUInt16Number*)dst = _cmsQuickSaturateWord(n * 65535.0f);
236}
237
238static
239void fromDBLtoFLT(void* dst, const void* src)
240{
241       cmsFloat64Number n = *(cmsFloat64Number*)src;
242       *(cmsFloat32Number*)dst = (cmsFloat32Number) n;
243}
244
245static
246void fromDBLtoHLF(void* dst, const void* src)
247{
248       cmsFloat32Number n = (cmsFloat32Number) *(cmsFloat64Number*)src;
249       *(cmsUInt16Number*)dst = _cmsFloat2Half(n);
250}
251
252static
253void copy64(void* dst, const void* src)
254{
255       memmove(dst, src, sizeof(cmsFloat64Number));
256}
257
258
259// Returns the position (x or y) of the formatter in the table of functions
260static
261int FormatterPos(cmsUInt32Number frm)
262{
263       int  b = T_BYTES(frm);
264
265       if (b == 0 && T_FLOAT(frm))
266              return 4; // DBL
267       if (b == 2 && T_FLOAT(frm))
268              return 2; // HLF
269       if (b == 4 && T_FLOAT(frm))
270              return 3; // FLT
271       if (b == 2 && !T_FLOAT(frm))
272              return 1; // 16
273       if (b == 1 && !T_FLOAT(frm))
274              return 0; // 8
275
276       return -1; // not recognized
277
278}
279
280// Obtains a alpha-to-alpha funmction formatter
281static
282cmsFormatterAlphaFn _cmsGetFormatterAlpha(cmsContext id, cmsUInt32Number in, cmsUInt32Number out)
283{
284static cmsFormatterAlphaFn FormattersAlpha[5][5] = {
285
286       /* from 8 */  { copy8,      from8to16,   from8toHLF,   from8toFLT,   from8toDBL   },
287       /* from 16*/  { from16to8,  copy16,      from16toHLF,  from16toFLT,  from16toDBL  },
288       /* from HLF*/ { fromHLFto8, fromHLFto16, copy16,       fromHLFtoFLT, fromHLFtoDBL },
289       /* from FLT*/ { fromFLTto8, fromFLTto16, fromFLTtoHLF, copy32,       fromFLTtoDBL },
290       /* from DBL*/ { fromDBLto8, fromDBLto16, fromDBLtoHLF, fromDBLtoFLT, copy64 }};
291
292        int in_n  = FormatterPos(in);
293        int out_n = FormatterPos(out);
294
295        if (in_n < 0 || out_n < 0 || in_n > 4 || out_n > 4) {
296
297               cmsSignalError(id, cmsERROR_UNKNOWN_EXTENSION, "Unrecognized alpha channel width");
298               return NULL;
299        }
300
301        return FormattersAlpha[in_n][out_n];
302}
303
304
305
306// This function computes the distance from each component to the next one in bytes.
307static
308void ComputeIncrementsForChunky(cmsUInt32Number Format,
309                                cmsUInt32Number ComponentStartingOrder[],
310                                cmsUInt32Number ComponentPointerIncrements[])
311{
312       cmsUInt32Number channels[cmsMAXCHANNELS];
313       int extra = T_EXTRA(Format);
314       int nchannels = T_CHANNELS(Format);
315       int total_chans = nchannels + extra;
316       int i;
317       int channelSize = trueBytesSize(Format);
318       int pixelSize = channelSize * total_chans;
319
320           // Sanity check
321           if (total_chans <= 0 || total_chans >= cmsMAXCHANNELS)
322                   return;
323
324        memset(channels, 0, sizeof(channels));
325
326       // Separation is independent of starting point and only depends on channel size
327       for (i = 0; i < extra; i++)
328              ComponentPointerIncrements[i] = pixelSize;
329
330       // Handle do swap
331       for (i = 0; i < total_chans; i++)
332       {
333              if (T_DOSWAP(Format)) {
334                     channels[i] = total_chans - i - 1;
335              }
336              else {
337                     channels[i] = i;
338              }
339       }
340
341       // Handle swap first (ROL of positions), example CMYK -> KCMY | 0123 -> 3012
342       if (T_SWAPFIRST(Format) && total_chans > 1) {
343
344              cmsUInt32Number tmp = channels[0];
345              for (i = 0; i < total_chans-1; i++)
346                     channels[i] = channels[i + 1];
347
348              channels[total_chans - 1] = tmp;
349       }
350
351       // Handle size
352       if (channelSize > 1)
353              for (i = 0; i < total_chans; i++) {
354                     channels[i] *= channelSize;
355              }
356
357       for (i = 0; i < extra; i++)
358              ComponentStartingOrder[i] = channels[i + nchannels];
359}
360
361
362
363//  On planar configurations, the distance is the stride added to any non-negative
364static
365void ComputeIncrementsForPlanar(cmsUInt32Number Format,
366                                cmsUInt32Number BytesPerPlane,
367                                cmsUInt32Number ComponentStartingOrder[],
368                                cmsUInt32Number ComponentPointerIncrements[])
369{
370       cmsUInt32Number channels[cmsMAXCHANNELS];
371       int extra = T_EXTRA(Format);
372       int nchannels = T_CHANNELS(Format);
373       int total_chans = nchannels + extra;
374       int i;
375       int channelSize = trueBytesSize(Format);
376
377       // Sanity check
378       if (total_chans <= 0 || total_chans >= cmsMAXCHANNELS)
379           return;
380
381       memset(channels, 0, sizeof(channels));
382
383       // Separation is independent of starting point and only depends on channel size
384       for (i = 0; i < extra; i++)
385              ComponentPointerIncrements[i] = channelSize;
386
387       // Handle do swap
388       for (i = 0; i < total_chans; i++)
389       {
390              if (T_DOSWAP(Format)) {
391                     channels[i] = total_chans - i - 1;
392              }
393              else {
394                     channels[i] = i;
395              }
396       }
397
398       // Handle swap first (ROL of positions), example CMYK -> KCMY | 0123 -> 3012
399       if (T_SWAPFIRST(Format) && total_chans > 0) {
400
401              cmsUInt32Number tmp = channels[0];
402              for (i = 0; i < total_chans - 1; i++)
403                     channels[i] = channels[i + 1];
404
405              channels[total_chans - 1] = tmp;
406       }
407
408       // Handle size
409       for (i = 0; i < total_chans; i++) {
410              channels[i] *= BytesPerPlane;
411       }
412
413       for (i = 0; i < extra; i++)
414              ComponentStartingOrder[i] = channels[i + nchannels];
415}
416
417
418
419// Dispatcher por chunky and planar RGB
420static
421void  ComputeComponentIncrements(cmsUInt32Number Format,
422                                 cmsUInt32Number BytesPerPlane,
423                                 cmsUInt32Number ComponentStartingOrder[],
424                                 cmsUInt32Number ComponentPointerIncrements[])
425{
426       if (T_PLANAR(Format)) {
427
428              ComputeIncrementsForPlanar(Format,  BytesPerPlane, ComponentStartingOrder, ComponentPointerIncrements);
429       }
430       else {
431              ComputeIncrementsForChunky(Format,  ComponentStartingOrder, ComponentPointerIncrements);
432       }
433
434}
435
436
437
438// Handles extra channels copying alpha if requested by the flags
439void _cmsHandleExtraChannels(_cmsTRANSFORM* p, const void* in,
440                                               void* out,
441                                               cmsUInt32Number PixelsPerLine,
442                                               cmsUInt32Number LineCount,
443                                               const cmsStride* Stride)
444{
445    cmsUInt32Number i, j, k;
446    cmsUInt32Number nExtra;
447    cmsUInt32Number SourceStartingOrder[cmsMAXCHANNELS];
448    cmsUInt32Number SourceIncrements[cmsMAXCHANNELS];
449    cmsUInt32Number DestStartingOrder[cmsMAXCHANNELS];
450    cmsUInt32Number DestIncrements[cmsMAXCHANNELS];
451
452    cmsFormatterAlphaFn copyValueFn;
453
454    // Make sure we need some copy
455    if (!(p->dwOriginalFlags & cmsFLAGS_COPY_ALPHA))
456        return;
457
458    // Exit early if in-place color-management is occurring - no need to copy extra channels to themselves.
459    if (p->InputFormat == p->OutputFormat && in == out)
460        return;
461
462    // Make sure we have same number of alpha channels. If not, just return as this should be checked at transform creation time.
463    nExtra = T_EXTRA(p->InputFormat);
464    if (nExtra != T_EXTRA(p->OutputFormat))
465        return;
466
467    // Anything to do?
468    if (nExtra == 0)
469        return;
470
471    // Compute the increments
472    ComputeComponentIncrements(p->InputFormat, Stride->BytesPerPlaneIn, SourceStartingOrder, SourceIncrements);
473    ComputeComponentIncrements(p->OutputFormat, Stride->BytesPerPlaneOut, DestStartingOrder, DestIncrements);
474
475    // Check for conversions 8, 16, half, float, dbl
476    copyValueFn = _cmsGetFormatterAlpha(p->ContextID, p->InputFormat, p->OutputFormat);
477
478    if (nExtra == 1) { // Optimized routine for copying a single extra channel quickly
479
480        cmsUInt8Number* SourcePtr;
481        cmsUInt8Number* DestPtr;
482
483        cmsUInt32Number SourceStrideIncrement = 0;
484        cmsUInt32Number DestStrideIncrement = 0;
485
486        // The loop itself
487        for (i = 0; i < LineCount; i++) {
488
489            // Prepare pointers for the loop
490            SourcePtr = (cmsUInt8Number*)in + SourceStartingOrder[0] + SourceStrideIncrement;
491            DestPtr = (cmsUInt8Number*)out + DestStartingOrder[0] + DestStrideIncrement;
492
493            for (j = 0; j < PixelsPerLine; j++) {
494
495                copyValueFn(DestPtr, SourcePtr);
496
497                SourcePtr += SourceIncrements[0];
498                DestPtr += DestIncrements[0];
499            }
500
501            SourceStrideIncrement += Stride->BytesPerLineIn;
502            DestStrideIncrement += Stride->BytesPerLineOut;
503        }
504
505    }
506    else { // General case with more than one extra channel
507
508        cmsUInt8Number* SourcePtr[cmsMAXCHANNELS];
509        cmsUInt8Number* DestPtr[cmsMAXCHANNELS];
510
511        cmsUInt32Number SourceStrideIncrements[cmsMAXCHANNELS];
512        cmsUInt32Number DestStrideIncrements[cmsMAXCHANNELS];
513
514        memset(SourceStrideIncrements, 0, sizeof(SourceStrideIncrements));
515        memset(DestStrideIncrements, 0, sizeof(DestStrideIncrements));
516
517        // The loop itself
518        for (i = 0; i < LineCount; i++) {
519
520            // Prepare pointers for the loop
521            for (j = 0; j < nExtra; j++) {
522
523                SourcePtr[j] = (cmsUInt8Number*)in + SourceStartingOrder[j] + SourceStrideIncrements[j];
524                DestPtr[j] = (cmsUInt8Number*)out + DestStartingOrder[j] + DestStrideIncrements[j];
525            }
526
527            for (j = 0; j < PixelsPerLine; j++) {
528
529                for (k = 0; k < nExtra; k++) {
530
531                    copyValueFn(DestPtr[k], SourcePtr[k]);
532
533                    SourcePtr[k] += SourceIncrements[k];
534                    DestPtr[k] += DestIncrements[k];
535                }
536            }
537
538            for (j = 0; j < nExtra; j++) {
539
540                SourceStrideIncrements[j] += Stride->BytesPerLineIn;
541                DestStrideIncrements[j] += Stride->BytesPerLineOut;
542            }
543        }
544    }
545}
546
547
548