Skip to main content
Skip table of contents

Merging documents with bookmarks

This example was originally written in answer to the question How to merge PDFs and add bookmarks? for iText 5.

The code here is a direct port from the iText 5 code. Merging documents while maintaining bookmarks in iText 7 and later versions is done automatically when using the PdfMerger (Java/.NET) class.

insertandadaptoutlines

JAVA
JAVA
package com.itextpdf.samples.sandbox.merge;

import com.itextpdf.forms.PdfPageFormCopier;
import com.itextpdf.kernel.pdf.PdfDocument;
import com.itextpdf.kernel.pdf.PdfOutline;
import com.itextpdf.kernel.pdf.PdfReader;
import com.itextpdf.kernel.pdf.PdfWriter;
import com.itextpdf.kernel.pdf.navigation.PdfExplicitDestination;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;

public class InsertAndAdaptOutlines {
    public static final String DEST = "./target/sandbox/merge/insert_and_adapt_outlines.pdf";

    public static final String INSERT = "./src/main/resources/pdfs/hello.pdf";
    public static final String SRC = "./src/main/resources/pdfs/bookmarks.pdf";

    public static void main(String[] args) throws IOException {
        File file = new File(DEST);
        file.getParentFile().mkdirs();

        new InsertAndAdaptOutlines().manipulatePdf(DEST);
    }

    protected void manipulatePdf(String dest) throws IOException {
        PdfDocument pdfDoc = new PdfDocument(new PdfReader(SRC), new PdfWriter(dest));
        int insertPageNumber = 4;

        // Copier contains the additional logic to copy acroform fields to a new page.
        // PdfPageFormCopier uses some caching logic which can potentially improve performance
        // in case of the reusing of the same instance.
        PdfPageFormCopier formCopier = new PdfPageFormCopier();
        PdfDocument insertDoc = new PdfDocument(new PdfReader(INSERT));
        insertDoc.copyPagesTo(1, 1, pdfDoc, insertPageNumber, formCopier);
        insertDoc.close();

        PdfOutline outlines = pdfDoc.getOutlines(false);
        PdfOutline outline = outlines.getAllChildren().get(0).addOutline("Hello", insertPageNumber - 1);
        outline.addDestination(PdfExplicitDestination.createFit(pdfDoc.getPage(insertPageNumber)));

        pdfDoc.close();
    }
}
C#
C#
using System;
using System.IO;
using iText.Forms;
using iText.Kernel.Pdf;
using iText.Kernel.Pdf.Navigation;

namespace iText.Samples.Sandbox.Merge
{
    public class InsertAndAdaptOutlines
    {
        public static readonly String DEST = "results/sandbox/merge/insert_and_adapt_outlines.pdf";

        public static readonly String INSERT = "../../../resources/pdfs/hello.pdf";
        public static readonly String SRC = "../../../resources/pdfs/bookmarks.pdf";

        public static void Main(String[] args)
        {
            FileInfo file = new FileInfo(DEST);
            file.Directory.Create();

            new InsertAndAdaptOutlines().ManipulatePdf(DEST);
        }

        protected void ManipulatePdf(String dest)
        {
            PdfDocument pdfDoc = new PdfDocument(new PdfReader(SRC), new PdfWriter(dest));
            int insertPageNumber = 4;

            // Copier contains the additional logic to copy acroform fields to a new page.
            // PdfPageFormCopier uses some caching logic which can potentially improve performance
            // in case of the reusing of the same instance.
            PdfPageFormCopier formCopier = new PdfPageFormCopier();
            PdfDocument insertDoc = new PdfDocument(new PdfReader(INSERT));
            insertDoc.CopyPagesTo(1, 1, pdfDoc, insertPageNumber, formCopier);
            insertDoc.Close();

            PdfOutline outlines = pdfDoc.GetOutlines(false);
            PdfOutline outline = outlines.GetAllChildren()[0].AddOutline("Hello", insertPageNumber - 1);
            outline.AddDestination(PdfExplicitDestination.CreateFit(pdfDoc.GetPage(insertPageNumber)));

            pdfDoc.Close();
        }
    }
}

mergewithoutlines

JAVA
JAVA
/**
 * <p>
 * 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 com.itextpdf.samples.sandbox.merge;

import com.itextpdf.kernel.pdf.PdfDocument;
import com.itextpdf.kernel.pdf.PdfOutline;
import com.itextpdf.kernel.pdf.PdfReader;
import com.itextpdf.kernel.pdf.PdfWriter;
import com.itextpdf.kernel.pdf.navigation.PdfExplicitDestination;
import com.itextpdf.kernel.utils.PdfMerger;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;

public class MergeWithOutlines {
    public static final String DEST = "./target/sandbox/merge/merge_with_outlines.pdf";

    public static final String SRC1 = "./src/main/resources/pdfs/hello.pdf";
    public static final String SRC2 = "./src/main/resources/pdfs/links1.pdf";
    public static final String SRC3 = "./src/main/resources/pdfs/links2.pdf";

    public static void main(String[] args) throws IOException {
        File file = new File(DEST);
        file.getParentFile().mkdirs();

        new MergeWithOutlines().manipulatePdf(DEST);
    }

    protected void manipulatePdf(String dest) throws IOException {
        PdfDocument pdfDoc = new PdfDocument(new PdfWriter(dest));
        PdfDocument srcDoc1 = new PdfDocument(new PdfReader(SRC1));
        PdfDocument srcDoc2 = new PdfDocument(new PdfReader(SRC2));
        PdfDocument srcDoc3 = new PdfDocument(new PdfReader(SRC3));

        int numberOfPages1 = srcDoc1.getNumberOfPages();
        int numberOfPages2 = srcDoc2.getNumberOfPages();
        int numberOfPages3 = srcDoc3.getNumberOfPages();

        PdfMerger merger = new PdfMerger(pdfDoc);
        merger.setCloseSourceDocuments(true)
                .merge(srcDoc1, 1, numberOfPages1)
                .merge(srcDoc2, 1, numberOfPages2)
                .merge(srcDoc3, 1, numberOfPages3);

        PdfOutline rootOutline = pdfDoc.getOutlines(false);

        int page = 1;
        PdfOutline helloWorld = rootOutline.addOutline("Hello World");
        helloWorld.addDestination(PdfExplicitDestination.createFit(pdfDoc.getPage(page)));
        page += numberOfPages1;

        PdfOutline link1 = helloWorld.addOutline("link1");
        link1.addDestination(PdfExplicitDestination.createFit(pdfDoc.getPage(page)));
        page += numberOfPages2;

        PdfOutline link2 = rootOutline.addOutline("Link 2");
        link2.addDestination(PdfExplicitDestination.createFit(pdfDoc.getPage(page)));

        pdfDoc.close();
    }
}
C#
C#
using System;
using System.IO;
using iText.Kernel.Pdf;
using iText.Kernel.Pdf.Navigation;
using iText.Kernel.Utils;

namespace iText.Samples.Sandbox.Merge
{
    public class MergeWithOutlines
    {
        public static readonly String DEST = "results/sandbox/merge/merge_with_outlines.pdf";

        public static readonly String SRC1 = "../../../resources/pdfs/hello.pdf";
        public static readonly String SRC2 = "../../../resources/pdfs/links1.pdf";
        public static readonly String SRC3 = "../../../resources/pdfs/links2.pdf";

        public static void Main(String[] args)
        {
            FileInfo file = new FileInfo(DEST);
            file.Directory.Create();

            new MergeWithOutlines().ManipulatePdf(DEST);
        }

        protected void ManipulatePdf(String dest)
        {
            PdfDocument pdfDoc = new PdfDocument(new PdfWriter(dest));
            PdfDocument srcDoc1 = new PdfDocument(new PdfReader(SRC1));
            PdfDocument srcDoc2 = new PdfDocument(new PdfReader(SRC2));
            PdfDocument srcDoc3 = new PdfDocument(new PdfReader(SRC3));

            int numberOfPages1 = srcDoc1.GetNumberOfPages();
            int numberOfPages2 = srcDoc2.GetNumberOfPages();
            int numberOfPages3 = srcDoc3.GetNumberOfPages();

            PdfMerger merger = new PdfMerger(pdfDoc);
            merger.SetCloseSourceDocuments(true)
                .Merge(srcDoc1, 1, numberOfPages1)
                .Merge(srcDoc2, 1, numberOfPages2)
                .Merge(srcDoc3, 1, numberOfPages3);

            PdfOutline rootOutline = pdfDoc.GetOutlines(false);

            int page = 1;
            PdfOutline helloWorld = rootOutline.AddOutline("Hello World");
            helloWorld.AddDestination(PdfExplicitDestination.CreateFit(pdfDoc.GetPage(page)));
            page += numberOfPages1;

            PdfOutline link1 = helloWorld.AddOutline("link1");
            link1.AddDestination(PdfExplicitDestination.CreateFit(pdfDoc.GetPage(page)));
            page += numberOfPages2;

            PdfOutline link2 = rootOutline.AddOutline("Link 2");
            link2.AddDestination(PdfExplicitDestination.CreateFit(pdfDoc.GetPage(page)));

            pdfDoc.Close();
        }
    }
}

Resources

bookmarks.pdf
hello.pdf
links1.pdf
links2.pdf

Results

cmp_insert_and_adapt_outlines.pdf

cmp_merge_with_outlines.pdf


JavaScript errors detected

Please note, these errors can depend on your browser setup.

If this problem persists, please contact our support.