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 "SkColorSpace.h" | 8 #include "SkColorSpace.h" |
9 #include "SkColorSpace_Base.h" | 9 #include "SkColorSpace_Base.h" |
10 #include "SkEndian.h" | 10 #include "SkEndian.h" |
11 #include "SkOnce.h" | 11 #include "SkOnce.h" |
12 | 12 |
13 #define SkColorSpacePrintf(...) | |
14 | |
13 static bool color_space_almost_equal(float a, float b) { | 15 static bool color_space_almost_equal(float a, float b) { |
14 return SkTAbs(a - b) < 0.01f; | 16 return SkTAbs(a - b) < 0.01f; |
15 } | 17 } |
16 | 18 |
17 //////////////////////////////////////////////////////////////////////////////// ////////////////// | 19 //////////////////////////////////////////////////////////////////////////////// ////////////////// |
18 | 20 |
19 SkColorSpace::SkColorSpace(GammaNamed gammaNamed, const SkMatrix44& toXYZD50, Na med named) | 21 SkColorSpace::SkColorSpace(GammaNamed gammaNamed, const SkMatrix44& toXYZD50, Na med named) |
20 : fGammaNamed(gammaNamed) | 22 : fGammaNamed(gammaNamed) |
21 , fToXYZD50(toXYZD50) | 23 , fToXYZD50(toXYZD50) |
22 , fNamed(named) | 24 , fNamed(named) |
23 {} | 25 {} |
24 | 26 |
25 SkColorSpace_Base::SkColorSpace_Base(sk_sp<SkGammas> gammas, const SkMatrix44& t oXYZD50, | 27 SkColorSpace_Base::SkColorSpace_Base(GammaNamed gammaNamed, const SkMatrix44& to XYZD50, Named named, |
msarett
2016/06/14 21:30:28
Now SkColorSpace's have a GammaNamed *or* the incr
| |
26 Named named, sk_sp<SkData> profileData) | 28 sk_sp<SkData> profileData) |
27 : INHERITED(kNonStandard_GammaNamed, toXYZD50, named) | 29 : INHERITED(gammaNamed, toXYZD50, named) |
28 , fGammas(std::move(gammas)) | 30 , fGammas(nullptr) |
29 , fProfileData(std::move(profileData)) | 31 , fProfileData(std::move(profileData)) |
30 {} | 32 {} |
31 | 33 |
32 SkColorSpace_Base::SkColorSpace_Base(sk_sp<SkGammas> gammas, GammaNamed gammaNam ed, | |
33 const SkMatrix44& toXYZD50, Named named, | |
34 sk_sp<SkData> profileData) | |
35 : INHERITED(gammaNamed, toXYZD50, named) | |
36 , fGammas(std::move(gammas)) | |
37 , fProfileData(std::move(profileData)) | |
38 {} | |
39 | |
40 SkColorSpace_Base::SkColorSpace_Base(SkColorLookUpTable* colorLUT, sk_sp<SkGamma s> gammas, | 34 SkColorSpace_Base::SkColorSpace_Base(SkColorLookUpTable* colorLUT, sk_sp<SkGamma s> gammas, |
41 const SkMatrix44& toXYZD50, sk_sp<SkData> p rofileData) | 35 const SkMatrix44& toXYZD50, sk_sp<SkData> p rofileData) |
42 : INHERITED(kNonStandard_GammaNamed, toXYZD50, kUnknown_Named) | 36 : INHERITED(kNonStandard_GammaNamed, toXYZD50, kUnknown_Named) |
43 , fColorLUT(colorLUT) | 37 , fColorLUT(colorLUT) |
44 , fGammas(std::move(gammas)) | 38 , fGammas(std::move(gammas)) |
45 , fProfileData(std::move(profileData)) | 39 , fProfileData(std::move(profileData)) |
46 {} | 40 {} |
47 | 41 |
48 static constexpr float gSRGB_toXYZD50[] { | 42 static constexpr float gSRGB_toXYZD50[] { |
49 0.4358f, 0.2224f, 0.0139f, // * R | 43 0.4358f, 0.2224f, 0.0139f, // * R |
(...skipping 25 matching lines...) Expand all Loading... | |
75 color_space_almost_equal(toXYZD50.getFloat(2, 2), standard[8]) && | 69 color_space_almost_equal(toXYZD50.getFloat(2, 2), standard[8]) && |
76 color_space_almost_equal(toXYZD50.getFloat(0, 3), 0.0f) && | 70 color_space_almost_equal(toXYZD50.getFloat(0, 3), 0.0f) && |
77 color_space_almost_equal(toXYZD50.getFloat(1, 3), 0.0f) && | 71 color_space_almost_equal(toXYZD50.getFloat(1, 3), 0.0f) && |
78 color_space_almost_equal(toXYZD50.getFloat(2, 3), 0.0f) && | 72 color_space_almost_equal(toXYZD50.getFloat(2, 3), 0.0f) && |
79 color_space_almost_equal(toXYZD50.getFloat(3, 0), 0.0f) && | 73 color_space_almost_equal(toXYZD50.getFloat(3, 0), 0.0f) && |
80 color_space_almost_equal(toXYZD50.getFloat(3, 1), 0.0f) && | 74 color_space_almost_equal(toXYZD50.getFloat(3, 1), 0.0f) && |
81 color_space_almost_equal(toXYZD50.getFloat(3, 2), 0.0f) && | 75 color_space_almost_equal(toXYZD50.getFloat(3, 2), 0.0f) && |
82 color_space_almost_equal(toXYZD50.getFloat(3, 3), 1.0f); | 76 color_space_almost_equal(toXYZD50.getFloat(3, 3), 1.0f); |
83 } | 77 } |
84 | 78 |
85 static SkOnce g2Dot2CurveGammasOnce; | 79 static void set_gamma_value(SkGammaCurve* gamma, float value) { |
86 static SkGammas* g2Dot2CurveGammas; | 80 if (color_space_almost_equal(2.2f, value)) { |
87 static SkOnce gLinearGammasOnce; | 81 gamma->fNamed = SkColorSpace::k2Dot2Curve_GammaNamed; |
88 static SkGammas* gLinearGammas; | 82 } else if (color_space_almost_equal(1.0f, value)) { |
89 | 83 gamma->fNamed = SkColorSpace::kLinear_GammaNamed; |
90 sk_sp<SkColorSpace> SkColorSpace::NewRGB(const float gammaVals[3], const SkMatri x44& toXYZD50) { | 84 } else if (color_space_almost_equal(0.0f, value)) { |
91 return SkColorSpace_Base::NewRGB(gammaVals, toXYZD50, nullptr); | 85 SkColorSpacePrintf("Treating invalid zero gamma as linear."); |
86 gamma->fNamed = SkColorSpace::kLinear_GammaNamed; | |
87 } | |
92 } | 88 } |
93 | 89 |
94 sk_sp<SkColorSpace> SkColorSpace_Base::NewRGB(const float gammaVals[3], const Sk Matrix44& toXYZD50, | 90 sk_sp<SkColorSpace> SkColorSpace_Base::NewRGB(float values[3], const SkMatrix44& toXYZD50) { |
95 sk_sp<SkData> profileData) { | 91 SkGammaCurve curves[3]; |
96 sk_sp<SkGammas> gammas = nullptr; | 92 set_gamma_value(&curves[0], values[0]); |
97 GammaNamed gammaNamed = kNonStandard_GammaNamed; | 93 set_gamma_value(&curves[1], values[1]); |
94 set_gamma_value(&curves[2], values[2]); | |
98 | 95 |
99 // Check if we really have sRGB or Adobe RGB | 96 GammaNamed gammaNamed = SkGammas::Named(curves); |
100 if (color_space_almost_equal(2.2f, gammaVals[0]) && | 97 if (kNonStandard_GammaNamed == gammaNamed) { |
101 color_space_almost_equal(2.2f, gammaVals[1]) && | 98 sk_sp<SkGammas> gammas(new SkGammas(std::move(curves[0]), std::move(curv es[1]), |
102 color_space_almost_equal(2.2f, gammaVals[2])) | 99 std::move(curves[2]))); |
103 { | 100 return sk_sp<SkColorSpace>(new SkColorSpace_Base(nullptr, gammas, toXYZD 50, nullptr)); |
104 g2Dot2CurveGammasOnce([] { | |
105 g2Dot2CurveGammas = new SkGammas(2.2f, 2.2f, 2.2f); | |
106 }); | |
107 gammas = sk_ref_sp(g2Dot2CurveGammas); | |
108 gammaNamed = k2Dot2Curve_GammaNamed; | |
109 | |
110 if (xyz_almost_equal(toXYZD50, gSRGB_toXYZD50)) { | |
111 return SkColorSpace::NewNamed(kSRGB_Named); | |
112 } else if (xyz_almost_equal(toXYZD50, gAdobeRGB_toXYZD50)) { | |
113 return SkColorSpace::NewNamed(kAdobeRGB_Named); | |
114 } | |
115 } else if (color_space_almost_equal(1.0f, gammaVals[0]) && | |
116 color_space_almost_equal(1.0f, gammaVals[1]) && | |
117 color_space_almost_equal(1.0f, gammaVals[2])) | |
118 { | |
119 gLinearGammasOnce([] { | |
120 gLinearGammas = new SkGammas(1.0f, 1.0f, 1.0f); | |
121 }); | |
122 gammas = sk_ref_sp(gLinearGammas); | |
123 gammaNamed = kLinear_GammaNamed; | |
124 } | 101 } |
125 | 102 |
126 if (!gammas) { | 103 return SkColorSpace_Base::NewRGB(gammaNamed, toXYZD50, nullptr); |
127 gammas = sk_sp<SkGammas>(new SkGammas(gammaVals[0], gammaVals[1], gammaV als[2])); | 104 } |
105 | |
106 sk_sp<SkColorSpace> SkColorSpace_Base::NewRGB(GammaNamed gammaNamed, const SkMat rix44& toXYZD50, | |
107 sk_sp<SkData> profileData) { | |
108 switch (gammaNamed) { | |
109 case kSRGB_GammaNamed: | |
110 if (xyz_almost_equal(toXYZD50, gSRGB_toXYZD50)) { | |
111 return SkColorSpace::NewNamed(kSRGB_Named); | |
112 } | |
113 break; | |
114 case k2Dot2Curve_GammaNamed: | |
115 if (xyz_almost_equal(toXYZD50, gAdobeRGB_toXYZD50)) { | |
116 return SkColorSpace::NewNamed(kAdobeRGB_Named); | |
117 } | |
118 break; | |
119 case kNonStandard_GammaNamed: | |
120 // This is not allowed. | |
121 return nullptr; | |
122 default: | |
123 break; | |
128 } | 124 } |
129 return sk_sp<SkColorSpace>(new SkColorSpace_Base(gammas, gammaNamed, toXYZD5 0, kUnknown_Named, | 125 |
130 std::move(profileData))); | 126 return sk_sp<SkColorSpace>(new SkColorSpace_Base(gammaNamed, toXYZD50, kUnkn own_Named, |
127 profileData)); | |
128 } | |
129 | |
130 sk_sp<SkColorSpace> SkColorSpace::NewRGB(GammaNamed gammaNamed, const SkMatrix44 & toXYZD50) { | |
131 return SkColorSpace_Base::NewRGB(gammaNamed, toXYZD50, nullptr); | |
131 } | 132 } |
132 | 133 |
133 sk_sp<SkColorSpace> SkColorSpace::NewNamed(Named named) { | 134 sk_sp<SkColorSpace> SkColorSpace::NewNamed(Named named) { |
134 static SkOnce sRGBOnce; | 135 static SkOnce sRGBOnce; |
135 static SkColorSpace* sRGB; | 136 static SkColorSpace* sRGB; |
136 static SkOnce adobeRGBOnce; | 137 static SkOnce adobeRGBOnce; |
137 static SkColorSpace* adobeRGB; | 138 static SkColorSpace* adobeRGB; |
138 | 139 |
139 switch (named) { | 140 switch (named) { |
140 case kSRGB_Named: { | 141 case kSRGB_Named: { |
141 g2Dot2CurveGammasOnce([] { | |
142 g2Dot2CurveGammas = new SkGammas(2.2f, 2.2f, 2.2f); | |
143 }); | |
144 | |
145 sRGBOnce([] { | 142 sRGBOnce([] { |
146 SkMatrix44 srgbToxyzD50(SkMatrix44::kUninitialized_Constructor); | 143 SkMatrix44 srgbToxyzD50(SkMatrix44::kUninitialized_Constructor); |
147 srgbToxyzD50.set3x3ColMajorf(gSRGB_toXYZD50); | 144 srgbToxyzD50.set3x3ColMajorf(gSRGB_toXYZD50); |
148 sRGB = new SkColorSpace_Base(sk_ref_sp(g2Dot2CurveGammas), k2Dot 2Curve_GammaNamed, | 145 sRGB = new SkColorSpace_Base(kSRGB_GammaNamed, srgbToxyzD50, kSR GB_Named, nullptr); |
149 srgbToxyzD50, kSRGB_Named, nullptr) ; | |
150 }); | 146 }); |
151 return sk_ref_sp(sRGB); | 147 return sk_ref_sp(sRGB); |
152 } | 148 } |
153 case kAdobeRGB_Named: { | 149 case kAdobeRGB_Named: { |
154 g2Dot2CurveGammasOnce([] { | |
155 g2Dot2CurveGammas = new SkGammas(2.2f, 2.2f, 2.2f); | |
156 }); | |
157 | |
158 adobeRGBOnce([] { | 150 adobeRGBOnce([] { |
159 SkMatrix44 adobergbToxyzD50(SkMatrix44::kUninitialized_Construct or); | 151 SkMatrix44 adobergbToxyzD50(SkMatrix44::kUninitialized_Construct or); |
160 adobergbToxyzD50.set3x3ColMajorf(gAdobeRGB_toXYZD50); | 152 adobergbToxyzD50.set3x3ColMajorf(gAdobeRGB_toXYZD50); |
161 adobeRGB = new SkColorSpace_Base(sk_ref_sp(g2Dot2CurveGammas), | 153 adobeRGB = new SkColorSpace_Base(k2Dot2Curve_GammaNamed, adoberg bToxyzD50, |
162 k2Dot2Curve_GammaNamed, adoberg bToxyzD50, | |
163 kAdobeRGB_Named, nullptr); | 154 kAdobeRGB_Named, nullptr); |
164 }); | 155 }); |
165 return sk_ref_sp(adobeRGB); | 156 return sk_ref_sp(adobeRGB); |
166 } | 157 } |
167 default: | 158 default: |
168 break; | 159 break; |
169 } | 160 } |
170 return nullptr; | 161 return nullptr; |
171 } | 162 } |
172 | 163 |
173 //////////////////////////////////////////////////////////////////////////////// /////////////////// | 164 //////////////////////////////////////////////////////////////////////////////// /////////////////// |
174 | 165 |
175 #include "SkFixed.h" | 166 #include "SkFixed.h" |
176 #include "SkTemplates.h" | 167 #include "SkTemplates.h" |
177 | 168 |
178 #define SkColorSpacePrintf(...) | |
179 | |
180 #define return_if_false(pred, msg) \ | 169 #define return_if_false(pred, msg) \ |
181 do { \ | 170 do { \ |
182 if (!(pred)) { \ | 171 if (!(pred)) { \ |
183 SkColorSpacePrintf("Invalid ICC Profile: %s.\n", (msg)); \ | 172 SkColorSpacePrintf("Invalid ICC Profile: %s.\n", (msg)); \ |
184 return false; \ | 173 return false; \ |
185 } \ | 174 } \ |
186 } while (0) | 175 } while (0) |
187 | 176 |
188 #define return_null(msg) \ | 177 #define return_null(msg) \ |
189 do { \ | 178 do { \ |
(...skipping 173 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
363 }; | 352 }; |
364 | 353 |
365 static constexpr uint32_t kTAG_rXYZ = SkSetFourByteTag('r', 'X', 'Y', 'Z'); | 354 static constexpr uint32_t kTAG_rXYZ = SkSetFourByteTag('r', 'X', 'Y', 'Z'); |
366 static constexpr uint32_t kTAG_gXYZ = SkSetFourByteTag('g', 'X', 'Y', 'Z'); | 355 static constexpr uint32_t kTAG_gXYZ = SkSetFourByteTag('g', 'X', 'Y', 'Z'); |
367 static constexpr uint32_t kTAG_bXYZ = SkSetFourByteTag('b', 'X', 'Y', 'Z'); | 356 static constexpr uint32_t kTAG_bXYZ = SkSetFourByteTag('b', 'X', 'Y', 'Z'); |
368 static constexpr uint32_t kTAG_rTRC = SkSetFourByteTag('r', 'T', 'R', 'C'); | 357 static constexpr uint32_t kTAG_rTRC = SkSetFourByteTag('r', 'T', 'R', 'C'); |
369 static constexpr uint32_t kTAG_gTRC = SkSetFourByteTag('g', 'T', 'R', 'C'); | 358 static constexpr uint32_t kTAG_gTRC = SkSetFourByteTag('g', 'T', 'R', 'C'); |
370 static constexpr uint32_t kTAG_bTRC = SkSetFourByteTag('b', 'T', 'R', 'C'); | 359 static constexpr uint32_t kTAG_bTRC = SkSetFourByteTag('b', 'T', 'R', 'C'); |
371 static constexpr uint32_t kTAG_A2B0 = SkSetFourByteTag('A', '2', 'B', '0'); | 360 static constexpr uint32_t kTAG_A2B0 = SkSetFourByteTag('A', '2', 'B', '0'); |
372 | 361 |
373 bool load_xyz(float dst[3], const uint8_t* src, size_t len) { | 362 static bool load_xyz(float dst[3], const uint8_t* src, size_t len) { |
374 if (len < 20) { | 363 if (len < 20) { |
375 SkColorSpacePrintf("XYZ tag is too small (%d bytes)", len); | 364 SkColorSpacePrintf("XYZ tag is too small (%d bytes)", len); |
376 return false; | 365 return false; |
377 } | 366 } |
378 | 367 |
379 dst[0] = SkFixedToFloat(read_big_endian_int(src + 8)); | 368 dst[0] = SkFixedToFloat(read_big_endian_int(src + 8)); |
380 dst[1] = SkFixedToFloat(read_big_endian_int(src + 12)); | 369 dst[1] = SkFixedToFloat(read_big_endian_int(src + 12)); |
381 dst[2] = SkFixedToFloat(read_big_endian_int(src + 16)); | 370 dst[2] = SkFixedToFloat(read_big_endian_int(src + 16)); |
382 SkColorSpacePrintf("XYZ %g %g %g\n", dst[0], dst[1], dst[2]); | 371 SkColorSpacePrintf("XYZ %g %g %g\n", dst[0], dst[1], dst[2]); |
383 return true; | 372 return true; |
384 } | 373 } |
385 | 374 |
386 static constexpr uint32_t kTAG_CurveType = SkSetFourByteTag('c', 'u', 'r', ' v'); | 375 static constexpr uint32_t kTAG_CurveType = SkSetFourByteTag('c', 'u', 'r', ' v'); |
387 static constexpr uint32_t kTAG_ParaCurveType = SkSetFourByteTag('p', 'a', 'r', ' a'); | 376 static constexpr uint32_t kTAG_ParaCurveType = SkSetFourByteTag('p', 'a', 'r', ' a'); |
388 | 377 |
389 bool load_gammas(SkGammaCurve* gammas, uint32_t numGammas, const uint8_t* src, s ize_t len) { | 378 static bool load_gammas(SkGammaCurve* gammas, uint32_t numGammas, const uint8_t* src, size_t len) { |
390 for (uint32_t i = 0; i < numGammas; i++) { | 379 for (uint32_t i = 0; i < numGammas; i++) { |
391 if (len < 12) { | 380 if (len < 12) { |
392 // FIXME (msarett): | 381 // FIXME (msarett): |
393 // We could potentially return false here after correctly parsing *s ome* of the | 382 // We could potentially return false here after correctly parsing *s ome* of the |
394 // gammas correctly. Should we somehow try to indicate a partial su ccess? | 383 // gammas correctly. Should we somehow try to indicate a partial su ccess? |
395 SkColorSpacePrintf("gamma tag is too small (%d bytes)", len); | 384 SkColorSpacePrintf("gamma tag is too small (%d bytes)", len); |
396 return false; | 385 return false; |
397 } | 386 } |
398 | 387 |
399 // We need to count the number of bytes in the tag, so we are able to mo ve to the | 388 // We need to count the number of bytes in the tag, so we are able to mo ve to the |
(...skipping 11 matching lines...) Expand all Loading... | |
411 !safe_add((size_t) 12, tagBytes, &tagBytes)) | 400 !safe_add((size_t) 12, tagBytes, &tagBytes)) |
412 { | 401 { |
413 SkColorSpacePrintf("Invalid gamma count"); | 402 SkColorSpacePrintf("Invalid gamma count"); |
414 return false; | 403 return false; |
415 } | 404 } |
416 | 405 |
417 if (0 == count) { | 406 if (0 == count) { |
418 // Some tags require a gamma curve, but the author doesn't a ctually want | 407 // Some tags require a gamma curve, but the author doesn't a ctually want |
419 // to transform the data. In this case, it is common to see a curve with | 408 // to transform the data. In this case, it is common to see a curve with |
420 // a count of 0. | 409 // a count of 0. |
421 gammas[i].fValue = 1.0f; | 410 gammas[i].fNamed = SkColorSpace::kLinear_GammaNamed; |
422 break; | 411 break; |
423 } else if (len < tagBytes) { | 412 } else if (len < tagBytes) { |
424 SkColorSpacePrintf("gamma tag is too small (%d bytes)", len) ; | 413 SkColorSpacePrintf("gamma tag is too small (%d bytes)", len) ; |
425 return false; | 414 return false; |
426 } | 415 } |
427 | 416 |
428 const uint16_t* table = (const uint16_t*) (src + 12); | 417 const uint16_t* table = (const uint16_t*) (src + 12); |
429 if (1 == count) { | 418 if (1 == count) { |
430 // The table entry is the gamma (with a bias of 256). | 419 // The table entry is the gamma (with a bias of 256). |
431 uint16_t value = read_big_endian_short((const uint8_t*) tabl e); | 420 float value = (read_big_endian_short((const uint8_t*) table) ) / 256.0f; |
432 gammas[i].fValue = value / 256.0f; | 421 set_gamma_value(&gammas[i], value); |
433 if (0.0f == gammas[i].fValue) { | 422 SkColorSpacePrintf("gamma %g\n", value); |
434 SkColorSpacePrintf("Cannot have zero gamma value"); | |
435 return false; | |
436 } | |
437 SkColorSpacePrintf("gamma %d %g\n", value, gammas[i].fValue) ; | |
438 break; | 423 break; |
439 } | 424 } |
440 | 425 |
441 // Check for frequently occurring curves and use a fast approxim ation. | 426 // Check for frequently occurring sRGB curves. |
442 // We do this by sampling a few values and see if they match our expectation. | 427 // We do this by sampling a few values and see if they match our expectation. |
443 // A more robust solution would be to compare each value in this curve against | 428 // A more robust solution would be to compare each value in this curve against |
444 // a 2.2f curve see if we remain below an error threshold. At t his time, | 429 // an sRGB curve to see if we remain below an error threshold. At this time, |
445 // we haven't seen any images in the wild that make this kind of | 430 // we haven't seen any images in the wild that make this kind of |
446 // calculation necessary. We encounter identical gamma curves o ver and | 431 // calculation necessary. We encounter identical gamma curves o ver and |
447 // over again, but relatively few variations. | 432 // over again, but relatively few variations. |
448 if (1024 == count) { | 433 if (1024 == count) { |
449 // The magic values were chosen because they match a very co mmon sRGB | 434 // The magic values were chosen because they match a very co mmon sRGB |
450 // gamma table and the less common Canon sRGB gamma table (w hich use | 435 // gamma table and the less common Canon sRGB gamma table (w hich use |
451 // different rounding rules). | 436 // different rounding rules). |
452 if (0 == read_big_endian_short((const uint8_t*) &table[0]) & & | 437 if (0 == read_big_endian_short((const uint8_t*) &table[0]) & & |
453 3366 == read_big_endian_short((const uint8_t*) &tabl e[257]) && | 438 3366 == read_big_endian_short((const uint8_t*) &tabl e[257]) && |
454 14116 == read_big_endian_short((const uint8_t*) &tab le[513]) && | 439 14116 == read_big_endian_short((const uint8_t*) &tab le[513]) && |
455 34318 == read_big_endian_short((const uint8_t*) &tab le[768]) && | 440 34318 == read_big_endian_short((const uint8_t*) &tab le[768]) && |
456 65535 == read_big_endian_short((const uint8_t*) &tab le[1023])) { | 441 65535 == read_big_endian_short((const uint8_t*) &tab le[1023])) { |
457 gammas[i].fValue = 2.2f; | 442 gammas[i].fNamed = SkColorSpace::kSRGB_GammaNamed; |
458 break; | 443 break; |
459 } | 444 } |
460 } else if (26 == count) { | 445 } else if (26 == count) { |
461 // The magic values were chosen because they match a very co mmon sRGB | 446 // The magic values were chosen because they match a very co mmon sRGB |
462 // gamma table. | 447 // gamma table. |
463 if (0 == read_big_endian_short((const uint8_t*) &table[0]) & & | 448 if (0 == read_big_endian_short((const uint8_t*) &table[0]) & & |
464 3062 == read_big_endian_short((const uint8_t*) &tabl e[6]) && | 449 3062 == read_big_endian_short((const uint8_t*) &tabl e[6]) && |
465 12824 == read_big_endian_short((const uint8_t*) &tab le[12]) && | 450 12824 == read_big_endian_short((const uint8_t*) &tab le[12]) && |
466 31237 == read_big_endian_short((const uint8_t*) &tab le[18]) && | 451 31237 == read_big_endian_short((const uint8_t*) &tab le[18]) && |
467 65535 == read_big_endian_short((const uint8_t*) &tab le[25])) { | 452 65535 == read_big_endian_short((const uint8_t*) &tab le[25])) { |
468 gammas[i].fValue = 2.2f; | 453 gammas[i].fNamed = SkColorSpace::kSRGB_GammaNamed; |
469 break; | 454 break; |
470 } | 455 } |
471 } else if (4096 == count) { | 456 } else if (4096 == count) { |
472 // The magic values were chosen because they match Nikon, Ep son, and | 457 // The magic values were chosen because they match Nikon, Ep son, and |
473 // LCMS sRGB gamma tables (all of which use different roundi ng rules). | 458 // LCMS sRGB gamma tables (all of which use different roundi ng rules). |
474 if (0 == read_big_endian_short((const uint8_t*) &table[0]) & & | 459 if (0 == read_big_endian_short((const uint8_t*) &table[0]) & & |
475 950 == read_big_endian_short((const uint8_t*) &table [515]) && | 460 950 == read_big_endian_short((const uint8_t*) &table [515]) && |
476 3342 == read_big_endian_short((const uint8_t*) &tabl e[1025]) && | 461 3342 == read_big_endian_short((const uint8_t*) &tabl e[1025]) && |
477 14079 == read_big_endian_short((const uint8_t*) &tab le[2051]) && | 462 14079 == read_big_endian_short((const uint8_t*) &tab le[2051]) && |
478 65535 == read_big_endian_short((const uint8_t*) &tab le[4095])) { | 463 65535 == read_big_endian_short((const uint8_t*) &tab le[4095])) { |
479 gammas[i].fValue = 2.2f; | 464 gammas[i].fNamed = SkColorSpace::kSRGB_GammaNamed; |
480 break; | 465 break; |
481 } | 466 } |
482 } | 467 } |
483 | 468 |
484 // Otherwise, fill in the interpolation table. | 469 // Otherwise, fill in the interpolation table. |
485 gammas[i].fTableSize = count; | 470 gammas[i].fTableSize = count; |
486 gammas[i].fTable = std::unique_ptr<float[]>(new float[count]); | 471 gammas[i].fTable = std::unique_ptr<float[]>(new float[count]); |
487 for (uint32_t j = 0; j < count; j++) { | 472 for (uint32_t j = 0; j < count; j++) { |
488 gammas[i].fTable[j] = | 473 gammas[i].fTable[j] = |
489 (read_big_endian_short((const uint8_t*) &table[j])) / 65535.0f; | 474 (read_big_endian_short((const uint8_t*) &table[j])) / 65535.0f; |
(...skipping 13 matching lines...) Expand all Loading... | |
503 uint16_t format = read_big_endian_short(src + 8); | 488 uint16_t format = read_big_endian_short(src + 8); |
504 if (kExponential_ParaCurveType == format) { | 489 if (kExponential_ParaCurveType == format) { |
505 tagBytes = 12 + 4; | 490 tagBytes = 12 + 4; |
506 if (len < tagBytes) { | 491 if (len < tagBytes) { |
507 SkColorSpacePrintf("gamma tag is too small (%d bytes)", len); | 492 SkColorSpacePrintf("gamma tag is too small (%d bytes)", len); |
508 return false; | 493 return false; |
509 } | 494 } |
510 | 495 |
511 // Y = X^g | 496 // Y = X^g |
512 int32_t g = read_big_endian_int(src + 12); | 497 int32_t g = read_big_endian_int(src + 12); |
513 gammas[i].fValue = SkFixedToFloat(g); | 498 set_gamma_value(&gammas[i], SkFixedToFloat(g)); |
514 } else { | 499 } else { |
515 // Here's where the real parametric gammas start. There are many | 500 // Here's where the real parametric gammas start. There are many |
516 // permutations of the same equations. | 501 // permutations of the same equations. |
517 // | 502 // |
518 // Y = (aX + b)^g + c for X >= d | 503 // Y = (aX + b)^g + c for X >= d |
519 // Y = eX + f otherwise | 504 // Y = eX + f otherwise |
520 // | 505 // |
521 // We will fill in with zeros as necessary to always match t he above form. | 506 // We will fill in with zeros as necessary to always match t he above form. |
522 float g = 0.0f, a = 0.0f, b = 0.0f, c = 0.0f, d = 0.0f, e = 0.0f, f = 0.0f; | 507 float g = 0.0f, a = 0.0f, b = 0.0f, c = 0.0f, d = 0.0f, e = 0.0f, f = 0.0f; |
523 switch(format) { | 508 switch(format) { |
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
600 } | 585 } |
601 | 586 |
602 // Recognize and simplify a very common parametric represent ation of sRGB gamma. | 587 // Recognize and simplify a very common parametric represent ation of sRGB gamma. |
603 if (color_space_almost_equal(0.9479f, a) && | 588 if (color_space_almost_equal(0.9479f, a) && |
604 color_space_almost_equal(0.0521f, b) && | 589 color_space_almost_equal(0.0521f, b) && |
605 color_space_almost_equal(0.0000f, c) && | 590 color_space_almost_equal(0.0000f, c) && |
606 color_space_almost_equal(0.0405f, d) && | 591 color_space_almost_equal(0.0405f, d) && |
607 color_space_almost_equal(0.0774f, e) && | 592 color_space_almost_equal(0.0774f, e) && |
608 color_space_almost_equal(0.0000f, f) && | 593 color_space_almost_equal(0.0000f, f) && |
609 color_space_almost_equal(2.4000f, g)) { | 594 color_space_almost_equal(2.4000f, g)) { |
610 gammas[i].fValue = 2.2f; | 595 gammas[i].fNamed = SkColorSpace::kSRGB_GammaNamed; |
611 } else { | 596 } else { |
612 // Fail on invalid gammas. | 597 // Fail on invalid gammas. |
613 if (d <= 0.0f) { | 598 if (d <= 0.0f) { |
614 // Y = (aX + b)^g + c for always | 599 // Y = (aX + b)^g + c for always |
615 if (0.0f == a || 0.0f == g) { | 600 if (0.0f == a || 0.0f == g) { |
616 SkColorSpacePrintf("A or G is zero, constant gam ma function " | 601 SkColorSpacePrintf("A or G is zero, constant gam ma function " |
617 "is nonsense"); | 602 "is nonsense"); |
618 return false; | 603 return false; |
619 } | 604 } |
620 } else if (d >= 1.0f) { | 605 } else if (d >= 1.0f) { |
(...skipping 20 matching lines...) Expand all Loading... | |
641 } | 626 } |
642 | 627 |
643 break; | 628 break; |
644 } | 629 } |
645 default: | 630 default: |
646 SkColorSpacePrintf("Unsupported gamma tag type %d\n", type); | 631 SkColorSpacePrintf("Unsupported gamma tag type %d\n", type); |
647 return false; | 632 return false; |
648 } | 633 } |
649 | 634 |
650 // Ensure that we have successfully read a gamma representation. | 635 // Ensure that we have successfully read a gamma representation. |
651 SkASSERT(gammas[i].isValue() || gammas[i].isTable() || gammas[i].isParam etric()); | 636 SkASSERT(gammas[i].isNamed() || gammas[i].isValue() || gammas[i].isTable () || |
637 gammas[i].isParametric()); | |
652 | 638 |
653 // Adjust src and len if there is another gamma curve to load. | 639 // Adjust src and len if there is another gamma curve to load. |
654 if (i != numGammas - 1) { | 640 if (i != numGammas - 1) { |
655 // Each curve is padded to 4-byte alignment. | 641 // Each curve is padded to 4-byte alignment. |
656 tagBytes = SkAlign4(tagBytes); | 642 tagBytes = SkAlign4(tagBytes); |
657 if (len < tagBytes) { | 643 if (len < tagBytes) { |
658 return false; | 644 return false; |
659 } | 645 } |
660 | 646 |
661 src += tagBytes; | 647 src += tagBytes; |
(...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
789 if (0 != offsetToColorLUT && offsetToColorLUT < len) { | 775 if (0 != offsetToColorLUT && offsetToColorLUT < len) { |
790 if (!load_color_lut(colorLUT, inputChannels, outputChannels, src + offse tToColorLUT, | 776 if (!load_color_lut(colorLUT, inputChannels, outputChannels, src + offse tToColorLUT, |
791 len - offsetToColorLUT)) { | 777 len - offsetToColorLUT)) { |
792 SkColorSpacePrintf("Failed to read color LUT from A to B tag.\n"); | 778 SkColorSpacePrintf("Failed to read color LUT from A to B tag.\n"); |
793 } | 779 } |
794 } | 780 } |
795 | 781 |
796 uint32_t offsetToMCurves = read_big_endian_int(src + 20); | 782 uint32_t offsetToMCurves = read_big_endian_int(src + 20); |
797 if (0 != offsetToMCurves && offsetToMCurves < len) { | 783 if (0 != offsetToMCurves && offsetToMCurves < len) { |
798 if (!load_gammas(gammas, outputChannels, src + offsetToMCurves, len - of fsetToMCurves)) { | 784 if (!load_gammas(gammas, outputChannels, src + offsetToMCurves, len - of fsetToMCurves)) { |
799 SkColorSpacePrintf("Failed to read M curves from A to B tag.\n"); | 785 SkColorSpacePrintf("Failed to read M curves from A to B tag. Using linear gamma.\n"); |
786 gammas[0].fNamed = SkColorSpace::kLinear_GammaNamed; | |
787 gammas[1].fNamed = SkColorSpace::kLinear_GammaNamed; | |
788 gammas[2].fNamed = SkColorSpace::kLinear_GammaNamed; | |
800 } | 789 } |
801 } | 790 } |
802 | 791 |
803 uint32_t offsetToMatrix = read_big_endian_int(src + 16); | 792 uint32_t offsetToMatrix = read_big_endian_int(src + 16); |
804 if (0 != offsetToMatrix && offsetToMatrix < len) { | 793 if (0 != offsetToMatrix && offsetToMatrix < len) { |
805 if (!load_matrix(toXYZ, src + offsetToMatrix, len - offsetToMatrix)) { | 794 if (!load_matrix(toXYZ, src + offsetToMatrix, len - offsetToMatrix)) { |
806 SkColorSpacePrintf("Failed to read matrix from A to B tag.\n"); | 795 SkColorSpacePrintf("Failed to read matrix from A to B tag.\n"); |
796 toXYZ->setIdentity(); | |
807 } | 797 } |
808 } | 798 } |
809 | 799 |
810 return true; | 800 return true; |
811 } | 801 } |
812 | 802 |
813 sk_sp<SkColorSpace> SkColorSpace::NewICC(const void* input, size_t len) { | 803 sk_sp<SkColorSpace> SkColorSpace::NewICC(const void* input, size_t len) { |
814 if (!input || len < kICCHeaderSize) { | 804 if (!input || len < kICCHeaderSize) { |
815 return_null("Data is null or not large enough to contain an ICC profile" ); | 805 return_null("Data is null or not large enough to contain an ICC profile" ); |
816 } | 806 } |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
865 const ICCTag* g = ICCTag::Find(tags.get(), tagCount, kTAG_gXYZ); | 855 const ICCTag* g = ICCTag::Find(tags.get(), tagCount, kTAG_gXYZ); |
866 const ICCTag* b = ICCTag::Find(tags.get(), tagCount, kTAG_bXYZ); | 856 const ICCTag* b = ICCTag::Find(tags.get(), tagCount, kTAG_bXYZ); |
867 if (r && g && b) { | 857 if (r && g && b) { |
868 float toXYZ[9]; | 858 float toXYZ[9]; |
869 if (!load_xyz(&toXYZ[0], r->addr((const uint8_t*) base), r->fLen gth) || | 859 if (!load_xyz(&toXYZ[0], r->addr((const uint8_t*) base), r->fLen gth) || |
870 !load_xyz(&toXYZ[3], g->addr((const uint8_t*) base), g->fLen gth) || | 860 !load_xyz(&toXYZ[3], g->addr((const uint8_t*) base), g->fLen gth) || |
871 !load_xyz(&toXYZ[6], b->addr((const uint8_t*) base), b->fLen gth)) | 861 !load_xyz(&toXYZ[6], b->addr((const uint8_t*) base), b->fLen gth)) |
872 { | 862 { |
873 return_null("Need valid rgb tags for XYZ space"); | 863 return_null("Need valid rgb tags for XYZ space"); |
874 } | 864 } |
865 SkMatrix44 mat(SkMatrix44::kUninitialized_Constructor); | |
866 mat.set3x3ColMajorf(toXYZ); | |
875 | 867 |
876 // It is not uncommon to see missing or empty gamma tags. This indicates | 868 // It is not uncommon to see missing or empty gamma tags. This indicates |
877 // that we should use unit gamma. | 869 // that we should use unit gamma. |
878 SkGammaCurve curves[3]; | 870 SkGammaCurve curves[3]; |
879 r = ICCTag::Find(tags.get(), tagCount, kTAG_rTRC); | 871 r = ICCTag::Find(tags.get(), tagCount, kTAG_rTRC); |
880 g = ICCTag::Find(tags.get(), tagCount, kTAG_gTRC); | 872 g = ICCTag::Find(tags.get(), tagCount, kTAG_gTRC); |
881 b = ICCTag::Find(tags.get(), tagCount, kTAG_bTRC); | 873 b = ICCTag::Find(tags.get(), tagCount, kTAG_bTRC); |
882 if (!r || !load_gammas(&curves[0], 1, r->addr((const uint8_t*) b ase), r->fLength)) | 874 if (!r || !load_gammas(&curves[0], 1, r->addr((const uint8_t*) b ase), r->fLength)) |
883 { | 875 { |
884 SkColorSpacePrintf("Failed to read R gamma tag.\n"); | 876 SkColorSpacePrintf("Failed to read R gamma tag.\n"); |
877 curves[0].fNamed = SkColorSpace::kLinear_GammaNamed; | |
885 } | 878 } |
886 if (!g || !load_gammas(&curves[1], 1, g->addr((const uint8_t*) b ase), g->fLength)) | 879 if (!g || !load_gammas(&curves[1], 1, g->addr((const uint8_t*) b ase), g->fLength)) |
887 { | 880 { |
888 SkColorSpacePrintf("Failed to read G gamma tag.\n"); | 881 SkColorSpacePrintf("Failed to read G gamma tag.\n"); |
882 curves[1].fNamed = SkColorSpace::kLinear_GammaNamed; | |
889 } | 883 } |
890 if (!b || !load_gammas(&curves[2], 1, b->addr((const uint8_t*) b ase), b->fLength)) | 884 if (!b || !load_gammas(&curves[2], 1, b->addr((const uint8_t*) b ase), b->fLength)) |
891 { | 885 { |
892 SkColorSpacePrintf("Failed to read B gamma tag.\n"); | 886 SkColorSpacePrintf("Failed to read B gamma tag.\n"); |
887 curves[2].fNamed = SkColorSpace::kLinear_GammaNamed; | |
893 } | 888 } |
894 | 889 |
895 sk_sp<SkGammas> gammas(new SkGammas(std::move(curves[0]), std::m ove(curves[1]), | 890 GammaNamed gammaNamed = SkGammas::Named(curves); |
896 std::move(curves[2]))); | 891 if (kNonStandard_GammaNamed == gammaNamed) { |
897 SkMatrix44 mat(SkMatrix44::kUninitialized_Constructor); | 892 sk_sp<SkGammas> gammas(new SkGammas(std::move(curves[0]), st d::move(curves[1]), |
898 mat.set3x3ColMajorf(toXYZ); | 893 std::move(curves[2]))); |
899 if (gammas->isValues()) { | 894 return sk_sp<SkColorSpace>(new SkColorSpace_Base(nullptr, st d::move(gammas), |
900 // When we have values, take advantage of the NewFromRGB ini tializer. | 895 mat, std::m ove(data))); |
901 // This allows us to check for canonical sRGB and Adobe RGB. | |
902 float gammaVals[3]; | |
903 gammaVals[0] = gammas->fRed.fValue; | |
904 gammaVals[1] = gammas->fGreen.fValue; | |
905 gammaVals[2] = gammas->fBlue.fValue; | |
906 return SkColorSpace_Base::NewRGB(gammaVals, mat, std::move(d ata)); | |
907 } else { | 896 } else { |
908 return sk_sp<SkColorSpace>(new SkColorSpace_Base(std::move(g ammas), mat, | 897 return SkColorSpace_Base::NewRGB(gammaNamed, mat, std::move( data)); |
909 kUnknown_Na med, | |
910 std::move(d ata))); | |
911 } | 898 } |
912 } | 899 } |
913 | 900 |
914 // Recognize color profile specified by A2B0 tag. | 901 // Recognize color profile specified by A2B0 tag. |
915 const ICCTag* a2b0 = ICCTag::Find(tags.get(), tagCount, kTAG_A2B0); | 902 const ICCTag* a2b0 = ICCTag::Find(tags.get(), tagCount, kTAG_A2B0); |
916 if (a2b0) { | 903 if (a2b0) { |
917 SkAutoTDelete<SkColorLookUpTable> colorLUT(new SkColorLookUpTabl e()); | 904 SkAutoTDelete<SkColorLookUpTable> colorLUT(new SkColorLookUpTabl e()); |
918 SkGammaCurve curves[3]; | 905 SkGammaCurve curves[3]; |
919 SkMatrix44 toXYZ(SkMatrix44::kUninitialized_Constructor); | 906 SkMatrix44 toXYZ(SkMatrix44::kUninitialized_Constructor); |
920 if (!load_a2b0(colorLUT, curves, &toXYZ, a2b0->addr((const uint8 _t*) base), | 907 if (!load_a2b0(colorLUT, curves, &toXYZ, a2b0->addr((const uint8 _t*) base), |
921 a2b0->fLength)) { | 908 a2b0->fLength)) { |
922 return_null("Failed to parse A2B0 tag"); | 909 return_null("Failed to parse A2B0 tag"); |
923 } | 910 } |
924 | 911 |
925 sk_sp<SkGammas> gammas(new SkGammas(std::move(curves[0]), std::m ove(curves[1]), | 912 GammaNamed gammaNamed = SkGammas::Named(curves); |
926 std::move(curves[2]))); | 913 if (colorLUT->fTable || kNonStandard_GammaNamed == gammaNamed) { |
927 if (colorLUT->fTable) { | 914 sk_sp<SkGammas> gammas(new SkGammas(std::move(curves[0]), st d::move(curves[1]), |
915 std::move(curves[2]))); | |
916 | |
928 return sk_sp<SkColorSpace>(new SkColorSpace_Base(colorLUT.re lease(), | 917 return sk_sp<SkColorSpace>(new SkColorSpace_Base(colorLUT.re lease(), |
929 std::move(g ammas), toXYZ, | 918 std::move(g ammas), toXYZ, |
930 std::move(d ata))); | 919 std::move(d ata))); |
931 } else if (gammas->isValues()) { | |
932 // When we have values, take advantage of the NewFromRGB ini tializer. | |
933 // This allows us to check for canonical sRGB and Adobe RGB. | |
934 float gammaVals[3]; | |
935 gammaVals[0] = gammas->fRed.fValue; | |
936 gammaVals[1] = gammas->fGreen.fValue; | |
937 gammaVals[2] = gammas->fBlue.fValue; | |
938 return SkColorSpace_Base::NewRGB(gammaVals, toXYZ, std::move (data)); | |
939 } else { | 920 } else { |
940 return sk_sp<SkColorSpace>(new SkColorSpace_Base(std::move(g ammas), toXYZ, | 921 return SkColorSpace_Base::NewRGB(gammaNamed, toXYZ, std::mov e(data)); |
941 kUnknown_Na med, | |
942 std::move(d ata))); | |
943 } | 922 } |
944 } | 923 } |
945 } | 924 } |
946 default: | 925 default: |
947 break; | 926 break; |
948 } | 927 } |
949 | 928 |
950 return_null("ICC profile contains unsupported colorspace"); | 929 return_null("ICC profile contains unsupported colorspace"); |
951 } | 930 } |
952 | 931 |
(...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1072 ptr[2] = SkEndian_SwapBE32(1); | 1051 ptr[2] = SkEndian_SwapBE32(1); |
1073 | 1052 |
1074 // Convert gamma to 16-bit fixed point. | 1053 // Convert gamma to 16-bit fixed point. |
1075 uint16_t* ptr16 = (uint16_t*) (ptr + 3); | 1054 uint16_t* ptr16 = (uint16_t*) (ptr + 3); |
1076 ptr16[0] = SkEndian_SwapBE16((uint16_t) (value * 256.0f)); | 1055 ptr16[0] = SkEndian_SwapBE16((uint16_t) (value * 256.0f)); |
1077 | 1056 |
1078 // Pad tag with zero. | 1057 // Pad tag with zero. |
1079 ptr16[1] = 0; | 1058 ptr16[1] = 0; |
1080 } | 1059 } |
1081 | 1060 |
1061 static float get_gamma_value(const SkGammaCurve* curve) { | |
1062 switch (curve->fNamed) { | |
1063 case SkColorSpace::kSRGB_GammaNamed: | |
1064 // FIXME (msarett): kSRGB cannot be represented by a value. | |
1065 case SkColorSpace::k2Dot2Curve_GammaNamed: | |
1066 return 2.2f; | |
1067 case SkColorSpace::kLinear_GammaNamed: | |
1068 return 1.0f; | |
1069 default: | |
1070 SkASSERT(curve->isValue()); | |
1071 return curve->fValue; | |
1072 } | |
1073 } | |
1074 | |
1082 sk_sp<SkData> SkColorSpace_Base::writeToICC() const { | 1075 sk_sp<SkData> SkColorSpace_Base::writeToICC() const { |
1083 // Return if this object was created from a profile, or if we have already s erialized | 1076 // Return if this object was created from a profile, or if we have already s erialized |
1084 // the profile. | 1077 // the profile. |
1085 if (fProfileData) { | 1078 if (fProfileData) { |
1086 return fProfileData; | 1079 return fProfileData; |
1087 } | 1080 } |
1088 | 1081 |
1089 // The client may create an SkColorSpace using an SkMatrix44, but currently we only | 1082 // The client may create an SkColorSpace using an SkMatrix44, but currently we only |
1090 // support writing profiles with 3x3 matrices. | 1083 // support writing profiles with 3x3 matrices. |
1091 // TODO (msarett): Fix this! | 1084 // TODO (msarett): Fix this! |
(...skipping 21 matching lines...) Expand all Loading... | |
1113 | 1106 |
1114 // Write XYZ tags | 1107 // Write XYZ tags |
1115 write_xyz_tag((uint32_t*) ptr, fToXYZD50, 0); | 1108 write_xyz_tag((uint32_t*) ptr, fToXYZD50, 0); |
1116 ptr += kTAG_XYZ_Bytes; | 1109 ptr += kTAG_XYZ_Bytes; |
1117 write_xyz_tag((uint32_t*) ptr, fToXYZD50, 1); | 1110 write_xyz_tag((uint32_t*) ptr, fToXYZD50, 1); |
1118 ptr += kTAG_XYZ_Bytes; | 1111 ptr += kTAG_XYZ_Bytes; |
1119 write_xyz_tag((uint32_t*) ptr, fToXYZD50, 2); | 1112 write_xyz_tag((uint32_t*) ptr, fToXYZD50, 2); |
1120 ptr += kTAG_XYZ_Bytes; | 1113 ptr += kTAG_XYZ_Bytes; |
1121 | 1114 |
1122 // Write TRC tags | 1115 // Write TRC tags |
1123 SkASSERT(as_CSB(this)->fGammas->fRed.isValue()); | 1116 GammaNamed gammaNamed = this->gammaNamed(); |
1124 write_trc_tag((uint32_t*) ptr, as_CSB(this)->fGammas->fRed.fValue); | 1117 if (kNonStandard_GammaNamed == gammaNamed) { |
1125 ptr += SkAlign4(kTAG_TRC_Bytes); | 1118 write_trc_tag((uint32_t*) ptr, get_gamma_value(&as_CSB(this)->fGammas->f Red)); |
1126 SkASSERT(as_CSB(this)->fGammas->fGreen.isValue()); | 1119 ptr += SkAlign4(kTAG_TRC_Bytes); |
1127 write_trc_tag((uint32_t*) ptr, as_CSB(this)->fGammas->fGreen.fValue); | 1120 write_trc_tag((uint32_t*) ptr, get_gamma_value(&as_CSB(this)->fGammas->f Green)); |
1128 ptr += SkAlign4(kTAG_TRC_Bytes); | 1121 ptr += SkAlign4(kTAG_TRC_Bytes); |
1129 SkASSERT(as_CSB(this)->fGammas->fBlue.isValue()); | 1122 write_trc_tag((uint32_t*) ptr, get_gamma_value(&as_CSB(this)->fGammas->f Blue)); |
1130 write_trc_tag((uint32_t*) ptr, as_CSB(this)->fGammas->fBlue.fValue); | 1123 ptr += SkAlign4(kTAG_TRC_Bytes); |
1131 ptr += SkAlign4(kTAG_TRC_Bytes); | 1124 } else { |
1125 switch (gammaNamed) { | |
1126 case SkColorSpace::kSRGB_GammaNamed: | |
1127 // FIXME (msarett): kSRGB cannot be represented by a value. | |
1128 case SkColorSpace::k2Dot2Curve_GammaNamed: | |
1129 write_trc_tag((uint32_t*) ptr, 2.2f); | |
1130 ptr += SkAlign4(kTAG_TRC_Bytes); | |
1131 write_trc_tag((uint32_t*) ptr, 2.2f); | |
1132 ptr += SkAlign4(kTAG_TRC_Bytes); | |
1133 write_trc_tag((uint32_t*) ptr, 2.2f); | |
1134 ptr += SkAlign4(kTAG_TRC_Bytes); | |
1135 break; | |
1136 case SkColorSpace::kLinear_GammaNamed: | |
1137 write_trc_tag((uint32_t*) ptr, 1.0f); | |
1138 ptr += SkAlign4(kTAG_TRC_Bytes); | |
1139 write_trc_tag((uint32_t*) ptr, 1.0f); | |
1140 ptr += SkAlign4(kTAG_TRC_Bytes); | |
1141 write_trc_tag((uint32_t*) ptr, 1.0f); | |
1142 ptr += SkAlign4(kTAG_TRC_Bytes); | |
1143 break; | |
1144 default: | |
1145 SkASSERT(false); | |
1146 break; | |
1147 } | |
1148 } | |
1132 | 1149 |
1133 // Write white point tag | 1150 // Write white point tag |
1134 uint32_t* ptr32 = (uint32_t*) ptr; | 1151 uint32_t* ptr32 = (uint32_t*) ptr; |
1135 ptr32[0] = SkEndian_SwapBE32(kXYZ_PCSSpace); | 1152 ptr32[0] = SkEndian_SwapBE32(kXYZ_PCSSpace); |
1136 ptr32[1] = 0; | 1153 ptr32[1] = 0; |
1137 // TODO (msarett): These values correspond to the D65 white point. This may not always be | 1154 // TODO (msarett): These values correspond to the D65 white point. This may not always be |
1138 // correct. | 1155 // correct. |
1139 ptr32[2] = SkEndian_SwapBE32(0x0000f351); | 1156 ptr32[2] = SkEndian_SwapBE32(0x0000f351); |
1140 ptr32[3] = SkEndian_SwapBE32(0x00010000); | 1157 ptr32[3] = SkEndian_SwapBE32(0x00010000); |
1141 ptr32[4] = SkEndian_SwapBE32(0x000116cc); | 1158 ptr32[4] = SkEndian_SwapBE32(0x000116cc); |
1142 ptr += kTAG_XYZ_Bytes; | 1159 ptr += kTAG_XYZ_Bytes; |
1143 | 1160 |
1144 // Write copyright tag | 1161 // Write copyright tag |
1145 memcpy(ptr, gEmptyTextTag, sizeof(gEmptyTextTag)); | 1162 memcpy(ptr, gEmptyTextTag, sizeof(gEmptyTextTag)); |
1146 | 1163 |
1147 // TODO (msarett): Should we try to hold onto the data so we can return imme diately if | 1164 // TODO (msarett): Should we try to hold onto the data so we can return imme diately if |
1148 // the client calls again? | 1165 // the client calls again? |
1149 return SkData::MakeFromMalloc(profile.release(), kICCProfileSize); | 1166 return SkData::MakeFromMalloc(profile.release(), kICCProfileSize); |
1150 } | 1167 } |
OLD | NEW |