ASP.Net MVC——使用 ITextSharp 完美解决HTML转PDF(中文也可以)_dllnw04060的博客-程序员宅基地

技术标签: 测试  

前言:

最近在做老师交代的一个在线写实验报告的小项目中,有这么个需求:把学生提交的实验报告(HTML形式)直接转成PDF,方便下载和打印。

以前都是直接用rdlc报表实现的,可这次牵扯到图片,并且更为重要的一点是 PDF的格式得跟学生提交的HMTL页面一样。经过网上查阅资料,

找到了ITextSharp插件。

ITextSharp很强大,但是在处理HMTL中的 img标签时,src中只能是绝对路径。 

解决方法我写在了另一篇文章中

正文:

ITextSharp就不多介绍了。项目的链接下载链接为http://files.cnblogs.com/files/zuochengsi-9/H%E8%BD%ACPDF.zip

下开始项目之前得添加 ITextSharp.dll和ITextSharp.xmlworker.dll  后者是解决中文用的

可以从NuGet中下载引用,具体方法就不介绍了。网上很多解决方案。

项目结构图:

下面先说下主要操作:

步骤:1、将本地的某个视图转成字符串。

         2、将字符串整合成PDF的文档,并返回byte数组。

         3、讲比特流写到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

 

转载于:https://www.cnblogs.com/zuochengsi-9/p/5483808.html

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/dllnw04060/article/details/102341321

智能推荐

OpenFlow与VxLAN在云网络的应用_cisco_eigrp的博客-程序员宅基地_openflow vxlan

我叫庞俊英,来自阿里巴巴技术保障部,我们部门负责整个阿里集团所有业务如蚂蚁、淘宝、阿里云等等业务部门的基础设施。两年前我来过这里,去年没来,因为觉得去年没什么可讲的,所以这次我向大家汇报内容的是有一个连续性的,就是我前年提了哪些问题,这些问题现在解决了吗?然后还有哪些问题还需要解决,我希望业界帮我们做什么,我会是这样一个思路来向大家汇报。我是个工程师,所以我的PPT里面如果有很漂亮的图,一

使用 Docker部署 Tensorflow Serving 模型服务_xiedelong的博客-程序员宅基地_docker部署tensorflow

准备工作拉取 tensorflow servering 的 docker 镜像:sudo docker pull tensorflow/serving,一般是已经有的进入到一个测试目录:cd /home/q/test_dir/然后下载官方Demo目录:git clone https://github.com/tensorflow/serving如果无法下载,去网站 down 下来(附件),然后 deploy 上传到 linux 实体机中部署启动sudo docker run -t --rm

利用docker 创建mysql_Docker创建Mysql容器的简单步骤_穆舍的博客-程序员宅基地

前言前面我们已经安装好了Docker,也简单了解了Docker。下面就来给大家介绍下Docker创建Mysql容器的简单步骤,话不多说了,来一起看看详细的介绍吧步骤如下1、启动docker服务[[email protected] ~]# systemctl start docker2、查看docker里面的镜像[[email protected] ~]# docker imagesREPOSITORY TAG IM...

AE要素选择(点选和拉框选择)_weixin_34414650的博客-程序员宅基地

选择一个要素或者一个要素集(FeatureSelection)的方法很多,如IMap::SelectByShape、ILayer::search、IFeatureSection::SelectFeature等方法主要用到的方法:IMap接口的SelectFeature(Layer, Feature) (方法,从一个Layer中选择一个Feature);IMap接口SelectBySha...

启发测试计划:上下文模型_TIB的博客-程序员宅基地

 启发测试计划:上下文模型陈能技2007-8-12 原文:原文:Heuristic Test Planning:Context Modal - James Bach  Context-Driven Planning 上下文驱动计划1、 明白谁会参与项目,他们发挥什么作用2、 明白GIVENS(给定的条件),并谈判决定给定的工作约束,明白给定的资源限制

重调SJA1000_动感小麦兜的博客-程序员宅基地_sja1000

从接触SJA1000到现在已经一年多了,去年2月份搞好了之后基本就没再动过,一直跑着之前的程序,没问题也没额外的收货。直到昨天,有人说要通过can总线传输温度,恰巧当时设计板子时预留了DS18B20的接口。起初测试时,温度在液晶上一直显示为0,于是怀疑单块板子在不进行can通信时可能会卡死,于是找了另一块板子,让两者通信时再读温度,还是不行。最后单独找了个测温度的程序,把液晶移植过去,结果液晶

随便推点

Android 开发者必备的书单_JeffreyLau7的博客-程序员宅基地

Android 方面的书籍可谓是百花齐放,这几本书的作者都是在一线互联网公司奋斗的工程师,他们把多年的工作经验,身心耕植,汇聚成一本书。作为菜鸟的我们,只有一睹大神的风采了。所以借这个周末,我也列举了一些书,作为一个Android 开发工程师,这些书都是不可多得的好书,书中知识迟早是要掌握的。我们都知道开发Android App 是用Java 语言的,当然你也可以使用其他语言来

循环商业模式为时尚产业带来7000亿美元商机_普通网友的博客-程序员宅基地

•到2030年,循环商业模式在全球时尚市场所占的份额有可能达到23%,这代表着7000亿美元的商机。•循环商业模式可以帮助时尚产业向更好的增长模式转变,使产业收入不再依赖生产和资源利用。•要让积极的经济和环境成果最大化,需要重新设计绩效指标、产品和供应网络以适应循环商业模式,并形成更大规模的循环商业模式。2021年11月23日艾伦·麦克阿瑟基金会(“基金会”)的最新研究发现,到2030年,在租赁和转售等领域,循环商业模式在全球时尚市场所占的份额有可能达到23%,蕴藏着7000亿美元的商机

html5 matrix,javascript - HTML5 Canvas get transform matrix? - Stack Overflow_weixin_39582569的博客-程序员宅基地

EDIT(1/10/2020): MDN now indicates that getTransform() is supported in most major browsers; the code below may still have value as a part of implementing a polyfill for Internet Explorer, Edge, and An...

怎样生活更有意义?_禅与计算机程序设计艺术的博客-程序员宅基地

怎样生活更有意义?简单生活。复杂的音乐产生放纵复杂的食品产生疾病,质朴的音乐文艺教育能产生心灵方面的节制。质朴的体育锻炼产生身体健康。节制自己的快乐。我们知道最大最强烈的快乐是色欲。而正确的爱,是对有秩序的事物和美的事物,有节制的、和谐的爱。我们不应该追求复杂的节奏和多样的韵律。我们应该考虑什么是有秩序的、勇敢的生活。在有秩序的社会里,每个人都有他应该干的工作。——柏拉图《理想国》每个人,一生只做...

Unity3d——4种灯光的简介_正版游戏的受害者的博客-程序员宅基地

灯光Light一、简介光源 (Lights) 是每个场景的重要组成部分。网格和纹理决定了场景的形状和外观,而光源则决定了三维环境的颜色和氛围。您可能会在每个场景中使用多个光源。让它们一起工作需要一些实践,但结果却相当惊人。二、灯光类型Unity 5.5中有 4 种灯光。创建灯光的方式同创建其他游戏对象的方式相似:(1)Directional方向光源。这种类型的灯光可以被放...

川师大java试卷_成都大学Javaweb期末试卷总结版_九十纳魔狼的博客-程序员宅基地

成都大学期末试卷四、编程题(共15分)第一个Servlet1文件,读取一个请求参数test(字符串),存放在请求范围内,然后把请求转发给第二个Servlet2.。第二个Servlet2文件(url为output),向客户输出Servlet1的结果。根据注释补充下列代码。(15分)public class Servlet1 extends HttpServlet {public void servi...

推荐文章

热门文章

相关标签