c# - 如何在 C# 中使用 iText7 从页面顶部开始绘制长表?
问题描述
PDF由添加到文档中的多个段落组成,并且有一个长表需要从一页(不是第一页)的顶部开始设置,这意味着一个段落将被分成两部分。
如果表格很短(长度不超过页面高度),可以通过处理起始页的 Page Event来优雅地完成,只需将表格以固定的位置和大小添加到画布上,并设置文档的上边距。
PdfDocumentEvent docEvent = (PdfDocumentEvent)currentEvent;
PdfDocument pdfDoc = docEvent.GetDocument();
PdfPage page = docEvent.GetPage();
var currentPageNumber = pdfDoc.GetPageNumber(page);
var addingTablesOfPage = addingTables.Where(t => t.PageNumber == currentPageNumber && t.Prepared).ToList();
if (addingTablesOfPage != null && addingTablesOfPage.Count > 0)
{
PdfCanvas canvas = new PdfCanvas(page.NewContentStreamBefore(), page.GetResources(), pdfDoc);
PageSize pageSize = pdfDoc.GetDefaultPageSize();
var pageHeight = pageSize.GetHeight() - Constants.DocumentMargins[0] - Constants.DocumentMargins[2];
var pageWidth = pageSize.GetWidth() - Constants.DocumentMargins[1] - Constants.DocumentMargins[3];
var totalHeight = 0f;
var alignRight = false;
// add tables to the top of page
foreach (var table in addingTablesOfPage.OrderBy(t => t.Type).ToList())
{
var tableWidth = 0f;
float coordX = 0;
tableWidth = pageWidth;
coordX = pageSize.GetX() + doc.GetLeftMargin();
totalHeight += table.TableHeight;
float coordY = pageSize.GetTop() - Constants.DocumentMargins[0] - totalHeight;
Rectangle rect = new Rectangle(coordX, coordY, tableWidth, table.TableHeight);
var tableCanvas = new Canvas(canvas, rect);
tableCanvas.Add(table.Table);
tableCanvas.Close();
}
float topMargin = Constants.DocumentMargins[0] + totalHeight;
doc.SetTopMargin(topMargin);
}
else
{
doc.SetTopMargin(Constants.DocumentMargins[0]);
}
但是这里的表格太长了,会被分成多页。据我所知,Canvas 类主要针对需要将元素添加到页面/XObject 上的特定预定义区域的情况,而不是将您的内容溢出到下一个区域的情况。那么我怎样才能实现这种行为呢?
谢谢!
解决方案
您要实现的目标的描述非常模糊(不清楚它是围绕表格的段落,还是段落之间的表格;不清楚表格是否绑定到段落中的任何文本等),但是我的回答应该会引导你走向正确的方向。
我将向您展示如何将适合到当前页面末尾的段落部分添加到文档中,然后添加跨越多个页面的表格,然后添加段落的剩余部分。
首先,我们需要为我们的段落提供一个自定义渲染器,它只会渲染当前适合页面的部分,并且会记住稍后添加的其余部分。
private static class CustomParagraphRenderer extends ParagraphRenderer {
public CustomParagraphRenderer leftover;
private CustomParagraphRenderer toDraw;
public CustomParagraphRenderer(Paragraph modelElement) {
super(modelElement);
}
@Override
public LayoutResult layout(LayoutContext layoutContext) {
LayoutResult result = super.layout(layoutContext);
if (result.getStatus() == LayoutResult.PARTIAL) {
// Expected result here is that paragraph splits across pages
leftover = (CustomParagraphRenderer) result.getOverflowRenderer();
toDraw = (CustomParagraphRenderer) result.getSplitRenderer();
return new LayoutResult(LayoutResult.FULL, result.getSplitRenderer().getOccupiedArea(), null, null);
}
return result;
}
@Override
public void draw(DrawContext drawContext) {
if (toDraw != null) {
toDraw.draw(drawContext);
} else {
super.draw(drawContext);
}
}
@Override
public IRenderer getNextRenderer() {
return new CustomParagraphRenderer((Paragraph) modelElement);
}
}
现在,我们在文档中添加一些占位符矩形只是为了占用一些空间用于测试目的,然后我们使用自定义渲染器添加我们的段落(请注意,期望是该段落将尽可能多地呈现在当前页面上,并且剩余部分将被记住),然后我们添加跨越多个页面的表格,最后,我们添加剩余段落部分。
PdfDocument pdfDocument = new PdfDocument(new PdfWriter(outFileName));
Document document = new Document(pdfDocument);
document.setFontSize(20);
Div emptyArea = new Div().setHeight(400).setBackgroundColor(ColorConstants.RED);
document.add(emptyArea);
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 500; i++) {
sb.append(i).append(" ");
}
Paragraph p = new Paragraph(sb.toString());
p.setNextRenderer(new CustomParagraphRenderer(p).setParent(document.getRenderer()));
CustomParagraphRenderer paragraphRenderer = (CustomParagraphRenderer) p.createRendererSubTree();
// Add first part of the paragraph
document.getRenderer().addChild(paragraphRenderer);
Table table = new Table(3);
for (int i = 0; i < 25; i++) {
for (int j = 0; j < 3; j++) {
table.addCell(new Cell().add(new Paragraph("Cell (" + i + ", " + j + ")")));
}
}
// Add big table
document.add(table);
// Add leftover paragraph part
document.getRenderer().addChild(paragraphRenderer.leftover.setParent(document.getRenderer()));
document.close();
结果如下所示。请注意,我特意添加了后续数字作为段落内容,以便清楚地表明这是一个被表格打断的连续段落:
推荐阅读
- python - 使用 Python subprocess.Popen 和 pty 在哑终端中运行交互式 Bash
- c++ - 通过 shared_ptr 访问子类的字段
- javascript - 我试图给我的下拉背景颜色,但它没有实现
- ios - 从另一个目标访问一个目标 Plist
- r - 无法(重新)安装 rJava (macOS)
- c - 在 C 中打印链接列表时出现段错误
- java - 即使经过验证,也无法在运行时找到 Xpath
- sql - pgp_sym_decrypt 与选择查询一起使用
- c# - 获取 Azure 的访问令牌
- go - 在 Go 中使用 cron 定期运行 Colly web scraper