Как выбрать цвет фона в зависимости от цвета шрифта, чтобы добиться нужного контраста

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

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();
    }
}

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

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

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

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

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

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

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();
    }
}

person Community    schedule 20.07.2011    source источник
comment
В качестве примечания, ConvertBack односторонние преобразователи должны выдавать NotSupportedException, поскольку реализации не будет.   -  person H.B.    schedule 20.07.2011


Ответы (4)


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

Y = 0.2126 R + 0.7152 G + 0.0722 B

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

Изменить: Пример схемы реализации преобразования:

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;
}

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

person H.B.    schedule 20.07.2011
comment
Кажется, что выбор черного или белого сработает; теперь, используя формулу яркости, которую вы опубликовали, Y будет варьироваться от 0 до 255; есть идеи о том, где я бы нарисовал линию на песке? - person ; 20.07.2011
comment
Думаю, я понимаю, что вы имеете в виду с 0,5: 0,5 * 255 = 127,5; если ›, то используйте черный фон, иначе используйте белый. AFAICT с серией случайных цветов, похоже, отлично работает! - person ; 20.07.2011
comment
Это один из способов взглянуть на это (вы также можете разделить все каналы на 255,0 или результат); он действительно работает, поэтому я использовал его раньше (два года назад). - person H.B.; 20.07.2011
comment
Вы также можете проверить несколько пороговых значений, чтобы увидеть, какой из них лучше, я бы использовал тот, который ниже (например, 0,25), поскольку цвета на дисплее компьютера, как правило, довольно яркие. - person H.B.; 20.07.2011

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

person Can Poyrazoğlu    schedule 20.07.2011

Технология 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)

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

person Bohdan    schedule 01.09.2016

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

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

person Security Hound    schedule 20.07.2011
comment
Я не думаю, что это было бы визуально привлекательно, например, красный на голубом или зеленый на пурпурном было бы не очень приятно смотреть, ИМО. Но в остальном приятно создать контраст в любом случае, если, конечно, цвет не близок к серому. - person Can Poyrazoğlu; 20.07.2011
comment
@can poyrazoğlu - Автор попросил дать хороший метод, чтобы найти контраст, который дает цвет на другом конце спектра. Контрастный цвет для красного при использовании этого метода на самом деле очень хорош. Желто-зеленый; Забываю, какого именно цвета. - person Security Hound; 20.07.2011