使用 pdfbox 从 pdf 中提取图像

Posted

技术标签:

【中文标题】使用 pdfbox 从 pdf 中提取图像【英文标题】:extract images from pdf using pdfbox 【发布时间】:2012-02-01 01:45:39 【问题描述】:

我正在尝试。示例pdfhere

但我只得到空白图像。

我正在尝试的代码:-

public static void main(String[] args) 
   PDFImageExtract obj = new PDFImageExtract();
    try 
        obj.read_pdf();
     catch (IOException ex) 
        System.out.println("" + ex);
    



 void read_pdf() throws IOException 
    PDDocument document = null; 
    try 
        document = PDDocument.load("C:\\Users\\Pradyut\\Documents\\MCS-034.pdf");
     catch (IOException ex) 
        System.out.println("" + ex);
    
    List pages = document.getDocumentCatalog().getAllPages();
    Iterator iter = pages.iterator(); 
    int i =1;
    String name = null;

    while (iter.hasNext()) 
        PDPage page = (PDPage) iter.next();
        PDResources resources = page.getResources();
        Map pageImages = resources.getImages();
        if (pageImages != null)  
            Iterator imageIter = pageImages.keySet().iterator();
            while (imageIter.hasNext()) 
                String key = (String) imageIter.next();
                PDXObjectImage image = (PDXObjectImage) pageImages.get(key);
                image.write2file("C:\\Users\\Pradyut\\Documents\\image" + i);
                i ++;
            
        
    


谢谢

【问题讨论】:

PDF 由 JBIG2 编码的图像组成。我不确定 pdfBox 是否支持这些。 我可以在这个应用程序中使用库 jbig2-imageio:code.google.com/p/jbig2-imageio/wiki/Usage 吗?将其作为库 jar 或类路径添加到应用程序吗? 我在测试您的代码时遇到了问题:“UnsupportedOper” 你找到了如何解码 JBIG2 图像的答案吗? @PradyutBhattacharya 您是否找到了如何使用jbig2-imageio 解码 JBIG2 图像的解决方案?谢谢 【参考方案1】:

只需将.jpeg 添加到路径的末尾即可:

image.write2file("C:\\Users\\Pradyut\\Documents\\image" + i + ".jpeg");

这对我有用。

【讨论】:

【参考方案2】:

您可以使用PDPage.convertToImage() 函数将PDF 页面转换为BufferedImage。接下来可以使用 BufferedImage 创建一个 Image。

使用以下参考资料了解更多详情:

PDFBox 中的所有 PDF 相关类都可以进入 Apache PDFBox 1.8.3 API Here可以查看PDPage相关文档。

并且不要忘记在 PDPage 类中查找PDPage.convertToImage() 函数。

【讨论】:

【参考方案3】:

而不是调用

image.write2file("C:\\Users\\Pradyut\\Documents\\image" + i);

您可以使用ImageIO.write() 静态方法以您需要的任何格式写入 RGB 图像。这里我使用了 PNG:

File outputFile = new File( "C:\\Users\\Pradyut\\Documents\\image" + i + ".png");
ImageIO.write( image.getRGBImage(), "png", outputFile);

【讨论】:

【参考方案4】:

下面的GetImagesFromPDF java 类获取04-Request-Headers.pdf 文件中的所有图像并将这些文件保存到目标文件夹PDFCopy

import java.io.File;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDResources;
import org.apache.pdfbox.pdmodel.graphics.xobject.PDXObjectImage;

@SuppressWarnings( "unchecked", "rawtypes", "deprecation" )
public class GetImagesFromPDF 
    public static void main(String[] args) 
        try 
            String sourceDir = "C:/PDFCopy/04-Request-Headers.pdf";// Paste pdf files in PDFCopy folder to read
            String destinationDir = "C:/PDFCopy/";
            File oldFile = new File(sourceDir);
            if (oldFile.exists()) 
            PDDocument document = PDDocument.load(sourceDir);

            List<PDPage> list = document.getDocumentCatalog().getAllPages();

            String fileName = oldFile.getName().replace(".pdf", "_cover");
            int totalImages = 1;
            for (PDPage page : list) 
                PDResources pdResources = page.getResources();

                Map pageImages = pdResources.getImages();
                if (pageImages != null) 

                    Iterator imageIter = pageImages.keySet().iterator();
                    while (imageIter.hasNext()) 
                        String key = (String) imageIter.next();
                        PDXObjectImage pdxObjectImage = (PDXObjectImage) pageImages.get(key);
                        pdxObjectImage.write2file(destinationDir + fileName+ "_" + totalImages);
                        totalImages++;
                    
                
            
         else 
            System.err.println("File not exists");
        
     catch (Exception e) 
        e.printStackTrace();
    

【讨论】:

有没有办法对此进行排序或确保它是连续完成的? @Ian 你想按顺序获取图像吗? @COBRA.cH 告诉我你正在尝试哪个版本? 我没有找到表达式 pdResources.getImages();使用 pdfbox 2.0.25【参考方案5】:

对于 PDFBox 2.0.1,pudaykiran 的回答必须稍作修改,因为某些 API 已更改。

public static void testPDFBoxExtractImages() throws Exception 
    PDDocument document = PDDocument.load(new File("D:/Temp/Test.pdf"));
    PDPageTree list = document.getPages();
    for (PDPage page : list) 
        PDResources pdResources = page.getResources();
        for (COSName c : pdResources.getXObjectNames()) 
            PDXObject o = pdResources.getXObject(c);
            if (o instanceof org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject) 
                File file = new File("D:/Temp/" + System.nanoTime() + ".png");
                ImageIO.write(((org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject)o).getImage(), "png", file);
            
        
    

【讨论】:

太棒了!为我工作。但在我的 cese 中添加了 jai-imageio-jpeg2000 依赖项来转换 jpeg2000 图像。【参考方案6】:

这是使用 PDFBox 2.0.1 的代码,它将从 PDF 中获取所有图像的列表。这与其他代码的不同之处在于它将递归遍历文档,而不是尝试从顶层获取图像。

public List<RenderedImage> getImagesFromPDF(PDDocument document) throws IOException 
        List<RenderedImage> images = new ArrayList<>();
    for (PDPage page : document.getPages()) 
        images.addAll(getImagesFromResources(page.getResources()));
    

    return images;


private List<RenderedImage> getImagesFromResources(PDResources resources) throws IOException 
    List<RenderedImage> images = new ArrayList<>();

    for (COSName xObjectName : resources.getXObjectNames()) 
        PDXObject xObject = resources.getXObject(xObjectName);

        if (xObject instanceof PDFormXObject) 
            images.addAll(getImagesFromResources(((PDFormXObject) xObject).getResources()));
         else if (xObject instanceof PDImageXObject) 
            images.add(((PDImageXObject) xObject).getImage());
        
    

    return images;

【讨论】:

这应该被标记为正确答案。这在 Java11 和 PDFBox 2.0.12 上对我有用 @Matt 您只考虑xObjectPDFormXObjectPDImageXObject 的情况。但根据the Javadoc,它也可能是PDPostScriptXObjectPDPostScriptXObject 不能还包含更多图像吗?【参考方案7】:

这是@Matt 答案的 kotlin 版本。

fun <R> PDResources.onImageResources(block: (RenderedImage) -> (R)): List<R> =
        this.xObjectNames.flatMap 
            when (val xObject = this.getXObject(it)) 
                is PDFormXObject -> xObject.resources.onImageResources(block)
                is PDImageXObject -> listOf(block(xObject.image))
                else -> emptyList()
            
        

您可以像这样在 PDPage 资源上使用它:

page.resources.onImageResources  image ->
    Files.createTempFile("image", "xxx").also  path-> 
        if(!ImageIO.write(it, "xxx", file.toFile()))
            IllegalStateException("Couldn't write image to file")
    

"xxx" 是您需要的格式(如 "jpeg"

【讨论】:

【参考方案8】:

对于只想复制并粘贴此代码的人

import org.apache.pdfbox.contentstream.PDFStreamEngine;
import org.apache.pdfbox.contentstream.operator.Operator;
import org.apache.pdfbox.cos.COSBase;
import org.apache.pdfbox.cos.COSName;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.graphics.PDXObject;
import org.apache.pdfbox.pdmodel.graphics.form.PDFormXObject;
import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.List;
import java.util.UUID;

public class ExtractImagesUseCase extends PDFStreamEngine
    private final String filePath;
    private final String outputDir;

    // Constructor
    public ExtractImagesUseCase(String filePath,
                                String outputDir)
        this.filePath = filePath;
        this.outputDir = outputDir;
    

    // Execute
    public void execute()
        try
            File file = new File(filePath);
            PDDocument document = PDDocument.load(file);

            for(PDPage page : document.getPages())
                processPage(page);
            

        catch(IOException e)
            e.printStackTrace();
        
    

    @Override
    protected void processOperator(Operator operator, List<COSBase> operands) throws IOException
        String operation = operator.getName();

        if("Do".equals(operation))
            COSName objectName = (COSName) operands.get(0);
            PDXObject pdxObject = getResources().getXObject(objectName);

            if(pdxObject instanceof PDImageXObject)
                // Image
                PDImageXObject image = (PDImageXObject) pdxObject;
                BufferedImage bImage = image.getImage();

                // File
                String randomName = UUID.randomUUID().toString();
                File outputFile = new File(outputDir,randomName + ".png");

                // Write image to file
                ImageIO.write(bImage, "PNG", outputFile);

            else if(pdxObject instanceof PDFormXObject)
                PDFormXObject form = (PDFormXObject) pdxObject;
                showForm(form);
            
        

        else super.processOperator(operator, operands);
    

演示

public class ExtractImageDemo
    public static void main(String[] args)
        String filePath = "C:\\Users\\John\\Downloads\\Documents\\sample-file.pdf";
        String outputDir = "C:\\Users\\John\\Downloads\\Documents\\Output";

        ExtractImagesUseCase useCase = new ExtractImagesUseCase(
                filePath,
                outputDir
        );
        useCase.execute();
    

【讨论】:

以上是关于使用 pdfbox 从 pdf 中提取图像的主要内容,如果未能解决你的问题,请参考以下文章

Java 使用PDFBox提取PDF文件中的图片

PDFBox如何提取超链接信息

如何提取PDFBox的超链接信息

Delphi提取PDF文本

从pdf文件中提取特定数据

如何从Java中提取PDF文件中的表格数据