Использование цвета и color.darker в Android?
Хорошо, поэтому у меня есть целочисленная переменная в моем приложении. Это значение цвета, заданное цветовым подборщиком в моих предпочтениях. Теперь мне нужно использовать как этот цвет, так и более темную версию любого цвета, который может быть.
Теперь я знаю, что в стандартной Java существует метод Color.darker(), но, похоже, в Android нет эквивалента. Кто-нибудь знает об эквиваленте или обходных решениях?
Ответы
Ответ 1
Простейшим, я думаю, было бы преобразование в HSV, потемнение там и преобразование назад:
float[] hsv = new float[3];
int color = getColor();
Color.colorToHSV(color, hsv);
hsv[2] *= 0.8f; // value component
color = Color.HSVToColor(hsv);
Чтобы облегчить, простым подходом может быть умножение компонента значения на что-то > 1.0. Однако вам нужно будет закрепить результат в диапазоне [0.0, 1.0]. Кроме того, простое умножение не будет осветлять черный.
Поэтому лучшее решение: уменьшить разницу от 1.0 компонента значения, чтобы облегчить:
hsv[2] = 1.0f - 0.8f * (1.0f - hsv[2]);
Это полностью параллельна подходу для потемнения, просто используя 1 как источник вместо 0. Он работает, чтобы осветлить любой цвет (даже черный) и не требует никакого зажима. Это можно упростить:
hsv[2] = 0.2f + 0.8f * hsv[2];
Однако из-за возможных эффектов округления арифметики с плавающей запятой я был бы обеспокоен тем, что результат может превысить 1.0f (возможно, один бит). Лучше придерживаться немного более сложной формулы.
Ответ 2
Вот что я создал:
/**
* Returns darker version of specified <code>color</code>.
*/
public static int darker (int color, float factor) {
int a = Color.alpha( color );
int r = Color.red( color );
int g = Color.green( color );
int b = Color.blue( color );
return Color.argb( a,
Math.max( (int)(r * factor), 0 ),
Math.max( (int)(g * factor), 0 ),
Math.max( (int)(b * factor), 0 ) );
}
Ответ 3
Ответ Ted для облегчения цвета не работал у меня, поэтому вот решение, которое может помочь кому-то другому:
/**
* Lightens a color by a given factor.
*
* @param color
* The color to lighten
* @param factor
* The factor to lighten the color. 0 will make the color unchanged. 1 will make the
* color white.
* @return lighter version of the specified color.
*/
public static int lighter(int color, float factor) {
int red = (int) ((Color.red(color) * (1 - factor) / 255 + factor) * 255);
int green = (int) ((Color.green(color) * (1 - factor) / 255 + factor) * 255);
int blue = (int) ((Color.blue(color) * (1 - factor) / 255 + factor) * 255);
return Color.argb(Color.alpha(color), red, green, blue);
}
Ответ 4
Процедура Java Color для darken и brighten не требует ничего особенного. Фактически, это просто развернутое понимание того, какая яркость применяется к соответствующим цветам. То есть вы можете просто взять красные, зеленые, синие значения. Умножьте их на любой коэффициент, убедитесь, что они правильно попали в гамму.
Ниже приведен код, найденный в классе Color.
private static final double FACTOR = 0.7;
//...
public Color darker() {
return new Color(Math.max((int)(getRed() *FACTOR), 0),
Math.max((int)(getGreen()*FACTOR), 0),
Math.max((int)(getBlue() *FACTOR), 0),
getAlpha());
}
Очевидно, что из этого мы можем увидеть, как это сделать в android. Возьмите значения RGB, умножьте их на коэффициент и обмотайте их в гамму. (Перекодировано с нуля по причинам лицензирования).
public int crimp(int c) {
return Math.min(Math.max(c, 0), 255);
}
public int darken(int color) {
double factor = 0.7;
return (color & 0xFF000000) |
(crimp((int) (((color >> 16) & 0xFF) * factor)) << 16) |
(crimp((int) (((color >> 8) & 0xFF) * factor)) << 8) |
(crimp((int) (((color) & 0xFF) * factor)));
}
Обратите внимание, что это то же самое, что только увеличение яркости в HSB, B - просто самый яркий фактор, оттенок - это соотношение между различными цветами, а S - насколько они далеко друг от друга. Поэтому, если мы просто возьмем все цвета и умножим их на коэффициент, мы получим те же цвета в одном и том же миксе с немного более белым/черным в них.
Многие современные цветовые пространства также делают это с вычислением значения Y через различные цветовые компоненты, которые наилучшим образом приближают яркость. Таким образом, вы могли бы, если бы хотели преобразовать в лучшую форму Y или L через любой из современных цветовых пространств и преобразовать их, другие цветовые пространства имеют лучшую форму гамма в отношении того, насколько каждый цвет способствует реальной яркости, легкости, белизну, черноту или что-то другое, что цветовое пространство вызывает это. Это сделало бы лучшую работу, но для большинства целей это твердое.
Итак, в крайнем случае вы можете сделать это, перейдя в Lab, уменьшив L-компонент и преобразовывая его.
Здесь код для этого:
static int darken(int color) {
double factor = 0.7;
double[] returnarray = new double[3];
convertRGBsRGB(returnarray, ((color >> 16) & 0xFF), ((color >> 8) & 0xFF), (color & 0xFF));
convertRGBXYZ(returnarray,returnarray[0], returnarray[1], returnarray[2]);
convertXYZLab(returnarray,returnarray[0], returnarray[1], returnarray[2]);
returnarray[0] *= factor;
convertLabXYZ(returnarray,returnarray[0], returnarray[1], returnarray[2]);
convertXYZRGB(returnarray,returnarray[0], returnarray[1], returnarray[2]);
return (color & 0xFF000000) | convertsRGBRGB(returnarray);
}
static void convertRGBsRGB(double[] returnarray, int R, int G, int B) {
double var_R = (((double) R) / 255.0d); //RGB from 0 to 255
double var_G = (((double) G) / 255.0d);
double var_B = (((double) B) / 255.0d);
returnarray[0] = var_R;
returnarray[1] = var_G;
returnarray[2] = var_B;
}
static int convertsRGBRGB(double[] sRGB) {
int red = (int) (sRGB[0] * 255);
int green = (int) (sRGB[1] * 255);
int blue = (int) (sRGB[2] * 255);
red = crimp(red);
green = crimp(green);
blue = crimp(blue);
return (red << 16) | (green << 8) | blue;
}
public static int crimp(int v) {
if (v > 0xff) {
v = 0xff;
}
if (v < 0) {
v = 0;
}
return v;
}
public static final double ref_X = 95.047; //ref_X = 95.047 Observer= 2°, Illuminant= D65
public static final double ref_Y = 100.000; //ref_Y = 100.000
public static final double ref_Z = 108.883;//ref_Z = 108.883
static void convertRGBXYZ(double[] returnarray, double var_R, double var_G, double var_B) {
if (var_R > 0.04045) {
var_R = Math.pow(((var_R + 0.055) / 1.055), 2.4);
} else {
var_R = var_R / 12.92;
}
if (var_G > 0.04045) {
var_G = Math.pow(((var_G + 0.055) / 1.055), 2.4);
} else {
var_G = var_G / 12.92;
}
if (var_B > 0.04045) {
var_B = Math.pow(((var_B + 0.055) / 1.055), 2.4);
} else {
var_B = var_B / 12.92;
}
var_R = var_R * 100;
var_G = var_G * 100;
var_B = var_B * 100; //Observer. = 2°, Illuminant = D65
double X = var_R * 0.4124 + var_G * 0.3576 + var_B * 0.1805;
double Y = var_R * 0.2126 + var_G * 0.7152 + var_B * 0.0722;
double Z = var_R * 0.0193 + var_G * 0.1192 + var_B * 0.9505;
returnarray[0] = X;
returnarray[1] = Y;
returnarray[2] = Z;
}
static void convertXYZLab(double[] returnarray, double X, double Y, double Z) {
double var_X = X / ref_X;
double var_Y = Y / ref_Y;
double var_Z = Z / ref_Z;
if (var_X > 0.008856) {
var_X = Math.cbrt(var_X);
} else {
var_X = (7.787 * var_X) + (16.0d / 116.0d);
}
if (var_Y > 0.008856) {
var_Y = Math.cbrt(var_Y);
} else {
var_Y = (7.787 * var_Y) + (16.0d / 116.0d);
}
if (var_Z > 0.008856) {
var_Z = Math.cbrt(var_Z);
} else {
var_Z = (7.787 * var_Z) + (16.0d / 116.0d);
}
double CIE_L = (116 * var_Y) - 16;
double CIE_a = 500 * (var_X - var_Y);
double CIE_b = 200 * (var_Y - var_Z);
returnarray[0] = CIE_L;
returnarray[1] = CIE_a;
returnarray[2] = CIE_b;
}
static void convertLabXYZ(double[] returnarray, double CIE_L, double CIE_a, double CIE_b) {
double var_Y = (CIE_L + 16) / 116;
double var_X = CIE_a / 500 + var_Y;
double var_Z = var_Y - CIE_b / 200;
if ((var_Y * var_Y * var_Y) > 0.008856) {
var_Y = (var_Y * var_Y * var_Y);
} else {
var_Y = (((var_Y - 16) / 116)) / 7.787;
}
if ((var_X * var_X * var_X) > 0.008856) {
var_X = (var_X * var_X * var_X);
} else {
var_X = ((var_X - 16) / 116) / 7.787;
}
if ((var_Z * var_Z * var_Z) > 0.008856) {
var_Z = (var_Z * var_Z * var_Z);
} else {
var_Z = ((var_Z - 16) / 116) / 7.787;
}
double X = ref_X * var_X; //ref_X = 95.047 Observer= 2°, Illuminant= D65
double Y = ref_Y * var_Y; //ref_Y = 100.000
double Z = ref_Z * var_Z; //ref_Z = 108.883
returnarray[0] = X;
returnarray[1] = Y;
returnarray[2] = Z;
}
static void convertXYZRGB(double[] returnarray, double X, double Y, double Z) {
double var_X = X / 100; //X from 0 to 95.047 (Observer = 2°, Illuminant = D65)
double var_Y = Y / 100; //Y from 0 to 100.000
double var_Z = Z / 100; //Z from 0 to 108.883
double var_R = (var_X * 3.2406) + (var_Y * -1.5372) + (var_Z * -0.4986);
double var_G = (var_X * -0.9689) + (var_Y * 1.8758) + (var_Z * 0.0415);
double var_B = (var_X * 0.0557) + (var_Y * -0.2040) + (var_Z * 1.0570);
if (var_R > 0.0031308) {
var_R = 1.055 * (Math.pow(var_R, (1f / 2.4f))) - 0.055;
} else {
var_R = 12.92 * var_R;
}
if (var_G > 0.0031308) {
var_G = 1.055 * (Math.pow(var_G, (1f / 2.4f))) - 0.055;
} else {
var_G = 12.92 * var_G;
}
if (var_B > 0.0031308) {
var_B = 1.055 * (Math.pow(var_B, (1f / 2.4f))) - 0.055;
} else {
var_B = 12.92 * var_B;
}
returnarray[0] = var_R;
returnarray[1] = var_G;
returnarray[2] = var_B;
}
В моих парах строки есть то же, что и Color.darken(), изображение образцового набора цветов (эти цвета являются максимальным расстоянием от всех предыдущих цветов через CIE-LabD2000, просто используя их в качестве надежных наборов цветов. )
Цвет указателя, Color.darker() и мой основной darken(), все в ФАКТОР 0.7.
(они должны быть идентичными)
Далее для тех, кто предложил использовать Lab для затемнения,
Цвет указателя, Color.darker() и Lab Darker(), все в ФАКТОРЕ 0,7.
(это улучшение стоит времени сосать?)
Ответ 5
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
getWindow().setStatusBarColor(CircleView.shiftColorDown(color));
}// color is 'int' value