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