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.
Update this Project is now available on CodePlex
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