Określ kolor czcionki na podstawie koloru tła

Biorąc pod uwagę system (na przykład stronę internetową), który pozwala użytkownikowi dostosować kolor tła dla niektórych sekcji, ale nie kolor czcionki (aby ograniczyć liczbę opcji do minimum), czy istnieje sposób, aby programowo określić, czy "jasny" lub "ciemny" kolor czcionki jest konieczny?

Jestem pewien, że jest jakiś algorytm, ale nie wiem wystarczająco dużo o kolorach, jasności, itp, aby to rozgryźć na własną rękę.

Author: wchargin, 2009-12-06

16 answers

Napotkałem podobny problem. Musiałem znaleźć dobrą metodę wyboru kontrastowego koloru czcionki do wyświetlania etykiet tekstowych na colorscales / heatmaps. Musiała to być metoda uniwersalna, a generowany kolor miał być "dobrze wyglądający", co oznacza, że proste generowanie koloru uzupełniającego nie było dobrym rozwiązaniem - czasami generowało dziwne, bardzo intensywne kolory, które trudno było oglądać i czytać.

Po długich godzinach testów i próbach rozwiązania tego problemu, dowiedziałem się, że najlepsze rozwiązaniem jest wybranie białej czcionki dla "ciemnych" kolorów i czarnej czcionki dla" jasnych " kolorów.

Oto przykład funkcji, której używam w 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);
}
Została ona przetestowana pod kątem wielu różnych kolorów (tęcza, skala szarości, ciepło, lód i wiele innych) i jest jedyną "uniwersalną" metodą, jaką odkryłem.

Edit
Zmieniono formułę liczenia a na "luminancję percepcyjną" - naprawdę wygląda lepiej! Już zaimplementowane w moim oprogramowaniu, wygląda świetnie.

Edycja 2 @WebSeed podał świetny działający przykład tego algorytmu: http://codepen.io/WebSeed/full/pvgqEq/

 385
Author: Gacek,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-07-24 13:07:08

Dziękuję @Gacek . Oto wersja dla Androida:

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

I ulepszona (krótsza) wersja:

@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;
}
 11
Author: Thomas Vos,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-02-10 12:20:28

Na wypadek gdyby ktoś chciał krótszą, może łatwiejszą do zrozumienia wersję odpowiedzi Gacka:

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

Uwaga: usunąłem inwersję wartości luma (aby jasne kolory miały wyższą wartość, co wydaje mi się bardziej naturalne i jest również 'domyślną' metodą obliczeniową.

Użyłem tych samych stałych, co Gacek z tutaj, ponieważ działały dla mnie świetnie.

(można to również zaimplementować jako metodę rozszerzenia używając następującego podpisu:

public static Color ContrastColor(this Color iColor)

Można następnie wywołać przez foregroundColor = background.ContrastColor().)

 9
Author: Marcus Mangelsdorf,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-10-09 12:21:11

Moja szybka realizacja odpowiedzi Gacka:

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)
}
 6
Author: jovit.royeca,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-08-03 06:24:24

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;
};
 6
Author: matfin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-09-20 20:55:05

To bardzo pomocna odpowiedź. Dzięki za to!

Chciałbym udostępnić wersję 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 );

}

Teraz zastanawiam się, jak użyć algorytmu do automatycznego tworzenia kolorów kursora dla linków menu. Jasne nagłówki stają się ciemniejsze i odwrotnie.

 5
Author: ricotheque,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-07-04 04:06:05

Dzięki za ten post.

Dla każdego, kto może być zainteresowany, oto przykład tej funkcji w Delphi:

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;
 4
Author: user3233041,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-10-09 16:27:36

Brzydki Pyton jeśli nie masz ochoty go pisać:)

'''
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'
 1
Author: Joseph Coco,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-06-02 23:01:02

Miałem ten sam problem, ale musiałem go rozwinąć w PHP . Użyłem @Garek 'S solution i użyłem również tej odpowiedzi: Konwertuj kolor sześciokątny na wartości RGB w PHP , Aby przekonwertować kod koloru sześciokątnego na RGB.

Więc się tym dzielę.

Chciałem użyć tej funkcji z podanym kolorem szesnastkowym tła, ale nie zawsze zaczynającym się od'#'.

//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;
}
 1
Author: GregV,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-05-16 11:30:21

IOS Swift 3.0 (Rozszerzenie 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
}
 1
Author: Josh O'Connor,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-06-08 17:54:56

Jeśli manipulujesz przestrzeniami kolorów w celu uzyskania efektu wizualnego, łatwiej jest pracować w HSL (odcień, nasycenie i jasność) niż w RGB. Przenoszenie kolorów w RGB, aby dać naturalnie przyjemne efekty, wydaje się być dość koncepcyjnie trudne, podczas gdy konwersja do HSL, manipulowanie tam, a następnie konwersja z powrotem jest bardziej intuicyjna w koncepcji i niezmiennie daje lepsze wyniki.

Wikipedia ma dobre wprowadzenie do HSL i blisko spokrewnionego HSV. Oraz w sieci jest darmowy kod do konwersji (na przykład tutaj jest implementacja javascript )

To, jakiej precyzyjnej transformacji użyjesz, jest kwestią gustu, ale osobiście myślałem, że odwrócenie odcienia i lekkości składników na pewno wygeneruje dobry kontrast kolorów o wysokim kontraście jako pierwsze przybliżenie, ale można łatwo przejść do bardziej subtelnych efektów.

 0
Author: Cruachan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-06-19 10:34:43

Możesz mieć dowolny tekst barwy na dowolnym tle barwy i upewnić się, że jest czytelny. Robię to cały czas. Istnieje na to formuła w Javascript na czytelny tekst w Kolorze-STW * Jak jest napisane na tym linku, wzór jest wariacją na temat obliczenia korekcji odwrotnej gamma, choć trochę bardziej zarządzalne IMHO. Menu po prawej stronie tego linku i powiązanych z nim stron wykorzystuje losowo generowane kolory tekstu i tła, zawsze czytelne. Więc tak, oczywiście może to być załatwione, nie ma problemu.

 0
Author: Dave Collier,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-01-19 17:48:46

Jako rozszerzenie Kotlin / 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
}
 0
Author: Gabriel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-11-03 21:57:13

Odmiana Androida, która przechwytuje również Alfę.

(dzięki @ 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);
}
 0
Author: Brill Pappin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-03-06 16:12:40

Realizacja celu-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];
}
 0
Author: Andreas Lytter,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-04-02 17:34:14

Swift 4 Przykład:

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

}

UPDATE - okazało się, że 0.6 było lepszym testem dla zapytania

 0
Author: RichAppz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-06-15 10:32:14