1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "ui/gfx/color_utils.h"
14 #include "base/basictypes.h"
15 #include "base/logging.h"
16 #include "build/build_config.h"
18 #include "skia/ext/skia_utils_win.h"
20 #include "third_party/skia/include/core/SkBitmap.h"
22 namespace color_utils
{
25 // Helper functions -----------------------------------------------------------
29 int calcHue(double temp1
, double temp2
, double hue
) {
35 double result
= temp1
;
37 result
= temp1
+ (temp2
- temp1
) * hue
* 6.0;
38 else if (hue
* 2.0 < 1.0)
40 else if (hue
* 3.0 < 2.0)
41 result
= temp1
+ (temp2
- temp1
) * (2.0 / 3.0 - hue
) * 6.0;
43 // Scale the result from 0 - 255 and round off the value.
44 return static_cast<int>(result
* 255 + .5);
47 // Next two functions' formulas from:
48 // http://www.w3.org/TR/WCAG20/#relativeluminancedef
49 // http://www.w3.org/TR/WCAG20/#contrast-ratiodef
51 double ConvertSRGB(double eight_bit_component
) {
52 const double component
= eight_bit_component
/ 255.0;
53 return (component
<= 0.03928) ?
54 (component
/ 12.92) : pow((component
+ 0.055) / 1.055, 2.4);
57 SkColor
LumaInvertColor(SkColor color
) {
59 SkColorToHSL(color
, &hsl
);
61 return HSLToSkColor(hsl
, 255);
64 double ContrastRatio(double foreground_luminance
, double background_luminance
) {
65 DCHECK_GE(foreground_luminance
, 0.0);
66 DCHECK_GE(background_luminance
, 0.0);
67 foreground_luminance
+= 0.05;
68 background_luminance
+= 0.05;
69 return (foreground_luminance
> background_luminance
) ?
70 (foreground_luminance
/ background_luminance
) :
71 (background_luminance
/ foreground_luminance
);
77 // ----------------------------------------------------------------------------
79 unsigned char GetLuminanceForColor(SkColor color
) {
80 int luma
= static_cast<int>((0.3 * SkColorGetR(color
)) +
81 (0.59 * SkColorGetG(color
)) +
82 (0.11 * SkColorGetB(color
)));
83 return std::max(std::min(luma
, 255), 0);
86 double RelativeLuminance(SkColor color
) {
87 return (0.2126 * ConvertSRGB(SkColorGetR(color
))) +
88 (0.7152 * ConvertSRGB(SkColorGetG(color
))) +
89 (0.0722 * ConvertSRGB(SkColorGetB(color
)));
92 void SkColorToHSL(SkColor c
, HSL
* hsl
) {
93 double r
= static_cast<double>(SkColorGetR(c
)) / 255.0;
94 double g
= static_cast<double>(SkColorGetG(c
)) / 255.0;
95 double b
= static_cast<double>(SkColorGetB(c
)) / 255.0;
96 double vmax
= std::max(std::max(r
, g
), b
);
97 double vmin
= std::min(std::min(r
, g
), b
);
98 double delta
= vmax
- vmin
;
99 hsl
->l
= (vmax
+ vmin
) / 2;
100 if (SkColorGetR(c
) == SkColorGetG(c
) && SkColorGetR(c
) == SkColorGetB(c
)) {
103 double dr
= (((vmax
- r
) / 6.0) + (delta
/ 2.0)) / delta
;
104 double dg
= (((vmax
- g
) / 6.0) + (delta
/ 2.0)) / delta
;
105 double db
= (((vmax
- b
) / 6.0) + (delta
/ 2.0)) / delta
;
106 // We need to compare for the max value because comparing vmax to r, g, or b
107 // can sometimes result in values overflowing registers.
108 if (r
>= g
&& r
>= b
)
110 else if (g
>= r
&& g
>= b
)
111 hsl
->h
= (1.0 / 3.0) + dr
- db
;
112 else // (b >= r && b >= g)
113 hsl
->h
= (2.0 / 3.0) + dg
- dr
;
117 else if (hsl
->h
> 1.0)
120 hsl
->s
= delta
/ ((hsl
->l
< 0.5) ? (vmax
+ vmin
) : (2 - vmax
- vmin
));
124 SkColor
HSLToSkColor(const HSL
& hsl
, SkAlpha alpha
) {
126 double saturation
= hsl
.s
;
127 double lightness
= hsl
.l
;
129 // If there's no color, we don't care about hue and can do everything based on
136 else if (lightness
>= 1.0)
139 light
= SkDoubleToFixed(lightness
) >> 8;
141 return SkColorSetARGB(alpha
, light
, light
, light
);
144 double temp2
= (lightness
< 0.5) ?
145 (lightness
* (1.0 + saturation
)) :
146 (lightness
+ saturation
- (lightness
* saturation
));
147 double temp1
= 2.0 * lightness
- temp2
;
148 return SkColorSetARGB(alpha
,
149 calcHue(temp1
, temp2
, hue
+ 1.0 / 3.0),
150 calcHue(temp1
, temp2
, hue
),
151 calcHue(temp1
, temp2
, hue
- 1.0 / 3.0));
154 SkColor
HSLShift(SkColor color
, const HSL
& shift
) {
156 int alpha
= SkColorGetA(color
);
157 SkColorToHSL(color
, &hsl
);
159 // Replace the hue with the tint's hue.
163 // Change the saturation.
166 hsl
.s
*= shift
.s
* 2.0;
168 hsl
.s
+= (1.0 - hsl
.s
) * ((shift
.s
- 0.5) * 2.0);
171 SkColor result
= HSLToSkColor(hsl
, alpha
);
176 // Lightness shifts in the style of popular image editors aren't actually
177 // represented in HSL - the L value does have some effect on saturation.
178 double r
= static_cast<double>(SkColorGetR(result
));
179 double g
= static_cast<double>(SkColorGetG(result
));
180 double b
= static_cast<double>(SkColorGetB(result
));
181 if (shift
.l
<= 0.5) {
182 r
*= (shift
.l
* 2.0);
183 g
*= (shift
.l
* 2.0);
184 b
*= (shift
.l
* 2.0);
186 r
+= (255.0 - r
) * ((shift
.l
- 0.5) * 2.0);
187 g
+= (255.0 - g
) * ((shift
.l
- 0.5) * 2.0);
188 b
+= (255.0 - b
) * ((shift
.l
- 0.5) * 2.0);
190 return SkColorSetARGB(alpha
,
193 static_cast<int>(b
));
196 void BuildLumaHistogram(const SkBitmap
& bitmap
, int histogram
[256]) {
197 DCHECK_EQ(SkBitmap::kARGB_8888_Config
, bitmap
.config());
199 SkAutoLockPixels
bitmap_lock(bitmap
);
201 int pixel_width
= bitmap
.width();
202 int pixel_height
= bitmap
.height();
203 for (int y
= 0; y
< pixel_height
; ++y
) {
204 for (int x
= 0; x
< pixel_width
; ++x
)
205 ++histogram
[GetLuminanceForColor(bitmap
.getColor(x
, y
))];
209 SkColor
AlphaBlend(SkColor foreground
, SkColor background
, SkAlpha alpha
) {
215 int f_alpha
= SkColorGetA(foreground
);
216 int b_alpha
= SkColorGetA(background
);
218 double normalizer
= (f_alpha
* alpha
+ b_alpha
* (255 - alpha
)) / 255.0;
219 if (normalizer
== 0.0)
220 return SK_ColorTRANSPARENT
;
222 double f_weight
= f_alpha
* alpha
/ normalizer
;
223 double b_weight
= b_alpha
* (255 - alpha
) / normalizer
;
225 double r
= (SkColorGetR(foreground
) * f_weight
+
226 SkColorGetR(background
) * b_weight
) / 255.0;
227 double g
= (SkColorGetG(foreground
) * f_weight
+
228 SkColorGetG(background
) * b_weight
) / 255.0;
229 double b
= (SkColorGetB(foreground
) * f_weight
+
230 SkColorGetB(background
) * b_weight
) / 255.0;
232 return SkColorSetARGB(static_cast<int>(normalizer
),
235 static_cast<int>(b
));
238 SkColor
BlendTowardOppositeLuminance(SkColor color
, SkAlpha alpha
) {
239 unsigned char background_luminance
=
240 color_utils::GetLuminanceForColor(color
);
241 const SkColor blend_color
=
242 (background_luminance
< 128) ? SK_ColorWHITE
: SK_ColorBLACK
;
243 return color_utils::AlphaBlend(blend_color
, color
, alpha
);
246 SkColor
GetReadableColor(SkColor foreground
, SkColor background
) {
247 const SkColor foreground2
= LumaInvertColor(foreground
);
248 const double background_luminance
= RelativeLuminance(background
);
249 return (ContrastRatio(RelativeLuminance(foreground
), background_luminance
) >=
250 ContrastRatio(RelativeLuminance(foreground2
), background_luminance
)) ?
251 foreground
: foreground2
;
254 SkColor
InvertColor(SkColor color
) {
255 return SkColorSetARGB(
257 255 - SkColorGetR(color
),
258 255 - SkColorGetG(color
),
259 255 - SkColorGetB(color
));
262 SkColor
GetSysSkColor(int which
) {
264 return skia::COLORREFToSkColor(GetSysColor(which
));
267 return SK_ColorLTGRAY
;
271 } // namespace color_utils