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 "SkColorPriv.h" | 8 #include "SkColorPriv.h" |
9 #include "SkColorSpace_Base.h" | 9 #include "SkColorSpace_Base.h" |
10 #include "SkColorSpaceXform.h" | 10 #include "SkColorSpaceXform.h" |
| 11 #include "SkOpts.h" |
11 | 12 |
12 static inline bool compute_gamut_xform(SkMatrix44* srcToDst, const SkMatrix44& s
rcToXYZ, | 13 static inline bool compute_gamut_xform(SkMatrix44* srcToDst, const SkMatrix44& s
rcToXYZ, |
13 const SkMatrix44& dstToXYZ) { | 14 const SkMatrix44& dstToXYZ) { |
14 if (!dstToXYZ.invert(srcToDst)) { | 15 if (!dstToXYZ.invert(srcToDst)) { |
15 return false; | 16 return false; |
16 } | 17 } |
17 | 18 |
18 srcToDst->postConcat(srcToXYZ); | 19 srcToDst->postConcat(srcToXYZ); |
19 return true; | 20 return true; |
20 } | 21 } |
21 | 22 |
22 std::unique_ptr<SkColorSpaceXform> SkColorSpaceXform::New(const sk_sp<SkColorSpa
ce>& srcSpace, | 23 std::unique_ptr<SkColorSpaceXform> SkColorSpaceXform::New(const sk_sp<SkColorSpa
ce>& srcSpace, |
23 const sk_sp<SkColorSpa
ce>& dstSpace) { | 24 const sk_sp<SkColorSpa
ce>& dstSpace) { |
24 if (!srcSpace || !dstSpace) { | 25 if (!srcSpace || !dstSpace) { |
25 // Invalid input | 26 // Invalid input |
26 return nullptr; | 27 return nullptr; |
27 } | 28 } |
28 | 29 |
29 if (as_CSB(srcSpace)->colorLUT() || as_CSB(dstSpace)->colorLUT()) { | 30 if (as_CSB(srcSpace)->colorLUT() || as_CSB(dstSpace)->colorLUT()) { |
30 // Unimplemented | 31 // Unimplemented |
31 return nullptr; | 32 return nullptr; |
32 } | 33 } |
33 | 34 |
34 SkMatrix44 srcToDst(SkMatrix44::kUninitialized_Constructor); | 35 SkMatrix44 srcToDst(SkMatrix44::kUninitialized_Constructor); |
35 if (!compute_gamut_xform(&srcToDst, srcSpace->xyz(), dstSpace->xyz())) { | 36 if (!compute_gamut_xform(&srcToDst, srcSpace->xyz(), dstSpace->xyz())) { |
36 return nullptr; | 37 return nullptr; |
37 } | 38 } |
38 | 39 |
39 if (as_CSB(srcSpace)->gammas()->isValues() && as_CSB(dstSpace)->gammas()->is
Values()) { | 40 if (SkColorSpace::k2Dot2Curve_GammaNamed == srcSpace->gammaNamed() && |
40 float srcGammas[3]; | 41 SkColorSpace::k2Dot2Curve_GammaNamed == dstSpace->gammaNamed()) |
41 float dstGammas[3]; | 42 { |
42 srcGammas[0] = as_CSB(srcSpace)->gammas()->fRed.fValue; | 43 return std::unique_ptr<SkColorSpaceXform>(new Sk2Dot2Xform(srcToDst)); |
43 srcGammas[1] = as_CSB(srcSpace)->gammas()->fGreen.fValue; | |
44 srcGammas[2] = as_CSB(srcSpace)->gammas()->fBlue.fValue; | |
45 dstGammas[0] = 1.0f / as_CSB(dstSpace)->gammas()->fRed.fValue; | |
46 dstGammas[1] = 1.0f / as_CSB(dstSpace)->gammas()->fGreen.fValue; | |
47 dstGammas[2] = 1.0f / as_CSB(dstSpace)->gammas()->fBlue.fValue; | |
48 | |
49 return std::unique_ptr<SkColorSpaceXform>( | |
50 new SkGammaByValueXform(srcGammas, srcToDst, dstGammas)); | |
51 } | 44 } |
52 | 45 |
53 return std::unique_ptr<SkColorSpaceXform>( | 46 return std::unique_ptr<SkColorSpaceXform>( |
54 new SkDefaultXform(as_CSB(srcSpace)->gammas(), srcToDst, as_CSB(dstS
pace)->gammas())); | 47 new SkDefaultXform(as_CSB(srcSpace)->gammas(), srcToDst, as_CSB(dstS
pace)->gammas())); |
55 } | 48 } |
56 | 49 |
57 ////////////////////////////////////////////////////////////////////////////////
/////////////////// | 50 ////////////////////////////////////////////////////////////////////////////////
/////////////////// |
58 | 51 |
| 52 Sk2Dot2Xform::Sk2Dot2Xform(const SkMatrix44& srcToDst) |
| 53 { |
| 54 // Build row major 4x4 matrix: |
| 55 // rX gX bX 0 |
| 56 // rY gY bY 0 |
| 57 // rZ gZ bZ 0 |
| 58 // rQ gQ bQ 0 |
| 59 fSrcToDst[0] = srcToDst.getFloat(0, 0); |
| 60 fSrcToDst[1] = srcToDst.getFloat(0, 1); |
| 61 fSrcToDst[2] = srcToDst.getFloat(0, 2); |
| 62 fSrcToDst[3] = 0.0f; |
| 63 fSrcToDst[4] = srcToDst.getFloat(1, 0); |
| 64 fSrcToDst[5] = srcToDst.getFloat(1, 1); |
| 65 fSrcToDst[6] = srcToDst.getFloat(1, 2); |
| 66 fSrcToDst[7] = 0.0f; |
| 67 fSrcToDst[8] = srcToDst.getFloat(2, 0); |
| 68 fSrcToDst[9] = srcToDst.getFloat(2, 1); |
| 69 fSrcToDst[10] = srcToDst.getFloat(2, 2); |
| 70 fSrcToDst[11] = 0.0f; |
| 71 fSrcToDst[12] = srcToDst.getFloat(3, 0); |
| 72 fSrcToDst[13] = srcToDst.getFloat(3, 1); |
| 73 fSrcToDst[14] = srcToDst.getFloat(3, 2); |
| 74 fSrcToDst[15] = 0.0f; |
| 75 } |
| 76 |
| 77 void Sk2Dot2Xform::xform_RGBA_8888(uint32_t* dst, const uint32_t* src, uint32_t
len) const { |
| 78 SkOpts::color_xform_2Dot2_RGBA_to_8888(dst, src, len, fSrcToDst); |
| 79 } |
| 80 |
| 81 ////////////////////////////////////////////////////////////////////////////////
/////////////////// |
| 82 |
59 static inline float byte_to_float(uint8_t v) { | 83 static inline float byte_to_float(uint8_t v) { |
60 return ((float) v) * (1.0f / 255.0f); | 84 return ((float) v) * (1.0f / 255.0f); |
61 } | 85 } |
62 | 86 |
63 static inline uint8_t clamp_float_to_byte(float v) { | 87 // Expand range from 0-1 to 0-255, then convert. |
| 88 static inline uint8_t clamp_normalized_float_to_byte(float v) { |
64 v = v * 255.0f; | 89 v = v * 255.0f; |
65 if (v > 255.0f) { | 90 if (v >= 254.5f) { |
66 return 255; | 91 return 255; |
67 } else if (v <= 0.0f) { | 92 } else if (v < 0.5f) { |
68 return 0; | 93 return 0; |
69 } else { | 94 } else { |
70 return (uint8_t) (v + 0.5f); | 95 return (uint8_t) (v + 0.5f); |
71 } | 96 } |
72 } | 97 } |
73 | 98 |
74 ////////////////////////////////////////////////////////////////////////////////
/////////////////// | |
75 | |
76 SkGammaByValueXform::SkGammaByValueXform(float srcGammas[3], const SkMatrix44& s
rcToDst, | |
77 float dstGammas[3]) | |
78 : fSrcToDst(srcToDst) | |
79 { | |
80 memcpy(fSrcGammas, srcGammas, 3 * sizeof(float)); | |
81 memcpy(fDstGammas, dstGammas, 3 * sizeof(float)); | |
82 } | |
83 | |
84 void SkGammaByValueXform::xform_RGBA_8888(uint32_t* dst, const uint32_t* src, ui
nt32_t len) const { | |
85 while (len-- > 0) { | |
86 float srcFloats[3]; | |
87 srcFloats[0] = byte_to_float((*src >> 0) & 0xFF); | |
88 srcFloats[1] = byte_to_float((*src >> 8) & 0xFF); | |
89 srcFloats[2] = byte_to_float((*src >> 16) & 0xFF); | |
90 | |
91 // Convert to linear. | |
92 srcFloats[0] = pow(srcFloats[0], fSrcGammas[0]); | |
93 srcFloats[1] = pow(srcFloats[1], fSrcGammas[1]); | |
94 srcFloats[2] = pow(srcFloats[2], fSrcGammas[2]); | |
95 | |
96 // Convert to dst gamut. | |
97 float dstFloats[3]; | |
98 dstFloats[0] = srcFloats[0] * fSrcToDst.getFloat(0, 0) + | |
99 srcFloats[1] * fSrcToDst.getFloat(1, 0) + | |
100 srcFloats[2] * fSrcToDst.getFloat(2, 0) + fSrcToDst.getFl
oat(3, 0); | |
101 dstFloats[1] = srcFloats[0] * fSrcToDst.getFloat(0, 1) + | |
102 srcFloats[1] * fSrcToDst.getFloat(1, 1) + | |
103 srcFloats[2] * fSrcToDst.getFloat(2, 1) + fSrcToDst.getFl
oat(3, 1); | |
104 dstFloats[2] = srcFloats[0] * fSrcToDst.getFloat(0, 2) + | |
105 srcFloats[1] * fSrcToDst.getFloat(1, 2) + | |
106 srcFloats[2] * fSrcToDst.getFloat(2, 2) + fSrcToDst.getFl
oat(3, 2); | |
107 | |
108 // Convert to dst gamma. | |
109 dstFloats[0] = pow(dstFloats[0], fDstGammas[0]); | |
110 dstFloats[1] = pow(dstFloats[1], fDstGammas[1]); | |
111 dstFloats[2] = pow(dstFloats[2], fDstGammas[2]); | |
112 | |
113 *dst = SkPackARGB32NoCheck(((*src >> 24) & 0xFF), | |
114 clamp_float_to_byte(dstFloats[0]), | |
115 clamp_float_to_byte(dstFloats[1]), | |
116 clamp_float_to_byte(dstFloats[2])); | |
117 | |
118 dst++; | |
119 src++; | |
120 } | |
121 } | |
122 | |
123 ////////////////////////////////////////////////////////////////////////////////
/////////////////// | |
124 | |
125 // Interpolating lookup in a variably sized table. | 99 // Interpolating lookup in a variably sized table. |
126 static inline float interp_lut(uint8_t byte, float* table, size_t tableSize) { | 100 static inline float interp_lut(uint8_t byte, float* table, size_t tableSize) { |
127 float index = byte_to_float(byte) * (tableSize - 1); | 101 float index = byte_to_float(byte) * (tableSize - 1); |
128 float diff = index - sk_float_floor2int(index); | 102 float diff = index - sk_float_floor2int(index); |
129 return table[(int) sk_float_floor2int(index)] * (1.0f - diff) + | 103 return table[(int) sk_float_floor2int(index)] * (1.0f - diff) + |
130 table[(int) sk_float_ceil2int(index)] * diff; | 104 table[(int) sk_float_ceil2int(index)] * diff; |
131 } | 105 } |
132 | 106 |
133 // Inverse table lookup. Ex: what index corresponds to the input value? This w
ill | 107 // Inverse table lookup. Ex: what index corresponds to the input value? This w
ill |
134 // have strange results when the table is non-increasing. But any sane gamma | 108 // have strange results when the table is non-increasing. But any sane gamma |
(...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
254 dstFloats[i] = 0.0f; | 228 dstFloats[i] = 0.0f; |
255 } else { | 229 } else { |
256 dstFloats[i] = (pow(dstFloats[i] - gamma.fC, 1.0f / gamm
a.fG) - gamma.fB) | 230 dstFloats[i] = (pow(dstFloats[i] - gamma.fC, 1.0f / gamm
a.fG) - gamma.fB) |
257 / gamma.fA; | 231 / gamma.fA; |
258 } | 232 } |
259 } | 233 } |
260 } | 234 } |
261 } | 235 } |
262 | 236 |
263 *dst = SkPackARGB32NoCheck(((*src >> 24) & 0xFF), | 237 *dst = SkPackARGB32NoCheck(((*src >> 24) & 0xFF), |
264 clamp_float_to_byte(dstFloats[0]), | 238 clamp_normalized_float_to_byte(dstFloats[0]), |
265 clamp_float_to_byte(dstFloats[1]), | 239 clamp_normalized_float_to_byte(dstFloats[1]), |
266 clamp_float_to_byte(dstFloats[2])); | 240 clamp_normalized_float_to_byte(dstFloats[2]))
; |
267 | 241 |
268 dst++; | 242 dst++; |
269 src++; | 243 src++; |
270 } | 244 } |
271 } | 245 } |
OLD | NEW |