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 4.6.2正式发布带来众多特性
虽然大多数人的注意力都集中在.NET Core上,但与原来的.NET Framework相关的工作还在继续..NET Framework 4.6.2正式版已于近日发布,其重点是安全和WinForms/ ...
- HttpUrlConnection 基础使用
From https://developer.android.com/reference/java/net/HttpURLConnection.html HttpUrlConnection: A UR ...
- Android注解使用之通过annotationProcessor注解生成代码实现自己的ButterKnife框架
前言: Annotation注解在Android的开发中的使用越来越普遍,例如EventBus.ButterKnife.Dagger2等,之前使用注解的时候需要利用反射机制势必影响到运行效率及性能,直 ...
- 【开发软件】 在Mac下配置php开发环境:Apache+php+MySql
本文地址 原文地址 本文提纲: 1. 启动Apache 2. 运行PHP 3. 配置Mysql 4. 使用PHPMyAdmin 5. 附录 有问题请先 看最后的附录 摘要: 系统OS X ...
- 5.2 Array类型的方法汇总
所有对象都具有toString(),toLocaleString(),valueOf()方法. 1.数组转化为字符串 toString(),toLocaleString() ,数组调用这些方法,则返回 ...
- DevExpress第三方控件使用实例之ASPxPopupControl弹出子窗体
弹出页面控件:ASPxPopupControl, <dxpc:ASPxPopupControl ID="popubCtr" runat="server" ...
- oracle 误删数据恢复
1.根据时间点查系统版本号scn: select timestamp_to_scn(to_timestamp('2013-01-07 11:20:00','YYYY-MM-DD HH:MI:SS')) ...
- MEF学习
一. 什么是MEF MEF(Managed Extensibility Framework)是一个用于创建可扩展的轻型应用程序的库. 应用程序开发人员可利用该库发现并使用扩展,而无需进行配置. 扩 ...
- 关于ie6/7下的z-index
z-index这个属性其实在挺多地方都会用到,在百度上搜索也有大量关于z-index的篇幅去阐述这个属性,特别是在ie6下的z-index处理有更多的相关文章,本文就不再围绕z-index这一属性的基 ...
- 让Unity NavMesh为我所用
Unity里面整合了一个NavMesh功能,虽然让人又爱又恨. 但当你在其他地方需要这个NavMesh的数据时,就更让人欲罢不能了. 比如说服务器需要Unity的NavMesh数据时. 比如说你想将U ...