【PDFBox】-读取文件

基本的读取

1. 添加依赖

确保在你的项目中添加PDFBox的依赖。如果你使用Maven,可以在pom.xml中添加以下依赖:

<dependency>
    <groupId>org.apache.pdfbox</groupId>
    <artifactId>pdfbox</artifactId>
    <version>3.0.3</version>
</dependency>

2. 读取PDF文件

使用PDDocument类加载PDF文件,获取文字和图片。

3. 完整代码示例

import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDResources;
import org.apache.pdfbox.pdmodel.common.PDRectangle;
import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject;
import org.apache.pdfbox.text.PDFTextStripper;
import org.apache.pdfbox.text.TextPosition;

import java.awt.geom.Rectangle2D;
import java.io.File;
import java.io.IOException;
import java.util.List;
import java.util.Map;

public class PDFParser {

    public static void main(String[] args) {
        if (args.length != 1) {
            System.err.println("Usage: java PDFParser <path-to-pdf-file>");
            System.exit(1);
        }

        String pdfFilePath = args[0];

        try (PDDocument document = PDDocument.load(new File(pdfFilePath))) {
            // 提取文本及其坐标
            extractTextWithPositions(document);

            // 提取图片及其坐标
            extractImagesWithPositions(document);
        } catch (IOException e) {
            System.err.println("Error reading PDF file: " + e.getMessage());
            e.printStackTrace();
        }
    }

    private static void extractTextWithPositions(PDDocument document) throws IOException {
        PDFTextStripper stripper = new PDFTextStripper() {
            @Override
            protected void writeString(String string, List<TextPosition> textPositions) throws IOException {
                for (TextPosition text : textPositions) {
                    System.out.println("Text: " + text.getUnicode() +
                            ", X: " + text.getXDirAdj() +
                            ", Y: " + text.getYDirAdj() +
                            ", Font Size: " + text.getFontSizeInPt());
                }
            }
        };

        stripper.setSortByPosition(true);
        stripper.setStartPage(0);
        stripper.setEndPage(document.getNumberOfPages());
        stripper.writeText(document, System.out);
    }

    private static void extractImagesWithPositions(PDDocument document) throws IOException {
        for (PDPage page : document.getPages()) {
            PDResources resources = page.getResources();
            for (COSName name : resources.getXObjectNames()) {
                if (resources.isImageXObject(name)) {
                    PDImageXObject image = (PDImageXObject) resources.getXObject(name);
                    Rectangle2D position = getImagePosition(page, name, resources);
                    System.out.println("Image: " + name.getName() +
                            ", Width: " + image.getWidth() +
                            ", Height: " + image.getHeight() +
                            ", X: " + position.getX() +
                            ", Y: " + position.getY());
                }
            }
        }
    }

    private static Rectangle2D getImagePosition(PDPage page, COSName name, PDResources resources) throws IOException {
        PDRectangle mediaBox = page.getMediaBox();
        double pageWidth = mediaBox.getWidth();
        double pageHeight = mediaBox.getHeight();

        List<PDRectangle> positions = page.findImagePositions(name, resources);
        if (positions.isEmpty()) {
            throw new IOException("Image not found on the page.");
        }

        PDRectangle position = positions.get(0); // Assuming the first occurrence is the correct one
        return new Rectangle2D.Double(position.getLowerLeftX(), pageHeight - position.getUpperRightY(),
                position.getWidth(), position.getHeight());
    }
}

如果想自定义一些操作,比如读取的结果要解析坐标,根据坐标进行一些判断,最终形成结构化的数据,怎么做呢?

定制化的读取

1. 说明

PDFBox 提供了丰富的API来处理PDF文档中的文本、图像、表格、链接等元素。下面是一个详细的示例,来看看怎么做。

2. 创建PDF解析器

创建一个PDF解析器类,继承自PDFStreamEngine,重写processOperator方法以处理不同的PDF操作符。

import org.apache.pdfbox.contentstream.operator.Operator;
import org.apache.pdfbox.contentstream.operator.state.SetLineWidth;
import org.apache.pdfbox.cos.COSBase;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.common.PDRectangle;
import org.apache.pdfbox.pdmodel.font.PDFont;
import org.apache.pdfbox.pdmodel.font.PDType1Font;
import org.apache.pdfbox.pdmodel.graphics.color.PDColor;
import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject;
import org.apache.pdfbox.pdmodel.graphics.state.PDExtendedGraphicsState;
import org.apache.pdfbox.text.PDFTextStripper;

import java.io.IOException;
import java.util.List;

public class CustomPDFParser extends PDFStreamEngine {

    public CustomPDFParser() throws IOException {
        super();
        addOperator(new SetLineWidth());
        // 添加其他需要处理的操作符
    }

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

        switch (operation) {
            case "Tj": // 处理文本
                handleText(arguments);
                break;
            case "Do": // 处理图像
                handleImage(arguments);
                break;
            case "re": // 处理矩形
                handleRectangle(arguments);
                break;
            case "BDC": // 处理标记内容
                handleMarkedContentBegin(arguments);
                break;
            case "EMC": // 处理标记内容结束
                handleMarkedContentEnd();
                break;
            case "Tf": // 处理字体设置
                handleFontSetting(arguments);
                break;
            case "rg": // 处理填充颜色
                handleFillColor(arguments);
                break;
            case "RG": // 处理描边颜色
                handleStrokeColor(arguments);
                break;
            default:
                super.processOperator(operator, arguments);
                break;
        }
    }

    private void handleText(List<COSBase> arguments) throws IOException {
        String text = ((COSString) arguments.get(0)).getString();
        System.out.println("Text: " + text);
    }

    private void handleImage(List<COSBase> arguments) throws IOException {
        PDImageXObject image = (PDImageXObject) getResources().getXObject((COSName) arguments.get(0));
        System.out.println("Image: " + image.getHeight() + "x" + image.getWidth());
    }

    private void handleRectangle(List<COSBase> arguments) throws IOException {
        float x = arguments.get(0).toFloat();
        float y = arguments.get(1).toFloat();
        float width = arguments.get(2).toFloat();
        float height = arguments.get(3).toFloat();
        System.out.println("Rectangle: " + x + ", " + y + ", " + width + ", " + height);
    }

    private void handleMarkedContentBegin(List<COSBase> arguments) throws IOException {
        String tag = ((COSName) arguments.get(0)).getName();
        System.out.println("Marked Content Begin: " + tag);
    }

    private void handleMarkedContentEnd() throws IOException {
        System.out.println("Marked Content End");
    }

    private void handleFontSetting(List<COSBase> arguments) throws IOException {
        PDFont font = (PDType1Font) getResources().getFont((COSName) arguments.get(0));
        float size = arguments.get(1).toFloat();
        System.out.println("Font Setting: " + font.getFontName() + ", " + size);
    }

    private void handleFillColor(List<COSBase> arguments) throws IOException {
        float r = arguments.get(0).toFloat();
        float g = arguments.get(1).toFloat();
        float b = arguments.get(2).toFloat();
        System.out.println("Fill Color: " + r + ", " + g + ", " + b);
    }

    private void handleStrokeColor(List<COSBase> arguments) throws IOException {
        float r = arguments.get(0).toFloat();
        float g = arguments.get(1).toFloat();
        float b = arguments.get(2).toFloat();
        System.out.println("Stroke Color: " + r + ", " + g + ", " + b);
    }
}

3. 解析PDF文件

创建一个测试类来解析PDF文件并调用自定义的解析器。

import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;

import java.io.File;
import java.io.IOException;

public class Main {
    public static void main(String[] args) {
        try (PDDocument document = PDDocument.load(new File("path/to/your/pdf/file.pdf"))) {
            CustomPDFParser parser = new CustomPDFParser();
            for (PDPage page : document.getPages()) {
                parser.processPage(page);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

4.特定元素的定制化读取

比如,我们只需要处理的是文本,上面的方法其实偏底层一点,我们是判断了操作符号来处理各个元素的,其实PDFBox还有更高级一点的方法,提供了更友好的API和更丰富的功能。
PDFTextStripper 类,专门用于提取PDF文档中的文本内容。如果你需要对文本进行更复杂的处理,可以继承 PDFTextStripper 并重写其方法。

以下是一个示例

1. 创建自定义的 PDFTextStripper
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.text.PDFTextStripper;
import org.apache.pdfbox.text.TextPosition;

import java.io.IOException;

public class CustomPDFTextStripper extends PDFTextStripper {

    public CustomPDFTextStripper() throws IOException {
        super();
    }

    @Override
    protected void writeString(String string, List<TextPosition> textPositions) throws IOException {
        // 处理每个字符的位置和属性
        for (TextPosition text : textPositions) {
            System.out.println("Character: " + text.getCharacter());
            System.out.println("X: " + text.getXDirAdj());
            System.out.println("Y: " + text.getYDirAdj());
            System.out.println("Font: " + text.getFont().getFontDescriptor().getFontName());
            System.out.println("Size: " + text.getFontSizeInPt());
            System.out.println("Color: " + text.getColor());
            System.out.println("-------------------");
        }
    }

    @Override
    protected void writePageSeparator() throws IOException {
        // 处理页面分隔符
        System.out.println("\n------------------- Page Separator -------------------\n");
    }

    @Override
    protected void startPage(PDPage page) throws IOException {
        // 处理页面开始
        System.out.println("Starting page: " + page.getPageNumber());
    }

    @Override
    protected void endPage(PDPage page) throws IOException {
        // 处理页面结束
        System.out.println("Ending page: " + page.getPageNumber());
    }
}
2. 使用自定义的 PDFTextStripper 解析PDF文件
import org.apache.pdfbox.pdmodel.PDDocument;

import java.io.File;
import java.io.IOException;

public class Main {
    public static void main(String[] args) {
        try (PDDocument document = PDDocument.load(new File("path/to/your/pdf/file.pdf"))) {
            CustomPDFTextStripper stripper = new CustomPDFTextStripper();
            stripper.setSortByPosition(true); // 按位置排序文本
            stripper.setStartPage(1); // 设置起始页
            stripper.setEndPage(document.getNumberOfPages()); // 设置结束页
            stripper.getText(document); // 提取文本
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
3. 解释
  • writeString: 重写此方法可以处理每个字符的位置和属性。textPositions 列表包含了当前字符串中每个字符的位置信息。
  • writePageSeparator: 重写此方法可以在每页之间插入分隔符。
  • startPage: 重写此方法可以在每页开始时执行某些操作。
  • endPage: 重写此方法可以在每页结束时执行某些操作。

其他元素的读取也有相应的处理类,可以继承并重写,我们后续一一介绍。有问题欢迎关注公众号交流。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

前鼻音太阳熊

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值