PDFBox 2.x页面图片重定位问题:移除后添加无显示求助
解决PDFBox 2.x移除页面图片后重新添加不显示的问题
我帮你排查了代码里的几个关键问题,这些问题直接导致了页面图片不显示的情况:
问题分析
1. 内容流处理逻辑错误
你在stripUnusedImages里处理token时,只移除了图片的COSName,但留下了对应的Do指令(PDF里绘制图片的完整指令是[图片名称] Do),这会让内容流出现语法错误,PDF阅读器会直接忽略整个错误的内容流,包括你后续追加的新图片绘制代码。
2. 资源处理混乱
你调用了未实现的copyResources方法,而且在importPage后直接复用原页面的资源,没有正确清理掉被移除的图片资源,这会导致资源引用异常。
3. 图片移除逻辑不符合预期
你当前只移除带有metadata的图片,如果你要移除所有现有图片,这个判断条件完全不符合需求。
修正后的代码
下面是调整后的完整代码,我修复了上述所有问题:
import org.apache.pdfbox.cos.COSName; import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.pdmodel.PDPage; import org.apache.pdfbox.pdmodel.PDPageContentStream; import org.apache.pdfbox.pdmodel.PDResources; import org.apache.pdfbox.pdmodel.common.PDStream; import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject; import org.apache.pdfbox.pdmodel.graphics.xobject.PDXObject; import org.apache.pdfbox.contentstream.ContentStreamWriter; import org.apache.pdfbox.contentstream.PDFStreamParser; import java.io.File; import java.io.IOException; import java.io.OutputStream; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; public class PdfImageRelocate { public static void main(String[] args) { try { PDDocument document = PDDocument.load(new File("..\\sampleWithImage_with_barcode_img.pdf")); PDDocument newDocument = new PDDocument(); for (int i = 0; i < document.getNumberOfPages(); i++) { PDPage sourcePage = document.getPage(i); // 导入页面到新文档 PDPage pdPage = newDocument.importPage(sourcePage); // 移除页面所有现有图片 stripAllImages(pdPage, newDocument); // 添加新图片 PDImageXObject pdImage = PDImageXObject.createFromFile("D:\\copy\\pic.jpg", newDocument); // 追加新内容到页面 PDPageContentStream contents = new PDPageContentStream(newDocument, pdPage, PDPageContentStream.AppendMode.APPEND, true); // 绘制图片到指定位置 contents.drawImage(pdImage, 0, 0, 50, 30); System.out.println("Image inserted Successfully."); contents.close(); } newDocument.save("..\\RemovedImage.pdf"); document.close(); newDocument.close(); } catch (Exception e) { e.printStackTrace(); } } // 移除页面所有现有图片的方法 protected static void stripAllImages(PDPage page, PDDocument document) throws IOException { PDResources resources = page.getResources(); PDFStreamParser parser = new PDFStreamParser(page); parser.parse(); List<Object> tokens = parser.getTokens(); List<Object> newTokens = new ArrayList<>(); // 记录需要保留的非图片XObject名称 Set<COSName> retainedXObjects = new HashSet<>(); for (int j = 0; j < tokens.size(); j++) { Object token = tokens.get(j); // 检查是否是图片绘制指令对:[COSName] Do if (token instanceof COSName && j + 1 < tokens.size() && "Do".equals(tokens.get(j + 1))) { COSName cosName = (COSName) token; PDXObject xObject = resources.getXObject(cosName); if (xObject instanceof PDImageXObject) { // 跳过图片名称和对应的Do指令 j++; continue; } else { // 保留非图片的XObject retainedXObjects.add(cosName); newTokens.add(token); } } else { newTokens.add(token); } } // 重新构建资源,只保留非图片资源 PDResources newResources = new PDResources(); // 复制字体、颜色空间等必要资源 newResources.setFonts(resources.getFonts()); newResources.setExtGState(resources.getExtGState()); newResources.setColorSpaces(resources.getColorSpaces()); // 添加需要保留的非图片XObject for (COSName name : retainedXObjects) { newResources.put(name, resources.getXObject(name)); } page.setResources(newResources); // 生成合法的新内容流 PDStream newContents = new PDStream(document); try (OutputStream outputStream = newContents.createOutputStream()) { ContentStreamWriter writer = new ContentStreamWriter(outputStream); writer.writeTokens(newTokens); } newContents.addCompression(); page.setContents(newContents); } }
关键修正点说明
- 正确处理内容流:现在会完整跳过图片绘制的
[图片名称] Do指令对,不会留下语法错误的内容流,确保PDF阅读器能正常解析。 - 清理资源:创建新的资源对象,只保留字体、颜色空间等非图片资源,彻底移除图片资源的引用。
- 移除所有图片:调整逻辑为移除页面中所有的
PDImageXObject,完全符合你“移除现有图片”的需求。 - 确保内容合法:替换后的内容流完全合法,后续追加的新图片绘制指令能被正确识别和显示。
内容的提问来源于stack exchange,提问作者Ronak
相关产品推荐
相关产品推荐

