Java - Get an Image of a JPanel

11,952

Solution 1

Here is an SSCCE illustrating that it works. A common mistake is to pass null as the ImageObserver of the drawImage method, because the loading of the image is asynchronous.

import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;

import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

public class TestPrint {

    protected static void initUI() throws MalformedURLException {
        final ImageIcon image = new ImageIcon(new URL("http://www.travelblog.org/Wallpaper/pix/tb_fiji_sunset_wallpaper.jpg"));
        JPanel panel = new JPanel() {
            @Override
            protected void paintComponent(java.awt.Graphics g) {
                super.paintComponent(g);
                g.drawImage(image.getImage(), 0, 0, this);
            };
        };
        panel.setPreferredSize(new Dimension(image.getIconWidth(), image.getIconHeight()));
        panel.setSize(panel.getPreferredSize());
        BufferedImage bi = new BufferedImage(panel.getWidth(), panel.getHeight(), BufferedImage.TYPE_INT_RGB);
        Graphics g = bi.createGraphics();
        panel.print(g);
        g.dispose();
        try {
            ImageIO.write(bi, "png", new File("test.png"));
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {

            @Override
            public void run() {
                try {
                    initUI();
                } catch (MalformedURLException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        });
    }
}

Solution 2

Your code works for me.

Here is a simple example. Resize the frame to see the panel change size and the image move around.

public static void main(String[] args) {
    JFrame frame = new JFrame("Test");
    JPanel panel = new JPanel();
    panel.setBackground(Color.BLUE);
    JLabel label = new JLabel("Image");
    label.setForeground(Color.RED);
    panel.add(label);
    frame.add(panel, BorderLayout.NORTH);
    frame.pack();
    JLabel image = new JLabel(new ImageIcon(createImage(panel)));
    frame.add(image, BorderLayout.SOUTH);
    frame.pack();
    label.setText("Original");      
    frame.setVisible(true);
}

private static BufferedImage createImage(JPanel panel) {
    int w = panel.getWidth();
    int h = panel.getHeight();
    BufferedImage bi = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
    Graphics2D g = bi.createGraphics();
    panel.paint(g);
    return bi;
}

So your problem must be elsewhere. Make sure your panel has positive size at the point that you create an image of it.

Solution 3

Here's a quick example method that you can add to any of your Java 2/JDK 1.2 applications. Simply pass in the component you want to snapshot and the filename you want to save into.

public void saveComponentAsJPEG(Component myComponent, String filename) {
    Dimension size = myComponent.getSize();
    BufferedImage myImage = new BufferedImage(size.width, size.height, BufferedImage.TYPE_INT_RGB);
    Graphics2D g2 = myImage.createGraphics();
    myComponent.paint(g2);
    try {
        OutputStream out = new FileOutputStream(filename);
        JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(out);
        encoder.encode(myImage);
        out.close();
    } catch (Exception e) {
        System.out.println(e);
    }
}

This method is very versatile. It can be used to take snapshots of a wide variety of Java application components. Please do be forewarned, however, that you use com.sun.image.codec.jpeg at some risk to the portability of your code.

EDIT: I tested the code to make sure and all seems fine:

import com.sun.image.codec.jpeg.JPEGCodec;
import com.sun.image.codec.jpeg.JPEGImageEncoder;
import java.awt.*;
import java.awt.geom.Ellipse2D;
import java.awt.image.BufferedImage;
import java.io.FileOutputStream;
import java.io.OutputStream;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class ScreenCapture extends JFrame {

    public ScreenCapture() {
        createAndShowUI();
    }

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {

            @Override
            public void run() {
                ScreenCapture screenCapture = new ScreenCapture();
            }
        });
    }

    private void createAndShowUI() {
        setTitle("Test Screen Capture");
        setSize(300, 300);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setLocationRelativeTo(null);
        getContentPane().add(new DrawingPanel());
        setVisible(true);
        saveComponentAsJPEG(this, "C:/test.jpg");

    }

    public void saveComponentAsJPEG(Component myComponent, String filename) {
        Dimension size = myComponent.getSize();
        BufferedImage myImage = new BufferedImage(size.width, size.height, BufferedImage.TYPE_INT_RGB);
        Graphics2D g2 = myImage.createGraphics();
        myComponent.paint(g2);
        try {
            OutputStream out = new FileOutputStream(filename);
            JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(out);
            encoder.encode(myImage);
            out.close();
        } catch (Exception e) {
            System.out.println(e);
        }
    }

    class DrawingPanel extends JPanel {

        public DrawingPanel() {
            setDoubleBuffered(true);
        }

        @Override
        public void paintComponent(Graphics grphcs) {
            super.paintComponents(grphcs);
            Graphics2D g2d = (Graphics2D) grphcs;

            RenderingHints rhints = g2d.getRenderingHints();
            boolean antialiasOn = rhints.containsValue(RenderingHints.VALUE_ANTIALIAS_ON);

            if (!antialiasOn) {
                g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
            }

            Shape circle = new Ellipse2D.Float(100.0f, 100.0f, 100.0f, 100.0f);

            g2d.setColor(Color.RED);
            g2d.draw(circle);
            g2d.fill(circle);
        }
    }
}
Share:
11,952
Christos Baziotis
Author by

Christos Baziotis

Updated on June 24, 2022

Comments

  • Christos Baziotis
    Christos Baziotis almost 2 years

    I am writing a program in which I paint on a JPanel. How do I get an Image of the JPanel which is painted on it? I tried this code but all I get is a blank image with the Background color of my JPanel. The BufferedImage does not contain what is painted on my panel.

        private BufferedImage createImage(JPanel panel) {    
            int w = panel.getWidth();
            int h = panel.getHeight();
            BufferedImage bi = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
            Graphics2D g = bi.createGraphics();
            panel.paint(g);
            return bi;
        }
    

    What am I doing wrong?

  • Guillaume Polet
    Guillaume Polet almost 12 years
    @sijoune Try the code I posted above and see the differences with your code to spot your problem.
  • Christos Baziotis
    Christos Baziotis almost 12 years
    I tried it and the same thing happens. I dont get it. I must be doing something else wrong, but i cant find it.
  • David Kroukamp
    David Kroukamp almost 12 years
    check my edit, and maybe then post the code that could be giving problems, i dont see how though, because as you can see once you pass a component and filename to the method it does the rest?