C#/. Net Stop using Aspose and iTextSharp! QuestPDF operation generates PDFs faster and more efficiently!

C#/. Net Stop using Aspose and iTextSharp! QuestPDF operation generates PDFs faster and more efficiently!

It provides a layout engine designed with full paging support and flexibility requirements in mind! It's much easier to use than the common Aspose and iTextSharp on the market!

最后更新 4/23/2022 1:55 PM
黑哥聊dotNet
预计阅读 8 分钟
分类
.NET
标签
.NET C# PDF generate PDF Aspose

1. About QuestPDF

QuestPDF is an open source tool library that can generate pdf documents in. NET or. NET Core

It provides a layout engine designed with full paging support and flexibility requirements in mind! It's much easier to use than the common Aspose and iTextSharp on the market!

2. installation

Install-Package QuestPDF

3. example

3.1 simple example

The generated Pdf document is divided into three parts: Header, Content, and Footer. The following is the example code:

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");

PDF results generated by the above code:

3.2 template generation

Use templates to generate work to design a total of three application layers:

  1. Document Model (a set of classes that describe the content of a PDF document)
  2. Data sources (maps domain entities to layers of the document model)
  3. Template (a presentation layer that describes how to visualize information and convert it into a PDF file)

For example, when we design basic invoice information, we need to design a shopping list, the address of a seller and buyer, and the invoice number, etc. We design three Model classes like this:

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; }
}

After the Model is defined, we will define some fake data to populate the 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 = "测试电话"
        };
    }
}

Then we build our template scaffold. If we want to use template scaffold, we need to define a new class that implements the IDdocument interface.

This interface contains two methods:

  1. DocumentMetadata GetMetadata();
  2. void Compose(IDocumentContainer container);

The first is some basic information about the template document, and the second is the container of the template. Based on these principles, we designed a template layer class:

 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);
            });
    }
}

A pdf page always has three elements: header, footer, and content. Check out the documentation we generated:

So far, we have built a very simple page, with each section having a different color or size.

Next we will fill in his header. After we have sorted out the data source, we can call the Element method to fill it in:

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");
            });

        })
        ;

    });
}

Finally, let's implement the content:

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 1
        table.ColumnsDefinition(columns =>
        {
            columns.ConstantColumn(25);
            columns.RelativeColumn(3);
            columns.RelativeColumn();
            columns.RelativeColumn();
            columns.RelativeColumn();
        });

        // step 2
        table.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 3
        foreach (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);
            }
        }
    });

}

After these preparations are completed, we can generate the Pdf document:

var filePath = "invoice.pdf";

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

4. summary

Of course, there are many interesting functions. Today, I will give you a concept to give you an impression of this thing. I will continue to output the relevant functions of this library later. If you are interested in this library, you can continue to pay attention to me! Weixin Official Accounts [Black Brother Chat dotNet]

Keep Exploring

延伸阅读

更多文章
同分类 / 同标签 4/22/2026

Support for. NET by operating system versions (250707 update)

Use virtual machines and test machines to test the support of each version of the operating system for. NET. After installing the operating system, it is passed by measuring the corresponding running time of the installation and being able to run the Stardust Agent.

继续阅读