如何将背景颜色应用于 iText7 中的 table 圆角单元格?

How to apply background color to table cell with round corners in iText7?

我画的 table 是圆角的。 table 是动态的,可以增长到多个页面。现在我想给单元格应用一些背景颜色。每个单元格都可以有自己不同的颜色(不是硬编码的)。但问题是当我将背景颜色应用于角落单元格时,颜色会从角落溢出。角单元的外角是圆的。圆角的实现是使用此方法完成的 .

为了实现这一点,我创建了一个单元格渲染器,它覆盖了 drawBackground() 方法来绘制预期的结果。

CellBackgroundColorRenderer.java

public class CellBackgroundColorRenderer extends CellRenderer {
    protected Color color;
    protected boolean isColoredBackground;
 
    public CellBackgroundColorRenderer(Cell modelElement, Color color, boolean isColoredBackground) {
        super(modelElement);
        this.color = color;
        this.isColoredBackground = isColoredBackground;
    }
 
    @Override
    public void drawBackground(DrawContext drawContext) {
        Rectangle rect = getOccupiedAreaBBox();
        PdfCanvas canvas = drawContext.getCanvas();
        
        // drawing white rectangle on top any pre existing background color. 
        canvas.saveState().rectangle(rect).setFillColor(new DeviceRgb(255, 255, 255)).fillStroke().restoreState();
        
        // drawing round corner rectangle for colored bg.
        canvas.saveState().roundRectangle(rect.getLeft(),rect.getBottom(), rect.getWidth(), rect.getHeight(), 5).setFillColor(color).fillStroke();
       
        // TODO fill color in those cell corners which are in conjuntion with other cells. 
        canvas.restoreState();
 
    }
}

TableBorderRenderer.java

public class TableBorderRenderer extends TableRenderer {
    
    private int numberOfColumns;
    public TableBorderRenderer(Table modelElement) {
        super(modelElement);
        numberOfColumns = modelElement.getNumberOfColumns();
    }

    @Override
    public IRenderer getNextRenderer() {
        return new TableBorderRenderer((Table) modelElement);
    }

    @Override
    public void draw(DrawContext drawContext) {

        CellRenderer[] cellRenderers = rows.get(0);
        
        Cell cell = (Cell) cellRenderers[0].getModelElement();
        ((Cell) cellRenderers[0].getModelElement()).setNextRenderer(new CellBackgroundColorRenderer((Cell) cellRenderers[0].getModelElement(), new DeviceRgb(255, 150, 255), true));
        
        ((Cell) cellRenderers[numberOfColumns-1].getModelElement()).setNextRenderer(new CellBackgroundColorRenderer((Cell) cellRenderers[numberOfColumns-1].getModelElement(), new DeviceRgb(255, 150, 255), true));

        super.draw(drawContext);
    }
    
    @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);
        
        aboveCanvas.saveState().setStrokeColor(new DeviceRgb(255,255,255)).rectangle(rect).stroke().restoreState();
        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);
    }
}

TableTest.java

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 的 draw() 中,我将 CellBackgroundColorRenderer 设置为模态元素,即单元格。现在,我仅为第一行设置 CellBackgroudnColorRenderer。但是当我 运行 程序时,它甚至没有进入 cellRenderer 的 drawBackground()。

我不确定我在这里遗漏了什么。我的方法正确吗?如果没有,你能指导我正确的方法吗?

谢谢。

无需手动为单元格绘制背景颜色 - 功能已经存在:

Table table = new Table(3);
for (int i=0; i < 100; i++) {
    for (int j=0; j < 3; j++) {
        table.addCell(new Cell()
                .setBackgroundColor(ColorConstants.GREEN)
                .add(new Paragraph("Cell content")));
    }
}
table.setNextRenderer(new TableBorderRenderer(table));
document.add(table);

您唯一需要做的就是剪掉那些绘制在圆角之外的背景。为此,您可以在 TableRenderer 中重载 drawChildren

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

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

        aboveCanvas.saveState().setLineWidth(lineWidth).setStrokeColor(new DeviceRgb(255,255,255)).rectangle(rect).stroke().restoreState();
        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);
    }

    @Override
    public void drawChildren(DrawContext drawContext) {
        Rectangle rect = getOccupiedAreaBBox();
        float lineWidth = 0.5f;
        rect.applyMargins(lineWidth, lineWidth, lineWidth, lineWidth, false);

        PdfCanvas canvas = drawContext.getCanvas();
        canvas.saveState();
        canvas.roundRectangle(rect.getLeft(), rect.getBottom(), rect.getWidth(), rect.getHeight(), 5);
        canvas.clip().endPath();
        super.drawChildren(drawContext);
        canvas.restoreState();
    }
}

视觉结果:

我更新了 TableRenderer,因此它使用给定的颜色和给定的半径绘制圆角边框。

using iText.Kernel.Colors;
using iText.Kernel.Pdf.Canvas;
using iText.Layout.Element;
using iText.Layout.Renderer;
using iText.Kernel.Colors;


public class TableBorderRenderer : TableRenderer
{
    private const float lineWidth = 0.5f;
    private readonly float _radius;
    private readonly Color _color;

    public TableBorderRenderer(Table modelElement, float radius, Color color = null) : base(modelElement)
    {
        _radius = radius;
        _color = color ?? PdfColors.White;
    }

    public override IRenderer GetNextRenderer()
    {
        return new TableBorderRenderer((Table)modelElement, _radius, _color);
    }

    protected override void DrawBorders(DrawContext drawContext)
    {
        var rect = GetOccupiedAreaBBox();
        var currentPage = drawContext
            .GetDocument()
            .GetPage(GetOccupiedArea().GetPageNumber());

        var aboveCanvas = new PdfCanvas(currentPage.NewContentStreamAfter(), currentPage.GetResources(), drawContext.GetDocument());

        rect.ApplyMargins(lineWidth, lineWidth, lineWidth, lineWidth, false);

        aboveCanvas
            .SaveState()
            .SetLineWidth(lineWidth)
            .SetStrokeColor(_color)
            .RoundRectangle(rect.GetLeft(), rect.GetBottom(), rect.GetWidth(), rect.GetHeight(), _radius)
            .Stroke()
            .RestoreState();

        base.DrawBorders(drawContext);
    }

    public override void DrawChildren(DrawContext drawContext)
    {
        var rect = GetOccupiedAreaBBox();
        rect.ApplyMargins(lineWidth, lineWidth, lineWidth, lineWidth, false);

        var canvas = drawContext
            .GetCanvas()
            .SaveState()
            .RoundRectangle(rect.GetLeft(), rect.GetBottom(), rect.GetWidth(), rect.GetHeight(), _radius)
            .Clip()
            .EndPath();

        base.DrawChildren(drawContext);
        canvas.RestoreState();
    }
}