如何借助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
相关产品推荐
相关产品推荐

