合并两个(或多个)PDF


75

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

问题: 我想允许用户运行所有报告,也只运行一个报告。我以为可以通过创建报告然后执行以下操作来做到这一点:

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");
}

这样可以为我提供一个充满报告的文件夹,但是我想通过电子邮件将每个星期的报告发送给所有人。所以我需要将它们结合起来。

有没有一种简单的方法,而无需安装任何其他第三方控件?我已经有了DevExpress和CrystalReports,并且我不想添加太多。

最好在foreach循环中或在单独的循环中组合它们?(或另一种方法)


看来我将需要一些第三方库,感谢所有帮助。
内森·库普

Answers:


114

我必须解决一个类似的问题,最终要做的是创建一个小的pdfmerge实用程序,该实用程序使用本质上是MIT许可的PDFSharp项目。

该代码非常简单,我需要一个cmdline实用程序,因此与用于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]);
    }
}

啊,看起来马丁(Martin)击败了我,我是说这是因为我正在挖掘代码示例:)
安德鲁·伯恩斯

嗨安德鲁,你会请看一看这个....请stackoverflow.com/questions/6953471/...
user682417

是否有人在CopyPages(one,outDocument)周围出现“非静态字段,方法或属性需要对象引用”的错误?CopyPages(两个,outDocument);
user001 2015年

2
如果您是从nuget安装PDFSharp的,请确保您使用的是预发行版本,否则可能会遇到此错误:stackoverflow.com/questions/36788746/…–
mkimmet

我不知道它是否仍在维护,该站点是否只是临时的无法访问或一段时间以来都无法访问。无论如何,NuGet链接nuget.org/packages/PdfSharp
Cfun

35

这是一个单个函数,它将使用PDFSharp合并X份PDF

using PdfSharp;
using PdfSharp.Pdf;
using PdfSharp.Pdf.IO;

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);
    }
}

3
需要使用PdfSharp;使用PdfSharp.Pdf; 使用PdfSharp.Pdf.IO;
B.Hawkins '18

您在string [] pdf中传递什么值?它是文件路径。
KMR

@KMR是的,它是文件路径。
JustMaier

8

我想出了这一点,并希望使用PdfSharp与您分享。

在这里,您可以将多个Pdfs合二为一,而不需要输出目录(按照输入列表的顺序)

    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;
        }           
    }

3

我将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;
    }
}


2

这是使用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<string>IEnumerable<Stream>它也应该工作。请注意,该方法不会关闭OutputStream,它将该任务委托给Stream创建者。


1

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


1

byte[]使用iTextSharp结合两个至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


我在您的代码所需的外部库上添加了信息。请始终添加使用答案所需的所有信息。
mkl

1

我将以上两者结合在一起,因为我需要合并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();
        } 



0

我已经用PDFBox完成了。我想它的工作方式与iTextSharp类似。



0

我知道很多人都推荐过PDF Sharp,但是自2008年6月以来似乎没有对该项目进行过更新。此外,该源不可用。

就个人而言,我一直在使用iTextSharp,它非常容易使用。


2

0

下面的方法得到了Listbyte阵列是PDFbyte数组,然后返回一个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:需要安装一个NuGet名为的软件包[PdfSharp][1]。因此,在Package Manage Console窗口中输入:

安装包PdfSharp


0

以下方法使用iTextSharp合并两个pdf(f1和f2)。第二个pdf附加在特定索引f1之后。

 string f1 = "D:\\a.pdf";
 string f2 = "D:\\Iso.pdf";
 string outfile = "D:\\c.pdf";
 appendPagesFromPdf(f1, f2, outfile, 3);




  public static void appendPagesFromPdf(String f1,string f2, String destinationFile, int startingindex)
        {
            PdfReader p1 = new PdfReader(f1);
            PdfReader p2 = new PdfReader(f2);
            int l1 = p1.NumberOfPages, l2 = p2.NumberOfPages;


            //Create our destination file
            using (FileStream fs = new FileStream(destinationFile, FileMode.Create, FileAccess.Write, FileShare.None))
            {
                Document doc = new Document();

                PdfWriter w = PdfWriter.GetInstance(doc, fs);
                doc.Open();
                for (int page = 1; page <= startingindex; page++)
                {
                    doc.NewPage();
                    w.DirectContent.AddTemplate(w.GetImportedPage(p1, page), 0, 0);
                    //Used to pull individual pages from our source

                }//  copied pages from first pdf till startingIndex
                for (int i = 1; i <= l2;i++)
                {
                    doc.NewPage();
                    w.DirectContent.AddTemplate(w.GetImportedPage(p2, i), 0, 0);
                }// merges second pdf after startingIndex
                for (int i = startingindex+1; i <= l1;i++)
                {
                    doc.NewPage();
                    w.DirectContent.AddTemplate(w.GetImportedPage(p1, i), 0, 0);
                }// continuing from where we left in pdf1 

                doc.Close();
                p1.Close();
                p2.Close();

            }
        }

1
这是一种非常有损的方法(所有注释都会丢失),并且在合并页面和页面旋转时会遇到问题。看看hmadrigal的答案可以找到更好的方法。
mkl

谢谢,我会检查一下。
维拉·辛格

0

为了解决类似的问题,我使用了iTextSharp,如下所示:

//Create the document which will contain the combined PDF's
Document document = new Document();

//Create a writer for de document
PdfCopy writer = new PdfCopy(document, new FileStream(OutPutFilePath, FileMode.Create));
if (writer == null)
{
     return;
}

//Open the document
document.Open();

//Get the files you want to combine
string[] filePaths = Directory.GetFiles(DirectoryPathWhereYouHaveYourFiles);
foreach (string filePath in filePaths)
{
     //Read the PDF file
     using (PdfReader reader = new PdfReader(vls_FilePath))
     {
         //Add the file to the combined one
         writer.AddDocument(reader);
     }
}

//Finally close the document and writer
writer.Close();
document.Close();
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.