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         }

大家有更好的解決方式,希望賜教。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM