C# 用itextsharp把Html转PDF

首先得下载itextsharp

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

一、新建一个HtmlToPdfHelper类

namespace ClassLibrary1
{
    /// <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;

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

        //生成PDF
        public bool BuilderPDF()
        {
            try
            {
                string pdfSavePath = Path.Combine(m_PDFSaveFloder, Guid.NewGuid().ToString()+".pdf");
                if (!Directory.Exists(m_PDFSaveFloder))
                {
                    Directory.CreateDirectory(m_PDFSaveFloder);
                }
                using (FileStream fs = new FileStream(pdfSavePath, FileMode.OpenOrCreate))
                {
                    byte[] htmlByte = ConvertHtmlTextToPDF(m_HtmlString);
                    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();

                #region 图片的处理
                CssFilesImpl cssFiles = new CssFilesImpl();
                cssFiles.Add(XMLWorkerHelper.GetInstance().GetDefaultCSS());
                var cssResolver = new StyleAttrCSSResolver(cssFiles);

                var tagProcessors = (DefaultTagProcessorFactory)Tags.GetHtmlTagProcessorFactory();
                tagProcessors.RemoveProcessor(HTML.Tag.IMG); // remove the default processor
                tagProcessors.AddProcessor(HTML.Tag.IMG, new CustomImageTagProcessor(m_ImageXYDic)); // use new processor

                var hpc = new HtmlPipelineContext(new CssAppliersImpl(new XMLWorkerFontProvider()));
                hpc.SetAcceptUnknown(true).AutoBookmark(true).SetTagFactory(tagProcessors); // inject the tagProcessors

                var charset = Encoding.UTF8;
                var htmlPipeline = new HtmlPipeline(hpc, new PdfWriterPipeline(doc, writer));
                var pipeline = new CssResolverPipeline(cssResolver, htmlPipeline);
                var worker = new XMLWorker(pipeline, true);
                var xmlParser = new XMLParser(true, worker, charset);
                xmlParser.Parse(new StringReader(htmlText));
                #endregion

                //使用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();

                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
                , "Content/arialuni.ttf");//arial unicode MS是完整的unicode字型。

            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);
                }
            }
        }
    }
}

二、新建一个测式类

namespace ClassLibrary1
{
    /// <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));

                HtmlToPdfHelper pdfHelper = new HtmlToPdfHelper(htmlStr, m_PdfSaveFolder, imageXYDic);

                pdfHelper.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 模版

<!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两张图片,在Content目录下添加从百度找的字体arialuni.ttf

五、在Default.aspx界面写入调用代码

public partial class _Default : Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        PersonEntity personEntity = new PersonEntity();
        personEntity.BuildPDF();
    }
}

六、运行Default.aspx页面后,将在网站目录PDFFolder中生成了一个PDF,效果如下图

七、源码在我上传的CSDN资源中 https://download.csdn.net/download/junshangshui/10561974

猜你喜欢

转载自blog.csdn.net/junshangshui/article/details/81193614