DEV Community

Apitron
Apitron

Posted on

Generating PDF file (invoice) using C#

In the my first post, I want to share some of my experience generating PDF documents using Apitron.PDF.Kit for .NET and introduce basic PDF creation techniques. As an example, I chose a frequently used document - an invoice.

Invoice

The code

I won’t dive into platform specifics here and focus only on PDF generation and related code.

A few functions responsible for PDF generation are listed below:

private void GenerateInvoice(Stream stream)
string imagesPath = @"..\..\images";
FlowDocument document = new FlowDocument();

document.StyleManager.RegisterStyle("gridrow.tableHeader",new Style() {Background = RgbColors.LightSlateGray});
document.StyleManager.RegisterStyle("gridrow.centerAlignedCells > *,gridrow > *.centerAlignedCell",new Style() {Align = Align.Center, Margin = new Thickness(0)});
document.StyleManager.RegisterStyle("gridrow > *.leftAlignedCell",new Style() {Align = Align.Left, Margin = new Thickness(5, 0, 0, 0)});
document.StyleManager.RegisterStyle("gridrow > *",new Style() {Align = Align.Right, Margin = new Thickness(0, 0, 5, 0)});

ResourceManager resourceManager = new ResourceManager();
resourceManager.RegisterResource(
    new Apitron.PDF.Kit.FixedLayout.Resources.XObjects.Image("logo",
    Path.Combine(imagesPath, "storeLogo.png"), true) {Interpolate = true});

resourceManager.RegisterResource(new Apitron.PDF.Kit.FixedLayout.Resources.XObjects.Image("stamp",Path.Combine(imagesPath, "stamp.png"), true) {Interpolate = true});
document.PageHeader.Margin = new Thickness(0, 40, 0, 20);
document.PageHeader.Padding = new Thickness(10, 0, 10, 0);
document.PageHeader.Height = 120;
document.PageHeader.Background = RgbColors.LightGray;
document.PageHeader.LineHeight = 60;
document.PageHeader.Add(new Image("logo"){Height = 50, Width = 50, VerticalAlign = VerticalAlign.Middle});
document.PageHeader.Add(new TextBlock("Invoice")
                        {
                            Display = Display.InlineBlock,
                            Align = Align.Right,
                            Font = new Font(StandardFonts.CourierBold, 20),
                            Color = RgbColors.Black
                        });
Section pageSection = new Section() {Padding = new Thickness(20)};
pageSection.AddItems(CreateInfoSubsections(new string[] {txtCompany.Text,"Bill to:\r\n" + txtCustomerInfo.Text}));

pageSection.Add(new Hr() {Padding = new Thickness(0, 20, 0, 20)});
pageSection.Add(CreateProductsGrid());
pageSection.Add(new Br {Height = 20});
pageSection.Add(new Section() {Width = 250, Display = Display.InlineBlock});
pageSection.Add(new Image("stamp"));

document.Add(pageSection);
document.Write(stream, resourceManager, new PageBoundary(Boundaries.A4));
private Grid CreateProductsGrid()
Grid productsGrid = new Grid(20, Length.Auto, 30, 50, 55, 60);
productsGrid.Add(new GridRow(new TextBlock("#"), new TextBlock("Product"), new TextBlock("Qty."), new TextBlock("Price"), new TextBlock("Disc.(%)"), new TextBlock("Total")) Class = "tableHeader centerAlignedCells"});Decimal invoiceTotal = 0;


foreach (ProductEntry product in products)
{
    TextBlock pos = new TextBlock(product.Pos.ToString()) {Class = "centerAlignedCell"};
    TextBlock description = new TextBlock(product.Description) {Class = "leftAlignedCell"};
    TextBlock qty = new TextBlock(product.Qty.ToString()) {Class = "centerAlignedCell"};
    TextBlock price = new TextBlock( product.Price.ToString(CultureInfo.InvariantCulture));
    TextBlock discount = new TextBlock(product.Discount.ToString(CultureInfo.InvariantCulture));
    TextBlock total = new TextBlock(product.Total.ToString(CultureInfo.InvariantCulture));
    productsGrid.Add(new GridRow(pos, description, qty, price, discount, total));
    invoiceTotal += product.Total;
}

productsGrid.Add(new GridRow(new TextBlock("Total(USD)") {ColSpan = 4}, new TextBlock(invoiceTotal.ToString(CultureInfo.InvariantCulture)) {ColSpan = 2}));

return productsGrid;

Top comments (6)

Collapse
 
fservais911 profile image
fservais911

am interested in achieving the same, but with invoices that can span over multiple pages. The difficulty is the we need a page footer (printing the running total), a page header (for pages > 1) were that running total is brought forward), etc.
Can anybody help (against payment of course) ?
contact frank.servais@git.ch

Collapse
 
prettymonstress profile image
prettymonstress • Edited

Hi, @fservais911
pdfflow.io allows you to add automatic repeating areas (repeating header, repeating footer, repeating left area, repeating right area, and area by coordinates) to:

  • only odd pages of the section;
  • only oven pages of the section;
  • both odd and even pages.

All you need is to call AddFooterToBothPages() method and then add there a paragraph with your total amount, and it will be printed at every page of the section containing your table:

public static const string totalAmount = "679.35";
DocumentBuilder.New()
    .AddSection()
        .AddTable()
            .SetDataSource(InvoiceData);
    .ToSection()
        .AddFooterToBothPages(height: 80)
            .AddLine()
                .SetWidth(3)
        .ToArea()
            .AddParagraph ("Total: " + totalAmount)
                .SetHorizontalAlignment(HorizontalAlignment.Right);
                .SetFontColor(Color.Gray)
                .SetFontSize(8)
.ToDocument()
    .Build("Invoice.pdf");
Enter fullscreen mode Exit fullscreen mode
Collapse
 
arkadiybirger profile image
arkadiy-birger

@fservais911 I will send you an email with a suggestion on how to achieve this. Please monitor your inbox and reach out to me if somehow it gets lost. I think it is relatively easily achieved with the PDFFlow Library, please also see the extensive samples published github.com/gehtsoft-usa/PDF.Flow.E....

Collapse
 
fservais911 profile image
fservais911

Thank you, I appreciate examples, but really am pressed by tine to find a solution. I really need an example that meets our requirements.

Thread Thread
 
arkadiybirger profile image
arkadiy-birger

Do you mind posting the more detailed requirements/mock-up of the invoice and I will post the code sample to satisfy your requirement?

Collapse
 
fservais911 profile image
fservais911

Where is the page break triggered with, I assume, a new page header... etc... ?
I cannot find any code for that in the BankAccountStatement sample