Yazı tipi rengini arka plan rengine göre belirleme


248

Kullanıcının bir bölüm için arka plan rengini özelleştirmesine, ancak yazı tipi rengini (seçenek sayısını minimumda tutmayacak şekilde) özelleştirmesine izin veren bir sistem (örneğin bir web sitesi) verildiğinde, bir "açık" veya " koyu "yazı tipi rengi gerekli mi?

Eminim bazı algoritmalar vardır, ama renkler, parlaklık, vb. Hakkında kendi başıma anlamaya yetecek kadar bilgim yok.

Yanıtlar:


447

Benzer bir sorunla karşılaştım. Renk ölçekleri / ısı haritaları üzerinde metin etiketleri görüntülemek için kontrast yazı tipi rengini seçmek için iyi bir yöntem bulmak zorundaydım. Evrensel bir yöntem olmalıydı ve üretilen renk "iyi görünümlü" olmalıydı, bu da basit bir tamamlayıcı renk üretmenin iyi bir çözüm olmadığı anlamına geliyordu - bazen izlemesi ve okunması zor garip, çok yoğun renkler üretiyordu.

Uzun süren testlerden ve bu sorunu çözmeye çalıştıktan sonra, en iyi çözümün "koyu" renkler için beyaz yazı tipi ve "parlak" renkler için siyah yazı tipi seçmek olduğunu öğrendim.

İşte C # kullanıyorum işlevi bir örnek:

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

Bu, birçok farklı renk ölçeği (gökkuşağı, gri tonlama, ısı, buz ve diğerleri) için test edildi ve bulduğum tek "evrensel" yöntemdi.

Düzenle "Algılayıcı parlaklık"
sayma formülü değiştirildi a- gerçekten daha iyi görünüyor! Zaten benim yazılım uygulanmış, harika görünüyor.

Edit 2 @WebSeed bu algoritmanın harika bir çalışma örneğini sağladı: http://codepen.io/WebSeed/full/pvgqEq/


14
Muhtemelen önemli değildir, ancak parlaklığı hesaplamak için daha iyi bir işlev isteyebilirsiniz stackoverflow.com/questions/596216/…
Josh Lee

1
Bu mükemmel olacak gibi görünüyor.
Joseph Daigle

Tam da bugün ihtiyacım olan şey.
Chris W

Algısal Luminance ağırlıklarınız nereden geliyor?
Mat


23

Birisinin GaceK'nin cevabının daha kısa, belki daha kolay bir versiyonunu istemesi durumunda :

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

Not: Luma değerinin tersini kaldırdım (parlak renklerin daha yüksek bir değere sahip olmasını sağlamak, benim için daha doğal görünen ve aynı zamanda 'varsayılan' hesaplama yöntemidir.

Benim için harika çalıştıkları için buradan GaceK ile aynı sabitleri kullandım .

(Bunu aşağıdaki imzayı kullanarak bir Genişletme Yöntemi olarak da uygulayabilirsiniz :

public static Color ContrastColor(this Color iColor)

Daha sonra aracılığıyla arayabilirsiniz foregroundColor = background.ContrastColor().)


11

Teşekkürler @Gacek . İşte Android için bir sürüm:

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

Ve geliştirilmiş (daha kısa) bir versiyon:

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

Eğer kurtulmak @Marcus Mangelsdorf (değişikliklerini uygulamak verseydin, okumak için daha kısa ve daha kolay olacağını 1 - ...parçası ve yeniden adlandırma aiçinluminance
ridcully at

İlkini kullanarak, alfa da yakalayabilirsiniz.
Brill Pappin

9

Swift'in Gacık'ın cevabını uygulaması:

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

Hızla, r / g / b CGFloats olduğundan, parlaklığı hesaplamak için "/ 255" 'e ihtiyacınız yoktur: parlaklık = 1 - ((0.299 * r) + (0.587 * g) + (0.114 * b))
SuperDuperTango

8

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

Bu gönderi için teşekkürler.

Kim ilgilenebilirse, işte Delphi'deki bu işlevin bir örneği:

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;

Son satırdan dördüncü sırada küçük bir hata var. Sonuç: = clBlack bundan sonra noktalı virgül olmamalıdır;
Andy k

5

Bu çok yardımcı bir cevap. Bunun için teşekkürler!

Bir SCSS sürümünü paylaşmak istiyorum:

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

}

Şimdi, menü bağlantıları için fareyle üzerine gelme renklerini otomatik olarak oluşturmak için algoritmayı nasıl kullanacağınızı anlıyoruz. Işık başlıkları daha koyu bir havada asılı kalır ve bunun tersi de geçerlidir.


3

Çarpıntı uygulaması

Color contrastColor(Color color) {
  if (color == Colors.transparent || color.alpha < 50) {
    return Colors.black;
  }
  double luminance = (0.299 * color.red + 0.587 * color.green + 0.114 * color.blue) / 255;
  return luminance > 0.5 ? Colors.black : Colors.white;
}

Tüm yaptığım önek 'statik' idi. Teşekkürler!
Pete Alvin

2

Çirkin Python yazmak istemiyorsanız :)

'''
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'

2

Aynı sorunu vardı ama PHP geliştirmek zorunda kaldı . @ Garek çözümünü kullandım ve bu cevabı da kullandım: HEX renk kodunu RGB'ye dönüştürmek için PHP'de onaltılık rengi RGB değerlerine dönüştürün.

Ben de paylaşıyorum.

Bu işlevi verilen Arka Plan HEX rengiyle kullanmak istedim, ancak her zaman '#' ile başlamıyorum.

//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

Kotlin / Android uzantısı olarak:

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
}

1

Objektif-c için bir uygulama

+ (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];
}

2
Diğer kullanıcılara kodunuzda neler olduğunu bildirmek için buraya bir açıklama eklemelisiniz
Michael

1

iOS Swift 3.0 (UIColor uzantısı):

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
İşlev beklendiği gibi çalışıyor ancak linting ve force dökümlere dikkat edin
RichAppz

1
Harika, aşağıdaki Swift 4 için
örneğime göz atın

1

Swift 4 Örnek:

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

}

GÜNCELLEME - 0.6Sorgu için daha iyi bir test yatağı bulundu


RGB renk alanı olduğu için bunun aslında birçok durumda başarısız olması muhtemeldir. İçindeki öğelerin sayısı CGColor.componentsrenk uzayına bağlı olarak değişir: örneğin, UIColor.whitebir CGColor'a yayınlandığında yalnızca iki tane vardır: [1.0, 1.0]tam alfa ile gri tonlamalı (tamamen beyaz) bir rengi temsil eder. Bir UIColor'un RGB elemanlarını çıkarmanın daha iyi bir yoluUIColor.getRed(_ red:, green:, blue:, alpha:)
Scott Matthewman

1

Google kapatma kitaplığında w3c önerisine başvuran bir algoritma olduğunu unutmayın : http://www.w3.org/TR/AERT#color-contrast . Ancak, bu API'da başlangıç ​​noktası olarak önerilen renklerin bir listesini sağlarsınız.

/**
 * Find the "best" (highest-contrast) of the suggested colors for the prime
 * color. Uses W3C formula for judging readability and visual accessibility:
 * http://www.w3.org/TR/AERT#color-contrast
 * @param {goog.color.Rgb} prime Color represented as a rgb array.
 * @param {Array<goog.color.Rgb>} suggestions Array of colors,
 *     each representing a rgb array.
 * @return {!goog.color.Rgb} Highest-contrast color represented by an array.
 */
goog.color.highContrast = function(prime, suggestions) {
  var suggestionsWithDiff = [];
  for (var i = 0; i < suggestions.length; i++) {
    suggestionsWithDiff.push({
      color: suggestions[i],
      diff: goog.color.yiqBrightnessDiff_(suggestions[i], prime) +
          goog.color.colorDiff_(suggestions[i], prime)
    });
  }
  suggestionsWithDiff.sort(function(a, b) { return b.diff - a.diff; });
  return suggestionsWithDiff[0].color;
};


/**
 * Calculate brightness of a color according to YIQ formula (brightness is Y).
 * More info on YIQ here: http://en.wikipedia.org/wiki/YIQ. Helper method for
 * goog.color.highContrast()
 * @param {goog.color.Rgb} rgb Color represented by a rgb array.
 * @return {number} brightness (Y).
 * @private
 */
goog.color.yiqBrightness_ = function(rgb) {
  return Math.round((rgb[0] * 299 + rgb[1] * 587 + rgb[2] * 114) / 1000);
};


/**
 * Calculate difference in brightness of two colors. Helper method for
 * goog.color.highContrast()
 * @param {goog.color.Rgb} rgb1 Color represented by a rgb array.
 * @param {goog.color.Rgb} rgb2 Color represented by a rgb array.
 * @return {number} Brightness difference.
 * @private
 */
goog.color.yiqBrightnessDiff_ = function(rgb1, rgb2) {
  return Math.abs(
      goog.color.yiqBrightness_(rgb1) - goog.color.yiqBrightness_(rgb2));
};


/**
 * Calculate color difference between two colors. Helper method for
 * goog.color.highContrast()
 * @param {goog.color.Rgb} rgb1 Color represented by a rgb array.
 * @param {goog.color.Rgb} rgb2 Color represented by a rgb array.
 * @return {number} Color difference.
 * @private
 */
goog.color.colorDiff_ = function(rgb1, rgb2) {
  return Math.abs(rgb1[0] - rgb2[0]) + Math.abs(rgb1[1] - rgb2[1]) +
      Math.abs(rgb1[2] - rgb2[2]);
};

0

Görsel efekt için renk uzaylarını işliyorsanız, HSL'de (Ton, Doygunluk ve Hafiflik) çalışmak genellikle RGB'den daha kolaydır. Doğal olarak hoş efektler vermek için renkleri RGB'de taşımak oldukça kavramsal olarak zor olma eğilimindedir, oysa HSL'ye dönüştürmek, oradan manipüle etmek, daha sonra tekrar dönüştürmek konseptte daha sezgiseldir ve her zaman daha iyi görünümlü sonuçlar verir.

Vikipedi bir sahiptir iyi bir giriş HSL ve yakından ilişkili HSV. Ve dönüşüm yapmak için net çevresinde ücretsiz kod var (örneğin, burada bir javascript uygulaması var )

Kullandığınız kesin dönüşüm bir zevk meselesidir, ancak kişisel olarak Ton ve Hafiflik bileşenlerini tersine çevirmenin ilk yaklaşım olarak iyi bir yüksek kontrast rengi üreteceğinden emin olabilirdim, ancak daha ince efektlere kolayca gidebilirsiniz.


1
Evet, ama aynı zamanda insan gözünün yeşili diğer renklerden çok daha baskın ve mavi daha az görebildiğini düşünün (bu yüzden mavi, görüntü formatlarında daha az renk biti alır).
wchargin

1
Aslında. HSL'ye geçeceksek, YUV'ya tam atlayabilir ve insan algısını hesaba katabiliriz.
David Bradbury

0

Herhangi bir renk tonu arka planında herhangi bir renk tonu metnine sahip olabilir ve okunabilir olduğundan emin olabilirsiniz. Onu her zaman yaparım. Bunun için Renkli Okunabilir Metin Üzerine Javascript'te bir formül var - STW * Bu bağlantıda belirtildiği gibi, formül biraz daha yönetilebilir IMHO olsa da, ters gama ayarlama hesaplamasında bir varyasyon. Bu bağlantının sağ tarafındaki menüler ve ilişkili sayfaları, metin ve arka plan için her zaman okunabilir şekilde rastgele oluşturulmuş renkler kullanır. Yani evet, açıkça yapılabilir, sorun değil.


0

Alfa'yı da yakalayan bir Android varyasyonu.

(teşekkürler @ 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 /programming/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

base@ Gacek'in cevap almak için R sürümünü ( luminancekendi eşiğinizi kolayca uygulayabilirsiniz)

# vectorized
luminance = function(col) c(c(.299, .587, .114) %*% col2rgb(col)/255)

Kullanımı:

luminance(c('black', 'white', '#236FAB', 'darkred', '#01F11F'))
# [1] 0.0000000 1.0000000 0.3730039 0.1629843 0.5698039

0

Dayanarak gacek cevabı ve analiz ettikten sonra @ WebSeed örneğini ile DALGA tarayıcı uzantısı, ben kontrast oranına dayanan siyah ya da beyaz metin (W3C tanımlanan seçtiği aşağıdaki sürümü ile gelip ettik Web İçeriği Erişilebilirlik Kılavuzu (WCAG) 2.1 ) , parlaklık yerine.

Bu kod (javascript içinde):

// As defined in WCAG 2.1
var relativeLuminance = function (R8bit, G8bit, B8bit) {
  var RsRGB = R8bit / 255.0;
  var GsRGB = G8bit / 255.0;
  var BsRGB = B8bit / 255.0;

  var R = (RsRGB <= 0.03928) ? RsRGB / 12.92 : Math.pow((RsRGB + 0.055) / 1.055, 2.4);
  var G = (GsRGB <= 0.03928) ? GsRGB / 12.92 : Math.pow((GsRGB + 0.055) / 1.055, 2.4);
  var B = (BsRGB <= 0.03928) ? BsRGB / 12.92 : Math.pow((BsRGB + 0.055) / 1.055, 2.4);

  return 0.2126 * R + 0.7152 * G + 0.0722 * B;
};

var blackContrast = function(r, g, b) {
  var L = relativeLuminance(r, g, b);
  return (L + 0.05) / 0.05;
};

var whiteContrast = function(r, g, b) {
  var L = relativeLuminance(r, g, b);
  return 1.05 / (L + 0.05);
};

// If both options satisfy AAA criterion (at least 7:1 contrast), use preference
// else, use higher contrast (white breaks tie)
var chooseFGcolor = function(r, g, b, prefer = 'white') {
  var Cb = blackContrast(r, g, b);
  var Cw = whiteContrast(r, g, b);
  if(Cb >= 7.0 && Cw >= 7.0) return prefer;
  else return (Cb > Cw) ? 'black' : 'white';
};

WAVE'de sıfır düşük kontrast hatası üreten @ WebSeed kod kodunun çatalında çalışan bir örnek bulunabilir .

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.