2009-12-06 41 views
174

Cho một hệ thống (ví dụ trang web) cho phép người dùng tùy chỉnh màu nền cho một số phần nhưng không phải màu phông chữ (để giữ số tùy chọn ở mức tối thiểu), có cách nào không để lập trình xác định xem màu phông chữ "sáng" hoặc "tối" có cần thiết không?Xác định màu phông chữ dựa trên màu nền

Tôi chắc chắn có một số thuật toán, nhưng tôi không biết đủ về màu sắc, độ sáng, v.v ... để tự mình tìm ra.

Trả lời

350

Tôi gặp sự cố tương tự. Tôi đã phải tìm một phương pháp tốt để chọn màu phông chữ tương phản để hiển thị nhãn văn bản trên colorcales/heatmaps. Nó phải là phương pháp phổ quát và màu sắc được tạo ra phải "đẹp trai", có nghĩa là màu bổ sung tạo ra đơn giản không phải là giải pháp tốt - đôi khi nó tạo ra những màu lạ, rất chuyên sâu khó xem và đọc.

Sau nhiều giờ thử nghiệm và cố gắng giải quyết vấn đề này, tôi phát hiện ra rằng giải pháp tốt nhất là chọn phông chữ màu trắng cho màu "tối" và phông chữ màu đen cho màu "sáng".

Dưới đây là một ví dụ về chức năng Tôi đang sử dụng trong C#:

Color ContrastColor(Color color) 
{ 
    int d = 0; 

    // Counting the perceptive luminance - human eye favors green color... 
    double a = 1 - (0.299 * color.R + 0.587 * color.G + 0.114 * color.B)/255; 

    if (a < 0.5) 
     d = 0; // bright colors - black font 
    else 
     d = 255; // dark colors - white font 

    return Color.FromArgb(d, d, d); 
} 

này đã được thử nghiệm cho nhiều colorscales khác nhau (cầu vồng, màu xám, nhiệt, nước đá, và nhiều người khác) và chỉ là phương pháp "phổ quát" Tôi phát hiện ra.

Sửa
Thay đổi công thức đếm a để "sáng sâu sắc" - nó thực sự trông tốt hơn! Đã triển khai nó trong phần mềm của tôi, trông rất tuyệt.

Chỉnh sửa 2 @WebSeed cung cấp một ví dụ làm việc vĩ đại của thuật toán này: http://codepen.io/WebSeed/full/pvgqEq/

+10

Nó có lẽ không quan trọng, nhưng bạn có thể muốn có một chức năng tốt hơn để tính toán độ sáng http: // stackoverflow.com/questions/596216/công thức-để-xác định-độ sáng-of-rgb-màu –

+0

Điều này có vẻ như nó sẽ được hoàn hảo. –

+0

Cải thiện mã - bây giờ thậm chí còn tốt hơn – Gacek

0

Nếu bạn đang thao tác không gian màu cho hiệu ứng hình ảnh nó thường dễ dàng hơn để làm việc trong HSL (Hue, Saturation và Lightness) so với RGB. Việc di chuyển các màu trong RGB để tạo ra các hiệu ứng tự nhiên có xu hướng khá khó khăn, trong khi chuyển đổi thành HSL, thao tác ở đó, sau đó chuyển đổi trở lại lại trực quan hơn trong khái niệm và luôn cho kết quả tìm kiếm tốt hơn.

Wikipedia có good introduction đối với HSL và HSV có liên quan chặt chẽ. Và có mã miễn phí khắp nơi trên net để làm việc chuyển đổi (ví dụ here is a javascript implementation)

gì chuyển đổi chính xác bạn sử dụng là một vấn đề của hương vị, nhưng cá nhân tôi có thể nghĩ đảo ngược các thành phần Huế và Lightness sẽ chắc chắn để tạo ra một màu sắc tương phản cao tốt như là một xấp xỉ đầu tiên, nhưng bạn có thể dễ dàng đi cho các hiệu ứng tinh tế hơn.

+1

Có, nhưng hãy xem xét rằng mắt người có thể nhìn thấy màu xanh lá cây nhiều hơn nhiều so với các màu khác, và màu xanh ít hơn (đó là lý do tại sao màu xanh được bit màu ít hơn trong các định dạng hình ảnh). – wchargin

+1

Thật vậy. Nếu chúng ta sẽ chuyển sang HSL, chúng ta cũng có thể thực hiện bước nhảy vọt đến YUV và xem xét đến nhận thức của con người. –

3

Cảm ơn bài đăng này.

Đối với bất cứ ai có thể quan tâm, đây là một ví dụ về chức năng đó trong 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; 
+0

bạn có thể chỉnh sửa và cập nhật câu trả lời của riêng bạn. – wmk

0

Bạn có thể có bất kỳ văn bản màu trên bất kỳ nền màu sắc và đảm bảo rằng nó là rõ ràng. Tôi làm nó suốt. Có một công thức cho điều này trong Javascript trên Readable Text in Colour – STW* Như nó nói trên liên kết đó, công thức là một biến thể về tính toán điều chỉnh nghịch đảo gamma, mặc dù IMHO dễ quản lý hơn một chút. Các menu ở bên phải của liên kết đó và các trang liên kết của nó sử dụng các màu được tạo ngẫu nhiên cho văn bản và nền, luôn dễ đọc. Vì vậy, có, rõ ràng nó có thể được thực hiện, không có vấn đề.

5

Chỉ trong trường hợp ai đó muốn có một phiên bản ngắn hơn, có thể dễ dàng hơn để hiểu của GaceK's answer:

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

Lưu ý: tôi loại bỏ các đảo ngược giá trị luma (để làm cho màu sắc tươi sáng có một cao hơn giá trị, những gì có vẻ tự nhiên hơn với tôi và cũng là phương pháp tính toán 'mặc định'.

Tôi đã sử dụng các hằng số giống như GaceK từ here vì chúng hoạt động tốt cho tôi

(Bạn cũng có thể thực hiện điều này như một Extension Method sử dụng chữ ký sau đây:.

public static Color ContrastColor(this Color iColor) 

Sau đó bạn có thể gọi nó qua foregroundColor = background.ContrastColor())

2

thực hiện Swift của tôi về câu trả lời Gacek của:

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

Nhanh chóng, vì r/g/b là CGFloats, bạn không cần "/ 255" để tính độ sáng: để độ sáng = 1 - ((0,299 * r) + (0,587 * g) + (0,14 * b))) – SuperDuperTango

1

Python xấu xí nếu bạn không muốn viết nó :)

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

Đây là một câu trả lời hữu ích. Cảm ơn cho nó!

tôi muốn chia sẻ một phiên bản 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); 

} 

Bây giờ tìm ra cách sử dụng các thuật toán để tự động tạo ra màu sắc di chuột cho các liên kết đơn. Tiêu đề sáng có hình thu nhỏ hơn và ngược lại.

8

Cảm ơn bạn @Gacek. Dưới đây là một phiên bản dành cho 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); 
} 

Và một cải thiện (ngắn hơn) phiên bản:

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

Nó sẽ thậm chí ngắn hơn và dễ đọc hơn, nếu bạn áp dụng các thay đổi của @Marcus Mangelsdorf (loại bỏ phần '1 - ...' và đổi tên 'a' thành' luminance' – Ridcully

+0

Sử dụng đầu tiên một, bạn có thể nắm bắt alpha là tốt. –

2

iOS Swift 3.0 (UIColor mở rộng):

func isLight() -> Bool 
{ 
    let components = self.cgColor.components 

    let firstComponent = ((components?[0])! * 299) 
    let secondComponent = ((components?[1])! * 587) 
    let thirdComponent = ((components?[2])! * 114) 
    let brightness = (firstComponent + secondComponent + thirdComponent)/1000 

    if brightness < 0.5 
    { 
     return false 
    } 
    else 
    { 
     return true 
    } 
} 
3

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

Là Kotlin/Android e xtension:

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

Biến thể Android cũng nắm bắt alpha.

(nhờ @ 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); 
} 
Các vấn đề liên quan