zoukankan      html  css  js  c++  java
  • 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='150px;height:150px;background-color:blue;'></div>";
                string htmlUrl = "https://wkhtmltopdf.org/downloads.html";
    
                /// 把 HTML 文本内容转换为 PDF
                HtmlTextConvertToPdf(strHtml, @"C:UsersAdministratorDesktop01.pdf");
    
                /// 把 HTML 文件转换为 PDF
                HtmlConvertToPdf(htmlUrl, @"C:UsersAdministratorDesktop02.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

  • 相关阅读:
    使用nltk库查找英文同义词和反义词
    argostranslate 翻译的使用
    python从git上安装相应的依赖库
    json.dumps()函数解析
    python将xml文件转为json
    python匹配字符串中,某个词的位置
    TypeError: Cannot read property 'version' of undefined
    js常用工程类函数 | 下载链接 | 自定义下载内容
    C# Visual Studio 2019 代码自动补全 TAB+TAB
    国内开源镜像站点汇总
  • 原文地址:https://www.cnblogs.com/Brambling/p/7994095.html
Copyright © 2011-2022 走看看