结合两个(或更多)PDF的

背景:我需要为销售人员提供每周报告包。 这个软件包包含几个(5-10)水晶报告。

问题:我希望允许用户运行所有报告,并且只运行一个报告。 我想我可以通过创build报告来做到这一点,然后做:

List<ReportClass> reports = new List<ReportClass>(); reports.Add(new WeeklyReport1()); reports.Add(new WeeklyReport2()); reports.Add(new WeeklyReport3()); <snip> foreach (ReportClass report in reports) { report.ExportToDisk(ExportFormatType.PortableDocFormat, @"c:\reports\" + report.ResourceName + ".pdf"); } 

这将为我提供一个包含所有报告的文件夹,但是我想用每周的所有报告给每个人发一封PDF。 所以我需要把它们结合起来

有没有简单的方法来做到这一点,而无需安装更多的第三方控制? 我已经有DevExpress和CrystalReports,我不想添加太多。

将它们合并到foreach循环还是单独循环最好? (或另一种方式)

谢谢

我不得不解决一个类似的问题,我最终做的是创build一个使用PDFSharp项目的小型pdfmerge实用程序,该项目基本上是MIT许可的。

代码很简单,我需要一个cmdline实用程序,所以我有更多的专用于parsing参数的代码,而不是我为PDF合并所做的:

 using (PdfDocument one = PdfReader.Open("file1.pdf", PdfDocumentOpenMode.Import)) using (PdfDocument two = PdfReader.Open("file2.pdf", PdfDocumentOpenMode.Import)) using (PdfDocument outPdf = new PdfDocument()) { CopyPages(one, outPdf); CopyPages(two, outPdf); outPdf.Save("file1and2.pdf"); } void CopyPages(PdfDocument from, PdfDocument to) { for (int i = 0; i < from.PageCount; i++) { to.AddPage(from.Pages[i]); } } 

这是一个单一的function,将使用PDFSharp合并X个PDF文件

 public static void MergePDFs(string targetPath, params string[] pdfs) { using(PdfDocument targetDoc = new PdfDocument()){ foreach (string pdf in pdfs) { using (PdfDocument pdfDoc = PdfReader.Open(pdf, PdfDocumentOpenMode.Import)) { for (int i = 0; i < pdfDoc.PageCount; i++) { targetDoc.AddPage(pdfDoc.Pages[i]); } } } targetDoc.Save(targetPath); } } 

PDFsharp似乎允许将多个PDF文档合并为一个。

而ITextSharp也是如此 。

这是我想出来的,想和大家分享一下。

  public static byte[] MergePdf(List<byte[]> pdfs) { List<PdfSharp.Pdf.PdfDocument> lstDocuments = new List<PdfSharp.Pdf.PdfDocument>(); foreach (var pdf in pdfs) { lstDocuments.Add(PdfReader.Open(new MemoryStream(pdf), PdfDocumentOpenMode.Import)); } using (PdfSharp.Pdf.PdfDocument outPdf = new PdfSharp.Pdf.PdfDocument()) { for(int i = 1; i<= lstDocuments.Count; i++) { foreach(PdfSharp.Pdf.PdfPage page in lstDocuments[i-1].Pages) { outPdf.AddPage(page); } } MemoryStream stream = new MemoryStream(); outPdf.Save(stream, false); byte[] bytes = stream.ToArray(); return bytes; } } 

这里有一些很好的答案,但是我想我可能会提到pdftk可能对这个任务有用。 您不必直接生成一个PDF,而是可以生成您需要的每个PDF,然后将它们作为后处理与pdftk结合在一起。 这甚至可以在程序中使用system()或ShellExecute()调用完成。

以下是使用PDFSharp和ConcatenateDocuments的示例链接

我知道很多人都推荐PDF Sharp,但是从2008年6月份开始这个项目并没有更新,而且源码也没有。

就我个人而言,我一直在玩iTextSharp,这很容易处理。

我用iTextsharp与c#合并PDF文件。 这是我使用的代码。

 string[] lstFiles=new string[3]; lstFiles[0]=@"C:/pdf/1.pdf"; lstFiles[1]=@"C:/pdf/2.pdf"; lstFiles[2]=@"C:/pdf/3.pdf"; PdfReader reader = null; Document sourceDocument = null; PdfCopy pdfCopyProvider = null; PdfImportedPage importedPage; string outputPdfPath=@"C:/pdf/new.pdf"; sourceDocument = new Document(); pdfCopyProvider = new PdfCopy(sourceDocument, new System.IO.FileStream(outputPdfPath, System.IO.FileMode.Create)); //Open the output file sourceDocument.Open(); try { //Loop through the files list for (int f = 0; f < lstFiles.Length-1; f++) { int pages =get_pageCcount(lstFiles[f]); reader = new PdfReader(lstFiles[f]); //Add pages of current file for (int i = 1; i <= pages; i++) { importedPage = pdfCopyProvider.GetImportedPage(reader, i); pdfCopyProvider.AddPage(importedPage); } reader.Close(); } //At the end save the output file sourceDocument.Close(); } catch (Exception ex) { throw ex; } private int get_pageCcount(string file) { using (StreamReader sr = new StreamReader(File.OpenRead(file))) { Regex regex = new Regex(@"/Type\s*/Page[^s]"); MatchCollection matches = regex.Matches(sr.ReadToEnd()); return matches.Count; } } 

将使用iTextSharp的两个byte[]结合到版本5.x:

 internal static MemoryStream mergePdfs(byte[] pdf1, byte[] pdf2) { MemoryStream outStream = new MemoryStream(); using (Document document = new Document()) using (PdfCopy copy = new PdfCopy(document, outStream)) { document.Open(); copy.AddDocument(new PdfReader(pdf1)); copy.AddDocument(new PdfReader(pdf2)); } return outStream; } 

而不是byte[]的,也可以通过Stream

我结合了上述两个,因为我需要合并3个pdfbytes并返回一个字节

 internal static byte[] mergePdfs(byte[] pdf1, byte[] pdf2,byte[] pdf3) { MemoryStream outStream = new MemoryStream(); using (Document document = new Document()) using (PdfCopy copy = new PdfCopy(document, outStream)) { document.Open(); copy.AddDocument(new PdfReader(pdf1)); copy.AddDocument(new PdfReader(pdf2)); copy.AddDocument(new PdfReader(pdf3)); } return outStream.ToArray(); } 

这里的解决schemehttp://www.wacdesigns.com/2008/10/03/merge-pdf-files-using-c它使用免费的开源iTextSharp库http://sourceforge.net/projects/itextsharp

我已经用PDFBox做了这个。 我想它的作用与iTextSharp类似。

你可以试试pdf- shuffler gtk-apps.org

下面的方法得到一个byte数组,它是PDF byte数组,然后返回一个byte数组。

 using ...; using PdfSharp.Pdf; using PdfSharp.Pdf.IO; public static class PdfHelper { public static byte[] PdfConcat(List<byte[]> lstPdfBytes) { byte[] res; using (var outPdf = new PdfDocument()) { foreach (var pdf in lstPdfBytes) { using (var pdfStream = new MemoryStream(pdf)) using (var pdfDoc = PdfReader.Open(pdfStream, PdfDocumentOpenMode.Import)) for (var i = 0; i < pdfDoc.PageCount; i++) outPdf.AddPage(pdfDoc.Pages[i]); } using (var memoryStreamOut = new MemoryStream()) { outPdf.Save(memoryStreamOut, false); res = Stream2Bytes(memoryStreamOut); } } return res; } public static void DownloadAsPdfFile(string fileName, byte[] content) { var ms = new MemoryStream(content); HttpContext.Current.Response.Clear(); HttpContext.Current.Response.ContentType = "application/pdf"; HttpContext.Current.Response.AddHeader("content-disposition", $"attachment;filename={fileName}.pdf"); HttpContext.Current.Response.Buffer = true; ms.WriteTo(HttpContext.Current.Response.OutputStream); HttpContext.Current.Response.End(); } private static byte[] Stream2Bytes(Stream input) { var buffer = new byte[input.Length]; using (var ms = new MemoryStream()) { int read; while ((read = input.Read(buffer, 0, buffer.Length)) > 0) ms.Write(buffer, 0, read); return ms.ToArray(); } } } 

所以,将PdfHelper.PdfConcat方法的结果传递给PdfHelper.DownloadAsPdfFile方法。

PS:需要安装名为[PdfSharp][1] NuGet软件包。 所以在Package Manage Console窗口中键入:

安装包PdfSharp

这里是一个使用iTextSharp的例子

 public static void MergePdf(Stream outputPdfStream, IEnumerable<string> pdfFilePaths) { using (var document = new Document()) using (var pdfCopy = new PdfCopy(document, outputPdfStream)) { pdfCopy.CloseStream = false; try { document.Open(); foreach (var pdfFilePath in pdfFilePaths) { using (var pdfReader = new PdfReader(pdfFilePath)) { pdfCopy.AddDocument(pdfReader); pdfReader.Close(); } } } finally { document?.Close(); } } } 

PdfReader的构造函数有很多重载。 可以用IEnumerable<Stream>replace参数typesIEnumerable<string> IEnumerable<Stream> ,它也可以工作。 请注意,该方法不closuresOutputStream,它将该任务委派给Stream创build者。