Spire.Presentation 11.3.1 现已正式发布。该版本优化了 PowerPoint 到 PDF 的转换功能。同时,一些在获取形状阴影效果、加载 3D 动画以及转换文档时出现的问题也得以成功被修复。更多详情如下。
问题修复:
https://www.e-iceblue.cn/Downloads/Spire-Presentation-NET.html
我们很高兴地宣布发布 Spire.Doc for .NET 14.3.5。本次发布支持 Word 到 Excel 的转换,能够将 Word 内容直接导出为 Excel 电子表格。此外,与导出相关的类已重新组织到更清晰的命名空间结构中,以提高 API 的可读性。更多详细信息如下。
新功能:
Document.SaveToFile("output.xlsx", FileFormat.XLSX);
调整:
Spire.PDF 12.3.7 现已发布。本版本增强了 PDF 转 Word 和图片的转换功能,同时修复了多个问题,例如合并 PDF 时程序抛出 “System.OutOfMemoryException” 异常的问题,以及转换 PDF 到 Word 时内容格式不正确的问题。更多详情如下。
问题修复:

OFD (Open Fixed-layout Document) 是电子公文出版版式内容的国家标准,在国内广泛应用于电子发票、政府采购和官方文档存档等。对于 C++ 开发者而言,快速转换 PDF 为 OFD 文件是一项常见的开发需求。
本教程将演示如何使用 Spire.PDF for C++ 库来自动化处理这个任务,主要从三个角度进行介绍,包括:转换单个 PDF 文档为 OFD、提取 PDF 页面转换以及批量转换多个文件。通过这些示例,你可以用 C++ 代码轻松在应用程序中集成 PDF 转 OFD 的功能。
将整个 PDF 文件转换为 OFD 是最常见,也是最基础的操作。在 Spire.PDF for C++ 的帮助下,该任务仅需三个核心步骤就能轻松完成:初始化文档、加载 PDF 源文件、导出为 OFD。下面为具体的步骤介绍:
核心步骤:
代码示例:
#include "Spire.Pdf.o.h"
using namespace Spire::Pdf;
int main()
{
// 创建 PdfDocument 实例
PdfDocument* pdf = new PdfDocument();
// 加载 PDF 源文件
pdf->LoadFromFile(L"/input/示例文档.pdf");
// 将 PDF 保存为 OFD 文档
pdf->SaveToFile(L"/output/转OFD.ofd", FileFormat::OFD);
// 释放资源
pdf->Close();
delete pdf;
return 0;
}
下面是 PDF 源文档与转换后的 OFD 文档对比图:

除了 OFD 转换,Spire.PDF 还支持将 PDF 转换为 Word 或 Excel,帮助你在不同办公需求间快速切换。
在实际应用时,你可能只需要转换 PDF 的一部分,例如只提取发票页或报告的特定章节。这不仅能减小文件体积,还能确保输出的 OFD 仅包含业务相关数据,无需对结果文档再进行编辑。
核心步骤:
代码示例(提取第 2 至第 3 页):
#include "Spire.Pdf.o.h"
#include <iostream>
using namespace Spire::Pdf;
int main()
{
// 创建 PdfDocument 实例并加载 PDF
intrusive_ptr<PdfDocument> oldPdf = new PdfDocument();
oldPdf->LoadFromFile(L"/input/示例文档.pdf");
// 创建新的 PdfDocument 对象用于存放提取的页面
intrusive_ptr<PdfDocument> newPdf = new PdfDocument();
// 获取源文件总页数
int pageCount = oldPdf->GetPages()->GetCount();
std::cout << "总页数: " << pageCount << std::endl;
// 提取第 2 页到第 3 页
if (pageCount >= 3)
{
for (int i = 1; i <= 2; i++)
{
// 在目标文档中创建相同尺寸的新页面
intrusive_ptr<PdfMargins> margins = new PdfMargins(0);
intrusive_ptr<PdfPageBase> newPage = newPdf->GetPages()->Add(oldPdf->GetPages()->GetItem(i)->GetSize(), margins);
// 基于源页面创建模板,并将其绘制到新页面上
oldPdf->GetPages()->GetItem(i)->CreateTemplate()->Draw(newPage, new PointF(0, 0));
}
// 将提取后的结果保存为 OFD
newPdf->SaveToFile(L"E:/Administrator/Python1/output/页面转OFD.ofd", FileFormat::OFD);
std::cout << "指定范围页面已成功转换并保存为 OFD。" << std::endl;
}
// 关闭文档
newPdf->Close();
oldPdf->Close();
return 0;
}

推荐阅读:在 C++ 中将图像转换为 OFD(PNG、JPG、BMP)
在处理大规模历史档案或云存储同步时,手动逐个转换 PDF 文件效率低下。对于多文件的业务流,例如迁移历史存档或同步云端目录等来说,实现多个 PDF 文档的批量自动化转换是一项核心需求。
通过利用 Spire.PDF 库,我们可以构建一套实用的解决方案,自动检测并转换目标文件夹下的所有 PDF 文件,从而节省人力成本。
核心步骤:
代码示例:
#include "Spire.Pdf.o.h"
#include <iostream>
#include <filesystem>
#include <string>
namespace fs = std::filesystem;
using namespace Spire::Pdf;
int main()
{
// 定义输入和输出目录
std::string inputDir = "/input/pdf/";
std::string outputDir = "/output/pdftoofd/";
// 创建 PdfDocument 实例
intrusive_ptr<PdfDocument> pdf = new PdfDocument();
// 遍历输入目录
for (const auto& entry : fs::directory_iterator(inputDir))
{
// 仅处理 .pdf 文件
if (entry.path().extension() == ".pdf")
{
// 获取当前文件路径
std::wstring inputPath = entry.path().wstring();
// 构造输出文件名
std::wstring outputFileName = entry.path().stem().wstring() + L".ofd";
std::wstring outputPath = fs::path(outputDir).wstring() + outputFileName;
// 加载并转换
pdf->LoadFromFile(inputPath.c_str());
pdf->SaveToFile(outputPath.c_str(), FileFormat::OFD);
std::wcout << L"转换完成: " << outputFileName << std::endl;
}
}
pdf->Close();
std::cout << "批量转换任务已全部完成。" << std::endl;
return 0;
}

在掌握了批量转换技术后,你还可以通过学习如何在 C++ 中将多个 PDF 文件合并为一个 PDF,来进一步优化文档处理流程。
Q: OFD 格式是否能完美还原 PDF 的所有元素?
A: 是的,通过 Spire.PDF 进行的转换能够很好地保留文本、矢量图形和图像。其内部绘图逻辑能做到将 PDF 的布局和视觉完整性准确映射到 OFD 标准中。
Q: 转换过程如何处理 PDF 中的高分辨率图片?
A: 转换引擎会保留原始 PDF 图像的 DPI 和压缩设置。即使是批量处理,输出的 OFD 文件也能在保持高质量渲染的同时避免文件体积异常变大。
Q: PDF 表单或交互式元素能否转换?
A: OFD 主要是一种用于查看和打印的固定布局格式。在转换过程中,交互式表单字段一般会被扁平化为可视化图层,以确保数据在 OFD 文档中清晰可见,其交互性在 OFD 中将不再被激活。
Spire.PDF for C++ 为处理 OFD 转换提供了灵活且强大的 API。无论是简单的格式转换,还是复杂的页面提取与批量自动化流,该库都能确保稳定且完整的输出。
如果你对 Spire.PDF 库感兴趣,欢迎该Email地址已收到反垃圾邮件插件保护。要显示它您需要在浏览器中启用JavaScript。申请 30 天免费临时授权,在无限制的环境下深度体验该库的所有功能!
PDF 属性是提供有关 PDF 文件的附加信息的元数据。通常,这些属性包括但不限于文档的标题、作者、关键字、主题和创建文档的应用程序。在处理大量的 PDF 文件时,添加属性是必不可少的,因为它可以提升文件的可检索性。在本文中,您将学习如何使用 Spire.PDF for .NET 以编程方式设置或获取 PDF 属性。
首先,您需要将 Spire.XLS for .NET 包含的 DLL 文件作为引用添加到您的 .NET 项目中。DLL 文件可以从此链接下载,也可以通过 NuGet 安装。
PM> Install-Package Spire.XLS基本的 PDF 文档属性,如标题、作者、主题和关键字,使用户以后更容易搜索或检索特定文档。以下是如何使用 Spire.PDF for .NET 设置这些属性的详细步骤。
using Spire.Pdf;
namespace PDFProperties
{
class Properties
{
static void Main(string[] args)
{
//创建一个PdfDocument实例
PdfDocument pdf = new PdfDocument();
//加载PDF文件
pdf.LoadFromFile("示例文档.pdf");
//设置标题
pdf.DocumentInformation.Title = "PDF (可移植文档格式)";
//设置作者
pdf.DocumentInformation.Author = "冰蓝科技";
//设置主题
pdf.DocumentInformation.Subject = "设置PDF属性";
//设置关键字
pdf.DocumentInformation.Keywords = ".NET PDF, 属性, 文档";
//设置生成器名称
pdf.DocumentInformation.Producer = "Spire.PDF";
//保存结果文档
pdf.SaveToFile("Pdf属性.pdf");
pdf.Dispose();
}
}
}Imports Spire.Pdf
Namespace PDFProperties
Friend Class Properties
Private Shared Sub Main(ByVal args As String())
'创建一个PdfDocument实例
Dim pdf As PdfDocument = New PdfDocument()
'加载PDF文件
pdf.LoadFromFile("示例文档.pdf")
'设置标题
pdf.DocumentInformation.Title = "PDF (可移植文档格式)"
'设置作者
pdf.DocumentInformation.Author = "冰蓝科技"
'设置主题
pdf.DocumentInformation.Subject = "设置PDF属性"
'设置关键字
pdf.DocumentInformation.Keywords = ".NET PDF, 属性, 文档"
'设置生成器名称
pdf.DocumentInformation.Producer = "Spire.PDF"
'保存结果文档
pdf.SaveToFile("Pdf属性.pdf")
pdf.Dispose()
End Sub
End Class
End Namespace
要获取特定的 PDF 属性,可以使用 PdfDocumentInformation 类下的相应属性。以下是详细的步骤。
using Spire.Pdf;
using System.IO;
using System.Text;
namespace GetPdfProperties
{
class Program
{
static void Main(string[] args)
{
//创建一个PdfDocument实例
PdfDocument pdf = new PdfDocument();
//加载PDF文件
pdf.LoadFromFile("Pdf属性.pdf");
//创建StringBuilder实例
StringBuilder content = new StringBuilder();
//获取PDF文档属性并将其附加到StringBuilder中
content.Append("标题: " + pdf.DocumentInformation.Title + "\r\n");
content.Append("作者: " + pdf.DocumentInformation.Author + "\r\n");
content.Append("主题: " + pdf.DocumentInformation.Subject + "\r\n");
content.Append("关键字: " + pdf.DocumentInformation.Keywords + "\r\n");
content.Append("PDF生成器: " + pdf.DocumentInformation.Producer + "\r\n");
//将StringBuilder写入TXT文件
File.WriteAllText("获取PDF属性.txt", content.ToString());
}
}
}Imports Spire.Pdf
Imports System.IO
Imports System.Text
Namespace GetPdfProperties
Friend Class Program
Private Shared Sub Main(ByVal args As String())
'创建一个PdfDocument实例
Dim pdf As PdfDocument = New PdfDocument()
'加载PDF文件
pdf.LoadFromFile("Pdf属性.pdf")
'创建StringBuilder实例
Dim content As StringBuilder = New StringBuilder()
'获取PDF文档属性并将其附加到StringBuilder中
content.Append("标题: " & pdf.DocumentInformation.Title.ToString().ToString() & vbCrLf)
content.Append("作者: " & pdf.DocumentInformation.Author.ToString().ToString() & vbCrLf)
content.Append("主题: " & pdf.DocumentInformation.Subject.ToString().ToString() & vbCrLf)
content.Append("关键字: " & pdf.DocumentInformation.Keywords.ToString().ToString() & vbCrLf)
content.Append("PDF生成器: " & pdf.DocumentInformation.Producer.ToString().ToString() & vbCrLf)
'将StringBuilder写入TXT文件
Call File.WriteAllText("获取PDF属性.txt", content.ToString())
End Sub
End Class
End Namespace
如果您希望删除结果文档中的评估消息,或者摆脱功能限制,请该Email地址已收到反垃圾邮件插件保护。要显示它您需要在浏览器中启用JavaScript。获取有效期 30 天的临时许可证。
在PDF文档中,自定义文档属性可以用来存储特定的元数据类型,例如版本号或公司名称等。我们可以给一个PDF文档添加自定义文档属性,同时也可以查看和删除PDF文档中已有的自定义属性。
本文将介绍如何使用Spire.PDF组件在PDF文档中添加、获取和删除自定义文档属性。
添加自定义文档属性
//实例化一个PdfDocument对象
PdfDocument doc = new PdfDocument();
//载入PDF文档
doc.LoadFromFile("Input.pdf");
//添加自定义文档属性
doc.DocumentInformation.SetCustomProperty("版本号", "6.0.5");
doc.DocumentInformation.SetCustomProperty("公司名称", "E-iceblue");
doc.DocumentInformation.SetCustomProperty("产品", "Spire.Doc for .NET");
//保存文档
doc.SaveToFile("添加自定义属性.pdf");
'实例化一个PdfDocument对象
Dim doc As New PdfDocument()
'载入PDF文档
doc.LoadFromFile("Input.pdf")
'添加自定义文档属性
doc.DocumentInformation.SetCustomProperty("版本号", "6.0.5");
doc.DocumentInformation.SetCustomProperty("公司名称", "E-iceblue");
doc.DocumentInformation.SetCustomProperty("产品", "Spire.Doc for .NET");
'保存文档
doc.SaveToFile("添加自定义属性.pdf")

获取自定义文档属性
//实例化一个PdfDocument对象
PdfDocument doc = new PdfDocument();
//载入PDF文档
doc.LoadFromFile("添加自定义属性.pdf");
//获取指定自定义属性
string version = doc.DocumentInformation.GetCustomProperty("版本号");
string company = doc.DocumentInformation.GetCustomProperty("公司名称");
string product = doc.DocumentInformation.GetCustomProperty("产品");
//获取所有自定义文档属性
//Dictionary<string, string> allCustomProperties = doc.DocumentInformation.GetAllCustomerDefined();
Console.WriteLine("{0}\n{1}\n{2}\n", "版本号:" + version, "公司名称:" + company, "产品:" + product);
'实例化一个PdfDocument对象
Dim doc As New PdfDocument()
'载入PDF文档
doc.LoadFromFile("添加自定义属性.pdf")
'获取指定自定义属性
Dim version As String = doc.DocumentInformation.GetCustomProperty("版本号")
Dim company As String = doc.DocumentInformation.GetCustomProperty("公司名称")
Dim product As String = doc.DocumentInformation.GetCustomProperty("产品")
'获取所有自定义文档属性
'Dictionary allCustomProperties = doc.DocumentInformation.GetAllCustomerDefined();
Console.WriteLine("{0}" & vbLf & "{1}" & vbLf & "{2}" & vbLf, Convert.ToString("版本号:") & version, Convert.ToString("公司名称:") & company, Convert.ToString("产品:") & product)

删除自定义文档属性
//实例化一个PdfDocument对象
PdfDocument doc = new PdfDocument();
//载入PDF文档
doc.LoadFromFile("添加自定义属性.pdf");
//删除指定自定义属性
doc.DocumentInformation.RemoveCustomProperty("版本号");
//保存文档
doc.SaveToFile("删除自定义属性.pdf");
'实例化一个PdfDocument对象
Dim doc As New PdfDocument()
'载入PDF文档
doc.LoadFromFile("添加自定义属性.pdf")
'删除指定自定义属性
doc.DocumentInformation.RemoveCustomProperty("版本号")
'保存文档
doc.SaveToFile("删除自定义属性.pdf")


PDF(可移植文档格式)因其在跨平台环境下保持一致的布局和格式而被广泛用于文档共享、分发和存档。在PDF 文档开发过程中,开发者常常需要通过程序对 PDF 文件进行编辑操作,例如替换文本、插入图片、添加水印或提取页面等。
在本教程中,你将学习如何使用 Spire.PDF for .NET 库通过编程方式在 C# 中编辑 PDF 文件。
尽管 Adobe Acrobat 等工具提供手动编辑 PDF 的功能,但通过 C# 编程方式编辑 PDF 有显著优势:
Spire.PDF for .NET 是一个功能强大的 .NET PDF 库,可让开发者在 .NET 应用中生成、读取、编辑和转换 PDF 文件,支持 .NET Framework 和 .NET Core。

该库为开发者提供了丰富的PDF操作功能:
在 C# 中修改 PDF 文件通常涉及以下步骤:创建项目、安装库、加载 PDF、进行必要修改、保存文档。以下是每一步的详细说明。
在开始编辑 PDF 之前,需要创建一个新的 C# 项目:
接下来,需要安装 Spire.PDF 库,它提供读取、编辑和保存 PDF 所需的全部功能。
可以通过 NuGet 包管理器控制台安装:
Install-Package Spire.PDF
或者通过 NuGet 包管理器 GUI 搜索 Spire.PDF 并点击安装。
在对已有 PDF 文件进行修改之前,需要先将其加载到 PdfDocument 对象中,以便访问文档的页面、文本和图片等内容。
using Spire.Pdf;
PdfDocument pdf = new PdfDocument();
pdf.LoadFromFile("示例.pdf");
编辑文本、插入图片、管理页面和添加水印是 PDF 开发中的常见操作。下面将逐一介绍这些操作,并附上示例代码说明。
文本编辑是 PDF 中最常见的操作。你可以选择替换已有文本或在特定页面添加新文本。
替换已有文本:
在 PDF 中替换文本可以针对单页或整个文档更新内容,同时保持原有格式不变。使用 PdfTextReplacer 类,可快速实现文本的查找与替换操作:
// 获取第一页
PdfPageBase page = pdf.Pages[0];
// 创建 PdfTextReplacer 对象
PdfTextReplacer textReplacer = new PdfTextReplacer(page);
// 将所有目标文本替换为新文本
textReplacer.ReplaceAllText("旧文本", "新文本");
添加新文本:
除了替换已有文本,还可以在 PDF 页面任意位置添加新文本,只需一行代码:
page.Canvas.DrawString(
"你好,世界!",
new PdfTrueTypeFont(new Font("宋体", 15f, FontStyle.Bold), true),
new PdfSolidBrush(Color.Black),
90, 30
);
PDF 文档中通常包含视觉元素,如徽标、图表或插图。开发者可以在PDF中插入新图片,或者更新旧图片以增强文档的视觉效果。
插入图片:
// 加载图片
PdfImage image = PdfImage.FromFile("logo.png");
// 在指定位置绘制图片,并设置大小
page.Canvas.DrawImage(image, 100, 150, 200, 100);
更新图片:
// 加载新图片
PdfImage newImage = PdfImage.FromFile("image1.jpg");
// 创建 PdfImageHelper 实例
PdfImageHelper imageHelper = new PdfImageHelper();
// 获取页面上的图片信息
PdfImageInfo[] imageInfo = imageHelper.GetImagesInfo(page);
// 用新图片替换页面上的第一张图片
imageHelper.ReplaceImage(imageInfo[0], newImage);
页面管理是 PDF 编辑的另一个重要方面,包括添加新页面、删除不需要的页面,以及将特定页面提取到新文档。
添加新页面:
// 添加新页面
PdfPageBase newPage = pdf.Pages.Add();
删除页面:
// 删除最后一页
pdf.Pages.RemoveAt(pdf.Pages.Count - 1);
提取页面到新文档:
// 创建新 PDF 文档
PdfDocument newPdf = new PdfDocument();
// 将原文档的第三页提取到新 PDF
newPdf.InsertPage(pdf, pdf.Pages[2]);
// 保存新 PDF
newPdf.SaveToFile("提取页面.pdf");
在 PDF 中添加水印可帮助标识机密信息、添加品牌或保护知识产权。开发者可以通过代码在任意页面上轻松添加水印:
// 遍历 PDF 文档的每一页
foreach (PdfPageBase page in pdf.Pages)
{
// 创建一个平铺画刷(Tiling Brush),尺寸为页面宽度的一半,高度为页面高度的三分之一
PdfTilingBrush brush = new PdfTilingBrush(
new SizeF(page.Canvas.ClientSize.Width / 2, page.Canvas.ClientSize.Height / 3));
// 设置透明度为 0.3,使水印半透明
brush.Graphics.SetTransparency(0.3f);
// 保存当前图形状态,方便后续恢复
brush.Graphics.Save();
// 将坐标原点移动到画刷中心
brush.Graphics.TranslateTransform(brush.Size.Width / 2, brush.Size.Height / 2);
// 将坐标系旋转 -45 度,使水印呈斜角
brush.Graphics.RotateTransform(-45);
// 在画刷上绘制文字“DO NOT COPY”,如需绘制中文,需使用PdfTrueTypeFont并改为中文字体
// 使用 Helvetica 字体,字号 24,颜色为紫罗兰色,文字居中
brush.Graphics.DrawString(
"DO NOT COPY",
new PdfFont(PdfFontFamily.Helvetica, 24),
PdfBrushes.Violet,
0, 0,
new PdfStringFormat(PdfTextAlignment.Center));
// 恢复之前保存的图形状态
brush.Graphics.Restore();
// 重置透明度为 1(不透明)
brush.Graphics.SetTransparency(1);
// 将画刷绘制到页面整个区域,实现水印效果
page.Canvas.DrawRectangle(brush, new RectangleF(new PointF(0, 0), page.Canvas.ClientSize));
}
完成所有编辑后,最后一步是保存修改并释放资源:
// 保存修改后的 PDF 并释放资源
pdf.SaveToFile("修改.pdf");
pdf.Close();
输出PDF文档:

在程序化编辑 PDF 时,遵循以下实用技巧,可以确保输出准确、可读且高效:
本教程介绍了如何使用 Spire.PDF 在 C# 中编辑 PDF 文件,涵盖文本替换、图片插入、页面管理及水印添加等操作。每个步骤均提供实用代码示例,帮助开发者通过程序化方式高效处理 PDF,提高文档操作效率与专业性。
A1: 使用 Spire.PDF,可以替换已有文本或添加新文本。PdfTextReplacer 和 page.Canvas.DrawString() 提供精确控制,同时保持 PDF 格式一致。
A2: 通过 PdfTextReplacer 查找并替换文本,或使用 page.Canvas.DrawString() 在任意位置添加新文本,实现程序化 PDF 编辑。
A3: 可以,使用 PdfImage 和 PdfImageHelper 将图片绘制或替换到 PDF 页面上,支持图像更新和插入操作。
A4: 可使用 C# 和 Spire.PDF 程序化添加文本或图片水印,并控制透明度、旋转和位置,可应用于单页或所有页面。
A5: 创建新的 PDF 文档,将原文档的指定页面插入新文档,实现单页或页范围提取,便于程序化处理 PDF 文件。

在 C++ 中将图像转换为 OFD(Open Fixed-layout Document)格式,是文档处理系统中的常见需求。尤其在中国,OFD 已成为官方文档归档、交换和分发的重要标准格式。在实际开发过程中,开发人员往往需要将扫描文档或图片文件转换为 OFD 文档,以便统一存储、归档,或集成到电子文档管理系统和自动化工作流程中。
如果从底层自行实现图像到 OFD 的转换,通常需要处理图像格式解析、页面尺寸设置以及文档结构构建等复杂细节,同时还要确保生成的文件符合 OFD 规范。借助 Spire.PDF for C++,开发人员可以通过简洁的 API 快速实现图像到 OFD 的转换。该库支持 PNG、JPG、BMP、TIFF 和 EMF 等常见图像格式,并自动处理文档结构和渲染过程。
本文将介绍如何在 C++ 中实现图像转换为 OFD 文档,并提供单图像转换、多图像生成多页 OFD 以及批量转换等实用示例。
快速导航
OFD 是一种基于 XML 的固定版式文档格式,其功能与 PDF 类似,但在字符集支持和政府文档标准方面针对中文环境进行了优化。
将图像转换为 OFD,本质上是创建一个符合 OFD 规范的文档结构,并将图像内容嵌入到文档页面中。
图像转 OFD 的常见应用场景包括:
在实际实现中,通常的处理流程是:创建文档对象,将图像绘制到页面上,然后按照 OFD 规范导出为 OFD 文件。
在 C++ 中实现图像到 OFD 的转换之前,需要先安装并配置 Spire.PDF for C++。
将 Spire.PDF 添加到 C++ 项目的最简单方式是使用 NuGet,它会自动下载库文件并配置相关依赖。
安装步骤如下:
安装完成后,可以在代码中引入该库:
#include "Spire.Pdf.o.h"
您也可以 下载 Spire.PDF for C++,然后通过配置 include 和 lib 目录手动将其集成到项目中。
详细说明请参考:
如何在 C++ 应用程序中集成 Spire.PDF for C++
下面的示例演示如何将单个图像文件转换为 OFD 文档。代码首先创建一个 PDF 文档对象,然后加载图像并将其绘制到页面上,最后将文档保存为 OFD 格式。
#include "Spire.Pdf.o.h"
using namespace Spire::Pdf;
int main()
{
// 创建新的 PDF 文档
PdfDocument* ofd = new PdfDocument();
// 加载图像文件
auto image = PdfImage::FromFile(L"Sample.jpg");
// 根据图像尺寸计算页面大小
float pageWidth = image->GetWidth();
float pageHeight = image->GetHeight();
// 添加与图像尺寸匹配的页面
auto page = ofd->GetPages()->Add(new SizeF(pageWidth, pageHeight));
// 在页面上绘制图像
page->GetCanvas()->DrawImage(image, 0, 0, pageWidth, pageHeight);
// 保存为 OFD 文件
ofd->SaveToFile(L"ImageToOfd.ofd", FileFormat::OFD);
// 释放资源
delete ofd;
return 0;
}
以下截图展示了由源图像生成的 OFD 文档效果。

PdfDocument 表示文档对象,用于创建页面并导出最终的 OFD 文件。
PdfImage::FromFile() 从指定路径加载图像文件,并创建可绘制到页面上的图像对象。
PdfDocument::GetPages()->Add() 向文档中添加新页面。本示例根据图像尺寸动态设置页面大小。
PdfCanvas::DrawImage() 将图像绘制到页面画布的指定位置和尺寸。
SaveToFile() 将文档保存到磁盘,并使用 FileFormat::OFD 指定输出格式为 OFD。
这种方式可以确保图像在 OFD 页面中以正确比例显示,从而保持原始图像质量。
默认情况下,文档页面可能包含边距,这会导致图像周围出现空白区域。如果希望图像完全填充页面,可以将页面边距设置为 0:
ofd->GetPageSettings()->SetMargins(0.0);
如果需要保留一定留白,也可以自定义边距:
ofd->GetPageSettings()->SetMargins(10.0);
合理设置边距有助于控制页面布局效果。
注意:如果代码运行时出现 C++ 版本兼容性问题,可通过如下方式解决:
_SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNINGISO C++14 标准 (/std:c++14)在文档归档或批量处理场景中,通常需要将多张图像合并到同一个 OFD 文件中。下面的示例展示了如何创建一个多页 OFD 文档,并在每个页面中放置一张不同的图像。
代码会遍历图像文件列表,为每张图像创建独立页面,并根据图像尺寸设置页面大小,然后将图像绘制到对应页面中。
#include "Spire.Pdf.o.h"
#include <vector>
#include <filesystem>
#include <algorithm>
using namespace Spire::Pdf;
namespace fs = std::filesystem;
int main()
{
// 创建新的 PDF 文档(用于保存为 OFD)
PdfDocument* ofd = new PdfDocument();
// 指定图片文件夹
std::wstring folderPath = L"./images";
// 遍历文件夹
for (const auto& entry : fs::directory_iterator(folderPath))
{
if (!entry.is_regular_file())
continue;
std::wstring path = entry.path().wstring();
std::wstring ext = entry.path().extension().wstring();
// 转为小写方便比较
std::transform(ext.begin(), ext.end(), ext.begin(), ::towlower);
// 判断是否为支持的图片格式
if (ext == L".png" || ext == L".jpg" || ext == L".jpeg" || ext == L".bmp")
{
// 加载图片
auto image = PdfImage::FromFile(path.c_str());
// 获取图片尺寸
float pageWidth = image->GetWidth();
float pageHeight = image->GetHeight();
// 创建页面
auto page = ofd->GetPages()->Add(new SizeF(pageWidth, pageHeight));
// 绘制图片
page->GetCanvas()->DrawImage(image, 0, 0, pageWidth, pageHeight);
}
}
// 保存为 OFD
ofd->SaveToFile(L"multi_page_document.ofd", FileFormat::OFD);
delete ofd;
return 0;
}
以下截图展示了生成的多页 OFD 文档,每张图像分别置于独立页面。

此实现遍历图像文件集合,为每张图像创建独立页面,并以恰当的尺寸绘制内容。生成的 OFD 文档在单一文件中保留所有源图像的顺序和版式。
注意: #include <filesystem> 仅在 C++ 17 及以上的 C++ 标准下可用。
如果需要对已经转换出的 OFD 文档进行合并操作,请参考 如何使用 C++ 合并 OFD/PDF 文档。
在许多实际文档工作流中,页面通常需要遵循 标准页面尺寸,而不是直接使用图像原始尺寸。例如,扫描的合同、表格或报告往往需要统一为 A4 或 Letter 等标准页面格式。
要实现这一点,可以先创建具有固定尺寸的页面,然后按照比例缩放图像,使其在不变形的情况下适应页面范围。
下面的示例演示了如何在保持纵横比的前提下,将图像缩放并适配到固定页面大小。
#define NOMINMAX
#include "Spire.Pdf.o.h"
#include <algorithm>
using namespace Spire::Pdf;
int main()
{
// 创建新的 PDF 文档
PdfDocument* ofd = new PdfDocument();
// 添加固定尺寸的页面(如 A4)
PdfPageBase* page = ofd->GetPages()->Add(PdfPageSize::A4);
// 加载图像
auto image = PdfImage::FromFile(L"Sample.jpg");
// 获取页面尺寸
float pageWidth = page->GetCanvas()->GetClientSize().GetWidth();
float pageHeight = page->GetCanvas()->GetClientSize().GetHeight();
// 获取图像尺寸
float imgWidth = image->GetWidth();
float imgHeight = image->GetHeight();
// 计算等比缩放比例
float scale = std::min(pageWidth / imgWidth, pageHeight / imgHeight);
float scaledWidth = imgWidth * scale;
float scaledHeight = imgHeight * scale;
// 在页面上绘制缩放后的图像
page->GetCanvas()->DrawImage(image, 0, 0, scaledWidth, scaledHeight);
// 保存为 OFD
ofd->SaveToFile(L"FixedPageSize.ofd", FileFormat::OFD);
delete ofd;
return 0;
}
以下截图展示了图像如何缩放以适应固定页面尺寸(A4),同时保持其纵横比。

这种方法确保不同尺寸的图像可以统一放置在标准化文档版式中,同时保持原始比例,避免图像变形。相同技术也可应用于从多张图像生成多页 OFD 文档的场景。
在自动化文档处理系统中,往往需要将大量图像文件批量转换为 OFD 文档。为了提高代码复用性,可以将转换逻辑封装为独立函数,并通过循环处理多个文件。
下面的示例演示了一种简单的批量处理实现方式,同时包含基本的错误处理和进度输出。
#include "Spire.Pdf.o.h"
#include <vector>
#include <iostream>
#include <filesystem>
#include <algorithm>
using namespace Spire::Pdf;
namespace fs = std::filesystem;
void ConvertImageToOFD(const std::wstring& inputPath, const std::wstring& outputPath)
{
// 创建新的 PDF 文档(用于生成 OFD)
PdfDocument* ofd = new PdfDocument();
try
{
// 加载图像文件
auto image = PdfImage::FromFile(inputPath.c_str());
// 计算页面尺寸(与图像尺寸保持一致)
float pageWidth = image->GetWidth();
float pageHeight = image->GetHeight();
// 添加与图像尺寸匹配的页面
auto page = ofd->GetPages()->Add(new SizeF(pageWidth, pageHeight));
// 在页面上绘制图像
page->GetCanvas()->DrawImage(image, 0, 0, pageWidth, pageHeight);
// 保存为 OFD
ofd->SaveToFile(outputPath.c_str(), FileFormat::OFD);
std::wcout << L"已转换:" << inputPath << L" -> " << outputPath << std::endl;
}
catch (const std::exception& ex)
{
std::wcout << L"转换 " << inputPath << L" 时出错:" << ex.what() << std::endl;
}
// 清理文档
delete ofd;
}
int main()
{
// 定义要遍历的图片文件夹
std::wstring folderPath = L"./images";
// 遍历文件夹中的所有文件,并自动执行转换
for (const auto& entry : fs::directory_iterator(folderPath))
{
// 仅处理普通文件
if (!entry.is_regular_file())
continue;
fs::path filePath = entry.path();
std::wstring ext = filePath.extension().wstring();
// 将扩展名转换为小写以便统一比较
std::transform(ext.begin(), ext.end(), ext.begin(), ::towlower);
// 判断是否为支持的图像格式
if (ext == L".png" || ext == L".jpg" || ext == L".jpeg" || ext == L".bmp")
{
// 获取输入图像路径
std::wstring inputPath = filePath.wstring();
// 生成对应的 OFD 输出路径(与图像同名)
fs::path outputPath = filePath.parent_path() / (filePath.stem().wstring() + L".ofd");
// 执行转换
ConvertImageToOFD(inputPath, outputPath.wstring());
}
}
std::wcout << L"批量转换完成。" << std::endl;
return 0;
}
这种批处理方式提供:
该实现独立处理每张图像,确保单个失败不会中断整个批量操作。
确保图像文件路径正确且可访问。加载图像时建议使用绝对路径或验证工作目录:
// 为提高可靠性,使用绝对路径
auto image = PdfImage::FromFile(L"C:\\Documents\\scanned_invoice.png");
妥善清理 PdfDocument 和 PdfImage 对象以防止内存泄漏。使用后务必删除动态分配的对象:
delete ofd;
Spire.PDF 支持常见图像格式,包括 PNG、JPEG、BMP、EMF 和 TIFF。请确保输入文件采用受支持的格式。对于不受支持的格式,需先使用图像处理库将其转换为受支持格式。
当基于图像尺寸创建页面时,请注意过大的图像可能导致生成的 OFD 文档难以查看或打印。建议对大图像实施尺寸限制或缩放处理:
#define NOMINMAX
#include <algorithm>
// 应用最大页面尺寸限制
const float MAX_WIDTH = 1000.0f;
const float MAX_HEIGHT = 1400.0f;
float pageWidth = std::min(static_cast<float>(image->GetWidth()), MAX_WIDTH);
float pageHeight = std::min(static_cast<float>(image->GetHeight()), MAX_HEIGHT);
处理包含中文字符或特殊符号的文件路径时,应使用宽字符串(std::wstring)以确保正确的编码处理,避免文件操作中出现编码问题。
如果在某些环境中遇到编译问题,可尝试在 项目属性 → C/C++ → 预处理器 → 预处理器定义 中添加 _SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING;也可在 项目属性 → 配置属性 → 常规 中,将 C++ 语言标准 设置为 ISO C++14 标准 (/std:c++14)。
本文介绍了如何使用 Spire.PDF for C++ 将图像转换为 OFD 文档。通过简单的 API 调用,开发人员即可实现单图像转换、多图像生成多页文档以及批量转换等功能。
该技术在扫描文档数字化、电子档案管理以及自动化文档处理流程中具有广泛应用。
除了 OFD 转换外,Spire.PDF for C++ 还提供丰富的 PDF 文档处理能力,包括 PDF 创建、编辑、转换以及多种格式导出等功能。借助该库,开发人员可以高效完成复杂的文档处理任务,同时确保生成文档符合相关行业标准。
如需体验完整功能,可 申请 30 天免费许可证。
不需要。Spire.PDF 可以独立完成图像到 OFD 的转换,无需依赖 Adobe Acrobat 或其他外部 PDF 软件。
Spire.PDF 支持常见图像格式,包括 PNG、JPEG、BMP、EMF 和 TIFF。
是的。Spire.PDF 针对服务器环境进行了优化,可以高效处理大量图像转换任务。
可以。Spire.PDF 允许在页面画布上绘制文本或图片,因此可以在导出为 OFD 前添加水印。
相关教程:
不会。转换过程中会保留原始图像的分辨率和质量,页面尺寸也会根据图像大小进行适配。
Spire.Doc 14.3 现已发布。本次更新新增支持“定义网格时自动调整为右缩进”与“为字体调整字间距”功能,同时提供多个新接口用于添加与操作 SmartArt 图形。此外,三个在操作 Word 文档时出现问题也已成功被修复。详情如下。
新功能:
paragraph.Format.AdjustRightIndent =true;//默认值是true
textRange.CharacterFormat.Kerning = 2.5f;
Document document = new Document();
Section section = document.AddSection();
Spire.Doc.Documents.Paragraph paragraph = section.AddParagraph(); paragraph.Format.HorizontalAlignment = HorizontalAlignment.Center;
Spire.Doc.Fields.TextRange textRange = paragraph.AppendText("RepeatingBendingProcess");
textRange.CharacterFormat.FontSize = 28f;
textRange.CharacterFormat.FontName = "Times New Roman";
paragraph = section.AddParagraph();
paragraph = section.AddParagraph();
paragraph.Format.HorizontalAlignment = HorizontalAlignment.Center;
// 添加采用“分段流程”版式的SmartArt图形
Spire.Doc.Fields.Shapes.Shape shape = paragraph.AppendSmartArt(SmartArtType.RepeatingBendingProcess, 432, 252);
SmartArt repeatingBendingSmartArt = shape.SmartArt;
// 添加节点文本
SmartArtNode process1 = repeatingBendingSmartArt.Nodes[0];
process1.Text = "1";
((Spire.Doc.Fields.TextRange)process1.Paragraphs[0].ChildObjects[0]).CharacterFormat.FontName = "Calibri";
((Spire.Doc.Fields.TextRange)process1.Paragraphs[0].ChildObjects[0]).CharacterFormat.FontSize = 20f;
((Spire.Doc.Fields.TextRange)process1.Paragraphs[0].ChildObjects[0]).CharacterFormat.TextColor = Color.Crimson;
// 添加节点文本
SmartArtNode process2 = repeatingBendingSmartArt.Nodes[1];
process2.Text = "2";
((Spire.Doc.Fields.TextRange)process2.Paragraphs[0].ChildObjects[0]).CharacterFormat.FontSize = 15f;
// 添加节点文本
SmartArtNode process3 = repeatingBendingSmartArt.Nodes[2];
process3.Text = "3";
((Spire.Doc.Fields.TextRange)process3.Paragraphs[0].ChildObjects[0]).CharacterFormat.FontSize = 10f;
// 添加节点文本
SmartArtNode process4 = repeatingBendingSmartArt.Nodes[3];
process4.Text = "4";
((Spire.Doc.Fields.TextRange)process4.Paragraphs[0].ChildObjects[0]).CharacterFormat.FontSize = 10f;
// 添加节点文本
SmartArtNode process5 = repeatingBendingSmartArt.Nodes[4];
process5.Text = "5";
((Spire.Doc.Fields.TextRange)process5.Paragraphs[0].ChildObjects[0]).CharacterFormat.FontSize = 10f;
document.SaveToFile(outputFile, FileFormat.Docx);
document.Close();
using (Document document = new Document(inputFile))
{
// 遍历所有节
foreach (Section section in document.Sections)
{
if (section?.Paragraphs == null) continue;
// 遍历节内所有段落
foreach (Spire.Doc.Documents.Paragraph paragraph in section.Paragraphs)
{
foreach (var childObj in paragraph.ChildObjects)
{
if (childObj is Spire.Doc.Fields.Shapes.Shape shape && shape.HasSmartArt)
{
SmartArt smartArt = shape.SmartArt;
if (smartArt == null) continue;
TraverseSmartArtNodes(smartArt.Nodes, builder, 0);
}
}
}
}
}
public static void TraverseSmartArtNodes(SmartArtNodeCollection nodes, StringBuilder builder, int level)
{
if (nodes == null || nodes.Count == 0) return;
for (int nodeIdx = 0; nodeIdx < nodes.Count; nodeIdx++)
{
SmartArtNode node = nodes[nodeIdx];
if (node == null) continue;
// 清理节点文本
string nodeText = node.Text != null ? node.Text.Trim() : "空文本";
if (nodeText == "\r" || string.IsNullOrEmpty(nodeText)) continue;
// 拼接节点层级标识
string nodePrefix;
switch (level)
{
case 0:
nodePrefix = "smartArt.Nodes";
break;
case 1:
nodePrefix = "smartArt.Nodes.ChildNodes";
break;
case 2:
nodePrefix = "smartArt.Nodes.ChildNodes.ChildNodes";
break;
default:
nodePrefix = $"smartArt.Nodes.Level{level}";
break;
}
// 基础文本输出
builder.AppendLine($"{nodePrefix}_{nodeIdx}:{nodeText}");
// 递归处理子节点
TraverseSmartArtNodes(node.ChildNodes, builder, level + 1);
}
}
问题修复:
Spire.PDF for Java 12.3.2 现已正式发布。该版本支持设置 PDF 2.0 版本,同时修复了一些问题,例如中文文本绘制时标点符号位于行首的问题。更多详情如下。
新功能:
doc.getFileInfo().setVersion(PdfVersion.Version_2_0);
问题修复: