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));
Enter fullscreen mode Exit fullscreen mode
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;
Enter fullscreen mode Exit fullscreen mode

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