/* * Copyright 2012 Axel Winkler, Daniel Dunér * * This file is part of Daxplore Presenter. * * Daxplore Presenter is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 2.1 of the License, or * (at your option) any later version. * * Daxplore Presenter is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with Daxplore Presenter. If not, see <http://www.gnu.org/licenses/>. */ package org.daxplore.presenter.shared; /** * A class that represents a color. * * <p>Supports RGB, HSV and HSL color formats.</p> * * <p>Suitable for use in GWT applications and in standard Java.</p> */ public class Color { /** * An enum representing different color models. */ public enum Model { RGB, HSV, HSL } private double r, g, b; private double hslh, hsls, hsll; private double hsvh, hsvs, hsvv; /** * Instantiates a new color from RGB values. * * @param r * the red part of the RGB representation [0, 255] * @param g * the green part of the RGB representation [0, 255] * @param b * the blue part of the RGB representation [0, 255] */ public Color(double r, double g, double b) { this.r = r; this.g = g; this.b = b; calcHSL(); calcHSV(); } /** * Instantiates a new color from HSL or HSV values. * * @param h * the hue [0.0, 360.0) * @param s * the saturation [0.0, 1.0] * @param lightnessOrValue * the lightness (if HSL) or value (if HSV) [0.0, 1.0] * @param model * the color model used to interpret the lightnessOrValue argument */ public Color(double hue, double saturation, double lightnessOrValue, Model model) { double red = 0, green = 0, blue = 0; double h = hue%360; double s = saturation; if (s < 0) { s = 0; } else if (s > 1) { s = 1.0; } double lov = lightnessOrValue; if (lov < 0) { lov = 0.0; } else if (lov > 1) { lov = 1.0; } double C = 0, hprim = 0, X = 0, m = 0; switch (model) { case HSL: hslh = h; hsls = s; hsll = lov; // Code based on math from http://en.wikipedia.org/wiki/HSL_and_HSV#From_HSL C = (1 - Math.abs(2 * lov - 1)) * s; hprim = h / 60; X = C * (1 - Math.abs(hprim % 2 - 1)); m = lov - 0.5 * C; break; case HSV: hsvh = h; hsvs = s; hsvv = lov; // Code based on math from http://en.wikipedia.org/wiki/HSL_and_HSV#From_HSV C = lov * s; hprim = h / 60; X = C * (1 - Math.abs(hprim % 2 - 1)); m = lov - C; break; default: throw new IllegalArgumentException("Illegal model in hsl/hsv method: " + model.toString()); } if (hprim < 1) { red = C; green = X; blue = 0; } else if (hprim < 2) { red = X; green = C; blue = 0; } else if (hprim < 3) { red = 0; green = C; blue = X; } else if (hprim < 4) { red = 0; green = X; blue = C; } else if (hprim < 5) { red = X; green = 0; blue = C; } else if (hprim < 6) { red = C; green = 0; blue = X; } red += m; green += m; blue += m; this.r = red * 255; this.g = green * 255; this.b = blue * 255; switch (model) { case HSL: calcHSV(); break; case HSV: calcHSL(); break; default: throw new IllegalArgumentException("Illegal model in hsl/hsv method: " + model.toString()); } } /** * Convenience method for converting a HSL color to a RGB representation. * * @param h * the hue part of a HSL representation [0.0, 360.0) * @param s * the saturation part of a HSL representation [0.0, 1.0] * @param l * the lightness part of a HSL representation [0.0, 1.0] * @return the three RGB values as an int[] */ public static double[] hslToRgb(double h, double s, double l) { Color temp = new Color(h, s, l, Model.HSL); double[] out = { temp.getRed(), temp.getGreen(), temp.getBlue() }; return out; } /** * Convenience method for converting a HSV color to a RGB representation. * * @param h * the hue part of a HSV representation [0.0, 360.0) * @param s * the saturation part of a HSV representation [0.0, 1.0] * @param l * the value part of a HSV representation [0.0, 1.0] * @return the three RGB values as an int[] */ public static double[] hsvToRgb(double h, double s, double v) { Color temp = new Color(h, s, v, Model.HSV); double[] out = { temp.getRed(), temp.getGreen(), temp.getBlue() }; return out; } /** * Convenience method for converting a RGB color to a HSV representation. * * @param r * the red part of the RGB representation [0, 255] * @param g * the green part of the RGB representation [0, 255] * @param b * the blue part of the RGB representation [0, 255] * @return the three HSV values as a double[] */ public static double[] rgbToHsv(double r, double g, double b) { Color temp = new Color(r, g, b); double[] out = { temp.getHSVHue(), temp.getHSVSaturation(), temp.getHSVValue() }; return out; } /** * Convenience method for converting a RGB color to a HSL representation. * * @param r * the red part of the RGB representation [0, 255] * @param g * the green part of the RGB representation [0, 255] * @param b * the blue part of the RGB representation [0, 255] * @return the three HSL values as a double[] */ public static double[] rgbToHsl(double r, double g, double b) { Color temp = new Color(r, g, b); double[] out = { temp.getHSLHue(), temp.getHSLSaturation(), temp.getHSLLightness() }; return out; } /** * Get the red value if the color is represented as RGB. * * @return the red part of the RGB representation [0, 255] */ public double getRed() { return r; } /** * Get the green value if the color is represented as RGB. * * @return the green part of the RGB representation [0, 255] */ public double getGreen() { return g; } /** * Get the blue value if the color is represented as RGB. * * @return the blue part of the RGB representation [0, 255] */ public double getBlue() { return b; } /** * Get the blue value if the color is represented as HSV. * * @return the HSV hue [0.0, 360.0) */ public double getHSVHue() { return hsvh; } /** * Get the saturation if the color is represented as HSV. * * @return the HSV saturation [0.0, 1.0] */ public double getHSVSaturation() { return hsvs; } /** * Get the value if the color is represented as HSV. * * @return the HSV value [0.0, 1.0] */ public double getHSVValue() { return hsvv; } /** * Get the hue if the color is represented as HSL. * * @return the HSL hue [0.0, 360.0) */ public double getHSLHue() { return hslh; } /** * Get the saturation if the color is represented as HSL. * * @return the HSL saturation [0.0, 1.0] */ public double getHSLSaturation() { return hsls; } /** * Get the lightness if the color is represented as HSL. * * @return the HSL lightness [0.0, 1.0] */ public double getHSLLightness() { return hsll; } /** * Get a hex RGB representation of the color, useful in CSS. * * @return the hex color representation */ public String getHexValue() { return ("#" + pad(Integer.toHexString((int)Math.round(r))) + pad(Integer.toHexString((int)Math.round(g))) + pad(Integer.toHexString((int)Math.round(b)))) .toUpperCase(); } /** * Convenience method for converting a HSV color to a hex representation, * useful in CSS. * * @param h * the hue part of a HSV representation [0.0, 360.0) * @param s * the saturation part of a HSV representation [0.0, 1.0] * @param v * the value part of a HSV representation [0.0, 1.0] * @return the string */ public static String hsvToHex(double h, double s, double v) { return new Color(h, s, v, Model.HSV).getHexValue(); } /** * Convenience method for converting a HSL color to a hex representation, * useful in CSS. * * @param h * the hue part of a HSL representation [0.0, 360.0) * @param s * the saturation part of a HSL representation [0.0, 1.0] * @param l * the lightness part of a HSL representation [0.0, 1.0] * @return the string */ public static String hslToHex(double h, double s, double l) { return new Color(h, s, l, Model.HSL).getHexValue(); } private static String pad(String in) { if (in.length() == 0) { return "00"; } if (in.length() == 1) { return "0" + in; } return in; } /** * A human-readable representation of the color as RGB. */ @Override public String toString() { return "red=" + r + ", green=" + g + ", blue=" + b; } private void calcHSL() { double nr = r / 255.0, ng = g / 255.0, nb = b / 255.0; double max = Math.max(nr, Math.max(ng, nb)); double min = Math.min(nr, Math.min(ng, nb)); double h, s, l = (max + min) / 2; if (max == min) { h = s = 0; // achromatic } else { double d = max - min; s = l > 0.5 ? d / (2 - max - min) : d / (max + min); if (nr > ng && nr > nb) { h = (ng - nb) / d + (ng < nb ? 6 : 0); // max(r,g,b) = r } else if (ng > nb) { h = (nb - nr) / d + 2; // max(r,g,b) = g } else { h = (nr - ng) / d + 4; // max(r,g,b) = b } h = h / 6; } hslh = h * 360; hsls = s; hsll = l; } private void calcHSV() { double nr = r / 255.0, ng = g / 255.0, nb = b / 255.0; double max = Math.max(nr, Math.max(ng, nb)); double min = Math.min(nr, Math.min(ng, nb)); double h = max, s, v = max; double d = max - min; s = (max == 0) ? 0 : d / max; if (max == min) { h = 0; // achromatic } else { if (max == nr) { h = (ng - nb) / d + (ng < nb ? 6 : 0); } else if (max == ng) { h = (nb - nr) / d + 2; } else if (max == nb) { h = (nr - ng) / d + 4; } h /= 6; } hsvh = h * 360; hsvs = s; hsvv = v; } }