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