ASP.Net MVC——使用 ITextSharp 完美解决HTML转PDF(中文也可以)
前言:
最近在做老师交代的一个在线写实验报告的小项目中,有这么个需求:把学生提交的实验报告(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, , 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(, 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, , 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(, 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
ASP.Net MVC——使用 ITextSharp 完美解决HTML转PDF(中文也可以)的更多相关文章
- Asp.net MVC Razor常见问题及解决方法
没有经验的童鞋就是这样磕磕碰碰出来的经验. 1,Datatype的错误提示消息无法自定义 这也许是Asp.net MVC的一个Bug.ViewModel中定义了DataType为Date字段: [Re ...
- Asp.net MVC Razor常见问题及解决方法(转载>云中客)
没有经验的童鞋就是这样磕磕碰碰出来的经验. 1,Datatype的错误提示消息无法自定义 这也许是Asp.net MVC的一个Bug.ViewModel中定义了DataType为Date字段: 1 2 ...
- 【译】Asp.net mvc 使用ITextSharp PDF to HTML (解决img标签问题)
前言:因项目需求,需要将HTML代码转成PDF.大致上已经实现了,可以是发现使用ITextSharp(我现在的版本是5.5.9)的时候,img标签中的src只能跟绝对路径. 在百度上找了一个上午,有一 ...
- 完美解决ubuntu下sublime中文输入问题
声明 1.本人整理文章,转载请注明出处. 2.参考资料 http://my.oschina.net/tsl0922/blog/113495 问题描述 在ubuntu下想使用sublime,但是不能输入 ...
- 完美解决ExtJs6上传中文文件名乱码,后端SpringMVC
ExtJs上传中文文件名乱码,观察请求. ExtJs6上传乱码从后台无法解决,因为文件名请求里面就已经乱码了,后台无法解码. 除非请求参数正确没有乱码,后台因为编码设置不一样,可以通过后台处理乱码 这 ...
- 解决html导出pdf中文乱码问题的正确姿势
简介 本文使用jspdf 1.5.3版.GitHub地址:https://github.com/MrRio/jsPDF jspdf是歪果仁开发的,因此在一开始就没想过支持非英文以外的文字,这就导致了非 ...
- ASP.NET MVC学习之视图篇(1)
一.前言 不知道还有多少读者从第一篇开始一直学习到如今,笔者也会一直坚持将ASP.NET MVC的学习完美的结束掉,然后开始写如何配合其他框架使用ASP.NET MVC的随笔.当然笔者后面的随笔如果没 ...
- ASP.NET MVC模型绑定的6个建议(转载)
ASP.NET MVC模型绑定的6个建议 发表于2011-08-03 10:25| 来源博客园| 31 条评论| 作者冠军 validationasp.netmvc.netasp 摘要:ASP.NET ...
- 如何在FineUIMvc(ASP.NET MVC)视图中绑定多个模型?
起因 这是知识星球内的一个网友提出的,按理说ASP.NET MVC中一个视图只能绑定一个模型(Model),在视图顶部标识如下: @model IEnumerable<FineUICore.Ex ...
随机推荐
- 【.net 深呼吸】细说CodeDom(3):命名空间
在上一篇文章中,老周介绍了表达式和语句,尽管老周没有把所有的内容都讲一遍,但相信大伙至少已经掌握基本用法.在本文中,咱们继续探讨 CodeDom 方面的奥秘,这一次咱们聊聊命名空间. 在开始之前,老周 ...
- [原]一个针对LVS的压力测试报告
LVS 测试报告 测试计划 基本功能测试 流量压力测试 响应时间测试 配置正确性测试 灾难恢复测试 测试点 基本功能测试 客户端IP地址正确性 RealServer 访问Internet测试(包括Ip ...
- 分享两个BPM配置小技巧
1.小技巧 流程图修改后发布的话版本号会+1,修改次数多了之后可能会导致版本号很高,这个时候可以将流程导出,然后删除对应的流程包再导入,发布数据模型和流程图之后,版本清零 2.小技巧 有的同事入职后使 ...
- 热修复-Tinker
微信开源,真是喜出望外,必须要去看看啊,比起nuwa来微信好很多,而且github上也有专门的官方文档说明,还有很多资料查询 参考地址:https://github.com/Tencent/tinke ...
- JavaScript中的this
本文尽量避免概念性的讲解,那样太抽象 所以下面以一些简单的例子,从易到难对this的用法总结 1.方法中的this会指向当前执行该方法的对象 如: var name = "window&qu ...
- [DS] 标记字段
标记字段 代码中有时候有这种需求:需要一个公共访问的标记字段,以下称为标记字段. 下面是案例: 一个订单详情页面,如果页面在显示中,程序中其它地方需要访问这个"正在查看中"的订单信 ...
- mono for android学习过程系列教程(2)
接着上一讲继续开始写,今天介绍的是安卓的基本组成结构. 在大多数情况下,MONO FOR ANDROID的命名空间和Android的命名空间 是互相映射的.有时候需要大小写,非字母数字字符的用法以及名 ...
- iOS开发系列--音频播放、录音、视频播放、拍照、视频录制
--iOS多媒体 概览 随着移动互联网的发展,如今的手机早已不是打电话.发短信那么简单了,播放音乐.视频.录音.拍照等都是很常用的功能.在iOS中对于多媒体的支持是非常强大的,无论是音视频播放.录制, ...
- 简单事件机制Java实现
一个很简单方便的事件处理方法. 使用效果 事件发布者: //定义事件 public static EventTrans<String> AuthFailed = new EventTran ...
- CSharpGL(9)解析OBJ文件并用CSharpGL渲染
CSharpGL(9)解析OBJ文件并用CSharpGL渲染 2016-08-13 由于CSharpGL一直在更新,现在这个教程已经不适用最新的代码了.CSharpGL源码中包含10多个独立的Demo ...