How during work itext find out coordinates text?

后端 未结 1 1343
醉酒成梦
醉酒成梦 2021-01-26 16:16

I want to know the coordinates of the text that is added to the page. And apply some canvas to this text. (for example custom underline or strikethrough or text inside the tria

相关标签:
1条回答
  • 2021-01-26 16:48

    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.

    0 讨论(0)
提交回复
热议问题