package com.bootstrap.utils; import android.graphics.Color; import android.graphics.ColorMatrix; import android.graphics.ColorMatrixColorFilter; public final class ColorUtils { private final static float R_LUM = 0.213f; // 0.3086f private final static float G_LUM = 0.715f; // 0.6094f private final static float B_LUM = 0.072f; // 0.0820f private ColorUtils() { } public static int compositeColors(final int fg, final int bg) { final float alpha1 = Color.alpha(fg) / 255f; final float alpha2 = Color.alpha(bg) / 255f; float a = (alpha1 + alpha2) * (1f - alpha1); float r = (Color.red(fg) * alpha1) + (Color.red(bg) * alpha2 * (1f - alpha1)); float g = (Color.green(fg) * alpha1) + (Color.green(bg) * alpha2 * (1f - alpha1)); float b = (Color.blue(fg) * alpha1) + (Color.blue(bg) * alpha2 * (1f - alpha1)); return Color.argb((int) a, (int) r, (int) g, (int) b); } public static int crossFade(final float fraction, final int startColor, final int endColor) { int startA = (startColor >> 24) & 0xff; int startR = (startColor >> 16) & 0xff; int startG = (startColor >> 8) & 0xff; int startB = startColor & 0xff; int endA = (endColor >> 24) & 0xff; int endR = (endColor >> 16) & 0xff; int endG = (endColor >> 8) & 0xff; int endB = endColor & 0xff; return (startA + (int) (fraction * (endA - startA))) << 24 | (startR + (int) (fraction * (endR - startR))) << 16 | (startG + (int) (fraction * (endG - startG))) << 8 | (startB + (int) (fraction * (endB - startB))); } public static double calculateLuminance(final int color) { double red = Color.red(color) / 255d; red = red < 0.03928 ? red / 12.92 : Math.pow((red + 0.055) / 1.055, 2.4); double green = Color.green(color) / 255d; green = green < 0.03928 ? green / 12.92 : Math.pow((green + 0.055) / 1.055, 2.4); double blue = Color.blue(color) / 255d; blue = blue < 0.03928 ? blue / 12.92 : Math.pow((blue + 0.055) / 1.055, 2.4); return (0.2126 * red) + (0.7152 * green) + (0.0722 * blue); } public static float[] RGBtoHSL(final int color) { final float rf = Color.red(color) / 255f; final float gf = Color.green(color) / 255f; final float bf = Color.blue(color) / 255f; final float max = Math.max(rf, Math.max(gf, bf)); final float min = Math.min(rf, Math.min(gf, bf)); final float deltaMaxMin = max - min; float h, s; float l = (max + min) / 2f; if (max == min) { // Monochrome h = s = 0f; } else { if (max == rf) { h = ((gf - bf) / deltaMaxMin) % 6f; } else if (max == gf) { h = ((bf - rf) / deltaMaxMin) + 2f; } else { h = ((rf - gf) / deltaMaxMin) + 4f; } s = deltaMaxMin / (1f - Math.abs(2f * l - 1f)); } return new float[]{(h * 60f) % 360f, s, l}; } public static int HSLtoRGB(final float[] hsl) { final float h = hsl[0]; final float s = hsl[1]; final float l = hsl[2]; final float c = (1f - Math.abs(2 * l - 1f)) * s; final float m = l - 0.5f * c; final float x = c * (1f - Math.abs((h / 60f % 2f) - 1f)); final int hueSegment = (int) h / 60; int r = 0, g = 0, b = 0; switch (hueSegment) { case 0: r = Math.round(255 * (c + m)); g = Math.round(255 * (x + m)); b = Math.round(255 * m); break; case 1: r = Math.round(255 * (x + m)); g = Math.round(255 * (c + m)); b = Math.round(255 * m); break; case 2: r = Math.round(255 * m); g = Math.round(255 * (c + m)); b = Math.round(255 * (x + m)); break; case 3: r = Math.round(255 * m); g = Math.round(255 * (x + m)); b = Math.round(255 * (c + m)); break; case 4: r = Math.round(255 * (x + m)); g = Math.round(255 * m); b = Math.round(255 * (c + m)); break; case 5: case 6: r = Math.round(255 * (c + m)); g = Math.round(255 * m); b = Math.round(255 * (x + m)); break; } r = Math.max(0, Math.min(255, r)); g = Math.max(0, Math.min(255, g)); b = Math.max(0, Math.min(255, b)); return Color.rgb(r, g, b); } public static ColorMatrixColorFilter modifySaturation(final float amount) { final ColorMatrix colorMatrix = new ColorMatrix(); colorMatrix.setSaturation(amount); return new ColorMatrixColorFilter(colorMatrix); } public static ColorMatrixColorFilter tint(final float r, final float g, final float b) { final ColorMatrix colorMatrix = new ColorMatrix(); final ColorMatrix colorScale = new ColorMatrix(); colorScale.setScale(r, g, b, 1.0f); colorMatrix.postConcat(colorScale); return new ColorMatrixColorFilter(colorMatrix); } public static void alpha(final float v, final ColorMatrix matrix) { if (v < 0.0f || v > 1.f) { throw new RuntimeException("Alpha has to be in range [0, 1.0]"); } final float[] array = matrix.getArray(); array[18] = v; } public static ColorMatrix brightness(float v) { if (v < -1.f || v > 1.f) { throw new RuntimeException("Brightness has to be in range [-1.0, 1.0]"); } final boolean negative = v < 0.f; v = Math.abs(v); final float n = v * v * v * 9.f + 1.f; final float t = negative ? -n * 204.f * v : 0.f; // @formatter:off return new ColorMatrix(new float[]{ n, 0.f, 0.f, 0.f, t, 0.f, n, 0.f, 0.f, t, 0.f, 0.f, n, 0.f, t, 0.f, 0.f, 0.f, 1.f, 0.f }); // @formatter:on } public static ColorMatrix lightness(final float v) { if (v < -1.f || v > 1.f) { throw new RuntimeException("Lightness has to be in range [-1.0, 1.0]"); } final float t = v * 255.f; return new ColorMatrix(new float[]{ 1.f, 0.f, 0.f, 0.f, t, 0.f, 1.f, 0.f, 0.f, t, 0.f, 0.f, 1.f, 0.f, t, 0.f, 0.f, 0.f, 1.f, 0.f }); } public static ColorMatrix contrast(final float v) { if (v < -1.f || v > 1.f) { throw new RuntimeException("Contrast has to be in range [-1.0, 1.0]"); } final float n = v + 1.f; final float t = 128.f * (1.f - n); // @formatter:off final float[] matrix = new float[]{ n, 0.f, 0.f, 0.f, t, 0.f, n, 0.f, 0.f, t, 0.f, 0.f, n, 0.f, t, 0.f, 0.f, 0.f, 1.f, 0.f }; // @formatter:on return new ColorMatrix(matrix); } public static void contrast(final float v, final ColorMatrix matrix) { if (v < -1.f || v > 1.f) { throw new RuntimeException("Contrast has to be in range [-1.0, 1.0]"); } final float n = v + 1.f; final float t = 128.f * (1.f - n); final float[] array = matrix.getArray(); array[0] = n; array[4] = t; array[6] = n; array[9] = t; array[12] = n; array[14] = t; } public static ColorMatrix levels(final int channel, final float v) { if (v < -1.f || v > 1.f) { throw new RuntimeException("Level has to be in range [-1.0, 1.0]"); } final float r = (channel == 0 || channel == 3) ? 1.f + v * 1.f : 1.f; final float g = (channel == 1 || channel == 3) ? 1.f + v * 1.f : 1.f; final float b = (channel == 2 || channel == 3) ? 1.f + v * 1.f : 1.f; // @formatter:off final float[] matrix = new float[]{ r, 0.f, 0.f, 0.f, 0.f, 0.f, g, 0.f, 0.f, 0.f, 0.f, 0.f, b, 0.f, 0.f, 0.f, 0.f, 0.f, 1.f, 0.f }; // @formatter:on return new ColorMatrix(matrix); } public static ColorMatrix saturation(final float v) { if (v < -1.f || v > 1.f) { throw new RuntimeException("Saturation has to be in range [-1.0, 1.0]"); } final float n = 1.f + (v > 0.f ? 3.f * v : v); final float r = (1.f - n) * R_LUM; final float g = (1.f - n) * G_LUM; final float b = (1.f - n) * B_LUM; // @formatter:off final float[] matrix = new float[]{ r + n, g, b, 0.f, 0.f, r, g + n, b, 0.f, 0.f, r, g, b + n, 0.f, 0.f, 0.f, 0.f, 0.f, 1.f, 0.f }; // @formatter:on return new ColorMatrix(matrix); } public static void saturation(final float v, final ColorMatrix matrix) { if (v < -1.f || v > 1.f) { throw new RuntimeException("Saturation has to be in range [-1.0, 1.0]"); } final float n = 1.f + (v > 0.f ? 3.f * v : v); final float r = (1.f - n) * R_LUM; final float g = (1.f - n) * G_LUM; final float b = (1.f - n) * B_LUM; final float[] array = matrix.getArray(); array[0] = r + n; array[1] = g; array[2] = b; array[5] = r; array[6] = g + n; array[7] = b; array[7] = b; array[10] = r; array[11] = g; array[12] = b + n; } public static ColorMatrix colorize(final int color, final int intensity) { final float p = intensity / 100.f; final float up = Math.abs(p); float r = Color.red(color) / 255.f; float g = Color.green(color) / 255.f; float b = Color.blue(color) / 255.f; if (p < 0.f) { r = 1.f - r; g = 1.f - g; b = 1.f - b; } final float irl = 1.f - (1.f - R_LUM) * up; final float igl = 1.f - (1.f - G_LUM) * up; final float ibl = 1.f - (1.f - B_LUM) * up; final float rl = R_LUM * up; final float gl = G_LUM * up; final float bl = B_LUM * up; // @formatter:off final float[] matrix = new float[]{ irl, gl, bl, 0.f, r * p * 255.f, rl, igl, bl, 0.f, g * p * 255.f, rl, gl, ibl, 0.f, b * p * 255.f, 0.f, 0.f, 0.f, 1.f, 0.f }; // @formatter:on return new ColorMatrix(matrix); } public static ColorMatrix multiply(final int color) { final float r = Color.red(color) / 255.f; final float g = Color.green(color) / 255.f; final float b = Color.blue(color) / 255.f; // @formatter:off return new ColorMatrix(new float[]{ r, 0.f, 0.f, 0.f, 0.f, 0.f, g, 0.f, 0.f, 0.f, 0.f, 0.f, b, 0.f, 0.f, 0.f, 0.f, 0.f, 1.f, 0.f }); // @formatter:on } public static ColorMatrix dim(final float v) { if (v < 0.f || v > 1.f) { throw new RuntimeException("Dim has to be in range [0, 1.0]"); } final float n = 1.f - (1.f * v); // @formatter:off return new ColorMatrix(new float[]{ n, 0.f, 0.f, 0.f, 0.f, 0.f, n, 0.f, 0.f, 0.f, 0.f, 0.f, n, 0.f, 0.f, 0.f, 0.f, 0.f, 1.f, 0.f }); // @formatter:on } public static int get100(final int color) { return ColorUtils.compositeColors(0xb2ffffff, color) | 0xFF000000; } public static int get50(final int color) { return ColorUtils.compositeColors(0xe1ffffff, color) | 0xFF000000; } public static int get700(final int color) { return ColorUtils.compositeColors(0x32000000, color) | 0xFF000000; } public static int alpha87(final int color) { return Color.argb(222, Color.red(color), Color.green(color), Color.blue(color)); } public static int alpha54(final int color) { return Color.argb(56, Color.red(color), Color.green(color), Color.blue(color)); } }