bawa bawa - 27 days ago 15
Java Question

Drawing on a buffered image

I am trying to draw on a buffered image. I am able to get the picture on the frame but it doesnt seem to draw on the image. If I use

BufferedImage bufferedImage = new BufferedImage(1280, 800,BufferedImage.TYPE_INT_RGB);


then it seems to draw the string but I would like to ideally draw on the image as I need to plot some coordinates on the image for a project. Any guidance would be highly appreciated. Excuse the bad indentation

import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Toolkit;
import java.awt.image.BufferedImage;
import java.io.IOException;

import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class drawTest extends JPanel {

public void paint(Graphics g) {
Image img = createImageWithText();
g.drawImage(img, 20,20,this);
}

private Image createImageWithText(){
BufferedImage bufferedImage = new BufferedImage(1280, 800,BufferedImage.TYPE_INT_RGB);
// BufferedImage bufferedImage = new BufferedImage()
Graphics g = bufferedImage.getGraphics();

try {
bufferedImage = ImageIO.read(getClass().getResource("Unknown.jpg"));

} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
g.drawString("Point is here", 20,20);


return bufferedImage;
}

public static void main(String[] args) {
JFrame frame = new JFrame();
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
double width = screenSize.getWidth();
double height = screenSize.getHeight();
frame.getContentPane().add(new drawTest());

frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// frame.setSize(200, 200);

frame.setExtendedState(JFrame.MAXIMIZED_BOTH);
System.out.println(height + " " + width);
frame.setVisible(true);
}
}

Answer

You're creating two BufferedImage objects -- one that you get the Graphics context from and draw text on, and the other that holds the picture obtained via ImageIO, that you don't draw text on. You return the latter, so it makes sense that the picture holds no new text.

    // BufferedImage Object ONE
    BufferedImage bufferedImage = new BufferedImage(1280, 800, BufferedImage.TYPE_INT_RGB); 
    Graphics g = bufferedImage.getGraphics();  // Graphics for the first object only

    try {
        // BufferedImage object TWO
        bufferedImage = ImageIO.read(getClass().getResource("Unknown.jpg"));

    } catch (IOException e) {
        e.printStackTrace();
    }

    // draw with the graphics context for the first object
    g.drawString("Point is here", 20, 20);

    return bufferedImage; // but return the second

Solution: don't do this, create one BufferedImage only, say via ImageIO, get its Graphics context, draw with it, dispose the Graphics when done, and return it.

e.g.,

// have method accept the image path and 
// have it throw an exception if the path is bad
private Image createImageWithText2(String resourcePath) throws IOException {

    // create one and only one BufferedImage object. 
    // If this fails, the exception will bubble up the call chain
    BufferedImage bufferedImage = ImageIO.read(getClass().getResource(resourcePath));

    // get the Graphics context for this single BufferedImage object 
    Graphics g = bufferedImage.getGraphics();  

    g.drawString("Point is here", 20, 20);

    g.dispose();  // get rid of the Graphics context to save resources

    return bufferedImage;
}

Other problems with your code is here:

public void paint(Graphics g) {
   Image img = createImageWithText();
   g.drawImage(img, 20,20,this);
}

Problems include:

  • You're overriding the wrong painting method. You should override paintComponent, not paint, and in fact your question mentions paintComponent, so I'm not sure why you're doing this.
  • You're overriding a painting method but not calling the super's method, breaking the painting chain.
  • You're doing file I/O unnecessarily repeatedly within a painting method, a method that has the greatest effect on the perceived responsiveness of your GUI, and so something you don't want to do. Read the image in once store it to a variable, use the variable within paintComponent, and never do file I/O within a painting method.
  • You will want to learn and use Java naming conventions. Variable names should all begin with a lower letter while class names with an upper case letter. Learning this and following this will allow us to better understand your code, and would allow you to better understand the code of others.
Comments