OLD | NEW |
| (Empty) |
1 // Copyright (c) 2010 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. | |
4 | |
5 #include "gfx/color_utils.h" | |
6 | |
7 #include <math.h> | |
8 #if defined(OS_WIN) | |
9 #include <windows.h> | |
10 #endif | |
11 | |
12 #include <algorithm> | |
13 | |
14 #include "base/basictypes.h" | |
15 #include "base/logging.h" | |
16 #include "build/build_config.h" | |
17 #if defined(OS_WIN) | |
18 #include "skia/ext/skia_utils_win.h" | |
19 #endif | |
20 #include "third_party/skia/include/core/SkBitmap.h" | |
21 | |
22 namespace color_utils { | |
23 | |
24 // Helper functions ----------------------------------------------------------- | |
25 | |
26 namespace { | |
27 | |
28 double calcHue(double temp1, double temp2, double hue) { | |
29 if (hue < 0.0) | |
30 ++hue; | |
31 else if (hue > 1.0) | |
32 --hue; | |
33 | |
34 if (hue * 6.0 < 1.0) | |
35 return temp1 + (temp2 - temp1) * hue * 6.0; | |
36 if (hue * 2.0 < 1.0) | |
37 return temp2; | |
38 if (hue * 3.0 < 2.0) | |
39 return temp1 + (temp2 - temp1) * (2.0 / 3.0 - hue) * 6.0; | |
40 | |
41 return temp1; | |
42 } | |
43 | |
44 int GetLumaForColor(SkColor* color) { | |
45 int luma = static_cast<int>((0.3 * SkColorGetR(*color)) + | |
46 (0.59 * SkColorGetG(*color)) + | |
47 (0.11 * SkColorGetB(*color))); | |
48 return std::max(std::min(luma, 255), 0); | |
49 } | |
50 | |
51 // Next two functions' formulas from: | |
52 // http://www.w3.org/TR/WCAG20/#relativeluminancedef | |
53 // http://www.w3.org/TR/WCAG20/#contrast-ratiodef | |
54 | |
55 double ConvertSRGB(double eight_bit_component) { | |
56 const double component = eight_bit_component / 255.0; | |
57 return (component <= 0.03928) ? | |
58 (component / 12.92) : pow((component + 0.055) / 1.055, 2.4); | |
59 } | |
60 | |
61 SkColor LumaInvertColor(const SkColor& color) { | |
62 HSL hsl; | |
63 SkColorToHSL(color, &hsl); | |
64 hsl.l = 1.0 - hsl.l; | |
65 return HSLToSkColor(hsl, 255); | |
66 } | |
67 | |
68 double ContrastRatio(double foreground_luminance, double background_luminance) { | |
69 // NOTE: Only pass in numbers obtained from RelativeLuminance(), since those | |
70 // are guaranteed to be > 0 and thus not cause a divide-by-zero error here. | |
71 return (foreground_luminance > background_luminance) ? | |
72 (foreground_luminance / background_luminance) : | |
73 (background_luminance / foreground_luminance); | |
74 } | |
75 | |
76 } // namespace | |
77 | |
78 // ---------------------------------------------------------------------------- | |
79 | |
80 double RelativeLuminance(SkColor color) { | |
81 return (0.2126 * ConvertSRGB(SkColorGetR(color))) + | |
82 (0.7152 * ConvertSRGB(SkColorGetG(color))) + | |
83 (0.0722 * ConvertSRGB(SkColorGetB(color))) + 0.05; | |
84 } | |
85 | |
86 void SkColorToHSL(SkColor c, HSL* hsl) { | |
87 double r = static_cast<double>(SkColorGetR(c)) / 255.0; | |
88 double g = static_cast<double>(SkColorGetG(c)) / 255.0; | |
89 double b = static_cast<double>(SkColorGetB(c)) / 255.0; | |
90 double vmax = std::max(std::max(r, g), b); | |
91 double vmin = std::min(std::min(r, g), b); | |
92 double delta = vmax - vmin; | |
93 hsl->l = (vmax + vmin) / 2; | |
94 if (delta) { | |
95 double dr = (((vmax - r) / 6.0) + (delta / 2.0)) / delta; | |
96 double dg = (((vmax - g) / 6.0) + (delta / 2.0)) / delta; | |
97 double db = (((vmax - b) / 6.0) + (delta / 2.0)) / delta; | |
98 // We need to compare for the max value because comparing vmax to r, | |
99 // g or b can sometimes result in values overflowing registers. | |
100 if (r >= g && r >= b) | |
101 hsl->h = db - dg; | |
102 else if (g >= r && g >= b) | |
103 hsl->h = (1.0 / 3.0) + dr - db; | |
104 else // (b >= r && b >= g) | |
105 hsl->h = (2.0 / 3.0) + dg - dr; | |
106 | |
107 if (hsl->h < 0.0) | |
108 ++hsl->h; | |
109 else if (hsl->h > 1.0) | |
110 --hsl->h; | |
111 | |
112 hsl->s = delta / ((hsl->l < 0.5) ? (vmax + vmin) : (2 - vmax - vmin)); | |
113 } else { | |
114 hsl->h = hsl->s = 0; | |
115 } | |
116 } | |
117 | |
118 SkColor HSLToSkColor(const HSL& hsl, SkAlpha alpha) { | |
119 double hue = hsl.h; | |
120 double saturation = hsl.s; | |
121 double lightness = hsl.l; | |
122 | |
123 // If there's no color, we don't care about hue and can do everything based | |
124 // on brightness. | |
125 if (!saturation) { | |
126 uint8 light; | |
127 | |
128 if (lightness < 0) | |
129 light = 0; | |
130 else if (lightness >= 1.0) | |
131 light = 255; | |
132 else | |
133 light = SkDoubleToFixed(lightness) >> 8; | |
134 | |
135 return SkColorSetARGB(alpha, light, light, light); | |
136 } | |
137 | |
138 double temp2 = (lightness < 0.5) ? | |
139 (lightness * (1.0 + saturation)) : | |
140 (lightness + saturation - (lightness * saturation)); | |
141 double temp1 = 2.0 * lightness - temp2; | |
142 return SkColorSetARGB(alpha, | |
143 static_cast<int>(calcHue(temp1, temp2, hue + 1.0 / 3.0) * 255), | |
144 static_cast<int>(calcHue(temp1, temp2, hue) * 255), | |
145 static_cast<int>(calcHue(temp1, temp2, hue - 1.0 / 3.0) * 255)); | |
146 } | |
147 | |
148 SkColor HSLShift(SkColor color, const HSL& shift) { | |
149 HSL hsl; | |
150 int alpha = SkColorGetA(color); | |
151 SkColorToHSL(color, &hsl); | |
152 | |
153 // Replace the hue with the tint's hue. | |
154 if (shift.h >= 0) | |
155 hsl.h = shift.h; | |
156 | |
157 // Change the saturation. | |
158 if (shift.s >= 0) { | |
159 if (shift.s <= 0.5) | |
160 hsl.s *= shift.s * 2.0; | |
161 else | |
162 hsl.s += (1.0 - hsl.s) * ((shift.s - 0.5) * 2.0); | |
163 } | |
164 | |
165 SkColor result = HSLToSkColor(hsl, alpha); | |
166 | |
167 if (shift.l < 0) | |
168 return result; | |
169 | |
170 // Lightness shifts in the style of popular image editors aren't | |
171 // actually represented in HSL - the L value does have some effect | |
172 // on saturation. | |
173 double r = static_cast<double>(SkColorGetR(result)); | |
174 double g = static_cast<double>(SkColorGetG(result)); | |
175 double b = static_cast<double>(SkColorGetB(result)); | |
176 if (shift.l <= 0.5) { | |
177 r *= (shift.l * 2.0); | |
178 g *= (shift.l * 2.0); | |
179 b *= (shift.l * 2.0); | |
180 } else { | |
181 r += (255.0 - r) * ((shift.l - 0.5) * 2.0); | |
182 g += (255.0 - g) * ((shift.l - 0.5) * 2.0); | |
183 b += (255.0 - b) * ((shift.l - 0.5) * 2.0); | |
184 } | |
185 return SkColorSetARGB(alpha, | |
186 static_cast<int>(r), | |
187 static_cast<int>(g), | |
188 static_cast<int>(b)); | |
189 } | |
190 | |
191 bool IsColorCloseToTransparent(SkAlpha alpha) { | |
192 const int kCloseToBoundary = 64; | |
193 return alpha < kCloseToBoundary; | |
194 } | |
195 | |
196 bool IsColorCloseToGrey(int r, int g, int b) { | |
197 const int kAverageBoundary = 15; | |
198 int average = (r + g + b) / 3; | |
199 return (abs(r - average) < kAverageBoundary) && | |
200 (abs(g - average) < kAverageBoundary) && | |
201 (abs(b - average) < kAverageBoundary); | |
202 } | |
203 | |
204 SkColor GetAverageColorOfFavicon(SkBitmap* favicon, SkAlpha alpha) { | |
205 int r = 0, g = 0, b = 0; | |
206 | |
207 SkAutoLockPixels favicon_lock(*favicon); | |
208 SkColor* pixels = static_cast<SkColor*>(favicon->getPixels()); | |
209 // Assume ARGB_8888 format. | |
210 DCHECK(favicon->getConfig() == SkBitmap::kARGB_8888_Config); | |
211 SkColor* current_color = pixels; | |
212 | |
213 DCHECK(favicon->width() <= 16 && favicon->height() <= 16); | |
214 | |
215 int pixel_count = favicon->width() * favicon->height(); | |
216 int color_count = 0; | |
217 for (int i = 0; i < pixel_count; ++i, ++current_color) { | |
218 // Disregard this color if it is close to black, close to white, or close | |
219 // to transparent since any of those pixels do not contribute much to the | |
220 // color makeup of this icon. | |
221 int cr = SkColorGetR(*current_color); | |
222 int cg = SkColorGetG(*current_color); | |
223 int cb = SkColorGetB(*current_color); | |
224 | |
225 if (IsColorCloseToTransparent(SkColorGetA(*current_color)) || | |
226 IsColorCloseToGrey(cr, cg, cb)) | |
227 continue; | |
228 | |
229 r += cr; | |
230 g += cg; | |
231 b += cb; | |
232 ++color_count; | |
233 } | |
234 | |
235 return color_count ? | |
236 SkColorSetARGB(alpha, r / color_count, g / color_count, b / color_count) : | |
237 SkColorSetARGB(alpha, 0, 0, 0); | |
238 } | |
239 | |
240 void BuildLumaHistogram(SkBitmap* bitmap, int histogram[256]) { | |
241 SkAutoLockPixels bitmap_lock(*bitmap); | |
242 // Assume ARGB_8888 format. | |
243 DCHECK(bitmap->getConfig() == SkBitmap::kARGB_8888_Config); | |
244 | |
245 int pixel_width = bitmap->width(); | |
246 int pixel_height = bitmap->height(); | |
247 for (int y = 0; y < pixel_height; ++y) { | |
248 SkColor* current_color = static_cast<uint32_t*>(bitmap->getAddr32(0, y)); | |
249 for (int x = 0; x < pixel_width; ++x, ++current_color) | |
250 histogram[GetLumaForColor(current_color)]++; | |
251 } | |
252 } | |
253 | |
254 SkColor AlphaBlend(SkColor foreground, SkColor background, SkAlpha alpha) { | |
255 if (alpha == 0) | |
256 return background; | |
257 if (alpha == 255) | |
258 return foreground; | |
259 | |
260 int f_alpha = SkColorGetA(foreground); | |
261 int b_alpha = SkColorGetA(background); | |
262 | |
263 double normalizer = (f_alpha * alpha + b_alpha * (255 - alpha)) / 255.0; | |
264 if (normalizer == 0.0) | |
265 return SkColorSetARGB(0, 0, 0, 0); | |
266 | |
267 double f_weight = f_alpha * alpha / normalizer; | |
268 double b_weight = b_alpha * (255 - alpha) / normalizer; | |
269 | |
270 double r = (SkColorGetR(foreground) * f_weight + | |
271 SkColorGetR(background) * b_weight) / 255.0; | |
272 double g = (SkColorGetG(foreground) * f_weight + | |
273 SkColorGetG(background) * b_weight) / 255.0; | |
274 double b = (SkColorGetB(foreground) * f_weight + | |
275 SkColorGetB(background) * b_weight) / 255.0; | |
276 | |
277 return SkColorSetARGB(static_cast<int>(normalizer), | |
278 static_cast<int>(r), | |
279 static_cast<int>(g), | |
280 static_cast<int>(b)); | |
281 } | |
282 | |
283 SkColor GetReadableColor(SkColor foreground, SkColor background) { | |
284 const SkColor foreground2 = LumaInvertColor(foreground); | |
285 const double background_luminance = RelativeLuminance(background); | |
286 return (ContrastRatio(RelativeLuminance(foreground), background_luminance) >= | |
287 ContrastRatio(RelativeLuminance(foreground2), background_luminance)) ? | |
288 foreground : foreground2; | |
289 } | |
290 | |
291 SkColor GetSysSkColor(int which) { | |
292 #if defined(OS_WIN) | |
293 return skia::COLORREFToSkColor(GetSysColor(which)); | |
294 #else | |
295 NOTIMPLEMENTED(); | |
296 return SK_ColorLTGRAY; | |
297 #endif | |
298 } | |
299 | |
300 } // namespace color_utils | |
OLD | NEW |