Printing multi-frame Tiff images in VB.NET to a certain printer tray
A part of work I was asked to create a simple program that prints a multi-frame Tiff image from the file system to a (user-definable) printer and specific tray and to add some fun the ability to specify which page to start on and the ability to skip X number of pages between.
This is a edge case and finding the information was a huge task, while I do program VB.NET some (I know and use at least four languages,) I am mainly a web app programmer so I don’t know much about image manipulation and printing, I feared I would be heading into Win32 API land and flash backs of my days as a VB6 programmer came flooding back.
Luckily it wasn’t that hard, getting the correct information and merging it together was 95% of my battle. Following the jump will reveal the secrets.
This is a console application that I built, so it required me to add the System.Drawing reference so I could access it’s namespace. You will need the following namespaces to work:
-
Imports System.Drawing
-
Imports System.Drawing.Printing
-
Imports System.Drawing.Imaging
We need to declare a few global variables. I know I know, global variables are bad mmmkay. It leaves a bad taste in my mouth too, but it makes things easier, if you have a better way I’d like to know.
This is a console app and it takes commandline arguments so the we declare the main subroutine as such:
-
Sub Main()
-
Main(Environment.getCommandLineArgs())
-
End Sub
I suppose you could handle the command line args right in this subroutine but I like to overload it and make look like a normal command line app would. So now we create the meat of our program.
-
Private Sub Main(byVal args() as string)
-
‘Initialize variables
-
Dim tray As String = ""
-
Dim printer As String = ""
-
Dim filepath As String = ""
-
Dim ps As PaperSource
-
Dim trayfound As Boolean = False
-
start = 1
-
skip = 1
-
Dim parameter(1), arg As String
-
‘iterate through the commandline arguements
-
For Each arg In args
-
‘VB.NET sends the program name as one of the args so we need to check for that
-
‘and we don’t was superfluous args, just the ones that start with our switch delimiter
-
If (arg.IndexOf("-") = 0) Then
-
parameter(0) = arg.Substring(0, arg.IndexOf(":")) ‘The switch
-
parameter(1) = arg.Substring(arg.IndexOf(":") + 1, arg.Length - arg.IndexOf(":") - 1) ‘The value
-
Select parameter(0)
-
Case "-file"
-
filepath = parameter(1)
-
Case "-p"
-
printer = parameter(1)
-
Case "-start"
-
start = parameter(1)
-
Case "-step"
-
skip = parameter(1)
-
Case "-tray"
-
‘tray names can contain spaces so they need to be enclosed in quotes
-
‘to prevent it from getting split up as VB.Net Args are space delimited
-
tray = parameter(1).Replace("""", "")
-
End Select
-
‘Load the tiff image
-
tiffImage = Image.FromFile(filepath)
-
‘Create an instance of a PrintDocument
-
printDoc = New PrintDocument()
-
‘If the printer switch wasn’t specified it will use the computer’s default printer
-
If (printer <> "") Then
-
printDoc.PrinterSettings.PrinterName = printer
-
End If
-
‘If the user wants to print to a specific tray we will need to iterate through the printers
-
‘Trays to find the appropriate one and then reassign the PrintDocs default settings
-
If tray <> "" Then
-
For Each ps In printDoc.PrinterSettings.PaperSources
-
If ps.SourceName = tray Then
-
printDoc.DefaultPageSettings.PaperSource = ps
-
trayfound = True
-
Exit For
-
End If
-
Next
-
End If
-
‘Now that everything is in order we can begin the print
-
printDoc.Print()
-
End If
-
End For
-
End Sub
Just a note on the above code, I left out a lot of error checking, so make sure you do proper checking or the code will probably fail if you don’t have all the switches properly entered.
Now for the Counter Intuitive part of the code. This is a little confusing and I will explain it after.
-
Private Sub printDoc_PrintPage(ByVal sender As Object, ByVal e As System.Drawing.Printing.PrintPageEventArgs) Handles printDoc.PrintPage
-
tiffImage.SelectActiveFrame(FrameDimension.Page, start - 1)
-
start += skip
-
e.Graphics.DrawImage(tiffImage, 0, 0)
-
If (start < tiffImage.GetFrameCount(FrameDimension.Page)) Then
-
e.HasMorePages = True
-
Else
-
e.HasMorePages = False
-
End If
-
End Sub
When printDoc.Print() is called it triggers it’s PrintPage event, we select a page in our image and set it as the active frame (generally the first image in the multi-frame tiff, but it could start anywhere.) Then we increment the next page to be selected by the step specified by the user (or default of 1 page.) We then send the active frame to “e.graphics” via it’s drawImage method. My image is standard 8×11 inches so I set the top right corner to 0×0 so it fits the entire page, you may want to place a smaller image in the center of your document so you will have to do your own math to change this. Finally we check to see if there are any more frames in the Tiff image that we will need to print, if there is we set a flag that there are more pages to print and as a result the printDoc.PrintPages event is triggered again and this is why we needed global variables the next page runs through this process again and start is incremented again, etc. If you think of it as a Do While loop it’s much easier to understand.
I hope this helps some people out there looking for this sort of functionality as it took me about 5 hours to piece this simple bit of code together from various forums, tips and MSDN reference.
Technorati Tags: VB.NET, .NET, Printing, Tray, Tiff, Multi-page, Multi-frame, Image
Popularity: 86% [?]
August 3rd, 2007 at 9:42 am
[...] is a continuation of “Printing multi-frame Tiff images in VB.NET to a certain printer tray.” A problem came up that I hadn’t accounted for and my client came back to me. I was [...]