文章目录
- 前言
- 了解 Spire
- 使用Spire.PDF
- 1 创建简单的PDF文档
- 2 创建带有格式的PDF文档(使用Draw)
- 头部信息
- 页眉
- 页脚
- 测试数据
- 完整的代码
- 3 创建带有格式的PDF文档(使用Gird)
- 小结
先上一个效果图
前言
项目中需要将一些数据转存为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\r\n 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
函数类,可以自由自定义绘制格式,就是需要计算高度和宽度,相对复杂一点。