ASP.Net MVC——使用 ITextSharp 完美解决HTML转PDF(中文也可以)
前言:
最近在做老師交代的一個在線寫實驗報告的小項目中,有這么個需求:把學生提交的實驗報告(HTML形式)直接轉成PDF,方便下載和打印。
以前都是直接用rdlc報表實現的,可這次牽扯到圖片,并且更為重要的一點是 PDF的格式得跟學生提交的HMTL頁面一樣。經過網上查閱資料,
找到了ITextSharp插件。
ITextSharp很強大,但是在處理HMTL中的 img標簽時,src中只能是絕對路徑。?
解決方法我寫在了另一篇文章中
正文:
ITextSharp就不多介紹了。項目的鏈接下載鏈接為http://files.cnblogs.com/files/zuochengsi-9/H%E8%BD%ACPDF.zip
下開始項目之前得添加 ITextSharp.dll和ITextSharp.xmlworker.dll ?后者是解決中文用的
可以從NuGet中下載引用,具體方法就不介紹了。網上很多解決方案。
項目結構圖:
下面先說下主要操作:
步驟:1、將本地的某個視圖轉成字符串。
???????? 2、將字符串整合成PDF的文檔,并返回byte數組。
???????? 3、講比特流寫到HTTP內容主體的二進制流中去。
?
?視圖轉字符串代碼:
首先新建兩個類,轉字符串的邏輯主要在RenderViewToString方法中。
public class HtmlViewRenderer{public string RenderViewToString(Controller controller, string viewName, object viewData){var renderedView = new StringBuilder();using (var responseWriter = new StringWriter(renderedView)){var fakeResponse = new HttpResponse(responseWriter);var fakeContext = new HttpContext(HttpContext.Current.Request, fakeResponse);var fakeControllerContext = new ControllerContext(new HttpContextWrapper(fakeContext), controller.ControllerContext.RouteData, controller.ControllerContext.Controller);var oldContext = HttpContext.Current;HttpContext.Current = fakeContext;using (var viewPage = new ViewPage()){var html = new HtmlHelper(CreateViewContext(responseWriter, fakeControllerContext), viewPage);html.RenderPartial(viewName,viewData);HttpContext.Current = oldContext;}}return renderedView.ToString();}private static ViewContext CreateViewContext(TextWriter responseWriter, ControllerContext fakeControllerContext){return new ViewContext(fakeControllerContext, new FakeView(), new ViewDataDictionary(), new TempDataDictionary(), responseWriter);}} public class FakeView : IView{public void Render(ViewContext viewContext, TextWriter writer){throw new NotImplementedException();}}?
再新建一個控制器,調用剛剛寫好的RenderViewToString方法。(后面會再新建一個HomeController,繼承這個PdfViewController,再在HomeController的Action里調用ViewPdf就行)
public class PdfViewController : Controller{private readonly HtmlViewRenderer htmlViewRenderer;public PdfViewController(){this.htmlViewRenderer = new HtmlViewRenderer();}protected string ViewPdf(string viewName,object model){// Render the view html to a string.string htmlText = this.htmlViewRenderer.RenderViewToString(this, viewName,model);return htmlText;}}"字符串轉byte[]"?? (這個方法放在后面寫的HomeController中)
public byte[] ConvertHtmlTextToPDF(string htmlText){if (string.IsNullOrEmpty(htmlText)){return null;}//避免當htmlText無任何html tag標籤的純文字時,轉PDF時會掛掉,所以一律加上<p>標籤htmlText = "<p>" + htmlText + "</p>";MemoryStream outputStream = new MemoryStream();//要把PDF寫到哪個串流byte[] data = Encoding.UTF8.GetBytes(htmlText);//字串轉成byte[]MemoryStream msInput = new MemoryStream(data);Document doc = new Document();//要寫PDF的文件,建構子沒填的話預設直式A4PdfWriter writer = PdfWriter.GetInstance(doc, outputStream);//指定文件預設開檔時的縮放為100%PdfDestination pdfDest = new PdfDestination(PdfDestination.XYZ, 0, doc.PageSize.Height, 1f);//開啟Document文件 doc.Open();//使用XMLWorkerHelper把Html parse到PDF檔裡XMLWorkerHelper.GetInstance().ParseXHtml(writer, doc, msInput, null, Encoding.UTF8, new UnicodeFontFactory());//將pdfDest設定的資料寫到PDF檔PdfAction action = PdfAction.GotoLocalPage(1, pdfDest, writer);writer.SetOpenAction(action);doc.Close();msInput.Close();outputStream.Close();//回傳PDF檔案 return outputStream.ToArray();}其中XMLWorkerHelper.GetInstance().ParseXHtml(writer, doc, msInput,?null, Encoding.UTF8,?new?UnicodeFontFactory());這段代碼中的“UnicodeFontFactory”類,封裝了中文字體的設置。代碼如下:
?
public class UnicodeFontFactory : FontFactoryImp {private static readonly string arialFontPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Fonts),"arialuni.ttf");//arial unicode MS是完整的unicode字型。private static readonly string 標楷體Path = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Fonts),"KAIU.TTF");//標楷體public override Font GetFont(string fontname, string encoding, bool embedded, float size, int style, BaseColor color,bool cached){//可用Arial或標楷體,自己選一個BaseFont baseFont = BaseFont.CreateFont(標楷體Path, BaseFont.IDENTITY_H, BaseFont.EMBEDDED);return new Font(baseFont, size, style, color);} }?
再新建一個類,用來將比特流輸出到response.OutputStream中:
?
public class BinaryContentResult : ActionResult{private readonly string contentType;private readonly byte[] contentBytes;public BinaryContentResult(byte[] contentBytes, string contentType){this.contentBytes = contentBytes;this.contentType = contentType; }public override void ExecuteResult(ControllerContext context){var response = context.HttpContext.Response;response.Clear();response.Cache.SetCacheability(HttpCacheability.Public);response.ContentType = this.contentType;//下面這段加上就是一個下載頁面
response.AppendHeader("Content-Disposition", "attachment;filename=" + HttpUtility.UrlEncode("文件名.pdf", System.Text.Encoding.UTF8));
using (var stream = new MemoryStream(this.contentBytes)){stream.WriteTo(response.OutputStream);stream.Flush();}}}
?
現在來看一下HomeController
using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Net; using System.Text; using System.Web; using System.Web.Mvc; using HTML轉PDF.Models; using iTextSharp.text; using iTextSharp.text.pdf; using iTextSharp.tool.xml; using ReportManagement;namespace HTML轉PDF.Controllers {public class HomeController :PdfViewController{//// GET: /Home/public ActionResult Index(){return View();}/// <summary>/// 執行此Url,下載PDF檔案/// </summary>/// <returns></returns>public ActionResult DownloadPdf(){var person = new People("左成");string htmlText = this.ViewPdf("Preview",person);byte[] pdfFile = this.ConvertHtmlTextToPDF(htmlText);return new BinaryContentResult(pdfFile, "application/pdf");}/// <summary>/// 將Html文字 輸出到PDF檔裡/// </summary>/// <param name="htmlText"></param>/// <returns></returns>public byte[] ConvertHtmlTextToPDF(string htmlText){if (string.IsNullOrEmpty(htmlText)){return null;}//避免當htmlText無任何html tag標籤的純文字時,轉PDF時會掛掉,所以一律加上<p>標籤htmlText = "<p>" + htmlText + "</p>";MemoryStream outputStream = new MemoryStream();//要把PDF寫到哪個串流byte[] data = Encoding.UTF8.GetBytes(htmlText);//字串轉成byte[]MemoryStream msInput = new MemoryStream(data);Document doc = new Document();//要寫PDF的文件,建構子沒填的話預設直式A4PdfWriter writer = PdfWriter.GetInstance(doc, outputStream);//指定文件預設開檔時的縮放為100%PdfDestination pdfDest = new PdfDestination(PdfDestination.XYZ, 0, doc.PageSize.Height, 1f);//開啟Document文件 doc.Open();//使用XMLWorkerHelper把Html parse到PDF檔裡XMLWorkerHelper.GetInstance().ParseXHtml(writer, doc, msInput, null, Encoding.UTF8, new UnicodeFontFactory());//將pdfDest設定的資料寫到PDF檔PdfAction action = PdfAction.GotoLocalPage(1, pdfDest, writer);writer.SetOpenAction(action);doc.Close();msInput.Close();outputStream.Close();//回傳PDF檔案 return outputStream.ToArray();}} }步驟二的ConvertHtmlTextToPDF方法,我就直接放在了這里面,沒管那些設計原則了。上面代碼中“Preview”是本地的一個視圖,最好和HomeController在一個區域里面,不然得改步驟一的代碼。
?最后是我的前臺部分的代碼,寫的很簡單(Preview.cshtml)。
| 1 2 3 4 | @model HTML轉PDF.Models.People ??<!-- 下面是我機器上的絕對路徑? -->???????? <img src="E:\12.bmp"?width="64"?height="64"?/> <p>大家好,我叫"@Model.Name"</p> |
特別注意:關于跳轉到我們寫的“DownloadPdf”Action時,千萬不要用ajax.ActionLink(坑了我好久)。不然會出現亂碼,我也沒找到解決方案。
參考資料:http://www.tuicool.com/articles/aUfqeu
???????http://dwtedx.com/itshare_233.html
?
?轉載請注明出處:http://www.cnblogs.com/zuochengsi-9/p/5483808.html
?
轉載于:https://www.cnblogs.com/waw/p/7235894.html
總結
以上是生活随笔為你收集整理的ASP.Net MVC——使用 ITextSharp 完美解决HTML转PDF(中文也可以)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 处理Img标签中src无效时出现的bor
- 下一篇: SQL建表公共字段脚本