/*
* Copyright 1996-2002 by Andruid Kerne. All rights reserved.
* CONFIDENTIAL. Use is subject to license terms.
*/
package ecologylab.generic;
import java.awt.Color;
/**
* Tools for manipulating color spaces.
*/
public class Palette
extends Debug
{
static float delta = .085f;
static final String colorNames[] =
{
"blue", "black", "cyan", "darkGray", "gray",
"green", "lightGray", "magenta", "orange",
"pink", "red", "white", "yellow",
};
static final Color colors[] =
{
Color.blue, Color.black, Color.cyan, Color.darkGray, Color.gray,
Color.green, Color.lightGray, Color.magenta, Color.orange,
Color.pink, Color.red, Color.white, Color.yellow,
};
Palette(){}
// generate complementary color
public static int Complement(Color c)
{
float hsb[] = new float[3];
Color.RGBtoHSB (c.getRed(), c.getGreen(), c.getBlue(), hsb);
hsb[0] += .5f;
if (hsb[0] > 1)
hsb[0] -= 1;
return Color.HSBtoRGB(hsb[0], hsb[1], hsb[2]);
}
public static Color complement(Color c)
{
return new Color(Complement(c));
}
// return 2 colors delta away from the input
public static void Split(Color input, int[] output)
{
float hsb[] = new float[3];
float newHue;
Color.RGBtoHSB (input.getRed(), input.getGreen(), input.getBlue(),
hsb);
newHue = (hsb[0] + delta) % 1.0f;
output[0] = Color.HSBtoRGB(newHue, hsb[1], hsb[2]);
newHue = (hsb[0] - delta) % 1.0f;
output[1] = Color.HSBtoRGB(newHue, hsb[1], hsb[2]);
}
public static Color hsvColor(float h, float s, float v)
{
int rgb[] = rgb(h,s,v);
Color result = new Color(rgb[0], rgb[1], rgb[2]);
//println("Palette.hsvColor("+h+","+s+","+v+") = " + result);
return result;
}
// hsv to rgb
public static int[] rgb(float hf, float s, float v)
{
float r=0,g=0,b=0;
float h = hf * 6;
if (s == 0)
{
r = v;
g = v;
b = v;
}
else
{
int i = (int) Math.floor(h);
float f = h - i;
float p = v * (1 - s);
float q = v * (1 - s*f);
float t = v * (1 - s*(1-f));
switch (i)
{
case 0:
r = v;
g = t;
b = p;
break;
case 1:
r = q;
g = v;
b = p;
break;
case 2:
r = p;
g = v;
b = t;
break;
case 3:
r = p;
g = q;
b = v;
break;
case 4:
r = t;
g = p;
b = v;
break;
case 5:
r = v;
g = p;
b = q;
break;
}
}
int rgb[] = new int[3];
rgb[0] = (int) (r * 255);
rgb[1] = (int) (g * 255);
rgb[2] = (int) (b * 255);
// System.out.println("rgb( " +hf+","+s+","+v+" => "+
// rgb[0]+","+rgb[1]+","+rgb[2]);
return rgb;
}
// hsv to rgb
public static void rgb(float hf, float s, float v, float[] result)
{
float r=0,g=0,b=0;
float h = hf * 6;
if (s == 0)
{
r = v;
g = v;
b = v;
}
else
{
int i = (int) Math.floor(h);
float f = h - i;
float p = v * (1 - s);
float q = v * (1 - s*f);
float t = v * (1 - s*(1-f));
switch (i)
{
case 0:
r = v;
g = t;
b = p;
break;
case 1:
r = q;
g = v;
b = p;
break;
case 2:
r = p;
g = v;
b = t;
break;
case 3:
r = p;
g = q;
b = v;
break;
case 4:
r = t;
g = p;
b = v;
break;
case 5:
r = v;
g = p;
b = q;
break;
}
}
result[0] = r;
result[1] = g;
result[2] = b;
}
// from rgb to hsv
public static float[] hsv(Color c)
{
// note that when saturation=0, hue is undefined (we'll set to 0)
float hsv[] = new float[3];
Color.RGBtoHSB (c.getRed(), c.getGreen(), c.getBlue(), hsv);
float f = Math.min(hsv[1],.999f);
hsv[1] = f;
f = Math.min(hsv[2],.999f);
hsv[2] = f;
// System.out.println("hsv("+c+")="+hsv[0]+","+hsv[1]+","+hsv[2]);
return hsv;
}
public static float[] myHsv(Color c)
{
return myHsv(c.getRed(), c.getGreen(), c.getBlue());
}
public static float[] myHsv(int ri, int gi, int bi)
{
float r = ((float) ri) / 255,
g = ((float) gi) / 255,
b = ((float) bi) / 255;
float h, s;
int isMax; // 0 red, 1 green, 2 blue
// nb: ties don't effect value calculation
// ties here don't effect hue calculation due to code below
// ties aren't effecting sat calcuation -- seems weak,
// but actually, photoshop seems that way, too
float max;
float min = Math.min(Math.min(r,g), b);
if (r >= b)
{
if (r >= g)
{
max = r; // perhaps r==b or r==g
isMax = 0;
}
else // perhaps r==b; g is true max
{
max = g;
isMax = 1;
}
}
else
{
if (g >= b)
{
max = g; // perhaps g==b
isMax = 1;
}
else
{
max = b; // b is true max
isMax = 2;
}
}
float delta = max - min;
// calculate saturation
if (max == 0)
s = 0;
else
s = delta / max; // (s == 0) also if delta = 0
// calculate hue
if (s == 0)
h = (float) Math.random(); // hue is undefined when sat == 0
else
{
// red = 0 yellow = 60 (1) green = 120 (2)
// cyan= 180 (3) blue = 240 (4) magenta = 300 (5)
// scale of 0 to 6, intitally
switch (isMax)
{
case 0: // red is max
if (r == b)
h = 5; // pure magenta
else if (r == g)
h = 1; // pure yellow
else
h = (g-b) / delta; // between yellow & magenta
break;
case 1: // green is max
if (g == b)
h = 3; // pure cyan
else
h = 2 + (b-r) / delta; // between cyan & yellow
break;
default: // case 2: blue is max
h = 4 + (r-g) / delta; // between magenta & cyan
}
h = h * 60;
if (h < 0)
h += 360;
h = h / 360;
}
float hsv[] = {h, s, max};
// System.out.println("myHsv("+r+","+g+","+b+")="+
// hsv[0]+","+hsv[1]+","+hsv[2]);
return hsv;
}
public static float hue(Color c) { return myHsv(c)[0]; }
public static float sat(Color c) { return myHsv(c)[1]; }
public static float value(Color c) { return myHsv(c)[2]; }
public static Color value(Color c, float newValue)
{
float hsv[] = myHsv(c);
return Color.getHSBColor(hsv[0], hsv[1], newValue);
}
public static Color nearby(Color c, int HSorB, float factor)
{
float hsb[] = new float[3], changer;
// ??? could perhaps make it smaller w shifts and &&
Color.RGBtoHSB(c.getRed(), c.getGreen(), c.getBlue(), hsb);
// System.out.println("Palette.nearby() " + hsb);
changer = (hsb[HSorB] + MathTools.pM(MathTools.randGain(.35f), factor)
+ 1.0f)
% 1.0f;
hsb[HSorB] = changer;
return Color.getHSBColor(hsb[0], hsb[1], hsb[2]);
}
public static Color hsb(float hue, float saturation, float brightness)
{ return new Color(Color.HSBtoRGB(hue, saturation, brightness)); }
static public Color hexToColor(String s)
{
Color result = Color.white;
boolean change = false;
for (int i=0; i!=colors.length; i++)
if (s.equalsIgnoreCase(colorNames[i]))
{
result = colors[i];
change = true;
break;
}
if (!change)
{
int j = s.indexOf("#") + 1;
if (j > -1)
{
s = s.substring(j);
result = new Color(Integer.parseInt(s,16));
}
}
return result;
}
// { return Color.getHSBColor(hue, saturation, brightness); }
}