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