In general, programs do not directly touch hardware
to draw. Instead, programs use graphical libraries for drawing. Those
libraries, in turn, rely on device drivers to touch the underlying
hardware. And so, graphical output typically involves these software
layers:
The core graphics library on desktop Windows is the Graphics Device Interface (GDI, gdi32.dll). With .NET, Microsoft added a second library (GDI+, gdiplus.dll)
to add new drawing support. While GDI+ was intended to support
managed-code drawing, the library is also accessible from native-mode
application programmers: The library can be called from unmanaged
(native-mode) C++ programs. On the desktop, these two graphics
libraries—GDI and GDI+—provide the underpinnings for all of the .NET
graphics classes. And so, with .NET Framework programs running on the
Windows desktop, the architecture of graphical output involves the
following elements:
Managed-code program
Shared managed-code library (System.Drawing.dll)
GDI+ native-code library (gdiplus.dll)
GDI native-code library (gdi32.dll)
Graphics device driver (display driver or printer driver)
Windows CE supports a select
set of GDI drawing functions. There is no library explicitly named “GDI”
in Windows CE. Instead, the graphical output functions reside in the COREDLL.DLL
library. These functions are exactly like their desktop counterparts,
so even if there is no library named “GDI” in Windows CE, we refer to
these functions as “GDI functions.”
Of the desktop’s 400
or so GDI functions, only 85 exist in Windows CE. Windows CE has no GDI+
drawing functions. This limits the extent to which Windows CE can
support .NET drawing functions.
With these limits, you might
wonder whether Windows CE can create interesting graphical output. The
answer is a resounding “yes!” The functions that are present were
hand-picked as the ones that programs tend to use most. It represents a
good set of text, raster, and vector functions so that programs can draw
rich text output, display bitmaps in a wide range of formats, and draw
complex vector objects.
On both desktop and compact versions, the main .NET graphical library is System.Drawing.dll.
At 59KB, the .NET Compact Framework library is significantly smaller
than its 616KB desktop counterpart. While the desktop library supports
five namespaces, the .NET Compact Framework version supports one: System.Drawing
(plus tiny fragments of two other namespaces). The architecture for
drawing from a .NET Compact Framework program is as follows:
Managed-code program
Managed-code library (System.Drawing.dll)
GDI functions in the native-code library (COREDLL.DLL)
Graphics device driver (display or printer)
From
the arrangement of these software layers, a savvy .NET Compact
Framework programmer can divine two interesting points: (1) The
managed-code library depends on the built-in GDI drawing functions, and
managed-code programs can do the same; and (2) as on the desktop,
display screens and printers require a dedicated graphics driver to
operate.
1. Drawing Surfaces
On the Windows desktop, there are four types of drawing surfaces:
When we use the term drawing surface,
we mean either a physical drawing surface or a logical drawing surface.
Two of the four drawing surfaces in the list are physical drawing
surfaces, which require dedicated device drivers: display screens and
printers. The other two drawing surfaces are logical drawing surfaces:
bitmaps and metafiles. These latter two store pictures for eventual
output to a device.
Bitmaps and metafiles are similar enough that they share a common base class in the desktop .NET Framework: the Image class. Metafiles are not officially supported in Windows CE, however, and so their wrapper, the Metafile
class, does not exist in the current version of the .NET Compact
Framework. Because metafiles might someday be supported in a future
version of the .NET Compact Framework, they are worth a brief mention
here.
1.1. Display Screens
The display screen
plays a central role in all GUI environments because it is on the
display screen that a user interacts with the various GUI applications.
The real stars of the display screen are the windows after which the
operating system gets its name. A window acts as a virtual console for interacting with a user. The physical console for a desktop PC consists of a display
screen, a mouse, and a keyboard. On a Pocket PC, the physical console
is made up of a display screen, a stylus and a touch-sensitive screen
for pointing, and hardware buttons for input (supported, of course, by
the on-screen keyboard).
All graphical output on the display screen is directed to one window or another. Enforcement of window boundaries relies on clipping.
Clipping is the establishment and enforcement of drawing boundaries; a
program can draw inside clipping boundaries but not outside them. The
simplest clipping boundaries are a rectangle. The area inside a window
where a program may draw is referred to as the window’s client area.
1.2. Printers
Printers are the
best-established and most-connected peripherals in the world of
computers. While some industry pundits still rant about the
soon-to-arrive paperless office, just the opposite has occurred. Demand
for printed output has continued to go up, not down. Perhaps the world
of computers—with its flashing LCD displays, volatile RAM, and
ever-shrinking silicon—makes a person want something that is more real.
Printing from Windows
CE–powered devices is still in its infancy, which is a nice way to say
that it is not well supported. The official story is that users have not
asked for it—in other words, there is not a good enough business case
for adding better printing support. Someday that may change, but until
then you are on your own when it comes to creating hard-copy output from
a Windows Mobile device.
1.3. Bitmaps
Bitmaps provide a way to
store a picture. Like its desktop counterparts, Windows CE supports
device-independent bitmaps (DIBs) as first-class citizens. In-memory
bitmaps can be created of any size and treated like any other drawing surface. After a program has drawn to a bitmap, that image can be put on the display screen.
If you look closely, you
can see that Windows CE and the .NET Compact Framework support other
raster formats. Supported formats include GIF, PNG, and JPEG. When
Visual Studio .NET reads files with these formats (which it uses for
inclusion in image lists, for example), it converts the raster data to a
bitmap. The same occurs when a PNG or JPEG file is read from
the object store into a .NET Compact Framework program. Whatever
external format is used for raster data, Windows CE prefers bitmaps.
1.4. Metafiles
A second
picture-storing mechanism supported by desktop Windows consists of
metafiles. A metafile is a record-and-playback mechanism that stores the
details of GDI drawing calls. The 32-bit version of Windows metafiles
are known as Enhanced Metafiles (EMFs). The following Win32 native metafile functions are exported from COREDLL.DLL but are not officially supported in Windows CE, although they might gain official support in some future version of Windows CE:
CreateEnhMetaFile
PlayEnhMetaFile
CloseEnhMetaFile
DeleteEnhMetaFile
1.5. Supported Drawing Surfaces
Of these four types of
drawing surfaces, three have official support in Windows CE: display
screens, printers, and bitmaps. Only two are supported by the .NET
Compact Framework: display screens and bitmaps. Support for bitmaps
centers on the Bitmap
class. We start this discussion
of graphical output with the drawing surface that is the focus in all
GUI systems: the display screen.
2. Drawing Function Families
All of the graphical output functions can be organized into one of three drawing function families:
Each
family has its own set of drawing attributes and its own logic for how
its drawing is done. The distinction between these three kinds of output
extends from the drawing program into the graphics device drivers. Each
family is complex enough for a programmer to spend many years mastering
the details and intricacies of each type of drawing. The drawing
support is rich enough, however, so that you do not have to be an expert
to take advantage of what is offered.
2.1. Text Output
For drawing text, the
most important issue involves selection of the font because all text
drawing requires a font, and the font choice has the greatest impact on
the visual display of text. The only other drawing attribute that
affects text drawing is color—both the foreground text and the color of
the background area.
2.2. Raster Output
Raster data involves
working with arrays of pixels, sometimes known as bitmaps or image data.
Internally, raster data is stored as a DIB. Six basic DIB formats are supported in the
various versions of Windows: 1, 4, 8, 16, 24, and 32 bits per pixel.
Windows CE adds a seventh DIB format to this set: 2 bits per pixel.
Windows CE provides very
good support for raster data. You can dynamically create bitmaps, draw
on bitmaps, display them for the user to see, and store them on disk. A
bitmap, in fact, has the same rights and privileges as the display
screen. By this we mean you use the same set of drawing functions both
for the screen and for bitmaps. This means you can use bitmaps to
achieve interesting effects by first drawing to a bitmap and
subsequently copying that image to the display screen. An important
difference from desktop versions of Windows is that Windows CE does not
support any type of coordinate transformations, and in particular there
is no support for the rotation of bitmaps; the .NET Compact Framework
inherits these limitations because it relies on native Win32 API
functions for all of its graphics support.
2.3. Vector Output
Vector drawing
involves drawing geometric figures such as ellipses, rectangles, and
polygons. There are, in fact, two sets of drawing functions for each type of figure. One set draws the border of geometric figures with a pen. The other set of functions fills the interiors of geometric figures using a brush.
3. .NET Compact Framework Graphics
The .NET Framework
has six namespaces that support the various graphical output classes. In
the .NET Compact Framework, just one namespace has made the cut: System.Drawing. This namespace and its various classes are packaged in the System.Drawing.dll
assembly. For a detailed comparison between the graphics support in the
.NET Framework and in the .NET Compact Framework, see the sidebar Comparing Supported Desktop and Smart-Device Drawing.
The System.Drawing
namespace in the .NET Compact Framework holds the primary elements used
to draw on a device screen from managed code. The desktop .NET
Framework provides five namespaces for creating graphical output, but in
the .NET Compact Framework this has been pared back to two: System.Drawing and System.Drawing.Design (plus some fragments from two other namespaces).
Table 1
summarizes the .NET namespaces supported in the desktop .NET Framework,
along with details of how these features are supported in the .NET
Compact Framework. The System.Drawing namespace supports drawing on a device screen. A second namespace, System.Drawing.Design,
helps when building a custom control. In particular, this namespace
contains elements used to support design-time drawing of controls (i.e.,
drawing controls while they are being laid out inside the Designer).
The elements of this namespace reside in the System.CF.Design.dll
assembly, a different name from the assembly name used for the desktop.
The change in the filename makes it clear that this file supports .NET
Compact Framework programming.
Table 1. Desktop .NET Framework Drawing Namespaces in the .NET Compact FrameworkNamespace | Description | Support in the .NET Compact Framework |
---|
System.Drawing | Core drawing objects, data structures, and functions | A minimal set that allows for the drawing of text, raster, and vector objects with no built-in coordinate transformation | System.Drawing.Design | Support for the Designer and the various graphics editors of Visual Studio .NET | Support provided by a .NET Compact Framework–specific alternative library named System.CF.Design.dll | System.Drawing.Drawing2D | Support for advanced graphics features, including blends, line caps, line joins, paths, coordinate transforms, and regions | Not supported in the .NET Compact Framework (except for the CombineMode enumeration) | System.Drawing.Imaging | Support for storage of pictures in metafiles and bitmaps; bitmap conversion; and management of metadata in image files | Not supported in the .NET Compact Framework (except for the ImageAttributes class) | System.Drawing.Printing | Rich support for printing and the user interface for printing | Not supported in the .NET Compact Framework | System.Drawing.Text | Font management | Not supported in the .NET Compact Framework |
On the surface, it would be easy to conclude that Microsoft gutted the desktop System.Drawing.dll
library in creating the .NET Compact Framework edition. For one thing,
the desktop version is a whopping 456KB, while the compact version is a
scant 38KB. What’s more, the desktop
version supports 159 classes, while the compact version has a mere 17
classes. A more specific example of the difference between the desktop
.NET Framework and the .NET Compact Framework—from a drawing
perspective—is best appreciated by examining the Graphics class (a member of the System.Drawing
namespace). The desktop .NET Framework version of this class supports
244 methods and 18 properties; the .NET Compact Framework version
supports only 26 methods and 2 properties. By this accounting, it
appears that the prognosis of “gutted” is correct. Yet, as any thinking
person knows, looks can be deceiving.
To
better understand the differences between the desktop .NET Framework
and the .NET Compact Framework, we have to dig deeper into the Graphics
class. To really see the differences between the desktop and compact
versions, we must study the overloaded methods. If we do, we see that
the desktop .NET Framework provides many overloaded methods for each
drawing call, while the .NET Compact Framework provides far fewer. For
example, the desktop .NET Framework provides six different ways to call DrawString (the text drawing function), while there is only one in the .NET Compact Framework. And there are 30 versions of DrawImage (the function for drawing a bitmap) in the desktop .NET Framework but only 4 in the .NET Compact Framework.
We have, in short, fewer
ways to draw objects—but in general we can draw most of the same things
with the .NET Compact Framework that we can draw on the desktop. This
supports a central design goal of Windows CE, which is to be a small,
compact operating system. Win32 programmers who have worked in Windows
CE will recognize that a similar trimming has been done to define the
Windows CE support for the Win32 API. Instead of calling this a
“subset,” we prefer to take a cue from the music recording industry and
use the term greatest hits. The .NET Compact Framework implementation of the System.Drawing namespace is, we believe, the greatest hits of the desktop System.Drawing namespace.
In comparing the
desktop .NET Framework to the .NET Compact Framework, an interesting
pattern emerges that involves floating-point numbers. In the desktop
.NET Framework, most of the overloaded methods take floating-point
coordinates. For all of the overloaded versions of the DrawString methods, you can use only
floating-point coordinates. In the .NET Compact Framework, few drawing
functions have floating-point parameters—most take either int32 or a Rectangle to specify drawing coordinates. A notable exception is the DrawString
function, which never takes integer coordinates in the desktop .NET
Framework; in the .NET Compact Framework, it is the sole drawing method
that accepts floating-point values.
It is worth
noting that the underlying drawing functions (both in the operating
system and at the device driver level) use exclusively integer
coordinates. The reason is more an accident of history than anything
else. The Win32 API and its supporting operating systems trace their
origins back to the late 1980s, when the majority of systems did not
have built-in floating-point hardware. Such support is taken for granted
today, which is no doubt why the .NET Framework has such rich support
for floating-point values.
A fundamental part
of any graphics software is the coordinate system used to specify the
location of objects drawn on a drawing surface. The desktop .NET
Framework supports seven distinct drawing coordinate systems in the GraphicsUnit enumeration. Among the supported coordinate systems are Pixel, Inch, and Millimeter. While the .NET Compact Framework supports this same enumeration, it has only one member: Pixel.
This means that when you draw on a device screen, you are limited to
using pixel coordinates. One exception involves fonts, whose height is
always specified in Point units.
This brings up
another difference between the desktop .NET Framework and the .NET
Compact Framework: available coordinate transformations. The desktop
provides a rich set of coordinate transformations—scrolling, scaling,
and rotating—through the Matrix class and the 3 × 3 geometric transform provided in the System.Drawing.Drawing2D
namespace. The .NET Compact Framework, by contrast, supports no
coordinate mapping. That means that, on handheld devices, application
software that wants to scale, scroll, or rotate must handle the
arithmetic itself because neither the .NET Compact Framework nor the
underlying operating system provides any coordinate transformation
helpers. What the .NET Compact Framework provides, as far as coordinates
go, is actually the same thing that the underlying Windows CE system
provides: pixels, more pixels, and only pixels.
While it might be lean,
the set of drawing services provided in the .NET Compact Framework is
surprisingly complete. That is, almost anything you can draw with the
desktop .NET Framework can be drawn with the .NET Compact Framework. The
key difference between the two implementations is that the desktop
provides a far wider array of tools and helpers for drawing. Programmers
of the desktop .NET Framework are likely to have little trouble getting
comfortable in the .NET Compact Framework, once they get used to the
fact that there are far fewer features. But those same programmers are
likely to be a bit frustrated when porting desktop .NET Framework code
to the .NET Compact Framework world and are likely to have to rewrite
and retrofit quite a few of their applications’ drawing elements.
|
3.1. The Role of the Graphics Class
The most important class for creating graphical output is the Graphics class. It is not the only class in the System.Drawing namespace, but only the Graphics class has drawing methods. This class holds methods such as DrawString for drawing a string of text, DrawImage for displaying a bitmap onto the display screen, and DrawRectangle for drawing the outline of a rectangle. Here is a list of the other classes in the System.Drawing namespace for the .NET Compact Framework:
Bitmap
Brush
Color
Font
FontFamily
Icon
Image
Pen
Region
SolidBrush
SystemColors
These other classes
support objects that aid in the creation of graphical output, but none
have any methods that actually cause graphical output to appear
anywhere. So, while you are going to need these other classes and will
use these other classes, they play a secondary role to the primary
graphical output class in the .NET Compact Framework: Graphics.
3.2. Drawing Support for Text Output
Table 2 summarizes the methods of the Graphics class that support text drawing. The DrawString method draws text, while the MeasureString
method calculates the bounding box of a text string. This calculation
is needed because graphical output involves putting different types of
graphical objects on a sea of pixels. When dealing with a lot of text,
it is important to measure the size of each text box to make sure the
spacing matches the spacing as defined by the font designer. Failure to
use proper spacing creates a poor result. In the worst cases, it makes
the output of your program unattractive to users. Even if a user does
not immediately notice minor spacing problems, the human eye is very
finicky about what text it considers acceptable. Poor spacing makes text
harder to read because
readers must strain their eyes to read the text. Properly spaced text
makes readers—and their eyes—happier than poorly spaced text does.
Table 2. System.Drawing.Graphics Methods for Text Drawing
Method | Comment |
---|
DrawString | Draws a single line of text using a specified font and text color |
MeasureString | Calculates the width and height of a specific character string using a specific font |
3.3. Drawing Support for Raster Output
Table 3 summarizes the methods of the Graphics
class that draw raster data. We define raster graphics as those
functions that operate on an array of pixels. Two of the listed
functions copy an icon (DrawIcon) or a bitmap (DrawImage)
to a drawing surface. The other two methods fill a rectangular area
with the color of an indicated brush.
Table 3. System.Drawing.Graphics Methods for Raster Drawing
Method | Comment |
---|
Clear | Accepts a color value and uses that value to fill the entire surface of a window or the entire surface of a bitmap |
DrawIcon | Draws an icon at a specified location. An icon is a raster image created from two rectangular bitmap masks. The DrawIcon method draws an icon by applying one of the masks to the drawing surface, using a Boolean AND operator, followed by the use of the XOR
operator to apply the second mask to the drawing surface. The benefit
of icons is that they allow portions of an otherwise rectangular image
to display the screen behind the icon. The disadvantage of icons is that
they are larger than comparable bitmaps and also slower to draw |
DrawImage | Draws a bitmap onto the display screen or draws a bitmap onto the surface of another bitmap |
FillRegion | Fills
a region with the color specified in a brush. A region is defined as a
set of one or more rectangles joined by Boolean operations |
3.4. Drawing Support for Vector Output
Table 4 summarizes the seven methods in the Graphics class that draw vector Graphics
objects in the .NET Compact Framework. There are substantially fewer
supported vector methods than in the desktop .NET Framework. The vector
methods whose names start with Draw draw lines. The vector methods whose names start with Fill fill areas.
Table 4. System.Drawing.Graphics Methods for Vector Drawing
Method | Comment |
---|
DrawEllipse | Draws the outline of an ellipse using a pen |
DrawLine | Draws a straight line using a pen |
DrawPolygon | Draws the outline of a polygon using a pen |
DrawRectangle | Draws the outline of a rectangle using a pen |
FillEllipse | Fills the interior of an ellipse using a brush |
FillPolygon | Fills the interior of a polygon using a brush |
FillRectangle | Fills the interior of a rectangle using a brush |