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

如何借助PDFContentStreamEditor调整XObjects内的运算符与操作数?

编辑PDF XObject内容:扩展PDFContentStreamEditor的解决方案

我使用PDFContentStreamEditor类可以正常操作PDF主页面内容的运算符与操作数,但发现该编辑器默认无法处理XObjects。请问有没有可行的示例代码,用来调整XObjects中的运算符与操作数?

我已经尝试过两种方法,但都没达到预期效果:

  • 遍历页面资源中的XObjects:
PDResources pdResources = page.getResources();
pdResources.getXObjectNames().forEach(propertyName -> {
    PDXObject xObject = pdResources.getXObject(propertyName);
    if(xObject instanceof PDFormXObject pdformxobject) {
        // 不确定此处如何执行编辑操作
    }
});
  • 重写PDFContentStreamEditor的processTransparencyGroup方法:
    我原本以为这能接近解决方案,但实际只能在XObject内添加Contents元素,无法修改根对象的运算符与操作数:
@Override
protected void processTransparencyGroup(PDTransparencyGroup group){
    PDStream stream = new PDStream(document, group.getContents());
    replacementForm = new ContentStreamWriter(replacementFormStream = stream.createOutputStream(COSName.FLATE_DECODE));
    super.processTransparencyGroup(group);
    replacementFormStream.close();

    group.getCOSObject().setItem(COSName.CONTENTS, stream);
    replacementForm = null;
    replacementFormStream = null;
}

解决方案:递归处理Form XObject内容流

要让PDFContentStreamEditor能够处理XObjects,核心思路是递归遍历并处理所有Form XObject的内容流,将编辑器的逻辑从主页面扩展到嵌套的XObject上。以下是一个完整的可行实现:

自定义扩展编辑器

import org.apache.pdfbox.cos.COSBase;
import org.apache.pdfbox.cos.COSName;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDResources;
import org.apache.pdfbox.pdmodel.common.PDStream;
import org.apache.pdfbox.pdmodel.graphics.form.PDFormXObject;
import org.apache.pdfbox.contentstream.ContentStreamWriter;
import org.apache.pdfbox.contentstream.operator.Operator;

import java.io.IOException;
import java.io.OutputStream;
import java.util.List;

public class ExtendedContentStreamEditor extends PDFContentStreamEditor {
    public ExtendedContentStreamEditor(PDDocument document) {
        super(document);
    }

    @Override
    protected void processPage(PDPage page) throws IOException {
        // 先处理主页面内容
        super.processPage(page);
        // 遍历页面资源中的XObject并处理
        processXObjects(page.getResources());
    }

    private void processXObjects(PDResources resources) throws IOException {
        if (resources == null) return;
        
        for (COSName name : resources.getXObjectNames()) {
            PDXObject xObject = resources.getXObject(name);
            if (xObject instanceof PDFormXObject formXObject) {
                // 处理当前Form XObject的内容流
                processFormXObject(formXObject);
                // 递归处理Form XObject自身的资源(嵌套XObject)
                processXObjects(formXObject.getResources());
            }
        }
    }

    private void processFormXObject(PDFormXObject formXObject) throws IOException {
        PDStream originalStream = formXObject.getContentStream();
        if (originalStream == null) return;
        
        PDStream newStream = new PDStream(getDocument());
        try (OutputStream os = newStream.createOutputStream(COSName.FLATE_DECODE)) {
            ContentStreamWriter writer = new ContentStreamWriter(os);
            setContentStreamWriter(writer);
            // 复用编辑器的运算符解析逻辑处理原始流
            processOperatorStream(originalStream.createInputStream());
        } finally {
            setContentStreamWriter(null);
        }
        
        // 替换Form XObject的内容流
        formXObject.setContentStream(newStream);
    }

    // 重写此方法实现具体的编辑逻辑
    @Override
    protected void processOperator(Operator operator, List<COSBase> operands) throws IOException {
        // 示例:修改文本显示指令、调整图形路径或过滤特定运算符
        // 比如:if ("Tj".equals(operator.getName())) { ... 修改文本内容 ... }
        super.processOperator(operator, operands);
    }
}

使用示例

import org.apache.pdfbox.pdmodel.PDDocument;

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

public class EditXObjectDemo {
    public static void main(String[] args) {
        try (PDDocument document = PDDocument.load(new File("input.pdf"))) {
            ExtendedContentStreamEditor editor = new ExtendedContentStreamEditor(document);
            for (PDPage page : document.getPages()) {
                editor.processPage(page);
            }
            document.save(new File("output.pdf"));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

关键说明

  • 该实现会递归处理页面及其所有嵌套层级的Form XObject,确保所有内容都能被编辑
  • 通过调用processOperatorStream方法,复用了PDFContentStreamEditor的运算符解析与处理逻辑
  • 你只需要在processOperator方法中编写具体的编辑规则(比如修改操作数、替换运算符、过滤特定指令等)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 21:46:24