为每个 pdf 页面添加页码和作为页脚对齐的文本

Posted

技术标签:

【中文标题】为每个 pdf 页面添加页码和作为页脚对齐的文本【英文标题】:Add a page number and text aligned as footer to every pdf page 【发布时间】:2020-06-17 08:29:45 【问题描述】:

我添加了一个示例项目来重现该问题到 GitHub 存储库,我希望这会有所帮助: Click to go to the Github repo

我需要在 PDF 中添加文本和页数,此 PDF 来自发票。

我已经尝试过使用事件(但是这些示例是针对 java 的,并且不完整,或者我认为它们是),但它不起作用,我遇到了同样的错误,因此无法对齐文本。

正如我所说,我正在尝试使用表格和画布来实现这一点,如果 PDF 只有一页,则代码可以正常工作。

但是超过一页我得到这个错误:

This exception was originally thrown at this call stack:  KernelExtensions.Get<TKey,

TValue>(System.Collections.Generic.IDictionary, TKey) iText.Kernel.Pdf.PdfDictionary.Get(iText.Kernel.Pdf.PdfName, bool) iText.Kernel.Pdf.PdfDictionary.GetAsNumber(iText.Kernel.Pdf.PdfName) iText.Kernel.Pdf.PdfPage.GetRotation() iText.Kernel.Pdf.Canvas.PdfCanvas.PdfCanvas(iText.Kernel.Pdf.PdfPage) BoarGiveMeMoar.Invoices.InvoiceToPdf.AddFooter(iText.Layout.Document) InvoiceToPdf.cs InvoiceToPdf.cs 中的 BoarGiveMeMoar.Invoices.InvoiceToPdf.FillPdf.AnonymousMethod__4() Task.cs 中的 System.Threading.Tasks.Task.InnerInvoke() Task.cs 中的 System.Threading.Tasks.Task..cctor.AnonymousMethod__274_0(object) System.Threading.ExecutionContext.RunFromThreadPoolDispatchLoop(System.Threading.Thread, System.Threading.ExecutionContext,System.Threading.ContextCallback, 对象)在 ExecutionContext.cs ... [调用堆栈被截断]

这是我的代码,但我从上面得到错误:

private readonly int smallFontSize = 6;
private readonly int stdFontSize = 7;

public void FillPdf(string filename)

    using var pdfWriter = new PdfWriter(filename);
    using var pdfDoc = new PdfDocument(pdfWriter);
    using var doc = new Document(pdfDoc, PageSize.LETTER);

    doc.SetMargins(12, 12, 36, 12);

    AddData(doc);
    AddFooter(doc);

    doc.Close();


private void AddData(Document doc)

    Table table = new Table(UnitValue.CreatePercentArray(5)).UseAllAvailableWidth();
    PdfFont bold = PdfFontFactory.CreateFont(StandardFonts.HELVETICA_BOLD);


    for (int i = 0; i < 250; i++)
    
        var cell = new Cell(1, 5)
            .Add(new Paragraph($"My Favorite animals are boars and hippos")
            .SetFontSize(stdFontSize).SetFont(bold));

        cell.SetBorder(Border.NO_BORDER);
        cell.SetPadding(0);
        table.AddCell(cell);
    

    doc.Add(table);


private void AddFooter(Document doc)

    if (doc is null)
        return;

    Table table = new Table(UnitValue.CreatePercentArray(60)).UseAllAvailableWidth();

    int numberOfPages = doc.GetPdfDocument().GetNumberOfPages();
    for (int i = 1; i <= numberOfPages; i++)
    
        PdfPage page = doc.GetPdfDocument().GetPage(i);
        PdfCanvas pdfCanvas = new PdfCanvas(page);
        Rectangle rectangle = new Rectangle(
            0,
            0,
            page.GetPageSize().GetWidth(),
            15);

        Canvas canvas = new Canvas(pdfCanvas, doc.GetPdfDocument(), rectangle);

        var cell = new Cell(1, 20).SetFontSize(smallFontSize);
        cell.SetBorder(Border.NO_BORDER);
        cell.SetPadding(0);                
        table.AddCell(cell);

        cell = new Cell(1, 20).Add(new Paragraph("This document is an invoice")
            .SetTextAlignment(TextAlignment.CENTER)).SetFontSize(smallFontSize);
        cell.SetBorder(Border.NO_BORDER);
        cell.SetPadding(0);                
        table.AddCell(cell);

        cell = new Cell(1, 10).SetFontSize(smallFontSize);
        cell.SetBorder(Border.NO_BORDER);
        cell.SetPadding(0);                
        table.AddCell(cell);

        cell = new Cell(1, 7)
            .Add(new Paragraph($"Page string.Format(CultureInfo.InvariantCulture, "0:#,0", i) of string.Format(CultureInfo.InvariantCulture, "0:#,0", numberOfPages)   ")
            .SetTextAlignment(TextAlignment.RIGHT)).SetFontSize(smallFontSize);
        cell.SetBorder(Border.NO_BORDER);
        cell.SetPadding(0);                
        table.AddCell(cell);

        cell = new Cell(1, 3).SetFontSize(smallFontSize);
        cell.SetBorder(Border.NO_BORDER);
        cell.SetPadding(0);                
        table.AddCell(cell);

        canvas.Add(table).SetFontSize(smallFontSize);
        canvas.Close();
    


代码调用示例:

new InvoiceToPdf()
            .FillPdf(@$"Environment.GetFolderPath(Environment.SpecialFolder.Desktop)\*** Invoice Test.pdf");

我在创建新 PdfCanvas 的这一行中遇到错误

PdfCanvas pdfCanvas = new PdfCanvas(page);

那么,你们中的任何人都有解决方案吗?

【问题讨论】:

您好,请附上人们可以运行并重现您的问题的代码示例。现在这是不可能的,因为尚不清楚FillPdf 做了什么以及如何做。 嗨@AlexeySubach,我添加了一个写一些虚拟文本的方法,这应该足以填满至少2页,这样,错误就出来了 你的代码应该如何运行?您添加了三个方法,但没有入口点。我像这样运行您的代码:PdfDocument pdfDocument = new PdfDocument(new PdfWriter(outFileName)); Document document = new Document(pdfDocument); AddData(document);,一切都按预期工作。我删除了异步/等待代码。您能否尝试以同步方式运行代码并检查问题是否仍然存在并附加完整的端到端代码以重现问题? 对不起,我的错,我写的最后一条评论似乎是在添加数据时引发错误,但不是,在添加页脚时抛出。 【参考方案1】:

默认情况下,为了减少内存消耗,您正在创建的 PDF 文档的页面在填满时会被刷新。

这意味着当内容被写入时,例如在文档的第 3 页上,第 1 页的内容已经写入磁盘,现在添加更多内容为时已晚。

一个选项是首先创建一个文档并关闭它,然后用读写器打开它,即:new PdfDocument(PdfReader, PdfWriter),再次在PdfDocument周围创建Document,并将内容附加到像现在这样记录:

public void FillPdf(string filename)

    
        using var pdfWriter = new PdfWriter(tempFilename);
        using var pdfDoc = new PdfDocument(pdfWriter);
        using var doc = new Document(pdfDoc, PageSize.LETTER);

        doc.SetMargins(12, 12, 36, 12);

        AddData(doc);
        doc.Close();
    

    
        using var pdfWriter = new PdfWriter(filename);
        using var pdfReader = new PdfReader(tempFilename);
        using var pdfDoc = new PdfDocument(pdfReader, pdfWriter);
        using var doc = new Document(pdfDoc, PageSize.LETTER);

        doc.SetMargins(12, 12, 36, 12);

        AddFooter(doc);
        doc.Close();
    

第二种选择是不要尽快刷新内容,而是将其保存在内存中。您只需对代码稍作修改即可做到这一点:将第三个参数传递给 Document 构造函数

using var doc = new Document(pdfDoc, PageSize.LETTER, false);

请记住,在某些极端情况下,第二个选项可能会导致在文档末尾创建额外的空白页面(例如,当您将如此大的图像添加到文档中时,它甚至无法放入完整的文档中)页),因此请谨慎使用。不过,它不应该对您处理常规的简单内容造成任何问题

【讨论】:

以上是关于为每个 pdf 页面添加页码和作为页脚对齐的文本的主要内容,如果未能解决你的问题,请参考以下文章

WPS2012 正文部分怎么页码总数怎么才能不算上封面和目录的

使用 CSS 在 PDF 的每一页中添加页脚文本

怎么在WORD页眉中添加页码为page1ofn?

如何使用 iTextSharp 为横向生成的页面添加页脚到 PDF 文档

java itextpdf怎么设置pdf页眉页脚

如何在Excel中添加页眉页脚?