ASP.NET MVC 拓展ActionResult实现Html To Pdf 导出

时间:2023-11-18 20:47:38

之前实现了html直接转换为word文档的功能,那么是否也同样可以直接转换为pdf文档呢,网上搜了下html to pdf 的开源插件有很多 如:wkhtmltopdf,pdfsharp,itextsharp等

本文使用itextsharp实现如何将html文件转换为pdf文档

 

首先使用Nuget安装itextsharp插件

  1. Install-Package itextsharp.xmlworker

创建FileContentResult文件继承自ActionResult,方法HtmlToPdf中实现了如何将一段html转换为pdf文档逻辑,itextsharp.xmlworker能够支持丰富的css和html标签,但是有一个很大的缺点就是不支持中文,网上的一些解决中文字体的逻辑,在新版里面已经不支持了,在以下的示例代码中已经解决此问题,重点是以下两部代码:

FontFactory.RegisterDirectories();//注册当前系统中所支持的字体

worker.ParseXHtml(pdfWriter, document, new MemoryStream(Encoding.UTF8.GetBytes(sbHtml.ToString())), null, Encoding.UTF8, new UnicodeFontFactory()); //指定要使用的字体

 

  1. public
    class PdfContentResult : ActionResult
  2. {
  3.     public PdfContentResult() : this(null, null) { }
  4.     public PdfContentResult(string viewName) : this(null, viewName) { }
  5.     public PdfContentResult(object model) : this(model, null) { }
  6.     public PdfContentResult(object model, string viewName)
  7.     {
  8.         this.ViewName = viewName;
  9.         ViewData = null != model ? new ViewDataDictionary(model) : null;
  10.     }
  11.     public ViewDataDictionary ViewData { get; set; } = new ViewDataDictionary();
  12.     public
    string ViewName { get; set; }
  13.     public IView View { get; set; }
  14.     public
    override
    void ExecuteResult(ControllerContext context)
  15.     {
  16.         if (String.IsNullOrEmpty(ViewName))
  17.         {
  18.             ViewName = context.RouteData.GetRequiredString("action");
  19.         }
  20.         if (ViewData == null)
  21.         {
  22.             ViewData = context.Controller.ViewData;
  23.         }
  24.         ViewEngineResult result = ViewEngines.Engines.FindView(context, ViewName, null);
  25.         View = result.View;
  26.         StringBuilder sbHtml = new StringBuilder();
  27.         TextWriter txtWriter = new StringWriter(sbHtml);
  28.         ViewContext viewContext = new ViewContext(context, View, ViewData, context.Controller.TempData, txtWriter);
  29.         result.View.Render(viewContext, txtWriter);
  30.         HttpResponseBase httpResponse = context.HttpContext.Response;
  31.         httpResponse.ContentType = System.Net.Mime.MediaTypeNames.Application.Pdf;
  32.         //加入此头部文件会直接下载pdf文件,而不是在浏览器中预览呈现
  33.         //context.HttpContext.Response.AppendHeader("Content-Disposition", string.Format("attachment;filename={0}.pdf", ViewName));
  34.         HtmlToPdf(sbHtml, httpResponse);
  35.         result.ViewEngine.ReleaseView(context, View);
  36.     }
  37.     private
    static
    void HtmlToPdf(StringBuilder sbHtml, HttpResponseBase httpResponse)
  38.     {
  39.         using (Document document = new Document(PageSize.A4, 4, 4, 4, 4))
  40.         {
  41.             using (PdfWriter pdfWriter = PdfWriter.GetInstance(document, httpResponse.OutputStream))
  42.             {
  43.                 document.Open();
  44.                 FontFactory.RegisterDirectories();//注册系统中所支持的字体
  45.                 XMLWorkerHelper worker = XMLWorkerHelper.GetInstance();
  46.                 //UnicodeFontFactory 自定义实现解决itextsharp.xmlworker 不支持中文的问题
  47.                 worker.ParseXHtml(pdfWriter, document, new MemoryStream(Encoding.UTF8.GetBytes(sbHtml.ToString())), null, Encoding.UTF8, new UnicodeFontFactory());
  48.                 document.Close();
  49.             }
  50.         }
  51.     }
  52. }

 

UnicodeFontFactory完整代码

 

  1. public
    class UnicodeFontFactory : FontFactoryImp
  2. {
  3.     static UnicodeFontFactory()
  4.     {
  5.     }
  6.     public
    override Font GetFont(string fontname, string encoding, bool embedded, float size, int style, BaseColor color, bool cached)
  7.     {
  8.         return FontFactory.GetFont("arial unicode ms", BaseFont.IDENTITY_H, BaseFont.EMBEDDED);
  9.     }
  10. }

 

 

如何确定哪些字体在itextsharp中是支持中文的呢,可以通过下面这个小程序验证输出所有的字体名称,及是否支持中文

通过控制台应用程序执行完成后,打开生成的pdf文件,查看 字体名称是否有中文 " 我支持中文" ,如果存在则表示支持中文,否则不支持中文

  1. Document document = new Document();
  2. PdfWriter writer = PdfWriter.GetInstance(document, new FileStream(@"c:\pdf\pdf.pdf", FileMode.Create));
  3. document.Open();
  4. FontFactory.RegisterDirectories();
  5. foreach (var item in FontFactory.RegisteredFonts)
  6. {
  7.     Font font = FontFactory.GetFont(item, BaseFont.IDENTITY_H, BaseFont.EMBEDDED);
  8.     document.Add(new Paragraph(item + "<p>我支持中文</p>", font));
  9. }
  10. document.Close();

 

 

上面说了如何转换html为pdf及怎么解决中文字体的问题,那么怎么使用定义的PdfContentResult呢,

使用方式一:直接在控制器的Action方法中返回PdfContentResult实例

  1. public
    class PdfController : Controller
  2.     {
  3.         // GET: Pdf
  4.         public ActionResult Index()
  5.         {
  6.             return
    new PdfContentResult(null,"index");
  7.         }
  8.     }

 

使用方式二:添加Controller类的拓展方法,然后在控制器的Action方法中返回对应的拓展方法

  1. public
    static
    class ControllerExtensions
  2.   {
  3.       public
    static PdfContentResult Pdf(this Controller controller, object model)
  4.       {
  5.           return
    new PdfContentResult(model);
  6.       }
  7.       public
    static PdfContentResult Pdf(this Controller controller, object model, string fileName)
  8.       {
  9.           return
    new PdfContentResult(model, fileName);
  10.       }
  11.       public
    static PdfContentResult Pdf(this Controller controller, string fileName)
  12.       {
  13.           return
    new PdfContentResult(fileName);
  14.       }
  15.   }

 

这种感觉用起来是不是与return view();一样

  1. public
    class PdfController : Controller
  2. {
  3.     // GET: Pdf
  4.     public ActionResult Index()
  5.     {
  6.         return
    this.Pdf(null, "index");
  7.     }
  8. }

 

可能有人会问pdf文档的内容在哪里维护,直接打开Action对应的View视图,像写mvc页面一样布局pdf内容就可以了

 

至于itextsharp更多功能支持,请参考此文档:http://developers.itextpdf.com/