我一直在尝试通过 C# 以编程方式从生成的 SVG 创建 pdf 页面。我想分享我的解决方法,因为大多数提供的解决方案都不是免费的......
SVG 代表可缩放矢量图形。 SVG 图像以矢量图形格式定义并存储在 XML 文本文件中。因此,可以在不损失质量的情况下缩放 SVG 图像的大小,并且可以搜索、索引、编写脚本和压缩 SVG 文件。这种行为允许放大并且永远不会损失质量,这在 pdf 中(特别是当您想使用绘图和图表时)相对于 png 或 jpeg 来说是一个很大的改进。
大多数 PDF 生成器需要渲染图像,因此它们失去了我们感兴趣的可扩展性属性,但是,有一些工具似乎可以从 svg 创建此 pdf,在这里我将向您展示如何创建更长的 PDF文件。
对于第一次成功的尝试,我使用了
PDFSharp
和外部程序 Inkscape
。为了简单起见,让我省略 SVG 生成,并假设我们正在处理的文件夹中有两个 SVG 图像。首先,我做了一个使用 Inkscape 命令行的功能(记住在尝试之前安装该程序!)从 svg 创建 pdf,如下所示:
public void ConvertSvgToPdfWithInkscape(string tempSvgFilePath, string pdfFilePath)
{
// Path to the Inkscape executable
string inkscapePath = "C:/Program Files/Inkscape/bin/inkscape.exe"; // Replace with the actual path
// Construct the command for converting SVG to PDF
string command = $"\"{inkscapePath}\" \"{tempSvgFilePath}\" --export-filename=\"{pdfFilePath}\"";
// Create a process to execute the Inkscape command
using (Process process = new Process())
{
ProcessStartInfo startInfo = new ProcessStartInfo
{
FileName = "cmd.exe",
RedirectStandardInput = true,
RedirectStandardOutput = true,
RedirectStandardError = true,
UseShellExecute = false,
CreateNoWindow = true
};
process.StartInfo = startInfo;
process.Start();
// Execute the Inkscape command
process.StandardInput.WriteLine(command);
process.StandardInput.Flush();
process.StandardInput.Close();
// Wait for the process to finish
process.WaitForExit();
// Check if there were any errors
string errorOutput = process.StandardError.ReadToEnd();
if (!string.IsNullOrEmpty(errorOutput))
{
throw new Exception($"Inkscape Error: {errorOutput}");
}
}
}
然后,在一个循环中,我开始使用 PDFSharp 的
AddPage
方法将页面添加到带有 svgs 的文档中:
using System.Diagnostics;
using System;
using System.Text;
using System.Windows;
using PdfSharp.Pdf;
using PdfSharp.Pdf.IO;
using System.Reflection;
using System.IO;
Encoding.RegisterProvider(System.Text.CodePagesEncodingProvider.Instance);
string path = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location);
var document = new PdfDocument();
string tempPDF = "temp.pdf";
var list = Directory.GetFiles(path, "*.svg", SearchOption.AllDirectories);
for (int ev = 0; ev < list.Length; ev++)
{
ConvertSvgToPdfWithInkscape(list[ev], tempPDF);
PdfDocument inputDocument = PdfReader.Open(tempPDF, PdfDocumentOpenMode.Import);
document.AddPage(inputDocument.Pages[0]);
}
File.Delete(tempPDF);
string fileName = path + "/output.pdf";
// Save and start View
document.Save(fileName);
我不喜欢这个解决方案,因为我们使用外部程序,它不是 C# 原生的,但它可以完成工作!
我的第二次尝试是使用
iText7
,我发现我需要安装itext7.bouncy-castle-fips-adapter
和itext7.font-asian
才能工作(不知道为什么!)。我一直使用 PDFSharp
来合并 pdf,但我知道可以使用 iText 来完成。这就是审判:
using System;
using System.Text;
using System.Windows;
using PdfSharp.Pdf.IO;
using System.Reflection;
using System.IO;
using iText.Svg.Converter;
using iText.Layout.Font;
using iText.Svg.Processors.Impl;
Encoding.RegisterProvider(System.Text.CodePagesEncodingProvider.Instance);
string path = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location);
var document = new PdfSharp.Pdf.PdfDocument();
string tempPDF = "temp.pdf";
var list = Directory.GetFiles(path, "*.svg", SearchOption.AllDirectories);
for (int ev = 0; ev < list.Length; ev++)
{
FontProvider provider = new FontProvider();
SvgConverterProperties props = new SvgConverterProperties();
props.SetCharset("Windows-1252");
props.SetFontProvider(provider);
FileStream svgPath = File.Open(list[ev], FileMode.Open);
FileStream pdfPath = File.Create(tempPDF);
SvgConverter.CreatePdf(svgPath, pdfPath, props);
PdfSharp.Pdf.PdfDocument inputDocument = PdfSharp.Pdf.IO.PdfReader.Open(tempPDF, PdfDocumentOpenMode.Import);
document.AddPage(inputDocument.Pages[0]);
}
File.Delete(tempPDF);
string fileName = path + "/output.pdf";
// Save and start View
document.Save(fileName);
这个过程在速度和 C# 原生方面是最好的,但是结果并不是完美的,所以我希望在这里我们可以讨论正在发生的事情,并希望找到完成此任务的最终解决方案,因为 SVG 和 pdf在一起看起来棒极了! :)
由于这篇文章很大(至少对我来说),我将编辑我可能犯的错误,例如打字错误或错误的代码复制粘贴(我试图省略非必要部分)。请耐心等待!
所以问题是:是否有人能够像我的测试 2 那样以编程方式完成此操作,但结果却准确?或者您是否猜出在第二种情况下无法正确将 svg 转换为 pdf 的情况?
由于您依赖于默认 Windows 许可字体,因此应用程序需要在 MS Windows 中运行,因此迄今为止最简单的方法是使用本机系统“生成”带有嵌入 SegoeUI 字体的 PDF,这是任何当前 Windows 上的简单无头命令.
Wrap.cmd
echo ^<html^>^<head^>^<style^>@media print { @page { size: 1200px 920px; }}^</style^>^<body style="margin-top: -10px;width: 1200px;"^>^<div style="height: 900px;">^>>wrap.html
copy wrap.html+w7u.svg wrap1.html && copy wrap1.html+wbc.svg wrap2.html && echo ^</div^>^</body^>^</html^>>>wrap2.html
"C:\Program Files\Microsoft\Edge\Application\msedge.exe" --headless=old --print-to-pdf="%cd%\fred1.pdf" --print-to-pdf-no-header "%cd%\wrap2.html"
您可能想知道为什么我必须将页面大小“调整”20pts,这正是 HTML 与 16 位 BOM 的行为方式,因此我总是发现每种文件组合都有不同的值!。