如何将圆角边框应用于 table(单页/多页)?

How to apply round corner border to table (single page / multipage)?

我想将圆角边框应用于 table。这个 table 是动态的。这意味着它可以增长到多个页面,也可以容纳在一个页面中。

如果table出现在单页中,则所有四个角单元格的最外角应绘制为圆角。 如果 table 增长到多页(比如 3 页),则所有 3 页的所有四个角单元格的最外角都应绘制为圆形。

这是我用来实现上述场景的方法。

public void createPdf(String dest) throws FileNotFoundException {
        
        PdfWriter writer = new PdfWriter(DEST);
        PdfDocument pdfDoc = new PdfDocument(writer);
        Document document = new Document(pdfDoc, PageSize.A4, false);
        
        Table table = new Table(3);
        for (int i=0; i < 100; i++) {
            for (int j=0; j < 3; j++) {
                table.addCell(new Cell().add(new Paragraph("Cell content")));
            }
        }
        table.setNextRenderer(new TableBorderRenderer(table));
        document.add(table);
        document.close();
        
}

TableBorderRenderer.java

public class TableBorderRenderer extends TableRenderer {
    public TableBorderRenderer(Table modelElement) {
        super(modelElement);
    }

    @Override
    public IRenderer getNextRenderer() {
        return new TableBorderRenderer((Table) modelElement);
    }
    
    @Override
    protected void drawBorders(DrawContext drawContext) {
        Rectangle rect = getOccupiedAreaBBox();
        PdfPage currentPage = drawContext.getDocument().getPage(getOccupiedArea().getPageNumber());
        PdfCanvas aboveCanvas = new PdfCanvas(currentPage.newContentStreamAfter(), currentPage.getResources(), drawContext.getDocument());
        
        // drawing white rectangle over table border in order to hide it.
        aboveCanvas.saveState().setStrokeColor(new DeviceRgb(255,255,255)).rectangle(rect).stroke().restoreState();
        
        // drawing red round rectangle which will be shown as boundary.
        aboveCanvas.saveState().setLineWidth(0.5f).setStrokeColor(new DeviceRgb(255,0,0)).roundRectangle(rect.getLeft(), rect.getBottom(), rect.getWidth(), rect.getHeight(), 5).stroke().restoreState();
        
        super.drawBorders(drawContext);
    }
}

现在代码可以正常工作,但渲染有问题。当我在 table 边框上方绘制白色边框时,它并没有完全重叠。此外,外部红色边框略微超出预期区域。简单来说,白色矩形和红色矩形不重合。因此,外边界和单元格边界之间存在一些间隙。 我附上了上面代码生成的输出。要注意到此问题,您可能需要稍微缩放 PDF。

我对此有一些疑问: 我正在使用 top canvas 来获得预期的解决方案。但是有什么方法可以在渲染时直接修改 table 边框吗?我试过了

drawContext.getCanvas()
            .saveState()
            .roundRectangle(rect.getLeft(), rect.getBottom(), rect.getWidth(), rect.getHeight(), 5).stroke().restoreState();

但在这种方法中,边界与单元格边界重叠(也需要单元格边界)。如果我遗漏了一些东西来防止这个问题,请指导我。

谢谢。

getOccupiedAreaBBox方法给出了边框区域的外边界框。但是,边框有自己的厚度,当您默认在 PDF 中绘制线条时,您应该将线条的中心传递给绘图操作,同时传递外部 bbox 坐标,因此边距小且重叠不精确。

要解决此问题,您需要将边框线宽度的一半添加到矩形的所有边缘:

float lineWidth = 0.5f;
rect.applyMargins(lineWidth / 2, lineWidth / 2, lineWidth / 2, lineWidth / 2, false);

综上所述,定制代码如下:

@Override
protected void drawBorders(DrawContext drawContext) {
    Rectangle rect = getOccupiedAreaBBox();
    PdfPage currentPage = drawContext.getDocument().getPage(getOccupiedArea().getPageNumber());
    PdfCanvas aboveCanvas = new PdfCanvas(currentPage.newContentStreamAfter(), currentPage.getResources(), drawContext.getDocument());

    float lineWidth = 0.5f;
    rect.applyMargins(lineWidth / 2, lineWidth / 2, lineWidth / 2, lineWidth / 2, false);

    // drawing white rectangle over table border in order to hide it.
    aboveCanvas.saveState().setLineWidth(lineWidth).setStrokeColor(new DeviceRgb(255,255,255)).rectangle(rect).stroke().restoreState();

    // drawing red round rectangle which will be shown as boundary.
    aboveCanvas.saveState().setLineWidth(lineWidth).setStrokeColor(new DeviceRgb(255,0,0))
            .roundRectangle(rect.getLeft(), rect.getBottom(), rect.getWidth(), rect.getHeight(), 5).stroke().restoreState();

    super.drawBorders(drawContext);
}

产生以下视觉结果: