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

iText5中不可移除水印透明度不足遮挡内容,如何解决?

解决iText5中水印遮挡文本及透明度问题的方案

针对你遇到的水印遮挡正文、透明度异常问题,可通过调整代码中的绘制逻辑、层级控制和透明度设置来解决,同时保留水印不可移除的特性。以下是具体修改方案:

核心问题分析

  1. 重复填充导致水印过深:原代码在嵌套循环内多次填充整个页面的Pattern,叠加后水印颜色变深,遮挡正文。
  2. 透明度设置位置错误:将透明度应用在页面内容层而非Pattern本身,导致叠加效果失控。
  3. 文本高度计算错误:原代码用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();
        }
    }
}

关键修改说明

  1. 移除重复填充:将水印文本绘制逻辑移到Pattern内部,仅一次性填充整个页面的Pattern,避免多次叠加导致水印过深。
  2. 透明度绑定到Pattern:直接在PatternPainter上设置透明度,确保水印整体淡度一致,不会因叠加失控。
  3. 使用混合模式:通过BM_MULTIPLY混合模式让水印与正文颜色融合,而非直接覆盖,大幅降低对正文可读性的影响。
  4. 优化颜色与尺寸:改用浅灰色水印,调整文本尺寸和间距,平衡可见性与阅读体验。

内容的提问来源于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.28 08:31:10