我们的网站业务会生成一个报告,用网页展示出来,要有生成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的更多相关文章

  1. C#生成PDF总结

    (一)C#生成PDF总结 (1)iTextSharp控件对iTextSharp研究还可以表格.文字.各种GDI对象,图片,水印,文字旋转(2)aspose的控件(3)PDF Library这个类库(只 ...

  2. 利用Java动态生成 PDF 文档

    利用Java动态生成 PDF 文档,则需要开源的API.首先我们先想象需求,在企业应用中,客户会提出一些复杂的需求,比如会针对具体的业务,构建比较典型的具备文档性质的内容,一般会导出PDF进行存档.那 ...

  3. html 生成pdf

    HTML生成PDF(c#) 最近因为工作需要,小小的研究了一下HTML生成PDF的方法,这方面的内容很多,但要么是不尽如人意的方法,要么就是那种收费的类库!为了广大.neter的福利,把自己的一点小小 ...

  4. iTextSharp生成pdf的一个简单例子

    效果图: 参考:http://www.cnblogs.com/CareySon/archive/2011/11/09/2243496.html http://www.cnblogs.com/julyl ...

  5. 生成 PDF 全攻略【2】在已有PDF上添加内容

    项目在变,需求在变,不变的永远是敲击键盘的程序员..... PDF 生成后,有时候需要在PDF上面添加一些其他的内容,比如文字,图片.... 经历几次失败的尝试,终于获取到了正确的代码书写方式. 在此 ...

  6. PHP 生成PDF

    一个项目中需要用到网页生成PDF,就是将整个网页生成一个PDF文件, 以前也用过HTML2PDF,只能生成一些简单的HTML代码,复杂的HTML + css 生成的效果惨不忍睹, 百度了一下,发现有个 ...

  7. 用js生成PDF的方案

    在java里,我们常用Itext来生成pdf,在pdf文件里组合图片,文字,画表格,画线等操作,还会遇到中文支持的问题. 那好,现在想直接在web前端就生成pdf怎么办,目前有以下几个解决方案 1:J ...

  8. 使用TCPDF插件生成pdf以及pdf的中文处理

    目录(?)[+] 多种多样的pdf开发库 WKHTMLTOPDF 2FPDF 3TCPDF 中文问题   做了这么多年项目,以前只是在别人的项目中了解过PHP生成pdf文件,知道并不难,但是涉及到了p ...

  9. linux下编译bib、tex生成pdf文件

    实验: 在linux环境下,编译(英文)*.bib和*.tex文件,生成pdf文件. 环境: fedora 20(uname -a : Linux localhost.localdomain 3.19 ...

随机推荐

  1. C 利用strtok, feof 截取字符串

    #cat /tmp/fff 10:hugetlb:/hello/06b11c9967cc0e106f5f4673246f671aa7388f623f58b250d9d9cb0f8c0f2b18 9:d ...

  2. Django-cookie与session操作

    添加cookie: def login(req): if req.method=="POST": uf = UserInfoForm(req.POST) if uf.is_vali ...

  3. 洛谷 3203 HNOI2010 BOUNCE 弹飞绵羊

    [题解] 这道题可以用Link-Cut Tree写.. 首先建立一个虚拟节点N+1,$i$与$N+1$连边表示$i$被弹飞了 对于修改操作,先$cut(i,min(n+1,i+k[i]))$,然后再$ ...

  4. hdu2015 偶数求和【C++】

    偶数求和 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submis ...

  5. Leetcode 48.旋转矩阵

    旋转矩阵 给定一个 n × n 的二维矩阵表示一个图像. 将图像顺时针旋转 90 度. 说明: 你必须在原地旋转图像,这意味着你需要直接修改输入的二维矩阵.请不要使用另一个矩阵来旋转图像. 示例 1: ...

  6. Python之路【第一篇】:Python基础

    本节内容 Python介绍 发展史 Python 2 or 3? 安装 Hello World程序 变量 用户输入 模块初识 .pyc是个什么鬼? 数据类型初识 数据运算 表达式if ...else语 ...

  7. 小记——GTMD校园网

    前言 学校一年前开通了校园网,然鹅信号未覆盖我们住的公寓,又多忍受了一年的小破宽带(10M带宽,100块300个小时) 上个星期,架设了一年的校园网终于通了,然后我们发现——校园网69元一个月,一个用 ...

  8. Clojure:解决Selmer与AngularJS的 标签混淆问题

    Selmer是Clojure的一个模板类库,下面是它的一个DEMO模板: <ul> {% for item in items %} <li>{{item}}</li> ...

  9. [Vue] Code split by route in VueJS

    In this lesson I show how to use webpack to code split based on route in VueJS. Code splitting is a ...

  10. MySQL 调优 —— Using filesort

    出现这个问题的解决办法在于 MySQL 每次查询仅仅能使用一个索引, 而你的 SQL 语句 WHERE 条件和 ORDER BY 的条件不一样, 索引没建好的话. 那么 ORDER BY 就使用不到索 ...