ASP. NET MVC项目 使用iTextSharp将网页代码生成PDF文件

一、功能背景:

  1.一直在完善公司内部的数据驱动平台系统,最近给我一个值班表的功能,大体功能需求如图(展示每月值班表,需要实现编辑、打印、模板及生成PDF)

二、功能介绍

  1.前三个编辑、打印、模板功能使用UEditor编辑器都能轻松实现

    ueditor模板修改:①.找到目录下 ueditor/dialogs/template/config.js 文件,将原模板的标题及内容替换成自己的就OK

            ②.若替换后不显示,清一下浏览器缓存就OK了

  2.比较头疼的便是将tab标签下的网页上展示的内容生成PDF模板的功能,自己查了一下午还是觉得iTextSharp比较容易操作。

    第一步:我们先将iTextSharp所需要引用的NuGet程序包添加安装到项目中(添加引用——管理NuGet程序包——联机搜索iTextSharp——安装)

    第二步:创建PDFHelper帮助类(标红的为使用iTextSharp需要引用的)

  1 using System;
  2 using System.Collections.Generic;
  3 using System.IO;
  4 using System.Linq;
  5 using System.Net;
  6 using System.Text;
  7 using System.Threading.Tasks;
  8 using System.Web;
  9 using iTextSharp.text;
 10 using iTextSharp.text.pdf;
 11 using iTextSharp.tool.xml;
 12 
 13 namespace Labthink.BI.Helpers
 14 {
 15     /// <summary>
 16     /// Html字符串转PDF输出帮助类
 17     /// </summary>
 18     public class HtmlToPdfHelper
 19     {
 20         #region HtmlToPDF
 21 
 22         /// <summary>
 23         /// 判断是否有乱码
 24         /// </summary>
 25         /// <param name="txt"></param>
 26         /// <returns></returns>
 27         private static bool IsMessyCode(string txt)
 28         {
 29             var bytes = Encoding.UTF8.GetBytes(txt);
 30             for (var i = 0; i < bytes.Length; i++)
 31             {
 32                 if (i < bytes.Length - 3)
 33                     if (bytes[i] == 239 && bytes[i + 1] == 191 && bytes[i + 2] == 189)
 34                     {
 35                         return true;
 36                     }
 37             }
 38             return false;
 39         }
 40 
 41         /// <summary>
 42         /// 将Html字符串 输出到PDF档里
 43         /// </summary>
 44         /// <param name="htmlText"></param>
 45         /// <returns></returns>
 46         public static byte[] ConvertHtmlTextToPdf(string htmlText)
 47         {
 48             return ConvertHtmlTextToPdf(htmlText, "", 0, 0, 0, 0);
 49         }
 50 
 51         /// <summary>
 52         /// 将Html字符串 输出到PDF档里,并添加水印
 53         /// </summary>
 54         /// <param name="htmlText">网页代码</param>
 55         /// <param name="picPath">水印路径</param>
 56         /// <param name="left">距离左边距离</param>
 57         /// <param name="top">距顶部距离</param>
 58         /// <param name="width">水印宽度</param>
 59         /// <param name="height">水印高度</param>
 60         /// <returns></returns>
 61         public static byte[] ConvertHtmlTextToPdf(string htmlText, string picPath, int left, int top, int width, int height)
 62         {
 63             if (string.IsNullOrEmpty(htmlText))
 64             {
 65                 return null;
 66             }
 67             //避免当htmlText无任何html tag标签的纯文字时,转PDF时会挂掉,所以一律加上<p>标签
 68             htmlText = "<p>" + htmlText + "</p>";
 69             MemoryStream outputStream = new MemoryStream();//要把PDF写到哪个串流
 70             byte[] data = Encoding.UTF8.GetBytes(htmlText);//字串转成byte[]
 71             MemoryStream msInput = new MemoryStream(data);
 72             //Rectangle rect = new Rectangle(11 * 72, 8.5f * 72);自定义纸张大小
 73             Document doc = new Document(PageSize._11X17, 20, 0, 20, 0);//要写PDF的文件,建构子没填的话预设直式A4
 74             PdfWriter writer = PdfWriter.GetInstance(doc, outputStream);
 75             //指定文件预设开档时的缩放为100%
 76             PdfDestination pdfDest = new PdfDestination(PdfDestination.XYZ, 0, doc.PageSize.Height, 1f);
 77             //开启Document文件 
 78             doc.Open();
 79 
 80             //写入水印图片
 81             if (!string.IsNullOrEmpty(picPath))
 82             {
 83                 Image img = Image.GetInstance(picPath);
 84                 //设置图片的位置
 85                 img.SetAbsolutePosition(width + left, (doc.PageSize.Height - height) - top);
 86                 //设置图片的大小
 87                 img.ScaleAbsolute(width, height);
 88                 doc.Add(img);
 89             }
 90             try
 91             {
 92                 //使用XMLWorkerHelper把Html parse到PDF档里
 93                 XMLWorkerHelper.GetInstance().ParseXHtml(writer, doc, msInput, null, Encoding.UTF8);
 94                 //将pdfDest设定的资料写到PDF档
 95                 PdfAction action = PdfAction.GotoLocalPage(1, pdfDest, writer);
 96                 writer.SetOpenAction(action);
 97             }
 98             catch (Exception)
 99             {
100                 return null;
101             }
102             doc.Close();
103             msInput.Close();
104             outputStream.Close();
105             //回传PDF档案 
106             return outputStream.ToArray();
107         }
108 
109         #endregion
110         该注释掉的方法为获取某文件下的HTML代码来生成PDF,因为我是直接取的数据库中存的HTML代码,所以改成了下面的方法。
111         /// <summary>
112         /// 获取网站内容,包含了 HTML+CSS+JS
113         /// </summary>
114         /// <returns>String返回网页信息</returns>
115         //public static string GetWebContent(string inpath)
116         //{
117         //    try
118         //    {
119         //        WebClient myWebClient = new WebClient();
120         //        //获取或设置用于向Internet资源的请求进行身份验证的网络凭据
121         //        myWebClient.Credentials = CredentialCache.DefaultCredentials;
122         //        //从指定网站下载数据
123         //        Byte[] pageData = myWebClient.DownloadData(inpath);
124         //        //如果获取网站页面采用的是GB2312,则使用这句
125         //        string pageHtml = Encoding.UTF8.GetString(pageData);
126         //        bool isBool = IsMessyCode(pageHtml);//判断使用哪种编码 读取网页信息
127         //        if (!isBool)
128         //        {
129         //            string pageHtml1 = Encoding.UTF8.GetString(pageData);
130         //            pageHtml = pageHtml1;
131         //        }
132         //        else
133         //        {
134         //            string pageHtml2 = Encoding.Default.GetString(pageData);
135         //            pageHtml = pageHtml2;
136         //        }
137         //        return pageHtml;
138         //    }
139         //    catch (WebException webEx)
140         //    {
141         //        return webEx.Message;
142         //    }
143         //}
144         public static string GetWebContent(string monthContent)
145         {
146             try
147             {
148                 WebClient myWebClient = new WebClient();
149                 //获取或设置用于向Internet资源的请求进行身份验证的网络凭据
150                 myWebClient.Credentials = CredentialCache.DefaultCredentials;
151                 //从指定网站下载数据
152                 //Byte[] pageData = myWebClient.DownloadData(inpath);
153                 //如果获取网站页面采用的是GB2312,则使用这句
154                 string pageHtml = monthContent;
155                 //bool isBool = IsMessyCode(pageHtml);//判断使用哪种编码 读取网页信息
156                 //if (!isBool)
157                 //{
158                 //    string pageHtml1 = Encoding.UTF8.GetString(pageData);
159                 //    pageHtml = pageHtml1;
160                 //}
161                 //else
162                 //{
163                 //    string pageHtml2 = Encoding.Default.GetString(pageData);
164                 //    pageHtml = pageHtml2;
165                 //}
166                 return pageHtml;
167             }
168             catch (WebException webEx)
169             {
170                 return webEx.Message;
171             }
172         }
173 
174         /// <summary>
175         /// 将pdf文件流输出至浏览器下载
176         /// </summary>
177         /// <param name="pdfFile">PDF文件流</param>
178         public static void PdfDownload(byte[] pdfFile,string title)
179         {
180             byte[] buffer = pdfFile;
181             Stream iStream = new MemoryStream(buffer);
182             try
183             {
184                 int length;
185                 long dataToRead;
186                 //string filename = DateTime.Now.ToString("yyyyMMddHHmmss") + ".pdf";//保存的文件名称
187                 string filename = title + ".pdf";
188                 dataToRead = iStream.Length;
189                 HttpContext.Current.Response.Clear();
190                 HttpContext.Current.Response.ClearHeaders();
191                 HttpContext.Current.Response.ClearContent();
192                 HttpContext.Current.Response.ContentType = "application/pdf"; //文件类型 
193                 HttpContext.Current.Response.AddHeader("Content-Length", dataToRead.ToString());//添加文件长度,进而显示进度 
194                 HttpContext.Current.Response.AddHeader("Content-Disposition", "attachment; filename=" + HttpUtility.UrlEncode(filename, Encoding.UTF8));
195                 while (dataToRead > 0)
196                 {
197                     if (HttpContext.Current.Response.IsClientConnected)
198                     {
199                         length = buffer.Length;
200                         HttpContext.Current.Response.OutputStream.Write(buffer, 0, length);
201                         HttpContext.Current.Response.Flush();
202                         buffer = new Byte[length];
203                         dataToRead = dataToRead - length;
204                     }
205                     else
206                     {
207                         dataToRead = -1;
208                     }
209                 }
210             }
211             catch (Exception ex)
212             {
213                 HttpContext.Current.Response.Write("文件下载时出现错误!");
214             }
215             finally
216             {
217                 if (iStream != null)
218                 {
219                     iStream.Close();
220                 }
221                 //结束响应,否则将导致网页内容被输出到文件,进而文件无法打开  
222                 HttpContext.Current.Response.Flush();
223                 HttpContext.Current.Response.End();
224             }
225         }
226     }
227 }

    第三步:控制器中需要添加的代码

        /// <summary>
        /// 获取MVC视图Html
        /// </summary>
        /// <param name="context">控制器上下文</param>
        /// <param name="viewName">视图名称</param>
        /// <param name="param"></param>
        /// <returns></returns>
        public static string GetViewHtml(ControllerContext context, string viewName)
        {
            if (string.IsNullOrEmpty(viewName))
                viewName = context.RouteData.GetRequiredString("action");
            using (var sw = new StringWriter())
            {
                ViewEngineResult viewResult = ViewEngines.Engines.FindPartialView(context, viewName);
                var viewContext = new ViewContext(context, viewResult.View, context.Controller.ViewData, context.Controller.TempData, sw);
                try
                {
                    viewResult.View.Render(viewContext, sw);
                }
                catch (Exception ex)
                {
                    throw;
                }

                return sw.GetStringBuilder().ToString();
            }
        }

        [NoAuthorization]
        public ActionResult IndexPdf(string Year, string month)
        {
            //获取值班内容
            string monthContent = helper.GetRotaMonth(Year, month);
            //值班标题
            string title = "";
            //从网址下载Html字符串(方法一)
            //string inpath = System.Web.HttpContext.Current.Server.MapPath("~/Upload/Rota/September.html");
       //string htmlText = HtmlToPdfHelper.GetWebContent(inpath)//如果读取文件中的HTML代码调用此方法
            string htmlText = HtmlToPdfHelper.GetWebContent(monthContent);//这是调用的我获取的数据库中的内容
            //获取MVC视图Html字符串(方法二)
            //string htmlText = GetViewHtml(ControllerContext, "EditIndex");
//如果直接调用视图中的HTML调调用此方法,不建议用此方法,因为视图中有数据会是动态生成的,这时会获取不到报错 //水印图片路径 //string picPath = Server.MapPath("~/PDFTemplate/TemplateImg/authentication-iocn.png"); //string picPath = Server.MapPath("~/Upload/Rota/authentication-iocn.png"); //html转pdf并加上水印 //byte[] pdfFile = HtmlToPdfHelper.ConvertHtmlTextToPdf(htmlText, "", 100, 200, 100, 100); byte[] pdfFile = HtmlToPdfHelper.ConvertHtmlTextToPdf(htmlText); //输出至客户端 HtmlToPdfHelper.PdfDownload(pdfFile, title);//此处调用步骤6方法 return View(); }

  这就是使用iTextSharp生成PDF的方法,但是生成的PDF格式和正常做的会稍有不同。

 

posted @ 2018-09-20 11:38  徒然喜欢你  阅读(1858)  评论(6编辑  收藏  举报