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

夙愿已清 提交于 2021-01-29 06:16:37

问题


I want to apply round corner border to a table. This table is dynamic. That means it can grow up to multiple pages or can accommodate in single page.

If table comes in single page, then outermost corner of all four corner cells should be drawn as rounded. If table grows up to multiple pages (say 3 pages), then outermost corner of all four corner cells should be drawn as rounded for all 3 pages.

Here is the approach which I am using to implement the above scenario.

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

Now the code is working fine as it is supposed to be, but there is an issue with the rendering. when i draw the white border on top of table border it does not overlap it completely. Also the outer red border is drawn slightly outside the expected area. In simple words, white rectangle and red rectangle are not coinciding with each other. So there is some gap coming between the outer border and cell borders. I am attaching the generated output from above code. To notice the issue you might need to zoom the PDF a little bit.

I have some doubts regarding the same: I am using a top canvas to get the expected solution. But is there any approach in which I can modify the table border directly while rendering? I tried

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

But in this approach border is overlapped by the cell borders (cell borders are needed as well). If I am missing something to prevent this issue, guide me.

Thanks.


回答1:


The getOccupiedAreaBBox method gives you the outer bounding box of the border area. Borders, however, have thickness on their own, and when you draw lines in PDF by default you should pass the center of the line to the drawing operation, while you are passing the outer bbox coordinates, hence the small margin and imprecise overlap.

To fix the issue, you need to add half of the border line width to all of the edges of your rectangle:

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

All in all, the following customized code:

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

Yields the following visual result:



来源:https://stackoverflow.com/questions/62757836/how-to-apply-round-corner-border-to-table-single-page-multipage

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!