Adding JFreeChart to Itextpdf in Landscape

A discussion forum for JFreeChart (a 2D chart library for the Java platform).
Post Reply
gw1500se
Posts: 19
Joined: Tue Nov 21, 2017 3:36 pm
antibot: No, of course not.

Adding JFreeChart to Itextpdf in Landscape

Post by gw1500se » Tue Nov 21, 2017 4:53 pm

I've found several suggestions for adding a JFreeChart to my PDF document but I've only gotten one to kind of work. I say "kind of work" because it does not seem to do what I need. I have a timeseries chart, that has been generated from real time sampled data displayed on the monitor from my app, which I now want to add to a PDF report. Here is my current code segment:

Code: Select all

Document document = new Document(PageSize.A4.rotate());
		Font titleFont = new Font(FontFamily.TIMES_ROMAN, 40.f, Font.NORMAL, BaseColor.BLUE);
		Font subTitleFont = new Font(FontFamily.TIMES_ROMAN, 25.f, Font.NORMAL, BaseColor.RED);
		Font dateFont = new Font(FontFamily.TIMES_ROMAN, 20.f, Font.NORMAL, BaseColor.GREEN);
		PdfWriter writer=null;
		try {
			writer=PdfWriter.getInstance(document,new FileOutputStream(filePath.getText()));
			writer.setPageEvent(new Footer(document));
			document.open();
			document.add(setParagraph("Stoker Monitor Report", titleFont));
			document.add(setParagraph(name.getText(), subTitleFont));
			document.add(setParagraph(date.getText(), dateFont));
			Rectangle page=writer.getPageSize();
			float sizeY=page.getHeight();
			float sizeX=page.getWidth();
			System.out.println("page size is "+Float.toString(sizeX)+" X "+Float.toString(sizeY));
			float currentY=writer.getVerticalPosition(false);
			System.out.println("distance from top="+Float.toString(sizeY-currentY));
			ByteArrayOutputStream bos = new ByteArrayOutputStream();
			ImageIO.write(Chart.getInstance().getImage(), "png", bos);
			Image image = Image.getInstance(bos.toByteArray());
			image.setRotationDegrees(90);
			image.scalePercent(10.f);
			document.add(image);
		} catch (DocumentException | IOException e1) {
			System.err.println("Unable to open " + filePath.getText() + " for writing");
			e1.printStackTrace();
		}
		document.close();
There are several problems I need to resolve (positioning and sizing) but the main issue at this point is the rotation and image itself. What I get seems really weird. Instead of simply getting a landscape version of the displayed chart it rotates the chart but appears to not rotate the axes. I wind up with a chart that has re-scaled the x-axis to fit the now larger y dimension (including many more ticks) and re-scaled the y-axes to fit the smaller x dimension (tick labels are now too wide to display). I am totally confused about what is happening. The 'image' object is a PDF object, right? How can it re-scale and re-label what I expected to be a copied image of the chart. There seems to be some kind of interaction between itextpdf and JFreeChart that is not making sense to me.

The bottom line is I want to take the JFreeChart created, effectively as a screenshot, and add it to my PDF document in landscape orientation. My method above seems to have been the wrong choice although it was the easiest I found. So my question is what is the proper method I should be using to accomplish what I thought would be a simple task? TIA.

paradoxoff
Posts: 1633
Joined: Sat Feb 17, 2007 1:51 pm

Re: Adding JFreeChart to Itextpdf in Landscape

Post by paradoxoff » Tue Nov 21, 2017 9:10 pm

I have no idea what the singletons Chart and Image might be, but it seems that you create a bitmap from a JFreeChart and then integrate that bitmap into a PDF document.
Is that a must-have? I am normally creating PDFs that contain the chart as vector graphic, that can be zoomed without loss of quality.
Here is an example:

Code: Select all

package jfree;

import java.awt.geom.Ellipse2D;
import java.awt.Graphics2D;
import java.awt.geom.Rectangle2D;
import java.awt.Shape;
import java.io.FileOutputStream;
import javax.swing.*;
import java.text.SimpleDateFormat;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.*;
import org.jfree.chart.plot.*;
import org.jfree.chart.renderer.xy.*;
import org.jfree.data.xy.DefaultXYDataset;
import java.awt.Color;
import com.lowagie.text.DocumentException;
import com.lowagie.text.FontFactory;
import com.lowagie.text.PageSize;
import com.lowagie.text.pdf.DefaultFontMapper;
import com.lowagie.text.pdf.PdfContentByte;
import com.lowagie.text.pdf.PdfTemplate;
import com.lowagie.text.pdf.PdfWriter;

public class SimpleXYPlotToPDF {

    public static void main(String[] args) throws Exception {
        int count = 20;
        int series = 3;
        DefaultXYDataset dataset = new DefaultXYDataset();
        long start = System.currentTimeMillis();
        long increment = 1000 * 60 * 20; //20 min
        for (int s = 0; s < series; s++) {
            double[][] data = new double[2][count];
            for (int i = 0; i < count; i++) {
                data[0][i] = start + increment * i;
                data[1][i] = (s + 1) * i;
            }
            dataset.addSeries("Series " + s, data);
        }
        SimpleDateFormat sdf = new SimpleDateFormat("dd/MMMM/yy HH,mm,ss");
        DateAxis xAxis = new DateAxis("Date axis");
        xAxis.setDateFormatOverride(sdf);
        NumberAxis yAxis = new NumberAxis("y axis");
        XYLineAndShapeRenderer renderer = new XYLineAndShapeRenderer(false, true);
        renderer.setUseOutlinePaint(true);
        Shape shape = new Ellipse2D.Double(-4, -4, 8, 8);
        for (int i = 0; i < series; i++) {
            renderer.setSeriesShape(i, shape);
            renderer.setSeriesOutlinePaint(i, Color.black);
        }
        XYPlot plot = new XYPlot(dataset, xAxis, yAxis, renderer);
        JFreeChart chart = new JFreeChart(plot);
        float width = 600;
        float height = 400;
        FileOutputStream out = new FileOutputStream("SimpleXYPlotToPDF.pdf");
        com.lowagie.text.Rectangle rect = new com.lowagie.text.Rectangle(width, height);
        com.lowagie.text.Document document = new com.lowagie.text.Document(PageSize.A4.rotate());
        PdfWriter writer = null;
        writer = PdfWriter.getInstance(document, out);
        document.open();
        DefaultFontMapper mapper = new DefaultFontMapper();
        FontFactory.registerDirectories();
        mapper.insertDirectory("C:\\WINNT\\Fonts");
        PdfContentByte cb = writer.getDirectContent();
        PdfTemplate tp = cb.createTemplate(width, height);
        Graphics2D g2d = tp.createGraphics(width, height, mapper);
        tp.setWidth(width);
        tp.setHeight(height);
        chart.draw(g2d, new Rectangle2D.Float(0, 0, width, height));
        g2d.dispose();
        cb.addTemplate(tp, 0, 0);
        document.close();
    }
}

gw1500se
Posts: 19
Joined: Tue Nov 21, 2017 3:36 pm
antibot: No, of course not.

Re: Adding JFreeChart to Itextpdf in Landscape

Post by gw1500se » Tue Nov 21, 2017 10:21 pm

Thanks for the reply. No, it is not a must have it was all I could find that I got to work. Your solution sounds much better. Can you point me to the documentation to accomplish that?

paradoxoff
Posts: 1633
Joined: Sat Feb 17, 2007 1:51 pm

Re: Adding JFreeChart to Itextpdf in Landscape

Post by paradoxoff » Wed Nov 22, 2017 10:24 am

What kind of documentation do you need?
My code sample demonstrates you to create a PDF containing a JFreeChart as vector graphic.
Google should give you sources for both the API documentation and tutorials of itext.

gw1500se
Posts: 19
Joined: Tue Nov 21, 2017 3:36 pm
antibot: No, of course not.

Re: Adding JFreeChart to Itextpdf in Landscape

Post by gw1500se » Wed Nov 22, 2017 1:53 pm

The method you suggested is one I tried and could not get to work. The first problem was that my IDE does not like the library 'com.lowagie' and I get all kinds of deprecated warnings. Documentation I found seemed to imply I should not be using that library but rather should use the Maven library instead. I was not able to put together a syntax free series of statements using 'com.itextpdf' instead. There were lots of issues depending on which graphics library I used (e.g. java.awt.text.Rectangle2D vs com.itextpdf.text.Rectangle2D) with more deprecated methods. Since I could not figure out which was correct and there was no documentation to help me resolve that, I gave up and found the method I was using.

After resolving all the deprecated method warnings, this is where I got stuck using your suggestion:

Code: Select all

Rectangle page=writer.getPageSize();
	float sizeY=page.getHeight();
	float sizeX=page.getWidth();
	PdfContentByte cb=writer.getDirectContent();
	PdfTemplate tp=cb.createTemplate(sizeX,sizeY);
	PdfGraphics2D g2d=new PdfGraphics2D(cb,sizeX,sizeY);
	tp.setWidth(sizeX);
	tp.setHeight(sizeY);
    // the following gets the errors:
    // - Graphics2D cannot be resolved to a type
    //	- The method draw(java.awt.Graphics2D, java.awt.geom.Rectangle2D) in the type JFreeChart is not applicable for the arguments (Graphics2D, 
    //	 com.itextpdf.awt.geom.Rectangle2D)
	Chart.getInstance().getChart().draw((Graphics2D) g2d, (Rectangle2D) new Rectangle2D.Float(0, 0,sizeX,sizeY));

paradoxoff
Posts: 1633
Joined: Sat Feb 17, 2007 1:51 pm

Re: Adding JFreeChart to Itextpdf in Landscape

Post by paradoxoff » Wed Nov 22, 2017 5:14 pm

gw1500se wrote: After resolving all the deprecated method warnings, this is where I got stuck using your suggestion:

Code: Select all

Rectangle page=writer.getPageSize();
    // - Graphics2D cannot be resolved to a type
    //	- The method draw(java.awt.Graphics2D, java.awt.geom.Rectangle2D) in the type JFreeChart is not applicable for the arguments (Graphics2D, 
    //	 com.itextpdf.awt.geom.Rectangle2D)
	Chart.getInstance().getChart().draw((Graphics2D) g2d, (Rectangle2D) new Rectangle2D.Float(0, 0,sizeX,sizeY));
Graphics2D cannot be resolved to a type: Solution: you need to import java.awt.Graphics. Note that you do not need to cast g2d to Graphics2D, since g2d is an instance of PdfGraphics2D which already makes it a Graphics2D because PdfGraphics2D extends Graphics2D.
For the remaining errors regarding the various Rectangle2D: admittently, it is a bit confusing to have the classes com.itextpdf.awt.geom.Rectangle2D and java.awt.geom.Rectangle2D, that do not share a common ancestor in their inheritance hierachie. You need to use the fully qualified name for at least one of the classes (as I have done for new com.lowagie.text.Rectangle).

gw1500se
Posts: 19
Joined: Tue Nov 21, 2017 3:36 pm
antibot: No, of course not.

Re: Adding JFreeChart to Itextpdf in Landscape

Post by gw1500se » Wed Nov 22, 2017 5:44 pm

Thanks but I am still not there yet. I added the suggested imports and changed the 'draw' parameters:

Code: Select all

Chart.getInstance().getChart().draw(g2d, new com.itextpdf.awt.geom.Rectangle2D.Float(0, 0,sizeX,sizeY));
It didn't help the errors:

The method draw(java.awt.Graphics2D, java.awt.geom.Rectangle2D) in the type JFreeChart is not applicable for the arguments (Graphics2D,
com.itextpdf.awt.geom.Rectangle2D)
- The method draw(Graphics2D, Rectangle2D) in the type JFreeChart is not applicable for the arguments (PdfGraphics2D, Rectangle2D.Float)
- Graphics2D cannot be resolved to a type

I imported 'java.awt.Graphics' but it did not get rid of the last error. I also tried 'java.awt.Graphics2D' and that did not help either.

paradoxoff
Posts: 1633
Joined: Sat Feb 17, 2007 1:51 pm

Re: Adding JFreeChart to Itextpdf in Landscape

Post by paradoxoff » Wed Nov 22, 2017 8:27 pm

gw1500se wrote: The method draw(java.awt.Graphics2D, java.awt.geom.Rectangle2D) in the type JFreeChart is not applicable for the arguments (Graphics2D,
com.itextpdf.awt.geom.Rectangle2D)
- The method draw(Graphics2D, Rectangle2D) in the type JFreeChart is not applicable for the arguments (PdfGraphics2D, Rectangle2D.Float)
- Graphics2D cannot be resolved to a type
First error: just use an instance of java.awt.geom.Rectangle2D and NOT one of com.itextpdf.awt.geom.Rectangle2D.
For the last erorr, I have no idea. If you have imported java.awt.Graphics2D, and you are still getting the error that it cannot be resolved to a type, then something really weird is going on. Googling for the error message suggests that it is a configuration issue with Eclipse.

gw1500se
Posts: 19
Joined: Tue Nov 21, 2017 3:36 pm
antibot: No, of course not.

Re: Adding JFreeChart to Itextpdf in Landscape

Post by gw1500se » Thu Nov 23, 2017 2:18 pm

Great! Your suggestion got rid of all errors for some reason. I am not getting the chart as I expected. My next hurdle is figuring out how to scale and position the image. But I assume that is an itextpdf issue not a jfreechart issue. Thanks again.

gw1500se
Posts: 19
Joined: Tue Nov 21, 2017 3:36 pm
antibot: No, of course not.

Re: Adding JFreeChart to Itextpdf in Landscape

Post by gw1500se » Fri Nov 24, 2017 3:07 pm

Arggg! This is so frustrating. After hours of fiddling with various parameters I am finally getting the chart to display the way I want but no matter what I try I cannot position it. This is my current code:

Code: Select all

Document document = new Document(PageSize.A4.rotate());
	Font titleFont = new Font(FontFamily.TIMES_ROMAN, 40.f, Font.NORMAL, BaseColor.BLUE);
	Font subTitleFont = new Font(FontFamily.TIMES_ROMAN, 25.f, Font.NORMAL, BaseColor.RED);
	Font dateFont = new Font(FontFamily.TIMES_ROMAN, 20.f, Font.NORMAL, BaseColor.GREEN);
	PdfWriter writer=null;
	try {
		writer=PdfWriter.getInstance(document,new FileOutputStream(filePath.getText()));
		writer.setPageEvent(new Footer(document));
		document.open();
		document.add(setParagraph("Stoker Monitor Report", titleFont));
		document.add(setParagraph(name.getText(), subTitleFont));
		document.add(setParagraph(date.getText(), dateFont));
		Rectangle page=writer.getPageSize();
		float sizeY=page.getHeight();
		float sizeX=page.getWidth();
		float scale=.7f;
		PdfContentByte cb=writer.getDirectContent();
		PdfTemplate tp=cb.createTemplate(sizeX*scale+1,sizeY*scale+1);
		PdfGraphics2D g2d=new PdfGraphics2D(cb,sizeX*scale+1,sizeY*scale+1);
		tp.setWidth(sizeX*scale+1);
		tp.setHeight(sizeY*scale+1);
		Chart.getInstance().getChart().draw(g2d, new java.awt.geom.Rectangle2D.Float(0,0,sizeX*scale,sizeY*scale));
		g2d.dispose();
		Image image=Image.getInstance(tp);
		image.setAbsolutePosition(sizeX, sizeY-200.f);
		document.add(image);
	} catch (DocumentException | IOException e1) {
		System.err.println("Unable to open " + filePath.getText() + " for writing");
		e1.printStackTrace();
	}
	document.close();
Why does 'image.setAbsolutePosition(sizeX, sizeY-200.f);' do nothing?

paradoxoff
Posts: 1633
Joined: Sat Feb 17, 2007 1:51 pm

Re: Adding JFreeChart to Itextpdf in Landscape

Post by paradoxoff » Fri Nov 24, 2017 4:43 pm

gw1500se wrote: Why does 'image.setAbsolutePosition(sizeX, sizeY-200.f);' do nothing?
An itext forum is likely to be a better place to ask. if you post this question elsewhere, please mention the other post in this thread.

gw1500se
Posts: 19
Joined: Tue Nov 21, 2017 3:36 pm
antibot: No, of course not.

Re: Adding JFreeChart to Itextpdf in Landscape

Post by gw1500se » Fri Nov 24, 2017 4:50 pm

Thanks. I've been looking for one but there doesn't seem to be any.

paradoxoff
Posts: 1633
Joined: Sat Feb 17, 2007 1:51 pm

Re: Adding JFreeChart to Itextpdf in Landscape

Post by paradoxoff » Fri Nov 24, 2017 6:44 pm

Ok, so start with some basic debugging.
What are the values for sizeX and sizeY?

Post Reply