Merging documents with bookmarks

Tags: PdfCopyBookmarksmerge documentsconcatenateiText 5

This example was written in answer to the question How to merge PDFs and add bookmarks?

Files: 
/**
 * Example written by Bruno Lowagie in answer to a question on StackOverflow
 * 
 * When concatenating documents, we add a named destination every time
 * a new document is started. After we've finished merging, we add an extra
 * page with the table of contents and links to the named destinations.
 */
package sandbox.merge;
 
import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.pdf.PdfCopy;
import com.itextpdf.text.pdf.PdfReader;
 
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import sandbox.WrapToTest;
 
@WrapToTest
public class MergeWithOutlines {
 
    public static final String SRC1 = "resources/pdfs/hello.pdf";
    public static final String SRC2 = "resources/pdfs/links1.pdf";
    public static final String SRC3 = "resources/pdfs/links2.pdf";
    public static final String DEST = "results/merge/merge_with_outlines.pdf";
 
    public Map<String, PdfReader> filesToMerge;
 
    public static void main(String[] args) throws IOException, DocumentException {
        File file = new File(DEST);
        file.getParentFile().mkdirs();
        new MergeWithOutlines().createPdf(DEST);
    }
 
 
    public void createPdf(String filename) throws IOException, DocumentException {
        Document document = new Document();
        PdfCopy copy = new PdfCopy(document, new FileOutputStream(filename));
        document.open();
        int page = 1;
        ArrayList<HashMap<String, Object>> outlines = new ArrayList<HashMap<String, Object>>();
        // add the first document
        PdfReader reader1 = new PdfReader(SRC1);
        copy.addDocument(reader1);
        // add the first outline element
        HashMap<String, Object> helloworld = new HashMap<String, Object>();
        helloworld.put("Title", "Hello World");
        helloworld.put("Action", "GoTo");
        helloworld.put("Page", String.format("%d Fit", page));
        outlines.add(helloworld);
        // update page count
        page += reader1.getNumberOfPages();
        // add the second document
        PdfReader reader2 = new PdfReader(SRC2);
        copy.addDocument(reader2);
        // add the second outline element as a kid of the first one
        ArrayList<HashMap<String, Object>> kids = new ArrayList<HashMap<String, Object>>();
        HashMap<String, Object> link1 = new HashMap<String, Object>();
        link1.put("Title", "link1");
        link1.put("Action", "GoTo");
        link1.put("Page", String.format("%d Fit", page));
        kids.add(link1);
        helloworld.put("Kids", kids);
        // update page count
        page += reader2.getNumberOfPages();
        // add the third document
        PdfReader reader3 = new PdfReader(SRC3);
        copy.addDocument(reader3);
        // add the third outline element to the root
        HashMap<String, Object> link2 = new HashMap<String, Object>();
        link2.put("Title", "Link 2");
        link2.put("Action", "GoTo");
        link2.put("Page", String.format("%d Fit", page));
        outlines.add(link2);
        // add the outlines
        copy.setOutlines(outlines);
        // close the document
        document.close();
        reader1.close();
        reader2.close();
        reader3.close();
    }
}
/*
 * Example written in answer to:
 * http://stackoverflow.com/questions/34381849
 */
package sandbox.merge;
 
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.pdf.PdfContentByte;
import com.itextpdf.text.pdf.PdfReader;
import com.itextpdf.text.pdf.PdfStamper;
import com.itextpdf.text.pdf.SimpleBookmark;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import sandbox.WrapToTest;
 
@WrapToTest
public class InsertAndAdaptOutlines {
 
    /** The original PDF file. */
    public static final String INSERT
        = "resources/pdfs/hello.pdf";
    /** The original PDF file. */
    public static final String SRC
        = "resources/pdfs/bookmarks.pdf";
    /** The resulting PDF file. */
    public static final String DEST
        = "results/merge/bookmarks_hello.pdf";
 
    /**
     * Main method.
     * @param    args    no arguments needed
     * @throws DocumentException 
     * @throws IOException
     */
    public static void main(String[] args)
        throws IOException, DocumentException {
        File file = new File(DEST);
        file.getParentFile().mkdirs();
        new InsertAndAdaptOutlines().manipulatePdf(SRC, DEST);
    }
 
    /**
     * Manipulates a PDF file src with the file dest as result
     * @param src the original PDF
     * @param dest the resulting PDF
     * @throws IOException
     * @throws DocumentException
     */
    public void manipulatePdf(String src, String dest)
        throws IOException, DocumentException {
        PdfReader insert = new PdfReader(INSERT);
        PdfReader reader = new PdfReader(src);
        PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(DEST));
        stamper.insertPage(4, insert.getPageSize(1));
        PdfContentByte cb = stamper.getOverContent(4);
        cb.addTemplate(stamper.getImportedPage(insert, 1), 0, 0);
        List<HashMap<String, Object>> outlines = SimpleBookmark.getBookmark(reader);
        HashMap<String, Object> entry = new HashMap<String, Object>();
        entry.put("Title", "Hello");
        entry.put("Action", "GoTo");
        entry.put("Page", "4 Fit");
        updateOutline(outlines, entry, 4);
        stamper.setOutlines(outlines);
        stamper.close();
    }
 
    public boolean updateOutline(List<HashMap<String, Object>> outlines, HashMap<String, Object> entry, int p) {
        int index = 0;
        for (HashMap<String, Object> outline : outlines) {
            Object kids = outline.get("Kids");
            if (kids != null) {
                updateOutline((List<HashMap<String, Object>>)kids, entry, p);
            }
            else {
                if (p < getPage(outline)) {
                    outlines.add(index, entry);
                    return true;
                }
                index++;
            }
        }
        return false;
    }
 
    public int getPage(HashMap<String, Object> outline) {
        Object page = outline.get("Page");
        if (page == null) return -1;
        String p = page.toString().substring(0, page.toString().indexOf(" "));
        return Integer.parseInt(p);
    }
}
Resources: 
File nameRaw URLUpdated
hello.pdfhello.pdf2015-10-11 3:52 pm
links1.pdflinks1.pdf2015-10-11 3:52 pm
links2.pdflinks2.pdf2015-10-11 3:52 pm
bookmarks.pdfbookmarks.pdf2015-10-24 11:09 pm
Results: