前言:

最近在做老师交代的一个在线写实验报告的小项目中,有这么个需求:把学生提交的实验报告(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(中文也可以)的更多相关文章

  1. Asp.net MVC Razor常见问题及解决方法

    没有经验的童鞋就是这样磕磕碰碰出来的经验. 1,Datatype的错误提示消息无法自定义 这也许是Asp.net MVC的一个Bug.ViewModel中定义了DataType为Date字段: [Re ...

  2. Asp.net MVC Razor常见问题及解决方法(转载>云中客)

    没有经验的童鞋就是这样磕磕碰碰出来的经验. 1,Datatype的错误提示消息无法自定义 这也许是Asp.net MVC的一个Bug.ViewModel中定义了DataType为Date字段: 1 2 ...

  3. 【译】Asp.net mvc 使用ITextSharp PDF to HTML (解决img标签问题)

    前言:因项目需求,需要将HTML代码转成PDF.大致上已经实现了,可以是发现使用ITextSharp(我现在的版本是5.5.9)的时候,img标签中的src只能跟绝对路径. 在百度上找了一个上午,有一 ...

  4. 完美解决ubuntu下sublime中文输入问题

    声明 1.本人整理文章,转载请注明出处. 2.参考资料 http://my.oschina.net/tsl0922/blog/113495 问题描述 在ubuntu下想使用sublime,但是不能输入 ...

  5. 完美解决ExtJs6上传中文文件名乱码,后端SpringMVC

    ExtJs上传中文文件名乱码,观察请求. ExtJs6上传乱码从后台无法解决,因为文件名请求里面就已经乱码了,后台无法解码. 除非请求参数正确没有乱码,后台因为编码设置不一样,可以通过后台处理乱码 这 ...

  6. 解决html导出pdf中文乱码问题的正确姿势

    简介 本文使用jspdf 1.5.3版.GitHub地址:https://github.com/MrRio/jsPDF jspdf是歪果仁开发的,因此在一开始就没想过支持非英文以外的文字,这就导致了非 ...

  7. ASP.NET MVC学习之视图篇(1)

    一.前言 不知道还有多少读者从第一篇开始一直学习到如今,笔者也会一直坚持将ASP.NET MVC的学习完美的结束掉,然后开始写如何配合其他框架使用ASP.NET MVC的随笔.当然笔者后面的随笔如果没 ...

  8. ASP.NET MVC模型绑定的6个建议(转载)

    ASP.NET MVC模型绑定的6个建议 发表于2011-08-03 10:25| 来源博客园| 31 条评论| 作者冠军 validationasp.netmvc.netasp 摘要:ASP.NET ...

  9. 如何在FineUIMvc(ASP.NET MVC)视图中绑定多个模型?

    起因 这是知识星球内的一个网友提出的,按理说ASP.NET MVC中一个视图只能绑定一个模型(Model),在视图顶部标识如下: @model IEnumerable<FineUICore.Ex ...

随机推荐

  1. Mapreduce的文件和hbase共同输入

    Mapreduce的文件和hbase共同输入 package duogemap;   import java.io.IOException;   import org.apache.hadoop.co ...

  2. mysql进阶之存储过程

    往往看别人的代码会有这样的感慨: 看不懂 理还乱 是离愁 别是一番滋味在心头 为什么要使用存储过程? 在mysql开发中使用存储过程的理由: 当希望在不同的应用程序或平台上执行相同的函数,或者封装特定 ...

  3. CSS 3学习——box-sizing和背景

    box-sizing 在CSS 2中设置元素的width和height仅仅是设置了元素内容区的宽和高,元素实际的尺寸是margin + border + padding + 内容区. CSS 3(截止 ...

  4. [笔记]kubernetes 无法启动问题

    在启动kubernetes的时候报错误. ERROR: timed out for http://localhost:4001/v2/keys/ 原因是无法启动etcd, etcd 监听4001本地端 ...

  5. ABP领域层

    1.实体Entites 1.1 概念 实体是DDD(领域驱动设计)的核心概念之一. 实体是具有唯一标识的ID且存储在数据库总.实体通常被映射成数据库中的一个表. 在ABP中,实体继承自Entity类. ...

  6. Linux实战教学笔记08:Linux 文件的属性(上半部分)

    第八节 Linux 文件的属性(上半部分) 标签(空格分隔):Linux实战教学笔记 第1章 Linux中的文件 1.1 文件属性概述(ls -lhi) linux里一切皆文件 Linux系统中的文件 ...

  7. Linux下的C Socket编程 -- server端的继续研究

    Linux下的C Socket编程(四) 延长server的生命周期 在前面的一个个例子中,server在处理完一个连接后便会立即结束掉自己,然而这种server并不科学啊,server应该是能够一直 ...

  8. css 填坑常用代码分享

    以下是常用的代码收集,没有任何技术含量,只是填坑的积累.转载请注明出处,谢谢. 因为提交比较麻烦,后来转置github:https://github.com/jsfront/src/blob/mast ...

  9. 性能测试工具 wrk 安装与使用

    介绍 今天给大家介绍一款开源的性能测试工具 wrk,简单易用,没有Load Runner那么复杂,他和 apache benchmark(ab)同属于性能测试工具,但是比 ab 功能更加强大,并且可以 ...

  10. mono中发送邮件并保存本次收件人的地址

    在ios端mono开发中,发送邮件可以选择调用ios原生email程序.有两种方式实现这种功能,一是程序跳转到ipad中email程序,另外一种是将发送邮件的界面在自己应用里弹出. 首先第一种方式的代 ...