使用iText 5添加不可移除RTL水印文本显示异常,如何修复?
修复iText 5中RTL水印文本显示异常的问题
核心问题分析
- 字体与编码不匹配:你使用的
HELVETICA_OBLIQUE是西文字体,不支持阿拉伯语字符;WINANSI编码无法正确解析阿拉伯语Unicode字符,导致字符显示乱码或错位。 - 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
相关产品推荐
相关产品推荐

