javascript技巧

关注公众号 jb51net

关闭
首页 > 网络编程 > JavaScript > javascript技巧 > JavaScript PDF转HTML

JavaScript实现高效实现PDF转HTML

作者:Eiceblue

在 Web 环境中,将 PDF 转换为 HTML 有助于提升内容的可访问性和交互性,本文将介绍如何在 React 应用中使用 Spire.PDF for JavaScript 库实现 PDF 转 HTML 功能,需要的小伙伴可以了解下

在 Web 环境中,将 PDF 转换为 HTML 有助于提升内容的可访问性和交互性。PDF 虽然因其稳定的版式和便捷的共享特性被广泛使用,但它在在线展示和交互方面存在一定局限。相比之下,HTML 具备更高的灵活性,使内容能够自适应不同设备,便于在网站和移动端流畅呈现。

本文将介绍如何在 React 应用中使用 Spire.PDF for JavaScript 库实现 PDF 转 HTML 功能。该库基于 WebAssembly 在浏览器端直接完成转换,无需后端服务支持,所有文件处理均在本地完成。

一、安装与配置

1. 安装依赖

在 React 项目的根目录中执行以下命令安装集合包:

npm i spire.office

2. 复制运行时文件

安装完成后,将lib中的以下文件复制到 React 项目的 public 文件夹中:

3. 添加字体文件

为确保 PDF 中文本的正确呈现,需要将所需的字体文件放置到项目的 public 目录下(例如 public/static/font/ 目录)。代码中通过 FetchFileToVFS 方法将这些字体加载到虚拟文件系统(VFS)中。

二、核心转换步骤

Spire.PDF for JavaScript 的 PDF 转 HTML 功能主要包含以下步骤:

  1. 加载 WebAssembly 模块 —— 通过动态创建 <script> 标签加载 Spire.Pdf.Base.js
  2. 加载字体文件到 VFS —— 使用 FetchFileToVFS() 方法将字体文件写入虚拟文件系统
  3. 加载 PDF 文件到 VFS —— 将用户选择的 PDF 文件写入虚拟文件系统
  4. 创建 PdfDocument 对象 —— 使用 wasmModule.PdfDocument() 实例化文档对象
  5. 加载并转换 PDF —— 调用 LoadFromFile() 加载 PDF,再调用 SaveToFile() 保存为 HTML
  6. 下载结果文件 —— 从 VFS 读取 HTML 文件并触发浏览器下载
  7. 资源清理 —— 删除 VFS 中的临时文件,释放内存

三、完整代码示例

以下是完整的 React 组件代码,实现了 PDF 转 HTML 的完整功能:

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

function App() {
  const [wasmModule, setWasmModule] = useState(null);
  const [loading, setLoading] = useState(true);
  const [selectedFile, setSelectedFile] = useState(null);
  const [converting, setConverting] = useState(false);
  const [message, setMessage] = useState('');
  const fileInputRef = useRef(null);

  // ========== 1. 加载 WASM 模块 ==========
  useEffect(() => {
    (async () => {
      try {
        setLoading(true);
        const publicUrl = process.env.PUBLIC_URL || '';
        const spireModule = await import(/* webpackIgnore: true */ `${publicUrl}/spire.pdf.js`);
        const rawModule = spireModule.default || spireModule;
        const instance = typeof rawModule === 'function'
          ? await rawModule({ locateFile: p => p.endsWith('.wasm') ? `${publicUrl}/${p}` : p })
          : rawModule;
        window.wasmModule = instance;
        setWasmModule(instance);
      } catch (err) {
        setMessage('❌ 加载引擎失败');
        console.error(err);
      } finally {
        setLoading(false);
      }
    })();
  }, []);

  // ========== 2. 文件选择 ==========
  const handleFileChange = (e) => {
    const file = e.target.files[0];
    if (file && file.type === 'application/pdf') {
      setSelectedFile(file);
      setMessage(`📄 ${file.name}`);
      fileInputRef.current.value = '';
    } else {
      alert('请选择 PDF 文件');
      setSelectedFile(null);
      setMessage('');
      fileInputRef.current.value = '';
    }
  };

  const clearFile = () => {
    setSelectedFile(null);
    setMessage('');
    fileInputRef.current.value = '';
  };

  // ========== 3. PDF 转 HTML 核心逻辑 ==========
  const convert = async () => {
    if (!wasmModule || !selectedFile || converting) return;
    const wasm = window.wasmModule?.spirepdf;
    const runtime = window.dotnetRuntime;
    if (!wasm || !runtime) return setMessage('❌ 引擎未就绪');

    setConverting(true);
    setMessage('⏳ 转换中...');
    let input = '', output = '';

    try {
      // 3a. 加载字体文件到虚拟文件系统(VFS)
      try {
        await window.spire.FetchFileToVFS('arial.ttf', '/Library/Fonts/', `${process.env.PUBLIC_URL}static/font/`);
      } catch (_) {}

      // 3b. 将用户选择的 PDF 文件写入 VFS
      const data = new Uint8Array(await selectedFile.arrayBuffer());
      input = selectedFile.name;
      runtime.Module.FS.writeFile(input, data);

      // 3c. 创建 PdfDocument 对象并加载 PDF
      const doc = new wasm.PdfDocument();
      doc.LoadFromFile(input);
      
      // 3d. 转换为 HTML 并保存到 VFS
      output = input.replace(/\.pdf$/i, '') + '.html';
      doc.SaveToFile({ fileName: output, fileFormat: wasm.FileFormat.HTML });

      // 3e. 从 VFS 读取 HTML 文件并触发下载
      const blob = new Blob([runtime.Module.FS.readFile(output)], { type: 'text/html' });
      const url = URL.createObjectURL(blob);
      const link = document.createElement('a');
      link.href = url;
      link.download = output;
      document.body.appendChild(link);
      link.click();
      document.body.removeChild(link);
      URL.revokeObjectURL(url);

      setMessage(`✅ 下载成功:${output}`);
      doc.Dispose();
      
      // 3f. 清理 VFS 中的临时文件
      try { runtime.Module.FS.unlink(input); runtime.Module.FS.unlink(output); } catch (_) {}
    } catch (err) {
      setMessage('❌ 转换失败');
      console.error(err);
      try { if (input) runtime.Module.FS.unlink(input); if (output) runtime.Module.FS.unlink(output); } catch (_) {}
    } finally {
      setConverting(false);
    }
  };

  // ========== 4. 渲染 UI ==========
  return (
    <div style={{ maxWidth: 500, margin: '40px auto', textAlign: 'center', padding: 20 }}>
      <h1>📄 PDF 转 HTML</h1>
      {loading && <p>⏳ 加载引擎...</p>}

      <div style={{ margin: '20px 0' }}>
        <input ref={fileInputRef} type="file" accept=".pdf" onChange={handleFileChange}
               disabled={loading || !wasmModule || converting} style={{ display: 'none' }} id="pdfInput" />
        <label htmlFor="pdfInput" style={{
          padding: '8px 20px', background: '#4caf50', color: '#fff', borderRadius: 4,
          cursor: 'pointer', opacity: (loading || !wasmModule || converting) ? 0.5 : 1,
          pointerEvents: (loading || !wasmModule || converting) ? 'none' : 'auto'
        }}>选择文件</label>
        <span style={{ marginLeft: 15 }}>{selectedFile ? `📎 ${selectedFile.name}` : '(未选择)'}</span>
        {selectedFile && <button onClick={clearFile} style={{ marginLeft: 10, padding: '2px 10px', background: '#f44336', color: '#fff', border: 'none', borderRadius: 3 }}>清除</button>}
      </div>

      <button onClick={convert} disabled={loading || !wasmModule || !selectedFile || converting}
              style={{ padding: '10px 30px', fontSize: 16, background: '#1a73e8', color: '#fff', border: 'none', borderRadius: 4, opacity: (loading || !wasmModule || !selectedFile || converting) ? 0.6 : 1 }}>
        {converting ? '转换中...' : '转换为 HTML'}
      </button>

      {message && <p style={{ marginTop: 20, padding: 8, background: message.includes('✅') ? '#e8f5e9' : '#ffebee', borderRadius: 4 }}>{message}</p>}
    </div>
  );
}

export default App;

复制完整代码到 src/App.js,然后运行 npm start 启动开发服务器。浏览器将自动打开 http://localhost:3000,界面显示后即可选择 PDF 文件并转换为 HTML。

四、代码解析

1. WASM 模块加载(useEffect)

组件挂载时通过动态 import() 加载 spire.pdf.js 文件,并传入 locateFile 函数指定 WASM 文件的路径。加载完成后将模块实例保存到 window.wasmModule 和组件状态中,供后续转换使用。

2. 虚拟文件系统(VFS)

Spire.PDF for JavaScript 基于 WebAssembly 在浏览器端运行,通过虚拟文件系统(VFS)管理所有输入输出文件。所有文件读写操作都在 VFS 中完成,无需上传到服务器:

3. 字体加载

window.spire.FetchFileToVFS() 方法用于将字体文件从本地加载到 VFS 的 /Library/Fonts/ 目录。如果字体加载失败(例如字体文件不存在),代码会忽略错误继续执行,但可能导致 PDF 中的文本渲染不完整或无法转换。

4. PDF 转换核心 API

五、高级配置:自定义转换选项

PdfDocument.ConvertOptions.SetPdfToHtmlOptions() 方法允许对转换进行精细控制,可设置以下参数:

参数类型说明
useEmbeddedSvgbool是否在生成的 HTML 中嵌入 SVG
useEmbeddedImgbool是否将图像作为 SVG 嵌入(需 useEmbeddedSvgtrue
maxPageOneFileint单个 HTML 文件包含的最大 PDF 页数(需 useEmbeddedSvgtrue
useHighQualityEmbeddedSvgbool是否嵌入高质量 SVG(影响图像质量和文件大小,需 useEmbeddedSvgtrue

使用示例:

const doc = new wasm.PdfDocument();
doc.LoadFromFile(input);
doc.ConvertOptions.SetPdfToHtmlOptions({
    useEmbeddedSvg: true,
    useEmbeddedImg: true,
    maxPageOneFile: 10,
    useHighQualityEmbeddedSvg: false
});
doc.SaveToFile({ fileName: output, fileFormat: wasm.FileFormat.HTML });

通过上述步骤,你可以在 React 应用中快速实现纯前端的 PDF 转 HTML 功能,所有处理均在用户浏览器本地完成,有效保护数据隐私。

到此这篇关于JavaScript实现高效实现PDF转HTML的文章就介绍到这了,更多相关JavaScript PDF转HTML内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文