25

I am using the Apache PDFBox java library to create PDFs. Is there a way to create a data-table using pdfbox? If there is no such API to do it, I would require to manually draw the table using drawLine etc., Any suggestions on how to go about this?

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
Keshav
  • 4,408
  • 8
  • 31
  • 50

4 Answers4

26

Source: Creating tables with PDFBox

The following method draws a table with the specified table content. Its a bit of a hack and will work for small strings of text. It does not perform word wrapping, but you can get an idea of how it is done. Give it a go!

/**
 * @param page
 * @param contentStream
 * @param y the y-coordinate of the first row
 * @param margin the padding on left and right of table
 * @param content a 2d array containing the table data
 * @throws IOException
 */
public static void drawTable(PDPage page, PDPageContentStream contentStream, 
                            float y, float margin, 
                            String[][] content) throws IOException {
    final int rows = content.length;
    final int cols = content[0].length;
    final float rowHeight = 20f;
    final float tableWidth = page.findMediaBox().getWidth() - margin - margin;
    final float tableHeight = rowHeight * rows;
    final float colWidth = tableWidth/(float)cols;
    final float cellMargin=5f;

    //draw the rows
    float nexty = y ;
    for (int i = 0; i <= rows; i++) {
        contentStream.drawLine(margin, nexty, margin+tableWidth, nexty);
        nexty-= rowHeight;
    }

    //draw the columns
    float nextx = margin;
    for (int i = 0; i <= cols; i++) {
        contentStream.drawLine(nextx, y, nextx, y-tableHeight);
        nextx += colWidth;
    }

    //now add the text        
    contentStream.setFont( PDType1Font.HELVETICA_BOLD , 12 );        

    float textx = margin+cellMargin;
    float texty = y-15;        
    for(int i = 0; i < content.length; i++){
        for(int j = 0 ; j < content[i].length; j++){
            String text = content[i][j];
            contentStream.beginText();
            contentStream.moveTextPositionByAmount(textx,texty);
            contentStream.drawString(text);
            contentStream.endText();
            textx += colWidth;
        }
        texty-=rowHeight;
        textx = margin+cellMargin;
    }
}

Usage:

PDDocument doc = new PDDocument();
PDPage page = new PDPage();
doc.addPage( page );

PDPageContentStream contentStream = new PDPageContentStream(doc, page);

String[][] content = {{"a","b", "1"}, 
                      {"c","d", "2"}, 
                      {"e","f", "3"}, 
                      {"g","h", "4"}, 
                      {"i","j", "5"}} ;

drawTable(page, contentStream, 700, 100, content);
contentStream.close();
doc.save("test.pdf" );
dogbane
  • 266,786
  • 75
  • 396
  • 414
  • And what about table cell content? – Rekin Oct 06 '10 at 13:19
  • 1
    To set cell text you will have to call `drawString`. It gets complicated if you want to wrap text within cells. – dogbane Oct 06 '10 at 13:21
  • I've added a basic form of word wrapping (including \n in the content string when you want it to wrap) and also custom column widths: https://gist.github.com/scobal/6125430 – Mark Pope Jul 31 '13 at 19:42
  • Hi, can i use apache pdf box for html rendering?I didn't find any solution so far. – Vikas Sharma Dec 08 '15 at 07:16
  • @androidDev This is late, but for others who want to use Apache PdfBox for Android, there is very good library that I found. https://github.com/TomRoush/PdfBox-Android/ – Shashank Saxena Feb 17 '17 at 06:39
  • drawLine method is now depricated. Any other alternative options. Thanks! – Dinesh M Jun 08 '17 at 16:53
  • 1
    @DineshMailapur for the record, I proposed an updated version for v 2.x https://stackoverflow.com/a/44721627/1997376 – Nicolas Filotto Jun 23 '17 at 12:37
16

I created a small api for creating tables using PDFBox. It can be found on github ( https://github.com/dhorions/boxable ) .

A sample of a generated pdf can be found here http://goo.gl/a7QvRM.

Any hints or suggestions are welcome.

quodlibet
  • 452
  • 3
  • 8
  • will it work for Android also?? because you have used java.awt.color class which is not supported by Dalvik VM. – androidDev May 29 '14 at 11:39
  • Are rowspan and colspan supported? – Warren Nocos Jun 02 '16 at 06:00
  • colspan is supported ( example https://s3.amazonaws.com/misc.quodlibet.be/Boxable/CSVexampleAdvanced.pdf ). – quodlibet Jun 03 '16 at 08:06
  • Actually tried Boxable. I must say if you have a small fixed table it works well. But if you need to customize something, like e.g. fixed column widths, you are screwed. Also the code quality is laking. Odd data structures like "List", ignoring generics where ever possible and a couple of other odd things. – ssindelar Sep 16 '16 at 07:00
  • Hi @Casey, thanks for using Boxable. We're always open to improving the library. You are very welcome to address some of the issues yourself and submit a pull request, or to open issues for specific problems you encounter. I'm sure the contributers will do their best to accomodate your needs. – quodlibet Sep 21 '16 at 18:06
12

Since I had the same problem some time ago I started to build a small library for it which I am also trying to keep up to date.

It uses Apache PDFBox 2.x and can be found here: https://github.com/vandeseer/easytable

It allows for quite some customizations like setting the font, background color, padding etc. on the cell level, vertical and horizontal alignment, cell spanning, word wrapping and images in cells.

Drawing tables across several pages is also possible.

You can create tables like this for instance:

enter image description here

The code for this example can be found here – other examples in the same folder as well.

philonous
  • 3,621
  • 3
  • 27
  • 24
10

The accepted answer is nice but it will work with Apache PDFBox 1.x only, for Apache PDFBox 2.x you will need to modify a little bit the code to make it work properly.

So here is the same code but that is compatible with Apache PDFBox 2.x:

The method drawTable:

public static void drawTable(PDPage page, PDPageContentStream contentStream,
    float y, float margin, String[][] content) throws IOException {
    final int rows = content.length;
    final int cols = content[0].length;
    final float rowHeight = 20.0f;
    final float tableWidth = page.getMediaBox().getWidth() - 2.0f * margin;
    final float tableHeight = rowHeight * (float) rows;
    final float colWidth = tableWidth / (float) cols;

    //draw the rows
    float nexty = y ;
    for (int i = 0; i <= rows; i++) {
        contentStream.moveTo(margin, nexty);
        contentStream.lineTo(margin + tableWidth, nexty);
        contentStream.stroke();
        nexty-= rowHeight;
    }

    //draw the columns
    float nextx = margin;
    for (int i = 0; i <= cols; i++) {
        contentStream.moveTo(nextx, y);
        contentStream.lineTo(nextx, y - tableHeight);
        contentStream.stroke();
        nextx += colWidth;
    }

    //now add the text
    contentStream.setFont(PDType1Font.HELVETICA_BOLD, 12.0f);

    final float cellMargin = 5.0f;
    float textx = margin + cellMargin;
    float texty = y - 15.0f;
    for (final String[] aContent : content) {
        for (String text : aContent) {
            contentStream.beginText();
            contentStream.newLineAtOffset(textx, texty);
            contentStream.showText(text);
            contentStream.endText();
            textx += colWidth;
        }
        texty -= rowHeight;
        textx = margin + cellMargin;
    }
}

The Usage updated to use the try-with-resources statement to close the resources properly:

try (PDDocument doc = new PDDocument()) {
    PDPage page = new PDPage();
    doc.addPage(page);

    try (PDPageContentStream contentStream = new PDPageContentStream(doc, page)) {
        String[][] content = {{"a", "b", "1"},
            {"c", "d", "2"},
            {"e", "f", "3"},
            {"g", "h", "4"},
            {"i", "j", "5"}};
        drawTable(page, contentStream, 700.0f, 100.0f, content);
    }
    doc.save("test.pdf");
}
Nicolas Filotto
  • 43,537
  • 11
  • 94
  • 122