Преобразование цветов RGBA, HSL и HSLA в RGB (или в объект java.awt.Color)

Я ищу описание алгоритмов преобразования цветов RGBA, HSL и HSLA в цвет RGB или библиотеку для их преобразования в объект java.awt.Color.

Можете вы помочь мне?


person Antonio Giovanni Schiavone    schedule 11.09.2012    source источник


Ответы (3)


С новой информацией из комментариев я изменю это, чтобы отразить то, что у вас есть, и то, что вам нужно.

Во-первых, нам нужно разобрать строку rgb/hsl. Это можно сделать довольно легко, используя пару регулярных выражений и String.split:

private static final Pattern hexRegex = Pattern.compile("#[\\dA-Fa-f]{6}");
private static final Pattern rgbRegex = Pattern.compile("rgba?\\([^)]*\\)", Pattern.CASE_INSENSITIVE);
private static final Pattern hlsRegex = Pattern.compile("hlsa?\\([^)]*\\)", Pattern.CASE_INSENSITIVE);

Первый Pattern соответствует любому шестнадцатеричному коду. Второй соответствует rgb(something) или rgba(something). Третий такой же, как и второй, но с hsl и hsla. Чтобы использовать их:

public static int[] getRGB(String cssString) {
    if (hexRegex.matcher(cssString).matches())
        return getRgbFromHex(cssString);
    if (rgbRegex.matcher(cssString).matches())
        return getRgbFromRgb(cssString);
    if (hslRegex.matcher(cssString).matches())
        return getRgbFromHsl(cssString);
    return null; // no match
}

private static int[] getRgbFromHex(String hexString) {
    int rgb = Integer.decode(hexString);
    Color c = new Color(rgb);
    return new int[] { c.getRed(), c.getGreen(), c.getBlue(), c.getAlpha() };
}

private static int[] getRgbFromRgb(String rgbString) {
    String[] values = rgbString.split("[\\s,()]");
    // values[0] is just "rgb" or "rgba"
    String red = values[1];
    String green = values[2];
    String blue = values[3];
    String alpha = "1.0";
    if (values.length >= 5) {
        alpha = values[4];
    }
    return new int[] {
        parseValue(red, 255),
        parseValue(green, 255),
        parseValue(blue, 255),
        parseAlpha(alpha),
    };
}

private static int[] getRgbFromHsl(String hslString) {
    String[] values = hslString.split("[\\s,()]");
    // values[0] is just "hsl" or "hsla"
    String hue = values[1];
    String sat = values[2];
    String light = values[3];
    String alpha = "1.0";
    if (values.length >= 5) {
        alpha = values[4];
    }
    int h = parseValue(hue, 360);
    double s = parsePercent(sat);
    double l = parsePercent(light);
    int a = parseAlpha(alpha);
    return hslToRgb(h, s, l, a);
}

private static int[] hslToRgb(int h, double s, double l, int a) {
    // TODO Calculate me
    int r = 0;
    int g = 0;
    int b = 0;
    return new int[] { r, g, b, a };
}

private static int parseValue(String val, int max) {
    if (val.endsWith("%")) {
        return (int) (parsePercent(val) * max);
    }
    return Integer.parseInt(val);
}

private static double parsePercent(String perc) {
    return Integer.parseInt(perc.substring(0, perc.length() - 1)) / 100.0;
}

private static int parseAlpha(String alpha) {
    return (int) (Double.parseDouble(alpha) * 255);
}

Вот что все делает:

  • getRGB — берет строку CSS, определяет ее формат, затем переходит к ее разбору. Возвращает null, если не может определить формат (т. е. он недействителен). Возвращаемый массив будет состоять из 4 элементов, r, g, b и a, и все значения будут находиться в диапазоне от 0 до 255.
  • getRgbFromHex — использует Integer.decode для анализа, так как это делает для нас # шестнадцатеричных чисел, а затем использует Color для получения значений RGB.
  • getRgbFromRgb — анализирует значения из строки rgb (включая rgba). Разбивает строку на пробелы, запятые или круглые скобки, затем анализирует каждое отдельное значение и создает из них массив.
  • getRgbFromHsl — ведет себя аналогично getRgbFromRgb, но со значениями HSL и соответствующим синтаксическим анализом вместо синтаксического анализа RGB.
  • hslToRgb - Это ваша логика расчета, которую вы уже сделали в своих комментариях. Просто вычислите int значения r, g и b здесь из h, s и l, и этот метод будет работать.
  • parseValue — если это процент, он возвращает проанализированный процент, умноженный на значение max, в противном случае он просто анализирует его как int, используя Integer.parseInt.
  • parsePercent — анализирует целую часть строки и возвращает значение в виде double, деленного на 100.
  • parseAlpha — анализирует альфа-канал как double и возвращает его, умноженный на 255.

Тестирование с rgb/rgba подтверждает, что это работает:

public static void main(String[] args) {
    System.out.println(Arrays.toString(getRGB("#FF00CC")));
    System.out.println(Arrays.toString(getRGB("rgb(255,0,0)")));
    System.out.println(Arrays.toString(getRGB("rgba(255,0,0,0.5)")));
    System.out.println(Arrays.toString(getRGB("rgba(100%,0%,30%,0.5)")));
}

Это печатает:

[255, 0, 204, 255]
[255, 0, 0, 255]
[255, 0, 0, 127]
[255, 0, 76, 127]

Еще одна вещь, которую вы, возможно, захотите рассмотреть, - это использование округления вместо прямого приведения к int для процентного материала. Это улучшит точность процентов.

Дайте мне знать, если у вас возникнут дополнительные вопросы.

person Brian    schedule 12.09.2012

Вы можете использовать Color.HSBtoRGB и Color.RGBtoHSB. Например:

int r = 0, g = 255, b = 255;
float[] hsb = Color.RGBtoHSB(r, g, b, null);
for (float f : hsb) {
    System.out.println(f);
}

Это выводит:

0.5
1.0
1.0

Эти три значения float являются значениями H, S и B соответственно. Для цветов с альфа-каналом альфа не меняется с RGB на HSB, поэтому A == A.

Чтобы создать Color с возвращаемым массивом:

Color color = Color.getHSBColor(hsb[0], hsb[1], hsb[2]);

Я не могу вам помочь без более подробной информации о том, что именно вы хотите в качестве ввода и вывода.


Изменить: см. мой другой ответ.

person Brian    schedule 11.09.2012
comment
Моя цель - преобразовать все допустимые значения цвета CSS ( /a> ) в RGB. Преобразование шестнадцатеричных цветов и имен цветов легко, я ищу преобразование RGBA, HSL и HSLA. Ваш метод не работает, HSL и HSB - разные системы представлений. - person Antonio Giovanni Schiavone; 12.09.2012
comment
@AntonioGiovanniSchiavone Итак, что у вас есть для ввода? Что-то вроде rgb(0,255,255) или #00FFFF? Если вам нужно выполнить синтаксический анализ до этого значения, вот хороший анализатор CSS для Java. Могу ли я предположить, что это то, что у вас есть для ввода? Фактическое значение свойства из CSS в виде строки? - person Brian; 12.09.2012
comment
@AntonioGiovanniSchiavone Кроме того, извините за HSB / HSL, я совершенно неправильно прочитал ваш пост: X Я исправлю это, как только узнаю, что вы ищете. - person Brian; 12.09.2012
comment
Как описано в приведенной выше ссылке, для HSL у меня есть ввод как hsl (220,100%, 63%), мой вывод - массив [r, g, b]. Для HSL я решил реализовать этот алгоритм geekymonkey.com/Programming/CSharp/RGB2HSL_HSL2RGB.htm. Все еще нужна помощь для RGBA и HSLA. - person Antonio Giovanni Schiavone; 12.09.2012
comment
@AntonioGiovanniSchiavone дополнительный A - это просто значение альфа (прозрачности), которое, насколько мне известно, не меняется с RGBA на HSLA. Другими словами, для преобразования A в A не требуется никаких преобразований. Вы можете подумать о том, чтобы ваш выходной массив имел 4 параметра, [r, g, b, a], и сделать a по умолчанию равным 100% альфа (255, 1,0 или 100%), если это не так. указано (в противном случае это значение по умолчанию). Я немного обновлю свой ответ, я не могу банкомат. - person Brian; 12.09.2012
comment
Вы имеете в виду, что rgb(r,g,b) и rgba(r,g,b,a) (с включенным в [0-1]) ВСЕГДА имеют один и тот же цвет? А также вы имеете в виду, что hsl(h,s%,l%) и hsla(h,s%,l%,a) (с включенным в [0-1]) ВСЕГДА имеют один и тот же цвет? (я не специалист в передаче цветов) - person Antonio Giovanni Schiavone; 12.09.2012
comment
@AntonioGiovanniSchiavone В некотором смысле они одного цвета, но с разной прозрачностью. Это означает, что они могут отображаться по-разному, поскольку могут сливаться с фоном, но основной цвет остается тем же. Другими словами, rgb(255,0,0) (красный, полностью непрозрачный) точно такой же, как rgb(255,0,0,1.0) (красный, полностью непрозрачный). rgb(255,0,0,0.5) имеет тот же базовый цвет (красный), но наполовину прозрачный (также известный как полупрозрачный). На белом фоне он будет казаться светлее, чем его непрозрачный аналог, но, скажем, на зеленом фоне он будет выглядеть иначе. Я обновлю свой ответ сейчас. - person Brian; 12.09.2012

Ваши правила регулярных выражений не работают нормально, потому что они допускают неправильную строку (например, "rgba(1000,500%,500%,2)" ) и запрещают правильную форму (например, "#fff" ).

Я написал более строгие и правильные правила регулярных выражений:

    String keywords_color_regex = "^[a-z]*$";
    String hex_color_regex = "^#[0-9a-f]{3}([0-9a-f]{3})?$";
    String rgb_color_regex = "^rgb\\(\\s*(0|[1-9]\\d?|1\\d\\d?|2[0-4]\\d|25[0-5])\\s*,\\s*(0|[1-9]\\d?|1\\d\\d?|2[0-4]\\d|25[0-5])\\s*,\\s*(0|[1-9]\\d?|1\\d\\d?|2[0-4]\\d|25[0-5])\\s*\\)$";
    String rgba_color_regex = "^rgba\\(\\s*(0|[1-9]\\d?|1\\d\\d?|2[0-4]\\d|25[0-5])\\s*,\\s*(0|[1-9]\\d?|1\\d\\d?|2[0-4]\\d|25[0-5])\\s*,\\s*(0|[1-9]\\d?|1\\d\\d?|2[0-4]\\d|25[0-5])\\s*,\\s*((0.[1-9])|[01])\\s*\\)$";
    String hsl_color_regex = "^hsl\\(\\s*(0|[1-9]\\d?|[12]\\d\\d|3[0-5]\\d)\\s*,\\s*((0|[1-9]\\d?|100)%)\\s*,\\s*((0|[1-9]\\d?|100)%)\\s*\\)$";

Для rgba и hsla моя цель — рассчитать реальный отображаемый цвет. Поэтому мне было интересно, если, учитывая цвет rgba/hsla и цвет его фона, есть ли способ «смешать» их для вычисления отображаемого цвета...

person Antonio Giovanni Schiavone    schedule 17.09.2012