zoukankan      html  css  js  c++  java
  • 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         }

    大家有更好的解决方式,希望赐教。

  • 相关阅读:
    postgres 错误duplicate key value violates unique constraint 解决方案
    Golang包管理工具之govendor的使用
    《算法竞赛进阶指南》0x26广搜变形 HDOJ3085 双向BFS
    《算法竞赛进阶指南》0x26广搜变形 POJ3635
    《算法竞赛进阶指南》0x26广搜变形 电路维修 01最短路问题
    《算法竞赛进阶指南》0x25广度优先搜索 推箱子游戏 双重BFS
    《算法竞赛进阶指南》0x25广度优先搜索 多源floodfill
    《算法竞赛进阶指南》0x25广度优先搜索 POJ3322 Bloxorz I
    NETCORE
    VUE- 异步等待方法嵌套
  • 原文地址:https://www.cnblogs.com/chimeile/p/PDF.html
Copyright © 2011-2022 走看看