zoukankan      html  css  js  c++  java
  • [C#]使用第三方开源库iText7.pdfHtml,将Html转换成Pdf,以及如何以Html作为打印模板

    使用第三方开源库iText7.pdfHtml,将html和css转成pdf,官方:https://itextpdf.com/en/demos/convert-html-css-to-pdf-free-online;

    官方示例:

    using System.IO;
    using iText.Html2pdf;
    
    namespace WebsiteDemoPdfHtml
    {
        class Program
        {
            private static string ORIG = "/uploads/input.html";
            private static string OUTPUT_FOLDER = "/myfiles/";
    
            static void Main(string[] args)
            {
                string pdfDest = OUTPUT_FOLDER + "output.pdf";
                HtmlConverter.ConvertToPdf(new FileStream(ORIG, FileMode.Open), new FileStream(pdfDest, FileMode.Create));
            }
        }
    }

    官方可以下载到详细的使用说明文档:

    设置默认打印纸张大小:

    var pdfDest = "hello.pdf";
    var pdfWriter = new PdfWriter (pdfDest);
    var pdf = new PdfDocument (pdfWriter);
    
    var pageSize = PageSize.A4; // 设置默认打印纸张大小,css @page规则可覆盖这个
    pdf.SetDefaultPageSize (pageSize);

    支持css @page规则控制打印设置选项,例如css @page设置A3打印纸,横向打印,这些规规将覆盖上面的设置默认打印纸张大小:

    @page {
        size: A3 landscape;
    }

    如果需要引入其他资源,比如插入图片,需要设置根目录,将资源文件放入根目录或子文件夹下:

    var properties = new ConverterProperties ();
    properties.SetBaseUri ("wwwroot"); // 设置根目录

    默认不支持中文字体,需要修改默认字体提供者,使其支持系统字体:

    var provider = new DefaultFontProvider (true, true, true); // 第三个参数为True,以支持系统字体,否则不支持中文
    properties.SetFontProvider (provider);

    支持css @media规则,使其在不同设备上显示不同效果,比如在预览时使用Screen设备显示彩色效果,在打印时使用Print设备增强黑白效果:

    var mediaDeviceDescription = new MediaDeviceDescription (MediaType.PRINT); // 指当前设备类型,如果是预览使用SCREEN
    mediaDeviceDescription.SetWidth (pageSize.GetWidth ());
    properties.SetMediaDeviceDescription (mediaDeviceDescription);

    最后是以html作为打印模板,加载数据,再转成pdf;

    官方推荐的是使用XSL转换(xmlns:xsl="http://www.w3.org/1999/XSL/Transform"),将xml转换成html,但该示例目前仅支持java,c#找不到相关源码,并且该方式不支持模板预览,不方便用户修改模板:

    所以还是推荐使用正则替换规则导入数据,下面是示例html:

    <!DOCTYPE html>
    
    <html lang="en" xmlns="http://www.w3.org/1999/xhtml">
    <head>
        <meta charset="utf-8" />
        <title></title>
        <style type="text/css">
            @page {
                size: A4 landscape;
            }
    
            ul {
                margin-left: 0;
                padding-left: 0;
            }
    
                ul li {
                    list-style: none;
                }
    
                    ul li:after {
                        content: "";
                        display: block;
                        clear: both;
                    }
    
                    ul li p {
                        float: left;
                        margin-left: 2em;
                    }
    
                        ul li p:first-child {
                            margin-left: 0;
                        }
    
                        ul li p img {
                            width: 36px;
                            height: 36px;
                        }
        </style>
    </head>
    <body>
        <h3>使用第三方库iText7.pdfHtml,将Html转换成Pdf,以及如何以Html作为打印模板</h3>
        <h5>{{ListOfNames}}</h5>
        <ul>
            <!--template-start-->
            <li>
                <p><img src="{{Avatar}}" /></p>
                <p>姓名:{{Name}}</p>
                <p>年龄:{{Age}}</p>
                <p>性别:{{Sex}}</p>
            </li>
            <!--template-end-->
        </ul>
    </body>
    </html>
    View Code

    使用双大括号{{field}}作为书签,但因为有列表数据,如果直接替换,可能将列表数据修改,所以应该先替换列表数据,在该示例中,以<!--template-start-->作为模板匹配头,以<!--template-end-->作为模板匹配尾,然后不断复制匹配字段,如果子模版又有子模版,则先替换子模版,以此类推,下面是完整代码:

    using iText.Html2pdf;
    using iText.Html2pdf.Resolver.Font;
    using iText.Kernel.Geom;
    using iText.Kernel.Pdf;
    using iText.StyledXmlParser.Css.Media;
    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Reflection;
    using System.Text;
    using System.Text.RegularExpressions;
    
    namespace Demo
    {
        class Program
        {
            static void Main(String[] args)
            {
                var pdfDest = "hello.pdf";
                var pdfWriter = new PdfWriter(pdfDest);
                var pdf = new PdfDocument(pdfWriter);
    
                var pageSize = PageSize.A4;       // 设置默认页面大小,css @page规则可覆盖这个
                pdf.SetDefaultPageSize(pageSize);
    
                var properties = new ConverterProperties();
                properties.SetBaseUri("wwwroot");     // 设置根目录
                properties.SetCharset("utf-8");
    
                var provider = new DefaultFontProvider(true, true, true);       // 第三个参数为True,以支持系统字体,否则不支持中文
                properties.SetFontProvider(provider);
    
                var mediaDeviceDescription = new MediaDeviceDescription(MediaType.PRINT);      // 指当前设备类型,如果是预览使用SCREEN
                mediaDeviceDescription.SetWidth(pageSize.GetWidth());
    
                properties.SetMediaDeviceDescription(mediaDeviceDescription);
    
                var peoples = new List<People>
                {
                    new People { Avatar = "avatar.jpg", Name = "小明", Age = 23, Sex = "" },
                    new People { Avatar = "avatar.jpg", Name = "小王", Age = 18, Sex = "" },
                    new People { Avatar = "avatar.jpg", Name = "小樱", Age = 19, Sex = "" },
                    new People { Avatar = "avatar.jpg", Name = "小兰", Age = 20, Sex = "" },
                };
    
                var htmlTemplate = File.ReadAllText("wwwroot/hello.html");
    
                Dictionary<String, String> dic = null;
                Regex regex = null;
    
                var start = "<!--template-start-->";
                var end = "<!--template-end-->";
    
                var match = Regex.Match(htmlTemplate, $@"{start}(.|s)+?{end}");
    
                if (match != null && match.Value.Length > start.Length + end.Length)
                {
                    var template = match.Value.Substring(start.Length, match.Value.Length - start.Length - end.Length);
    
                    var sb = new StringBuilder(start);
    
                    foreach (var people in peoples)
                    {
                        dic = HtmlTemplateDataBuilder.Create(people);
                        regex = new Regex(String.Join("|", dic.Keys));
                        sb.Append(regex.Replace(template, m => dic[m.Value]));
                    }
    
                    sb.Append(end);
    
                    htmlTemplate = htmlTemplate.Replace(match.Value, sb.ToString());
                }
    
                dic = new Dictionary<String, String> { ["{{ListOfNames}}"] = "人员列表" };
                regex = new Regex(String.Join("|", dic.Keys), RegexOptions.IgnoreCase);
    
                var html = regex.Replace(htmlTemplate, m => dic[m.Value]);
                HtmlConverter.ConvertToPdf(html, pdf, properties);
            }
    
            struct People
            {
                public String Avatar { get; set; }      // 头像
                public String Name { get; set; }        // 姓名
                public Int32 Age { get; set; }          // 年龄
                public String Sex { get; set; }         // 性别
            }
    
            public static class HtmlTemplateDataBuilder
            {
                public static Dictionary<String, String> Create(Object obj)
                {
                    var props = obj.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.GetProperty);
    
                    var dic = new Dictionary<String, String>();
    
                    foreach (var prop in props)
                    {
                        dic.Add("{{" + prop.Name + "}}", prop.GetValue(obj, null).ToString());
                    }
    
                    return dic;
                }
            }
        }
    }
    View Code

     

  • 相关阅读:
    (转)AS3中实现卡马克卷轴算法
    (转)flash位图缓存cacheAsBitmap
    (转)addFrameScript函数的纠结
    (转)flash安全策略文件
    (转)脏矩形技术学习
    (转)stopImmediatePropagation 和stopPropagation的区别
    (转)flash对象池技术
    揭开嵌入式C面试题背后的玄机
    一次遍历找链表倒数第n个节点
    N!的尾部连续0的个数
  • 原文地址:https://www.cnblogs.com/pumbaa/p/14150445.html
Copyright © 2011-2022 走看看