【问题标题】:How during work itext find out coordinates text?在工作中itext如何找出坐标文本?
【发布时间】:2019-05-02 21:31:29
【问题描述】:

我想知道添加到页面的文本的坐标。 并将一些画布应用于此文本。 (例如自定义下划线或删除线或三角形内的文本)

我只需要几个字

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**

【问题讨论】:

  • 请解释清楚。多次阅读您的问题,我仍然不知道它是关于什么的。
  • @mkl 我想在某些包含标签的文本上添加画布,例如 hello。当我在文档中添加单词时,我希望这个单词用画布或下划线删除线
  • @mkl 请帮忙)
  • 对于下划线只需使用带有com.itextpdf.layout.property.Underline 值的com.itextpdf.layout.property.Property.UNDERLINE 属性。
  • @mkl 我知道这一点。我只是举了一个例子。我需要在某些单词上使用画布。

标签: java itext itext7


【解决方案1】:

在 iText7 中,您使用自定义 Renderer 来实现此类任务。该技术显示在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();

即您只需将自定义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 方法中侦听该通用标记,请参阅this answer 以获取示例。


在你问的评论中

我可以用桌子做吗? (使用帮助画布绘制边框)

是的,您再次为此使用关联的渲染器,例如见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();

这里的第一个表格显示了在关闭标准表格单元格边框后如何使用表格渲染器执行此操作,而第二个表格显示了如何使用单元格渲染器执行此操作。

自定义的渲染器类是

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

分别。


正如Alexey Subachthis answer 中解释的那样,Renderer 的完整自定义也应该覆盖getNextRenderer() 方法。 特别是如果在问题,这是必要的,否则自定义仅适用于 OP 观察到的第一个区域。

【讨论】:

  • 非常感谢。我爱你!你从哪里得到所有这些信息?也许有一本书?
  • “你从哪里得到所有这些信息” - 好吧,我确信它必须是一个渲染器(因为它可能是什么)但我承认我发现这个非常只是因为我知道在 itext 5 中可以使用通用标签来做到这一点:所以我寻找使用通用标签的 itext 5 示例,找到 itext 5 变体,然后从那里切换到 itext 7 示例。
  • @forseti420 “我可以用表格来做吗?(使用帮助画布绘制边框)” - 我假设您可以通过更改单元格渲染来完全自定义表格边框。渲染器中甚至可能有一个可以覆盖的绘制边框的方法。
  • @forseti420 我编辑了我的答案以包含并参考表格和表格单元格渲染器自定义的示例。
  • 请单独提出一个问题(您可以在其中引用此问题和 itext 示例代码)并创建一个简短的测试程序来说明该问题。
猜你喜欢
  • 2011-02-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-05-15
  • 1970-01-01
  • 1970-01-01
  • 2019-01-23
相关资源
最近更新 更多