| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright 2016 Google Inc. | 2 * Copyright 2016 Google Inc. |
| 3 * | 3 * |
| 4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
| 5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
| 6 */ | 6 */ |
| 7 | 7 |
| 8 #include "SkAtomics.h" | 8 #include "SkAtomics.h" |
| 9 #include "SkColorSpace.h" | 9 #include "SkColorSpace.h" |
| 10 | 10 |
| 11 void SkFloat3::dump() const { | 11 void SkFloat3::dump() const { |
| 12 SkDebugf("[%7.4f %7.4f %7.4f]\n", fVec[0], fVec[1], fVec[2]); | 12 SkDebugf("[%7.4f %7.4f %7.4f]\n", fVec[0], fVec[1], fVec[2]); |
| 13 } | 13 } |
| 14 | 14 |
| 15 void SkFloat3x3::dump() const { | |
| 16 SkDebugf("[%7.4f %7.4f %7.4f] [%7.4f %7.4f %7.4f] [%7.4f %7.4f %7.4f]\n", | |
| 17 fMat[0], fMat[1], fMat[2], | |
| 18 fMat[3], fMat[4], fMat[5], | |
| 19 fMat[6], fMat[7], fMat[8]); | |
| 20 } | |
| 21 | |
| 22 ////////////////////////////////////////////////////////////////////////////////
////////////////// | 15 ////////////////////////////////////////////////////////////////////////////////
////////////////// |
| 23 | 16 |
| 24 static int32_t gUniqueColorSpaceID; | 17 static int32_t gUniqueColorSpaceID; |
| 25 | 18 |
| 26 SkColorSpace::SkColorSpace(const SkFloat3& gamma, const SkFloat3x3& toXYZD50, Na
med named) | 19 SkColorSpace::SkColorSpace(const SkFloat3& gamma, const SkMatrix44& toXYZD50, Na
med named) |
| 27 : fGamma(gamma) | 20 : fGamma(gamma) |
| 28 , fToXYZD50(toXYZD50) | 21 , fToXYZD50(toXYZD50) |
| 29 , fToXYZOffset({{ 0.0f, 0.0f, 0.0f }}) | |
| 30 , fUniqueID(sk_atomic_inc(&gUniqueColorSpaceID)) | 22 , fUniqueID(sk_atomic_inc(&gUniqueColorSpaceID)) |
| 31 , fNamed(named) | 23 , fNamed(named) |
| 32 {} | 24 {} |
| 33 | 25 |
| 34 SkColorSpace::SkColorSpace(SkColorLookUpTable colorLUT, const SkFloat3& gamma, | 26 SkColorSpace::SkColorSpace(SkColorLookUpTable colorLUT, const SkFloat3& gamma, |
| 35 const SkFloat3x3& toXYZD50, const SkFloat3& toXYZOffs
et) | 27 const SkMatrix44& toXYZD50) |
| 36 : fColorLUT(std::move(colorLUT)) | 28 : fColorLUT(std::move(colorLUT)) |
| 37 , fGamma(gamma) | 29 , fGamma(gamma) |
| 38 , fToXYZD50(toXYZD50) | 30 , fToXYZD50(toXYZD50) |
| 39 , fToXYZOffset(toXYZOffset) | |
| 40 , fUniqueID(sk_atomic_inc(&gUniqueColorSpaceID)) | 31 , fUniqueID(sk_atomic_inc(&gUniqueColorSpaceID)) |
| 41 , fNamed(kUnknown_Named) | 32 , fNamed(kUnknown_Named) |
| 42 {} | 33 {} |
| 43 | 34 |
| 44 sk_sp<SkColorSpace> SkColorSpace::NewRGB(const SkFloat3x3& toXYZD50, const SkFlo
at3& gamma) { | 35 sk_sp<SkColorSpace> SkColorSpace::NewRGB(const SkMatrix44& toXYZD50, const SkFlo
at3& gamma) { |
| 45 return sk_sp<SkColorSpace>(new SkColorSpace(gamma, toXYZD50, kUnknown_Named)
); | 36 return sk_sp<SkColorSpace>(new SkColorSpace(gamma, toXYZD50, kUnknown_Named)
); |
| 46 } | 37 } |
| 47 | 38 |
| 48 const SkFloat3 gSRGB_gamma {{ 2.2f, 2.2f, 2.2f }}; | 39 const SkFloat3 gSRGB_gamma {{ 2.2f, 2.2f, 2.2f }}; |
| 49 const SkFloat3x3 gSRGB_toXYZD50 {{ | 40 const float gSRGB_toXYZD50[9] { |
| 50 0.4358f, 0.2224f, 0.0139f, // * R | 41 0.4358f, 0.2224f, 0.0139f, // * R |
| 51 0.3853f, 0.7170f, 0.0971f, // * G | 42 0.3853f, 0.7170f, 0.0971f, // * G |
| 52 0.1430f, 0.0606f, 0.7139f, // * B | 43 0.1430f, 0.0606f, 0.7139f, // * B |
| 53 }}; | 44 }; |
| 54 | 45 |
| 55 sk_sp<SkColorSpace> SkColorSpace::NewNamed(Named named) { | 46 sk_sp<SkColorSpace> SkColorSpace::NewNamed(Named named) { |
| 56 switch (named) { | 47 switch (named) { |
| 57 case kSRGB_Named: | 48 case kSRGB_Named: { |
| 58 return sk_sp<SkColorSpace>(new SkColorSpace(gSRGB_gamma, gSRGB_toXYZ
D50, kSRGB_Named)); | 49 SkMatrix44 srgbToxyzD50(SkMatrix44::kUninitialized_Constructor); |
| 50 srgbToxyzD50.set3x3ColMajorf(gSRGB_toXYZD50); |
| 51 return sk_sp<SkColorSpace>(new SkColorSpace(gSRGB_gamma, srgbToxyzD5
0, kSRGB_Named)); |
| 52 } |
| 59 default: | 53 default: |
| 60 break; | 54 break; |
| 61 } | 55 } |
| 62 return nullptr; | 56 return nullptr; |
| 63 } | 57 } |
| 64 | 58 |
| 65 ////////////////////////////////////////////////////////////////////////////////
/////////////////// | 59 ////////////////////////////////////////////////////////////////////////////////
/////////////////// |
| 66 | 60 |
| 67 #include "SkFixed.h" | 61 #include "SkFixed.h" |
| 68 #include "SkTemplates.h" | 62 #include "SkTemplates.h" |
| (...skipping 344 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 413 if (1 == precision) { | 407 if (1 == precision) { |
| 414 colorLUT->fTable[i] = ((float) ptr[i]) / 255.0f; | 408 colorLUT->fTable[i] = ((float) ptr[i]) / 255.0f; |
| 415 } else { | 409 } else { |
| 416 colorLUT->fTable[i] = ((float) read_big_endian_short(ptr)) / 65535.0
f; | 410 colorLUT->fTable[i] = ((float) read_big_endian_short(ptr)) / 65535.0
f; |
| 417 } | 411 } |
| 418 } | 412 } |
| 419 | 413 |
| 420 return true; | 414 return true; |
| 421 } | 415 } |
| 422 | 416 |
| 423 bool load_matrix(SkFloat3x3* toXYZ, SkFloat3* toXYZOffset, const uint8_t* src, s
ize_t len) { | 417 bool load_matrix(SkMatrix44* toXYZ, const uint8_t* src, size_t len) { |
| 424 if (len < 48) { | 418 if (len < 48) { |
| 425 SkColorSpacePrintf("Matrix tag is too small (%d bytes).", len); | 419 SkColorSpacePrintf("Matrix tag is too small (%d bytes).", len); |
| 426 return false; | 420 return false; |
| 427 } | 421 } |
| 428 | 422 |
| 429 toXYZ->fMat[0] = SkFixedToFloat(read_big_endian_int(src)); | 423 float array[16]; |
| 430 toXYZ->fMat[3] = SkFixedToFloat(read_big_endian_int(src + 4)); | 424 array[ 0] = SkFixedToFloat(read_big_endian_int(src)); |
| 431 toXYZ->fMat[6] = SkFixedToFloat(read_big_endian_int(src + 8)); | 425 array[ 1] = SkFixedToFloat(read_big_endian_int(src + 4)); |
| 432 toXYZ->fMat[1] = SkFixedToFloat(read_big_endian_int(src + 12)); | 426 array[ 2] = SkFixedToFloat(read_big_endian_int(src + 8)); |
| 433 toXYZ->fMat[4] = SkFixedToFloat(read_big_endian_int(src + 16)); | 427 array[ 3] = 0; |
| 434 toXYZ->fMat[7] = SkFixedToFloat(read_big_endian_int(src + 20)); | 428 array[ 4] = SkFixedToFloat(read_big_endian_int(src + 12)); |
| 435 toXYZ->fMat[2] = SkFixedToFloat(read_big_endian_int(src + 24)); | 429 array[ 5] = SkFixedToFloat(read_big_endian_int(src + 16)); |
| 436 toXYZ->fMat[5] = SkFixedToFloat(read_big_endian_int(src + 28)); | 430 array[ 6] = SkFixedToFloat(read_big_endian_int(src + 20)); |
| 437 toXYZ->fMat[8] = SkFixedToFloat(read_big_endian_int(src + 32)); | 431 array[ 7] = 0; |
| 438 toXYZOffset->fVec[0] = SkFixedToFloat(read_big_endian_int(src + 36)); | 432 array[ 8] = SkFixedToFloat(read_big_endian_int(src + 24)); |
| 439 toXYZOffset->fVec[1] = SkFixedToFloat(read_big_endian_int(src + 40)); | 433 array[ 9] = SkFixedToFloat(read_big_endian_int(src + 28)); |
| 440 toXYZOffset->fVec[2] = SkFixedToFloat(read_big_endian_int(src + 44)); | 434 array[10] = SkFixedToFloat(read_big_endian_int(src + 32)); |
| 435 array[11] = 0; |
| 436 array[12] = SkFixedToFloat(read_big_endian_int(src + 36)); // translate R |
| 437 array[13] = SkFixedToFloat(read_big_endian_int(src + 40)); // translate G |
| 438 array[14] = SkFixedToFloat(read_big_endian_int(src + 44)); |
| 439 array[15] = 1; |
| 440 toXYZ->setColMajorf(array); |
| 441 return true; | 441 return true; |
| 442 } | 442 } |
| 443 | 443 |
| 444 bool load_a2b0(SkColorLookUpTable* colorLUT, SkFloat3* gamma, SkFloat3x3* toXYZ, | 444 bool load_a2b0(SkColorLookUpTable* colorLUT, SkFloat3* gamma, SkMatrix44* toXYZ, |
| 445 SkFloat3* toXYZOffset, const uint8_t* src, size_t len) { | 445 const uint8_t* src, size_t len) { |
| 446 if (len < 32) { | 446 if (len < 32) { |
| 447 SkColorSpacePrintf("A to B tag is too small (%d bytes).", len); | 447 SkColorSpacePrintf("A to B tag is too small (%d bytes).", len); |
| 448 return false; | 448 return false; |
| 449 } | 449 } |
| 450 | 450 |
| 451 uint32_t type = read_big_endian_uint(src); | 451 uint32_t type = read_big_endian_uint(src); |
| 452 if (kTAG_AtoBType != type) { | 452 if (kTAG_AtoBType != type) { |
| 453 // FIXME (msarett): Need to support lut8Type and lut16Type. | 453 // FIXME (msarett): Need to support lut8Type and lut16Type. |
| 454 SkColorSpacePrintf("Unsupported A to B tag type.\n"); | 454 SkColorSpacePrintf("Unsupported A to B tag type.\n"); |
| 455 return false; | 455 return false; |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 492 uint32_t offsetToMCurves = read_big_endian_int(src + 20); | 492 uint32_t offsetToMCurves = read_big_endian_int(src + 20); |
| 493 if (0 != offsetToMCurves && offsetToMCurves < len) { | 493 if (0 != offsetToMCurves && offsetToMCurves < len) { |
| 494 if (!load_gammas(gamma->fVec, outputChannels, src + offsetToMCurves, len
- offsetToMCurves)) | 494 if (!load_gammas(gamma->fVec, outputChannels, src + offsetToMCurves, len
- offsetToMCurves)) |
| 495 { | 495 { |
| 496 SkColorSpacePrintf("Failed to read M curves from A to B tag.\n"); | 496 SkColorSpacePrintf("Failed to read M curves from A to B tag.\n"); |
| 497 } | 497 } |
| 498 } | 498 } |
| 499 | 499 |
| 500 uint32_t offsetToMatrix = read_big_endian_int(src + 16); | 500 uint32_t offsetToMatrix = read_big_endian_int(src + 16); |
| 501 if (0 != offsetToMatrix && offsetToMatrix < len) { | 501 if (0 != offsetToMatrix && offsetToMatrix < len) { |
| 502 if (!load_matrix(toXYZ, toXYZOffset, src + offsetToMatrix, len - offsetT
oMatrix)) { | 502 if (!load_matrix(toXYZ, src + offsetToMatrix, len - offsetToMatrix)) { |
| 503 SkColorSpacePrintf("Failed to read matrix from A to B tag.\n"); | 503 SkColorSpacePrintf("Failed to read matrix from A to B tag.\n"); |
| 504 } | 504 } |
| 505 } | 505 } |
| 506 | 506 |
| 507 return true; | 507 return true; |
| 508 } | 508 } |
| 509 | 509 |
| 510 sk_sp<SkColorSpace> SkColorSpace::NewICC(const void* base, size_t len) { | 510 sk_sp<SkColorSpace> SkColorSpace::NewICC(const void* base, size_t len) { |
| 511 const uint8_t* ptr = (const uint8_t*) base; | 511 const uint8_t* ptr = (const uint8_t*) base; |
| 512 | 512 |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 550 } | 550 } |
| 551 } | 551 } |
| 552 | 552 |
| 553 switch (header.fInputColorSpace) { | 553 switch (header.fInputColorSpace) { |
| 554 case kRGB_ColorSpace: { | 554 case kRGB_ColorSpace: { |
| 555 // Recognize the rXYZ, gXYZ, and bXYZ tags. | 555 // Recognize the rXYZ, gXYZ, and bXYZ tags. |
| 556 const ICCTag* r = ICCTag::Find(tags.get(), tagCount, kTAG_rXYZ); | 556 const ICCTag* r = ICCTag::Find(tags.get(), tagCount, kTAG_rXYZ); |
| 557 const ICCTag* g = ICCTag::Find(tags.get(), tagCount, kTAG_gXYZ); | 557 const ICCTag* g = ICCTag::Find(tags.get(), tagCount, kTAG_gXYZ); |
| 558 const ICCTag* b = ICCTag::Find(tags.get(), tagCount, kTAG_bXYZ); | 558 const ICCTag* b = ICCTag::Find(tags.get(), tagCount, kTAG_bXYZ); |
| 559 if (r && g && b) { | 559 if (r && g && b) { |
| 560 SkFloat3x3 toXYZ; | 560 float toXYZ[9]; |
| 561 if (!load_xyz(&toXYZ.fMat[0], r->addr((const uint8_t*) base), r-
>fLength) || | 561 if (!load_xyz(&toXYZ[0], r->addr((const uint8_t*) base), r->fLen
gth) || |
| 562 !load_xyz(&toXYZ.fMat[3], g->addr((const uint8_t*) base), g-
>fLength) || | 562 !load_xyz(&toXYZ[3], g->addr((const uint8_t*) base), g->fLen
gth) || |
| 563 !load_xyz(&toXYZ.fMat[6], b->addr((const uint8_t*) base), b-
>fLength)) | 563 !load_xyz(&toXYZ[6], b->addr((const uint8_t*) base), b->fLen
gth)) |
| 564 { | 564 { |
| 565 return_null("Need valid rgb tags for XYZ space"); | 565 return_null("Need valid rgb tags for XYZ space"); |
| 566 } | 566 } |
| 567 | 567 |
| 568 // It is not uncommon to see missing or empty gamma tags. This
indicates | 568 // It is not uncommon to see missing or empty gamma tags. This
indicates |
| 569 // that we should use unit gamma. | 569 // that we should use unit gamma. |
| 570 SkFloat3 gamma {{ 1.0f, 1.0f, 1.0f }}; | 570 SkFloat3 gamma {{ 1.0f, 1.0f, 1.0f }}; |
| 571 r = ICCTag::Find(tags.get(), tagCount, kTAG_rTRC); | 571 r = ICCTag::Find(tags.get(), tagCount, kTAG_rTRC); |
| 572 g = ICCTag::Find(tags.get(), tagCount, kTAG_gTRC); | 572 g = ICCTag::Find(tags.get(), tagCount, kTAG_gTRC); |
| 573 b = ICCTag::Find(tags.get(), tagCount, kTAG_bTRC); | 573 b = ICCTag::Find(tags.get(), tagCount, kTAG_bTRC); |
| 574 if (!r || | 574 if (!r || |
| 575 !load_gammas(&gamma.fVec[0], 1, r->addr((const uint8_t*) bas
e), r->fLength)) | 575 !load_gammas(&gamma.fVec[0], 1, r->addr((const uint8_t*) bas
e), r->fLength)) |
| 576 { | 576 { |
| 577 SkColorSpacePrintf("Failed to read R gamma tag.\n"); | 577 SkColorSpacePrintf("Failed to read R gamma tag.\n"); |
| 578 } | 578 } |
| 579 if (!g || | 579 if (!g || |
| 580 !load_gammas(&gamma.fVec[1], 1, g->addr((const uint8_t*) bas
e), g->fLength)) | 580 !load_gammas(&gamma.fVec[1], 1, g->addr((const uint8_t*) bas
e), g->fLength)) |
| 581 { | 581 { |
| 582 SkColorSpacePrintf("Failed to read G gamma tag.\n"); | 582 SkColorSpacePrintf("Failed to read G gamma tag.\n"); |
| 583 } | 583 } |
| 584 if (!b || | 584 if (!b || |
| 585 !load_gammas(&gamma.fVec[2], 1, b->addr((const uint8_t*) bas
e), b->fLength)) | 585 !load_gammas(&gamma.fVec[2], 1, b->addr((const uint8_t*) bas
e), b->fLength)) |
| 586 { | 586 { |
| 587 SkColorSpacePrintf("Failed to read B gamma tag.\n"); | 587 SkColorSpacePrintf("Failed to read B gamma tag.\n"); |
| 588 } | 588 } |
| 589 return SkColorSpace::NewRGB(toXYZ, gamma); | 589 |
| 590 SkMatrix44 mat(SkMatrix44::kUninitialized_Constructor); |
| 591 mat.set3x3ColMajorf(toXYZ); |
| 592 return SkColorSpace::NewRGB(mat, gamma); |
| 590 } | 593 } |
| 591 | 594 |
| 592 // Recognize color profile specified by A2B0 tag. | 595 // Recognize color profile specified by A2B0 tag. |
| 593 const ICCTag* a2b0 = ICCTag::Find(tags.get(), tagCount, kTAG_A2B0); | 596 const ICCTag* a2b0 = ICCTag::Find(tags.get(), tagCount, kTAG_A2B0); |
| 594 if (a2b0) { | 597 if (a2b0) { |
| 595 SkColorLookUpTable colorLUT; | 598 SkColorLookUpTable colorLUT; |
| 596 SkFloat3 gamma; | 599 SkFloat3 gamma; |
| 597 SkFloat3x3 toXYZ; | 600 SkMatrix44 toXYZ(SkMatrix44::kUninitialized_Constructor); |
| 598 SkFloat3 toXYZOffset; | 601 if (!load_a2b0(&colorLUT, &gamma, &toXYZ, a2b0->addr((const uint
8_t*) base), |
| 599 if (!load_a2b0(&colorLUT, &gamma, &toXYZ, &toXYZOffset, | 602 a2b0->fLength)) { |
| 600 a2b0->addr((const uint8_t*) base), a2b0->fLength)) { | |
| 601 return_null("Failed to parse A2B0 tag"); | 603 return_null("Failed to parse A2B0 tag"); |
| 602 } | 604 } |
| 603 | 605 |
| 604 return sk_sp<SkColorSpace>(new SkColorSpace(std::move(colorLUT),
gamma, toXYZ, | 606 return sk_sp<SkColorSpace>(new SkColorSpace(std::move(colorLUT),
gamma, toXYZ)); |
| 605 toXYZOffset)); | |
| 606 } | 607 } |
| 607 | 608 |
| 608 } | 609 } |
| 609 default: | 610 default: |
| 610 break; | 611 break; |
| 611 } | 612 } |
| 612 | 613 |
| 613 return_null("ICC profile contains unsupported colorspace"); | 614 return_null("ICC profile contains unsupported colorspace"); |
| 614 } | 615 } |
| OLD | NEW |