检测PDF文件是否包含3D元素

7

是否有办法检测PDF文档中是否包含3D元素(嵌入的通用3D对象),而不需要读取文件内容?这些信息能否从元数据中获取?


2
阅读该文件会受到多大的惩罚? - Tim Biegeleisen
罚款并不大,因为一旦在阅读过程中发现了PDF中的U3D内容(http://stackoverflow.com/questions/24731195/how-to-check-pdf-is-3d-or-normal-in-java),你就可以跳出流。只是我们希望尽可能避免这种情况,因为我们有特定的查看器用于特定的文件格式。 - Wai Yan
你是真的在寻找包含作为对象的3D元素的PDF文件,就像链接答案中所描述的吗?还是你在寻找那些实际上在某些页面上被使用和展示的PDF文件中的这种元素? - mkl
你是想在文件中显示U3D内容,还是只需要快速检查文件是否包含U3D元素? - iPDFdev
我只需要进行快速检查,因为我已经有一个第三方查看器来处理显示。 - Wai Yan
3个回答

6
据我所知,并不需要将任何信息放入元数据中,以说明文档可能包含3D元素。
尽管如此,一些U3D编写软件可能会在XML元数据中提供一些提示。
长篇回答:
您必须至少部分解析PDF页树才能找出。
从技术上讲,3D元素是作为注释实现的。要发现任何注释,您必须遵循以下解析路径:
1. 读取概览。它告诉您文档的/Root间接对象的对象编号。 2. 读取交叉引用表。它告诉您文档中每个间接对象的字节偏移量。 3. 转到表示文档页面树根的间接对象。读取其/Pages键。这告诉您哪个间接对象代表文档页面的根。 4. 转到代表/Pages的间接对象。读取其/Kids键。这告诉您其他间接对象代表文档页面。 5. 转到代表文档页面的每个间接对象。寻找所有(可选)/Annots键。如果存在,则指向表示(可能各种各样的)注释的其他间接对象。
现在,您已经发现PDF是否包含注释。如果没有,请在此处停止。如果是,则继续确定注释类型:
1. 转到上一步中找到的所有间接对象。它们是/Type /Annot的。看看它们是否还是/Subtype /3D的。如果是,则找到了3D注释。(注意,这仍然可能不是U3D!) 2. 在最后找到的间接对象(带有/Subtype /3D键)内搜索额外的/3DD键。它指向包含实际3D流的间接对象。 3. 转到包含3D流的间接对象。其对象字典应再次包含一对键值对/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元素是对象流的一部分时。


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;
            }
        }

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”元素,它列出了文件中存在的所有注释,并查找子类型为“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的答案。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接