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

如何使用iText或PdfBox扁平化PDF中的图章注释?

问题与解决方案

问题详情

现有一份添加了图章注释的PDF文档,目前仅能扁平化其中的AcroForm表单域,但图章注释无法被扁平化。在Mac的Preview应用中打开仅扁平化表单域后的PDF时,仍可移动、删除图章注释,需要实现表单域与图章注释的同时扁平化,以限制此类编辑操作。

添加图章的现有代码如下:

PdfReader reader1 = new PdfReader(file);
ByteArrayOutputStream mos = new ByteArrayOutputStream();
PdfDocument docc = new PdfDocument(reader1, new PdfWriter(mos),new StampingProperties().useAppendMode());
String filePath = "rectangle.png";
ImageData img = ImageDataFactory.create(filePath);
Rectangle rect=null;
float w = img.getWidth();
float h = img.getHeight();
rect = new Rectangle(0,0,250,400);
PdfFormXObject xObj = new PdfFormXObject(new Rectangle(w,h));
PdfCanvas canvas = new PdfCanvas(xObj, docc);
canvas.addImageAt(img,0,0,false);
PdfStampAnnotation stamp = new PdfStampAnnotation(rect);
stamp.setNormalAppearance(xObj.getPdfObject());
docc.getPage(1).addAnnotation(stamp);

docc.close();

file = new File("Annotation Added.pdf");
FileOutputStream fout1 = new FileOutputStream(file);
fout1.write(mos.toByteArray());
fout1.close();

解决方案

要同时扁平化表单域和图章注释,需注意以下几点:

  • 移除useAppendMode()追加模式,该模式会保留原有注释结构,不利于扁平化操作;
  • 先处理表单域扁平化,再遍历页面注释,将注释的外观绘制到页面内容流后移除注释。

完整实现代码如下:

import com.itextpdf.kernel.pdf.*;
import com.itextpdf.kernel.pdf.annot.PdfAnnotation;
import com.itextpdf.kernel.pdf.annot.PdfStampAnnotation;
import com.itextpdf.kernel.pdf.xobject.PdfFormXObject;
import com.itextpdf.io.image.ImageDataFactory;
import com.itextpdf.kernel.geom.Rectangle;
import com.itextpdf.kernel.pdf.canvas.PdfCanvas;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.util.List;

public class FlattenPdf {
    public static void main(String[] args) throws Exception {
        File inputFile = new File("input.pdf"); // 替换为你的输入PDF路径
        File outputFile = new File("Flattened_Output.pdf");

        PdfReader reader = new PdfReader(inputFile);
        ByteArrayOutputStream mos = new ByteArrayOutputStream();
        // 不使用追加模式,使用正常 stamper 模式
        PdfDocument doc = new PdfDocument(reader, new PdfWriter(mos));

        // 1. 扁平化表单域
        PdfAcroForm acroForm = PdfAcroForm.getAcroForm(doc, true);
        if (acroForm != null) {
            acroForm.flattenFields();
        }

        // 2. 扁平化图章注释
        int pageCount = doc.getNumberOfPages();
        for (int i = 1; i <= pageCount; i++) {
            PdfPage page = doc.getPage(i);
            List<PdfAnnotation> annotations = page.getAnnotations();
            // 倒序遍历,避免移除元素时索引混乱
            for (int j = annotations.size() - 1; j >= 0; j--) {
                PdfAnnotation annot = annotations.get(j);
                if (annot instanceof PdfStampAnnotation) {
                    PdfStampAnnotation stampAnnot = (PdfStampAnnotation) annot;
                    PdfDictionary normalAppearance = stampAnnot.getNormalAppearance();
                    if (normalAppearance != null) {
                        PdfFormXObject xObj = PdfFormXObject.makeXObject(normalAppearance, doc);
                        Rectangle annotRect = stampAnnot.getRectangle().toRectangle();
                        // 获取页面内容画布,在现有内容上方绘制注释外观
                        PdfCanvas canvas = new PdfCanvas(page.newContentStreamBefore(), page.getResources(), doc);
                        canvas.addXObject(xObj, annotRect.getX(), annotRect.getY());
                    }
                    // 移除注释
                    page.removeAnnotation(annot);
                }
            }
        }

        doc.close();

        // 写入输出文件
        FileOutputStream fout = new FileOutputStream(outputFile);
        fout.write(mos.toByteArray());
        fout.close();
    }
}

关键说明

  • 倒序遍历页面注释列表,避免移除元素时导致的索引越界问题;
  • 使用page.newContentStreamBefore()获取内容画布,确保注释外观绘制在页面原有内容之上;
  • 先处理表单扁平化,再处理注释扁平化,保证所有可编辑元素都被固化到页面内容中。

内容的提问来源于stack exchange,提问作者Akhil NagaSai

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.29 11:57:54