Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(178)

Side by Side Diff: ui/gfx/color_transform.cc

Issue 2652503002: Use SkICC in gfx::ICCProfile and gfx::ColorSpace (Closed)
Patch Set: Rebase Created 3 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « ui/gfx/color_transform.h ('k') | ui/gfx/color_transform_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
24 Transform Invert(const Transform& t) { 32 Transform Invert(const Transform& t) {
25 Transform ret = t; 33 Transform ret = t;
26 if (!t.GetInverse(&ret)) { 34 if (!t.GetInverse(&ret)) {
27 LOG(ERROR) << "Inverse should alsways be possible."; 35 LOG(ERROR) << "Inverse should alsways be possible.";
28 } 36 }
29 return ret; 37 return ret;
30 } 38 }
31 39
32 GFX_EXPORT Transform GetPrimaryMatrix(ColorSpace::PrimaryID id) { 40 float FromLinear(ColorSpace::TransferID id, float v) {
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) {
164 switch (id) { 41 switch (id) {
165 case ColorSpace::TransferID::SMPTEST2084_NON_HDR: 42 case ColorSpace::TransferID::SMPTEST2084_NON_HDR:
166 // Should already be handled. 43 // 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.
182 break; 44 break;
183 45
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 case ColorSpace::TransferID::LINEAR_HDR:
205 return v;
206
207 case ColorSpace::TransferID::LOG: 46 case ColorSpace::TransferID::LOG:
208 if (v < 0.01f) 47 if (v < 0.01f)
209 return 0.0f; 48 return 0.0f;
210 return 1.0f + log(v) / log(10.0f) / 2.0f; 49 return 1.0f + log(v) / log(10.0f) / 2.0f;
211 50
212 case ColorSpace::TransferID::LOG_SQRT: 51 case ColorSpace::TransferID::LOG_SQRT:
213 if (v < sqrt(10.0f) / 1000.0f) 52 if (v < sqrt(10.0f) / 1000.0f)
214 return 0.0f; 53 return 0.0f;
215 return 1.0f + log(v) / log(10.0f) / 2.5f; 54 return 1.0f + log(v) / log(10.0f) / 2.5f;
216 55
(...skipping 15 matching lines...) Expand all
232 float l = 0.0045f; 71 float l = 0.0045f;
233 if (v < -l) { 72 if (v < -l) {
234 return -(a * powf(-4.0f * v, 0.45f) + (a - 1.0f)) / 4.0f; 73 return -(a * powf(-4.0f * v, 0.45f) + (a - 1.0f)) / 4.0f;
235 } else if (v <= b) { 74 } else if (v <= b) {
236 return 4.5f * v; 75 return 4.5f * v;
237 } else { 76 } else {
238 return a * powf(v, 0.45f) - (a - 1.0f); 77 return a * powf(v, 0.45f) - (a - 1.0f);
239 } 78 }
240 } 79 }
241 80
242 case ColorSpace::TransferID::IEC61966_2_1: { // SRGB
243 v = fmax(0.0f, v);
244 float a = 1.055f;
245 float b = 0.0031308f;
246 if (v < b) {
247 return 12.92f * v;
248 } else {
249 return a * powf(v, 1.0f / 2.4f) - (a - 1.0f);
250 }
251 }
252 case ColorSpace::TransferID::SMPTEST2084: { 81 case ColorSpace::TransferID::SMPTEST2084: {
253 // Go from scRGB levels to 0-1. 82 // Go from scRGB levels to 0-1.
254 v *= 80.0f / 10000.0f; 83 v *= 80.0f / 10000.0f;
255 v = fmax(0.0f, v); 84 v = fmax(0.0f, v);
256 float m1 = (2610.0f / 4096.0f) / 4.0f; 85 float m1 = (2610.0f / 4096.0f) / 4.0f;
257 float m2 = (2523.0f / 4096.0f) * 128.0f; 86 float m2 = (2523.0f / 4096.0f) * 128.0f;
258 float c1 = 3424.0f / 4096.0f; 87 float c1 = 3424.0f / 4096.0f;
259 float c2 = (2413.0f / 4096.0f) * 32.0f; 88 float c2 = (2413.0f / 4096.0f) * 32.0f;
260 float c3 = (2392.0f / 4096.0f) * 32.0f; 89 float c3 = (2392.0f / 4096.0f) * 32.0f;
261 return powf((c1 + c2 * powf(v, m1)) / (1.0f + c3 * powf(v, m1)), m2); 90 return powf((c1 + c2 * powf(v, m1)) / (1.0f + c3 * powf(v, m1)), m2);
262 } 91 }
263 92
264 case ColorSpace::TransferID::SMPTEST428_1:
265 v = fmax(0.0f, v);
266 return powf(48.0f * v + 52.37f, 1.0f / 2.6f);
267
268 // Spec: http://www.arib.or.jp/english/html/overview/doc/2-STD-B67v1_0.pdf 93 // Spec: http://www.arib.or.jp/english/html/overview/doc/2-STD-B67v1_0.pdf
269 case ColorSpace::TransferID::ARIB_STD_B67: { 94 case ColorSpace::TransferID::ARIB_STD_B67: {
270 const float a = 0.17883277f; 95 const float a = 0.17883277f;
271 const float b = 0.28466892f; 96 const float b = 0.28466892f;
272 const float c = 0.55991073f; 97 const float c = 0.55991073f;
273 v = fmax(0.0f, v); 98 v = fmax(0.0f, v);
274 if (v <= 1) 99 if (v <= 1)
275 return 0.5f * sqrtf(v); 100 return 0.5f * sqrtf(v);
276 else 101 else
277 return a * log(v - b) + c; 102 return a * log(v - b) + c;
278 } 103 }
279 104
280 // Chrome-specific values below 105 default:
281 case ColorSpace::TransferID::GAMMA24: 106 // Handled by SkColorSpaceTransferFn.
282 v = fmax(0.0f, v); 107 break;
283 return powf(v, 1.0f / 2.4f);
284 } 108 }
285 109 NOTREACHED();
286 v = fmax(0.0f, v); 110 return 0;
287 float a = 1.099296826809442f;
288 float b = 0.018053968510807f;
289 if (v <= b) {
290 return 4.5f * v;
291 } else {
292 return a * powf(v, 0.45f) - (a - 1.0f);
293 }
294 } 111 }
295 112
296 GFX_EXPORT float ToLinear(ColorSpace::TransferID id, float v) { 113 float ToLinear(ColorSpace::TransferID id, float v) {
297 switch (id) { 114 switch (id) {
298 case ColorSpace::TransferID::CUSTOM:
299 // TODO(hubbe): Actually implement custom transfer functions.
300 case ColorSpace::TransferID::RESERVED0:
301 case ColorSpace::TransferID::RESERVED:
302 case ColorSpace::TransferID::UNSPECIFIED:
303 case ColorSpace::TransferID::UNKNOWN:
304 // All unknown values default to BT709
305
306 case ColorSpace::TransferID::BT709:
307 case ColorSpace::TransferID::SMPTE170M:
308 case ColorSpace::TransferID::BT2020_10:
309 case ColorSpace::TransferID::BT2020_12:
310 // BT709 is our "default" cause, so put the code after the switch
311 // to avoid "control reaches end of non-void function" errors.
312 break;
313
314 case ColorSpace::TransferID::GAMMA22:
315 v = fmax(0.0f, v);
316 return powf(v, 2.2f);
317
318 case ColorSpace::TransferID::GAMMA28:
319 v = fmax(0.0f, v);
320 return powf(v, 2.8f);
321
322 case ColorSpace::TransferID::SMPTE240M: {
323 v = fmax(0.0f, v);
324 float a = 1.11157219592173128753f;
325 float b = 0.02282158552944503135f;
326 if (v <= FromLinear(ColorSpace::TransferID::SMPTE240M, b)) {
327 return v / 4.0f;
328 } else {
329 return powf((v + a - 1.0f) / a, 1.0f / 0.45f);
330 }
331 }
332
333 case ColorSpace::TransferID::LINEAR:
334 case ColorSpace::TransferID::LINEAR_HDR:
335 return v;
336
337 case ColorSpace::TransferID::LOG: 115 case ColorSpace::TransferID::LOG:
338 if (v < 0.0f) 116 if (v < 0.0f)
339 return 0.0f; 117 return 0.0f;
340 return powf(10.0f, (v - 1.0f) * 2.0f); 118 return powf(10.0f, (v - 1.0f) * 2.0f);
341 119
342 case ColorSpace::TransferID::LOG_SQRT: 120 case ColorSpace::TransferID::LOG_SQRT:
343 if (v < 0.0f) 121 if (v < 0.0f)
344 return 0.0f; 122 return 0.0f;
345 return powf(10.0f, (v - 1.0f) * 2.5f); 123 return powf(10.0f, (v - 1.0f) * 2.5f);
346 124
(...skipping 15 matching lines...) Expand all
362 float l = 0.0045f; 140 float l = 0.0045f;
363 if (v < FromLinear(ColorSpace::TransferID::BT1361_ECG, -l)) { 141 if (v < FromLinear(ColorSpace::TransferID::BT1361_ECG, -l)) {
364 return -powf((1.0f - a - v * 4.0f) / a, 1.0f / 0.45f) / 4.0f; 142 return -powf((1.0f - a - v * 4.0f) / a, 1.0f / 0.45f) / 4.0f;
365 } else if (v <= FromLinear(ColorSpace::TransferID::BT1361_ECG, b)) { 143 } else if (v <= FromLinear(ColorSpace::TransferID::BT1361_ECG, b)) {
366 return v / 4.5f; 144 return v / 4.5f;
367 } else { 145 } else {
368 return powf((v + a - 1.0f) / a, 1.0f / 0.45f); 146 return powf((v + a - 1.0f) / a, 1.0f / 0.45f);
369 } 147 }
370 } 148 }
371 149
372 case ColorSpace::TransferID::IEC61966_2_1: { // SRGB
373 v = fmax(0.0f, v);
374 float a = 1.055f;
375 float b = 0.0031308f;
376 if (v < FromLinear(ColorSpace::TransferID::IEC61966_2_1, b)) {
377 return v / 12.92f;
378 } else {
379 return powf((v + a - 1.0f) / a, 2.4f);
380 }
381 }
382
383 case ColorSpace::TransferID::SMPTEST2084: { 150 case ColorSpace::TransferID::SMPTEST2084: {
384 v = fmax(0.0f, v); 151 v = fmax(0.0f, v);
385 float m1 = (2610.0f / 4096.0f) / 4.0f; 152 float m1 = (2610.0f / 4096.0f) / 4.0f;
386 float m2 = (2523.0f / 4096.0f) * 128.0f; 153 float m2 = (2523.0f / 4096.0f) * 128.0f;
387 float c1 = 3424.0f / 4096.0f; 154 float c1 = 3424.0f / 4096.0f;
388 float c2 = (2413.0f / 4096.0f) * 32.0f; 155 float c2 = (2413.0f / 4096.0f) * 32.0f;
389 float c3 = (2392.0f / 4096.0f) * 32.0f; 156 float c3 = (2392.0f / 4096.0f) * 32.0f;
390 v = powf( 157 v = powf(
391 fmax(powf(v, 1.0f / m2) - c1, 0) / (c2 - c3 * powf(v, 1.0f / m2)), 158 fmax(powf(v, 1.0f / m2) - c1, 0) / (c2 - c3 * powf(v, 1.0f / m2)),
392 1.0f / m1); 159 1.0f / m1);
393 // This matches the scRGB definition that 1.0 means 80 nits. 160 // This matches the scRGB definition that 1.0 means 80 nits.
394 // TODO(hubbe): It would be *nice* if 1.0 meant more than that, but 161 // TODO(hubbe): It would be *nice* if 1.0 meant more than that, but
395 // that might be difficult to do right now. 162 // that might be difficult to do right now.
396 v *= 10000.0f / 80.0f; 163 v *= 10000.0f / 80.0f;
397 return v; 164 return v;
398 } 165 }
399 166
400 case ColorSpace::TransferID::SMPTEST428_1:
401 return (powf(v, 2.6f) - 52.37f) / 48.0f;
402
403 // Chrome-specific values below
404 case ColorSpace::TransferID::GAMMA24:
405 v = fmax(0.0f, v);
406 return powf(v, 2.4f);
407
408 case ColorSpace::TransferID::SMPTEST2084_NON_HDR: 167 case ColorSpace::TransferID::SMPTEST2084_NON_HDR:
409 v = fmax(0.0f, v); 168 v = fmax(0.0f, v);
410 return fmin(2.3f * pow(v, 2.8f), v / 5.0f + 0.8f); 169 return fmin(2.3f * pow(v, 2.8f), v / 5.0f + 0.8f);
411 170
412 // Spec: http://www.arib.or.jp/english/html/overview/doc/2-STD-B67v1_0.pdf 171 // Spec: http://www.arib.or.jp/english/html/overview/doc/2-STD-B67v1_0.pdf
413 case ColorSpace::TransferID::ARIB_STD_B67: { 172 case ColorSpace::TransferID::ARIB_STD_B67: {
414 v = fmax(0.0f, v); 173 v = fmax(0.0f, v);
415 const float a = 0.17883277f; 174 const float a = 0.17883277f;
416 const float b = 0.28466892f; 175 const float b = 0.28466892f;
417 const float c = 0.55991073f; 176 const float c = 0.55991073f;
418 float v_ = 0.0f; 177 float v_ = 0.0f;
419 if (v <= 0.5f) { 178 if (v <= 0.5f) {
420 v_ = (v * 2.0f) * (v * 2.0f); 179 v_ = (v * 2.0f) * (v * 2.0f);
421 } else { 180 } else {
422 v_ = exp((v - c) / a) + b; 181 v_ = exp((v - c) / a) + b;
423 } 182 }
424 return v_; 183 return v_;
425 } 184 }
185
186 default:
187 // Handled by SkColorSpaceTransferFn.
188 break;
426 } 189 }
427 190 NOTREACHED();
428 v = fmax(0.0f, v); 191 return 0;
429 float a = 1.099296826809442f;
430 float b = 0.018053968510807f;
431 if (v < FromLinear(ColorSpace::TransferID::BT709, b)) {
432 return v / 4.5f;
433 } else {
434 return powf((v + a - 1.0f) / a, 1.0f / 0.45f);
435 }
436 } 192 }
437 193
438 GFX_EXPORT Transform GetTransferMatrix(ColorSpace::MatrixID id) { 194 GFX_EXPORT Transform GetTransferMatrix(ColorSpace::MatrixID id) {
439 // Default values for BT709; 195 // Default values for BT709;
440 float Kr = 0.2126f; 196 float Kr = 0.2126f;
441 float Kb = 0.0722f; 197 float Kb = 0.0722f;
442 switch (id) { 198 switch (id) {
443 case ColorSpace::MatrixID::RGB: 199 case ColorSpace::MatrixID::RGB:
444 return Transform(); 200 return Transform();
445 201
(...skipping 166 matching lines...) Expand 10 before | Expand all | Expand 10 after
612 for (size_t i = 0; i < num; i++) 368 for (size_t i = 0; i < num; i++)
613 matrix_.TransformPoint(colors + i); 369 matrix_.TransformPoint(colors + i);
614 } 370 }
615 371
616 private: 372 private:
617 Transform matrix_; 373 Transform matrix_;
618 }; 374 };
619 375
620 class ColorTransformFromLinear : public ColorTransformInternal { 376 class ColorTransformFromLinear : public ColorTransformInternal {
621 public: 377 public:
622 explicit ColorTransformFromLinear(ColorSpace::TransferID transfer) 378 explicit ColorTransformFromLinear(ColorSpace::TransferID transfer,
623 : transfer_(transfer) { 379 const SkColorSpaceTransferFn& fn,
624 // Map LINEAR_HDR to LINEAR for optimizations. 380 bool fn_valid)
625 if (transfer_ == ColorSpace::TransferID::LINEAR_HDR) { 381 : transfer_(transfer), fn_(fn), fn_valid_(fn_valid) {
382 if (transfer_ == ColorSpace::TransferID::LINEAR_HDR)
626 transfer_ = ColorSpace::TransferID::LINEAR; 383 transfer_ = ColorSpace::TransferID::LINEAR;
627 }
628 } 384 }
629 bool Prepend(ColorTransformInternal* prev) override { 385 bool Prepend(ColorTransformInternal* prev) override {
630 return prev->Join(*this); 386 return prev->Join(*this);
631 } 387 }
632 388
633 bool IsNull() override { return transfer_ == ColorSpace::TransferID::LINEAR; } 389 bool IsNull() override { return transfer_ == ColorSpace::TransferID::LINEAR; }
634 390
635 void transform(ColorTransform::TriStim* colors, size_t num) override { 391 void transform(ColorTransform::TriStim* colors, size_t num) override {
636 for (size_t i = 0; i < num; i++) { 392 if (fn_valid_) {
637 colors[i].set_x(FromLinear(transfer_, colors[i].x())); 393 for (size_t i = 0; i < num; i++) {
638 colors[i].set_y(FromLinear(transfer_, colors[i].y())); 394 colors[i].set_x(EvalSkTransferFn(fn_, colors[i].x()));
639 colors[i].set_z(FromLinear(transfer_, colors[i].z())); 395 colors[i].set_y(EvalSkTransferFn(fn_, colors[i].y()));
396 colors[i].set_z(EvalSkTransferFn(fn_, colors[i].z()));
397 }
398 } else {
399 for (size_t i = 0; i < num; i++) {
400 colors[i].set_x(FromLinear(transfer_, colors[i].x()));
401 colors[i].set_y(FromLinear(transfer_, colors[i].y()));
402 colors[i].set_z(FromLinear(transfer_, colors[i].z()));
403 }
640 } 404 }
641 } 405 }
642 406
643 private: 407 private:
644 friend class ColorTransformToLinear; 408 friend class ColorTransformToLinear;
645 ColorSpace::TransferID transfer_; 409 ColorSpace::TransferID transfer_;
410 SkColorSpaceTransferFn fn_;
411 bool fn_valid_ = false;
646 }; 412 };
647 413
648 class ColorTransformToLinear : public ColorTransformInternal { 414 class ColorTransformToLinear : public ColorTransformInternal {
649 public: 415 public:
650 explicit ColorTransformToLinear(ColorSpace::TransferID transfer) 416 explicit ColorTransformToLinear(ColorSpace::TransferID transfer,
651 : transfer_(transfer) { 417 const SkColorSpaceTransferFn& fn,
652 // Map LINEAR_HDR to LINEAR for optimizations. 418 bool fn_valid)
653 if (transfer_ == ColorSpace::TransferID::LINEAR_HDR) { 419 : transfer_(transfer), fn_(fn), fn_valid_(fn_valid) {
420 if (transfer_ == ColorSpace::TransferID::LINEAR_HDR)
654 transfer_ = ColorSpace::TransferID::LINEAR; 421 transfer_ = ColorSpace::TransferID::LINEAR;
655 }
656 } 422 }
657 423
658 bool Prepend(ColorTransformInternal* prev) override { 424 bool Prepend(ColorTransformInternal* prev) override {
659 return prev->Join(*this); 425 return prev->Join(*this);
660 } 426 }
661 427
662 static bool IsGamma22(ColorSpace::TransferID transfer) { 428 static bool IsGamma22(ColorSpace::TransferID transfer) {
663 switch (transfer) { 429 switch (transfer) {
664 // We don't need to check BT709 here because it's been translated into 430 // We don't need to check BT709 here because it's been translated into
665 // SRGB in ColorSpaceToColorSpaceTransform::ColorSpaceToLinear below. 431 // SRGB in ColorSpaceToColorSpaceTransform::ColorSpaceToLinear below.
(...skipping 16 matching lines...) Expand all
682 } 448 }
683 449
684 bool IsNull() override { return transfer_ == ColorSpace::TransferID::LINEAR; } 450 bool IsNull() override { return transfer_ == ColorSpace::TransferID::LINEAR; }
685 451
686 // Assumes BT2020 primaries. 452 // Assumes BT2020 primaries.
687 static float Luma(const ColorTransform::TriStim& c) { 453 static float Luma(const ColorTransform::TriStim& c) {
688 return c.x() * 0.2627f + c.y() * 0.6780f + c.z() * 0.0593f; 454 return c.x() * 0.2627f + c.y() * 0.6780f + c.z() * 0.0593f;
689 } 455 }
690 456
691 void transform(ColorTransform::TriStim* colors, size_t num) override { 457 void transform(ColorTransform::TriStim* colors, size_t num) override {
692 if (transfer_ == ColorSpace::TransferID::SMPTEST2084_NON_HDR) { 458 if (fn_valid_) {
459 for (size_t i = 0; i < num; i++) {
460 colors[i].set_x(EvalSkTransferFn(fn_, colors[i].x()));
461 colors[i].set_y(EvalSkTransferFn(fn_, colors[i].y()));
462 colors[i].set_z(EvalSkTransferFn(fn_, colors[i].z()));
463 }
464 } else if (transfer_ == ColorSpace::TransferID::SMPTEST2084_NON_HDR) {
693 for (size_t i = 0; i < num; i++) { 465 for (size_t i = 0; i < num; i++) {
694 ColorTransform::TriStim ret(ToLinear(transfer_, colors[i].x()), 466 ColorTransform::TriStim ret(ToLinear(transfer_, colors[i].x()),
695 ToLinear(transfer_, colors[i].y()), 467 ToLinear(transfer_, colors[i].y()),
696 ToLinear(transfer_, colors[i].z())); 468 ToLinear(transfer_, colors[i].z()));
697 if (Luma(ret) > 0.0) { 469 if (Luma(ret) > 0.0) {
698 ColorTransform::TriStim smpte2084( 470 ColorTransform::TriStim smpte2084(
699 ToLinear(ColorSpace::TransferID::SMPTEST2084, colors[i].x()), 471 ToLinear(ColorSpace::TransferID::SMPTEST2084, colors[i].x()),
700 ToLinear(ColorSpace::TransferID::SMPTEST2084, colors[i].y()), 472 ToLinear(ColorSpace::TransferID::SMPTEST2084, colors[i].y()),
701 ToLinear(ColorSpace::TransferID::SMPTEST2084, colors[i].z())); 473 ToLinear(ColorSpace::TransferID::SMPTEST2084, colors[i].z()));
702 smpte2084.Scale(Luma(ret) / Luma(smpte2084)); 474 smpte2084.Scale(Luma(ret) / Luma(smpte2084));
703 ret = smpte2084; 475 ret = smpte2084;
704 } 476 }
705 colors[i] = ret; 477 colors[i] = ret;
706 } 478 }
707 } else { 479 } else {
708 for (size_t i = 0; i < num; i++) { 480 for (size_t i = 0; i < num; i++) {
709 colors[i].set_x(ToLinear(transfer_, colors[i].x())); 481 colors[i].set_x(ToLinear(transfer_, colors[i].x()));
710 colors[i].set_y(ToLinear(transfer_, colors[i].y())); 482 colors[i].set_y(ToLinear(transfer_, colors[i].y()));
711 colors[i].set_z(ToLinear(transfer_, colors[i].z())); 483 colors[i].set_z(ToLinear(transfer_, colors[i].z()));
712 } 484 }
713 } 485 }
714 } 486 }
715 487
716 private: 488 private:
717 ColorSpace::TransferID transfer_; 489 ColorSpace::TransferID transfer_;
490 SkColorSpaceTransferFn fn_;
491 bool fn_valid_ = false;
718 }; 492 };
719 493
720 // BT2020 Constant Luminance is different than most other 494 // BT2020 Constant Luminance is different than most other
721 // ways to encode RGB values as YUV. The basic idea is that 495 // ways to encode RGB values as YUV. The basic idea is that
722 // transfer functions are applied on the Y value instead of 496 // transfer functions are applied on the Y value instead of
723 // on the RGB values. However, running the transfer function 497 // on the RGB values. However, running the transfer function
724 // on the U and V values doesn't make any sense since they 498 // on the U and V values doesn't make any sense since they
725 // are centered at 0.5. To work around this, the transfer function 499 // are centered at 0.5. To work around this, the transfer function
726 // is applied to the Y, R and B values, and then the U and V 500 // is applied to the Y, R and B values, and then the U and V
727 // values are calculated from that. 501 // values are calculated from that.
(...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after
863 void disable_optimizations() { disable_optimizations_ = true; } 637 void disable_optimizations() { disable_optimizations_ = true; }
864 638
865 private: 639 private:
866 bool disable_optimizations_ = false; 640 bool disable_optimizations_ = false;
867 std::vector<std::unique_ptr<ColorTransformInternal>> transforms_; 641 std::vector<std::unique_ptr<ColorTransformInternal>> transforms_;
868 }; 642 };
869 643
870 class ColorSpaceToColorSpaceTransform { 644 class ColorSpaceToColorSpaceTransform {
871 public: 645 public:
872 static Transform GetPrimaryTransform(const ColorSpace& c) { 646 static Transform GetPrimaryTransform(const ColorSpace& c) {
873 if (c.primaries_ == ColorSpace::PrimaryID::CUSTOM) { 647 SkMatrix44 sk_matrix;
874 return Transform(c.custom_primary_matrix_[0], c.custom_primary_matrix_[1], 648 c.GetPrimaryMatrix(&sk_matrix);
875 c.custom_primary_matrix_[2], c.custom_primary_matrix_[3], 649 return Transform(sk_matrix);
876 c.custom_primary_matrix_[4], c.custom_primary_matrix_[5],
877 c.custom_primary_matrix_[6], c.custom_primary_matrix_[7],
878 c.custom_primary_matrix_[8], c.custom_primary_matrix_[9],
879 c.custom_primary_matrix_[10],
880 c.custom_primary_matrix_[11], 0.0f, 0.0f, 0.0f, 1.0f);
881 } else {
882 return GetPrimaryMatrix(c.primaries_);
883 }
884 } 650 }
885 651
886 static void ColorSpaceToColorSpace(ColorSpace from, 652 static void ColorSpaceToColorSpace(ColorSpace from,
887 ColorSpace to, 653 ColorSpace to,
888 ColorTransform::Intent intent, 654 ColorTransform::Intent intent,
889 TransformBuilder* builder) { 655 TransformBuilder* builder) {
890 if (intent == ColorTransform::Intent::INTENT_PERCEPTUAL) { 656 if (intent == ColorTransform::Intent::INTENT_PERCEPTUAL) {
891 switch (from.transfer_) { 657 switch (from.transfer_) {
892 case ColorSpace::TransferID::UNSPECIFIED: 658 case ColorSpace::TransferID::UNSPECIFIED:
893 case ColorSpace::TransferID::BT709: 659 case ColorSpace::TransferID::BT709:
(...skipping 22 matching lines...) Expand all
916 from.transfer_ = ColorSpace::TransferID::GAMMA24; 682 from.transfer_ = ColorSpace::TransferID::GAMMA24;
917 } 683 }
918 break; 684 break;
919 685
920 default: // Do nothing 686 default: // Do nothing
921 break; 687 break;
922 } 688 }
923 689
924 // TODO(hubbe): shrink gamuts here (never stretch gamuts) 690 // TODO(hubbe): shrink gamuts here (never stretch gamuts)
925 } 691 }
692
926 builder->Append(base::MakeUnique<ColorTransformMatrix>( 693 builder->Append(base::MakeUnique<ColorTransformMatrix>(
927 GetRangeAdjustMatrix(from.range_, from.matrix_))); 694 GetRangeAdjustMatrix(from.range_, from.matrix_)));
695
928 builder->Append(base::MakeUnique<ColorTransformMatrix>( 696 builder->Append(base::MakeUnique<ColorTransformMatrix>(
929 Invert(GetTransferMatrix(from.matrix_)))); 697 Invert(GetTransferMatrix(from.matrix_))));
930 builder->Append(base::MakeUnique<ColorTransformToLinear>(from.transfer_)); 698
699 SkColorSpaceTransferFn to_linear_fn;
700 bool to_linear_fn_valid = from.GetTransferFunction(&to_linear_fn);
701 builder->Append(base::MakeUnique<ColorTransformToLinear>(
702 from.transfer_, to_linear_fn, to_linear_fn_valid));
703
931 if (from.matrix_ == ColorSpace::MatrixID::BT2020_CL) { 704 if (from.matrix_ == ColorSpace::MatrixID::BT2020_CL) {
932 // BT2020 CL is a special case. 705 // BT2020 CL is a special case.
933 builder->Append(base::MakeUnique<ColorTransformFromBT2020CL>()); 706 builder->Append(base::MakeUnique<ColorTransformFromBT2020CL>());
934 } 707 }
935 builder->Append( 708 builder->Append(
936 base::MakeUnique<ColorTransformMatrix>(GetPrimaryTransform(from))); 709 base::MakeUnique<ColorTransformMatrix>(GetPrimaryTransform(from)));
937 710
938 builder->Append(base::MakeUnique<ColorTransformMatrix>( 711 builder->Append(base::MakeUnique<ColorTransformMatrix>(
939 Invert(GetPrimaryTransform(to)))); 712 Invert(GetPrimaryTransform(to))));
940 if (to.matrix_ == ColorSpace::MatrixID::BT2020_CL) { 713 if (to.matrix_ == ColorSpace::MatrixID::BT2020_CL) {
941 // BT2020 CL is a special case. 714 // BT2020 CL is a special case.
942 builder->Append(base::MakeUnique<ColorTransformToBT2020CL>()); 715 builder->Append(base::MakeUnique<ColorTransformToBT2020CL>());
943 } 716 }
944 717
945 builder->Append(base::MakeUnique<ColorTransformFromLinear>(to.transfer_)); 718 SkColorSpaceTransferFn from_linear_fn;
719 bool from_linear_fn_valid = to.GetInverseTransferFunction(&from_linear_fn);
720 builder->Append(base::MakeUnique<ColorTransformFromLinear>(
721 to.transfer_, from_linear_fn, from_linear_fn_valid));
722
946 builder->Append( 723 builder->Append(
947 base::MakeUnique<ColorTransformMatrix>(GetTransferMatrix(to.matrix_))); 724 base::MakeUnique<ColorTransformMatrix>(GetTransferMatrix(to.matrix_)));
725
948 builder->Append(base::MakeUnique<ColorTransformMatrix>( 726 builder->Append(base::MakeUnique<ColorTransformMatrix>(
949 Invert(GetRangeAdjustMatrix(to.range_, to.matrix_)))); 727 Invert(GetRangeAdjustMatrix(to.range_, to.matrix_))));
950 } 728 }
951 }; 729 };
952 730
953 class QCMSColorTransform : public ColorTransformInternal { 731 class QCMSColorTransform : public ColorTransformInternal {
954 public: 732 public:
955 // Takes ownership of the profiles 733 // Takes ownership of the profiles
956 QCMSColorTransform(qcms_profile* from, qcms_profile* to) 734 QCMSColorTransform(qcms_profile* from, qcms_profile* to)
957 : from_(from), to_(to) {} 735 : from_(from), to_(to) {}
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after
1033 from_profile ? ColorSpace::CreateXYZD50() : from, 811 from_profile ? ColorSpace::CreateXYZD50() : from,
1034 to_profile ? ColorSpace::CreateXYZD50() : to, intent, &builder); 812 to_profile ? ColorSpace::CreateXYZD50() : to, intent, &builder);
1035 if (to_profile) { 813 if (to_profile) {
1036 builder.Append(std::unique_ptr<ColorTransformInternal>( 814 builder.Append(std::unique_ptr<ColorTransformInternal>(
1037 new QCMSColorTransform(GetXYZD50Profile(), to_profile))); 815 new QCMSColorTransform(GetXYZD50Profile(), to_profile)));
1038 } 816 }
1039 817
1040 return builder.GetTransform(); 818 return builder.GetTransform();
1041 } 819 }
1042 820
821 // static
822 float ColorTransform::ToLinearForTesting(ColorSpace::TransferID transfer,
823 float v) {
824 ColorSpace space(ColorSpace::PrimaryID::BT709, transfer,
825 ColorSpace::MatrixID::RGB, ColorSpace::RangeID::FULL);
826 SkColorSpaceTransferFn to_linear_fn;
827 bool to_linear_fn_valid = space.GetTransferFunction(&to_linear_fn);
828 ColorTransformToLinear to_linear_transform(transfer, to_linear_fn,
829 to_linear_fn_valid);
830 TriStim color(v, v, v);
831 to_linear_transform.transform(&color, 1);
832 return color.x();
833 }
834
835 // static
836 float ColorTransform::FromLinearForTesting(ColorSpace::TransferID transfer,
837 float v) {
838 ColorSpace space(ColorSpace::PrimaryID::BT709, transfer,
839 ColorSpace::MatrixID::RGB, ColorSpace::RangeID::FULL);
840 SkColorSpaceTransferFn from_linear_fn;
841 bool from_linear_fn_valid = space.GetInverseTransferFunction(&from_linear_fn);
842
843 ColorTransformFromLinear from_linear_transform(transfer, from_linear_fn,
844 from_linear_fn_valid);
845 TriStim color(v, v, v);
846 from_linear_transform.transform(&color, 1);
847 return color.x();
848 }
849
1043 } // namespace gfx 850 } // namespace gfx
OLDNEW
« no previous file with comments | « ui/gfx/color_transform.h ('k') | ui/gfx/color_transform_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698