This article is about the anti-alias drawing support under GDI using C++. It refers to MFC or non-MFC applications. Here, a small class called
CTGraphics is presented. It has anti-alias support for drawing basic primitives: lines, arcs, ellipses (circles), round rectangles, polylines, and pies. You can define other interesting shapes using this basic primitives.
What is the "aliasing" effect? It is the effect of jagged-edges (or stairs in other words) that appear when you draw some graphic shapes using the basic Windows GDI. See the image below:
So what is the problem with this? Well, if you want your computer generated graphics (or images) to look nice, this is not a good way to do it. How does this happen then? It is because of the limited screen resolution, that is a limited number of pixels, horizontal or vertical, that can be drawn on the screen. Their size is so small that you can't see them, so that is why this will happen when you want to draw a line using the
LineTo() methods of the Windows GDI.
What to do then? Now, this is a place where a technique called "anti-aliasing" is coming at the scene. It must do something to blur those edges so different approaches were taken for this action. One is called a super-sampling of the original image. It renders an image at high frequency (scaled original image 2x or more), and then it performs low-pass filtering of that super-sampled image so the edges will become less sharp, and when you scale this image down again (to the original size), you will have an anti-aliasing effect in action. This is a very memory consuming method but it will work.
Another method (implemented here) is the so called pre-filtering of the original image. It averages the amount of pixels that is covered with the primitive equation. The ideal line will not cover the whole pixel but a part of it, so this method sets the intensity of that pixel to some value other than the maximum for the line that you are drawing. So while you draw your line, you set the line pixels to some value. This method is less memory consuming than the previous one but it takes a lot of math to implement it to work correctly, so you can see where the compromise is.
Whichever way you do anti-aliasing, you will get an output similar to the following:
So, you have modified the original line pixels so that now line edges are a bit smoothed. The
CTGraphics class does its work in a similar manner. It supports anti-aliasing for the following:
- Round Rectangles
- Bezier Splines
However, you are free to extend its functionality on other shapes and graphic primitives. You can combine basic shapes and get more complex shapes (this is how the Round Rectangle is done: by combining Lines and Arcs).
Using the code
To use the source provided, just include the TGraphics.h and TGraphics.cpp files in your MS Visual C++ Project. Using the described class is very simple, see below:
// hDC is obtained somewhere else
// Variables x1, y1, x2 and y2 are defined somewhere else
COLORREF color = RGB(255, 0, 0); // Pick some nice line color
// You have everything, now draw anti-aliased line
tGraphics.DrawLine(hDC, x1, y1, x2, y2, color);
It is very simple, isn't it? Other methods of the
CTGraphics class work very similar so I will not explain each of them.
Here is presented a small C++ class which performs anti-aliased drawing using Windows GDI and C++. However, no speed records were a goal here, so don't expect the demo to run the fastest it can. This is just the demo of the functionality that was required to have smooth edges while drawing lines and arcs, at the first place. Also, just 1px width of the "drawing pen" is supported. This may sound not perfect, but this was only done in order to finish the job, not to make it harder than it already is.
Points of interest
I was looking for this subject all over the Internet and CodeProject and found different solutions, more or less similar. I wanted to extend the basic line anti-aliasing algorithms (like Wu's algorithm present on the CodeProject) to arcs and other shapes. I don't say this is the best result you can achieve, but it finished the job for me very quickly. You also may find that, due to float numbers involved in the calculations, the output is not perfect, but I leave this as an exercise for you. As an example of different approaches, you may find in the source of the
CTGraphics class that ellipse is not done using an arc of 360 degrees, although it could be. Instead I used a similar and a bit modified math equation.
CTGraphics class version 1.01.
In this release, the support for the following were added:
- Bezier Splines