Apache PDFBox Java library - Is there an API for creating tables?

32,320

Solution 1

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" );

Solution 2

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.

Solution 3

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.

Solution 4

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");
}
Share:
32,320

Related videos on Youtube

Keshav
Author by

Keshav

Hi!

Updated on July 09, 2022

Comments

  • Keshav
    Keshav almost 2 years

    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?

  • Rekin
    Rekin over 13 years
    And what about table cell content?
  • dogbane
    dogbane over 13 years
    To set cell text you will have to call drawString. It gets complicated if you want to wrap text within cells.
  • Mark Pope
    Mark Pope almost 11 years
    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: gist.github.com/scobal/6125430
  • androidDev
    androidDev about 10 years
    will it work for Android also?? because you have used java.awt.color class which is not supported by Dalvik VM.
  • Vikas Sharma
    Vikas Sharma over 8 years
    Hi, can i use apache pdf box for html rendering?I didn't find any solution so far.
  • Warren Nocos
    Warren Nocos about 8 years
    Are rowspan and colspan supported?
  • quodlibet
    quodlibet about 8 years
    colspan is supported ( example s3.amazonaws.com/misc.quodlibet.be/Boxable/… ).
  • ssindelar
    ssindelar almost 8 years
    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<List>", ignoring generics where ever possible and a couple of other odd things.
  • quodlibet
    quodlibet almost 8 years
    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.
  • Shashank Saxena
    Shashank Saxena over 7 years
    @androidDev This is late, but for others who want to use Apache PdfBox for Android, there is very good library that I found. github.com/TomRoush/PdfBox-Android
  • Dinesh M
    Dinesh M about 7 years
    drawLine method is now depricated. Any other alternative options. Thanks!
  • Nicolas Filotto
    Nicolas Filotto about 7 years
    @DineshMailapur for the record, I proposed an updated version for v 2.x stackoverflow.com/a/44721627/1997376
  • GhostCat
    GhostCat almost 7 years
    Half way through!
  • GhostCat
    GhostCat almost 7 years
    Sure will! I might slow down upon reaching the legendary badge ... but well, still 35 days to go for that.