1. 程式人生 > >C# 使用 wkhtmltopdf 把HTML文本或文件轉換為PDF

C# 使用 wkhtmltopdf 把HTML文本或文件轉換為PDF

null 官網 添加 inpu pre pty 彩色 分辨率 tput

一、簡介

之前也記錄過一篇關於把 HTML 文本或 HTML 文件轉換為 PDF 的博客,只是之前那種方法有些局限性。

後來又了解到 wkhtmltopdf.exe 這個工具,這個工具比起之前的那種方法簡直是太好用了。
它是一個使用 Qt WebKit 引擎做渲染的,能夠把 HTML 文檔轉換成 PDF 文檔或圖片(image) 的命令行工具。
支持多個平臺,可在 windows、linux 等系統下運行。
你可以從這裏獲取到它:https://wkhtmltopdf.org/downloads.html

二、安裝

下載完成之後你需要先安裝它,然後你就能獲取到 wkhtmltopdf.exe 這個文件了,還包括有一個 wkhtmltoimage.exe 文件,
第一個文件是把 HTML 文檔轉換為 PDF 文檔的,後一個文件是把 HTML 文檔轉換為圖片的(Image),使用方法類似,只是調用的文件不一樣而已,這裏就不多做介紹。

我在安裝完成之後把 wkhtmltopdf.exe 這個文件放到了程序集所在的目錄,當然,你也可以不這麽做,但是就需要修改相應的路徑。

三、代碼

下面不多說了,貼出我的代碼。

   public partial class Form3 : Form
    {
        public Form3()
        {
            InitializeComponent();

            string strHtml = "<p style=‘color:red;text-align:center;background-color:#000000;‘>Hello World!<p><div style=‘width:150px;height:150px;background-color:blue;‘></div>
"; string htmlUrl = "https://wkhtmltopdf.org/downloads.html"; /// 把 HTML 文本內容轉換為 PDF HtmlTextConvertToPdf(strHtml, @"C:\Users\Administrator\Desktop\001.pdf"); /// 把 HTML 文件轉換為 PDF HtmlConvertToPdf(htmlUrl, @"C:\Users\Administrator\Desktop\002.pdf"); }
/// <summary> /// HTML文本內容轉換為PDF /// </summary> /// <param name="strHtml">HTML文本內容</param> /// <param name="savePath">PDF文件保存的路徑</param> /// <returns></returns> public bool HtmlTextConvertToPdf(string strHtml, string savePath) { bool flag = false; try { string htmlPath = HtmlTextConvertFile(strHtml); flag = HtmlConvertToPdf(htmlPath, savePath); File.Delete(htmlPath); } catch { flag = false; } return flag; } /// <summary> /// HTML轉換為PDF /// </summary> /// <param name="htmlPath">可以是本地路徑,也可以是網絡地址</param> /// <param name="savePath">PDF文件保存的路徑</param> /// <returns></returns> public bool HtmlConvertToPdf(string htmlPath, string savePath) { bool flag = false; CheckFilePath(savePath); ///這個路徑為程序集的目錄,因為我把應用程序 wkhtmltopdf.exe 放在了程序集同一個目錄下 string exePath = AppDomain.CurrentDomain.BaseDirectory.ToString() + "wkhtmltopdf.exe"; if (!File.Exists(exePath)) { throw new Exception("No application wkhtmltopdf.exe was found."); } try { ProcessStartInfo processStartInfo = new ProcessStartInfo(); processStartInfo.FileName = exePath; processStartInfo.WorkingDirectory = Path.GetDirectoryName(exePath); processStartInfo.UseShellExecute = false; processStartInfo.CreateNoWindow = true; processStartInfo.RedirectStandardInput = true; processStartInfo.RedirectStandardOutput = true; processStartInfo.RedirectStandardError = true; processStartInfo.Arguments = GetArguments(htmlPath, savePath); Process process = new Process(); process.StartInfo = processStartInfo; process.Start(); process.WaitForExit(); ///用於查看是否返回錯誤信息 //StreamReader srone = process.StandardError; //StreamReader srtwo = process.StandardOutput; //string ss1 = srone.ReadToEnd(); //string ss2 = srtwo.ReadToEnd(); //srone.Close(); //srone.Dispose(); //srtwo.Close(); //srtwo.Dispose(); process.Close(); process.Dispose(); flag = true; } catch { flag = false; } return flag; } /// <summary> /// 獲取命令行參數 /// </summary> /// <param name="htmlPath"></param> /// <param name="savePath"></param> /// <returns></returns> private string GetArguments(string htmlPath,string savePath) { if (string.IsNullOrEmpty(htmlPath)) { throw new Exception("HTML local path or network address can not be empty."); } if(string.IsNullOrEmpty(savePath)) { throw new Exception("The path saved by the PDF document can not be empty."); } StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append(" --page-height 100 "); //頁面高度100mm stringBuilder.Append(" --page-width 100 "); //頁面寬度100mm stringBuilder.Append(" --header-center 我是頁眉 "); //設置居中顯示頁眉 stringBuilder.Append(" --header-line "); //頁眉和內容之間顯示一條直線 stringBuilder.Append(" --footer-center \"Page [page] of [topage]\" "); //設置居中顯示頁腳 stringBuilder.Append(" --footer-line "); //頁腳和內容之間顯示一條直線 stringBuilder.Append(" " + htmlPath + " "); //本地 HTML 的文件路徑或網頁 HTML 的URL地址 stringBuilder.Append(" " + savePath + " "); //生成的 PDF 文檔的保存路徑 return stringBuilder.ToString(); } /// <summary> /// 驗證保存路徑 /// </summary> /// <param name="savePath"></param> private void CheckFilePath(string savePath) { string ext = string.Empty; string path = string.Empty; string fileName = string.Empty; ext = Path.GetExtension(savePath); if (string.IsNullOrEmpty(ext) || ext.ToLower() != ".pdf") { throw new Exception("Extension error:This method is used to generate PDF files."); } fileName = Path.GetFileName(savePath); if (string.IsNullOrEmpty(fileName)) { throw new Exception("File name is empty."); } try { path = savePath.Substring(0, savePath.IndexOf(fileName)); if (!Directory.Exists(path)) { Directory.CreateDirectory(path); } } catch { throw new Exception("The file path does not exist."); } } /// <summary> /// HTML文本內容轉HTML文件 /// </summary> /// <param name="strHtml">HTML文本內容</param> /// <returns>HTML文件的路徑</returns> public string HtmlTextConvertFile(string strHtml) { if (string.IsNullOrEmpty(strHtml)) { throw new Exception("HTML text content cannot be empty."); } try { string path = AppDomain.CurrentDomain.BaseDirectory.ToString() + @"html\"; if (!Directory.Exists(path)) { Directory.CreateDirectory(path); } string fileName = path + DateTime.Now.ToString("yyyyMMddHHmmssfff") + new Random().Next(1000, 10000) + ".html"; FileStream fileStream = new FileStream(fileName, FileMode.Create, FileAccess.ReadWrite, FileShare.ReadWrite); StreamWriter streamWriter = new StreamWriter(fileStream, Encoding.Default); streamWriter.Write(strHtml); streamWriter.Flush(); streamWriter.Close(); streamWriter.Dispose(); fileStream.Close(); fileStream.Dispose(); return fileName; } catch { throw new Exception("HTML text content error."); } } }

PS:在這裏我遇到了一個問題,剛開始設置的命令行參數不起作用,比如:--page-height 100 等。
我也查看了輸出的錯誤信息,後來發現是因為 wkhtmltopdf.exe 這個文件的路徑存在中文的目錄。
然後我就把 wkhtmltopdf.exe 這個文件所在路徑的所有目錄都改為了英文,就這樣就可以了。

四、命令行參數

下面是一些命令行參數的介紹:

全局選項:
--collate                     打印多個副本時進行檢查(默認設置)
--no-collate                  打印多個副本時不進行檢查
--cookie-jar <path>           從指定的cookie JAR文件中讀寫 cookie 數據
--copies <number>             打印 PDF 文件的份數(默認值為:1)
--dpi <dpi>                   設置一個分辨率,對於 X11 系統沒有作用(默認值為:96)
--extended-help               相對 -H 參數的設置,顯示更詳細的說明文檔
--grayscale                   將生成灰度的 PDF 文檔,占用空間小,但是不會有彩色
--help                        顯示幫助信息  
--htmldoc                     輸出程序的 HTML 幫助文檔
--image-dpi <integer>         當頁面存在內嵌圖片時,指定圖像的分辨率(默認值為:600)
--image-quality <interger>    當使用 JPEG 算法壓縮圖片時,指定圖像的質量(默認值為:94)
--license                     輸出授權許可信息並退出
--lowquality                  生成低質量的 PDF/PS,能夠減少最終生成文檔所占用的存儲空間
--manpage                     輸出程序的手冊頁
--quiet                     靜默模式,不輸出任何信息
--read-args-from-stdin      從標準輸入讀取命令行參數
--readme                    輸出程序的 Readme 文檔
--version                   輸出版本信息並退出
--no-pdf-compression        設置為不要對 PDF 對象使用無損壓縮
--margin-bottom <unitreal>  設置頁面的底邊距,單位毫米(mm)
--margin-left <unitreal>    設置頁面的左邊距 (默認值為:10mm)
--margin-right <unitreal>   設置頁面的右邊距 (默認值為:10mm)
--margin-top <unitreal>     設置頁面的上邊距,單位毫米(mm)
--page-size <Size>          設置頁面的大小,如:A4、Letter等(默認值為:A4)
--page-height <unitreal>    設置頁面高度,單位毫米(mm)
--page-width <unitreal>     設置頁面寬度,單位毫米(mm)
--orientation <orientation> 設置文檔模式為風景或肖像(默認值為:肖像)
--title <text>              生成的 PDF 文檔的標題(如果沒有指定,則使用第一個文檔的標題)

大綱選項:
--dump-default-toc-xsl     轉儲到默認的 TOC xsl 樣式表到標準輸出文件
--dump-outline <file>      將大綱轉儲到指定的文件(XML 文件)
--outline                  在生成的 PDF 文檔中添加大綱(默認設置)
--no-outline               不要在生成的 PDF 文檔中添加大綱
--outline-depth <level>    設置大綱的深度(默認值為:4)

頁面選項:
--allow <path>                    允許加載指定文件夾中的文件(可重復使用此參數指定多個文件)
--background                      輸出頁面背景到 PDF 文檔(默認設置)
--no-background                   不輸出頁面背景到 PDF 文檔
--bypass-proxy-for <value>        設置主機的代理(可重復指定多個代理)
--cache-dir <path>                Web緩存目錄
--checkbox-checked-svg <path>     使用指定的SVG文件渲染選中的復選框
--checkbox-svg <path>             使用指定的SVG文件渲染未選中的復選框
--cookie <name> <value>           設置訪問網頁時額外的 cookie,value 應該是 url 編碼的(可重復使用此參數指定多個 cookie)
--custom-header <name> <value>    設置訪問網頁時額外的 HTTP 頭(可重復使用此參數指定多個 HTTP 頭)
--custom-header-propagation       為每個資源請求添加自定義的 HTTP 頭
--no-custom-header-propagation    不要為每個資源請求添加自定義的 HTTP 頭
--debug-javascript                顯示 JavaScript 調試輸出的內容
--no-debug-javascript             不顯示 JavaScript 調試輸出的內容(默認設置)
--encoding <encoding>             設置輸入文本的默認編碼
--disable-external-links          禁止頁面中的外鏈生成超鏈接
--enable-external-links           允許頁面中的外鏈生成超鏈接(默認設置)
--disable-forms                   不要將 HTML 表單轉換為 PDF 表單(默認設置)
--enable-forms                    將 HTML 表單轉換為 PDF 表單
--images                          加載圖片並輸出到 PDF 文檔(默認設置)
--no-images                       在生成的 PDF 文檔中過濾掉圖片
--disable-internal-links          禁止頁面中的內鏈生成超鏈接
--enable-internal-links           允許頁面中的內鏈生成超連接(默認設置)
--disable-javascript              禁止 Web 頁面運行 JavaScript
--enable-javascript               允許 Web 頁面運行 JavaScript(默認設置)
--javascript-delay <msec>         延遲指定的時間,等待 JavaScript 執行完成,單位毫秒(ms)(默認值為:200)
--load-error-handling <handler>   指定如何處理無法加載的頁面:abort、ignore、skip(默認值為:abort)
--load-media-error-handling <handler>     指定如何處理無法加載的媒體文件:abort、ignore、skip(默認值為:ignore)
--disable-local-file-access               不允許一個本地文件加載其他的本地文件,使用命令行參數 --allow 指定的目錄除外。
--enable-local-file-access                允許將本地文件轉換到其他本地文件中讀取(默認設置)
--exclude-from-outline                    不要將頁面包含在內容表和大綱中
--include-in-outline                      將頁面包含在內容表和大綱中(默認設置)
--page-offset <offset>                    設置頁碼的起始值(默認值為:0)
--minimum-font-size <int>                 設置最小的字體大小
--disable-plugins                         禁用已安裝的插件(默認設置)
--enable-plugins                          啟用已安裝的插件(但插件可能不起作用)
--post <name> <value>                     添加一個附加字段(可以重復使用該參數添加多個附加字段)
--post-file <name> <value>                添加一個附加文件(可以重復使用該參數添加多個附加文件)
--print-media-type                        使用打印媒體類型代替屏幕
--no-print-media-type                     不使用打印媒體類型代替屏幕(默認設置)
--proxy <proxy>                           使用代理
--radiobutton-checked-svg <path>          使用指定的SVG文件渲染選中的單選按鈕
--radiobutton-svg <path>                  使用指定的SVG文件渲染未選中的單選按鈕
--run-sript <js>                          在頁面加載完成後運行這個額外的 JavaScript(可以重復使用該參數添加多個額外的 JavaScript)
--disable-smart-shrinking                 禁用智能收縮策略
--enable-smart-shrinking                  啟用智能收縮策略(默認設置)
--stop-slow-scripts                       停止運行緩慢的 JavaScript 代碼(默認設置)
--no-stop-slow-scripts                    不停止運行緩慢的 JavaScript 代碼
--disable-toc-back-links                  禁止從標頭鏈接到內容表(默認設置)
--enable-toc-back-links                   允許從標頭鏈接到內容表
--user-style-sheet <url>                  指定一個用戶樣式表,以便加載每個頁面
--username <username>                     HTTP 身份認證的用戶名
--password <password>                     HTTP 身份認證的密碼
--viewport-size <>                        設置窗口大小,需要自定義滾動條或 CSS 屬性來自適應窗口大小
--window-status <windowStatus>            等到window.status等於這個字符串前渲染頁面
--zoom <float>                            設置轉換成 PDF 時頁面的縮放比例(默認值為:1)
--default-header                          添加一個默認的頁眉,左邊是頁面的名稱,右邊是頁碼,是下面的縮寫:
                                          --header-left=‘[webpage]‘ 
                                          --header-right=‘[page]/[toPage]‘ 
                                          --top 2cm 
                                          --header-line
                                        
頁眉和頁腳選項:
--footer-left <text>              居左顯示頁腳文本
--footer-center <text>            居中顯示頁腳文本
--footer-right <text>             居右顯示頁腳文本
--footer-font-name <name>         設置頁腳的字體名稱(默認值為:Arial)
--footer-font-size <size>         設置頁腳的字體大小(默認值為:12)
--footer-html <url>               添加一個 HTML 作為頁腳
--footer-line                     在頁腳上方顯示一條直線
--no-footer-line                  不在頁腳上方顯示一條直線(默認設置)
--footer-spacing <real>           設置頁腳與內容之間的間距,單位毫米(mm)(默認值為:0)
    
--header-left <text>              居左顯示頁眉文本
--header-center <text>            居中顯示頁眉文本
--header-right <text>             居右顯示頁眉文本
--header-font-name <name>         設置頁眉的字體名稱(默認值為:Arial)
--header-font-size <size>         設置頁眉的字體大小(默認值為:12)
--header-html <url>               添加一個 HTML 作為頁眉
--header-line                     在頁眉下方顯示一條直線
--no-header-line                  不在頁眉下方顯示一條直線(默認設置)
--header-spacing <real>           設置頁眉與內容之間的間距,單位毫米(mm)(默認值為:0)
--replace <name> <value>          在頁眉和頁腳中替換指定名稱的值(可以重復使用該參數指定多個需要替換的名稱和值)

內容表選項:
--disable-dotted-lines            不要在 TOC 中使用虛線
--toc-header-text <text>          設置 TOC 的標題文本(默認值為:內容表)
--toc-level-indentation <width>   在 TOC 縮進每一級的標題長度(默認值為:1em)
--disable-toc-links               在 TOC 中不生成指向內容錨點的超鏈接
--toc-text-size-shrink <real>     在 TOC 中的每一級標題,字體按這個比例縮放(默認值為:0.8)
--xsl-style-sheet <file>          使用指定的 XSL 樣式表打印內容表

頁眉和頁腳:
頁眉和頁腳可以使用參數 --header-* 和 --footer-* 添加到文檔中。
有些參數也需要提供一個字符串 text 作為參數值。例如:--header-left
可以在 text 中使用以下變量,將會把以下變量替換為對應的值。

* [page]       當前正在打印的頁面的頁碼
* [frompage]   打印的第一頁的頁碼
* [topage]     打印的最後一頁的頁碼
* [webpage]    當前正在打印的頁面的 URL
* [section]    當前正在打印的章節的名稱
* [subsection] 當前正在打印的分段的名稱
* [date]       本地系統格式的當前日期
* [isodate]    ISO 8601 擴展格式的當前日期
* [time]       本地系統格式的當前時間
* [title]      當前頁對象的標題
* [doctitle]   輸出文檔的標題
* [sitepage]   當前正在處理的對象中當前頁面的頁碼
* [sitepages]  當前正在處理的對象中的總頁數

舉個例子:
--header-right "Page [page] of [toPage]",
會在頁面的右上角生成一個類似 Page x of y 的字符串,
其中 x 是當前頁面的頁碼, y 是當前文檔最後一頁的頁碼。

五、推薦

下面推薦兩篇比較好的文章,一篇是官網的英文版的介紹,另一篇是中文版的介紹。
具體的大家自己去看吧。
英文版推薦:https://wkhtmltopdf.org/usage/wkhtmltopdf.txt
中文版推薦:http://www.jianshu.com/p/4d65857ffe5e

C# 使用 wkhtmltopdf 把HTML文本或文件轉換為PDF