This source file includes following definitions.
- calcHue
- ConvertSRGB
- LumaInvertColor
- ContrastRatio
- GetLuminanceForColor
- RelativeLuminance
- SkColorToHSL
- HSLToSkColor
- HSLShift
- BuildLumaHistogram
- AlphaBlend
- BlendTowardOppositeLuminance
- GetReadableColor
- InvertColor
- GetSysSkColor
#include "ui/gfx/color_utils.h"
#include <math.h>
#if defined(OS_WIN)
#include <windows.h>
#endif
#include <algorithm>
#include "base/basictypes.h"
#include "base/logging.h"
#include "build/build_config.h"
#if defined(OS_WIN)
#include "skia/ext/skia_utils_win.h"
#endif
#include "third_party/skia/include/core/SkBitmap.h"
namespace color_utils {
namespace {
int calcHue(double temp1, double temp2, double hue) {
if (hue < 0.0)
++hue;
else if (hue > 1.0)
--hue;
double result = temp1;
if (hue * 6.0 < 1.0)
result = temp1 + (temp2 - temp1) * hue * 6.0;
else if (hue * 2.0 < 1.0)
result = temp2;
else if (hue * 3.0 < 2.0)
result = temp1 + (temp2 - temp1) * (2.0 / 3.0 - hue) * 6.0;
return static_cast<int>(result * 255 + .5);
}
double ConvertSRGB(double eight_bit_component) {
const double component = eight_bit_component / 255.0;
return (component <= 0.03928) ?
(component / 12.92) : pow((component + 0.055) / 1.055, 2.4);
}
SkColor LumaInvertColor(SkColor color) {
HSL hsl;
SkColorToHSL(color, &hsl);
hsl.l = 1.0 - hsl.l;
return HSLToSkColor(hsl, 255);
}
double ContrastRatio(double foreground_luminance, double background_luminance) {
DCHECK_GE(foreground_luminance, 0.0);
DCHECK_GE(background_luminance, 0.0);
foreground_luminance += 0.05;
background_luminance += 0.05;
return (foreground_luminance > background_luminance) ?
(foreground_luminance / background_luminance) :
(background_luminance / foreground_luminance);
}
}
unsigned char GetLuminanceForColor(SkColor color) {
int luma = static_cast<int>((0.3 * SkColorGetR(color)) +
(0.59 * SkColorGetG(color)) +
(0.11 * SkColorGetB(color)));
return std::max(std::min(luma, 255), 0);
}
double RelativeLuminance(SkColor color) {
return (0.2126 * ConvertSRGB(SkColorGetR(color))) +
(0.7152 * ConvertSRGB(SkColorGetG(color))) +
(0.0722 * ConvertSRGB(SkColorGetB(color)));
}
void SkColorToHSL(SkColor c, HSL* hsl) {
double r = static_cast<double>(SkColorGetR(c)) / 255.0;
double g = static_cast<double>(SkColorGetG(c)) / 255.0;
double b = static_cast<double>(SkColorGetB(c)) / 255.0;
double vmax = std::max(std::max(r, g), b);
double vmin = std::min(std::min(r, g), b);
double delta = vmax - vmin;
hsl->l = (vmax + vmin) / 2;
if (SkColorGetR(c) == SkColorGetG(c) && SkColorGetR(c) == SkColorGetB(c)) {
hsl->h = hsl->s = 0;
} else {
double dr = (((vmax - r) / 6.0) + (delta / 2.0)) / delta;
double dg = (((vmax - g) / 6.0) + (delta / 2.0)) / delta;
double db = (((vmax - b) / 6.0) + (delta / 2.0)) / delta;
if (r >= g && r >= b)
hsl->h = db - dg;
else if (g >= r && g >= b)
hsl->h = (1.0 / 3.0) + dr - db;
else
hsl->h = (2.0 / 3.0) + dg - dr;
if (hsl->h < 0.0)
++hsl->h;
else if (hsl->h > 1.0)
--hsl->h;
hsl->s = delta / ((hsl->l < 0.5) ? (vmax + vmin) : (2 - vmax - vmin));
}
}
SkColor HSLToSkColor(const HSL& hsl, SkAlpha alpha) {
double hue = hsl.h;
double saturation = hsl.s;
double lightness = hsl.l;
if (!saturation) {
uint8 light;
if (lightness < 0)
light = 0;
else if (lightness >= 1.0)
light = 255;
else
light = SkDoubleToFixed(lightness) >> 8;
return SkColorSetARGB(alpha, light, light, light);
}
double temp2 = (lightness < 0.5) ?
(lightness * (1.0 + saturation)) :
(lightness + saturation - (lightness * saturation));
double temp1 = 2.0 * lightness - temp2;
return SkColorSetARGB(alpha,
calcHue(temp1, temp2, hue + 1.0 / 3.0),
calcHue(temp1, temp2, hue),
calcHue(temp1, temp2, hue - 1.0 / 3.0));
}
SkColor HSLShift(SkColor color, const HSL& shift) {
HSL hsl;
int alpha = SkColorGetA(color);
SkColorToHSL(color, &hsl);
if (shift.h >= 0)
hsl.h = shift.h;
if (shift.s >= 0) {
if (shift.s <= 0.5)
hsl.s *= shift.s * 2.0;
else
hsl.s += (1.0 - hsl.s) * ((shift.s - 0.5) * 2.0);
}
SkColor result = HSLToSkColor(hsl, alpha);
if (shift.l < 0)
return result;
double r = static_cast<double>(SkColorGetR(result));
double g = static_cast<double>(SkColorGetG(result));
double b = static_cast<double>(SkColorGetB(result));
if (shift.l <= 0.5) {
r *= (shift.l * 2.0);
g *= (shift.l * 2.0);
b *= (shift.l * 2.0);
} else {
r += (255.0 - r) * ((shift.l - 0.5) * 2.0);
g += (255.0 - g) * ((shift.l - 0.5) * 2.0);
b += (255.0 - b) * ((shift.l - 0.5) * 2.0);
}
return SkColorSetARGB(alpha,
static_cast<int>(r),
static_cast<int>(g),
static_cast<int>(b));
}
void BuildLumaHistogram(const SkBitmap& bitmap, int histogram[256]) {
DCHECK_EQ(kPMColor_SkColorType, bitmap.colorType());
SkAutoLockPixels bitmap_lock(bitmap);
int pixel_width = bitmap.width();
int pixel_height = bitmap.height();
for (int y = 0; y < pixel_height; ++y) {
for (int x = 0; x < pixel_width; ++x)
++histogram[GetLuminanceForColor(bitmap.getColor(x, y))];
}
}
SkColor AlphaBlend(SkColor foreground, SkColor background, SkAlpha alpha) {
if (alpha == 0)
return background;
if (alpha == 255)
return foreground;
int f_alpha = SkColorGetA(foreground);
int b_alpha = SkColorGetA(background);
double normalizer = (f_alpha * alpha + b_alpha * (255 - alpha)) / 255.0;
if (normalizer == 0.0)
return SK_ColorTRANSPARENT;
double f_weight = f_alpha * alpha / normalizer;
double b_weight = b_alpha * (255 - alpha) / normalizer;
double r = (SkColorGetR(foreground) * f_weight +
SkColorGetR(background) * b_weight) / 255.0;
double g = (SkColorGetG(foreground) * f_weight +
SkColorGetG(background) * b_weight) / 255.0;
double b = (SkColorGetB(foreground) * f_weight +
SkColorGetB(background) * b_weight) / 255.0;
return SkColorSetARGB(static_cast<int>(normalizer),
static_cast<int>(r),
static_cast<int>(g),
static_cast<int>(b));
}
SkColor BlendTowardOppositeLuminance(SkColor color, SkAlpha alpha) {
unsigned char background_luminance =
color_utils::GetLuminanceForColor(color);
const SkColor blend_color =
(background_luminance < 128) ? SK_ColorWHITE : SK_ColorBLACK;
return color_utils::AlphaBlend(blend_color, color, alpha);
}
SkColor GetReadableColor(SkColor foreground, SkColor background) {
const SkColor foreground2 = LumaInvertColor(foreground);
const double background_luminance = RelativeLuminance(background);
return (ContrastRatio(RelativeLuminance(foreground), background_luminance) >=
ContrastRatio(RelativeLuminance(foreground2), background_luminance)) ?
foreground : foreground2;
}
SkColor InvertColor(SkColor color) {
return SkColorSetARGB(
SkColorGetA(color),
255 - SkColorGetR(color),
255 - SkColorGetG(color),
255 - SkColorGetB(color));
}
SkColor GetSysSkColor(int which) {
#if defined(OS_WIN)
return skia::COLORREFToSkColor(GetSysColor(which));
#else
NOTIMPLEMENTED();
return SK_ColorLTGRAY;
#endif
}
}