Skip to main content

Merge PDF Documents

  • 4 minutes to read

Use appendDocument() methods to append an external PDF document to the current document. You can append content from a stream, channel, or an existing PdfDocument instance. Optional LoadOptions allow you to configure how the appended document is loaded.

Append an Existing PDF Document

Call the appendDocument(PdfDocument document) method to append an existing PDF document instance.

// Open a document to append.
try (PdfDocument source = new PdfDocument(
        FileChannel.open(Path.of("source.pdf")))) {

    // Append the document to the current document.
    pdfDocument.appendDocument(source);
}

Append a Document from a Channel

Call the appendDocument(ReadableByteChannel channel) method to append a PDF document from a readable channel.

// Append a PDF document from a readable channel.
try (ReadableByteChannel channel =
         FileChannel.open(Path.of("source.pdf"))) {

    pdfDocument.appendDocument(channel);
}

Append a Document from a Channel with Load Options

Call the appendDocument(ReadableByteChannel channel, LoadOptions loadOptions) method to append a PDF document from a channel using custom load options.

// Configure load options for the appended document.
LoadOptions options = new LoadOptions();
options.setMetadataSyncMode(MetadataSyncMode.AUTO);
options.setSyncMetadata(true);
options.setPassword("USER_PASSWORD");

// Append a PDF document from a channel with custom load options.
try (ReadableByteChannel channel =
         FileChannel.open(Path.of("source.pdf"))) {

    pdfDocument.appendDocument(channel, options);
}

Append a Document from a Stream

Call the appendDocument(InputStream stream) method to append a PDF document from a stream.

// Append a PDF document from an input stream.
try (InputStream stream = Files.newInputStream(Path.of("source.pdf"))) {
    pdfDocument.appendDocument(stream);
}

Append a Document from a Stream with Load Options

Call the appendDocument(InputStream stream, LoadOptions loadOptions) method to append a PDF document from a stream using custom load settings.

// Configure load options for the appended document.
LoadOptions options = new LoadOptions();
options.setDetachStreamAfterLoadComplete(true);
options.setMetadataSyncMode(MetadataSyncMode.AUTO);
options.setSyncMetadata(true);

// Append a PDF document with custom load options.
try (InputStream stream = Files.newInputStream(Path.of("source.pdf"))) {
    pdfDocument.appendDocument(stream, options);
}

Merge PDF Files into a Single Document

The following code snippet creates a PDF document, appends pages from source documents, and saves the result:

try (PdfDocument destinationDocument = new PdfDocument();
     InputStream firstDocumentStream =
             Files.newInputStream(Path.of("Document1.pdf"));
     InputStream secondDocumentStream =
             Files.newInputStream(Path.of("Document2.pdf"))) {

    // Append pages from the first document.
    destinationDocument.appendDocument(firstDocumentStream);

    // Append pages from the second document.
    destinationDocument.appendDocument(secondDocumentStream);

    // Save the merged document.
    try (OutputStream outputStream =
                 Files.newOutputStream(Path.of("MergedDocument.pdf"))) {
        destinationDocument.save(outputStream);
    }
}

Resolve Merge Conflicts

When you append/merge PDF documents that contain AcroForm fields, the source and target documents may contain fields with identical names. The API resolves conflicts and returns an AppendDocumentResult object with information about affected fields.

Log Resolved Form Field Conflicts

Use AppendDocumentResult.getResolvedFieldNameConflicts() method to access form field name conflicts that the API resolved during the append/merge operation.

// Open a document to append.
try (PdfDocument source = new PdfDocument(
        FileChannel.open(Path.of("Source.pdf")))) {

    // Append the document to the current document.
    AppendDocumentResult result = pdfDocument.appendDocument(source);

    // Check for resolved form field name conflicts.
    for (FormFieldNameConflict conflict : result.getResolvedFieldNameConflicts()) {
        System.out.println("Target field: " + conflict.getTargetField());
        System.out.println("Renamed source field: " + conflict.getRenamedField());
    }
}
Member Description
getTargetField() Returns the form field from the target document.
getRenamedField() Returns the source form field with the new name.

Detect Form Field Name Collisions

Use the PdfDocument.getFieldNameCollisions() method to identify form fields with the same name before you merge or manipulate them.

The following code snippet finds form fields with the same name, merges each group into a single target field, and saves the updated PDF document:

package pdf;

import com.devexpress.docs.pdf.*;

import java.nio.channels.*;
import java.nio.file.*;
import java.util.List;

public class Main {
    public static void main(String[] args) throws Exception {

        try (FileChannel channel = FileChannel.open(Path.of("Document.pdf"));
             PdfDocument pdfDocument = new PdfDocument(channel)) {

            // Get form field name collisions.
            for (FormFieldNameCollision collision : pdfDocument.getFieldNameCollisions()) {

                System.out.println("Field name: " + collision.getFullName());

                List<FormField> fields = collision.getFields();
                if (fields.size() > 1) {

                    // Merge fields with the same name.
                    FormField target = fields.getFirst();
                    FormField[] sources = fields.subList(1, fields.size())
                            .toArray(new FormField[0]);

                    pdfDocument.mergeFormFields(target, sources);
                }
            }

            try (WritableByteChannel writableByteChannel =
                         FileChannel.open(Path.of("Document_Updated.pdf"),
                                 StandardOpenOption.CREATE,
                                 StandardOpenOption.WRITE,
                                 StandardOpenOption.TRUNCATE_EXISTING)) {

                pdfDocument.save(writableByteChannel);
            }
        }
    }
}
See Also