使用 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 示例中得到了演示。
在此示例中,我们创建了一个扩展 PdfPageEventHelper
的 TableHeader
类。我们在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 时放置页码的主要内容,如果未能解决你的问题,请参考以下文章
acrofields不使用多页文档打印 - itextsharp
使用 itextsharp 将图像 html 旁边的文本放置到 pdf