Преобразование из HSV (HSB в Java) в RGB без использования java.ОУ.Цвет (запрещен в Google App Engine)
Я решил, что должен опубликовать этот вопрос, даже если я уже нашел решение, поскольку реализация Java не была легко доступна, когда я искал ее.
Использование HSV вместо RGB позволяет генерировать цвета с одинаковой насыщенностью и яркостью (то, что я хотел).
Google App Engine не позволяет использовать java.ОУ.Цвет, поэтому выполнение следующих действий для преобразования между HSV и RGB не является опцией:
Color c = Color.getHSBColor(hue, saturation, value);
String rgb = Integer.toHexString(c.getRGB());
Edit: я переместил свой ответ, как описано в комментарий Ника Джонсона.
Ex animo, - Александр.
7 ответов:
Я ничего не знаю о цветовой математике, но я могу предложить эту альтернативную структуру для кода, которая щекочет мое эстетическое чувство, потому что она сделала для меня очевидным, что каждый из 6 случаев-это просто другая перестановка значений, t и p. (кроме того, у меня есть иррациональный страх перед длинными цепочками if-else.)
public static String hsvToRgb(float hue, float saturation, float value) { int h = (int)(hue * 6); float f = hue * 6 - h; float p = value * (1 - saturation); float q = value * (1 - f * saturation); float t = value * (1 - (1 - f) * saturation); switch (h) { case 0: return rgbToString(value, t, p); case 1: return rgbToString(q, value, p); case 2: return rgbToString(p, value, t); case 3: return rgbToString(p, q, value); case 4: return rgbToString(t, p, value); case 5: return rgbToString(value, p, q); default: throw new RuntimeException("Something went wrong when converting from HSV to RGB. Input was " + hue + ", " + saturation + ", " + value); } } public static String rgbToString(float r, float g, float b) { String rs = Integer.toHexString((int)(r * 256)); String gs = Integer.toHexString((int)(g * 256)); String bs = Integer.toHexString((int)(b * 256)); return rs + gs + bs; }
Вы должны использовать реализацию HSBtoRGB, предоставленную Oracle, копируя ее исходный код в свой проект. Ява.ОУ.Цвет является открытым исходным кодом. Алгоритмы, предоставляемые Peter Recore и Yngling, не являются надежными и возвращают незаконные значения RGB, такие как "256,256,0" для определенных входных данных. Реализация Oracle является надежной, вместо того, чтобы использовать его.
Мой код для преобразования:
/** * @param H * 0-360 * @param S * 0-100 * @param V * 0-100 * @return color in hex string */ public static String hsvToRgb(float H, float S, float V) { float R, G, B; H /= 360f; S /= 100f; V /= 100f; if (S == 0) { R = V * 255; G = V * 255; B = V * 255; } else { float var_h = H * 6; if (var_h == 6) var_h = 0; // H must be < 1 int var_i = (int) Math.floor((double) var_h); // Or ... var_i = // floor( var_h ) float var_1 = V * (1 - S); float var_2 = V * (1 - S * (var_h - var_i)); float var_3 = V * (1 - S * (1 - (var_h - var_i))); float var_r; float var_g; float var_b; if (var_i == 0) { var_r = V; var_g = var_3; var_b = var_1; } else if (var_i == 1) { var_r = var_2; var_g = V; var_b = var_1; } else if (var_i == 2) { var_r = var_1; var_g = V; var_b = var_3; } else if (var_i == 3) { var_r = var_1; var_g = var_2; var_b = V; } else if (var_i == 4) { var_r = var_3; var_g = var_1; var_b = V; } else { var_r = V; var_g = var_1; var_b = var_2; } R = var_r * 255; // RGB results from 0 to 255 G = var_g * 255; B = var_b * 255; } String rs = Integer.toHexString((int) (R)); String gs = Integer.toHexString((int) (G)); String bs = Integer.toHexString((int) (B)); if (rs.length() == 1) rs = "0" + rs; if (gs.length() == 1) gs = "0" + gs; if (bs.length() == 1) bs = "0" + bs; return "#" + rs + gs + bs; }
Пример использования на Android:
tv.setBackgroundColor(Color.parseColor((ColorOperations.hsvToRgb(100, 100, 57))));
Ответ @Peter Recore не использует округление.
Вероятно, несколько более правильным способом его использования является копирование содержимого с java.ОУ.Цвет и вот как это выглядело в Java 6:
public static int HSBtoRGB(float hue, float saturation, float brightness) { int r = 0, g = 0, b = 0; if (saturation == 0) { r = g = b = (int) (brightness * 255.0f + 0.5f); } else { float h = (hue - (float)Math.floor(hue)) * 6.0f; float f = h - (float)java.lang.Math.floor(h); float p = brightness * (1.0f - saturation); float q = brightness * (1.0f - saturation * f); float t = brightness * (1.0f - (saturation * (1.0f - f))); switch ((int) h) { case 0: r = (int) (brightness * 255.0f + 0.5f); g = (int) (t * 255.0f + 0.5f); b = (int) (p * 255.0f + 0.5f); break; case 1: r = (int) (q * 255.0f + 0.5f); g = (int) (brightness * 255.0f + 0.5f); b = (int) (p * 255.0f + 0.5f); break; case 2: r = (int) (p * 255.0f + 0.5f); g = (int) (brightness * 255.0f + 0.5f); b = (int) (t * 255.0f + 0.5f); break; case 3: r = (int) (p * 255.0f + 0.5f); g = (int) (q * 255.0f + 0.5f); b = (int) (brightness * 255.0f + 0.5f); break; case 4: r = (int) (t * 255.0f + 0.5f); g = (int) (p * 255.0f + 0.5f); b = (int) (brightness * 255.0f + 0.5f); break; case 5: r = (int) (brightness * 255.0f + 0.5f); g = (int) (p * 255.0f + 0.5f); b = (int) (q * 255.0f + 0.5f); break; } } return 0xff000000 | (r << 16) | (g << 8) | (b << 0); }
Округление здесь кажется правильным.
Решение было найдено здесь: http://martin.ankerl.com/2009/12/09/how-to-create-random-colors-programmatically/
Ankerl Мартин обеспечивает хороший пост на эту тему, и предоставляет скрипт на Ruby. Для тех, кто слишком занят (или ленив), чтобы реализовать его на Java, вот то, что я сделал (я уверен, что это может быть написано более эффективно, пожалуйста, не стесняйтесь комментировать):
public static String hsvToRgb(float hue, float saturation, float value) { float r, g, b; int h = (int)(hue * 6); float f = hue * 6 - h; float p = value * (1 - saturation); float q = value * (1 - f * saturation); float t = value * (1 - (1 - f) * saturation); if (h == 0) { r = value; g = t; b = p; } else if (h == 1) { r = q; g = value; b = p; } else if (h == 2) { r = p; g = value; b = t; } else if (h == 3) { r = p; g = q; b = value; } else if (h == 4) { r = t; g = p; b = value; } else if (h <= 6) { r = value; g = p; b = q; } else { throw new RuntimeException("Something went wrong when converting from HSV to RGB. Input was " + hue + ", " + saturation + ", " + value); } String rs = Integer.toHexString((int)(r * 255)); String gs = Integer.toHexString((int)(g * 255)); String bs = Integer.toHexString((int)(b * 255)); return rs + gs + bs; }
Используйте ColorUtils , который обеспечивает
HSLToColor(float\[\] hsl)
И
[RGBToHSL(int r, int g, int b, float\[\] hsl)]
Методы, которые очень легко преобразовать друг в друга!
Например:
float[] hsl = new float[]{1.5, 2.0, 1.5}; int color = ColorUtils.HSLToColor(hsl);
Теперь получите цвет
float[] hslStub = new float[3]; float[] hslFromColor = ColorUtils.colorToHSL(color, hslStub);
Теперь получите hsl