A couple of months ago I've written a handful of SetPixel methods that made it easier to use the WriteableBitmap, but they only provided a better interface for the Pixels Property and had no real functionality. This time I've written a more algorithmic method which performs a rasterization of a line: The famous DrawLine(). As the name implies is it used to draw a line between two points in the bitmap. To say it in advance: This is the way for drawing huge amounts of lines in Silverlight. I've used the elegant C# 3.0 extension methods again to add this functionality to the existing WriteableBitmap class.
The application includes various scenarios where line-drawing is performed and it is also possible to set the number of lines to control the work load. The Silverlight frame rate counter at the upper left side shows the current FPS in the left-most column. You can find some details about the other parameters in this excellent blog post by András Velvárt(@vbandi).
For comparison I've also added a randomized line drawing scenario using the UIElement Line.
How it works
I've implemented two common line-drawing algorithms: The well-known Bresenham algorithm that uses only cheap integer arithmetic and a Digital Differential Analyzer (DDA) which is based upon floating point arithmetic. I don't want to explain the algorithmic details that were already explained several times in the literature or on the web. The linked Wikipedia articles are a good starting point if you are interested.
The signature of the extension methods
DrawLine(this WriteableBitmap bmp, int x1, int y1, int x2, int y2, Color color); DrawLine(this WriteableBitmap bmp, int x1, int y1, int x2, int y2, int color); DrawLineBresenham(this WriteableBitmap bmp, int x1, int y1, int x2, int y2, int color); Clear(this WriteableBitmap bmp, Color color);The default DrawLine() method uses a DDA algorithm and is available for the Color structure and an integer value as line color. Furthermore it needs the x and y coordinate of the start point (x1, y1) and the end point (x2, y2) of the line.
I have also added a Clear() method that fills the whole WriteableBitmap with a Color.
// Initialize the WriteableBitmap with size 512x512 WriteableBitmap writeableBmp = new WriteableBitmap(512, 512); // Set it as source of an Image control ImageControl.Source = writeableBmp; // Fill the WriteableBitmap with white color writeableBmp.Clear(Colors.White); // Draw a black line from P1(10, 5) to P2(20, 40) writeableBmp.DrawLine(10, 5, 20, 40, Colors.Black); // Render it! writeableBmp.Invalidate();
The WriteableBitmap line-drawing approach is more than 20-30 times faster as UIElement Line. So if you need to draw many lines and don't need anti-aliasing or other UIELement properties, the DrawLine() extensions methods are the right choice.
One interesting fact: The Bresenham algorithm that uses only simple integer operations is not the fastest line-drawing algorithm anymore. It was one of the earliest computer graphics algorithms invented in the 1960s. Since then the hardware has changed dramatically and a simple floating point DDA technique gives almost the same results on modern hardware.
Please keep in mind that these results may differ depending on the used hardware.
You can download the sample application as a Visual Studio 2008 solution including the complete and documented ready-to-use WriteableBitmapExtensions class from here. Check out my Codeplex project WriteableBitmapEx for an up to date version of the extension methods.
Have fun and let me know it if you do some cool stuff with it.
To be continued...
I'm planning to write more shape extensions for the WriteableBitmap like DrawRectangle(), DrawEllipse(), DrawPolyline(), etc. I will publish them in follow-up blog posts.
Goto Drawing Shapes - Silverlight WriteableBitmap Extensions III