Create random shapes - java

I have declared my variables to get random values with SecureRandom class.
Inside my paintComponent method I have a for loop in case to creating many random shapes.
If the Random value equals to zero, draw a rectangle shape else draw an oval.
When I run my project I get only one shape because all my variables are outside of my loop.
Any hints please how to achieve that scenario ( to create many random shapes ) ?
Thanks.
My declarations :
SecureRandom RC = new SecureRandom();
int r = RC.nextInt();
int g2 = RC.nextInt();
int b = RC.nextInt();
int cl = (r + g2 + b) / 3;
int choice = RC.nextInt(2);
int x = RC.nextInt(230);
int y = RC.nextInt(250);
int w = RC.nextInt(115);
int h = RC.nextInt(125);
My paintComponent method :
for(int i = 1; i <= 10; i++)
{
super.paintComponent(g);
Color mc = new Color(cl);
if(choice == 0)
{
g.setColor(mc);
g.fillRect(x, y, w, h);
}
else
{
g.setColor(mc);
g.fillOval(x, y, w, h);
}
}

When I run my project I get only one shape because all my variables are outside of my loop.
That's correct. You need to call choice = RC.nextInt(2); inside the loop, and based on the value you get back, create either a new oval or rectangle.
It would probably be a good idea (although not strictly necessary) to write separate functions for creating random ovals and rectangles. That way your loop doesn't have to be cluttered with this code.

You need to place all the variables you are using to create your random shape into your for loop so that after each iteration of the for-loop you create a new random value for each variable. Simply take all your variables that you need and place them inside the for-loop that will only be used inside the for-loop. Any variable you want to be the same throughout, you initialize outside before the for-loop.
The following code creates a completely random rectangle or oval each iteration
for(int i = 1; i <= 10; i++)
{
int r = RC.nextInt();
int g2 = RC.nextInt();
int b = RC.nextInt();
int cl = (r + g2 + b) / 3;
int x = RC.nextInt(230);
int y = RC.nextInt(250);
int w = RC.nextInt(115);
int h = RC.nextInt(125);
super.paintComponent(g);
Color mc = new Color(cl);
int choice = RC.nextInt(2);
if(choice == 0)
{
g.setColor(mc);
g.fillRect(x, y, w, h);
}
else
{
g.setColor(mc);
g.fillOval(x, y, w, h);
}
}

Related

Using for loop to make multiple drawLine shapes [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 4 years ago.
Improve this question
I am making a star using a draw line. I want to run a for loop to expand a star into multiple stars in a grid-like pattern. I am fairly new to java and could use some help with my code. The gride pattern that I would like the stars to open up too isn't too specific as far as columns x rows go. even making 6 stars or 9 stars is fine, as long as they are in a grid-like pattern.
So far, I have the star drawn with drawLine. At one point I got two stars but they were to close to each other. When I run the code it looks like I have a whole bunch of stars sort of staggered on top of each other and being able to get two stars on Star Field, I would like to get more in such 5x6 pattern or something close. I believe I might be having a hard time computing the math in the for loops to get this to happen.
Should I run, multiple nested for loops or is there a way to do this with using a minimal amount of for loops?
public static void drawFlag(int stars, int stripes, java.awt.Graphics
g, int x, int y, int width, int height) {
// Sets backround rectangle color to white
g.setColor(Color.WHITE);
g.fillRect(x, y, width, height);
// Draw filled red rectangles *stripes*
int stripeHeight = height/stripes;
g.setColor(Color.RED);
int lastStripeDrawnY = 0;
// For loop runs red stripes
for (int i = y; i < y + height - 2*stripeHeight; i = i + 2*stripeHeight)
{
g.fillRect(x, i, width, stripeHeight);
lastStripeDrawnY = i;
}
// expands strips across the rectangle
int lastStripeY = lastStripeDrawnY+2*stripeHeight;
int lastStripeHeight = y + height - lastStripeY;
if (stripes%2 != 0) {
g.fillRect(x, lastStripeY, width, lastStripeHeight);
}
int stars1 = 15;
for (int cols = 1; cols <= stars1; cols++) {
int rows = stars1/cols;
if (cols > rows && cols <2*rows && cols*rows == stars1) {
}
}
// Draws the starField
int numberOfRedStripes = (int)Math.ceil(stripes/2.0);
int starFieldHeight = numberOfRedStripes*stripeHeight;
int starFieldWidth = starFieldHeight*width/height;
g.setColor(Color.BLUE);
g.fillRect(x, y, starFieldWidth, starFieldHeight);
for (int x1 = 0; x1+100 <+ starFieldWidth-5; x1++) {
if(x1/5*4 == stars) {
drawStar(g,x1,y,50);
for(int y1 = 0; y1 <=starFieldHeight-5;y1++) {
if(y1/4*2 == stars) {
drawStar(g,x,y1,50);
}
}
}
}
}
// drawLine the star
public static void drawStar(java.awt.Graphics g, int x, int y, int size)
{
g.setColor(Color.WHITE);
g.drawLine(x+size/2, y+size/6, x+4*size/5, y+5*size/6);
g.drawLine(x+4*size/5,y+5*size/6, x+size/6, y+2*size/5);
g.drawLine(x+size/6, y+2*size/5, x+5*size/6, y+2*size/5);
g.drawLine(x+5*size/6, y+2*size/5, x+size/5, y+5*size/6);
g.drawLine(x+size/5, y+5*size/6, x+size/2, y+size/6);
}
}
Expand one star into a checkered grid-like pattern.
There are a number of ways you can approach this problem, you can, as you've started, simply try and build each star individually based on the required x/y position.
You could make a single star that was always at 0x0 and translate the Graphics context to the desire x/y position
Or, you could take advantage of the Shape API.
This allows you to define a self contained object which describes the shape you are trying to create.
public class StarShape extends Path2D.Double {
public StarShape(double size) {
double mid = size / 2d;
moveTo(mid, 0);
lineTo((size * 0.6d), (size * 0.4d));
lineTo(size, (size * 0.4d));
lineTo((size * 0.72d), (size * 0.58d));
lineTo((size * 0.85d), size);
lineTo((size * 0.5d), (size * 0.72d));
lineTo((size * 0.2), size);
lineTo((size * 0.325d), (size * 0.58d));
lineTo(0, (size * 0.4d));
lineTo((size * 0.4d), (size * 0.4d));
closePath();
}
}
There are lots of side benefits to this, but the immediate benefit is that it's "paintable". You can pass an instance of it directly to Graphics2D and have it painted and/or filled based on your needs.
Now, with that in hand, you can do something like...
public class TestPane extends JPanel {
private StarShape star;
private double starSize = 10;;
public TestPane() {
star = new StarShape(starSize);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
double y = 0;
for (int yIndex = 0; yIndex < getHeight() / starSize; yIndex++) {
double x = 0;
for (int xIndex = 0; xIndex < getWidth() / starSize; xIndex++) {
AffineTransform at = AffineTransform.getTranslateInstance(x, y);
PathIterator path = star.getPathIterator(at);
GeneralPath p = new GeneralPath();
p.append(path, true);
g2d.fill(p);
x += starSize;
}
y += starSize;
}
g2d.dispose();
}
}
The reason I'd prefer this method, is it doesn't affect the origin of the original starShape. You could also use the technique to cache the results, so you're not repeatedly doing it in the paintComponent method.
You could also do something like...
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
double y = 0;
for (int yIndex = 0; yIndex < getHeight() / starSize; yIndex++) {
double x = 0;
for (int xIndex = 0; xIndex < getWidth() / starSize; xIndex++) {
Graphics2D starg = (Graphics2D) g2d.create();
starg.translate(x, y);
starg.fill(star);
starg.dispose();
x += starSize;
}
y += starSize;
}
g2d.dispose();
}
Which changes the origin of the Graphics context instead or something like...
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
double xCount = getWidth() / starSize;
for (int yIndex = 0; yIndex < getHeight() / starSize; yIndex++) {
for (int xIndex = 0; xIndex < getWidth() / starSize; xIndex++) {
g2d.fill(star);
star.transform(AffineTransform.getTranslateInstance(starSize, 0));
}
star.transform(AffineTransform.getTranslateInstance(-(starSize) * xCount, starSize));
}
g2d.dispose();
}
which changes the origin of the star itself.
Personally, I prefer not to affect the original and instead simply change the context in how it's painted, but which method you use will come down to your needs.
Okay, that might seem like a lot of work for little gain, but the Shapes API is extremely powerful. Because it's point based (instead of pixel based), it can be more easily resized, without generating pixilation. It's very simple to rotate, through the use of AffineTransform and makes for a much simpler point of re-use.
Want to make the stars bigger? Simply change starStar, for example...
private double starSize = 50;
and the API takes care of the rest...
I used your drawStar() function and built this StarPanel. Try it and see if it gives you some hints for what you are trying to achieve.
Note that I removed g.setColor(Color.WHITE); line from your drawStar() function. We need to be careful when we set color of Graphics object. In many cases, this is the reason why we don't see what we draw.
import javax.swing.JFrame;
import javax.swing.JPanel;
import java.awt.Color;
import java.awt.Graphics;
public class StarPanel extends JPanel
{
private int xStarting;
private int yStarting;
private int numberOfRows;
private int numberOfColumns;
private int xDisplacement;
private int yDisplacement;
public StarPanel(int xStarting, int yStarting,
int numberOfRows, int numberOfColumns,
int xDisplacement, int yDisplacement)
{
this.xStarting = xStarting;
this.yStarting = yStarting;
this.numberOfRows = numberOfRows;
this.numberOfColumns = numberOfColumns;
this.xDisplacement = xDisplacement;
this.yDisplacement = yDisplacement;
}
public static void main(String[] args)
{
StarPanel starPanel = new StarPanel(50, 50, 5, 6, 75, 75);
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(starPanel);
frame.setBounds(300, 200, 500, 600);
frame.setVisible(true);
}
#Override
protected void paintComponent(Graphics g)
{
super.paintComponent(g);
for (int row = 0; row < numberOfRows; row++) {
for (int column = 0; column < numberOfColumns; column++) {
drawStar(g, xStarting + (row * xDisplacement), yStarting + (column * yDisplacement), 50);
}
}
}
// drawLine the star
public static void drawStar(java.awt.Graphics g, int x, int y, int size)
{
g.drawLine(x+size/2, y+size/6, x+4*size/5, y+5*size/6);
g.drawLine(x+4*size/5,y+5*size/6, x+size/6, y+2*size/5);
g.drawLine(x+size/6, y+2*size/5, x+5*size/6, y+2*size/5);
g.drawLine(x+5*size/6, y+2*size/5, x+size/5, y+5*size/6);
g.drawLine(x+size/5, y+5*size/6, x+size/2, y+size/6);
}
}

Java Code not working. Using loops to draw stripes on the US Flag

I am attempting to draw the US flag using java. I have pretty much done all this coding using lots of variables. It should be at least displaying the stripes, blue box, and the stars(ovals in this case). However, when I run the code through the compiler, and run it, all it displayes is a white background with a red stripe on the top. Could I please receive some help to see where my error is? I have tried everything.
Here is the code:
import javax.swing.JFrame;
import javax.swing.JPanel;
import java.awt.Graphics;
import java.awt.Color;
public class UsFlag extends JPanel {
int w = getWidth();
int h = getHeight();
int numberStripes = 13;
int numStarCol = 8;
int numStarRow = 6;
int stripeHeight = h/numberStripes;
int boxWidth = (int)(w*0.4);
int boxHeight = 7 * stripeHeight;
int starWidth = boxWidth/numStarCol;
int starHeight = boxHeight/numStarRow;
/*public UsFlag() {
//ask user to enter number of stripes, star columns, and star rows
}*/
#Override
public void paintComponent(Graphics g) {
int w = getWidth();
int h = getHeight();
//Background
g.setColor(Color.RED);
g.fillRect(0, 0, w, h);
//Stripes
g.setColor(Color.WHITE);
for (int i = 0; i < numberStripes; i += 1) {
g.fillRect(0,stripeHeight, w, stripeHeight);
stripeHeight = stripeHeight + 45;
}
//Blue Rect
g.setColor(Color.BLUE);
g.fillRect(0, 0, boxWidth, boxHeight);
//stars
int y = 0;
int x = 0;
for (int j = 0; j < numStarRow; j++){
for (int i = 0; i < numStarCol; i++){
g.setColor(Color.WHITE);
g.fillOval(5, 5, starWidth, starHeight);
x += starWidth;
}
y += starHeight;
x = 0;
}
}
public static void main(String[] args) {
JFrame window = new JFrame();
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.setSize(400, 400);
window.setContentPane(new UsFlag());
window.setVisible(true);
}
}
The first two parameters for the fillRect() method and the fillOval() method are considered coordinates (x & y) for the object you want to paint. This means that for x you need to place a integer pixel value as to where you want the Left edge of the object is to Start being painting from along the horizontal plain, and for y you need to place a integer pixel value as to where you want the Top edge of the object is to Start being painting from along the vertical plain. For fillRect() for example:
g.fillRect(20, 20, 100, 30);
The other two parameters are for the Width (w) and Height (h) in pixels of the object to paint. Use the the variable i from your for loop (y = i + 30; for example) to draw objects below one another. Read this for more information.

How to determine the coordinates of the next rectangle on JPanel

i have an arraylist RecArray of objects with each object containing two int values, one for the width and for the height of a rectangle. Each rectangle's height and width are a multiple of ten. the rectangles have to be passed on to the surface as in the given order in RecArray from left to right and from top to bottom. my problem is i can not find the x,y coordinates of the next rectangle. what im trying to do is, starting at the coordinate (0,0) i generate the first rectangle, add it to an arraylist RecList. Then i set the x and y coordinates. x becomes x = x+RecArray.get(0).getLength1() + 1. if x is greater than the width of the jpanel surface then it becomes 0 and y becomes y = y + 10 . starting from the second object in the RecArray i try to generate rectangles with the given coordinates and width&height. Then i try to compare them with all the previous rectangles to see if there is any overlapping. if there is no overlapping, the rectangle will be drawn, if there is overlapping, the x coordinate of the rec becomes x = RecList.get(j).width+1 and if that exceeds the width x becomes 0 and y is y=y+10. Then i regenate the current rectangle with the new coordinates and compare with the other rectangles in RecList again till i find the right spot for the current rectangle.ive been dealing with that issue for the last 5 days and am really fed up now. i would greatly appreciate any tipps. and Please be patient with me. im still learning programming.
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
Rectangle rec = new Rectangle(x, y, RecArray.get(0).getWidth(),
RecArray.get(0).getHeight());
RecList.add(rec);
recPaint(g2,RecArray.get(0));
x = x + RecArray.get(0).getWidth() + 1;
int i;
for (i = 1; i < RecArray.size(); i++) {
if (x >= this.getArea().getWidth()) {
x = 0;
y = y + 10;
}
Rectangle rec1 = new Rectangle(x, y, RecArray.get(i)
.getWidth(), RecArray.get(i).getheight());
for (int j= 0; j < RecList.size(); j++) {
if (!recIntersect(rec1, RecList.get(j))) {
RecList.add(rec1);
recPaint(g2,RecArray.get(i));
break;
}
else {
x = RecList.get(j).width;
if (x >= this.getFlaeche().getLength1()) {
x = 0;
y = y + 10;
}
rec1 = new Rectangle(x, y,RecArray.get(i). .getWidth(),
RecArray.get(i).getHeight());
}
x = x + RecArray.get(i).getWidth();
}
//With this method using the given rec parameter a rectangle will be drawn on the g2 and filled in blue colour
private void recPaint (Graphics2D g2, RecType rec){
g2.setColor(Color.BLUE);
g2.fillRect(x, y, rec.getWidth(),
rec.getLength2());
g2.setColor(Color.BLACK);
g2.drawRect(x, y, rec.getHeight(),
rec.getLength2());
}
// returns true, if two rectangles overlap
private boolean recIntersect(Rectangle rec1, Rectangle rec2) {
if( rec1.intersects(rec2)){
return true;
}
return false;
}
Edit: apparently i haven't stated clearly what my problem is. my problem is, that the way i generate (x,y) coordinates of the rectangles is obviously wrong. the way my algorithm works doesnt get the results i want. i want my rectangles to be placed neatly next to/above/below each other WITHOUT overlapping, which is not the case.
Separate out your List of Rectangles. Calculate the X, Y coordinates once.
Since I didn't have your object class, I used the Dimension class, which holds a width and a length. I used the Rectangle class to hold the objects that will eventually be drawn in your Swing GUI.
Divide and conquer. Separate out your GUI model, view, and controller(s). This way, you can focus on one piece of the puzzle at a time.
Here are the results of my test code when I ran it with a drawing area of 500, 400.
java.awt.Rectangle[x=0,y=0,width=100,height=100]
java.awt.Rectangle[x=100,y=0,width=20,height=10]
java.awt.Rectangle[x=120,y=0,width=40,height=20]
java.awt.Rectangle[x=160,y=0,width=60,height=40]
java.awt.Rectangle[x=220,y=0,width=80,height=60]
java.awt.Rectangle[x=300,y=0,width=20,height=10]
java.awt.Rectangle[x=320,y=0,width=120,height=110]
Here are the results of my test code when I ran it with a drawing area of 200, 200.
java.awt.Rectangle[x=0,y=0,width=100,height=100]
java.awt.Rectangle[x=100,y=0,width=20,height=10]
java.awt.Rectangle[x=120,y=0,width=40,height=20]
java.awt.Rectangle[x=0,y=100,width=60,height=40]
java.awt.Rectangle[x=60,y=100,width=80,height=60]
java.awt.Rectangle[x=140,y=100,width=20,height=10]
And here's the code. I fit rectangles on the X axis until I can't fit another rectangle. Then I add the maximum height to Y, reset the X to zero, reset the maximum height and fit the next row of rectangles.
Create test applications like I did here and make sure that you can create the GUI model long before you create the GUI view and GUI controller.
package com.ggl.testing;
import java.awt.Dimension;
import java.awt.Rectangle;
import java.util.ArrayList;
import java.util.List;
public class CalculatingRectangles {
public static void main(String[] args) {
CalculatingRectangles calculatingRectangles = new CalculatingRectangles();
Dimension drawingArea = new Dimension(200, 200);
List<Dimension> dimensions = new ArrayList<>();
dimensions.add(new Dimension(100, 100));
dimensions.add(new Dimension(20, 10));
dimensions.add(new Dimension(40, 20));
dimensions.add(new Dimension(60, 40));
dimensions.add(new Dimension(80, 60));
dimensions.add(new Dimension(20, 10));
dimensions.add(new Dimension(120, 110));
List<Rectangle> rectangles = calculatingRectangles
.calculatingRectangles(drawingArea, dimensions);
System.out.println(displayRectangles(rectangles));
}
private static String displayRectangles(List<Rectangle> rectangles) {
StringBuilder builder = new StringBuilder();
for (Rectangle r : rectangles) {
builder.append(r);
builder.append(System.getProperty("line.separator"));
}
return builder.toString();
}
public List<Rectangle> calculatingRectangles(Dimension drawingArea,
List<Dimension> dimensions) {
int width = drawingArea.width;
int height = drawingArea.height;
int x = 0;
int y = 0;
int index = 0;
int maxHeight = 0;
boolean hasRoom = dimensions.size() > index;
List<Rectangle> rectangles = new ArrayList<>();
while (hasRoom) {
Dimension d = dimensions.get(index);
maxHeight = Math.max(maxHeight, d.height);
if ((x + d.width) <= width && (y + maxHeight) <= height) {
Rectangle r = new Rectangle(x, y, d.width, d.height);
x += d.width;
rectangles.add(r);
index++;
if (index >= dimensions.size()) {
hasRoom = false;
}
} else {
y += maxHeight;
if (y > height) {
hasRoom = false;
}
x = 0;
}
}
return rectangles;
}
}

Single array to store multiple variables in each element

EDIT: to clarify, one of my requirements is to use a single array.
I am having trouble storing multiple variables to a single element in an array. We are creating a really simple program to mimic Microsoft Paint. One of the requirements is to store each element I draw in to an array so that the 'paint' method repaints the drawings each time the windows is minimized and then redisplayed. Here are the requirements
We are to assume a max size for the array is 20.
Each element should include 5 variables:
char shape (l for line, r for rectangle, c for circle)
Start x value
Start y value
width (rectangle), or ending x (line), or radius (circle)
height (rectangle), or ending y (line), or radius (circle)
Here is my code for the array class:
class storeDraws {
final int MAXSIZE = 20;
static int S[];
static int n; //number of draws user makes
static char shape;
static double px, py, w, h;
storeDraws () {
S = new int [MAXSIZE];
n = 0;
shape = 'l';
px = 0;
py = 0;
w = 0;
h = 0;
}
}
I have read a few places that I can input the array as (using the mouseReleased(MouseEvent e) method:
storeDraws[] input = new storeDraws{value, value, value, value, value};
But I don't think that would work for what I am trying to do with the 'paint' method to redraw the shapes. I thought I could somehow pass it using the standard format of S[n] = (char, double, double, double, double), but I get warning that this is illegal.
Edit 8:30 am
I got this part working. In my class here is my code now.
class storeDraws {
static char shape;
static int px, py, w, h;
storeDraws () {
shape = 'l';
px = 0;
py = 0;
w = 0;
h = 0;
}
}
I then declared this in the DrawPanel class:
private storeDraws[] store = new storeDraws[20];
private int n = 0;
And mouseReleased method of DrawPanel:
public void mouseReleased(MouseEvent e) {
if (drawShape == "line") {
store[n].shape = 'l';
store[n].px = p1.x;
store[n].py = p1.y;
store[n].w = p3.x;
store[n].h = p3.y;
n++;
}
And paint:
public void paint(Graphics g) {
for (int i = 0; i < n; i++) {
if (store[i].shape == 'l')
g.drawLine(store[n].px, store[n].py, store[n].w, store[n].h);
But if I draw 6 lines it only repaints the last line.
I think you need to separate some of the functionality you want. You can have a class for each of the elements and then store instances of the class in an array of DrawingElement objects.
So you'd do something like this:
DrawingElement[] drawing = new DrawingElement[20];
DrawingElement circle = new DrawingElement('c', 10, 10, 10, 10);
DrawingElement rect = new DrawingElement('r', 20, 10, 10, 10);
drawing[0] = circle;
drawing[1] = rect;
Note: If you need to be able to get the number of objects in the array (variable n in your code) you may want to use some implementation of
a Linked List (which has a size() method) and do some check when adding elements to make sure you don't add past the max of 20.
Example with LinkedList:
LinkedList<DrawingElement> drawing = new LinkedList<DrawingElement>();
DrawingElement circle = new DrawingElement('c', 10, 10, 10, 10);
DrawingElement rect = new DrawingElement('r', 20, 10, 10, 10);
drawing.add(circle);
drawing.add(rect);
int n = drawing.size(); //will be 2
The Drawing Element Class:
public class DrawingElement
{
char shape;
double px, py, w, h;
public DrawingElement(char shape, double px, double py, double w, double h)
{
this.shape = shape;
this.px = px;
this.py = py;
this.w = w;
this.h = h;
}
//Add getters and setters (accessors and mutators) for class variables
}
I think you should use collection for this purpose.Create array, store values
then add each array object in collection(list).
you can use arraylist instead of array. this will help you to store different variable.
If there is need of using only array you can use object array
Sample Code
object a[]= {'a',10,10.2,10.3,10.4,10.5}
Please refer ArrayList
In your case it would be better to use Java Collection(ArrayList) rather than Array.
First point, We cannot store different types of variables values into an Array.
An array is a container object that holds a fixed number of values of a single type.
Here you are trying to store multiple type of variables into integer array.
see this link:
https://docs.oracle.com/javase/tutorial/java/nutsandbolts/arrays.html
To overcome this drawback, We have Collection API introduced with JDK1.5
Refer this link:
http://docs.oracle.com/javase/tutorial/collections/index.html

Converting Colors

I'm trying to write a method for my game that will take an image, the hex value for the old color, and the hex value for the new color and then convert all pixels of the old color to the new color. Right now, the method paints the entire image the new color, as if the if statement is not working at all. This the method:
private void convertColors(BufferedImage img, int oldColor, int newColor)
{
Graphics g = img.getGraphics();
g.setColor(new Color(newColor));
Color old = new Color(oldColor);
for(int x = 0; x < img.getWidth(); x++)
{
for(int y = 0; y < img.getHeight(); y++)
{
Color tmp = new Color(img.getRGB(x, y));
if(tmp.equals(old));
{
System.out.println("Temp=" + tmp.toString() + "Old=" + old.toString() + "New=" + g.getColor().toString());
g.fillRect(x, y, 1, 1);
}
}
}
g.dispose();
}
*The hex for oldColor is 0xFFFFFF (white) and for newColor is 0xFF0000 (red).
Using the println method I get these kind of results:
Temp=java.awt.Color[r=0,g=0,b=0]Old=java.awt.Color[r=255,g=255,b=255]New=java.awt.Color[r=255,g=0,b=0]
Temp=java.awt.Color[r=255,g=255,b=255]Old=java.awt.Color[r=255,g=255,b=255]New=java.awt.Color[r=255,g=0,b=0]
The scond line looks correct, the temp color and the old are the same, but that is obviously not the case with the first. I have also tried creating a new BufferedImage and copy over the pixels but that leaves the same result... Does the equals method not work as I think it does or does this entire method just not work and there's a better way to do this? Thanks for you help in advance.
Just remove the ; after if(tmp.equals(old)).
Otherwise you compare the colors and do nothing after the comparsion and always choose the new color.
Besides that you need to reorganize your code a little bit to make it slightly more efficient:
Graphics g = img.getGraphics();
g.setColor(new Color(newColor));
for(int x = 0; x < img.getWidth(); x++) {
for(int y = 0; y < img.getHeight(); y++) {
if(img.getRGB(x, y) == oldColor) {//check if pixel color matches old color
g.fillRect(x, y, 1, 1);//fill the pixel with the right color
}
}
}
g.dispose();
Just because i was interested in the topic: relying on image filters you could do all that via:
class ColorSwapFilter extends RGBImageFilter {
int newColor, oldColor;
public ColorSwapFilter(int newColor, int oldColor) {
canFilterIndexColorModel = true;
this.newColor = newColor;
this.oldColor = oldColor;
}
#Override
public int filterRGB(int x, int y, int rgb) {
return rgb == oldColor ? newColor : oldColor;
}
}
which should be called via
BufferedImage img;//your image
ColorSwapFilter filter = new ColorSwapFilter(...,...);//your colors to be swapped.
ImageProducer producer = img.getSource();
producer = new FilteredImageSource(producer, filter);
Image im = Toolkit.getDefaultToolkit().createImage(producer);
You have a semicolon direct after your if statement if(tmp.equals(old));
This esentially tells Java that your if statement has only one command associated with it, and that command is a single semicolon, effectively meaning "do nothing". If you remove it, it will restore the condition on the block of code beneath it, which right now is just running every time regardless of the condition.
I got it to work; this is the working convertColors method:
private BufferedImage convertColors(BufferedImage img, int oldColor, int newColor)
{
int [] pixels = new int [img.getWidth() * img.getHeight()];
img.getRGB(0, 0, img.getWidth(), img.getHeight(), pixels, 0, img.getWidth());
Color old = new Color(oldColor);
Color newC = new Color(newColor);
for(int x = 0; x < img.getWidth(); x++)
{
for(int y = 0; y < img.getHeight(); y++)
{
Color tmp = new Color(pixels[x + y * img.getWidth()]);
if(tmp.equals(old))
{
pixels[x + y * img.getWidth()] = newC.getRGB();
}
}
}
img.setRGB(0, 0, img.getWidth(), img.getHeight(), pixels, 0, img.getWidth());
return newImg;
}

Categories

Resources