运行以下代码行时,使用DinkToPdf
库将html转换为PDF的过程需要很长的时间:ConverterToPdf.Convert(pdf)
我该如何解决这个问题?
public byte[] ConvertReportToPDFAsync<TViewModel>() where TViewModel : new()
{
var globalSettings = new GlobalSettings
{
ColorMode = ColorMode.Color,
Orientation = Orientation.Portrait,
PaperSize = PaperKind.A4,
Margins = new MarginSettings { Top = 10 },
DocumentTitle = documentTitle,
};
var objectSettings = new ObjectSettings
{
PagesCount = true,
HtmlContent =@"<html><body><div>Hello</div></body></html>",
WebSettings = { DefaultEncoding = "utf -8", UserStyleSheet = Path.Combine(Directory.GetCurrentDirectory(), "assets", "PruefReportDataTableFormat.css") },
HeaderSettings = { FontName = "Arial", FontSize = 9, Right = "Page [page] of [toPage]", Line = true },
FooterSettings = { FontName = "Arial", FontSize = 9, Line = true, Center = "Report Footer" }
};
var pdf = new HtmlToPdfDocument()
{
GlobalSettings = globalSettings,
Objects = { objectSettings }
};
byte[] file = ConverterToPdf.Convert(pdf); // TOO LONG PROCESS !!!!
return file;
}
启动课程:
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddHttpContextAccessor();
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
services.AddMemoryCache(); services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1).AddSessionStateTempDataProvider();
services.AddSingleton(typeof(IConverter), new SynchronizedConverter(new PdfTools())); // DinkToPdf
}
}
已更新:
跟踪后,我发现问题出在 WkHtmlToXBindings.wkhtmltopdf_convert
方法 namespace DinkToPdf
namespace DinkToPdf
{
public sealed class PdfTools : ITools, IDisposable
{
// some codes
public bool DoConversion(IntPtr converter)
{
return WkHtmlToXBindings.wkhtmltopdf_convert(converter); // ACTUALLY TOO LONG PROCESS OCCURS HERE !!!!
}
}
}
更新2:
深入研究之后,我发现在这行代码中, Monitor.Wait((object) task1);
是一个漫长的过程!
(我无法更改此代码,因为该代码是dinktopdf.dll
文件的一部分。)
namespace DinkToPdf
{
public class SynchronizedConverter : BasicConverter
{
public TResult Invoke<TResult>(Func<TResult> @delegate)
{
this.StartThread();
Task<TResult> task1 = new Task<TResult>(@delegate);
Task<TResult> task2 = task1;
bool lockTaken = false;
try
{
Monitor.Enter((object) task2, ref lockTaken);
this.conversions.Add((Task) task1);
Monitor.Wait((object) task1); //Bottleneck!! LONG PROCESS!!
}
finally
{
if (lockTaken)
Monitor.Exit((object) task2);
}
if (task1.Exception != null)
throw task1.Exception;
return task1.Result;
}
}
}
答案 0 :(得分:0)
我看不到您如何获得ConverterToPdf
,但可以尝试以下操作:如果在服务中使用var converter = new SynchronizedConverter(new PdfTools());´, remove it, and just inject
IConverter`初始化转换器。
我尝试过并且这种方法有效,毕竟,我们已经注册了转换器,我们不需要使用new
关键字来创建实例。
答案 1 :(得分:0)
这是您在Startup.cs上创建的单例,因此首先需要执行的是用依赖项注入填充根对象。
private readonly IConverter _converter;
public YourControllerService(IConverter converter)
{
_converter = converter
}
public void CreatePdf() {
byte[] bytes = _converter.Convert(doc);
}
其次,请确保使用网络安全字体来加快渲染速度。在html内部使用来自外部url的字体会减慢该过程。例如,假设这是您的html模板,您有5个页面:
<html>
<head>
<style>
@import url('https://fonts.googleapis.com/css?family=Source+Sans+Pro:300,700');
body {
font-family: 'Source Sans Pro', sans-serif;
}
<style>
<head>
</html>
如果您通过以下方式对此进行更改:
<html>
<head>
<style>
body {
font-family: 'Verdana';
}
<style>
<head>
</html>
您将看到速度差异。另外,根据我的经验,降低DPI也会影响渲染速度。
var doc = new HtmlToPdfDocument()
{
GlobalSettings = {
ColorMode = ColorMode.Color,
Orientation = Orientation.Landscape,
PaperSize = PaperKind.A4,
DPI = 320,
Out = path
},
Objects = {
new ObjectSettings() {
PagesCount = true,
HtmlContent = html,
WebSettings = { DefaultEncoding = "UTF-8", LoadImages = true },
FooterSettings = { FontSize = 8, Right = "Page [page] of [toPage]", Line = false, Spacing = 2.812 }
}
}
};
byte[] bytes = _converter.Convert(doc);
希望有帮助。