C# Html转PDF 用itextsharp把Html转PDF 完整版

首先得下载itextsharp

有两个dll, itextsharp.dll和itextsharp.xmlworker.dll

在fonts目录下添加从百度找的字体arialuni.ttf

原文文字排版会乱我进行了修改,内容不能有&符号
原文链接:https://blog.csdn.net/junshangshui/article/details/81193614

一、新建一个HtmlToPdfHelper类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
 /// <summary>
    /// HTML转PDF帮助类
    /// </summary>
    public class HtmlToPdfHelper
    {
        /// <summary>
        /// 准备好的html字符串
        /// </summary>
        private string m_HtmlString;

        /// <summary>
        /// PDF保存目录(绝对路径)
        /// </summary>
        private string m_PDFSaveFloder;

        /// <summary>
        /// 图片XY字典,例如 [{img1, 100,200},{img2,20,30}}
        /// </summary>
        private Dictionary<string, Tuple<float, float>> m_ImageXYDic = null;

        /// <summary>
        /// PDF保存目录(绝对路径)
        /// </summary>
        private string FileName;

        public HtmlToPdfHelper(string htmlString, string pdfSaveFloder, Dictionary<string, Tuple<float, float>> imageXYDic,string fileName)
        {
            m_HtmlString = htmlString;
            m_PDFSaveFloder = pdfSaveFloder;
            m_ImageXYDic = imageXYDic;
            FileName = fileName;
        }

        //生成PDF
        public bool BuilderPDF()
        {
            try
            {
                string pdfSavePath = Path.Combine(m_PDFSaveFloder, FileName + ".pdf");
                if (!Directory.Exists(m_PDFSaveFloder))
                {
                    Directory.CreateDirectory(m_PDFSaveFloder);
                }
                using (FileStream fs = new FileStream(pdfSavePath, FileMode.OpenOrCreate))
                {
                    byte[] htmlByte = ConvertHtmlTextToPDF(m_HtmlString);
                    string HTML= Encoding.UTF8.GetString(htmlByte);
                    fs.Write(htmlByte, 0, htmlByte.Length);
                    return true;
                }
            }
            catch (Exception ex)
            {
                throw new ApplicationException("保存PDF到磁盘时异常", ex);
            }
        }

        //将html字符串转为字节数组(代码来自百度)
        private byte[] ConvertHtmlTextToPDF(string htmlText)
        {
            if (string.IsNullOrEmpty(htmlText))
            {
                return null;
            }
            //避免當htmlText無任何html tag標籤的純文字時,轉PDF時會掛掉,所以一律加上<p>標籤
            htmlText = "<p>" + htmlText + "</p>";

            try
            {
     
                MemoryStream outputStream = new MemoryStream();//要把PDF寫到哪個串流
                byte[] data = Encoding.UTF8.GetBytes(htmlText);//字串轉成byte[]
                MemoryStream msInput = new MemoryStream(data);
                Document doc = new Document();//要寫PDF的文件,建構子沒填的話預設直式A4
                PdfWriter writer = PdfWriter.GetInstance(doc, outputStream);
                //指定文件預設開檔時的縮放為100%
                PdfDestination pdfDest = new PdfDestination(PdfDestination.XYZ, 0, doc.PageSize.Height, 1f);
                //開啟Document文件
                doc.Open();
                //使用XMLWorkerHelper把Html parse到PDF檔裡
                XMLWorkerHelper.GetInstance().ParseXHtml(writer, doc, msInput, null, Encoding.UTF8, new UnicodeFontFactory());
                //將pdfDest設定的資料寫到PDF檔
                PdfAction action = PdfAction.GotoLocalPage(1, pdfDest, writer);
                writer.SetOpenAction(action);
                doc.Close();
                msInput.Close();
                outputStream.Close();
                //回傳PDF檔案
                return outputStream.ToArray();
            }
            catch (Exception ex)
            {
                throw new ApplicationException("转PDF时异常", ex);
            }
        }

        //字体工厂(代码来自百度)
        public class UnicodeFontFactory : FontFactoryImp
        {
            private static readonly string arialFontPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory
                , "fonts/arialuni.ttf");//arial unicode MS是完整的unicode字型。
            private static readonly string 标楷体Path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory,
           "fonts/KAIU.TTF");//标楷体

            public override Font GetFont(string fontname, string encoding, bool embedded, float size, int style, BaseColor color,
                bool cached)
            {
                BaseFont baseFont = BaseFont.CreateFont(arialFontPath, BaseFont.IDENTITY_H, BaseFont.EMBEDDED);
                return new Font(baseFont, size, style, color);
            }
        }

        //自定义的图片处理类(代码来自百度)
        public class CustomImageTagProcessor : iTextSharp.tool.xml.html.Image
        {
            //个人加入的图片位置处理代码
            private float _offsetX = 0;
            private float _offsetY = 0;

            private Dictionary<string, Tuple<float, float>> _imageXYDict;//个人加入的图片位置处理代码
            public CustomImageTagProcessor(Dictionary<string, Tuple<float, float>> imageXYDict)//个人加入的图片位置处理代码
            {
                _imageXYDict = imageXYDict;
            }

            protected void SetImageXY(string imageId)//个人加入的图片位置处理代码
            {
                if (_imageXYDict == null)
                {
                    return;
                }
                Tuple<float, float> xyTuple = null;
                _imageXYDict.TryGetValue(imageId, out xyTuple);

                if (xyTuple != null)
                {
                    _offsetX = xyTuple.Item1;
                    _offsetY = xyTuple.Item2;
                }
            }

            public override IList<IElement> End(IWorkerContext ctx, Tag tag, IList<IElement> currentContent)
            {
                IDictionary<string, string> attributes = tag.Attributes;
                string src;
                if (!attributes.TryGetValue(HTML.Attribute.SRC, out src))
                    return new List<IElement>(1);

                if (string.IsNullOrEmpty(src))
                    return new List<IElement>(1);

                string imageId;//个人加入的图片位置处理代码
                if (!attributes.TryGetValue(HTML.Attribute.ID, out imageId))//个人加入的图片位置处理代码
                    return new List<IElement>(1);

                if (string.IsNullOrEmpty(imageId))
                    return new List<IElement>(1);

                SetImageXY(imageId);//个人加入的图片位置处理代码

                if (src.StartsWith("data:image/", StringComparison.InvariantCultureIgnoreCase))
                {
                    // data:[][;charset=][;base64],
                    var base64Data = src.Substring(src.IndexOf(",") + 1);
                    var imagedata = Convert.FromBase64String(base64Data);
                    var image = iTextSharp.text.Image.GetInstance(imagedata);

                    var list = new List<IElement>();
                    var htmlPipelineContext = GetHtmlPipelineContext(ctx);
                    list.Add(GetCssAppliers().Apply(new Chunk((iTextSharp.text.Image)GetCssAppliers().Apply(image, tag, htmlPipelineContext), _offsetX, _offsetY, true), tag, htmlPipelineContext));
                    return list;
                }
                else
                {
                    return base.End(ctx, tag, currentContent);
                }


            }
        }
    }

二、新建一个测式类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
    /// <summary>
    /// 测试类
    /// </summary>
    public class PersonEntity
    {
        /// <summary>
        /// html模版绝对路径
        /// </summary>
        public string m_HtmlTemplatePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Scripts/person.html");
 
        /// <summary>
        /// PDF生成的目录(绝对路径)
        /// </summary>
        public string m_PdfSaveFolder = Path.Combine(AppDomain.CurrentDomain.BaseDirectory,"PDFFolder");
 
        public PersonEntity()
        {
        }
 
        /// <summary>
        /// 生成PDF
        /// </summary>
        public void BuildPDF()
        {
 
            using (StreamReader reader = new StreamReader(m_HtmlTemplatePath))
            {
                string htmlStr = reader.ReadToEnd();//读取html模版
 
                string iamgeBase64Str1 = ImageToBase64String(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Scripts/img1.jpg"));
                string iamgeBase64Str2 = ImageToBase64String(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Scripts/img2.jpg"));
 
                htmlStr = htmlStr.Replace("@PersonName", "张三");
                htmlStr = htmlStr.Replace("@PersonImage1", iamgeBase64Str1);
                htmlStr = htmlStr.Replace("@PersonImage2", iamgeBase64Str2);
 
                Dictionary<string, Tuple<float, float>> imageXYDic = new Dictionary<string, Tuple<float, float>>();
                imageXYDic.Add("img1", new Tuple<float,float>(10,20));
                imageXYDic.Add("img2", new Tuple<float, float>(200, 300));

                string fliename = Guid.NewGuid().ToString();//文件名称
                HtmlToPdfHelper pdfHelper = new HtmlToPdfHelper(htmlStr, m_PdfSaveFolder, imageXYDic,fliename);
 
                pdfHelper.BuilderPDF();//生成PDF

                //不带照片 HTML内容

                //html样式内容则需要拼接
            //StringBuilder sb = new StringBuilder();
            //sb.Append(
            //  "<html xmlns:v="urn:schemas-microsoft-com:vml"  xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:w="urn:schemas-microsoft-com:office:word" xmlns:m="http://schemas.microsoft.com/office/2004/12/omml"xmlns = "http://www.w3.org/TR/REC-html40"><body>");
            //sb.Append(htmlStr);
            //sb.Append("</body></html>");

                HtmlToPdfHelper pdfHelper2 = new HtmlToPdfHelper(htmlStr, m_PdfSaveFolder, null,fliename );
 
                pdfHelper2.BuilderPDF();//生成PDF


            }
        }
 
        //图片转为base64字符串
        public string ImageToBase64String(string imagePath)
        {
            try
            {
                Bitmap bitmap = new Bitmap(imagePath);
 
                MemoryStream ms = new MemoryStream();
 
                bitmap.Save(ms, ImageFormat.Jpeg);
                byte[] bytes = new byte[ms.Length];
 
                ms.Position = 0;
                ms.Read(bytes, 0, (int) ms.Length);
                ms.Close();
 
                return Convert.ToBase64String(bytes);
            }
            catch (Exception ex)
            {
                throw new ApplicationException("图片转base64字符串时异常", ex);
            }
        }
    }

三、在网站的Scripts目录下添加person.htm 模版

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title></title>
</head>
<body>
<p>@PersonName</p>
<table border="1px">
    <tr>
        <td>
            <img id="img1" src="data:image/jpeg;base64,@PersonImage1" style="width: 50px; height: 50px;"/>
        </td>
    </tr>
</table>
 
<img id="img2" src="data:image/jpeg;base64,@PersonImage2" style="width: 50px; height: 50px;" />
</body>
</html>

四、在网站的Scripts目录下添加img1.jpg和imag2.jpg两张图片