iText5中不可移除水印透明度不足遮挡内容,如何解决?
解决iText5中水印遮挡文本及透明度问题的方案
针对你遇到的水印遮挡正文、透明度异常问题,可通过调整代码中的绘制逻辑、层级控制和透明度设置来解决,同时保留水印不可移除的特性。以下是具体修改方案:
核心问题分析
- 重复填充导致水印过深:原代码在嵌套循环内多次填充整个页面的Pattern,叠加后水印颜色变深,遮挡正文。
- 透明度设置位置错误:将透明度应用在页面内容层而非Pattern本身,导致叠加效果失控。
- 文本高度计算错误:原代码用
getAscentPoint + getDescentPoint计算文本高度,实际应为差值,导致水印间距异常。
修改后的完整代码
public class TestWatermark { public static String resourcesPath = "C:\\Users\\java\\Desktop\\TestWaterMark\\"; public static String FILE_NAME = resourcesPath + "test.pdf"; public static void main(String[] args) throws IOException { System.out.println("########## STARTED ADDING WATERMARK ###########"); ByteArrayOutputStream baos = new ByteArrayOutputStream(); try { byte[] byteArray = Files.readAllBytes(Paths.get(FILE_NAME)); String watermarkText = "confidential"; String fontPath = resourcesPath + "myCustomFont.ttf"; Font arabicFont = FontFactory.getFont(fontPath, BaseFont.IDENTITY_H, 16); BaseFont baseFont = arabicFont.getBaseFont(); PdfReader reader = new PdfReader(byteArray); PdfStamper stamper = new PdfStamper(reader, baos); int numberOfPages = reader.getNumberOfPages(); float textSize = 24; // 正确计算文本实际高度( ascent - descent ) float textHeight = baseFont.getAscentPoint(watermarkText, textSize) - baseFont.getDescentPoint(watermarkText, textSize); float spacing = 100; // 水印之间的间距 for (int i = 1; i <= numberOfPages; i++) { Rectangle pageSize = reader.getPageSizeWithRotation(i); PdfContentByte content = stamper.getOverContent(i); // 保留overContent确保水印不可移除 // 创建页面尺寸的PatternPainter PdfPatternPainter patternPainter = content.createPattern(pageSize.getWidth(), pageSize.getHeight()); // 给Pattern设置透明度,控制水印整体淡度 PdfGState patternState = new PdfGState(); patternState.setFillOpacity(0.1f); // 0.1的透明度既可见又不遮挡正文 patternPainter.saveState(); patternPainter.setGState(patternState); // 使用浅灰色作为水印颜色,降低对正文的干扰 BaseColor lightGray = new BaseColor(180, 180, 180); patternPainter.setColorFill(lightGray); // 在Pattern中一次性绘制所有水印文本 patternPainter.beginText(); patternPainter.setTextRenderingMode(PdfContentByte.TEXT_RENDER_MODE_FILL); patternPainter.setFontAndSize(baseFont, textSize); for (float x = 70f; x < pageSize.getWidth(); x += textHeight + spacing) { for (float y = 90f; y < pageSize.getHeight(); y += textHeight + spacing) { patternPainter.showTextAlignedKerned(Element.ALIGN_MIDDLE, watermarkText, x, y, 45f); } } patternPainter.endText(); patternPainter.restoreState(); // 应用混合模式,让水印与正文融合而非覆盖 PdfGState contentState = new PdfGState(); contentState.setBlendMode(PdfGState.BM_MULTIPLY); content.saveState(); content.setGState(contentState); // 一次性将Pattern填充到整个页面 content.setColorFill(new PatternColor(patternPainter)); content.rectangle(pageSize.getLeft(), pageSize.getBottom(), pageSize.getWidth(), pageSize.getHeight()); content.fill(); content.restoreState(); } stamper.close(); reader.close(); byteArray = baos.toByteArray(); File outputFile = new File(resourcesPath + "output.pdf"); if (outputFile.exists()) { outputFile.delete(); } Files.write(outputFile.toPath(), byteArray); System.out.println("########## FINISHED ADDING WATERMARK ###########"); } catch (Exception e) { e.printStackTrace(); } } }
关键修改说明
- 移除重复填充:将水印文本绘制逻辑移到Pattern内部,仅一次性填充整个页面的Pattern,避免多次叠加导致水印过深。
- 透明度绑定到Pattern:直接在PatternPainter上设置透明度,确保水印整体淡度一致,不会因叠加失控。
- 使用混合模式:通过
BM_MULTIPLY混合模式让水印与正文颜色融合,而非直接覆盖,大幅降低对正文可读性的影响。 - 优化颜色与尺寸:改用浅灰色水印,调整文本尺寸和间距,平衡可见性与阅读体验。
内容的提问来源于stack exchange,提问作者Mahmoud Saleh
相关产品推荐
相关产品推荐

