You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用Java/NodeJS提取带OCR文本层PDF的文本数据

带OCR隐形文本层PDF的文本提取方案

核心失败原因

  • OCR生成的文本层默认是不可见渲染状态:通常是字号1px、透明度0、垫在扫描位图下方的文本,绝大多数PDF解析库的默认配置会主动过滤这类「不显示在页面上」的文本
  • 部分OCR工具会把文本层放在独立的可选内容组(也就是PDF图层)里,默认解析逻辑会跳过标记为隐藏的图层内容
  • Apache Tika的默认PDF解析配置开启了重叠文本过滤、隐藏内容跳过规则,刚好命中OCR文本层的特征,所以提取不到内容是配置问题,不是文件没有文本层

Java 实现方案

不要用默认配置的Tika,直接基于PDFBox做解析,配置自由度更高,稳定版选2.0.x分支即可,不要用3.0的beta版。
先引入Maven依赖:

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

提取代码:

import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.text.PDFTextStripper;
import java.io.File;
import java.io.IOException;

public class OcrPdfTextExtractor {
    public static String extractText(String pdfPath) throws IOException {
        try (PDDocument document = PDDocument.load(new File(pdfPath))) {
            PDFTextStripper stripper = new PDFTextStripper();
            // 以下三个配置是提取OCR层的核心
            stripper.setSortByPosition(true); // 按页面排版顺序还原文本
            stripper.setSuppressDuplicateOverlappingText(false); // 关闭重叠文本过滤,不要把OCR层当重复内容删掉
            stripper.setAddMoreFormatting(true);
            return stripper.getText(document);
        }
    }

    public static void main(String[] args) throws IOException {
        String text = extractText("target_file.pdf");
        System.out.println(text);
    }
}

如果必须用Tika,需要手动覆写PDFParser的配置,把上述三个参数传入PDFTextStripper,不要用AutoDetectParser的默认参数。

NodeJS 实现方案

用pdfjs-dist做解析,不要用封装过度的第三方pdf提取包,这类包基本都默认开了不可见文本过滤。依赖选3.x稳定版即可:

npm install pdfjs-dist@3.11.174

提取代码:

const pdfjsLib = require('pdfjs-dist/legacy/build/pdf.js');
const fs = require('fs');

async function extractOcrPdf(filePath) {
    const fileBuffer = fs.readFileSync(filePath);
    const pdfDocument = await pdfjsLib.getDocument({
        data: new Uint8Array(fileBuffer),
        disableRange: true,
        disableStream: true
    }).promise;

    let fullText = '';
    for (let pageIdx = 1; pageIdx <= <= pdfDocument.numPages; pageIdx++) {
        const page = await pdfDocument.getPage(pageIdx);
        const textContent = await page.getTextContent({
            includeMarkedContent: true, // 关键配置:提取标记内容层的文本,不要跳过隐藏内容
            disableCombineTextItems: false
        });
        // 按坐标排序还原正常阅读顺序,避免文本顺序错乱
        const sortedItems = textContent.items.sort((a, b) => {
            const yDiff = b.transform[5] - a.transform[5];
            return Math.abs(yDiff) < 2 ? a.transform[4] - b.transform[4] : yDiff;
        });
        const pageText = sortedItems.map(item => item.str).join(' ');
        fullText += `\n=== 第${pageIdx}页 ===\n${pageText}`;
    }
    return fullText;
}

// 调用示例
extractOcrPdf('target_file.pdf').then(res => console.log(res));

排错校验

  • 写代码前先做基础校验:用本地PDF阅读器打开文件,尝试拖动鼠标选中文本,如果能选中复制出内容,说明文件确实带OCR层,上述代码可以正常提取;如果选不中,说明文件是纯扫描位图,没有嵌入文本层,需要自己跑OCR识别
  • 如果提取出乱码:说明OCR层用了自定义嵌入字体且没有附带ToUnicode映射表,这种情况需要单独提取嵌入字体做编码映射,常规解析方案无法处理
  • 不要用iText 5.x版本做提取,该版本对隐藏内容的过滤逻辑写死在源码里,改配置的成本远高于换PDFBox

内容的提问来源于stack exchange,提问作者TryBlock

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 03:48:22