Skip to content
Hrvoje Štimac edited this page Apr 26, 2017 · 27 revisions

Welcome to the boxable wiki!

FAQ

Creating text,image,table with boxable

Okay, first things first. What we always need is our PDDocument and PDPage :

PDPage myPage = new PDPage(PDRectangle.A4);
PDDocument mainDocument = new PDDocument();

If we want to add something else in our PDF document except tables (i.e some text, image etc.) then we will need content stream:

PDPageContentStream contentStream = new PDPageContentStream(mainDocument, myPage);

Text (outside of the table)

That is something that we always need. Now, how about random text in PDF document, i.e our document title

contentStream.beginText();
contentStream.setFont(PDType1Font.HELVETICA_BOLD, 22);
contentStream.moveTextPositionByAmount(50, 700);
contentStream.drawString("Document title");
contentStream.endText();

Also it is pretty easy to write some text inside PDF Document with PDStreamUtils.write(final PDPageContentStream stream, final String text, final PDFont font, final float fontSize, final float x, final float y, final Color color) method where :

  • text - The text which will be displayed.
  • font - The font of the text
  • fontSize - The font size of the text
  • x - Start X coordinate for text.
  • y - Start Y coordinate for text.
  • color - Color of the text

Maybe it is better to put that in some context, here is second example how to write document title with method mention above.

[...]
private PDPageContentStream cos;
private PDPage page;
private PDFont font = PDType1Font.HELVETICA;
private float leftMargin = 50;
private marginBetweenYElements = 10;
private float titleFontSize = 18;
[...]
private void drawPageTitle() throws IOException {
        // draw document title first
        PDStreamUtils.write(cos, "Document title", titleFontSize, leftMargin, yPosition,
                Color.BLACK);

        // drop Y position with default margin between vertical elements
        yPosition -= marginBetweenYElements;
    }

Table

What about simple table? Say no more:

//Dummy Table
    float margin = 50;
// starting y position is whole page height subtracted by top and bottom margin
    float yStartNewPage = myPage.getMediaBox().getHeight() - (2 * margin);
// we want table across whole page width (subtracted by left and right margin ofcourse)
    float tableWidth = myPage.getMediaBox().getWidth() - (2 * margin);

    boolean drawContent = true;
    float yStart = yStartNewPage;
    float bottomMargin = 70;
// y position is your coordinate of top left corner of the table
    float yPosition = 550;

    BaseTable table = new BaseTable(550, yStartNewPage, bottomMargin, tableWidth, margin, mainDocument, myPage, true, drawContent);


    Row<PDPage> headerRow = table.createRow(15f);
    Cell<PDPage> cell = headerRow.createCell(100, "Header");
    table.addHeaderRow(headerRow);


    Row<PDPage> row = table.createRow(12);
    cell = row.createCell(30, "Data 1");
    cell = row.createCell(70, "Some value");

    table.draw();


    contentStream.close();
    mainDocument.addPage(myPage);
    mainDocument.save("testfile.pdf");
    mainDocument.close();

Image

It is very similar process just like writing text. All work is done by ''Ìmage.draw(final PDDocument doc, final PDPageContentStream stream, float x, float y)'' method where:

  • doc - PDDocument where drawing will be applied
  • stream - PDPageContentStream where drawing will be applied
  • x - X coordinate for image drawing
  • y - Y coordinate for image drawing

Lets put that in context, for example, drawing logo on our PDF document:

[...]
Image image = new Image(ImageIO.read(new File("/../logo.png")));
// imagine we have pretty big logo and we want scale that a little bit
float imageWidth = 75;
image = image.scaleByWidth(imageWidth);
image.draw(document, contentStream, xPosition, yPosition)

Important Always close your contentStream before saving the document!

[...]
contentStream.close();
// Save the document
File file = new File("test.pdf");
 System.out.println("Sample file saved at : " + file.getAbsolutePath());
 Files.createParentDirs(file);
 doc.save(file);
 doc.close();

If you don’t do this you will be getting something like:

java.lang.IllegalStateException: Cannot read while there is an open stream writer
    at org.apache.pdfbox.cos.COSStream.createRawInputStream(COSStream.java:128)
[...]

Some other interesting methods for drawing and image scaling are:

draw(final PDDocument doc, final PDPageContentStream stream, float x, float y)
scaleByWidth(float width)
scaleByHeight(float height)
scale(float boundWidth, float boundHeight)

And that’s it! You are ready to go! If you want to see some more stylish tables please check next chapter.

Various table layout styles

  • The same table is printed multiple times with different layouts
  • Different pre-defined styles are used
  • 0 or more layouters can be applied to a table.
//Draw table once with default Style
table.getRows().get(0).getCells().get(0).setText("Test 4 -  Default Style");
table.getLayouters().add(new DefaultCellLayouter(Styles.DEFAULT));
table.draw();

image

//Green Style with Zebra Layouter
table.getRows().get(0).getCells().get(0).setText("Test 4 -  Green Style with Zebra Layouter");
table.getLayouters().clear();
table.getLayouters().add(new DefaultCellLayouter(Styles.GREEN));
table.getLayouters().add(new ZebraCellLayouter(Styles.GREEN));
table.draw();

image

//Candy Style with Vertical Zebra Layouter
table.getRows().get(0).getCells().get(0).setText("Test 4 -  Candy Style with Vertical Zebra Layouter");
table.getLayouters().clear();
table.getLayouters().add(new DefaultCellLayouter(Styles.CANDY));
table.getLayouters().add(new VerticalZebraCellLayouter(Styles.CANDY));
table.draw();

image

//Default Style with  Zebra Layouter and Matrix Layouter
table.getRows().get(0).getCells().get(0).setText("Test 4 -  Default Style with Zebra Layouter and Matrix Layouter and centered headers");
table.getLayouters().clear();
table.getLayouters().add(new DefaultCellLayouter(Styles.DEFAULT));
table.getLayouters().add(new ZebraCellLayouter(Styles.DEFAULT));
table.getLayouters().add(new MatrixCellLayouter(Styles.DEFAULT));
table.draw();

image

//Custom style
table.getRows().get(0).getCells().get(0).setText("Test 4 -  Custom Style");
DefaultStyle customStyle = new DefaultStyle()
                    .withBorder(new LineStyle(Color.ORANGE, (float) 0.5))
                    .withFont(PDType1Font.COURIER)
                    .withAlignAccent2(HorizontalAlignment.CENTER);
table.getLayouters().clear();
table.getLayouters().add(new DefaultCellLayouter(customStyle));
table.draw();

image

Here's the output for all of the above : APIv2.0.pdf

Landscape (A4)

PDPage page = new PDPage(new PDRectangle(PDRectangle.A4.getHeight(), PDRectangle.A4.getWidth()));

Portrait (A4)

PDPage page = new PDPage(PDRectange.A4);

How to get table height dynamically?

float newYPosition = table.draw();

How I can get current page if my table is on multiple pages? If table is displayed on multiple pages the current page can be obtained with table.getCurrentPage(). Something like :

[...]
// did we change the page?
if (table.getCurrentPage() != page) {
    cos.close();
    page = table.getCurrentPage();
    cos = new PDPageContentStream(document, page, true, true);
}

Retrieving current table page

If table is displayed on multiple pages the current page can be obtained with table.getCurrentPage(). Something like :

[...]
// did we change the page?
if (table.getCurrentPage() != page) {
    cos.close();
    page = table.getCurrentPage();
    cos = new PDPageContentStream(document, page, true, true);
}

How to get two tables with same y position?

Let's say that we want two tables by each other (pay attention on spaceBetweenTables variable and x/y positioning of the tables!)

                int startNewPageY = 700;
		int bottomMargin = 100;
		int leftMargin = 25;
		PDPage currentPage = new PDPage();
                int spaceBetweenTables = 50;
	
		// we want 2 tables so our table width is 50% of page width without left and right margin AND provided space between tables
		float tableWidth = 0.5f * (currentPage.getMediaBox().getWidth() - (2 * leftMargin)- spaceBetweenTables);
		PDDocument document = new PDDocument();
		document.addPage(currentPage);

		BaseTable table1 = new BaseTable(700, startNewPageY, bottomMargin, tableWidth, leftMargin, document,
				currentPage, true, true);
                [...]
                table1.draw();
                // pay attention where start x position for this table -> left margin + first table width + space between our tables
		BaseTable table2 = new BaseTable(700, startNewPageY, bottomMargin, tableWidth, leftMargin + tableWidth + spaceBetweenTables, document,
				currentPage, true, true);
                [...]
                table2.draw();

(Same principal is if you go with DataTable implementation)

Then we should get something like this:

Two tables

The same principle is for multiple tables where we need only adjust tableWidth variable and BaseTable's argument that is responsible for x positioning.

Clone this wiki locally