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

如何实现可同时在Web Worker和Node.js环境中运行的扫描版PDF文本提取方案

如何实现可同时在Web Worker和Node.js环境中运行的扫描版PDF文本提取方案

嘿,这个问题我之前做PDF处理的时候也踩过坑!既要避开主线程卡顿,又要同时兼容Web Worker和Node.js,核心就是得把依赖DOM的部分给替换掉,咱们一步步来解决:


核心思路:解耦DOM依赖,用跨环境的图像数据处理方式

你原来的代码卡在document.createElement('canvas')——这玩意儿在Web Worker和Node.js里都没法用。所以我们要把PDF页面渲染成像素数据(ImageData)或者Buffer,而不是死磕浏览器DOM里的Canvas元素,同时让Tesseract.js直接处理这些原生数据格式。


1. Web Worker环境下的适配方案

Web Worker里支持OffscreenCanvas,这是不依赖DOM的独立画布对象,刚好能和PDF.js的渲染逻辑配合,而且Tesseract.js也能直接识别它的图像数据。

下面是修改后的Worker代码:

import * as pdfjsLib from 'pdfjs-dist';
import Tesseract from 'tesseract.js';

// 配置PDF.js的Worker路径
pdfjsLib.GlobalWorkerOptions.workerSrc = 'pdfjs-dist/build/pdf.worker.js';

async function extractTextFromScannedPDF(arrayBuffer) {
  const pdf = await pdfjsLib.getDocument(arrayBuffer).promise;
  let fullText = '';

  // 遍历所有页面(可以改成只处理指定页面)
  for (let pageNum = 1; pageNum <= pdf.numPages; pageNum++) {
    const page = await pdf.getPage(pageNum);
    // 放大页面提升OCR准确率,可根据实际情况调整
    const viewport = page.getViewport({ scale: 2.0 });

    // 使用OffscreenCanvas替代DOM Canvas
    const canvas = new OffscreenCanvas(viewport.width, viewport.height);
    const context = canvas.getContext('2d');

    await page.render({ canvasContext: context, viewport }).promise;

    // 获取图像数据传给Tesseract
    const imageData = context.getImageData(0, 0, viewport.width, viewport.height);
    const { data: { text } } = await Tesseract.recognize(
      imageData,
      'eng',
      { logger: m => console.log(`Page ${pageNum}: ${m.status}`) }
    );

    fullText += `--- Page ${pageNum} ---
${text}

`;
  }

  return fullText;
}

// 监听主线程传来的PDF数据
self.onmessage = async (e) => {
  try {
    const text = await extractTextFromScannedPDF(e.data.arrayBuffer);
    self.postMessage({ success: true, text });
  } catch (err) {
    self.postMessage({ success: false, error: err.message });
  }
};

主线程调用Worker的代码示例:

function runExtractionInWorker(file) {
  const worker = new Worker('./pdf-ocr-worker.js');
  
  const fileReader = new FileReader();
  fileReader.readAsArrayBuffer(file);
  
  fileReader.onload = (e) => {
    worker.postMessage({ arrayBuffer: e.target.result });
    
    worker.onmessage = (msg) => {
      if (msg.data.success) {
        console.log('提取完成:', msg.data.text);
        // 在这里处理提取后的文本
      } else {
        console.error('提取失败:', msg.data.error);
      }
      worker.terminate();
    };
  };
}

// 绑定文件选择事件
document.getElementById('pdf-input').addEventListener('change', (e) => {
  runExtractionInWorker(e.target.files[0]);
});

2. Node.js环境下的适配方案

Node.js里没有Canvas和DOM,所以需要用pdfjs-dist的Node版本,搭配canvas模块替代浏览器Canvas,同时Tesseract.js在Node环境中可以直接处理Canvas实例或者Buffer。

首先安装依赖:

npm install pdfjs-dist canvas tesseract.js

Node.js代码示例:

const fs = require('fs').promises;
const pdfjsLib = require('pdfjs-dist');
const { createCanvas } = require('canvas');
const Tesseract = require('tesseract.js');

// Node环境下配置PDF.js的Worker路径
pdfjsLib.GlobalWorkerOptions.workerSrc = require.resolve('pdfjs-dist/build/pdf.worker.js');

async function extractTextFromScannedPDF(filePath) {
  const arrayBuffer = await fs.readFile(filePath);
  const pdf = await pdfjsLib.getDocument(arrayBuffer).promise;
  let fullText = '';

  for (let pageNum = 1; pageNum <= pdf.numPages; pageNum++) {
    const page = await pdf.getPage(pageNum);
    const viewport = page.getViewport({ scale: 2.0 });

    // 使用node-canvas创建画布
    const canvas = createCanvas(viewport.width, viewport.height);
    const context = canvas.getContext('2d');

    await page.render({ canvasContext: context, viewport }).promise;

    // Node环境下Tesseract可直接识别Canvas实例
    const { data: { text } } = await Tesseract.recognize(
      canvas,
      'eng',
      { logger: m => console.log(`Page ${pageNum}: ${m.status}`) }
    );

    fullText += `--- Page ${pageNum} ---
${text}

`;
  }

  return fullText;
}

// 调用示例
extractTextFromScannedPDF('./your_pdf.pdf')
  .then(text => {
    console.log('提取结果:', text);
    return fs.writeFile('./output.txt', text);
  })
  .catch(err => console.error('出错:', err));

关键改动说明

  • 移除DOM依赖:Web Worker用OffscreenCanvas,Node用node-canvas,彻底摆脱对document对象的依赖
  • 统一OCR逻辑:Tesseract.js支持多种输入类型(ImageData、Canvas、Buffer),跨环境可以复用核心识别代码
  • 性能优化:Web Worker把重计算移到后台线程,Node里用异步遍历避免阻塞事件循环,都能解决大PDF卡顿的问题

额外小建议

  • 调整scale参数:放大页面(比如设为2.0)能显著提升低分辨率扫描件的OCR准确率
  • 批量处理:如果PDF页数极多,可以分批次处理,避免内存占用过高
  • 多语言支持:需要识别其他语言时,把Tesseract的语言代码换成对应值(比如'chi_sim'对应简体中文),并确保下载对应的训练包

备注:内容来源于stack exchange,提问作者Devr

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.14 13:44:34