用 QuestPDF操作生成PDF更快更高效!

1514366c1497e80fa6b677dc8c441a07.png

QuestPDF

QuestPDF是一个开源的工具库,可以在.NET或者.Net Core中生成pdf文档

它提供了一个布局引擎,设计时考虑到了完整的分页支持以及灵活性要求!比市面上常见的Aspose和iTextSharp好用太多了!GitHub地址

安装

Install-Package QuestPDF

657b899653e7ae63c49c7ad0a9da78be.png

例子

  • 简单例子

生成Pdf文档一共分为三部分,Header(页眉),Content(内容),Footer(页脚)

Document.Create(container =>
{container.Page(page =>{page.Size(PageSizes.A4);page.Margin(2, Unit.Centimetre);page.Background(Colors.White);page.DefaultTextStyle(x => x.FontSize(20));page.Header().Text("Hello PDF!").SemiBold().FontSize(36).FontColor(Colors.Blue.Medium);page.Content().PaddingVertical(1, Unit.Centimetre).Column(x =>{x.Spacing(20);x.Item().Text(Placeholders.LoremIpsum());x.Item().Image(Placeholders.Image(200, 100));});page.Footer().AlignCenter().Text(x =>{x.Span("Page ");x.CurrentPageNumber();});});
})
.GeneratePdf("hello.pdf");

29d87342efbb5f91f6675212ce6bda29.png

  • 模板生成

使用模板生成一共设计三个应用层的工作:

  • 文档Model(一组描述 PDF 文档内容的类)

  • 数据源(将域实体映射到文档模型的层)

  • 模板(描述如何可视化信息并将其转换为 PDF 文件的表示层)

比如我们设计一个基本的发票信息 要设计一个购物清单,一个卖家买家的地址,以及发票编号等等 我们设计这样的3个Model类

public class InvoiceModel{public int InvoiceNumber { get; set; }public DateTime IssueDate { get; set; }public DateTime DueDate { get; set; }public Address SellerAddress { get; set; }public Address CustomerAddress { get; set; }public List<OrderItem> Items { get; set; }public string Comments { get; set; }}public class OrderItem{public string Name { get; set; }public decimal Price { get; set; }public int Quantity { get; set; }}public class Address{public string CompanyName { get; set; }public string Street { get; set; }public string City { get; set; }public string State { get; set; }public object Email { get; set; }public string Phone { get; set; }}

Model定义好了之后我们就定义一些假数据来填充pdf

public static class InvoiceDocumentDataSource{private static Random Random = new Random();public static InvoiceModel GetInvoiceDetails(){var items = Enumerable.Range(1, 8).Select(i => GenerateRandomOrderItem()).ToList();return new InvoiceModel{InvoiceNumber = Random.Next(1_000, 10_000),IssueDate = DateTime.Now,DueDate = DateTime.Now + TimeSpan.FromDays(14),SellerAddress = GenerateRandomAddress(),CustomerAddress = GenerateRandomAddress(),Items = items,Comments ="测试备注"};}private static OrderItem GenerateRandomOrderItem(){return new OrderItem{Name = "商品",Price = (decimal)Math.Round(Random.NextDouble() * 100, 2),Quantity = Random.Next(1, 10)};}private static Address GenerateRandomAddress(){return new Address{CompanyName = "测试商店",Street = "测试街道",City = "测试城市",State = "测试状态",Email = "测试邮件",Phone = "测试电话"};}}

然后搭建我们的模板脚手架 我们要使用模板脚手架,就要定义一个实现IDocument接口的新类开始。该接口包含两个方法

  • DocumentMetadata GetMetadata();

  • void Compose(IDocumentContainer container);

第一个是模板文档的一些基础信息 第二个是模板的容器 基于这些原则我们设计一个模板层类

public class InvoiceDocument : IDocument{public InvoiceModel Model { get; }public InvoiceDocument(InvoiceModel model){Model = model;}public DocumentMetadata GetMetadata() => DocumentMetadata.Default;public void Compose(IDocumentContainer container){container.Page(page =>{page.PageColor(Colors.Red.Lighten1);page.Size(PageSizes.A4);page.Margin(10);//外边距page.Header().Height(100).Background(Colors.LightBlue.Lighten1);page.Content().Background(Colors.Grey.Lighten3);page.Footer().Height(50).Background(Colors.Grey.Lighten1);});}
}

pdf的page页面总是有三个元素:页眉,页脚,内容。查看一下我们生成的文档

4a5724285c86a700be17fe8d39e003d8.png

到目前为止,我们已经搭建了一个非常简单的页面,其中每个部分都有不同的颜色或大小

接下来我们来填充他的页眉,我们把数据源整理好了之后,就可以调用Element方法填充

public void Compose(IDocumentContainer container){container.Page(page =>{page.PageColor(Colors.Red.Lighten1);page.Size(PageSizes.A4);page.Margin(10);//外边距page.Header().Height(100).Background(Colors.LightBlue.Lighten1).Element(ComposeHeader);page.Content().Background(Colors.Grey.Lighten3);page.Footer().Height(50).Background(Colors.Grey.Lighten1);});}void ComposeHeader(IContainer container){var titleStyle = TextStyle.Default.FontSize(20).SemiBold().FontColor(Colors.Blue.Medium);container.Row(row =>{row.RelativeItem().Column(column =>{column.Item().Text($"发票 #{Model.InvoiceNumber}").FontFamily("simhei").Style(titleStyle);column.Item().Text(text =>{text.Span("发行日期: ").SemiBold().FontFamily("simhei");text.Span($"{Model.IssueDate:d}").FontFamily("simhei");});column.Item().Text(text =>{text.Span("支付日期: ").FontFamily("simhei").SemiBold();text.Span($"{Model.DueDate:d}").FontFamily("simhei");});});});}

1c2f13b2514bb7720ddab5585505e0d6.png

最后我们来实现内容,

public void Compose(IDocumentContainer container){container.Page(page =>{page.PageColor(Colors.Red.Lighten1);page.Size(PageSizes.A4);page.Margin(10);//外边距page.Header().Height(100).Background(Colors.LightBlue.Lighten1).Element(ComposeHeader);page.Content().Background(Colors.Grey.Lighten3).Element(ComposeContent);page.Footer().Height(50).Background(Colors.Grey.Lighten1);});}void ComposeHeader(IContainer container){var titleStyle = TextStyle.Default.FontSize(20).SemiBold().FontColor(Colors.Blue.Medium);container.Row(row =>{row.RelativeItem().Column(column =>{column.Item().Text($"发票 #{Model.InvoiceNumber}").FontFamily("simhei").Style(titleStyle);column.Item().Text(text =>{text.Span("发行日期: ").SemiBold().FontFamily("simhei");text.Span($"{Model.IssueDate:d}").FontFamily("simhei");});column.Item().Text(text =>{text.Span("支付日期: ").FontFamily("simhei").SemiBold();text.Span($"{Model.DueDate:d}").FontFamily("simhei");});});});}void ComposeContent(IContainer container){container.Table(table =>{// step 1table.ColumnsDefinition(columns =>{columns.ConstantColumn(25);columns.RelativeColumn(3);columns.RelativeColumn();columns.RelativeColumn();columns.RelativeColumn();});// step 2table.Header(header =>{header.Cell().Text("#").FontFamily("simhei");header.Cell().Text("商品").FontFamily("simhei");header.Cell().AlignRight().Text("价格").FontFamily("simhei");header.Cell().AlignRight().Text("数量").FontFamily("simhei");header.Cell().AlignRight().Text("总价").FontFamily("simhei");header.Cell().ColumnSpan(5).PaddingVertical(5).BorderBottom(1).BorderColor(Colors.Black);});// step 3foreach (var item in Model.Items){table.Cell().Element(CellStyle).Text(Model.Items.IndexOf(item) + 1).FontFamily("simhei");table.Cell().Element(CellStyle).Text(item.Name).FontFamily("simhei");table.Cell().Element(CellStyle).AlignRight().Text($"{item.Price}$").FontFamily("simhei");table.Cell().Element(CellStyle).AlignRight().Text(item.Quantity).FontFamily("simhei");table.Cell().Element(CellStyle).AlignRight().Text($"{item.Price * item.Quantity}$").FontFamily("simhei");static IContainer CellStyle(IContainer container){return container.BorderBottom(1).BorderColor(Colors.Grey.Lighten2).PaddingVertical(5);}}});}

在这些准备工作做完了之后我们就可以生成Pdf文档了

var filePath = "invoice.pdf";var model = InvoiceDocumentDataSource.GetInvoiceDetails();var document = new InvoiceDocument(model);document.GeneratePdf(filePath);

326542a9d0362c2e7fe881830cebd4fc.png

当然还有很多好玩的功能,今天就给大家讲个概念,让大家对这个东西有个印象,后面我会继续输出该库的相关功能。如果你们对该库感兴趣,可以持续关注我!微信公众号【黑哥聊dotNet】

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/284410.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ASP.NET vs MVC vs WebForms

许多ASP.NET开发人员开始接触MVC认为MVC与ASP.NET完全没有关系&#xff0c;是一个全新的Web开发&#xff0c;事实上ASP.NET是创建WEB应用的框架而MVC是能够用更好的方法来组织并管理代码的一种更高级架构体系&#xff0c;所以可以称之为ASP.NET MVC。 我们可将原来的ASP.NET称为…

产品经理有哪些类型?

不知道大家是如何给产品经理这个职业进行分类&#xff0c; 按负责的产品&#xff1f;按等级&#xff1f;按工作年限&#xff1f;按工作方向等&#xff1f; 一、按工作内容分 1. 功能设计产品经理 最常见的了&#xff0c;负责的工作就是设计出功能来。从 APP 的界面&#xff0…

在Blazor 中自定义权限验证

Blazor是什么Blazor 是微软在 .NET 里推出的一个 WEB 客户端 UI 交互的框架&#xff0c;使用 Blazor 你可以代替 JavaScript 来实现自己的页面交互逻辑&#xff0c;可以很大程度上进行 C# 代码的复用&#xff0c;Blazor 对于 .NET 开发人员来说是一个不错的选择。需求背景其实我…

看出每个应用程序最高可用内存是多少

int maxMemory (int) (Runtime.getRuntime().maxMemory() / 1024); Log.d("TAG", "Max memory is " maxMemory "KB"); 转载于:https://www.cnblogs.com/coderwjq/p/6501639.html

中文分词之HMM模型详解

文章转载自: http://yanyiwu.com/work/2014/04/07/hmm-segment-xiangjie.html HMM(Hidden Markov Model): 隐式马尔科夫模型。 HMM模型可以应用在很多领域&#xff0c;所以它的模型参数描述一般都比较抽象&#xff0c;以下篇幅针对HMM的模型参数介绍直接使用它在中文分词中的实…

【ArcGIS微课1000例】0035:地图面状符号设计教程

地图符号是表示地图内容的基本手段,它由形状不同、大小不一、色彩有别的图形和文字组成。 地图符号是地图的语言,是一种图形语言。它与文字语言相比较,最大的特点是形象直观,一目了然。 本文讲解ArcGIS中面状符号设计方法。 文章目录 一、新建符号样式二、面状符号设计1. 斜…

MySQL夺命15问,你能坚持到第几问?

前言 MySQL在面试中经常被问到&#xff0c;本文总结了面试中的经典问题。 1. 数据库三大范式是什么&#xff1f; 第一范式&#xff1a;每个列都不可以再拆分。 第二范式&#xff1a;在第一范式的基础上&#xff0c;非主键列完全依赖于主键&#xff0c;而不能是依赖于主键的一部…

ios元素定位

原文地址http://www.cnblogs.com/meitian/p/7373460.html 第一种&#xff1a;通过Appium1.6的Inspector来查看 具体安装方式前面的随笔已经介绍了&#xff1a;http://www.cnblogs.com/meitian/p/7360017.html可以通过定位找到元素xpath或name个人不推荐用这个方法&#xff0c;实…

分治法——循环赛日程表

1、问题描述&#xff1a;有n2^k个远动员选手&#xff0c;设计比赛日程表实现&#xff1a;&#xff08;1&#xff09;每个选手必须与n-1个选手比赛&#xff08;2&#xff09;每个选手一天只比赛一场&#xff08;3&#xff09;比赛共进行n-1天输入&#xff1a;n人输出&#xff1a…

使用 LSM-Tree 思想基于.NET 6.0 C# 写个 KV 数据库(案例版)

文章有点长&#xff0c;耐心看完应该可以懂实际原理到底是啥子。这是一个KV数据库的C#实现&#xff0c;目前用.NET 6.0实现的&#xff0c;目前算是属于雏形&#xff0c;骨架都已经完备&#xff0c;毕竟刚完工不到一星期。当然&#xff0c;这个其实也算是NoSQL的雏形&#xff0c…

35.使用拦截器实现权限验证

转自&#xff1a;https://wenku.baidu.com/view/84fa86ae360cba1aa911da02.html 为了说明此问题&#xff0c;我们建立struts2auth项目&#xff0c;流程图如下&#xff1a; 简短说明&#xff1a;当我们访问main.jsp页面&#xff0c;并试图通过此页面中的链接地址&#xff1a;not…

如何保证缓存和数据库的一致性?

1. 问题分析 2. Cache-Aside 2.1 读缓存 2.2 写缓存 2.3 延迟双删 2.4 如何确保原子性 3. Read-Through/Write-Through 3.1 Read-Through 3.2 Write-Through 4. Write Behind 很多小伙伴在面试的时候&#xff0c;应该都遇到过类似的问题&#xff0c;如何确保缓存和数据库…

Pressed状态和clickable,duplicateParentState的关系

做Android开发的人都用过Selector,可以方便的实现View在不同状态下的背景。不过&#xff0c;相信大部分开发者遇到过和我一样的问题&#xff0c;本文会从源码角度&#xff0c;解释这些问题。 首先&#xff0c;这里简单描述一下&#xff0c;我遇到的问题&#xff1a; 界面上有个…

Hbase笔记4 java操作Hbase

暂无转载于:https://www.cnblogs.com/mrxiaohe/p/6512481.html

【招聘(南京)】 慧咨环球南京研发中心 .NET和Blazor 前端

主要的亮点快速增长的、产品导向型的全球性科技公司设计和开发市场领先的软件解决方案WLB — 工作生活相平衡澳洲排名前五的软件公司混合办公 — 3天在家办公&#xff0c;2天在办公室办公在C#和.NET开发&#xff0c;企业级系统研发&#xff0c;软件工程方面有长期的优秀实践和技…

用Python+Django在Eclipse环境下开发web网站【转】

一、创建一个项目如果这是你第一次使用Django&#xff0c;那么你必须进行一些初始设置。也就是通过自动生成代码来建立一个Django项目--一个Django项目的设置集&#xff0c;包含了数据库配置、Django详细选项设置和应用 特性配置&#xff0c;具体操作步骤如下所示。 1.新建Djan…

[转]数据结构KMP算法配图详解(超详细)

KMP算法配图详解 前言 KMP算法是我们数据结构串中最难也是最重要的算法。难是因为KMP算法的代码很优美简洁干练&#xff0c;但里面包含着非常深的思维。真正理解代码的人可以说对KMP算法的了解已经相当深入了。而且这个算法的不少东西的确不容易讲懂&#xff0c;很多正规的书本…

BGP-MED-2

BGP-MED-2如图&#xff1a;当AS100去往AS300的60、10的网络时&#xff0c;60走R3&#xff0c;10走R1!使用MED属性影响选路&#xff01; R2的配置 bgp 200peer 1.1.1.1 as-number 100 peer 1.1.1.1 ebgp-max-hop 255 peer 1.1.1.1 connect-interface LoopBack0peer 4.4.4.4 as-n…

WPF 实现 Gitee 气泡菜单(一)

WPF 实现 Gitee 气泡菜单&#xff08;一&#xff09;气泡菜单&#xff08;一&#xff09;作者&#xff1a;WPFDevelopersOrg原文链接&#xff1a; https://github.com/WPFDevelopersOrg/WPFDevelopers框架使用大于等于.NET40&#xff1b;Visual Studio 2022;项目使用 MIT 开…

[转]LVS负载均衡(LVS简介、三种工作模式、十种调度算法)

一、LVS简介 LVS&#xff08;Linux Virtual Server&#xff09;即Linux虚拟服务器&#xff0c;是由章文嵩博士主导的开源负载均衡项目&#xff0c;目前LVS已经被集成到Linux内核模块中。该项目在Linux内核中实现了基于IP的数据请求负载均衡调度方案&#xff0c;其体系结构如图1…