带有许多文本元素的事件下划线 itext7

event underline with many Text element itext7

我需要为自定义下划线扩展 TextRenderer,但在一个元素文本中我有一个字母。 我有大文本并执行此操作:

String s = "d < like to filter > RENDER_TEXT events as they are <written> to an output file. I have a <PDF that has some text in it> that I want filtered out. I've found that I can walk the document once and determine the characteristics of the render events that I want to filter. Now I'd like to copy the pages of the source document and skip over some RENDER_TEXT events so that the text does not appear in the destination document. I have an IEventFilter that will accept the correct events. I just need to know how to put this filter on the document writer.";
String[] words = s.split("");
Paragraph paragraph = new Paragraph();
Text text = null;
boolean isUnderStart  = false;
boolean isUnderEnd  = false;
int i = 1;
for (String word : words) {


    if (word.equals("<")) {
        isUnderStart = true;
    }
    if (word.equals(">")) {
        isUnderEnd = true;
    }


    text = new Text(word);

    text.setNextRenderer(new Word25TextRenderer(text, isUnderStart,isUnderEnd));
    isUnderStart = false;
    isUnderEnd = false;

    paragraph.add(text);
    i++;
}

doc.add(paragraph);

doc.close();

"<" и ">" 我做测试(在实际程序中,我使用 Jsoup) 在这个符号的帮助下,我找到了第一个符号和结束符号的坐标轴。这是绘制 canvas 元素(直线、曲线到)所必需的。我还添加了布尔值以绘制两次,第一个字母和第二个字母的坐标。

一行的所有单词,如果我想为两行画下划线,它不会中断。这部分:<PDF that has some text in it>

static class Word25TextRenderer extends TextRenderer {
    private boolean isUnderStart;
    private boolean isUnderEnd;

    public Word25TextRenderer(Text textElement, boolean isUnderStart, boolean isUnderEnd) {
        super(textElement);
        this.isUnderStart = isUnderStart;
        this.isUnderEnd = isUnderEnd;
    }

    @Override
    public IRenderer getNextRenderer() {

        return new Word25TextRenderer((Text) modelElement, isUnderStart, isUnderEnd);

    }

    @Override
    public void draw(DrawContext drawContext) {
        super.draw(drawContext);

        Rectangle textRect = getOccupiedAreaBBox();
        int pageNumber = getOccupiedArea().getPageNumber();
        PdfCanvas canvas = drawContext.getCanvas();
        if (isUnderStart) {
            canvas
                    .saveState()
                    .setStrokeColor(DeviceRgb.RED)
                    .moveTo(textRect.getRight(), textRect.getBottom());
        }
        if (isUnderEnd) {
            canvas.curveTo(textRect.getRight(), textRect.getBottom() + textRect.getHeight() / 2,
                    textRect.getRight(), textRect.getBottom(),
                    textRect.getRight(), textRect.getBottom())
                    .stroke()
                    .restoreState();
        }

    }
}

也许你知道其他方法? 这是最后发生的事情

p.s:我在文本中添加了一个元素,因为之后我会单独更改元素(字体、字体大小等)这是必要的!

与其在 Text 元素/渲染器级别添加下划线,不如在 Paragraph 级别添加下划线更方便,其中所有关于行拆分的信息都是已知的,因为您必须在同一 Text 中位于不同行的部分下划线。

我们将创建一个 CustomText class 来存储有关我们是否仍要为那段文本加下划线的信息(尽管我们可以在常规 [=13] 上使用 setProperty =]元素):

static class CustomText extends Text {
    private boolean isUnderStart;
    private boolean isUnderEnd;

    public CustomText(String text, boolean isUnderStart, boolean isUnderEnd) {
        super(text);
        this.isUnderStart = isUnderStart;
        this.isUnderEnd = isUnderEnd;
    }

    public boolean isUnderStart() {
        return isUnderStart;
    }

    public boolean isUnderEnd() {
        return isUnderEnd;
    }
}

最重要的部分是我们的习惯ParagraphRenderer - 我们翻过几行,记住最后一个“左括号”,或者文本块开始定义要加下划线的文本的开始,然后一旦我们面对“右括号”,或定义文本结尾的文本块,我们为整个区域进行实际绘图。此外,如果在完成线路检查时我们仍然有“开括号”,我们会通过在线路的剩余部分下划线来处理拆分。这里是代码:

static class CustomParagraphRenderer extends ParagraphRenderer {
    public CustomParagraphRenderer(Paragraph modelElement) {
        super(modelElement);
    }

    @Override
    public IRenderer getNextRenderer() {
        return new CustomParagraphRenderer((Paragraph) modelElement);
    }

    @Override
    public void draw(DrawContext drawContext) {
        super.draw(drawContext);
        Rectangle lastRectStart = null;
        for (int i = 0; i < lines.size(); i++) {
            LineRenderer lineRenderer = lines.get(i);
            boolean anyEventsThisLine = false;
            for (IRenderer renderer : lineRenderer.getChildRenderers()) {
                if (renderer.getModelElement() instanceof CustomText &&
                        (((CustomText) renderer.getModelElement()).isUnderEnd()
                                || ((CustomText) renderer.getModelElement()).isUnderStart())) {
                    anyEventsThisLine = true;

                    if ((((CustomText) renderer.getModelElement()).isUnderEnd())) {
                        Rectangle endRect = renderer.getOccupiedArea().getBBox();
                        PdfCanvas canvas = drawContext.getCanvas();
                        canvas.saveState().setStrokeColor(ColorConstants.RED)
                                .moveTo(lastRectStart.getRight(), lastRectStart.getBottom())
                                .curveTo(endRect.getRight(), endRect.getBottom() + endRect.getHeight() / 2,
                                        endRect.getRight(), endRect.getBottom(),
                                        endRect.getRight(), endRect.getBottom())
                                .stroke().restoreState();
                        lastRectStart = null;
                    } else {
                        lastRectStart = renderer.getOccupiedArea().getBBox();
                    }
                }
            }
            if (lastRectStart != null && !anyEventsThisLine) {
                // Underline the whole line
                PdfCanvas canvas = drawContext.getCanvas();
                Rectangle lineRect = lineRenderer.getOccupiedArea().getBBox();
                canvas.saveState().setStrokeColor(ColorConstants.RED)
                        .moveTo(lineRect.getLeft(), lineRect.getBottom())
                        .curveTo(lineRect.getRight(), lineRect.getBottom() + lineRect.getHeight() / 2,
                                lineRect.getRight(), lineRect.getBottom(),
                                lineRect.getRight(), lineRect.getBottom())
                        .stroke().restoreState();
            }
            if (lastRectStart != null) {
                // Draw till end of line
                Rectangle endRect = lineRenderer.getChildRenderers().get(lineRenderer.getChildRenderers().size() - 1)
                        .getOccupiedArea().getBBox();
                PdfCanvas canvas = drawContext.getCanvas();
                canvas.saveState().setStrokeColor(ColorConstants.RED)
                        .moveTo(lastRectStart.getRight(), lastRectStart.getBottom())
                        .curveTo(endRect.getRight(), endRect.getBottom() + endRect.getHeight() / 2,
                                endRect.getRight(), endRect.getBottom(),
                                endRect.getRight(), endRect.getBottom())
                        .stroke().restoreState();
                if (i + 1 < lines.size()) {
                    lastRectStart = lines.get(i + 1).getChildRenderers().get(0).getOccupiedArea().getBBox();
                } else {
                    lastRectStart = null;
                }
            }
        }
    }
}

主要入口点代码只有细微的变化:

PdfDocument pdfDocument = new PdfDocument(new PdfWriter("C:/path/to.pdf"));
Document doc = new Document(pdfDocument);
String s = "d < like to filter > RENDER_TEXT events as they are <written> to an output file. I have a <PDF that has some text in it> that I want filtered out. I've found that I can walk the document once and determine the characteristics of the render events that I want to filter. Now I'd like to copy the pages of the source document and skip over some RENDER_TEXT events so that the text does not appear in the destination document. I have an IEventFilter that will accept the correct events. I just need to know how to put this filter on the document writer.";
String[] words = s.split("");
Paragraph paragraph = new Paragraph();
paragraph.setNextRenderer(new CustomParagraphRenderer(paragraph));
Text text = null;
boolean isUnderStart  = false;
boolean isUnderEnd  = false;
int i = 1;
for (String word : words) {
    if (word.equals("<")) {
        isUnderStart = true;
    }
    if (word.equals(">")) {
        isUnderEnd = true;
    }

    text = new CustomText(word, isUnderStart, isUnderEnd);

    isUnderStart = false;
    isUnderEnd = false;

    paragraph.add(text);
    i++;
}

doc.add(paragraph);

doc.close();