How to use the iText Android library
“I need this list in a PDF” — It’s a popular demand request by a lot of Android users.
In particular cases, users might want to have their data printed out in PDF files. Data such as payment proofs, transaction journals, history reports, etc. This is a simple need. Unfortunately, many android apps let this feature flow away from their users.
There are some reasons why the PDF export feature doesn’t exist in apps. One of them is the complexity of its implementation — which is an assumption. Having a feature that lets users export their data into a PDF file is not as complex as solving arithmetic problems. Let’s see how to implement it in an Android application.
One of the PDF libraries that is developer-friendly to implement is the iText
library. To start using this library, we need to implement the iText dependency in our app Gradle.
implementation ("com.itextpdf:itextpdf:5.5.13.1")
Once it is synced in the project, we can go to the next step, setting up our manifest. This is to let the app access the phone storage since we are going to create a PDF file, and, of course, save it in the phone storage.
Add this code into the manifest.
<manifest
...
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
Don’t forget the legacy request to support Android 11 and higher.
android:requestLegacyExternalStorage="true"
We are now done having the iText
library in our project. Easy? Wait, it’s not even the beginning of our PDF exporting method.
To start, let’s create a PDF service class so that our UI class is not contaminated with our PDF configuration. In this class, we can directly define our font style.
We just need to set the font style by calling the Font
. That is how we set the font style to be used in our next configuration.
We have also prepared our pdf writer namely pdf
that we will initialize later. Now let’s prepare the file for our PDF document.
The path
is the phone storage directory where the PDF file will be exported in. Now let’s take a look at the file
configuration. The if (!file.exists()) file.createNewFile()
line functions to create our PDF file.
Now we have prepared the storage directory and file. However, the file we have created is still a blank file. That’s nothing to do with it in this step.
Now let’s dig deeper into document initialization. To make a PDF file, we need to initialize iText
document. This initialized variable will then act as our paper that we will write our data on. The document = Document()
is the document initialization.
The document.setMargins
and document.setPageSize
is how we set margin and page layout. We have had a document with a blank page now.
The document creation does not end there. Since we are about to make a PDF file, we have to set the document to be a PDF file bypdf = PdfWriter.getInstance(document,FileOutputStream(file))
and to reduce the memory consumption of the file size, we compress the file as well by calling the pdf.setFullCompression()
.
Easy. Let’s turn into the basic concept of writing the data into our document.
To start working on the document, of course, we need to open the document. The code above has directly opened our document by calling document.open()
.
Writing a document is actually similar to typing directly into a Doc file in Microsoft Office. What makes it different is just we have no cursor and we need to control it programmatically.
In other words, we need to make sure that the element we add to our document is in the right place. Below are the basic tips on how to programmatically write our data into the document.
- To add an empty line, we can add a paragraph with a space string.
document.add(Paragraph(" "))
- To write a paragraph, we just need to write a paragraph content inside the paragraph bracket above
Paragraph("YOUR_PARAGRAPH")
. However, to avoid creating paragraphs with the same style repeatedly, we can create a paragraph within a function to be called every time we need it.
private fun createParagraph(content: String): Paragraph{
val paragraph = Paragraph(content, BODY_FONT)
paragraph.firstLineIndent = 25f
paragraph.alignment = Element.ALIGN_JUSTIFIED
return paragraph
}
- We can then easily create paragraphs by calling the
createParagraph
function to be added to our document. Below is how to use it.
document.add(createParagraph(“PARAGRAPH_CONTENT”))
document.newPage()
- To make a table, we need to define a PDF table. The following code shows how to make a table:
private fun createTable(column: Int, columnWidth: FloatArray): PdfPTable {
val table = PdfPTable(column)
table.widthPercentage = 100f
table.setWidths(columnWidth)
table.headerRows = 1
table.defaultCell.verticalAlignment = Element.ALIGN_CENTER
table.defaultCell.horizontalAlignment = Element.ALIGN_CENTER
return table
}
In the code above, we have a parameter namedcolumn:Int
which is the number of columns. Besides, we also have a columnWidth
that is an array of float. This float array is the list of every single column of the table created. Easy? yes, everything is clearly understandable.
Inside a table, there must be rows and columns. Any particular area among them is called a cell. However, the rows are not defined here. It will be automatically generated by the cell we fill. Now let’s take a look at the next step for more.
- The following code shows how to write inside a cell:
private fun createCell(content: String): PdfPCell {
val cell = PdfPCell(Phrase(content))
cell.horizontalAlignment = Element.ALIGN_CENTER
cell.verticalAlignment = Element.ALIGN_MIDDLE
//setup padding
cell.setPadding(8f)
cell.isUseAscender = true
cell.paddingLeft = 4f
cell.paddingRight = 4f
cell.paddingTop = 8f
cell.paddingBottom = 8f
return cell
}
The main point of the code above is that for everything we want to write in any particular cell, we need to define a PDF cell. The PDF cell plays as our cursor position. To avoid repeatedly defining a cell, the function above requires the cell content purposing to directly put our content inside the cell.
Note: If all columns in a row have been filled by cells, the table will generate a new row automatically when we add another cell.
We are going to have a paper consisting of two paragraphs and our user data having four variables (id, first name, middle name, last name).
The user data class and its list are as follows:
data class User(
val id: Int,
val firstName: String,
val middleName: String,
val lastName: String
)val userData = listOf(
User(1, "Amir", "Tan", "Khan"),
User(2, "Michael", "Calvin", "Gonzalez"),
User(3, "Alim", "Bin", "Hasan"),
User(4, "John", "Carl", "Tean"),
User(5, "James", "Brown", "Cold"),
User(6, "Virats", "Kader", "Can"),
User(7, "Lim", "Lui", "Pao"),
User(8, "Endro", "Tava", "Pero"),
User(9, "Dani", "Pedro", "Leo"),
User(10, "Leonardo", "Chris", "Luiza")
)
Now let’s make a function to do the tasks.
All done, we have configured all functions needed to export our user data into PDF. Now let’s call this function from our activity, fragment, or composable context.
The sample below shows how to call the function from activity:
All set. We have created the PDF export function in our UI class and its result response as well. However, in different cases, the response could vary depending on our needs.
In this sample case, we let the app directly open the file after the PDF is created. Below is the result preview.

Notes: When opening the file we have created, we need to access the real path of the file. The
FileHandler
used in the above code is not from thejava.util.logging
class. Refer here to access the source code. Another important note is to request read file permission from the user. Check the full source code of the activity for more here.
Below is the project sample code:
Exporting data into PDF is a cool feature that is actually simple to implement as long as we know the underlying concept of how an iText document adds an element.
To sum up, we can simply make use of the library to provide a PDF export feature in our app without having to request our backend server to do so.
Hopefully, this is something to learn. Happy coding and cheers.