C# 如何合并多个pdf文件(在运行时生成)?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/15925616/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-10 18:29:21  来源:igfitidea点击:

How to merge multiple pdf files (generated in run time)?

c#asp.netpdfitextsharprdlc

提问by Anyname Donotcare

How to merge multiple pdf files (generated on run time) through ItextSharpthen printing them.

如何合并多个 pdf 文件(在运行时生成)ItextSharp然后打印它们。

I found the following linkbut that method requires the pdf names considering that the pdf files stored and this is not my case .

我找到了以下链接,但考虑到存储的 pdf 文件,该方法需要 pdf 名称,这不是我的情况。



I have multiple reports i'll convert them to pdf filesthrough this method :

我有多个报告,我将pdf files通过此方法将它们转换为:

private void AddReportToResponse(LocalReport followsReport)
{
    string mimeType;
    string encoding;
    string extension;
    string[] streams = new string[100];
    Warning[] warnings = new Warning[100];
    byte[] pdfStream = followsReport.Render("PDF", "", out mimeType, out encoding, out extension, out streams, out warnings);
  //Response.Clear();
  //Response.ContentType = mimeType;
  //Response.AddHeader("content-disposition", "attachment; filename=Application." + extension);
  //Response.BinaryWrite(pdfStream);
  //Response.End();
}

Now i want to merge all those generated files (Bytes) in one pdf file to print it

现在我想将所有生成的文件 ( Bytes)合并到一个 pdf 文件中以进行打印

采纳答案by mkl

If you want to merge source documents using iText(Sharp), there are two basic situations:

如果要使用 iText(Sharp) 合并源文档,有两种基本情况:

  1. You really want to merge the documents, acquiring the pages in their original format, transfering as much of their content and their interactive annotations as possible. In this case you should use a solution based on a member of the Pdf*Copy*family of classes.

  2. You actually want to integrate pages from the source documents into a new document but want the new document to govern the general format and don't care for the interactive features (annotations...) in the original documents (or even want to get rid of them). In this case you should use a solution based on the PdfWriterclass.

  1. 您确实希望合并文档,以原始格式获取页面,传输尽可能多的内容和交互式注释。在这种情况下,您应该使用基于Pdf*Copy*类家族成员的解决方案。

  2. 您实际上希望将源文档中的页面集成到新文档中,但希望新文档管理通用格式并且不关心原始文档中的交互功能(注释...)(甚至想要摆脱其中)。在这种情况下,您应该使用基于PdfWriter类的解决方案。

You can find details in chapter 6(especially section 6.4) of iText in Action — 2nd Edition. The Java sample code can be accessed hereand the C#'ified versions here.

您可以在iText in Action - 2nd Edition 的第 6 章(尤其是第 6.4 节)中找到详细信息。Java的示例代码可以访问这里和C#“指明分数版本在这里

A simple sample using PdfCopyis Concatenate.java/ Concatenate.cs. The central piece of code is:

一个简单的示例PdfCopyConcatenate.java/ Concatenate.cs。核心代码是:

byte[] mergedPdf = null;
using (MemoryStream ms = new MemoryStream())
{
    using (Document document = new Document())
    {
        using (PdfCopy copy = new PdfCopy(document, ms))
        {
            document.Open();

            for (int i = 0; i < pdf.Count; ++i)
            {
                PdfReader reader = new PdfReader(pdf[i]);
                // loop over the pages in that document
                int n = reader.NumberOfPages;
                for (int page = 0; page < n; )
                {
                    copy.AddPage(copy.GetImportedPage(reader, ++page));
                }
            }
        }
    }
    mergedPdf = ms.ToArray();
}

Here pdfcan either be defined as a List<byte[]>immediately containing the source documents (appropriate for your use case of merging intermediate in-memory documents) or as a List<String>containing the names of source document files (appropriate if you merge documents from disk).

这里pdf可以定义为List<byte[]>直接包含源文档(适用于合并中间内存文档的用例)或List<String>包含源文档文件的名称(适用于从磁盘合并文档)。

An overview at the end of the referenced chapter summarizes the usage of the classes mentioned:

参考章节末尾的概述总结了提到的类的用法:

  • PdfCopy: Copies pages from one or more existing PDF documents. Major downsides: PdfCopydoesn't detect redundant content, and it fails when concatenating forms.

  • PdfCopyFields: Puts the fields of the different forms into one form. Can be used to avoid the problems encountered with form fields when concatenating forms using PdfCopy. Memory use can be an issue.

  • PdfSmartCopy: Copies pages from one or more existing PDF documents. PdfSmartCopyis able to detect redundant content, but it needs more memory and CPU than PdfCopy.

  • PdfWriter: Generates PDF documents from scratch. Can import pages from other PDF documents. The major downside is that all interactive features of the imported page (annotations, bookmarks, fields, and so forth) are lost in the process.

  • PdfCopy:从一个或多个现有 PDF 文档复制页面。主要缺点:PdfCopy不检测冗余内容,并且在连接表单时失败。

  • PdfCopyFields: 将不同表单的字段合并为一个表单。可用于避免在使用 连接表单时遇到的表单字段问题PdfCopy。内存使用可能是一个问题。

  • PdfSmartCopy:从一个或多个现有 PDF 文档复制页面。PdfSmartCopy能够检测冗余内容,但它需要比PdfCopy.

  • PdfWriter:从头开始生成 PDF 文档。可以从其他 PDF 文档导入页面。主要的缺点是导入页面的所有交互功能(注释、书签、字段等)在此过程中都丢失了。

回答by DSlagle

Here is some code I pulled out of an old project I had. It was a web application but I was using iTextSharp to merge pdf files then print them.

这是我从一个旧项目中提取的一些代码。这是一个网络应用程序,但我使用 iTextSharp 合并 pdf 文件然后打印它们。

public static class PdfMerger
    {
        /// <summary>
        /// Merge pdf files.
        /// </summary>
        /// <param name="sourceFiles">PDF files being merged.</param>
        /// <returns></returns>
        public static byte[] MergeFiles(List<Stream> sourceFiles)
        {
            Document document = new Document();
            MemoryStream output = new MemoryStream();

            try
            {
                // Initialize pdf writer
                PdfWriter writer = PdfWriter.GetInstance(document, output);
                writer.PageEvent = new PdfPageEvents();

                // Open document to write
                document.Open();
                PdfContentByte content = writer.DirectContent;

                // Iterate through all pdf documents
                for (int fileCounter = 0; fileCounter < sourceFiles.Count; fileCounter++)
                {
                    // Create pdf reader
                    PdfReader reader = new PdfReader(sourceFiles[fileCounter]);
                    int numberOfPages = reader.NumberOfPages;

                    // Iterate through all pages
                    for (int currentPageIndex = 1; currentPageIndex <=
                                        numberOfPages; currentPageIndex++)
                    {
                        // Determine page size for the current page
                        document.SetPageSize(
                            reader.GetPageSizeWithRotation(currentPageIndex));

                        // Create page
                        document.NewPage();
                        PdfImportedPage importedPage =
                            writer.GetImportedPage(reader, currentPageIndex);


                        // Determine page orientation
                        int pageOrientation = reader.GetPageRotation(currentPageIndex);
                        if ((pageOrientation == 90) || (pageOrientation == 270))
                        {
                            content.AddTemplate(importedPage, 0, -1f, 1f, 0, 0,
                                reader.GetPageSizeWithRotation(currentPageIndex).Height);
                        }
                        else
                        {
                            content.AddTemplate(importedPage, 1f, 0, 0, 1f, 0, 0);
                        }
                    }
                }
            }
            catch (Exception exception)
            {
                throw new Exception("There has an unexpected exception" +
                        " occured during the pdf merging process.", exception);
            }
            finally
            {
                document.Close();
            }
            return output.GetBuffer();
        }
    }



    /// <summary>
    /// Implements custom page events.
    /// </summary>
    internal class PdfPageEvents : IPdfPageEvent
    {
        #region members
        private BaseFont _baseFont = null;
        private PdfContentByte _content;
        #endregion

        #region IPdfPageEvent Members
        public void OnOpenDocument(PdfWriter writer, Document document)
        {
            _baseFont = BaseFont.CreateFont(BaseFont.HELVETICA,
                                BaseFont.CP1252, BaseFont.NOT_EMBEDDED);
            _content = writer.DirectContent;
        }

        public void OnStartPage(PdfWriter writer, Document document)
        { }

        public void OnEndPage(PdfWriter writer, Document document)
        { }

        public void OnCloseDocument(PdfWriter writer, Document document)
        { }

        public void OnParagraph(PdfWriter writer,
                    Document document, float paragraphPosition)
        { }

        public void OnParagraphEnd(PdfWriter writer,
                    Document document, float paragraphPosition)
        { }

        public void OnChapter(PdfWriter writer, Document document,
                                float paragraphPosition, Paragraph title)
        { }

        public void OnChapterEnd(PdfWriter writer,
                    Document document, float paragraphPosition)
        { }

        public void OnSection(PdfWriter writer, Document document,
                    float paragraphPosition, int depth, Paragraph title)
        { }

        public void OnSectionEnd(PdfWriter writer,
                    Document document, float paragraphPosition)
        { }

        public void OnGenericTag(PdfWriter writer, Document document,
                                    Rectangle rect, string text)
        { }
        #endregion

        private float GetCenterTextPosition(string text, PdfWriter writer)
        {
            return writer.PageSize.Width / 2 - _baseFont.GetWidthPoint(text, 8) / 2;
        }
    }

I didn't write this, but made some modifications. I can't remember where I found it. After I merged the PDFs I would call this method to insert javascript to open the print dialog when the PDF is opened. If you change bSilent to true then it should print silently to their default printer.

我没有写这个,但做了一些修改。我不记得我在哪里找到的。合并 PDF 后,我将调用此方法插入 javascript 以在打开 PDF 时打开打印对话框。如果您将 bSilent 更改为 true,则它应该以静默方式打印到其默认打印机。

public Stream addPrintJStoPDF(Stream thePDF)
{
    MemoryStream outPutStream = null;
    PRStream finalStream = null;
    PdfDictionary page = null;
    string content = null;

    //Open the stream with iTextSharp
    var reader = new PdfReader(thePDF);

    outPutStream = new MemoryStream(finalStream.GetBytes());
    var stamper = new PdfStamper(reader, (MemoryStream)outPutStream);
    var jsText = "var res = app.setTimeOut('this.print({bUI: true, bSilent: false, bShrinkToFit: false});', 200);";
    //Add the javascript to the PDF
    stamper.JavaScript = jsText;

    stamper.FormFlattening = true;
    stamper.Writer.CloseStream = false;
    stamper.Close();

    //Set the stream to the beginning
    outPutStream.Position = 0;

    return outPutStream;
}

Not sure how well the above code is written since I pulled it from somewhere else and I haven't worked in depth at all with iTextSharp but I do know that it did work at merging PDFs that I was generating at runtime.

不确定上面的代码写得有多好,因为我是从其他地方提取的,而且我根本没有使用 iTextSharp 进行过深入的工作,但我知道它确实可以合并我在运行时生成的 PDF。

回答by Sajitha Rathnayake

I used iTextsharp with c# to combine pdf files. This is the code I used.

我使用 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;
    }
}

回答by Murat Aykanat

To avoid the memory issues mentioned, I used file stream instead of memory stream(mentioned in ITextSharp Out of memory exception merging multiple pdf) to merge pdf files:

为了避免提到的内存问题,我使用文件流而不是内存流(在ITextSharp Out of memory exception merging multiple pdf 中提到)来合并 pdf 文件:

        var parentDirectory = Directory.GetParent(SelectedDocuments[0].FilePath);
        var savePath = parentDirectory + "\MergedDocument.pdf";

        using (var fs = new FileStream(savePath, FileMode.Create))
        {
            using (var document = new Document())
            {
                using (var pdfCopy = new PdfCopy(document, fs))
                {
                    document.Open();
                    for (var i = 0; i < SelectedDocuments.Count; i++)
                    {
                        using (var pdfReader = new PdfReader(SelectedDocuments[i].FilePath))
                        {
                            for (var page = 0; page < pdfReader.NumberOfPages;)
                            {
                                pdfCopy.AddPage(pdfCopy.GetImportedPage(pdfReader, ++page));
                            }
                        }
                    }
                }
            }
        }

回答by Nina

Tested with iTextSharp-LGPL4.1.6:

使用iTextSharp-LGPL4.1.6测试:

    public static byte[] ConcatenatePdfs(IEnumerable<byte[]> documents)
    {
        using (var ms = new MemoryStream())
        {
            var outputDocument = new Document();
            var writer = new PdfCopy(outputDocument, ms);
            outputDocument.Open();

            foreach (var doc in documents)
            {
                var reader = new PdfReader(doc);
                for (var i = 1; i <= reader.NumberOfPages; i++)
                {
                    writer.AddPage(writer.GetImportedPage(reader, i));
                }
                writer.FreeReader(reader);
                reader.Close();
            }

            writer.Close();
            outputDocument.Close();
            var allPagesContent = ms.GetBuffer();
            ms.Flush();

            return allPagesContent;
        }
    }

回答by JIYAUL MUSTAPHA

****/*For Multiple PDF Print..!!*/****

<button type="button" id="btnPrintMultiplePdf" runat="server" class="btn btn-primary btn-border btn-sm"
                                                                onserverclick="btnPrintMultiplePdf_click">
                                                                <i class="fa fa-file-pdf-o"></i>Print Multiple pdf</button>

protected void btnPrintMultiplePdf_click(object sender, EventArgs e)
    {
        if (ValidateForMultiplePDF() == true)
        {
            #region Declare Temp Variables..!!
            CheckBox chkList = new CheckBox();
            HiddenField HidNo = new HiddenField();

            string Multi_fofile, Multi_listfile;
            Multi_fofile = Multi_listfile = "";
            Multi_fofile = Server.MapPath("PDFRNew");
            #endregion

            for (int i = 0; i < grdRnew.Rows.Count; i++)
            {
                #region Find Grd Controls..!!
                CheckBox Chk_One = (CheckBox)grdRnew.Rows[i].FindControl("chkOne");
                Label lbl_Year = (Label)grdRnew.Rows[i].FindControl("lblYear");
                Label lbl_No = (Label)grdRnew.Rows[i].FindControl("lblCode");
                #endregion

                if (Chk_One.Checked == true)
                {
                    HidNo .Value = llbl_No .Text.Trim()+ lbl_Year .Text;

                    if (File.Exists(Multi_fofile + "\" + HidNo.Value.ToString() + ".pdf"))
                    {
                        #region Get Multiple Files Name And Paths..!!
                        if (Multi_listfile != "")
                        {
                            Multi_listfile = Multi_listfile + ",";
                        }
                        Multi_listfile = Multi_listfile + Multi_fofile + "\" + HidNo.Value.ToString() + ".pdf";

                        #endregion
                    }
                }
            }

            #region For Generate Multiple Pdf..!!
            if (Multi_listfile != "")
            {
                String[] Multifiles = Multi_listfile.Split(',');
                string DestinationFile = Server.MapPath("PDFRNew") + "\Multiple.Pdf";
                MergeFiles(DestinationFile, Multifiles);

                Response.ContentType = "pdf";
                Response.AddHeader("Content-Disposition", "attachment;filename=\"" + DestinationFile + "\"");
                Response.TransmitFile(DestinationFile);
                Response.End();
            }
            else
            {

            }
            #endregion
        }
    }

    private void MergeFiles(string DestinationFile, string[] SourceFiles)
    {
        try
        {
            int f = 0;
            /**we create a reader for a certain Document**/
            PdfReader reader = new PdfReader(SourceFiles[f]);
            /**we retrieve the total number of pages**/
            int n = reader.NumberOfPages;
            /**Console.WriteLine("There are " + n + " pages in the original file.")**/
            /**Step 1: creation of a document-object**/
            Document document = new Document(reader.GetPageSizeWithRotation(1));
            /**Step 2: we create a writer that listens to the Document**/
            PdfWriter writer = PdfWriter.GetInstance(document, new FileStream(DestinationFile, FileMode.Create));
            /**Step 3: we open the Document**/
            document.Open();
            PdfContentByte cb = writer.DirectContent;
            PdfImportedPage page;
            int rotation;
            /**Step 4: We Add Content**/
            while (f < SourceFiles.Length)
            {
                int i = 0;
                while (i < n)
                {
                    i++;
                    document.SetPageSize(reader.GetPageSizeWithRotation(i));
                    document.NewPage();
                    page = writer.GetImportedPage(reader, i);
                    rotation = reader.GetPageRotation(i);
                    if (rotation == 90 || rotation == 270)
                    {
                        cb.AddTemplate(page, 0, -1f, 1f, 0, 0, reader.GetPageSizeWithRotation(i).Height);
                    }
                    else
                    {
                        cb.AddTemplate(page, 1f, 0, 0, 1f, 0, 0);
                    }
                    /**Console.WriteLine("Processed page " + i)**/
                }
                f++;
                if (f < SourceFiles.Length)
                {
                    reader = new PdfReader(SourceFiles[f]);
                    /**we retrieve the total number of pages**/
                    n = reader.NumberOfPages;
                    /**Console.WriteLine("There are"+n+"pages in the original file.")**/
                }
            }
            /**Step 5: we Close the Document**/
            document.Close();
        }
        catch (Exception e)
        {
            string strOb = e.Message;
        }
    }

    private bool ValidateForMultiplePDF()
    {
        bool chkList = false;

        foreach (GridViewRow gvr in grdRnew.Rows)
        {
            CheckBox Chk_One = (CheckBox)gvr.FindControl("ChkSelectOne");
            if (Chk_One.Checked == true)
            {
                chkList = true;
            }
        }
        if (chkList == false)
        {
            divStatusMsg.Style.Add("display", "");
            divStatusMsg.Attributes.Add("class", "alert alert-danger alert-dismissable");
            divStatusMsg.InnerText = "ERROR !!...Please Check At Least On CheckBox.";
            grdRnew.Focus();
            set_timeout();
            return false;
        }
        return true;
    }