QuestPDF
QuestPDF是一個開源的工具庫,可以在.NET或者.Net Core中生成pdf文檔
它提供了一個布局引擎,設計時考慮到了完整的分頁支持以及靈活性要求!比市面上常見的Aspose和iTextSharp好用太多了!GitHub地址
安裝
Install-Package QuestPDF
例子
簡單例子
生成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");
模板生成
使用模板生成一共設計三個應用層的工作:
文檔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頁面總是有三個元素:頁眉,頁腳,內容。查看一下我們生成的文檔
到目前為止,我們已經搭建了一個非常簡單的頁面,其中每個部分都有不同的顏色或大小
接下來我們來填充他的頁眉,我們把數據源整理好了之后,就可以調用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");});});});}
最后我們來實現內容,
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);
當然還有很多好玩的功能,今天就給大家講個概念,讓大家對這個東西有個印象,后面我會繼續輸出該庫的相關功能。如果你們對該庫感興趣,可以持續關注我!微信公眾號【黑哥聊dotNet】