Bitmap の操作 > Direct2D エフェクトの適用 |
Direct2D は、Microsoft によって設計された 2D グラフィック API で、画像を操作するための広範な組み込みおよびカスタムのエフェクトが提供されています。この API を使用すると、ビットマップ、2D ジオメトリ、テキストの高品質で高速なレンダリングが可能です。
Bitmap では、Direct2D のエフェクトを使用したり、画像にエフェクトを適用することができます。Bitmap を使用して適用できる画像エフェクトを次に一覧します。
これらのエフェクトから 1 つを選んで画像に適用してみましょう。次の図は、Bitmap で Direct2D を使用する例として、組み込み 2D エフェクトの 1 つ、シャドウを示しています。
コードで、Bitmap が Direct2D ビットマップに変換されます。次に Direct2D を使用して画像を操作し、Direct3D API との相互運用によって組み込みエフェクト、シャドウが適用されます。 すべての操作が完了したら、画像が Direct2D ビットマップから C1Bitmap にロードし直されます。
画像にシャドウエフェクトを適用するには、C1.Util.DX.Direct2D.Effects 名前空間のメンバクラスである Shadow、AffineTransform2D、 Composite のプロパティを使用します。
以下の手順は、2D シャドウエフェクトを画像に適用する方法を示します。この例では、「クイックスタート」で作成したサンプルを使用します。
Imports D2D = C1.Util.DX.Direct2D Imports D3D = C1.Util.DX.Direct3D11 Imports DW = C1.Util.DX.DirectWrite Imports DXGI = C1.Util.DX.DXGI Imports C1.Util.DX
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;
Private bitmap As C1Bitmap ' 装置独立リソース Private d2dFactory As D2D.Factory2 Private dwFactory As DW.Factory ' 装置リソース Private dxgiDevice As DXGI.Device Private d2dContext As D2D.DeviceContext1 ' Direct2Dの組み込み効果 Private shadow As D2D.Effects.Shadow Private affineTransform As D2D.Effects.AffineTransform2D Private composite As D2D.Effects.Composite
C1Bitmap bitmap; // 装置独立リソース D2D.Factory2 d2dFactory; DW.Factory dwFactory; // 装置リソース DXGI.Device dxgiDevice; D2D.DeviceContext1 d2dContext; // Direct2Dの組み込み効果 D2D.Effects.Shadow shadow; D2D.Effects.AffineTransform2D affineTransform; D2D.Effects.Composite composite;
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 }
' Direct2DおよびDirectWriteファクトリを作成します d2dFactory = D2D.Factory2.Create(D2D.FactoryType.SingleThreaded) dwFactory = DW.Factory.Create(DW.FactoryType.[Shared]) ' GPUリソースを作成します CreateDeviceResources()
// Direct2DおよびDirectWriteファクトリを作成します d2dFactory = D2D.Factory2.Create(D2D.FactoryType.SingleThreaded); dwFactory = DW.Factory.Create(DW.FactoryType.Shared); // GPUリソースを作成します CreateDeviceResources();
Private Sub Button_Click(sender As Object, e As RoutedEventArgs) UpdateImageSource(ImageEffect.Shadow) End Sub Private Sub CreateDeviceResources() 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 ' ハードウェアが利用できない場合はWARPを使用します 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 <> CInt(&H887A0004UI) Then ' DXGI_ERROR_UNSUPPORTED Exit For End If Next result.CheckError() d3dContext.Dispose() ' DXGI装置を格納します(アプリケーションが中断されているときにトリミングするため) dxgiDevice = d3dDevice.QueryInterface(Of DXGI.Device)() d3dDevice.Dispose() ' RenderTargetを作成します(Direct2D描画用のDeviceContext) 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 ' 組み込みの効果を作成します shadow = D2D.Effects.Shadow.Create(rt) affineTransform = D2D.Effects.AffineTransform2D.Create(rt) composite = D2D.Effects.Composite.Create(rt) 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 ' レンダー対象オブジェクト Dim rt = d2dContext ' 対象Direct2Dビットマップを作成します 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) ' 対象ビットマップをレンダー対象に関連付けます rt.SetTarget(targetBmp) ' 描画を開始します rt.BeginDraw() ' 対象ビットマップをクリアします rt.Clear(Nothing) ' C1Bitmap画像をDirect2D画像に変換します Dim d2dBitmap = bitmap.ToD2DBitmap1(rt, D2D.BitmapOptions.None) 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() If Not rt.EndDraw(True) Then targetBmp.Dispose() ' 旧GPU装置が削除された場合、装置リソースを再作成してみてください DiscardDeviceResources() CreateDeviceResources() Return End If ' 対象ビットマップをデタッチします rt.SetTarget(Nothing) ' 一時的なC1Bitmapオブジェクトを作成します Dim outBitmap = New C1Bitmap(bitmap.ImagingFactory) ' Direct2D対象ビットマップからC1Bitmapに画像をインポートします outBitmap.Import(targetBmp, rt, New RectL(w, h)) targetBmp.Dispose() ' C1BitmapをWriteableBitmapに変換し、イメージソースとして使用します image.Source = outBitmap.ToWriteableBitmap() outBitmap.Dispose() End Sub Private Sub DiscardDeviceResources() shadow.Dispose() affineTransform.Dispose() composite.Dispose() dxgiDevice.Dispose() d2dContext.Dispose() 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 Button_Click(object sender, RoutedEventArgs e) { UpdateImageSource(ImageEffect.Shadow); } private void CreateDeviceResources() { 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++) { // ハードウェアが利用できない場合はWARPを使用します 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(); // DXGI装置を格納します(アプリケーションが中断されているときにトリミングするため) dxgiDevice = d3dDevice.QueryInterface<DXGI.Device>(); d3dDevice.Dispose(); // RenderTargetを作成します(Direct2D描画用のDeviceContext) 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; // 組み込みの効果を作成します shadow = D2D.Effects.Shadow.Create(rt); affineTransform = D2D.Effects.AffineTransform2D.Create(rt); composite = D2D.Effects.Composite.Create(rt); } void UpdateImageSource(ImageEffect imageEffect) { // ソース画像の範囲外のピクセルを変更する可能性のある交換があるため、 // これらのピクセルを表示するためのマージンが必要です var targetOffset = new Point2F(marginLT, marginLT); int w = bitmap.PixelWidth + marginLT + marginRB; int h = bitmap.PixelHeight + marginLT + marginRB; // レンダー対象オブジェクト var rt = d2dContext; // 対象Direct2Dビットマップを作成します 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); // 対象ビットマップをレンダー対象に関連付けます rt.SetTarget(targetBmp); // 描画を開始します rt.BeginDraw(); // 対象ビットマップをクリアします rt.Clear(null); // C1Bitmap画像をDirect2D画像に変換します var d2dBitmap = bitmap.ToD2DBitmap1(rt, D2D.BitmapOptions.None); switch (imageEffect) { case ImageEffect.Original: rt.DrawImage(d2dBitmap, targetOffset); break; case ImageEffect.Shadow: rt.DrawImage(ApplyShadow(d2dBitmap), targetOffset); break; } d2dBitmap.Dispose(); if (!rt.EndDraw(true)) { targetBmp.Dispose(); // 旧GPU装置が削除された場合、装置リソースを再作成してみてください DiscardDeviceResources(); CreateDeviceResources(); return; } // 対象ビットマップをデタッチします rt.SetTarget(null); // 一時的なC1Bitmapオブジェクトを作成します var outBitmap = new C1Bitmap(bitmap.ImagingFactory); // Direct2D対象ビットマップからC1Bitmapに画像をインポートします outBitmap.Import(targetBmp, rt, new RectL(w, h)); targetBmp.Dispose(); // C1BitmapをWriteableBitmapに変換し、イメージソースとして使用します image.Source = outBitmap.ToWriteableBitmap(); outBitmap.Dispose(); } private void DiscardDeviceResources() { shadow.Dispose(); affineTransform.Dispose(); composite.Dispose(); dxgiDevice.Dispose(); d2dContext.Dispose(); } 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; }