1
votes

I try to draw some nested tables in iText as i thought it would be the easiest way to position everything.

enter image description here

So i have multiple tables inside another table who all have background color and/or strokes (via PdfPCellEvents). Unfortunately the strokes of the outer table are overlapping the background of the inner table. I assume that comes from a wrong order of applying or some wrong set saveState or restoreState in my PdfPCellEvents.

Can anyone explain the right usage of saveState and restoreState to me and give me a hint how to apply backgrounds and strokes the right way?

Here is my code for adding a striped background cell:

PdfPCell scaleBackground = new PdfPCell();
scaleBackground.setBorder(Rectangle.NO_BORDER);
scaleBackground.setVerticalAlignment(Element.ALIGN_TOP);
scaleBackground.setCellEvent(new StripedScaleBackground(max, scaleHeight));

cellLayout method of StripedScaleBackground:

public void cellLayout(PdfPCell cell, Rectangle rect, PdfContentByte[] canvases)
{
    PdfContentByte canvas = canvases[PdfPTable.LINECANVAS];
    float llx = rect.getLeft();
    float lly = rect.getBottom();
    float urx = rect.getRight();
    float ury = rect.getTop();

    // Light scale lines with padding from left
    canvas.setLineWidth(Constants.BORDER_WIDTH_THIN);
    canvas.setColorStroke(Colors.LIGHT_GRAY);

    float paddingLeft = 22f;
    for (int i = 0; i <= this.maxValue; i++)
    {
        canvas.moveTo(llx + paddingLeft, lly + (this.scaleHeight * (i + 1)));
        canvas.lineTo(urx, lly + (this.scaleHeight * (i + 1)));
    }

    // Vertical line
    canvas.moveTo(llx + (((urx - llx) + paddingLeft) / 2), ury);
    canvas.lineTo(llx + (((urx - llx) + paddingLeft) / 2), lly);
    canvas.stroke();

    // Fat line left and right
    canvas.moveTo(llx, ury);
    canvas.lineTo(llx, lly);
    canvas.moveTo(urx, ury);
    canvas.lineTo(urx, lly);

    canvas.setLineWidth(0.8f);
    canvas.setColorStroke(Colors.MEDIUM_GRAY);
    canvas.stroke();

    canvas.saveState();
    canvas.restoreState();
}

The bar charts are tables where each cell has a cell event for gradient and border. The bar charts are added to the scaleBackground PdfPCell of the first piece of code and have following PdfPCellEvents (example of black part of the chart):

public void cellLayout(PdfPCell cell, Rectangle rect, PdfContentByte[] canvases)
{
    PdfContentByte backgroundCanvas = canvases[PdfPTable.BACKGROUNDCANVAS];
    float llx = rect.getLeft();
    float lly = rect.getBottom();
    float urx = rect.getRight();
    float ury = rect.getTop();

    // Draw background

    // Define shading with direction and color
    PdfShading shading = PdfShading.simpleAxial(this.writer,
                    llx, ury,
                    llx, lly,
                    Colors.BAR_CHART_BLACK_LIGHT, Colors.BAR_CHART_BLACK_DARK);

    PdfShadingPattern pattern = new PdfShadingPattern(shading);
    backgroundCanvas.setShadingFill(pattern);

    // Draw shape with defined shading
    backgroundCanvas.moveTo(llx, ury);
    backgroundCanvas.lineTo(llx, lly);
    backgroundCanvas.lineTo(urx, lly);
    backgroundCanvas.lineTo(urx, ury);
    backgroundCanvas.lineTo(llx, ury);
    backgroundCanvas.fill();

    backgroundCanvas.saveState();
    backgroundCanvas.restoreState();

    // Draw border
    PdfContentByte lineCanvas = canvases[PdfPTable.LINECANVAS];

    float lineWidth = Constants.BORDER_WIDTH_THIN;
    lineCanvas.setLineWidth(lineWidth);
    lineCanvas.moveTo(llx, ury - lineWidth);
    lineCanvas.lineTo(llx, lly);
    lineCanvas.lineTo(urx, lly);
    lineCanvas.lineTo(urx, ury - lineWidth);

    lineCanvas.setColorStroke(BaseColor.BLACK);
    lineCanvas.stroke();

    lineCanvas.saveState();
    lineCanvas.restoreState();
}
1

1 Answers

0
votes

This is the order of the different direct content layers:

  • PdfPtable.BASECANVAS—Anything placed here will be under the table.
  • PdfPtable.BACKGROUNDCANVAS—This is the layer where the backgrounds are drawn.
  • PdfPtable.LINECANVAS—This is the layer where the lines are drawn.
  • PdfPtable.TEXTCANVAS—This is the layer where the text goes. Anything placed here will cover the table.

This was taken from the book "iText in Action - Second Edition."

You also ask about saveState() and restoreState(). This is explained in Chapter 2 of the iText 7 tutorial:

First we save the current graphics state with the saveState() method, then we change the state and draw whatever lines or shapes we want to draw, finally, we use the restoreState() method to return to the original graphics state. All the changes that we applied after saveState() will be undone. This is especially interesting if you change multiple values (line width, color,...) or when it's difficult to calculate the reverse change (returning to the original coordinate system).

Your code was too long for me to inspect, but I highly doubt that saveState()/restoreState() would be the cause of your problem.

I would try to avoid nesting tables as much as possible. It is usually much easier (and more efficient) to use colspan and rowspan.

If this doesn't solve your problem, please explain your problem in one sentence.