In my previous article I talked about how to save and image created
by and Effect. I’ve been doing more work on my own project and worked out how
to render a 2D drawing and export it.
The trick is to re-draw the image onto a bitmap.
If you create a render method like this one which draws a gradient:
private void
Render(DeviceContext context2D)
{
context2D.BeginDraw();
var size = context2D.PixelSize;
// Add brush fill
var stops = new
GradientStopCollection(context2D, new
GradientStop[] {
new GradientStop() { Color = Colors.Green, Position =
0 },
new GradientStop() { Color = Colors.Yellow, Position
= 1f }});
var brushProps = new
LinearGradientBrushProperties();
brushProps.StartPoint = new
DrawingPointF(size.Width / 2, 0);
brushProps.EndPoint = new
DrawingPointF(size.Width / 2, size.Height);
var brush = new
LinearGradientBrush(context2D, brushProps, stops);
context2D.FillRectangle(new RectangleF(0, 0, (float)size.Width,
(float)size.Height), brush);
context2D.EndDraw();
context2D.EndDraw();
}
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:
public async void Save()
{
// Get 3D device for creating 2D device
var device3D =
new
SharpDX.Direct3D11.Device(SharpDX.Direct3D.DriverType.Hardware,
SharpDX.Direct3D11.DeviceCreationFlags.BgraSupport);
// Get DXGI device
var dxgiDevice2 =
device3D.QueryInterface<SharpDX.DXGI.Device2>();
// Create new 2D
device
var device2D = new
Device(dxgiDevice2);
var context2D = new
DeviceContext(device2D, DeviceContextOptions.None);
// Create image
SharpDX.Direct2D1.PixelFormat
format = new
SharpDX.Direct2D1.PixelFormat(SharpDX.DXGI.Format.B8G8R8A8_UNorm,
AlphaMode.Premultiplied);
SharpDX.Direct2D1.BitmapProperties1
props = new BitmapProperties1(format,
Windows.Graphics.Display.DisplayProperties.LogicalDpi,
Windows.Graphics.Display.DisplayProperties.LogicalDpi,
BitmapOptions.Target | BitmapOptions.CannotDraw);
SharpDX.Direct2D1.Bitmap1
saveImage = new Bitmap1(context2D, this._deviceManager.ContextDirect2D.PixelSize,
props);
context2D.Target
= saveImage;
// Render
this.Render(context2D);
Now we have finally caught our drawing and we can export it
in the same way as the last article:
// Launch file picker
Windows.Storage.Pickers.FileSavePicker picker = new Windows.Storage.Pickers.FileSavePicker();
picker.FileTypeChoices.Add("Png",
new List<string>() { ".png"
});
var file = await picker.PickSaveFileAsync();
if (file == null)
return;
// Create imaging factory
var factory = new
ImagingFactory();
// Get stream
var fStream = await
file.OpenAsync(Windows.Storage.FileAccessMode.ReadWrite);
MemoryStream ms = new
MemoryStream(100000);
ms.Position = 0;
// Create a WIC outputstream
WICStream stream = new
WICStream(factory, ms);
var size = context2D.PixelSize;
// Initialize a Jpeg encoder with this
stream
var wicBitmapEncoder = new
SharpDX.WIC.PngBitmapEncoder(factory, BitmapEncoderGuids.Png);
wicBitmapEncoder.Initialize(stream);
// Create a Frame encoder
var wicFrameEncoder = new
BitmapFrameEncode(wicBitmapEncoder);
wicFrameEncoder.Initialize();
// Create image encoder
ImageEncoder wicImageEncoder;
SharpDX.WIC.ImagingFactory2 factory2 = new ImagingFactory2();
factory2.CreateImageEncoder(device2D, out wicImageEncoder);
var imgParams = new
ImageParameters();
imgParams.PixelFormat = format;
imgParams.PixelHeight = (int)size.Height;
imgParams.PixelWidth = (int)size.Width;
wicImageEncoder.WriteFrame(saveImage,
wicFrameEncoder, ref imgParams);
// Commit changes
wicFrameEncoder.Commit();
wicBitmapEncoder.Commit();
byte[] buffer = new byte[ms.Length];
ms.Position = 0;
await ms.ReadAsync(buffer, 0, (int)ms.Length);
var opStream = fStream.AsStreamForWrite();
await opStream.WriteAsync(buffer, 0,
buffer.Length);
await opStream.FlushAsync();
// Dispose
wicFrameEncoder.Dispose();
wicBitmapEncoder.Dispose();
stream.Dispose();
ms.Dispose();
opStream.Dispose();
factory.Dispose();
Well, I have a few more issues of my own to solve, but this
is all the tough stuff done!
How can I render text inside of an image using SharpDX?? I want to render a final picture like a meme, two text boxes, one at the bottom and one at the top. Thanks
ReplyDeleteTake a look at the SharpDX DirectWrite samples
ReplyDeletePlease let us know the sharpdx version and the headers you included... in SharpDX things like "Device" are defined in numerous places... I can't make your code work!
ReplyDeleteEven better, post the full source =) ... thanks for this article anyhow.
V2.4.2
ReplyDeleteUsings:
using SharpDX;
using SharpDX.Direct2D1;
using SharpDX.DirectWrite;
using SharpDX.WIC;