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