如何在 C# 中使用 iText7 从页面顶部开始绘制长 table?

How to get a long table drawed starting from the top of page using iText7 in C#?

PDF Page Example

PDF是由几个添加到文档中的段落组成的,有一个很长的table需要设置从一页的顶部开始(而不是第一页),这意味着一个段落将被拆分分为两部分。

如果table很短(长度不超过页面高度),可以通过处理开始页面的页面事件来优雅地完成,只需添加table到固定位置和大小的canvas,并设置文档的上边距。

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]);
}

但是这里的table太长了,会被分成多页。据我所知,Canvas class 主要针对需要将元素添加到页面/XObject 上的特定预定义区域的情况,而不是将内容溢出到下一个区域。那么我怎样才能实现这种行为呢?

谢谢!

对您要实现的目标的描述非常模糊(不清楚它是围绕 table 的段落,还是段落之间的 table;不清楚 table 是否绑定到段落中的任何文本等),但我的回答应该会引导您走向正确的方向。

我将向您展示如何将适合当前页末尾的段落部分添加到文档中,然后添加跨越多个页面的 table,然后添加剩余部分你的段落。

首先,我们的段落需要一个自定义渲染器,它将只渲染当前适合页面的部分,并记住其余部分以便稍后添加。

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);
    }
}

现在,我们在文档中添加了一些占位符矩形,只是为了占用一些 space 用于测试目的,然后我们使用自定义渲染器添加我们的段落(请注意,预期段落将是尽可能在当前页面上呈现,剩下的部分会被记住),然后我们添加我们的 table 跨越多个页面,最后,我们添加我们的剩余段落部分。

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();

结果如下。请注意,我特意添加了后续数字作为段落内容,以便很明显这是一个连续的段落,被 table:

打断