Introduction
I've been using GDI+ now for several years. I primarily use GDI+ when
assisting in the development of custom UI's. I've noticed that complex vector graphics are being increasingly
incorporated into UIs. The reason for this seems to be that graphic artist love
to use antialaising, gradients, blends and transparency to give a "quality
feel" to UI. I have strong bias toward the use of vector graphics because they
are easy to manipulate and scale at runtime. Because of that we've been
using GDI+ for awhile now to create custom UIs. However, I've recently run
into several quality issues related to native GDI+ antialiasing that I thought
would be of general interest to codeproject readers.
The issues I�ve recently seen are:
-
Ugly Thumbnails � small
vector drawing often look terrible when using the native GDI+ antialiasing.
Often they are not easily recognizable from their original, larger images.
Especially when the image is very small.
-
Seams Show � Vector drawings
which are constructed by abutting several objects in an attempt to make a
seamless transition often have very noticeable artifacts.
-
Unexpected Artifacts � some
vector drawings have unexpected artifacts when antialiased using GDI+. Often
these are caused by seams, but thin lines and other graphic elements can cause
unpleasant artifacts.
Since my goal when using GDI+ is to produce a very high quality
looking image, I needed a way to address these quality issues. Don't get me
wrong, I'm not saying that the native GDI+ antialiasing is bad, frankly it's
amazingly good and quite fast. However, there are times when it just isn't good
enough.
The following sections in this article describe these artifacts
in more detail and offer a simple algorithm that can eliminate most of these
issues in your images -- at a steep price.
Cleaning Ugly Thumbnails
Thumbnails are small images that are often used to help a user see many possible
selections at one time. It�s important that thumbnails be easily identifiable
when very small; otherwise they are of limited value. Unfortunately the native
antialiasing in GDI+ often produces very poor quality thumbnails (See the left
and middle images above).
In the image above you can see that Native GDI+ antialiasing about 30% faster
than custom antialiasing. Larger images can have up to 10x difference. However
the quality of the custom antialiased thumbnail is very high and is much easier
to associate with its original, larger image. Because of the increased
rendering time, this custom antialiasing technique should only
be used when absolutely necessary.
Are Your Seams Showing
Another case where GDI+ native antialiasing gets into trouble is when there are
seams that are intended to be invisible in your art. This can be caused by
several things:
Blends � Blends are
essentially a gradient that morphs between two or more shapes. Since GDI+
doesn�t support blends directly they are usually constructed by creating
multiple paths, one for each shape change, and filling those paths with the
next calculated color in the gradient. Unfortunately this process can produce
seams which alias badly when native antialiasing is turned on.
Abutting Objects - It's
very common when building web graphics or when skinning an application to build
bitmaps that are intended to appear seam-less when the graphics
are abutted next to each other. There are times when using vector objects
that this same technique would be useful. Unfortunately your seams will most
likely show if you turn on antialiasing.
The artifacts that appear tend to be splits in the graphics or odd looking
gradients (see examples in the image below).
Unexpected Aliasing
The native GDI+ antialiasing has trouble with small lines. In
the example below, notice how the lines for the whiskers and around the text
are oddly emphasized and aliased. This is not what the original artwork
intended. This kind of aliasing gets worse as the image is scaled smaller.
The Custom Antialiasing Algorithm
To produce a higher quality image than native GDI+ antialiasing, I use the
following algorithm.
- Construct an off-screen bitmap that is 2, 4 or 8 times larger that the
image I intend to output. It is important to use a power of 2 for the offscreen
bitmap.
- Draw the vector images scaled appropriately for the larger offscreen
bitmap.
- Use
Graphics.DrawImage
with InterpolationMode
set to
HighQualityBicubic
when stretch bliting the image to the smaller value.
The output using this algorithm is significantly better in most cases than the
native GDI+ antialiasing method, but with a significant penalty in drawing
time.
Bitmap offscreen = new Bitmap(bounds.Width*4, bounds.Height*4);
Graphics ofg = Graphics.FromImage(offscreen);
Matrix t = m.Clone();
t.Translate(-bounds.Left, -bounds.Top, MatrixOrder.Append);
t.Scale(4.0f, 4.0f, MatrixOrder.Append);
Paint(ofg, t);
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
g.DrawImage(offscreen, bounds, 0, 0, offscreen.Width, offscreen.Height,
GraphicsUnit.Pixel);
History
- Originally written on Dec 29th, 2004.
Acknowledgments
The example program associated with this article, uses GDI+
vector graphics code that was created from example files from Adobe
Illustrator CS (cheshire cat.ai and crystal.ai) and from Scott Ketterer
(aquabutton.ai). I think these examples illustrate very well the complex
graphics that are possible using GDI+ vector graphics and issues that can occur
when using them.