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 ...
随机推荐
- macOS 我的装机
最近多次配置 Mac 的开发环境,稍微记录一下 1 创建无付费信息的Apple ID 2 Xcode gem 源更改 3 Alfred 4 微信 5 SourceTree 6 Sublime Te ...
- JavaScript 字符串实用常操纪要
JavaScript 字符串用于存储和处理文本.因此在编写 JS 代码之时她总如影随形,在你处理用户的输入数据的时候,在读取或设置 DOM 对象的属性时,在操作 Cookie 时,在转换各种不同 Da ...
- [APUE]UNIX进程的环境(上)
一. 前言 本章将学习:当执行程序时,其main函数是如何被调用的,命令行参数是如何传送给执行程序的,典型的存储器布局是什么样式,如何分配另外的存储空间,进程如何使用环境变量,进程终止的不同方式等.另 ...
- AFNetworking 3.0 源码解读(十一)之 UIButton/UIProgressView/UIWebView + AFNetworking
AFNetworking的源码解读马上就结束了,这一篇应该算是倒数第二篇,下一篇会是对AFNetworking中的技术点进行总结. 前言 上一篇我们总结了 UIActivityIndicatorVie ...
- angularjs 依赖注入--自己学着实现
在用angular依赖注入时,感觉很好用,他的出现是 为了"削减计算机程序的耦合问题" ,我怀着敬畏与好奇的心情,轻轻的走进了angular源码,看看他到底是怎么实现的,我也想写个 ...
- Windows下Visual studio 2013 编译 Audacity
编译的Audacity版本为2.1.2,由于实在windows下编译,其源代码可以从Github上取得 git clone https://github.com/audacity/audacity. ...
- iOS架构一个中型普通App的一些经验总结
这一版比较完善的的App终于提交审核了.有时间写写自己的一些经验的总结了.自己主导的从0到比较成型的app到目前来说也只有两个,但是其中的很多东西都是大同小异.基本上是想到了什么就写什么,感觉写的不到 ...
- css中line-height行高的深入学习
之前对css中行高line-height的理解还是有些肤浅,深入后才发觉里面包罗万象.学习行高line-height,首先从基本原理开始 (标注该文章转载 http://www.cnblogs.com ...
- CentOS下Zabbix安装部署及汉化
搭建环境:Centos6.5_x86_64,Zabbix2.4.5,epel 源 服务端: 1.安装开发软件包yum -y groupinstall "Development Tools&q ...
- EF里Guid类型数据的自增长、时间戳和复杂类型的用法
通过前两章Lodging和Destination类的演示,大家肯定基本了解Code First是怎么玩的了,本章继续演示一些很实用的东西.文章的开头提示下:提供的demo为了后面演示效果,前面代码有些 ...