将 Word 文档转换为图片,是在线预览、生成缩略图以及限制内容被随意复制时最常用的处理方式,转换后的图片在任何设备上都能以一致的排版呈现。Spire.Doc for JavaScript 基于 WebAssembly 在浏览器端直接完成此转换,通过虚拟文件系统(VFS)管理输入输出文件,无需后端服务支持。
本文介绍两个核心功能点:
有关安装和项目配置,请参考 React 项目中集成 Spire.Doc for JavaScript。以下示例默认已安装 Spire.Doc 并完成 WebAssembly 模块初始化。
文档页面转图片
文档页面转图片的核心流程分为三个阶段:首先通过 FetchFileToVFS 将字体文件和目标 Word 文档载入 WASM 虚拟文件系统;然后实例化 Document 加载文档,调用 SaveImageToStreams 并传入 pageIndex 将指定页面渲染为图片,保存到 VFS 中;最后从 VFS 读取生成的图片文件,封装为 Blob 后生成下载链接。
import React from 'react';
function App() {
const ToImage = async () => {
// 获取 Spire.Doc WASM 模块
const docModule = window.wasmModule?.spiredoc;
if (!docModule) {
alert('Spire.Doc is not ready yet');
return;
}
// 将字体文件载入虚拟文件系统 (VFS)
await window.spire.FetchFileToVFS('ARIALUNI.TTF', '/Library/Fonts/', `${process.env.PUBLIC_URL}/font/`);
const inputFileName = 'ToImage.docx';
// 将目标 Word 文档载入 VFS
await window.spire.FetchFileToVFS(inputFileName, '', `${process.env.PUBLIC_URL}data/`);
// 创建 Document 实例并加载文档
const doc = new docModule.Document();
doc.LoadFromFile(inputFileName);
// 定义输出文件名
const outputFileName = "ToImage-result.png";
// 将第一页转换为图片流,并保存到 VFS
let img = doc.SaveImageToStreams({ pageIndex: 0, type: docModule.ImageType.Bitmap });
img.Save(outputFileName);
// 释放资源
doc.Dispose();
// 从 VFS 读取生成的文件,封装为 Blob 对象
const modifiedFileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
const blob = new Blob([modifiedFileArray], { type: 'image/png'});
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = outputFileName;
a.click();
URL.revokeObjectURL(url);
};
return (
<div style={{ textAlign: 'center', height: '300px' }}>
<h1>转换指定的页面到图片</h1>
<button onClick={ToImage}>
生成
</button>
</div>
);
}
export default App;
文档页面通过 SaveImageToStreams 转换后生成的 PNG 图片

文档对象转图片
除了整页转换,实际项目中还常需要将文档中的某个元素单独导出为图片,例如为表格生成预览图,或把文档中的形状提取出来作为独立素材。段落、表格、表格行、表格单元格和形状都可以通过 Clone 方法复制到新建的 Document 中,再调用 SaveImageToStreams 渲染为图片。转换结果统一写入 VFS 中的输出目录,最后使用 JSZip 打包为一个 ZIP 文件供用户下载。
需要注意的是,形状(Shape)无法直接加入新建文档的段落中,示例中先将文档保存到内存流再重新加载,让形状在新文档中获得完整的布局上下文后再渲染。
import React from 'react';
import JSZip from "jszip";
function App() {
const ToImage = async () => {
// 获取 Spire.Doc WASM 模块
const docModule = window.wasmModule?.spiredoc;
if (!docModule) {
alert('Spire.Doc is not ready yet');
return;
}
// 将字体文件载入虚拟文件系统 (VFS)
await window.spire.FetchFileToVFS('ARIALUNI.TTF', '/Library/Fonts/', `${process.env.PUBLIC_URL}/font/`);
// 将目标 Word 文档载入 VFS
const inputFileName = "ConvertObjectToImage.docx";
await window.spire.FetchFileToVFS(inputFileName, "", `${process.env.PUBLIC_URL}/data/`);
// 在 VFS 中定义并创建输出目录
const outputDirectoryName = "outputFolder/";
await window.dotnetRuntime.Module.FS.mkdirTree(outputDirectoryName);
// 创建 Document 实例并加载文档
const doc = new docModule.Document();
doc.LoadFromFile(inputFileName);
// 获取第一节及其正文
let section = doc.Sections.get_Item(0);
let body = section.Body;
// 获取第一个段落并转换为图片
let paragraph = body.Paragraphs.get_Item(0);
let imageStream1 = ConvertParagraphToImage(paragraph, docModule);
let imageFile1 = outputDirectoryName + "ConvertParagraphToImage.png";
window.dotnetRuntime.Module.FS.writeFile(imageFile1, imageStream1.Save());
// 获取第一个表格并转换为图片
let table = body.Tables.get_Item(0);
let imageStream2 = ConvertTableToImage(table, docModule);
let imageFile2 = outputDirectoryName + "ConvertTableToImage.jpg";
window.dotnetRuntime.Module.FS.writeFile(imageFile2, imageStream2.Save());
// 获取第一个表格的第一行并转换为图片
let row = table.Rows.get_Item(0);
let imageStream3 = ConvertTableRowToImage(row, docModule);
let imageFile3 = outputDirectoryName + "ConvertTableRowToImage.bmp";
window.dotnetRuntime.Module.FS.writeFile(imageFile3, imageStream3.Save());
// 获取第一行的第一个单元格并转换为图片
let cell = row.Cells.get_Item(0);
let imageStream4 = ConvertTableCellToImage(cell, docModule);
let imageFile4 = outputDirectoryName + "ConvertTableCellToImage.png";
window.dotnetRuntime.Module.FS.writeFile(imageFile4, imageStream4.Save());
// 遍历段落,将其中的形状转换为图片
for (let i = 0; i < section.Paragraphs.Count; i++) {
let para = section.Body.Paragraphs.get_Item(i);
for (let j = 0; j < para.ChildObjects.Count; j++) {
let docObj = para.ChildObjects.get_Item(j);
if (docObj.DocumentObjectType == docModule.DocumentObjectType.Shape) {
let imageStream5 = ConvertShapeToImage(docObj, docModule);
let imageFile5 = outputDirectoryName + "ConvertShapeToImage-" + j + ".png";
window.dotnetRuntime.Module.FS.writeFile(imageFile5, imageStream5.Save());
i++;
}
}
}
// 释放资源
doc.Dispose();
// 将输出目录下的所有图片打包为 ZIP 文件
const zip = new JSZip();
const addFilesToZip = async (folderPath, zipFolder) => {
let items = await window.dotnetRuntime.Module.FS.readdir(folderPath);
items = items.filter((item) => item !== "." && item !== "..");
for (const item of items) {
const itemPath = `${folderPath}/${item}`;
try {
const fileData = await window.dotnetRuntime.Module.FS.readFile(itemPath);
zipFolder.file(item, fileData);
} catch (error) {
const zipSubFolder = zipFolder.folder(item);
await addFilesToZip(itemPath, zipSubFolder);
}
}
};
await addFilesToZip(outputDirectoryName, zip);
const zipBlob = await zip.generateAsync({ type: "blob" });
// 从 VFS 读取生成的文件,封装为 Blob 对象
const url = URL.createObjectURL(zipBlob);
const a = document.createElement('a');
a.href = url;
a.download = "ConvertObjectToImage_out.zip";
a.click();
URL.revokeObjectURL(url);
};
// 将段落转换为图片
function ConvertParagraphToImage(paragraph, docModule) {
let doc = new docModule.Document();
let section = doc.AddSection();
section.Body.ChildObjects.Add(paragraph.Clone());
let imageStream = doc.SaveImageToStreams({ pageIndex: 0, type: docModule.ImageType.Bitmap });
doc.Close();
return imageStream;
}
// 将表格转换为图片
function ConvertTableToImage(table, docModule) {
let doc = new docModule.Document();
let section = doc.AddSection();
section.Body.ChildObjects.Add(table.Clone());
let imageStream = doc.SaveImageToStreams({ pageIndex: 0, type: docModule.ImageType.Bitmap });
doc.Close();
return imageStream;
}
// 将表格行转换为图片
function ConvertTableRowToImage(tableRow, docModule) {
let doc = new docModule.Document();
let section = doc.AddSection();
let table = section.AddTable();
table.Rows.Add(tableRow.Clone());
let imageStream = doc.SaveImageToStreams({ pageIndex: 0, type: docModule.ImageType.Bitmap });
doc.Close();
return imageStream;
}
// 将表格单元格转换为图片
function ConvertTableCellToImage(tableCell, docModule) {
let doc = new docModule.Document();
let section = doc.AddSection();
let table = section.AddTable();
table.AddRow().Cells.Add(tableCell.Clone());
let imageStream = doc.SaveImageToStreams({ pageIndex: 0, type: docModule.ImageType.Bitmap });
doc.Close();
return imageStream;
}
// 将形状转换为图片
function ConvertShapeToImage(shape, docModule) {
let doc = new docModule.Document();
let section = doc.AddSection();
section.AddParagraph().ChildObjects.Add(shape.Clone());
let memoryStream = new docModule.Stream();
doc.SaveToStream({ stream: memoryStream, fileFormat: docModule.FileFormat.Docx });
doc.LoadFromStream({ stream: memoryStream, fileFormat: docModule.FileFormat.Docx });
let imageStream = doc.SaveImageToStreams({ pageIndex: 0, type: docModule.ImageType.Bitmap });
memoryStream.Close();
doc.Close();
return imageStream;
}
return (
<div style={{ textAlign: 'center', height: '300px' }}>
<h1>转换元素到图片</h1>
<button onClick={ToImage}>
生成
</button>
</div>
);
}
export default App;
文档对象转换后打包生成的 ZIP 文件中的图片

常见问题
生成的图片中文字缺失或乱码
原因:WASM 虚拟文件系统中缺少渲染所需的字体文件。SaveImageToStreams 渲染文本时需从 VFS 中读取字体,若未预加载则文字区域会留白或显示为乱码。
解决:转换前通过 FetchFileToVFS 将字体文件载入 VFS:
await window.spire.FetchFileToVFS(
'ARIALUNI.TTF', '/Library/Fonts/',
`${process.env.PUBLIC_URL}/static/font/`
);
只生成了第一页的图片
原因:SaveImageToStreams 每次调用只渲染 pageIndex 指定的单个页面,示例中固定传入 0,因此多页文档只会输出第一页的图片。
解决:通过 PageCount 获取文档总页数并逐页遍历,为每一页生成独立的图片文件:
for (let i = 0; i < doc.PageCount; i++) {
let img = doc.SaveImageToStreams({
pageIndex: i, type: wasmModule.ImageType.Bitmap
});
img.Save(`ToImage-page-${i + 1}.png`);
}
获取免费许可证
如果您希望删除结果文档中的评估消息,或者摆脱功能限制,请该Email地址已收到反垃圾邮件插件保护。要显示它您需要在浏览器中启用JavaScript。获取有效期 30 天的临时许可证。







