因個人需求,需要將html格式轉換成PDF並加上水印圖片。於是乎第一次接觸這種需求的小菜鳥博主我,在某度搜索引擎上不斷的查閱關鍵字資料、踩坑,終於有了一個相應的解決方案。以下是解決步驟,記錄下來方便以後的回顧,以及各位大神們的品鑒。 1、在 NuGet 搜索 itextsharp 關鍵字 下載以下截 ...
因個人需求,需要將html格式轉換成PDF並加上水印圖片。於是乎第一次接觸這種需求的小菜鳥博主我,在某度搜索引擎上不斷的查閱關鍵字資料、踩坑,終於有了一個相應的解決方案。以下是解決步驟,記錄下來方便以後的回顧,以及各位大神們的品鑒。
1、在 NuGet 搜索 itextsharp 關鍵字 下載以下截圖圈中的兩個包,一般下載完後項目會自引用。
2、在項目文件中引入以下命名空間(建議下麵提及的代碼封裝成類庫,方便項目間調用,個人取捨)
3、Html字元串轉pdf文件流,加水印圖片以及未加水印重載 精簡幫助類(由博主踩坑整理,僅完成個人業務需求)
1 /// <summary> 2 /// Html字元串轉PDF輸出幫助類 3 /// </summary> 4 public class HtmlToPdfHelper 5 { 6 #region HtmlToPDF 7 8 /// <summary> 9 /// 判斷是否有亂碼 10 /// </summary> 11 /// <param name="txt"></param> 12 /// <returns></returns> 13 private static bool IsMessyCode(string txt) 14 { 15 var bytes = Encoding.UTF8.GetBytes(txt); 16 for (var i = 0; i < bytes.Length; i++) 17 { 18 if (i < bytes.Length - 3) 19 if (bytes[i] == 239 && bytes[i + 1] == 191 && bytes[i + 2] == 189) 20 { 21 return true; 22 } 23 } 24 return false; 25 } 26 27 /// <summary> 28 /// 將Html字元串 輸出到PDF檔里 29 /// </summary> 30 /// <param name="htmlText"></param> 31 /// <returns></returns> 32 public static byte[] ConvertHtmlTextToPdf(string htmlText) 33 { 34 return ConvertHtmlTextToPdf(htmlText, "", 0, 0, 0, 0); 35 } 36 37 /// <summary> 38 /// 將Html字元串 輸出到PDF檔里,並添加水印 39 /// </summary> 40 /// <param name="htmlText">網頁代碼</param> 41 /// <param name="picPath">水印路徑</param> 42 /// <param name="left">距離左邊距離</param> 43 /// <param name="top">距頂部距離</param> 44 /// <param name="width">水印寬度</param> 45 /// <param name="height">水印高度</param> 46 /// <returns></returns> 47 public static byte[] ConvertHtmlTextToPdf(string htmlText, string picPath, int left, int top, int width, int height) 48 { 49 if (string.IsNullOrEmpty(htmlText)) 50 { 51 return null; 52 } 53 //避免當htmlText無任何html tag標簽的純文字時,轉PDF時會掛掉,所以一律加上<p>標簽 54 htmlText = "<p>" + htmlText + "</p>"; 55 MemoryStream outputStream = new MemoryStream();//要把PDF寫到哪個串流 56 byte[] data = Encoding.UTF8.GetBytes(htmlText);//字串轉成byte[] 57 MemoryStream msInput = new MemoryStream(data); 58 Document doc = new Document();//要寫PDF的文件,建構子沒填的話預設直式A4 59 PdfWriter writer = PdfWriter.GetInstance(doc, outputStream); 60 //指定文件預設開檔時的縮放為100% 61 PdfDestination pdfDest = new PdfDestination(PdfDestination.XYZ, 0, doc.PageSize.Height, 1f); 62 //開啟Document文件 63 doc.Open(); 64 65 //寫入水印圖片 66 if (!string.IsNullOrEmpty(picPath)) 67 { 68 Image img = Image.GetInstance(picPath); 69 //設置圖片的位置 70 img.SetAbsolutePosition(width + left, (doc.PageSize.Height - height) - top); 71 //設置圖片的大小 72 img.ScaleAbsolute(width, height); 73 doc.Add(img); 74 } 75 try 76 { 77 //使用XMLWorkerHelper把Html parse到PDF檔里 79 XMLWorkerHelper.GetInstance().ParseXHtml(writer, doc, msInput, null, Encoding.UTF8); 80 //將pdfDest設定的資料寫到PDF檔 81 PdfAction action = PdfAction.GotoLocalPage(1, pdfDest, writer); 82 writer.SetOpenAction(action); 83 } 84 catch (Exception) 85 { 86 return null; 87 } 88 doc.Close(); 89 msInput.Close(); 90 outputStream.Close(); 91 //回傳PDF檔案 92 return outputStream.ToArray(); 94 } 95 96 #endregion 97 98 }
4、獲取網頁字元串方法
1 /// <summary> 2 /// 獲取網站內容,包含了 HTML+CSS+JS 3 /// </summary> 4 /// <returns>String返回網頁信息</returns> 5 public static string GetWebContent(string inpath) 6 { 7 try 8 { 9 WebClient myWebClient = new WebClient(); 10 //獲取或設置用於向Internet資源的請求進行身份驗證的網路憑據 11 myWebClient.Credentials = CredentialCache.DefaultCredentials; 12 //從指定網站下載數據 13 Byte[] pageData = myWebClient.DownloadData(inpath); 14 //如果獲取網站頁面採用的是GB2312,則使用這句 15 string pageHtml = Encoding.UTF8.GetString(pageData); 16 bool isBool = IsMessyCode(pageHtml);//判斷使用哪種編碼 讀取網頁信息 17 if (!isBool) 18 { 19 string pageHtml1 = Encoding.UTF8.GetString(pageData); 20 pageHtml = pageHtml1; 21 } 22 else 23 { 24 string pageHtml2 = Encoding.Default.GetString(pageData); 25 pageHtml = pageHtml2; 26 } 27 return pageHtml; 28 } 29 catch (WebException webEx) 30 { 31 return webEx.Message; 32 } 33 }
5、MVC設計模式下獲取控制器視圖Html方法,很XX的一個問題就是只能獲取調用此方法的控制器下所有視圖,不能跨控制器獲取視圖,有待優化
1 /// <summary> 2 /// 獲取MVC視圖Html 3 /// </summary> 4 /// <param name="context">控制器上下文</param> 5 /// <param name="viewName">視圖名稱</param> 6 /// <param name="param"></param> 7 /// <returns></returns> 8 public static string GetViewHtml(ControllerContext context, string viewName) 9 { 10 if (string.IsNullOrEmpty(viewName)) 11 viewName = context.RouteData.GetRequiredString("action"); 12 using (var sw = new StringWriter()) 13 { 14 ViewEngineResult viewResult = ViewEngines.Engines.FindPartialView(context, viewName); 15 var viewContext = new ViewContext(context, viewResult.View, context.Controller.ViewData, context.Controller.TempData, sw); 16 try 17 { 18 viewResult.View.Render(viewContext, sw); 19 } 20 catch (Exception ex) 21 { 22 throw; 23 } 24 25 return sw.GetStringBuilder().ToString(); 26 } 27 }
6、將pdf流輸出至客戶瀏覽器下載方法
1 /// <summary> 2 /// 將pdf文件流輸出至瀏覽器下載 3 /// </summary> 4 /// <param name="pdfFile">PDF文件流</param> 5 public static void PdfDownload(byte[] pdfFile) 6 { 7 byte[] buffer = pdfFile; 8 Stream iStream = new MemoryStream(buffer); 9 try 10 { 11 int length; 12 long dataToRead; 13 string filename = DateTime.Now.ToString("yyyyMMddHHmmss") + ".pdf";//保存的文件名稱 14 dataToRead = iStream.Length; 15 HttpContext.Current.Response.Clear(); 16 HttpContext.Current.Response.ClearHeaders(); 17 HttpContext.Current.Response.ClearContent(); 18 HttpContext.Current.Response.ContentType = "application/pdf"; //文件類型 19 HttpContext.Current.Response.AddHeader("Content-Length", dataToRead.ToString());//添加文件長度,進而顯示進度 20 HttpContext.Current.Response.AddHeader("Content-Disposition", "attachment; filename=" + HttpUtility.UrlEncode(filename, Encoding.UTF8)); 21 while (dataToRead > 0) 22 { 23 if (HttpContext.Current.Response.IsClientConnected) 24 { 25 length = buffer.Length; 26 HttpContext.Current.Response.OutputStream.Write(buffer, 0, length); 27 HttpContext.Current.Response.Flush(); 28 buffer = new Byte[length]; 29 dataToRead = dataToRead - length; 30 } 31 else 32 { 33 dataToRead = -1; 34 } 35 } 36 } 37 catch (Exception ex) 38 { 39 HttpContext.Current.Response.Write("文件下載時出現錯誤!"); 40 } 41 finally 42 { 43 if (iStream != null) 44 { 45 iStream.Close(); 46 } 47 //結束響應,否則將導致網頁內容被輸出到文件,進而文件無法打開 48 HttpContext.Current.Response.Flush(); 49 HttpContext.Current.Response.End(); 50 51 } 52 }
7、MVC控制器下調用Demo(步驟4、6 方法封裝至幫助類)
1 public class HomeController : Controller 2 { 3 // 4 // GET: /Home/ 5 6 public ActionResult Index() 7 { 8 //從網址下載Html字元串(方法一) 9 string inpath = System.Web.HttpContext.Current.Server.MapPath("~/PDFTemplate/test.html"); 10 string htmlText = HtmlToPdfHelper.GetWebContent(inpath);//此處調用步驟4方法 11 12 //獲取MVC視圖Html字元串(方法二) 13 //string htmlText = GetViewHtml(ControllerContext, "Test");//此處調用步驟5方法 14 15 //水印圖片路徑 16 string picPath = Server.MapPath("~/PDFTemplate/TemplateImg/authentication-iocn.png"); 17 //html轉pdf並加上水印 18 byte[] pdfFile = HtmlToPdfHelper.ConvertHtmlTextToPdf(htmlText, picPath, 100, 200, 100, 100); 19 //輸出至客戶端 20 HtmlToPdfHelper.PdfDownload(pdfFile);//此處調用步驟6方法 21 22 return View(); 23 } 24 25 public ActionResult Test() 26 { 27 return View(); 28 } 29 30 /// <summary> 31 /// 獲取MVC視圖Html 32 /// </summary> 33 /// <param name="context"></param> 34 /// <param name="viewName">視圖名稱</param> 35 /// <returns></returns> 36 public static string GetViewHtml(ControllerContext context, string viewName) 37 { 38 if (string.IsNullOrEmpty(viewName)) 39 viewName = context.RouteData.GetRequiredString("action"); 40 using (var sw = new StringWriter()) 41 { 42 ViewEngineResult viewResult = ViewEngines.Engines.FindPartialView(context, viewName); 43 var viewContext = new ViewContext(context, viewResult.View, context.Controller.ViewData, 44 context.Controller.TempData, sw); 45 try 46 { 47 viewResult.View.Render(viewContext, sw); 48 } 49 catch (Exception ex) 50 { 51 throw; 52 } 53 54 return sw.GetStringBuilder().ToString(); 55 } 56 } 57 }
總結:我理解的解決思路是將html讀取轉換成字元串,之後再通過 itextsharp 轉換成 pdf 比特流 傳輸至客戶端或直接保存至伺服器生成鏈接供用戶下載。(新手上路,不妥之處,歡迎各位大神指教)
以上代碼僅滿足個人業務邏輯需求,如侵刪,謝謝瀏覽,交流反饋QQ:414796825(請註明來源:博客) 。