Save drawing on Jpanel as image - java

I am developing a drawing program using java socket. Multiple users can draw and save it as jpeg. Currently my save image function only save a blank canvas. It cannot save the co-ordinates drawn.
I am sharing part of my code below. =)
I did not use paint or paintComponent for my Canvas class because of the use java socket i am experiencing sending coordinate errors. Instead i am using massDraw().
class Canvas extends JPanel {
private int x, y;
private float x2, y2;
public Canvas() {
super();
this.setBackground(Color.white);
}
public void massDraw(int px, int py, int x, int y, int red, int green,
int blue, int size) {
Graphics g = canvas.getGraphics();
Graphics2D g2d = (Graphics2D) g;
g2d.setRenderingHints(myBrush);
g2d.setStroke(new BasicStroke(size, BasicStroke.CAP_ROUND,
BasicStroke.JOIN_BEVEL));
g2d.setColor(new Color(red, green, blue));
g.drawLine(px, py, x, y);
}
}// end Canvas class
SaveJpegOP class
class saveJpegOP implements ActionListener {
public void actionPerformed(ActionEvent e) {
// Ask for file name
String str = JOptionPane
.showInputDialog(null, "Enter File Name : ");
// save as jpeg
BufferedImage bufImage = new BufferedImage(canvas.getSize().width, canvas.getSize().height,BufferedImage.TYPE_INT_RGB);
canvas.paint(bufImage.createGraphics());
try {
ImageIO.write(bufImage, "jpg", new File(str + ".jpg"));
} catch (IOException ex) {
ex.printStackTrace();
}
}
}

Blank canvas is saved because massDraw() is never called, especially it's not called when you invoke canvas.paint(bufImage.createGraphics()) in saveJpegOP.
paint() basically redraws entire component and since you decided not to override it (or paintComponent()), drawMass() is never called and empty canvas is painted.
So you need to override paintComponent() and call massDraw() with appropriate parameters. The parameter values can be, for instance, earlier set as properties in the Canvas class.

Related

How can I rotate rectangle in Java?

My rectangle code:
class Rectangle extends JPanel {
int x = 105;
int y= 100;
int width = 50;
int height = 100;
public void paint(Graphics g) {
g.drawRect (x, y, width, height);
g.setColor(Color.WHITE);
}
Rectangle r = new Rectangle();
and I have a button "rotate". When the user presses the button with the mouse, the rectangle must rotate 15 degrees.
This is my action code:
public void actionPerformed(ActionEvent e){
Object source = e.getSource();
if( source == rotate){
AffineTransform transform = new AffineTransform();
transform.rotate(Math.toRadians(15), r.getX() + r.getWidth()/2, r.getY() + height/2);
r.add(transform);
}
}
But the code doesn't work. I don't know why? What do you think?
My edited-action-code part:
public void actionPerformed(ActionEvent e){
Object source = e.getSource();
if( source == rotate){
Paint p = new Paint();
panel1.add(r);
repaint();
}
}
class Paint extends JPanel {
public void paintComponent(Graphics g)
{
super.paintComponent(g);
Graphics2D g2d = (Graphics2D)g;
g2d.setColor(Color.WHITE);
g2d.translate(r.getX()+(r.WIDTH/2), r.getY()+(r.HEIGHT/2));
g2d.rotate(Math.toRadians(15));
r.equals(g2d);
repaint();
}
}
Custom painting is done by overriding the paintComponent() method, not paint(). Don't forget the super.paintComponent() at the start.
The paintComponent() method is where the painting is done so that is were you need the rotation code. So you could set a variable to indicate if you need to do the rotation or not. So all the ActionListener does is set the variable and then invoke repaint().
Or, I've never tried applying a rotation directly to the Rectangle (I've always applied it to the Graphics object in the painting method). Maybe you just need to invoke repaint() on the panel in your ActionListener. The panel won't know you've changed the Rectangle, so you need to tell it to repaint itself.

Java 2D programming: Rendering techniques

I have been programming in java for a while now and I've just now started 2D graphics(game development). While coding my game, I have noticed rendering issues with my game. While my player is running around the screen, the pixels will glitch around. It's like lag on a multiplayer game, but its barely noticeable. After researching this issue I have not come up with any solutions, so I'm asking for your help.
MY QUESTION: I am experiencing poor rendering in my game and I'm wondering if my way of rendering is poor. If so, Can you point me to any resources?
MY RENDERING CLASS
public class Render extends JPanel implements Runnable{
int SCREEN_WIDTH,SCREEN_HEIGHT;
Game game;
Thread t;
public Render(int w,int h,Game g){
this.SCREEN_WIDTH = w;
this.SCREEN_HEIGHT = h;
this.game = g;
this.setDoubleBuffered(true);
}
public void run(){
while(true){
repaint();
}
}
public void paint(Graphics g){
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.translate(-this.game.getCamera().getX(), -game.getCamera().getY());
g2d.setColor(Color.black);
//fill the screen with black
g2d.fillRect(0, 0, game.getLevelHandler().getLevel().getWidth() * 32, game.getLevelHandler().getLevel().getHeight() * 32);
/**for(Entity E: game.getObjects()){
E.draw(g2d);
}*/
//send the graphics object to my player...IS THIS OKAY TO DO?
game.getPlayer().draw(g2d);
}
public void start(){
t = new Thread(this);
t.start();
}
}
public class Player extends Entity{
float dx,dy,moveSpeed;
boolean jumping, canJump;
float terminalVelocity,acceleration = 0;
int GravityCounter,jumps,maxJumps,jumpheight = 0;
public Player(float x, float y, float w, float h, ObjectID id, Game g) {
super(x, y, w, h, id, g);
//gravity
terminalVelocity += 7;
acceleration += 0.2;
moveSpeed += 2.5;
//jumping
jumpheight = 40;
maxJumps = 2;
jumps = maxJumps;
}
public void tick() {
dx = 0;
dy = 0;
collisions();
move();
x += dx;
y += dy;
}
public void collisions(){
}
public void move(){
}
//the drawing
public void draw(Graphics2D g) {
g.setColor(Color.green);
g.drawRect((int)x, (int)y, (int)w, (int)h);
}
}
EDIT: downloadable link here
, If any changes are needed, I'll try and correct it. Also, does this glitching happen when there is a memory leak?
I revised my code because of suggestions, This is what I have now.
RENDERER:
public class Render extends JPanel implements Runnable{
int SCREEN_WIDTH,SCREEN_HEIGHT;
Game game;
Thread t;
public Render(int w,int h,Game g){
this.SCREEN_WIDTH = w;
this.SCREEN_HEIGHT = h;
this.game = g;
this.setDoubleBuffered(true);
}
public void run(){
while(true){
repaint();
try {
Thread.sleep(16);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public synchronized void paint(Graphics g){
Graphics2D g2d = (Graphics2D) g;
g2d.translate(-this.game.getCamera().getX(), -game.getCamera().getY());
g2d.setColor(Color.black);
g2d.fillRect(0, 0, game.getLevelHandler().getLevel().getWidth() * 32, game.getLevelHandler().getLevel().getHeight() * 32);
for(Entity E: game.getObjects()){
synchronized(E){E.draw(g2d);}
}
synchronized(game.getPlayer()){game.getPlayer().draw(g2d);}
}
public void start(){
t = new Thread(this);
t.start();
}
}
The player class did not change
Source Code: here
I know what's happening here because I was having the exact same problem in the game I'm writing. It sure is a hard thing to find. Your problem is happening because you're rounding your x and y variables when you draw.
g.drawRect((int)x, (int)y, (int)w, (int)h);
This is causing your rectangle to jump around a bit. Because it looks like your rectangle can have decimal coordinates, you need to be able to draw the rectangle at decimal coordinates. There's a pretty easy way to do that, but instead let's use a way that will work regardless of what you're drawing.
You're going to need to use some transformations, personally I like AffineTransform's. There are lots of tutorials about these, but this is the first (non-documentation) result of a google search https://docs.oracle.com/javase/tutorial/2d/advanced/transforming.html. I know you're already doing some transformations, but this is what your draw method will look like after you add them.
public void draw(Graphics2D g) {
AffineTransform original = g.getTransform(); // keep a copy of the original so that we can restore it
AffineTransform transform = (AffineTransform)original.clone();
transform.translate((double)x, (double)y); // translate the transform to the player location, note that x and y can be non-integers here.
g.transform(transform); // apply the transformation.
g.setColor(Color.green);
g.drawRect(0, 0, (int)w, (int)h);
g.setTransform(original); // restore the original transformation
}
For the rest of your walls and stuff, you can use this exact same method. Remember that the "screen" location of an object is the object's game location minus the camera's game location. Good luck with your game.

Transparency not working in java

I have an image, with a complete transparent background. However when I draw this image, ingame, it has a kind of shade to it, and I have no clue why. I would like to get that out of there. Does anyone have an idea? I don't have the reputation to post images of it apparently... So I'll try to give some more information.
I have the Color.DARK_GRAY as background, and when I draw the image, you see a lighter gray square around it.
Then when I draw a couple of these images ontop of eachother, that square gets lighter and lighter.
If I draw the image ontop of another image however, this effect does not occur.
Here I load the image
public BlackChip() {
this.value = 500;
this.url = "res/images/poker/blackchip.png";
this.file = new File(url);
BufferedImage bi;
try {
bi = ImageIO.read(file);
this.image = bi;
} catch (IOException e) {
e.printStackTrace();
}
}
Here I draw the image
public void renderChip(Chip chip, int x, int y) {
g.drawImage(chip.getImage(), x, y, null);
}
Here I call that method
public void render() {
screen.renderBackground(Color.DARK_GRAY);
pokertable.render(Game.width / 2 - pokertable.getImage().getWidth(null) / 2, 50);
screen.renderChip(cs.getWhiteChip(), 380, 310);
screen.renderChip(cs.getRedChip(), 430, 310);
screen.renderChip(cs.getGreenChip(), 480, 310);
screen.renderChip(cs.getBlueChip(), 530, 310);
screen.renderChip(cs.getBlackChip(), 580, 310); //this one is it
}
link to the images:
https://drive.google.com/file/d/0Bz-4pfUssUeHRWkxaUhodWNILWc/edit?usp=sharing
Well... this doesn't work either because i need 10 reputation to post more then 1 link
you can see the effect on this link, it's the image with full transparent background, drawn multiple times.
I can't tell if this is the exact cause of the problem, because you haven't provided a MCVE but this method
public void renderChip(Chip chip, int x, int y) {
g.drawImage(chip.getImage(), x, y, null);
}
Just looks wrong. All custom painting should be done within the context of the provided Graphics object in the overridden paintComponent method. If you have not overriden paintComponent in a JPanel or a JComponent then you are likely not painting correctly. You may be doing something like
public class SomePanel extends JPanel {
private Graphics g;
public SomePanel() {
g = getGraphics();
}
}
Which is completely wrong. You should instead be doing something like
public class SomePanel extends JPanel {
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
// do painting here
}
}
You Classes can then have it's own render method that takes a Graphics object as an argument. Then can be called in the paintComponent method. Maybe something like
public class Chip {
private JComponent imageObserver;
private BufferedImage chipImage;
int x, y;
public Chip(BufferedImage chipImage, int x, int y, JComponent imageObserver){
this.chipImage;
this.x = x;
this.y = y;
this.imageObserver = imageObserver;
}
public void renderChip(Graphics g) {
g.getImage(chipImage, x, y, imageObserver);
}
}
And your panel
public class SomePanel extends JPanel {
private List<Chip> chips;
public SomePanel() {
chips = new ArrayList<Chip>();
// add new Chips
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
for (Chip chip: chips) {
chip.renderChip(g);
}
}
}

Java graphics programming draw image error

Hello I'm getting an error drawing an image onto my frame. I'm not sure what's going wrong here.
Im getting the following error here.
Java: 77: cannot find symbol
symbol: variable image
location: class DrawComponent
g.drawImage(image, 0, 0, null);
class DrawComponent extends JComponent {
public void paintComponent(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
// draw a circle with the same center
double centerX = 250;
double centerY = 180;
double radius = 20;
Ellipse2D circle = new Ellipse2D.Double();
circle.setFrameFromCenter(centerX, centerY, centerX + radius, centerY + radius);
g2.setPaint(Color.RED);
g2.fill(circle);
g2.draw(circle);
String filename = "SydneyOperaHouse.jpeg";
try{
Image image = ImageIO.read(new File(filename));
}catch(IOException ex){
// Handle Exeption
}
g.drawImage(image, 0, 0, null);
}
}
Any help would be great :)
A few points.
To address the problem of the attribute scope. The image attribute should be handed to (or loaded in) the constructor and stored as a class attribute that is visible to the paint method. Never try load images (or do other potentially long running tasks) in this method.
An image for BG will typically be an embedded resource by the time of deployment, so access it by URL.
A JComponent is an ImageObserver so g.drawImage(image, 0, 0, null); should be
g.drawImage(image, 0, 0, this);
I suspect the image drawing at 0x0 should precede (be done before) drawing the red ellipse, or it will draw over the top of it.
Here is an example based on an image of Sydney (no, not the bloody opera house - fussy, fussy..).
import java.awt.*;
import java.awt.geom.Ellipse2D;
import javax.swing.*;
import javax.imageio.ImageIO;
import java.net.URL;
public class DrawComponent extends JComponent {
private Image image;
DrawComponent(Image image) {
this.image = image;
Dimension d = new Dimension(image.getWidth(this),image.getHeight(this));
this.setPreferredSize(d);
}
public void paintComponent(Graphics g) {
// always call super first, to get borders etc.
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
// paint the BG
g.drawImage(image, 0, 0, this);
// draw a circle with the same center
double centerX = 250;
double centerY = 180;
double radius = 20;
Ellipse2D circle = new Ellipse2D.Double();
circle.setFrameFromCenter(centerX, centerY, centerX + radius, centerY + radius);
g2.setPaint(Color.RED);
g2.fill(circle);
g2.draw(circle);
}
public static void main(String[] args) throws Exception {
String s = "http://pscode.org/media/citymorn1.jpg";
final Image image = ImageIO.read(new URL(s));
Runnable r = new Runnable() {
#Override
public void run() {
JComponent gui = new DrawComponent(image);
JOptionPane.showMessageDialog(null, gui);
}
};
SwingUtilities.invokeLater(r);
}
}
You simply declare your image variable in the try block... It is not visible outside it.
try{
Image image = ImageIO.read(new File(filename));
}catch(IOException ex){
// Handle Exeption
}
g.drawImage(image, 0, 0, null);
The scope of the variable image is wrong. Note that you are declaring the variable inside the try-block. The variable doesn't exist outside of the { ... } of the try-block.
Declare the variable outside the try-block:
Image image = null;
try {
image = ImageIO.read(new File(filename));
} catch(IOException ex) {
// Handle Exeption
}
if (image != null) {
g.drawImage(image, 0, 0, null);
}
By the way, you should not be doing I/O inside the paintComponent method. It's better to load the image somewhere else (when the application starts up, for example), store it in a member variable, and use it inside the paintComponent method.
When you load the image in the paintComponent method, it's going to load it every time the component needs to be painted. This will make your application slow.
What would you expect here in the case of an exception ?
String filename = "SydneyOperaHouse.jpeg";
try{
Image image = ImageIO.read(new File(filename));
}catch(IOException ex){
// Handle Exeption
}
g.drawImage(image, 0, 0, null);
You should declare/initalise and draw within the try{} block.

java.awt.Graphics change color after drawing

I have asked a similar question a while ago here, but didn't get an answer. The original question was about changing the color of a shape after clicking on it. But I am puzzled on how to access the shape at all after it is drawn.
This is my paintComponent method
#Override
protected void paintComponent(Graphics graph) {
super.paintComponent(graph);
Graphics2D g = (Graphics2D) graph;
// smooth graphics
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
// moving to the middle of the panel
g.translate(this.getWidth()/2, this.getHeight()/2);
// painting colored arcs
for(int i = 0; i < 4; i++) {
g.setColor(dimColors[i]);
g.fill(arcs[i]);
}
// painting borders
g.setColor(Color.BLACK);
g.setStroke(new BasicStroke(5F));
g.drawLine(-98, 0, 98, 0);
g.drawLine(0, -98, 0, 98);
g.draw(circle);
// painting central white circle
g.setColor(Color.WHITE);
g.fill(smallCircle);
g.setColor(Color.BLACK);
g.draw(smallCircle);
}
the arcs[] array contains a bunch of Arc2D's that are drawn on the panel. My question is now, if I want to change the color of, for example arcs[0], how do I do that?
Thanks!
EDIT: I now have this MouseAdapter event
private class MyMouseAdapter extends MouseAdapter {
public void mousePressed(MouseEvent e) {
Point p = e.getPoint();
Component c = getComponentAt(p);
Graphics g = c.getGraphics();
dimColors[1] = Color.RED;
paintComponent(g);
}
}
And it works, it changes the color of arc[1] because arcs[1] has dimColors[1] set as color when drawing it.
However, I still can't figure out how to check wether the right arc was clicked. Right now you just click anywhere on the graphics panel and it changes the color of that specific arc
This doesn't answer your earlier question, however it does answer your question of click detection. To do this it is best to use Graphics2D because it is a lot easier to write than most other options. Here is an example:
public class GraphicsPanel extends JPanel implements MouseListener
{
private Rectangle2D rect;
First we create our Graphics2D rectangle rect.
public void paintComponent(Graphics g)
{
super.paintComponent(g);
Graphics2D g2d = (Graphics2D)(g);
g2d.setColor(Color.GREEN);
rect = new Rectangle2D.Double(70, 70, 100, 100);
g2d.fill(rect);
this.addMouseListener(this);
}
And then we override the paintComponent method and create our new Rectangle2D.Double object.
We then fill the rectangle with g2d.fill() and then add a mouse listener to the JPanel.
public void mousePressed(MouseEvent e)
{
if(rect.contains(e.getX(), e.getY()))
System.out.println("Rectangle clicked");
}
}
Finally, we need to see if that rectangle contains the point where the user clicked. To do this, simply see if the rectangle we created contains the user's click location by using the Rectangle2D.double's contains(int x, int y) method. That's it!
if I want to change the color of, for example arcs[0], how do I do that?
A line (or whatever) only exists as a bunch of pixels that were painted in the original color. To change its color you must change the current color and draw it again.

Categories

Resources