Introduction to iText 7
Getting started with the latest version of iText 7, with instructions on generating PDF content and then stylizing it to suit your needs.
Join the DZone community and get the full member experience.
Join For FreeOverview
In this article, I will introduce the latest version of the iText 7 library. I will provide an example of how to generate a PDF using the library and some methods for testing PDF content. This will be followed by examples of styling texts or paragraphs. To start, I'll begin with a short overview of the library to provide readers with a better understanding of the concept.
Purpose of iText Library
The iText library can be used to manipulate almost any PDF. It can be used to create static or dynamic PDFs and manipulate already existing PDFs with minimum concern for the PDF standards. The library is a collection of several components, but the primary concern of this article is the IText Core component. See some definitions from the iText site.
Key features:
iText 7 Core is a straightforward, performant and extensible library that is ready to handle the challenges of today's digital document workflows.
Main benefits:
With iText 7 Core you don't have to worry about PDF technologies and standards, you can just focus on your business needs and document content. At the same time your development team has full access to all internal PDF structures, offering them the possibility to read, insert, update and delete any PDF object they want. In addition to this, they can benefit from our rich and up-to-date technical documentation in the Resource Center.
License
The library has been using the AGPL license model since iText 5. That means the library is free to use in open source projects. However, a commercial license is needed for usage in any commercial project.
Note: I have to admit their support is excellent and they never let me down.
History
The iText 7 is quite a matured library in its 4th edition (see versions 1, 2, 5, and 7). Besides that, the library is constantly adding new features. You can see the evolution of the library (the collection of components) in the image below.
Maven Dependencies
To get started with the library we need to add itext7-core
Maven dependency to your pom.xml
as defined in the code below. We can find the latest available version of iText 7 in the Maven Central repository.
x
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itext7-core</artifactId>
<version>7.1.13</version>
<type>pom</type>
</dependency>
Additionally, our code depends on the JUnit framework (for unit testing purposes) delivered by the SpringBoot Test Starter.
x
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<version>2.4.0</version>
<scope>test</scope>
</dependency>
Simple Text
The library in version 7 is not so different from the previous versions. Therefore, the code has changed only minimally, although there are some notable differences.
To start with the iText 7 library, we should learn first how to generate a PDF containing simple text.
Note: this example uses JDK15, but it's not a hard constraint. The code should work fine with JDK8 as well.
Generate PDF Content
To generate our first PDF with the library we need to prepare several instances to be able to add the content. Our goal is to prepare an instance of com.itextpdf.layout.Document
class and add some content there.
The library uses a concept quite similar to DOM where the root element is represented by the instance of Document
class. We can add any block element there (e.g. paragraph, list, or table). The block elements can contain more specific objects (e.g. text or image).
To start, we need to follow these steps:
- Create an instance of
PdfWriter
class (line 13) to specify the target file name and path and optionally (as is our case) create an instance ofWritterProperties
class to specify the desired PDF version (the version is 2.0 in our case) for the generated PDF (lines 11-12). The generated PDF will be saved into the file specified in the variable filesimplePdf
(line 10). - Create an instance of
PdfDocument
class to handle the writing of the added content according to the PDF specification (line 14). - Create an instance of
Document
class as the main point to work with the PDF. It serves as the root element where we can add all the desired elements representing our content (line 15). - Define the text to be added into the PDF and add it wrapped as a
Paragraph
element into theDocument
instance (line 17). Of course, we can add more content, but it's sufficient for now.
x
class DzoneTests {
final static Logger log = LoggerFactory.getLogger(DzoneTests.class);
void simpleText() throws Exception {
var textContent = "Sapiensplendide noluisse ... mollis verterem alia regione quidam.";
String simplePdf = "target/dzone-simple-text.pdf";
WriterProperties wp = new WriterProperties();
wp.setPdfVersion(PdfVersion.PDF_2_0);
try (PdfWriter writer = new PdfWriter(simplePdf, wp);
PdfDocument pdfDocument = new PdfDocument(writer);
Document document = new Document(pdfDocument)) {
document.add(new Paragraph(textContent));
} catch (FileNotFoundException e) {
log.error("Creating PDF failed", e);
throw new ITextException(e.getMessage());
}
// to be tested later
}
}
Note: you can find a similar example using iText 5. Be aware that the text in the code above (the literal assigned to variable textContent
) is not complete in order to make the example readable. The value itself is not important. You may need the whole code.
Now, we can check the output of the generated code from the code above (see the next screenshot):
In thedzone-simple-text.pdf
file, we can also find the desired values of PDF properties as highlighted in the screenshot below with red. You can see thePDF Producer
value added by iText Library and PDF Version specified earlier in WritterProperties
by us (line 12).
Test Generated PDF Content
The generated PDF should also be tested to verify that the content has appeared as intended. There are several ways to test such content, but the simplest way is to check the PDF content as text since no formatting of the content has been added yet.
To test the PDF, we need to know the file path we used for PDF generation (the variable simplePdf
) and follow these steps:
- Create an instance of
PdfReader
class to specify the filename we want to load (line 11). - Create an instance of
PdfDocument
class as the main point to work with the document, which is the same as before (line 11). - Read the first page from the PDF as a text with the help of
LocationTextExtractionStrategy
class (lines 12-14) from the iText library. - Verify the first 10 characters to be the same as they were generated (line 11). Note: such a test is not perfect, but for our purposes it is appropriate.
x
class DzoneTests {
private static Lorem lorem = LoremIpsum.getInstance();
void simpleText() throws Exception {
String simplePdf = "target/dzone-simple-text.pdf";
// generate PDF as in previous example
try (PdfDocument pdfDocument = new PdfDocument(new PdfReader(simplePdf))) {
String firstPageContent = PdfTextExtractor.getTextFromPage(
pdfDocument.getFirstPage(),
new LocationTextExtractionStrategy());
assertThat(firstPageContent).startsWith(textContent.substring(0, 10));
}
}
}
When thegenerateSimplePdf
test is triggered (e.g. within the preferred IDE, Eclipse in our case), then the new file dzone-simple.pdf
can be found under the target folder in your project. Moreover, we verified that the PDF contains the expected content when the test passed successfully (see screenshot below).
Styled Text
Since we know how to generate a PDF, we can move on to investigate the possibilities of styling a text (more "advanced" objects like tables or QR codes are not within this scope). This part is focused on these areas:
- Styling of text: block elements inside a single paragraph.
- Styling of paragraph: paragraphs inside the document (on the page).
Styling of Text
When we want to style some text, we need to add an instance of Text
class into the instance ofParagraph
class (to use the overloadedadd
method). With that, we can define the specific features of every defined Text instance. To achieve this, we need to follow these steps:
- Create an instance of
Document
(lines 7-10). It's the same as it was demonstrated in our first example. - Create an instance of
Paragraph
class where all the styled Text elements will be added later (line 12). - Create an instance of
Text
class with the desired features (lines 13, 15, and 17). - Any line break can be achieved by adding a new line break character into the
paragraph
instance (lines 14 and 16). - The styling itself is realized by the method
styledText
with the set of passed arguments to be set on Text instance (lines 35-62). The only tricky part is the creation ofPdfFont
class from the passed family name as aString
(lines 63-70). We just translate the checkedIOException
into our runtimeITextException
to make our code easier.
void styledText() throws Exception {
var label1 = "big blue Courier font";
var label2 = "underlined bold default font with yellow background";
var label3 = "crossed italic";
String simplePdf = "target/dzone-styled-text.pdf";
try (PdfWriter writer = new PdfWriter(simplePdf);
PdfDocument pdfDocument = new PdfDocument(writer);
Document document = new Document(pdfDocument)) {
Paragraph paragraph = new Paragraph();
paragraph.add(styledText(label1, BLUE, null, COURIER, 30f, false, false, false, false));
paragraph.add("\n");
paragraph.add(styledText(label2, RED, YELLOW, null, null, true, false, true, false));
paragraph.add("\n");
paragraph.add(styledText(label3, null, null, null, null, false, true, false, true));
document.add(paragraph);
} catch (FileNotFoundException e) {
log.error("Creating PDF failed", e);
throw new ITextException(e.getMessage());
}
try (PdfDocument pdfDocument = new PdfDocument(new PdfReader(simplePdf))) {
String firstPageContent = PdfTextExtractor.getTextFromPage(
pdfDocument.getFirstPage(),
new LocationTextExtractionStrategy());
assertThat(firstPageContent).startsWith(label1);
assertThat(firstPageContent).contains(label2);
assertThat(firstPageContent).endsWith(label3);
}
}
public Text styledText(String label, Color color, Color backgroundColor, String fontFamily, Float fontSize, boolean isBold, boolean isItalic, boolean isUnderline, boolean isLineThrough) {
Text text = new Text(label);
if (nonNull(color)) {
text.setFontColor(color);
}
if (nonNull(backgroundColor)) {
text.setBackgroundColor(backgroundColor);
}
if (nonNull(fontFamily)) {
text.setFont(createFont(fontFamily));
}
if (nonNull(fontSize)) {
text.setFontSize(fontSize);
}
if (isBold) {
text.setBold();
}
if (isItalic) {
text.setItalic();
}
if (isUnderline) {
text.setUnderline();
}
if (isLineThrough) {
text.setLineThrough();
}
return text;
}
PdfFont createFont(String fontFamily) {
try {
return PdfFontFactory.createFont(fontFamily);
} catch (IOException e) {
throw new ITextException("Font creation failed", e);
}
}
The generated PDF contains a single paragraph element with three styled text blocks, each one on a separate line (see the next screenshot).
Styling of Paragraph
As well as styling eachText
element independently, we can also do a similar styling on a whole Paragraph
element. These steps demonstrate how to do that:
- Create an instance of
Document
as done before (lines 7-10) same as before. - Create an instance of
Paragraph
class with the rotation of 45° (lines 12-14). Please be aware you need to pass the rotation value to the library in radians. Such logic is encapsulated in thecalculateRadiusFromDegree
method (lines 42-45). - Create an instance of
Paragraph
class green dashed borderline. In order to add a paragraph border with some styles, you need to create a new instance ofcom.itextpdf.layout.borders.Border
class with the desired features first and pass it tosetBorder
method. We used theDashedBorder
class for that purpose, passing the values in the constructor (lines 16-18). Note: there are more options for border styling. You can find another example achieved by theSolidBorder
class in the next example. - Create an instance of
Paragraph
defined with a margin (the offset of the paragraph on the page) and padding (the offset of the elements in the paragraph). We set 3 pixels for the margin and 6 pixels for the padding (lines 21-22). We can check the location of the solid border in the last paragraph in the next image to see those settings.
xxxxxxxxxx
void styledParagraph() throws Exception {
var label1 = "45° rotation";
var label2 = "green solid border";
var label3 = "6px margin & 3px padding & solid border";
String simplePdf = "target/dzone-styled-paragraph.pdf";
try (PdfWriter writer = new PdfWriter(simplePdf);
PdfDocument pdfDocument = new PdfDocument(writer);
Document document = new Document(pdfDocument)) {
Paragraph rotatedParagraph = new Paragraph(label1);
rotatedParagraph.setRotationAngle(calculateRadiusFromDegree(45f));
document.add(rotatedParagraph);
Paragraph borderedParagraph = new Paragraph(label2);
borderedParagraph.setBorder(new DashedBorder(GREEN, 2f));
document.add(borderedParagraph);
Paragraph offsetedParagraph = new Paragraph(label3);
offsetedParagraph.setMargin(6f);
offsetedParagraph.setPadding(3f);
offsetedParagraph.setBorder(new SolidBorder(1f));
document.add(offsetedParagraph);
} catch (FileNotFoundException e) {
log.error("Creating PDF failed", e);
throw new ITextException(e.getMessage());
}
try (PdfDocument pdfDocument = new PdfDocument(new PdfReader(simplePdf))) {
String firstPageContent = PdfTextExtractor.getTextFromPage(
pdfDocument.getFirstPage(),
new LocationTextExtractionStrategy());
// assertThat(firstPageContent).contains(label1);
assertThat(firstPageContent).contains(label2);
assertThat(firstPageContent).contains(label3);
}
}
private double calculateRadiusFromDegree(Float rotation) {
// half rotation in Radians is Pi (3.14) -> full rotation is 2 Pi
return PI / 180 * rotation;
}
The generated PDF contains three paragraph elements with the defined styling (see the next screenshot).
The result of a styled paragraph in PDF.
What else can be done?
As I said in the beginning, the IText 7 is a quite powerful library and we just scratched the surface of it in this article. Other features of the library include:
- more elements (e.g. tables, barcodes or QR codes),
- add behavior (e.g. layers, forms, bookmarks or attachments),
- modify PDF (e.g. add page counter or watermark),
- convert an HTML into PDF,
- test PDF formatting,
- and more.
Conclusion
This article has covered the basics of the IText 7 usage. It was started with the generation of a simple PDF. After that, some text and paragraph styling were added. You can find the demonstrated codes in my GitHub repository.
In the next article, I will cover the generation of barcodes and QR codes.
Opinions expressed by DZone contributors are their own.
Comments