| 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 #include "SkColorSpacePriv.h" |
| 10 #include "SkOnce.h" | 11 #include "SkOnce.h" |
| 11 | 12 |
| 12 static bool color_space_almost_equal(float a, float b) { | 13 static bool color_space_almost_equal(float a, float b) { |
| 13 return SkTAbs(a - b) < 0.01f; | 14 return SkTAbs(a - b) < 0.01f; |
| 14 } | 15 } |
| 15 | 16 |
| 16 void SkFloat3::dump() const { | |
| 17 SkDebugf("[%7.4f %7.4f %7.4f]\n", fVec[0], fVec[1], fVec[2]); | |
| 18 } | |
| 19 | |
| 20 ////////////////////////////////////////////////////////////////////////////////
////////////////// | 17 ////////////////////////////////////////////////////////////////////////////////
////////////////// |
| 21 | 18 |
| 22 static int32_t gUniqueColorSpaceID; | 19 static int32_t gUniqueColorSpaceID; |
| 23 | 20 |
| 24 SkColorSpace::SkColorSpace(SkGammas gammas, const SkMatrix44& toXYZD50, Named na
med) | 21 SkColorSpace::SkColorSpace(sk_sp<SkGammas> gammas, const SkMatrix44& toXYZD50, N
amed named) |
| 25 : fGammas(std::move(gammas)) | 22 : fGammas(gammas) |
| 26 , fToXYZD50(toXYZD50) | 23 , fToXYZD50(toXYZD50) |
| 27 , fUniqueID(sk_atomic_inc(&gUniqueColorSpaceID)) | 24 , fUniqueID(sk_atomic_inc(&gUniqueColorSpaceID)) |
| 28 , fNamed(named) | 25 , fNamed(named) |
| 29 {} | 26 {} |
| 30 | 27 |
| 31 SkColorSpace::SkColorSpace(SkColorLookUpTable colorLUT, SkGammas gammas, | 28 SkColorSpace::SkColorSpace(SkColorLookUpTable* colorLUT, sk_sp<SkGammas> gammas, |
| 32 const SkMatrix44& toXYZD50) | 29 const SkMatrix44& toXYZD50) |
| 33 : fColorLUT(std::move(colorLUT)) | 30 : fColorLUT(colorLUT) |
| 34 , fGammas(std::move(gammas)) | 31 , fGammas(gammas) |
| 35 , fToXYZD50(toXYZD50) | 32 , fToXYZD50(toXYZD50) |
| 36 , fUniqueID(sk_atomic_inc(&gUniqueColorSpaceID)) | 33 , fUniqueID(sk_atomic_inc(&gUniqueColorSpaceID)) |
| 37 , fNamed(kUnknown_Named) | 34 , fNamed(kUnknown_Named) |
| 38 {} | 35 {} |
| 39 | 36 |
| 40 const float gSRGB_toXYZD50[] { | 37 const float gSRGB_toXYZD50[] { |
| 41 0.4358f, 0.2224f, 0.0139f, // * R | 38 0.4358f, 0.2224f, 0.0139f, // * R |
| 42 0.3853f, 0.7170f, 0.0971f, // * G | 39 0.3853f, 0.7170f, 0.0971f, // * G |
| 43 0.1430f, 0.0606f, 0.7139f, // * B | 40 0.1430f, 0.0606f, 0.7139f, // * B |
| 44 }; | 41 }; |
| (...skipping 22 matching lines...) Expand all Loading... |
| 67 color_space_almost_equal(toXYZD50.getFloat(2, 2), standard[8]) && | 64 color_space_almost_equal(toXYZD50.getFloat(2, 2), standard[8]) && |
| 68 color_space_almost_equal(toXYZD50.getFloat(0, 3), 0.0f) && | 65 color_space_almost_equal(toXYZD50.getFloat(0, 3), 0.0f) && |
| 69 color_space_almost_equal(toXYZD50.getFloat(1, 3), 0.0f) && | 66 color_space_almost_equal(toXYZD50.getFloat(1, 3), 0.0f) && |
| 70 color_space_almost_equal(toXYZD50.getFloat(2, 3), 0.0f) && | 67 color_space_almost_equal(toXYZD50.getFloat(2, 3), 0.0f) && |
| 71 color_space_almost_equal(toXYZD50.getFloat(3, 0), 0.0f) && | 68 color_space_almost_equal(toXYZD50.getFloat(3, 0), 0.0f) && |
| 72 color_space_almost_equal(toXYZD50.getFloat(3, 1), 0.0f) && | 69 color_space_almost_equal(toXYZD50.getFloat(3, 1), 0.0f) && |
| 73 color_space_almost_equal(toXYZD50.getFloat(3, 2), 0.0f) && | 70 color_space_almost_equal(toXYZD50.getFloat(3, 2), 0.0f) && |
| 74 color_space_almost_equal(toXYZD50.getFloat(3, 3), 1.0f); | 71 color_space_almost_equal(toXYZD50.getFloat(3, 3), 1.0f); |
| 75 } | 72 } |
| 76 | 73 |
| 77 sk_sp<SkColorSpace> SkColorSpace::NewRGB(SkGammas gammas, const SkMatrix44& toXY
ZD50) { | 74 static SkOnce gStandardGammasOnce; |
| 75 static SkGammas* gStandardGammas; |
| 76 |
| 77 sk_sp<SkColorSpace> SkColorSpace::NewRGB(float gammaVals[3], const SkMatrix44& t
oXYZD50) { |
| 78 sk_sp<SkGammas> gammas = nullptr; |
| 79 |
| 78 // Check if we really have sRGB or Adobe RGB | 80 // Check if we really have sRGB or Adobe RGB |
| 79 if (color_space_almost_equal(2.2f, gammas.fRed.fValue) && | 81 if (color_space_almost_equal(2.2f, gammaVals[0]) && |
| 80 color_space_almost_equal(2.2f, gammas.fGreen.fValue) && | 82 color_space_almost_equal(2.2f, gammaVals[1]) && |
| 81 color_space_almost_equal(2.2f, gammas.fBlue.fValue)) | 83 color_space_almost_equal(2.2f, gammaVals[2])) |
| 82 { | 84 { |
| 85 gStandardGammasOnce([] { |
| 86 gStandardGammas = new SkGammas(2.2f, 2.2f, 2.2f); |
| 87 }); |
| 88 gammas = sk_ref_sp(gStandardGammas); |
| 89 |
| 83 if (xyz_almost_equal(toXYZD50, gSRGB_toXYZD50)) { | 90 if (xyz_almost_equal(toXYZD50, gSRGB_toXYZD50)) { |
| 84 return SkColorSpace::NewNamed(kSRGB_Named); | 91 return SkColorSpace::NewNamed(kSRGB_Named); |
| 85 } else if (xyz_almost_equal(toXYZD50, gAdobeRGB_toXYZD50)) { | 92 } else if (xyz_almost_equal(toXYZD50, gAdobeRGB_toXYZD50)) { |
| 86 return SkColorSpace::NewNamed(kAdobeRGB_Named); | 93 return SkColorSpace::NewNamed(kAdobeRGB_Named); |
| 87 } | 94 } |
| 88 } | 95 } |
| 89 | 96 |
| 90 return sk_sp<SkColorSpace>(new SkColorSpace(std::move(gammas), toXYZD50, kUn
known_Named)); | 97 if (!gammas) { |
| 98 gammas = sk_ref_sp(new SkGammas(gammaVals[0], gammaVals[1], gammaVals[2]
)); |
| 99 } |
| 100 return sk_sp<SkColorSpace>(new SkColorSpace(gammas, toXYZD50, kUnknown_Named
)); |
| 91 } | 101 } |
| 92 | 102 |
| 93 sk_sp<SkColorSpace> SkColorSpace::NewNamed(Named named) { | 103 sk_sp<SkColorSpace> SkColorSpace::NewNamed(Named named) { |
| 94 static SkOnce sRGBOnce; | 104 static SkOnce sRGBOnce; |
| 95 static SkColorSpace* sRGB; | 105 static SkColorSpace* sRGB; |
| 96 static SkOnce adobeRGBOnce; | 106 static SkOnce adobeRGBOnce; |
| 97 static SkColorSpace* adobeRGB; | 107 static SkColorSpace* adobeRGB; |
| 98 | 108 |
| 99 switch (named) { | 109 switch (named) { |
| 100 case kSRGB_Named: { | 110 case kSRGB_Named: { |
| 111 gStandardGammasOnce([] { |
| 112 gStandardGammas = new SkGammas(2.2f, 2.2f, 2.2f); |
| 113 }); |
| 114 |
| 101 sRGBOnce([] { | 115 sRGBOnce([] { |
| 102 SkMatrix44 srgbToxyzD50(SkMatrix44::kUninitialized_Constructor); | 116 SkMatrix44 srgbToxyzD50(SkMatrix44::kUninitialized_Constructor); |
| 103 srgbToxyzD50.set3x3ColMajorf(gSRGB_toXYZD50); | 117 srgbToxyzD50.set3x3ColMajorf(gSRGB_toXYZD50); |
| 104 sRGB = new SkColorSpace(SkGammas(2.2f, 2.2f, 2.2f), srgbToxyzD50
, kSRGB_Named); | 118 sRGB = new SkColorSpace(sk_ref_sp(gStandardGammas), srgbToxyzD50
, kSRGB_Named); |
| 105 }); | 119 }); |
| 106 return sk_ref_sp(sRGB); | 120 return sk_ref_sp(sRGB); |
| 107 } | 121 } |
| 108 case kAdobeRGB_Named: { | 122 case kAdobeRGB_Named: { |
| 123 gStandardGammasOnce([] { |
| 124 gStandardGammas = new SkGammas(2.2f, 2.2f, 2.2f); |
| 125 }); |
| 126 |
| 109 adobeRGBOnce([] { | 127 adobeRGBOnce([] { |
| 110 SkMatrix44 adobergbToxyzD50(SkMatrix44::kUninitialized_Construct
or); | 128 SkMatrix44 adobergbToxyzD50(SkMatrix44::kUninitialized_Construct
or); |
| 111 adobergbToxyzD50.set3x3ColMajorf(gAdobeRGB_toXYZD50); | 129 adobergbToxyzD50.set3x3ColMajorf(gAdobeRGB_toXYZD50); |
| 112 adobeRGB = new SkColorSpace(SkGammas(2.2f, 2.2f, 2.2f), adobergb
ToxyzD50, | 130 adobeRGB = new SkColorSpace(sk_ref_sp(gStandardGammas), adobergb
ToxyzD50, |
| 113 kAdobeRGB_Named); | 131 kAdobeRGB_Named); |
| 114 }); | 132 }); |
| 115 return sk_ref_sp(adobeRGB); | 133 return sk_ref_sp(adobeRGB); |
| 116 } | 134 } |
| 117 default: | 135 default: |
| 118 break; | 136 break; |
| 119 } | 137 } |
| 120 return nullptr; | 138 return nullptr; |
| 121 } | 139 } |
| 122 | 140 |
| (...skipping 406 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 529 array[10] = SkFixedToFloat(read_big_endian_int(src + 32)); | 547 array[10] = SkFixedToFloat(read_big_endian_int(src + 32)); |
| 530 array[11] = 0; | 548 array[11] = 0; |
| 531 array[12] = SkFixedToFloat(read_big_endian_int(src + 36)); // translate R | 549 array[12] = SkFixedToFloat(read_big_endian_int(src + 36)); // translate R |
| 532 array[13] = SkFixedToFloat(read_big_endian_int(src + 40)); // translate G | 550 array[13] = SkFixedToFloat(read_big_endian_int(src + 40)); // translate G |
| 533 array[14] = SkFixedToFloat(read_big_endian_int(src + 44)); | 551 array[14] = SkFixedToFloat(read_big_endian_int(src + 44)); |
| 534 array[15] = 1; | 552 array[15] = 1; |
| 535 toXYZ->setColMajorf(array); | 553 toXYZ->setColMajorf(array); |
| 536 return true; | 554 return true; |
| 537 } | 555 } |
| 538 | 556 |
| 539 bool SkColorSpace::LoadA2B0(SkColorLookUpTable* colorLUT, SkGammas* gammas, SkMa
trix44* toXYZ, | 557 bool SkColorSpace::LoadA2B0(SkColorLookUpTable* colorLUT, sk_sp<SkGammas> gammas
, SkMatrix44* toXYZ, |
| 540 const uint8_t* src, size_t len) { | 558 const uint8_t* src, size_t len) { |
| 541 if (len < 32) { | 559 if (len < 32) { |
| 542 SkColorSpacePrintf("A to B tag is too small (%d bytes).", len); | 560 SkColorSpacePrintf("A to B tag is too small (%d bytes).", len); |
| 543 return false; | 561 return false; |
| 544 } | 562 } |
| 545 | 563 |
| 546 uint32_t type = read_big_endian_uint(src); | 564 uint32_t type = read_big_endian_uint(src); |
| 547 if (kTAG_AtoBType != type) { | 565 if (kTAG_AtoBType != type) { |
| 548 // FIXME (msarett): Need to support lut8Type and lut16Type. | 566 // FIXME (msarett): Need to support lut8Type and lut16Type. |
| 549 SkColorSpacePrintf("Unsupported A to B tag type.\n"); | 567 SkColorSpacePrintf("Unsupported A to B tag type.\n"); |
| (...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 655 float toXYZ[9]; | 673 float toXYZ[9]; |
| 656 if (!load_xyz(&toXYZ[0], r->addr((const uint8_t*) base), r->fLen
gth) || | 674 if (!load_xyz(&toXYZ[0], r->addr((const uint8_t*) base), r->fLen
gth) || |
| 657 !load_xyz(&toXYZ[3], g->addr((const uint8_t*) base), g->fLen
gth) || | 675 !load_xyz(&toXYZ[3], g->addr((const uint8_t*) base), g->fLen
gth) || |
| 658 !load_xyz(&toXYZ[6], b->addr((const uint8_t*) base), b->fLen
gth)) | 676 !load_xyz(&toXYZ[6], b->addr((const uint8_t*) base), b->fLen
gth)) |
| 659 { | 677 { |
| 660 return_null("Need valid rgb tags for XYZ space"); | 678 return_null("Need valid rgb tags for XYZ space"); |
| 661 } | 679 } |
| 662 | 680 |
| 663 // It is not uncommon to see missing or empty gamma tags. This
indicates | 681 // It is not uncommon to see missing or empty gamma tags. This
indicates |
| 664 // that we should use unit gamma. | 682 // that we should use unit gamma. |
| 665 SkGammas gammas; | 683 sk_sp<SkGammas> gammas(new SkGammas()); |
| 666 r = ICCTag::Find(tags.get(), tagCount, kTAG_rTRC); | 684 r = ICCTag::Find(tags.get(), tagCount, kTAG_rTRC); |
| 667 g = ICCTag::Find(tags.get(), tagCount, kTAG_gTRC); | 685 g = ICCTag::Find(tags.get(), tagCount, kTAG_gTRC); |
| 668 b = ICCTag::Find(tags.get(), tagCount, kTAG_bTRC); | 686 b = ICCTag::Find(tags.get(), tagCount, kTAG_bTRC); |
| 669 if (!r || !SkColorSpace::LoadGammas(&gammas.fRed, 1, | 687 if (!r || !SkColorSpace::LoadGammas(&gammas->fRed, 1, |
| 670 r->addr((const uint8_t*) bas
e), r->fLength)) { | 688 r->addr((const uint8_t*) bas
e), r->fLength)) { |
| 671 SkColorSpacePrintf("Failed to read R gamma tag.\n"); | 689 SkColorSpacePrintf("Failed to read R gamma tag.\n"); |
| 672 } | 690 } |
| 673 if (!g || !SkColorSpace::LoadGammas(&gammas.fGreen, 1, | 691 if (!g || !SkColorSpace::LoadGammas(&gammas->fGreen, 1, |
| 674 g->addr((const uint8_t*) bas
e), g->fLength)) { | 692 g->addr((const uint8_t*) bas
e), g->fLength)) { |
| 675 SkColorSpacePrintf("Failed to read G gamma tag.\n"); | 693 SkColorSpacePrintf("Failed to read G gamma tag.\n"); |
| 676 } | 694 } |
| 677 if (!b || !SkColorSpace::LoadGammas(&gammas.fBlue, 1, | 695 if (!b || !SkColorSpace::LoadGammas(&gammas->fBlue, 1, |
| 678 b->addr((const uint8_t*) bas
e), b->fLength)) { | 696 b->addr((const uint8_t*) bas
e), b->fLength)) { |
| 679 SkColorSpacePrintf("Failed to read B gamma tag.\n"); | 697 SkColorSpacePrintf("Failed to read B gamma tag.\n"); |
| 680 } | 698 } |
| 681 | 699 |
| 682 SkMatrix44 mat(SkMatrix44::kUninitialized_Constructor); | 700 SkMatrix44 mat(SkMatrix44::kUninitialized_Constructor); |
| 683 mat.set3x3ColMajorf(toXYZ); | 701 mat.set3x3ColMajorf(toXYZ); |
| 684 return SkColorSpace::NewRGB(std::move(gammas), mat); | 702 if (gammas->isValues()) { |
| 703 // When we have values, take advantage of the NewFromRGB ini
tializer. |
| 704 // This allows us to check for canonical sRGB and Adobe RGB. |
| 705 float gammaVals[3]; |
| 706 gammaVals[0] = gammas->fRed.fValue; |
| 707 gammaVals[1] = gammas->fGreen.fValue; |
| 708 gammaVals[2] = gammas->fBlue.fValue; |
| 709 return SkColorSpace::NewRGB(gammaVals, mat); |
| 710 } else { |
| 711 return sk_sp<SkColorSpace>(new SkColorSpace(gammas, mat, kUn
known_Named)); |
| 712 } |
| 685 } | 713 } |
| 686 | 714 |
| 687 // Recognize color profile specified by A2B0 tag. | 715 // Recognize color profile specified by A2B0 tag. |
| 688 const ICCTag* a2b0 = ICCTag::Find(tags.get(), tagCount, kTAG_A2B0); | 716 const ICCTag* a2b0 = ICCTag::Find(tags.get(), tagCount, kTAG_A2B0); |
| 689 if (a2b0) { | 717 if (a2b0) { |
| 690 SkColorLookUpTable colorLUT; | 718 SkAutoTDelete<SkColorLookUpTable> colorLUT(new SkColorLookUpTabl
e()); |
| 691 SkGammas gammas; | 719 sk_sp<SkGammas> gammas(new SkGammas()); |
| 692 SkMatrix44 toXYZ(SkMatrix44::kUninitialized_Constructor); | 720 SkMatrix44 toXYZ(SkMatrix44::kUninitialized_Constructor); |
| 693 if (!SkColorSpace::LoadA2B0(&colorLUT, &gammas, &toXYZ, | 721 if (!SkColorSpace::LoadA2B0(colorLUT, gammas, &toXYZ, |
| 694 a2b0->addr((const uint8_t*) base), a
2b0->fLength)) { | 722 a2b0->addr((const uint8_t*) base), a
2b0->fLength)) { |
| 695 return_null("Failed to parse A2B0 tag"); | 723 return_null("Failed to parse A2B0 tag"); |
| 696 } | 724 } |
| 697 | 725 |
| 698 // If there is no colorLUT, use NewRGB. This allows us to check
if the | 726 if (colorLUT->fTable) { |
| 699 // profile is sRGB. | 727 return sk_sp<SkColorSpace>(new SkColorSpace(colorLUT.release
(), gammas, toXYZ)); |
| 700 if (!colorLUT.fTable) { | 728 } else if (gammas->isValues()) { |
| 701 return SkColorSpace::NewRGB(std::move(gammas), toXYZ); | 729 // When we have values, take advantage of the NewFromRGB ini
tializer. |
| 730 // This allows us to check for canonical sRGB and Adobe RGB. |
| 731 float gammaVals[3]; |
| 732 gammaVals[0] = gammas->fRed.fValue; |
| 733 gammaVals[1] = gammas->fGreen.fValue; |
| 734 gammaVals[2] = gammas->fBlue.fValue; |
| 735 return SkColorSpace::NewRGB(gammaVals, toXYZ); |
| 736 } else { |
| 737 return sk_sp<SkColorSpace>(new SkColorSpace(gammas, toXYZ, k
Unknown_Named)); |
| 702 } | 738 } |
| 703 | |
| 704 return sk_sp<SkColorSpace>(new SkColorSpace(std::move(colorLUT),
std::move(gammas), | |
| 705 toXYZ)); | |
| 706 } | 739 } |
| 707 | 740 |
| 708 } | 741 } |
| 709 default: | 742 default: |
| 710 break; | 743 break; |
| 711 } | 744 } |
| 712 | 745 |
| 713 return_null("ICC profile contains unsupported colorspace"); | 746 return_null("ICC profile contains unsupported colorspace"); |
| 714 } | 747 } |
| OLD | NEW |