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