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

如何使用Java从PDF文件中移除图片?现有实现代码运行报错求解决

你要实现的功能是移除PDF中所有的图片资源,报错的核心原因是处理Do操作符时未校验前置参数是否存在,以及资源字典处理逻辑有问题,以下是修正后的可运行代码:

import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDResources;
import org.apache.pdfbox.pdmodel.graphics.PDXObject;
import org.apache.pdfbox.contentstream.PDFStreamParser;
import org.apache.pdfbox.contentstream.operator.Operator;
import org.apache.pdfbox.cos.*;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;

public class TEST04 {
    public static void main(String[] args) throws IOException {
        System.out.println("Hi");
        //原始PDF路径
        String oriPDFFile = IFileUtils.getDesktopPath().getAbsoluteFile() + "\\1.pdf";
        //输出PDF路径
        String outPDFFile = IFileUtils.getDesktopPath().getAbsoluteFile() + "\\2.pdf";
        strip(oriPDFFile, outPDFFile);
    }

    //移除PDF图片
    public static void strip(String pdfFile, String pdfFileOut) throws IOException {
        try (PDDocument document = PDDocument.load(new File(pdfFile))) {
            List<PDPage> pageList = IterUtil.toList(document.getDocumentCatalog().getPages());
            for (PDPage page : pageList) {
                //仅复制资源字典,不要复制整个页的COS对象
                COSDictionary resDict = new COSDictionary(page.getResources().getCOSObject());
                PDFStreamParser parser = new PDFStreamParser(page);
                List<?> tokens = parser.getTokens();
                List<Object> newTokens = new ArrayList<>();

                for (int j = 0; j < tokens.size(); j++) {
                    Object token = tokens.get(j);
                    if (token instanceof Operator) {
                        Operator operator = (Operator) token;
                        //Do操作符对应绘制XObject(包括图片)
                        if ("Do".equals(operator.getName())) {
                            //校验前一个元素是否存在且为COSName,避免索引越界
                            if (!newTokens.isEmpty() && newTokens.get(newTokens.size() - 1) instanceof COSName) {
                                COSName cosName = (COSName) newTokens.remove(newTokens.size() - 1);
                                //确认是图片类型的XObject再删除,避免误删其他资源
                                PDXObject xObject = page.getResources().getXObject(cosName);
                                if (xObject != null && "Image".equals(xObject.getCOSObject().getNameAsString(COSName.SUBTYPE))) {
                                    deleteObject(resDict, cosName);
                                    continue;
                                } else {
                                    //不是图片就把参数加回去,保留其他XObject
                                    newTokens.add(cosName);
                                }
                            }
                        }
                    }
                    newTokens.add(token);
                }
                //重写页内容流
                PDStream newContents = new PDStream(document);
                try (OutputStream outputStream = newContents.createOutputStream()) {
                    ContentStreamWriter writer = new ContentStreamWriter(outputStream);
                    writer.writeTokens(newTokens);
                }
                page.setContents(newContents);
                page.setResources(new PDResources(resDict));
            }
            document.save(pdfFileOut);
        }
    }

    //递归删除指定名称的资源
    public static boolean deleteObject(COSDictionary d, COSName name) {
        for(COSName key : d.keySet()) {
            if(name.equals(key)) {
                d.removeItem(key);
                return true;
            }
            COSBase object = d.getDictionaryObject(key);
            if(object instanceof COSDictionary) {
                if(deleteObject((COSDictionary)object, name)) {
                    return true;
                }
            }
        }
        return false;
    }
}

核心修改点

  • 新增Do操作符前的参数合法性校验,避免索引越界异常
  • 仅复制页的资源字典而非整个页的COS对象,避免页属性丢失导致的PDF损坏
  • 增加XObject类型校验,仅删除图片类资源,保留表单、矢量图等其他XObject资源
  • 用try-with-resources管理PDDocument生命周期,避免资源泄漏

错误日志

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.05 06:27:02