Home | History | Annotate | Download | only in src
      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
     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
     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
     66 void copy8(void* dst, const void* src)
     67 {
     68        memmove(dst, src, 1);
     69 }
     70 
     71 static
     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
     79 void from8toFLT(void* dst, const void* src)
     80 {
     81        *(cmsFloat32Number*)dst = (*(cmsUInt8Number*)src) / 255.0f;
     82 }
     83 
     84 static
     85 void from8toDBL(void* dst, const void* src)
     86 {
     87        *(cmsFloat64Number*)dst = (*(cmsUInt8Number*)src) / 255.0;
     88 }
     89 
     90 static
     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
    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
    107 void copy16(void* dst, const void* src)
    108 {
    109        memmove(dst, src, 2);
    110 }
    111 
    112 void from16toFLT(void* dst, const void* src)
    113 {
    114        *(cmsFloat32Number*)dst = (*(cmsUInt16Number*)src) / 65535.0f;
    115 }
    116 
    117 void from16toDBL(void* dst, const void* src)
    118 {
    119        *(cmsFloat64Number*)dst = (*(cmsUInt16Number*)src) / 65535.0f;
    120 }
    121 
    122 static
    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
    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
    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
    146 void copy32(void* dst, const void* src)
    147 {
    148        memmove(dst, src, sizeof(cmsFloat32Number));
    149 }
    150 
    151 static
    152 void fromFLTtoDBL(void* dst, const void* src)
    153 {
    154        cmsFloat32Number n = *(cmsFloat32Number*)src;
    155        *(cmsFloat64Number*)dst = (cmsFloat64Number)n;
    156 }
    157 
    158 static
    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
    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
    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
    183 void fromHLFtoFLT(void* dst, const void* src)
    184 {
    185        *(cmsFloat32Number*)dst = _cmsHalf2Float(*(cmsUInt16Number*)src);
    186 }
    187 
    188 static
    189 void fromHLFtoDBL(void* dst, const void* src)
    190 {
    191        *(cmsFloat64Number*)dst = (cmsFloat64Number)_cmsHalf2Float(*(cmsUInt16Number*)src);
    192 }
    193 
    194 // From double
    195 static
    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
    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
    210 void fromDBLtoFLT(void* dst, const void* src)
    211 {
    212        cmsFloat64Number n = *(cmsFloat64Number*)src;
    213        *(cmsFloat32Number*)dst = (cmsFloat32Number) n;
    214 }
    215 
    216 static
    217 void fromDBLtoHLF(void* dst, const void* src)
    218 {
    219        cmsFloat32Number n = (cmsFloat32Number) *(cmsFloat64Number*)src;
    220        *(cmsUInt16Number*)dst = _cmsFloat2Half(n);
    221 }
    222 
    223 static
    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
    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
    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
    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
    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
    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
    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