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


一、簡介

之前也記錄過一篇關於把 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

 


免責聲明!

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



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