对于所有在.net 5 中寻找有效解决方案的人,请看这里。
这是我的工作解决方案。
使用wkhtmltopdf:
- 从here下载并安装
wkhtmltopdf最新版本。
- 使用下面的代码。
public static string HtmlToPdf(string outputFilenamePrefix, string[] urls,
string[] options = null,
string pdfHtmlToPdfExePath = @"C:\Program Files\wkhtmltopdf\bin\wkhtmltopdf.exe")
{
string urlsSeparatedBySpaces = string.Empty;
try
{
//Determine inputs
if ((urls == null) || (urls.Length == 0))
throw new Exception("No input URLs provided for HtmlToPdf");
else
urlsSeparatedBySpaces = String.Join(" ", urls); //Concatenate URLs
string outputFilename = outputFilenamePrefix + "_" + DateTime.Now.ToString("yyyy-MM-dd-hh-mm-ss-fff") + ".PDF"; // assemble destination PDF file name
var p = new System.Diagnostics.Process()
{
StartInfo =
{
FileName = pdfHtmlToPdfExePath,
Arguments = ((options == null) ? "" : string.Join(" ", options)) + " " + urlsSeparatedBySpaces + " " + outputFilename,
UseShellExecute = false, // needs to be false in order to redirect output
RedirectStandardOutput = true,
RedirectStandardError = true,
RedirectStandardInput = true, // redirect all 3, as it should be all 3 or none
WorkingDirectory = Path.Combine(Path.GetDirectoryName(Assembly.GetEntryAssembly().Location))
}
};
p.Start();
// read the output here...
var output = p.StandardOutput.ReadToEnd();
var errorOutput = p.StandardError.ReadToEnd();
// ...then wait n milliseconds for exit (as after exit, it can't read the output)
p.WaitForExit(60000);
// read the exit code, close process
int returnCode = p.ExitCode;
p.Close();
// if 0 or 2, it worked so return path of pdf
if ((returnCode == 0) || (returnCode == 2))
return outputFilename;
else
throw new Exception(errorOutput);
}
catch (Exception exc)
{
throw new Exception("Problem generating PDF from HTML, URLs: " + urlsSeparatedBySpaces + ", outputFilename: " + outputFilenamePrefix, exc);
}
}
- 并将上述方法调用为
HtmlToPdf("test", new string[] { "https://www.google.com" }, new string[] { "-s A5" });
- 如果您需要将
HTML字符串转换为PDF,调整上述方法并将Arguments替换为Process StartInfo为$@"/C echo | set /p=""{htmlText}"" | ""{pdfHtmlToPdfExePath}"" {((options == null) ? "" : string.Join(" ", options))} - ""C:\Users\xxxx\Desktop\{outputFilename}""";
这种方法的缺点:
- 截至发布此答案的
wkhtmltopdf 的最新版本不支持最新的HTML5 和CSS3。因此,如果您尝试将任何 html 导出为 CSS GRID,则输出将与预期不同。
- 您需要处理并发问题。
使用chrome headless:
- 从here下载并安装最新的chrome浏览器。
- 使用下面的代码。
var p = new System.Diagnostics.Process()
{
StartInfo =
{
FileName = "C:/Program Files (x86)/Google/Chrome/Application/chrome.exe",
Arguments = @"/C --headless --disable-gpu --run-all-compositor-stages-before-draw --print-to-pdf-no-header --print-to-pdf=""C:/Users/Abdul Rahman/Desktop/test.pdf"" ""C:/Users/Abdul Rahman/Desktop/grid.html""",
}
};
p.Start();
// ...then wait n milliseconds for exit (as after exit, it can't read the output)
p.WaitForExit(60000);
// read the exit code, close process
int returnCode = p.ExitCode;
p.Close();
- 这会将
html 文件转换为pdf 文件。
- 如果您需要将一些
url 转换为pdf,请使用以下Argument 到Process StartInfo
@"/C --headless --disable-gpu --run-all-compositor-stages-before-draw --print-to-pdf-no-header --print-to-pdf=""C:/Users/Abdul Rahman/Desktop/test.pdf"" ""https://www.google.com""",
这种方法的缺点:
- 这可以与最新的
HTML5 和CSS3 功能一起正常工作。输出将与您在浏览器中查看的相同,但通过 IIS 运行时,您需要在 LocalSystem 身份下运行应用程序的 AppliactionPool,或者您需要提供 read/write 访问 IISUSRS。
使用Selenium WebDriver:
- 安装 Nuget 包
Selenium.WebDriver 和 Selenium.WebDriver.ChromeDriver。
- 使用下面的代码。
public async Task<byte[]> ConvertHtmlToPdf(string html)
{
var directory = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonDocuments), "ApplicationName");
Directory.CreateDirectory(directory);
var filePath = Path.Combine(directory, $"{Guid.NewGuid()}.html");
await File.WriteAllTextAsync(filePath, html);
var driverOptions = new ChromeOptions();
// In headless mode, PDF writing is enabled by default (tested with driver major version 85)
driverOptions.AddArgument("headless");
using var driver = new ChromeDriver(driverOptions);
driver.Navigate().GoToUrl(filePath);
// Output a PDF of the first page in A4 size at 90% scale
var printOptions = new Dictionary<string, object>
{
{ "paperWidth", 210 / 25.4 },
{ "paperHeight", 297 / 25.4 },
{ "scale", 0.9 },
{ "pageRanges", "1" }
};
var printOutput = driver.ExecuteChromeCommandWithResult("Page.printToPDF", printOptions) as Dictionary<string, object>;
var pdf = Convert.FromBase64String(printOutput["data"] as string);
File.Delete(filePath);
return pdf;
}
这种方法的优点:
- 这只需要安装 Nuget 并使用最新的
HTML5 和 CSS3 功能按预期工作。输出将与您在浏览器中查看的相同。
这种方法的缺点:
- 这种方法需要在运行应用的服务器上安装最新的 chrome 浏览器。
使用这种方法,请务必在.csproj文件中添加<PublishChromeDriver>true</PublishChromeDriver>,如下所示:
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
<LangVersion>latest</LangVersion>
<Nullable>enable</Nullable>
<PublishChromeDriver>true</PublishChromeDriver>
</PropertyGroup>
这将在发布项目时发布chrome driver。
这是我的工作项目 repo 的链接 - HtmlToPdf
在使用可用选项几乎花了 2 天后,我得到了上述答案,并最终实现了基于 Selenium 的解决方案及其工作。希望这可以帮助您并节省您的时间。