|
JFreechart Example |
This week we had an interesting conundrum at work. We had a
headless server which is not uncommon, that would not generate charts in our web based application. Apparently some of the charts are not used very often, or it would have been reported sooner. The charts in question were originally created using
Rogue Wave Software charting software from 1999-2000. This software was used to create charts in
AWT based applications. Yes, I said AWT not Swing, and I know that it is very old.
The particular charts do not have replacements available in free charting software like
JFreechart currently, and are available only as commercial software. We had purchased the original software and licenses from Rogue Wave, and did not want to purchase new commercial software.
Now to the conundrum. Since Java 1.4, heavyweight AWT and Swing components throw a
HeadlessException
, if you attempt to run them on a headless system.
As you can see from the list, it does not leave much room for the developer to work with in a headless environment. Fair enough, AWT/Swing are
GUI environments.
The graphical libraries used to create charts in the case of Rogue Wave and JFreechart generally expect a GUI framework. Rogue Wave is expecting to generate the chart images in a
Window
, or one of its subclasses like
Frame
. This can cause an issue as you can see. So I am left with a couple of components that I can use like
Component
,
Canvas
, and
Panel
.
You can create a headless environment and check it with the code below.
System.setProperty("java.awt.headless", "true");
boolean headless = GraphicsEnvironment.isHeadless();
System.out.println("Headless: " + headless);
So how do you generate the charts, or create images in general on a headless system. It turns out to be quite simple. Since all components have a
paint(Graphics g)
method, and JFreechart has a
createBufferedImage()
method. These turn out to be the keys.
Solution
We need to create a
BufferedImage
which we can pass to the
Component
to paint. Once we create the image to paint to, we simply ask the component to paint it, and use
ImageIO
to output our chart.
Note: You will need to have the Rogue Wave graphing and gif libraries, or you may comment out those code sections.
NetBeans 6.9 project files:
HeadlessAWT.zip
Headless.java
package com.bluelotussoftware.graph.headless.example;
import java.awt.*;
import java.io.*;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.util.Locale;
import com.roguewave.chart.awt.datamodels.v2_2.SampleData;
import com.roguewave.chart.awt.standard.v2_2.beans.PieChart;
import com.roguewave.chart.awt.standard.v2_2.beans.LineChart;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.encoders.ImageFormat;
import org.jfree.data.general.DefaultKeyedValuesDataset;
import org.jfree.data.general.DefaultPieDataset;
@author
@version
public class Headless {
private static BufferedImage generateRectangle(Component component, int width, int height) {
BufferedImage bufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
Graphics graphics = bufferedImage.getGraphics();
graphics.setColor(Color.WHITE);
graphics.fillRect(0, 0, width, height);
graphics.setColor(Color.ORANGE);
graphics.fill3DRect(50, 50, 300, 300, true);
component.paint(graphics);
return bufferedImage;
}
private static BufferedImage generateRectangle(Component component) {
return generateRectangle(component, 400, 400);
}
private static BufferedImage generateCylinder(int width, int height) {
Panel panel = new Panel();
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
Graphics graphics = image.getGraphics();
graphics.setColor(Color.WHITE);
graphics.fillRect(0, 0, width, height);
graphics.setColor(Color.ORANGE);
graphics.drawOval(100, 100, 50, 75);
graphics.fillOval(200, 100, 50, 75);
graphics.drawLine(125, 100, 225, 100);
graphics.drawLine(125, 175, 225, 175);
panel.paint(graphics);
return image;
}
private static boolean save(BufferedImage image, Component component) {
boolean success = false;
try {
ImageIO.write(image, "gif", new FileOutputStream(component.getClass().getSimpleName() + ".gif"));
success = true;
} catch (FileNotFoundException fnfe) {
fnfe.printStackTrace(System.err);
} catch (IOException ex) {
ex.printStackTrace(System.err);
}
return success;
}
@param
public static void main(String[] args) throws IOException {
System.setProperty("java.awt.headless", "true");
boolean headless = GraphicsEnvironment.isHeadless();
System.out.println("Headless: " + headless);
Toolkit tk = Toolkit.getDefaultToolkit();
tk.beep();
BufferedImage bufferedImage = null;
boolean success = false;
Component component = new Component() {
private static final long serialVersionUID = 3109256773218160485L;
};
Canvas canvas = new Canvas();
Panel panel = new Panel();
bufferedImage = Headless.generateRectangle(component);
success = Headless.save(bufferedImage, component);
System.out.println("Created " + component.getClass().getSimpleName() + " : " + success);
success = false;
bufferedImage = Headless.generateRectangle(canvas);
success = Headless.save(bufferedImage, canvas);
System.out.println("Created " + canvas.getClass().getSimpleName() + " : " + success);
success = false;
bufferedImage = Headless.generateCylinder(400, 400);
success = Headless.save(bufferedImage, panel);
System.out.println("Created " + panel.getClass().getSimpleName() + " : " + success);
success = false;
SampleData sd = new SampleData();
LineChart lineChart = new LineChart();
lineChart.setData(sd);
PieChart pieChart = new PieChart();
pieChart.setData(sd);
lineChart.setSize(400, 400);
pieChart.setSize(400, 400);
bufferedImage = new BufferedImage(400, 400, BufferedImage.TYPE_INT_RGB);
Graphics2D g = (Graphics2D) bufferedImage.getGraphics();
lineChart.paint(g);
ImageIO.write(bufferedImage, ImageFormat.PNG, new FileOutputStream("LineChart.png"));
pieChart.paint(g);
ImageIO.write(bufferedImage, ImageFormat.PNG, new FileOutputStream("PieChart.png"));
DefaultPieDataset dpds = new DefaultKeyedValuesDataset();
dpds.setValue("Java", 60.0);
dpds.setValue("C++", 20.0);
dpds.setValue("MS Technologies", 10.0);
dpds.setValue("Misc.", 10.0);
JFreeChart jfc = ChartFactory.createPieChart("Programming Languages", dpds, true, true, Locale.ENGLISH);
bufferedImage = jfc.createBufferedImage(400, 400);
ImageIO.write(bufferedImage, "gif", new FileOutputStream("jfc-piechart.gif"));
}
}