ASP.Net MVC——使用 ITextSharp 完美解決HTML轉PDF(中文也能夠)

前言:html

最近在作老師交代的一個在線寫實驗報告的小項目中,有這麼個需求:把學生提交的實驗報告(HTML形式)直接轉成PDF,方便下載和打印。ajax

之前都是直接用rdlc報表實現的,可此次牽扯到圖片,而且更爲重要的一點是 PDF的格式得跟學生提交的HMTL頁面同樣。通過網上查閱資料,數組

找到了ITextSharp插件。app

ITextSharp很強大,可是在處理HMTL中的 img標籤時,src中只能是絕對路徑。 ide

解決方法我寫在了另外一篇文章中字體

正文:ui

ITextSharp就很少介紹了。項目的連接下載連接爲http://files.cnblogs.com/files/zuochengsi-9/H%E8%BD%ACPDF.zipthis

下開始項目以前得添加 ITextSharp.dll和ITextSharp.xmlworker.dll  後者是解決中文用的spa

能夠從NuGet中下載引用,具體方法就不介紹了。網上不少解決方案。插件

項目結構圖:

下面先說下主要操做:

步驟:一、將本地的某個視圖轉成字符串。

         二、將字符串整合成PDF的文檔,並返回byte數組。

         三、講比特流寫到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的文件,建構子沒填的話預設直式A4
            PdfWriter 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的文件,建構子沒填的話預設直式A4
            PdfWriter 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)。

@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

相關文章
相關標籤/搜索