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 |