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