Merge PDF files using Java
Table of contents

Explore how our Java PDF library enables seamless merging of multiple PDF files and other document formats into a single PDF. This comprehensive guide demonstrates using our web services interface to combine documents while preserving formatting, adding bookmarks, and applying security settings. Learn how to efficiently merge PDFs with Java code while maintaining support for watermarks and handling various file formats.
To facilitate the new PDF merging facility in our Document Converter for SharePoint, we’ve added the ability to convert and merge multiple files to our core PDF conversion engine, which our SharePoint product shares with our generic Java- and .NET-oriented [Document Converter Services][dcs].
This post describe in detail how to invoke this new merging facility from your own code. The demo uses Java, but the web services-based interface is identical when used from .NET. For more information, refer to the .NET version of this article.
This post is part of a series related to manipulating PDF files using web services. The other blog posts include:
- Converting Office files to PDF format using a web services-based interface (C# / .NET)
- Converting Office files to PDF format using a web services-based interface (Java)
- Invoking the Document Converter web service from Visual Studio 2005 using VB.net
- Using watermarking features of Nutrient Document Converter Services (C# / .NET).
- Using the PDF watermarking features from Java-based environments
Key features
The key features of the new merging facilities include:
- Convert and merge any supported file format — including HTML, AutoCAD, [MS-Office][], InfoPath, TIFF, and MSG — or merge existing PDF files.
- Apply different watermarks on each individual file, as well as on the entire merged file (e.g. page numbering).
- Apply PDF security settings and restrictions on the merged file.
- Optionally skip (and report) corrupt or unsupported files.
- Add PDF bookmarks for each converted file.
- Apply any
ConversionSetting
supported by the regular conversion process.
Object model
The object model is relatively straightforward. The classes related to PDF merging are displayed below. A number of enumerations are used by the various classes, and these can be found in our post about converting files using the web services interface. A detailed developer guide is available here.
The web service method that controls merging of files is called ProcessBatch
(highlighted in the screenshot above). It accepts a ProcessingOptions
object that holds all information about the source files to convert and the MergeSettings
to apply, which may optionally include security- and watermarking- related settings. A Results
object is returned that, when it comes to merging of files, always contains a single file in element 0
that holds the byte array for the merged PDF file.
Sample code
The following sample merges all files specified on the command line into a single PDF. If the source files aren’t already in PDF format, it automatically converts them in the process. A PDF bookmark is automatically generated for each merged file as well.
The example described below assumes the following:
- The JDK has been installed and configured.
- The conversion service and all prerequisites have been installed in line with the administration guide.
- The conversion service is running in the default anonymous mode. This is not an absolute requirement, but it makes initial experimentation much easier.
The first step is to generate proxy classes for the web service by executing the following command:
wsimport https://localhost:41734/Muhimbi.DocumentConverter.WebService/?wsdl -d src -Xnocompile -p com.muhimbi.ws
Feel free to change the package name and destination directory to something more suitable for your organization.
wsimport
automatically generates the Java class names. Unfortunately, some of the generated names are rather long and ugly, so you may want to consider renaming some — particularly the exception classes — to something friendlier. However, this means that if you ever run wsimport
again, you’ll need to reapply those changes. For more information, refer to the high-level overview of the object model exposed by the web service.
Once the proxy classes have been created, add the following sample code to your project. Run the code and make sure the files to merge are specified on the command line.
As of version 5.2, this sample code is automatically installed alongside the product:
package com.muhimbi.app;
import com.muhimbi.ws.*;import java.io.*;import java.net.URL;import javax.xml.bind.JAXBElement;import javax.xml.namespace.QName;
public class WsClient {
private final static String DOCUMENTCONVERTERSERVICE_WSDL_LOCATION = "https://localhost:41734/Muhimbi.DocumentConverter.WebService/?wsdl";
private static ObjectFactory _objectFactory = new ObjectFactory();
public static void main(String[] args) { try { if (args.length == 0) { System.out.println("Please specify one or more file names to convert and merge."); } else { System.out.println("Merging files");
// ** Initialise Web Service
DocumentConverterService_Service dcss = new DocumentConverterService_Service(new URL(DOCUMENTCONVERTERSERVICE_WSDL_LOCATION), new QName("https://tempuri.org/", "DocumentConverterService")); DocumentConverterService dcs = dcss.getBasicHttpBindingDocumentConverterService();
// ** Get the options for all files that need to be merged
ProcessingOptions processingOptions = getProcessingOptions(args);
// ** Carry out the merging (and converting if needed)
BatchResults results = dcs.processBatch(processingOptions);
// ** Get the content of the first file, which holds the merged file in the byte array
byte[] convertedFile = results.getResults().getValue().getBatchResult().get(0).getFile().getValue();
// ** Write converted file to file system
writeFile(convertedFile, "merged.pdf"); System.out.println("Files merged into 'merged.pdf'"); }
} catch (IOException e) { System.out.println(e.getMessage()); } catch (DocumentConverterServiceProcessBatchWebServiceFaultExceptionFaultFaultMessage e) { printException(e.getFaultInfo()); } }
public static ProcessingOptions getProcessingOptions(String[] sourceFileNames) throws IOException { // ** Options and all settings for batch conversion
ProcessingOptions processingOptions = new ProcessingOptions();
// ** Specify the minimum level of merge settings, you can optionally add watermarks and security settings
MergeSettings mergeSettings = new MergeSettings(); mergeSettings.setBreakOnError(false); processingOptions.setMergeSettings(_objectFactory.createProcessingOptionsMergeSettings(mergeSettings));
// ** Create an array of files to merge
ArrayOfSourceFile sourceFiles = new ArrayOfSourceFile(); for (int i = 0; i < sourceFileNames.length; i++) { SourceFile sourceFile = getSourceFile(sourceFileNames[i]); sourceFiles.getSourceFile().add(sourceFile); }
processingOptions.setSourceFiles(_objectFactory.createProcessingOptionsSourceFiles(sourceFiles)); return processingOptions; }
public static SourceFile getSourceFile(String fileName) throws IOException { File file = new File(fileName);
// ** Read the contents of the file
System.out.println("- Reading: " + fileName); byte[] sourceFileContent = readFile(fileName);
// ** Set the absolute minimum open options
OpenOptions openOptions = getOpenOptions(getFileName(file), getFileExtension(file));
// ** Set the absolute minimum conversion settings.
ConversionSettings conversionSettings = getConversionSettings();
// ** Create merge settings for each file and set the name for the PDF bookmark
FileMergeSettings fileMergeSettings = new FileMergeSettings(); fileMergeSettings.setTopLevelBookmark(_objectFactory.createFileMergeSettingsTopLevelBookmark(file.getName()));
// ** Create a source file object and return it
SourceFile sourceFile = new SourceFile(); sourceFile.setOpenOptions(_objectFactory.createSourceFileOpenOptions(openOptions)); sourceFile.setConversionSettings(_objectFactory.createSourceFileConversionSettings(conversionSettings)); sourceFile.setMergeSettings(_objectFactory.createSourceFileMergeSettings(fileMergeSettings)); sourceFile.setFile(_objectFactory.createSourceFileFile(sourceFileContent)); return sourceFile; }
public static OpenOptions getOpenOptions(String fileName, String fileExtension) { OpenOptions openOptions = new OpenOptions(); // ** Set the minimum required open options. Additional options are available
openOptions.setOriginalFileName(_objectFactory.createOpenOptionsOriginalFileName(fileName)); openOptions.setFileExtension(_objectFactory.createOpenOptionsFileExtension(fileExtension)); return openOptions; }
public static ConversionSettings getConversionSettings() { ConversionSettings conversionSettings = new ConversionSettings(); // ** Set the minimum required conversion settings. Additional settings are available
conversionSettings.setQuality(ConversionQuality.OPTIMIZE_FOR_PRINT); conversionSettings.setRange(ConversionRange.ALL_DOCUMENTS); conversionSettings.getFidelity().add("Full"); conversionSettings.setFormat(OutputFormat.PDF); return conversionSettings; }
public static String getFileName(File file) { String fileName = file.getName(); return fileName; }
public static String getFileExtension(File file) { String fileName = file.getName(); return fileName.substring(fileName.lastIndexOf('.') + 1, fileName.length()); }
public static byte[] readFile(String filepath) throws IOException { File file = new File(filepath); InputStream is = new FileInputStream(file); long length = file.length(); byte[] bytes = new byte[(int) length];
int offset = 0; int numRead; while (offset < bytes.length && (numRead = is.read(bytes, offset, bytes.length - offset)) >= 0) { offset += numRead; }
if (offset < bytes.length) { throw new IOException("Could not completely read file " + file.getName()); } is.close(); return bytes; }
public static void writeFile(byte[] fileContent, String filepath) throws IOException { OutputStream os = new FileOutputStream(filepath); os.write(fileContent); os.close(); }
public static void printException(WebServiceFaultException serviceFaultException) { System.out.println(serviceFaultException.getExceptionType()); JAXBElement < ArrayOfstring > element = serviceFaultException.getExceptionDetails(); ArrayOfstring value = element.getValue(); for (String msg: value.getString()) { System.out.println(msg); } }
}
Conclusion
Merging multiple PDF and other supported document formats using Java is made seamless and robust with Nutrient Document Converter Services. By leveraging the ProcessBatch
method, developers can not only combine various file types into a single, well-structured PDF, but also preserve formatting, apply watermarks, set security options, and generate dynamic bookmarks — all from within a consistent web services interface.
Whether you’re handling bulk document workflows, building PDF automation into enterprise systems, or simply looking to streamline multi-file handling, the provided Java integration delivers both flexibility and reliability. With minimal setup and powerful customization options, integrating document merging into your Java applications has never been easier.