Merge PDF files with iText# and .NET
I’ve made a simple class to merge PDF files using iText#:
csharp:
using System;
using System.Collections.Generic;
using System.IO;
using iTextSharp.text;
using iTextSharp.text.pdf;
public class PdfMerge
{
private BaseFont baseFont;
private bool enablePagination = false;
private readonly List<PdfReader> documents;
private int totalPages;
public BaseFont BaseFont
{
get { return baseFont; }
set { baseFont = value; }
}
public bool EnablePagination
{
get { return enablePagination; }
set
{
enablePagination = value;
if (value && baseFont == null)
baseFont = BaseFont.CreateFont(BaseFont.HELVETICA, BaseFont.CP1252, BaseFont.NOT_EMBEDDED);
}
}
public List<PdfReader> Documents
{
get { return documents; }
}
public void AddDocument(string filename)
{
documents.Add(new PdfReader(filename));
}
public void AddDocument(Stream pdfStream)
{
documents.Add(new PdfReader(pdfStream));
}
public void AddDocument(byte[] pdfContents)
{
documents.Add(new PdfReader(pdfContents));
}
public void AddDocument(PdfReader pdfDocument)
{
documents.Add(pdfDocument);
}
public void Merge(string outputFilename)
{
Merge(new FileStream(outputFilename, FileMode.Create));
}
public void Merge(Stream outputStream)
{
if (outputStream == null || !outputStream.CanWrite)
throw new Exception("OutputStream es nulo o no se puede escribir en éste.");
Document newDocument = null;
try
{
newDocument = new Document();
PdfWriter pdfWriter = PdfWriter.GetInstance(newDocument, outputStream);
newDocument.Open();
PdfContentByte pdfContentByte = pdfWriter.DirectContent;
if (EnablePagination)
documents.ForEach(delegate(PdfReader doc)
{
totalPages += doc.NumberOfPages;
});
int currentPage = 1;
foreach (PdfReader pdfReader in documents)
{
for (int page = 1; page <= pdfReader.NumberOfPages; page++)
{
newDocument.NewPage();
PdfImportedPage importedPage = pdfWriter.GetImportedPage(pdfReader, page);
pdfContentByte.AddTemplate(importedPage, 0, 0);
if (EnablePagination)
{
pdfContentByte.BeginText();
pdfContentByte.SetFontAndSize(baseFont, 9);
pdfContentByte.ShowTextAligned(PdfContentByte.ALIGN_CENTER,
string.Format("{0} de {1}", currentPage++, totalPages), 520, 5, 0);
pdfContentByte.EndText();
}
}
}
}
finally
{
outputStream.Flush();
if (newDocument != null)
newDocument.Close();
outputStream.Close();
}
}
public PdfMerge()
{
documents = new List<PdfReader>();
}
}
using System.Collections.Generic;
using System.IO;
using iTextSharp.text;
using iTextSharp.text.pdf;
public class PdfMerge
{
private BaseFont baseFont;
private bool enablePagination = false;
private readonly List<PdfReader> documents;
private int totalPages;
public BaseFont BaseFont
{
get { return baseFont; }
set { baseFont = value; }
}
public bool EnablePagination
{
get { return enablePagination; }
set
{
enablePagination = value;
if (value && baseFont == null)
baseFont = BaseFont.CreateFont(BaseFont.HELVETICA, BaseFont.CP1252, BaseFont.NOT_EMBEDDED);
}
}
public List<PdfReader> Documents
{
get { return documents; }
}
public void AddDocument(string filename)
{
documents.Add(new PdfReader(filename));
}
public void AddDocument(Stream pdfStream)
{
documents.Add(new PdfReader(pdfStream));
}
public void AddDocument(byte[] pdfContents)
{
documents.Add(new PdfReader(pdfContents));
}
public void AddDocument(PdfReader pdfDocument)
{
documents.Add(pdfDocument);
}
public void Merge(string outputFilename)
{
Merge(new FileStream(outputFilename, FileMode.Create));
}
public void Merge(Stream outputStream)
{
if (outputStream == null || !outputStream.CanWrite)
throw new Exception("OutputStream es nulo o no se puede escribir en éste.");
Document newDocument = null;
try
{
newDocument = new Document();
PdfWriter pdfWriter = PdfWriter.GetInstance(newDocument, outputStream);
newDocument.Open();
PdfContentByte pdfContentByte = pdfWriter.DirectContent;
if (EnablePagination)
documents.ForEach(delegate(PdfReader doc)
{
totalPages += doc.NumberOfPages;
});
int currentPage = 1;
foreach (PdfReader pdfReader in documents)
{
for (int page = 1; page <= pdfReader.NumberOfPages; page++)
{
newDocument.NewPage();
PdfImportedPage importedPage = pdfWriter.GetImportedPage(pdfReader, page);
pdfContentByte.AddTemplate(importedPage, 0, 0);
if (EnablePagination)
{
pdfContentByte.BeginText();
pdfContentByte.SetFontAndSize(baseFont, 9);
pdfContentByte.ShowTextAligned(PdfContentByte.ALIGN_CENTER,
string.Format("{0} de {1}", currentPage++, totalPages), 520, 5, 0);
pdfContentByte.EndText();
}
}
}
}
finally
{
outputStream.Flush();
if (newDocument != null)
newDocument.Close();
outputStream.Close();
}
}
public PdfMerge()
{
documents = new List<PdfReader>();
}
}
Usage:
csharp:
string basePath = "c:\\pdf";
PdfMerge demo = new PdfMerge();
demo.AddDocument(Path.Combine(basePath, "static-dynamic-typing-meijer.pdf"));
demo.AddDocument(Path.Combine(basePath, "composable-memory-transactions.pdf"));
demo.Merge("mergedPapers.pdf");
Console.WriteLine("Archivo generado en: {0}", Path.GetFullPath("mergedPapers.pdf"));
PdfMerge demo = new PdfMerge();
demo.AddDocument(Path.Combine(basePath, "static-dynamic-typing-meijer.pdf"));
demo.AddDocument(Path.Combine(basePath, "composable-memory-transactions.pdf"));
demo.Merge("mergedPapers.pdf");
Console.WriteLine("Archivo generado en: {0}", Path.GetFullPath("mergedPapers.pdf"));
If you want the source code, you can download the Visual Studio 2005 solution.
8 Responses to “Merge PDF files with iText# and .NET”
July 19th, 2007 at 10:09 am
[...] the previous post I showed a class to merge PDF files using iText#, but it seems that there’s a better approach [...]
September 19th, 2007 at 2:27 pm
It forgives to invade its mail thus, but it would like to know if you has some source of iTextSharp that it makes convert of a page ASP/HTML for PDF directly. It forgives for the English but I am Brazilian. Thank very much.
Estevam
September 20th, 2007 at 7:49 am
Luiz, take a look to the following links:
http://www.ujihara.jp/iTextdotNET/en/examplesvb.html
http://geekswithblogs.net/casualjim/articles/59943.aspx
March 24th, 2008 at 3:29 pm
Thank you for your piece of code, tt´s very useful.
May 8th, 2008 at 3:06 pm
Olá Alex,
Eu já tinha feito um merge de PDF, mas mesmo assim testei o seu e tem o mesmo problema que o meu.
Toda vez que eu crio o novo documento eu perco todas as assinaturas digitais do original, você tem idéia como eu faço esse merge utilizando cópia de bytes?
Eu consegui fazer apenas uma cópia utilizando bytes sem perder as assinaturas digitais mas não consegui fazer o merge. Segue meu código.
PdfReader readersign = new PdfReader(pathpdfreader);
FileStream pdffile = new FileStream(pathpdfhashed, FileMode.Create );
PdfStamper stp = PdfStamper.CreateSignature(readersign, pdffile, \’\', null, true);
PdfSignatureAppearance sap = stp.SignatureAppearance;
PdfSignature dic = new PdfSignature(PdfName.ADOBE_PPKMS, PdfName.ADBE_PKCS7_SHA1);
sap.CryptoDictionary = dic;
int csize = 4000;
Hashtable exc = new Hashtable();
exc[PdfName.CONTENTS] = csize * 2 + 2;
sap.PreClose(exc);
byte[] outc = new byte[csize];
PdfDictionary dic2 = new PdfDictionary();
dic2.Put(PdfName.CONTENTS, new PdfString(outc).SetHexWriting(true));
sap.Close(dic2);
July 1st, 2008 at 12:38 am
I had to tweak my document object to take pagesize.letter in the constructor. I had to get my margins to line up the same way as my originals. Clearly, that could be more dynamic on my part to read the size of the incoming docs first.
However, my point is that this got me 99% of the way there. It was greatly helpful… thanks!
July 21st, 2008 at 8:57 am
Hi,
I want to ask you if this code with AddTemplate maked PDFs that are readable with not professional Acrobat Reader? I have heard that the normal Acrobat Reader is not supporting templates.
July 21st, 2008 at 9:02 am
Hi, again!
I\’m using your code and I\’m trying yo merge two equal pdf file s but it\’s not working because it says there are duplicate pages. What should I do if I want one and the same element (page) to repeat several times on a pdf document. Probably it\’s not doing implicit renaming of the form fields?
Leave a Reply