/*
* Copyright 2010 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.common.css.compiler.gssfunctions;
import java.awt.Color;
import java.lang.Math;
/**
* Utility functions to deal with colors.
*
* @author dgajda@google.com (Damian Gajda)
*/
class ColorUtil {
/** Index of Hue in HSB and HSL array. */
static final int H = 0;
/** Index of Saturation in HSB and HSL array. */
static final int S = 1;
/** Index of Brightness in HSB array. */
static final int B = 2;
/** Index of Lightness in HSL array. */
static final int L = 2;
static float[] toHsb(Color color) {
return Color.RGBtoHSB(
color.getRed(), color.getGreen(), color.getBlue(), null);
}
static String formatColor(Color color) {
return String.format("#%02X%02X%02X",
color.getRed(), color.getGreen(), color.getBlue());
}
static Color hsbToColor(float[] inputHsb) {
return Color.getHSBColor(inputHsb[H], inputHsb[S], inputHsb[B]);
}
/**
* Convert a color in HSB color space to one in HSL color space.
*
* @param inputHsb HSB color in a array of three floats, 0 is Hue, 1 is
* Saturation and 2 is Brightness
* @return HSL color in array of three floats, 0 is Hue, 1 is
* Saturation and 2 is Lightness
*/
static float[] hsbToHsl(float[] inputHsb) {
float hHsb = inputHsb[H];
float sHsb = inputHsb[S];
float bHsb = inputHsb[B];
float hHsl = hHsb;
float lHsl = bHsb * (2 - sHsb) / 2;
float sHsl = bHsb * sHsb / (1 - Math.abs(2 * lHsl - 1));
float[] hsl = {hHsl, sHsl, lHsl};
return hsl;
}
/**
* Get the HSL values of a color.
*
* @param color Color to get the HSL values
* @return array of floats representing the color in HSL color space
*/
static float[] toHsl(Color color) {
return hsbToHsl(toHsb(color));
}
/**
* Convert a color in HSL color space to one in HSB color space.
*
* @param inputHsl HSL color in a array of three floats, 0 is Hue, 1 is
* Saturation and 2 is Lightness
* @return HSB color in array of three floats, 0 is Hue, 1 is
* Saturation and 2 is Brightness
*/
static float[] hslToHsb(float[] inputHsl) {
float hHsl = inputHsl[H];
float sHsl = inputHsl[S];
float lHsl = inputHsl[L];
float hHsb = hHsl;
float bHsb = (2 * lHsl + sHsl * (1 - Math.abs(2 * lHsl - 1))) / 2;
float sHsb = 2 * (bHsb - lHsl) / bHsb;
float[] hsb = {hHsb, sHsb, bHsb};
return hsb;
}
/**
* Get the color from the HSL floats
*
* @param inputHsl HSL color
* @return Java color
*/
static Color hslToColor(float[] inputHsl) {
float[] hsb = hslToHsb(inputHsl);
return Color.getHSBColor(hsb[H], hsb[S], hsb[B]);
}
/**
* Tests whether the given colors are contrasting colors, according to the
* test described in the W3C accessibility evaluation working draft
* {@link "http://www.w3.org/TR/AERT#color-contrast"}. This is a lenient
* version of the test which allows the user to pass in the accepted leniency
* margin.
*
* <p>The value of the leniency margin is in the range 0 to 1.0. 0 means
* that the test is not lenient at all, 1.0 means that the test will pass for
* all colors that are different. It is recommended not to use values of more
* than 0.01.
*
* @param color1 the first of the two checked colors
* @param color2 the second of the two checked colors
* @param margin the test leniency margin
* @return whether the given colors are considered contrasting, taking the
* leniency margin into account
*/
static boolean testContrast(Color color1, Color color2, float margin) {
float differenceFraction = 1f - margin;
return luminanceDiff(color1, color2) > 125 * differenceFraction
&& colorDiff(color1, color2) > 500 * differenceFraction;
}
/**
* Tests whether the given colors are contrasting colors, according to the
* test described in the W3C accessibility evaluation working draft
* {@link "http://www.w3.org/TR/AERT#color-contrast"}.
*
* @param color1 the first of the two checked colors
* @param color2 the second of the two checked colors
* @return whether the given colors are considered contrasting
*/
static boolean testContrast(Color color1, Color color2) {
return luminanceDiff(color1, color2) > 125
&& colorDiff(color1, color2) > 500;
}
/**
* Computes the luminance difference of two colors (a value in range 0-255).
* It is the luminance value equal to the Y component of the YIQ or the YUV
* color space models.
*/
static int luminanceDiff(Color c1, Color c2) {
return Math.abs(luminance(c1) - luminance(c2));
}
/**
* Computes the luminance value of a color (a value in range 0-255).
* It is the luminance value equal to the Y component of the YIQ or the YUV
* color space models.
*/
static int luminance(Color color) {
return luminance(color.getRed(), color.getGreen(), color.getBlue());
}
/**
* Computes the luminance value of a color (a value in range 0-255).
* It is the luminance value equal to the Y component of the YIQ or the YUV
* color space models.
*/
static int luminance(int red, int green, int blue) {
return (red * 299 + green * 587 + blue * 114) / 1000;
}
/**
* Calculates the Manhattan distance of two colors in the RGB color space
* (a value in range 0-(255*3)).
*/
static int colorDiff(Color color1, Color color2) {
return colorDiff(
color1.getRed(), color1.getGreen(), color1.getBlue(),
color2.getRed(), color2.getGreen(), color2.getBlue());
}
/**
* Calculates the Manhattan distance of two colors in the RGB color space
* (a value in range 0-(255*3)).
*/
static int colorDiff(int r1, int g1, int b1, int r2, int g2, int b2) {
return Math.abs(r1 - r2) + Math.abs(g1 - g2) + Math.abs(b1 - b2);
}
// Utility class, static methods only.
private ColorUtil() {
}
}