You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

iText7多Text元素场景下如何绘制指定波浪下划线?

iText7 多Text元素自定义下划线定位问题解决方案

问题根因

你把完整字符串拆分为单个字符对应的Text元素后,每个DashedLineTextRenderer拿到的getOccupiedAreaBBox()仅为单个字符的宽高,你原逻辑里固定画200单位长度的曲线,自然会出现定位错位、重复绘制的问题。同时单个字符的Renderer互相独立,无法感知相邻字符的位置,也就无法绘制连续的下划线。

方案1(优先推荐:无需拆分Text)

如果没有必须拆分单个字符的业务需求(比如不同字符要设置不同颜色/字体),直接给整段文本对应的单个Text设置自定义Renderer即可,原有绘制逻辑无需修改:

String s = "This text is underlined with a dashed line";
Paragraph paragraph = new Paragraph();
Text text = new Text(s);
text.setNextRenderer(new DashedLineTextRenderer(text));
paragraph.add(text);
doc.add(paragraph);
doc.close();

该方案可以直接还原单个Text元素场景下的正常波浪线效果。

方案2(必须拆分多个Text场景)

如果确实需要拆分多个Text元素(比如单字符定制样式),需要通过自定义ParagraphRenderer收集同一行内所有需要加下划线的Text的位置,合并后统一绘制连续下划线:

第一步:修改自定义TextRenderer,仅做标记不做绘制

private static class DashedLineTextRenderer extends TextRenderer {
    // 标记是否需要绘制下划线
    public boolean needUnderline = true;

    public DashedLineTextRenderer(Text textElement) {
        super(textElement);
    }

    @Override
    public IRenderer getNextRenderer() {
        return new DashedLineTextRenderer((Text) modelElement);
    }
    // 移除原draw方法里的下划线绘制逻辑,仅保留文本绘制
    @Override
    public void draw(DrawContext drawContext) {
        super.draw(drawContext);
    }
}

第二步:自定义ParagraphRenderer统一绘制下划线

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

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

    @Override
    public void draw(DrawContext drawContext) {
        super.draw(drawContext);
        PdfCanvas canvas = drawContext.getCanvas();
        // 按行处理,合并同一行内所有需要加下划线Text的占用区域
        for (LineRenderer line : lines) {
            List<Rectangle> underlineRects = new ArrayList<>();
            for (IRenderer child : line.getChildRenderers()) {
                if (child instanceof DashedLineTextRenderer && ((DashedLineTextRenderer) child).needUnderline) {
                    underlineRects.add(child.getOccupiedAreaBBox());
                }
            }
            if (!underlineRects.isEmpty()) {
                // 计算连续区域的左右边界与统一基线Y坐标
                float left = underlineRects.stream().min(Comparator.comparing(Rectangle::getLeft)).get().getLeft();
                float right = underlineRects.stream().max(Comparator.comparing(Rectangle::getRight)).get().getRight();
                float bottomY = underlineRects.get(0).getBottom();
                float totalWidth = right - left;
                // 基于完整区域绘制自适应长度的波浪线,可自行调整曲线参数匹配样式需求
                canvas.moveTo(left, bottomY);
                canvas.curveTo(left + totalWidth * 0.25f, bottomY + 2,
                        left + totalWidth * 0.5f, bottomY -2,
                        left + totalWidth * 0.75f, bottomY +2,
                        right, bottomY);
                canvas.stroke();
            }
        }
    }
}

第三步:调用时给Paragraph绑定自定义Renderer

String s = "This text is underlined with a dashed line";
Paragraph paragraph = new Paragraph();
// 给Paragraph设置自定义Renderer
paragraph.setNextRenderer(new UnderlineParagraphRenderer(paragraph));
Text text;
for (int i = 0; i <s.length() ; i++) {
    text = new Text(String.valueOf(s.charAt(i)));
    paragraph.add(text);
    text.setNextRenderer(new DashedLineTextRenderer(text));
}
doc.add(paragraph);
doc.close();

内容的提问来源于stack exchange,提问作者cixikoy607

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.14 23:24:03