7

有没有办法在不读取文件内容的情况下检测 PDF 是否包含 3D 元素(嵌入的通用 3D 对象)?可以从元数据中获取这些信息吗?

4

3 回答 3

6

AFAIK,没有要求将任何信息放入其元数据中,说明文档中可能包含 3D 元素。

不过,一些 U3D 编写软件可能会XML元数据中添加一些提示。

长答案

您必须至少部分解析 PDF 页面树才能找到答案。

从技术上讲,3D 元素是作为注释实现的。要发现任何注释,您必须遵循以下解析路径:

  1. 阅读预告片。它告诉您/Root文档的间接对象的对象编号。

  2. 阅读交叉引用表。它告诉您文档中每个间接对象的字节偏移量。

  3. 转到/Root间接对象。读它的/Pages钥匙。这告诉您哪个间接对象代表文档页面树的根。

  4. 转到表示 的间接对象/Pages。读它的/Kids钥匙。这会告诉您哪些其他间接对象代表文档页面。

  5. 转到表示文档页面的每个间接对象。查找任何(可选)/Annots密钥。如果存在,它将指向表示(可能是各种)注释的其他间接对象。

现在您已经知道 PDF 是否包含注释。如果没有,请停在这里。如果是,请继续确定注释类型:

  1. 转到上一步中找到的所有间接对象。它们属于/Type /Annot. 看看它们是否还属于/Subtype /3D. 如果是,您已找到 3D 注释。(注意,这可能还不是 U3D 的!)

  2. 在最后找到的间接对象(带有/Subtype /3D键的对象)中,查找 的附加键/3DD。它指向包含实际 3D 流的间接对象。

  3. 转到包含 3D 流的间接对象。它的对象字典应该再次包含一个 key:value 对/Type /3D。看它的/Subtype钥匙。如果它说/U3D你找到了你要找的东西......

简答

你可能会很幸运,通过使用这样的好老来收获一些低垂的果实grep

$> grep -a U3D cc-7-july09.pdf

  /Subtype /U3D
  /MS /U3D
  /U3DPath [ <135BB3D42FBD85F7C2E178> <056D9A891FB5FDCE8E> ]
  /MS /U3D
  /U3DPath [ <5FFAF35CE3CBD34FAE5360> <4DDFD6048FC6DA05> ]
  /MS /U3D
  /U3DPath [ <2E4E4FD7FEC771038BC5EA> <2A6579CC91BE0B> ]
  /MS /U3D
  /U3DPath [ <6F303AF9850721D5D1FC6C> <7D1B08BEAE4A5A9BEDBB> ]
  /MS /U3D
  /U3DPath [ <F270A04603F0DE08B8AA29> <EE5180016FFBD542> ]
  /MS /U3D
  /U3DPath [ <A1D5848F6841ADA9A3583C> <A3F8A5D45849D392EF> ]
  /MS /U3D
  /U3DPath [ <34B8650D178BBDFF61DC03> <2D8F4C7D3CD980F976> ]
  /MS /U3D
  /U3DPath [ <843CD0339FD1852CCA235B> <9719FB65A990897F> ]

但是,这不适用于所有 3D PDF 文档,尤其是当 3D 元素是对象流的一部分时。

于 2015-08-17T22:05:45.053 回答
0

对于足以知道 PDF 是否包含任何3D 内容(包括但不限于通用 3D 对象)的情况,您还可以在特征提取模式下使用VeraPDF软件。按照以下步骤获取所有注释类型(包括 3D 注释)的列表。

首先编辑 VerapDF 的“features.xml”配置文件,如下所述:

https://docs.verapdf.org/cli/config/#features.xml

确保它<feature>ANNOTATION</feature>包含在enabledFeatures元素中。

这个文件为例,运行:

verapdf --off --extract action_goto3dview.ar10.pdf > action_goto3dview.ar10.xml

在输出中,检查 "annotations" 元素,它列出了文件中存在的所有注释,并查找具有 subType "3D" 的注释(表示 3D 注释):

<annotation id="annotIndir186">
<subType>3D</subType>
<rectangle lly="129.348" llx="163.939" urx="437.813" ury="331.861"></rectangle>
<width>273.874</width>
<height>202.513</height>
<contents>3D Model</contents>
<annotationName>3D3</annotationName>
<resources>
    <xobject id="xobjIndir187"></xobject>
</resources>
<invisible>false</invisible>
<hidden>false</hidden>
<print>true</print>
<noZoom>false</noZoom>
<noRotate>false</noRotate>
<noView>false</noView>
<readOnly>true</readOnly>
<locked>false</locked>
<toggleNoView>false</toggleNoView>
<lockedContents>false</lockedContents>
</annotation>

这对应于上面@kurt-pfeifle 答案中的第 1 步。由于 VeraPDF 没有深入到识别 U3D 流所需的级别,对于需要该级别详细信息的情况,我建议 @kurt-pfeifle 回答。

于 2022-01-20T17:54:24.037 回答
0

对于与我们有同样问题的任何人,这是我们使用“iText”提出的一种方法(免费版本仍然可用)。

缺点是您需要遍历文件的每个页面以检查内容,但对我们来说仍然足够快。

        PdfReader reader = new PdfReader(contents);
        int pages = reader.getNumberOfPages();
        boolean pdf3D = false;
        for (int i = 1; i <= pages; i++) {
            PdfDictionary page = reader.getPageN(i);
            PdfArray array = page.getAsArray(PdfName.ANNOTS);
            if (array == null) {
                continue;
            }
            for (ListIterator<PdfObject> iter = array.listIterator(); iter.hasNext();) {
                PdfDictionary annot = (PdfDictionary) PdfReader.getPdfObject(iter.next());
                PdfObject pdfObject = annot.get(PdfName.SUBTYPE);
                if (pdfObject != null) {
                    if (PdfName._3D.equals(pdfObject) || PdfName.GOTO3DVIEW.equals(pdfObject)) {
                        pdf3D = true;
                        break;
                    }
                }
            }
            if (pdf3D) {
                // if we already any of 3D element, we can break the loop
                break;
            }
        }
于 2016-03-04T10:41:09.333 回答