如何从PDF中提取图像及其元数据?

时间:2011-04-13 18:30:15

标签: java pdf itext pdfbox

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

5 个答案:

答案 0 :(得分:6)

图像不包含元数据,并作为原始数据存储,需要将其组合成图像。我写了2篇博客文章,解释了图像数据如何存储在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/

的PDF文件中

答案 1 :(得分:4)

我不同意其他人并为您的问题提供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(图片涂层)的生产步骤之后获得所有图像信息。

答案 2 :(得分:1)

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

  

PDF格式的光栅图像(称为图像XObjects)由带有关联流的字典表示。

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

答案 3 :(得分:1)

简答

可能,但可能不是。

长答案

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

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

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

CITT:看起来不那样。

JBIG2:错误......我所以,但是我没有从我刚刚浏览过的规格中清除。

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

答案 4 :(得分:0)

使用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));

            }


}