In previous article about Generating PDF files using iText JAR, Kiran Hegde had described a nice and basic way of generating PDF files in Java using iTest JAR. It is a great starter tutorial for those who wants to start working with iText.
In one of the requirement, I had to merge two or more PDF files and generate a single PDF file out of it. I thought of implementing the functionality from scratch in iText, but then thought to google it and see if already someone have written code for what I was looking for.
As expected, I got a nice implementation of java code that merges 2 or more PDF files using iText jar. I thought of dissecting the code in this post and give credit to original author of the post.
Merge PDF files in Java using iText JAR
So here we go. First let us see the code.
package net.viralpatel.itext.pdf; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import com.lowagie.text.Document; import com.lowagie.text.pdf.BaseFont; import com.lowagie.text.pdf.PdfContentByte; import com.lowagie.text.pdf.PdfImportedPage; import com.lowagie.text.pdf.PdfReader; import com.lowagie.text.pdf.PdfWriter; public class MergePDF {
public static void main(String[] args) {
try {
List<InputStream> pdfs = new ArrayList<InputStream>();
pdfs.add( new FileInputStream( "c:\\1.pdf" ));
pdfs.add( new FileInputStream( "c:\\2.pdf" ));
OutputStream output = new FileOutputStream( "c:\\merge.pdf" );
MergePDF.concatPDFs(pdfs, output, true );
} catch (Exception e) {
e.printStackTrace();
}
}
public static void concatPDFs(List<InputStream> streamOfPDFFiles,
OutputStream outputStream, boolean paginate) {
Document document = new Document();
try {
List<InputStream> pdfs = streamOfPDFFiles;
List<PdfReader> readers = new ArrayList<PdfReader>();
int totalPages = 0 ;
Iterator<InputStream> iteratorPDFs = pdfs.iterator();
// Create Readers for the pdfs.
while (iteratorPDFs.hasNext()) {
InputStream pdf = iteratorPDFs.next();
PdfReader pdfReader = new PdfReader(pdf);
readers.add(pdfReader);
totalPages += pdfReader.getNumberOfPages();
}
// Create a writer for the outputstream
PdfWriter writer = PdfWriter.getInstance(document, outputStream);
document.open();
BaseFont bf = BaseFont.createFont(BaseFont.HELVETICA,
BaseFont.CP1252, BaseFont.NOT_EMBEDDED);
PdfContentByte cb = writer.getDirectContent(); // Holds the PDF
// data
PdfImportedPage page;
int currentPageNumber = 0 ;
int pageOfCurrentReaderPDF = 0 ;
Iterator<PdfReader> iteratorPDFReader = readers.iterator();
// Loop through the PDF files and add to the output.
while (iteratorPDFReader.hasNext()) {
PdfReader pdfReader = iteratorPDFReader.next();
// Create a new page in the target for each source page.
while (pageOfCurrentReaderPDF < pdfReader.getNumberOfPages()) {
document.newPage();
pageOfCurrentReaderPDF++;
currentPageNumber++;
page = writer.getImportedPage(pdfReader,
pageOfCurrentReaderPDF);
cb.addTemplate(page, 0 , 0 );
// Code for pagination.
if (paginate) {
cb.beginText();
cb.setFontAndSize(bf, 9 );
cb.showTextAligned(PdfContentByte.ALIGN_CENTER, ""
+ currentPageNumber + " of " + totalPages, 520 ,
5 , 0 );
cb.endText();
}
}
pageOfCurrentReaderPDF = 0 ;
}
outputStream.flush();
document.close();
outputStream.close();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (document.isOpen())
document.close();
try {
if (outputStream != null )
outputStream.close();
} catch (IOException ioe) {
ioe.printStackTrace();
}
}
} } |
If you see what the code does is pretty simple.
- In main() method, we create a List of InputStream objects that points to all the input PDF files we need to merge
- We call MergePDF.concatPDFs() static method passing list of input PDFs, OutputStream object for merged output PDF and a boolean flag that represents whether you need to include page numbers at the end of each page as command line arguments
- In concatPDFs() method, first we convert List of InputStream objects to List of PdfReader objects in first while loop. And also we keep count of the total pages in all the input PDF files.
- Next we create BaseFont object using BaseFont.createFont() method. This will be the font for writing page numbers
- Next we create output objects to write our merged PDF file using Document class object and PdfWriter.getInstance() method
- Finally we write all the input PDFs into merged output PDF iterating each PDF and then writing each page of it in two while loops
- And then, close all the streams and clear all the buffers. Good boys do this
So now we know how to merge PDF files into one, let us see the way to split a PDF file or extract a part of PDF into another PDF.
Split PDF files in Java using iText JAR
Let us see the code.
/**
* @author viralpatel.net
*
* @param inputStream Input PDF file
* @param outputStream Output PDF file
* @param fromPage start page from input PDF file
* @param toPage end page from input PDF file
*/ public static void splitPDF(InputStream inputStream,
OutputStream outputStream, int fromPage, int toPage) {
Document document = new Document();
try {
PdfReader inputPDF = new PdfReader(inputStream);
int totalPages = inputPDF.getNumberOfPages();
//make fromPage equals to toPage if it is greater
if (fromPage > toPage ) {
fromPage = toPage;
}
if (toPage > totalPages) {
toPage = totalPages;
}
// Create a writer for the outputstream
PdfWriter writer = PdfWriter.getInstance(document, outputStream);
document.open();
PdfContentByte cb = writer.getDirectContent(); // Holds the PDF data
PdfImportedPage page;
while (fromPage <= toPage) {
document.newPage();
page = writer.getImportedPage(inputPDF, fromPage);
cb.addTemplate(page, 0 , 0 );
fromPage++;
}
outputStream.flush();
document.close();
outputStream.close();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (document.isOpen())
document.close();
try {
if (outputStream != null )
outputStream.close();
} catch (IOException ioe) {
ioe.printStackTrace();
}
} } |
In above code, we have created a method splitPDF () that can be used to extracts pages out of a PDF and write it into another PDF. The code is pretty much self explanatory and is similar to the one to merge PDF files.
Thus, if you need to split an input.pdf (having 20 pages) into output1.pdf (1-12 pages of input.pdf) and output2.pdf (13-20 of input.pdf), you can call the above method as follow:
public static void main(String[] args) {
try {
MergePDF.splitPDF( new FileInputStream( "C:\\input.pdf" ),
new FileOutputStream( "C:\\output1.pdf" ), 1 , 12 );
MergePDF.splitPDF( new FileInputStream( "C:\\input.pdf" ),
new FileOutputStream( "C:\\output2.pdf" ), 13 , 20 );
} catch (Exception e) {
e.printStackTrace();
} } |