OLD | NEW |
1 // Copyright (c) 2016 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2016 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "ui/gfx/color_transform.h" | 5 #include "ui/gfx/color_transform.h" |
6 | 6 |
7 #include <vector> | 7 #include <vector> |
8 | 8 |
9 #include "base/logging.h" | 9 #include "base/logging.h" |
10 #include "base/memory/ptr_util.h" | 10 #include "base/memory/ptr_util.h" |
11 #include "ui/gfx/color_space.h" | 11 #include "ui/gfx/color_space.h" |
12 #include "ui/gfx/icc_profile.h" | 12 #include "ui/gfx/icc_profile.h" |
13 #include "ui/gfx/transform.h" | 13 #include "ui/gfx/transform.h" |
14 #include "third_party/qcms/src/qcms.h" | 14 #include "third_party/qcms/src/qcms.h" |
15 | 15 |
16 #ifndef THIS_MUST_BE_INCLUDED_AFTER_QCMS_H | 16 #ifndef THIS_MUST_BE_INCLUDED_AFTER_QCMS_H |
17 extern "C" { | 17 extern "C" { |
18 #include "third_party/qcms/src/chain.h" | 18 #include "third_party/qcms/src/chain.h" |
19 }; | 19 }; |
20 #endif | 20 #endif |
21 | 21 |
22 namespace gfx { | 22 namespace gfx { |
23 | 23 |
24 float EvalSkTransferFn(const SkColorSpaceTransferFn& fn, float x) { | |
25 if (x < 0) | |
26 return 0; | |
27 if (x < fn.fD) | |
28 return fn.fC * x + fn.fF; | |
29 return powf(fn.fA * x + fn.fB, fn.fG) + fn.fE; | |
30 } | |
31 | |
32 Transform Invert(const Transform& t) { | 24 Transform Invert(const Transform& t) { |
33 Transform ret = t; | 25 Transform ret = t; |
34 if (!t.GetInverse(&ret)) { | 26 if (!t.GetInverse(&ret)) { |
35 LOG(ERROR) << "Inverse should alsways be possible."; | 27 LOG(ERROR) << "Inverse should alsways be possible."; |
36 } | 28 } |
37 return ret; | 29 return ret; |
38 } | 30 } |
39 | 31 |
40 float FromLinear(ColorSpace::TransferID id, float v) { | 32 GFX_EXPORT Transform GetPrimaryMatrix(ColorSpace::PrimaryID id) { |
| 33 SkColorSpacePrimaries primaries = {0}; |
| 34 switch (id) { |
| 35 case ColorSpace::PrimaryID::CUSTOM: |
| 36 NOTREACHED(); |
| 37 |
| 38 case ColorSpace::PrimaryID::RESERVED0: |
| 39 case ColorSpace::PrimaryID::RESERVED: |
| 40 case ColorSpace::PrimaryID::UNSPECIFIED: |
| 41 case ColorSpace::PrimaryID::UNKNOWN: |
| 42 case ColorSpace::PrimaryID::BT709: |
| 43 // BT709 is our default case. Put it after the switch just |
| 44 // in case we somehow get an id which is not listed in the switch. |
| 45 // (We don't want to use "default", because we want the compiler |
| 46 // to tell us if we forgot some enum values.) |
| 47 primaries.fRX = 0.640f; |
| 48 primaries.fRY = 0.330f; |
| 49 primaries.fGX = 0.300f; |
| 50 primaries.fGY = 0.600f; |
| 51 primaries.fBX = 0.150f; |
| 52 primaries.fBY = 0.060f; |
| 53 primaries.fWX = 0.3127f; |
| 54 primaries.fWY = 0.3290f; |
| 55 break; |
| 56 |
| 57 case ColorSpace::PrimaryID::BT470M: |
| 58 primaries.fRX = 0.67f; |
| 59 primaries.fRY = 0.33f; |
| 60 primaries.fGX = 0.21f; |
| 61 primaries.fGY = 0.71f; |
| 62 primaries.fBX = 0.14f; |
| 63 primaries.fBY = 0.08f; |
| 64 primaries.fWX = 0.31f; |
| 65 primaries.fWY = 0.316f; |
| 66 break; |
| 67 |
| 68 case ColorSpace::PrimaryID::BT470BG: |
| 69 primaries.fRX = 0.64f; |
| 70 primaries.fRY = 0.33f; |
| 71 primaries.fGX = 0.29f; |
| 72 primaries.fGY = 0.60f; |
| 73 primaries.fBX = 0.15f; |
| 74 primaries.fBY = 0.06f; |
| 75 primaries.fWX = 0.3127f; |
| 76 primaries.fWY = 0.3290f; |
| 77 break; |
| 78 |
| 79 case ColorSpace::PrimaryID::SMPTE170M: |
| 80 case ColorSpace::PrimaryID::SMPTE240M: |
| 81 primaries.fRX = 0.630f; |
| 82 primaries.fRY = 0.340f; |
| 83 primaries.fGX = 0.310f; |
| 84 primaries.fGY = 0.595f; |
| 85 primaries.fBX = 0.155f; |
| 86 primaries.fBY = 0.070f; |
| 87 primaries.fWX = 0.3127f; |
| 88 primaries.fWY = 0.3290f; |
| 89 break; |
| 90 |
| 91 case ColorSpace::PrimaryID::FILM: |
| 92 primaries.fRX = 0.681f; |
| 93 primaries.fRY = 0.319f; |
| 94 primaries.fGX = 0.243f; |
| 95 primaries.fGY = 0.692f; |
| 96 primaries.fBX = 0.145f; |
| 97 primaries.fBY = 0.049f; |
| 98 primaries.fWX = 0.310f; |
| 99 primaries.fWY = 0.136f; |
| 100 break; |
| 101 |
| 102 case ColorSpace::PrimaryID::BT2020: |
| 103 primaries.fRX = 0.708f; |
| 104 primaries.fRY = 0.292f; |
| 105 primaries.fGX = 0.170f; |
| 106 primaries.fGY = 0.797f; |
| 107 primaries.fBX = 0.131f; |
| 108 primaries.fBY = 0.046f; |
| 109 primaries.fWX = 0.3127f; |
| 110 primaries.fWY = 0.3290f; |
| 111 break; |
| 112 |
| 113 case ColorSpace::PrimaryID::SMPTEST428_1: |
| 114 primaries.fRX = 1.0f; |
| 115 primaries.fRY = 0.0f; |
| 116 primaries.fGX = 0.0f; |
| 117 primaries.fGY = 1.0f; |
| 118 primaries.fBX = 0.0f; |
| 119 primaries.fBY = 0.0f; |
| 120 primaries.fWX = 1.0f / 3.0f; |
| 121 primaries.fWY = 1.0f / 3.0f; |
| 122 break; |
| 123 |
| 124 case ColorSpace::PrimaryID::SMPTEST431_2: |
| 125 primaries.fRX = 0.680f; |
| 126 primaries.fRY = 0.320f; |
| 127 primaries.fGX = 0.265f; |
| 128 primaries.fGY = 0.690f; |
| 129 primaries.fBX = 0.150f; |
| 130 primaries.fBY = 0.060f; |
| 131 primaries.fWX = 0.314f; |
| 132 primaries.fWY = 0.351f; |
| 133 break; |
| 134 |
| 135 case ColorSpace::PrimaryID::SMPTEST432_1: |
| 136 primaries.fRX = 0.680f; |
| 137 primaries.fRY = 0.320f; |
| 138 primaries.fGX = 0.265f; |
| 139 primaries.fGY = 0.690f; |
| 140 primaries.fBX = 0.150f; |
| 141 primaries.fBY = 0.060f; |
| 142 primaries.fWX = 0.3127f; |
| 143 primaries.fWY = 0.3290f; |
| 144 break; |
| 145 |
| 146 case ColorSpace::PrimaryID::XYZ_D50: |
| 147 primaries.fRX = 1.0f; |
| 148 primaries.fRY = 0.0f; |
| 149 primaries.fGX = 0.0f; |
| 150 primaries.fGY = 1.0f; |
| 151 primaries.fBX = 0.0f; |
| 152 primaries.fBY = 0.0f; |
| 153 primaries.fWX = 0.34567f; |
| 154 primaries.fWY = 0.35850f; |
| 155 break; |
| 156 } |
| 157 |
| 158 SkMatrix44 matrix; |
| 159 primaries.toXYZD50(&matrix); |
| 160 return Transform(matrix); |
| 161 } |
| 162 |
| 163 GFX_EXPORT float FromLinear(ColorSpace::TransferID id, float v) { |
41 switch (id) { | 164 switch (id) { |
42 case ColorSpace::TransferID::SMPTEST2084_NON_HDR: | 165 case ColorSpace::TransferID::SMPTEST2084_NON_HDR: |
43 // Should already be handled. | 166 // Should already be handled. |
| 167 NOTREACHED(); |
| 168 case ColorSpace::TransferID::CUSTOM: |
| 169 // TODO(hubbe): Actually implement custom transfer functions. |
| 170 case ColorSpace::TransferID::RESERVED0: |
| 171 case ColorSpace::TransferID::RESERVED: |
| 172 case ColorSpace::TransferID::UNSPECIFIED: |
| 173 case ColorSpace::TransferID::UNKNOWN: |
| 174 // All unknown values default to BT709 |
| 175 |
| 176 case ColorSpace::TransferID::BT709: |
| 177 case ColorSpace::TransferID::SMPTE170M: |
| 178 case ColorSpace::TransferID::BT2020_10: |
| 179 case ColorSpace::TransferID::BT2020_12: |
| 180 // BT709 is our "default" cause, so put the code after the switch |
| 181 // to avoid "control reaches end of non-void function" errors. |
44 break; | 182 break; |
45 | 183 |
| 184 case ColorSpace::TransferID::GAMMA22: |
| 185 v = fmax(0.0f, v); |
| 186 return powf(v, 1.0f / 2.2f); |
| 187 |
| 188 case ColorSpace::TransferID::GAMMA28: |
| 189 v = fmax(0.0f, v); |
| 190 return powf(v, 1.0f / 2.8f); |
| 191 |
| 192 case ColorSpace::TransferID::SMPTE240M: { |
| 193 v = fmax(0.0f, v); |
| 194 float a = 1.11157219592173128753f; |
| 195 float b = 0.02282158552944503135f; |
| 196 if (v <= b) { |
| 197 return 4.0f * v; |
| 198 } else { |
| 199 return a * powf(v, 0.45f) - (a - 1.0f); |
| 200 } |
| 201 } |
| 202 |
| 203 case ColorSpace::TransferID::LINEAR: |
| 204 return v; |
| 205 |
46 case ColorSpace::TransferID::LOG: | 206 case ColorSpace::TransferID::LOG: |
47 if (v < 0.01f) | 207 if (v < 0.01f) |
48 return 0.0f; | 208 return 0.0f; |
49 return 1.0f + log(v) / log(10.0f) / 2.0f; | 209 return 1.0f + log(v) / log(10.0f) / 2.0f; |
50 | 210 |
51 case ColorSpace::TransferID::LOG_SQRT: | 211 case ColorSpace::TransferID::LOG_SQRT: |
52 if (v < sqrt(10.0f) / 1000.0f) | 212 if (v < sqrt(10.0f) / 1000.0f) |
53 return 0.0f; | 213 return 0.0f; |
54 return 1.0f + log(v) / log(10.0f) / 2.5f; | 214 return 1.0f + log(v) / log(10.0f) / 2.5f; |
55 | 215 |
(...skipping 15 matching lines...) Expand all Loading... |
71 float l = 0.0045f; | 231 float l = 0.0045f; |
72 if (v < -l) { | 232 if (v < -l) { |
73 return -(a * powf(-4.0f * v, 0.45f) + (a - 1.0f)) / 4.0f; | 233 return -(a * powf(-4.0f * v, 0.45f) + (a - 1.0f)) / 4.0f; |
74 } else if (v <= b) { | 234 } else if (v <= b) { |
75 return 4.5f * v; | 235 return 4.5f * v; |
76 } else { | 236 } else { |
77 return a * powf(v, 0.45f) - (a - 1.0f); | 237 return a * powf(v, 0.45f) - (a - 1.0f); |
78 } | 238 } |
79 } | 239 } |
80 | 240 |
| 241 case ColorSpace::TransferID::IEC61966_2_1: { // SRGB |
| 242 v = fmax(0.0f, v); |
| 243 float a = 1.055f; |
| 244 float b = 0.0031308f; |
| 245 if (v < b) { |
| 246 return 12.92f * v; |
| 247 } else { |
| 248 return a * powf(v, 1.0f / 2.4f) - (a - 1.0f); |
| 249 } |
| 250 } |
81 case ColorSpace::TransferID::SMPTEST2084: { | 251 case ColorSpace::TransferID::SMPTEST2084: { |
82 // Go from scRGB levels to 0-1. | 252 // Go from scRGB levels to 0-1. |
83 v *= 80.0f / 10000.0f; | 253 v *= 80.0f / 10000.0f; |
84 v = fmax(0.0f, v); | 254 v = fmax(0.0f, v); |
85 float m1 = (2610.0f / 4096.0f) / 4.0f; | 255 float m1 = (2610.0f / 4096.0f) / 4.0f; |
86 float m2 = (2523.0f / 4096.0f) * 128.0f; | 256 float m2 = (2523.0f / 4096.0f) * 128.0f; |
87 float c1 = 3424.0f / 4096.0f; | 257 float c1 = 3424.0f / 4096.0f; |
88 float c2 = (2413.0f / 4096.0f) * 32.0f; | 258 float c2 = (2413.0f / 4096.0f) * 32.0f; |
89 float c3 = (2392.0f / 4096.0f) * 32.0f; | 259 float c3 = (2392.0f / 4096.0f) * 32.0f; |
90 return powf((c1 + c2 * powf(v, m1)) / (1.0f + c3 * powf(v, m1)), m2); | 260 return powf((c1 + c2 * powf(v, m1)) / (1.0f + c3 * powf(v, m1)), m2); |
91 } | 261 } |
92 | 262 |
| 263 case ColorSpace::TransferID::SMPTEST428_1: |
| 264 v = fmax(0.0f, v); |
| 265 return powf(48.0f * v + 52.37f, 1.0f / 2.6f); |
| 266 |
93 // Spec: http://www.arib.or.jp/english/html/overview/doc/2-STD-B67v1_0.pdf | 267 // Spec: http://www.arib.or.jp/english/html/overview/doc/2-STD-B67v1_0.pdf |
94 case ColorSpace::TransferID::ARIB_STD_B67: { | 268 case ColorSpace::TransferID::ARIB_STD_B67: { |
95 const float a = 0.17883277f; | 269 const float a = 0.17883277f; |
96 const float b = 0.28466892f; | 270 const float b = 0.28466892f; |
97 const float c = 0.55991073f; | 271 const float c = 0.55991073f; |
98 v = fmax(0.0f, v); | 272 v = fmax(0.0f, v); |
99 if (v <= 1) | 273 if (v <= 1) |
100 return 0.5f * sqrtf(v); | 274 return 0.5f * sqrtf(v); |
101 else | 275 else |
102 return a * log(v - b) + c; | 276 return a * log(v - b) + c; |
103 } | 277 } |
104 | 278 |
105 default: | 279 // Chrome-specific values below |
106 // Handled by SkColorSpaceTransferFn. | 280 case ColorSpace::TransferID::GAMMA24: |
107 break; | 281 v = fmax(0.0f, v); |
| 282 return powf(v, 1.0f / 2.4f); |
108 } | 283 } |
109 NOTREACHED(); | 284 |
110 return 0; | 285 v = fmax(0.0f, v); |
| 286 float a = 1.099296826809442f; |
| 287 float b = 0.018053968510807f; |
| 288 if (v <= b) { |
| 289 return 4.5f * v; |
| 290 } else { |
| 291 return a * powf(v, 0.45f) - (a - 1.0f); |
| 292 } |
111 } | 293 } |
112 | 294 |
113 float ToLinear(ColorSpace::TransferID id, float v) { | 295 GFX_EXPORT float ToLinear(ColorSpace::TransferID id, float v) { |
114 switch (id) { | 296 switch (id) { |
| 297 case ColorSpace::TransferID::CUSTOM: |
| 298 // TODO(hubbe): Actually implement custom transfer functions. |
| 299 case ColorSpace::TransferID::RESERVED0: |
| 300 case ColorSpace::TransferID::RESERVED: |
| 301 case ColorSpace::TransferID::UNSPECIFIED: |
| 302 case ColorSpace::TransferID::UNKNOWN: |
| 303 // All unknown values default to BT709 |
| 304 |
| 305 case ColorSpace::TransferID::BT709: |
| 306 case ColorSpace::TransferID::SMPTE170M: |
| 307 case ColorSpace::TransferID::BT2020_10: |
| 308 case ColorSpace::TransferID::BT2020_12: |
| 309 // BT709 is our "default" cause, so put the code after the switch |
| 310 // to avoid "control reaches end of non-void function" errors. |
| 311 break; |
| 312 |
| 313 case ColorSpace::TransferID::GAMMA22: |
| 314 v = fmax(0.0f, v); |
| 315 return powf(v, 2.2f); |
| 316 |
| 317 case ColorSpace::TransferID::GAMMA28: |
| 318 v = fmax(0.0f, v); |
| 319 return powf(v, 2.8f); |
| 320 |
| 321 case ColorSpace::TransferID::SMPTE240M: { |
| 322 v = fmax(0.0f, v); |
| 323 float a = 1.11157219592173128753f; |
| 324 float b = 0.02282158552944503135f; |
| 325 if (v <= FromLinear(ColorSpace::TransferID::SMPTE240M, b)) { |
| 326 return v / 4.0f; |
| 327 } else { |
| 328 return powf((v + a - 1.0f) / a, 1.0f / 0.45f); |
| 329 } |
| 330 } |
| 331 |
| 332 case ColorSpace::TransferID::LINEAR: |
| 333 return v; |
| 334 |
115 case ColorSpace::TransferID::LOG: | 335 case ColorSpace::TransferID::LOG: |
116 if (v < 0.0f) | 336 if (v < 0.0f) |
117 return 0.0f; | 337 return 0.0f; |
118 return powf(10.0f, (v - 1.0f) * 2.0f); | 338 return powf(10.0f, (v - 1.0f) * 2.0f); |
119 | 339 |
120 case ColorSpace::TransferID::LOG_SQRT: | 340 case ColorSpace::TransferID::LOG_SQRT: |
121 if (v < 0.0f) | 341 if (v < 0.0f) |
122 return 0.0f; | 342 return 0.0f; |
123 return powf(10.0f, (v - 1.0f) * 2.5f); | 343 return powf(10.0f, (v - 1.0f) * 2.5f); |
124 | 344 |
(...skipping 15 matching lines...) Expand all Loading... |
140 float l = 0.0045f; | 360 float l = 0.0045f; |
141 if (v < FromLinear(ColorSpace::TransferID::BT1361_ECG, -l)) { | 361 if (v < FromLinear(ColorSpace::TransferID::BT1361_ECG, -l)) { |
142 return -powf((1.0f - a - v * 4.0f) / a, 1.0f / 0.45f) / 4.0f; | 362 return -powf((1.0f - a - v * 4.0f) / a, 1.0f / 0.45f) / 4.0f; |
143 } else if (v <= FromLinear(ColorSpace::TransferID::BT1361_ECG, b)) { | 363 } else if (v <= FromLinear(ColorSpace::TransferID::BT1361_ECG, b)) { |
144 return v / 4.5f; | 364 return v / 4.5f; |
145 } else { | 365 } else { |
146 return powf((v + a - 1.0f) / a, 1.0f / 0.45f); | 366 return powf((v + a - 1.0f) / a, 1.0f / 0.45f); |
147 } | 367 } |
148 } | 368 } |
149 | 369 |
| 370 case ColorSpace::TransferID::IEC61966_2_1: { // SRGB |
| 371 v = fmax(0.0f, v); |
| 372 float a = 1.055f; |
| 373 float b = 0.0031308f; |
| 374 if (v < FromLinear(ColorSpace::TransferID::IEC61966_2_1, b)) { |
| 375 return v / 12.92f; |
| 376 } else { |
| 377 return powf((v + a - 1.0f) / a, 2.4f); |
| 378 } |
| 379 } |
| 380 |
150 case ColorSpace::TransferID::SMPTEST2084: { | 381 case ColorSpace::TransferID::SMPTEST2084: { |
151 v = fmax(0.0f, v); | 382 v = fmax(0.0f, v); |
152 float m1 = (2610.0f / 4096.0f) / 4.0f; | 383 float m1 = (2610.0f / 4096.0f) / 4.0f; |
153 float m2 = (2523.0f / 4096.0f) * 128.0f; | 384 float m2 = (2523.0f / 4096.0f) * 128.0f; |
154 float c1 = 3424.0f / 4096.0f; | 385 float c1 = 3424.0f / 4096.0f; |
155 float c2 = (2413.0f / 4096.0f) * 32.0f; | 386 float c2 = (2413.0f / 4096.0f) * 32.0f; |
156 float c3 = (2392.0f / 4096.0f) * 32.0f; | 387 float c3 = (2392.0f / 4096.0f) * 32.0f; |
157 v = powf( | 388 v = powf( |
158 fmax(powf(v, 1.0f / m2) - c1, 0) / (c2 - c3 * powf(v, 1.0f / m2)), | 389 fmax(powf(v, 1.0f / m2) - c1, 0) / (c2 - c3 * powf(v, 1.0f / m2)), |
159 1.0f / m1); | 390 1.0f / m1); |
160 // This matches the scRGB definition that 1.0 means 80 nits. | 391 // This matches the scRGB definition that 1.0 means 80 nits. |
161 // TODO(hubbe): It would be *nice* if 1.0 meant more than that, but | 392 // TODO(hubbe): It would be *nice* if 1.0 meant more than that, but |
162 // that might be difficult to do right now. | 393 // that might be difficult to do right now. |
163 v *= 10000.0f / 80.0f; | 394 v *= 10000.0f / 80.0f; |
164 return v; | 395 return v; |
165 } | 396 } |
166 | 397 |
| 398 case ColorSpace::TransferID::SMPTEST428_1: |
| 399 return (powf(v, 2.6f) - 52.37f) / 48.0f; |
| 400 |
| 401 // Chrome-specific values below |
| 402 case ColorSpace::TransferID::GAMMA24: |
| 403 v = fmax(0.0f, v); |
| 404 return powf(v, 2.4f); |
| 405 |
167 case ColorSpace::TransferID::SMPTEST2084_NON_HDR: | 406 case ColorSpace::TransferID::SMPTEST2084_NON_HDR: |
168 v = fmax(0.0f, v); | 407 v = fmax(0.0f, v); |
169 return fmin(2.3f * pow(v, 2.8f), v / 5.0f + 0.8f); | 408 return fmin(2.3f * pow(v, 2.8f), v / 5.0f + 0.8f); |
170 | 409 |
171 // Spec: http://www.arib.or.jp/english/html/overview/doc/2-STD-B67v1_0.pdf | 410 // Spec: http://www.arib.or.jp/english/html/overview/doc/2-STD-B67v1_0.pdf |
172 case ColorSpace::TransferID::ARIB_STD_B67: { | 411 case ColorSpace::TransferID::ARIB_STD_B67: { |
173 v = fmax(0.0f, v); | 412 v = fmax(0.0f, v); |
174 const float a = 0.17883277f; | 413 const float a = 0.17883277f; |
175 const float b = 0.28466892f; | 414 const float b = 0.28466892f; |
176 const float c = 0.55991073f; | 415 const float c = 0.55991073f; |
177 float v_ = 0.0f; | 416 float v_ = 0.0f; |
178 if (v <= 0.5f) { | 417 if (v <= 0.5f) { |
179 v_ = (v * 2.0f) * (v * 2.0f); | 418 v_ = (v * 2.0f) * (v * 2.0f); |
180 } else { | 419 } else { |
181 v_ = exp((v - c) / a) + b; | 420 v_ = exp((v - c) / a) + b; |
182 } | 421 } |
183 return v_; | 422 return v_; |
184 } | 423 } |
| 424 } |
185 | 425 |
186 default: | 426 v = fmax(0.0f, v); |
187 // Handled by SkColorSpaceTransferFn. | 427 float a = 1.099296826809442f; |
188 break; | 428 float b = 0.018053968510807f; |
| 429 if (v < FromLinear(ColorSpace::TransferID::BT709, b)) { |
| 430 return v / 4.5f; |
| 431 } else { |
| 432 return powf((v + a - 1.0f) / a, 1.0f / 0.45f); |
189 } | 433 } |
190 NOTREACHED(); | |
191 return 0; | |
192 } | 434 } |
193 | 435 |
194 GFX_EXPORT Transform GetTransferMatrix(ColorSpace::MatrixID id) { | 436 GFX_EXPORT Transform GetTransferMatrix(ColorSpace::MatrixID id) { |
195 // Default values for BT709; | 437 // Default values for BT709; |
196 float Kr = 0.2126f; | 438 float Kr = 0.2126f; |
197 float Kb = 0.0722f; | 439 float Kb = 0.0722f; |
198 switch (id) { | 440 switch (id) { |
199 case ColorSpace::MatrixID::RGB: | 441 case ColorSpace::MatrixID::RGB: |
200 return Transform(); | 442 return Transform(); |
201 | 443 |
(...skipping 166 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
368 for (size_t i = 0; i < num; i++) | 610 for (size_t i = 0; i < num; i++) |
369 matrix_.TransformPoint(colors + i); | 611 matrix_.TransformPoint(colors + i); |
370 } | 612 } |
371 | 613 |
372 private: | 614 private: |
373 Transform matrix_; | 615 Transform matrix_; |
374 }; | 616 }; |
375 | 617 |
376 class ColorTransformFromLinear : public ColorTransformInternal { | 618 class ColorTransformFromLinear : public ColorTransformInternal { |
377 public: | 619 public: |
378 explicit ColorTransformFromLinear(ColorSpace::TransferID transfer, | 620 explicit ColorTransformFromLinear(ColorSpace::TransferID transfer) |
379 const SkColorSpaceTransferFn& fn, | 621 : transfer_(transfer) {} |
380 bool fn_valid) | |
381 : transfer_(transfer), fn_(fn), fn_valid_(fn_valid) {} | |
382 bool Prepend(ColorTransformInternal* prev) override { | 622 bool Prepend(ColorTransformInternal* prev) override { |
383 return prev->Join(*this); | 623 return prev->Join(*this); |
384 } | 624 } |
385 | 625 |
386 bool IsNull() override { return transfer_ == ColorSpace::TransferID::LINEAR; } | 626 bool IsNull() override { return transfer_ == ColorSpace::TransferID::LINEAR; } |
387 | 627 |
388 void transform(ColorTransform::TriStim* colors, size_t num) override { | 628 void transform(ColorTransform::TriStim* colors, size_t num) override { |
389 if (fn_valid_) { | 629 for (size_t i = 0; i < num; i++) { |
390 for (size_t i = 0; i < num; i++) { | 630 colors[i].set_x(FromLinear(transfer_, colors[i].x())); |
391 colors[i].set_x(EvalSkTransferFn(fn_, colors[i].x())); | 631 colors[i].set_y(FromLinear(transfer_, colors[i].y())); |
392 colors[i].set_y(EvalSkTransferFn(fn_, colors[i].y())); | 632 colors[i].set_z(FromLinear(transfer_, colors[i].z())); |
393 colors[i].set_z(EvalSkTransferFn(fn_, colors[i].z())); | |
394 } | |
395 } else { | |
396 for (size_t i = 0; i < num; i++) { | |
397 colors[i].set_x(FromLinear(transfer_, colors[i].x())); | |
398 colors[i].set_y(FromLinear(transfer_, colors[i].y())); | |
399 colors[i].set_z(FromLinear(transfer_, colors[i].z())); | |
400 } | |
401 } | 633 } |
402 } | 634 } |
403 | 635 |
404 private: | 636 private: |
405 friend class ColorTransformToLinear; | 637 friend class ColorTransformToLinear; |
406 ColorSpace::TransferID transfer_; | 638 ColorSpace::TransferID transfer_; |
407 SkColorSpaceTransferFn fn_; | |
408 bool fn_valid_ = false; | |
409 }; | 639 }; |
410 | 640 |
411 class ColorTransformToLinear : public ColorTransformInternal { | 641 class ColorTransformToLinear : public ColorTransformInternal { |
412 public: | 642 public: |
413 explicit ColorTransformToLinear(ColorSpace::TransferID transfer, | 643 explicit ColorTransformToLinear(ColorSpace::TransferID transfer) |
414 const SkColorSpaceTransferFn& fn, | 644 : transfer_(transfer) {} |
415 bool fn_valid) | |
416 : transfer_(transfer), fn_(fn), fn_valid_(fn_valid) {} | |
417 | 645 |
418 bool Prepend(ColorTransformInternal* prev) override { | 646 bool Prepend(ColorTransformInternal* prev) override { |
419 return prev->Join(*this); | 647 return prev->Join(*this); |
420 } | 648 } |
421 | 649 |
422 static bool IsGamma22(ColorSpace::TransferID transfer) { | 650 static bool IsGamma22(ColorSpace::TransferID transfer) { |
423 switch (transfer) { | 651 switch (transfer) { |
424 // We don't need to check BT709 here because it's been translated into | 652 // We don't need to check BT709 here because it's been translated into |
425 // SRGB in ColorSpaceToColorSpaceTransform::ColorSpaceToLinear below. | 653 // SRGB in ColorSpaceToColorSpaceTransform::ColorSpaceToLinear below. |
426 case ColorSpace::TransferID::GAMMA22: | 654 case ColorSpace::TransferID::GAMMA22: |
(...skipping 15 matching lines...) Expand all Loading... |
442 } | 670 } |
443 | 671 |
444 bool IsNull() override { return transfer_ == ColorSpace::TransferID::LINEAR; } | 672 bool IsNull() override { return transfer_ == ColorSpace::TransferID::LINEAR; } |
445 | 673 |
446 // Assumes BT2020 primaries. | 674 // Assumes BT2020 primaries. |
447 static float Luma(const ColorTransform::TriStim& c) { | 675 static float Luma(const ColorTransform::TriStim& c) { |
448 return c.x() * 0.2627f + c.y() * 0.6780f + c.z() * 0.0593f; | 676 return c.x() * 0.2627f + c.y() * 0.6780f + c.z() * 0.0593f; |
449 } | 677 } |
450 | 678 |
451 void transform(ColorTransform::TriStim* colors, size_t num) override { | 679 void transform(ColorTransform::TriStim* colors, size_t num) override { |
452 if (fn_valid_) { | 680 if (transfer_ == ColorSpace::TransferID::SMPTEST2084_NON_HDR) { |
453 for (size_t i = 0; i < num; i++) { | |
454 colors[i].set_x(EvalSkTransferFn(fn_, colors[i].x())); | |
455 colors[i].set_y(EvalSkTransferFn(fn_, colors[i].y())); | |
456 colors[i].set_z(EvalSkTransferFn(fn_, colors[i].z())); | |
457 } | |
458 } else if (transfer_ == ColorSpace::TransferID::SMPTEST2084_NON_HDR) { | |
459 for (size_t i = 0; i < num; i++) { | 681 for (size_t i = 0; i < num; i++) { |
460 ColorTransform::TriStim ret(ToLinear(transfer_, colors[i].x()), | 682 ColorTransform::TriStim ret(ToLinear(transfer_, colors[i].x()), |
461 ToLinear(transfer_, colors[i].y()), | 683 ToLinear(transfer_, colors[i].y()), |
462 ToLinear(transfer_, colors[i].z())); | 684 ToLinear(transfer_, colors[i].z())); |
463 if (Luma(ret) > 0.0) { | 685 if (Luma(ret) > 0.0) { |
464 ColorTransform::TriStim smpte2084( | 686 ColorTransform::TriStim smpte2084( |
465 ToLinear(ColorSpace::TransferID::SMPTEST2084, colors[i].x()), | 687 ToLinear(ColorSpace::TransferID::SMPTEST2084, colors[i].x()), |
466 ToLinear(ColorSpace::TransferID::SMPTEST2084, colors[i].y()), | 688 ToLinear(ColorSpace::TransferID::SMPTEST2084, colors[i].y()), |
467 ToLinear(ColorSpace::TransferID::SMPTEST2084, colors[i].z())); | 689 ToLinear(ColorSpace::TransferID::SMPTEST2084, colors[i].z())); |
468 smpte2084.Scale(Luma(ret) / Luma(smpte2084)); | 690 smpte2084.Scale(Luma(ret) / Luma(smpte2084)); |
469 ret = smpte2084; | 691 ret = smpte2084; |
470 } | 692 } |
471 colors[i] = ret; | 693 colors[i] = ret; |
472 } | 694 } |
473 } else { | 695 } else { |
474 for (size_t i = 0; i < num; i++) { | 696 for (size_t i = 0; i < num; i++) { |
475 colors[i].set_x(ToLinear(transfer_, colors[i].x())); | 697 colors[i].set_x(ToLinear(transfer_, colors[i].x())); |
476 colors[i].set_y(ToLinear(transfer_, colors[i].y())); | 698 colors[i].set_y(ToLinear(transfer_, colors[i].y())); |
477 colors[i].set_z(ToLinear(transfer_, colors[i].z())); | 699 colors[i].set_z(ToLinear(transfer_, colors[i].z())); |
478 } | 700 } |
479 } | 701 } |
480 } | 702 } |
481 | 703 |
482 private: | 704 private: |
483 ColorSpace::TransferID transfer_; | 705 ColorSpace::TransferID transfer_; |
484 SkColorSpaceTransferFn fn_; | |
485 bool fn_valid_ = false; | |
486 }; | 706 }; |
487 | 707 |
488 // BT2020 Constant Luminance is different than most other | 708 // BT2020 Constant Luminance is different than most other |
489 // ways to encode RGB values as YUV. The basic idea is that | 709 // ways to encode RGB values as YUV. The basic idea is that |
490 // transfer functions are applied on the Y value instead of | 710 // transfer functions are applied on the Y value instead of |
491 // on the RGB values. However, running the transfer function | 711 // on the RGB values. However, running the transfer function |
492 // on the U and V values doesn't make any sense since they | 712 // on the U and V values doesn't make any sense since they |
493 // are centered at 0.5. To work around this, the transfer function | 713 // are centered at 0.5. To work around this, the transfer function |
494 // is applied to the Y, R and B values, and then the U and V | 714 // is applied to the Y, R and B values, and then the U and V |
495 // values are calculated from that. | 715 // values are calculated from that. |
(...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
631 void disable_optimizations() { disable_optimizations_ = true; } | 851 void disable_optimizations() { disable_optimizations_ = true; } |
632 | 852 |
633 private: | 853 private: |
634 bool disable_optimizations_ = false; | 854 bool disable_optimizations_ = false; |
635 std::vector<std::unique_ptr<ColorTransformInternal>> transforms_; | 855 std::vector<std::unique_ptr<ColorTransformInternal>> transforms_; |
636 }; | 856 }; |
637 | 857 |
638 class ColorSpaceToColorSpaceTransform { | 858 class ColorSpaceToColorSpaceTransform { |
639 public: | 859 public: |
640 static Transform GetPrimaryTransform(const ColorSpace& c) { | 860 static Transform GetPrimaryTransform(const ColorSpace& c) { |
641 SkMatrix44 sk_matrix; | 861 if (c.primaries_ == ColorSpace::PrimaryID::CUSTOM) { |
642 c.GetPrimaryMatrix(&sk_matrix); | 862 return Transform(c.custom_primary_matrix_[0], c.custom_primary_matrix_[1], |
643 return Transform(sk_matrix); | 863 c.custom_primary_matrix_[2], c.custom_primary_matrix_[3], |
| 864 c.custom_primary_matrix_[4], c.custom_primary_matrix_[5], |
| 865 c.custom_primary_matrix_[6], c.custom_primary_matrix_[7], |
| 866 c.custom_primary_matrix_[8], c.custom_primary_matrix_[9], |
| 867 c.custom_primary_matrix_[10], |
| 868 c.custom_primary_matrix_[11], 0.0f, 0.0f, 0.0f, 1.0f); |
| 869 } else { |
| 870 return GetPrimaryMatrix(c.primaries_); |
| 871 } |
644 } | 872 } |
645 | 873 |
646 static void ColorSpaceToColorSpace(ColorSpace from, | 874 static void ColorSpaceToColorSpace(ColorSpace from, |
647 ColorSpace to, | 875 ColorSpace to, |
648 ColorTransform::Intent intent, | 876 ColorTransform::Intent intent, |
649 TransformBuilder* builder) { | 877 TransformBuilder* builder) { |
650 if (intent == ColorTransform::Intent::INTENT_PERCEPTUAL) { | 878 if (intent == ColorTransform::Intent::INTENT_PERCEPTUAL) { |
651 switch (from.transfer_) { | 879 switch (from.transfer_) { |
652 case ColorSpace::TransferID::UNSPECIFIED: | 880 case ColorSpace::TransferID::UNSPECIFIED: |
653 case ColorSpace::TransferID::BT709: | 881 case ColorSpace::TransferID::BT709: |
(...skipping 22 matching lines...) Expand all Loading... |
676 from.transfer_ = ColorSpace::TransferID::GAMMA24; | 904 from.transfer_ = ColorSpace::TransferID::GAMMA24; |
677 } | 905 } |
678 break; | 906 break; |
679 | 907 |
680 default: // Do nothing | 908 default: // Do nothing |
681 break; | 909 break; |
682 } | 910 } |
683 | 911 |
684 // TODO(hubbe): shrink gamuts here (never stretch gamuts) | 912 // TODO(hubbe): shrink gamuts here (never stretch gamuts) |
685 } | 913 } |
686 | |
687 builder->Append(base::MakeUnique<ColorTransformMatrix>( | 914 builder->Append(base::MakeUnique<ColorTransformMatrix>( |
688 GetRangeAdjustMatrix(from.range_, from.matrix_))); | 915 GetRangeAdjustMatrix(from.range_, from.matrix_))); |
689 | |
690 builder->Append(base::MakeUnique<ColorTransformMatrix>( | 916 builder->Append(base::MakeUnique<ColorTransformMatrix>( |
691 Invert(GetTransferMatrix(from.matrix_)))); | 917 Invert(GetTransferMatrix(from.matrix_)))); |
692 | 918 builder->Append(base::MakeUnique<ColorTransformToLinear>(from.transfer_)); |
693 SkColorSpaceTransferFn to_linear_fn; | |
694 bool to_linear_fn_valid = from.GetTransferFunction(&to_linear_fn); | |
695 builder->Append(base::MakeUnique<ColorTransformToLinear>( | |
696 from.transfer_, to_linear_fn, to_linear_fn_valid)); | |
697 | |
698 if (from.matrix_ == ColorSpace::MatrixID::BT2020_CL) { | 919 if (from.matrix_ == ColorSpace::MatrixID::BT2020_CL) { |
699 // BT2020 CL is a special case. | 920 // BT2020 CL is a special case. |
700 builder->Append(base::MakeUnique<ColorTransformFromBT2020CL>()); | 921 builder->Append(base::MakeUnique<ColorTransformFromBT2020CL>()); |
701 } | 922 } |
702 builder->Append( | 923 builder->Append( |
703 base::MakeUnique<ColorTransformMatrix>(GetPrimaryTransform(from))); | 924 base::MakeUnique<ColorTransformMatrix>(GetPrimaryTransform(from))); |
704 | 925 |
705 builder->Append(base::MakeUnique<ColorTransformMatrix>( | 926 builder->Append(base::MakeUnique<ColorTransformMatrix>( |
706 Invert(GetPrimaryTransform(to)))); | 927 Invert(GetPrimaryTransform(to)))); |
707 if (to.matrix_ == ColorSpace::MatrixID::BT2020_CL) { | 928 if (to.matrix_ == ColorSpace::MatrixID::BT2020_CL) { |
708 // BT2020 CL is a special case. | 929 // BT2020 CL is a special case. |
709 builder->Append(base::MakeUnique<ColorTransformToBT2020CL>()); | 930 builder->Append(base::MakeUnique<ColorTransformToBT2020CL>()); |
710 } | 931 } |
711 | 932 |
712 SkColorSpaceTransferFn from_linear_fn; | 933 builder->Append(base::MakeUnique<ColorTransformFromLinear>(to.transfer_)); |
713 bool from_linear_fn_valid = to.GetInverseTransferFunction(&from_linear_fn); | |
714 builder->Append(base::MakeUnique<ColorTransformFromLinear>( | |
715 to.transfer_, from_linear_fn, from_linear_fn_valid)); | |
716 | |
717 builder->Append( | 934 builder->Append( |
718 base::MakeUnique<ColorTransformMatrix>(GetTransferMatrix(to.matrix_))); | 935 base::MakeUnique<ColorTransformMatrix>(GetTransferMatrix(to.matrix_))); |
719 | |
720 builder->Append(base::MakeUnique<ColorTransformMatrix>( | 936 builder->Append(base::MakeUnique<ColorTransformMatrix>( |
721 Invert(GetRangeAdjustMatrix(to.range_, to.matrix_)))); | 937 Invert(GetRangeAdjustMatrix(to.range_, to.matrix_)))); |
722 } | 938 } |
723 }; | 939 }; |
724 | 940 |
725 class QCMSColorTransform : public ColorTransformInternal { | 941 class QCMSColorTransform : public ColorTransformInternal { |
726 public: | 942 public: |
727 // Takes ownership of the profiles | 943 // Takes ownership of the profiles |
728 QCMSColorTransform(qcms_profile* from, qcms_profile* to) | 944 QCMSColorTransform(qcms_profile* from, qcms_profile* to) |
729 : from_(from), to_(to) {} | 945 : from_(from), to_(to) {} |
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
805 from_profile ? ColorSpace::CreateXYZD50() : from, | 1021 from_profile ? ColorSpace::CreateXYZD50() : from, |
806 to_profile ? ColorSpace::CreateXYZD50() : to, intent, &builder); | 1022 to_profile ? ColorSpace::CreateXYZD50() : to, intent, &builder); |
807 if (to_profile) { | 1023 if (to_profile) { |
808 builder.Append(std::unique_ptr<ColorTransformInternal>( | 1024 builder.Append(std::unique_ptr<ColorTransformInternal>( |
809 new QCMSColorTransform(GetXYZD50Profile(), to_profile))); | 1025 new QCMSColorTransform(GetXYZD50Profile(), to_profile))); |
810 } | 1026 } |
811 | 1027 |
812 return builder.GetTransform(); | 1028 return builder.GetTransform(); |
813 } | 1029 } |
814 | 1030 |
815 // static | |
816 float ColorTransform::ToLinearForTesting(ColorSpace::TransferID transfer, | |
817 float v) { | |
818 ColorSpace space(ColorSpace::PrimaryID::BT709, transfer, | |
819 ColorSpace::MatrixID::RGB, ColorSpace::RangeID::FULL); | |
820 SkColorSpaceTransferFn to_linear_fn; | |
821 bool to_linear_fn_valid = space.GetTransferFunction(&to_linear_fn); | |
822 ColorTransformToLinear to_linear_transform(transfer, to_linear_fn, | |
823 to_linear_fn_valid); | |
824 TriStim color(v, v, v); | |
825 to_linear_transform.transform(&color, 1); | |
826 return color.x(); | |
827 } | |
828 | |
829 // static | |
830 float ColorTransform::FromLinearForTesting(ColorSpace::TransferID transfer, | |
831 float v) { | |
832 ColorSpace space(ColorSpace::PrimaryID::BT709, transfer, | |
833 ColorSpace::MatrixID::RGB, ColorSpace::RangeID::FULL); | |
834 SkColorSpaceTransferFn from_linear_fn; | |
835 bool from_linear_fn_valid = space.GetInverseTransferFunction(&from_linear_fn); | |
836 | |
837 ColorTransformFromLinear from_linear_transform(transfer, from_linear_fn, | |
838 from_linear_fn_valid); | |
839 TriStim color(v, v, v); | |
840 from_linear_transform.transform(&color, 1); | |
841 return color.x(); | |
842 } | |
843 | |
844 } // namespace gfx | 1031 } // namespace gfx |
OLD | NEW |