How can i make the rendering process faster in JAVA? - java

I am making a software that has a screen filtering process. The code can already shift the colors and apply it to the frame the only problem is that It takes around 40-50 seconds for the filtered window to render. Is there any way I can make it faster? I would also like to ask which part of the code makes the process longer and time consuming. I will really appreciate the help. Thanks!
Here is my code.
public RedGreenFilter(int k1, int k2, int k3) {
this.k1 = k1;
this.k2 = k2;
this.k3 = k3;
}
#Override
public BufferedImage filter(final BufferedImage src, BufferedImage dst) {
if (dst == null) {
dst = this.createCompatibleDestImage(src, null);
}
// make sure the two images have the same size, color space, etc.
// MISSING !!! ???
DataBufferInt inBuffer = (DataBufferInt) src.getRaster().getDataBuffer();
DataBufferInt outBuffer = (DataBufferInt) dst.getRaster().getDataBuffer();
int[] inData = inBuffer.getData();
int[] outData = outBuffer.getData();
int simR = 0, simG = 0, simB = 0, mild = 10, moderate = 20, strong = 40;
float cIndex = MyDeficiency.cIndex;
float angle = MyDeficiency.angle;
float x = 0, y = 0, z = 0;
int prevIn = 0;
int prevOut = 0;
final int length = inData.length;
int corrG;
int corrR;
int corrB;
int SizeOfScreen = src.getHeight() * src.getWidth();
final int[] redArray = new int[SizeOfScreen];
final int[] blueArray = new int[SizeOfScreen];
final int[] greenArray = new int[SizeOfScreen];
for (int i = 0; i < SizeOfScreen; i++) {
final int in = inData[i];
if (in == prevIn) {
outData[i] = prevOut;
} else {
final int r = (0xff0000 & in) >> 16;
final int g = (0xff00 & in) >> 8;
final int b = 0xff & in;
// get linear rgb values in the range 0..2^15-1
final int r_lin = rgb2lin_red_LUT[r];
final int g_lin = rgb2lin_red_LUT[g];
final int b_lin = rgb2lin_red_LUT[b];
//http://publication.gunadarma.ac.id/bitstream/123456789/12232/1/Slide_Mahendra_54411250.pdf
float L = (17.8824f * r + 43.5161f * g + 4.11935f * b);
float M = (3.4565f * r + 27.1554f * g + 3.86714f * b);
float S = (0.02996f * r + 0.18431f * g + 1.46709f * b);
float dL = ( 0 * L + 2.02344f * M - 2.52581f * S);
float dM = ( 0 * L + 1 * M + 0 * S);
float dS = ( 0 * L + 0 * M + 1 * S);
float pL = ( 1 * L + 0 * M + 0 * S);
float pM = ( 0.494207f * L + 0 * M + 1.24827f * S);
float pS = ( 0 * L + 0 * M + 1 * S);
// simulated red and green are identical
// scale the matrix values to 0..2^15 for integer computations
// of the simulated protan values.
// divide after the computation by 2^15 to rescale.
// also divide by 2^15 asnd multiply by 2^8 to scale the linear rgb to 0..255
// total division is by 2^15 * 2^15 / 2^8 = 2^22
// shift the bits by 22 places instead of dividing
int r_blind = (int) (k1 * r_lin + k2 * g_lin) >> 22;
int b_blind = (int) (k3 * r_lin - k3 * g_lin + 32768 * b_lin) >> 22;
if (r_blind < 0) {
r_blind = 0;
} else if (r_blind > 255) {
r_blind = 255;
}
if (b_blind < 0) {
b_blind = 0;
} else if (b_blind > 255) {
b_blind = 255;
}
// convert reduced linear rgb to gamma corrected rgb
int red = lin2rgb_LUT[r_blind];
red = red >= 0 ? red : 256 + red; // from unsigned to signed
int blue = lin2rgb_LUT[b_blind];
blue = blue >= 0 ? blue : 256 + blue; // from unsigned to signed
if(k1 == 9591 && k2 == 23173){
x = dL;
y = dM;
z = dS;
}
if(k1 == 3683 && k2 == 29084){
x = pL;
y = pM;
z = pS;
}
//SEVERITY
//PROTAN
//normal to mild
if (angle > 0.70 && cIndex < 1.2){
simR = (int)(0.0809533970341018f * x -0.1305188419612954f * y + 0.11673398252989027f * z);
simG = (int)(-0.01025222049871863f * x + 0.054025275314902886f * y -0.11362003603724172f * z);
simB = (int)(-0.0003651971010795924f * x -0.004121801653701777f * y + 0.693511617368688f * z);
}
//mild to moderate
else if (angle > 0.70 && cIndex < 3 && cIndex > 1.20){
simR = (int)(0.0809533970341018f * x -0.1305188419612954f * y + 0.11673398252989027f * z) + mild;
simG = (int)(-0.01025222049871863f * x + 0.054025275314902886f * y -0.11362003603724172f * z);
simB = (int)(-0.0003651971010795924f * x -0.004121801653701777f * y + 0.693511617368688f * z);
}
//moderate to strong
else if (angle > 0.70 && cIndex < 4 && cIndex > 3){
simR = (int)(0.0809533970341018f * x -0.1305188419612954f * y + 0.11673398252989027f * z) + moderate;
simG = (int)(-0.01025222049871863f * x + 0.054025275314902886f * y -0.11362003603724172f * z);
simB = (int)(-0.0003651971010795924f * x -0.004121801653701777f * y + 0.693511617368688f * z);
}
//strong to super strong
else if (angle > 0.70 && cIndex > 4){
simR = (int)(0.0809533970341018f * x -0.1305188419612954f * y + 0.11673398252989027f * z) + strong;
simG = (int)(-0.01025222049871863f * x + 0.054025275314902886f * y -0.11362003603724172f * z);
simB = (int)(-0.0003651971010795924f * x -0.004121801653701777f * y + 0.693511617368688f * z);
}
//DEUTAN
//normal to mild
if (angle < 0.70 && angle > -65.00 && cIndex < 1.2){
simR = (int)(0.0809533970341018f * x -0.1305188419612954f * y + 0.11673398252989027f * z);
simG = (int)(-0.01025222049871863f * x + 0.054025275314902886f * y -0.11362003603724172f * z);
simB = (int)(-0.0003651971010795924f * x -0.004121801653701777f * y + 0.693511617368688f * z);
}
//mild to moderate
else if (angle < 0.70 && angle > -65.00 && cIndex < 3 && cIndex > 1.20){
simR = (int)(0.0809533970341018f * x -0.1305188419612954f * y + 0.11673398252989027f * z);
simG = (int)(-0.01025222049871863f * x + 0.054025275314902886f * y -0.11362003603724172f * z) + mild;
simB = (int)(-0.0003651971010795924f * x -0.004121801653701777f * y + 0.693511617368688f * z);
}
//moderate to strong
else if (angle < 0.70 && angle > -65 && cIndex < 4 && cIndex > 3){
simR = (int)(0.0809533970341018f * x -0.1305188419612954f * y + 0.11673398252989027f * z);
simG = (int)(-0.01025222049871863f * x + 0.054025275314902886f * y -0.11362003603724172f * z) + moderate;
simB = (int)(-0.0003651971010795924f * x -0.004121801653701777f * y + 0.693511617368688f * z) ;
}
//strong to super strong
else if (angle < 0.7 && angle > -65 && cIndex > 4){
simR = (int)(0.0809533970341018f * x -0.1305188419612954f * y + 0.11673398252989027f * z);
simG = (int)(-0.01025222049871863f * x + 0.054025275314902886f * y -0.11362003603724172f * z) + strong;
simB = (int)(-0.0003651971010795924f * x -0.004121801653701777f * y + 0.693511617368688f * z) ;
}
int errR = r - simR;
int errG = g - simG;
int errB = b - simB;
float errModR = (0 * errR + 0 * errG + 0 * errB);
float errModG = (0.7f * errR + 1 * errG + 0 * errB);
float errModB = (0.7f * errR + 0 * errG + 1 * errB);
corrR = (int) errModR + r;
corrG = (int) errModG + g;
corrB = (int) errModB + b;
/*
int corrR = 0;
int corrG = 0;
int corrB = 0;
*/
//MyDeficiency my = new MyDeficiency();
if(r == 255 && g == 255 && b == 255){
corrR = corrG = corrB = 255;
}
if(r == 0 && g == 0 && b == 0){
corrR = corrG = corrB = 0;
}
final int out = 0xff000000 | (corrR << 16) | (corrG << 8) | corrB ;
redArray[i] = (out >> 16) & 0xFF;
greenArray[i] = (out >> 8) & 0xFF;
blueArray[i] = (out >> 0) & 0xFF;
//System.out.println("r: " +" " + redArray[i]+ " "+ " g:" +" " +greenArray[i] +" " +"b:"+" "+ blueArray[i] + " " +"i:"+ " "+i);
//System.out.println("sR: " + (red << 16) + "sG: " +(red <<8)+ " sB: " + blue);
//outData[i] = out;
//prevIn = in;
//prevOut = out;
}
}
//System.out.println(SizeOfScreen);
Window w = new Window(null);
w.add(new JComponent() {
public void paintComponent(Graphics g) {
int alpha = 190; // 50% transparent
int pixelcounter = 0;
for(int i = 0; i < src.getHeight(); i++){
for(int j = 0; j < src.getWidth(); j++){
Color myColour = new Color(redArray[pixelcounter],greenArray[pixelcounter],blueArray[pixelcounter], alpha);
g.setColor(myColour);
g.fillRect(j,i,1,1);
pixelcounter++;
}
}
}
public Dimension getPreferredSize() {
return new Dimension(src.getWidth(), src.getHeight());
}
});
w.pack();
w.setLocationRelativeTo(null);
w.setAlwaysOnTop(true);
/**
* This sets the background of the window to be transparent.
*/
AWTUtilities.setWindowOpaque(w, false);
setTransparent(w);
w.setVisible(true);
//w.setVisible(false);
return dst;
}
}

Related

Filling Ellipse [Java]

I'm trying fill my Ellipse, the code works although I was wondering if there is a more efficient approach.
This will fill the first half of the circle given a percentage. And then it will fill the second half of the circle.
Let me know if you want to see any other functions. I was mainly concerned about filling it.
public void drawOrb() {
this.icon.drawSprite(this.xPos - this.icon.getWidth() / 2, 29 - this.icon.getHeight() / 2);
int radius = 19;
fillCircleAlpha(this.xPos, this.yPos, radius, 0, 35); // Draws a filled circle given a radius and alpha value.
Ellipse2D.Double circleToAvoid = drawCircle(this.xPos - radius, this.yPos - radius, radius * 2, 0, //The inner circle.
125);
Ellipse2D.Double circleToStart = drawCircle(this.xPos - (radius + 4), this.yPos - (radius + 4),
radius * 2 + 8, 0, 150); // The outer circle.
radius = 23;
int r2 = radius * radius;
int area = r2 << 2;
int rr = radius << 1;
for (int area2 = (int) (area * progress * 2.0), i = 0; i < area2; ++i) { //
int tx = i % rr;
int ty = i / rr;
if (!circleToAvoid.contains(circleToStart.getCenterX() + tx, circleToStart.getY() + ty) //If the index is inside the circle.
&& circleToStart.contains(circleToStart.getCenterX() + tx, circleToStart.getY() + ty)) {
drawPixelsWithOpacity(16777215, this.yPos + ty - radius, 1, 1, 75, this.xPos + tx); // Used to fill each pixel within the circle.
}
}
if (progress > 0.5) {
for (int area3 = (int) (area * (progress - 0.5) * 2.0), j = 0; j < area3; ++j) {
int tx2 = j % rr;
int ty2 = j / rr;
if (!circleToAvoid.contains(circleToStart.getCenterX() - tx2, circleToStart.getMaxY() - ty2)
&& circleToStart.contains(circleToStart.getCenterX() - tx2 - 1.0,
circleToStart.getMaxY() - ty2)) {
drawPixelsWithOpacity(16777215, (int) circleToStart.getMaxY() - ty2, 1, 1, 75,
(int) circleToStart.getCenterX() - tx2 - 1);
}
}
}
radius = 19;
drawCircle(this.xPos - (radius + 4), this.yPos - (radius + 4), radius * 2 + 8, 0, 150);
}
public static void drawPixelsWithOpacity(int color, int yPos, int pixelWidth, int pixelHeight, int opacityLevel, int xPos) {
if (xPos < topX) {
pixelWidth -= topX - xPos;
xPos = topX;
}
if (yPos < topY) {
pixelHeight -= topY - yPos;
yPos = topY;
}
if (xPos + pixelWidth > bottomX)
pixelWidth = bottomX - xPos;
if (yPos + pixelHeight > bottomY)
pixelHeight = bottomY - yPos;
int l1 = 256 - opacityLevel;
int i2 = (color >> 16 & 0xff) * opacityLevel;
int j2 = (color >> 8 & 0xff) * opacityLevel;
int k2 = (color & 0xff) * opacityLevel;
int k3 = width - pixelWidth;
int l3 = xPos + yPos * width;
if (l3 > pixels.length - 1) {
l3 = pixels.length - 1;
}
for (int i4 = 0; i4 < pixelHeight; i4++) {
for (int j4 = -pixelWidth; j4 < 0; j4++) {
int l2 = (pixels[l3] >> 16 & 0xff) * l1;
int i3 = (pixels[l3] >> 8 & 0xff) * l1;
int j3 = (pixels[l3] & 0xff) * l1;
int k4 = ((i2 + l2 >> 8) << 16) + ((j2 + i3 >> 8) << 8) + (k2 + j3 >> 8);
pixels[l3++] = k4;
}
l3 += k3;
}
}
public static Ellipse2D.Double drawCircle(final int x, final int y, final int diameter, final int color, final int opacity) {
final Ellipse2D.Double circle = new Ellipse2D.Double(x, y, diameter, diameter);
for (int i = 0; i < diameter; ++i) {
for (int i2 = 0; i2 < diameter; ++i2) {
if (circle.contains(i + x, i2 + y) && (!circle.contains(i + x - 1, i2 + y - 1) || !circle.contains(i + x + 1, i2 + y + 1) || !circle.contains(i + x - 1, i2 + y + 1) || !circle.contains(i + x + 1, i2 + y - 1))) {
drawPixelsWithOpacity(color, i2 + y, 1, 1, opacity, i + x);
}
}
}
return circle;
}

Rendering a Textured sphere in JOGL

I've been looking for hours now to find a good way to draw a textured sphere in JOGL. All I need is a point in the right direction or some code that works for someone. So far all I have been able to find is helloTexture (while it works, it is obviously not a sphere), would there be a way to convert this into a sphere or should i try my luck somewhere else?
I wrote this for you, it's untested since I modified it to work with GL_TRIANGLES, try and let me know
radius is the sphere radius, rings are the horizontal slices, sectors the vertical ones
private void createGeometry(float radius, short rings, short sectors) {
float R = 1f / (float)(rings - 1);
float S = 1f / (float)(sectors - 1);
short r, s;
float x, y, z;
points = new float[rings * sectors * 3];
normals = new float[rings * sectors * 3];
texcoords = new float[rings * sectors * 2];
int t = 0, v = 0, n = 0;
for(r = 0; r < rings; r++) {
for(s = 0; s < sectors; s++) {
x = (float) (Math.cos(2 * Math.PI * s * S) * Math.sin(Math.PI * r * R ));
y = (float) Math.sin(-Math.PI / 2 + Math.PI * r * R );
z = (float) (Math.sin(2 * Math.PI * s * S) * Math.sin(Math.PI * r * R ));
texcoords[t++] = s * S;
texcoords[t++] = r * R;
points[v++] = x * radius;
points[v++] = y * radius;
points[v++] = z * radius;
normals[n++] = x;
normals[n++] = y;
normals[n++] = z;
}
}
int counter = 0;
indices = new short[rings * sectors * 6];
for(r = 0; r < rings - 1; r++){
for(s = 0; s < sectors-1; s++) {
indices[counter++] = (short) (r * sectors + s);
indices[counter++] = (short) (r * sectors + (s + 1));
indices[counter++] = (short) ((r + 1) * sectors + (s + 1));
indices[counter++] = (short) ((r + 1) * sectors + (s + 1));
indices[counter++] = (short) (r * sectors + (s + 1));
indices[counter++] = (short) ((r + 1) * sectors + s);
}
}
}

java unreachable code error (Render class game development)

i have been working on a java game engine but my render keeps getting the unreachable code error.The error appears at the setPixels method.
public class Renderer {
private int width, height;
private byte[] pixels;
public Renderer(GameContainer gc){
width = gc.getWidth();
height = gc.getHeight();
pixels = ((DataBufferByte)gc.getWindow().getImage().getRaster().getDataBuffer()).getData();
}
public void setPixel(int x, int y, float a, float r, float g, float b){
if((x < 0 || x>= width || y < 0 || y>= height) || a == 0){
return;
int index = (x + y * width) * 4;
pixels[index] = (byte)((a * 255f) + 0.5f);
pixels[index + 1] = (byte)((b * 255f) + 0.5f);
pixels[index + 2] = (byte)((g * 255f) + 0.5f);
pixels[index + 3] = (byte)((r * 255f) + 0.5f);
}
}
public void clear(){
for(int x = 0; x < width; x++){
for(int y = 0; y < height; y++){
setPixel(x,y,1,0,1,1);
}
}
}
}
I think this is what you are trying to do?
Your if statement should not be enclosing all the statements in your function.
public void setPixel(int x, int y, float a, float r, float g, float b){
// Check for invalid values
if((x < 0 || x>= width || y < 0 || y>= height) || a == 0){
// Break out of function if invalid values detected
return;
}
// Update pixel
int index = (x + y * width) * 4;
pixels[index] = (byte)((a * 255f) + 0.5f);
pixels[index + 1] = (byte)((b * 255f) + 0.5f);
pixels[index + 2] = (byte)((g * 255f) + 0.5f);
pixels[index + 3] = (byte)((r * 255f) + 0.5f);
}
The return statement ends the execution of a method. In the event that the if statement is run in the code below, the method will hit the return and end before doing all the other stuff. You don't seem to need a return statement in setPixel since there isn't a need to end the method prematurely.
public void setPixel(int x, int y, float a, float r, float g, float b) {
if((x < 0 || x>= width || y < 0 || y>= height) || a == 0){
//return;
int index = (x + y * width) * 4;
pixels[index] = (byte)((a * 255f) + 0.5f);
pixels[index + 1] = (byte)((b * 255f) + 0.5f);
pixels[index + 2] = (byte)((g * 255f) + 0.5f);
pixels[index + 3] = (byte)((r * 255f) + 0.5f);
}
}

Java heightmap using lwjgl

I have coded a heightmap but it seems to lag the client. I just don't know how to increase the fps. I get about 3-6fps with the heightmap. Im using a quite large bmp for the heightmap, I think its 1024x1024. When i use a smaller on its fine, maybe im just not using the code effectively. Is there a better way to code this heightmap or did I just code it wrong. It is my first time I have worked on a heightmap. Thanks
public class HeightMap {
private final float xScale, yScale, zScale;
private float[][] heightMap;
private FloatBuffer vertices, normals, texCoords;
private IntBuffer indices;
private Vector3f[] verticesArray, normalsArray;
private int[] indicesArray;
private int width;
private int height;
public float getHeight(int x, int y) {
return heightMap[x][y] * yScale;
}
public HeightMap(String path, int resolution) {
heightMap = loadHeightmap("heightmap.bmp");
xScale = 1000f / resolution;
yScale = 8;
zScale = 1000f / resolution;
verticesArray = new Vector3f[width * height];
vertices = BufferUtils.createFloatBuffer(3 * width * height);
texCoords = BufferUtils.createFloatBuffer(2 * width * height);
for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++) {
final int pos = height * x + y;
final Vector3f vertex = new Vector3f(xScale * x, yScale * heightMap[x][y], zScale * y);
verticesArray[pos] = vertex;
vertex.store(vertices);
texCoords.put(x / (float) width);
texCoords.put(y / (float) height);
}
}
vertices.flip();
texCoords.flip();
normalsArray = new Vector3f[height * width];
normals = BufferUtils.createFloatBuffer(3 * width * height);
final float xzScale = xScale;
for (int x = 0; x < width; ++x) {
for (int y = 0; y < height; ++y) {
final int nextX = x < width - 1 ? x + 1 : x;
final int prevX = x > 0 ? x - 1 : x;
float sx = heightMap[nextX][y] - heightMap[prevX][y];
if (x == 0 || x == width - 1) {
sx *= 2;
}
final int nextY = y < height - 1 ? y + 1 : y;
final int prevY = y > 0 ? y - 1 : y;
float sy = heightMap[x][nextY] - heightMap[x][prevY];
if (y == 0 || y == height - 1) {
sy *= 2;
}
final Vector3f normal = new Vector3f(-sx * yScale, 2 * xzScale, sy * yScale).normalise(null);
normalsArray[height * x + y] = normal;
normal.store(normals);
}
}
normals.flip();
indicesArray = new int[6 * (height - 1) * (width - 1)];
indices = BufferUtils.createIntBuffer(6 * (width - 1) * (height - 1));
for (int i = 0; i < width - 1; i++) {
for (int j = 0; j < height - 1; j++) {
int pos = (height - 1) * i + j;
indices.put(height * i + j);
indices.put(height * (i + 1) + j);
indices.put(height * (i + 1) + (j + 1));
indicesArray[6 * pos] = height * i + j;
indicesArray[6 * pos + 1] = height * (i + 1) + j;
indicesArray[6 * pos + 2] = height * (i + 1) + (j + 1);
indices.put(height * i + j);
indices.put(height * i + (j + 1));
indices.put(height * (i + 1) + (j + 1));
indicesArray[6 * pos + 3] = height * i + j;
indicesArray[6 * pos + 4] = height * i + (j + 1);
indicesArray[6 * pos + 5] = height * (i + 1) + (j + 1);
}
}
indices.flip();
}
private float[][] loadHeightmap(String fileName) {
try {
BufferedImage img = ImageIO.read(ResourceLoader.getResourceAsStream(fileName));
width = img.getWidth();
height = img.getHeight();
float[][] heightMap = new float[width][height];
for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++) {
heightMap[x][y] = 0xFF & img.getRGB(x, y);
}
}
return heightMap;
} catch (IOException e) {
System.out.println("Nincs meg a heightmap!");
return null;
}
}
public void render() {
glEnableClientState(GL_NORMAL_ARRAY);
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glNormalPointer(0, normals);
glVertexPointer(3, 0, vertices);
glTexCoordPointer(2, 0, texCoords);
glDrawElements(GL_TRIANGLE_STRIP, indices);
glDisableClientState(GL_NORMAL_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY);
}
}
Sorry to bring up an old topic, however i see a lot of people ask this:
Use a display list, instead of re-making the heightmap every time.
TheCodingUniverse has a good tutorial on how to do this.

Converting from HSV (HSB in Java) to RGB without using java.awt.Color (disallowed on Google App Engine)

I figured I should post this question, even if I have already found a solution, as a Java implementation was not readily available when I searched for it.
Using HSV instead of RGB allows the generation of colors with the same saturation and brightness (something I wanted).
Google App Engine does not allow use of java.awt.Color, so doing the following to convert between HSV and RGB is not an option:
Color c = Color.getHSBColor(hue, saturation, value);
String rgb = Integer.toHexString(c.getRGB());
Edit: I moved my answer as described in the comment by Nick Johnson.
Ex animo, - Alexander.
I don't know anything about color math, but I can offer this alternative structure for the code, which tickles my aesthetic sense because it made it obvious to me how each of the 6 cases is just a different permutation of value, t and p. (Also I have an irrational fear of long if-else chains.)
public static String hsvToRgb(float hue, float saturation, float value) {
int h = (int)(hue * 6);
float f = hue * 6 - h;
float p = value * (1 - saturation);
float q = value * (1 - f * saturation);
float t = value * (1 - (1 - f) * saturation);
switch (h) {
case 0: return rgbToString(value, t, p);
case 1: return rgbToString(q, value, p);
case 2: return rgbToString(p, value, t);
case 3: return rgbToString(p, q, value);
case 4: return rgbToString(t, p, value);
case 5: return rgbToString(value, p, q);
default: throw new RuntimeException("Something went wrong when converting from HSV to RGB. Input was " + hue + ", " + saturation + ", " + value);
}
}
public static String rgbToString(float r, float g, float b) {
String rs = Integer.toHexString((int)(r * 256));
String gs = Integer.toHexString((int)(g * 256));
String bs = Integer.toHexString((int)(b * 256));
return rs + gs + bs;
}
You should use the HSBtoRGB implementation provided by Oracle, copying its source code into your project. java.awt.Color is open-source. The algorithms provided by Peter Recore and Yngling are not robust and will return illegal RGB values like "256,256,0" for certain inputs. Oracle's implementation is robust, use it instead.
Use ColorUtils which provides
HSLToColor(float\[\] hsl)
And
[RGBToHSL(int r, int g, int b, float\[\] hsl)]
Methods which are very easy to convert to each other!
For example:
float[] hsl = new float[]{1.5, 2.0, 1.5};
int color = ColorUtils.HSLToColor(hsl);
Now get the color
float[] hslStub = new float[3];
float[] hslFromColor = ColorUtils.colorToHSL(color, hslStub);
Now get the hsl
Here is the sourcecode.
The solution was found here: http://martin.ankerl.com/2009/12/09/how-to-create-random-colors-programmatically/
Martin Ankerl provides a good post on the subject, and provides Ruby script. For those too busy (or lazy) to implement it in Java, here's the one I did (I am sure it can be written more effectively, please feel free to comment):
public static String hsvToRgb(float hue, float saturation, float value) {
float r, g, b;
int h = (int)(hue * 6);
float f = hue * 6 - h;
float p = value * (1 - saturation);
float q = value * (1 - f * saturation);
float t = value * (1 - (1 - f) * saturation);
if (h == 0) {
r = value;
g = t;
b = p;
} else if (h == 1) {
r = q;
g = value;
b = p;
} else if (h == 2) {
r = p;
g = value;
b = t;
} else if (h == 3) {
r = p;
g = q;
b = value;
} else if (h == 4) {
r = t;
g = p;
b = value;
} else if (h <= 6) {
r = value;
g = p;
b = q;
} else {
throw new RuntimeException("Something went wrong when converting from HSV to RGB. Input was " + hue + ", " + saturation + ", " + value);
}
String rs = Integer.toHexString((int)(r * 255));
String gs = Integer.toHexString((int)(g * 255));
String bs = Integer.toHexString((int)(b * 255));
return rs + gs + bs;
}
My code for converting:
/**
* #param H
* 0-360
* #param S
* 0-100
* #param V
* 0-100
* #return color in hex string
*/
public static String hsvToRgb(float H, float S, float V) {
float R, G, B;
H /= 360f;
S /= 100f;
V /= 100f;
if (S == 0)
{
R = V * 255;
G = V * 255;
B = V * 255;
} else {
float var_h = H * 6;
if (var_h == 6)
var_h = 0; // H must be < 1
int var_i = (int) Math.floor((double) var_h); // Or ... var_i =
// floor( var_h )
float var_1 = V * (1 - S);
float var_2 = V * (1 - S * (var_h - var_i));
float var_3 = V * (1 - S * (1 - (var_h - var_i)));
float var_r;
float var_g;
float var_b;
if (var_i == 0) {
var_r = V;
var_g = var_3;
var_b = var_1;
} else if (var_i == 1) {
var_r = var_2;
var_g = V;
var_b = var_1;
} else if (var_i == 2) {
var_r = var_1;
var_g = V;
var_b = var_3;
} else if (var_i == 3) {
var_r = var_1;
var_g = var_2;
var_b = V;
} else if (var_i == 4) {
var_r = var_3;
var_g = var_1;
var_b = V;
} else {
var_r = V;
var_g = var_1;
var_b = var_2;
}
R = var_r * 255; // RGB results from 0 to 255
G = var_g * 255;
B = var_b * 255;
}
String rs = Integer.toHexString((int) (R));
String gs = Integer.toHexString((int) (G));
String bs = Integer.toHexString((int) (B));
if (rs.length() == 1)
rs = "0" + rs;
if (gs.length() == 1)
gs = "0" + gs;
if (bs.length() == 1)
bs = "0" + bs;
return "#" + rs + gs + bs;
}
Example of use on Android:
tv.setBackgroundColor(Color.parseColor((ColorOperations.hsvToRgb(100, 100, 57))));
The answer by #Peter Recore do not use rounding.
Probably somewhat more correct way to use it is to copy the content from java.awt.Color and this is how it looked in Java 6:
public static int HSBtoRGB(float hue, float saturation, float brightness) {
int r = 0, g = 0, b = 0;
if (saturation == 0) {
r = g = b = (int) (brightness * 255.0f + 0.5f);
} else {
float h = (hue - (float)Math.floor(hue)) * 6.0f;
float f = h - (float)java.lang.Math.floor(h);
float p = brightness * (1.0f - saturation);
float q = brightness * (1.0f - saturation * f);
float t = brightness * (1.0f - (saturation * (1.0f - f)));
switch ((int) h) {
case 0:
r = (int) (brightness * 255.0f + 0.5f);
g = (int) (t * 255.0f + 0.5f);
b = (int) (p * 255.0f + 0.5f);
break;
case 1:
r = (int) (q * 255.0f + 0.5f);
g = (int) (brightness * 255.0f + 0.5f);
b = (int) (p * 255.0f + 0.5f);
break;
case 2:
r = (int) (p * 255.0f + 0.5f);
g = (int) (brightness * 255.0f + 0.5f);
b = (int) (t * 255.0f + 0.5f);
break;
case 3:
r = (int) (p * 255.0f + 0.5f);
g = (int) (q * 255.0f + 0.5f);
b = (int) (brightness * 255.0f + 0.5f);
break;
case 4:
r = (int) (t * 255.0f + 0.5f);
g = (int) (p * 255.0f + 0.5f);
b = (int) (brightness * 255.0f + 0.5f);
break;
case 5:
r = (int) (brightness * 255.0f + 0.5f);
g = (int) (p * 255.0f + 0.5f);
b = (int) (q * 255.0f + 0.5f);
break;
}
}
return 0xff000000 | (r << 16) | (g << 8) | (b << 0);
}
Rounding here seems to be correct.
Using SWT you can use following code snippet:
RGB rgb = new RGB(r, g, b);
float[] hsbColor = rgb.getHSB();
rgb = new RGB(hsbColor[0], hsbColor[1], hsbColor[2]);
I know that this is an old question, but all the answers I've seen here multiply the hue with 6. This is wrong. I took a look at the Wikipedia article and there it says that you have to divide by 60.
Here is one which I tested written in Kotlin
fun hsvToRgb(hsv: FloatArray): IntArray {
val (hue, saturation, value) = hsv
val h: Int = (hue / 60).toInt()
val f = hue / 60 - h
val p = value * (1 - saturation)
val q = value * (1 - f * saturation)
val t = value * (1 - (1 - f) * saturation)
val rgb = when (h) {
0 -> floatArrayOf(value, t, p)
1 -> floatArrayOf(q, value, p)
2 -> floatArrayOf(p, value, t)
3 -> floatArrayOf(p, q, value)
4 -> floatArrayOf(t, p, value)
5, 6 -> floatArrayOf(value, p, q)
else -> throw Exception()
}.map { it * 255 }
val (r, g, b) = rgb
return intArrayOf(r.toInt(), g.toInt(), b.toInt())
}
Here my Java implementation
public static int[] hsvToRgb(float[] hsv) {
final float hue = hsv[0];
final float saturation = hsv[1];
final float value = hsv[2];
final int h = (int) hue / 60;
final float f = hue / 60 - h;
final float p = value * (1 - saturation);
final float q = value * (1 - f * saturation);
final float t = value * (1 - (1 - f) * saturation);
float[] rgb = switch (h) {
case 0 -> new float[]{value, t, p};
case 1 -> new float[]{q, value, p};
case 2 -> new float[]{p, value, t};
case 3 -> new float[]{p, q, value};
case 4 -> new float[]{t, p, value};
case 5, 6 -> new float[]{value, p, q};
default -> throw new IllegalStateException();
};
rgb[0] = rgb[0] * 255;
rgb[1] = rgb[1] * 255;
rgb[2] = rgb[2] * 255;
return new int[]{(int) rgb[0], (int) rgb[1], (int) rgb[2]};
}

Categories

Resources