Generating PDF in Java Using PDFBox Tutorial

We have already seen examples of generating PDF in Java using iText and generating PDF in Java using OpenPDF. In this post we’ll learn about another option for generating PDF in Java using Apache PDFBox.

Apache PDFBox library

The Apache PDFBox library (https://pdfbox.apache.org/) is an open source Java tool for working with PDF documents. This project allows creation of new PDF documents, manipulation of existing documents and the ability to extract content from documents.

Maven Dependency for PDFBox

<dependency>
  <groupId>org.apache.pdfbox</groupId>
  <artifactId>pdfbox</artifactId>
  <version>2.0.13</version>
</dependency>

Examples of PDF generation using PDFBox and Java given in this post.

HelloWorld PDF using Java and PDFBox

We’ll start with creating a simple HelloWorld PDF which also shows font and text color settings for the content. For creating a PDF using PDFBox and adding content to it you need to do the following steps.

  1. Create a new PDF document using PDDocument class. Instantiating this class you can create an empty PDF document.
  2. Add page to that empty PDF document using PDPage class. This adds a blank page to the PDF document.
  3. Write to that page using PDPageContentStream class.
  4. You need to call beginText() method of the PDPageContentStream class before starting text operations and endText() method to end text operations.
  5. For setting the starting position for the line use newLineAtOffset() method. Original position on a page is at the bottom left corner, you need to bring it to the position from where you want the text to start.
import java.awt.Color;
import java.io.IOException;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDPageContentStream;
import org.apache.pdfbox.pdmodel.font.PDType1Font;

public class HelloWorldPDF {
  public static final String CREATED_PDF = "F://knpcode//result//PDFBox//HelloWorld.pdf";
  public static void main(String[] args) {
    try {
      PDDocument pdfDoc = new PDDocument();
      PDPage firstPage = new PDPage();
      // add page to the PDF document
      pdfDoc.addPage(firstPage);
      // For writing to a page content stream
      try(PDPageContentStream cs = new PDPageContentStream(pdfDoc, firstPage)){
        cs.beginText();
        // setting font family and font size
        cs.setFont(PDType1Font.COURIER, 15);
        // color for the text
        cs.setNonStrokingColor(Color.RED);
        // starting position
        cs.newLineAtOffset(20, 750);
        cs.showText("Hello World PDF created using PDFBox");
        // go to next line
        cs.newLine();
        cs.endText();
      }
      // save PDF document
      pdfDoc.save(CREATED_PDF);
      pdfDoc.close();
    } catch (IOException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }
  }
}

Hello World PDFBox Java

Adding Multiple lines and multi-line text to PDF using PDFBox

If you have to add multiple lines to PDF and there is a text that spans multiple lines then the extra methods that you need to use are-

  1. Use newLine() method of the PDPageContentStream class to move to the start of the next line of text. This requires the leading to have been set which can be done using setLeading() method.
  2. For text spanning multiple lines there is no support in PDFBox so you need to do that calculation using the allowed width for the page and using the font size and width to calculate the space taken by each word in the line.
import java.awt.Color;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDPageContentStream;
import org.apache.pdfbox.pdmodel.font.PDFont;
import org.apache.pdfbox.pdmodel.font.PDType1Font;

public class CreatePDF {
	public static final String CREATED_PDF = "F://knpcode//result//PDFBox//Content.pdf";
	public static void main(String[] args) {
		try {
			PDDocument pdfDoc = new PDDocument();
			PDPage firstPage = new PDPage();
			// add page to the PDF document
			pdfDoc.addPage(firstPage);
			// For writing to a page content stream
			try(PDPageContentStream cs = new PDPageContentStream(pdfDoc, firstPage)){
				cs.beginText();
				cs.setFont(PDType1Font.COURIER, 15);
				cs.newLineAtOffset(20, 750);
				cs.setLeading(12);
				cs.showText("Hello World PDF created using PDFBox");
				cs.newLine();
				String text = "This text spans multiple lines and it is added to the PDF dcoument generated using PDFBox";
				showMultiLineText(text, 20, 762, 580, firstPage, cs, PDType1Font.COURIER, 15);
				cs.setFont(PDType1Font.TIMES_BOLD, 15);
				cs.setNonStrokingColor(Color.RED);
				cs.showText("While adding this line font and color settings are changed.");
				cs.newLine();
				cs.endText();
			}
			pdfDoc.save(CREATED_PDF);
			pdfDoc.close();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
  private static void showMultiLineText(String text, int x, int y, int allowedWidth, PDPage page, PDPageContentStream contentStream, PDFont font, int fontSize) throws IOException {
    List<String> lines = new ArrayList<String>();
    String line = "";
    // split the text on spaces
    String[] words = text.split(" ");
    for(String word : words) {
      if(!line.isEmpty()) {
        line += " ";
      }
      // check if adding the word to the line surpasses the width of the page
      int size = (int) (fontSize * font.getStringWidth(line + word) / 1000);
      if(size > allowedWidth) {
        // if line + word surpasses the width of the page, add the line without the current word
        lines.add(line);
        // start new line with the current word
        line = word;
      } else {
        // if line + word fits the page width, add the current word to the line
        line += word;
      }
    }
    lines.add(line);
    for(String ln : lines) {
      System.out.println("Line- " + ln);    
      contentStream.showText(ln);
      contentStream.newLine();
    }
  }
}

MultiLine Text PDFBox

Adding text to an existing PDF using PDFBox

If you want to add a new page to an existing PDF document then you can load existing PDF using load() method of the PDDocument class.

import java.io.File;
import java.io.IOException;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDPageContentStream;
import org.apache.pdfbox.pdmodel.font.PDType1Font;

public class CreatePDF {
	public static final String CREATED_PDF = "F://knpcode//result//PDFBox//Content.pdf";
	public static void main(String[] args) {
		try {
			// Load existing PDF
			PDDocument pdfDoc = PDDocument.load(new File(CREATED_PDF));
			PDPage page = new PDPage();
			// add page to the PDF document
			pdfDoc.addPage(page);
			// For writing to a page content stream
			try(PDPageContentStream cs = new PDPageContentStream(pdfDoc, page)){
				cs.beginText();
				cs.setFont(PDType1Font.TIMES_ROMAN, 12);
				cs.newLineAtOffset(20, 750);
				cs.setLeading(12);
				cs.showText("This is a new page added to an existing PDF document");
				cs.newLine();
				cs.endText();
			}
			pdfDoc.save(CREATED_PDF);
			pdfDoc.close();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
}

Converting text file to PDF using PDFBox

In the Java example there is a text file (Test.txt) which is converted to a PDF using PDFBox. In this example we’ll also cover the scenario where apart from text that may span multiple lines there is content that may span multiple pages in the PDF. In PDFBox each new page has to be created and added to the document before content can be written to that page.
For content in multiple pages in PDFBox you need to keep track of the height of the content in the page and when that height exceeds the allowed height add a new page. Allowed height may vary based on the type of the document, in this example A4 page size is considered.
Current height is calculated by adding line height to current height for each line written to the PDF document.

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDPageContentStream;
import org.apache.pdfbox.pdmodel.font.PDFont;
import org.apache.pdfbox.pdmodel.font.PDType1Font;

public class CreatePDF {
  // Text file that has to be converted
  public static final String SOURCE_FILE = "F://knpcode//result//Test.txt";
  public static final String CREATED_PDF = "F://knpcode//result//PDFBox//Content.pdf";
  static double currentHeight = 0;
  static PDPageContentStream cs = null;
  public static void main(String[] args) {
    try {
      PDDocument pdfDoc = new PDDocument();
      // for text file
      BufferedReader br = new BufferedReader(new FileReader(SOURCE_FILE));
      PDPage page = new PDPage();
      // add page to the PDF document
      pdfDoc.addPage(page);
      String line;
      cs = new PDPageContentStream(pdfDoc, page);
      cs.beginText();
      cs.setFont(PDType1Font.TIMES_ROMAN, 12);
      cs.newLineAtOffset(20, 750);
      cs.setLeading(12);
      // Read text file line by line
      while ((line = br.readLine()) != null) {
        System.out.println("Line-- " + line);
        showMultiLineText(pdfDoc, line, 20, 750, 580, 820, page, PDType1Font.TIMES_ROMAN, 15);				
      }				
      if(cs != null) {
        cs.endText();
        cs.close();
      }
      pdfDoc.save(CREATED_PDF);
      br.close();
      pdfDoc.close();
    } catch (IOException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }
  }
	
  /**
   * 
   * @param pdfDoc
   * @param text
   * @param x
   * @param y
   * @param allowedWidth - allowed width for the line before content goes to next line
   * @param allowedHeight - Allowed height for the page before another page is added
   * @param page
   * @param font
   * @param fontSize
   * @throws IOException
   */
  private static void showMultiLineText(PDDocument pdfDoc, String text, int x, int y, int allowedWidth, double allowedHeight, PDPage page, PDFont font, int fontSize) throws IOException {
    List<String> lines = new ArrayList<String>();
    String line = "";
    // split the text on spaces
    String[] words = text.split(" ");
    for(String word : words) {
      if(!line.isEmpty()) {
        line += " ";
      }
      // check if adding the word to the line surpasses the width of the page
      int size = (int) (fontSize * font.getStringWidth(line + word) / 1000);
      if(size > allowedWidth) {
        // if line + word surpasses the width of the page, add the line without the current word
        lines.add(line);
        // start new line with the current word
        line = word;
      } else {
        // if line + word fits the page width, add the current word to the line
        line += word;
      }
    }
    lines.add(line);

    for(String ln : lines) {
      System.out.println("Line- " + ln); 
      // for each line add line height to current height 
      // line height = 1.2 * fontSize is taken here 
      currentHeight = currentHeight + 1.2 * fontSize;
      System.out.println("currentHeight " + currentHeight);

      if(currentHeight >= allowedHeight) {
        System.out.println("adding new page " + currentHeight);
        // When current height is more than allowed height for the page
        // create a new page
        page = new PDPage();
        // add page to the PDF document
        pdfDoc.addPage(page);
        // reset currentHeight
        currentHeight = 0;
        cs.endText();
        cs.close();
        cs = new PDPageContentStream(pdfDoc, page);
        cs.beginText();
        cs.setFont(PDType1Font.TIMES_ROMAN, 12);
        cs.newLineAtOffset(20, 750);
        cs.setLeading(12);
      }
      cs.showText(ln);
      cs.newLine();  
    }
  }
}

Adding image to a PDF documents using PDFBox

To add an image to PDF document, PDImageXObject class in PDFBox library is used.

import java.io.IOException;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDPageContentStream;
import org.apache.pdfbox.pdmodel.font.PDType1Font;
import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject;

public class PDFImage {
  public static final String CREATED_PDF = "F://knpcode//result//PDFBox//Image.pdf";
  public static void main(String[] args) {		
    PDDocument pdfDoc;
    try {
      pdfDoc = new PDDocument();	
      PDPage page = new PDPage();
      pdfDoc.addPage(page);
      // Create image object using the image location
      PDImageXObject image = PDImageXObject.createFromFile("images//PDFBox image.png", pdfDoc);
      try(PDPageContentStream cs = new PDPageContentStream(pdfDoc, page)){
        cs.beginText();
        // setting font family and font size
        cs.setFont(PDType1Font.HELVETICA_BOLD, 14);
        // starting position in the page
        cs.newLineAtOffset(20, 700);
        cs.setLeading(12);
        cs.showText("In this page an image is added using PDFBox");
        cs.newLine();
        cs.endText();
        cs.drawImage(image, 20, 550);
      }
      pdfDoc.save(CREATED_PDF);
      pdfDoc.close();
        
    }catch (IOException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }		
  }
}

Image PDFBox Java
Related Posts

That’s all for the topic Generating PDF in Java Using PDFBox Tutorial. If something is missing or you have something to share about the topic please write a comment.


You may also like

6 Comments

  1. Hello!
    This article looks really nice,a lot more easier than the earliest versions of pdfBox.I have one issue that i cannot solve from one week.I can’t calculate the end of a page.I should have an exact picture at every single page.Since my table is going on the second page of the pdf document i have that picture only on the first page.Could you help me solve this.

  2. You can get total no. of pages using getNumberOfPages() method.

    PDDocument doc = PDDocument.load(new File(“sample.pdf”));
    int totalPages = pdfDoc.getNumberOfPages();

  3. Hi,
    My program logic requires me to write dynamic data onto pdf. I have written code that generates a new page whenever the Y offset goes below 200. Then I want to write content to this new page. but my content streamer overwrites data on the first page again. So I end up with first page being overwritten many times and the remaining pages are empty

  4. I hope you are adding a new page and opening stream for that page-
    if(Y offset > 200) THEN
    PDPage page = new PDPage();
    // add page to the PDF document
    pdfDoc.addPage(page);
    try(PDPageContentStream cs = new PDPageContentStream(pdfDoc, page)){
    Write data

    }

  5. Hi,
    I am. I even tried using a new content stream. Giving a simplified version where I am trying to add 3 lines on one page, then add another page and then write the fourth line there. but it still overwrites line text 4 on text 1 of the first page
    This is my code:

    PDDocument document = new PDDocument();
    PDPage page = new PDPage(PDRectangle.A4);
    document.addPage(page);
    PDPageContentStream contentStream = new PDPageContentStream(document, page,true,true);
    contentStream.beginText();
    contentStream.setFont(PDType1Font.COURIER, 12);
    contentStream.setLeading(15f);
    contentStream.newLineAtOffset(100,800);
    System.out.println(c.size());
    contentStream.showText(“text1”);
    contentStream.newLine();
    contentStream.showText(“text2”);
    contentStream.newLine();
    contentStream.showText(“text3”);
    contentStream.newLine();
    contentStream.endText();
    contentStream.close();
    PDPage newpage = new PDPage(PDRectangle.A4);
    document.addPage(newpage);
    PDPageContentStream contentStream1 = new PDPageContentStream(document, page,true,true);
    contentStream1.beginText();
    contentStream1.setFont(PDType1Font.COURIER, 12);
    contentStream1.setLeading(15f);
    contentStream1.newLineAtOffset(100,800);

    contentStream1.showText(“text4”);
    contentStream1.endText();
    contentStream1.close();

  6. I think i figured out why. I make a page called “newPage”, but i am creating the content stream for the initial page

    the code should be changed to
    PDPageContentStream contentStream1 = new PDPageContentStream(document, newPage,true,true);

    Thanks for your help. This page really helped me a lot. Thanks again

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.