当前位置: 首页 > 知识库问答 >
问题:

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

慕容嘉荣
2023-03-14

我使用这种技术从另一个源pdf导出acroform到新的pdf文件。

结果pdf with acroform只有您可以在此处下载

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

我的问题是如何从Resources[]中获取xject或字体,并检查它们是否在页面的某个地方使用,如果不从Resources[]中删除它的话。

如果使用或不使用某些资源时在PDPage中搜索很复杂,如何从资源[]中删除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
                }

            }
        }

备注:此处讨论了在@mkl建议后创建的问题

以下是我必须从pdf://create FORM from original中提取acroform的当前代码

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无资源

这个没有资源的时间表单是73Ko,而我的原始pdf是75Ko。

共有1个答案

齐锐进
2023-03-14

嗯,我认为你现在的任务比你在问题中要求的要简单得多。我解释你的

我使用这种技术从另一个源pdf导出acroform到新的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());

这个没有资源的时间表单是73Ko,而我的原始pdf是75Ko。

深入查看“没有资源的表单.pdf”,问题变得很清楚:

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

该P值指定为

P dictionary(可选,除非下面另有说明;PDF 1.3;不在FDF文件中使用)对与此批注关联的页面对象的间接引用。

(ISO 32000-1,表164——所有注释词典通用的条目)

因此,您将目标页面的注释设置为源页面的注释,但其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测试已验证)

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

 类似资料:
  • 问题内容: 我正在应用程序中构建搜索,并且需要一种将从服务器中以JSON数组形式获取的建议放入快速搜索框下方显示的建议列表中的方法。 有没有一种简单的方法可以使快速搜索框读取此类资源? 当前,我正在尝试使用ContentProvider,但是接口方法清楚地表明应该在查询数据库以获取建议。我想如果您要搜索存储在应用程序内部的数据,则使用ContentProvider是正确的方法。但是我不确定,如果您

  • 我有一个艰难的时间与dexGuard使它不删除我访问这种方式的资源: int resourceId=getResources()。getIdentifier(“图片”、“数组”、getActivity()。getPackageName()); 当我执行应用程序时,会出现以下异常: JAVAlang.RuntimeException:无法启动android活动。所容纳之物res.Resources$

  • 正如标题所说,我目前正试图找到BST的最大节点,我想删除它。我有方法来查找最大节点和删除节点准备从我的算法书,但我不知道如何在主方法中使用它们。我有一个方法,可以通过输入一个数字插入节点,例如8,这将打印一个级别有序的树:4, 2, 6, 1, 3, 5, 7其中4是根。我希望能够找到最后一个节点并删除它。到目前为止,我有这些方法: 我的主要方法是这样的: 我希望能够自由插入任何节点,并且树仍然能

  • 我需要实现一个在我看来更适合SOAP而不是RESTful服务的搜索,因此我正在努力将其表达为RESTendpoint。 公司(companyId) 合同(Contractd,companyId,privilegeGroupId) PrivilegeGroup(privilegeGroupId,privilegeId) 特权(privilegeId) 主键以粗体显示。 FindPrivilegesB

  • 问题内容: 在哪里可以找到有关WDS的文档,特别是使用C#中的SQL查询来查询WDS?是否有任何资源列出可以从SystemIndex查询的列?另外,我希望查询返回“上下文”,即就像WDS客户端从找到搜索词的文档中的几行开始一样。尽管我相信3+的API是相同的,但我正在使用WDS 4.0。我检查了MSDN和其他站点,但是没有运气。 问题答案: 在MSDN论坛上发布并得到答案:可以搜索的列或属性:ht

  • 问题内容: 我有一个会话变量,其中包含带有值的深层json对象: 例如,我想找到带有“ Piranha the Fish”的行,然后将其删除(并再次对其进行json_encode)。这该怎么做?我想我需要在结果数组中搜索并找到要删除的父键,但是我还是被卡住了。 问题答案: 会将JSON对象转换为由嵌套数组组成的PHP结构。然后,您只需要遍历它们和不需要的一个即可。