1 /* 2 * Copyright 2016 Google Inc. 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8 #include "SkAutoMalloc.h" 9 #include "SkColorSpace.h" 10 #include "SkColorSpacePriv.h" 11 #include "SkColorSpace_A2B.h" 12 #include "SkColorSpace_XYZ.h" 13 #include "SkEndian.h" 14 #include "SkFixed.h" 15 #include "SkICCPriv.h" 16 #include "SkTemplates.h" 17 18 #define return_if_false(pred, msg) \ 19 do { \ 20 if (!(pred)) { \ 21 SkColorSpacePrintf("Invalid ICC Profile: %s.\n", (msg)); \ 22 return false; \ 23 } \ 24 } while (0) 25 26 #define return_null(msg) \ 27 do { \ 28 SkColorSpacePrintf("Invalid ICC Profile: %s.\n", (msg)); \ 29 return nullptr; \ 30 } while (0) 31 32 static uint16_t read_big_endian_u16(const uint8_t* ptr) { 33 return ptr[0] << 8 | ptr[1]; 34 } 35 36 static uint32_t read_big_endian_u32(const uint8_t* ptr) { 37 return ptr[0] << 24 | ptr[1] << 16 | ptr[2] << 8 | ptr[3]; 38 } 39 40 static int32_t read_big_endian_i32(const uint8_t* ptr) { 41 return (int32_t) read_big_endian_u32(ptr); 42 } 43 44 static constexpr float kWhitePointD50[] = { 0.96420f, 1.00000f, 0.82491f, }; 45 46 struct ICCProfileHeader { 47 uint32_t fSize; 48 49 // No reason to care about the preferred color management module (ex: Adobe, Apple, etc.). 50 // We're always going to use this one. 51 uint32_t fCMMType_ignored; 52 53 uint32_t fVersion; 54 uint32_t fProfileClass; 55 uint32_t fInputColorSpace; 56 uint32_t fPCS; 57 uint32_t fDateTime_ignored[3]; 58 uint32_t fSignature; 59 60 // Indicates the platform that this profile was created for (ex: Apple, Microsoft). This 61 // doesn't really matter to us. 62 uint32_t fPlatformTarget_ignored; 63 64 // Flags can indicate: 65 // (1) Whether this profile was embedded in a file. This flag is consistently wrong. 66 // Ex: The profile came from a file but indicates that it did not. 67 // (2) Whether we are allowed to use the profile independently of the color data. If set, 68 // this may allow us to use the embedded profile for testing separate from the original 69 // image. 70 uint32_t fFlags_ignored; 71 72 // We support many output devices. It doesn't make sense to think about the attributes of 73 // the device in the context of the image profile. 74 uint32_t fDeviceManufacturer_ignored; 75 uint32_t fDeviceModel_ignored; 76 uint32_t fDeviceAttributes_ignored[2]; 77 78 uint32_t fRenderingIntent; 79 int32_t fIlluminantXYZ[3]; 80 81 // We don't care who created the profile. 82 uint32_t fCreator_ignored; 83 84 // This is an MD5 checksum. Could be useful for checking if profiles are equal. 85 uint32_t fProfileId_ignored[4]; 86 87 // Reserved for future use. 88 uint32_t fReserved_ignored[7]; 89 90 uint32_t fTagCount; 91 92 void init(const uint8_t* src, size_t len) { 93 SkASSERT(kICCHeaderSize == sizeof(*this)); 94 95 uint32_t* dst = (uint32_t*) this; 96 for (uint32_t i = 0; i < kICCHeaderSize / 4; i++, src+=4) { 97 dst[i] = read_big_endian_u32(src); 98 } 99 } 100 101 bool valid() const { 102 return_if_false(fSize >= kICCHeaderSize, "Size is too small"); 103 104 uint8_t majorVersion = fVersion >> 24; 105 return_if_false(majorVersion <= 4, "Unsupported version"); 106 107 // These are the four basic classes of profiles that we might expect to see embedded 108 // in images. Additional classes exist, but they generally are used as a convenient 109 // way for CMMs to store calculated transforms. 110 return_if_false(fProfileClass == kDisplay_Profile || 111 fProfileClass == kInput_Profile || 112 fProfileClass == kOutput_Profile || 113 fProfileClass == kColorSpace_Profile, 114 "Unsupported profile"); 115 116 switch (fInputColorSpace) { 117 case kRGB_ColorSpace: 118 SkColorSpacePrintf("RGB Input Color Space"); 119 break; 120 case kCMYK_ColorSpace: 121 SkColorSpacePrintf("CMYK Input Color Space\n"); 122 break; 123 case kGray_ColorSpace: 124 SkColorSpacePrintf("Gray Input Color Space\n"); 125 break; 126 default: 127 SkColorSpacePrintf("Unsupported Input Color Space: %c%c%c%c\n", 128 (fInputColorSpace>>24)&0xFF, (fInputColorSpace>>16)&0xFF, 129 (fInputColorSpace>> 8)&0xFF, (fInputColorSpace>> 0)&0xFF); 130 return false; 131 } 132 133 switch (fPCS) { 134 case kXYZ_PCSSpace: 135 SkColorSpacePrintf("XYZ PCS\n"); 136 break; 137 case kLAB_PCSSpace: 138 SkColorSpacePrintf("Lab PCS\n"); 139 break; 140 default: 141 // ICC currently (V4.3) only specifices XYZ and Lab PCS spaces 142 SkColorSpacePrintf("Unsupported PCS space: %c%c%c%c\n", 143 (fPCS>>24)&0xFF, (fPCS>>16)&0xFF, 144 (fPCS>> 8)&0xFF, (fPCS>> 0)&0xFF); 145 return false; 146 } 147 148 return_if_false(fSignature == kACSP_Signature, "Bad signature"); 149 150 // TODO (msarett): 151 // Should we treat different rendering intents differently? 152 // Valid rendering intents include kPerceptual (0), kRelative (1), 153 // kSaturation (2), and kAbsolute (3). 154 if (fRenderingIntent > 3) { 155 // Warn rather than fail here. Occasionally, we see perfectly 156 // normal profiles with wacky rendering intents. 157 SkColorSpacePrintf("Warning, bad rendering intent.\n"); 158 } 159 160 return_if_false( 161 color_space_almost_equal(SkFixedToFloat(fIlluminantXYZ[0]), kWhitePointD50[0]) && 162 color_space_almost_equal(SkFixedToFloat(fIlluminantXYZ[1]), kWhitePointD50[1]) && 163 color_space_almost_equal(SkFixedToFloat(fIlluminantXYZ[2]), kWhitePointD50[2]), 164 "Illuminant must be D50"); 165 166 return_if_false(fTagCount <= 100, "Too many tags"); 167 168 return true; 169 } 170 }; 171 172 template <class T> 173 static bool safe_add(T arg1, T arg2, size_t* result) { 174 SkASSERT(arg1 >= 0); 175 SkASSERT(arg2 >= 0); 176 if (arg1 >= 0 && arg2 <= std::numeric_limits<T>::max() - arg1) { 177 T sum = arg1 + arg2; 178 if (sum <= std::numeric_limits<size_t>::max()) { 179 *result = static_cast<size_t>(sum); 180 return true; 181 } 182 } 183 return false; 184 } 185 186 static bool safe_mul(uint32_t arg1, uint32_t arg2, uint32_t* result) { 187 uint64_t product64 = (uint64_t) arg1 * (uint64_t) arg2; 188 uint32_t product32 = (uint32_t) product64; 189 if (product32 != product64) { 190 return false; 191 } 192 193 *result = product32; 194 return true; 195 } 196 197 struct ICCTag { 198 uint32_t fSignature; 199 uint32_t fOffset; 200 uint32_t fLength; 201 202 const uint8_t* init(const uint8_t* src) { 203 fSignature = read_big_endian_u32(src); 204 fOffset = read_big_endian_u32(src + 4); 205 fLength = read_big_endian_u32(src + 8); 206 return src + 12; 207 } 208 209 bool valid(size_t len) { 210 size_t tagEnd; 211 return_if_false(safe_add(fOffset, fLength, &tagEnd), 212 "Tag too large, overflows integer addition"); 213 return_if_false(tagEnd <= len, "Tag too large for ICC profile"); 214 return true; 215 } 216 217 const uint8_t* addr(const uint8_t* src) const { 218 return src + fOffset; 219 } 220 221 static const ICCTag* Find(const ICCTag tags[], int count, uint32_t signature) { 222 for (int i = 0; i < count; ++i) { 223 if (tags[i].fSignature == signature) { 224 return &tags[i]; 225 } 226 } 227 return nullptr; 228 } 229 }; 230 231 static bool load_xyz(float dst[3], const uint8_t* src, size_t len) { 232 if (len < 20) { 233 SkColorSpacePrintf("XYZ tag is too small (%d bytes)", len); 234 return false; 235 } 236 237 dst[0] = SkFixedToFloat(read_big_endian_i32(src + 8)); 238 dst[1] = SkFixedToFloat(read_big_endian_i32(src + 12)); 239 dst[2] = SkFixedToFloat(read_big_endian_i32(src + 16)); 240 SkColorSpacePrintf("XYZ %g %g %g\n", dst[0], dst[1], dst[2]); 241 return true; 242 } 243 244 static SkGammas::Type set_gamma_value(SkGammas::Data* data, float value) { 245 if (color_space_almost_equal(2.2f, value)) { 246 data->fNamed = k2Dot2Curve_SkGammaNamed; 247 return SkGammas::Type::kNamed_Type; 248 } 249 250 if (color_space_almost_equal(1.0f, value)) { 251 data->fNamed = kLinear_SkGammaNamed; 252 return SkGammas::Type::kNamed_Type; 253 } 254 255 if (color_space_almost_equal(0.0f, value)) { 256 return SkGammas::Type::kNone_Type; 257 } 258 259 data->fValue = value; 260 return SkGammas::Type::kValue_Type; 261 } 262 263 static float read_big_endian_16_dot_16(const uint8_t buf[4]) { 264 // It just so happens that SkFixed is also 16.16! 265 return SkFixedToFloat(read_big_endian_i32(buf)); 266 } 267 268 /** 269 * @param outData Set to the appropriate value on success. If we have table or 270 * parametric gamma, it is the responsibility of the caller to set 271 * fOffset. 272 * @param outParams If this is a parametric gamma, this is set to the appropriate 273 * parameters on success. 274 * @param outTagBytes Will be set to the length of the tag on success. 275 * @src Pointer to tag data. 276 * @len Length of tag data in bytes. 277 * 278 * @return kNone_Type on failure, otherwise the type of the gamma tag. 279 */ 280 static SkGammas::Type parse_gamma(SkGammas::Data* outData, SkColorSpaceTransferFn* outParams, 281 size_t* outTagBytes, const uint8_t* src, size_t len) { 282 if (len < 12) { 283 SkColorSpacePrintf("gamma tag is too small (%d bytes)", len); 284 return SkGammas::Type::kNone_Type; 285 } 286 287 // In the case of consecutive gamma tags, we need to count the number of bytes in the 288 // tag, so that we can move on to the next tag. 289 size_t tagBytes; 290 291 uint32_t type = read_big_endian_u32(src); 292 // Bytes 4-7 are reserved and should be set to zero. 293 switch (type) { 294 case kTAG_CurveType: { 295 uint32_t count = read_big_endian_u32(src + 8); 296 297 // tagBytes = 12 + 2 * count 298 // We need to do safe addition here to avoid integer overflow. 299 if (!safe_add(count, count, &tagBytes) || 300 !safe_add((size_t) 12, tagBytes, &tagBytes)) 301 { 302 SkColorSpacePrintf("Invalid gamma count"); 303 return SkGammas::Type::kNone_Type; 304 } 305 306 if (len < tagBytes) { 307 SkColorSpacePrintf("gamma tag is too small (%d bytes)", len); 308 return SkGammas::Type::kNone_Type; 309 } 310 *outTagBytes = tagBytes; 311 312 if (0 == count) { 313 // Some tags require a gamma curve, but the author doesn't actually want 314 // to transform the data. In this case, it is common to see a curve with 315 // a count of 0. 316 outData->fNamed = kLinear_SkGammaNamed; 317 return SkGammas::Type::kNamed_Type; 318 } 319 320 const uint16_t* table = (const uint16_t*) (src + 12); 321 if (1 == count) { 322 // The table entry is the gamma (with a bias of 256). 323 float value = (read_big_endian_u16((const uint8_t*) table)) / 256.0f; 324 SkColorSpacePrintf("gamma %g\n", value); 325 326 return set_gamma_value(outData, value); 327 } 328 329 // This optimization is especially important for A2B profiles, where we do 330 // not resize tables or interpolate lookups. 331 if (2 == count) { 332 if (0 == read_big_endian_u16((const uint8_t*) &table[0]) && 333 65535 == read_big_endian_u16((const uint8_t*) &table[1])) { 334 outData->fNamed = kLinear_SkGammaNamed; 335 return SkGammas::Type::kNamed_Type; 336 } 337 } 338 339 // Check for frequently occurring sRGB curves. 340 // We do this by sampling a few values and see if they match our expectation. 341 // A more robust solution would be to compare each value in this curve against 342 // an sRGB curve to see if we remain below an error threshold. At this time, 343 // we haven't seen any images in the wild that make this kind of 344 // calculation necessary. We encounter identical gamma curves over and 345 // over again, but relatively few variations. 346 if (1024 == count) { 347 // The magic values were chosen because they match both the very common 348 // HP sRGB gamma table and the less common Canon sRGB gamma table (which use 349 // different rounding rules). 350 if (0 == read_big_endian_u16((const uint8_t*) &table[0]) && 351 3366 == read_big_endian_u16((const uint8_t*) &table[257]) && 352 14116 == read_big_endian_u16((const uint8_t*) &table[513]) && 353 34318 == read_big_endian_u16((const uint8_t*) &table[768]) && 354 65535 == read_big_endian_u16((const uint8_t*) &table[1023])) { 355 outData->fNamed = kSRGB_SkGammaNamed; 356 return SkGammas::Type::kNamed_Type; 357 } 358 } 359 360 if (26 == count) { 361 // The magic values match a clever "minimum size" approach to representing sRGB. 362 // code.facebook.com/posts/411525055626587/under-the-hood-improving-facebook-photos 363 if (0 == read_big_endian_u16((const uint8_t*) &table[0]) && 364 3062 == read_big_endian_u16((const uint8_t*) &table[6]) && 365 12824 == read_big_endian_u16((const uint8_t*) &table[12]) && 366 31237 == read_big_endian_u16((const uint8_t*) &table[18]) && 367 65535 == read_big_endian_u16((const uint8_t*) &table[25])) { 368 outData->fNamed = kSRGB_SkGammaNamed; 369 return SkGammas::Type::kNamed_Type; 370 } 371 } 372 373 if (4096 == count) { 374 // The magic values were chosen because they match Nikon, Epson, and 375 // lcms2 sRGB gamma tables (all of which use different rounding rules). 376 if (0 == read_big_endian_u16((const uint8_t*) &table[0]) && 377 950 == read_big_endian_u16((const uint8_t*) &table[515]) && 378 3342 == read_big_endian_u16((const uint8_t*) &table[1025]) && 379 14079 == read_big_endian_u16((const uint8_t*) &table[2051]) && 380 65535 == read_big_endian_u16((const uint8_t*) &table[4095])) { 381 outData->fNamed = kSRGB_SkGammaNamed; 382 return SkGammas::Type::kNamed_Type; 383 } 384 } 385 386 // Otherwise, we will represent gamma with a table. 387 outData->fTable.fSize = count; 388 return SkGammas::Type::kTable_Type; 389 } 390 case kTAG_ParaCurveType: { 391 // Determine the format of the parametric curve tag. 392 uint16_t format = read_big_endian_u16(src + 8); 393 if (format > kGABCDEF_ParaCurveType) { 394 SkColorSpacePrintf("Unsupported gamma tag type %d\n", type); 395 return SkGammas::Type::kNone_Type; 396 } 397 398 if (kExponential_ParaCurveType == format) { 399 tagBytes = 12 + 4; 400 if (len < tagBytes) { 401 SkColorSpacePrintf("gamma tag is too small (%d bytes)", len); 402 return SkGammas::Type::kNone_Type; 403 } 404 405 // Y = X^g 406 float g = read_big_endian_16_dot_16(src + 12); 407 408 *outTagBytes = tagBytes; 409 return set_gamma_value(outData, g); 410 } 411 412 // Here's where the real parametric gammas start. There are many 413 // permutations of the same equations. 414 // 415 // Y = (aX + b)^g + e for X >= d 416 // Y = cX + f otherwise 417 // 418 // We will fill in with zeros as necessary to always match the above form. 419 if (len < 24) { 420 SkColorSpacePrintf("gamma tag is too small (%d bytes)", len); 421 return SkGammas::Type::kNone_Type; 422 } 423 float g = read_big_endian_16_dot_16(src + 12); 424 float a = read_big_endian_16_dot_16(src + 16); 425 float b = read_big_endian_16_dot_16(src + 20); 426 float c = 0.0f, d = 0.0f, e = 0.0f, f = 0.0f; 427 switch(format) { 428 case kGAB_ParaCurveType: 429 tagBytes = 12 + 12; 430 431 // Y = (aX + b)^g for X >= -b/a 432 // Y = 0 otherwise 433 d = -b / a; 434 break; 435 case kGABC_ParaCurveType: 436 tagBytes = 12 + 16; 437 if (len < tagBytes) { 438 SkColorSpacePrintf("gamma tag is too small (%d bytes)", len); 439 return SkGammas::Type::kNone_Type; 440 } 441 442 // Y = (aX + b)^g + e for X >= -b/a 443 // Y = e otherwise 444 e = read_big_endian_16_dot_16(src + 24); 445 d = -b / a; 446 f = e; 447 break; 448 case kGABDE_ParaCurveType: 449 tagBytes = 12 + 20; 450 if (len < tagBytes) { 451 SkColorSpacePrintf("gamma tag is too small (%d bytes)", len); 452 return SkGammas::Type::kNone_Type; 453 } 454 455 // Y = (aX + b)^g for X >= d 456 // Y = cX otherwise 457 c = read_big_endian_16_dot_16(src + 24); 458 d = read_big_endian_16_dot_16(src + 28); 459 break; 460 case kGABCDEF_ParaCurveType: 461 tagBytes = 12 + 28; 462 if (len < tagBytes) { 463 SkColorSpacePrintf("gamma tag is too small (%d bytes)", len); 464 return SkGammas::Type::kNone_Type; 465 } 466 467 // Y = (aX + b)^g + e for X >= d 468 // Y = cX + f otherwise 469 c = read_big_endian_16_dot_16(src + 24); 470 d = read_big_endian_16_dot_16(src + 28); 471 e = read_big_endian_16_dot_16(src + 32); 472 f = read_big_endian_16_dot_16(src + 36); 473 break; 474 default: 475 SkASSERT(false); 476 return SkGammas::Type::kNone_Type; 477 } 478 479 outParams->fG = g; 480 outParams->fA = a; 481 outParams->fB = b; 482 outParams->fC = c; 483 outParams->fD = d; 484 outParams->fE = e; 485 outParams->fF = f; 486 487 if (!is_valid_transfer_fn(*outParams)) { 488 return SkGammas::Type::kNone_Type; 489 } 490 491 if (is_almost_srgb(*outParams)) { 492 outData->fNamed = kSRGB_SkGammaNamed; 493 return SkGammas::Type::kNamed_Type; 494 } 495 496 if (is_almost_2dot2(*outParams)) { 497 outData->fNamed = k2Dot2Curve_SkGammaNamed; 498 return SkGammas::Type::kNamed_Type; 499 } 500 501 *outTagBytes = tagBytes; 502 return SkGammas::Type::kParam_Type; 503 } 504 default: 505 SkColorSpacePrintf("Unsupported gamma tag type %d\n", type); 506 return SkGammas::Type::kNone_Type; 507 } 508 } 509 510 /** 511 * Returns the additional size in bytes needed to store the gamma tag. 512 */ 513 static size_t gamma_alloc_size(SkGammas::Type type, const SkGammas::Data& data) { 514 switch (type) { 515 case SkGammas::Type::kNamed_Type: 516 case SkGammas::Type::kValue_Type: 517 return 0; 518 case SkGammas::Type::kTable_Type: 519 return sizeof(float) * data.fTable.fSize; 520 case SkGammas::Type::kParam_Type: 521 return sizeof(SkColorSpaceTransferFn); 522 default: 523 SkASSERT(false); 524 return 0; 525 } 526 } 527 528 /** 529 * Sets invalid gamma to the default value. 530 */ 531 static void handle_invalid_gamma(SkGammas::Type* type, SkGammas::Data* data) { 532 if (SkGammas::Type::kNone_Type == *type) { 533 *type = SkGammas::Type::kNamed_Type; 534 535 // Guess sRGB in the case of a malformed transfer function. 536 data->fNamed = kSRGB_SkGammaNamed; 537 } 538 } 539 540 /** 541 * Finish loading the gammas, now that we have allocated memory for the SkGammas struct. 542 * 543 * There's nothing to do for the simple cases, but for table gammas we need to actually 544 * read the table into heap memory. And for parametric gammas, we need to copy over the 545 * parameter values. 546 * 547 * @param memory Pointer to start of the SkGammas memory block 548 * @param offset Bytes of memory (after the SkGammas struct) that are already in use. 549 * @param data In-out variable. Will fill in the offset to the table or parameters 550 * if necessary. 551 * @param params Parameters for gamma curve. Only initialized/used when we have a 552 * parametric gamma. 553 * @param src Pointer to start of the gamma tag. 554 * 555 * @return Additional bytes of memory that are being used by this gamma curve. 556 */ 557 static size_t load_gammas(void* memory, size_t offset, SkGammas::Type type, 558 SkGammas::Data* data, const SkColorSpaceTransferFn& params, 559 const uint8_t* src) { 560 void* storage = SkTAddOffset<void>(memory, offset + sizeof(SkGammas)); 561 562 switch (type) { 563 case SkGammas::Type::kNamed_Type: 564 case SkGammas::Type::kValue_Type: 565 // Nothing to do here. 566 return 0; 567 case SkGammas::Type::kTable_Type: { 568 data->fTable.fOffset = offset; 569 570 float* outTable = (float*) storage; 571 const uint16_t* inTable = (const uint16_t*) (src + 12); 572 for (int i = 0; i < data->fTable.fSize; i++) { 573 outTable[i] = (read_big_endian_u16((const uint8_t*) &inTable[i])) / 65535.0f; 574 } 575 576 return sizeof(float) * data->fTable.fSize; 577 } 578 case SkGammas::Type::kParam_Type: 579 data->fTable.fOffset = offset; 580 memcpy(storage, ¶ms, sizeof(SkColorSpaceTransferFn)); 581 return sizeof(SkColorSpaceTransferFn); 582 default: 583 SkASSERT(false); 584 return 0; 585 } 586 } 587 588 static constexpr uint32_t kTAG_AtoBType = SkSetFourByteTag('m', 'A', 'B', ' '); 589 static constexpr uint32_t kTAG_lut8Type = SkSetFourByteTag('m', 'f', 't', '1'); 590 static constexpr uint32_t kTAG_lut16Type = SkSetFourByteTag('m', 'f', 't', '2'); 591 592 static bool load_color_lut(sk_sp<SkColorLookUpTable>* colorLUT, uint32_t inputChannels, 593 size_t precision, const uint8_t gridPoints[3], const uint8_t* src, 594 size_t len) { 595 switch (precision) { 596 case 1: // 8-bit data 597 case 2: // 16-bit data 598 break; 599 default: 600 SkColorSpacePrintf("Color LUT precision must be 8-bit or 16-bit. Found: %d-bit\n", 601 8*precision); 602 return false; 603 } 604 605 uint32_t numEntries = SkColorLookUpTable::kOutputChannels; 606 for (uint32_t i = 0; i < inputChannels; i++) { 607 if (1 >= gridPoints[i]) { 608 SkColorSpacePrintf("Each input channel must have at least two grid points."); 609 return false; 610 } 611 612 if (!safe_mul(numEntries, gridPoints[i], &numEntries)) { 613 SkColorSpacePrintf("Too many entries in Color LUT."); 614 return false; 615 } 616 } 617 618 uint32_t clutBytes; 619 if (!safe_mul(numEntries, precision, &clutBytes)) { 620 SkColorSpacePrintf("Too many entries in Color LUT.\n"); 621 return false; 622 } 623 624 if (len < clutBytes) { 625 SkColorSpacePrintf("Color LUT tag is too small (%d / %d bytes).\n", len, clutBytes); 626 return false; 627 } 628 629 // Movable struct colorLUT has ownership of fTable. 630 void* memory = sk_malloc_throw(sizeof(SkColorLookUpTable) + sizeof(float) * numEntries); 631 *colorLUT = sk_sp<SkColorLookUpTable>(new (memory) SkColorLookUpTable(inputChannels, 632 gridPoints)); 633 634 float* table = SkTAddOffset<float>(memory, sizeof(SkColorLookUpTable)); 635 const uint8_t* ptr = src; 636 for (uint32_t i = 0; i < numEntries; i++, ptr += precision) { 637 if (1 == precision) { 638 table[i] = ((float) *ptr) / 255.0f; 639 } else { 640 table[i] = ((float) read_big_endian_u16(ptr)) / 65535.0f; 641 } 642 } 643 644 return true; 645 } 646 647 /** 648 * Reads a matrix out of an A2B tag of an ICC profile. 649 * If |translate| is true, it will load a 3x4 matrix out that corresponds to a XYZ 650 * transform as well as a translation, and if |translate| is false it only loads a 651 * 3x3 matrix with no translation 652 * 653 * @param matrix The matrix to store the result in 654 * @param src Data to load the matrix out of. 655 * @param len The length of |src|. 656 * Must have 48 bytes if |translate| is set and 36 bytes otherwise. 657 * @param translate Whether to read the translation column or not 658 * @param pcs The profile connection space of the profile this matrix is for 659 * 660 * @return false on failure, true on success 661 */ 662 static bool load_matrix(SkMatrix44* matrix, const uint8_t* src, size_t len, bool translate, 663 SkColorSpace_A2B::PCS pcs) { 664 const size_t minLen = translate ? 48 : 36; 665 if (len < minLen) { 666 SkColorSpacePrintf("Matrix tag is too small (%d bytes).", len); 667 return false; 668 } 669 670 float encodingFactor; 671 switch (pcs) { 672 case SkColorSpace_A2B::PCS::kLAB: 673 encodingFactor = 1.f; 674 break; 675 case SkColorSpace_A2B::PCS::kXYZ: 676 encodingFactor = 65535 / 32768.f; 677 break; 678 default: 679 encodingFactor = 1.f; 680 SkASSERT(false); 681 break; 682 } 683 float array[16]; 684 array[ 0] = encodingFactor * SkFixedToFloat(read_big_endian_i32(src)); 685 array[ 1] = encodingFactor * SkFixedToFloat(read_big_endian_i32(src + 4)); 686 array[ 2] = encodingFactor * SkFixedToFloat(read_big_endian_i32(src + 8)); 687 688 array[ 4] = encodingFactor * SkFixedToFloat(read_big_endian_i32(src + 12)); 689 array[ 5] = encodingFactor * SkFixedToFloat(read_big_endian_i32(src + 16)); 690 array[ 6] = encodingFactor * SkFixedToFloat(read_big_endian_i32(src + 20)); 691 692 array[ 8] = encodingFactor * SkFixedToFloat(read_big_endian_i32(src + 24)); 693 array[ 9] = encodingFactor * SkFixedToFloat(read_big_endian_i32(src + 28)); 694 array[10] = encodingFactor * SkFixedToFloat(read_big_endian_i32(src + 32)); 695 696 if (translate) { 697 array[ 3] = encodingFactor * SkFixedToFloat(read_big_endian_i32(src + 36)); // translate R 698 array[ 7] = encodingFactor * SkFixedToFloat(read_big_endian_i32(src + 40)); // translate G 699 array[11] = encodingFactor * SkFixedToFloat(read_big_endian_i32(src + 44)); // translate B 700 } else { 701 array[ 3] = 0.0f; 702 array[ 7] = 0.0f; 703 array[11] = 0.0f; 704 } 705 706 array[12] = 0.0f; 707 array[13] = 0.0f; 708 array[14] = 0.0f; 709 array[15] = 1.0f; 710 matrix->setRowMajorf(array); 711 SkColorSpacePrintf("A2B0 matrix loaded:\n"); 712 for (int r = 0; r < 4; ++r) { 713 SkColorSpacePrintf("|"); 714 for (int c = 0; c < 4; ++c) { 715 SkColorSpacePrintf(" %f ", matrix->get(r, c)); 716 } 717 SkColorSpacePrintf("|\n"); 718 } 719 return true; 720 } 721 722 static inline SkGammaNamed is_named(const sk_sp<SkGammas>& gammas) { 723 for (uint8_t i = 0; i < gammas->channels(); ++i) { 724 if (!gammas->isNamed(i) || gammas->data(i).fNamed != gammas->data(0).fNamed) { 725 return kNonStandard_SkGammaNamed; 726 } 727 } 728 return gammas->data(0).fNamed; 729 } 730 731 /** 732 * Parse and load an entire stored curve. Handles invalid gammas as well. 733 * 734 * There's nothing to do for the simple cases, but for table gammas we need to actually 735 * read the table into heap memory. And for parametric gammas, we need to copy over the 736 * parameter values. 737 * 738 * @param gammaNamed Out-variable. The named gamma curve. 739 * @param gammas Out-variable. The stored gamma curve information. Can be null if 740 * gammaNamed is a named curve 741 * @param inputChannels The number of gamma input channels 742 * @param rTagPtr Pointer to start of the gamma tag. 743 * @param taglen The size in bytes of the tag 744 * 745 * @return false on failure, true on success 746 */ 747 static bool parse_and_load_gamma(SkGammaNamed* gammaNamed, sk_sp<SkGammas>* gammas, 748 uint8_t inputChannels, const uint8_t* tagSrc, size_t tagLen) { 749 SkGammas::Data data[kMaxColorChannels]; 750 SkColorSpaceTransferFn params[kMaxColorChannels]; 751 SkGammas::Type type[kMaxColorChannels]; 752 const uint8_t* tagPtr[kMaxColorChannels]; 753 754 tagPtr[0] = tagSrc; 755 756 *gammaNamed = kNonStandard_SkGammaNamed; 757 758 // On an invalid first gamma, tagBytes remains set as zero. This causes the two 759 // subsequent to be treated as identical (which is what we want). 760 size_t tagBytes = 0; 761 type[0] = parse_gamma(&data[0], ¶ms[0], &tagBytes, tagPtr[0], tagLen); 762 handle_invalid_gamma(&type[0], &data[0]); 763 size_t alignedTagBytes = SkAlign4(tagBytes); 764 765 bool allChannelsSame = false; 766 if (inputChannels * alignedTagBytes <= tagLen) { 767 allChannelsSame = true; 768 for (uint8_t i = 1; i < inputChannels; ++i) { 769 if (0 != memcmp(tagSrc, tagSrc + i * alignedTagBytes, tagBytes)) { 770 allChannelsSame = false; 771 break; 772 } 773 } 774 } 775 if (allChannelsSame) { 776 if (SkGammas::Type::kNamed_Type == type[0]) { 777 *gammaNamed = data[0].fNamed; 778 } else { 779 size_t allocSize = sizeof(SkGammas); 780 return_if_false(safe_add(allocSize, gamma_alloc_size(type[0], data[0]), &allocSize), 781 "SkGammas struct is too large to allocate"); 782 void* memory = sk_malloc_throw(allocSize); 783 *gammas = sk_sp<SkGammas>(new (memory) SkGammas(inputChannels)); 784 load_gammas(memory, 0, type[0], &data[0], params[0], tagPtr[0]); 785 786 for (uint8_t channel = 0; channel < inputChannels; ++channel) { 787 (*gammas)->fType[channel] = type[0]; 788 (*gammas)->fData[channel] = data[0]; 789 } 790 } 791 } else { 792 for (uint8_t channel = 1; channel < inputChannels; ++channel) { 793 tagPtr[channel] = tagPtr[channel - 1] + alignedTagBytes; 794 tagLen = tagLen > alignedTagBytes ? tagLen - alignedTagBytes : 0; 795 tagBytes = 0; 796 type[channel] = parse_gamma(&data[channel], ¶ms[channel], &tagBytes, 797 tagPtr[channel], tagLen); 798 handle_invalid_gamma(&type[channel], &data[channel]); 799 alignedTagBytes = SkAlign4(tagBytes); 800 } 801 802 size_t allocSize = sizeof(SkGammas); 803 for (uint8_t channel = 0; channel < inputChannels; ++channel) { 804 return_if_false(safe_add(allocSize, gamma_alloc_size(type[channel], data[channel]), 805 &allocSize), 806 "SkGammas struct is too large to allocate"); 807 } 808 void* memory = sk_malloc_throw(allocSize); 809 *gammas = sk_sp<SkGammas>(new (memory) SkGammas(inputChannels)); 810 811 uint32_t offset = 0; 812 for (uint8_t channel = 0; channel < inputChannels; ++channel) { 813 (*gammas)->fType[channel] = type[channel]; 814 offset += load_gammas(memory,offset, type[channel], &data[channel], params[channel], 815 tagPtr[channel]); 816 (*gammas)->fData[channel] = data[channel]; 817 818 } 819 } 820 821 if (kNonStandard_SkGammaNamed == *gammaNamed) { 822 *gammaNamed = is_named(*gammas); 823 if (kNonStandard_SkGammaNamed != *gammaNamed) { 824 // No need to keep the gammas struct, the enum is enough. 825 *gammas = nullptr; 826 } 827 } 828 return true; 829 } 830 831 static bool is_lut_gamma_linear(const uint8_t* src, size_t count, size_t precision) { 832 // check for linear gamma (this is very common in lut gammas, as they aren't optional) 833 const float normalizeX = 1.f / (count - 1); 834 for (uint32_t x = 0; x < count; ++x) { 835 const float y = precision == 1 ? (src[x] / 255.f) 836 : (read_big_endian_u16(src + 2*x) / 65535.f); 837 if (!color_space_almost_equal(x * normalizeX, y)) { 838 return false; 839 } 840 } 841 return true; 842 } 843 844 static bool load_lut_gammas(sk_sp<SkGammas>* gammas, SkGammaNamed* gammaNamed, size_t numTables, 845 size_t entriesPerTable, size_t precision, const uint8_t* src, 846 size_t len) { 847 if (precision != 1 && precision != 2) { 848 SkColorSpacePrintf("Invalid gamma table precision %d\n", precision); 849 return false; 850 } 851 uint32_t totalEntries; 852 return_if_false(safe_mul(entriesPerTable, numTables, &totalEntries), 853 "Too many entries in gamma table."); 854 uint32_t readBytes; 855 return_if_false(safe_mul(precision, totalEntries, &readBytes), 856 "SkGammas struct is too large to read"); 857 if (len < readBytes) { 858 SkColorSpacePrintf("Gamma table is too small. Provided: %d. Required: %d\n", 859 len, readBytes); 860 return false; 861 } 862 863 uint32_t writeBytesPerChannel; 864 return_if_false(safe_mul(sizeof(float), entriesPerTable, &writeBytesPerChannel), 865 "SkGammas struct is too large to allocate"); 866 const size_t readBytesPerChannel = precision * entriesPerTable; 867 size_t numTablesToUse = 1; 868 for (size_t tableIndex = 1; tableIndex < numTables; ++tableIndex) { 869 if (0 != memcmp(src, src + readBytesPerChannel * tableIndex, readBytesPerChannel)) { 870 numTablesToUse = numTables; 871 break; 872 } 873 } 874 875 if (1 == numTablesToUse) { 876 if (is_lut_gamma_linear(src, entriesPerTable, precision)) { 877 *gammaNamed = kLinear_SkGammaNamed; 878 return true; 879 } 880 } 881 *gammaNamed = kNonStandard_SkGammaNamed; 882 883 uint32_t writetableBytes; 884 return_if_false(safe_mul(numTablesToUse, writeBytesPerChannel, &writetableBytes), 885 "SkGammas struct is too large to allocate"); 886 size_t allocSize = sizeof(SkGammas); 887 return_if_false(safe_add(allocSize, (size_t)writetableBytes, &allocSize), 888 "SkGammas struct is too large to allocate"); 889 890 void* memory = sk_malloc_throw(allocSize); 891 *gammas = sk_sp<SkGammas>(new (memory) SkGammas(numTables)); 892 893 for (size_t tableIndex = 0; tableIndex < numTablesToUse; ++tableIndex) { 894 const uint8_t* ptr = src + readBytesPerChannel * tableIndex; 895 const size_t offset = sizeof(SkGammas) + tableIndex * writeBytesPerChannel; 896 float* table = SkTAddOffset<float>(memory, offset); 897 if (1 == precision) { 898 for (uint32_t i = 0; i < entriesPerTable; ++i, ptr += 1) { 899 table[i] = ((float) *ptr) / 255.0f; 900 } 901 } else if (2 == precision) { 902 for (uint32_t i = 0; i < entriesPerTable; ++i, ptr += 2) { 903 table[i] = ((float) read_big_endian_u16(ptr)) / 65535.0f; 904 } 905 } 906 } 907 908 SkASSERT(1 == numTablesToUse|| numTables == numTablesToUse); 909 910 size_t tableOffset = 0; 911 for (size_t tableIndex = 0; tableIndex < numTables; ++tableIndex) { 912 (*gammas)->fType[tableIndex] = SkGammas::Type::kTable_Type; 913 (*gammas)->fData[tableIndex].fTable.fOffset = tableOffset; 914 (*gammas)->fData[tableIndex].fTable.fSize = entriesPerTable; 915 if (numTablesToUse > 1) { 916 tableOffset += writeBytesPerChannel; 917 } 918 } 919 920 return true; 921 } 922 923 bool load_a2b0_a_to_b_type(std::vector<SkColorSpace_A2B::Element>* elements, const uint8_t* src, 924 size_t len, SkColorSpace_A2B::PCS pcs) { 925 SkASSERT(len >= 32); 926 // Read the number of channels. The four bytes (4-7) that we skipped are reserved and 927 // must be zero. 928 const uint8_t inputChannels = src[8]; 929 const uint8_t outputChannels = src[9]; 930 if (SkColorLookUpTable::kOutputChannels != outputChannels) { 931 // We only handle RGB outputs. The number of output channels must be 3. 932 SkColorSpacePrintf("Output channels (%d) must equal 3 in A to B tag.\n", outputChannels); 933 return false; 934 } 935 if (inputChannels == 0 || inputChannels > 4) { 936 // And we only support 4 input channels. 937 // ICC says up to 16 but our decode can only handle 4. 938 // It could easily be extended to support up to 8, but we only allow CMYK/RGB 939 // input color spaces which are 3 and 4 so let's restrict it to 4 instead of 8. 940 // We can always change this check when we support bigger input spaces. 941 SkColorSpacePrintf("Input channels (%d) must be between 1 and 4 in A to B tag.\n", 942 inputChannels); 943 return false; 944 } 945 946 947 // It is important that these are loaded in the order of application, as the 948 // order you construct an A2B color space's elements is the order it is applied 949 950 // If the offset is non-zero it indicates that the element is present. 951 const uint32_t offsetToACurves = read_big_endian_i32(src + 28); 952 if (0 != offsetToACurves && offsetToACurves < len) { 953 const size_t tagLen = len - offsetToACurves; 954 SkGammaNamed gammaNamed; 955 sk_sp<SkGammas> gammas; 956 if (!parse_and_load_gamma(&gammaNamed, &gammas, inputChannels, src + offsetToACurves, 957 tagLen)) { 958 return false; 959 } 960 if (gammas) { 961 elements->push_back(SkColorSpace_A2B::Element(std::move(gammas))); 962 } else if (kLinear_SkGammaNamed != gammaNamed) { 963 elements->push_back(SkColorSpace_A2B::Element(gammaNamed, inputChannels)); 964 } 965 } 966 967 const uint32_t offsetToColorLUT = read_big_endian_i32(src + 24); 968 if (0 != offsetToColorLUT && offsetToColorLUT < len) { 969 sk_sp<SkColorLookUpTable> colorLUT; 970 const uint8_t* clutSrc = src + offsetToColorLUT; 971 const size_t clutLen = len - offsetToColorLUT; 972 // 16 bytes reserved for grid points, 1 for precision, 3 for padding. 973 // The color LUT data follows after this header. 974 static constexpr uint32_t kColorLUTHeaderSize = 20; 975 if (clutLen < kColorLUTHeaderSize) { 976 SkColorSpacePrintf("Color LUT tag is too small (%d bytes).", clutLen); 977 return false; 978 } 979 980 SkASSERT(inputChannels <= kMaxColorChannels); 981 uint8_t gridPoints[kMaxColorChannels]; 982 for (uint32_t i = 0; i < inputChannels; ++i) { 983 gridPoints[i] = clutSrc[i]; 984 } 985 // Space is provided for a maximum of 16 input channels. 986 // Now we determine the precision of the table values. 987 const uint8_t precision = clutSrc[16]; 988 if (!load_color_lut(&colorLUT, inputChannels, precision, gridPoints, 989 clutSrc + kColorLUTHeaderSize, clutLen - kColorLUTHeaderSize)) { 990 SkColorSpacePrintf("Failed to read color LUT from A to B tag.\n"); 991 return false; 992 } 993 elements->push_back(SkColorSpace_A2B::Element(std::move(colorLUT))); 994 } 995 996 const uint32_t offsetToMCurves = read_big_endian_i32(src + 20); 997 if (0 != offsetToMCurves && offsetToMCurves < len) { 998 const size_t tagLen = len - offsetToMCurves; 999 SkGammaNamed gammaNamed; 1000 sk_sp<SkGammas> gammas; 1001 if (!parse_and_load_gamma(&gammaNamed, &gammas, outputChannels, src + offsetToMCurves, 1002 tagLen)) { 1003 return false; 1004 } 1005 if (gammas) { 1006 elements->push_back(SkColorSpace_A2B::Element(std::move(gammas))); 1007 } else if (kLinear_SkGammaNamed != gammaNamed) { 1008 elements->push_back(SkColorSpace_A2B::Element(gammaNamed, outputChannels)); 1009 } 1010 } 1011 1012 const uint32_t offsetToMatrix = read_big_endian_i32(src + 16); 1013 if (0 != offsetToMatrix && offsetToMatrix < len) { 1014 SkMatrix44 matrix(SkMatrix44::kUninitialized_Constructor); 1015 if (!load_matrix(&matrix, src + offsetToMatrix, len - offsetToMatrix, true, pcs)) { 1016 SkColorSpacePrintf("Failed to read matrix from A to B tag.\n"); 1017 } else if (!matrix.isIdentity()) { 1018 elements->push_back(SkColorSpace_A2B::Element(matrix)); 1019 } 1020 } 1021 1022 const uint32_t offsetToBCurves = read_big_endian_i32(src + 12); 1023 if (0 != offsetToBCurves && offsetToBCurves < len) { 1024 const size_t tagLen = len - offsetToBCurves; 1025 SkGammaNamed gammaNamed; 1026 sk_sp<SkGammas> gammas; 1027 if (!parse_and_load_gamma(&gammaNamed, &gammas, outputChannels, src + offsetToBCurves, 1028 tagLen)) { 1029 return false; 1030 } 1031 if (gammas) { 1032 elements->push_back(SkColorSpace_A2B::Element(std::move(gammas))); 1033 } else if (kLinear_SkGammaNamed != gammaNamed) { 1034 elements->push_back(SkColorSpace_A2B::Element(gammaNamed, outputChannels)); 1035 } 1036 } 1037 1038 return true; 1039 } 1040 1041 bool load_a2b0_lutn_type(std::vector<SkColorSpace_A2B::Element>* elements, const uint8_t* src, 1042 size_t len, SkColorSpace_A2B::PCS pcs) { 1043 const uint32_t type = read_big_endian_u32(src); 1044 switch (type) { 1045 case kTAG_lut8Type: 1046 SkASSERT(len >= 48); 1047 break; 1048 case kTAG_lut16Type: 1049 SkASSERT(len >= 52); 1050 break; 1051 default: 1052 SkASSERT(false); 1053 return false; 1054 } 1055 // Read the number of channels. 1056 // The four bytes (4-7) that we skipped are reserved and must be zero. 1057 const uint8_t inputChannels = src[8]; 1058 const uint8_t outputChannels = src[9]; 1059 if (SkColorLookUpTable::kOutputChannels != outputChannels) { 1060 // We only handle RGB outputs. The number of output channels must be 3. 1061 SkColorSpacePrintf("Output channels (%d) must equal 3 in A to B tag.\n", outputChannels); 1062 return false; 1063 } 1064 if (inputChannels == 0 || inputChannels > 4) { 1065 // And we only support 4 input channels. 1066 // ICC says up to 16 but our decode can only handle 4. 1067 // It could easily be extended to support up to 8, but we only allow CMYK/RGB 1068 // input color spaces which are 3 and 4 so let's restrict it to 4 instead of 8. 1069 // We can always change this check when we support bigger input spaces. 1070 SkColorSpacePrintf("Input channels (%d) must be between 1 and 4 in A to B tag.\n", 1071 inputChannels); 1072 return false; 1073 } 1074 1075 const uint8_t clutGridPoints = src[10]; 1076 // 11th byte reserved for padding (required to be zero) 1077 1078 SkMatrix44 matrix(SkMatrix44::kUninitialized_Constructor); 1079 load_matrix(&matrix, &src[12], len - 12, false, pcs); 1080 if (!matrix.isIdentity()) { 1081 // ICC specs (10.8/10.9) say lut8/16Type profiles must have identity matrices 1082 // if the input color space is not PCSXYZ, and we do not support PCSXYZ input color spaces 1083 // so we should never encounter a non-identity matrix here. 1084 // However, 2 test images from the ICC website have RGB input spaces and non-identity 1085 // matrices so we're not going to fail here, despite being against the spec. 1086 SkColorSpacePrintf("Warning: non-Identity matrix found in non-XYZ input color space" 1087 "lut profile"); 1088 elements->push_back(SkColorSpace_A2B::Element(matrix)); 1089 } 1090 1091 size_t dataOffset = 48; 1092 // # of input table entries 1093 size_t inTableEntries = 256; 1094 // # of output table entries 1095 size_t outTableEntries = 256; 1096 size_t precision = 1; 1097 if (kTAG_lut16Type == type) { 1098 dataOffset = 52; 1099 inTableEntries = read_big_endian_u16(src + 48); 1100 outTableEntries = read_big_endian_u16(src + 50); 1101 precision = 2; 1102 1103 constexpr size_t kMaxLut16GammaEntries = 4096; 1104 if (inTableEntries < 2) { 1105 SkColorSpacePrintf("Too few (%d) input gamma table entries. Must have at least 2.\n", 1106 inTableEntries); 1107 return false; 1108 } else if (inTableEntries > kMaxLut16GammaEntries) { 1109 SkColorSpacePrintf("Too many (%d) input gamma table entries. Must have at most %d.\n", 1110 inTableEntries, kMaxLut16GammaEntries); 1111 return false; 1112 } 1113 1114 if (outTableEntries < 2) { 1115 SkColorSpacePrintf("Too few (%d) output gamma table entries. Must have at least 2.\n", 1116 outTableEntries); 1117 return false; 1118 } else if (outTableEntries > kMaxLut16GammaEntries) { 1119 SkColorSpacePrintf("Too many (%d) output gamma table entries. Must have at most %d.\n", 1120 outTableEntries, kMaxLut16GammaEntries); 1121 return false; 1122 } 1123 } 1124 1125 const size_t inputOffset = dataOffset; 1126 return_if_false(len >= inputOffset, "A2B0 lutnType tag too small for input gamma table"); 1127 sk_sp<SkGammas> inputGammas; 1128 SkGammaNamed inputGammaNamed; 1129 if (!load_lut_gammas(&inputGammas, &inputGammaNamed, inputChannels, inTableEntries, precision, 1130 src + inputOffset, len - inputOffset)) { 1131 SkColorSpacePrintf("Failed to read input gammas from lutnType tag.\n"); 1132 return false; 1133 } 1134 SkASSERT(inputGammas || inputGammaNamed != kNonStandard_SkGammaNamed); 1135 if (kLinear_SkGammaNamed != inputGammaNamed) { 1136 if (kNonStandard_SkGammaNamed != inputGammaNamed) { 1137 elements->push_back(SkColorSpace_A2B::Element(inputGammaNamed, inputChannels)); 1138 } else { 1139 elements->push_back(SkColorSpace_A2B::Element(std::move(inputGammas))); 1140 } 1141 } 1142 1143 const size_t clutOffset = inputOffset + precision*inTableEntries*inputChannels; 1144 return_if_false(len >= clutOffset, "A2B0 lutnType tag too small for CLUT"); 1145 sk_sp<SkColorLookUpTable> colorLUT; 1146 const uint8_t gridPoints[kMaxColorChannels] = { 1147 clutGridPoints, clutGridPoints, clutGridPoints, clutGridPoints 1148 }; 1149 if (!load_color_lut(&colorLUT, inputChannels, precision, gridPoints, src + clutOffset, 1150 len - clutOffset)) { 1151 SkColorSpacePrintf("Failed to read color LUT from lutnType tag.\n"); 1152 return false; 1153 } 1154 SkASSERT(colorLUT); 1155 elements->push_back(SkColorSpace_A2B::Element(std::move(colorLUT))); 1156 1157 size_t clutSize = precision * outputChannels; 1158 for (int i = 0; i < inputChannels; ++i) { 1159 clutSize *= clutGridPoints; 1160 } 1161 const size_t outputOffset = clutOffset + clutSize; 1162 return_if_false(len >= outputOffset, "A2B0 lutnType tag too small for output gamma table"); 1163 sk_sp<SkGammas> outputGammas; 1164 SkGammaNamed outputGammaNamed; 1165 if (!load_lut_gammas(&outputGammas, &outputGammaNamed, outputChannels, outTableEntries, 1166 precision, src + outputOffset, len - outputOffset)) { 1167 SkColorSpacePrintf("Failed to read output gammas from lutnType tag.\n"); 1168 return false; 1169 } 1170 SkASSERT(outputGammas || outputGammaNamed != kNonStandard_SkGammaNamed); 1171 if (kLinear_SkGammaNamed != outputGammaNamed) { 1172 if (kNonStandard_SkGammaNamed != outputGammaNamed) { 1173 elements->push_back(SkColorSpace_A2B::Element(outputGammaNamed, outputChannels)); 1174 } else { 1175 elements->push_back(SkColorSpace_A2B::Element(std::move(outputGammas))); 1176 } 1177 } 1178 1179 return true; 1180 } 1181 1182 static inline int icf_channels(SkColorSpace::Type iccType) { 1183 switch (iccType) { 1184 case SkColorSpace::kRGB_Type: 1185 return 3; 1186 case SkColorSpace::kCMYK_Type: 1187 return 4; 1188 default: 1189 SkASSERT(false); 1190 return 0; 1191 } 1192 } 1193 1194 static bool load_a2b0(std::vector<SkColorSpace_A2B::Element>* elements, const uint8_t* src, 1195 size_t len, SkColorSpace_A2B::PCS pcs, 1196 SkColorSpace::Type iccType) { 1197 if (len < 4) { 1198 return false; 1199 } 1200 const uint32_t type = read_big_endian_u32(src); 1201 1202 switch (type) { 1203 case kTAG_AtoBType: 1204 if (len < 32) { 1205 SkColorSpacePrintf("A to B tag is too small (%d bytes).", len); 1206 return false; 1207 } 1208 SkColorSpacePrintf("A2B0 tag is of type lutAtoBType\n"); 1209 if (!load_a2b0_a_to_b_type(elements, src, len, pcs)) { 1210 return false; 1211 } 1212 break; 1213 case kTAG_lut8Type: 1214 if (len < 48) { 1215 SkColorSpacePrintf("lut8 tag is too small (%d bytes).", len); 1216 return false; 1217 } 1218 SkColorSpacePrintf("A2B0 tag of type lut8Type\n"); 1219 if (!load_a2b0_lutn_type(elements, src, len, pcs)) { 1220 return false; 1221 } 1222 break; 1223 case kTAG_lut16Type: 1224 if (len < 52) { 1225 SkColorSpacePrintf("lut16 tag is too small (%d bytes).", len); 1226 return false; 1227 } 1228 SkColorSpacePrintf("A2B0 tag of type lut16Type\n"); 1229 if (!load_a2b0_lutn_type(elements, src, len, pcs)) { 1230 return false; 1231 } 1232 break; 1233 default: 1234 SkColorSpacePrintf("Unsupported A to B tag type: %c%c%c%c\n", (type>>24)&0xFF, 1235 (type>>16)&0xFF, (type>>8)&0xFF, type&0xFF); 1236 return false; 1237 } 1238 SkASSERT(SkColorSpace_A2B::PCS::kLAB == pcs || SkColorSpace_A2B::PCS::kXYZ == pcs); 1239 static constexpr int kPCSChannels = 3; // must be PCSLAB or PCSXYZ 1240 if (elements->empty()) { 1241 return kPCSChannels == icf_channels(iccType); 1242 } 1243 // now let's verify that the input/output channels of each A2B element actually match up 1244 if (icf_channels(iccType) != elements->front().inputChannels()) { 1245 SkColorSpacePrintf("Input channel count does not match first A2B element's input count"); 1246 return false; 1247 } 1248 for (size_t i = 1; i < elements->size(); ++i) { 1249 if ((*elements)[i - 1].outputChannels() != (*elements)[i].inputChannels()) { 1250 SkColorSpacePrintf("A2B elements don't agree in input/output channel counts"); 1251 return false; 1252 } 1253 } 1254 if (kPCSChannels != elements->back().outputChannels()) { 1255 SkColorSpacePrintf("PCS channel count doesn't match last A2B element's output count"); 1256 return false; 1257 } 1258 return true; 1259 } 1260 1261 static bool tag_equals(const ICCTag* a, const ICCTag* b, const uint8_t* base) { 1262 if (!a || !b) { 1263 return a == b; 1264 } 1265 1266 if (a->fLength != b->fLength) { 1267 return false; 1268 } 1269 1270 if (a->fOffset == b->fOffset) { 1271 return true; 1272 } 1273 1274 return !memcmp(a->addr(base), b->addr(base), a->fLength); 1275 } 1276 1277 static inline bool is_close_to_d50(const SkMatrix44& matrix) { 1278 // rX + gX + bX 1279 float X = matrix.getFloat(0, 0) + matrix.getFloat(0, 1) + matrix.getFloat(0, 2); 1280 1281 // rY + gY + bY 1282 float Y = matrix.getFloat(1, 0) + matrix.getFloat(1, 1) + matrix.getFloat(1, 2); 1283 1284 // rZ + gZ + bZ 1285 float Z = matrix.getFloat(2, 0) + matrix.getFloat(2, 1) + matrix.getFloat(2, 2); 1286 1287 static const float kD50_WhitePoint[3] = { 0.96420f, 1.00000f, 0.82491f }; 1288 1289 // This is a bit more lenient than QCMS and Adobe. Is there a reason to be stricter here? 1290 return (SkTAbs(X - kD50_WhitePoint[0]) <= 0.04f) && 1291 (SkTAbs(Y - kD50_WhitePoint[1]) <= 0.04f) && 1292 (SkTAbs(Z - kD50_WhitePoint[2]) <= 0.04f); 1293 } 1294 1295 static sk_sp<SkColorSpace> make_xyz(const ICCProfileHeader& header, ICCTag* tags, int tagCount, 1296 const uint8_t* base, sk_sp<SkData> profileData) { 1297 if (kLAB_PCSSpace == header.fPCS) { 1298 return nullptr; 1299 } 1300 1301 // Recognize the rXYZ, gXYZ, and bXYZ tags. 1302 const ICCTag* r = ICCTag::Find(tags, tagCount, kTAG_rXYZ); 1303 const ICCTag* g = ICCTag::Find(tags, tagCount, kTAG_gXYZ); 1304 const ICCTag* b = ICCTag::Find(tags, tagCount, kTAG_bXYZ); 1305 if (!r || !g || !b) { 1306 return nullptr; 1307 } 1308 1309 float toXYZ[9]; 1310 if (!load_xyz(&toXYZ[0], r->addr(base), r->fLength) || 1311 !load_xyz(&toXYZ[3], g->addr(base), g->fLength) || 1312 !load_xyz(&toXYZ[6], b->addr(base), b->fLength)) 1313 { 1314 return_null("Need valid rgb tags for XYZ space"); 1315 } 1316 SkMatrix44 mat(SkMatrix44::kUninitialized_Constructor); 1317 mat.set3x3(toXYZ[0], toXYZ[1], toXYZ[2], 1318 toXYZ[3], toXYZ[4], toXYZ[5], 1319 toXYZ[6], toXYZ[7], toXYZ[8]); 1320 if (!is_close_to_d50(mat)) { 1321 return_null("XYZ matrix is not D50"); 1322 } 1323 1324 // If some, but not all, of the gamma tags are missing, assume that all 1325 // gammas are meant to be the same. 1326 r = ICCTag::Find(tags, tagCount, kTAG_rTRC); 1327 g = ICCTag::Find(tags, tagCount, kTAG_gTRC); 1328 b = ICCTag::Find(tags, tagCount, kTAG_bTRC); 1329 if ((!r || !g || !b)) { 1330 if (!r) { 1331 r = g ? g : b; 1332 } 1333 if (!g) { 1334 g = r ? r : b; 1335 } 1336 if (!b) { 1337 b = r ? r : g; 1338 } 1339 } 1340 1341 SkGammaNamed gammaNamed = kNonStandard_SkGammaNamed; 1342 sk_sp<SkGammas> gammas = nullptr; 1343 size_t tagBytes; 1344 if (r && g && b) { 1345 if (tag_equals(r, g, base) && tag_equals(g, b, base)) { 1346 SkGammas::Data data; 1347 SkColorSpaceTransferFn params; 1348 SkGammas::Type type = 1349 parse_gamma(&data, ¶ms, &tagBytes, r->addr(base), r->fLength); 1350 handle_invalid_gamma(&type, &data); 1351 1352 if (SkGammas::Type::kNamed_Type == type) { 1353 gammaNamed = data.fNamed; 1354 } else { 1355 size_t allocSize = sizeof(SkGammas); 1356 if (!safe_add(allocSize, gamma_alloc_size(type, data), &allocSize)) { 1357 return_null("SkGammas struct is too large to allocate"); 1358 } 1359 void* memory = sk_malloc_throw(allocSize); 1360 gammas = sk_sp<SkGammas>(new (memory) SkGammas(3)); 1361 load_gammas(memory, 0, type, &data, params, r->addr(base)); 1362 1363 for (int i = 0; i < 3; ++i) { 1364 gammas->fType[i] = type; 1365 gammas->fData[i] = data; 1366 } 1367 } 1368 } else { 1369 SkGammas::Data rData; 1370 SkColorSpaceTransferFn rParams; 1371 SkGammas::Type rType = 1372 parse_gamma(&rData, &rParams, &tagBytes, r->addr(base), r->fLength); 1373 handle_invalid_gamma(&rType, &rData); 1374 1375 SkGammas::Data gData; 1376 SkColorSpaceTransferFn gParams; 1377 SkGammas::Type gType = 1378 parse_gamma(&gData, &gParams, &tagBytes, g->addr(base), g->fLength); 1379 handle_invalid_gamma(&gType, &gData); 1380 1381 SkGammas::Data bData; 1382 SkColorSpaceTransferFn bParams; 1383 SkGammas::Type bType = 1384 parse_gamma(&bData, &bParams, &tagBytes, b->addr(base), b->fLength); 1385 handle_invalid_gamma(&bType, &bData); 1386 1387 size_t allocSize = sizeof(SkGammas); 1388 if (!safe_add(allocSize, gamma_alloc_size(rType, rData), &allocSize) || 1389 !safe_add(allocSize, gamma_alloc_size(gType, gData), &allocSize) || 1390 !safe_add(allocSize, gamma_alloc_size(bType, bData), &allocSize)) { 1391 return_null("SkGammas struct is too large to allocate"); 1392 } 1393 void* memory = sk_malloc_throw(allocSize); 1394 gammas = sk_sp<SkGammas>(new (memory) SkGammas(3)); 1395 1396 uint32_t offset = 0; 1397 gammas->fType[0] = rType; 1398 offset += load_gammas(memory, offset, rType, &rData, rParams, 1399 r->addr(base)); 1400 1401 gammas->fType[1] = gType; 1402 offset += load_gammas(memory, offset, gType, &gData, gParams, 1403 g->addr(base)); 1404 1405 gammas->fType[2] = bType; 1406 load_gammas(memory, offset, bType, &bData, bParams, b->addr(base)); 1407 1408 gammas->fData[0] = rData; 1409 gammas->fData[1] = gData; 1410 gammas->fData[2] = bData; 1411 } 1412 } else { 1413 // Guess sRGB if the profile is missing transfer functions. 1414 gammaNamed = kSRGB_SkGammaNamed; 1415 } 1416 1417 if (kNonStandard_SkGammaNamed == gammaNamed) { 1418 // It's possible that we'll initially detect non-matching gammas, only for 1419 // them to evaluate to the same named gamma curve. 1420 gammaNamed = is_named(gammas); 1421 } 1422 1423 if (kNonStandard_SkGammaNamed == gammaNamed) { 1424 return sk_sp<SkColorSpace>(new SkColorSpace_XYZ(gammaNamed, 1425 std::move(gammas), 1426 mat, std::move(profileData))); 1427 } 1428 1429 return SkColorSpace::MakeRGB(gammaNamed, mat); 1430 } 1431 1432 static sk_sp<SkColorSpace> make_gray(const ICCProfileHeader& header, ICCTag* tags, int tagCount, 1433 const uint8_t* base, sk_sp<SkData> profileData) { 1434 if (kLAB_PCSSpace == header.fPCS) { 1435 return nullptr; 1436 } 1437 1438 const ICCTag* grayTRC = ICCTag::Find(tags, tagCount, kTAG_kTRC); 1439 if (!grayTRC) { 1440 return_null("grayTRC tag required for monochrome profiles."); 1441 } 1442 SkGammas::Data data; 1443 SkColorSpaceTransferFn params; 1444 size_t tagBytes; 1445 SkGammas::Type type = 1446 parse_gamma(&data, ¶ms, &tagBytes, grayTRC->addr(base), grayTRC->fLength); 1447 handle_invalid_gamma(&type, &data); 1448 1449 SkMatrix44 toXYZD50(SkMatrix44::kIdentity_Constructor); 1450 toXYZD50.setFloat(0, 0, kWhitePointD50[0]); 1451 toXYZD50.setFloat(1, 1, kWhitePointD50[1]); 1452 toXYZD50.setFloat(2, 2, kWhitePointD50[2]); 1453 if (SkGammas::Type::kNamed_Type == type) { 1454 return SkColorSpace::MakeRGB(data.fNamed, toXYZD50); 1455 } 1456 1457 size_t allocSize = sizeof(SkGammas); 1458 if (!safe_add(allocSize, gamma_alloc_size(type, data), &allocSize)) { 1459 return_null("SkGammas struct is too large to allocate"); 1460 } 1461 void* memory = sk_malloc_throw(allocSize); 1462 sk_sp<SkGammas> gammas = sk_sp<SkGammas>(new (memory) SkGammas(3)); 1463 load_gammas(memory, 0, type, &data, params, grayTRC->addr(base)); 1464 for (int i = 0; i < 3; ++i) { 1465 gammas->fType[i] = type; 1466 gammas->fData[i] = data; 1467 } 1468 1469 return sk_sp<SkColorSpace>(new SkColorSpace_XYZ(kNonStandard_SkGammaNamed, 1470 std::move(gammas), 1471 toXYZD50, std::move(profileData))); 1472 } 1473 1474 static sk_sp<SkColorSpace> make_a2b(SkColorSpace::Type iccType, 1475 const ICCProfileHeader& header, ICCTag* tags, int tagCount, 1476 const uint8_t* base, sk_sp<SkData> profileData) { 1477 const ICCTag* a2b0 = ICCTag::Find(tags, tagCount, kTAG_A2B0); 1478 if (a2b0) { 1479 const SkColorSpace_A2B::PCS pcs = kXYZ_PCSSpace == header.fPCS 1480 ? SkColorSpace_A2B::PCS::kXYZ 1481 : SkColorSpace_A2B::PCS::kLAB; 1482 std::vector<SkColorSpace_A2B::Element> elements; 1483 if (load_a2b0(&elements, a2b0->addr(base), a2b0->fLength, pcs, iccType)) { 1484 return sk_sp<SkColorSpace>(new SkColorSpace_A2B(iccType, std::move(elements), 1485 pcs, std::move(profileData))); 1486 } 1487 } 1488 1489 return nullptr; 1490 } 1491 1492 sk_sp<SkColorSpace> SkColorSpace::MakeICC(const void* input, size_t len) { 1493 if (!input || len < kICCHeaderSize) { 1494 return_null("Data is null or not large enough to contain an ICC profile"); 1495 } 1496 1497 // Create our own copy of the input. 1498 void* memory = sk_malloc_throw(len); 1499 memcpy(memory, input, len); 1500 sk_sp<SkData> profileData = SkData::MakeFromMalloc(memory, len); 1501 const uint8_t* base = profileData->bytes(); 1502 const uint8_t* ptr = base; 1503 1504 // Read the ICC profile header and check to make sure that it is valid. 1505 ICCProfileHeader header; 1506 header.init(ptr, len); 1507 if (!header.valid()) { 1508 return nullptr; 1509 } 1510 1511 // Adjust ptr and len before reading the tags. 1512 if (len < header.fSize) { 1513 SkColorSpacePrintf("ICC profile might be truncated.\n"); 1514 } else if (len > header.fSize) { 1515 SkColorSpacePrintf("Caller provided extra data beyond the end of the ICC profile.\n"); 1516 len = header.fSize; 1517 } 1518 ptr += kICCHeaderSize; 1519 len -= kICCHeaderSize; 1520 1521 // Parse tag headers. 1522 uint32_t tagCount = header.fTagCount; 1523 SkColorSpacePrintf("ICC profile contains %d tags.\n", tagCount); 1524 if (len < kICCTagTableEntrySize * tagCount) { 1525 return_null("Not enough input data to read tag table entries"); 1526 } 1527 1528 SkAutoTArray<ICCTag> tags(tagCount); 1529 for (uint32_t i = 0; i < tagCount; i++) { 1530 ptr = tags[i].init(ptr); 1531 SkColorSpacePrintf("[%d] %c%c%c%c %d %d\n", i, (tags[i].fSignature >> 24) & 0xFF, 1532 (tags[i].fSignature >> 16) & 0xFF, (tags[i].fSignature >> 8) & 0xFF, 1533 (tags[i].fSignature >> 0) & 0xFF, tags[i].fOffset, tags[i].fLength); 1534 1535 if (!tags[i].valid(kICCHeaderSize + len)) { 1536 return_null("Tag is too large to fit in ICC profile"); 1537 } 1538 } 1539 1540 Type a2b_type = kRGB_Type; 1541 switch (header.fInputColorSpace) { 1542 case kRGB_ColorSpace: { 1543 sk_sp<SkColorSpace> colorSpace = 1544 make_xyz(header, tags.get(), tagCount, base, profileData); 1545 if (colorSpace) { 1546 return colorSpace; 1547 } 1548 break; 1549 } 1550 case kGray_ColorSpace: { 1551 return make_gray(header, tags.get(), tagCount, base, profileData); 1552 } 1553 case kCMYK_ColorSpace: 1554 a2b_type = kCMYK_Type; 1555 break; 1556 default: 1557 return_null("ICC profile contains unsupported colorspace"); 1558 } 1559 1560 return make_a2b(a2b_type, header, tags.get(), tagCount, base, profileData); 1561 } 1562