IT俱乐部 JavaScript React结合WASM实现PDF文本提取功能

React结合WASM实现PDF文本提取功能

PDF 文本提取是文档自动化场景里非常常见的需求。传统方案大多是后端服务读取 PDF 再返回文本,当面对大量用户、大体积 PDF 文件时,会带来服务器压力、文件上传带宽消耗等问题。

借助 WASM 技术,我们可以把 PDF 解析能力放到浏览器前端完成:文件不需要上传到任何服务器,所有解析逻辑在本地浏览器运行,隐私性更好,也减轻后端负担。

本文将使用 Spire.PDF for JavaScript(WASM),结合 React 实现一个本地 PDF 文本提取工具。用户只需要选择本地 PDF,前端直接解析并导出提取后的文本为 .txt 文件。

一、技术选型与运行原理

1.1 库的基本信息

Spire.PDF for JavaScript 是一个运行在浏览器端的 PDF 操作库,核心通过 WebAssembly 编译,提供 JavaScript API 用于加载、解析和操作 PDF 文档。它支持从 PDF 中提取文本、图片、表单数据等,本文仅使用其文本提取功能。

1.2 工作流程

用户选择 PDF 文件
    ↓
浏览器读取为 ArrayBuffer
    ↓
WASM 模块加载 PDF 文档
    ↓
逐页提取文本内容
    ↓
生成 TXT 文件并下载

整个过程在客户端完成,无需上传服务器。

二、项目搭建与文件准备

2.1 依赖文件

执行 npm i spire.office 获取所需资源,然后将以下文件放置在 React 项目的 public/ 目录下:

  • spire.pdf.js
  • spire.pdf.wasm
  • spire.common.js
  • Spire.Common.Wasm.zip
  • _framework 文件夹

2.2 React 环境

使用 Create React App 或 Vite 创建的项目均可,本文示例基于 React 函数组件和 Hooks。

三、核心代码实现

3.1 模块加载(WASM 初始化)

由于 WASM 文件需异步加载,我们在 useEffect 中动态导入,并存储模块实例到 state。

useEffect(() => {
  (async () => {
    try {
      const publicUrl = process.env.PUBLIC_URL || '';
      // 动态导入 JS 胶水代码,webpackIgnore 避免打包处理
      const spireModule = await import(/* webpackIgnore: true */ `${publicUrl}/spire.pdf.js`);
      const rawModule = spireModule.default || spireModule;
      // 加载 WASM,指定 locateFile 以找到 .wasm 文件
      const loadedModule = typeof rawModule === 'function'
        ? await rawModule({ locateFile: p => p.endsWith('.wasm') ? `${publicUrl}/${p}` : p })
        : rawModule;
      setPdfModule(loadedModule);
    } catch (error) {
      console.error('加载 spire.pdf.js 失败:', error);
    }
  })();
}, []);

关键点:

  • webpackIgnore: true 防止 Webpack 改写动态导入路径。
  • locateFile 回调用于告诉 WASM 加载器 .wasm 文件的具体位置。

3.2 文件选择与状态管理

使用 useRef 隐藏原生 ,通过自定义按钮触发选择,提升 UI 一致性。

const fileInputRef = useRef(null);

const handleFileChange = (e) => {
  const file = e.target.files[0];
  if (file && file.type === 'application/pdf') {
    setSelectedFile(file);
  } else {
    alert('请选择一个有效的 PDF 文件');
    e.target.value = '';
  }
};

const handleSelectFile = () => {
  fileInputRef.current.click();
};

3.3 文本提取函数

核心提取逻辑封装在 ExtractPDFText 中,流程如下:

const ExtractPDFText = async () => {
  if (!selectedFile) return;
  const spirepdf = pdfModule?.spirepdf;
  if (!spirepdf) {
    alert('模块尚未加载完成');
    return;
  }

  setIsExtracting(true);
  try {
    // 1. 读取文件为字节数组
    const arrayBuffer = await selectedFile.arrayBuffer();
    const uint8Array = new Uint8Array(arrayBuffer);

    // 2. 创建 PDF 文档对象并加载
    const pdf = new spirepdf.PdfDocument();
    pdf.LoadFromBytes(uint8Array);

    // 3. 配置提取选项(默认即可)
    const extractOptions = new spirepdf.PdfTextExtractOptions();
    let text = '';

    // 4. 遍历所有页面
    for (let i = 0; i 

注意:

  • PdfDocument.LoadFromBytes 接受 Uint8Array 类型。
  • 提取时需循环 pdf.Pages.Count,页码从 0 开始。
  • 下载使用 Blob 和 URL.createObjectURL,无需后端参与。

四、UI 交互优化

为了更好的用户体验,我们添加了加载状态、按钮禁用、文件已选提示等。

4.1 状态定义

  • selectedFile:当前选中的文件对象
  • isExtracting:是否正在提取,用于显示加载状态和禁用按钮
  • pdfModule:WASM 模块是否加载完成

4.2 按钮状态控制

const isButtonDisabled = !selectedFile || isExtracting || !pdfModule;

4.3 样式设计(内联样式)

采用卡片居中布局,按钮使用主色 #1a73e8,并提供悬停和禁用样式。

完整样式代码见下方完整组件。

五、完整组件代码

以下为整合后的 App.js 文件,可直接复制使用(需提前放置好 spire.pdf.js 和 .wasm 文件在 public/ 目录)。

import React, { useState, useEffect, useRef } from 'react';

function App() {
  const [pdfModule, setPdfModule] = useState(null);
  const [selectedFile, setSelectedFile] = useState(null);
  const [isExtracting, setIsExtracting] = useState(false);
  const fileInputRef = useRef(null);

  // 加载 WASM 模块
  useEffect(() => {
    (async () => {
      try {
        const publicUrl = process.env.PUBLIC_URL || '';
        const spireModule = await import(/* webpackIgnore: true */ `${publicUrl}/spire.pdf.js`);
        const rawModule = spireModule.default || spireModule;
        const loadedModule = typeof rawModule === 'function'
          ? await rawModule({ locateFile: p => p.endsWith('.wasm') ? `${publicUrl}/${p}` : p })
          : rawModule;
        setPdfModule(loadedModule);
      } catch (error) {
        console.error('加载 spire.pdf.js 失败:', error);
        alert('PDF 库加载失败,请刷新重试');
      }
    })();
  }, []);

  const handleSelectFile = () => {
    fileInputRef.current.click();
  };

  const handleFileChange = (e) => {
    const file = e.target.files[0];
    if (file && file.type === 'application/pdf') {
      setSelectedFile(file);
    } else {
      alert('请选择一个有效的 PDF 文件');
      e.target.value = '';
    }
  };

  const ExtractPDFText = async () => {
    if (!selectedFile) {
      alert('请先选择一个 PDF 文件');
      return;
    }

    const spirepdf = pdfModule?.spirepdf;
    if (!spirepdf) {
      alert('WASM 模块尚未加载完成,请稍后重试');
      return;
    }

    setIsExtracting(true);
    try {
      const arrayBuffer = await selectedFile.arrayBuffer();
      const uint8Array = new Uint8Array(arrayBuffer);

      const pdf = new spirepdf.PdfDocument();
      pdf.LoadFromBytes(uint8Array);

      const extractOptions = new spirepdf.PdfTextExtractOptions();
      let text = '';

      for (let i = 0; i 
      

📄 PDF 文本提取器

(e.currentTarget.style.backgroundColor = '#d2e3fc')} onMouseLeave={(e) => (e.currentTarget.style.backgroundColor = '#e8f0fe')} > 📂 选择 PDF 文件
{selectedFile && (
✅ 已选择:{selectedFile.name}
)}
{isExtracting && (
处理中,请稍候…
)}

);
}

export default App;

本文收集自网络,不代表IT俱乐部立场,转载请注明出处。https://www.2it.club/navsub/js/18710.html
上一篇
下一篇
联系我们

联系我们

在线咨询: QQ交谈

邮箱: 1120393934@qq.com

工作时间:周一至周五,9:00-17:30,节假日休息

关注微信
微信扫一扫关注我们

微信扫一扫关注我们

返回顶部