JFreeCharts in PDF with JSF and Seam

Category: JBoss

5:00 PM, Thu, Dec 20 2007

In Tuesday's blog entry, we went into detail about the creation of a new JSF custom tag to render Graphics2D in a JBoss Seam PDF. Our original motivation was to be able to render arbitrary JFreeChart drawings into PDFs. JBoss Seam PDF tag library has charting capabilities built-in, but it can only produce a limited range of charts. The Seam PDF library also has the ability to render bitmap images. But it lacks the ability to render an arbitrary Graphics2D object, which means that we can't make full use of JFreeChart, or Batik SVG rendering, or Swing components, or all the other wonderful graphics capabilities of Java.

We created a tag library that takes a java.awt.Component and puts it in the PDF output. This would then allow us to render a JFreeChart with a bean method like this:

public Component getChartComponent() {
  return new org.jfree.chart.ChartPanel(chart);
}

Easy. The org.jfree.chart.ChartPanel takes a JFreeChart as an argument, and is a sub-class of javax.swing.JPanel, which itself is a subclass of java.awt.Component, which is what the Chiral PDF tag takes as a value.

I did it, and here is a zoomed-in image of what I got:

JFreeChart PDF Seam example

An ugly bitmap.

There must be something going on in the org.jfree.chart.ChartPanel that is rendering it as a BufferedImage, instead of drawing it using the vector operations of Graphics2D. I notice that there is a buffering parameter in the ChartPanel class. Maybe by setting that correctly it would work.

But rather than figuring that out, it's easier to create my own extension of java.awt.Component. I only need to write a constructor, with one line, and a paint(Graphics graphics) method, which also happens to be one line long:

public final class ChartComponent extends Component {

    public ChartComponent(JFreeChart chart) { this.chart = chart; }
    private final JFreeChart chart;
    
    @Override public void paint(Graphics gr) {
        final Graphics2D g = (Graphics2D) gr;
        chart.draw(g, new Rectangle(getWidth(), getHeight()));
    }   
}

Now my chart generating bean can return:

public Component getChartComponent() {
  return new ChartComponent(chart);
}

and we get a beautiful vector chart in the PDF:

JFreeChart PDF Seam example

It works.

Rather than creating our ChartComponent class, we could have used an anonymous inner class in the chart generating bean:

public Component getChartComponent() {
  final JFreeChart myChart = this.chart; // must be final
  return new java.awt.Component() {
    @Override public void paint(Graphics gr) {
        final Graphics2D g = (Graphics2D) gr;
        myChart.draw(g, new Rectangle(getWidth(), getHeight()));
    }
  };
}

In other news, Chiral Software is now enrolled as a JBoss contributor, and our PDF graphics tag will be included in the upcoming JBoss Seam 2.0.1.