我们的网站业务会生成一个报告,用网页展示出来,要有生成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. CentOS 7 不能连接网路的解决方法

    ---恢复内容开始--- 刚安装的CentOS7 是不能连接网络的,更不能使用yum 进行应用的安装 (1)通过ip addr或者是 ifconfig获取需要编辑的文件名 (2)vi /etc/sys ...

  2. PAT (Advanced Level) Practice(更新中)

    Source: PAT (Advanced Level) Practice Reference: [1]胡凡,曾磊.算法笔记[M].机械工业出版社.2016.7 Outline: 基础数据结构: 线性 ...

  3. 洛谷——P2921 [USACO08DEC]在农场万圣节Trick or Treat on the Farm

    P2921 [USACO08DEC]在农场万圣节Trick or Treat on the Farm 题意翻译 题目描述 每年,在威斯康星州,奶牛们都会穿上衣服,收集农夫约翰在N(1<=N< ...

  4. (C/C++学习)12.获取系统时间制作时钟(system()略解)

    说明:通过调用函数来获取系统当前时间,并制作一个数字式的时钟,时钟的显示包括年.月.日.小时.分以及秒,通过系统屏幕的刷新来对不断更新的时间进行屏幕的显示. 一.对相关函数的学习 1.time_t t ...

  5. PAT 1119 Pre- and Post-order Traversals

    Suppose that all the keys in a binary tree are distinct positive integers. A unique binary tree can ...

  6. Python与常见加密方式

    前言 我们所说的加密方式,都是对二进制编码的格式进行加密的,对应到Python中,则是我们的Bytes. 所以当我们在Python中进行加密操作的时候,要确保我们操作的是Bytes,否则就会报错. 将 ...

  7. 重庆OI2017 老 C 的任务

    老 C 的任务 时间限制: 2 Sec  内存限制: 512 MB 题目描述 老 C 是个程序员. 最近老 C 从老板那里接到了一个任务——给城市中的手机基站写个管理系统.作为经验丰富的程序员,老 C ...

  8. 利用DTrace实时检测MySQl

    与我们大多数人想象的不同,DTrace用于MySQL时不需对MySQL做任何更改.DTrace最强大的“提供器”(provider,是一组可观测的探测器)是FBT(Functional Boundar ...

  9. 反射调用android系统级API函数

    try { Class<?> mClass = Class.forName("com.android.server.wifi.WifiSettingsStore"); ...

  10. 改动虚拟机镜像的rootpassword

    有时从网上下载的虚拟机镜像.没有rootpassword,必须通过秘钥登录.然后秘钥又须要麻烦的注入到里面去.想用,却无法登录.非常头痛.本文提供一种通过改动虚拟机镜像里面的/etc/shadow文件 ...