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

时间:2015-08-17 01:08:06

标签: pdf 3d 2d u3d

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

2 个答案:

答案 0 :(得分:5)

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

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

长答案

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

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

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

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

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

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

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

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

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

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

    3. 转到包含3D流的间接对象。它的对象字典应该再次包含一个/Type /3D的键值对。查看其/Subtype密钥。如果它说/U3D你找到了你想要的东西......

    4. 简答

      你可能很幸运,通过使用这样的好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元素是对象流的一部分。

答案 1 :(得分: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;
            }
        }