Print PDF in .NET – Part 1

.NET Framework provides good support for printing in Windows Forms, WPF and Windows Store applications. You can easily show print preview dialog, customize print settings and, actually, print documents. You just need to prepare your document for printing – convert the document to a sequence of drawing commands or convert the document to the one of printer-friendly formats like XPS. It might be painful if format of your document is a complex one.

PDF is an example of such a complex document format. It is one of the most popular file formats for publishing documents, but .NET does not support printing of PDF documents out of the box.

Docotic.Pdf library adds support for printing PDF documents in .NET applications. I will show how to build a Windows Forms application that prints PDF documents. The application will display print preview dialog before printing, will have support for custom print settings and, of course, will print PDF documents to the selected printer.

Hello World

I will start with a simple “Hello World” printing application. I will use .NET Framework 4.5 in this example, but it is not necessary. You can use .NET Framework 2.0 or any newer versions.

Start by creating a new Windows Forms project named PrintPdf.

Create Windows Forms project

Rename main form class from Form1 to MainForm and change Form.Text to “Print PDF”.

Put a Print button on the main form.

Add "Print" button

The application will create a simple PDF document and print it using Docotic.Pdf library when user clicks Print button.

In order to use the Docotic.Pdf library in an application, you should download the library, install it and reference the library’s assembly from your project.

In a real-world application, you would probably prefer to distribute the library with your application. It means you might want to make a local copy of the Docotic.Pdf and reference the copy from the application. To do so:

  • create Docotic folder in the project folder
  • copy Bitmiracle.Docotic.Pdf.dll and Bitmiracle.Docotic.Pdf.xml files from installation directory to the Docotic folder
  • reference the Bitmiracle.Docotic.Pdf.dll from the application.

Please note that Bitmiracle.Docotic.Pdf.xml file is not required for the library to function properly. However, this file adds IntelliSense support for the library methods and properties and can ease development. You can remove the file when you finish developing your application.

Add Docotic.Pdf reference

It is time to get back to the Print button. Double-click the button in the forms designer and add the following code:

using BitMiracle.Docotic.Pdf;
...

private void printButton_Click(object sender, EventArgs e)
{
    using (PdfDocument pdf = new PdfDocument())
    {
        PdfCanvas canvas = pdf.Pages[0].Canvas;
        canvas.FontSize = 36;
        canvas.DrawString("Hello World");

        pdf.Save("result.pdf");
        System.Diagnostics.Process.Start("result.pdf");
    }
}

The code creates simple one-page PDF document and saves it to the result.pdf file:

Hello World PDF

The code, which creates document, is ready and it is time to add printing support. The app will use the PrintDocument class from the framework and will provide recommended delegates for the events exposed by the class. Modify the code in MainForm.cs:

using System;
using System.Drawing.Printing;
using System.Windows.Forms;
using BitMiracle.Docotic.Pdf;

namespace BitMiracle.Docotic.Samples.PrintPdf
{
    public partial class MainForm : Form
    {
        private PrintDocument m_printDocument;
        private PdfDocument m_pdf;

        public MainForm()
        {
            InitializeComponent();

            m_printDocument = new PrintDocument();
            m_printDocument.BeginPrint += printDocument_BeginPrint;
            m_printDocument.PrintPage += printDocument_PrintPage;
            m_printDocument.EndPrint += printDocument_EndPrint;
        }

        private void printButton_Click(object sender, EventArgs e)
        {
            m_printDocument.Print();
        }

        private void printDocument_BeginPrint(object sender, PrintEventArgs e)
        {
            m_pdf = new PdfDocument();

            PdfCanvas canvas = m_pdf.Pages[0].Canvas;
            canvas.FontSize = 36;
            canvas.DrawString("Hello World");
        }

        private void printDocument_PrintPage(object sender, PrintPageEventArgs e)
        {
            m_pdf.Pages[0].Draw(e.Graphics);
        }

        private void printDocument_EndPrint(object sender, PrintEventArgs e)
        {
            m_pdf.Dispose();
            m_pdf = null;
        }
    }
}

Also, modify the MainForm.Dispose method in MainForm.designer.cs:

protected override void Dispose(bool disposing)
{
    if (disposing)
    {
        if (components != null)
            components.Dispose();

        m_printDocument.Dispose();

        if (m_pdf != null)
            m_pdf.Dispose();
    }

    base.Dispose(disposing);
}

That is all! Now clicking the Print button will print the PDF document to the default system printer.

The code above creates instance of the PrintDocument class and subscribes to its events in the form’s constructor. There are three key events.

You should prepare necessary resources in a delegate for the PrintDocument.BeginPrint event. This is where the code creates an instance of the PdfDocument class. For printing, there is no need to save PdfDocument to file. That is why the application keeps the document in memory only.

private void printDocument_BeginPrint(object sender, PrintEventArgs e)
{
    m_pdf = new PdfDocument();

    PdfCanvas canvas = m_pdf.Pages[0].Canvas;
    canvas.FontSize = 36;
    canvas.DrawString("Hello World");
}

A handler for the PrintDocument.PrintPage event is the place where the app actually prints document pages. The handler accepts PrintPageEventArgs argument, which contains the Graphics property. Drawing on this Graphics will produce output on paper.

The code for PDF printing with Docotic.Pdf is very simple:  just pass Graphics as argument for the PdfPage.Draw method. The library will convert the PDF document to the sequence drawing commands.

private void printDocument_PrintPage(object sender, PrintPageEventArgs e)
{
    m_pdf.Pages[0].Draw(e.Graphics);
}

The application should clean resources used while printing up in a handler for the PrintDocument.EndPrint event. The code disposes instance of the PdfDocument class there.

private void printDocument_EndPrint(object sender, PrintEventArgs e)
{
    m_pdf.Dispose();
    m_pdf = null;
}

Summary

We have completed first version of our printing application. It generates single-paged PDF document and prints it to the default system printer.

In the next part, we are going to extend the application. We will learn how to show print settings dialog, how to show print preview, how to print multi-paged PDF documents and much more. Do not miss it!

Download source code