001/* 002 * $Id: ColorUtilities.java 1496 2006-10-22 03:26:24Z gfx $ 003 * 004 * Dual-licensed under LGPL (Sun and Romain Guy) and BSD (Romain Guy). 005 * 006 * Copyright 2005 Sun Microsystems, Inc., 4150 Network Circle, 007 * Santa Clara, California 95054, U.S.A. All rights reserved. 008 * 009 * Copyright (c) 2006 Romain Guy <romain.guy@mac.com> 010 * All rights reserved. 011 * 012 * Redistribution and use in source and binary forms, with or without 013 * modification, are permitted provided that the following conditions 014 * are met: 015 * 1. Redistributions of source code must retain the above copyright 016 * notice, this list of conditions and the following disclaimer. 017 * 2. Redistributions in binary form must reproduce the above copyright 018 * notice, this list of conditions and the following disclaimer in the 019 * documentation and/or other materials provided with the distribution. 020 * 3. The name of the author may not be used to endorse or promote products 021 * derived from this software without specific prior written permission. 022 * 023 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 024 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 025 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 026 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 027 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 028 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 029 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 030 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 031 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 032 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 033 */ 034 035package org.jdesktop.swingx.graphics; 036 037import java.awt.Color; 038 039/** 040 * <p><code>ColorUtilities</code> contains a set of tools to perform 041 * common color operations easily.</p> 042 * 043 * @author Romain Guy <romain.guy@mac.com> 044 */ 045public class ColorUtilities { 046 private ColorUtilities() { 047 } 048 049 /** 050 * <p>Returns the HSL (Hue/Saturation/Luminance) equivalent of a given 051 * RGB color. All three HSL components are between 0.0 and 1.0.</p> 052 * 053 * @param color the RGB color to convert 054 * @return a new array of 3 floats corresponding to the HSL components 055 */ 056 public static float[] RGBtoHSL(Color color) { 057 return RGBtoHSL(color.getRed(), color.getGreen(), color.getBlue(), null); 058 } 059 060 /** 061 * <p>Returns the HSL (Hue/Saturation/Luminance) equivalent of a given 062 * RGB color. All three HSL components are between 0.0 and 1.0.</p> 063 * 064 * @param color the RGB color to convert 065 * @param hsl a pre-allocated array of floats; can be null 066 * @return <code>hsl</code> if non-null, a new array of 3 floats otherwise 067 * @throws IllegalArgumentException if <code>hsl</code> has a length lower 068 * than 3 069 */ 070 public static float[] RGBtoHSL(Color color, float[] hsl) { 071 return RGBtoHSL(color.getRed(), color.getGreen(), color.getBlue(), hsl); 072 } 073 074 /** 075 * <p>Returns the HSL (Hue/Saturation/Luminance) equivalent of a given 076 * RGB color. All three HSL components are between 0.0 and 1.0.</p> 077 * 078 * @param r the red component, between 0 and 255 079 * @param g the green component, between 0 and 255 080 * @param b the blue component, between 0 and 255 081 * @return a new array of 3 floats corresponding to the HSL components 082 */ 083 public static float[] RGBtoHSL(int r, int g, int b) { 084 return RGBtoHSL(r, g, b, null); 085 } 086 087 /** 088 * <p>Returns the HSL (Hue/Saturation/Luminance) equivalent of a given 089 * RGB color. All three HSL components are floats between 0.0 and 1.0.</p> 090 * 091 * @param r the red component, between 0 and 255 092 * @param g the green component, between 0 and 255 093 * @param b the blue component, between 0 and 255 094 * @param hsl a pre-allocated array of floats; can be null 095 * @return <code>hsl</code> if non-null, a new array of 3 floats otherwise 096 * @throws IllegalArgumentException if <code>hsl</code> has a length lower 097 * than 3 098 */ 099 public static float[] RGBtoHSL(int r, int g, int b, float[] hsl) { 100 if (hsl == null) { 101 hsl = new float[3]; 102 } else if (hsl.length < 3) { 103 throw new IllegalArgumentException("hsl array must have a length of" + 104 " at least 3"); 105 } 106 107 if (r < 0) r = 0; 108 else if (r > 255) r = 255; 109 if (g < 0) g = 0; 110 else if (g > 255) g = 255; 111 if (b < 0) b = 0; 112 else if (b > 255) b = 255; 113 114 float var_R = (r / 255f); 115 float var_G = (g / 255f); 116 float var_B = (b / 255f); 117 118 float var_Min; 119 float var_Max; 120 float del_Max; 121 122 if (var_R > var_G) { 123 var_Min = var_G; 124 var_Max = var_R; 125 } else { 126 var_Min = var_R; 127 var_Max = var_G; 128 } 129 if (var_B > var_Max) { 130 var_Max = var_B; 131 } 132 if (var_B < var_Min) { 133 var_Min = var_B; 134 } 135 136 del_Max = var_Max - var_Min; 137 138 float H, S, L; 139 L = (var_Max + var_Min) / 2f; 140 141 if (del_Max - 0.01f <= 0.0f) { 142 H = 0; 143 S = 0; 144 } else { 145 if (L < 0.5f) { 146 S = del_Max / (var_Max + var_Min); 147 } else { 148 S = del_Max / (2 - var_Max - var_Min); 149 } 150 151 float del_R = (((var_Max - var_R) / 6f) + (del_Max / 2f)) / del_Max; 152 float del_G = (((var_Max - var_G) / 6f) + (del_Max / 2f)) / del_Max; 153 float del_B = (((var_Max - var_B) / 6f) + (del_Max / 2f)) / del_Max; 154 155 if (var_R == var_Max) { 156 H = del_B - del_G; 157 } else if (var_G == var_Max) { 158 H = (1 / 3f) + del_R - del_B; 159 } else { 160 H = (2 / 3f) + del_G - del_R; 161 } 162 if (H < 0) { 163 H += 1; 164 } 165 if (H > 1) { 166 H -= 1; 167 } 168 } 169 170 hsl[0] = H; 171 hsl[1] = S; 172 hsl[2] = L; 173 174 return hsl; 175 } 176 177 /** 178 * <p>Returns the RGB equivalent of a given HSL (Hue/Saturation/Luminance) 179 * color.</p> 180 * 181 * @param h the hue component, between 0.0 and 1.0 182 * @param s the saturation component, between 0.0 and 1.0 183 * @param l the luminance component, between 0.0 and 1.0 184 * @return a new <code>Color</code> object equivalent to the HSL components 185 */ 186 public static Color HSLtoRGB(float h, float s, float l) { 187 int[] rgb = HSLtoRGB(h, s, l, null); 188 return new Color(rgb[0], rgb[1], rgb[2]); 189 } 190 191 /** 192 * <p>Returns the RGB equivalent of a given HSL (Hue/Saturation/Luminance) 193 * color. All three RGB components are integers between 0 and 255.</p> 194 * 195 * @param h the hue component, between 0.0 and 1.0 196 * @param s the saturation component, between 0.0 and 1.0 197 * @param l the luminance component, between 0.0 and 1.0 198 * @param rgb a pre-allocated array of ints; can be null 199 * @return <code>rgb</code> if non-null, a new array of 3 ints otherwise 200 * @throws IllegalArgumentException if <code>rgb</code> has a length lower 201 * than 3 202 */ 203 public static int[] HSLtoRGB(float h, float s, float l, int[] rgb) { 204 if (rgb == null) { 205 rgb = new int[3]; 206 } else if (rgb.length < 3) { 207 throw new IllegalArgumentException("rgb array must have a length of" + 208 " at least 3"); 209 } 210 211 if (h < 0) h = 0.0f; 212 else if (h > 1.0f) h = 1.0f; 213 if (s < 0) s = 0.0f; 214 else if (s > 1.0f) s = 1.0f; 215 if (l < 0) l = 0.0f; 216 else if (l > 1.0f) l = 1.0f; 217 218 int R, G, B; 219 220 if (s - 0.01f <= 0.0f) { 221 R = (int) (l * 255.0f); 222 G = (int) (l * 255.0f); 223 B = (int) (l * 255.0f); 224 } else { 225 float var_1, var_2; 226 if (l < 0.5f) { 227 var_2 = l * (1 + s); 228 } else { 229 var_2 = (l + s) - (s * l); 230 } 231 var_1 = 2 * l - var_2; 232 233 R = (int) (255.0f * hue2RGB(var_1, var_2, h + (1.0f / 3.0f))); 234 G = (int) (255.0f * hue2RGB(var_1, var_2, h)); 235 B = (int) (255.0f * hue2RGB(var_1, var_2, h - (1.0f / 3.0f))); 236 } 237 238 rgb[0] = R; 239 rgb[1] = G; 240 rgb[2] = B; 241 242 return rgb; 243 } 244 245 private static float hue2RGB(float v1, float v2, float vH) { 246 if (vH < 0.0f) { 247 vH += 1.0f; 248 } 249 if (vH > 1.0f) { 250 vH -= 1.0f; 251 } 252 if ((6.0f * vH) < 1.0f) { 253 return (v1 + (v2 - v1) * 6.0f * vH); 254 } 255 if ((2.0f * vH) < 1.0f) { 256 return (v2); 257 } 258 if ((3.0f * vH) < 2.0f) { 259 return (v1 + (v2 - v1) * ((2.0f / 3.0f) - vH) * 6.0f); 260 } 261 return (v1); 262 } 263}