回答:
同様の問題が発生しました。カラースケール/ヒートマップにテキストラベルを表示するために、対照的なフォントの色を選択するための適切な方法を見つける必要がありました。それは普遍的な方法である必要があり、生成された色は「見栄えが良い」必要がありました。つまり、補色を生成するだけでは良い解決策ではありませんでした。
長時間のテストとこの問題の解決を試みた結果、「暗い」色には白いフォントを、「明るい」色には黒いフォントを選択することが最善の解決策であることがわかりました。
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);
}
これは、さまざまなカラースケール(レインボー、グレースケール、ヒート、アイス、その他多数)でテストされており、私が見つけた唯一の「ユニバーサル」な方法です。
編集
カウントの式a
を「知覚的な輝度」に変更しました-見栄えがよくなりました!私のソフトウェアにはすでに実装されており、見栄えが良いです。
編集2 @WebSeedは、このアルゴリズムの優れた実用例を提供しました:http ://codepen.io/WebSeed/full/pvgqEq/
誰かがGaceKの答えのバージョンを理解しやすくしたい場合に備えて:
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;
}
注:輝度値の反転を削除しました(明るい色をより高い値にするために、私にとってはより自然に見え、「デフォルト」の計算方法でもあります。
ここではGaceKと同じ定数を使用しました。
(これを、 次のシグネチャを使用して、拡張メソッドます:
public static Color ContrastColor(this Color iColor)
その後、を介してそれを呼び出すことができforegroundColor = background.ContrastColor()
ます。)
ありがとう@Gacek。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);
}
そして改善された(より短い)バージョン:
@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;
}
1 - ...
パーツをa
luminance
Gacekの答えの私のSwift実装:
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)
}
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;
};
この投稿をありがとう。
興味がある人のために、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;
これはとても役立つ答えです。それをありがとう!
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 );
}
次に、アルゴリズムを使用してメニューリンクのホバー色を自動作成する方法を理解します。明るいヘッダーは暗いホバーを取得し、逆も同様です。
Flutterの実装
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;
}
書きたくない場合は醜いPython :)
'''
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'
同じ問題がありましたが、PHPで開発する必要がありました。私は@Garekのソリューションを使用し、この回答も使用しました 。PHPで16進カラーをRGB値に変換して、HEXカラーコードをRGBに変換します。
だから私はそれを共有しています。
この関数を特定の背景HEXカラーで使用したいのですが、常に「#」から始まるわけではありません。
//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;
}
+ (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];
}
iOS Swift 3.0(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
}
Swift 4の例:
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)
}
}
更新 - 0.6
クエリのテストベッドとして優れていることが判明
CGColor.components
、色空間によって異なります。たとえば、UIColor.white
CGColorにキャストした場合、2つしかありません:[1.0, 1.0]
完全なアルファを持つグレースケール(完全な白)色を表します。UIColorのRGB要素を抽出するより良い手段であるUIColor.getRed(_ red:, green:, blue:, alpha:)
このためのアルゴリズムが、w3c勧告を参照するgoogleクロージャライブラリにあることに注意してください:http : //www.w3.org/TR/AERT#color-contrast。ただし、このAPIでは、出発点として推奨される色のリストを提供します。
/**
* 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]);
};
視覚効果のために色空間を操作している場合、RGBよりもHSL(色相、彩度、明度)での作業が一般的に簡単です。RGBで色を移動して自然に楽しい効果を与えることは概念的に非常に難しい傾向がありますが、HSLへの変換、そこでの操作、その後の再変換は概念がより直感的であり、常により良い結果をもたらします。
ウィキペディアには、HSLと密接に関連するHSVの紹介があります。そして、変換を行うためのネットの周りに無料のコードがあります(たとえば、これはjavascript実装です))
どの正確な変換を使用するかは好みの問題ですが、個人的には、色相と明度のコンポーネントを逆にすると、最初の近似として適切なハイコントラストカラーが生成されるはずですが、より微妙な効果を簡単に得ることができます。
任意の色相の背景に任意の色相のテキストを設定して、読みやすくすることができます。私はいつもそれをしています。JavaScriptには、カラーの読み取り可能なテキストに関するSTW * の公式があります。そのリンクで述べられているように、この公式は逆ガンマ調整計算のバリエーションですが、IMHOは少し扱いやすくなっています。そのリンクの右側のメニューとそれに関連するページでは、ランダムに生成された色がテキストと背景に使用され、常に判読可能です。ですから、そうすることができます。問題ありません。
アルファもキャプチャするAndroidのバリエーション。
(@ 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);
}
基づいてGacekの回答、および分析の後WebSeedの例@とWAVEのブラウザ拡張機能、Iは、コントラスト比に基づいて、黒または白のテキストを選択し、次のバージョン(W3Cの中で定義されているように作ってみたWebコンテンツアクセシビリティガイドライン(WCAG)2.1) 、輝度の代わりに。
これは(JavaScriptの)コードです:
// 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';
};
実際の例は 、@ WebSeedのcodepenの私のフォークにあり、WAVEで低コントラストエラーを生成しません。