Merge PDF files in C# with OnePDF, keeping bookmarks, links and form fields, merge PDFs held in memory, or append chosen pages to a file.
using OnePdf; string[] files = ["chapter-1.pdf", "chapter-2.pdf"]; List<PdfDocument> sources = files.Select(f => PdfDocument.Open(f)).ToList(); try { using PdfDocument merged = PdfDocument.Merge(sources); merged.SetInfo("Title", "Collected chapters"); // Merge copies no metadata merged.Save("merged.pdf"); Console.WriteLine($"{merged.PageCount} pages"); foreach (PdfOutlineItem bookmark in merged.Outline) Console.WriteLine($" bookmark: {bookmark.Title}"); } finally { foreach (PdfDocument source in sources) source.Dispose(); } // PDFs held in memory: open the bytes, merge, and get bytes back. byte[] first = File.ReadAllBytes("chapter-1.pdf"); byte[] second = File.ReadAllBytes("chapter-2.pdf"); using (PdfDocument a = PdfDocument.Open(first)) using (PdfDocument b = PdfDocument.Open(second)) using (PdfDocument both = PdfDocument.Merge([a, b])) { var buffer = new MemoryStream(); both.Save(buffer); Console.WriteLine($"{buffer.Length:N0} bytes in memory"); } // Append only the first page of another file to an existing document. using (PdfDocument target = PdfDocument.Open("chapter-1.pdf", new PdfOpenOptions { AllowEditing = true })) using (PdfDocument other = PdfDocument.Open("chapter-2.pdf")) { target.ImportPages(other, [0]); target.Save("chapter-1-plus.pdf"); Console.WriteLine($"chapter-1-plus.pdf: {target.PageCount} pages"); }
4 pages bookmark: Chapter 1, part 1 bookmark: Chapter 1, part 2 bookmark: Chapter 2, part 1 bookmark: Chapter 2, part 2 32,147 bytes in memory chapter-1-plus.pdf: 3 pages
What comes along
- Bookmarks that lead to copied pages are appended after the existing ones.
- Links between copied pages keep working. A link to a page that was left behind keeps its rectangle and loses its target.
- Form fields come with the field tree above them. A field name already used in the target gets a
_2,_3suffix, so fields of the same name are renamed, not merged. - Tagged structure, page labels and optional content of the copied pages.
- Each shared font or image is copied once, however many pages use it.
Not carried: the sources' metadata, signatures, document-level JavaScript and permissions. Merge writes no title, so set one with SetInfo.
Good to know
MergeandImportPagestake any open document, including encrypted ones. An encrypted source imports as plain content, so a merged result is unencrypted unless you save it withPdfSaveOptions.Encryption = PdfEncryptionAction.Set.- The merged document lives in memory and doesn’t refer to its sources, which you can dispose as soon as
Mergereturns. ImportPages(source, indexes, insertAt)inserts at a position instead of appending.
To go the other way, see Split a PDF. Every rule for copied pages is in Page operations.
A longer walk-through with bookmarks, links, form fields and an ASP.NET Core endpoint: Merge PDF files in C#.