• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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