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-2017 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// Alpha copy ------------------------------------------------------------------------------------------------------------------
59
60// Floor to byte, taking care of saturation
61cmsINLINE cmsUInt8Number _cmsQuickSaturateByte(cmsFloat64Number d)
62{
63 d += 0.5;
64 if (d <= 0) return 0;
65 if (d >= 255.0) return 255;
66
67 return (cmsUInt8Number) _cmsQuickFloorWord(d);
68}
69
70
71// Return the size in bytes of a given formatter
72static
73cmsUInt32Number trueBytesSize(cmsUInt32Number Format)
74{
75 cmsUInt32Number fmt_bytes = T_BYTES(Format);
76
77 // For double, the T_BYTES field returns zero
78 if (fmt_bytes == 0)
79 return sizeof(double);
80
81 // Otherwise, it is already correct for all formats
82 return fmt_bytes;
83}
84
85
86// Several format converters
87
88typedef void(*cmsFormatterAlphaFn)(void* dst, const void* src);
89
90
91// From 8
92
93static
94void copy8(void* dst, const void* src)
95{
96 memmove(dst, src, 1);
97}
98
99static
100void from8to16(void* dst, const void* src)
101{
102 cmsUInt8Number n = *(cmsUInt8Number*)src;
103 *(cmsUInt16Number*) dst = FROM_8_TO_16(n);
104}
105
106static
107void from8toFLT(void* dst, const void* src)
108{
109 *(cmsFloat32Number*)dst = (*(cmsUInt8Number*)src) / 255.0f;
110}
111
112static
113void from8toDBL(void* dst, const void* src)
114{
115 *(cmsFloat64Number*)dst = (*(cmsUInt8Number*)src) / 255.0;
116}
117
118static
119void from8toHLF(void* dst, const void* src)
120{
121#ifndef CMS_NO_HALF_SUPPORT
122 cmsFloat32Number n = (*(cmsUInt8Number*)src) / 255.0f;
123 *(cmsUInt16Number*)dst = _cmsFloat2Half(n);
124#else
125 cmsUNUSED_PARAMETER(dst);
126 cmsUNUSED_PARAMETER(src);
127#endif
128}
129
130// From 16
131
132static
133void from16to8(void* dst, const void* src)
134{
135 cmsUInt16Number n = *(cmsUInt16Number*)src;
136 *(cmsUInt8Number*) dst = FROM_16_TO_8(n);
137}
138
139static
140void copy16(void* dst, const void* src)
141{
142 memmove(dst, src, 2);
143}
144
145void from16toFLT(void* dst, const void* src)
146{
147 *(cmsFloat32Number*)dst = (*(cmsUInt16Number*)src) / 65535.0f;
148}
149
150void from16toDBL(void* dst, const void* src)
151{
152 *(cmsFloat64Number*)dst = (*(cmsUInt16Number*)src) / 65535.0f;
153}
154
155static
156void from16toHLF(void* dst, const void* src)
157{
158#ifndef CMS_NO_HALF_SUPPORT
159 cmsFloat32Number n = (*(cmsUInt16Number*)src) / 65535.0f;
160 *(cmsUInt16Number*)dst = _cmsFloat2Half(n);
161#else
162 cmsUNUSED_PARAMETER(dst);
163 cmsUNUSED_PARAMETER(src);
164#endif
165}
166
167// From Float
168
169static
170void fromFLTto8(void* dst, const void* src)
171{
172 cmsFloat32Number n = *(cmsFloat32Number*)src;
173 *(cmsUInt8Number*)dst = _cmsQuickSaturateByte(n * 255.0f);
174}
175
176static
177void fromFLTto16(void* dst, const void* src)
178{
179 cmsFloat32Number n = *(cmsFloat32Number*)src;
180 *(cmsUInt16Number*)dst = _cmsQuickSaturateWord(n * 65535.0f);
181}
182
183static
184void copy32(void* dst, const void* src)
185{
186 memmove(dst, src, sizeof(cmsFloat32Number));
187}
188
189static
190void fromFLTtoDBL(void* dst, const void* src)
191{
192 cmsFloat32Number n = *(cmsFloat32Number*)src;
193 *(cmsFloat64Number*)dst = (cmsFloat64Number)n;
194}
195
196static
197void fromFLTtoHLF(void* dst, const void* src)
198{
199#ifndef CMS_NO_HALF_SUPPORT
200 cmsFloat32Number n = *(cmsFloat32Number*)src;
201 *(cmsUInt16Number*)dst = _cmsFloat2Half(n);
202#else
203 cmsUNUSED_PARAMETER(dst);
204 cmsUNUSED_PARAMETER(src);
205#endif
206}
207
208
209// From HALF
210
211static
212void fromHLFto8(void* dst, const void* src)
213{
214#ifndef CMS_NO_HALF_SUPPORT
215 cmsFloat32Number n = _cmsHalf2Float(*(cmsUInt16Number*)src);
216 *(cmsUInt8Number*)dst = _cmsQuickSaturateByte(n * 255.0f);
217#else
218 cmsUNUSED_PARAMETER(dst);
219 cmsUNUSED_PARAMETER(src);
220#endif
221
222}
223
224static
225void fromHLFto16(void* dst, const void* src)
226{
227#ifndef CMS_NO_HALF_SUPPORT
228 cmsFloat32Number n = _cmsHalf2Float(*(cmsUInt16Number*)src);
229 *(cmsUInt16Number*)dst = _cmsQuickSaturateWord(n * 65535.0f);
230#else
231 cmsUNUSED_PARAMETER(dst);
232 cmsUNUSED_PARAMETER(src);
233#endif
234}
235
236static
237void fromHLFtoFLT(void* dst, const void* src)
238{
239#ifndef CMS_NO_HALF_SUPPORT
240 *(cmsFloat32Number*)dst = _cmsHalf2Float(*(cmsUInt16Number*)src);
241#else
242 cmsUNUSED_PARAMETER(dst);
243 cmsUNUSED_PARAMETER(src);
244#endif
245}
246
247static
248void fromHLFtoDBL(void* dst, const void* src)
249{
250#ifndef CMS_NO_HALF_SUPPORT
251 *(cmsFloat64Number*)dst = (cmsFloat64Number)_cmsHalf2Float(*(cmsUInt16Number*)src);
252#else
253 cmsUNUSED_PARAMETER(dst);
254 cmsUNUSED_PARAMETER(src);
255#endif
256}
257
258// From double
259static
260void fromDBLto8(void* dst, const void* src)
261{
262 cmsFloat64Number n = *(cmsFloat64Number*)src;
263 *(cmsUInt8Number*)dst = _cmsQuickSaturateByte(n * 255.0);
264}
265
266static
267void fromDBLto16(void* dst, const void* src)
268{
269 cmsFloat64Number n = *(cmsFloat64Number*)src;
270 *(cmsUInt16Number*)dst = _cmsQuickSaturateWord(n * 65535.0f);
271}
272
273static
274void fromDBLtoFLT(void* dst, const void* src)
275{
276 cmsFloat64Number n = *(cmsFloat64Number*)src;
277 *(cmsFloat32Number*)dst = (cmsFloat32Number) n;
278}
279
280static
281void fromDBLtoHLF(void* dst, const void* src)
282{
283#ifndef CMS_NO_HALF_SUPPORT
284 cmsFloat32Number n = (cmsFloat32Number) *(cmsFloat64Number*)src;
285 *(cmsUInt16Number*)dst = _cmsFloat2Half(n);
286#else
287 cmsUNUSED_PARAMETER(dst);
288 cmsUNUSED_PARAMETER(src);
289#endif
290}
291
292static
293void copy64(void* dst, const void* src)
294{
295 memmove(dst, src, sizeof(cmsFloat64Number));
296}
297
298
299// Returns the position (x or y) of the formatter in the table of functions
300static
301int FormatterPos(cmsUInt32Number frm)
302{
303 cmsUInt32Number b = T_BYTES(frm);
304
305 if (b == 0 && T_FLOAT(frm))
306 return 4; // DBL
307#ifndef CMS_NO_HALF_SUPPORT
308 if (b == 2 && T_FLOAT(frm))
309 return 2; // HLF
310#endif
311 if (b == 4 && T_FLOAT(frm))
312 return 3; // FLT
313 if (b == 2 && !T_FLOAT(frm))
314 return 1; // 16
315 if (b == 1 && !T_FLOAT(frm))
316 return 0; // 8
317
318 return -1; // not recognized
319}
320
321// Obtains a alpha-to-alpha funmction formatter
322static
323cmsFormatterAlphaFn _cmsGetFormatterAlpha(cmsContext id, cmsUInt32Number in, cmsUInt32Number out)
324{
325static cmsFormatterAlphaFn FormattersAlpha[5][5] = {
326
327 /* from 8 */ { copy8, from8to16, from8toHLF, from8toFLT, from8toDBL },
328 /* from 16*/ { from16to8, copy16, from16toHLF, from16toFLT, from16toDBL },
329 /* from HLF*/ { fromHLFto8, fromHLFto16, copy16, fromHLFtoFLT, fromHLFtoDBL },
330 /* from FLT*/ { fromFLTto8, fromFLTto16, fromFLTtoHLF, copy32, fromFLTtoDBL },
331 /* from DBL*/ { fromDBLto8, fromDBLto16, fromDBLtoHLF, fromDBLtoFLT, copy64 }};
332
333 int in_n = FormatterPos(in);
334 int out_n = FormatterPos(out);
335
336 if (in_n < 0 || out_n < 0 || in_n > 4 || out_n > 4) {
337
338 cmsSignalError(id, cmsERROR_UNKNOWN_EXTENSION, "Unrecognized alpha channel width");
339 return NULL;
340 }
341
342 return FormattersAlpha[in_n][out_n];
343}
344
345
346
347// This function computes the distance from each component to the next one in bytes.
348static
349void ComputeIncrementsForChunky(cmsUInt32Number Format,
350 cmsUInt32Number ComponentStartingOrder[],
351 cmsUInt32Number ComponentPointerIncrements[])
352{
353 cmsUInt32Number channels[cmsMAXCHANNELS];
354 cmsUInt32Number extra = T_EXTRA(Format);
355 cmsUInt32Number nchannels = T_CHANNELS(Format);
356 cmsUInt32Number total_chans = nchannels + extra;
357 cmsUInt32Number i;
358 cmsUInt32Number channelSize = trueBytesSize(Format);
359 cmsUInt32Number pixelSize = channelSize * total_chans;
360
361 // Sanity check
362 if (total_chans <= 0 || total_chans >= cmsMAXCHANNELS)
363 return;
364
365 memset(channels, 0, sizeof(channels));
366
367 // Separation is independent of starting point and only depends on channel size
368 for (i = 0; i < extra; i++)
369 ComponentPointerIncrements[i] = pixelSize;
370
371 // Handle do swap
372 for (i = 0; i < total_chans; i++)
373 {
374 if (T_DOSWAP(Format)) {
375 channels[i] = total_chans - i - 1;
376 }
377 else {
378 channels[i] = i;
379 }
380 }
381
382 // Handle swap first (ROL of positions), example CMYK -> KCMY | 0123 -> 3012
383 if (T_SWAPFIRST(Format) && total_chans > 1) {
384
385 cmsUInt32Number tmp = channels[0];
386 for (i = 0; i < total_chans-1; i++)
387 channels[i] = channels[i + 1];
388
389 channels[total_chans - 1] = tmp;
390 }
391
392 // Handle size
393 if (channelSize > 1)
394 for (i = 0; i < total_chans; i++) {
395 channels[i] *= channelSize;
396 }
397
398 for (i = 0; i < extra; i++)
399 ComponentStartingOrder[i] = channels[i + nchannels];
400}
401
402
403
404// On planar configurations, the distance is the stride added to any non-negative
405static
406void ComputeIncrementsForPlanar(cmsUInt32Number Format,
407 cmsUInt32Number BytesPerPlane,
408 cmsUInt32Number ComponentStartingOrder[],
409 cmsUInt32Number ComponentPointerIncrements[])
410{
411 cmsUInt32Number channels[cmsMAXCHANNELS];
412 cmsUInt32Number extra = T_EXTRA(Format);
413 cmsUInt32Number nchannels = T_CHANNELS(Format);
414 cmsUInt32Number total_chans = nchannels + extra;
415 cmsUInt32Number i;
416 cmsUInt32Number channelSize = trueBytesSize(Format);
417
418 // Sanity check
419 if (total_chans <= 0 || total_chans >= cmsMAXCHANNELS)
420 return;
421
422 memset(channels, 0, sizeof(channels));
423
424 // Separation is independent of starting point and only depends on channel size
425 for (i = 0; i < extra; i++)
426 ComponentPointerIncrements[i] = channelSize;
427
428 // Handle do swap
429 for (i = 0; i < total_chans; i++)
430 {
431 if (T_DOSWAP(Format)) {
432 channels[i] = total_chans - i - 1;
433 }
434 else {
435 channels[i] = i;
436 }
437 }
438
439 // Handle swap first (ROL of positions), example CMYK -> KCMY | 0123 -> 3012
440 if (T_SWAPFIRST(Format) && total_chans > 0) {
441
442 cmsUInt32Number tmp = channels[0];
443 for (i = 0; i < total_chans - 1; i++)
444 channels[i] = channels[i + 1];
445
446 channels[total_chans - 1] = tmp;
447 }
448
449 // Handle size
450 for (i = 0; i < total_chans; i++) {
451 channels[i] *= BytesPerPlane;
452 }
453
454 for (i = 0; i < extra; i++)
455 ComponentStartingOrder[i] = channels[i + nchannels];
456}
457
458
459
460// Dispatcher por chunky and planar RGB
461static
462void ComputeComponentIncrements(cmsUInt32Number Format,
463 cmsUInt32Number BytesPerPlane,
464 cmsUInt32Number ComponentStartingOrder[],
465 cmsUInt32Number ComponentPointerIncrements[])
466{
467 if (T_PLANAR(Format)) {
468
469 ComputeIncrementsForPlanar(Format, BytesPerPlane, ComponentStartingOrder, ComponentPointerIncrements);
470 }
471 else {
472 ComputeIncrementsForChunky(Format, ComponentStartingOrder, ComponentPointerIncrements);
473 }
474
475}
476
477
478
479// Handles extra channels copying alpha if requested by the flags
480void _cmsHandleExtraChannels(_cmsTRANSFORM* p, const void* in,
481 void* out,
482 cmsUInt32Number PixelsPerLine,
483 cmsUInt32Number LineCount,
484 const cmsStride* Stride)
485{
486 cmsUInt32Number i, j, k;
487 cmsUInt32Number nExtra;
488 cmsUInt32Number SourceStartingOrder[cmsMAXCHANNELS];
489 cmsUInt32Number SourceIncrements[cmsMAXCHANNELS];
490 cmsUInt32Number DestStartingOrder[cmsMAXCHANNELS];
491 cmsUInt32Number DestIncrements[cmsMAXCHANNELS];
492
493 cmsFormatterAlphaFn copyValueFn;
494
495 // Make sure we need some copy
496 if (!(p->dwOriginalFlags & cmsFLAGS_COPY_ALPHA))
497 return;
498
499 // Exit early if in-place color-management is occurring - no need to copy extra channels to themselves.
500 if (p->InputFormat == p->OutputFormat && in == out)
501 return;
502
503 // Make sure we have same number of alpha channels. If not, just return as this should be checked at transform creation time.
504 nExtra = T_EXTRA(p->InputFormat);
505 if (nExtra != T_EXTRA(p->OutputFormat))
506 return;
507
508 // Anything to do?
509 if (nExtra == 0)
510 return;
511
512 // Compute the increments
513 ComputeComponentIncrements(p->InputFormat, Stride->BytesPerPlaneIn, SourceStartingOrder, SourceIncrements);
514 ComputeComponentIncrements(p->OutputFormat, Stride->BytesPerPlaneOut, DestStartingOrder, DestIncrements);
515
516 // Check for conversions 8, 16, half, float, dbl
517 copyValueFn = _cmsGetFormatterAlpha(p->ContextID, p->InputFormat, p->OutputFormat);
518
519 if (nExtra == 1) { // Optimized routine for copying a single extra channel quickly
520
521 cmsUInt8Number* SourcePtr;
522 cmsUInt8Number* DestPtr;
523
524 cmsUInt32Number SourceStrideIncrement = 0;
525 cmsUInt32Number DestStrideIncrement = 0;
526
527 // The loop itself
528 for (i = 0; i < LineCount; i++) {
529
530 // Prepare pointers for the loop
531 SourcePtr = (cmsUInt8Number*)in + SourceStartingOrder[0] + SourceStrideIncrement;
532 DestPtr = (cmsUInt8Number*)out + DestStartingOrder[0] + DestStrideIncrement;
533
534 for (j = 0; j < PixelsPerLine; j++) {
535
536 copyValueFn(DestPtr, SourcePtr);
537
538 SourcePtr += SourceIncrements[0];
539 DestPtr += DestIncrements[0];
540 }
541
542 SourceStrideIncrement += Stride->BytesPerLineIn;
543 DestStrideIncrement += Stride->BytesPerLineOut;
544 }
545
546 }
547 else { // General case with more than one extra channel
548
549 cmsUInt8Number* SourcePtr[cmsMAXCHANNELS];
550 cmsUInt8Number* DestPtr[cmsMAXCHANNELS];
551
552 cmsUInt32Number SourceStrideIncrements[cmsMAXCHANNELS];
553 cmsUInt32Number DestStrideIncrements[cmsMAXCHANNELS];
554
555 memset(SourceStrideIncrements, 0, sizeof(SourceStrideIncrements));
556 memset(DestStrideIncrements, 0, sizeof(DestStrideIncrements));
557
558 // The loop itself
559 for (i = 0; i < LineCount; i++) {
560
561 // Prepare pointers for the loop
562 for (j = 0; j < nExtra; j++) {
563
564 SourcePtr[j] = (cmsUInt8Number*)in + SourceStartingOrder[j] + SourceStrideIncrements[j];
565 DestPtr[j] = (cmsUInt8Number*)out + DestStartingOrder[j] + DestStrideIncrements[j];
566 }
567
568 for (j = 0; j < PixelsPerLine; j++) {
569
570 for (k = 0; k < nExtra; k++) {
571
572 copyValueFn(DestPtr[k], SourcePtr[k]);
573
574 SourcePtr[k] += SourceIncrements[k];
575 DestPtr[k] += DestIncrements[k];
576 }
577 }
578
579 for (j = 0; j < nExtra; j++) {
580
581 SourceStrideIncrements[j] += Stride->BytesPerLineIn;
582 DestStrideIncrements[j] += Stride->BytesPerLineOut;
583 }
584 }
585 }
586}
587
588
589