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 62cmsINLINE 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 73static 74int 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 89typedef void(*cmsFormatterAlphaFn)(void* dst, const void* src); 90 91 92// From 8 93 94static 95void copy8(void* dst, const void* src) 96{ 97 memmove(dst, src, 1); 98} 99 100static 101void from8to16(void* dst, const void* src) 102{ 103 cmsUInt8Number n = *(cmsUInt8Number*)src; 104 *(cmsUInt16Number*) dst = FROM_8_TO_16(n); 105} 106 107static 108void from8toFLT(void* dst, const void* src) 109{ 110 *(cmsFloat32Number*)dst = (*(cmsUInt8Number*)src) / 255.0f; 111} 112 113static 114void from8toDBL(void* dst, const void* src) 115{ 116 *(cmsFloat64Number*)dst = (*(cmsUInt8Number*)src) / 255.0; 117} 118 119static 120void 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 128static 129void from16to8(void* dst, const void* src) 130{ 131 cmsUInt16Number n = *(cmsUInt16Number*)src; 132 *(cmsUInt8Number*) dst = FROM_16_TO_8(n); 133} 134 135static 136void copy16(void* dst, const void* src) 137{ 138 memmove(dst, src, 2); 139} 140 141void from16toFLT(void* dst, const void* src) 142{ 143 *(cmsFloat32Number*)dst = (*(cmsUInt16Number*)src) / 65535.0f; 144} 145 146void from16toDBL(void* dst, const void* src) 147{ 148 *(cmsFloat64Number*)dst = (*(cmsUInt16Number*)src) / 65535.0f; 149} 150 151static 152void 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 160static 161void fromFLTto8(void* dst, const void* src) 162{ 163 cmsFloat32Number n = *(cmsFloat32Number*)src; 164 *(cmsUInt8Number*)dst = _cmsQuickSaturateByte(n * 255.0f); 165} 166 167static 168void fromFLTto16(void* dst, const void* src) 169{ 170 cmsFloat32Number n = *(cmsFloat32Number*)src; 171 *(cmsUInt16Number*)dst = _cmsQuickSaturateWord(n * 65535.0f); 172} 173 174static 175void copy32(void* dst, const void* src) 176{ 177 memmove(dst, src, sizeof(cmsFloat32Number)); 178} 179 180static 181void fromFLTtoDBL(void* dst, const void* src) 182{ 183 cmsFloat32Number n = *(cmsFloat32Number*)src; 184 *(cmsFloat64Number*)dst = (cmsFloat64Number)n; 185} 186 187static 188void fromFLTtoHLF(void* dst, const void* src) 189{ 190 cmsFloat32Number n = *(cmsFloat32Number*)src; 191 *(cmsUInt16Number*)dst = _cmsFloat2Half(n); 192} 193 194 195// From HALF 196 197static 198void fromHLFto8(void* dst, const void* src) 199{ 200 cmsFloat32Number n = _cmsHalf2Float(*(cmsUInt16Number*)src); 201 *(cmsUInt8Number*)dst = _cmsQuickSaturateByte(n * 255.0f); 202} 203 204static 205void fromHLFto16(void* dst, const void* src) 206{ 207 cmsFloat32Number n = _cmsHalf2Float(*(cmsUInt16Number*)src); 208 *(cmsUInt16Number*)dst = _cmsQuickSaturateWord(n * 65535.0f); 209} 210 211static 212void fromHLFtoFLT(void* dst, const void* src) 213{ 214 *(cmsFloat32Number*)dst = _cmsHalf2Float(*(cmsUInt16Number*)src); 215} 216 217static 218void fromHLFtoDBL(void* dst, const void* src) 219{ 220 *(cmsFloat64Number*)dst = (cmsFloat64Number)_cmsHalf2Float(*(cmsUInt16Number*)src); 221} 222 223// From double 224static 225void fromDBLto8(void* dst, const void* src) 226{ 227 cmsFloat64Number n = *(cmsFloat64Number*)src; 228 *(cmsUInt8Number*)dst = _cmsQuickSaturateByte(n * 255.0); 229} 230 231static 232void fromDBLto16(void* dst, const void* src) 233{ 234 cmsFloat64Number n = *(cmsFloat64Number*)src; 235 *(cmsUInt16Number*)dst = _cmsQuickSaturateWord(n * 65535.0f); 236} 237 238static 239void fromDBLtoFLT(void* dst, const void* src) 240{ 241 cmsFloat64Number n = *(cmsFloat64Number*)src; 242 *(cmsFloat32Number*)dst = (cmsFloat32Number) n; 243} 244 245static 246void fromDBLtoHLF(void* dst, const void* src) 247{ 248 cmsFloat32Number n = (cmsFloat32Number) *(cmsFloat64Number*)src; 249 *(cmsUInt16Number*)dst = _cmsFloat2Half(n); 250} 251 252static 253void 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 260static 261int 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 281static 282cmsFormatterAlphaFn _cmsGetFormatterAlpha(cmsContext id, cmsUInt32Number in, cmsUInt32Number out) 283{ 284static 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. 307static 308void 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 364static 365void 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 420static 421void 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 439void _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 548