尝试在 C# 中以编程方式将 SVG 嵌入 PDF [开源解决方案]

问题描述 投票:0回答:1

我一直在尝试通过 C# 以编程方式从生成的 SVG 创建 pdf 页面。我想分享我的解决方法,因为大多数提供的解决方案都不是免费的......

SVG 代表可缩放矢量图形。 SVG 图像以矢量图形格式定义并存储在 XML 文本文件中。因此,可以在不损失质量的情况下缩放 SVG 图像的大小,并且可以搜索、索引、编写脚本和压缩 SVG 文件。这种行为允许放大并且永远不会损失质量,这在 pdf 中(特别是当您想使用绘图和图表时)相对于 png 或 jpeg 来说是一个很大的改进。

大多数 PDF 生成器需要渲染图像,因此它们失去了我们感兴趣的可扩展性属性,但是,有一些工具似乎可以从 svg 创建此 pdf,在这里我将向您展示如何创建更长的 PDF文件。

测试1:PDFSharp + Inkscape

对于第一次成功的尝试,我使用了

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# 原生的,但它可以完成工作!

测试2:PDFSharp + iText7

我的第二次尝试是使用

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 的情况?

SVG 测试示例 正在尝试附加... svg1 svg2

结果测试1快照 exact result

结果测试2快照 close result but not perfect

c# pdf svg itext7 pdfsharp
1个回答
0
投票

由于您依赖于默认 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 的行为方式,因此我总是发现每种文件组合都有不同的值!。

© www.soinside.com 2019 - 2024. All rights reserved.