asp.net MVC設計模式中使用iTextSharp實現html字元串生成PDF文件

来源:https://www.cnblogs.com/GongQun/archive/2018/07/24/9360250.html
-Advertisement-
Play Games

因個人需求,需要將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(請註明來源:博客) 。

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • /// /// API接收Base64轉圖片 /// /// 圖片位元組 /// 儲存地址 /// public IHttpActionResult Index(String Img, String Path) { //轉圖片 byte[] bit = Convert.FromBase64String... ...
  • 近來,有項目需要使用到 DotNetty 這個非同步Socket框架。 這個框架是 微軟團隊 移植的 Java的 Netty —— 而且還能與 Java 現有的 Netty 對接。 Netty 如何的牛逼 我就不多介紹了。 DotNetty 基於 .Net 4.3 (實際至少需要 .Net 4.... ...
  • 需求:每個平臺分類下的門店,每個門店的名稱、圖片路徑、評分,每個門店下的四個產品的名稱、圖片路徑、評分 思路: 一開始門店動態化好寫,用Ajax就行了。但是每個門店下麵的產品,每個去請求一次查詢有點不太現實。 一開始準備用每個門店的Id去發起請求,被自己蠢哭了。 在換個思路用sql語句吧 同時把這麼 ...
  • 本文源自:https://github.com/cnxy/Dapper-zh-cn 本博客作者與Github上作者(cnxy)實為同一個作者。由於筆者翻譯水平有限,文本中錯誤難免,歡迎指正! 本文翻譯自:StackExchange.Dapper 原版教程源自:Dapper Tutorial 中文教程 ...
  • class Program { //第一種(1-2)+(3-4)+(5-6)...+m public static void Test(int m) { int z = 0; if (m % 2 == 0) { z = -(m / 2); ... ...
  • 微軟的eshop項目寫的很牛,學起來也比較吃力,最近公司剛好有一本書,說的就是.NET微服務,記下來。 因為微軟對性能的要求,docker裡面要有記憶體要求 解釋下這句代碼的意思: 然後你就成功了.... ...
  • 問題: 這幾天在裝.NET 的開發環境,在裝好VS2013和Oracle 11g之後,做了一個測試項目,運行調試沒問題 但是涉及到資料庫相關操作,如新建數據集、連接資料庫等在調試的時候則會出現如下錯誤: 目前百度之後現存的解決方案: 1. oracle odp.net 32位/64位版本的問題 "解 ...
  • https://www.cnblogs.com/cmt/p/4692920.html ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...