【问题标题】:How can I extract images and their metadata from PDFs?如何从 PDF 中提取图像及其元数据?
【发布时间】:2011-08-04 23:02:00
【问题描述】:

是否可以使用 Java 从 PDF 文件中提取图像并将其导出到特定文件夹而不会丢失其原始创建和修改日期?我试图通过使用 IText 和 PDFBox 来实现这个目标,但没有成功。欢迎任何想法或示例。

【问题讨论】:

    标签: java pdf itext pdfbox


    【解决方案1】:

    图像不包含元数据,并存储为需要组装成图像的原始数据。我在https://blog.idrsolutions.com/2010/04/understanding-the-pdf-file-format-how-are-images-stored/https://blog.idrsolutions.com/2010/09/understanding-the-pdf-file-format-images/ 写了 2 篇博文解释图像数据如何存储在 PDF 文件中

    【讨论】:

    • 我没有读过你的博客,但我不同意。图像的 XMP 元数据存储在 PDF 中,可以再次读取。我在高度生产环境中使用这种方法,并且效果很好。
    • 您可以在 PDF 中存储元数据,但图像中的元数据会丢失。许多存档系统使用 JPEG 中的元标记,除非 PDF 创建工具特别包含它,否则这些元标记会丢失。
    • 链接已失效。
    【解决方案2】:

    使用 SonwTide API 从 PDF 文件中获取元数据。使用 PDFTextStream.jar 最后它将返回所有 PDF 属性并在命令行上打印。

    public static void getPDFMetaData(String pdfFilePath) throws IOException{
    
                // input pdf file with location Add PDFTextStream.jar from snowtide web site to your code build path
                PDFTextStream stream = new PDFTextStream(pdfFilePath);
    
                // get collection of all document attribute names
                Set attributeKeys = stream.getAttributeKeys();
    
                // print the values of all document attributes to System.out
                Iterator iter = attributeKeys.iterator();
                String attrKey;
                while (iter.hasNext()) {
                    attrKey = (String)iter.next();
                    System.out.println(attrKey + " = " + stream.getAttribute(attrKey));
    
                }
    
    
    }
    

    【讨论】:

      【解决方案3】:

      我不同意其他人的观点,并为您的问题提供 POC:您可以通过以下方式使用 pdfbox 提取图像的 XMP 元数据:

      public void getXMPInformation() {
          // Open PDF document
          PDDocument document = null;
          try {
              document = PDDocument.load(PATH_TO_YOUR_DOCUMENT);
          } catch (IOException e) {
              e.printStackTrace();
          }
          // Get all pages and loop through them
          List pages = document.getDocumentCatalog().getAllPages();
          Iterator iter = pages.iterator();
          while( iter.hasNext() ) {
              PDPage page = (PDPage)iter.next();
              PDResources resources = page.getResources();            
              Map images = null;
              // Get all Images on page
              try {
                  images = resources.getImages();
              } catch (IOException e) {
                  e.printStackTrace();
              }
              if( images != null ) {
                  // Check all images for metadata
                  Iterator imageIter = images.keySet().iterator();
                  while( imageIter.hasNext() ) {
                      String key = (String)imageIter.next();
                      PDXObjectImage image = (PDXObjectImage)images.get( key );
                      PDMetadata metadata = image.getMetadata();
                      System.out.println("Found a image: Analyzing for Metadata");
                      if (metadata == null) {
                          System.out.println("No Metadata found for this image.");
                      } else {
                          InputStream xmlInputStream = null;
                          try {
                              xmlInputStream = metadata.createInputStream();
                          } catch (IOException e) {
                              e.printStackTrace();
                          }
                          try {
                              System.out.println("--------------------------------------------------------------------------------");
                              String mystring = convertStreamToString(xmlInputStream);
                              System.out.println(mystring);
                          } catch (IOException e) {
                              e.printStackTrace();
                          }
                      }
                      // Export the images
                      String name = getUniqueFileName( key, image.getSuffix() );
                          System.out.println( "Writing image:" + name );
                          try {
                              image.write2file( name );
                          } catch (IOException e) {
                              // TODO Auto-generated catch block
                              //e.printStackTrace();
                      }
                      System.out.println("--------------------------------------------------------------------------------");
                  }
              }
          }
      }
      

      还有“辅助方法”:

      public String convertStreamToString(InputStream is) throws IOException {
          /*
           * To convert the InputStream to String we use the BufferedReader.readLine()
           * method. We iterate until the BufferedReader return null which means
           * there's no more data to read. Each line will appended to a StringBuilder
           * and returned as String.
           */
          if (is != null) {
              StringBuilder sb = new StringBuilder();
              String line;
      
              try {
                  BufferedReader reader = new BufferedReader(new InputStreamReader(is, "UTF-8"));
                  while ((line = reader.readLine()) != null) {
                      sb.append(line).append("\n");
                  }
              } finally {
                  is.close();
              }
              return sb.toString();
          } else {       
              return "";
          }
      }
      
      private String getUniqueFileName( String prefix, String suffix ) {
          /*
          * imagecounter is a global variable that counts from 0 to the number of
          * extracted images
          */
          String uniqueName = null;
          File f = null;
          while( f == null || f.exists() ) {
              uniqueName = prefix + "-" + imageCounter;
              f = new File( uniqueName + "." + suffix );
          }
          imageCounter++;
          return uniqueName;
      }
      

      注意:这是一个快速而肮脏的概念证明,而不是一个风格良好的代码。

      在构建 PDF 文档之前,在 InDesign 中放置图像时必须具有 XMP 元数据。例如,可以使用 Photoshop 设置 XMP-Metdadata。请注意,p.e.并非所有 IPTC/Exif/... 信息都被转换为 XMP 元数据。只转换了少量字段。

      我在 JPG 和 PNG 图像上使用此方法,这些图像放置在使用 InDesign 构建的 PDF 中。它运行良好,我可以在制作步骤后从准备好的 PDF(图片涂层)中获取所有图像信息。

      【讨论】:

        【解决方案4】:

        简答

        也许,但也许不是。

        长答案

        PDF 原生支持 JPEG、JPEG2000(越来越普遍)、CITT(传真)3 和 4 以及 JBIG2(非常少见)。这些格式的图像可以逐字节复制到 PDF 中,并保留文件中的任何元数据。创建/更改日期通常是文件系统的一部分,而不是图像。

        JPEG:看起来它不支持内部元数据。

        JPEG2000:是的。里面可能有很多东西

        CITT:看起来不像。

        JBIG2:Err.. 我认为是这样,但从我刚刚略读的规格中无法明确。

        所有其他图像格式必须转换为像素,然后以某种方式压缩(通常使用 Flate/ZIP)。这些转换可以将元数据保留为 PDF 的 xml 元数据或图像字典的一部分,但我什至从未听说过这种情况。它只是被推销了。

        【讨论】:

          【解决方案5】:

          图像嵌入到 PDF 中时,一般不会保存原始创建和修改日期。只是原始像素数据被压缩和保存。但是,according to Wikipedia

          PDF 中的光栅图像(称为 Image XObjects)由具有关联流的字典表示。

          字典包含元数据,您可以在其中找到日期。

          【讨论】:

          • 但可能不会……看我的回答。
          猜你喜欢
          • 2019-08-07
          • 2019-08-30
          • 2013-01-09
          • 2013-05-14
          • 2011-01-29
          • 1970-01-01
          • 2013-08-12
          相关资源
          最近更新 更多