Как выбрать цвет фона в зависимости от цвета шрифта, чтобы иметь правильный контраст

Я не знаю много о цветовой композиции, поэтому я придумал этот алгоритм, который будет выбирать цвет фона на основе цвета шрифта на пробной основе ошибок:

public class BackgroundFromForegroundColorConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (!(value is Color))
            return value;
        Color color = (Color)value;
        if (color.R + color.G + color.B > 550)
            return new SolidColorBrush(Colors.Gray);
        else if (color.R + color.G + color.B > 400)
            return new SolidColorBrush(Colors.LightGray);
        else
            return new SolidColorBrush(Colors.White);
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

Я сделал некоторые googling об этом, но я не нашел ничего очень формального о различных способах цвет фона может быть рассчитан, чтобы получить хороший эффект контраста с цветом шрифта.

Итак, мой вопрос: есть ли более "формальный" подход, чтобы выбрать хороший фон, чтобы получить хороший контраст? Кроме того, как бы вы справились с выбором цвета фона с единственной целью сделать ваш текст максимально читаемым независимо от цвета шрифта?

быстрое обновление

немного больше контекста: я просто пытаюсь показать какой-то текст (например "быстрая коричневая лиса прыгает через ленивую собаку"), где пользователь выбирает цвет шрифта, вес шрифта, и т. д. Однако мне интересно посмотреть, что можно сделать, будь то супер просто или больше сложный.

окончательное редактирование

я решил пойти с чем H.B. suggested: похоже, он отлично работает со всеми цветами, которые я пробовал, в отличие от моего предыдущего алгоритма, передний план не всегда будет контрастировать с фоном. Мне было бы интересно узнать, есть ли формула, которая дает вам "оптимальный" фон для данного переднего плана, но для того, что мне нужно, черный/белый работает просто отлично. Это мой код в его текущей форме:

public class BackgroundFromForegroundColorConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (!(value is Color))
            return value;
        Color color = (Color)value;
        double Y = 0.2126 * color.ScR + 0.7152 * color.ScG + 0.0722 * color.ScB;
        return Y > 0.4 ? Brushes.Black : Brushes.White;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotSupportedException();
    }
}

4 ответов


существуют некоторые методы вычисления яркости цвета, основанные на том, что вы можете просто взять черный или белый фон, и вы получите приличную читаемость. См.Лума

Y = 0,2126 R + 0,7152 G + 0,0722 B

Я думаю, что порог будет 0.5, если вы используете нормализованные входные значения (0.0 - 1.0), но прошло некоторое время с тех пор, как я использовал это...

Edit: пример преобразования эскиз реализации:

public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
    var c = (Color)value;
    var l = 0.2126 * c.ScR + 0.7152 * c.ScG + 0.0722 * c.ScB;

    return l < 0.5 ? Brushes.White : Brushes.Black;
}

порог может на самом деле немного зависеть от дисплея и личных предпочтений, я бы предпочел что-то более низкое, что приведет к большей доле черных фонов.


Я думаю, что это больше вопрос дизайна, чем "официальный" способ. Так что это немного к вашему собственному решению. Можете ли вы привести несколько примеров, близких к тому, чего вы пытаетесь достичь? Я также работаю над чем-то похожим на вашу проблему в эти дни (создание онлайн-галереи, которая динамически меняет свой BG в соответствии с цветами на фотографиях в галерее), и я думаю, что я иду довольно хорошо, мой совет заключается в том, что, что бы вы ни выбрали в качестве фона, просто создайте слой черного или белого в фон, в зависимости от вашего цвета переднего плана (противоположная яркость), и таким образом вы в некотором смысле "ограничиваете" BG, например, BG может быть установлен на черный, и ваш текст тоже черный, но поверх BG есть белый слой, который делает текст читаемым. Непрозрачность слоя оставлена вам, попробуйте и посмотрите, что является лучшим значением. И вы можете реализовать все это в преобразователе значений, и эта композиция BG + 'layer' является не более чем значением цвета.


soulution Ramhound полностью терпит неудачу для цветов, имеющих каждый компонент около значения 128 (не все серые, как предлагается) - тогда вы получаете почти тот же цвет!

самый контрастный (другой) цвет для любого заданного цвета c вы просто получаете по

new Color(c.R > .5 ? 0 : 1, c.G > .5 ? 0 : 1, c.B > .5 ? 0 : 1)

или, если вам нужен диапазон 0-255

new Color(c.R > 127 ? 0 : 255, c.G > 127 ? 0 : 255, c.B > 127 ? 0 : 255)

видимость текста на заданном фоне всегда лучше, но не всегда приятно. В случае, если вы не хотите беспокоить сумасшедшими цветами, вы просто используете черно-белый, предложенный принятым ответом.


в проекте, над которым я работаю, мы решили формулу, которая разделяет цвет на красный зеленый синий и вычитает красный зеленый и синий из 255, чтобы получить почти идеальный цвет.