您现在的位置是:首页 >技术交流 >c# 数据保存为PDF(一) (spire pdf篇)网站首页技术交流

c# 数据保存为PDF(一) (spire pdf篇)

唠嗑一夏 2023-06-25 15:48:51
简介c# 数据保存为PDF(一) (spire pdf篇)


先上一个效果图
在这里插入图片描述

前言

项目中需要将一些数据转存为PDF ,打开时不会乱码也不可编辑,方便用户使用和查阅。
然后在网上找了一些资料,发现一个国产开发的组件那就是Spire,功能挺丰富的,可以保存为Excel、PDF、图片、PPT、二维码还带有邮件发送功能。

了解 Spire

该组件是由蓝冰科技制作的,官网在https://www.e-iceblue.cn/
在.NET、Java和Android不同平台下都有对应的语言组件支持,可谓是太强悍了。
在这里插入图片描述
有免费版本和收费的专业版本,当然牛人众多也有很多破解版。免费版有10页的页数限制,还有红色的水印。将PDF转为图片时仅支持转换前3页。

使用Spire.PDF

常用的类

PdfDocument pdf文档对象
PdfPageBase pdf页
PdfPageTemplateElement 页面模板 页眉页脚
PdfMargins 页边距
PdfPaddings 内边距
PdfGrid 网格对象
PdfGridRow 网格行
PdfTrueTypeFont 设置字体
PdfPen 设置画笔
PdfStringFormat 格式化字符串

1 创建简单的PDF文档

//初始化一个PdfDocument实例
PdfDocument document = new PdfDocument();

//设置边距
PdfUnitConvertor unitCvtr = new PdfUnitConvertor();
PdfMargins margins = new PdfMargins();
margins.Top = unitCvtr.ConvertUnits(2.54f, PdfGraphicsUnit.Centimeter, PdfGraphicsUnit.Point);
margins.Bottom = margins.Top;
margins.Left = unitCvtr.ConvertUnits(3.17f, PdfGraphicsUnit.Centimeter, PdfGraphicsUnit.Point);
margins.Right = margins.Left;

//添加新页
PdfPageBase page = document.Pages.Add(PdfPageSize.A4, margins);

//自定义PdfTrueTypeFont、PdfPen实例
PdfTrueTypeFont font = new PdfTrueTypeFont(new Font("宋体", 11f), true);
PdfPen pen = new PdfPen(Color.Black);

//使用DrawString方法在指定位置写入文本
string text = "我的第一个C# PDF文档";
page.Canvas.DrawString(text, font,pen,100,50);

//保存文档
document.SaveToFile("PDF创建.pdf");

在这里插入图片描述

2 创建带有格式的PDF文档(使用Draw)

确定要生成PDF文件的格式和样式,包含页眉, 页脚,中间是数据内容,内容是4列。

头部信息

主要是字体大小不一样,计算高度时要加上字体的高度
在这里插入图片描述


     private static float CreateTitle(PdfDocument document, PdfMargins margins)
        {
            //获取页面大小
            SizeF pageSize = document.PageSettings.Size;

            //声明 x y 两个float变量
            //  float x = margins.Left;
            float x = 0;
            float y = 0;

            string Report = "Parameter Settings Report(Program)";
            string dataTime = DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss");

            PdfPageBase page = document.Pages[0];

            PdfTrueTypeFont Font = new PdfTrueTypeFont(new Font("微软雅黑", 15f, FontStyle.Bold), true);
            PdfStringFormat Format = new PdfStringFormat(PdfTextAlignment.Left);

            //在footerSpace中绘制线段
            PdfPen pen = new PdfPen(PdfBrushes.Black, 0.1f);

            page.Canvas.DrawString(Report, Font, PdfBrushes.Black, x, y, Format);
            SizeF size = Font.MeasureString(Report);

            Format.Alignment = PdfTextAlignment.Right;
            Font = new PdfTrueTypeFont(new Font("微软雅黑", 12f, FontStyle.Bold), true);

            SizeF sizeTime = Font.MeasureString(dataTime);
            RectangleF Bounds = new RectangleF(pageSize.Width - 2*sizeTime.Width, y, sizeTime.Width, sizeTime.Height);

            page.Canvas.DrawString(dataTime, Font, PdfBrushes.Black, Bounds, Format);

            y +=  2 + size.Height ;
            page.Canvas.DrawLine(pen, x, y, pageSize.Width, y);

            Font = new PdfTrueTypeFont(new Font("微软雅黑", 12f, FontStyle.Bold), true);
            PdfTrueTypeFont Font2 = new PdfTrueTypeFont(new Font("微软雅黑", 11f, FontStyle.Regular), true);
            Format.Alignment = PdfTextAlignment.Left;
            
          
            y += 2 ;
           
            size = Font.MeasureString("Program");
            SizeF size2 = Font2.MeasureString("Drive Type/");

            float endY = y + size.Height + 2 + size2.Height;
            PdfPen penRe = new PdfPen(PdfBrushes.Gray, 0.1f);
           
            page.Canvas.DrawRectangle(penRe, PdfBrushes.LightCyan, new RectangleF(x, y, pageSize.Width, endY - y));


            page.Canvas.DrawString("  Program(Drive Selected / Connected)", Font, PdfBrushes.Black, x, y, Format);

            y += 2 + size.Height;
            page.Canvas.DrawString("  Drive Type/Model: ", Font2, PdfBrushes.Black, x, y, Format);

            
            y += 2 + size2.Height;
            page.Canvas.DrawLine(pen, x, y, pageSize.Width, y);

            y += 2;
            page.Canvas.DrawString("Projetc: p1", Font2, PdfBrushes.Black, x, y, Format);

           
            y += 2 + size2.Height;
            page.Canvas.DrawString("User: ", Font2, PdfBrushes.Black, x, y, Format);
           
            y += 2 + size2.Height;
            page.Canvas.DrawLine(pen, x, y, pageSize.Width , y);

            y += 2;
            page.Canvas.DrawString("Information ", Font2, PdfBrushes.Black, x, y, Format);

            y += 100;

            return y;
        }
页眉

页眉就是标题行了,包含这4列,还有字体、背景颜色的设置
在这里插入图片描述

       /// <summary>
        /// 绘制页眉
        /// </summary>
        /// <param name="document"></param>
        /// <param name="page"></param>
        /// <param name="startY"></param>
        /// <returns></returns>
        private static float DrawPDFCodeTitle(PdfDocument document, PdfPageBase page, float startY )
        {
            SizeF docSize = document.PageSettings.Size;
            float x = 0;
            float y = startY;

            PdfTrueTypeFont font = new PdfTrueTypeFont(new Font("微软雅黑", 9f, FontStyle.Bold));
            SizeF strSize = font.MeasureString("Default");

            //绘制背景色
            RectangleF rectangle = new RectangleF(0, startY, docSize.Width, strSize.Height * 2 + 5);
            page.Canvas.DrawRectangle(new PdfPen(PdfBrushes.DarkGray, 0.1f), PdfBrushes.LightCyan, rectangle);

            PdfStringFormat format = new PdfStringFormat(PdfTextAlignment.Left, PdfVerticalAlignment.Bottom);

          
            y += strSize.Height + 2;
            page.Canvas.DrawString(" Parameter", font, PdfBrushes.Black, x, y);

            x += (float)(docSize.Width * 0.31);
            page.Canvas.DrawString("Value", font, PdfBrushes.Black, x, y);
            
            x += (float)(docSize.Width * 0.098);
            page.Canvas.DrawString("Infomation", font, PdfBrushes.Black, x, y);
          
            x += (float)(docSize.Width * 0.3);
            page.Canvas.DrawString("Setting", font, PdfBrushes.Black, x, y);
            page.Canvas.DrawString("Default", font, PdfBrushes.Black, x, y - strSize.Height- 1);

            return (startY + strSize.Height * 2 + 5);
     }

页脚

页脚一般放置公司或个人的特征信息,加上页码
在这里插入图片描述


        /// <summary>
        /// 页脚
        /// </summary>
        /// <param name="document"></param>
        /// <param name="margins"></param>
        /// <returns></returns>
        private static PdfPageTemplateElement CreateFooterTemplate(PdfDocument document, PdfMargins margins)
        {
            //获取页面大小
            SizeF pageSize = document.PageSettings.Size;

            //创建PdfPageTemplateElement对象 footer,即页脚模板
            PdfPageTemplateElement footerSpace = new PdfPageTemplateElement(pageSize.Width, margins.Bottom);
            footerSpace.Foreground = false;

            //声明 x y 两个float变量
            float x = margins.Left;
            float y = 0;

            //在footerSpace中绘制线段
            PdfPen pen = new PdfPen(PdfBrushes.Black, 1f);
            footerSpace.Graphics.DrawLine(pen, x, y, pageSize.Width - x, y);

            //在footerSpace中绘制文字
            y = y + 5;
            PdfTrueTypeFont font = new PdfTrueTypeFont(new Font("微软雅黑", 10f, FontStyle.Bold), true);
            PdfStringFormat format = new PdfStringFormat(PdfTextAlignment.Left);
            String footerText = "Test for Windows(C) by 唠嗑一夏 Electric Corporation";
            footerSpace.Graphics.DrawString(footerText, font, PdfBrushes.Black, x, y, format);

                //在footerSpace中绘制当前页码和总页码数
                PdfPageNumberField number = new PdfPageNumberField();
                PdfPageCountField count = new PdfPageCountField();

            PdfCompositeField compositeField = new PdfCompositeField(font,
                PdfBrushes.Black, "{0}/{1}", number, count);
            
           

            compositeField.StringFormat = new PdfStringFormat(PdfTextAlignment.Right, PdfVerticalAlignment.Top);
            SizeF size = font.MeasureString(compositeField.Text);

            compositeField.Bounds = new RectangleF(pageSize.Width - x - size.Width, y, size.Width, size.Height);
            compositeField.Draw(footerSpace.Graphics);

            //返回页脚footerSpace
            return footerSpace;

        }

测试数据

在这里创建了100个数据做测试使用。


        /// <summary>
        /// 数据表格
        /// </summary>
        /// <returns></returns>
        private DataTable CreateData()
        {
            DataTable dt = new DataTable();
            DataColumn col1 = new DataColumn("Num", typeof(string));
            DataColumn col2 = new DataColumn("Name", typeof(string));
            DataColumn col3 = new DataColumn("Val", typeof(string));
            DataColumn col4 = new DataColumn("Des", typeof(string));
            DataColumn col5 = new DataColumn("Set", typeof(string));

            dt.Columns.Add(col1);
            dt.Columns.Add(col2);
            dt.Columns.Add(col3);
            dt.Columns.Add(col4);
            dt.Columns.Add(col5);

            Random random = new Random();
            List<string> nameList = new List<string>
            {
                "A", "BB", "CCC", "D",
                "E", "F", "G","H","II",
                "JJ", "LL", "M"
            };

            List<string> tempList = new List<string>
            {
                "dsd", "sdfdgvre", "Hello", "Gilrs",
                "Today", "YYYY", "dfgre","GSD","fdgfer",
                "Wesd", "DLG", "fsdahfi;o"
            };

            for(int i=0; i<10; i++)
            {
                for(int j=0; j<10; j++)
                {
                    DataRow dr = dt.NewRow();
                    dr[0] = "KK" + i.ToString("d2") + "." + j.ToString("d2");
                    dr[1] =  nameList[j];
                    if ( j % 3 == 0)
                    {
                        dr[2] = random.NextDouble().ToString("f3");
                    }
                    else
                    {
                        dr[2] = i * j - random.Next(0, 30);
                    }
                    dr[3] = tempList[j];

                    dr[4] =  random.NextDouble().ToString("f2");

                    //添加新行
                    dt.Rows.Add(dr);
                }
            }

            return dt;
        }

完整的代码

包含页眉、页脚、页边距、数据内容。这里主要通过Canvas.DrawString绘制所有数据。需要注意一点的是里面涉及了简单位置和高度的计算,绘制到什么时候可以换页继续绘制,关注点在document.PageSettings.Size的高度。

其中涉及的调用函数 SpireHelper.ActivateMemoryPatching(); 是为了去掉dll自带的红色警告字体。可以注释掉该行,不影响使用。也可以访问http://t.csdn.cn/k97kx 这篇文章里面有具体的代码。

        /// <summary>
        /// 保存到Pdf
        /// </summary>
        /// <param name="path">文件路径</param>
        public void SaveToPdfByDraw(string path)
        {
            //临时数据
            DataTable dataTable = CreateData();

            //去掉dll自带的红色警告字体
            SpireHelper.ActivateMemoryPatching();

            //初始化PdfDocument实例
            PdfDocument document = new PdfDocument();


            //禁用IncrementalUpdate
            document.FileInfo.IncrementalUpdate = false;

            //设置PDF文档的压缩级别
            document.CompressionLevel = PdfCompressionLevel.Best;


            //指定页面大小
            document.PageSettings.Size = PdfPageSize.A4;

            //设置页边距为0
            document.PageSettings.Margins = new PdfMargins(0, 40, 0, 0);

            //创建PdfMargins 对象,指定期望设置的页边距
            PdfMargins margins = new PdfMargins(40, 60, 40, 60);

            //在文档模板的顶部和顶部应用页脚模板
            document.Template.Bottom = CreateFooterTemplate(document, margins);


            //在文档模板的左右部分应用空白模板
            document.Template.Left = new PdfPageTemplateElement(margins.Left, document.PageSettings.Size.Height);
            document.Template.Right = new PdfPageTemplateElement(margins.Right, document.PageSettings.Size.Height);


            //自定义字体 和画笔
            PdfTrueTypeFont fontBold = new PdfTrueTypeFont(new Font("微软雅黑", 9f, FontStyle.Bold), true);
            PdfTrueTypeFont fontNormal = new PdfTrueTypeFont(new Font("微软雅黑", 9f, FontStyle.Regular), true);

            SizeF fontSize = fontBold.MeasureString("KK00.00");

            //添加数据到表格
            int count = dataTable.Rows.Count;
            string str = "";
            string strBak = "";
            int j = 0;
            float y = 0;

            SizeF docSize = document.PageSettings.Size;
            //在文档中添加页
            PdfPageBase page = document.Pages.Add();


            {
                //绘制项目表头
                float tempH = CreateTitle(document, margins);

                //绘制页眉表头
                y = DrawPDFCodeTitle(document, page, tempH + 5);
                y += 2;

                #region 全部
                for (int i = 0; i < count; i++)
                {
                    if ((y + fontSize.Height + 2) > (document.PageSettings.Height - margins.Bottom))
                    {//换页

                        page = document.Pages.Add();
                        //绘制页眉表头
                        y = DrawPDFCodeTitle(document, page, 0) + 1;
                    }

                    DataRow dataRow = dataTable.Rows[i];
                    strBak = dataRow[0].ToString().Substring(0, 4);
                    if (strBak != str)
                    {//绘制组
                        str = strBak;
                        string converStr = strBak;
                        fontSize = fontBold.MeasureString(converStr);

                        page.Canvas.DrawString(converStr, fontBold, PdfBrushes.Black, 0, y);

                        y += fontSize.Height + 2;
                        page.Canvas.DrawLine(new PdfPen(PdfBrushes.Black, 0.5f), 0, y, fontSize.Width, y);

                    }
                    else
                    {//绘制内容
                        y += 2;
                        string tempStr = dataRow[0].ToString() + " " + dataRow[1].ToString();

                        fontSize = fontNormal.MeasureString(tempStr);
                        if ((y + fontSize.Height + 2) > (document.PageSettings.Height - margins.Bottom))
                        {//换页

                            page = document.Pages.Add();
                            //绘制页眉表头
                            y = DrawPDFCodeTitle(document, page, 0) + 1;
                        }

                        float widthX = 0;
                        page.Canvas.DrawString(tempStr, fontNormal, PdfBrushes.Black, widthX, y);

                        widthX += (float)(docSize.Width * 0.31);
                        page.Canvas.DrawString(dataRow[2].ToString(), fontNormal, PdfBrushes.Black, widthX, y);

                        widthX += (float)(docSize.Width * 0.098);
                        page.Canvas.DrawString(dataRow[3].ToString(), fontNormal, PdfBrushes.Black, widthX, y);

                        widthX += (float)(docSize.Width * 0.3);
                        page.Canvas.DrawString(dataRow[4].ToString(), fontNormal, PdfBrushes.Black, widthX, y);

                        y += fontSize.Height + 2;
                    }

                }
                #endregion
            }

            //保存
            document.SaveToFile(path, Spire.Pdf.FileFormat.PDF);

            //打开创建的PDF
            System.Diagnostics.Process.Start(path);

        }


第一页的效果图
在这里插入图片描述

3 创建带有格式的PDF文档(使用Gird)

上一种方式是使用Draw绘制内容的,这里呢介绍另外一种相对简单的方式,使用Grid
的绘制。

        /// <summary>
        /// 保存到Pdf
        /// </summary>
        /// <param name="path">文件路径</param>
      
        public void SaveToPdfByGrid(string path)
        {
            //获取临时数据
            DataTable dataTable = CreateData();

            //去掉dll自带的红色警告字体
            SpireHelper.ActivateMemoryPatching();

            //初始化PdfDocument实例
            PdfDocument document = new PdfDocument();

            //禁用IncrementalUpdate
            document.FileInfo.IncrementalUpdate = false;

            //设置PDF文档的压缩级别
            document.CompressionLevel = PdfCompressionLevel.Best;

            //指定页面大小
            document.PageSettings.Size = PdfPageSize.A4;

            //设置页边距为0
            document.PageSettings.Margins = new PdfMargins(0, 60, 0, 0);

            //创建PdfMargins 对象,指定期望设置的页边距
            PdfMargins margins = new PdfMargins(40, 60, 40, 60);

            //在文档模板的顶部和顶部应用页眉页脚模板
             document.Template.Bottom = CreateFooterTemplate(document, margins);
           

            //在文档模板的左右部分应用空白模板
            document.Template.Left = new PdfPageTemplateElement(margins.Left, document.PageSettings.Size.Height);
            document.Template.Right = new PdfPageTemplateElement(margins.Right, document.PageSettings.Size.Height);


            //在文档中添加两页并写入文字
            PdfPageBase page = document.Pages.Add();

            float spaceH = CreateTitle(document, margins);
         

            //自定义字体 和画笔
            PdfPen pen = new PdfPen(Color.Transparent, 0.001f);
            pen.DashStyle = PdfDashStyle.None;

            PdfPen titlePen = new PdfPen(Color.Gray, 0.05f);
            pen.DashStyle = PdfDashStyle.Solid;

            PdfPen groupPen = new PdfPen(Color.Black, 0.1f);
            pen.DashStyle = PdfDashStyle.Solid;

            //创建PdfGrid类对象
            PdfGrid grid = new PdfGrid();

            //设置单元格填充
            grid.Style.CellPadding = new PdfPaddings(1, 1, 1, 1);

            //添加表格列数
            grid.Columns.Add(4);
            SizeF pageSize = document.PageSettings.Size;

            //设置列宽
            grid.Columns[0].Width = (float)(pageSize.Width * 0.35);
            grid.Columns[0].Width = (float)(pageSize.Width * 0.098); ;
            grid.Columns[0].Width = (float)(pageSize.Width * 0.42); ;
            grid.Columns[0].Width = (float)(pageSize.Width * 0.117); ;


            //添加表头行以及表格数据
            PdfGridRow[] pdfGridRows = grid.Headers.Add(1);
            for (int i = 0; i < pdfGridRows.Length; i++)
            {
                //指定字体
                pdfGridRows[i].Style.Font = new PdfTrueTypeFont(new Font("微软雅黑", 12f, FontStyle.Bold), true);
                pdfGridRows[i].Cells[0].Value = " Parameter";
                pdfGridRows[i].Cells[1].Value = "Value";
                pdfGridRows[i].Cells[2].Value = "Infomation";
                pdfGridRows[i].Cells[3].Value = "Default
 Setting";
                pdfGridRows[i].Style.BackgroundBrush = PdfBrushes.LightCyan;
                pdfGridRows[i].Style.TextBrush = PdfBrushes.Black;
                pdfGridRows[i].Height = 40f;


                pdfGridRows[i].Cells[0].StringFormat = new PdfStringFormat(PdfTextAlignment.Left, PdfVerticalAlignment.Bottom);
                pdfGridRows[i].Cells[1].StringFormat = new PdfStringFormat(PdfTextAlignment.Left, PdfVerticalAlignment.Bottom);
                pdfGridRows[i].Cells[2].StringFormat = new PdfStringFormat(PdfTextAlignment.Left, PdfVerticalAlignment.Bottom);
                pdfGridRows[i].Cells[3].StringFormat = new PdfStringFormat(PdfTextAlignment.Left, PdfVerticalAlignment.Bottom);



                pdfGridRows[i].Cells[0].Style.Borders.All = titlePen;
                pdfGridRows[i].Cells[0].Style.Borders.Right = pen;

                pdfGridRows[i].Cells[1].Style.Borders.All = titlePen;
                pdfGridRows[i].Cells[1].Style.Borders.Right = pen;
                pdfGridRows[i].Cells[1].Style.Borders.Left = pen;

                pdfGridRows[i].Cells[2].Style.Borders.All = titlePen;
                pdfGridRows[i].Cells[2].Style.Borders.Right = pen;
                pdfGridRows[i].Cells[2].Style.Borders.Left = pen;

                pdfGridRows[i].Cells[3].Style.Borders.All = titlePen;
                pdfGridRows[i].Cells[3].Style.Borders.Left = pen;

            }

            //设置重复表头(表格跨页时)
            grid.RepeatHeader = true;


            //添加数据到表格
            int count = dataTable.Rows.Count;
            string str = "";
            string strBak = "";
            int j = 0;
            bool IsGroup = false;
            for (int i = 0; i < count; i++)
            {
                PdfGridRow row = grid.Rows.Add();
                DataRow dataRow = dataTable.Rows[i];
                strBak = dataRow[0].ToString().Substring(0, 4);
                if (strBak != str)
                {
                    IsGroup = true;
                    str = strBak;
                    string converStr = strBak ;


                    //写入
                    row.Cells[0].Value = strBak ;
                    j++;

                    //指定字体
                    row.Cells[0].Style.Font = new PdfTrueTypeFont(new Font("微软雅黑", 9f, FontStyle.Bold), true);
                    row.Cells[0].Style.Borders.Bottom = groupPen;
                    row.Cells[0].Style.Borders.Top = pen;
                    row.Cells[0].Style.Borders.Left = pen;
                    row.Cells[0].Style.Borders.Right = pen;
                }
                else
                {
                    //指定字体
                    row.Style.Font = new PdfTrueTypeFont(new Font("微软雅黑", 9f, FontStyle.Regular), true);

                    row.Cells[0].Value = dataRow[0].ToString() + " " + dataRow[1].ToString(); 
                    row.Cells[1].Value = dataRow[2].ToString();
                   
                     row.Cells[2].Value = dataRow[3].ToString();


                    row.Cells[3].Value = dataRow[4].ToString(); ;

                    if (IsGroup)
                    {
                        IsGroup = false;
                        row.Cells[0].Style.Borders.Top = titlePen;
                        row.Cells[0].Style.Borders.Bottom = pen;
                        row.Cells[0].Style.Borders.Left = pen;
                        row.Cells[0].Style.Borders.Right = pen;
                    }
                    else
                    {
                        row.Cells[0].Style.Borders.All = pen;
                    }

                }

                row.Cells[1].Style.Borders.All = pen;
                row.Cells[2].Style.Borders.All = pen;
                row.Cells[3].Style.Borders.All = pen;
            }


            //在pdf页面绘制表格
            grid.Draw(page, new PointF(0, spaceH + 20));


            //保存文档
            document.SaveToFile(path);

            //打开PDF
            System.Diagnostics.Process.Start(path);
            
        }

在这里插入图片描述

小结

1、关于该组件的红色警告字体可以参考文章:http://t.csdn.cn/k97kx
2、使用PdfGrid放置内容会比较方便,简单,但格式花样就没有那么多。
3、使用 PdfPageBase.Canvas.Draw函数类,可以自由自定义绘制格式,就是需要计算高度和宽度,相对复杂一点。

风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。