您现在的位置是:首页 >技术杂谈 >c# 数据保存为PDF(三) (PdfSharp篇)网站首页技术杂谈
c# 数据保存为PDF(三) (PdfSharp篇)
PdfSharp 使用,创建PDF文档
往期文章:
1、 c# 数据保存为PDF(一) (Spire.PDF篇)
2、c# 数据保存为PDF(二) (Apose.Pdf篇)
前言
因为项目需求需要将数据导出存为PDF文档,方便客户使用。相比于TXT ,EXCEL等格式,导出PDF时可以减少字体乱码,文体格式不一样的痛点。在前面试用了Spire.PDF
和Aspose.Pdf
都可以导出我想要的格式的PDF,但这两个没有开源,正版都是要收费的,只好另寻他欢罢了。之后,寻寻觅觅,终于遇见PdfSharp
,相处一段时间后,那便是日久生情了,陷进去了,从此就是它啦。
关于 PdfSharp
PdfSharp是一个开源免费的.NET开发包,可以生成PDF格式的文档。对于第三个特点真的特好使,深有体会,后面会有一篇博文介绍的。
PdfSharp
组件主要特点有:
1.全部用C#重写设计和编写代码;
2.很容易使用对象模型来构建文档;
3. 可以生成PDF文件和显示在窗体或者打印,都使用同一个源文件;
4.可以修改、合并或者分割PDF文件;
5. 可以控制图片的透明度,嵌入字体。
下载 PdfSharp
通过VS自带的Nuget包管理器直接搜索PdfSharp
并下载。路径在工具-----Nuget包管理器-----管理解决方案的NuGet程序包…
使用PdfSharp
常用命名空间和类
命名空间
using PdfSharp;
using PdfSharp.Drawing;
using PdfSharp.Pdf;
常用类库
类库 | 描述 |
---|---|
PdfSharp.Pdf.PdfDocument | PDF文档 |
PdfSharp.Pdf.PdfPage | PDF 页面 |
PdfSharp.Drawing.XGraphics | 画布 |
PdfSharp.Drawing.XBrushes | 画刷 |
PdfSharp.Drawing.XPen | 画笔 |
PdfSharp.Drawing.XFont | 字体 |
PdfSharp.Drawing.XStringFormat | 字符串格式 |
PdfSharp.Drawing.XSize | 大小 |
1 创建一个简单的PDF文档
创建一个简单的HelloWorld.pdf文档。
/// <summary>
/// PdfSharp 创建一个简单的PDF
/// </summary>
public static void CreateSinglePdf()
{
// 创建一个PDF文档对象
PdfDocument document = new PdfDocument();
document.Info.Title = "Created with PDFsharp";
// 创建一个空的Page
PdfPage page = document.AddPage();
// 创建一个画布对象,用于绘制
XGraphics gfx = XGraphics.FromPdfPage(page);
// 创建字体
XFont font = new XFont("Verdana", 20, XFontStyle.BoldItalic);
// 绘制文本
gfx.DrawString("Hello, World!", font, XBrushes.Black,
new XRect(0, 0, page.Width, page.Height),
XStringFormats.Center);
// 保存文档
const string filename = "HelloWorld.pdf";
document.Save(filename);
}
2 创建一个带页脚的PDF文档
类似下图的模板:列数可以减少
分析需求:
1 有项目的头部介绍信息。
2 有页脚,页脚信息包括公司信息和页码。
3 表格内容有标题,换页到下页时标题也要有。
4 KK00 KK11 KK22等加粗有下划线,凸显出分类隔开的特点。
2.1 创建临时数据表
创建100*5的数据存放在DataTable中,仅用作测试。实际项目中,可以换成需要保存的数据内容。
/// <summary>
/// 数据表格
/// </summary>
/// <returns></returns>
private static 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;
}
2.2 创建页脚
一般包含公司信息和页码数。
/// <summary>
/// 绘制页脚
/// </summary>
/// <param name="page">页面</param>
/// <param name="gfx">画布</param>
/// <param name="cur">当前页序号</param>
/// <param name="total">总的页码数</param>
private static void DrawPDFFooter(PdfPage page, XGraphics gfx, int cur, int total)
{
//计算高度
float endY = (float)page.Height - padding_topBottom;
XFont Timefont = new XFont(fontName, 10, XFontStyle.Bold);
//测量字符串大小
XSize size = gfx.MeasureString("Drive Type/", Timefont);
//绘制页脚
gfx.DrawLine(new XPen(XColors.Black, 0.2f),
padding_leftRight,
endY,
page.Width - padding_leftRight,
endY);
endY += 2 + (float)size.Height;
//绘制信息
String footerText = "Test for Windows(C) by 唠嗑一夏 Electric Corporation";
gfx.DrawString(footerText, Timefont, XBrushes.Black, padding_leftRight,
endY);
Timefont = new XFont(fontName, 10, XFontStyle.Regular);
//绘制页码数
footerText = cur.ToString() + "/" + total.ToString();
gfx.DrawString(footerText, Timefont, XBrushes.Black,
(page.Width * 0.9), endY);
}
2.3 完整代码
在这里调用测试数据、页脚函数,项目头和数据内容整合在一起了。
主要使用到GDI的绘制,一直在使用XGraphics
的绘制文本DrawString
,绘制直线DrawLine
,绘制矩形框DrawRectangle
功能。涉及到页面高度,文本高度,文本宽度的计算,计算好了,绘制出来的效果才会好看,需要多尝试一下。
这里需要特别注意这个PdfSharp
控件支持的字体,并不是所有字体都支持,如果字体不存在则内容会显示乱码。
/// <summary>
/// 创建PDF
/// </summary>
public static void CreatePdfSharpPDF( )
{
try
{
//获取测试数据
DataTable dataTable = CreateData();
//创建文档对象
PdfDocument doc = new PdfDocument();
//创建空页
PdfPage page = doc.AddPage();
//设置纸张大小
page.Size = PageSize.A4;
List<XGraphics> gfxList = new List<XGraphics>();
//设置一个画布
XGraphics gfx = XGraphics.FromPdfPage(page);
gfxList.Add(gfx);
const string fontName = "华文宋体";
//设置字体
XFont Titlefont = new XFont(fontName, 14, XFontStyle.Bold);
XFont Timefont = new XFont(fontName, 12, XFontStyle.Regular);
//绘制标题
gfx.DrawString(" Parameter Settings Report(Program)", Titlefont, XBrushes.Black,
new XRect(padding_leftRight, 30, page.Width - padding_leftRight, 30),
XStringFormats.CenterLeft);
//日期
gfx.DrawString(DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss"), Timefont, XBrushes.Black,
new XRect(page.Width * 0.7, 30, page.Width * 0.3 - padding_leftRight, 30),
XStringFormats.BottomRight);
XPen linePen = new XPen(XColor.FromKnownColor(XKnownColor.Black), 0.1);
//绘制线
gfx.DrawLine(linePen,
new XPoint(padding_leftRight, 60), new XPoint(page.Width - padding_leftRight, 60));
//设置字体
Titlefont = new XFont(fontName, 12, XFontStyle.Bold);
Timefont = new XFont(fontName, 10, XFontStyle.Regular);
//测量字体的大小
XSize size = gfx.MeasureString("Program", Titlefont);
XSize size2 = gfx.MeasureString("Drive Type/", Timefont);
float y = 62;
float endY = (float)size.Height + 4 + (float)size2.Height;
//绘制矩形框和字符串
gfx.DrawRectangle(XBrushes.LightCyan, new XRect(padding_leftRight, y, page.Width - 2 * padding_leftRight, endY));
gfx.DrawString(" Program(Drive Selected / Connected)", Titlefont,
XBrushes.Black, padding_leftRight, y, XStringFormat.TopLeft);
y += 4 + (float)size.Height;
gfx.DrawString(" Drive Type/Model: ", Timefont,
XBrushes.Black, padding_leftRight, y, XStringFormat.TopLeft);
y += 4 + (float)size2.Height;
gfx.DrawLine(linePen,
new XPoint(padding_leftRight, y), new XPoint(page.Width - padding_leftRight, y));
y += 4;
gfx.DrawString(" Project: ", Titlefont,
XBrushes.Black, padding_leftRight, y, XStringFormat.TopLeft);
y += 4 + (float)size.Height;
gfx.DrawLine(linePen,
new XPoint(padding_leftRight, y), new XPoint(page.Width - padding_leftRight, y));
y += 4;
Titlefont = new XFont(fontName, 11, XFontStyle.Bold);
gfx.DrawString(" Information ", Titlefont,
XBrushes.Black, padding_leftRight, y, XStringFormat.TopLeft);
y += 100;
//项目的标题
y = DrawPDFCodeTitle(page, gfx, y) + 10;
//绘制功能码的字体
XFont funFont = new XFont(fontName, 9);
XFont FunBoldFont = new XFont(fontName, 9, XFontStyle.Underline | XFontStyle.Bold);
//字体的高度
XSize funcSize = gfx.MeasureString("KK00.00", funFont);
XSize funcBoldSize = gfx.MeasureString("KK00.00", FunBoldFont);
int count = dataTable.Rows.Count;
string str = "";
string strBak = "";
int j = 0;
for (int i = 0; i < count; i++)
{//遍历数据
if ((y + funcSize.Height + 3) > (page.Height - padding_topBottom))
{//换页
page = doc.Pages.Add();
page.Size = PageSize.A4;
gfx = XGraphics.FromPdfPage(page);
gfxList.Add(gfx);
//绘制内容表头
y = DrawPDFCodeTitle(page, gfx, 10) + 10;
}
DataRow dataRow = dataTable.Rows[i];
strBak = dataRow[0].ToString().Substring(0, 4);
if (strBak != str)
{//绘制分组
str = strBak;
string converStr = strBak ;
j++;
funcBoldSize = gfx.MeasureString(converStr, FunBoldFont);
y += (float)funcBoldSize.Height + 6;
gfx.DrawString(converStr, FunBoldFont, XBrushes.Black, padding_leftRight, y);
y += 2;
i--;
continue;
}
// else
{//绘制内容
string tempStr = dataRow[0].ToString() + " " + dataRow[1].ToString();
funcSize = gfx.MeasureString(tempStr, funFont);
y += (float)funcSize.Height + 3;
if ((y + funcSize.Height + 3) > (page.Height - padding_topBottom))
{//换页
page = doc.Pages.Add();
page.Size = PageSize.A4;
gfx = XGraphics.FromPdfPage(page);
gfxList.Add(gfx);
//绘制内容表头
y = DrawPDFCodeTitle(page, gfx, 10) + 10;
}
//序号+描述
float widthX = padding_leftRight;
gfx.DrawString(tempStr, funFont, XBrushes.Black, widthX, y);
//当前值
widthX += (float)(page.Width * 0.32);
gfx.DrawString(dataRow[2].ToString(), funFont, XBrushes.Black, widthX, y);
//设置值
widthX += (float)(page.Width * 0.31);
gfx.DrawString(dataRow[4].ToString(), funFont, XBrushes.Black, widthX, y);
}
}
gfx = null;
int Total = doc.PageCount;
for (int i = 0; i < Total; i++)
{//绘制页脚
DrawPDFFooter(page, gfxList[i], i + 1, Total);
}
string path = "PdfSharpDemo.pdf";
doc.Save(path);
}
catch (Exception ex)
{
}
}
效果图:也可以看文章最前面的动图
小结
PdfSharp创建PDF文档使用的是Drawing方式,用户可以通过绘制来实现自己各式各样的需求。
而且PdfSharp是免费开源的,这就秒杀了一大波其它付费的控件了。与Aspose.Pdf相比,PdfSharp生成PDF文件的速度快多了。
附录:
PdfSharp官网链接:http://www.pdfsharp.com/PDFsharp/
PdfSharp的使用Demo:http://www.pdfsharp.net/wiki/PDFsharpSamples.ashx?AspxAutoDetectCookieSupport=1