dcsimg
 

How to Create a PDF Document from a Java Program Using iText

Monday Jan 22nd 2018 by Manoj Debnath

Delve into the tool called iText, which enables a Java programmer to create PDF documents through Java code.

The Portable Document Format, aka PDF, is a de facto standard for document exchanges between users. Java programmers sometimes need to create document files of their application data to showcase business information or create a report that can be exchanged or printed without messing with the data layout and format. PDF is an ideal file format that can reliably do that independent of software hardware and operating system. This article delves into the tool called iText, which enables a Java programmer to create PDF documents through Java code.

An Overview

The Portable Document Format (PDF) is a product of the Camelot project by Dr. John Edward Warnock, 1991, co-founder of Adobe Systems. The goal was to enable anyone to capture documents from any application as an electronic version for document exchange. It stood the test of time and became a trusted format of electronic document exchange down the years. Although PDF is now an open file format (ISO-32000-1) maintained by the International Organization for Standardization (ISO), some indispensable parts to work with it are still proprietary (such as Adobe XML Forms Architecture and Adobe JavaScript) and defined by Adobe. A PDF document can contain various elements and not just mere text—such as links and buttons, form fields, audio, video, and business logic. It also can be signed electronically and is easily viewed using Acrobat Reader (a PDF reader application by Adobe). However, today there are many other open source PDF applications that can be used to create, read, and write PDF file format. The popular Microsoft Office and LibreOffice collections have options to export their documents in this format.

The iText is a Java library that enables a developer to generate and manipulate PDF documents through Java code on the fly. The library offers some powerful features to generate read-only, platform-independent documents which contain not only text but also lists, tables, and images. This library is particularly useful to create a consistent look-and-feel document; otherwise, what Java can do best is create an HTML page which is browser dependent. The API comes quite handy and has almost flat learning curve. The iText has a version that works with the .NET framework as well. For an iText library to work with Java, it requires Java version 5 and above.

Maven Dependencies: pom.xml

Here are the dependencies one needs to add into pom.xml to work out the following examples. The lines commented with <!-- START --> and <!-- END --> are essential; other tags and dependencies illustrated are discretionary.

<project xmlns="http://maven.apache.org/POM/4.0.0"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
      http://maven.apache.org/xsd/maven-4.0.0.xsd">
   <modelVersion>4.0.0</modelVersion>
   <groupId>org.mano.examples</groupId>
   <artifactId>itextexamples</artifactId>
   <version>1.0-SNAPSHOT</version>
   <packaging>jar</packaging>
   <name>itextexamples</name>
   <url>http://maven.apache.org</url>
   <properties>
      <project.build.sourceEncoding>UTF-8
         </project.build.sourceEncoding>
   </properties>
   <build>
      <plugins>
         <plugin>
            <groupId>
               org.apache.maven.plugins
            </groupId>
            <artifactId>
               maven-compiler-plugin
            </artifactId>
            <version>3.7.0</version>
            <configuration>
               <source>1.8</source>
               <target>1.8</target>
            </configuration>
         </plugin>
      </plugins>
   </build>
   <dependencies>
      <dependency>
         <groupId>junit</groupId>
         <artifactId>junit</artifactId>
         <version>3.8.1</version>
         <scope>test</scope>
      </dependency>

<!-- START -->

      <!-- add all iText 7 Community modules -->
      <dependency>
         <groupId>com.itextpdf</groupId>
         <artifactId>itext7-core</artifactId>
         <version>7.1.0</version>
         <type>pom</type>
      </dependency>
      <!-- https://mvnrepository.com/artifact/org.slf4j/
         slf4j-api -->
      <dependency>
         <groupId>org.slf4j</groupId>
         <artifactId>slf4j-api</artifactId>
         <version>1.7.25</version>
      </dependency>
      <dependency>
         <groupId>org.slf4j</groupId>
         <artifactId>slf4j-jdk14</artifactId>
         <version>1.7.25</version>
      </dependency>
<!-- END -->

   </dependencies>
</project>

Working with a PDF Document

Intuitively, a PDF file is a container for documents and an iText Document class is the default root element. It provides methods that work with the page size setting, page rotating, adding elements, and writing text according to specific co-ordinates. Because this class has no idea of the actual PDF format and their syntaxes, the library provides a subclass of Document, called the PdfDocument class. An instance of this class provides the entry point to work with the PDF document. This class provides the necessary functionalities to work with the PDF document, such as adding pages, font, and events; copying pages from one document to another; extracting document information; and so forth To open a PDF document for writing, it must be opened in association with a PdfWriter instance. In a similar manner, a PDF document to be opened for reading and parsing must be opened in association with an PdfReader instance. The PdfWriter is subscribing to the Java core class java.io.OutputStream and PdfReader to java.io.InputStream. They are both defined in the package named com.itextpdf.kernel.pdf. The PdfReader supplies five constructors, such as:

And, the constructors of PdfWriter are the following:

Any of these constructors may be used to create an instance of PdfWriter/PdfReader. The library provides the necessary functionalities to read and write byte information according to the rules of the PDF document.

A Quick Example

This is a very simple and rudimentary example to illustrate the ideas discussed earlier. The code is self-explanatory. The API documentation of iText 7 can be found in this link.

package org.mano.examples;
import com.itextpdf.kernel.geom.PageSize;
import com.itextpdf.kernel.pdf.PdfDocument;
import com.itextpdf.kernel.pdf.PdfPage;
import com.itextpdf.kernel.pdf.PdfWriter;
import com.itextpdf.kernel.pdf.canvas.PdfCanvas;
import com.itextpdf.layout.Document;
import com.itextpdf.layout.element.*;
import javax.swing.text.StyleConstants;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
public class PdfReportSample {
   private OutputStream fos;
   private PdfWriter writer;
   private PdfDocument pdfdoc;
   private Document doc;
   private String filename;

   public PdfReportSample(String filename)
         throws IOException{
      this.filename=filename;
      fos = new FileOutputStream(new File(filename));
      writer = new PdfWriter(fos);
      pdfdoc = new PdfDocument(writer);
      doc = new Document(pdfdoc);
      createSimpleTextReport();
      doc.close();
      writer.close();
   }

   private void createSimpleTextReport(){
      doc.add(new Paragraph("Available Processors: "
         + Runtime.getRuntime().availableProcessors()
         + " Cores"));
      doc.add(new Paragraph("Free Memory :"
         + Runtime.getRuntime().freeMemory() + " bytes"));
      doc.add(new Paragraph("Maximum Memory used
         by JVM :"
         + Runtime.getRuntime().maxMemory() + " bytes"));
      doc.add(new Paragraph("Total Memory available :"
         + Runtime.getRuntime().totalMemory() + " bytes"));
      doc.add(new Paragraph("File System Roots"));
      File roots[] = File.listRoots();
      List list = new List();
      for (File root : roots) {
         list.add(new ListItem("File system root: "
            + root.getAbsolutePath()))
            .add(new ListItem("Total space: "
               + root.getTotalSpace() + " bytes"))
            .add(new ListItem("Free space: "
               + root.getFreeSpace() + " bytes"))
            .add(new ListItem("Usable space: "
               + root.getUsableSpace() + " bytes"));
         doc.add(list);
      }
   }
}

The preceding data also can be stated in a tabular format, as follows. The code has been elaborated to make it more comprehensible.

private void createTabularReport(){
   Table table=new Table(3);
   table.addHeaderCell(new Cell().add(new
      Paragraph("Caption")));
   table.addHeaderCell(new Cell().add(new
      Paragraph("Value")));
   table.addHeaderCell(new Cell().add(new
      Paragraph("Unit")));
   table.addCell(new Cell().add(new
      Paragraph("Available Processors")));
   table.addCell(new Cell().add(new
      Paragraph(String.valueOf(Runtime.getRuntime()
      .availableProcessors()))));
   table.addCell(new Cell().add(new
      Paragraph("")));
   table.addCell(new Cell().add(new
      Paragraph("Free Memory")));
   table.addCell(new Cell().add(new
      Paragraph(String.valueOf(Runtime.getRuntime()
      .freeMemory()))));
   table.addCell(new Cell().add(new
      Paragraph("bytes")));
   table.addCell(new Cell().add(new
      Paragraph("Maximum Memory")));
   table.addCell(new Cell().add(new
      Paragraph(String.valueOf(Runtime.getRuntime()
      .maxMemory()))));
   table.addCell(new Cell().add(new
      Paragraph("bytes")));
   File roots[] = File.listRoots();
   for (File root : roots) {
      table.addCell(new Cell().add(new
         Paragraph("File System root")));
      table.addCell(new Cell().add(new
         Paragraph(root.getAbsolutePath())));
      table.addCell(new Cell().add(new
         Paragraph("bytes")));
      table.addCell(new Cell().add(new
         Paragraph("Total space")));
      table.addCell(new Cell().add(new Paragraph(
         String.valueOf(root.getTotalSpace()))));
      table.addCell(new Cell().add(new
         Paragraph("bytes")));
      table.addCell(new Cell().add(new
         Paragraph("Free space")));
      table.addCell(new Cell().add(new Paragraph(
         String.valueOf(root.getFreeSpace()))));
      table.addCell(new Cell().add(new
      Paragraph("bytes")));
      table.addCell(new Cell().add(new
         Paragraph("Usable space")));
      table.addCell(new Cell().add(new Paragraph(
         String.valueOf(root.getUsableSpace()))));
      table.addCell(new Cell().add(new
         Paragraph("bytes")));
   }
   doc.add(table);
}

The iText Library for the Java Programmer

Perhaps the most significant aspect of this library is that we are able to create a PDF document without having to know much about the intricacies of the PDF specification. The specification is huge and complex because it envelops much more than text, such as cross-reference tables, graphics, links, file attachment, rich media, and so on. The library, however, is limited in its support but nonetheless provides the essential features to create a PDF document programmatically. The API is intuitive and simple to learn. In most cases, developers do not need to create PDF documents that are complex. But, as the library develops, it is going to fill in the missing spots of the specification.

Conclusion

The iText developer home page offers extensive examples on various features of the library. There are numerous classes available to deal with various other aspects of the PDF format. This article simply scratched the surface to give a taste of what the library offers in general. Visit the links below to get a more comprehensive example on this.

References

Home
Mobile Site | Full Site