How during work itext find out coordinates text?

一个人想着一个人 提交于 2019-12-02 10:08:29

In iText7 you implement such tasks using a custom Renderer. The technique is shown in the DashedUnderline example:

PdfDocument pdfDoc = new PdfDocument(new PdfWriter(DEST));
Document doc = new Document(pdfDoc);
doc.add(new Paragraph("This text is not underlined"));
Text text1 = new Text("This text is underlined with a solid line");
text1.setUnderline(1, -3);
doc.add(new Paragraph(text1));
Text text2 = new Text("This text is underlined with a dashed line");
text2.setNextRenderer(new DashedLineTextRenderer(text2));
doc.add(new Paragraph(text2));
doc.close();

i.e. you merely set a custom Renderer to the Text bit in question. In the example at hand the custom Renderer class is

protected class DashedLineTextRenderer extends TextRenderer {
    public DashedLineTextRenderer(Text textElement) {
        super(textElement);
    }

    @Override
    public void draw(DrawContext drawContext) {
        super.draw(drawContext);
        Rectangle rect = this.getOccupiedAreaBBox();
        PdfCanvas canvas = drawContext.getCanvas();
        canvas
                .saveState()
                .setLineDash(3, 3)
                .moveTo(rect.getLeft(), rect.getBottom() - 3)
                .lineTo(rect.getRight(), rect.getBottom() - 3)
                .stroke()
                .restoreState();
    }
}

As you see you can override draw to first call the super implementation to have the text drawn normally. After that you can retrieve the area used for drawing the text by calling getOccupiedAreaBBox and use it for your task, be it for decorating the text or merely storing the position somewhere.


If you wonder why this example is in the events sub-package... the example corresponds to an iText5 example, and in iText5 you implement such a task by means of setting a generic tag to the Chunk in question and listening for that generic tag in the onGenericTag method of a page event listener, see this answer for an example.


In a comment you asked

Can i do it with table? (draw border with help canvas)

Yes, again you use the associated renderers for that, e.g. see the DottedLineCell example:

PdfDocument pdfDoc = new PdfDocument(new PdfWriter(dest));
Document doc = new Document(pdfDoc);
doc.add(new Paragraph("Table event"));
Table table = new Table(UnitValue.createPercentArray(3)).useAllAvailableWidth();
table.setNextRenderer(new DottedLineTableRenderer(table, new Table.RowRange(0, 2)));
table.addCell(new Cell().add(new Paragraph("A1")).setBorder(Border.NO_BORDER));
table.addCell(new Cell().add(new Paragraph("A2")).setBorder(Border.NO_BORDER));
table.addCell(new Cell().add(new Paragraph("A3")).setBorder(Border.NO_BORDER));
table.addCell(new Cell().add(new Paragraph("B1")).setBorder(Border.NO_BORDER));
table.addCell(new Cell().add(new Paragraph("B2")).setBorder(Border.NO_BORDER));
table.addCell(new Cell().add(new Paragraph("B3")).setBorder(Border.NO_BORDER));
table.addCell(new Cell().add(new Paragraph("C1")).setBorder(Border.NO_BORDER));
table.addCell(new Cell().add(new Paragraph("C2")).setBorder(Border.NO_BORDER));
table.addCell(new Cell().add(new Paragraph("C3")).setBorder(Border.NO_BORDER));
doc.add(table);
doc.add(new Paragraph("Cell event"));
table = new Table(UnitValue.createPercentArray(1)).useAllAvailableWidth();
Cell cell = new Cell().add(new Paragraph("Test"));
cell.setNextRenderer(new DottedLineCellRenderer(cell));
cell.setBorder(Border.NO_BORDER);
table.addCell(cell.setBorder(Border.NO_BORDER));
doc.add(table);

doc.close();

Here the first table shows how to do this using the table renderer after turning off standard table cell borders while the second table shows how to do this using the cell renderers.

The customized renderer classes are

private class DottedLineTableRenderer extends TableRenderer {
    public DottedLineTableRenderer(Table modelElement, Table.RowRange rowRange) {
        super(modelElement, rowRange);
    }

    @Override
    public void drawChildren(DrawContext drawContext) {
        super.drawChildren(drawContext);
        PdfCanvas canvas = drawContext.getCanvas();
        canvas.setLineDash(3f, 3f);
        // first horizontal line
        CellRenderer[] cellRenderers = rows.get(0);
        canvas.moveTo(cellRenderers[0].getOccupiedArea().getBBox().getLeft(),
                cellRenderers[0].getOccupiedArea().getBBox().getTop());
        canvas.lineTo(cellRenderers[cellRenderers.length - 1].getOccupiedArea().getBBox().getRight(),
                cellRenderers[cellRenderers.length - 1].getOccupiedArea().getBBox().getTop());

        for (int i = 0; i < rows.size(); i++) {
            cellRenderers = rows.get(i);
            // horizontal lines
            canvas.moveTo(cellRenderers[0].getOccupiedArea().getBBox().getX(),
                    cellRenderers[0].getOccupiedArea().getBBox().getY());
            canvas.lineTo(cellRenderers[cellRenderers.length - 1].getOccupiedArea().getBBox().getRight(),
                    cellRenderers[cellRenderers.length - 1].getOccupiedArea().getBBox().getBottom());
            // first vertical line
            Rectangle cellRect = cellRenderers[0].getOccupiedArea().getBBox();
            canvas.moveTo(cellRect.getLeft(), cellRect.getBottom());
            canvas.lineTo(cellRect.getLeft(), cellRect.getTop());
            // vertical lines
            for (int j = 0; j < cellRenderers.length; j++) {
                cellRect = cellRenderers[j].getOccupiedArea().getBBox();
                canvas.moveTo(cellRect.getRight(), cellRect.getBottom());
                canvas.lineTo(cellRect.getRight(), cellRect.getTop());
            }
        }
        canvas.stroke();
    }
}

and

private class DottedLineCellRenderer extends CellRenderer {
    public DottedLineCellRenderer(Cell modelElement) {
        super(modelElement);
    }

    @Override
    public void draw(DrawContext drawContext) {
        super.draw(drawContext);
        drawContext.getCanvas().setLineDash(3f, 3f);
        drawContext.getCanvas().rectangle(this.getOccupiedArea().getBBox());
        drawContext.getCanvas().stroke();
    }
}

respectively.


As explained by Alexey Subach in this answer, a complete customization of a Renderer should also override the getNextRenderer() method. In particular if an area break might occur in the object in question, this is necessary, otherwise the customization only works in the first area as the OP has observed.

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