I am drawing a graphical representation of information my simulation is generating. I have the graph displaying but the problem i am running into is to be able to save it as a .png. When it saves the png, the file is all black, so it's not saving my graph but creating some blank png file. The problem is I am having difficulty figuring out how to cast to a BufferedImage or a RenderedImage all of my attempts in eclipse throw errors and when I get it to compile, it works as how I described above. Any thoughts or suggestions? I have been stuck on this for a couple of weeks and either it is an obvious fix or I am not able to save it as png. But from the research i have conducted, it is possible to save a java 2d graphics img as a png file, I don't know what I am missing? A fresh pair of eyes would be greatly and immensely appreciated! Thank you in advance, I appreciate any and all advice or comments regarding this.
public class GraphDisplay extends JPanel implements RenderedImage {
final int PAD = 20;
Primate p;
public GraphDisplay(){
}
public GraphDisplay(Primate p){
this.p = p;
}
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D)g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
// now we can get x1,y1,x2,y2
double tlx= p.getMap().getX1();
double tly= p.getMap().getY1();
double brx= p.getMap().getX2();
double bry= p.getMap().getY2();
int w = getWidth();
int h= getHeight();
ArrayList <Tree> t= p.getMap().getTrees();
ArrayList<Double> xHist = p.getXHist();
ArrayList<Double> yHist = p.getYHist();
ArrayList<Double> testxHist = new ArrayList();
ArrayList<Double> testyHist = new ArrayList();
for(double i=34;i<1000;i+=5)
{
testxHist.add(i);
}
for(double i=34;i<1000;i+=5)
{
testyHist.add(i);
}
// Draw lines.
double scale=.45;
g2.setBackground(Color.WHITE);
g2.setPaint(Color.green.darker());
for(int i = 0; i < xHist.size()-1; i++) {
double x1 = PAD + (xHist.get(i)-tlx)*scale;
double y1 = (tly-yHist.get(i))*scale-PAD;
double x2 = PAD + (xHist.get(i+1)-tlx)*scale;
double y2 = (tly-yHist.get(i+1))*scale-PAD;
g2.draw(new Line2D.Double(x1, y1, x2, y2));
}
// Mark path points
if(p.getRoute()!=null)
{
ArrayList<Double> routeX= p.getRoute().getX();
ArrayList<Double> routeY= p.getRoute().getY();
g2.setPaint(Color.pink);
for(int i = 0; i < routeX.size()-1; i++) {
double x1 = PAD + (routeX.get(i)-tlx)*scale;
double y1 = (tly-routeY.get(i))*scale-PAD;
double x2 = PAD + (routeX.get(i+1)-tlx)*scale;
double y2 = (tly-routeY.get(i+1))*scale-PAD;
g2.draw(new Line2D.Double(x1, y1, x2, y2));
}
}
g2.setPaint(Color.red);
for(int i = 0; i < xHist.size(); i++) {
double x = PAD + (xHist.get(i)-tlx)*scale;
double y = (tly-yHist.get(i))*scale-PAD;
g2.fill(new Ellipse2D.Double(x-.75, y-.75, 1.5, 1.5));
}
//testing purposes
g2.setPaint(Color.BLACK);
for(int i=0;i<t.size();i++)
{
double x= PAD+(t.get(i).getX()-tlx)*scale;
double y= (tly-t.get(i).getY())*scale-PAD;
g2.fill(new Ellipse2D.Double(x-1,y-1,2,2));
}
}
public class GraphListener implements ActionListener
{
public void actionPerformed(ActionEvent event)
{
saveGraph(p);
}
}
public void saveGraph(Primate p)
{
ImageIcon saveIcon = new ImageIcon("save.png");
GraphDisplay graphImg = new GraphDisplay(p);
Object graph = new GraphDisplay(p);
BufferedImage buffGraph = new BufferedImage(500,500, BufferedImage.TYPE_INT_RGB);
graph = buffGraph.createGraphics();
RenderedImage rendGraph = (RenderedImage) graphImg;
String graphFileName = JOptionPane.showInputDialog("Please enter a name for the S1Mian graphical output file: ");
File f;
f = new File(graphFileName + ".png");
//every run is unique so do not allow the user to overwrite previously saved files...
if(!f.exists())
{
try{
ImageIO.write(buffGraph, "png", f);
JOptionPane.showMessageDialog(null, graphFileName + ".png has been created and saved to your directory...", "File Saved", JOptionPane.INFORMATION_MESSAGE, saveIcon);
}
catch (IOException e)
{
e.printStackTrace();
}
}
else{
JOptionPane.showMessageDialog(null, graphFileName +".png already exists please use a different file name...", "File Exists", JOptionPane.INFORMATION_MESSAGE, saveIcon);
}
}
public void createGraph(Primate p)
{
JFrame frame = new JFrame("S1Mian Graphical Output");
//frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //disabled now that graphical output is integrated into GUI as when clicked shut down entire program...
JPanel savePanel = new JPanel();
ImageIcon saveIcon = new ImageIcon("saveIcon.png");
JButton save = new JButton("Save");
save.setToolTipText("Saves the S1Mian graphical output to a .png file");
save.setIcon(saveIcon);
GraphListener gl = new GraphListener();
save.addActionListener(gl);
GraphDisplay graph = new GraphDisplay(p);
graph.setPreferredSize(new Dimension(950, 900));
JScrollPane graphScrollPane = new JScrollPane();
graphScrollPane.setViewportView(graph);
graphScrollPane.setViewportBorder(BorderFactory.createLineBorder(Color.black));
frame.getContentPane().add(graphScrollPane, BorderLayout.CENTER);
savePanel.add(save);
frame.getContentPane().add(savePanel, BorderLayout.NORTH);
frame.setSize(900,850);
frame.setLocation(200,200);
frame.setVisible(true);
}
It appears that you never actually paint to the BufferedImage in your saveGraph(..) routine.
After you create your BufferedImage and retrieve the Graphics object for that image, call the paintComponent method of your main class passing that graphics context. You also are create two GraphDisplay objects but never use either one.
At this point your BufferedImage should now have the same drawing that your panel had and you should be able to save the contents.
Screen Image will create a buffered image of the panel and write the image to a file.
See this example: Draw an Image and save to png.