2

I'm trying to learn PDFBox v2.0 but there seems to be few useful examples and tutorials to get started.

I want to create a simple PDF with text only (no images and fancy stuff) and it looks as the following:

1- Introduction
   This is an intro to the document

2- Data
   2.1- DataPart1
   This is some text here....
   2.2- DataPart2
   This is another text right here!

3- More Information
   Some important informational text here...

I have written the following code:

       PDPage firstPage = getNewPage();
PDPageContentStream firstContentStream = new PDPageContentStream(document, firstPage);
firstContentStream.setFont(HEADING_FONT, HEADING_FONT_SIZE);
firstContentStream.setNonStrokingColor(Color.BLUE);
firstContentStream.beginText();
firstContentStream.newLineAtOffset(MARGIN, firstPage.getMediaBox().getHeight() - MARGIN);
firstContentStream.showText("1- Introduction");
firstContentStream.endText();

firstContentStream.setFont(TEXT_FONT, TEXT_FONT_SIZE);
firstContentStream.setNonStrokingColor(Color.BLACK);
firstContentStream.beginText();
firstContentStream.showText("This document lists all the impacts that have been observed during the QA validation of the version v3.1 build");
firstContentStream.endText();
firstContentStream.close();
document.addPage(firstPage);

The text "This is the document intro" appears at the end of the page!

My question: do I have to set the cursor or the offset on every line???!

This seems like hard work. Does this mean I have to compute the string width and compare it to the page width and jump to new lines whenever the text fills the entire line?

I really don't understand.

And also how do I make it generate new pages whenever the current page is full?

Could you please give one simple example? Thanks in advance

Can't I just do something like:

contentStream.addTextOnNewLine("Some text here...");
  • 1
    possible duplicate of https://stackoverflow.com/questions/19635275/how-to-generate-multiple-lines-in-pdf-using-apache-pdfbox and https://stackoverflow.com/questions/16541660/creating-a-new-pdf-document-using-pdfbox-api – Tilman Hausherr Jul 01 '16 at 08:16
  • 1
    no you can't just do something like `contentStream.addTextOnNewLine()` and expect magic to happen. Unlike itext, PDFBox is rather low level. I had the same problem a few years ago, it cost me an afternoon to implement wrapping and reset when new page, but this is of course individual to an application. (Moving to a new page is the same as the code you already have, i.e. `new PDPage`, then `new PDPageContentStream()`, and `PDDocument.addPage()`. You may also have a look at the Boxable project, they use PDFBox and operate on a higher level. – Tilman Hausherr Jul 01 '16 at 08:21

1 Answers1

4

First of all please be aware that PDFBox has a very low-level text drawing API only, i.e. most methods you call directly correspond to a single instruction in the PDF content stream. In particular PDFBox does not come with a (publicly accessible) layout'ing functionality but you essentially have to do the layout'ing in your code. This is both a freedom (you are not bound by the limits of an existing machinery) and a burden (you have to do everything yourself).

In your case that means:

Does this mean I have to compute the string width and compare it to the page width and jump to new lines whenever the text fills the entire line?

Yes. Confer the answers @Tilman linked for you

and search some more on stackoverflow, there are further answer on different variations of that theme, e.g. for justified text blocks here.

But there is a detail in your code which in your case makes things possibly harder than necessary:

My question: do I have to set the cursor or the offset on every line???!

While you do have to re-position for every new line, it suffices to re-position by offset from the start of the previous line if you still are in the same text object, i.e. if you have not called endText() and beginText() in-between. E.g.:

PDPage firstPage = getNewPage();
PDPageContentStream firstContentStream = new PDPageContentStream(document, firstPage);
firstContentStream.setFont(HEADING_FONT, HEADING_FONT_SIZE);
firstContentStream.setNonStrokingColor(Color.BLUE);
firstContentStream.beginText();
firstContentStream.newLineAtOffset(MARGIN, firstPage.getMediaBox().getHeight() - MARGIN);
firstContentStream.showText("1- Introduction");
// removed firstContentStream.endText();

firstContentStream.setFont(TEXT_FONT, TEXT_FONT_SIZE);
firstContentStream.setNonStrokingColor(Color.BLACK);
// removed firstContentStream.beginText();
firstContentStream.newLineAtOffset(0, -TEXT_FONT_SIZE); // reposition, tightly packed text lines
firstContentStream.showText("This document lists all the impacts that have been observed during the QA validation of the version v3.1 build");
firstContentStream.endText();
firstContentStream.close();
document.addPage(firstPage);

newLineAtOffset(0, -TEXT_FONT_SIZE) sets the text insertion position at the same x coordinate as the start of the previous line and TEXT_FONT_SIZE units lower.

(Using TEXT_FONT_SIZE here will result in pretty tightly set text lines; you may want to use a higher value, e.g. 1.4 times the font size.)

Considering your description you might want to use a positive x offset value for the line after a heading, though.

The text "This is the document intro" appears at the end of the page!

This happens because the PDF instruction generated by firstContentStream.beginText() resets the text insertion position to the origin (0, 0) which by default is the lower left corner.

And also how do I make it generate new pages whenever the current page is full?

Well, it does not happen automatically, you explicitly have to do that when you want to switch to a new page. And you do that more or less exactly like you created your first page.

Community
  • 1
  • 1
mkl
  • 90,588
  • 15
  • 125
  • 265