Обратные противоположные цвета
У меня есть пользовательские настройки, где они могут выбирать цвета оповещений. Оповещение - это цвет фона текста или кнопки. Но проблема заключается в том, что если они выбирают темно-синий цвет, а у нас черные буквы, то контраста недостаточно, и вы не можете его прочитать.
Я попытался сделать функцию, чтобы получить противоположный цвет, но не зашел слишком далеко.
Есть ли такая функция?
13 ответов
Я обнаружил, что лучшим решением для меня является преобразование значений RGB в значения YIQ. Так как нас интересует только значение яркости (представленное Y), необходимо выполнить одно вычисление: Y = (299*R + 587*G + 114*B)/1000
, Код Java для этого будет выглядеть так:
public static Color getContrastColor(Color color) {
double y = (299 * color.getRed() + 587 * color.getGreen() + 114 * color.getBlue()) / 1000;
return y >= 128 ? Color.black : Color.white;
}
Вы можете видеть, что он просто решает использовать черный или белый, основываясь на яркости исходного цвета. И результат работает очень хорошо, на мой взгляд. Веса (299, 587, 114) пропорциональны чувствительности глаз (или, скорее, чувствительности сетчатки) к соответствующему цвету.
Используйте дополнительный цвет:
Алго прост, вычтите каждый компонент цвета из 255, чтобы получить новые компоненты цвета
Color textColor = Color.rgb(255-Color.red(bgColor),
255-Color.green(bgColor),
255-Color.blue(bgColor));
----- РЕДАКТИРОВАТЬ (поскольку дополнение на основе RGB может работать не всегда --------
Эти две ссылки очень полезны и по теме:
http://www.splitbrain.org/blog/2008-09/18-calculating_color_contrast_with_php
На основании решения Marks я бы предложил:
public static int getComplementaryColor(int colorToInvert) {
float[] hsv = new float[3];
Color.RGBToHSV(Color.red(colorToInvert), Color.green(colorToInvert),
Color.blue(colorToInvert), hsv);
hsv[0] = (hsv[0] + 180) % 360;
return Color.HSVToColor(hsv);
}
Кроме того, теперь я создал аналогичный метод для расчета фона по умолчанию для данного цвета:
public static int getContrastVersionForColor(int color) {
float[] hsv = new float[3];
Color.RGBToHSV(Color.red(color), Color.green(color), Color.blue(color),
hsv);
if (hsv[2] < 0.5) {
hsv[2] = 0.7f;
} else {
hsv[2] = 0.3f;
}
hsv[1] = hsv[1] * 0.2f;
return Color.HSVToColor(hsv);
}
Как указал Сарвар Эрфан, используйте дополнительные цвета. Для этого вы можете использовать целочисленную маску (которая будет быстрее, чем инвертирование компонентов цвета R, G, B по отдельности).
int textColor = bgColor ^ 0x00ffffff;
Целочисленное решение:
public static int getContrastColor(int color) {
double y = (299 * Color.red(color) + 587 * Color.green(color) + 114 * Color.blue(color)) / 1000;
return y >= 128 ? Color.BLACK : Color.WHITE;
}
Я получил это работает, я думаю:)
Вот функция:
public static int OpposeColor(int ColorToInvert)
{
int RGBMAX = 255;
float[] hsv = new float[3];
float H;
Log.i("HSV_H", "Start Color=" + ColorToInvert);
Color.RGBToHSV( Color.red( ColorToInvert), RGBMAX - Color.green( ColorToInvert), Color.blue(ColorToInvert), hsv);
Log.i("HSV_H", "Hue=" + hsv[0]);
Log.i("HSV_H", "Saturation=" + hsv[1]);
Log.i("HSV_H", "Value=" + hsv[2]);
H = (float) (hsv[0] + 0.5);
if (H > 1) H -= 1;
Log.i("HSV_H", "Hue2=" + H);
Log.i("HSV_H", "Color=" + Color.HSVToColor(hsv ));
return Color.HSVToColor(hsv );
}
Небольшая модификация ответа Саймонса
float[] hsv = new float[3];
java.awt.Color.RGBtoHSB( bgColour.getRed(), bgColour.getGreen(), bgColour.getBlue(), hsv );
hsv[2] = (hsv[2] + 180) % 360;
java.awt.Color invertedColour = java.awt.Color.getHSBColor( hsv[ 0 ], hsv[ 1 ], hsv[ 2 ] );
Есть ColorUtils.calculateLuminance(int color)
который можно использовать для определения, использовать ли темный или яркий цвет текста для заданного цвета фона.
пример:
if (ColorUtils.calculateLuminance(backgroundColor) <= 0.5) textColor = <bright>
else textColor = <dark>
Порог (0.5
в этом примере) можно было выбрать экспериментально для получения лучших визуальных результатов.
Другое общее решение для преобразования цвета в целочисленный формат:
private int getComplementaryColor( int color) {
int R = color & 255;
int G = (color >> 8) & 255;
int B = (color >> 16) & 255;
int A = (color >> 24) & 255;
R = 255 - R;
G = 255 - G;
B = 255 - B;
return R + (G << 8) + ( B << 16) + ( A << 24);
}
Должен ли текст быть цветом, полученным из цвета фона? Что если он просто чередуется между белым и черным в зависимости от интенсивности RGB? Идея состоит в том, что белый всегда будет виден на значениях rgb ниже определенной интенсивности, а черный всегда будет виден на остальных.
У меня нет рабочего алгоритма, которым можно поделиться, но вы можете попробовать что-то вроде:
int threshold = 50;
if(r < threshold && g < threshold && b < threshold) {
// set your font color to white
} else {
// set your font color to black
}
Вам, вероятно, придется немного поиграть с порогом, чтобы получить что-то красивое. Вы также можете немного подкрасить шрифт в зависимости от значения rgb.
Вы можете рассчитать разницу между каждым цветовым каналом (красный, зеленый и синий) и получить среднюю разницу, а затем провести некоторое сравнение на основе этого.
Для API 24+. Предупреждение, порог!=
0,5ф, мой вариант 0,29ф.
int color_inv = Color.luminance( color) > 0.29f ? Color.BLACK : Color.WHITE;
import android.graphics.Color;
import android.graphics.Paint;
/**
* Utilities for performing common color-related tasks.
* @author Ryan Ware
*
*/
public class ColorUtils {
public static int getComplimentColor(Paint paint) {
return getComplimentColor(paint.getColor());
}
/**
* Returns the complimentary (opposite) color.
* @param color int RGB color to return the compliment of
* @return int RGB of compliment color
*/
public static int getComplimentColor(int color) {
// get existing colors
int alpha = Color.alpha(color);
int red = Color.red(color);
int blue = Color.blue(color);
int green = Color.green(color);
// find compliments
red = (~red) & 0xff;
blue = (~blue) & 0xff;
green = (~green) & 0xff;
return Color.argb(alpha, red, green, blue);
}
/**
* Converts an int RGB color representation into a hexadecimal {@link String}.
* @param argbColor int RGB color
* @return {@link String} hexadecimal color representation
*/
public static String getHexStringForARGB(int argbColor) {
String hexString = "#";
hexString += ARGBToHex(Color.alpha(argbColor));
hexString += ARGBToHex(Color.red(argbColor));
hexString += ARGBToHex(Color.green(argbColor));
hexString += ARGBToHex(Color.blue(argbColor));
return hexString;
}
/**
* Converts an int R, G, or B value into a hexadecimal {@link String}.
* @param rgbVal int R, G, or B value
* @return {@link String} hexadecimal value
*/
private static String ARGBToHex(int rgbVal) {
String hexReference = "0123456789ABCDEF";
rgbVal = Math.max(0,rgbVal);
rgbVal = Math.min(rgbVal,255);
rgbVal = Math.round(rgbVal);
return String.valueOf( hexReference.charAt((rgbVal-rgbVal%16)/16) + "" + hexReference.charAt(rgbVal%16) );
}
}
спасибо: http://www.java2s.com/Code/Android/2D-Graphics/Returnsthecomplimentaryoppositecolor.htm