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

使用Apache PDFBox Overlay添加PDF水印,Acrobat无法识别该水印怎么办

问题原因

你用Overlay类实现的是页面内容平铺叠加,只是把水印PDF的内容合并到原始PDF的页面内容中,并没有生成Acrobat能识别的结构化水印对象。Acrobat的水印属于PDF标准中的**可选内容组(OCG)**结构,这类结构支持单独编辑、隐藏或删除操作,而简单的内容叠加无法被识别为这类结构化元素。

解决方案:生成Acrobat可识别的水印

要让Acrobat能识别并编辑水印,需要通过PDFBox创建关联到OCG的水印内容,以下是具体实现代码:

import org.apache.pdfbox.pdmodel.*;
import org.apache.pdfbox.pdmodel.common.PDRectangle;
import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject;
import org.apache.pdfbox.pdmodel.graphics.optionalcontent.PDOptionalContentGroup;
import org.apache.pdfbox.pdmodel.graphics.optionalcontent.PDOptionalContentProperties;
import org.apache.pdfbox.pdmodel.PDPageContentStream;

import java.io.File;
import java.io.IOException;

public class AddAcrobatRecognizableWatermark {
    public static void main(String[] args) throws IOException {
        // 加载原始PDF文档
        try (PDDocument originalDoc = PDDocument.load(new File("original.pdf"))) {
            // 加载水印PDF(假设为单页,内容为图像水印)
            try (PDDocument watermarkDoc = PDDocument.load(new File("watermark.pdf"))) {
                PDPage watermarkPage = watermarkDoc.getPage(0);
                PDImageXObject watermarkImage = null;

                // 从水印页面提取图像资源
                for (COSName name : watermarkPage.getResources().getXObjectNames()) {
                    if (watermarkPage.getResources().getXObject(name) instanceof PDImageXObject) {
                        watermarkImage = (PDImageXObject) watermarkPage.getResources().getXObject(name);
                        break;
                    }
                }

                if (watermarkImage == null) {
                    throw new IOException("水印PDF中未找到图像资源");
                }

                // 创建可选内容组(OCG)——Acrobat识别水印的核心
                PDOptionalContentProperties ocProps = originalDoc.getDocumentCatalog().getOCProperties();
                if (ocProps == null) {
                    ocProps = new PDOptionalContentProperties();
                    originalDoc.getDocumentCatalog().setOCProperties(ocProps);
                }
                PDOptionalContentGroup watermarkOCG = new PDOptionalContentGroup("Watermark");
                ocProps.addGroup(watermarkOCG);

                // 遍历原始PDF的每一页添加水印
                for (PDPage page : originalDoc.getPages()) {
                    PDRectangle pageSize = page.getMediaBox();
                    float pageWidth = pageSize.getWidth();
                    float pageHeight = pageSize.getHeight();
                    float imgWidth = watermarkImage.getWidth();
                    float imgHeight = watermarkImage.getHeight();

                    // 计算水印居中位置
                    float xPos = (pageWidth - imgWidth) / 2;
                    float yPos = (pageHeight - imgHeight) / 2;

                    // 向页面追加内容流,关联OCG
                    try (PDPageContentStream contentStream = new PDPageContentStream(
                            originalDoc, page, PDPageContentStream.AppendMode.APPEND, true, true)) {
                        // 标记内容属于水印OCG
                        contentStream.beginMarkedContent(COSName.OC, watermarkOCG);
                        // 绘制水印图像
                        contentStream.drawImage(watermarkImage, xPos, yPos, imgWidth, imgHeight);
                        contentStream.endMarkedContent();
                    }
                }

                // 保存最终文档
                originalDoc.save("watermarked_compatible.pdf");
            }
        }
    }
}
关键说明
  • 可选内容组(OCG):这是让Acrobat识别水印的核心,生成的水印会被归类到Acrobat的可选内容列表中,你可以通过「工具>编辑PDF>水印」菜单直接编辑或删除,也能在「导航窗格>内容」中控制水印的显示/隐藏。
  • 如果你的水印PDF包含的是文本或矢量图形而非图像,需要提取水印页面的内容流并复制到原始页面的OCG标记中,核心逻辑和上述代码一致,仅需替换图像绘制部分为内容流复制操作。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 13:07:54