最近领导给了一个新的需求:给了我一个html页面,让我导出Pdf页面
由于以前没有搞过这方面的需求,所以查百度找资料,找了一大堆的好东西,像ItextSharp和wkhtmltopdf
废话不说,进入正题
ItextSharp对Html5的canvas和css,js等支持不是很好,只适用于简单的页面导出。故放弃
导出方法一:使用wkhtmltopdf
这个需要安装wkhtmltopdf: https://wkhtmltopdf.org/downloads.html 下面的变量就是wkhtmltopdf的安装目录
1 public ActionResult ExportSocialPDF(int testerid) 2 { 3 try 4 { 5 var tester = _testerBll.Details(testerid); 6 string folder = string.Format("~/Temp/{0}", DateTime.Now.ToString("yyyyMMdd")); 7 if (!System.IO.Directory.Exists(Server.MapPath(folder))) 8 { 9 System.IO.Directory.CreateDirectory(Server.MapPath(folder)); 10 } 11 string fileName = string.Format("{0}-社会综合素质测试{1}", tester.name, DateTime.Now.ToString("yyyyMMddHHmmss")); 12 string pdfpath = fileName + ".pdf"; 13 ExportSocialPDFCore(tester, folder, pdfpath); 14 string filePath = Server.MapPath(folder) + "/" + pdfpath; 15 new System.Threading.Thread(DeleteOldFileFolder).Start(); 16 return File(filePath, "application/octet-stream", System.IO.Path.GetFileName(filePath)); 17 } 18 catch (Exception ex) 19 { 20 log.Error(ex); 21 return View(ex); 22 } 23 }
1 public void ExportSocialPDFCore(HqftTestPaper.Entity.t_testerEntity tester, string folder, string pdfpath) 2 { 3 string pdf = @"C:Program Fileswkhtmltopdfinwkhtmltopdf.exe"; 4 //string url = "http://localhost/TestManage/WordTemplate/index.html"; 5 string url = Url.Action("ExportPreview", "ExportPDF", new { testerid = tester.id }); 6 7 url = string.Format("http://{0}:{1}{2}",Request.Url.Host, Request.Url.Port, url); 8 9 string add = url + " "" + Server.MapPath(folder + "/" + pdfpath) + """; 10 Process p = System.Diagnostics.Process.Start(pdf, add); 11 p.WaitForExit(); 12 }
1 public void DeleteOldFileFolder() 2 { 3 string strPath = Server.MapPath("~/Temp/"); 4 string[] fileNames = System.IO.Directory.GetDirectories(strPath); 5 foreach (string fileName in fileNames) 6 { 7 string name = fileName.Substring(strPath.Length); 8 if (string.Compare(DateTime.Now.ToString("yyyyMMdd"), name) > 0) 9 { 10 System.IO.Directory.Delete(fileName, true); 11 } 12 } 13 }
注释:
1、t_testerEntity是个需要导出的测试者的类,大家可以自行脑补,只要一个id获取数据就可以了
2、此方法是现在本地生成一个Pdf,然后把路径传到View让浏览器下载,所以需要一个删除旧文件的方法
3、根据cshtml下载的页面,必须能够无限制的访问,就是直接把路径贴在浏览器中可以直接访问。
如果为了系统安全性,加了访问限制的,需要新建一个不受限制的Controller
导出方法二:页面先截图,然后生成Pdf
这个用的是Winform的WebBrowser控件,有限制:你的IE和你的WebBrowser内核可能不是一个版本的。Css支持率极低。个人认为不好用
1 using iTextSharp.text; 2 using iTextSharp.text.pdf; 3 using System; 4 using System.Drawing; 5 using System.IO; 6 using System.Threading; 7 using System.Windows.Forms; 8 9 namespace ExportPDF.Common 10 { 11 public class HtmlToPdf 12 { 13 WebBrowser webBrowser; 14 15 public void ConvertToImage(object url) 16 { 17 //string strUrl = "http://echarts.baidu.com/demo.html#pie-legend"; 18 webBrowser = new WebBrowser(); 19 //改变webBrowser内核版本 20 WebBrowserOper.BrowserEmulationSet(); 21 webBrowser.AllowNavigation = true; 22 webBrowser.Url = new Uri(url.ToString()); 23 webBrowser.ScrollBarsEnabled = true; 24 DateTime dtime = DateTime.Now; 25 double timespan = 0; 26 while (timespan < 10 || webBrowser.ReadyState != WebBrowserReadyState.Complete) 27 { 28 Application.DoEvents(); 29 DateTime time2 = DateTime.Now; 30 timespan = (time2 - dtime).TotalSeconds; 31 } 32 33 if (webBrowser.ReadyState == WebBrowserReadyState.Complete) 34 { 35 //htmlstr = webBrowser.DocumentText; 36 webBrowser_DocumentCompleted(); 37 } 38 //string html = ""; 39 40 //webBrowser.DocumentText = html; 41 } 42 43 /// <summary> 44 /// 在单线程中启用浏览器 45 /// </summary> 46 public void RunWithSingleThread() 47 { 48 string url = "http://localhost/Export/template/index.html"; 49 ParameterizedThreadStart ps = new ParameterizedThreadStart(ConvertToImage); 50 Thread t = new Thread(ps); 51 t.IsBackground = true; 52 t.SetApartmentState(ApartmentState.STA); 53 t.Start(url); 54 } 55 56 private void webBrowser_DocumentCompleted() 57 { 58 //获取解析后HTML的大小 59 System.Drawing.Rectangle rectangle = webBrowser.Document.Body.ScrollRectangle; 60 int width = rectangle.Width; 61 int height = rectangle.Height; 62 63 //设置解析后HTML的可视区域 64 webBrowser.Width = width; 65 webBrowser.Height = height; 66 67 Bitmap bitmap = new System.Drawing.Bitmap(width, height); 68 webBrowser.DrawToBitmap(bitmap, new System.Drawing.Rectangle(0, 0, width, height)); 69 70 //设置图片文件保存路径和图片格式,格式可以自定义 71 string filePath = AppDomain.CurrentDomain.BaseDirectory + "/SaveFile/" + DateTime.Now.ToString("yyyyMMddHHmmssfff") + ".png"; 72 bitmap.Save(filePath, System.Drawing.Imaging.ImageFormat.Png); 73 74 //创建PDF 75 FileStream fileStream = new FileStream(AppDomain.CurrentDomain.BaseDirectory + "/SaveFile/" + DateTime.Now.ToString("yyyyMMddHHmmssfff") + ".pdf", FileMode.Create); 76 77 byte[] result = CreatePDF(bitmap, width, height); 78 79 fileStream.Write(result, 0, result.Length); 80 81 fileStream.Close(); 82 fileStream.Dispose(); 83 } 84 85 private byte[] CreatePDF(Bitmap bitmap, int width, int height) 86 { 87 using (MemoryStream ms = new MemoryStream()) 88 { 89 Document doc = new Document(new iTextSharp.text.Rectangle(0, 0, width, height), 3, 3, 3, 3); // 左右上下 90 91 PdfWriter writer = PdfWriter.GetInstance(doc, ms); 92 93 writer.CloseStream = false; 94 95 doc.Open(); 96 97 iTextSharp.text.Image img = iTextSharp.text.Image.GetInstance(bitmap, System.Drawing.Imaging.ImageFormat.Png); 98 99 img.ScalePercent(100); // 放缩比例 100 101 doc.Add(img); // 添加图片对像 102 doc.Close(); 103 104 return ms.ToArray(); 105 } 106 } 107 } 108 }
1 using Microsoft.Win32; 2 using System; 3 using System.Diagnostics; 4 5 namespace ExportPDF.Common 6 { 7 public static class WebBrowserOper 8 { 9 public static void WebBrowserVersionEmulation() 10 { 11 const string BROWSER_EMULATION_KEY = @"SOFTWAREWow6432NodeMicrosoftInternet ExplorerMAINFeatureControlFEATURE_BROWSER_EMULATION"; 12 //const string BROWSER_EMULATION_KEY = @"SoftwareMicrosoftInternet ExplorerMainFeatureControlFEATURE_BROWSER_EMULATION"; 13 14 // app.exe and app.vshost.exe 15 RegistryKey browserEmulationKey = Registry.LocalMachine.OpenSubKey(BROWSER_EMULATION_KEY,RegistryKeyPermissionCheck.ReadWriteSubTree) ?? Registry.LocalMachine.CreateSubKey(BROWSER_EMULATION_KEY); 16 //RegistryKey browserEmulationKey = Registry.CurrentUser.OpenSubKey(BROWSER_EMULATION_KEY,RegistryKeyPermissionCheck.ReadWriteSubTree) ?? Registry.LocalMachine.CreateSubKey(BROWSER_EMULATION_KEY); 17 if (browserEmulationKey != null) 18 { 19 String appname = Process.GetCurrentProcess().ProcessName + ".exe"; 20 //Webpages are displayed in IE10 Standards mode, regardless of the !DOCTYPE directive. 21 const int browserEmulationMode = 10000; 22 23 if ((int)browserEmulationKey.GetValue(appname) != 1000) 24 { 25 browserEmulationKey.SetValue(appname, browserEmulationMode, RegistryValueKind.DWord); 26 } 27 browserEmulationKey.Close(); 28 } 29 } 30 31 32 33 /// <summary> 34 /// IE WebBrowser内核设置 35 /// </summary> 36 public static void BrowserEmulationSet() 37 { 38 //当前程序名称 39 var exeName = Process.GetCurrentProcess().ProcessName + ".exe"; 40 //系统注册表信息 41 var mreg = Registry.LocalMachine; 42 //IE注册表信息 43 var ie = mreg.OpenSubKey(@"SOFTWAREMicrosoftInternet ExplorerMAINFeatureControlFEATURE_BROWSER_EMULATION", RegistryKeyPermissionCheck.ReadWriteSubTree); 44 if (ie != null) 45 { 46 try 47 { 48 var val = ieVersionEmulation(ieVersion()); 49 if (val != 0) 50 { 51 ie.SetValue(exeName, val); 52 } 53 mreg.Close(); 54 } 55 catch (Exception ex) 56 { 57 Console.Write(ex.Message); 58 } 59 } 60 } 61 62 /// <summary> 63 /// IE版本号 64 /// </summary> 65 /// <returns></returns> 66 static int ieVersion() 67 { 68 //IE版本号 69 RegistryKey mreg = Registry.LocalMachine; 70 mreg = mreg.CreateSubKey("SOFTWARE\Microsoft\Internet Explorer"); 71 72 //更新版本 73 var svcVersion = mreg.GetValue("svcVersion"); 74 if (svcVersion != null) 75 { 76 mreg.Close(); 77 var v = svcVersion.ToString().Split('.')[0]; 78 return int.Parse(v); 79 } 80 else 81 { 82 //默认版本 83 var ieVersion = mreg.GetValue("Version"); 84 mreg.Close(); 85 if (ieVersion != null) 86 { 87 var v = ieVersion.ToString().Split('.')[0]; 88 return int.Parse(v); 89 } 90 } 91 return 0; 92 } 93 94 /// <summary> 95 /// 根据IE版本号 返回Emulation值 96 /// </summary> 97 /// <param name="ieVersion"></param> 98 /// <returns></returns> 99 static int ieVersionEmulation(int ieVersion) 100 { 101 //IE7 7000 (0x1B58) 102 if (ieVersion < 8) 103 { 104 return 0; 105 } 106 if (ieVersion == 8) 107 { 108 return 0x1F40;//8000 (0x1F40)、8888 (0x22B8) 109 } 110 if (ieVersion == 9) 111 { 112 return 0x2328;//9000 (0x2328)、9999 (0x270F) 113 } 114 else if (ieVersion == 10) 115 { 116 return 0x02710;//10000 (0x02710)、10001 (0x2711) 117 } 118 else if (ieVersion == 11) 119 { 120 return 0x2AF8;//11000 (0x2AF8)、11001 (0x2AF9 121 } 122 return 0; 123 } 124 } 125 }
另外还有一个导出Html的
1 using System.IO; 2 using System.Text; 3 using System.Web; 4 5 namespace ExportPDF.Common 6 { 7 public class ExportHtml 8 { 9 public void TemplateExport() 10 { 11 string templatePath = HttpContext.Current.Server.MapPath("~/Template/") + "index.html"; 12 string template = ""; 13 using (StreamReader sr = new StreamReader(templatePath)) 14 { 15 template=sr.ReadToEnd(); 16 } 17 //新的内容 18 StringBuilder context = new StringBuilder(); 19 /* 20 foreach (Student stu in stulist) 21 { 22 context.Append("<tr>"); 23 context.Append("<td>" + stu.XueHao + "</td><td>" + stu.XingMing + "</td>"); 24 context.Append("</tr>"); 25 } 26 string newContext = template.Replace("$student$", context.ToString()); 27 */ 28 //把newContext写入报表中 29 string path = HttpContext.Current.Server.MapPath("~/SaveFile/") + "report.html"; 30 using (StreamWriter sw = new StreamWriter(path, false)) 31 { 32 sw.WriteLine(template); 33 } 34 } 35 } 36 }
言尽于此