|Drawing Bitmaps – DrawingImage and DrawingVisual|
|Wednesday, 20 January 2010|
Page 2 of 2
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 =
The DrawingContext has a range of drawing methods that can be use to add drawing commands. For example:
Before you render the DrawingGroup you need to close the DrawingContext:
After this you can display the bitmap, i.e. a single yellow line, in the usual way:
DrawingImage 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:
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 =
Open its drawing context:
DrawingContext MyDC =
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:
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:
Now that you have a RenderTargetBitmap you can create a WriteableBitmap from it and start using it:
WriteableBitmap MyWbmap =
Once you have a WriteableBitmap bit map you should be able to do anything you want to.
|Last Updated ( Friday, 19 March 2010 )|