使用 iTextSharp 创建 PDF 时放置页码

Posted

技术标签:

【中文标题】使用 iTextSharp 创建 PDF 时放置页码【英文标题】:put page number when create PDF with iTextSharp 【发布时间】:2014-05-13 11:46:37 【问题描述】:

我正在使用 ASP MVC,我使用 iTextSharp 在我的应用程序中生成 PDF。但是现在我有一个问题:我打印列表并且当存在多页时,我想显示页码(例如:Page 1 to 4)。我找到了一些例子,但我认为它比我需要做的更复杂(比如exameple)。

编辑: 我找到了这个example 2。我可以计算页数,但我无法打印页数。

我做了什么:

public ActionResult downloadListaISCC(DateTime? DataFimFiltro)


//Code to generate list to PDF

   //My document
   Document doc1 = new Document();
   doc1.SetPageSize(iTextSharp.text.PageSize.A4);
   doc1.SetMargins(0f, 0f, 0f, 0f);
   doc1.NewPage();

   MemoryStream pdfStream = new MemoryStream();
   PdfWriter pdfWriter = PdfWriter.GetInstance(doc1, pdfStream);

   //Code to create table
   doc1.Add(table); //table list in document

   //Follow the example 2 (link)
   pdfWriter.CloseStream = true;
   doc1.Close();


   //E fui seguindo o exemplo do segundo link
   string file = "D:/gerarPDFOleotorres/"+ nomeDoc +""; 

   // add page numbers
   Document copyDoc = new Document();
   PdfCopy copyPdf = new PdfCopy(copyDoc, new FileStream(file, FileMode.Create));
   copyPdf.SetPageSize(PageSize.A4.Rotate());
   copyDoc.Open();

   // read the initial pdf document
   PdfReader reader = new PdfReader(pdfStream.ToArray());
   int totalPages = reader.NumberOfPages;

   PdfImportedPage copiedPage = null;
   iTextSharp.text.pdf.PdfCopy.PageStamp stamper = null;

   for (int i = 0; i < totalPages; i++)
   

       // get the page and create a stamper for that page
       copiedPage = copyPdf.GetImportedPage(reader, (i + 1));
       stamper = copyPdf.CreatePageStamp(copiedPage);

       // add a page number to the page
       ColumnText.ShowTextAligned(stamper.GetUnderContent(), Element.ALIGN_CENTER, new Phrase((i + 1) + "/" + totalPages, fontetexto), 820f, 15, 0);
        stamper.AlterContents();

       // add the altered page to the new document
       copyPdf.AddPage(copiedPage);
   

   copyDoc.Close();
   reader.Close();

   // flush and clear the document from memory
   pdfStream.Flush();
   pdfStream.Close();
    

【问题讨论】:

我现在看到您使用值 0 定义边距。这根本没有为您的页眉或页脚留下空间。这是你的意图吗? 【参考方案1】:

基本上,您有两种选择:一次创建文档,或者分两次创建文档。

如果一次性创建文档,事先并不知道Y(总页数)的值,所以需要创建一个PdfTemplate对象作为占位符。这在MovieCountries1 示例中得到了演示。

在此示例中,我们创建了一个扩展 PdfPageEventHelperTableHeader 类。我们在OnOpenDocument() 方法中为total 创建PdfTemplate 类的实例,我们在OnEndPage() 方法中使用这个total 占位符,在其中添加页眉或页脚,并填写总数OnCloseDocument() 方法中的页面数。

这种方法的缺点是很难预测total 所需的尺寸。优点是可以一次性创建文档(不需要先在内存中创建文档)。

如果您分两次创建文档,您首先创建没有页眉/页脚的文档,然后检查该文档以找出它包含多少页。然后使用PdfStamper 将页码添加到每一页。这显示在 TwoPasses 示例中。

这些示例取自我的书“iText in Action - Second Edition”。您可以从以下网址免费下载第 6 章:http://manning.com/lowagie2/samplechapter6.pdf

当您对特定功能有疑问时,请查阅 [官方文档][4]。

更新:我不明白你为什么喜欢看非官方的例子。我给你的例子是这样的:

using (PdfStamper stamper = new PdfStamper(reader, ms2)) 
    // Loop over the pages and add a header to each page
    int n = reader.NumberOfPages;
    for (int i = 1; i <= n; i++) 
        // Add content
    

但由于某种原因,您在 Google 上搜索了一个更复杂的示例(并且对于您需要的东西来说太过分了)。

只需将// Add content 部分替换为:

ColumnText.ShowTextAligned(stamper.GetUnderContent(), Element.ALIGN_CENTER, new Phrase((i + 1) + "/" + totalPages, fontetexto), 297f, 15f, 0);

请注意,我在 ShowTextAligned() 方法中调整了 x 值。您正在创建一个大小为 A4 的页面,这意味着您的页面宽度为 595 个用户单位。如果您在位置 x = 820 添加页码,将添加页脚,但它会在页面的可见区域之外。请不要在不知道每个方法的参数的情况下复制/粘贴代码。

【讨论】:

我尝试分两次创建文档。我会更新我的问题 它可能会按照您的方式工作,但您显然没有遵循我提到的 TwoPasses 示例。你为什么使用PdfCopy 而不是PdfStamper?我不明白你的选择。没有遵循我提供的建议是否有具体原因? 我找到了解决方案。我有float x 来定义位置编号错误。感谢您的帮助 @BrunoLowagie,哪一个是最好的方法? PdfPageEventHelper 或 PdfStamper。 @SteveGreene 这取决于您参考哪本书。 iText in Action 书籍(第 1 版:2007;第 2 版 2010)已过时。在 2012-2018 年期间,我写了几本在 Leanpub 上发布的免费电子书,但请注意,我在 2018 年离开了 iText Group,并且新所有者可能发布了更新得多的材料。正如我在最近的一本书 (entreprenerd.lowagie.com) 中所解释的,我今天不再隶属于 iText。【参考方案2】:

为了记录——我是这样用的

byte[] bytes = memoryStream.ToArray();

                //Save pdf in the temporary location.
System.IO.File.WriteAllBytes(Server.MapPath("~/TempReports/") + lbReports.Text + "_JEA.pdf", bytes);

/*This is a page counter - it stamps the number of pages in the document. 
 It will read dynamically the 'document' that was just closed above [document.Close();] from the location, 
 then in memory will write the new content plus the one from [byte[] bytes = memoryStream.ToArray();] 
 Solution has been applied from: https://www.aspsnippets.com/Articles/iTextSharp-Add-Page-numbers-to-existing-PDF-using-C-and-VBNet.aspx
 */
try

    File.ReadAllBytes(Server.MapPath("~/TempReports/") + lbReports.Text + "_JEA.pdf");
    iTextSharp.text.Font blackFont = FontFactory.GetFont("Arial", 7, iTextSharp.text.Font.BOLD, BaseColor.BLACK);
    using (MemoryStream stream = new MemoryStream())
    
        PdfReader reader = new PdfReader(bytes);
        using (PdfStamper stamper = new PdfStamper(reader, stream))
        
            int pages = reader.NumberOfPages;
            for (int i = 1; i <= pages; i++)
            
                ColumnText.ShowTextAligned(stamper.GetUnderContent(i),
                 @Element.ALIGN_LEFT, new Phrase(lbReports.Text + " - HD - JEA", blackFont), 63f, 24f, 0);

                ColumnText.ShowTextAligned(stamper.GetUnderContent(i),
                @Element.ALIGN_CENTER, new Phrase("Page " + i.ToString() + " of " + pages, blackFont), 300f, 24f, 0);

                ColumnText.ShowTextAligned(stamper.GetUnderContent(i),
                @Element.ALIGN_RIGHT, new Phrase("" + DateTime.Now, blackFont), 549f, 24f, 0);
            

            txConnection.Text = "This report contains " + pages + " page(s)";
        

        bytes = stream.ToArray();

    //End of page counter

    /*System.IO.File.WriteAllBytes will write all bytes to file again*/

    System.IO.File.WriteAllBytes(Server.MapPath("~/TempReports/") + lbReports.Text + "_JEA.pdf", bytes);

    // Temporary path that is used to display the pdf in the embed.
    System.IO.File.WriteAllBytes(Server.MapPath("~/TempReports/ReportsEmbed/") + lbReports.Text + "_JEA.pdf", bytes);

    /*this is what sends the PDF to the embed viewer object
     The ltEmbed is what receives the plugin to dispplay the file*/

    string embed = "<object data=\"0\" type=\"application/pdf\" width=\"698px\" height=\"450px\">";
    embed += "If you are unable to view file, you can download it from <a href = \"0\">here</a>";
    embed += " or download <a target = \"_blank\" href = \"http://get.adobe.com/reader/\">Adobe PDF Reader</a> to view it.";
    embed += "</object>";

    ltEmbed.Text = string.Format(embed, ("http://localhost:65423/TempReports/ReportsEmbed/") + lbReports.Text + "_JEA.pdf");
    memoryStream.Close();

    this.Context.ApplicationInstance.CompleteRequest();

catch (DocumentException exe)

    txConnection.Text = "There has been an error generating the file. Please try again. Error: " + exe;

【讨论】:

以上是关于使用 iTextSharp 创建 PDF 时放置页码的主要内容,如果未能解决你的问题,请参考以下文章

iTextSharp 创建带有空白页的 PDF

acrofields不使用多页文档打印 - itextsharp

使用 itextsharp 将图像 html 旁边的文本放置到 pdf

iTextSharp 创建页脚页 # of #

iTextSharp System.OutOfMemoryException

使用itextsharp将单独签名的哈希放置到PDF中的多个位置