Search code examples
imageswingjappletjava

Saving JPanel as image


I am developing an application allow user load an image in a layer. User can draw some picture on another layer and save only the image that user drawn.Here is my code:

import java.awt.Dimension;
import java.awt.Graphics;
import javax.swing.ImageIcon;
import javax.swing.JApplet;
import javax.swing.JLabel;
import javax.swing.JLayeredPane;
import javax.swing.JPanel;

public class LayerDemo extends JApplet {

    private JLayeredPane mainLayer;

    private JPanel layer1;

    private JPanel layer2;

    private JLabel label;

    private ImageIcon imgIcon;


    /**
     * Create the applet.
     */
    public LayerDemo() {    
    }

    public void init() {
        Dimension mainDemension = new Dimension(1024,768);
        setSize(mainDemension);

        mainLayer = new JLayeredPane();   
        layer1 = new JPanel();
        layer1.setOpaque(false);
        layer1.setBounds(0, 0, this.getWidth(), this.getHeight());
        imgIcon = new ImageIcon("bear.jpg");
        label = new JLabel(imgIcon);
        label.setBounds(0, 0, imgIcon.getIconWidth(), imgIcon.getIconHeight());
        layer1.add(label);

        layer2 = new PaintDemo(true);
        layer2.setOpaque(false);
        layer2.setBounds(0, 0, this.getWidth(), this.getHeight());

        mainLayer.add(layer1, 1);
        mainLayer.add(layer2, 2);
        this.setContentPane(mainLayer);
    }

    public void paint(Graphics g) {    
    }

}

This is the class for user draw:

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.RenderingHints;
import javax.imageio.ImageIO;
import javax.swing.JPanel;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import java.awt.event.MouseWheelListener;
import java.awt.event.MouseWheelEvent;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;

public class PaintDemo extends JPanel {
    /**
     * field explanation
     */
    private Point startPoint = new Point();

    private Point endPoint = new Point();

    private Graphics2D g2;

    private int minX;

    private int minY;

    private int maxX;

    private int maxY;

    private int height;

    private int width;


    /**
     * Create the panel.
     */

    public PaintDemo(boolean isDoubleBuffer) {

        addMouseWheelListener(new MouseWheelListener() {
            public void mouseWheelMoved(MouseWheelEvent e) {
            }
        });
        this.setDoubleBuffered(isDoubleBuffer);
        addMouseMotionListener(new MouseMotionAdapter() {
            @Override
            public void mouseDragged(MouseEvent e) {
                endPoint = e.getPoint();
                Graphics g = PaintDemo.this.getGraphics();
                paintComponent(g);
                minX = minX < endPoint.x ? minX : endPoint.x;
                minY = minY < endPoint.y ? minY : endPoint.y;
                maxX = maxX > endPoint.x ? maxX : endPoint.x;
                maxY = maxY > endPoint.y ? maxY : endPoint.y;
                startPoint = endPoint;
            }
        });
        addMouseListener(new MouseAdapter() {
            @Override
            public void mousePressed(MouseEvent e) {
                startPoint = e.getPoint();
                minX = startPoint.x;
                minY = startPoint.y;
                maxX = startPoint.x;
                maxY = startPoint.y;
            }

            @Override
            public void mouseReleased(MouseEvent e) {
                endPoint = e.getPoint();
                Graphics g = PaintDemo.this.getGraphics();
                paintComponent(g);
                minX = minX < endPoint.x ? minX : endPoint.x;
                minY = minY < endPoint.y ? minY : endPoint.y;
                maxX = maxX > endPoint.x ? maxX : endPoint.x;
                maxY = maxY > endPoint.y ? maxY : endPoint.y;
                minX = minX > 0 ? minX : 0;
                minY = minY > 0 ? minY : 0;
                maxX = maxX < 1024 ? maxX : 1024;
                maxY = maxY < 768 ? maxY : 768;
                width = maxX - minX;
                height = maxY - minY;
                saveImage();     
                startPoint = new Point();
                endPoint = new Point();

            }
        });
    }

    /**
     * Paint method
     * 
     * {@inheritDoc}
     */
    @Override
    public void paintComponent(Graphics g) {
        g2 = (Graphics2D)g;
        g2.setStroke(new BasicStroke(2, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
        g2.setFont(new Font("Serif", Font.BOLD, 18));
        g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        g2.setColor(Color.red);
        g2.drawLine(startPoint.x, startPoint.y, endPoint.x, endPoint.y);
    }

    public void saveImage() {
        BufferedImage bi = new BufferedImage(PaintDemo.this.getWidth(), PaintDemo.this.getHeight(), BufferedImage.TYPE_INT_RGB);
        Graphics2D g2 = bi.createGraphics();
        paintComponent(g2);
        g2.dispose();
        try
        {
            ImageIO.write(bi, "jpg", new File("clip.jpg"));
        }
        catch(IOException ioe)
        {
            System.out.println("Clip write help: " + ioe.getMessage());
        }
    }
}

When save the image, it just blank image.Please help me.Thank you so much. P/S: I have edited my code as your idea but it is not work. The result is no image background and still save blank image. :(


Solution

  • Custom painting is done by overriding the paintComponent() method of the panel. Then you use the Graphics object to do you painting.

    You should NOT have an empty paint() method.

    The drawline() method shouuld not use the getGraphics() method. Instead that code should be moved to the paintComponent() method and then use the Graphics object passed to the method.

    Also, you should NOT be overriding the paint() method of the applet. Since your code is painting the image at its actual size you should just use a JLabel to display the image by creating an ImageIcon. Then you add the label to the layered pane to use as your background image.

    Edit:

    Why do you still have the empty paint() method? Get rid of it there is no need to override the paint() method.

    When I run the code I get a security exception since applets are not able to write to a file so I can't test that part of your code. But in case you are interested I use Screen Image to create images of a component.

    However, you main problem is that the painting code is wrong. Yes you will see lines drawn, but they are not permanent. You should never use the getGraphics() method of a component when you want to do permanent paintinting. Try drawing some lines, then minimize the applete and then restore the applet and you will see what I mean.

    The solution for this is to do your drawing on a BufferedImage. See the DrawOnImage example from Custom Painting Approaches.