6

I'm newbie in jave, my first project is draw, and save a image from JPanel, my draw is done, but I cant save it after I draw in JPanel :(, So can you help me to fix it when I open the image after draw, It doesn't contain anything :( here my codes:

package image;
import java.awt.BorderLayout;
import java.awt.Button;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Graphics;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.nio.file.Path;
import javax.imageio.ImageIO;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;


public class paint extends JFrame{
private Point points[] = new Point[10000];
private Point pointends[] = new Point[10000];
private int pointCount = 0;
private JButton save_btn;
public paint()
{
    panel paint2 = new panel();
    add(paint2,BorderLayout.CENTER);
}
private class panel extends JPanel
{   
    private paint my_paint;
    public panel()
    {   
        setBackground(Color.WHITE);
        save_btn = new JButton();
        save_btn.setText("123");
        this.add(save_btn);
        ButtonHandler handler1 = new ButtonHandler();
        save_btn.addActionListener(handler1);
        MouseHandler handler = new MouseHandler();
        this.addMouseMotionListener(handler);

        this.addMouseListener(handler);
    }
    private class ButtonHandler implements ActionListener
    {

        @Override
        public void actionPerformed(ActionEvent arg0) {
            // TODO Auto-generated method stub
            savefile();
        }

    }
    @Override
    protected void paintComponent(Graphics g) 
    {
        // TODO Auto-generated method stub
        super.paintComponent(g);
        for(int i = 0;i <pointCount;i++)
        {   
            g.setColor(Color.RED);
            g.drawLine(points[i].x, points[i].y, pointends[i].x, pointends[i].y);
        }           
    }



private class MouseHandler extends MouseAdapter
{  
    @Override
    public void mouseDragged(MouseEvent e) 
    {
        // TODO Auto-generated method stub
            pointends[ pointCount-1] = e.getPoint();
            repaint();


    }
    @Override
    public void mousePressed(MouseEvent e) {
        // TODO Auto-generated method stub
        super.mousePressed(e);
        if(pointCount < points.length)
        {
            points[ pointCount ] = e.getPoint();
            pointends[ pointCount ] = e.getPoint();
            pointCount++; 
            repaint();
        }
    }
    @Override
    public void mouseReleased(MouseEvent e) {
        // TODO Auto-generated method stub
        super.mouseReleased(e);
        /*pointends[pointCount]=e.getPoint();
        repaint();
        pointCount++;
    */
    }

    }

}
public void savefile()
{
    BufferedImage image2 = new BufferedImage(panel.WIDTH, panel.HEIGHT,     BufferedImage.TYPE_INT_RGB);
    JFileChooser jFile = new JFileChooser();
    jFile.showSaveDialog(null);
    Path pth = jFile.getSelectedFile().toPath();
    JOptionPane.showMessageDialog(null, pth.toString());
    Graphics2D graphics2D = image2.createGraphics();
    try {
        ImageIO.write(image2, "", new File(pth.toString()));
    } catch (IOException ox) {
        // TODO: handle exception
        ox.printStackTrace();

}
}
}
Đăng Nguyễn
  • 122
  • 1
  • 3
  • 9

4 Answers4

14

Create BufferedImage to store your painting. When you paint, paint on BufferedImage.

When you need to display paint on JPanel, draw BufferedImage on JPanel.

This way, you can load / save painting to file.

Something like this:

import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JPanel;

public class Paint extends JPanel{
    private BufferedImage paintImage = new BufferedImage(500, 400, BufferedImage.TYPE_3BYTE_BGR);

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

    // draw painting
    public void updatePaint(){
        Graphics g = paintImage.createGraphics();

        // draw on paintImage using Graphics

        g.dispose();
        // repaint panel with new modified paint
        repaint();
    }

    public void save() throws IOException{
        ImageIO.write(paintImage, "PNG", new File("filename.png"));
    }

    public void load() throws IOException {
        paintImage = ImageIO.read(new File("filename.png"));
        // update panel with new paint image
        repaint();
    }
}
nullptr
  • 3,320
  • 7
  • 35
  • 68
7
private void saveImage(){
    BufferedImage imagebuf=null;
    try {
        imagebuf = new Robot().createScreenCapture(panel.bounds());
    } catch (AWTException e1) {
        // TODO Auto-generated catch block
        e1.printStackTrace();
    }  
     Graphics2D graphics2D = imagebuf.createGraphics();
     panel.paint(graphics2D);
     try {
        ImageIO.write(imagebuf,"jpeg", new File("save1.jpeg"));
    } catch (Exception e) {
        // TODO Auto-generated catch block
        System.out.println("error");
    }
}

result example of snippet code

Community
  • 1
  • 1
刘远圳
  • 594
  • 6
  • 5
6

There is a nice approach:

BufferedImage image = new BufferedImage(component.getWidth(), component.getHeight(), BufferedImage.TYPE_INT_ARGB);
Graphics g = image.getGraphics();
component.paint(g);
 try {
        ImageIO.write(image, "png", new File(filename));
    } catch (IOException ex) {
        Logger.getLogger(CustomApp.class.getName()).log(Level.SEVERE, null, ex);
   }

All what it does: It creates an image with visible component's size and ARGB type for transparency support. Then it get the graphics and pass that to the component we want to have snapshot of. It paints that component's child component including anything drawn on it.

Update: You can use component.print(Graphics g) too:

Dimension componentSize = component.getPreferredSize();
component.setSize(componentSize); // need to make sure that both sizes are equal
BufferedImage image = new BufferedImage(comonent.getWidth(), component.getHeight(), BufferedImage.TYPE_INT_RGB);
Graphics g = image.createGraphics();
g.fillRect(0, 0, image.getWidth(), image.getHeight());
component.print(g);

But this function will draw only the rendered graphics of the component but not the child components. I have tested it.


Edit:

  1. Your paint extends JFrame class can have a nice name, e.g., PaintFrame extends JFrame. Class name should not have a name of a function, paint is a verb, it is a function.
  2. panel extends JPanel : why should we go down choosing a class name with first letter of lower case? We can give our component name to reflect what we are doing with it: like, we are drawing so what about MyCanvas extends JPanel
  3. Inside the panel your first statement private paint my_paint; : what is it doing here unnecessarily ?
  4. your saveFile() function belongs to the JFrame and you have created your panel (on which you are drawing) local to the frame constructor. How should the saveFile() function have access to it? Declare your painting Panel in the JFrame class context as public or private.
  5. I have written in a meaningful way to read the sizes of the component using getWidth() and getHeight() But you are writing:

         BufferedImage image2 = new BufferedImage(panel.WIDTH, panel.HEIGHT, ...);
    

And again i have completely written the code how to save the image as a png using ImageIO.write(image, "png", "myFile.png") function. Please read the answers carefully.

Following resources might be helpful:

  1. A closer look at painting mechanism.
  2. Writing and saving images
Sage
  • 15,290
  • 3
  • 33
  • 38
  • I did like your code, but when I open image that I saved by default program, It display an Image with background color is black ! :( – Đăng Nguyễn Oct 27 '13 at 19:37
  • ok, the component you were trying to draw was visible ? It needs the component to be visible with `setVisible(true)`. let me know – Sage Oct 27 '13 at 19:44
  • Swing components, except top-level components (JFrame, JDialog, JWindow), are visible by default. You don't need to manually invoke the setVisible() method. – camickr Oct 27 '13 at 20:00
  • @camickr, yes, i meant that whither it was already visible by the time he intended to create the image. I am updating the answer with another approach. It should work as i have tested – Sage Oct 27 '13 at 20:14
  • @ĐăngNguyễn, i have updated the answer. See if it works for you. – Sage Oct 27 '13 at 20:18
  • @ĐăngNguyễn, you can try the first example with `JFrame` instead of `component`. Though, it will probably draw everything to the image. – Sage Oct 27 '13 at 20:29
  • Not sure why you keep throwing out ideas. You first suggestion was fine. The problem is with the OP's code. Your second suggestion won't work because the OP's code is wrong. The OP's custom component where he does the custom painting code doesn't have a preferred size so you would be trying to create an image of size 0. The OP needs to do some basic debugging. For example the OP should try to paint the JButton first so see if the painting logic works. If it works the problem is with the custom component. If it doesn't the problem is with the solution. – camickr Oct 27 '13 at 20:38
  • :), just jumping. So that he uses the idea once he can get everything working. Thanks for suggestions though, i will obey – Sage Oct 27 '13 at 21:03
  • I know its nice to help, but the OP has to make an effort as well. I don't see the OP trying anything except saying "it doesn't work". – camickr Oct 27 '13 at 21:42
  • @camickr, hi(yes) hi(yes) sir. :) – Sage Oct 27 '13 at 22:14
  • I can't save the image from jpanel after I draw some lines in it :(,I try to fix my code but I can't, I use BufferedImage and ImageIO.write to save, is it right or wrong? – Đăng Nguyễn Oct 29 '13 at 09:02
  • @ĐăngNguyễn, why you are not paying attention to the comments and answers ? camickr has told you to change the class name definition, but you didn't! I have written in complete meaningful way to save the image, but you are not paying any attention to the answer! – Sage Oct 29 '13 at 14:36
  • oh, sr , that's my wrong , I didn't read this,now I fixing it – Đăng Nguyễn Oct 29 '13 at 15:55
  • @ĐăngNguyễn, Fix it, and if it works don't forget to accept the answer among the answers that you think the best. – Sage Oct 29 '13 at 16:03
  • I have one question, what is "component" in your code, I dont declare it before – Đăng Nguyễn Oct 29 '13 at 17:32
  • @ĐăngNguyễn, i used "component" to reflect any `JComponent`. So use your own component in place of it. – Sage Oct 29 '13 at 17:38
  • I try replace "component" with "Jpanel" or "JFrame" but It doesn't work, Should I declare it before ? – Đăng Nguyễn Oct 29 '13 at 17:47
  • @ĐăngNguyễn, No you didn't get me. The `panel` object on which you are drawing, which you have added to JFrame, that is a component, you need to replace `component` with that component(panel) – Sage Oct 29 '13 at 17:49
  • oh yes, I can save it, I use "this" for "component" :), so happy. tks so much, I must improve my skill :) – Đăng Nguyễn Oct 29 '13 at 18:15
  • @ĐăngNguyễn, yes, glad to hear that and for accepting one of the answer from this panel. At least as you have chosen one ;) – Sage Oct 29 '13 at 18:23
0

Screen Image allows you to save an image of any component.

camickr
  • 321,443
  • 19
  • 166
  • 288