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