C# html生成PDF遇到的问题,从iTextSharp到wkhtmltopdf
我们的网站业务会生成一个报告,用网页展示出来,要有生成pdf并下载的功能,关键是生成pdf。
用内容一段段去拼pdf,想想就很崩溃,所以就去网上找直接把html生成pdf的方法。
网上资料大部分都是用的iTextSharp的XMLWorkerHelper做的(代码我贴在后面),遇到的问题是,它对css样式的支持比较古老或者说简单,所以重新改了一下我的html样式,div大部分都换成了table等,搞定后运行了一段时间没出什么问题。
但是,最近发现它有一种情况会报错。我的html内容是一个订单,包含多个小项,每个小项有自己的内容。最近发现如果小项的内容稍多,比如几千个字符,生成pdf时在分页那儿会陷入死循环。
由于我的小项一直被当成一整块,如果一页剩下的地方显示不完,它会整个挪到下一页,不会从中间截断,所以我猜测,如果被它判定一段内容是不能分割的,而内容的长度就已经超出了一整页的长度,就会出错。
我试图调整自己的内容的格式等等,让它不被判定为不可分割,没有成功,而且没有看到源码,最后没有解决问题,只好找另外的方式生成pdf。
第二次映入眼帘的是wkhtmltopdf,同时有人提到了Pechkin,是作者在wkhtmltopdf基础上开发的,更方便.NET开放使用,不过原版有个bug,有网友给出了修正版本。
这个的使用更简单,不过比较奇葩的是,需要把几个dll库放到根目录。
这一次接入完成后没有出现内容长了就挂掉的情况,但是也有个毛病:
它的分页非常“硬”,有可能会把一行字从中间拦腰截断,分在上下两页。
两害相权取其轻,只能先用着了。
如果能确定内容不会太长,还是iTextSharp比较好。
下面是两种方式的使用代码:
iTextSharp:
public class PDFHelper
{
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);
PdfDestination pdfDest = new PdfDestination(PdfDestination.XYZ, , doc.PageSize.Height, 1f);
//开启Document文件
doc.Open();
HeaderAndFooterEvent header = new HeaderAndFooterEvent();
header.tpl = writer.DirectContent.CreateTemplate(, );
writer.PageEvent = header; //使用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(); }
}
public class UnicodeFontFactory : FontFactoryImp
{ public override Font GetFont(string fontname, string encoding, bool embedded, float size, int style, BaseColor color, bool cached)
{
string FontPath = System.Web.Hosting.HostingEnvironment.MapPath("~/Font/"); BaseFont bfYaHei = BaseFont.CreateFont(FontPath + "msyh.ttc,1", BaseFont.IDENTITY_H, BaseFont.EMBEDDED);
return new Font(bfYaHei, size, style, color);
}
} public class HeaderAndFooterEvent : PdfPageEventHelper, IPdfPageEvent
{
public PdfTemplate tpl = null;
public bool PAGE_NUMBER = true;
private int PageCount = ;
private static string FontPath = System.Web.Hosting.HostingEnvironment.MapPath("~/Font/");
private static BaseFont bfYaHei = BaseFont.CreateFont(FontPath + "msyh.ttc,1", BaseFont.IDENTITY_H, BaseFont.EMBEDDED);
private static iTextSharp.text.Font font = new Font(bfYaHei, , Font.NORMAL, BaseColor.BLACK); //重写 关闭一个页面时
public override void OnEndPage(PdfWriter writer, Document document)
{
if (PAGE_NUMBER)
{
Phrase footer = new Phrase("www.XXXX.com 第" + writer.PageNumber + "页/共 页", font);
PdfContentByte cb = writer.DirectContent; //模版 显示总共页数
cb.AddTemplate(tpl, document.Right - + document.LeftMargin, document.Bottom - );//调节模版显示的位置 //页脚显示的位置
ColumnText.ShowTextAligned(cb, Element.ALIGN_CENTER, footer, document.Right - + document.LeftMargin, document.Bottom - , );
}
}
//重写 打开一个新页面时
public override void OnStartPage(PdfWriter writer, Document document)
{
if (PAGE_NUMBER)
{
PageCount += ;
writer.PageCount = PageCount;
}
}
//关闭PDF文档时
public override void OnCloseDocument(PdfWriter writer, Document document)
{
tpl.BeginText();
tpl.SetFontAndSize(bfYaHei, );//生成的模版的字体、颜色
tpl.ShowText(PageCount.ToString());//模版显示的内容
tpl.EndText();
tpl.ClosePath();
}
//定义输出文本
public static Paragraph InsertTitleContent(string text)
{ Paragraph paragraph = new Paragraph(text, font);//新建一行 paragraph.Alignment = Element.ALIGN_CENTER;//居中 paragraph.SpacingBefore = ; paragraph.SpacingAfter = ;
paragraph.SetLeading(, );//每行间的间隔
return paragraph;
}
}
Pechkin:
public static byte[] ConvertHtmlToPdf(string html)
{ try
{
using (IPechkin pechkin = Factory.Create(new GlobalConfig()))
{
ObjectConfig oc = new ObjectConfig();
oc.SetPrintBackground(true)
.SetLoadImages(true).Footer.SetContentSpacing().SetLeftText("www.XXXX.com").SetRightText("[page]/[toPage]");
byte[] pdf = pechkin.Convert(oc, html);
return pdf;
}
}
catch (Exception)
{ }
return null;
}
大家有更好的解决方式,希望赐教。
C# html生成PDF遇到的问题,从iTextSharp到wkhtmltopdf的更多相关文章
- C#生成PDF总结
(一)C#生成PDF总结 (1)iTextSharp控件对iTextSharp研究还可以表格.文字.各种GDI对象,图片,水印,文字旋转(2)aspose的控件(3)PDF Library这个类库(只 ...
- 利用Java动态生成 PDF 文档
利用Java动态生成 PDF 文档,则需要开源的API.首先我们先想象需求,在企业应用中,客户会提出一些复杂的需求,比如会针对具体的业务,构建比较典型的具备文档性质的内容,一般会导出PDF进行存档.那 ...
- html 生成pdf
HTML生成PDF(c#) 最近因为工作需要,小小的研究了一下HTML生成PDF的方法,这方面的内容很多,但要么是不尽如人意的方法,要么就是那种收费的类库!为了广大.neter的福利,把自己的一点小小 ...
- iTextSharp生成pdf的一个简单例子
效果图: 参考:http://www.cnblogs.com/CareySon/archive/2011/11/09/2243496.html http://www.cnblogs.com/julyl ...
- 生成 PDF 全攻略【2】在已有PDF上添加内容
项目在变,需求在变,不变的永远是敲击键盘的程序员..... PDF 生成后,有时候需要在PDF上面添加一些其他的内容,比如文字,图片.... 经历几次失败的尝试,终于获取到了正确的代码书写方式. 在此 ...
- PHP 生成PDF
一个项目中需要用到网页生成PDF,就是将整个网页生成一个PDF文件, 以前也用过HTML2PDF,只能生成一些简单的HTML代码,复杂的HTML + css 生成的效果惨不忍睹, 百度了一下,发现有个 ...
- 用js生成PDF的方案
在java里,我们常用Itext来生成pdf,在pdf文件里组合图片,文字,画表格,画线等操作,还会遇到中文支持的问题. 那好,现在想直接在web前端就生成pdf怎么办,目前有以下几个解决方案 1:J ...
- 使用TCPDF插件生成pdf以及pdf的中文处理
目录(?)[+] 多种多样的pdf开发库 WKHTMLTOPDF 2FPDF 3TCPDF 中文问题 做了这么多年项目,以前只是在别人的项目中了解过PHP生成pdf文件,知道并不难,但是涉及到了p ...
- linux下编译bib、tex生成pdf文件
实验: 在linux环境下,编译(英文)*.bib和*.tex文件,生成pdf文件. 环境: fedora 20(uname -a : Linux localhost.localdomain 3.19 ...
随机推荐
- modelsim 仿真软件 百度云分享 modelsim se 10.7 10.6d 10.6c 10.5 10.4
modelsim se 10.7 链接:https://pan.baidu.com/s/1NDC2yMCZmA4bIRSk2dUiTg 提取码:4l1d 复制这段内容后打开百度网盘手机App,操作更方 ...
- LIS(两种方法求最长上升子序列)
首先得明白一个概念:子序列不一定是连续的,可以是断开的. 有两种写法: 一.动态规划写法 复杂度:O(n^2) 代码: #include <iostream> #include <q ...
- 38.histogram的基础用法
主要知识点 histogram的理解及用法 histogram:他的作用是把一些连续的数据划分为一定的区间范围,使用连续的数据离散化,然后这这样离散化的数据就可以做聚合分析操作,操作过程类似于 ...
- python爬虫12 | 爸爸,他使坏,用动态的 Json 数据,我要怎么搞?
在前面我们玩了好多静态的 HTML 想必你应该知道怎么去爬这些数据了 但还有一些常见的动态数据 比如 商品的评论数据 实时的直播弹幕 岛国动作片的评分 等等 这些数据是会经常发生改变的 很多网站就会用 ...
- [Usaco2014 Mar]Sabotage
[Usaco2014 Mar]Sabotage 题目 Farmer John"s arch-nemesis, Farmer Paul, has decided to sabotage Far ...
- 种树(codevs 1768)
题目描述 Description 为了绿化乡村,H村积极响应号召,开始种树了. H村里有n幢房屋,这些屋子的排列顺序很有特点,在一条直线上.于是方便起见,我们给它们标上1~n.树就种在房子前面的空地上 ...
- MongoDB:更改数据库位置(Windows)
MongoDB在Windows中默认的数据库目录是c:\data.如果在没有该目录的情况下,直接运行mongod.exe,就会报如下错误: 在某些情况下,我们并不想把mongoDB的数据库放在c盘,这 ...
- oracle强化练习之单行函数
1. 显示dname和loc中间用-分隔 Select dname ||'-'|| loc From dept; 2. 将部门名称左填充为10位 Select lpad( dnam ...
- Codeforces Round #306 (Div. 2) A
题意 给一个字符串(长度<=10^5).问当中有没有一个"BA"和一个"AB"呢?假设都有而且它们不反复(即ABA不算),输出YES.否则输出NO. 思路 ...
- web 前端学习笔记
<!DOCTYPE HTML> <head> <style type="text/css"> body { background: #ff00 ...