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