This discussion is archived
10 Replies Latest reply: Jul 16, 2012 3:57 PM by jsmith RSS

LineChart in PDF with IText

925539 Newbie
Currently Being Moderated
Hello.
I'm currently developing an application that generates a chart from temperatures.
I need to generate a printing page A4 size, and want to include the chart in the middle of the page.
Can do that taking a screen capture with java.awt.Robot and putting as an image, but that is not for
production basis. Can anyone help me on this? My main goal is taking the chart and putting it in the middle
of a PDF for printing.
Thanks for your attention.
  • 1. Re: LineChart in PDF with IText
    MiPa Pro
    Currently Being Moderated
    With the latest preview release you can use the snapshot feature to create an image of your chart, convert that to a BufferedImage and you can then embed that into a PDF file via iText. You'll need the BufferedImage to either be able to write your image to a file and include that in the PDF or use the iText API directly to put the BufferedImage in there.
  • 2. Re: LineChart in PDF with IText
    925539 Newbie
    Currently Being Moderated
    But how could I do that capturing without depending on a new Stage being created for the Chart so to have a good image?
    Is there a way to put that LineChart in a Image object without a screen capture?
  • 3. Re: LineChart in PDF with IText
    MiPa Pro
    Currently Being Moderated
    >
    But how could I do that capturing without depending on a new Stage being created for the Chart so to have a good image?
    Is there a way to put that LineChart in a Image object without a screen capture?
    Yes - take a look at the snapshot method of the node class. (JavaFX 2.2 preview only !!!)
  • 4. Re: LineChart in PDF with IText
    jsmith Guru
    Currently Being Moderated
    I tried MiPa's recommendation of the snapshot (as he notes - it is not related to a screen capture) and it worked fine.
    import java.io.File;
    import java.io.IOException;
    import javafx.application.Application;
    import javafx.collections.*;
    import javafx.embed.swing.SwingFXUtils;
    import javafx.scene.*;
    import javafx.stage.Stage;
    import javafx.scene.chart.*;
    import javafx.scene.control.Label;
    import javafx.scene.image.*;
    import javafx.scene.layout.*;
    import javafx.scene.paint.Color;
    import javax.imageio.ImageIO;
    
    public class PieChartExport extends Application {
      @Override public void start(Stage stage) throws IOException {
        // create a chart.
        ObservableList<PieChart.Data> pieChartData =
          FXCollections.observableArrayList(
            new PieChart.Data("Grapefruit", 13),
            new PieChart.Data("Oranges", 25),
            new PieChart.Data("Plums", 10),
            new PieChart.Data("Pears", 22),
            new PieChart.Data("Apples", 30)
          );
        final PieChart chart = new PieChart(pieChartData);
        chart.setTitle("Imported Fruits");
    
        // render an image of the chart to a file.
        Pane chartContainer = new Pane();
        chartContainer.getChildren().add(chart);
        chart.setMinSize(Region.USE_PREF_SIZE, Region.USE_PREF_SIZE);
        chart.setPrefSize(2000, 2000);
        chart.setMaxSize(Region.USE_PREF_SIZE, Region.USE_PREF_SIZE);
        chart.setStyle("-fx-font-size: 36px;");
        Scene snapshotScene = new Scene(chartContainer); 
        SnapshotParameters params = new SnapshotParameters();
        params.setFill(Color.ALICEBLUE);
        Image image = chartContainer.snapshot(params, null);
        File file = new File("chart.png");
        ImageIO.write(SwingFXUtils.fromFXImage(image, null), "png", file);
    
        // layout the scene.
        VBox layout = new VBox(5);
        layout.getChildren().addAll(
          new Label("Wrote: " + file.getCanonicalPath()),
          new ImageView(new Image(file.toURI().toString(), 400, 0, true, true))
        );
        layout.setStyle("-fx-background-color: cornsilk; -fx-padding: 10;");
    
        // show the scene.
        stage.setScene(new Scene(layout));
        stage.show();
      }
      
      public static void main(String[] args) { launch(args); }
    }
    Edited by: jsmith on Jun 15, 2012 5:19 PM

    My first attempt at this failed, so I filed: http://javafx-jira.kenai.com/browse/RT-22558 "PieChart snapshot renders incorrectly"

    Kevin commented:
    This is a known limitation in CSS and layout processing. In order for either to work correctly for Node.snapshot(), the node in question must be attached to a Scene. The scene need not be attached to a Stage, so the following is sufficient, added any time after the chartContainer is constructed and before snapshot is called: Scene snapshotScene = new Scene(chartContainer);
    As part of finishing the API docs for snapshot, this limitation will be documented.
    Once I updated my code to construct a Scene for the node for which the snapshot was being taken, everything worked fine.
    I edited this post to include the working code.

    Note that once you save the image to a png, the 2000x2000 pixel image (at least in the case of this piechart), compresses really well (down to 164kb) - which should be fine to embed into a fairly compact and portable pdf.
  • 5. Re: LineChart in PDF with IText
    925539 Newbie
    Currently Being Moderated
    Hi. Thanks for the help.
    I can achive what i need with your help, but my chart .png comes out without the labels from the axis.
    Very strange, tried some things but no success.
    The code that takes the snapshot:
    public static void execute(ObservableList<Data<String, Double>> listData) throws IOException {                     
            ObservableList<Series<String, Double>> listSerie 
                    = FXCollections.observableArrayList();                        
            
            Series<String, Double> serie = new Series("Temperatura", listData);        
            listSerie.add(serie);
            NumberAxis y = new NumberAxis();
            CategoryAxis x = new CategoryAxis();
            LineChart chart = new LineChart(x, y, listSerie);        
                    
            Pane chartContainer = new Pane();
            chartContainer.getChildren().add(chart);
            chart.setMinSize(Region.USE_PREF_SIZE, Region.USE_PREF_SIZE);
            chart.setPrefSize(1600, 1200);
            chart.setMaxSize(Region.USE_PREF_SIZE, Region.USE_PREF_SIZE);
            chart.setStyle("-fx-font-size: 36px;");   
            Scene snapshotScene = new Scene(chartContainer);
            
            Image image = chart.snapshot(null, null);
            File file = new File("chart.png");
            ImageIO.write(SwingFXUtils.fromFXImage(image, null), "png", file);                                        
        }
    As you can see, i create a new chart with the same data. The axis are created the
    same way on both charts of the app. If i use the same chart, the first one gets vanished from
    the scene.

    This link takes you to a snapshot of my real application:
    https://dl.dropbox.com/u/21110079/Img/help-grafico.png

    This one is from the chart snapshot itself:
    https://dl.dropbox.com/u/21110079/Img/errado.png

    Maybe i'm doing the wrong way.
    Can help me with that!?
  • 6. Re: LineChart in PDF with IText
    jsmith Guru
    Currently Being Moderated
    Maybe i'm doing the wrong way.
    No I don't think so.
    Can help me with that!?
    I think this is caused by a bug in the JavaFX runtime.
    I created jira issue: http://javafx-jira.kenai.com/browse/RT-22736 "LineChart snapshot render incorrectly" so that you can track it - you can vote for or comment on the issue if you like.
  • 7. Re: LineChart in PDF with IText
    925539 Newbie
    Currently Being Moderated
    Voted, appreciate your time and concern.
    Now let me ask you:
    While that's being worked out, is there another way you can think for
    my app print a page with that chart in the middle?

    Edited by: alan-r on 20/06/2012 13:16
  • 8. Re: LineChart in PDF with IText
    jsmith Guru
    Currently Being Moderated
    is there another way you can think for my app print a page with that chart in the middle?
    no
  • 9. Re: LineChart in PDF with IText
    925539 Newbie
    Currently Being Moderated
    OK, just to close the topic and maybe help someone that tries to do the same thing.
    I was able to sort it out with some improv.
    First, if i grab take a snapshot of the LineChart from the scene, everything is ok with the picture, the two axis
    come along just fine, but the chart would vanish from the scene, leaving the screen partially empty.
    So i just instantiate a new chart with the same data and setContent(newChart) inside the AnchorPane.
    That way i have a nice pdf with the chart int he middle. The scene suffered a quick flash, with the chart recreation.
    But no problem with that, it's ok.
    One of the requirements of the app is that the user must be able to edit the values of the chart and print, slightly modified, just
    to round some pikes, and i was able to provide a live editing, allowing them to see the chart go up and down. The table and the chart
    share the same list of Data items, and providing a proper cellValueFactory does the trick.
    Thanks for the help.
  • 10. Re: LineChart in PDF with IText
    jsmith Guru
    Currently Being Moderated
    Quick update on one of the issues raised in this thread.

    jira issue: http://javafx-jira.kenai.com/browse/RT-22736 "LineChart snapshot render incorrectly"
    was resolved as Not an issue.

    Comment by Kevin Rushforth from the jira resolution:
    This is not a bug. By default, charts will animate the tick marks and labels on the axis, and a variety of other things over a period of time (up to 700 msec). So at the time the chart is created, the text labels are not yet created and won't be until after animation has run. We should document this limitation, though (I will add a note to RT-21572).

    There are two possible approaches that an application can take:

    1) set the animated property on the X and Y axes and the chart to false.

    xAxis.setAnimated(false);
    yAxis.setAnimated(false);
    chart.setAnimated(false);

    2) Wait for at least 700 msec for the animation to finish before taking the snapshot.

Legend

  • Correct Answers - 10 points
  • Helpful Answers - 5 points