Centric connect.engage.succeed

PDF generation using MigraDoc

Geschreven door Arnoud van Bokkem - 25 april 2016

Arnoud van Bokkem
Recently, one of my projects called for a PDF generation tool. I was developing an MVC web application that allowed a user to fill out a web form. The requirements stated that the user response should be saved in a PDF document for evidence, in case the date requested didn’t turn out the way it was supposed to.

So that I don't violate my non-disclosure agreement, let’s just say it was a dating app that allowed users to enter characteristics of their own, along with some characteristics they would like their date to have. Something like this:

Sketch form

Take note of the two columns and the unequal tables within, they will be important later on!

Choosing a pdf generator

After quickly searching for NuGet packages that implemented PDF generation, I realised I could go with one of two approaches: either render a view to a PDF document or generate a PDF document using code, possibly using some sort of template. The first approach is great if you want the user to download a PDF. However, since I wanted my business logic to create the PDF, and obviously didn’t want to call my presentation logic from my business logic, the latter was the way to go.

Next came the final choice: a few generators stood out, due to their popularity and the number of search hits they produced. Since I didn’t have a lot of time, the PDF generator should be easy to use. In the end, I selected MigraDoc since it looked really simple and promised to come with decent documentation. Like its advanced big brother PDFsharp, MigraDoc is a product of empira Software GmbH, and is published under the MIT License.

Creating the document

So, I had selected my PDF generator. The examples included in the source code were easy enough to follow and made sense if you thought of how a Word document is structured. Create a MigraDoc document, add a Section, add a Paragraph and add some text and pictures:

// Create a new MigraDoc document
Document document = new Document();

// Add a section to the document
Section section = document.AddSection();

// Add a paragraph to the section
Paragraph paragraph = section.AddParagraph();

// Add some text and an image to the paragraph
paragraph.AddFormattedText("Hello, World!", TextFormat.Italic);
paragraph.AddImage("SomeImage.png");

Next, create a PdfDocumentRenderer, assign the generated document to it, render it and save the result as a PDF document: 

// Create a renderer for the MigraDoc document.
PdfDocumentRenderer pdfRenderer = new PdfDocumentRenderer();

// Associate the MigraDoc document with a renderer
pdfRenderer.Document = document;

// Layout and render document to PDF
pdfRenderer.RenderDocument();

// Save the document...
pdfRenderer.PdfDocument.Save("HelloWorld.pdf");

That's all there is to it. You can also define new styles or change existing ones (similar to Word), and add images, tables and text frames. MigraDoc has an internal document description language (.mdddl) that can be saved and viewed in a text editor. In the samples provided with the source code, a document viewer is supplied to view these .mdddl files. This is great when you want to fine-tune the document's layout.

Tables

Since I wanted my PDF document to look like the web form which contained a number of panels with data, I was definitely going to need to add tables, and that was pretty easy to do too:

// Create table 
Table table = section.AddTable();

// Define two columns 
Column column = table.AddColumn(); 
column = table.AddColumn();

// Create two rows with content 
Row row = table.AddRow(); 
row.Cells[0].AddParagraph("Text row 0, column 0"); 
row.Cells[1].AddParagraph("Text in row 0, column 1");

row = table.AddRow(); 
row.Cells[0].AddParagraph("Text in row 1, column 0"); 
row.Cells[1].AddParagraph("Text in row 1, column 1");

And of course, as with all elements, you can also set all kinds of properties like margin, padding, colour and font.

However, as it turned out, the tables could not be nested. That is to say, I couldn’t do this:

// Create table for actual content within the left panel 
Cell cell = row.Cells[0]; 
Table innerTableLeft = cell.AddTable();// <- Cell does not have a method AddTable()

This produces a compile error: ‘Cell’ does not contain a definition for ‘AddTable’ and no extension method ‘Add’ accepting a first argument of type ‘Cell’ could be found (are you missing a using directive or an assembly reference?)

Too bad, since another option, combining tables and text boxes didn’t work well on dynamic content: one or the other would not resize properly, which resulted in overlapping content. Then, during a Google search, I stumbled upon this great hidden feature. You can add a table within a table by adding it to the Elements collection of the cell in the outer table:

// Nifty trick to get nested table 
Table innerTableLeft = cell.Elements.AddTable();

Now I could do all of my layout using tables! From there, it was a walk in the park to get my PDF document just the way I wanted it:

End result form

See the zip file for the source code to create your own cool Hearts Alike PDF document!

About Arnoud  
Craft Expert Arnoud van Bokkem is part of the .NET team within Craft, the development programme for IT professionals (powered by Centric). If you would like to follow his blog, sign up for Craft updates.

Tags:.NET

     
Reacties
  • Thingks
    Henri Koppen
    27 april 2016
    Leuke blog, helder beschreven.

    Kende MigraDoc nog niet, maar heb wel ervaring met bijv. itextsharp . Heerlijk die nuget packages, zo zie je dat je binnen een dag een oplossing begint die soms jarenlang mee gaat.
  • Centric
    Arnoud van Bokkem
    29 april 2016
    Thanks for your nice remark! Great to see my first blog ever being read.

    During my search, I saw quite a few mentions of iTextSharp, but based on the comments, I figured it would take some work to get it to work. A bit like MigraDocs big brother PDFSharp.

    And yes, NuGet is great, even though you still have some selecting to do. Searching for PDF returns 369 packages...
  • Centric
    Pieter
    02 november 2016
    I happened to have sort of the same requirement. Only I wanted to generate a pdf-document based on a generated html-document. I ended up with PDFSharp, but am not quite content with the generated output. Table-headers looked ugly for instance. Did you ran across anything like that?
  • Centric
    Arnoud van Bokkem
    01 december 2016
    Not directly. I was in for the quick and dirty at the time. But it was my understanding that PDFSharp was fully customizable, way more than Migradoc. I can't seem to find any table functionality in the PDFSharp documentation, nor a HTML to PDF converter. They mention this explicitly in the FAQ. (www.pdfsharp.net/wiki/PDFsharpFAQ.ashx#Can_I_use_PDFsharp_to_convert_HTML_or_RTF_to_PDF_10) Are you using the NuGet package mentioned to convert HTML to PDF? You would probably need to customize the output from such a converter to get what you want.

    With MigraDoc, it is possible to customize styles and define new ones and use these on controls in the document. I would say you have about as much flexibility as the table element in HTML or in Word, for instance. But like PDFSharp, no converter for HTML to PDF is present.
  • Private
    Deepesh Karmacharya
    12 juli 2018
    Great blog, I am also using Migradoc for pdf conversion but i am facing one issue that is convert html tag text to pdf. I am getting string field directly from DB with html tag. How can i convert that field in pdf with migradoc? Do you have any custom or extension function for this issue? I have google it but no luck.
    Help will be highly appreciate.
    Thanks in Advance
Schrijf een reactie
  • Captcha image
  • Verzenden