使用iText7和ASP.NET C#为PDF页脚添加页码及点线时显示异常求助
iText7 实现PDF页脚异常问题求助
基础情况
- 当前可使用 iText7 + C# ASP.NET 正常生成总页数为9页的PDF文件
- 开发目标:为PDF页脚添加两类内容
- 符合
1 of 9、2 of 9... 格式的当前页/总页码标注 - 装饰性点线分隔线
- 符合
遇到的异常问题
- 上述格式的页码仅在PDF的第8、9页正常显示,前7页无对应页码内容
- 点线装饰未在PDF第一页正常渲染
恳请各位开发者提供对应问题的解决方案
问题原因与解决方法
页码仅在最后两页显示的根因
当前代码中,PdfDocumentEvent.END_PAGE 事件的注册时机远晚于页面生成时机:
- 代码先完成了全部内容的添加,过程中生成了前7页,此时页脚事件处理器还未创建、未注册,这7页触发END_PAGE事件时无对应逻辑绘制页脚
- 等全部内容添加完成后,才创建
Footer实例、注册END_PAGE事件,只有后续新生成的第8、9页会触发页脚绘制逻辑,因此仅这两页显示页码
对应修改方案
- 调整事件注册时机:在完成
PdfDocument、Document对象初始化后,立刻实例化Footer并注册END_PAGE事件,确保每一页完成渲染时都能触发页脚绘制
修改后代码片段:// 原有初始化代码 PdfWriter writer = new PdfWriter(filename); PdfDocument pdf = new PdfDocument(writer); Document document = new Document(pdf); // 立刻注册页脚事件,不要等所有内容加载完再注册 Footer footerHandler = new Footer(); pdf.AddEventHandler(PdfDocumentEvent.END_PAGE, footerHandler); - 保留总页数占位逻辑:所有内容添加完成、执行
document.Close()之前,再调用WriteTotal方法把总页数写入之前创建的占位FormXObject,这个逻辑本身是正确的,不需要调整。
第一页点线不显示的根因
当前代码中的点线是作为内容流的一部分添加的,添加逻辑绑定了“遇到Set开头的非首条数据”才会触发:
- 第一页是首条数据的渲染载体,不满足触发条件,因此不会添加点线
- 点线被添加在新页面的最顶部,而非设计要求的页脚位置,位置逻辑错位
对应修改方案
如果点线是页脚的装饰元素,直接在Footer的HandleEvent方法中添加贯穿页边距的点线,替代原来在内容流里加LineSeparator的逻辑,这样所有页面(包括第一页)都会在统一位置显示点线。
修改后的Footer类关键代码片段:
public virtual void HandleEvent(Event @event) { PdfDocumentEvent docEvent = (PdfDocumentEvent)@event; PdfDocument pdf = docEvent.GetDocument(); PdfPage page = docEvent.GetPage(); int pageNumber = pdf.GetPageNumber(page); Rectangle pageSize = page.GetPageSize(); PdfCanvas pdfCanvas = new PdfCanvas(page.NewContentStreamBefore(), page.GetResources(), pdf); // 页脚区域绘制贯穿边距的点线:x方向从36到页面宽度-36,y坐标和页码对齐 float lineY = y + 5; pdfCanvas.SetStrokeColorGray(0.5f) .SetLineDash(1, 2) // 设置点线样式,和原设计保持一致 .MoveTo(36, lineY) .LineTo(pageSize.GetWidth() - 36, lineY) .Stroke(); Canvas canvas = new Canvas(pdfCanvas, pageSize); canvas.SetFontSize(10); Paragraph p = new Paragraph() .Add("Page ") .Add(pageNumber.ToString()) .Add(" of"); canvas.ShowTextAligned(p, x, y, TextAlignment.RIGHT); canvas.Close(); pdfCanvas.AddXObjectAt(placeholder, x + space, y - descent); pdfCanvas.Release(); }
同时删除原来在内容流里加LineSeparator的逻辑,避免点线错位到页面顶部。
原始问题代码
private void mtpdfnew() { DataTable dt = new DataTable(); filename = @"C:\inetpub\wwwroot\public\pdf\" + DateTime.Now.ToString("yyyyMMddHHmmss") + ".pdf"; PdfWriter writer = new PdfWriter(filename); PdfDocument pdf = new PdfDocument(writer); Document document = new Document(pdf); using (MySqlConnection myConnectionString = new MySqlConnection(ConfigurationManager.ConnectionStrings["cn"].ConnectionString)) { using (MySqlCommand cmd = new MySqlCommand("SP", myConnectionString)) { cmd.Connection.Open(); cmd.CommandType = CommandType.StoredProcedure; using (MySqlDataAdapter da = new MySqlDataAdapter(cmd)) { da.Fill(dt); if (dt.Rows.Count > 0) { for (int i = 0; i < dt.Rows.Count; i++) { contents = new Paragraph(dt.Rows[i]["contents"].ToString()) .SetTextAlignment(TextAlignment.JUSTIFIED) .SetFontSize(12); if (dt.Rows[i]["contents"].ToString().StartsWith("Set") && i != 0) { document.Add(new AreaBreak(AreaBreakType.NEXT_PAGE)); document.Add(new LineSeparator(new DottedLine(1, 2)).SetMarginTop(4)); } List<IElement> lst = HtmlConverter.ConvertToElements(dt.Rows[i]["contents"].ToString()).ToList(); for (int j = 0; j < lst.Count; j++) { IBlockElement element = (IBlockElement)lst[j]; if (dt.Rows[i]["contents"].ToString().StartsWith("Set")) { contents.SetFontSize(12) .SetBold() .SetFontColor(ColorConstants.BLUE); } else if (dt.Rows[i]["contents"].ToString().StartsWith("- ")) { contents.SetFontSize(10) .SetBold() .SetFontColor(ColorConstants.BLACK); } else { contents.SetTextAlignment(TextAlignment.JUSTIFIED_ALL) .SetFontSize(10) .SetFontColor(ColorConstants.BLACK); } element.SetProperty(Property.LEADING, new Leading(Leading.MULTIPLIED, -1f)); document.Add(element); } } // 原代码的事件注册时机太靠后,需要移到Document初始化之后 Footer footerHandler = new Footer(); pdf.AddEventHandler(PdfDocumentEvent.END_PAGE, footerHandler); footerHandler.WriteTotal(pdf); dest = filename.ToString(); document.Close(); } Response.Clear(); Response.ContentType = "application/pdf"; Response.AppendHeader("Content-Disposition", "attachment; filename=" + dest); Response.TransmitFile(dest); Response.End(); } } } } private class TableFooterEventHandler : IEventHandler { private Table table; public TableFooterEventHandler(Table table) { this.table = table; } public void HandleEvent(Event currentEvent) { PdfDocumentEvent docEvent = (PdfDocumentEvent)currentEvent; PdfDocument pdfDoc = docEvent.GetDocument(); PdfPage page = docEvent.GetPage(); int pageNumber = pdfDoc.GetPageNumber(page); Rectangle pageSize = page.GetPageSize(); PdfCanvas canvas = new PdfCanvas(page.NewContentStreamBefore(), page.GetResources(), pdfDoc); new Canvas(canvas, new Rectangle(36, 20, page.GetPageSize().GetWidth() - 72, 50)) .Add(table) .Close(); } } protected class Footer : IEventHandler { protected PdfFormXObject placeholder; protected float side = 20; protected float x = 300; protected float y = 25; protected float space = 4.5f; protected float descent = 3; public Footer() { placeholder = new PdfFormXObject(new Rectangle(0, 0, side, side)); } public virtual void HandleEvent(Event @event) { PdfDocumentEvent docEvent = (PdfDocumentEvent)@event; PdfDocument pdf = docEvent.GetDocument(); PdfPage page = docEvent.GetPage(); int pageNumber = pdf.GetPageNumber(page); Rectangle pageSize = page.GetPageSize(); PdfCanvas pdfCanvas = new PdfCanvas(page); Canvas canvas = new Canvas(pdfCanvas, pageSize); canvas.SetFontSize(10); Paragraph p = new Paragraph() .Add("Page ") .Add(pageNumber.ToString()) .Add(" of"); canvas.ShowTextAligned(p, x, y, TextAlignment.RIGHT); canvas.Close(); pdfCanvas.AddXObjectAt(placeholder, x + space, y - descent); pdfCanvas.Release(); } public void WriteTotal(PdfDocument pdfDoc) { Canvas canvas = new Canvas(placeholder, pdfDoc); canvas.SetFontSize(10); canvas.ShowTextAligned(pdfDoc.GetNumberOfPages().ToString(), 0, descent, TextAlignment.LEFT); canvas.Close(); } } private class TableHeaderEventHandler : IEventHandler { private Table table; private float tableHeight; private Document doc; public TableHeaderEventHandler(Document doc) { this.doc = doc; InitTable(); TableRenderer renderer = (TableRenderer)table.CreateRendererSubTree(); renderer.SetParent(new DocumentRenderer(doc)); LayoutResult result = renderer.Layout(new LayoutContext(new LayoutArea(0, PageSize.A4))); tableHeight = result.GetOccupiedArea().GetBBox().GetHeight(); } public void HandleEvent(Event currentEvent) { PdfDocumentEvent docEvent = (PdfDocumentEvent)currentEvent; PdfDocument pdfDoc = docEvent.GetDocument(); PdfPage page = docEvent.GetPage(); int pageNum = docEvent.GetDocument().GetPageNumber(page); PdfCanvas canvas = new PdfCanvas(page.NewContentStreamBefore(), page.GetResources(), pdfDoc); PageSize pageSize = pdfDoc.GetDefaultPageSize(); float coordX = pageSize.GetX() + doc.GetLeftMargin(); float coordY = pageSize.GetTop() - doc.GetTopMargin(); float width = pageSize.GetWidth() - doc.GetRightMargin() - doc.GetLeftMargin(); float height = GetTableHeight(); Rectangle rect = new Rectangle(coordX, coordY, width, height); new Canvas(canvas, rect) .Add(table) .Close(); } public float GetTableHeight() { return tableHeight; } private void InitTable() { } }
内容的提问来源于stack exchange,提问作者Edward Sheriff Curtis
相关产品推荐
相关产品推荐

