Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Convert a JPanel to an image in a JScrollPane

I want to convert an JPanel to an image. I used the following method:

public BufferedImage createImage(){

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

But the problem is that the JPanel is contained within a JScrollPane. So when I convert the jpanel to an image, the image contains only the parts visible in the jpanel and the parts that are hidden inside the scrollpane aren't contained in the image.

Are there any solutions to get the full content of the JPanel into an image?

like image 949
Sameera Kumarasingha Avatar asked Jan 27 '13 20:01

Sameera Kumarasingha


People also ask

How do I save an image from a JPanel?

When you need to display paint on JPanel, draw BufferedImage on JPanel. This way, you can load / save painting to file. Save this answer.

Can you add image to JPanel?

You need to add the MapLabel to the top JPanel, and make sure to size them all to the full size of the image (by overriding the GetPreferredSize()).

How do I make JScrollPane transparent?

You need to use setOpaque(false) to make it transparent. Call that both on the JScrollPane, and on it's ViewPort. sp. setOpaque(false); sp.


2 Answers

But the problem is that the JPanel is contained within a JScrollPane. So when I convert the jpanel to an image, the image contains only the parts visible in the jpanel and the parts that are hidden inside the scrollpane aren't contained in the image.

This doesnt happen to me... have you tried paintAll instead of paint?

Here is a great method which will capture the content of any Component visible or not (Its not mine I got it somewhere off the SO and have used it since):

public static BufferedImage componentToImage(Component component, boolean visible) {
    if (visible) {
        BufferedImage img = new BufferedImage(component.getWidth(), component.getHeight(), BufferedImage.TRANSLUCENT);
        Graphics2D g2d = (Graphics2D) img.getGraphics();
        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        component.paintAll(g2d);
        return img;
    } else {
        component.setSize(component.getPreferredSize());
        layoutComponent(component);
        BufferedImage img = new BufferedImage(component.getWidth(), component.getHeight(), BufferedImage.TRANSLUCENT);
        CellRendererPane crp = new CellRendererPane();
        crp.add(component);
        crp.paintComponent(img.createGraphics(), component, crp, component.getBounds());
        return img;
    }
}

private static void layoutComponent(Component c) {
    synchronized (c.getTreeLock()) {
        c.doLayout();
        if (c instanceof Container) {
            for (Component child : ((Container) c).getComponents()) {
                layoutComponent(child);
            }
        }
    }
}

Here is an example showcasing the above:

The frame view:

enter image description here

capture of the panel:

enter image description here

import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import javax.imageio.ImageIO;
import javax.swing.CellRendererPane;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;

public class Test {

    public Test() {
        createAndShowGui();
    }

    private void createAndShowGui() {
        JFrame frame = new JFrame() {
            @Override
            public Dimension getPreferredSize() {//size frame purposefully smaller
                return new Dimension(100, 100);
            }
        };
        frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);

        Image img = null;
        try {
            img = ImageIO.read(new URL("http://images4.wikia.nocookie.net/__cb20120515073660/naruto/images/0/09/Naruto_newshot.png")).getScaledInstance(200, 200, Image.SCALE_SMOOTH);
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        final ImagePanel imagePanel = new ImagePanel(200, 200, img);
        JScrollPane jsp = new JScrollPane(imagePanel);
        frame.add(jsp);


        frame.pack();
        frame.setVisible(true);
        BufferedImage bi = componentToImage(imagePanel, true);
        try {
            File outputfile = new File("c:/saved.png");
            ImageIO.write(bi, "png", outputfile);
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    public static BufferedImage componentToImage(Component component, boolean visible) {
        if (visible) {
            BufferedImage img = new BufferedImage(component.getWidth(), component.getHeight(), BufferedImage.TRANSLUCENT);
            Graphics2D g2d = (Graphics2D) img.getGraphics();
            g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
            component.paintAll(g2d);
            return img;
        } else {
            component.setSize(component.getPreferredSize());
            layoutComponent(component);
            BufferedImage img = new BufferedImage(component.getWidth(), component.getHeight(), BufferedImage.TRANSLUCENT);
            CellRendererPane crp = new CellRendererPane();
            crp.add(component);
            crp.paintComponent(img.createGraphics(), component, crp, component.getBounds());
            return img;
        }
    }

    private static void layoutComponent(Component c) {
        synchronized (c.getTreeLock()) {
            c.doLayout();
            if (c instanceof Container) {
                for (Component child : ((Container) c).getComponents()) {
                    layoutComponent(child);
                }
            }
        }
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                new Test();
            }
        });
    }
}

class ImagePanel extends JPanel {

    int width, height;
    Image bg;

    public ImagePanel(int width, int height, Image bg) {
        this.width = width;
        this.height = height;
        this.bg = bg;
    }

    @Override
    public Dimension getPreferredSize() {
        return new Dimension(width, height);
    }

    @Override
    protected void paintComponent(Graphics grphcs) {
        super.paintComponent(grphcs);
        grphcs.drawImage(bg, 0, 0, null);
    }
}

UPDATE:

As per your comment:

I wrote the BufferedImage into a file by using ImageIO.write(bufferedImage, "jpg" , file); this works fine for both png and gif images, but jpg image shows a red background instead of white. How can i slove that problem. Thanks

See this similar question/answer for more. You would do something like:

private static final int[] RGB_MASKS = {0xFF0000, 0xFF00, 0xFF};
private static final ColorModel RGB_OPAQUE = new DirectColorModel(32, RGB_MASKS[0], RGB_MASKS[1], RGB_MASKS[2]);
...

BufferedImage image = componentToImage(imagePanel, true);
saveJPeg(image, "c:/saved.jpg");

private void saveJPeg(BufferedImage image, String name) {
    PixelGrabber pg = new PixelGrabber(image, 0, 0, -1, -1, true);
    try {
        pg.grabPixels();
    } catch (InterruptedException ex) {
        ex.printStackTrace();
    }
    int width = pg.getWidth(), height = pg.getHeight();

    DataBuffer buffer = new DataBufferInt((int[]) pg.getPixels(), pg.getWidth() * pg.getHeight());
    WritableRaster raster = Raster.createPackedRaster(buffer, width, height, width, RGB_MASKS, null);
    BufferedImage bi = new BufferedImage(RGB_OPAQUE, raster, false, null);

    try {
        ImageIO.write(bi, "jpg", new File(name));
    } catch (IOException ex) {
        ex.printStackTrace();
    }
}
like image 172
David Kroukamp Avatar answered Oct 09 '22 15:10

David Kroukamp


SwingUtilities.paintComponent does it:

static void drawComponent(JComponent c,
                          BufferedImage destination) {

    JFrame frame = new JFrame();

    Graphics g = destination.createGraphics();

    SwingUtilities.paintComponent(g, c, frame.getContentPane(),
        0, 0, destination.getWidth(), destination.getHeight());

    g.dispose();

    frame.dispose();
}

static BufferedImage createSnapshotOf(JComponent c) {

    Dimension size = c.getSize();
    if (size.width <= 0 || size.height <= 0) {
        size = c.getPreferredSize();
    }

    BufferedImage snapshot =
        new BufferedImage(size.width, size.height,
            BufferedImage.TYPE_INT_ARGB);

    drawComponent(c, snapshot);

    return snapshot;
}
like image 44
VGR Avatar answered Oct 09 '22 15:10

VGR