Как во время работы itext выяснить координаты текста? - PullRequest
0 голосов
/ 03 мая 2019

Я хочу знать координаты текста, который добавляется на страницу. И примените к этому тексту холст. (например, пользовательское подчеркивание или зачеркивание или текст внутри треугольника)

Мне нужны только определенные слова

List<String> listString = new ArraList();

PdfDocument pdfDoc = new PdfDocument(new PdfWriter(DEST));

Document doc = new Document(pdfDoc, PageSize.A4);
for(String s:listString)
   //**underlineWord** hidden it will be removed
 if( s.contains("**underlineWord**")){
     s.replace("**underlineWord**","");
    Text text = new Text(s)
    Float[] coords = getCoords(text)
     Canvas canvas = new Canvas(...);
     setCustomUderline(coords)
 }


 doc.add(new Paragraph(text) );

Я знаю о PdfCanvasProcessor, но не пользуюсь им, потому что не буду знать об определенных словах (которые содержат **underlineWord**)

1 Ответ

2 голосов
/ 08 мая 2019

В iText7 вы реализуете такие задачи, используя пользовательский Renderer. Техника показана в примере DashedUnderline :

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

т.е. вы просто устанавливаете пользовательский Renderer в бит Text, о котором идет речь. В данном примере пользовательский класс Renderer равен

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

Как видите, вы можете переопределить draw, чтобы сначала вызвать реализацию super для нормального отображения текста. После этого вы можете извлечь область, используемую для рисования текста, вызвав getOccupiedAreaBBox и использовать ее для своей задачи, будь то для украшения текста или просто для сохранения позиции где-нибудь.


Если вам интересно, почему этот пример находится в подпакете events ... пример соответствует примеру iText5, и в iText5 вы реализуете такую ​​задачу посредством установки универсального тега чтобы узнать о Chunk и прослушивании этого общего тега в методе onGenericTag прослушивателя событий страницы, см. этот ответ для примера.


В комментарии вы спросили

Могу ли я сделать это с таблицей? (нарисовать границу с помощью холста)

Да, вы снова используете для этого связанные средства визуализации, например, см. DottedLineCell пример :

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

Здесь в первой таблице показано, как это сделать с помощью средства визуализации таблиц после отключения стандартных границ ячеек таблицы, а во второй таблице показано, как это сделать с помощью средств визуализации ячеек.

Настроенные классы рендерера:

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

и

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();
    }
}
* * Соответственно тысяча сорок-девять.

Как объяснил Алексей Субач в этом ответе , полная настройка Renderer также должна переопределить метод getNextRenderer(). В частности, если в рассматриваемом объекте может произойти разрыв области, это необходимо, в противном случае настройка работает только в первой области, как наблюдал OP.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...