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