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 |