java - 通过页面搜索已使用的资源并将其删除

标签 java pdfbox

我使用this technique将 acroform 从另一个源 pdf 导出到新的 pdf 文件。

结果 pdf 与 acroform 只有你可以 download here

我使用pdfcompressor在线网站来压缩这个pdf(59Ko),并将其缩小-64%。 这个网站似乎清理了资源中所有未使用的东西,这是 PDFDebugger 的屏幕截图

screenshot from PDFDebugger

我的问题是,如果不从资源[]中删除它,如何从资源[]中获取xobject或字体并检查它们是否在页面中的某个位置使用。

如果在PDPa​​ge中搜索某些资源是否被使用或未使用很复杂,我如何简单地从Resources[]中删除XObject或Font?

虽然在页面中搜索使用过的 xobject 超出了我的范围,但我只是尝试直接删除 COSObject,但它不起作用 ^^ :

        for (PDPage page : document.getPages()) {

            PDResources resources = page.getResources();

            // all xobject form resources
            for (COSName name : resources.getXObjectNames()) {
                page.getCOSObject().removeItem(name); // NOT WORKS
            }

            // all font resources from pages
            for (COSName name : resources.getFontNames()) {
                if (resources.getFont(name) instanceof PDFont) {
                    page.getCOSObject().removeItem(name); // NOT WORKS
                }

            }
        }

ps:@mkl推荐后创建的问题discussed here

更新1

这是我必须从 pdf 中提取 acroform 的当前代码: //从原始创建 FORM

PDDocument documentSrc = PDDocument.load(new File("original.pdf"));;
PDAcroForm acroFormSrc = documentSrc.getDocumentCatalog().getAcroForm();

PDDocument documentDest = new PDDocument();
for (PDPage page : documentSrc.getPages()) {
    PDPage destPage  = new PDPage(PDRectangle.A4);
    destPage.setMediaBox(page.getMediaBox());
    destPage.setCropBox(page.getCropBox());
    documentDest.addPage(destPage);
}

PDAcroForm acroFormDest = new PDAcroForm(documentDest);


acroFormDest.setCacheFields(true);
acroFormDest.setFields(acroFormSrc.getFields());
documentDest.getDocumentCatalog().setAcroForm(acroFormDest);

int pageIndex = 0;
for (PDPage page : documentSrc.getPages()) {
    documentDest.getPage(pageIndex).setAnnotations(page.getAnnotations());
    // after disabling this size increase
    //documentDest.getPage(pageIndex).setResources(page.getResources());
    pageIndex++;
}

acroFormDest.setDefaultAppearance(acroFormSrc.getDefaultAppearance());
acroFormDest.setDefaultResources(acroFormSrc.getDefaultResources());
acroFormDest.setQ(acroFormSrc.getQ());

// this is disabled because setResources is disabled above
//removeLinksInPages(documentDest);
//removeTextInDocument(documentDest);

此结果:pdf without resources

这次 form-without-resources 是 73Ko,而我原来的 pdf 是 75Ko。

最佳答案

减少页面对象的资源

嗯,我认为您当前的任务比您在问题中要求的要简单得多。我解读你的意思

I use this technique to export acroform to new pdf file from another source pdf.

暗示您实际上只想将 AcroForm 字段和功能从一个 PDF 转移到另一个 PDF,并且对原始文件的静态页面内容不感兴趣。

因此,您实际使用哪些页面资源这个问题的答案很简单:!页面资源是您不感兴趣的静态内容(页面内容流中)中使用的资源。

因此,无需首先将页面资源复制到新文档中,只需删除该行即可

documentDest.getPage(pageIndex).setResources(page.getResources());

来自引用答案中的代码。

<小时/>

顺便说一句:@Tilman 已经在对您用作模板的答案的评论中指出,感兴趣的资源是“acroform 的默认资源”,而不是页面资源。因此,您可能不仅想在 PDAcroForm 实例之间复制字段:

acroFormDest.setFields(acroFormSrc.getFields());

还有默认资源、默认外观和默认四边形

acroFormDest.setDefaultAppearance(acroFormSrc.getDefaultAppearance());
acroFormDest.setDefaultResources(acroFormSrc.getDefaultResources());
acroFormDest.setQ(acroFormSrc.getQ());

其他问题

引用错误页面的注释

This time form-without-resources is 73Ko while my original pdf is 75Ko.

深入研究一下“form-without-resources.pdf”,问题就变得清晰起来:

screen shot

如您所见,您的字段小部件注释指向错误的页面!

P 值指定为

P dictionary (Optional except as noted below; PDF 1.3; not used in FDF files) An indirect reference to the page object with which this annotation is associated.

(ISO 32000-1, Table 164 – Entries common to all annotation dictionaries)

因此,您将目标页面的注释设置为源页面的注释,但这些注释的 P 值仍然引用源页面。因此,您可以通过此引用将源页面及其所有资源拖到新文档中。因此,结果文件并不比源文件小一点也不奇怪。

如果您更改代码以更正P引用,例如像这样:

int pageIndex = 0;
for (PDPage page : documentSrc.getPages()) {
    PDPage destPage = documentDest.getPage(pageIndex);
    destPage.setAnnotations(page.getAnnotations());
    for (PDAnnotation annotation : destPage.getAnnotations())
        annotation.setPage(destPage);
    // after disabling this size increase
    //documentDest.getPage(pageIndex).setResources(page.getResources());
    pageIndex++;
}

( CopyForm 测试 testCopyLikeBeeImproved)

您将丢失对旧数据的这些引用。

关于java - 通过页面搜索已使用的资源并将其删除,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55416144/

相关文章:

java - 如何使用 Servlet 从 POST 请求获取 JSON 数据

java - Firebase突然报告无效签名

java - 如何将两个列表中的每个元素连接到一个新列表?

java - 为什么有时在 Java 中不需要声明 "new"对象?

java - PDFBOX内存不足

java - 在java中使用pdfbox将文本覆盖到以前创建的pdf文档上

私有(private)方法上的 Javax 验证不会被触发

pdf - 如何在不消耗内存的情况下进行流式 PDF 合并?

java - PDFBox 提取的文本不包含国际(非英语)字符

javafx-2 - 在 JavaFx 2.2 中截取场景或场景的一部分