Используете color и color.darker в Android? - PullRequest
61 голосов
/ 08 февраля 2011

Хорошо, у меня в приложении целочисленная переменная. Это значение цвета, устанавливаемое палитрой цветов в моих предпочтениях. Теперь мне нужно использовать как этот цвет, так и более темную версию любого цвета.

Теперь я знаю, что в стандартной Java есть метод Color.darker (), но в Android нет аналога. Кто-нибудь знает эквивалент или какие-либо обходные пути?

Ответы [ 4 ]

204 голосов
/ 08 февраля 2011

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

33 голосов
/ 24 октября 2014

Вот что я создал:

/**
 * 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 ) );
}
23 голосов
/ 21 января 2015

Ответ Теда, чтобы осветлить цвет, не работал для меня, поэтому вот решение, которое может помочь кому-то еще:

/**
 * 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);
}
6 голосов
/ 08 февраля 2017

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

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

Index Color, Color.darker () и мой базовый darken (), все в ФАКТОРЕ 0,7.index vs. darker vs. darken (они должны быть идентичны)

Далее для тех, кто предложил использовать Lab для затемнения,

Index Color, Color.darker () и Lab Darker (), все на ФАКТОРЕ 0,7.enter image description here (это улучшение стоит потраченного времени?)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...