将 Word 文档转换为 JPG 或 PNG 图片,在内容预览、社交分享、网页嵌入等场景中有较广泛的应用。与 PDF 转换类似,在浏览器端直接完成转换可以避免文档上传至服务器,减少传输过程中的数据暴露风险。本文介绍一种基于 WebAssembly 技术的纯前端转换方案,说明在 React 环境中如何将 Word 文档的每一页导出为图片文件。
一、技术原理
该方案的核心是一个运行在浏览器中的 WASM(WebAssembly)模块,它将文档处理引擎编译为浏览器可直接执行的二进制代码。由于 WASM 运行在沙箱环境中,无法直接访问本地文件系统,因此通过虚拟文件系统(VFS) 来管理文件读写。
转换流程如下:
- 将字体文件和 Word 文档加载到 VFS 中
Document对象从 VFS 读取源文件,逐页转换为图片流- 从 VFS 读取生成的图片数据,通过浏览器 API 触发下载
这一架构使得文档处理完全在客户端完成,无需依赖后端服务。
二、环境配置
2.1 安装依赖包
在项目根目录执行以下命令:
bash
npm i spire.office
2.2 迁移运行时文件
安装完成后,将 node_modules/spire.office/lib 中的以下文件复制到 React 项目的 public 文件夹:
spire.doc.jsSpire.Doc.Wasm.zipspire.common.jsSpire.Common.Wasm.zip_framework文件夹
这些文件是 WASM 模块运行所必需的资源,放置在 public 目录下可以确保构建工具不会错误地处理它们。
2.3 准备字体和文档资源
由于 WASM 环境不包含系统字体,如果文档中使用了特定字体(如 Times New Roman 或中文字体),需要将对应的字体文件放入 public/static/font/ 目录,并通过 FetchFileToVFS 方法加载到 VFS 中。测试用的 Word 文档可放入 public/static/data/ 目录。
三、WASM 模块加载
以下代码展示了在 React 组件中异步加载 WASM 模块的基本方式。这是所有转换示例共用的前置代码:
jsx
import React, { useState, useEffect } from 'react';
function App() {
const [wasmModule, setWasmModule] = useState(null);
useEffect(() => {
(async () => {
try {
const publicUrl = process.env.PUBLIC_URL || '';
const spireModule = await import(/* webpackIgnore: true */ `${publicUrl}/spire.doc.js`);
const rawModule = spireModule.default || spireModule;
window.wasmModule = typeof rawModule === 'function'
? await rawModule({ locateFile: p => p.endsWith('.wasm') ? `${publicUrl}/${p}` : p })
: rawModule;
setWasmModule(window.wasmModule);
} catch (error) {
console.error('Failed to load WASM module:', error);
}
})();
}, []);
// 转换函数将在后续定义
}
四、将 Word 转换为 JPG
Document.SaveImageToStreams() 方法可以将 Word 文档的指定页面转换为图片流。以下示例展示了如何逐页转换并触发下载:
jsx
const convertWord = async () => {
// 获取 WASM 模块中的 Spire.Doc 对象
const wasmModule = window.wasmModule.spiredoc;
if (wasmModule) {
// 将字体文件加载到虚拟文件系统(VFS)中
await window.spire.FetchFileToVFS('times.ttf', '/Library/Fonts/', `${process.env.PUBLIC_URL}/static/font/`);
await window.spire.FetchFileToVFS('timesbd.ttf', '/Library/Fonts/', `${process.env.PUBLIC_URL}/static/font/`);
await window.spire.FetchFileToVFS('timesbi.ttf', '/Library/Fonts/', `${process.env.PUBLIC_URL}/static/font/`);
await window.spire.FetchFileToVFS('timesi.ttf', '/Library/Fonts/', `${process.env.PUBLIC_URL}/static/font/`);
// 获取输入文件并添加到虚拟文件系统
const inputFileName = 'input.docx';
await window.spire.FetchFileToVFS(inputFileName, '', `${process.env.PUBLIC_URL}/static/data/`);
// 创建文档对象
const doc = new wasmModule.Document();
// 加载 Word 文件
doc.LoadFromFile(inputFileName);
// 获取文档总页数
const totalPages = doc.GetPageCount();
// 遍历每一页,转换为图片
for (let pageIndex = 0; pageIndex < totalPages; pageIndex++) {
// 将指定页面转换为图片流
let img = doc.SaveImageToStreams({ pageIndex, type: wasmModule.ImageType.Bitmap });
// 根据页码指定输出文件名
const outputFileName = `IMG-${pageIndex}.jpg`;
// 保存图片流为 JPG 文件
img.Save(outputFileName);
// 从虚拟文件系统读取保存的文件
const modifiedFileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
const modifiedFile = new Blob([modifiedFileArray], { type: 'image/jpeg' });
// 创建下载链接
const url = URL.createObjectURL(modifiedFile);
const a = document.createElement('a');
a.href = url;
a.download = outputFileName;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
URL.revokeObjectURL(url);
}
// 释放资源
doc.Dispose();
}
};
return (
<div style={{ textAlign: 'center', height: '300px' }}>
<h1>在 React 中将 Word 转换为 JPG</h1>
<button onClick={convertWord} disabled={!wasmModule}>
转换
</button>
</div>
);
}
export default App;
五、转换为 PNG 格式
将输出文件的扩展名和 Blob 的 MIME 类型从 image/jpeg 改为 image/png,即可输出 PNG 格式图片。其他转换逻辑保持一致:
jsx
const convertWord = async () => {
// 获取 WASM 模块中的 Spire.Doc 对象
const wasmModule = window.wasmModule.spiredoc;
if (wasmModule) {
// 将字体文件加载到虚拟文件系统(VFS)中
await window.spire.FetchFileToVFS('times.ttf', '/Library/Fonts/', `${process.env.PUBLIC_URL}/static/font/`);
await window.spire.FetchFileToVFS('timesbd.ttf', '/Library/Fonts/', `${process.env.PUBLIC_URL}/static/font/`);
await window.spire.FetchFileToVFS('timesbi.ttf', '/Library/Fonts/', `${process.env.PUBLIC_URL}/static/font/`);
await window.spire.FetchFileToVFS('timesi.ttf', '/Library/Fonts/', `${process.env.PUBLIC_URL}/static/font/`);
// 获取输入文件并添加到虚拟文件系统
const inputFileName = 'input.docx';
await window.spire.FetchFileToVFS(inputFileName, '', `${process.env.PUBLIC_URL}/static/data/`);
// 创建文档对象
const doc = new wasmModule.Document();
// 加载 Word 文件
doc.LoadFromFile(inputFileName);
// 获取文档总页数
const totalPages = doc.GetPageCount();
// 遍历每一页,转换为图片
for (let pageIndex = 0; pageIndex < totalPages; pageIndex++) {
// 将指定页面转换为图片流
let img = doc.SaveImageToStreams({ pageIndex, type: wasmModule.ImageType.Bitmap });
// 根据页码指定输出文件名
const outputFileName = `IMG-${pageIndex}.png`;
// 保存图片流为 PNG 文件
img.Save(outputFileName);
// 从虚拟文件系统读取保存的文件
const modifiedFileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
const modifiedFile = new Blob([modifiedFileArray], { type: 'image/png' });
// 创建下载链接
const url = URL.createObjectURL(modifiedFile);
const a = document.createElement('a');
a.href = url;
a.download = outputFileName;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
URL.revokeObjectURL(url);
}
// 释放资源
doc.Dispose();
}
};
return (
<div style={{ textAlign: 'center', height: '300px' }}>
<h1>在 React 中将 Word 转换为 PNG</h1>
<button onClick={convertWord} disabled={!wasmModule}>
转换
</button>
</div>
);
}
export default App;
六、关键参数说明
| 参数/方法 | 说明 |
|---|---|
SaveImageToStreams({ pageIndex, type }) |
将指定页面转换为图片流。pageIndex 从 0 开始计数 |
ImageType.Bitmap |
输出位图格式,可进一步保存为 JPG 或 PNG |
GetPageCount() |
获取文档的总页数,用于循环遍历 |
img.Save(fileName) |
将图片流保存为文件到 VFS 中 |
FS.readFile(fileName) |
从 VFS 中读取文件二进制数据 |
七、常见问题与注意事项
字体缺失导致乱码:如果文档使用了特殊字体而 VFS 中未加载对应字体,生成的图片可能出现文字错位或乱码。建议将所有用到的字体文件预先加载到 VFS 中。
多页文档的处理 :SaveImageToStreams 每次只能转换一页,需要通过 GetPageCount() 获取总页数后循环处理。对于页数较多的文档,可考虑添加进度提示以改善用户体验。
图片格式选择:JPG 格式使用有损压缩,文件体积较小,适合包含大量图片的文档;PNG 格式使用无损压缩,适合包含文字和图表的文档,清晰度更高。
资源释放 :转换完成后调用 doc.Dispose() 释放文档对象,避免内存泄漏。在处理大型文档时尤为重要。
WASM 加载问题 :如遇到模块加载失败,请检查 public 目录下的运行时文件是否完整,以及 locateFile 路径配置是否正确。可利用浏览器开发者工具的 Network 面板进行排查。
八、总结
本文介绍了在 React 应用中利用基于 WebAssembly 的文档处理方案,将 Word 文档逐页转换为 JPG 和 PNG 图片的方法。核心在于通过 Document.SaveImageToStreams() 方法将页面转换为图片流,再保存为图片文件并触发下载。该方案在浏览器端完成所有处理,无需将文档上传至服务器,适用于对数据隐私有要求的应用场景。开发者可根据实际需要选择 JPG 或 PNG 格式,并注意处理好文档中的字体资源。