C# html生成PDF遇到的问题,从iTextSharp到wkhtmltopdf
Posted hangjy
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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:
1 public class PDFHelper 2 { 3 public byte[] ConvertHtmlTextToPDF(string htmlText) 4 { 5 if (string.IsNullOrEmpty(htmlText)) 6 { 7 return null; 8 } 9 //避免当htmlText无任何html tag标签的纯文字时,转PDF时会挂掉,所以一律加上<p>标签 10 htmlText = "<p>" + htmlText + "</p>"; 11 MemoryStream outputStream = new MemoryStream();//要把PDF写到哪个串流 12 byte[] data = Encoding.UTF8.GetBytes(htmlText);//字串转成byte[] 13 MemoryStream msInput = new MemoryStream(data); 14 Document doc = new Document();//要写PDF的文件,建构子没填的话预设直式A4 15 16 PdfWriter writer = PdfWriter.GetInstance(doc, outputStream); 17 PdfDestination pdfDest = new PdfDestination(PdfDestination.XYZ, 0, doc.PageSize.Height, 1f); 18 //开启Document文件 19 doc.Open(); 20 HeaderAndFooterEvent header = new HeaderAndFooterEvent(); 21 header.tpl = writer.DirectContent.CreateTemplate(100, 100); 22 writer.PageEvent = header; 23 24 //使用XMLWorkerHelper把Html parse到PDF档里 25 XMLWorkerHelper.GetInstance().ParseXHtml(writer, doc, msInput, null, Encoding.UTF8, new UnicodeFontFactory()); 26 27 //将pdfDest设定的资料写到PDF档 28 PdfAction action = PdfAction.GotoLocalPage(1, pdfDest, writer); 29 writer.SetOpenAction(action); 30 doc.Close(); 31 msInput.Close(); 32 outputStream.Close(); 33 //回传PDF档案 34 return outputStream.ToArray(); 35 36 } 37 } 38 public class UnicodeFontFactory : FontFactoryImp 39 { 40 41 public override Font GetFont(string fontname, string encoding, bool embedded, float size, int style, BaseColor color, bool cached) 42 { 43 string FontPath = System.Web.Hosting.HostingEnvironment.MapPath("~/Font/"); 44 45 BaseFont bfYaHei = BaseFont.CreateFont(FontPath + "msyh.ttc,1", BaseFont.IDENTITY_H, BaseFont.EMBEDDED); 46 return new Font(bfYaHei, size, style, color); 47 } 48 } 49 50 public class HeaderAndFooterEvent : PdfPageEventHelper, IPdfPageEvent 51 { 52 public PdfTemplate tpl = null; 53 public bool PAGE_NUMBER = true; 54 private int PageCount = 1; 55 private static string FontPath = System.Web.Hosting.HostingEnvironment.MapPath("~/Font/"); 56 private static BaseFont bfYaHei = BaseFont.CreateFont(FontPath + "msyh.ttc,1", BaseFont.IDENTITY_H, BaseFont.EMBEDDED); 57 private static iTextSharp.text.Font font = new Font(bfYaHei, 10, Font.NORMAL, BaseColor.BLACK); 58 59 //重写 关闭一个页面时 60 public override void OnEndPage(PdfWriter writer, Document document) 61 { 62 if (PAGE_NUMBER) 63 { 64 Phrase footer = new Phrase("www.XXXX.com 第" + writer.PageNumber + "页/共 页", font); 65 PdfContentByte cb = writer.DirectContent; 66 67 //模版 显示总共页数 68 cb.AddTemplate(tpl, document.Right - 54 + document.LeftMargin, document.Bottom - 15);//调节模版显示的位置 69 70 71 //页脚显示的位置 72 ColumnText.ShowTextAligned(cb, Element.ALIGN_CENTER, footer, document.Right - 297 + document.LeftMargin, document.Bottom - 14, 0); 73 } 74 } 75 //重写 打开一个新页面时 76 public override void OnStartPage(PdfWriter writer, Document document) 77 { 78 if (PAGE_NUMBER) 79 { 80 PageCount += 1; 81 writer.PageCount = PageCount; 82 } 83 } 84 //关闭PDF文档时 85 public override void OnCloseDocument(PdfWriter writer, Document document) 86 { 87 tpl.BeginText(); 88 tpl.SetFontAndSize(bfYaHei, 10);//生成的模版的字体、颜色 89 tpl.ShowText(PageCount.ToString());//模版显示的内容 90 tpl.EndText(); 91 tpl.ClosePath(); 92 } 93 //定义输出文本 94 public static Paragraph InsertTitleContent(string text) 95 { 96 97 Paragraph paragraph = new Paragraph(text, font);//新建一行 98 99 paragraph.Alignment = Element.ALIGN_CENTER;//居中 100 101 paragraph.SpacingBefore = 5; 102 103 paragraph.SpacingAfter = 5; 104 paragraph.SetLeading(1, 2);//每行间的间隔 105 return paragraph; 106 } 107 }
Pechkin:
1 public static byte[] ConvertHtmlToPdf(string html) 2 { 3 4 try 5 { 6 using (IPechkin pechkin = Factory.Create(new GlobalConfig())) 7 { 8 ObjectConfig oc = new ObjectConfig(); 9 oc.SetPrintBackground(true) 10 .SetLoadImages(true).Footer.SetContentSpacing(30).SetLeftText("www.XXXX.com").SetRightText("[page]/[toPage]"); 11 byte[] pdf = pechkin.Convert(oc, html); 12 return pdf; 13 } 14 } 15 catch (Exception) 16 { 17 18 } 19 return null; 20 }
大家有更好的解决方式,希望赐教。
以上是关于C# html生成PDF遇到的问题,从iTextSharp到wkhtmltopdf的主要内容,如果未能解决你的问题,请参考以下文章
C# html生成PDF遇到的问题,从iTextSharp到wkhtmltopdf
iText7 & C# 从存储在 MSSQL DB 中的 PDF 中提取页面