在C#中,生成PDF时,如何获取页脚中的页码,格式为“第1页,共n页”或“第1 / n页”

问题描述

在将某些数据发布为PDF的C#代码中,我正在寻找一种在页脚(左,中或右索引)中放置页码方法

格式应如下所示:“第1页,共n页” ,其中 n 表示总页数。

PdfWriter writer = PdfWriter.GetInstance(doc,ms);
writer.CloseStream = false;

doc.open();
//Main pdf publishing code follows 

doc.Close();

解决方法

这看起来像是堆栈溢出时许多问题和答案的重复,但是如今这些问题的大多数答案都变得不是很有帮助,因为它们链接到了无法再找到的示例,例如由于将iText代码库从sourceforge迁移到github或由于itext网站的重新设计。此外,OP在评论中指出他确实知道一种方法,只是不知道如何将其应用于他的案子。

两种主要方法

首先,有两种主要方法可将“ y的第x页”页眉或页脚添加到使用iText创建的文档页面中:

  • (单遍方法)您可以使用页面事件(特别是OnEndPage方法)在此页面结束时以及在下一页开始之前向每个页面添加页眉/页脚/边距材料。
  • (两遍方法)或者您可以在第一遍中创建没有那些页眉或页脚的PDF,然后阅读该PDF并在第二遍中标记页脚/页眉/空白材料。

通常,人们更喜欢用页事件作为页眉和页脚材料,因为这样一来,无需从第一遍临时存储PDF,而是可以将其流式传输到目标,而仍处于创建过程中。

“ y的第x页”页脚/页眉很特殊,因为在写入所有内容之前,尚不知道最终的页数。因此,对于页面事件方法,必须使用一种技巧,并将对画布的引用添加到应显示总页面编号的每个页面。当所有常规内容都添加到文档中后,最后将总页码写入其中。不幸的是,人们不知道该模板到底需要多少空间,因此最终的页眉/页脚中的格式可能看起来有些尴尬。因此,这里最好采用两次通过方法。

Bruno撰写的《 iText in Action-2nd Edition》一书第6章的示例TwoPasses中介绍了如何使用iText 5.x在两遍中将“ y的第x页”标题添加到PDF。洛瓦吉。原始Java示例已由kuujinbo移植到C#。这里是关键代码:

PdfReader reader = new PdfReader(firstPass);
using (MemoryStream ms2 = new MemoryStream()) {
    // Create a stamper
    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++) {
            GetHeaderTable(i,n).WriteSelectedRows(0,-1,34,803,stamper.GetOverContent(i));
        }
    }
    // write content of ms2 somewhere,e.g. as ms2.ToArray()
}

public static PdfPTable GetHeaderTable(int x,int y) {
    PdfPTable table = new PdfPTable(2);
    table.TotalWidth = 527;
    table.LockedWidth = true;
    table.DefaultCell.FixedHeight = 20;
    table.DefaultCell.Border = Rectangle.BOTTOM_BORDER;
    table.AddCell("FOOBAR FILMFESTIVAL");
    table.DefaultCell.HorizontalAlignment = Element.ALIGN_RIGHT;
    table.AddCell(string.Format("Page {0} of {1}",x,y));
    return table;
}    

(在github /在kuujinbo.info上)

您的案件的申请

OP在评论中写道

我一直难以理解两步法,从哪里开始,如何在我的情况下应用

好的,您将自己的情况描述为:

iTextSharp.text.Document doc = new iTextSharp.text.Document(PageSize.A4.Rotate(),50f,50f);
{
    try
    {
        //Main pdf publishing code follows 
    }
    catch (Exception ex)
    {
        MessageBox.Show(ex.Message,"Error! try again.",MessageBoxButtons.OK,MessageBoxIcon.Error);
    }
    finally
    {
        doc.Close();
    }
}

首先,我建议您将其更改为:

try
{
    using (iTextSharp.text.Document doc = new iTextSharp.text.Document(PageSize.A4.Rotate(),50f))
    {
        //Main pdf publishing code follows
    }
}
catch (Exception ex)
{
    MessageBox.Show(ex.Message,MessageBoxIcon.Error);
}

因为您的原始方法会错过在关闭文档对象期间引发的异常! using (Document doc = ...) {...}结构取代了Document doc = ...; try {...} finally {doc.Close();}结构。

现在您的//Main pdf publishing code follows特别包含一个PdfWriter实例化,例如

PdfWriter writer = PdfWriter.GetInstance(doc,SOME_STREAM);

对于两次通过方法,您必须改为将PdfWriter定位到临时流。然后,对其内容应用上面引用的两次通过代码。只有这样的结果才能最终进入您的SOME_STREAM

一起:

try
{
    using (MemoryStream ms = new MemoryStream())
    {
        float leftRightMargin = 50f;
        using (iTextSharp.text.Document doc = new iTextSharp.text.Document(PageSize.A4.Rotate(),leftRightMargin,50f))
        {
            PdfWriter writer = PdfWriter.GetInstance(doc,ms);
            //Main pdf publishing code (except PdfWriter instantiation) follows
        }

        using (PdfReader reader = new PdfReader(ms.ToArray()))
        using (PdfStamper stamper = new PdfStamper(reader,SOME_STREAM))
        {
            int n = reader.NumberOfPages;
            for (int i = 1; i <= n; i++)
            {
                Rectangle cropBox = reader.GetCropBox(i);
                for (int rotation = reader.GetPageRotation(i); rotation > 0; rotation -= 90)
                    cropBox = cropBox.Rotate();
                GetHeaderTable(i,n,cropBox.Width - 2 * leftRightMargin).WriteSelectedRows(0,cropBox.GetTop(10),stamper.GetOverContent(i));
            }
        }
    }
}
catch (Exception ex)
{
    MessageBox.Show(ex.Message,MessageBoxIcon.Error);
}

public static PdfPTable GetHeaderTable(int x,int y,float width)
{
    PdfPTable table = new PdfPTable(2);
    table.TotalWidth = width;
    table.LockedWidth = true;
    table.DefaultCell.FixedHeight = 20;
    table.DefaultCell.Border = Rectangle.BOTTOM_BORDER;
    table.AddCell("Header test");
    table.DefaultCell.HorizontalAlignment = Element.ALIGN_RIGHT;
    table.AddCell(string.Format("Page {0} of {1}",y));
    return table;
}