在.NET中使用QuestPDF高效地生成PDF文档
【摘要】 前言在.NET平台中操作生成PDF的类库有很多如常见的有iTextSharp、PDFsharp、Aspose.PDF等,今天我们分享一个用于生成PDF文档的现代开源.NET库:QuestPDF,本文将介绍QuestPDF并使用它快速实现发票PDF文档生成功能。QuestPDF介绍QuestPDF 是一个用于生成 PDF 文档的现代开源 .NET 库。QuestPDF 由简洁易用的 C# Fl...
前言
在.NET平台中操作生成PDF的类库有很多如常见的有iTextSharp、PDFsharp、Aspose.PDF等,今天我们分享一个用于生成PDF文档的现代开源.NET库:QuestPDF,本文将介绍QuestPDF并使用它快速实现发票PDF文档生成功能。
QuestPDF介绍
QuestPDF 是一个用于生成 PDF 文档的现代开源 .NET 库。QuestPDF 由简洁易用的 C# Fluent API 提供全面的布局引擎。轻松生成 PDF 报告、发票、导出等。QuestPDF它提供了一个布局引擎,在设计时考虑了完整的分页支持。与其他库不同,它不依赖于 HTML 到 PDF 的转换,这在许多情况下是不可靠的。相反,它实现了自己的布局引擎,该引擎经过优化,可以满足所有与分页相关的要求。
QuestPDF License
分为社区版、专业版、和企业版。
创建一个控制台应用
创建一个名为QuestPDFExercise
的控制台应用。
安装QuestPDF Nuget包
搜索:QuestPDF
包进行安装。
快速实现发票PDF文档生成
创建InvoiceModel
namespace QuestPDFExercise
{
public class InvoiceModel
{
/// <summary>
/// 发票号码
/// </summary>
public int InvoiceNumber { get; set; }
/// <summary>
/// 发票开具日期
/// </summary>
public DateTime IssueDate { get; set; }
/// <summary>
/// 发票到期日期
/// </summary>
public DateTime DueDate { get; set; }
/// <summary>
/// 卖方公司名称
/// </summary>
public string SellerCompanyName { get; set; }
/// <summary>
/// 买方公司名称
/// </summary>
public string CustomerCompanyName { get; set; }
/// <summary>
/// 订单消费列表
/// </summary>
public List<OrderItem> OrderItems { get; set; }
/// <summary>
/// 备注
/// </summary>
public string Comments { get; set; }
}
public class OrderItem
{
/// <summary>
/// 消费类型
/// </summary>
public string Name { get; set; }
/// <summary>
/// 消费金额
/// </summary>
public decimal Price { get; set; }
/// <summary>
/// 消费数量
/// </summary>
public int Quantity { get; set; }
}
}
CreateInvoiceDetails
namespace QuestPDFExercise
{
public class CreateInvoiceDetails
{
private static readonly Random _random = new Random();
public enum InvoiceType
{
餐饮费,
交通费,
住宿费,
日用品,
娱乐费,
医疗费,
通讯费,
教育费,
装修费,
旅游费
}
/// <summary>
/// 获取发票详情数据
/// </summary>
/// <returns></returns>
public static InvoiceModel GetInvoiceDetails()
{
return new InvoiceModel
{
InvoiceNumber = _random.Next(1_000, 10_000),
IssueDate = DateTime.Now,
DueDate = DateTime.Now + TimeSpan.FromDays(14),
SellerCompanyName = "追逐时光者",
CustomerCompanyName = "DotNetGuide技术社区",
OrderItems = Enumerable
.Range(1, 20)
.Select(_ => GenerateRandomOrderItemInfo())
.ToList(),
Comments = "DotNetGuide技术社区是一个面向.NET开发者的开源技术社区,旨在为开发者们提供全面的C#/.NET/.NET Core相关学习资料、技术分享和咨询、项目推荐、招聘资讯和解决问题的平台。在这个社区中,开发者们可以分享自己的技术文章、项目经验、遇到的疑难技术问题以及解决方案,并且还有机会结识志同道合的开发者。我们致力于构建一个积极向上、和谐友善的.NET技术交流平台,为广大.NET开发者带来更多的价值和成长机会。"
};
}
/// <summary>
/// 订单信息生成
/// </summary>
/// <returns></returns>
private static OrderItem GenerateRandomOrderItemInfo()
{
var types = (InvoiceType[])Enum.GetValues(typeof(InvoiceType));
return new OrderItem
{
Name = types[_random.Next(types.Length)].ToString(),
Price = (decimal)Math.Round(_random.NextDouble() * 100, 2),
Quantity = _random.Next(1, 10)
};
}
}
}
CreateInvoiceDocument
using QuestPDF.Fluent;
using QuestPDF.Helpers;
using QuestPDF.Infrastructure;
namespace QuestPDFExercise
{
public class CreateInvoiceDocument : IDocument
{
/// <summary>
/// 获取Logo的的Image对象
/// </summary>
public static Image LogoImage { get; } = Image.FromFile("dotnetguide.png");
public InvoiceModel Model { get; }
public CreateInvoiceDocument(InvoiceModel model)
{
Model = model;
}
public DocumentMetadata GetMetadata() => DocumentMetadata.Default;
public void Compose(IDocumentContainer container)
{
container
.Page(page =>
{
//设置页面的边距
page.Margin(50);
//字体默认大小18号字体
page.DefaultTextStyle(x => x.FontSize(18));
//页眉部分
page.Header().Element(BuildHeaderInfo);
//内容部分
page.Content().Element(BuildContentInfo);
//页脚部分
page.Footer().AlignCenter().Text(text =>
{
text.CurrentPageNumber();
text.Span(" / ");
text.TotalPages();
});
});
}
#region 构建页眉部分
void BuildHeaderInfo(IContainer container)
{
container.Row(row =>
{
row.RelativeItem().Column(column =>
{
column.Item().Text($"发票编号 #{Model.InvoiceNumber}").FontFamily("fangsong").FontSize(20).SemiBold().FontColor(Colors.Blue.Medium);
column.Item().Text(text =>
{
text.Span("发行日期: ").FontFamily("fangsong").FontSize(13).SemiBold();
text.Span($"{Model.IssueDate:d}");
});
column.Item().Text(text =>
{
text.Span("终止日期: ").FontFamily("fangsong").FontSize(13).SemiBold();
text.Span($"{Model.DueDate:d}");
});
});
//在当前行的常量项中插入一个图像
row.ConstantItem(130).Image(LogoImage);
});
}
#endregion
#region 构建内容部分
void BuildContentInfo(IContainer container)
{
container.PaddingVertical(40).Column(column =>
{
column.Spacing(20);
column.Item().Row(row =>
{
row.RelativeItem().Component(new AddressComponent("卖方公司名称", Model.SellerCompanyName));
row.ConstantItem(50);
row.RelativeItem().Component(new AddressComponent("客户公司名称", Model.CustomerCompanyName));
});
column.Item().Element(CreateTable);
var totalPrice = Model.OrderItems.Sum(x => x.Price * x.Quantity);
column.Item().PaddingRight(5).AlignRight().Text($"总计: {totalPrice}").FontFamily("fangsong").SemiBold();
if (!string.IsNullOrWhiteSpace(Model.Comments))
column.Item().PaddingTop(25).Element(BuildComments);
});
}
/// <summary>
/// 创建表格
/// </summary>
/// <param name="container">container</param>
void CreateTable(IContainer container)
{
var headerStyle = TextStyle.Default.SemiBold();
container.Table(table =>
{
table.ColumnsDefinition(columns =>
{
columns.ConstantColumn(25);
columns.RelativeColumn(3);
columns.RelativeColumn();
columns.RelativeColumn();
columns.RelativeColumn();
});
table.Header(header =>
{
header.Cell().Text("#").FontFamily("fangsong");
header.Cell().Text("消费类型").Style(headerStyle).FontFamily("fangsong");
header.Cell().AlignRight().Text("花费金额").Style(headerStyle).FontFamily("fangsong");
header.Cell().AlignRight().Text("数量").Style(headerStyle).FontFamily("fangsong");
header.Cell().AlignRight().Text("总金额").Style(headerStyle).FontFamily("fangsong");
//设置了表头单元格的属性
header.Cell().ColumnSpan(5).PaddingTop(5).BorderBottom(1).BorderColor(Colors.Black);
});
foreach (var item in Model.OrderItems)
{
var index = Model.OrderItems.IndexOf(item) + 1;
table.Cell().Element(CellStyle).Text($"{index}").FontFamily("fangsong");
table.Cell().Element(CellStyle).Text(item.Name).FontFamily("fangsong");
table.Cell().Element(CellStyle).AlignRight().Text($"{item.Price}").FontFamily("fangsong");
table.Cell().Element(CellStyle).AlignRight().Text($"{item.Quantity}").FontFamily("fangsong");
table.Cell().Element(CellStyle).AlignRight().Text($"{item.Price * item.Quantity}").FontFamily("fangsong");
static IContainer CellStyle(IContainer container) => container.BorderBottom(1).BorderColor(Colors.Grey.Lighten2).PaddingVertical(5);
}
});
}
#endregion
#region 构建页脚部分
void BuildComments(IContainer container)
{
container.ShowEntire().Background(Colors.Grey.Lighten3).Padding(10).Column(column =>
{
column.Spacing(5);
column.Item().Text("DotNetGuide技术社区介绍").FontSize(14).FontFamily("fangsong").SemiBold();
column.Item().Text(Model.Comments).FontFamily("fangsong");
});
}
#endregion
}
public class AddressComponent : IComponent
{
private string Title { get; }
private string CompanyName { get; }
public AddressComponent(string title, string companyName)
{
Title = title;
CompanyName = companyName;
}
public void Compose(IContainer container)
{
container.ShowEntire().Column(column =>
{
column.Spacing(2);
column.Item().Text(Title).FontFamily("fangsong").SemiBold();
column.Item().PaddingBottom(5).LineHorizontal(1);
column.Item().Text(CompanyName).FontFamily("fangsong");
});
}
}
}
Program
using QuestPDF.Infrastructure;
using QuestPDF;
using QuestPDF.Fluent;
namespace QuestPDFExercise
{
internal class Program
{
static void Main(string[] args)
{
//1、请确保您有资格使用社区许可证,不设置的话会报异常。
Settings.License = LicenseType.Community;
//2、禁用QuestPDF库中文本字符可用性的检查
Settings.CheckIfAllTextGlyphsAreAvailable = false;
//3、PDF Document 创建
var invoiceSourceData = CreateInvoiceDetails.GetInvoiceDetails();
var document = new CreateInvoiceDocument(invoiceSourceData);
//4、生成 PDF 文件并在默认的查看器中显示
document.GeneratePdfAndShow();
}
}
}
完整示例源代码
示例运行效果图
【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱:
cloudbbs@huaweicloud.com
- 点赞
- 收藏
- 关注作者
评论(0)