It can be used by the
SurfaceImageSource’s render event and then reused for the export. To do the
save, a clean 2D Device and DeviceContext needs creating from the default 3D
device, then an image is created and the drawing rendered onto it:

Wednesday, 12 September 2012

I’m working on
a Windows 8 app which has a drawing element to it. The original WP7 app in
Silverlight was fine because a simple drawing rendered in XAML was captured
using WritableBitmap.Render and written to a file stream. This feature is
missing from the Windows 8 API, so it’s impossible to write a pure C#/XAML app
which can export a user created image. To get round this it’s possible to use
DirectX/XAML/C++ to create a XAML UI which can draw DirectX images.

DirectX/XAML/C++
offers a number of XAML containers which interface with DirectX and have
different behaviours:

I wanted to use a SurfaceImageSource, so I could have my DirectX image in line with
other XAML controls and containers.

The big problem
is that I don’t want to write a whole app in C++, it would take me a lot longer
than C# and it seemed like a sledge hammer to crack a nut using full
C++/DirectX for a simple application.

So after much research
and stress about what to do, I found SharpDX and thought all my prayers had
been answered! SharpDX is a full DirectX to C# interop library which allows
DirectX to be brought into C#/XAML apps in the same way as C++/XAML apps.

The major
problem was how to save the image you’ve drawn out of the DirectX image? There
are a small number of examples of how to do it in C++, so after a lot of cross referencing
the SharpDX source and tips from Alexandre Mutel on interfacing with a
WICStream, I managed to get it working.

This save
method was tested inside the EffectRenderer in the SharpDX lighting effect
sample. This is the whole code so you don’t need to paste it back together in
sections:

The first section gets a file stream from the user to write
the data to once it’s been extracted from the image, then creates an
intermediary MemoryStream for the WICStream to interface with (Alexandre pointed out that
the Win8 RandomAccessStream will not interface with a WICStream since it needs
to perform seek operations) and finally the WICStream itself which WIC will use
to write the image to.

The
second section creates a Bitmap Encoder, Frame Encoder and Image Encoder and
writes the image frame into the stream.

The
final section and the bit which caused me a lot of problems, is getting the
data from the stream. The encoders all need committing in order, but in many
C++ examples the WICStream is also committed which should flush the stream to
it’s destination, however it was throwing an exception:

An exception of type 'SharpDX.SharpDXException'
occurred in SharpDX.DLL but was not handled in user code

If there is a handler for this exception, the
program may be safely continued.

This isn’t particularly helpful, but I was advised that the WIC
stream doesn’t need flushing as the underlying stream should take care of this.
At this point I could see the memory stream had a size, but when I wrote it to
a buffer it was coming out all zeros. This was a simple mistake – the memory stream
just needs setting back to the start and it all started magically working!

All I need to do now is work out how to use DirectX to draw
my picture! I hope this helps some other people as it’s been causing me a
massive headache for a number of days!