码迷,mamicode.com
首页 > Windows程序 > 详细

C# 使用 wkhtmltopdf 把HTML文本或文件转换为PDF

时间:2017-12-06 19:41:20      阅读:899      评论:0      收藏:0      [点我收藏+]

标签:down   inpu   简介   验证   current   彩色   local   访问   第一个   

一、简介

之前也记录过一篇关于把 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

标签:down   inpu   简介   验证   current   彩色   local   访问   第一个   

原文地址:http://www.cnblogs.com/Brambling/p/7994095.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!