com.jidesoft.utils.ColorUtils Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jide-oss Show documentation
Show all versions of jide-oss Show documentation
JIDE Common Layer (Professional Swing Components)
/*
* @(#)ColorUtils.java 9/19/2006
*
* Copyright 2002 - 2006 JIDE Software Inc. All rights reserved.
*/
package com.jidesoft.utils;
import javax.swing.plaf.ColorUIResource;
import java.awt.*;
/**
* Several useful methods for Color.
*/
public class ColorUtils {
/**
* Gets a derived color from an existing color. The derived color is either lighter or darker version of the given
* color with the same hue.
*
* @param color the given color.
* @param ratio the ratio. 0.5f if the same color. Any ratio greater than 0.5f will make the result color lighter.
* Smaller than 0.5f will make the color darker.
*
* @return the derived color.
*/
public static Color getDerivedColor(Color color, float ratio) {
if (color != null) {
float[] hsl = RGBtoHSL(color);
if (hsl[2] < 0.4) {
hsl[2] = 0.4f;
}
if (ratio > 0.5) {
hsl[2] += (1f - hsl[2]) * 2 * (ratio - 0.5);
}
else {
hsl[2] -= hsl[2] * 2 * (0.5 - ratio);
}
int colorRGB = HSLtoRGB(hsl);
return new ColorUIResource(colorRGB);
}
else {
return null;
}
}
/**
* Converts a color from RBG to HSL color space.
*
* @param colorRGB the Color.
*
* @return color space in HSL.
*/
public static float[] RGBtoHSL(Color colorRGB) {
float r, g, b, h, s, l; //this function works with floats between 0 and 1
r = colorRGB.getRed() / 256.0f;
g = colorRGB.getGreen() / 256.0f;
b = colorRGB.getBlue() / 256.0f;
// Then, minColor and maxColor are defined. Min color is the value of the color component with
// the smallest value, while maxColor is the value of the color component with the largest value.
// These two variables are needed because the Lightness is defined as (minColor + maxColor) / 2.
float maxColor = Math.max(r, Math.max(g, b));
float minColor = Math.min(r, Math.min(g, b));
// If minColor equals maxColor, we know that R=G=B and thus the color is a shade of gray.
// This is a trivial case, hue can be set to anything, saturation has to be set to 0 because
// only then it's a shade of gray, and lightness is set to R=G=B, the shade of the gray.
//R == G == B, so it's a shade of gray
if (r == g && g == b) {
h = 0.0f; //it doesn't matter what value it has
s = 0.0f;
l = r; //doesn't matter if you pick r, g, or b
}
// If minColor is not equal to maxColor, we have a real color instead of a shade of gray, so more calculations are needed:
// Lightness (l) is now set to it's definition of (minColor + maxColor)/2.
// Saturation (s) is then calculated with a different formula depending if light is in the first half of the second half. This is because the HSL model can be represented as a double cone, the first cone has a black tip and corresponds to the first half of lightness values, the second cone has a white tip and contains the second half of lightness values.
// Hue (h) is calculated with a different formula depending on which of the 3 color components is the dominating one, and then normalized to a number between 0 and 1.
else {
l = (minColor + maxColor) / 2;
if (l < 0.5) s = (maxColor - minColor) / (maxColor + minColor);
else s = (maxColor - minColor) / (2.0f - maxColor - minColor);
if (r == maxColor) h = (g - b) / (maxColor - minColor);
else if (g == maxColor) h = 2.0f + (b - r) / (maxColor - minColor);
else h = 4.0f + (r - g) / (maxColor - minColor);
h /= 6; //to bring it to a number between 0 and 1
if (h < 0) h++;
}
// Finally, H, S and L are calculated out of h, s and l as integers between 0 and 255 and "returned"
// as the result. Returned, because H, S and L were passed by reference to the function.
float[] hsl = new float[3];
hsl[0] = h;
hsl[1] = s;
hsl[2] = l;
return hsl;
}
/**
* Converts from HSL color space to RGB color.
*
* @param hsl the hsl values.
*
* @return the RGB color.
*/
public static int HSLtoRGB(float[] hsl) {
float r, g, b, h, s, l; //this function works with floats between 0 and 1
float temp1, temp2, tempr, tempg, tempb;
h = hsl[0];
s = hsl[1];
l = hsl[2];
// Then follows a trivial case: if the saturation is 0, the color will be a grayscale color,
// and the calculation is then very simple: r, g and b are all set to the lightness.
//If saturation is 0, the color is a shade of gray
if (s == 0) {
r = g = b = l;
}
// If the saturation is higher than 0, more calculations are needed again.
// red, green and blue are calculated with the formulas defined in the code.
// If saturation > 0, more complex calculations are needed
else {
//Set the temporary values
if (l < 0.5) temp2 = l * (1 + s);
else temp2 = (l + s) - (l * s);
temp1 = 2 * l - temp2;
tempr = h + 1.0f / 3.0f;
if (tempr > 1) tempr--;
tempg = h;
tempb = h - 1.0f / 3.0f;
if (tempb < 0) tempb++;
//Red
if (tempr < 1.0 / 6.0) r = temp1 + (temp2 - temp1) * 6.0f * tempr;
else if (tempr < 0.5) r = temp2;
else if (tempr < 2.0 / 3.0) r = temp1 + (temp2 - temp1) * ((2.0f / 3.0f) - tempr) * 6.0f;
else r = temp1;
//Green
if (tempg < 1.0 / 6.0) g = temp1 + (temp2 - temp1) * 6.0f * tempg;
else if (tempg < 0.5) g = temp2;
else if (tempg < 2.0 / 3.0) g = temp1 + (temp2 - temp1) * ((2.0f / 3.0f) - tempg) * 6.0f;
else g = temp1;
//Blue
if (tempb < 1.0 / 6.0) b = temp1 + (temp2 - temp1) * 6.0f * tempb;
else if (tempb < 0.5) b = temp2;
else if (tempb < 2.0 / 3.0) b = temp1 + (temp2 - temp1) * ((2.0f / 3.0f) - tempb) * 6.0f;
else b = temp1;
}
// And finally, the results are returned as integers between 0 and 255.
int result = 0;
result += ((int) (r * 255) & 0xFF) << 16;
result += ((int) (g * 255) & 0xFF) << 8;
result += ((int) (b * 255) & 0xFF);
return result;
}
static final float OFFSET_180 = 180f;
static final float OFFSET_100 = 100f;
public static int[] calculateDifferent(float[] from, float[] to) {
int[] diff = new int[3];
diff[0] = floatToInteger(from[0], to[0], OFFSET_180, true);
diff[1] = floatToInteger(from[1], to[1], OFFSET_100, false);
diff[2] = floatToInteger(from[2], to[2], OFFSET_100, false);
return diff;
}
public static float[] applyDifference(float[] from, int[] diff) {
float[] to = new float[3];
to[0] = integerToFloat(from[0], diff[0], OFFSET_180, true);
to[1] = integerToFloat(from[1], diff[1], OFFSET_100, false);
to[2] = integerToFloat(from[2], diff[2], OFFSET_100, false);
return to;
}
private static int floatToInteger(float f, float f2, float offset, boolean rotate) {
if (rotate) {
int i = (int) ((f2 - f) * 2 * offset);
if (i > offset) {
return i - (int) (2 * offset);
}
else if (i < -offset) {
return i + (int) (2 * offset);
}
else {
return i;
}
}
else {
if (f != 0.0f) {
return (int) ((f2 - f) * offset / f);
}
else {
return (int) ((f2 - f) * offset);
}
}
}
private static float integerToFloat(float f, int i, float offset, boolean rotate) {
if (rotate) {
float v = f + i / (2 * offset);
if (v < 0.0f) {
return v + 1.0f;
}
else if (v > 1.0f) {
return v - 1.0f;
}
else {
return v;
}
}
else {
if (i > 0) {
return f + (1.0f - f) * i / offset;
}
else {
return f + f * i / offset;
}
}
}
/**
* Simply calls new Color(color, hasalpha) for each color in colors and returns all of them.
*
* @param hasAlpha true to consider the alpha when creating the Color.
* @param colors the color value.
*
* @return the colors with alpha added.
*/
public static Color[] toColors(boolean hasAlpha, int... colors) {
Color[] result = new Color[colors.length];
for (int i = 0; i < colors.length; i++) {
result[i] = new Color(colors[i], hasAlpha);
}
return result;
}
/**
* Converts from a color to gray scale color.
*
* @param c a color.
*
* @return a color in gray scale.
*/
public static Color toGrayscale(Color c) {
int gray = (int) (c.getRed() * 0.3 + c.getGreen() * 0.59 + c.getBlue() * 0.11);
return new Color(gray, gray, gray);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy