Drawing Bitmaps – DrawingImage and DrawingVisual
Written by Administrator   
Wednesday, 20 January 2010
Article Index
Drawing Bitmaps – DrawingImage and DrawingVisual
DrawingContext

Banner

DrawingContext – even lighter vectors

The GeometryDrawing classes are lightweight compared to the Shape classes but they are still full classes. The ultimate in lightweight vector drawing is provided by the DrawingContext that some Drawing classes provide. This approach to graphics will be familiar to any programmer "brought up" on the original Windows API and even the name sounds similar to the original DeviceContext or DC.

In this case however the drawing provided by the DrawingContext isn't immediate but part of the DirectX provided retained mode graphics that makes WPF different. That is when you draw using a DrawingContext you aren't drawing to the screen – nothing is being rendered. It's not until you have created the list of drawing instructions and actually render them that any drawing is actually performed.

To get a DrawingContext you need an object that can accept drawing commands. In this case the only suitable class is DrawingGroup and to get a DrawingContext you use its Open method. This clears anything that might have already been written to the DrawingGroup and returns a Drawing Context:

 DrawingContext MyDC = 
MyDrawingGroup.Open();

The DrawingContext has a range of drawing methods that can be use to add drawing commands. For example:

 MyDC.DrawLine(
new Pen(Brushes.Yellow,1),
new Point(34,67),
new Point(120, 0));

Before you render the DrawingGroup you need to close the DrawingContext:

 MyDC.Close();

After this you can display the bitmap, i.e. a single yellow line, in the usual way:

 DrawingImage MyDrawingImage = 
new DrawingImage(MyDrawingGroup);
image1.Source = MyDrawingImage;

It is important to notice that a drawing context has a DrawDrawing method which allows you to draw any existing vector graphic Drawing object directly. For example:

 MyDC.DrawDrawing(MyDrawingGroup);

will draw the DrawingGroup consisting of two lines as created earlier.

Using DrawDrawing you can have the best of both worlds – class based vector drawing and drawing methods.

Vector to WritableBitmap

The big problem with DrawingImage is that it descends directly from ImageSource which doesn't have the methods that you need to actually work with a bitmap at the pixel level. WriteableBitmap and RenderTargetBitmap do have everything you could need but as these are descended from BitmapSource you can't simply convert a DrawingImage into either class as they are not on the same branch of the class hierarchy.

There are a number of complicated juggling acts that can be performed to get a DrawingImage into either a RenderTargetBitmap or a WriteableBitmap. Fortunately it's quite easy when you know how.

The solution to the problem is the DrawingVisual class. This will render a drawing or any vector graphics you may want to create to a class that inherits from Visual – and anything that inherits from Visual can be rendered to a bitmap by RenderTargetBitmap. RenderTargetBitmap is more useful to us on two counts. The first is that it has a CopyPixel method which can be used to get at the pixel data. The second is that it is descended from BitmapSource and so can be used to create a WritableBitmap which in turn has methods that allow pixel manipulation.

For example, suppose you want to render MyDrawingGroup consisting of two lines as created earlier. All you have to do is first create a DrawingVisual:

 DrawingVisual MyDrawingVisual = 
new DrawingVisual();

Open its drawing context:

 DrawingContext MyDC = 
MyDrawingVisual.RenderOpen();

At this point you can use the drawing context's drawing methods to draw lines, ellipses and so on. You can also use its DrawDrawing method to draw any existing Drawing object. For example:

 MyDC.DrawDrawing(MyDrawingGroup);
MyDC.Close();

This draws the two lines in the DrawingGroup created earlier. When you are finished with the drawing context you have to close it as usual. Next you can complete the task by rendering the DrawingVisual to a RenderTargetBitmap:

 RenderTargetBitmap 
MyRenderTargetBitmap =
new RenderTargetBitmap(
100,100,96,96,
PixelFormats.Default);
MyRenderTargetBitmap.Render(
MyDrawingVisual);

Now that you have a RenderTargetBitmap you can create a WriteableBitmap from it and start using it:

 WriteableBitmap MyWbmap = 
new WriteableBitmap(MyDrawingImage);
image1.Source = MyWbmap;

Once you have a WriteableBitmap bit map you should be able to do anything you want to.

Banner


Custom Bitmap Effects - Getting started

The simplest possible custom effects project is enough for you to see how it all works and to move on to building your own effects that do something useful. This is an introduction to using HLSL in WP [ ... ]



RenderTargetBitmap - Visual vector to bitmap

RenderTargetBitmap will convert any Visual to a bitmap but sometimes it isn't quite as straighforward as just calling Render().



Custom Shape

Creating a custom Shape isn't difficult but it does have some hidden gotchas. We take a look at how best to do the job.



Custom BitmapSource

Even if you don't anticipate implementing your own custom BitmapSource finding out how to reveals quite a lot about the way that WPF bitmaps work.



Using the WPF .NET 4.0 DataGrid

WPF DataGrid (.NET 4)  can be difficult to understand if you aren't used to thinking about objects and collections. This easy to follow introduction explains where the rows and columns have gone. [ ... ]


Other Articles

<ASIN:0672330334>

<ASIN:0321374479>

<ASIN:0672328917>



Last Updated ( Friday, 19 March 2010 )