![]() |
Languages »
C# »
Applications
Intermediate
License: The Code Project Open License (CPOL)
FormPrint as a simple classBy J.ThomasAn article on how to print or save (as a bitmap file) WinForms or any other controls. |
C#2.0.NET1.1, .NET2.0, WinXP, GDI+, VS.NET2003, VS2005, Dev
|
|
Advanced Search Add to IE Search |
|
|
|
||||||||||||||||
The "private class" FormPrint enables you
to hardcopy any form or other control to a printer or to an image
file. To do so, the class uses the public static methods Print()
or Save(). This might be useful for documentation and
debugging reasons, either for developers or for users.
Other solutions I found in discussion boards were too large and complex to be used simply. Therefore, I decided to create my own solution.
The code is written for NET 2.0. An Adaptation to NET 1.1 is described later on in this article.
Insert into your source code a reference to this class:
using JThomas.Tools;
If you put this class into a separate assembly named Tools,
you need a reference in your application to Tools.Dll, of
course.
Insert into your source code, e.g., in a Click event
for a button or a ToolStripMenuItem, the call of the
class' methods with the form or control specified.
Here are some examples to print:
/// print the actual form on the default printer with default settings FormPrint.Print(this); /// print another form that may not call a null reference, of course FormPrint.Print(WinForm2); /// print any control on the default printer with default settings, e.g.: FormPrint.Print(panel1); /// print using special settings: 8 bpp pixelformat, another printer, /// your own margins instead of the default ones, landscape orientation Margins aMargins = new System.Drawing.Printing.Margins(80,50,40,40); FormPrint.Print(this, ColorDepthReduction.Colored8bpp, "PDF Printer", aMargins, false);
Here are some examples to save:
/// Save: this version sets filename and uses png format
FormPrint.Save(this, "E:\\Temp\\MainForm.Png");
/// Save: this version sets ImageFormat and filename with standard folder
FormPrint.Save(listBox1, System.Drawing.Imaging
.ImageFormat.Bmp, "Listbox.Bmp");Most of the parameters can be omitted.
Control Ctrl means the form, or any other control that
is to be printed or saved. This parameter is mandatory.
ImageFormat fImage tells how the bitmap has to be
saved; if omitted, ImageFormat.Png is used. Printing always uses png
format.
ColorDepthReduction f8bitPixel explains how the bitmap
is printed: Standard is None, i.e. PixelFormat.Canonical
as 32 bit colors; Colored8bpp converts the bitmap to
PixelFormat.Format8bppIndexed, and Grayscaled8bpp to 8
bpp grayscales. Take a look at "Printer
problems" later.
string sPrinterName explains that another printer than
the standard printer is to be used. If omitted, the standard printer
is used.
Margins aMargins sets special page margins. If
omitted, the default margins of the current printer are used.
bool bPortrait sets orientation as portrait (true) or
landscape (false). If omitted, orientation is set to portrait.
string sFileName contains the complete filename. If
it's only a filename without path, the bitmap is saved in the
actual folder. If the filename is omitted, a standard filename is
created as: user's folder � MyPictures', control's
name, and extension by imageformat.
The FormPrint class creates a bitmap for
the required form or control. This is sent to the standard printer or
to a file in a suitable format. One can call the actual form or
another form in the application, but also any other control (e.g.,
GroupBox, Panel, ...). All that is combined
in a simple class FormPrint.
The FormPrint class contains the following private
variables:
// The FormPrint instance cls is used to execute printing resp. saving.
static FormPrint cls;
// The bitmap bmp contains the copy of the control's graphics.
Bitmap bmp;
// deciding whether to print or save
bool Printing;
// additional: variables related to each of the parameters
// mentioned aboveYou call one of the overloaded static methods FormPrint.Print()
and FormPrint.Save() using the required parameters. If
you omit a parameter, default values are used.
All variants call a private static method FormPrint.Start()
that provides the work: First, it checks if all required
parameters are set. Next, a private instance cls of the
FormPrint class is created passing all parameters.
Finally, the private methods StartPrinting() and
StartSaving() do the underlying work.
// create the private formprint class cls
cls = new FormPrint(Ctrl, bPrint, fImage, f8bitPixel,
sPrinterName, aMargins, bPortrait, sFileName);
// execute the required printing resp. saving method
try {
if (bPrint) {
cls.StartPrinting();
} else {
cls.StartSaving();
}
} finally {
// free resources
cls.bmp.Dispose();
cls.bmp = null;
// in some situations, the next command is useful
Ctrl.Refresh();
}
The constructor creates a Bitmap object bmp
with the size and graphics of the control and copies the screen
content of the control into the Bitmap object bmp.
private FormPrint(Control Ctrl, bool bPrint,
// formatings, convertings
ImageFormat fImage, ColorDepthReduction f8bitPixel
// additional parameters for printing
string sPrinterName, Margins aMargins, bool bPortrait,
// additional parameter for saving
string sFileName)
{
// call the bitmap in the propriate way - NET 1.1 or NET 2.0
ctrl = Ctrl;
bmp = GetBitmap(Ctrl);
/* set all other parameters ... these instructions are removed here */
}Under NET 2.0, one can use a single instruction to copy the control's image.
// NET 2.0 - Copy the control's graphics directly to the bitmap
private Bitmap GetBitmap(Control Ctrl) {
// prepare the bitmap
Graphics grCtrl = Ctrl.CreateGraphics();
Bitmap Result = new Bitmap(Ctrl.Width, Ctrl.Height,
grCtrl);
// copy the control's graphics � not available
with NET 1.1
Ctrl.DrawToBitmap( Result, new Rectangle(0, 0,
Ctrl.Width, Ctrl.Height));
// that's all work for the bmp using NET 2.0
// instructions
return Result;
}
Under NET 1.1, one has to use a complex workaround using
Windows GDI. Therefore, this work is done by a separate method
GetBitmap(). Take a look at the source code, if you want
more information about that.
If you want to print, bmp is sent to a PrintDocument.
If required, some instructions are used (but not shown in the
following snippet): to apply printer name or page settings,
compressing a large bitmap to paper size, converting a 32bpp bitmap
to 8bpp bitmap to avoid printer memory problems.
private void StartPrinting() {
// create a document; the event handler PrintPage
// will connect it with the bitmap
using(PrintDocument doc = new PrintDocument()){
doc.PrintPage += new PrintPageEventHandler(
doc_PrintPage);
// setting printer name and page settings,
// if required
// if margins are set, then check if bitmap has to
// be compressed
if (PrinterMargins != null) {
// check if bmp size is larger than PaperSize
if ( (bmp.Width > bmpX) || (bmp.Height >
bmpY) )
GetThumbnail((int)bmpX, (int)bmpY);
}
// convert to 8-bit-pixel or grayscale to avoid
// printer problems
if (format8bitPixel != ColorDepthReduction.None) {
ConvertBitmapTo8Bpp(15);
// now print
doc.DocumentName = SaveFileName;
doc.Print();
}
}If you want to save, it's directly done by:
bmp.Save(SaveFileName, formatImage);
Additionally, the code contains some try-catch blocks,
the PrintPageEventHandler to connect the bmp
to the PrintDocument, doc, freeing
resources, and the utilities GetThumbnail() to compress
the bitmap and ConvertBitmapTo8Bpp().
Because converting can take some seconds, a ProgressForm
with a simple label is included. This is shown only if the printed
bitmap has more than 40,000 pixels (e.g., 200x200).
If you call the method via MenuItem.Click event, you
should use a ShortCut; otherwise the opened menu is
copied, too. Pay attention: Always the actual screen content is
printed or saved; if the form is partially hidden, the foreground
screen is printed. Controls that do not match are not always printed
correctly, e.g., a normal button on a toolbar. If Control.AutoScroll
is set, one must pay attention at the SDK documentation.
Two instructions are not compatible with NET 1.1; one of them
needs a complex way to workaround. To adapt, set the appropriate
#define directive:
/// with NET 2.0 use as follows:
#define NET_V20
#undef NET_V11
/// with NET 1.1 use as follows:
#define NET_V11
#undef NET_V20In both versions, a full screen form could lead to printer
problems, like "memory full" or "too many data". If so,
try to use 8 bit pixel format by ColorDepthReduction f8bitPixel
parameter. If the problem remains, you should print a smaller
control, e.g. a panel or groupbox, rather than the whole form. In
that case, I recommend to combine your form with some settings which
control should be printed.
To create a demo application, use the FormPrintDemoForm.cs
as main form and FormPrint.cs as additional
class. The form contains a listbox to choose any variant of
FormPrint.Print() and FormPrint.Save()
and a panel with 256 colored labels. You have to change the
constant values in the buttonStart_Click() method and
the richTextBox1.LoadFile() call in the constructor.
I chose more parameters than I originally planned. I omit the following possibilities:
Initially, I chose the way in the MSDN Library How to: Print a Windows Form.
Tim van Wassenhove
told me to use DrawToBitmap().
"Programmierhans"
showed how to copy a control's graphics with NET 1.1, and in
his post
at Aug 2, 2005 19:49 the method GetThumbnail().
Robert
Schmitz "robertico" developed converting a bitmap quickly to an 8bpp pixel format and grayscaling via
ConvertBitmapTo8Bpp(). (MSDN solution with
GetPixel/SetPixel needs an unacceptable amount of time.)
My intention is to combine all that to a simple class extended by variable parameters.
12/17/2006 - First version.
12/19/2006
1. added:
clearing resources (Bitmap, Graphics)
2. added: printing as
portrait or landscape
12/24/2006
1. changed: a
shorter way to copy the control's graphics into the bitmap's
one
2. comment changed: at present, there is no adaptation to NET
1.1.
12/25/2006
1. added: copy
the control's graphics to the bitmap with NET 1.1
2. changed:
variables and methods are grouped newly, but with no other
features
3. comment changed: adaptation to NET 1.1
4. comment
added: known problems, thanks for help
01/13/2007
1. NET 1.1
changed: form can be printed including title and menu bar
2.
changed: public method Execute() splitted to Print() resp. Save()
3.
changed: Print() allows several parameters: PrinterName, Margins,
Orientation
4. changed: printing can compress to papersize with
margins if necessary
5. changed: most of the parameters can be
omitted
6. changed: printer memory problem managed by converting
to PixelFormat.Format8bppIndexed and GrayScaled bitmap instead of
colored PixelFormat.Canonical
7. changed: Execute() uses progress
label while printing a large control (more than 40000 pixels, e.g.
200x200)
8. changed: private method Execute() splitted to
StartPrinting() resp. StartSaving()
01/22/2007
1. changed:
adaptation to NET 1.1 via #define
2. changed:
PixelFormat.Format8bppIndexed and grayscaling replaced by
ColorDepthReduction enumeration
03/22/2007
NET 2.0 improved to show RichTextBox or WebBrowser
(DrawToBitmap is not available to those controls)
General
News
Question
Answer
Joke
Rant
Admin
Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads.
|
PermaLink |
Privacy |
Terms of Use
Last Updated: 27 Mar 2007 Editor: Sean Ewington |
Copyright 2006 by J.Thomas Everything else Copyright © CodeProject, 1999-2010 Web21 | Advertise on the Code Project |