Spire.Barcode 7.5.8 现已正式发布。该版本成功修复了条码和二维码识别结果不正确的问题。更多详情如下。
问题修复:
Spire.Doc for Java 14.8.4 现已发布。该版本修复了多个 Word 转 SVG 和 Word 转 PDF 相关问题,包括 Word 转 SVG 时程序抛出异常,以及 Word 转 PDF 时布局与原文档不一致等问题。详情如下。
问题修复:
PDF 中的产品图、截图、图表和印章等图片常需要更新或复用:往 PDF 中插入新的图片、把旧 Logo 替换为新 Logo、删除过时的插图、或把 PDF 中的图片提取出来用于其他文档。由于 PDF 版式固定,直接用编辑器修改这些图片往往非常困难。
Spire.PDF for JavaScript 基于 WebAssembly 在浏览器端直接处理 PDF 文档,通过虚拟文件系统(VFS)管理输入输出文件,无需后端服务支持。借助 PdfImage、页面画布的 DrawImage 方法以及 PdfImageHelper 帮助类,您可以轻松完成对 PDF 图片的添加、替换、删除与提取。
本文介绍四个核心功能点:
有关安装和项目配置,请参考 React 项目中集成 Spire.PDF for JavaScript。以下示例默认已安装 Spire.PDF 并完成 WebAssembly 模块初始化。
添加图片是最常见的图片操作之一。核心思路是:先通过 PdfImage.FromFile 方法加载图片文件,再使用页面画布(Canvas)的 DrawImage 方法在页面的指定位置以指定尺寸绘制图片。其中 x、y 参数确定图片左上角的坐标,width、height 参数确定图片的显示尺寸。既可以向现有文档的指定页面添加图片,也可以像下面的示例那样在新建的空白文档中绘制图片。
function App() {
const addImageToPdf = async () => {
// 获取 Spire.PDF WASM 模块
const pdfModule = window.wasmModule?.spirepdf;
// 检查模块是否就绪
if (!pdfModule) {
alert('Spire.PDF is not ready yet');
return;
}
// 将图片载入 VFS
const inputImageName = 'TreePic.png';
await window.spire.FetchFileToVFS(inputImageName, "", `${process.env.PUBLIC_URL}/data/`);
// 创建 PdfDocument 对象
let doc = new pdfModule.PdfDocument();
// 添加一页
let page = doc.Pages.Add();
// 加载图片,并按比例缩放显示尺寸
let image = pdfModule.PdfImage.FromFile(inputImageName);
let width = image.Width * 0.6;
let height = image.Height * 0.6;
// 计算水平居中位置,并设置垂直位置
let x = (page.Canvas.ClientSize.Width - width) / 2;
let y = 60;
// 在页面的指定位置绘制图片
page.Canvas.DrawImage({ image: image, x: x, y: y, width: width, height: height });
// 定义为 PDF 格式的输出文件名
const outputFileName = '添加图片.pdf';
// 保存为 PDF 格式
doc.SaveToFile({ fileName: outputFileName });
doc.Close();
// 从 VFS 读取生成的 PDF 文件,触发下载
const fileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
const blob = new Blob([fileArray], { type: 'application/pdf' });
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>Add Image To PDF</h1>
<button onClick={addImageToPdf}>
Generate
</button>
</div>
);
}
export default App;
添加图片后生成的 PDF 文档

替换图片是指在保持原图片位置与占位尺寸不变的前提下,将页面中的某张图片内容替换为新图片。首先通过 PdfImageHelper 的 GetImagesInfo 方法获取页面上的图片信息数组,然后加载新图片,再调用 ReplaceImage 方法把指定索引的图片替换为新图片。替换后新图片会自动沿用原图片在页面上的位置与大小,页面整体版式保持不变。
function App() {
const replaceImageInPdf = async () => {
// 获取 Spire.PDF WASM 模块
const pdfModule = window.wasmModule?.spirepdf;
// 检查模块是否就绪
if (!pdfModule) {
alert('Spire.PDF is not ready yet');
return;
}
// 将 PDF 文件载入 VFS
const inputFileName = 'Business_Data_Overview.pdf';
await window.spire.FetchFileToVFS(inputFileName, "", `${process.env.PUBLIC_URL}/data/`);
// 将用于替换的新图片载入 VFS
const newImageName = 'ChartImage.png';
await window.spire.FetchFileToVFS(newImageName, "", `${process.env.PUBLIC_URL}/data/`);
// 创建 PdfDocument 对象并加载 PDF 文档
let doc = new pdfModule.PdfDocument();
doc.LoadFromFile(inputFileName);
// 获取第一页
let page = doc.Pages.get_Item(0);
// 创建 PdfImageHelper 对象,获取页面中的图片信息
let helper = new pdfModule.PdfImageHelper();
let images = helper.GetImagesInfo(page);
// 加载新图片,并替换页面中的第一张图片
let newImage = pdfModule.PdfImage.FromFile(newImageName);
helper.ReplaceImage(images[0], newImage);
// 定义为 PDF 格式的输出文件名
const outputFileName = '替换图片.pdf';
// 保存为 PDF 格式
doc.SaveToFile({ fileName: outputFileName });
doc.Close();
// 从 VFS 读取生成的 PDF 文件,触发下载
const fileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
const blob = new Blob([fileArray], { type: 'application/pdf' });
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>Replace Image In PDF</h1>
<button onClick={replaceImageInPdf}>
Generate
</button>
</div>
);
}
export default App;
替换图片后生成的 PDF 文档

删除图片是将 PDF 中不再需要的图片对象从页面中移除。与替换类似,先通过 PdfImageHelper 的 GetImagesInfo 方法获取页面上的图片信息数组,再调用 DeleteImage 方法并传入对应的图片信息对象,即可删除该图片。删除后原图片位置留空,页面上的文字、图形与整体版式不受影响。
function App() {
const deleteImageFromPdf = async () => {
// 获取 Spire.PDF WASM 模块
const pdfModule = window.wasmModule?.spirepdf;
// 检查模块是否就绪
if (!pdfModule) {
alert('Spire.PDF is not ready yet');
return;
}
// 将 PDF 文件载入 VFS
const inputFileName = 'Business_Data_Overview.pdf';
await window.spire.FetchFileToVFS(inputFileName, "", `${process.env.PUBLIC_URL}/data/`);
// 创建 PdfDocument 对象并加载 PDF 文档
let doc = new pdfModule.PdfDocument();
doc.LoadFromFile(inputFileName);
// 获取第一页
let page = doc.Pages.get_Item(0);
// 创建 PdfImageHelper 对象,获取页面中的图片信息
let helper = new pdfModule.PdfImageHelper();
let images = helper.GetImagesInfo(page);
// 删除页面中的第一张图片
helper.DeleteImage({ imageInfo: images[0] });
// 定义为 PDF 格式的输出文件名
const outputFileName = '删除图片.pdf';
// 保存为 PDF 格式
doc.SaveToFile({ fileName: outputFileName });
doc.Close();
// 从 VFS 读取生成的 PDF 文件,触发下载
const fileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
const blob = new Blob([fileArray], { type: 'application/pdf' });
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>Delete Image From PDF</h1>
<button onClick={deleteImageFromPdf}>
Generate
</button>
</div>
);
}
export default App;
删除图片后生成的 PDF 文档

提取图片是把 PDF 页面中已有的图片导出为独立的图片文件,方便在其他文档或系统中复用。通过 PdfImageHelper 的 GetImagesInfo 方法获取图片信息数组后,逐一访问图片信息对象的 Image 属性,调用其 Save 方法把图片保存到 VFS,再从 VFS 读取文件并触发下载即可。提取操作是只读的,不会修改原 PDF 文档。
function App() {
const extractImagesFromPdf = async () => {
// 获取 Spire.PDF WASM 模块
const pdfModule = window.wasmModule?.spirepdf;
// 检查模块是否就绪
if (!pdfModule) {
alert('Spire.PDF is not ready yet');
return;
}
// 将 PDF 文件载入 VFS
const inputFileName = 'Business_Data_Overview_中文.pdf';
await window.spire.FetchFileToVFS(inputFileName, "", `${process.env.PUBLIC_URL}/data/`);
// 创建 PdfDocument 对象并加载 PDF 文档
let doc = new pdfModule.PdfDocument();
doc.LoadFromFile(inputFileName);
// 获取第一页
let page = doc.Pages.get_Item(0);
// 创建 PdfImageHelper 对象,获取第一页中的图片信息
let helper = new pdfModule.PdfImageHelper();
let images = helper.GetImagesInfo(page);
// 遍历页面中的图片,逐一保存为独立的图片文件并触发下载
for (let i = 0; i < images.length; i++) {
const outputFileName = `提取图片_${i + 1}.png`;
images[i].Image.Save({ fileName: outputFileName });
// 从 VFS 读取提取的图片文件,触发下载
const fileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
const blob = new Blob([fileArray], { type: 'image/png' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = outputFileName;
a.click();
URL.revokeObjectURL(url);
}
doc.Close();
};
return (
<div style={{ textAlign: 'center', height: '300px' }}>
<h1>Extract Images From PDF</h1>
<button onClick={extractImagesFromPdf}>
Generate
</button>
</div>
);
}
export default App;
从 PDF 中提取出的图片文件

原因:GetImagesInfo 返回的是页面上所有图片的信息数组,数组顺序与图片在页面中的排列有关。
解决:可以通过数组索引访问特定图片,例如 images[0] 表示页面中的第一张图片;也可以读取图片信息对象的 Bounds 属性判断图片所在的区域,再结合位置筛选出目标图片。以下示例演示如何根据图片所在区域删除图片:
// 获取页面中的图片信息
let helper = new pdfModule.PdfImageHelper();
let images = helper.GetImagesInfo(page);
// 遍历图片,删除落在指定区域内的图片
for (let i = 0; i < images.length; i++) {
let rect = new pdfModule.RectangleF({ x: 100, y: 300, width: 30, height: 40 });
if (images[i].Bounds.IntersectsWith({ rect: rect })) {
helper.DeleteImage({ imageInfo: images[i] });
}
}
原因:DrawImage 的坐标与尺寸参数直接决定图片在页面上的显示效果。
解决:x、y 为图片左上角的坐标,width、height 为显示尺寸。若希望按原始比例缩放,可先读取 image.Width 与 image.Height,再乘以缩放系数计算目标尺寸;若希望居中显示,可读取 page.Canvas.ClientSize.Width 计算水平坐标,例如 x = (page.Canvas.ClientSize.Width - width) / 2。
原因:替换与删除操作只作用于图片对象本身。
解决:替换图片时新图片沿用原图片的位置与占位尺寸,页面其余内容不变;删除图片后原图片位置留空,页面上其余文字、图形与版式均不受影响。提取图片是只读操作,不会修改原文档。
如果您希望删除结果文档中的评估消息,或者摆脱功能限制,请该Email地址已收到反垃圾邮件插件保护。要显示它您需要在浏览器中启用JavaScript。获取有效期 30 天的临时许可证。
数据验证是控制 Excel 单元格输入内容的有效手段,它能在数据录入阶段拦截错误输入,确保数据的规范性和准确性。Spire.XLS for JavaScript 基于 WebAssembly 在浏览器端直接完成数据验证的设置、读取和删除操作,通过虚拟文件系统(VFS)管理输入输出文件,无需后端服务支持。
本文介绍三个核心功能点:
有关安装和项目配置,请参考 React 项目中集成 Spire.XLS for JavaScript。以下示例默认已安装 Spire.XLS 并完成 WebAssembly 模块初始化。
在日常表单和报表中,我们常常需要限制单元格的输入内容,例如只允许输入一定范围内的数字或日期、限定文本长度等。Spire.XLS for JavaScript 通过单元格的 DataValidation 属性设置验证规则,支持小数(Decimal)、整数(WholeNumber)、日期(Date)、时间(Time)、文本长度(TextLength)、列表(List)等多种验证类型。
function App() {
const sheetToSVG = async () => {
// 获取 Spire.XLS WASM 模块
const xlsModule = window.wasmModule?.spirexls;
// 检查模块是否就绪
if (!xlsModule) {
alert('Spire.Xls is not ready yet');
return;
}
// 将字体载入 VFS
await window.spire.FetchFileToVFS('simsun.ttc', '/Library/Fonts/', `${process.env.PUBLIC_URL}/font/`);
// 创建新工作簿
const workbook = new xlsModule.Workbook();
// 获取第一个工作表
const sheet = workbook.Worksheets.get(0);
// 设置小数验证:B12 单元格只能输入 3 到 6 之间的数字
sheet.Range.get("B11").Text = "Input Number(3-6):";
let rangeNumber = sheet.Range.get("B12");
rangeNumber.DataValidation.CompareOperator = xlsModule.ValidationComparisonOperator.Between;
rangeNumber.DataValidation.Formula1 = "3";
rangeNumber.DataValidation.Formula2 = "6";
rangeNumber.DataValidation.AllowType = xlsModule.CellDataType.Decimal;
rangeNumber.DataValidation.ErrorMessage = "Please input correct number!";
rangeNumber.DataValidation.ShowError = true;
rangeNumber.Style.KnownColor = xlsModule.ExcelColors.Gray25Percent;
// 设置日期验证:B15 单元格只能输入 2024 年内的日期
sheet.Range.get("B14").Text = "Input Date: 1/1/2024";
let rangeDate = sheet.Range.get("B15");
rangeDate.DataValidation.AllowType = xlsModule.CellDataType.Date;
rangeDate.DataValidation.CompareOperator = xlsModule.ValidationComparisonOperator.Between;
rangeDate.DataValidation.Formula1 = "1/1/2024";
rangeDate.DataValidation.Formula2 = "12/31/2024";
rangeDate.DataValidation.ErrorMessage = "Please input correct date!";
rangeDate.DataValidation.ShowError = true;
//支持设置AlertStyleType.Warning;AlertStyleType.Info;AlertStyleType.Stop
rangeDate.DataValidation.AlertStyle = xlsModule.AlertStyleType.Warning;
rangeDate.Style.KnownColor = xlsModule.ExcelColors.Gray25Percent;
// 设置文本长度验证:B18 单元格的文本长度不能超过 5 个字符
sheet.Range.get("B17").Text = "Input Text:";
let rangeTextLength = sheet.Range.get("B18");
rangeTextLength.DataValidation.AllowType = xlsModule.CellDataType.TextLength;
rangeTextLength.DataValidation.CompareOperator = xlsModule.ValidationComparisonOperator.LessOrEqual;
rangeTextLength.DataValidation.Formula1 = "5";
rangeTextLength.DataValidation.ErrorMessage = "Enter a Valid String!";
rangeTextLength.DataValidation.ShowError = true;
rangeTextLength.DataValidation.AlertStyle = xlsModule.AlertStyleType.Stop;
rangeTextLength.Style.KnownColor = xlsModule.ExcelColors.Gray25Percent;
// 自动调整第 2 列的列宽
sheet.AutoFitColumn(2);
const outputFileName = "DataValidation_out.xlsx";
workbook.SaveToFile({ fileName: outputFileName, version: xlsModule.ExcelVersion.Version2010 });
// 释放 workbook 对象以释放资源
workbook.Dispose();
// 从 VFS 读取转换后的文件,触发下载
const fileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
const blob = new Blob([fileArray], { type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" });
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>Add Data Validation</h1>
<button onClick={sheetToSVG}>
Start
</button>
</div>
);
}
export default App;
设置数据验证

在处理已有数据验证的 Excel 文档时,有时需要读取验证规则以了解单元格的输入约束。通过单元格的 DataValidation 属性可以获取验证对象,再读取 AllowType(验证类型)、CompareOperator(比较运算符)、Formula1(最小值/下限)、Formula2(最大值/上限)、IgnoreBlank(是否忽略空值)等设置。
function App() {
const sheetToSVG = async () => {
// 获取 Spire.XLS WASM 模块
const xlsModule = window.wasmModule?.spirexls;
// 检查模块是否就绪
if (!xlsModule) {
alert('Spire.Xls is not ready yet');
return;
}
// 将字体和 Excel 文件载入 VFS
await window.spire.FetchFileToVFS('simsun.ttc', '/Library/Fonts/', `${process.env.PUBLIC_URL}/font/`);
const inputFileName = 'GetSettingsOfDataValidation.xlsx';
await window.spire.FetchFileToVFS(inputFileName, '', `${process.env.PUBLIC_URL}/static/data/`);
// 加载工作簿
const workbook = new xlsModule.Workbook();
workbook.LoadFromFile({ fileName: inputFileName });
// 获取第一个工作表
const worksheet = workbook.Worksheets.get(0);
// 单元格 B4 设置了小数验证
const cell = worksheet.Range.get("B4");
// 获取该单元格的数据验证对象
const validation = cell.DataValidation;
// 获取验证设置
let allowType = validation.AllowType.toString();
let data = validation.CompareOperator.toString();
let minimum = validation.Formula1.toString();
let maximum = validation.Formula2.toString();
let ignoreBlank = validation.IgnoreBlank.toString();
// 拼接结果为字符串
let result = `Settings of Validation: \r\nAllow Type: ${allowType}\r\nData: ${data}\r\nMinimum: ${minimum}\r\nMaximum: ${maximum}\r\nIgnoreBlank: ${ignoreBlank}`;
const outputFileName = 'GetSettingsOfDataValidation-out.txt';
// 将结果写入 txt 文件
window.dotnetRuntime.Module.FS.writeFile(outputFileName, result);
// 释放 workbook 对象以释放资源
workbook.Dispose();
// 从 VFS 读取转换后的文件,触发下载
const fileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
const blob = new Blob([fileArray], { type: 'text/plain' });
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>Get Data Validation Settings</h1>
<button onClick={sheetToSVG}>
Start
</button>
</div>
);
}
export default App;

当验证规则不再需要时,可以通过工作表 DVTable 的 Remove 方法按单元格区域批量删除数据验证。删除时需要传入一个由矩形(Rectangle)组成的数组,用于定位工作表中要删除验证的区域。
function App() {
const sheetToSVG = async () => {
// 获取 Spire.XLS WASM 模块
const xlsModule = window.wasmModule?.spirexls;
// 检查模块是否就绪
if (!xlsModule) {
alert('Spire.Xls is not ready yet');
return;
}
// 将字体和 Excel 文件载入 VFS
await window.spire.FetchFileToVFS('simsun.ttc', '/Library/Fonts/', `${process.env.PUBLIC_URL}/font/`);
const inputFileName = 'RemoveDataValidation.xlsx';
await window.spire.FetchFileToVFS(inputFileName, '', `${process.env.PUBLIC_URL}/static/data/`);
// 加载工作簿
const workbook = new xlsModule.Workbook();
workbook.LoadFromFile({ fileName: inputFileName });
// 创建矩形数组,用于定位工作表中要删除验证的区域
let rectangles = [];
// 向数组添加矩形,该矩形指定从 A1 到 B3 的单元格区域
rectangles.push(xlsModule.Rectangle.FromLTRB(0, 0, 1, 2));
// 删除矩形所表示区域内的数据验证
workbook.Worksheets.get(0).DVTable.Remove(rectangles);
const outputFileName = 'RemoveDataValidation-out.xlsx';
workbook.SaveToFile({ fileName: outputFileName, version: xlsModule.ExcelVersion.Version2010 });
// 释放 workbook 对象以释放资源
workbook.Dispose();
// 从 VFS 读取转换后的文件,触发下载
const fileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
const blob = new Blob([fileArray], { type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" });
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>Remove Data Validation</h1>
<button onClick={sheetToSVG}>
Start
</button>
</div>
);
}
export default App;
删除数据验证

原因:目标单元格已存在其他验证规则,或设置的验证类型、比较运算符与需求不符。
解决:确认验证规则应用于正确的单元格区域,并检查 AllowType、CompareOperator、Formula1、Formula2 等属性的取值是否符合预期。
原因:目标单元格未设置数据验证,或读取的单元格范围与验证所在位置不一致。
解决:确认单元格已设置数据验证,并检查 Range.get 方法引用的单元格地址是否正确。
原因:DVTable.Remove 方法传入的矩形范围未覆盖实际的验证区域。
解决:根据验证覆盖的单元格区域调整 Rectangle.FromLTRB 方法中的坐标,确保矩形范围包含全部需要删除验证的单元格。
如果您希望删除结果文档中的评估消息,或者摆脱功能限制,请该Email地址已收到反垃圾邮件插件保护。要显示它您需要在浏览器中启用JavaScript。获取有效期 30 天的临时许可证。
在日常 Excel 数据处理中,筛选是快速定位和查看目标数据最常用的手段之一。自动筛选器(AutoFilter)允许用户通过点击表头的下拉箭头,快速筛选出符合条件的数据行,避免在大量数据中手动查找。Spire.XLS for JavaScript 基于 WebAssembly 在浏览器端直接完成此操作,通过虚拟文件系统(VFS)管理输入输出文件,无需后端服务支持。
本文介绍三个核心功能点:
有关安装和项目配置,请参考 React 项目中集成 Spire.XLS for JavaScript。以下示例默认已安装 Spire.XLS 并完成 WebAssembly 模块初始化。
在 Excel 中,自动筛选器是快速处理大量数据的重要功能,通过表头右侧的下拉箭头即可对每一列数据设置筛选条件。Spire.XLS for JavaScript 提供了 AutoFilters.Range 属性,只需将工作表的自动筛选范围设置为表头所在的单元格区域,即可为工作表添加自动筛选器。
function App() {
const addAutoFilter = async () => {
// 获取 Spire.XLS WASM 模块
const xlsModule = window.wasmModule?.spirexls;
// 检查模块是否就绪
if (!xlsModule) {
alert('Spire.Xls is not ready yet');
return;
}
// 将字体和 Excel 文件载入 VFS
await window.spire.FetchFileToVFS('simsun.ttc', '/Library/Fonts/', `${process.env.PUBLIC_URL}/font/`);
const inputFileName = 'FilterData.xlsx';
await window.spire.FetchFileToVFS(inputFileName, '', `${process.env.PUBLIC_URL}data/`);
// 加载工作簿
const workbook = new xlsModule.Workbook();
workbook.LoadFromFile({ fileName: inputFileName });
// 获取第一个工作表
const sheet = workbook.Worksheets.get(0);
// 设置自动筛选器范围:表头的 A 到 C 列
sheet.AutoFilters.Range = sheet.Range.get("A1:C1");
// 保存结果文件,指定 Excel 版本为 2016
const outputFileName = "AddAutoFilter_output.xlsx";
workbook.SaveToFile({ fileName: outputFileName, version: xlsModule.ExcelVersion.Version2016 });
// 释放 workbook 对象以释放资源
workbook.Dispose();
// 从 VFS 读取转换后的文件,触发下载
const fileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
const blob = new Blob([fileArray], { type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" });
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>Add AutoFilter</h1>
<button onClick={addAutoFilter}>
Start
</button>
</div>
);
}
export default App;
添加自动筛选器

添加自动筛选器后,还可以在代码中通过 CustomFilter 方法为指定列设置自定义过滤条件,再调用 Filter 方法应用筛选,从而自动筛选出符合条件的数据行。例如,下面的代码将第二列(国家)的过滤条件设置为等于"中国",应用筛选后仅保留国家为"中国"的数据行,其余行将被隐藏。
function App() {
const applyFilter = async () => {
// 获取 Spire.XLS WASM 模块
const xlsModule = window.wasmModule?.spirexls;
// 检查模块是否就绪
if (!xlsModule) {
alert('Spire.Xls is not ready yet');
return;
}
// 将字体和 Excel 文件载入 VFS
await window.spire.FetchFileToVFS('simsun.ttc', '/Library/Fonts/', `${process.env.PUBLIC_URL}/font/`);
const inputFileName = 'FilterData.xlsx';
await window.spire.FetchFileToVFS(inputFileName, '', `${process.env.PUBLIC_URL}data/`);
// 加载工作簿
const workbook = new xlsModule.Workbook();
workbook.LoadFromFile({ fileName: inputFileName });
// 获取第一个工作表
const sheet = workbook.Worksheets.get(0);
// 设置自动筛选器范围:第二列(国家)的表头和数据行
sheet.AutoFilters.Range = sheet.Range.get("B1:B51");
// 获取自动筛选器的第一列
const filterColumn = sheet.AutoFilters.get(0);
// 设置自定义过滤条件:筛选国家为"中国"的行
const strCrt = "中国";
sheet.AutoFilters.CustomFilter({
column: filterColumn,
operatorType: xlsModule.FilterOperatorType.Equal,
criteria: new xlsModule.String(strCrt)
});
// 应用筛选器
sheet.AutoFilters.Filter();
// 保存结果文件,指定 Excel 版本为 2016
const outputFileName = "ApplyFilter_output.xlsx";
workbook.SaveToFile({ fileName: outputFileName, version: xlsModule.ExcelVersion.Version2016 });
// 释放 workbook 对象以释放资源
workbook.Dispose();
// 从 VFS 读取转换后的文件,触发下载
const fileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
const blob = new Blob([fileArray], { type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" });
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>Apply Filter Condition</h1>
<button onClick={applyFilter}>
Start
</button>
</div>
);
}
export default App;
应用过滤条件筛选数据

当不再需要对数据进行筛选时,可以通过 AutoFilters.Clear 方法清除工作表上的所有自动筛选器,使数据恢复完整显示。
function App() {
const removeAutoFilter = async () => {
// 获取 Spire.XLS WASM 模块
const xlsModule = window.wasmModule?.spirexls;
// 检查模块是否就绪
if (!xlsModule) {
alert('Spire.Xls is not ready yet');
return;
}
// 将字体和 Excel 文件载入 VFS
await window.spire.FetchFileToVFS('simsun.ttc', '/Library/Fonts/', `${process.env.PUBLIC_URL}/font/`);
const inputFileName = 'FilteredData.xlsx';
await window.spire.FetchFileToVFS(inputFileName, '', `${process.env.PUBLIC_URL}data/`);
// 加载工作簿
const workbook = new xlsModule.Workbook();
workbook.LoadFromFile({ fileName: inputFileName });
// 获取第一个工作表
const sheet = workbook.Worksheets.get(0);
// 清除工作表中的所有自动筛选器
sheet.AutoFilters.Clear();
// 保存结果文件,指定 Excel 版本为 2016
const outputFileName = "RemoveAutoFilter_output.xlsx";
workbook.SaveToFile({ fileName: outputFileName, version: xlsModule.ExcelVersion.Version2016 });
// 释放 workbook 对象以释放资源
workbook.Dispose();
// 从 VFS 读取转换后的文件,触发下载
const fileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
const blob = new Blob([fileArray], { type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" });
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>Remove AutoFilter</h1>
<button onClick={removeAutoFilter}>
Start
</button>
</div>
);
}
export default App;
移除自动筛选器

原因:设置过滤条件后没有调用 Filter() 方法应用筛选;或者 AutoFilters.Range 设置的区域没有覆盖需要筛选的数据行。
解决:设置过滤条件后调用 sheet.AutoFilters.Filter();并确保 AutoFilters.Range 包含表头以及全部数据行所在的区域,例如示例中的 "B1:B51"。
原因:筛选条件是精确匹配,如果筛选值与单元格内容不完全一致(例如包含前后空格)则无法匹配;
解决:确保筛选值与单元格内容完全一致;
如果您希望删除结果文档中的评估消息,或者摆脱功能限制,请该Email地址已收到反垃圾邮件插件保护。要显示它您需要在浏览器中启用JavaScript。获取有效期 30 天的临时许可证。
拆分 PDF 文档是 Web 应用中的常见需求。例如,您可能需要将一份长报告分成多个单页文件、单独提取封面页,或将第一页与其余页面分开以便进一步处理。您无需将文件上传到服务器,而是可以直接在 React 应用中使用 JavaScript 执行这些操作。
Spire.PDF for JavaScript 使开发者能够在基于浏览器的应用中加载、操作和保存 PDF 文档。它通过 WebAssembly 和虚拟文件系统工作,允许在客户端处理 PDF 文件。
本文演示了如何在 React 中使用 Spire.PDF for JavaScript 通过 JavaScript 拆分 PDF 文档。
在 React 项目的根目录下打开终端,并安装 spire.office 包:
npm i spire.office
安装完成后,将安装包中的以下运行时文件和文件夹复制到 React 项目的 public 文件夹中:
public/
├── _framework/
├── spire.pdf.js
├── Spire.Pdf.Wasm.zip
├── spire.common.js
└── Spire.Common.Wasm.zip
JavaScript 加载器、WebAssembly 资源和支持框架文件在应用运行时必须保持为可访问的静态资源。有关详细设置说明和确切集成流程,请参阅如何在 React 项目中集成 Spire.PDF for JavaScript。
在以下示例中,待拆分的 PDF 文件名为 input.pdf。请将此文件也放在 public 文件夹中,以便在 React 应用中加载。
public/
├── input.pdf
└── ...
如果要将 PDF 文档拆分为多个单页 PDF 文件,可以使用 Split() 方法。此方法将原始 PDF 分隔成多个独立文档,并将每一页保存为一个新的 PDF 文件。
以下示例加载 input.pdf,逐页拆分,并在浏览器中下载生成的每个 PDF 文件。
import React, { useState, useEffect } from 'react';
function App() {
const [wasmModule, setWasmModule] = useState(null);
useEffect(() => {
(async () => {
const publicUrl = process.env.PUBLIC_URL || '';
const spireModule = await import(/* webpackIgnore: true */ `${publicUrl}/spire.pdf.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);
})();
}, []);
const loadPdfToVfs = async (fileName) => {
const publicUrl = process.env.PUBLIC_URL || '';
const response = await fetch(`${publicUrl}/${fileName}`);
const fileBytes = new Uint8Array(await response.arrayBuffer());
window.dotnetRuntime.Module.FS.writeFile(fileName, fileBytes, { flags: 'w+' });
return fileName;
};
const SplitPdf = async () => {
const wasmModule = window.wasmModule?.spirepdf;
if (!wasmModule) return;
const inputFile = await loadPdfToVfs('input.pdf');
const doc = new wasmModule.PdfDocument();
doc.LoadFromFile(inputFile);
const pageCount = doc.Pages.Count;
const outFileName = 'SplitDocument_result-{0}.pdf';
doc.Split(outFileName);
for (let i = 0; i < pageCount; i++) {
const splitFileName = `SplitDocument_result-${i}.pdf`;
const fileArray = window.dotnetRuntime.Module.FS.readFile(splitFileName);
const file = new Blob([fileArray], { type: 'application/pdf' });
const url = URL.createObjectURL(file);
const a = document.createElement('a');
a.href = url;
a.download = splitFileName;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
URL.revokeObjectURL(url);
}
};
return (
<div style={{ textAlign: 'center', height: '300px' }}>
<h1>Split PDF Documents in React</h1>
<button onClick={SplitPdf} disabled={!wasmModule}>
Split PDF
</button>
</div>
);
}
export default App;
输出结果:

该代码首先在 React 组件挂载时导入并初始化 Spire.PDF WebAssembly 模块。
const spireModule = await import(/* webpackIgnore: true */ `${publicUrl}/spire.pdf.js`);
然后,loadPdfToVfs() 函数从 public 文件夹加载 input.pdf 并将其写入虚拟文件系统:
window.dotnetRuntime.Module.FS.writeFile(fileName, fileBytes, { flags: 'w+' });
加载 PDF 文件后,创建一个 PdfDocument 对象并打开源 PDF:
const doc = new wasmModule.PdfDocument();
doc.LoadFromFile(inputFile);
Split() 方法将 PDF 文档拆分为多个独立的 PDF 文件。输出文件名中的 {0} 占位符会被页码索引替换:
const outFileName = 'SplitDocument_result-{0}.pdf';
doc.Split(outFileName);
最后,从虚拟文件系统中读取生成的 PDF 文件,转换为 Blob 对象,并在浏览器中下载。
在某些情况下,您可能不想将每一页都拆分为单独的文件。相反,您可能希望将某一页提取为独立的 PDF,并将剩余页面保存为另一个 PDF。这可以通过创建新的 PdfDocument 对象并将源文档中的选定页面插入其中来实现。
以下示例将 input.pdf 拆分为两个文件:
Split-1.pdf:包含第一页Split-2.pdf:包含剩余页面import React, { useState, useEffect } from 'react';
function App() {
const [wasmModule, setWasmModule] = useState(null);
useEffect(() => {
(async () => {
const publicUrl = process.env.PUBLIC_URL || '';
const spireModule = await import(/* webpackIgnore: true */ `${publicUrl}/spire.pdf.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);
})();
}, []);
const loadPdfToVfs = async (fileName) => {
const publicUrl = process.env.PUBLIC_URL || '';
const response = await fetch(`${publicUrl}/${fileName}`);
const fileBytes = new Uint8Array(await response.arrayBuffer());
window.dotnetRuntime.Module.FS.writeFile(fileName, fileBytes, { flags: 'w+' });
return fileName;
};
const SplitPdf = async () => {
const wasmModule = window.wasmModule?.spirepdf;
if (!wasmModule) return;
const inputFile = await loadPdfToVfs('input.pdf');
const doc = new wasmModule.PdfDocument();
doc.LoadFromFile(inputFile);
const newDoc1 = new wasmModule.PdfDocument();
const newDoc2 = new wasmModule.PdfDocument();
newDoc1.InsertPage(doc, 0);
newDoc2.InsertPageRange(doc, 1, doc.Pages.Count - 1);
newDoc1.SaveToFile('Split-1.pdf');
newDoc2.SaveToFile('Split-2.pdf');
for (const splitFileName of ['Split-1.pdf', 'Split-2.pdf']) {
const fileArray = window.dotnetRuntime.Module.FS.readFile(splitFileName);
const file = new Blob([fileArray], { type: 'application/pdf' });
const url = URL.createObjectURL(file);
const a = document.createElement('a');
a.href = url;
a.download = splitFileName;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
URL.revokeObjectURL(url);
}
};
return (
<div style={{ textAlign: 'center', height: '300px' }}>
<h1>Split PDF Documents in React</h1>
<button onClick={SplitPdf} disabled={!wasmModule}>
Split PDF
</button>
</div>
);
}
export default App;
输出结果:

此示例同样首先将源 PDF 文件加载到虚拟文件系统中,并使用 PdfDocument 打开它。
const doc = new wasmModule.PdfDocument();
doc.LoadFromFile(inputFile);
然后,创建两个新的 PDF 文档:
const newDoc1 = new wasmModule.PdfDocument();
const newDoc2 = new wasmModule.PdfDocument();
将源 PDF 的第一页插入到 newDoc1 中:
newDoc1.InsertPage(doc, 0);
使用 InsertPageRange() 将剩余页面插入到 newDoc2 中:
newDoc2.InsertPageRange(doc, 1, doc.Pages.Count - 1);
此处页码索引从 0 开始。数字 1 表示原始 PDF 的第二页,doc.Pages.Count - 1 表示第一页之后的所有剩余页面。
插入选定页面后,保存两个新的 PDF 文档:
newDoc1.SaveToFile('Split-1.pdf');
newDoc2.SaveToFile('Split-2.pdf');
最后,从虚拟文件系统中读取两个输出文件并下载到本地计算机。
本文演示了如何在 React 应用中使用 Spire.PDF for JavaScript 拆分 PDF 文档。使用 Split() 方法,您可以将 PDF 拆分为独立的单页文档。使用 InsertPage() 和 InsertPageRange(),您可以将特定页面或页面范围提取到新的 PDF 文件中。
这些方法对于构建基于浏览器的 PDF 工具、文档管理系统、在线文件处理应用以及其他需要在不进行服务器端处理的情况下拆分 PDF 的 React 应用非常有用。
我可以在 React 中将 PDF 拆分为每页一个文件吗?
可以。您可以使用 Spire.PDF for JavaScript 提供的 Split() 方法将 PDF 文档拆分为独立的 PDF 文件。原始 PDF 的每一页都将保存为一个独立的 PDF 文件。
我可以只拆分 PDF 中的特定页面范围吗?
可以。您可以不拆分每一页,而是创建一个新的 PdfDocument 对象,并使用 InsertPage() 或 InsertPageRange() 将源 PDF 中的选定页面复制到新的 PDF 文档中。
在 Spire.PDF for JavaScript 中页码索引是从 0 开始吗?
是的。页码索引从 0 开始。例如,页码索引 0 表示第一页,页码索引 1 表示第二页。使用 InsertPageRange() 时,请确保正确设置起始索引和页数。
我需要在 React 中拆分 PDF 文档时使用服务器吗?
不需要。使用 Spire.PDF for JavaScript,可以通过 WebAssembly 和虚拟文件系统在浏览器中加载、处理和保存 PDF。这使得无需将文件发送到服务器即可直接在 React 应用中拆分 PDF 文档成为可能。
如果您需要去除生成文档中的评估提示或解除功能限制,请该Email地址已收到反垃圾邮件插件保护。要显示它您需要在浏览器中启用JavaScript。获取有效期 30 天的临时许可证。
我们很高兴地宣布 Spire.Doc for Python 14.8.1 版本正式发布。本次版本新增 Paragraph.ReferenceEquals 方法,用于对比两个段落的对象。同时,我们成功修复了多个已知缺陷,详情如下。
新功能:
问题修复:
Spire.PDF 12.8.5 现已正式发布。该版本优化和调整了内部注释,修改及新增了相关 Demo 和文章,并对注释相关的类名及属性进行了调整,以提升 API 的一致性。详情如下。
调整:
| 原类名 | 新类名 |
| PdfTextMarkupAnnotationWidget | PdfTextMarkupAnnotation |
| PdfFreeTextAnnotationWidget | PdfFreeTextAnnotation |
| PdfTextAnnotationWidget | PdfTextAnnotation |
| PdfPopupAnnotationWidget | PdfPopupAnnotation |
| PdfLineAnnotationWidget | PdfLineAnnotation |
| PdfRubberStampAnnotationWidget | PdfRubberStampAnnotation |
| PdfPolyLineAnnotation | PdfPolylineAnnotation |
| PdfAttachmentAnnotation | PdfFileAttachmentAnnotation |
| PdfEmbeddedGoToAction | PdfGoToEmbeddedAction |
| PdfTextMarkupAnnotation | PdfHighlightAnnotation |
| 原属性 | 新属性 | 说明 |
| xxx.Text | xxx.Contents | 注释文本内容 |
| xxx.Author | xxx.Title | 注释作者 / 标题 |
| xxx.Bounds | xxx.Rectangle | 注释区域矩形 |
| xxx.TextMarkupColor | xxx.Color | 高亮 / 标记颜色 |
| xxx.Opacity | xxx.StrokingOpacity | 描边不透明度 |
| xxx.LineEndingStyle | xxx.CalloutLineEndingStyle | 引出线端点样式 |
| xxx.CalloutLines | xxx.CalloutLine | 引出线点数组 |
| xxx.BorderStyle / xxx.BorderWidth(lineBorder) | xxx.Border.Style / xxx.Border.Width | 线条边框样式 / 宽度 |
| xxx.BeginLineStyle / xxx.EndLineStyle | xxx.StartingStyle / xxx.EndingStyle | 线条端点样式 |
| xxx.InnerLineColor / xxx.BackColor | xxx.InteriorColor / xxx.Color | 线条内部颜色 / 背景色 |
| xxx.LeaderLineExt | xxx.LeaderLineExtension | 引线延长 |
| xxx.BorderEffect = PdfBorderEffect.BigCloud | xxx.Border.Effect = PdfBorderEffect.Cloudy | 边框云状效果 |
Spire.Presentation for Python 11.8.1 已发布。该版本支持将 PPTX 保存为视频,并修复了两个在转换和加载 PPT 文件时出现的问题。详情请查看下文。
新功能:
ppt = Presentation()
ppt.LoadFromFile(inputFile)
SaveToVideoOption saveOption = new SaveToVideoOption(ffmpegDir)
ppt.SaveToVideoOption=saveOption
ppt.SaveToFile(outputFile_mp4, FileFormat.MP4)
ppt.SaveToFile(outputFile_wmv, FileFormat.WMV)
ppt.Dispose()
问题修复:
https://www.e-iceblue.cn/Downloads/Spire-Presentation-Python.html
PDF 版式固定、便于分发,但其中的表格数据难以直接编辑与分析;Excel(XLSX)则是电子表格领域的通用格式,支持公式、排序、筛选与二次加工。实际业务中经常需要将 PDF 中的报表、账单、数据表转换为 Excel,以便继续编辑、汇总或录入系统。由于 PDF 与 Excel 的底层模型差异较大,转换时的布局策略对结果质量影响显著。
Spire.PDF for JavaScript 基于 WebAssembly 在浏览器端直接完成 PDF 到 Excel 的转换,通过虚拟文件系统(VFS)管理输入输出文件,无需后端服务支持。除了简单的常规转换外,还提供 XlsxLineLayoutOptions 与 XlsxTextLayoutOptions 两类转换选项,帮助您控制转换后的行布局与文本布局。
本文介绍三个核心功能点:
有关安装和项目配置,请参考 React 项目中集成 Spire.PDF for JavaScript。以下示例默认已安装 Spire.PDF 并完成 WebAssembly 模块初始化。
常规转换是最直接的 PDF 转 Excel 方式:创建 PdfDocument 对象加载 PDF 后,直接通过 SaveToFile 方法指定 FileFormat.XLSX 即可保存为 Excel 文档,无需设置任何转换选项。Spire.PDF 会按照默认策略解析 PDF 中的文本、表格与图形内容,适用于大多数常规文档的转换需求;当默认结果无法满足特定的布局要求时,再考虑使用 XlsxLineLayoutOptions 或 XlsxTextLayoutOptions 进行精细化控制。
function App() {
const convertToExcel = async () => {
// 获取 Spire.PDF WASM 模块
const pdfModule = window.wasmModule?.spirepdf;
// 检查模块是否就绪
if (!pdfModule) {
alert('Spire.PDF is not ready yet');
return;
}
// 将 PDF 文件与字体载入 VFS
await window.spire.FetchFileToVFS('ARIAL.TTF', '/Library/Fonts/', `${process.env.PUBLIC_URL}/font/`);
const inputFileName = '财务报表2025.pdf';
await window.spire.FetchFileToVFS(inputFileName, "", `${process.env.PUBLIC_URL}/data/`);
// 创建 PdfDocument 对象并加载 PDF 文档
let doc = new pdfModule.PdfDocument();
doc.LoadFromFile(inputFileName);
// 定义为 Excel 格式的输出文件名
const outputFileName = '输出Excel.xlsx';
// 保存为 Excel 格式
doc.SaveToFile({ fileName: outputFileName, fileFormat: pdfModule.FileFormat.XLSX });
doc.Close();
// 从 VFS 读取转换后的文件,触发下载
const fileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
const blob = new Blob([fileArray], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
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>Convert PDF To Excel</h1>
<button onClick={convertToExcel}>
Generate
</button>
</div>
);
}
export default App;
通过常规方式生成的 Excel 文档

表格边框、分隔线和图形等线条元素在转换到 Excel 时,需要通过行布局选项控制其保留方式。XlsxLineLayoutOptions 提供了多项行布局参数:是否转换为多个工作表、是否保留旋转文本、是否拆分包含多行文本的单元格、是否自动换行以及是否保留重叠文本。通过 ConvertOptions 的 SetPdfToXlsxOptions 方法传入该选项,再使用 SaveToFile 方法指定 FileFormat.XLSX 保存,即可完成转换。
function App() {
const convertToExcel = async () => {
// 获取 Spire.PDF WASM 模块
const pdfModule = window.wasmModule?.spirepdf;
// 检查模块是否就绪
if (!pdfModule) {
alert('Spire.PDF is not ready yet');
return;
}
// 将 PDF 文件与字体载入 VFS
await window.spire.FetchFileToVFS('ARIAL.TTF', '/Library/Fonts/', `${process.env.PUBLIC_URL}/font/`);
const inputFileName = '财务报表.pdf';
await window.spire.FetchFileToVFS(inputFileName, "", `${process.env.PUBLIC_URL}/data/`);
// 创建 PdfDocument 对象并加载 PDF 文档
let doc = new pdfModule.PdfDocument();
doc.LoadFromFile(inputFileName);
// 创建行布局转换选项
// 参数依次为:是否转换为多个工作表、是否保留旋转文本、是否拆分单元格、是否自动换行、是否保留重叠文本
let lineLayoutOptions = new pdfModule.XlsxLineLayoutOptions(true, true, false, true, true);
doc.ConvertOptions.SetPdfToXlsxOptions(lineLayoutOptions);
// 定义为 Excel 格式的输出文件名
const outputFileName = '行布局选项.xlsx';
// 保存为 Excel 格式
doc.SaveToFile({ fileName: outputFileName, fileFormat: pdfModule.FileFormat.XLSX });
doc.Close();
// 从 VFS 读取转换后的文件,触发下载
const fileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
const blob = new Blob([fileArray], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
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>Convert PDF To Excel using XlsxLineLayoutOptions</h1>
<button onClick={convertToExcel}>
Generate
</button>
</div>
);
}
export default App;
通过 XlsxLineLayoutOptions 转换选项生成的 Excel 文档

当 PDF 内容以文本和数值为主时,可以改用 XlsxTextLayoutOptions 控制文本布局转换参数,例如是否转换为多个工作表、是否保留旋转文本等。与行布局选项不同,该选项更侧重于文本内容的排布方式,适合表格线较少、以文字为主的文档。使用方法相同:通过 ConvertOptions 的 SetPdfToXlsxOptions 方法传入选项,再保存为 XLSX。
function App() {
const convertToExcel = async () => {
// 获取 Spire.PDF WASM 模块
const pdfModule = window.wasmModule?.spirepdf;
// 检查模块是否就绪
if (!pdfModule) {
alert('Spire.PDF is not ready yet');
return;
}
// 将 PDF 文件与字体载入 VFS
await window.spire.FetchFileToVFS('ARIAL.TTF', '/Library/Fonts/', `${process.env.PUBLIC_URL}/font/`);
const inputFileName = '报表.pdf';
await window.spire.FetchFileToVFS(inputFileName, "", `${process.env.PUBLIC_URL}/data/`);
// 创建 PdfDocument 对象并加载 PDF 文档
let doc = new pdfModule.PdfDocument();
doc.LoadFromFile(inputFileName);
// 创建文本布局转换选项
// 参数依次为:是否转换为多个工作表、是否保留旋转文本
let textLayoutOptions = new pdfModule.XlsxTextLayoutOptions(false, true);
doc.ConvertOptions.SetPdfToXlsxOptions(textLayoutOptions);
// 定义为 Excel 格式的输出文件名
const outputFileName = '文本布局选项.xlsx';
// 保存为 Excel 格式
doc.SaveToFile({ fileName: outputFileName, fileFormat: pdfModule.FileFormat.XLSX });
doc.Close();
// 从 VFS 读取转换后的文件,触发下载
const fileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
const blob = new Blob([fileArray], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
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>Convert PDF To Excel using XlsxTextLayoutOptions</h1>
<button onClick={convertToExcel}>
Generate
</button>
</div>
);
}
export default App;
通过 XlsxTextLayoutOptions 转换选项生成的 Excel 文档

原因:不设置转换选项时,Spire.PDF 会采用默认布局策略将 PDF 内容转换为 Excel。
解决:常规转换(不调用 SetPdfToXlsxOptions)步骤最少,适合内容结构简单、默认布局即可满足需求的文档;当需要对多工作表拆分、旋转文本、单元格拆分、自动换行等细节进行控制时,再根据文档内容选择 XlsxLineLayoutOptions(偏图形与线条)或 XlsxTextLayoutOptions(偏文本)。
原因:两类选项用于控制 PDF 转 Excel 时不同内容的保留方式。
解决:XlsxLineLayoutOptions 面向表格边框、线条等图形元素,可控制多工作表拆分、旋转文本、单元格拆分、自动换行与重叠文本等行为;XlsxTextLayoutOptions 面向文本内容,可控制是否合并到单个工作表以及是否保留旋转文本。请根据 PDF 内容以图形为主还是以文本为主选择合适的选项。
原因:受密码保护的加密 PDF 无法直接转换,需要先解密文档。
解决:在加载 PDF 时通过 LoadFromFile 的第二个参数传入密码进行解密,然后再转换并保存为 Excel:
// 加载带密码的 PDF 文档
let doc = new pdfModule.PdfDocument();
doc.LoadFromFile(inputFileName, "password");
// 保存为 Excel 格式
doc.SaveToFile({ fileName: outputFileName, fileFormat: pdfModule.FileFormat.XLSX });
doc.Close();
如果您希望删除结果文档中的评估消息,或者摆脱功能限制,请该Email地址已收到反垃圾邮件插件保护。要显示它您需要在浏览器中启用JavaScript。获取有效期 30 天的临时许可证。