这感觉就像堆栈溢出的许多问题和答案的重复,但这些问题的大多数答案现在都不是很有帮助,因为它们链接到无法再找到的示例,例如因为iText 代码库从 sourceforge 迁移到 github 或由于 itext 网站的重新设计。此外,OP 在评论中表示他确实知道一种方法,只是不知道如何将其应用于他的案例。
两种主要方法
首先,有两种主要方法可以将“Page x of y”页眉或页脚添加到您使用 iText 创建的文档的页面中:
- (一次性方法)您可以使用页面事件(特别是
OnEndPage 方法)在此页面完成时和下一页开始之前将页眉/页脚/边距材料添加到每个页面。李>
- (两遍方法)或者您可以在第一遍中创建没有这些页眉或页脚的 PDF,然后阅读该 PDF 并在第二遍中标记页脚/页眉/matgin 材料。
通常人们更喜欢页眉和页脚材料的页面事件,因为这样就不需要从第一遍临时存储 PDF,而是可以在创建过程中将其流式传输到目标。
“Page x of y”页脚/页眉是特殊的,因为在所有内容都写完之前,人们不知道最终的页数。因此,对于页面事件方法,必须使用一种技巧并将对画布的引用添加到应出现总页码的每个页面。当所有常规内容都添加到文档中时,最后将总页码写入其中。不幸的是,人们不知道该模板究竟需要多少空间,因此生成的页眉/页脚中的格式最终可能看起来有点尴尬。因此,这里可能首选两次通过的方法。
如何使用 iText 5.x 在两次传递中向 PDF 添加“Page x of y”标题在 Bruno Lowagie 撰写的“iText in Action - 2nd Edition”一书的第 6 章中的示例 TwoPasses 中进行了描述。 kuujinbo 已将原始 Java 示例移植到 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, 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, 50f, 50f, 50f))
{
//Main pdf publishing code follows
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "Error! try again.", MessageBoxButtons.OK, 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, leftRightMargin, 50f, 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, -1, leftRightMargin, cropBox.GetTop(10), stamper.GetOverContent(i));
}
}
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "Error! try again.", MessageBoxButtons.OK, 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}", x, y));
return table;
}