java - 如何从 PDF 文件中删除图像?
问题描述
您好,感谢您回答我的问题。这个问题困扰了我很长时间。
这个QS我搜了很久,在stack overFlow和google上看了很多文章,但是那些文章已经过时或者碎片化了,所以我不得不寻求帮助。我希望有人可以帮助我,拜托。
public class TEST04 {
public static void main(String[] args) throws IOException {
System.out.println("Hi");
//ori pdf file
String oriPDFFile = IFileUtils.getDesktopPath().getAbsoluteFile() + "\\1.pdf";
//out pdf file
String outPDFFile = IFileUtils.getDesktopPath().getAbsoluteFile() + "\\2.pdf";
strip(oriPDFFile, outPDFFile);
}
//parse
public static void strip(String pdfFile, String pdfFileOut) throws IOException {
//load ori pdf file
PDDocument document = PDDocument.load(new File(pdfFile));
//get All pages
List<PDPage> pageList = IterUtil.toList(document.getDocumentCatalog().getPages());
for (int i = 0; i < pageList.size(); i++) {
PDPage page = pageList.get(i);
COSDictionary newDictionary = new COSDictionary(page.getCOSObject());
PDFStreamParser parser = new PDFStreamParser(page);
List tokens = parser.getTokens();
List newTokens = new ArrayList();
for (int j = 0; j < tokens.size(); j++) {
Object token = tokens.get(j);
if (token instanceof Operator) {
Operator operator = (Operator) token;
if (operator.getName().equals("Do")) {
COSName cosName = (COSName) newTokens.remove(newTokens.size() - 1);
deleteObject(newDictionary, cosName);
continue;
}
}
newTokens.add(token);
}
PDStream newContents = new PDStream(document);
try (OutputStream outputStream = newContents.createOutputStream()) {
ContentStreamWriter writer = new ContentStreamWriter(outputStream);
writer.writeTokens(newTokens);
}
page.setContents(newContents);
// ContentStreamWriter writer = new ContentStreamWriter(newContents.createOutputStream());
// writer.writeTokens( newTokens );
// page.setContents(newContents);
PDResources newResources = new PDResources(newDictionary);
page.setResources(newResources);
}
document.save(pdfFileOut);
document.close();
}
//delete
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;
}
}
解决方案
按照Ali Yavari 回答中的提示,您创建了一个测试类。不幸的是,测试代码产生了异常。这个答案的重点是修复你的代码。
根据您发布的堆栈跟踪,保存文档时发生异常的图像;一些流被要求提供一个InputStream
并且它失败并显示消息“当有一个打开的流写入器时无法读取”。
因此,让我们看看您的代码在哪里打开了流编写器,但没有再次关闭它:
PDStream newContents = new PDStream(document);
ContentStreamWriter writer = new ContentStreamWriter(newContents.createOutputStream());
writer.writeTokens( newTokens );
page.setContents(newContents);
实际上,在这里您要求流 (the PDStream newContents
) 向 ( newContents.createOutputStream()
) 写入某些内容,但不要关闭它。
你可以这样做:
PDStream newContents = new PDStream(document);
try (OutputStream outputStream = newContents.createOutputStream()) {
ContentStreamWriter writer = new ContentStreamWriter(outputStream);
writer.writeTokens(newTokens);
}
page.setContents(newContents);
附带说明,您将不得不重新编写您对newDictionary
对象所做的操作。目前你
- 用页面字典条目初始化它,
- 递归地删除所有条目,其键是您删除的图像的名称,并且
- 将页面资源设置为此字典。
第 2 项可以删除的内容比您实际想要的要多得多,不同字典中的相同名称可能指的是具有完全不同含义的条目。此外,您无需进一步检查即可递归;如果字典之间存在循环关系,这可能会导致无限递归,即堆栈溢出异常。
第 3 项不恰当地将这个被操纵的页面克隆设置为原始页面的资源。这会创建一个完全损坏的页面结构。
相反,您应该从页面 ( resources = page.getResources()
) 中检索资源,然后通过将图像放入null
( resources.put(cosName, (PDXObject)null)
) 来删除它们。
推荐阅读
- visual-studio-code - 为什么我的 node_modules 文件夹在命令“npm install”后显示为灰色?
- c# - 如何使用 C# 替换请求 url 中的参数?
- java - ZipEntry 中的额外字节用于什么?
- dart - 如何将 json_annotation 与 Dart 扩展 ListBase 类一起使用
- insert - 通过 Dafny 实现堆插入(带规范)
- python - 如何使用 PonyORM 动态创建实体?
- flutter - Flutter - 如何在 TabBarView 的主体内导航?
- android - 如何创建可访问的 PrivateKeys?
- julia - Julia函数将秒转换为小时、分钟、秒的问题
- javascript - Next.js Router.push 没有设置任何 req.headers