Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Should I explicitly dispose the Graphics object?

Tags:

java

swing

awt

The javadoc said:

For efficiency, programmers should call dispose when finished using a Graphics object only if it was created directly from a component or another Graphics object.

So in the following code, should I call graphics.dispose() before returning? Or, can I?

{  ...  
BufferedImage result = new BufferedImage(toWidth, toHeight, BufferedImage.TYPE_INT_RGB);  

java.awt.Graphics graphics=result.getGraphics();

graphics.drawImage(im.getScaledInstance(toWidth, toHeight, java.awt.Image.SCALE_SMOOTH), 0, 0, null);  

return result;  
}

The BufferedImage result is returned and used elsewhere.

like image 736
smwikipedia Avatar asked Mar 26 '15 08:03

smwikipedia


2 Answers

The Graphics object can be disposed and should be disposed.

The getGraphics call of BufferedImage internally delegates to createGraphics, so there is no difference. The createGraphics call eventually delegates to the respective GraphicsEnvironment implementation, where (for the SunGraphicsEnvironment) it creates a new instance of a SunGraphics2D.

Finally, the dispose method of SunGraphics2D says the following:

  /**
   * This object has no resources to dispose of per se, but the
   * doc comments for the base method in java.awt.Graphics imply
   * that this object will not be useable after it is disposed.
   * So, we sabotage the object to prevent further use to prevent
   * developers from relying on behavior that may not work on
   * other, less forgiving, VMs that really need to dispose of
   * resources.
   */
  public void dispose() {
      surfaceData = NullSurfaceData.theInstance;
      invalidatePipe();
  }

which also gives a justification of why dispose indeed should be called (even if it is not strictly necessary in the default implementations)

like image 139
Marco13 Avatar answered Oct 22 '22 02:10

Marco13


public class Main{

    public static void main(String[] args) {
        BufferedImage img = get();

        Graphics g = img.getGraphics();

        //g.drawOval(5, 5, 5, 5); //this statement will work (you'll see the cirle)

        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        try {
            ImageIO.write( img, "jpg", baos );

            baos.flush();
            byte[] imageInByte = baos.toByteArray();
            baos.close();

            Files.write(Paths.get("test2.png"), imageInByte);
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }


    public static BufferedImage get(){
        BufferedImage res = new BufferedImage(50, 50, BufferedImage.TYPE_INT_ARGB);

        Graphics g = res.getGraphics();

        g.drawRect(0, 0, 20, 20);

        g.dispose();

        g.drawOval(5, 5, 5, 5); //this statement won't work, you'll only see the rect

        return res;
    }


}

As you can see, you can savely (and should) dispose the graphics in your method.

You can't use the graphics object in the method afterwards, so when you run the code, there won't be a circle in the picture. But if you comment out g.drawOval(5,5,5,5) in the method, but comment in the same statement in the main-Method, you will see a circle. So you can use it afterwards.

like image 32
Loki Avatar answered Oct 22 '22 02:10

Loki