| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright 2016 Google Inc. | 2 * Copyright 2016 Google Inc. |
| 3 * | 3 * |
| 4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
| 5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
| 6 */ | 6 */ |
| 7 | 7 |
| 8 #include "SkAtomics.h" | 8 #include "SkAtomics.h" |
| 9 #include "SkColorSpace.h" | 9 #include "SkColorSpace.h" |
| 10 | 10 |
| (...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 81 SkDebugf("[%7.4f %7.4f %7.4f] [%7.4f %7.4f %7.4f] [%7.4f %7.4f %7.4f]\n", | 81 SkDebugf("[%7.4f %7.4f %7.4f] [%7.4f %7.4f %7.4f] [%7.4f %7.4f %7.4f]\n", |
| 82 fMat[0], fMat[1], fMat[2], | 82 fMat[0], fMat[1], fMat[2], |
| 83 fMat[3], fMat[4], fMat[5], | 83 fMat[3], fMat[4], fMat[5], |
| 84 fMat[6], fMat[7], fMat[8]); | 84 fMat[6], fMat[7], fMat[8]); |
| 85 } | 85 } |
| 86 | 86 |
| 87 ////////////////////////////////////////////////////////////////////////////////
////////////////// | 87 ////////////////////////////////////////////////////////////////////////////////
////////////////// |
| 88 | 88 |
| 89 static int32_t gUniqueColorSpaceID; | 89 static int32_t gUniqueColorSpaceID; |
| 90 | 90 |
| 91 SkColorSpace::SkColorSpace(const SkFloat3& gamma, const SkFloat3x3& toXYZD50, Na
med named) | 91 SkColorSpace::SkColorSpace(SkGammas gammas, const SkFloat3x3& toXYZD50, Named na
med) |
| 92 : fGamma(gamma) | 92 : fGammas(std::move(gammas)) |
| 93 , fToXYZD50(toXYZD50) | 93 , fToXYZD50(toXYZD50) |
| 94 , fToXYZOffset({ 0.0f, 0.0f, 0.0f }) | 94 , fToXYZOffset({ 0.0f, 0.0f, 0.0f }) |
| 95 , fUniqueID(sk_atomic_inc(&gUniqueColorSpaceID)) | 95 , fUniqueID(sk_atomic_inc(&gUniqueColorSpaceID)) |
| 96 , fNamed(named) | 96 , fNamed(named) |
| 97 { | 97 { |
| 98 for (int i = 0; i < 3; ++i) { | 98 for (int i = 0; i < 3; ++i) { |
| 99 SkASSERT(SkFloatIsFinite(gamma.fVec[i])); | |
| 100 for (int j = 0; j < 3; ++j) { | 99 for (int j = 0; j < 3; ++j) { |
| 101 SkASSERT(SkFloatIsFinite(toXYZD50.fMat[3*i + j])); | 100 SkASSERT(SkFloatIsFinite(toXYZD50.fMat[3*i + j])); |
| 102 } | 101 } |
| 103 } | 102 } |
| 104 } | 103 } |
| 105 | 104 |
| 106 SkColorSpace::SkColorSpace(SkColorLookUpTable colorLUT, const SkFloat3& gamma, c
onst SkFloat3x3& toXYZD50, | 105 SkColorSpace::SkColorSpace(SkColorLookUpTable colorLUT, SkGammas gammas, const S
kFloat3x3& toXYZD50, |
| 107 const SkFloat3& toXYZOffset) | 106 const SkFloat3& toXYZOffset) |
| 108 : fColorLUT(std::move(colorLUT)) | 107 : fColorLUT(std::move(colorLUT)) |
| 109 , fGamma(gamma) | 108 , fGammas(gammas) |
| 110 , fToXYZD50(toXYZD50) | 109 , fToXYZD50(toXYZD50) |
| 111 , fToXYZOffset(toXYZOffset) | 110 , fToXYZOffset(toXYZOffset) |
| 112 , fUniqueID(sk_atomic_inc(&gUniqueColorSpaceID)) | 111 , fUniqueID(sk_atomic_inc(&gUniqueColorSpaceID)) |
| 113 , fNamed(kUnknown_Named) | 112 , fNamed(kUnknown_Named) |
| 114 {} | 113 {} |
| 115 | 114 |
| 116 sk_sp<SkColorSpace> SkColorSpace::NewRGB(const SkFloat3x3& toXYZD50, const SkFlo
at3& gamma) { | 115 sk_sp<SkColorSpace> SkColorSpace::NewRGB(const SkFloat3x3& toXYZD50, SkGammas ga
mmas) { |
| 117 for (int i = 0; i < 3; ++i) { | 116 for (int i = 0; i < 3; ++i) { |
| 118 if (!SkFloatIsFinite(gamma.fVec[i]) || gamma.fVec[i] < 0) { | |
| 119 return nullptr; | |
| 120 } | |
| 121 for (int j = 0; j < 3; ++j) { | 117 for (int j = 0; j < 3; ++j) { |
| 122 if (!SkFloatIsFinite(toXYZD50.fMat[3*i + j])) { | 118 if (!SkFloatIsFinite(toXYZD50.fMat[3*i + j])) { |
| 123 return nullptr; | 119 return nullptr; |
| 124 } | 120 } |
| 125 } | 121 } |
| 126 } | 122 } |
| 127 | 123 |
| 128 // check the matrix for invertibility | 124 // check the matrix for invertibility |
| 129 float d = det(toXYZD50); | 125 float d = det(toXYZD50); |
| 130 if (!SkFloatIsFinite(d) || !SkFloatIsFinite(1 / d)) { | 126 if (!SkFloatIsFinite(d) || !SkFloatIsFinite(1 / d)) { |
| 131 return nullptr; | 127 return nullptr; |
| 132 } | 128 } |
| 133 | 129 |
| 134 return sk_sp<SkColorSpace>(new SkColorSpace(gamma, toXYZD50, kUnknown_Named)
); | 130 return sk_sp<SkColorSpace>(new SkColorSpace(std::move(gammas), toXYZD50, kUn
known_Named)); |
| 135 } | 131 } |
| 136 | 132 |
| 137 void SkColorSpace::dump() const { | 133 void SkColorSpace::dump() const { |
| 138 fToXYZD50.dump(); | 134 fToXYZD50.dump(); |
| 139 fGamma.dump(); | |
| 140 } | 135 } |
| 141 | 136 |
| 142 ////////////////////////////////////////////////////////////////////////////////
////////////////// | 137 ////////////////////////////////////////////////////////////////////////////////
////////////////// |
| 143 | 138 |
| 144 const SkFloat3 gDevice_gamma {{ 0, 0, 0 }}; | |
| 145 const SkFloat3x3 gDevice_toXYZD50 {{ | 139 const SkFloat3x3 gDevice_toXYZD50 {{ |
| 146 1, 0, 0, | 140 1, 0, 0, |
| 147 0, 1, 0, | 141 0, 1, 0, |
| 148 0, 0, 1 | 142 0, 0, 1 |
| 149 }}; | 143 }}; |
| 150 | 144 |
| 151 const SkFloat3 gSRGB_gamma {{ 2.2f, 2.2f, 2.2f }}; | |
| 152 const SkFloat3x3 gSRGB_toXYZD50 {{ | 145 const SkFloat3x3 gSRGB_toXYZD50 {{ |
| 153 0.4358f, 0.2224f, 0.0139f, // * R | 146 0.4358f, 0.2224f, 0.0139f, // * R |
| 154 0.3853f, 0.7170f, 0.0971f, // * G | 147 0.3853f, 0.7170f, 0.0971f, // * G |
| 155 0.1430f, 0.0606f, 0.7139f, // * B | 148 0.1430f, 0.0606f, 0.7139f, // * B |
| 156 }}; | 149 }}; |
| 157 | 150 |
| 158 sk_sp<SkColorSpace> SkColorSpace::NewNamed(Named named) { | 151 sk_sp<SkColorSpace> SkColorSpace::NewNamed(Named named) { |
| 159 switch (named) { | 152 switch (named) { |
| 160 case kDevice_Named: | 153 case kDevice_Named: |
| 161 return sk_sp<SkColorSpace>(new SkColorSpace(gDevice_gamma, gDevice_t
oXYZD50, | 154 return sk_sp<SkColorSpace>(new SkColorSpace(std::move(SkGammas()), g
Device_toXYZD50, |
| 162 kDevice_Named)); | 155 kDevice_Named)); |
| 163 case kSRGB_Named: | 156 case kSRGB_Named: |
| 164 return sk_sp<SkColorSpace>(new SkColorSpace(gSRGB_gamma, gSRGB_toXYZ
D50, kSRGB_Named)); | 157 return sk_sp<SkColorSpace>(new SkColorSpace(std::move(SkGammas::sRGB
()), gSRGB_toXYZD50, |
| 158 kSRGB_Named)); |
| 165 default: | 159 default: |
| 166 break; | 160 break; |
| 167 } | 161 } |
| 168 return nullptr; | 162 return nullptr; |
| 169 } | 163 } |
| 170 | 164 |
| 171 ////////////////////////////////////////////////////////////////////////////////
/////////////////// | 165 ////////////////////////////////////////////////////////////////////////////////
/////////////////// |
| 172 | 166 |
| 173 #include "SkFixed.h" | 167 #include "SkFixed.h" |
| 174 #include "SkTemplates.h" | 168 #include "SkTemplates.h" |
| (...skipping 190 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 365 dst[2] = SkFixedToFloat(read_big_endian_int(src + 16)); | 359 dst[2] = SkFixedToFloat(read_big_endian_int(src + 16)); |
| 366 SkColorSpacePrintf("XYZ %g %g %g\n", dst[0], dst[1], dst[2]); | 360 SkColorSpacePrintf("XYZ %g %g %g\n", dst[0], dst[1], dst[2]); |
| 367 return true; | 361 return true; |
| 368 } | 362 } |
| 369 | 363 |
| 370 static const uint32_t kTAG_CurveType = SkSetFourByteTag('c', 'u', 'r', 'v'); | 364 static const uint32_t kTAG_CurveType = SkSetFourByteTag('c', 'u', 'r', 'v'); |
| 371 static const uint32_t kTAG_ParaCurveType = SkSetFourByteTag('p', 'a', 'r', 'a'); | 365 static const uint32_t kTAG_ParaCurveType = SkSetFourByteTag('p', 'a', 'r', 'a'); |
| 372 | 366 |
| 373 // FIXME (msarett): | 367 // FIXME (msarett): |
| 374 // We need to handle the possibility that the gamma curve does not correspond to
2.2f. | 368 // We need to handle the possibility that the gamma curve does not correspond to
2.2f. |
| 375 static bool load_gammas(float* gammas, uint32_t numGammas, const uint8_t* src, s
ize_t len) { | 369 static bool load_gammas(SkGamma* gammas, uint32_t numGammas, const uint8_t* src,
size_t len) { |
| 376 for (uint32_t i = 0; i < numGammas; i++) { | 370 for (uint32_t i = 0; i < numGammas; i++) { |
| 377 if (len < 12) { | 371 if (len < 12) { |
| 378 // FIXME (msarett): | 372 // FIXME (msarett): |
| 379 // We could potentially return false here after correctly parsing *s
ome* of the | 373 // We could potentially return false here after correctly parsing *s
ome* of the |
| 380 // gammas correctly. Should we somehow try to indicate a partial su
ccess? | 374 // gammas correctly. Should we somehow try to indicate a partial su
ccess? |
| 381 SkColorSpacePrintf("gamma tag is too small (%d bytes)", len); | 375 SkColorSpacePrintf("gamma tag is too small (%d bytes)", len); |
| 382 return false; | 376 return false; |
| 383 } | 377 } |
| 384 | 378 |
| 385 // We need to count the number of bytes in the tag, so we are able to mo
ve to the | 379 // We need to count the number of bytes in the tag, so we are able to mo
ve to the |
| 386 // next tag on the next loop iteration. | 380 // next tag on the next loop iteration. |
| 387 size_t tagBytes; | 381 size_t tagBytes; |
| 388 | 382 |
| 389 uint32_t type = read_big_endian_uint(src); | 383 uint32_t type = read_big_endian_uint(src); |
| 390 switch (type) { | 384 switch (type) { |
| 391 case kTAG_CurveType: { | 385 case kTAG_CurveType: { |
| 392 uint32_t count = read_big_endian_uint(src + 8); | 386 uint32_t count = read_big_endian_uint(src + 8); |
| 393 tagBytes = 12 + count * 2; | 387 tagBytes = 12 + count * 2; |
| 394 if (0 == count) { | 388 if (0 == count) { |
| 395 // Some tags require a gamma curve, but the author doesn't a
ctually want | 389 // Some tags require a gamma curve, but the author doesn't a
ctually want |
| 396 // to transform the data. In this case, it is common to see
a curve with | 390 // to transform the data. In this case, it is common to see
a curve with |
| 397 // a count of 0. | 391 // a count of 0. |
| 398 gammas[i] = 1.0f; | 392 gammas[i].fFlag = SkGamma::kGammaUseValueFlag; |
| 393 gammas[i].fValue = 1.0f; |
| 399 break; | 394 break; |
| 400 } else if (len < 12 + 2 * count) { | 395 } else if (len < 12 + 2 * count) { |
| 401 SkColorSpacePrintf("gamma tag is too small (%d bytes)", len)
; | 396 SkColorSpacePrintf("gamma tag is too small (%d bytes)", len)
; |
| 402 return false; | 397 return false; |
| 403 } | 398 } |
| 404 | 399 |
| 405 const uint16_t* table = (const uint16_t*) (src + 12); | 400 const uint16_t* table = (const uint16_t*) (src + 12); |
| 406 if (1 == count) { | 401 if (1 == count) { |
| 407 // Table entry is the exponent (bias 256). | 402 // Table entry is the exponent (bias 256). |
| 408 uint16_t value = read_big_endian_short((const uint8_t*) tabl
e); | 403 uint16_t value = read_big_endian_short((const uint8_t*) tabl
e); |
| 409 gammas[i] = value / 256.0f; | 404 gammas[i].fFlag = SkGamma::kGammaUseValueFlag; |
| 405 gammas[i].fValue = value / 256.0f; |
| 410 SkColorSpacePrintf("gamma %d %g\n", value, *gamma); | 406 SkColorSpacePrintf("gamma %d %g\n", value, *gamma); |
| 411 break; | 407 break; |
| 412 } | 408 } |
| 413 | 409 |
| 414 // Print the interpolation table. For now, we ignore this and g
uess 2.2f. | 410 // Fill in the interpolation table. |
| 415 for (uint32_t i = 0; i < count; i++) { | 411 // FIXME (msarett): |
| 416 SkColorSpacePrintf("curve[%d] %d\n", i, | 412 // We should recognize commonly occurring tables and just set ga
mma to 2.2f. |
| 417 read_big_endian_short((const uint8_t*) &table[i])); | 413 gammas[i].fFlag = SkGamma::kGammaUseTableFlag; |
| 414 gammas[i].fTableSize = count; |
| 415 gammas[i].fTable = std::unique_ptr(new float[count]); |
| 416 for (uint32_t j = 0; j < count; j++) { |
| 417 gammas[i].fTable[j] = |
| 418 (read_big_endian_short((const uint8_t*) &table[j]))
/ 65535.0f; |
| 418 } | 419 } |
| 419 | |
| 420 gammas[i] = 2.2f; | |
| 421 break; | 420 break; |
| 422 } | 421 } |
| 423 case kTAG_ParaCurveType: | 422 case kTAG_ParaCurveType: |
| 424 // Guess 2.2f. | 423 // Guess 2.2f. |
| 425 SkColorSpacePrintf("parametric curve\n"); | 424 SkColorSpacePrintf("parametric curve\n"); |
| 426 gammas[i] = 2.2f; | 425 gammas[i].fFlag = SkGamma::kGammaUseValueFlag; |
| 426 gammas[i].fValue = 2.2f; |
| 427 | 427 |
| 428 switch(read_big_endian_short(src + 8)) { | 428 switch(read_big_endian_short(src + 8)) { |
| 429 case 0: | 429 case 0: |
| 430 tagBytes = 12 + 4; | 430 tagBytes = 12 + 4; |
| 431 break; | 431 break; |
| 432 case 1: | 432 case 1: |
| 433 tagBytes = 12 + 12; | 433 tagBytes = 12 + 12; |
| 434 break; | 434 break; |
| 435 case 2: | 435 case 2: |
| 436 tagBytes = 12 + 16; | 436 tagBytes = 12 + 16; |
| (...skipping 362 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 799 } | 799 } |
| 800 | 800 |
| 801 // D65 white point of Rec. 709 [8] are: | 801 // D65 white point of Rec. 709 [8] are: |
| 802 // | 802 // |
| 803 // D65 white-point in unit luminance XYZ = 0.9505, 1.0000, 1.0890 | 803 // D65 white-point in unit luminance XYZ = 0.9505, 1.0000, 1.0890 |
| 804 // | 804 // |
| 805 // R G B white | 805 // R G B white |
| 806 // x 0.640 0.300 0.150 0.3127 | 806 // x 0.640 0.300 0.150 0.3127 |
| 807 // y 0.330 0.600 0.060 0.3290 | 807 // y 0.330 0.600 0.060 0.3290 |
| 808 // z 0.030 0.100 0.790 0.3582 | 808 // z 0.030 0.100 0.790 0.3582 |
| OLD | NEW |