Applying Direct2D Effects
In This Topic
Direct2D is a two-dimensional graphics API designed by Microsoft that offers a range of built-in and custom effects for manipulating images. The API provides high quality and fast rendering for bitmaps, 2D geometries, and text.
Bitmap allows you to use the Direct2D effects and apply them on images. Following is a list of image effects that can be applied to an image using Bitmap:
- Gaussian Blur
- Sharpen
- Horizontal Smear
- Shadow
- Displacement Map
- Emboss
- Edge Detect
- Sepia
Let us take one of these effects and apply it on an image. The following image shows one of the built-in 2D effects, shadow, presenting the use of Direct2D in Bitmap.

In terms of implementation, Bitmap is first converted to a Direct2D bitmap. Direct2D is then used to manipulate the image by applying the built-in shadow effect using interoperation with Direct3D API. After all the manipulations, the image is loaded back from Direct2D bitmap to C1Bitmap.
To apply shadow effect on an image, you can use the properties of Shadow, AffineTransform2D, and Composite classes, members of C1.Util.DX.Direct2D.Effects namespace.
The following steps illustrate applying the 2D shadow effect on an image. This example uses the sample created in the Quick Start.
- Add relevant namespaces.
Imports C1.Win.Bitmap
Imports D2D = C1.Util.DX.Direct2D
Imports D3D = C1.Util.DX.Direct3D11
Imports DW = C1.Util.DX.DirectWrite
Imports DXGI = C1.Util.DX.DXGI
using C1.Win.Bitmap;
using D2D = C1.Util.DX.Direct2D;
using D3D = C1.Util.DX.Direct3D11;
using DW = C1.Util.DX.DirectWrite;
using DXGI = C1.Util.DX.DXGI;
using C1.Util.DX;
- Create various class objects.
Private bitmap As C1Bitmap
Private lastGdiBitmap As Bitmap
' device-independent resources
Private d2dFactory As D2D.Factory2
Private dwFactory As DW.Factory
' device resources
Private dxgiDevice As DXGI.Device
Private d2dContext As D2D.DeviceContext1
' Direct2D built-in effects
Private shadow As D2D.Effects.Shadow
Private affineTransform As D2D.Effects.AffineTransform2D
Private composite As D2D.Effects.Composite
C1Bitmap bitmap;
Bitmap lastGdiBitmap;
// device-independent resources
D2D.Factory2 d2dFactory;
DW.Factory dwFactory;
// device resources
DXGI.Device dxgiDevice;
D2D.DeviceContext1 d2dContext;
// Direct2D built-in effects
D2D.Effects.Shadow shadow;
D2D.Effects.AffineTransform2D affineTransform;
D2D.Effects.Composite composite ;
- Declare constant integers and enumeration.
Const marginLT As Integer = 20
Const marginRB As Integer = 36
Public Enum ImageEffect
Original
Shadow
End Enum
const int marginLT = 20;
const int marginRB = 36;
public enum ImageEffect
{
Original,
Shadow
}
- Load the image in C1Bitmap using stream. For details, see Quick start.
- Add code to create resources, image source, and associate the image source with the image.
' create Direct2D and DirectWrite factories
d2dFactory = D2D.Factory2.Create(D2D.FactoryType.SingleThreaded)
dwFactory = DW.Factory.Create(DW.FactoryType.[Shared])
' create GPU resources
CreateDeviceResources()
// create Direct2D and DirectWrite factories
d2dFactory = D2D.Factory2.Create(D2D.FactoryType.SingleThreaded);
dwFactory = DW.Factory.Create(DW.FactoryType.Shared);
// create GPU resources
CreateDeviceResources();
- Add code to apply 2D shadow effect.
Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
UpdateImageSource(ImageEffect.Shadow)
End Sub
Private Sub CreateDeviceResources()
' create the Direct3D device
Dim actualLevel As D3D.FeatureLevel
Dim d3dContext As D3D.DeviceContext = Nothing
Dim d3dDevice = New D3D.Device(IntPtr.Zero)
Dim result = HResult.Ok
For i As Integer = 0 To 1
' use WARP if hardware is not available
Dim dt = If(i = 0, D3D.DriverType.Hardware, D3D.DriverType.Warp)
result = D3D.D3D11.CreateDevice(Nothing, dt, IntPtr.Zero,
D3D.DeviceCreationFlags.BgraSupport Or
D3D.DeviceCreationFlags.SingleThreaded,
Nothing, 0, D3D.D3D11.SdkVersion, d3dDevice,
actualLevel, d3dContext)
If result.Code <> &H887A0004 Then
' DXGI_ERROR_UNSUPPORTED
Exit For
End If
Next
result.CheckError()
d3dContext.Dispose()
' store the DXGI device (for trimming when the application is being suspended)
dxgiDevice = d3dDevice.QueryInterface(Of DXGI.Device)()
d3dDevice.Dispose()
' create a RenderTarget (DeviceContext for Direct2D drawing)
Dim d2dDevice = D2D.Device1.Create(d2dFactory, dxgiDevice)
Dim rt = D2D.DeviceContext1.Create(d2dDevice, D2D.DeviceContextOptions.None)
d2dDevice.Dispose()
rt.SetUnitMode(D2D.UnitMode.Pixels)
d2dContext = rt
' create built-in effects
shadow = D2D.Effects.Shadow.Create(rt)
affineTransform = D2D.Effects.AffineTransform2D.Create(rt)
composite = D2D.Effects.Composite.Create(rt)
End Sub
Private Sub DiscardDeviceResources()
shadow.Dispose()
affineTransform.Dispose()
composite.Dispose()
dxgiDevice.Dispose()
d2dContext.Dispose()
End Sub
Private Sub ClearGdiBitmap()
If lastGdiBitmap IsNot Nothing Then
PictureBox1.Image = Nothing
lastGdiBitmap.Dispose()
lastGdiBitmap = Nothing
End If
End Sub
Private Sub UpdateImageSource(imageEffect_1 As ImageEffect)
Dim targetOffset = New Point2F(marginLT, marginLT)
Dim w As Integer = bitmap.PixelWidth + marginLT + marginRB
Dim h As Integer = bitmap.PixelHeight + marginLT + marginRB
' the render target object
Dim rt = d2dContext
' create the target Direct2D bitmap
Dim bpTarget = New D2D.BitmapProperties1 _
(New D2D.PixelFormat(DXGI.Format.B8G8R8A8_UNorm, D2D.AlphaMode.Premultiplied),
CSng(bitmap.DpiX), CSng(bitmap.DpiY),
D2D.BitmapOptions.Target Or D2D.BitmapOptions.CannotDraw)
Dim targetBmp = D2D.Bitmap1.Create(rt, New Size2L(w, h), bpTarget)
' associate the target bitmap with render target
rt.SetTarget(targetBmp)
' start drawing
rt.BeginDraw()
' clear the target bitmap
rt.Clear(Nothing)
' convert C1Bitmap image to Direct2D image
Dim d2dBitmap = bitmap.ToD2DBitmap1(rt, D2D.BitmapOptions.None)
'apply the effect
Select Case imageEffect_1
Case ImageEffect.Original
rt.DrawImage(d2dBitmap, targetOffset)
Exit Select
Case ImageEffect.Shadow
rt.DrawImage(ApplyShadow(d2dBitmap), targetOffset)
Exit Select
End Select
d2dBitmap.Dispose()
' finish drawing (all drawing commands are executed at that moment)
rt.EndDraw()
' detach and actually dispose the target bitmap
rt.SetTarget(Nothing)
' create a temporary C1Bitmap object
Dim outBitmap = New C1Bitmap(bitmap.ImagingFactory)
' import the image from Direct2D target bitmap to C1Bitmap
outBitmap.Import(targetBmp, rt, New RectL(w, h))
targetBmp.Dispose()
' convert C1Bitmap to a System.Drawing.Bitmap
ClearGdiBitmap()
lastGdiBitmap = outBitmap.ToGdiBitmap()
outBitmap.Dispose()
' show the result in the PictureBox
PictureBox1.Image = lastGdiBitmap
End Sub
Private Function ApplyShadow(bitmap As D2D.Bitmap1) As D2D.Effect
shadow.SetInput(0, bitmap)
shadow.BlurStandardDeviation = 5.0F
affineTransform.SetInputEffect(0, shadow)
affineTransform.TransformMatrix = Matrix3x2.Translation(20.0F, 20.0F)
composite.SetInputEffect(0, affineTransform)
composite.SetInput(1, bitmap)
Return composite
End Function
private void button2_Click(object sender, EventArgs e)
{
UpdateImageSource(ImageEffect.Shadow);
}
void CreateDeviceResources()
{
// create the Direct3D device
D3D.FeatureLevel actualLevel;
D3D.DeviceContext d3dContext = null;
var d3dDevice = new D3D.Device(IntPtr.Zero);
var result = HResult.Ok;
for (int i = 0; i <= 1; i++)
{
// use WARP if hardware is not available
var dt = i == 0 ? D3D.DriverType.Hardware : D3D.DriverType.Warp;
result = D3D.D3D11.CreateDevice
(null, dt, IntPtr.Zero,
D3D.DeviceCreationFlags.BgraSupport | D3D.DeviceCreationFlags.SingleThreaded,
null, 0, D3D.D3D11.SdkVersion, d3dDevice, out actualLevel, out d3dContext);
if (result.Code != unchecked((int)0x887A0004)) // DXGI_ERROR_UNSUPPORTED
{
break;
}
}
result.CheckError();
d3dContext.Dispose();
// store the DXGI device (for trimming when the application is being suspended)
dxgiDevice = d3dDevice.QueryInterface<DXGI.Device>();
d3dDevice.Dispose();
// create a RenderTarget (DeviceContext for Direct2D drawing)
var d2dDevice = D2D.Device1.Create(d2dFactory, dxgiDevice);
var rt = D2D.DeviceContext1.Create(d2dDevice, D2D.DeviceContextOptions.None);
d2dDevice.Dispose();
rt.SetUnitMode(D2D.UnitMode.Pixels);
d2dContext = rt;
// create built-in effects
shadow = D2D.Effects.Shadow.Create(rt);
affineTransform = D2D.Effects.AffineTransform2D.Create(rt);
composite = D2D.Effects.Composite.Create(rt);
}
void DiscardDeviceResources()
{
shadow.Dispose();
affineTransform.Dispose();
composite.Dispose();
dxgiDevice.Dispose();
d2dContext.Dispose();
}
void ClearGdiBitmap()
{
if (lastGdiBitmap != null)
{
pictureBox1.Image = null;
lastGdiBitmap.Dispose();
lastGdiBitmap = null;
}
}
void UpdateImageSource(ImageEffect imageEffect)
{
var targetOffset = new Point2F(marginLT, marginLT);
int w = bitmap.PixelWidth + marginLT + marginRB;
int h = bitmap.PixelHeight + marginLT + marginRB;
// the render target object
var rt = d2dContext;
// create the target Direct2D bitmap
var bpTarget = new D2D.BitmapProperties1(
new D2D.PixelFormat(DXGI.Format.B8G8R8A8_UNorm, D2D.AlphaMode.Premultiplied),
(float)bitmap.DpiX,
(float)bitmap.DpiY, D2D.BitmapOptions.Target | D2D.BitmapOptions.CannotDraw);
var targetBmp = D2D.Bitmap1.Create(rt, new Size2L(w, h), bpTarget);
// associate the target bitmap with render target
rt.SetTarget(targetBmp);
// start drawing
rt.BeginDraw();
// clear the target bitmap
rt.Clear(null);
// convert C1Bitmap image to Direct2D image
var d2dBitmap = bitmap.ToD2DBitmap1(rt, D2D.BitmapOptions.None);
//apply the effect
switch (imageEffect)
{
case ImageEffect.Original:
rt.DrawImage(d2dBitmap, targetOffset);
break;
case ImageEffect.Shadow:
rt.DrawImage(ApplyShadow(d2dBitmap), targetOffset);
break;
}
d2dBitmap.Dispose();
// finish drawing (all drawing commands are executed at that moment)
rt.EndDraw();
// detach and actually dispose the target bitmap
rt.SetTarget(null);
// create a temporary C1Bitmap object
var outBitmap = new C1Bitmap(bitmap.ImagingFactory);
// import the image from Direct2D target bitmap to C1Bitmap
outBitmap.Import(targetBmp, rt, new RectL(w, h));
targetBmp.Dispose();
// convert C1Bitmap to a System.Drawing.Bitmap
ClearGdiBitmap();
lastGdiBitmap = outBitmap.ToGdiBitmap();
outBitmap.Dispose();
// show the result in the PictureBox
pictureBox1.Image = lastGdiBitmap;
}
D2D.Effect ApplyShadow(D2D.Bitmap1 bitmap)
{
shadow.SetInput(0, bitmap);
shadow.BlurStandardDeviation = 5f;
affineTransform.SetInputEffect(0, shadow);
affineTransform.TransformMatrix = Matrix3x2.Translation(20f, 20f);
composite.SetInputEffect(0, affineTransform);
composite.SetInput(1, bitmap);
return composite;
}