Обратные противоположные цвета

У меня есть пользовательская настройка, где они могут выбирать цвета предупреждений. Предупреждение - это цвет фона для текста или кнопки. Но проблема заключается в том, что если они выбирают темно-синий цвет, а у нас черные буквы, контраст не достаточно, и вы не можете его прочитать.

Я попытался сделать функцию, чтобы получить обратный противоположный цвет, но havent зашел слишком далеко.

Есть ли такая функция?

Ответ 1

Используйте дополнительный цвет:

Algo прост, вычтите каждый компонент цвета из 255, чтобы получить новые цветовые компоненты

Color textColor = Color.rgb(255-Color.red(bgColor),
                         255-Color.green(bgColor),
                         255-Color.blue(bgColor));

----- EDIT (поскольку дополнение на основе RGB может не работать всегда --------

Эти две ссылки очень полезны и по теме:

http://www.splitbrain.org/blog/2008-09/18-calculating_color_contrast_with_php

http://24ways.org/2010/calculating-color-contrast

Ответ 2

Я обнаружил, что лучшим решением для меня является преобразование значений 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) пропорциональны чувствительности глаз (или, скорее, чувствительности сетчатки) к соответствующему цвету.

Ответ 3

На основе решения 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);
}

Ответ 4

У меня это работает, я думаю:)

Вот функция:

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


}

Ответ 5

целочисленное решение:

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

Ответ 6

Должен ли текст быть цветом, полученным из цвета фона? Что, если он просто чередуется между белым и черным на основе интенсивности r g b? Идея состоит в том, что белые всегда будут видны на значениях r g b ниже определенной интенсивности, а черные всегда будут видны на остальных.

У меня нет рабочего алгоритма для совместного использования, но вы можете попробовать что-то в следующих строках:

int threshold = 50;
if(r < threshold && g < threshold && b < threshold) {
  // set your font color to white
} else {
  // set your font color to black
}

Вам, вероятно, придется немного поиграть с порогом, чтобы получить что-то хорошее. Вы также можете немного отточить шрифт, основанный на том, что значение r g b является доминирующим.

Ответ 7

Небольшая модификация ответа Саймонса

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

Ответ 8

Вы можете рассчитать разницу между каждым цветовым каналом (красным, зеленым и синим) и получить среднюю разницу - тогда сделайте некоторое сравнение, основанное на этом.

Ответ 9

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/Returnsthecomplimentaryopposingcolor.htm

Ответ 10

Существует ColorUtils.calculateLuminance(int color), который можно использовать для определения, использовать ли темный или светлый цвет текста для данного цвета фона.

Пример:

if (ColorUtils.calculateLuminance(backgroundColor) <= 0.5) textColor = <bright>
else textColor = <dark>

Порог (0.5 в этом примере) можно выбрать экспериментально для получения наилучших визуальных результатов.

Документация

Ответ 11

Как отметил Сарвар Эрфан, используйте дополнительные цвета. Для этого вы можете использовать целочисленную маску (которая будет быстрее, чем инвертирование компонентов цвета R, G, B отдельно).

int textColor = bgColor ^ 0x00ffffff;