【问题标题】:How to merge multiple pdf files (generated in run time)?如何合并多个pdf文件(在运行时生成)?
【发布时间】:2013-04-02 06:44:09
【问题描述】:

如何通过ItextSharp合并多个pdf文件(在运行时生成)然后打印出来。

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


我有多个报告,我将通过此方法将它们转换为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();
}

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

【问题讨论】:

  • 我认为问题类似于:stackoverflow.com/questions/3961804/…
  • 您找到的样本和其他评论者指向您的样本,使用PdfReader 阅读源文档。 PdfReader 有多个构造函数,一些以文件名字符串作为参数,一些字节数组包含 PDF;在你的情况下使用后者。但是,从找到的合并样本中,请不要使用PdfWriter 选择一种,而是使用PdfCopy, PdfSmartCopy, PdfCopyFields,PdfCopyForms 选择一种(选择取决于您的具体要求)。
  • @mkl:你能提供一个样本来解决这个问题吗?
  • 为什么你不推荐PdfWriter ??例如,当我使用PdfSmartCopy 时,我得到以下异常document has no pages !!
  • @just_name 当您使用PdfWriter 合并源 PDF 时,交互功能(表单和其他注释)会丢失。此外,生成的 PDF 在内部包含一个不必要的页面信息包装器,当多次迭代时,可能会导致 PDF 查看器在尝试显示 PDF 时失败。

标签: c# asp.net pdf itextsharp rdlc


【解决方案1】:
****/*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;
    }

【讨论】:

  • 如果您能解释一下这是如何回答问题的,将会更有帮助。
  • 请不要使用这种合并例程,除非您有非常具体的要求迫使您这样做。当您使用PdfWriter 合并源 PDF 时,交互功能(表单和其他注释)会丢失。此外,生成的 PDF 在内部包含一个不必要的页面信息包装器,当多次迭代时,可能会导致 PDF 查看器在尝试显示 PDF 时失败。
【解决方案2】:

iTextSharp-LGPL 4.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;
        }
    }

【讨论】:

    【解决方案3】:

    为了避免上面提到的内存问题,我使用文件流而不是内存流(在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));
                                }
                            }
                        }
                    }
                }
            }
    

    【讨论】:

      【解决方案4】:

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

      【讨论】:

        【解决方案5】:

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

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

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

        您可以在iText in Action — 2nd Editionchapter 6(尤其是第 6.4 节)中找到详细信息。 Java 示例代码可以访问here 和 C#'ified 版本here

        使用PdfCopy 的简单示例是Concatenate.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();
        }
        

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

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

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

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

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

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

        【讨论】:

        • 看到有人对这个答案投了反对票而没有留下评论来解释缺陷真的很有趣......话虽如此,iText 也在同时发展,很多 PdfCopyFields 特定的东西已经进入PdfCopy.
        • @BonusKun 合并真的很慢 - 如果速度特别慢,您可能需要自行创建一个问题,提供示例文档来重现问题... (顺便说一句,我投了赞成票。) - 谢谢!
        • 如果要将文件保存到磁盘,在“mergedPdf = ms.ToArray();”行之后,使用:System.IO.File.WriteAllBytes(@"C:\MyFileName.pdf" , 合并PDF);
        • 如果你想作为下载流怎么办? return File(ms, "application/pdf", "file.pdf") 不适合我
        • @MikeTeeVee 你错过了document.Close() - 不,using (Document document = new Document()) 隐式关闭文档。但是,如果您需要在using 的右括号之前获取内存流内容,则确实需要显式关闭。
        【解决方案6】:

        这是我从一个旧项目中提取的一些代码。这是一个网络应用程序,但我使用 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;
                }
            }
        

        这不是我写的,而是做了一些修改。我不记得我在哪里找到的。合并 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;
        }
        

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

        【讨论】:

        • 请不要使用这种合并例程,除非您有非常具体的要求迫使您这样做。当您使用PdfWriter 合并源 PDF 时,交互功能(表单和其他注释)会丢失。此外,生成的 PDF 在内部包含一个不必要的页面信息包装器,当多次迭代时,可能会导致 PDF 查看器在尝试显示 PDF 时失败。
        • 正如我所说,我是从生产中的旧代码中提取的,但 PDF 是从所见即所得编辑器构建的 html 生成的,因此我们没有交互功能。此外,我们的迭代通常一次只有 10 次左右,而且我们从来没有遇到过 pdf 无法打开的问题。我将其发布为示例,因为我们已将其在生产中运行,并且我知道它正在合并没有报告问题的 pdf。
        • 我无意冒犯;像你这样基于PdfWriter 的合并解决方案确实比在谷歌搜索时使用更适合的类的解决方案更常见,而且它们确实按照一种方式工作,所以它们并不是完全错误的。不过,基于Pdf*Copy* 的解决方案通常更易于使用(无需一次又一次地调整目标文档页面大小和旋转)、更完整(关于交互功能),并且产生更清晰的输出(相对于内部 PDF 结构)。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-04-03
        • 2017-08-30
        • 1970-01-01
        • 2013-01-22
        相关资源
        最近更新 更多