Thursday, September 07, 2017

Merge and Paginate PDF files using iText 5

In this post we will see a way to merge multiple PDF files while adding page numbers at the bottom of each page in the format Page 1 of 10. The following steps give a brief description of the steps used to merge and add page number to the merged PDF.
  1. Create com.itextpdf.text.pdf.PdfReader from all InputStreams and retrieve the page counts to get a total page count. We also add the readers to an ArrayList to use later.
    List<PdfReader> readers = new ArrayList<PdfReader>();
    int totalPageCount = 0;
    for (InputStream file : streamOfPDFFiles) {
    
     // Create Reader for each input stream and add to reader list
     PdfReader reader = new PdfReader(file);
     readers.add(reader);
     totalPageCount += reader.getNumberOfPages();
    }
  2. Create a PageStamp for each page. com.itextpdf.text.pdf.PdfCopy.PageStamp can be used to add content to pages in the merged PDF.
    PdfImportedPage page = copy.getImportedPage(reader, i);
    PageStamp stamp = copy.createPageStamp(page);
  3. Create a Chunk to hold the text. com.itextpdf.text.Chunk represents a block of text which can be assigned text properties like font etc.
    Chunk chunk = new Chunk(String.format("Page %d of %d", pageNumber, totalPageCount));
    Font font = new Font();
    font.setFamily(Font.FontFamily.HELVETICA.name());
    font.setSize(8);
    font.setStyle(Font.FontStyle.ITALIC.getValue());
    chunk.setFont(font);
  4. Add text into the PageStamp. The text location starts at the bottom left of the page, increasing from left to right horizontally and bottom to top vertically.
    ColumnText.showTextAligned(stamp.getUnderContent(), Element.ALIGN_RIGHT, new Phrase(chunk), 580, 10, 0);
  5. Add the new page to the merged PDF
    copy.addPage(page);
Here is the full code I used for merging 3 PDF files.
package com.aoj.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.List;

import com.itextpdf.text.Chunk;
import com.itextpdf.text.Document;
import com.itextpdf.text.Element;
import com.itextpdf.text.Font;
import com.itextpdf.text.PageSize;
import com.itextpdf.text.Phrase;
import com.itextpdf.text.pdf.ColumnText;
import com.itextpdf.text.pdf.PdfCopy;
import com.itextpdf.text.pdf.PdfCopy.PageStamp;
import com.itextpdf.text.pdf.PdfImportedPage;
import com.itextpdf.text.pdf.PdfReader;

public class ItextPdfMergePaginate {

 public static void main(String[] args) {
  List<InputStream> pdfs = new ArrayList<InputStream>();
  try (FileInputStream fis1 = new FileInputStream("c:\\test\\1.pdf");
    FileInputStream fis2 = new FileInputStream("c:\\test\\2.pdf");
    FileInputStream fis3 = new FileInputStream("c:\\test\\3.pdf");) {
   pdfs.add(fis1);
   pdfs.add(fis2);
   pdfs.add(fis3);
   OutputStream output = new FileOutputStream("c:\\test\\merge.pdf");
   mergeAndPaginate(pdfs, output);
  } catch (Exception e) {
   e.printStackTrace();
  }
 }

 public static void mergeAndPaginate(List<InputStream> streamOfPDFFiles, OutputStream outputStream) {
  Document document = new Document(PageSize.LETTER);

  try {

   // Open PdfCopy for to copy the merged document into outputStream
   PdfCopy copy = new PdfCopy(document, outputStream);

   document.open();

   // We will use the list of readers to get total page count and
   // process individual pages later
   List<PdfReader> readers = new ArrayList<PdfReader>();
   int totalPageCount = 0;
   for (InputStream file : streamOfPDFFiles) {

    // Create Reader for each input stream and add to reader list
    PdfReader reader = new PdfReader(file);
    readers.add(reader);

    totalPageCount += reader.getNumberOfPages();
   }

   // Number of pages processed so far.
   int currentPageNumber = 0;
   for (PdfReader reader : readers) {

    int pageCount = reader.getNumberOfPages();

    // Page Number starts with 1.
    for (int i = 1; i <= pageCount; i++) {
     int pageNumber = currentPageNumber + i;

     // Process one page at a time
     PdfImportedPage page = copy.getImportedPage(reader, i);
     PageStamp stamp = copy.createPageStamp(page);

     // Create chunk of text with page information and set font settings
     Chunk chunk = new Chunk(String.format("Page %d of %d", pageNumber, totalPageCount));
     Font font = new Font();
     font.setFamily(Font.FontFamily.HELVETICA.name());
     font.setSize(8);
     font.setStyle(Font.FontStyle.ITALIC.getValue());
     chunk.setFont(font);

     // Write the text into page (represented by stamp object
     ColumnText.showTextAligned(stamp.getUnderContent(), Element.ALIGN_RIGHT, new Phrase(chunk), 580, 10, 0);
     stamp.alterContents();

     // Add page after page info is written.
     copy.addPage(page);
    }
    currentPageNumber += pageCount;
   }
   outputStream.flush();
  } catch (Exception e) {
   e.printStackTrace();
  } finally {
   if (document.isOpen())
    document.close();
   try {
    if (outputStream != null)
     outputStream.close();
   } catch (IOException ioe) {
    ioe.printStackTrace();
   }
  }
 }
}
And here is the Gradle build file used for this example
apply plugin:'application'
mainClassName = "com.aoj.pdf.ItextPdfMergePaginate"
applicationName = 'java-pdf-examples'

repositories {
    mavenCentral()
}

dependencies {
    compile group: 'com.itextpdf', name: 'itextpdf', version: '5.5.12'

}

2 comments:

Popular Posts