Ken Tucker Blog

Adventures in .net

Print to PDF

Friday, April 4, 2008

The .Net framework provides a print document class for printing.  There are times that it would be nice to redirect what you are printing to a pdf.   In this example we are going to use the Sharp Pdf lib version 1.3.1 to print to a pdf. 

The sharp pdf lib allows you to add an image to a page in a pdf.  To make it possible to print to a pdf we are going to create a new print controller class which creates a bitmap and has the print document draw the page on the bitmap.  Then it adds the bitmap as a pdf page.  Once the document is done printing it saves the pdf to disk. 

 

http://sharppdf.sourceforge.net/

Update this Project is now available on CodePlex

http://www.codeplex.com/Print2Pdf

 

Imports sharpPDF

Public Class PdfPrintController
    Inherits Printing.PrintController
    Dim pdf As pdfDocument
    Dim bm As Image

    Private _Author As String = "Unknown"

    Public Property Author() As String
        Get
            Return _Author
        End Get
        Set(ByVal value As String)
            _Author = value
        End Set
    End Property

    Private _FileName As String = "Printed.pdf"
    Public Property FileName() As String
        Get
            Return _FileName
        End Get
        Set(ByVal value As String)
            _FileName = value
        End Set
    End Property

    Private _Title As String = "Unknown"
    Public Property Title() As String
        Get
            Return _Title
        End Get
        Set(ByVal value As String)
            _Title = value
        End Set
    End Property

    Public Overrides ReadOnly Property IsPreview() As Boolean
        Get
            Return True
        End Get
    End Property

    Public Overrides Function OnStartPage(ByVal document As System.Drawing.Printing.PrintDocument, ByVal e As System.Drawing.Printing.PrintPageEventArgs) As System.Drawing.Graphics
        bm = New Bitmap(e.PageBounds.Width, e.PageBounds.Height)
        Dim g As Graphics = Graphics.FromImage(bm)
        g.Clear(Color.White)
        Return g
    End Function

    Public Overrides Sub OnStartPrint(ByVal document As System.Drawing.Printing.PrintDocument, ByVal e As System.Drawing.Printing.PrintEventArgs)
        pdf = New pdfDocument(Title, Author)
        MyBase.OnStartPrint(document, e)
    End Sub

    Public Overrides Sub OnEndPage(ByVal document As System.Drawing.Printing.PrintDocument, ByVal e As System.Drawing.Printing.PrintPageEventArgs)
        Dim p As pdfPage = pdf.addPage(e.PageBounds.Height, e.PageBounds.Width)
        p.addImage(bm, 0, 0)
        MyBase.OnEndPage(document, e)
    End Sub

    Public Overrides Sub OnEndPrint(ByVal document As System.Drawing.Printing.PrintDocument, ByVal e As System.Drawing.Printing.PrintEventArgs)
        pdf.createPDF(FileName)
        MyBase.OnEndPrint(document, e)
    End Sub

End Class

Here is a sample which creates a pdf of the Northwind product list.

Imports System.Data.SqlClient

Public Class Form1
    Public WithEvents p As New Printing.PrintDocument
    Dim iRecord As Integer = 0
    Dim fntPrice As New Font("Arial", 12)
    Dim ds As New DataSet

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Dim strConn As String
        Dim conn As SqlConnection
        Dim da As SqlDataAdapter

        strConn = "Server = .\SQLEXPRESS;"
        strConn &= "Database = Northwind; Integrated Security = SSPI;"
        conn = New SqlConnection(strConn)
        da = New SqlDataAdapter("Select ProductName, UnitPrice From Products", conn)
        da.Fill(ds, "Products")

        DataGridView1.DataSource = ds.Tables("Products")
    End Sub

    Private Sub p_BeginPrint(ByVal sender As Object, ByVal e As System.Drawing.Printing.PrintEventArgs) Handles p.BeginPrint
        iRecord = 0
    End Sub

    Private Sub p_PrintPage(ByVal sender As Object, ByVal e As System.Drawing.Printing.PrintPageEventArgs) Handles p.PrintPage
        Dim g As Graphics = e.Graphics
        Dim iPageHeight As Integer = e.PageBounds.Height
        Dim iPageWidth As Integer = e.PageBounds.Width
        Dim iFntHeight As Integer = CInt(g.MeasureString("Test", fntPrice).Height)
        Dim iLinesPerPage As Integer = iPageHeight \ iFntHeight - 15
        Dim yPos As Integer = 0
        Dim iTop As Integer
        Dim iMax As Integer = ds.Tables("Products").Rows.Count
        Dim strDescription As String
        Dim x As Integer
        Dim xPos As Integer
        Dim strPrice As String
        Dim fntTitle As Font = New Font("Microsoft Sans Serf", 14)
        Dim iCount As Integer = ds.Tables("Products").Rows.Count
        Dim strDate As String = Trim(Now.ToLongDateString)
        Dim sf As New StringFormat
        sf.Alignment = StringAlignment.Far

        xPos = CInt(iPageWidth - g.MeasureString("Price List", fntTitle).Width) \ 2
        g.DrawString("Price List", fntTitle, Brushes.Black, xPos, 10)
        yPos = 10 + CInt(g.MeasureString("Price List", fntTitle).Height)

        xPos = CInt(iPageWidth - g.MeasureString(strDate, fntPrice).Width) \ 2
        g.DrawString(strDate, fntPrice, Brushes.Black, xPos, yPos)
        yPos += 2 * iFntHeight
        g.DrawString("Product", fntPrice, Brushes.Black, 50, yPos)

        g.DrawString("Price", fntPrice, Brushes.Black, _
                New Rectangle(430, yPos, 100, 2 * iFntHeight), sf)

        yPos += iFntHeight
        g.DrawLine(Pens.Black, 0, yPos, iPageWidth, yPos)

        e.HasMorePages = True
        iTop = yPos

        For x = 0 To iLinesPerPage
            If iRecord < imax Then
                With ds.Tables("Products").Rows(iRecord)
                    strDescription = .Item("ProductName").ToString
                    strPrice = Convert.ToDecimal(.Item("UnitPrice")).ToString("c")
                End With
                Dim rName As New Rectangle(5, yPos, 400, iFntHeight)
                Dim rPrice As New Rectangle(430, yPos, 100, iFntHeight)

                g.DrawString(strDescription, fntPrice, Brushes.Black, rName)
                g.DrawString(strPrice, fntPrice, Brushes.Black, rPrice, sf)
            Else
                e.HasMorePages = False
            End If
            yPos += iFntHeight
            iRecord += 1
        Next
        fntTitle.Dispose()
        If e.HasMorePages = False Then iRecord = 0
    End Sub

    Private Sub btnPrint_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnPrint.Click
        Dim pc As New PdfPrintController
        pc.Title = "Test Pdf"
        pc.Author = "Ken Tucker"
        pc.FileName = "Test.pdf"
        p.PrintController = pc
        p.Print()
    End Sub
End Class



kick it on DotNetKicks.com
Tags: ,
Filed Under: pdf, VB

Comments (8) -

most expensive cars said:

Thank you very much sir..
from 15days i was waiting for this script..

SSNLocator said:

this is really awesome code sir...can i get this code in pearl?
thanks,
Md.Raihaan

Busby SEO Test said:

thanks for sharing this nice tech code. thanks alot.

Corporate training said:

thanks for sharing great code..i really thanks..
regards,
dany

Diamonds said:

Thanks for the code. Had been looking for something like this

Comments are closed