Определение цвета шрифта на основе цвета фона
учитывая систему (например, веб-сайт), которая позволяет пользователю настраивать цвет фона для некоторого раздела, но не цвет шрифта (чтобы свести количество опций к минимуму), есть ли способ программно определить, необходим ли "светлый" или "темный" цвет шрифта?
Я уверен, что есть какой-то алгоритм, но я не знаю достаточно о цветах, светимости и т. д., Чтобы понять это самостоятельно.
16 ответов
я столкнулся с подобной проблемой. Мне пришлось найти хороший метод выбора контрастного цвета шрифта для отображения текстовых меток на цветных/тепловых картах. Это должен быть универсальный метод, и генерируемый цвет должен быть "красивым", что означает, что простое генерирование дополнительного цвета не является хорошим решением - иногда он генерирует странные, очень интенсивные цвета, которые трудно наблюдать и читать.
после долгих часов тестирования и попытки решить эту проблему, я узнал, что лучшее решение-выбрать белый шрифт для "темных" цветов и черный шрифт для "ярких" цветов.
вот пример функции, которую я использую в C#:
Color ContrastColor(Color color)
{
int d = 0;
// Counting the perceptive luminance - human eye favors green color...
double luminance = ( 0.299 * color.R + 0.587 * color.G + 0.114 * color.B)/255;
if (luminance > 0.5)
d = 0; // bright colors - black font
else
d = 255; // dark colors - white font
return Color.FromArgb(d, d, d);
}
Это было проверено для многих различных цветовых шкал (Радуга, оттенки серого, тепло, лед и многие другие) и является единственным "универсальным" методом, который я узнал.
редактировать
Изменена формула подсчета a
для "перцептивной яркости" - это действительно выглядит лучше! Уже реализовано в моя программа выглядит великолепно.
Edit 2 @Раздающему отличный пример такого алгоритма: http://codepen.io/WebSeed/full/pvgqEq/
спасибо @Gacek. Вот версия для Android:
@ColorInt
public static int getContrastColor(@ColorInt int color) {
// Counting the perceptive luminance - human eye favors green color...
double a = 1 - (0.299 * Color.red(color) + 0.587 * Color.green(color) + 0.114 * Color.blue(color)) / 255;
int d;
if (a < 0.5) {
d = 0; // bright colors - black font
} else {
d = 255; // dark colors - white font
}
return Color.rgb(d, d, d);
}
и улучшенная (более короткая) версия:
@ColorInt
public static int getContrastColor(@ColorInt int color) {
// Counting the perceptive luminance - human eye favors green color...
double a = 1 - (0.299 * Color.red(color) + 0.587 * Color.green(color) + 0.114 * Color.blue(color)) / 255;
return a < 0.5 ? Color.BLACK : Color.WHITE;
}
на всякий случай кто-то хотел бы более короткую, возможно, более легкую для понимания версию Гашек это!--5-->:
public Color ContrastColor(Color iColor)
{
// Calculate the perceptive luminance (aka luma) - human eye favors green color...
double luma = ((0.299 * iColor.R) + (0.587 * iColor.G) + (0.114 * iColor.B)) / 255;
// Return black for bright colors, white for dark colors
return luma > 0.5 ? Color.Black : Color.White;
}
Примечание: Я удалил инверсию Лума значение (чтобы яркие цвета имели более высокое значение, что кажется мне более естественным, а также является методом расчета по умолчанию.
я использовал те же константы, что и Гачек из здесь так как они отлично работали для меня.
(вы также можете реализуйте это как Метод Расширения используя следующую подпись:
public static Color ContrastColor(this Color iColor)
затем вы можете вызвать его через foregroundColor = background.ContrastColor()
.)
моя быстрая реализация ответа Гачека:
func contrastColor(color: UIColor) -> UIColor {
var d = CGFloat(0)
var r = CGFloat(0)
var g = CGFloat(0)
var b = CGFloat(0)
var a = CGFloat(0)
color.getRed(&r, green: &g, blue: &b, alpha: &a)
// Counting the perceptive luminance - human eye favors green color...
let luminance = 1 - ((0.299 * r) + (0.587 * g) + (0.114 * b))
if luminance < 0.5 {
d = CGFloat(0) // bright colors - black font
} else {
d = CGFloat(1) // dark colors - white font
}
return UIColor( red: d, green: d, blue: d, alpha: a)
}
Javascript [ES2015]
const hexToLuma = (colour) => {
const hex = colour.replace(/#/, '');
const r = parseInt(hex.substr(0, 2), 16);
const g = parseInt(hex.substr(2, 2), 16);
const b = parseInt(hex.substr(4, 2), 16);
return [
0.299 * r,
0.587 * g,
0.114 * b
].reduce((a, b) => a + b) / 255;
};
Это такой полезный ответ. Спасибо за это!
Я хотел бы поделиться версией SCSS:
@function is-color-light( $color ) {
// Get the components of the specified color
$red: red( $color );
$green: green( $color );
$blue: blue( $color );
// Compute the perceptive luminance, keeping
// in mind that the human eye favors green.
$l: 1 - ( 0.299 * $red + 0.587 * $green + 0.114 * $blue ) / 255;
@return ( $l < 0.5 );
}
теперь выясняем, как использовать алгоритм для автоматического создания цветов наведения для ссылок меню. Светлые заголовки получают более темное наведение, и наоборот.
Спасибо за этот пост.
для тех, кто может быть заинтересован, вот пример этой функции в Делфи:
function GetContrastColor(ABGColor: TColor): TColor;
var
ADouble: Double;
R, G, B: Byte;
begin
if ABGColor <= 0 then
begin
Result := clWhite;
Exit; // *** EXIT RIGHT HERE ***
end;
if ABGColor = clWhite then
begin
Result := clBlack;
Exit; // *** EXIT RIGHT HERE ***
end;
// Get RGB from Color
R := GetRValue(ABGColor);
G := GetGValue(ABGColor);
B := GetBValue(ABGColor);
// Counting the perceptive luminance - human eye favors green color...
ADouble := 1 - (0.299 * R + 0.587 * G + 0.114 * B) / 255;
if (ADouble < 0.5) then
Result := clBlack; // bright colors - black font
else
Result := clWhite; // dark colors - white font
end;
уродливый Python, если вам не хочется его писать:)
'''
Input a string without hash sign of RGB hex digits to compute
complementary contrasting color such as for fonts
'''
def contrasting_text_color(hex_str):
(r, g, b) = (hex_str[:2], hex_str[2:4], hex_str[4:])
return '000' if 1 - (int(r, 16) * 0.299 + int(g, 16) * 0.587 + int(b, 16) * 0.114) / 255 < 0.5 else 'fff'
У меня была та же проблема, но я должен был развить ее в PHP. Я использовал @Garek это решение и я также использовал этот ответ: преобразование шестнадцатеричного цвета В значения RGB в PHP для преобразования шестнадцатеричного цветового кода в RGB.
поэтому я разделяю его.
Я хотел использовать эту функцию с заданным шестнадцатеричным цветом фона, но не всегда начиная с"#".
//So it can be used like this way:
$color = calculateColor('#804040');
echo $color;
//or even this way:
$color = calculateColor('D79C44');
echo '<br/>'.$color;
function calculateColor($bgColor){
//ensure that the color code will not have # in the beginning
$bgColor = str_replace('#','',$bgColor);
//now just add it
$hex = '#'.$bgColor;
list($r, $g, $b) = sscanf($hex, "#%02x%02x%02x");
$color = 1 - ( 0.299 * $r + 0.587 * $g + 0.114 * $b)/255;
if ($color < 0.5)
$color = '#000000'; // bright colors - black font
else
$color = '#ffffff'; // dark colors - white font
return $color;
}
iOS Swift 3.0 (расширение UIColor):
func isLight() -> Bool
{
if let components = self.cgColor.components, let firstComponentValue = components[0], let secondComponentValue = components[1], let thirdComponentValue = components[2] {
let firstComponent = (firstComponentValue * 299)
let secondComponent = (secondComponentValue * 587)
let thirdComponent = (thirdComponentValue * 114)
let brightness = (firstComponent + secondComponent + thirdComponent) / 1000
if brightness < 0.5
{
return false
}else{
return true
}
}
print("Unable to grab components and determine brightness")
return nil
}
Если вы манипулируете цветовыми пространствами для визуального эффекта, обычно легче работать в HSL (оттенок, насыщенность и легкость), чем RGB. Перемещение цветов в RGB, чтобы дать естественно приятные эффекты, как правило, довольно концептуально сложно, в то время как преобразование в HSL, манипулирование там, а затем преобразование обратно снова является более интуитивным по концепции и неизменно дает лучшие результаты.
Википедия введение к HSL и близко родственным ВПГ. И есть бесплатный код вокруг сети, чтобы сделать преобразование (например,вот реализация javascript)
какое точное преобразование вы используете, это вопрос вкуса, но лично я бы подумал, что изменение оттенка и легкости компонентов будет наверняка генерировать хороший высококонтрастный цвет в первом приближении, но вы можете легко пойти на более тонкие эффекты.
вы можете иметь любой текст оттенка на любом фоне оттенка и убедиться, что он разборчив. Я делаю это все время. Для этого есть формула в Javascript на читаемый текст в цвете-STW* Как говорится в этой ссылке, формула является вариацией расчета обратной гамма-регулировки, хотя немного более управляемым IMHO. Меню в правой части этой ссылки и связанных с ней страниц используют случайно сгенерированные цвета для текста и фона, всегда разборчивые. Так что да, ясно можно сделать, без проблем.
как Котлин / Android расширение:
fun Int.getContrastColor(): Int {
// Counting the perceptive luminance - human eye favors green color...
val a = 1 - (0.299 * Color.red(this) + 0.587 * Color.green(this) + 0.114 * Color.blue(this)) / 255
return if (a < 0.5) Color.BLACK else Color.WHITE
}
Android вариант, который захватывает Альфа, а также.
(спасибо @thomas-vos)
/**
* Returns a colour best suited to contrast with the input colour.
*
* @param colour
* @return
*/
@ColorInt
public static int contrastingColour(@ColorInt int colour) {
// XXX https://stackoverflow.com/questions/1855884/determine-font-color-based-on-background-color
// Counting the perceptive luminance - human eye favors green color...
double a = 1 - (0.299 * Color.red(colour) + 0.587 * Color.green(colour) + 0.114 * Color.blue(colour)) / 255;
int alpha = Color.alpha(colour);
int d = 0; // bright colours - black font;
if (a >= 0.5) {
d = 255; // dark colours - white font
}
return Color.argb(alpha, d, d, d);
}
реализация для objective-c
+ (UIColor*) getContrastColor:(UIColor*) color {
CGFloat red, green, blue, alpha;
[color getRed:&red green:&green blue:&blue alpha:&alpha];
double a = ( 0.299 * red + 0.587 * green + 0.114 * blue);
return (a > 0.5) ? [[UIColor alloc]initWithRed:0 green:0 blue:0 alpha:1] : [[UIColor alloc]initWithRed:255 green:255 blue:255 alpha:1];
}
Swift 4 Пример:
extension UIColor {
var isLight: Bool {
let components = cgColor.components
let firstComponent = ((components?[0]) ?? 0) * 299
let secondComponent = ((components?[1]) ?? 0) * 587
let thirdComponent = ((components?[2]) ?? 0) * 114
let brightness = (firstComponent + secondComponent + thirdComponent) / 1000
return !(brightness < 0.6)
}
}
обновление - нашли что 0.6
был лучшим испытательным стендом для запроса