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

使用iText 5添加不可移除RTL水印文本显示异常,如何修复?

修复iText 5中RTL水印文本显示异常的问题

核心问题分析

  1. 字体与编码不匹配:你使用的HELVETICA_OBLIQUE是西文字体,不支持阿拉伯语字符;WINANSI编码无法正确解析阿拉伯语Unicode字符,导致字符显示乱码或错位。
  2. RTL文本未做双向处理:阿拉伯语属于从右到左(RTL)的双向文本,直接调用showTextAlignedKerned无法处理字符的连写规则和方向逻辑,导致文本顺序错乱。

修复步骤及代码示例

1. 替换为支持阿拉伯语的字体

选择支持阿拉伯语的字体(如Arial Unicode MS、Amiri等),并使用IDENTITY_H编码确保Unicode字符正确渲染:

// 加载支持阿拉伯语的字体,需确保字体文件可访问
BaseFont baseFont = BaseFont.createFont("Arial Unicode MS", BaseFont.IDENTITY_H, BaseFont.EMBEDDED);

2. 使用ColumnText处理RTL文本

iText5的ColumnText组件支持双向文本渲染,结合坐标变换实现旋转的RTL水印效果:

ByteArrayOutputStream baos = new ByteArrayOutputStream();

PdfReader reader = new PdfReader(byteArray);
PdfStamper stamper = new PdfStamper(reader, baos);

// 替换为支持阿拉伯语的字体
BaseFont baseFont = BaseFont.createFont("Arial Unicode MS", BaseFont.IDENTITY_H, BaseFont.EMBEDDED);
String watermarkText = "مسودة";
Font font = new Font(baseFont, 13);

int numberOfPages = reader.getNumberOfPages();
for (int i = 1; i <= numberOfPages; i++) {
    Rectangle pageSize = reader.getPageSizeWithRotation(i);

    // 保留原页面内容的逻辑不变
    PdfImportedPage pageContent = stamper.getImportedPage(reader, i);
    stamper.getWriter().addToBody(pageContent.getFormXObject(stamper.getWriter().getCompressionLevel()), pageContent.getIndirectReference());
    pageContent.setCopied();
    reader.getPageN(i).put(PdfName.CONTENTS, null);

    PdfPatternPainter bodyPainter = stamper.getOverContent(i).createPattern(pageSize.getWidth(), pageSize.getHeight());
    bodyPainter.addTemplate(pageContent, 0, 0);

    // 添加水印部分修改为ColumnText处理RTL
    PdfGState state = new PdfGState();
    state.setFillOpacity(0.3f);
    bodyPainter.saveState();
    bodyPainter.setGState(state);

    for (float x = 70f; x < pageSize.getWidth(); x += 100) {
        for (float y = 90; y < pageSize.getHeight(); y += 100) {
            bodyPainter.saveState();
            // 旋转画布45度,实现水印旋转效果
            bodyPainter.rotateText(45, x, y);
            
            // 配置ColumnText以RTL方向绘制文本
            ColumnText ct = new ColumnText(bodyPainter);
            ct.setRunDirection(PdfWriter.RUN_DIRECTION_RTL); // 设置文本从右到左渲染
            // 设置文本显示的矩形区域,确保水印居中
            ct.setSimpleColumn(new Phrase(watermarkText, font), x - 30, y - 10, x + 30, y + 10, 0, Element.ALIGN_CENTER);
            ct.go();
            
            bodyPainter.restoreState();
        }
    }
    bodyPainter.restoreState();

    // 原页面内容填充逻辑不变
    PdfContentByte canvas = stamper.getUnderContent(i);
    canvas.beginText();
    canvas.setFontAndSize(baseFont, 13);
    canvas.showTextAlignedKerned(Element.ALIGN_MIDDLE, "        ", 0, 0, 45f);
    canvas.endText();
    canvas.setColorFill(new PatternColor(bodyPainter));
    canvas.rectangle(pageSize.getLeft(), pageSize.getBottom(), pageSize.getWidth(), pageSize.getHeight());
    canvas.fill();
}

stamper.close();
reader.close();
byteArray = baos.toByteArray();

3. 额外注意事项

  • 字体文件访问:如果使用自定义字体文件(如Amiri),需将字体文件放入项目资源目录,并通过输入流加载:
    BaseFont baseFont = BaseFont.createFont("/fonts/Amiri-Regular.ttf", BaseFont.IDENTITY_H, BaseFont.EMBEDDED);
    
  • 坐标调整:rotateText会改变画布坐标系,需根据字体大小调整setSimpleColumn的参数,确保水印文本在目标位置居中显示。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 14:07:32