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

