#java #google-app-engine #colors #rgb #hsv
#java #google-app-engine #Цвет #rgb #hsv
Вопрос:
Я решил, что должен опубликовать этот вопрос, даже если я уже нашел решение, поскольку реализация Java была недоступна, когда я ее искал.
Использование HSV вместо RGB позволяет генерировать цвета с одинаковой насыщенностью и яркостью (то, что я хотел).
Google App Engine не разрешает использование java.awt.Color, поэтому выполнение следующих действий для преобразования между HSV и RGB не является вариантом:
Color c = Color.getHSBColor(hue, saturation, value);
String rgb = Integer.toHexString(c.getRGB());
Редактировать: я перенес свой ответ, как описано в комментарии Ника Джонсона.
Ex animo, — Alexander.
Комментарии:
1. Ответ на ваш собственный вопрос — это нормально, но вы должны опубликовать ответ как ответ, а не как часть вопроса.
2. Спасибо, Ник, я сделаю это завтра и отредактирую вопрос. (На данный момент я получил сообщение об ошибке: «Пользователи с репутацией менее 100 не могут ответить на свой вопрос в течение 8 часов после запроса. Вы можете ответить самостоятельно через 6 часов. До тех пор, пожалуйста, используйте комментарии или отредактируйте свой вопрос вместо этого «)
Ответ №1:
Я ничего не знаю о цветовой математике, но я могу предложить эту альтернативную структуру для кода, которая щекочет мое эстетическое чувство, потому что для меня стало очевидным, что каждый из 6 случаев — это просто другая перестановка значений, t и p . (Также у меня иррациональный страх перед длинным, если-цепочки 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;
}
Комментарии:
1. Это действительно намного красивее, за счет простого вызова другого метода.
2. Я уверен, что либо компилятор, либо JIT встроили бы дополнительный метод, если бы это был значительный прирост производительности.
3. Извините, что перетаскиваю 2-летнюю тему, но мне было интересно, подтвердит ли кто-нибудь что-нибудь для меня — следует
rgbToString
умножить на255
, нет256
? Потому что в противном случае, когдаr
это будет1.0
,rs
будет100
в шестнадцатеричном формате, что неверно.4. Да, хотя, если вы просто умножите на 255, то результаты, подобные 0.9999, будут усечены до 254, что тоже неверно. Правильный алгоритм будет реализовывать округление, присутствующее в java.awt.Color . HSBtoRGB()
5. Если ваше значение оттенка равно ровно 1, то h может легко быть 6, создавая ненужное исключение.
Ответ №2:
Вы должны использовать реализацию HSBtoRGB, предоставленную Oracle, скопировав ее исходный код в свой проект. java.awt.Color имеет открытый исходный код. Алгоритмы, предоставленные Питером Рекором и Инглингом, не являются надежными и будут возвращать недопустимые значения RGB, такие как «256,256,0» для определенных входных данных. Реализация Oracle надежна, используйте ее вместо этого.
Ответ №3:
Используйте 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
Вот исходный код.
Ответ №4:
Решение было найдено здесь: http://martin.ankerl.com/2009/12/09/how-to-create-random-colors-programmatically /
Мартин Анкерл предоставляет хороший пост на эту тему и предоставляет Ruby script. Для тех, кто слишком занят (или ленив), чтобы реализовать его на 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;
}
Комментарии:
1. Вероятно, следует указать последнее условие else
| else if (h <= 6) {
. И преобразование должно быть(r * 255)
etc not* 256
, поскольку диапазон цветов от 0 до 255.2. @ehartwell: отредактировано на основе ваших комментариев.
Ответ №5:
Мой код для преобразования:
/**
* @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))));
Комментарии:
1. привет, ты все еще жив??
Ответ №6:
Ответ @Peter Recore не использует округление.
Вероятно, несколько более правильный способ его использования — скопировать содержимое из java.awt.Color, и вот как это выглядело в 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);
}
Округление здесь кажется правильным.
Ответ №7:
Используя SWT, вы можете использовать следующий фрагмент кода:
RGB rgb = new RGB(r, g, b);
float[] hsbColor = rgb.getHSB();
rgb = new RGB(hsbColor[0], hsbColor[1], hsbColor[2]);
Комментарии:
1. Подтверждено. Хотя
(int,int,int)
конструктор принимает RGB,(float,float,float)
конструктор принимает HSB.
Ответ №8:
Я знаю, что это старый вопрос, но все ответы, которые я видел здесь, умножают оттенок на 6. Это неправильно. Я взглянул на статью в Википедии, и там говорится, что вы должны разделить на 60.
Вот тот, который я тестировал, написанный на Kotlin
fun hsvToRgb(hsv: FloatArray): IntArray {
val (hue, saturation, value) = hsv
val h: Int = (hue / 60).toInt()
val f = hue / 60 - h
val p = value * (1 - saturation)
val q = value * (1 - f * saturation)
val t = value * (1 - (1 - f) * saturation)
val rgb = when (h) {
0 -> floatArrayOf(value, t, p)
1 -> floatArrayOf(q, value, p)
2 -> floatArrayOf(p, value, t)
3 -> floatArrayOf(p, q, value)
4 -> floatArrayOf(t, p, value)
5, 6 -> floatArrayOf(value, p, q)
else -> throw Exception()
}.map { it * 255 }
val (r, g, b) = rgb
return intArrayOf(r.toInt(), g.toInt(), b.toInt())
}
Вот моя реализация Java
public static int[] hsvToRgb(float[] hsv) {
final float hue = hsv[0];
final float saturation = hsv[1];
final float value = hsv[2];
final int h = (int) hue / 60;
final float f = hue / 60 - h;
final float p = value * (1 - saturation);
final float q = value * (1 - f * saturation);
final float t = value * (1 - (1 - f) * saturation);
float[] rgb = switch (h) {
case 0 -> new float[]{value, t, p};
case 1 -> new float[]{q, value, p};
case 2 -> new float[]{p, value, t};
case 3 -> new float[]{p, q, value};
case 4 -> new float[]{t, p, value};
case 5, 6 -> new float[]{value, p, q};
default -> throw new IllegalStateException();
};
rgb[0] = rgb[0] * 255;
rgb[1] = rgb[1] * 255;
rgb[2] = rgb[2] * 255;
return new int[]{(int) rgb[0], (int) rgb[1], (int) rgb[2]};
}