Java Graphics.drawLine() inexact: drawn lines are too long - java

I have a polygon with the vertices (0,0), (100,0), (100,100), and (0,100).
I debugged the program and those are the exact lines that java is drawing.
Instead of drawing an exact square, some of the lines are a pixel too long:
http://gyazo.com/7418546c51c9a10fc690b18afcc96360.png
(The green circle is just me testing the centroid).
When I move the square out of the corner, you can see that the top left corner is the only corner that is exactly correct.
Why is this happening?
Right before drawLine, I wrote the lines to the console after they were converted to integer coordinates, and they were correct. So I can't see what could possibly be wrong except for the drawLine functions.
drawLine:
g.drawLine((int) line.getStart().getX(), (int) line.getStart().getY(),
(int) line.getEnd().getX(), (int) line.getEnd().getY());
The line has a start vector and an end vector. The vectors contain an x and y.
Even when doing this:
g.drawLine(0, 0, 100, 0);
g.drawLine(100, 0, 100, 100);
g.drawLine(100, 100, 0, 100);
g.drawLine(0, 100, 0, 0);
It still produces the same result.
This works though:
g.drawLine(0, 0, 100, 0);
g.drawLine(101, 0, 101, 100);
g.drawLine(100, 101, 0, 101);
g.drawLine(0, 100, 0, 0);

The example you provided is working:
BufferedImage bi = new BufferedImage(200, 200, BufferedImage.TYPE_INT_ARGB);
Graphics g = bi.getGraphics();
g.fillRect(0, 0, bi.getWidth(), bi.getHeight());
g.setColor(Color.red);
g.translate(50, 50);
g.drawLine(0, 0, 100, 0);
g.drawLine(100, 0, 100, 100);
g.drawLine(100, 100, 0, 100);
g.drawLine(0, 100, 0, 0);
JOptionPane.showMessageDialog(null, new ImageIcon(bi));
There is a bug https://bugs.openjdk.java.net/browse/JDK-8049901 that describes one possible issue.

Related

setColor on transparent background not showing correct color

I have a png image with transparency. I am trying to create a filled polygon on the image over the transparent area. I'm setting the color but the actual color in the final image is different than expected. Here is my code:
Graphics2D g = wifiImage.createGraphics();
int [] x = {0, 200, 0};
int [] y = {0, 0, 200};
g.setColor(new Color(255, 0, 0)); //Red color
g.drawPolygon(x, y, 3);
g.fillPolygon(x, y, 3);
g.dispose();
ImageIO.write(wifiImage, "png", new File("./output/finalImage.png"));
In the final image, I expect the Red color triangle. But it is some brownish color instead.
As a workaround, in my origImage, I replaced transparency with white color. In that case, it works.
Can anybody tell how to set the correct color on the transparent region of the png?
The PNG image is probably a palletted image where 'brownish' is the palette color closest to (255, 0, 0).
Try this:
BufferedImage copy = new BufferedImage(wifiImage.getWidth(), wifiImage.getHeight(), BufferedImage.TYPE_INT_ARGB);
g = copy.createGraphics();
copy.drawImage(wifiImage, 0, 0, null);
int [] x = {0, 200, 0};
int [] y = {0, 0, 200};
g.setColor(new Color(255, 0, 0)); //Red color
g.drawPolygon(x, y, 3);
g.fillPolygon(x, y, 3);
g.dispose();
ImageIO.write(copy, "png", new File("./output/finalImage.png"));

Animation not working Java Graphics

Completing a graphics program in Java, I'm trying to animate rain falling using a timer. Right now I am testing my code with a big blue rectangle so I can see where it's going but the animation isn't working for me. I'm very new to Java graphics so I could be making mistakes that just aren't clear to me.
When I try to repaint the square to move, and the paint function is called the whole screen blinks, this may be because I was using recursive functions to draw fractal trees, but I'm not sure. Is there a way to keep everything I have drawn from being repainted and just call repaint on the rain? Any guidance or tips would be appreciated.
import java.awt.*;
import javax.swing.*;
import java.lang.Math;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class FractalTree extends JFrame {
private int frameWidth = 1440;
private int frameHeight = 850;
private int rainX = 0;
private int rainY = 0;
public FractalTree()
{
setBounds(1000, 1000, frameWidth, frameHeight ); //graphics window size
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
ActionListener listener = new TimerListener();
final int DELAY = 1500;
Timer t = new Timer(DELAY, listener);
t.start();
setResizable(false);
}
public void setRain(int newRainX, int newRainY)
{
rainX = newRainX;
rainY = newRainY;
}
public void setSkyGround(Graphics g)
{
Color sky = new Color(180, 225, 255);
g.setColor(sky);
g.fillRect(0, 0, frameWidth, 550);
Color sun = new Color(225, 225, 150);
g.setColor(sun);
g.fillOval(1380, -40, 100, 100);
g.drawLine(frameWidth, 0, 1350, 550);
g.drawLine(frameWidth, 0, 1450, 550);
g.drawLine(1350, 550, 1450, 550);
int xpoints[] = {frameWidth, 1450, 1350};
int ypoints[] = {0, 550, 550};
int npoints = 3;
g.fillPolygon(xpoints, ypoints, npoints);
g.drawLine(frameWidth, 0, 1080, 550);
g.drawLine(frameWidth, 0, 880, 550);
g.drawLine(880, 550, 1080, 550);
int xpoints2[] = {frameWidth, 1080, 880};
int ypoints2[] = {0, 550, 550};
int npoints2 = 3;
g.fillPolygon(xpoints2, ypoints2, npoints2);
g.drawLine(frameWidth, 0, 480, 550);
g.drawLine(frameWidth, 0, 280, 550);
g.drawLine(480, 550, 280, 550);
int xpoints3[] = {frameWidth, 480, 280};
int ypoints3[] = {0, 550, 550};
int npoints3 = 3;
g.fillPolygon(xpoints3, ypoints3, npoints3);
g.drawLine(frameWidth, 0, 0, 430);
g.drawLine(frameWidth, 0, 0, 300);
g.drawLine(0, 430, 0, 300);
int xpoints4[] = {frameWidth, 0, 0};
int ypoints4[] = {0, 430, 300};
int npoints4 = 3;
g.fillPolygon(xpoints4, ypoints4, npoints4);
g.drawLine(frameWidth, 0, 0, 100);
g.drawLine(frameWidth, 0, 0, 0);
g.drawLine(0, 100, 0, 0);
int xpoints5[] = {frameWidth, 0, 0};
int ypoints5[] = {0, 0, 100};
int npoints5 = 3;
g.fillPolygon(xpoints5, ypoints5, npoints5);
Color grassBackground = new Color(150, 255, 170);
g.setColor(grassBackground);
g.fillRect(0, 550, frameWidth, frameHeight);
}
public void drawTree(Graphics g, int x1, int y1, double angle, int depth, int red, int green, int blue)
{
if (depth == 0)
{
Color doodle = new Color(red, green, blue);
g.setColor(doodle);
g.fillOval(x1, y1, 10, 10);
}
else
{
Graphics2D g2 = (Graphics2D) g;
g2.setStroke(new BasicStroke(depth));
Color brown = new Color(100, 25, 0);
g.setColor(brown);
int x2 = x1 + (int) (Math.cos(Math.toRadians(angle)) * depth * 10);
int y2 = y1 + (int) (Math.sin(Math.toRadians(angle)) * depth * 10);
g.drawLine(x1, y1, x2, y2);
drawTree(g, x2, y2, angle - 40, depth - 1, red, green, blue);
drawTree(g, x2, y2, angle + 20, depth - 1, red, green, blue);
}
}
public void realFlowers(Graphics g, int x, int y, int lenWid, int petals)
{
//calculates the increment
double inc = (2*Math.PI/petals);
g.setColor(Color.YELLOW);
//draws petals
for(int i = 0; i < petals; i++){
//keeps spacing consistent depandng on number of petals
double value = i * inc;
//draws petals with calculated spacing relative to number of petals
g.fillOval((int)((lenWid)*Math.cos(value)+x-lenWid/4),(int)((lenWid)*Math.sin(value)+y-lenWid/4), lenWid + lenWid/2, lenWid + lenWid/2);
}
//draws middle flower bud;
g.setColor(Color.ORANGE);
g.fillOval(x - lenWid/4, y - lenWid/4, lenWid + lenWid/2 , lenWid + lenWid/2);
}
public void drawGrass(Graphics g, int width, int height, int interval, int red, int green, int blue)
{
height = frameHeight - height;
Color grass = new Color(red, green, blue);
for(int i = 0; i < width; i= i + interval)
{
for(int j = frameHeight; j > height; j = j - interval)
{
g.setColor(grass);
g.fillRect(i, j, 3, 5);
}
}
}
public void rainDrops(Graphics g, int x, int y, int w, int h)
{
setRain(x, y);
Color rain = new Color(0, 76, 153);
g.setColor(rain);
g.fillRect(x, y, w, h);
}
public void moveRainBy(int dx, int dy)
{
rainX = rainX + dx;
rainY = rainY + dy;
repaint();
}
class TimerListener implements ActionListener
{
public void actionPerformed(ActionEvent event)
{
moveRainBy(1, 1);
}
}
public void paint(Graphics g) {
setSkyGround(g);
drawGrass(g, 1440, 315, 5, 0, 255, 0);
drawGrass(g, 1430, 310, 10, 0, 204, 0);
drawTree(g, 1085, 730, -90, 10, 255, 102, 102);
drawTree(g, 250, 600, -90, 8, 255, 255, 255);
drawTree(g, 1110, 740, -90, 4, 255, 102, 102);
drawTree(g, 1060, 745, -90, 2, 255, 102, 102);
realFlowers(g, 700,700, 8, 8);
rainDrops(g, 200, 200, 30, 30);
}
public static void main(String[] args) {
new FractalTree().setVisible(true);
}
}
When I try to repaint the square to move, and the paint function is called the whole screen blinks
This is because you've override paint of the a top level container (JFrame) which is not double buffered.
As a general recommendation, you should be basing your core functionality around a JPanel and override it's paintComponent method. Take a look at Performing Custom Painting and Painting in AWT and Swing for more details
You might like to also have a look at How to get the EXACT middle of a screen, even when re-sized and How can I set in the midst? for more details why it's not recommended to extend directly from JFrame and try to paint to it.
Is there a way to keep everything I have drawn from being repainted and just call repaint on the rain?
Painting is destructive, that is, each time paint/paintComponent is called, you are expected to repaint the entire state of the component from scratch.
You could use a buffering technique, using something like BufferedImage to paint your state to and simply have the paint methods draw the image, but that would depend on how complex a solution you want. If you were to use buffering technique, I would consider which elements are "static" and which elements are "dynamic". Painting those static elements to the buffer and then, when paint is called, painting the dynamic elements over the top the buffer

Java AffineTransform makes drawString disappear

This is super-weird. When I create a BufferedImage, and do not change the Graphics2D.transform(), then I can draw a line and text with no problem.
When I do set the transform (I am setting the user space to use EMUs instead of pixels), then I can draw the line using EMU coordinates, but I can't draw text.
code here:
public void testBitmaps2() throws Exception {
// no scaling
BufferedImage image = new BufferedImage(300, 300, BufferedImage.TYPE_INT_ARGB);
Graphics2D graphics = image.createGraphics();
graphics.setBackground(new Color(0x00FFFFFF, true));
graphics.clearRect(0, 0, 300, 300);
graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
graphics.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
java.awt.Font javaFont = new java.awt.Font("Arial", java.awt.Font.PLAIN, 24);
graphics.setFont(javaFont);
graphics.setColor(Color.BLACK);
graphics.setStroke(new BasicStroke(1));
graphics.draw(new Line2D.Float(100, 150, 200, 150));
graphics.drawString("hi there", 100, 150);
ImageIO.write(image, "png", new File("c:/temp/", "no_scaling.png"));
// scaling
image = new BufferedImage(300, 300, BufferedImage.TYPE_INT_ARGB);
graphics = image.createGraphics();
// scale to use EMUs, assuming 300DPI image
AffineTransform scaleToEmus = AffineTransform.getScaleInstance(300f / 914400f, 300f / 914400f);
graphics.transform(scaleToEmus);
graphics.setBackground(new Color(0x00FFFFFF, true));
graphics.clearRect(0, 0, 914400, 914400);
graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
graphics.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
javaFont = new java.awt.Font("Arial", java.awt.Font.PLAIN, 24);
graphics.setFont(javaFont);
graphics.setColor(Color.BLACK);
graphics.setStroke(new BasicStroke(914400 / 300));
graphics.draw(new Line2D.Float(914400 / 3, 914400 / 2, 914400 * 0.666f, 914400 / 2));
graphics.drawString("hi there", 914400 / 3, 914400 / 2);
ImageIO.write(image, "png", new File("c:/temp/", "scaling.png"));
}
Ok, the javadocs are wrong! The docs say:
size - the point size of the Font
However, you need to scale it up to match the transform scaling.

Unwanted Line Drawn by Java QuadCurve.2D

"I am trying to draw a QuadCurve line in Java. I am able to do this when I hard code the x and y values in each line, but when I try to draw the lines from a loop I get an unwanted line on the top. I want to have it in a loop so that I can create the values in another location and feed the values to my Drawing class. I think it may be a looping issue. I "stepped into" the code and the values in the array are all correct. I am in college so any help is appreciated. Thank you!
This code works:"
Graphics2D g2 = (Graphics2D) g.create();
g2.setPaint(Color.BLUE);
Shape drawLine1A = new QuadCurve2D.Float(40, 450, 100, 300, 210, 180);
Shape drawLine2A = new QuadCurve2D.Float(210, 180, 315, 150, 390, 240);
Shape drawLine3A = new QuadCurve2D.Float(390, 240, 430, 242, 480, 245);
g2.draw(drawLine1A);
g2.draw(drawLine2A);
g2.draw(drawLine3A);
"This code does not work correctly:"
Graphics2D g2 = (Graphics2D) g.create();
g2.setPaint(Color.BLUE);
Shape line;
int[] x = {40, 100, 210, 210, 315, 390, 390, 430, 480};
int[] y = {450, 300, 180, 180, 150, 240, 240, 242, 245};
int k;
int h;
for(int i = 0; i < 7; i++)
{
k = i + 1;
h = k + 1;
line = new QuadCurve2D.Float(x[i], y[i], x[k], y[k], x[h], y[h]);
g2.draw(line);
}
"I figured this out after. i had to increment i by 3 in order to have the coordinates in the right spots. Simple fix. I was looking at it for too long!"

How do I turn off text antialiasing in this Java function?

Basically I would like to turn off antialias in the following:
public BufferedImage createText(String text) {
//create image
BufferedImage image = new BufferedImage(95, 20,
BufferedImage.TYPE_INT_ARGB);
Graphics2D graphics = (Graphics2D) image.getGraphics();
//set background
graphics.setColor(Color.white);
graphics.fillRect(0, 0, 95, 20);
//draw text
graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_OFF);
graphics.setColor(Color.black);
graphics.setFont(new Font("volter", Font.PLAIN, 9));
graphics.drawString(text, 0, 10);
return image;
}
but it's not working, here is something this function generates:
I just want black and white to be used, nothing else so it's important I get antialias disabled!
Try this instead:
graphics.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
RenderingHints.VALUE_TEXT_ANTIALIAS_OFF);

Categories

Resources