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的主要内容,如果未能解决你的问题,请参考以下文章

如何运用Java组件itext生成pdf

C# html生成PDF遇到的问题,从iTextSharp到wkhtmltopdf

iText7 & C# 从存储在 MSSQL DB 中的 PDF 中提取页面

使用饼图生成 PDF -iText7

通过 iText 创建 PDF 文档时,某些 HTML 和 CSS 样式未应用

新手如何使用itext7生成pdf盖章