前段时间由于项目上的需求,要在.Net平台下实现把HTML内容生成图片或PDF文件的功能,特意在网上研究了几种方案,这里记录一下以备日后再次使用。当时想着找一种开发部署都比较清爽并且运行稳定的方案,但实际上两者同时满足基本不可能,只能做一个自己觉得合适的取舍,下面从两个维度(清爽指数和功能指数)逐一对比。
1. WebBrowser
这种方案在开发时不依赖任务外部程序集和nuget包,部署时也不需要安装额外的工具和服务,可以说是非常清爽了。它借助了WinForm下的WebBrowser控件实现HTML内容渲染,并把渲染结果绘制在Bitmap中,进而保存成图片或PDF文件。这种方案简单粗暴,是C#中最基础的实现方式,也是网上搜索结果最多的一种,下面看它的核心代码(从网上拼凑得来):
1 class WebBrowserPage2Image 2 { 3 Bitmap m_Bitmap; 4 5 string m_Url; 6 7 public void Convert(string pageUrl, string fileName) 8 { 9 m_Url = pageUrl; 10 Thread m_thread = new Thread(new ThreadStart(HtmlDrawToBitmap)); 11 m_thread.SetApartmentState(ApartmentState.STA); 12 m_thread.IsBackground = true; 13 m_thread.Start(); 14 m_thread.Join(); 15 MemoryStream stream = new MemoryStream(); 16 m_Bitmap.Save(stream, System.Drawing.Imaging.ImageFormat.Png); 17 byte[] buff = stream.ToArray(); 18 FileStream fs = new FileStream(fileName, FileMode.Create); 19 stream.WriteTo(fs); 20 stream.Dispose(); 21 stream.Close(); 22 fs.Close(); 23 } 24 25 private void HtmlDrawToBitmap() 26 { 27 WebBrowser browser = new WebBrowser(); 28 browser.ScrollBarsEnabled = false; 29 browser.Navigate(m_Url); 30 browser.DocumentCompleted += new WebBrowserDocumentCompletedEventHandler(delegate (object sender, WebBrowserDocumentCompletedEventArgs bdce) 31 { 32 if (browser.ReadyState == WebBrowserReadyState.Complete) 33 { 34 //myWebBrowser.Document.Body.Style = "zoom:180%"; 35 Rectangle r = browser.Document.Body.ScrollRectangle; 36 browser.Height = r.Height; 37 browser.Width = r.Width; 38 m_Bitmap = new Bitmap(browser.Width, browser.Height); 39 browser.BringToFront(); 40 browser.DrawToBitmap(m_Bitmap, new Rectangle() { Width = browser.Width, Height = browser.Height }); 41 } 42 }); 43 while (browser.ReadyState != WebBrowserReadyState.Complete) 44 { 45 Application.DoEvents(); 46 } 47 browser.Dispose(); 48 } 49 }
虽然开发起来非常简洁,但是问题也很明显。WebBrowser是Winform下的一个组件,在非Winform项目中运行会出现不可知的异常,即使在Winform项目中,数据量比较大的时候依然会出现卡死的情况。我做过500次循环的测试,在执行到100多次的时候程序出现假死不动也无异常抛出。除此之外,生成的图片失真也比较严重,特殊字体和部分CSS样式无法渲染。总的来说,基本无法达到生成环境需求。
清爽指数:★★★★★ 功能指数:★
2. Wkhtmltox
这也是网上广泛流传的一个方案,wkhtmltox是一套开源的命令行工具,提供了图片和PDF的转换能力,它采用C++编写,使用Webkit作为渲染引擎,开源地址是https://github.com/wkhtmltopdf/wkhtmltopdf。使用方法就是在命令行工具中执行命令,例如:
wkhtmltopdf --grayscale https://www.baidu.com baidu.pdf
如果要在.Net项目中使用的话,核心问题就是用程序唤起命令行,同时指定参数执行即可,类似于下面的代码:
System.Diagnostics.ProcessStartInfo Info = new System.Diagnostics.ProcessStartInfo(); Info.FileName = @"D:\dev\wkhtmltox\bin\wkhtmltopdf.exe"; Info.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden; Info.CreateNoWindow = true; Info.Arguments = @"-q --orientation Landscape https://www.baidu.com D:\\baidu.pdf"; System.Diagnostics.Process proc = System.Diagnostics.Process.Start(Info); proc.WaitForExit(); proc.Close();
更多强大的功能例如加水印、分页、改样式等可以参考这篇文章:https://www.cnblogs.com/82xb/p/7837597.html
详细的参数说明可以查看文档:https://wkhtmltopdf.org/usage/wkhtmltopdf.txt
GitHub上有很多针对各个开发语言的封装,使用起来比较方便,唯一不爽的是部署项目前要先安装好这个工具。
清爽指数:★★★★ 功能指数:★★★★