Search code examples
c#.netwpfpdfsharpmigradoc

PDFSharp / Migradoc PDF Generation for 3k+ rows going extremely slow


I'm trying to generate a PDF with about 3,500 records. It is taking almost 5-10 minutes. It's literally absurd. Am I missing something here? It's getting stuck on the RenderDocument() method. I'm using version 1.32 of MigraDoc.Rendering.dll and PdfSharp.dll

Here is a snippet of my code.. Maybe there is something I can optimize in the way I am building the PDF? Other PDFs I generate with this code with about 50 records creates instantly.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using MigraDoc.DocumentObjectModel;
using MigraDoc.DocumentObjectModel.Tables;
using MigraDoc.DocumentObjectModel.Shapes;
using MigraDoc.Rendering;
using System.Diagnostics;

namespace Migradoc_PDF_Example
{
    class PDFGenerator
    {
        Document document;
        public void BuildAndOpenPDF()
        {
            //Argument = true if unicode
            PdfDocumentRenderer pdfRenderer = new PdfDocumentRenderer(true); 

            // Set the MigraDoc document
            pdfRenderer.Document = document;

            // Create the PDF document
            pdfRenderer.RenderDocument();
            pdfRenderer.Save("ExamplePDF.pdf");

            //Let's create a process to open our generated PDF
            Process p = new Process(); 
            p.StartInfo = new ProcessStartInfo("ExamplePDF.pdf");
            p.Start(); //Open PDF
        }
        public PDFGenerator() //In this example, the class constructor will set up the document and BuildAndOpenPDF will build the file/open it
        {
            //Actually generate invoice document.. everything before this is getting the data built together before actually writing to the pdf
            document = new Document();
            document.Info.Title = "DOCUMENT TITLE";
            document.Info.Subject = "DOCUMENT SUBJECT";
            document.Info.Author = "Me";

            // Get the predefined style Normal.
            Style style; //Creates style variable so we can change the different styles in the document as seen below..
            style = document.Styles["Normal"]; //The normal style = default for everything
            style.Font.Name = "Times New Roman"; //Default normal Font Type to Times New Roman

            style = document.Styles[StyleNames.Header]; //Style for Header of document
            style.ParagraphFormat.AddTabStop("16cm", TabAlignment.Right);

            style = document.Styles[StyleNames.Footer]; //Style for footer of document
            style.ParagraphFormat.AddTabStop("8cm", TabAlignment.Center);

            // Create a new style called Table based on style Normal
            style = document.Styles.AddStyle("Table", "Normal");
            style.Font.Name = "Times New Roman";
            style.Font.Size = 9;

            // Create a new style called Reference based on style Normal
            style = document.Styles.AddStyle("Reference", "Normal");
            style.ParagraphFormat.SpaceBefore = "5mm";
            style.ParagraphFormat.SpaceAfter = "5mm";
            style.ParagraphFormat.TabStops.AddTabStop("16cm", TabAlignment.Right);

            // Create a new style called TextBox based on style Normal
            style = document.Styles.AddStyle("TextBox", "Normal");
            style.ParagraphFormat.Borders.Width = 2.5;
            style.ParagraphFormat.Borders.Distance = "3pt";
            style.ParagraphFormat.Shading.Color = Colors.SkyBlue;

            // Each MigraDoc document needs at least one section.
            Section section = document.AddSection();

            // Create TextFrame to store the text at the top (inside the borderFrame)
            TextFrame addressFrame;
            addressFrame = section.AddTextFrame(); //add this TextFrame to our section in the document
            addressFrame.Height = "1.5cm";  //12 Pt Font  = 0.5cm  so 3 lines = 1.5cm
            addressFrame.Width = "14cm"; //16 cm width - 1 inch left indention - 1 inch right indention = 14cm
            addressFrame.Left = "1cm";
            addressFrame.Top = "1.0cm";
            addressFrame.RelativeVertical = RelativeVertical.Page;
            addressFrame.LineFormat.Width = "1pt"; //Border pixel width = 1pt
            addressFrame.LineFormat.Color = Colors.Black; //Border color = black

            Paragraph addressinfo = addressFrame.AddParagraph(); //Add paragraph to addressFrame to store text
            addressinfo.Format.Alignment = ParagraphAlignment.Center; //Align paragraph in center
            addressinfo.AddFormattedText("LINE 1 EX.\n", TextFormat.Bold);
            addressinfo.AddFormattedText("LINE 2 EX.\n", TextFormat.Bold);
            addressinfo.AddFormattedText("LINE 3 EX.\n", TextFormat.Bold);
            addressinfo.Format.Font.Name = "Times New Roman";
            addressinfo.Format.Font.Size = 12;
            addressinfo.Format.SpaceAfter = 0;

            Paragraph Spacing = section.AddParagraph(); //Space between top and datagrid
            Spacing.Format.SpaceAfter = "4cm";

            /**************************************************************************************
             *                                  TABLE LOGIC BELOW
             *                                                                                   */
            //Next is all the crap for the table below
            Table table = section.AddTable();
            table.Style = "Table"; //Use the table style we created above
            table.Borders.Color = new Color(81, 125, 192); //Red, Green, Blue
            table.Borders.Width = 0.25;
            table.Borders.Left.Width = 0.5;
            table.Borders.Right.Width = 0.5;
            table.Rows.LeftIndent = 0;

            decimal tableWidth = 0.0M; //Used so we can center the table properly

            //Before adding any rows, we must add our columns
            Column column = table.AddColumn("1.0cm"); //ID Column
            tableWidth += 1.0M; //Required for table center to be properly calculated
            column.Format.Alignment = ParagraphAlignment.Left;

            column = table.AddColumn("1.0cm"); //Another Column
            tableWidth += 1.0M; //Required for table center to be properly calculated
            column.Format.Alignment = ParagraphAlignment.Left;

            column = table.AddColumn("1.0cm"); //Another Column
            tableWidth += 1.0M; //Required for table center to be properly calculated
            column.Format.Alignment = ParagraphAlignment.Left;

            column = table.AddColumn("1.0cm"); //Another Column
            tableWidth += 1.0M; //Required for table center to be properly calculated
            column.Format.Alignment = ParagraphAlignment.Left;

            column = table.AddColumn("1.0cm"); //Another Column
            tableWidth += 1.0M; //Required for table center to be properly calculated
            column.Format.Alignment = ParagraphAlignment.Left;

            column = table.AddColumn("1.0cm"); //Another Column
            tableWidth += 1.0M; //Required for table center to be properly calculated
            column.Format.Alignment = ParagraphAlignment.Left;

            table.Rows.LeftIndent = ((16 - tableWidth) / 2).ToString() + "cm"; //Use this to center the table - Note: Max table width = 16CM

            //Create Header Row for the table
            Row row = table.AddRow();
            row.HeadingFormat = true;
            row.Format.Alignment = ParagraphAlignment.Center;
            row.Format.Font.Bold = true;
            row.Shading.Color = new Color(235, 240, 249); //Red Green Blue
            row.Cells[0].AddParagraph("ID");
            row.Cells[0].Format.Alignment = ParagraphAlignment.Left;
            row.Cells[1].AddParagraph("poopy");
            row.Cells[1].Format.Alignment = ParagraphAlignment.Left;
            row.Cells[2].AddParagraph("butt");
            row.Cells[2].Format.Alignment = ParagraphAlignment.Left;
            row.Cells[3].AddParagraph("randall");
            row.Cells[3].Format.Alignment = ParagraphAlignment.Left;
            row.Cells[4].AddParagraph("jim");
            row.Cells[4].Format.Alignment = ParagraphAlignment.Left;
            row.Cells[5].AddParagraph("duh");
            row.Cells[5].Format.Alignment = ParagraphAlignment.Left;
            table.SetEdge(0, 0, 6, 1, Edge.Box, BorderStyle.Single, 0.75, Color.Empty); //This is to draw box around header row, arguments are weird, only change 3rd argument to # of columns

            //Now let's add our fake data
            for (int i=0; i<3600; i++)
            {
                Row newRow = table.AddRow();
                //ID Column [0]
                newRow.Cells[0].Format.Alignment = ParagraphAlignment.Left;
                newRow.Cells[0].AddParagraph("ID#"+i.ToString()); //Ex. ID#1 ID#2
                //Another Column [1]
                newRow.Cells[1].Format.Alignment = ParagraphAlignment.Left; 
                newRow.Cells[1].AddParagraph("test1"); 
                                                      //Amount Column [1]
                newRow.Cells[2].Format.Alignment = ParagraphAlignment.Left; 
                newRow.Cells[2].AddParagraph("test2"); 

                //Another Column [1]
                newRow.Cells[3].Format.Alignment = ParagraphAlignment.Left; 
                newRow.Cells[3].AddParagraph("test3"); 

                //Another Column [1]
                newRow.Cells[4].Format.Alignment = ParagraphAlignment.Left; 
                newRow.Cells[4].AddParagraph("test4"); 

                //Another Column [1]
                newRow.Cells[5].Format.Alignment = ParagraphAlignment.Left; 
                newRow.Cells[5].AddParagraph("test5"); 
            }

            // Create footer
            Paragraph footer = section.Footers.Primary.AddParagraph();
            footer.AddText("Created by Me " + DateTime.Now.Year.ToString());
            footer.Format.Font.Size = 8;
            footer.Format.Alignment = ParagraphAlignment.Center;
        }

    }
}

Solution

  • So found out that it is literally just extremely slow rendering large datasets, also PDF Sharp 1.5 Beta is still in beta so it isnt that much better either. I had to grab a 3rd party patch solution:

    Debug Mode: http://www.pakeha_by.my-webs.org/downloads/MigraDoc-1.32-patched-debug.zip

    and

    Release Mode: http://www.pakeha_by.my-webs.org/downloads/MigraDoc-1.32-patched-release.zip