| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2006-2008 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 "build/build_config.h" | |
| 6 | |
| 7 #include <math.h> | |
| 8 #if defined(OS_WIN) | |
| 9 #include <windows.h> | |
| 10 #endif | |
| 11 | |
| 12 #include "chrome/common/gfx/color_utils.h" | |
| 13 | |
| 14 #include "base/basictypes.h" | |
| 15 #include "base/logging.h" | |
| 16 #include "skia/include/SkBitmap.h" | |
| 17 | |
| 18 #if defined(OS_WIN) | |
| 19 #include "skia/ext/skia_utils_win.h" | |
| 20 #endif | |
| 21 | |
| 22 namespace color_utils { | |
| 23 | |
| 24 // These transformations are based on the equations in: | |
| 25 // http://en.wikipedia.org/wiki/Lab_color | |
| 26 // http://en.wikipedia.org/wiki/SRGB_color_space#Specification_of_the_transforma
tion | |
| 27 // See also: | |
| 28 // http://www.brucelindbloom.com/index.html?ColorCalculator.html | |
| 29 | |
| 30 static const double kCIEConversionAlpha = 0.055; | |
| 31 static const double kCIEConversionGamma = 2.2; | |
| 32 static const double kE = 0.008856; | |
| 33 static const double kK = 903.3; | |
| 34 | |
| 35 static double CIEConvertNonLinear(uint8 color_component) { | |
| 36 double color_component_d = static_cast<double>(color_component) / 255.0; | |
| 37 if (color_component_d > 0.04045) { | |
| 38 double base = (color_component_d + kCIEConversionAlpha) / | |
| 39 (1 + kCIEConversionAlpha); | |
| 40 return pow(base, kCIEConversionGamma); | |
| 41 } else { | |
| 42 return color_component_d / 12.92; | |
| 43 } | |
| 44 } | |
| 45 | |
| 46 // Note: this works only for sRGB. | |
| 47 void SkColorToCIEXYZ(SkColor c, CIE_XYZ* xyz) { | |
| 48 uint8 r = SkColorGetR(c); | |
| 49 uint8 g = SkColorGetG(c); | |
| 50 uint8 b = SkColorGetB(c); | |
| 51 | |
| 52 xyz->X = | |
| 53 0.4124 * CIEConvertNonLinear(r) + | |
| 54 0.3576 * CIEConvertNonLinear(g) + | |
| 55 0.1805 * CIEConvertNonLinear(b); | |
| 56 xyz->Y = | |
| 57 0.2126 * CIEConvertNonLinear(r) + | |
| 58 0.7152 * CIEConvertNonLinear(g) + | |
| 59 0.0722 * CIEConvertNonLinear(g); | |
| 60 xyz->Z = | |
| 61 0.0193 * CIEConvertNonLinear(r) + | |
| 62 0.1192 * CIEConvertNonLinear(g) + | |
| 63 0.9505 * CIEConvertNonLinear(b); | |
| 64 } | |
| 65 | |
| 66 static double LabConvertNonLinear(double value) { | |
| 67 if (value > 0.008856) { | |
| 68 double goat = pow(value, static_cast<double>(1) / 3); | |
| 69 return goat; | |
| 70 } | |
| 71 return (kK * value + 16) / 116; | |
| 72 } | |
| 73 | |
| 74 void CIEXYZToLabColor(const CIE_XYZ& xyz, LabColor* lab) { | |
| 75 CIE_XYZ white_xyz; | |
| 76 SkColorToCIEXYZ(SkColorSetRGB(255, 255, 255), &white_xyz); | |
| 77 double fx = LabConvertNonLinear(xyz.X / white_xyz.X); | |
| 78 double fy = LabConvertNonLinear(xyz.Y / white_xyz.Y); | |
| 79 double fz = LabConvertNonLinear(xyz.Z / white_xyz.Z); | |
| 80 lab->L = static_cast<int>(116 * fy) - 16; | |
| 81 lab->a = static_cast<int>(500 * (fx - fy)); | |
| 82 lab->b = static_cast<int>(200 * (fy - fz)); | |
| 83 } | |
| 84 | |
| 85 static uint8 sRGBColorComponentFromLinearComponent(double component) { | |
| 86 double result; | |
| 87 if (component <= 0.0031308) { | |
| 88 result = 12.92 * component; | |
| 89 } else { | |
| 90 result = (1 + kCIEConversionAlpha) * | |
| 91 pow(component, (static_cast<double>(1) / 2.4)) - | |
| 92 kCIEConversionAlpha; | |
| 93 } | |
| 94 return std::min(static_cast<uint8>(255), static_cast<uint8>(result * 255)); | |
| 95 } | |
| 96 | |
| 97 SkColor CIEXYZToSkColor(SkAlpha alpha, const CIE_XYZ& xyz) { | |
| 98 double r_linear = 3.2410 * xyz.X - 1.5374 * xyz.Y - 0.4986 * xyz.Z; | |
| 99 double g_linear = -0.9692 * xyz.X + 1.8760 * xyz.Y + 0.0416 * xyz.Z; | |
| 100 double b_linear = 0.0556 * xyz.X - 0.2040 * xyz.Y + 1.0570 * xyz.Z; | |
| 101 uint8 r = sRGBColorComponentFromLinearComponent(r_linear); | |
| 102 uint8 g = sRGBColorComponentFromLinearComponent(g_linear); | |
| 103 uint8 b = sRGBColorComponentFromLinearComponent(b_linear); | |
| 104 return SkColorSetARGB(alpha, r, g, b); | |
| 105 } | |
| 106 | |
| 107 static double gen_yr(const LabColor& lab) { | |
| 108 if (lab.L > (kE * kK)) | |
| 109 return pow((lab.L + 16.0) / 116, 3.0); | |
| 110 return static_cast<double>(lab.L) / kK; | |
| 111 } | |
| 112 | |
| 113 static double fy(const LabColor& lab) { | |
| 114 double yr = gen_yr(lab); | |
| 115 if (yr > kE) | |
| 116 return (lab.L + 16.0) / 116; | |
| 117 return (kK * yr + 16.0) / 116; | |
| 118 } | |
| 119 | |
| 120 static double fx(const LabColor& lab) { | |
| 121 return (static_cast<double>(lab.a) / 500) + fy(lab); | |
| 122 } | |
| 123 | |
| 124 static double gen_xr(const LabColor& lab) { | |
| 125 double x = fx(lab); | |
| 126 double x_cubed = pow(x, 3.0); | |
| 127 if (x_cubed > kE) | |
| 128 return x_cubed; | |
| 129 return (116.0 * x - 16.0) / kK; | |
| 130 } | |
| 131 | |
| 132 static double fz(const LabColor& lab) { | |
| 133 return fy(lab) - (static_cast<double>(lab.b) / 200); | |
| 134 } | |
| 135 | |
| 136 static double gen_zr(const LabColor& lab) { | |
| 137 double z = fz(lab); | |
| 138 double z_cubed = pow(z, 3.0); | |
| 139 if (z_cubed > kE) | |
| 140 return z_cubed; | |
| 141 return (116.0 * z - 16.0) / kK; | |
| 142 } | |
| 143 | |
| 144 void LabColorToCIEXYZ(const LabColor& lab, CIE_XYZ* xyz) { | |
| 145 CIE_XYZ result; | |
| 146 | |
| 147 CIE_XYZ white_xyz; | |
| 148 SkColorToCIEXYZ(SkColorSetRGB(255, 255, 255), &white_xyz); | |
| 149 | |
| 150 result.X = gen_xr(lab) * white_xyz.X; | |
| 151 result.Y = gen_yr(lab) * white_xyz.Y; | |
| 152 result.Z = gen_zr(lab) * white_xyz.Z; | |
| 153 | |
| 154 *xyz = result; | |
| 155 } | |
| 156 | |
| 157 void SkColorToLabColor(SkColor c, LabColor* lab) { | |
| 158 CIE_XYZ xyz; | |
| 159 SkColorToCIEXYZ(c, &xyz); | |
| 160 CIEXYZToLabColor(xyz, lab); | |
| 161 } | |
| 162 | |
| 163 SkColor LabColorToSkColor(const LabColor& lab, SkAlpha alpha) { | |
| 164 CIE_XYZ xyz; | |
| 165 LabColorToCIEXYZ(lab, &xyz); | |
| 166 return CIEXYZToSkColor(alpha, xyz); | |
| 167 } | |
| 168 | |
| 169 static const int kCloseToBoundary = 64; | |
| 170 static const int kAverageBoundary = 15; | |
| 171 | |
| 172 bool IsColorCloseToTransparent(SkAlpha alpha) { | |
| 173 return alpha < kCloseToBoundary; | |
| 174 } | |
| 175 | |
| 176 bool IsColorCloseToGrey(int r, int g, int b) { | |
| 177 int average = (r + g + b) / 3; | |
| 178 return (abs(r - average) < kAverageBoundary) && | |
| 179 (abs(g - average) < kAverageBoundary) && | |
| 180 (abs(b - average) < kAverageBoundary); | |
| 181 } | |
| 182 | |
| 183 SkColor GetAverageColorOfFavicon(SkBitmap* favicon, SkAlpha alpha) { | |
| 184 int r = 0, g = 0, b = 0; | |
| 185 | |
| 186 SkAutoLockPixels favicon_lock(*favicon); | |
| 187 SkColor* pixels = static_cast<SkColor*>(favicon->getPixels()); | |
| 188 // Assume ARGB_8888 format. | |
| 189 DCHECK(favicon->getConfig() == SkBitmap::kARGB_8888_Config); | |
| 190 SkColor* current_color = pixels; | |
| 191 | |
| 192 DCHECK(favicon->width() <= 16 && favicon->height() <= 16); | |
| 193 | |
| 194 int pixel_count = favicon->width() * favicon->height(); | |
| 195 int color_count = 0; | |
| 196 for (int i = 0; i < pixel_count; ++i, ++current_color) { | |
| 197 // Disregard this color if it is close to black, close to white, or close | |
| 198 // to transparent since any of those pixels do not contribute much to the | |
| 199 // color makeup of this icon. | |
| 200 int cr = SkColorGetR(*current_color); | |
| 201 int cg = SkColorGetG(*current_color); | |
| 202 int cb = SkColorGetB(*current_color); | |
| 203 | |
| 204 if (IsColorCloseToTransparent(SkColorGetA(*current_color)) || | |
| 205 IsColorCloseToGrey(cr, cg, cb)) | |
| 206 continue; | |
| 207 | |
| 208 r += cr; | |
| 209 g += cg; | |
| 210 b += cb; | |
| 211 ++color_count; | |
| 212 } | |
| 213 | |
| 214 SkColor result; | |
| 215 if (color_count > 0) { | |
| 216 result = SkColorSetARGB(alpha, | |
| 217 r / color_count, | |
| 218 g / color_count, | |
| 219 b / color_count); | |
| 220 } else { | |
| 221 result = SkColorSetARGB(alpha, 0, 0, 0); | |
| 222 } | |
| 223 return result; | |
| 224 } | |
| 225 | |
| 226 inline int GetLumaForColor(SkColor* color) { | |
| 227 int r = SkColorGetR(*color); | |
| 228 int g = SkColorGetG(*color); | |
| 229 int b = SkColorGetB(*color); | |
| 230 | |
| 231 int luma = static_cast<int>(0.3*r + 0.59*g + 0.11*b); | |
| 232 if (luma < 0) | |
| 233 luma = 0; | |
| 234 else if (luma > 255) | |
| 235 luma = 255; | |
| 236 | |
| 237 return luma; | |
| 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 | |
| 255 SkColor SetColorAlpha(SkColor c, SkAlpha alpha) { | |
| 256 return SkColorSetARGB(alpha, SkColorGetR(c), SkColorGetG(c), SkColorGetB(c)); | |
| 257 } | |
| 258 | |
| 259 SkColor GetSysSkColor(int which) { | |
| 260 #if defined(OS_WIN) | |
| 261 return skia::COLORREFToSkColor(::GetSysColor(which)); | |
| 262 #else | |
| 263 NOTIMPLEMENTED(); | |
| 264 return SK_ColorLTGRAY; | |
| 265 #endif | |
| 266 } | |
| 267 | |
| 268 } // namespace color_utils | |
| OLD | NEW |