Adding JFreeChart to Itextpdf in Landscape

A discussion forum for JFreeChart (a 2D chart library for the Java platform).

Adding JFreeChart to Itextpdf in Landscape

Postby 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.
gw1500se
 
Posts: 13
Joined: Tue Nov 21, 2017 3:36 pm

Re: Adding JFreeChart to Itextpdf in Landscape

Postby 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();
    }
}
paradoxoff
 
Posts: 1619
Joined: Sat Feb 17, 2007 1:51 pm

Re: Adding JFreeChart to Itextpdf in Landscape

Postby 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?
gw1500se
 
Posts: 13
Joined: Tue Nov 21, 2017 3:36 pm

Re: Adding JFreeChart to Itextpdf in Landscape

Postby 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.
paradoxoff
 
Posts: 1619
Joined: Sat Feb 17, 2007 1:51 pm

Re: Adding JFreeChart to Itextpdf in Landscape

Postby 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));
gw1500se
 
Posts: 13
Joined: Tue Nov 21, 2017 3:36 pm

Re: Adding JFreeChart to Itextpdf in Landscape

Postby 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).
paradoxoff
 
Posts: 1619
Joined: Sat Feb 17, 2007 1:51 pm

Re: Adding JFreeChart to Itextpdf in Landscape

Postby 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.
gw1500se
 
Posts: 13
Joined: Tue Nov 21, 2017 3:36 pm

Re: Adding JFreeChart to Itextpdf in Landscape

Postby 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.
paradoxoff
 
Posts: 1619
Joined: Sat Feb 17, 2007 1:51 pm

Re: Adding JFreeChart to Itextpdf in Landscape

Postby 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: 13
Joined: Tue Nov 21, 2017 3:36 pm

Re: Adding JFreeChart to Itextpdf in Landscape

Postby 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?
gw1500se
 
Posts: 13
Joined: Tue Nov 21, 2017 3:36 pm

Re: Adding JFreeChart to Itextpdf in Landscape

Postby 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.
paradoxoff
 
Posts: 1619
Joined: Sat Feb 17, 2007 1:51 pm

Re: Adding JFreeChart to Itextpdf in Landscape

Postby gw1500se » Fri Nov 24, 2017 4:50 pm

Thanks. I've been looking for one but there doesn't seem to be any.
gw1500se
 
Posts: 13
Joined: Tue Nov 21, 2017 3:36 pm

Re: Adding JFreeChart to Itextpdf in Landscape

Postby paradoxoff » Fri Nov 24, 2017 6:44 pm

Ok, so start with some basic debugging.
What are the values for sizeX and sizeY?
paradoxoff
 
Posts: 1619
Joined: Sat Feb 17, 2007 1:51 pm


Return to JFreeChart

Who is online

Users browsing this forum: Bing [Bot], Google [Bot], Yahoo [Bot] and 10 guests