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 DXGI = C1.Util.DX.DXGI Imports DW = C1.Util.DX.DirectWrite Imports C1.Util.DX
using D2D = C1.Util.DX.Direct2D; using D3D = C1.Util.DX.Direct3D11; using DXGI = C1.Util.DX.DXGI; using DW = C1.Util.DX.DirectWrite; using C1.Util.DX;
Private imgSource As SurfaceImageSource Private sisNative As DXGI.ISurfaceImageSourceNative Private btmp As C1Bitmap ' 装置独立リソース Private d2dF As D2D.Factory2 Private dwF As DW.Factory ' 装置リソース Private dxgiD As DXGI.Device Private d2dC As D2D.DeviceContext1 ' Direct2Dの組み込み効果 Private shadow As D2D.Effects.Shadow Private affineT As D2D.Effects.AffineTransform2D Private compst As D2D.Effects.Composite
SurfaceImageSource imgSource; DXGI.ISurfaceImageSourceNative sisNative; C1Bitmap btmp; // 装置独立リソース D2D.Factory2 d2dF; DW.Factory dwF; // 装置リソース DXGI.Device dxgiD; D2D.DeviceContext1 d2dC; // Direct2Dの組み込み効果 D2D.Effects.Shadow shadow; D2D.Effects.AffineTransform2D affineT; D2D.Effects.Composite compst;
Const marginLT As Integer = 20 Const marginRB As Integer = 36 Private Enum ImageEffect Original Shadow End Enum
const int marginLT = 20; const int marginRB = 36; enum ImageEffect { Original, Shadow }
' Direct2DおよびDirectWriteファクトリを作成します d2dF = D2D.Factory2.Create(D2D.FactoryType.SingleThreaded) dwF = DW.Factory.Create(DW.FactoryType.[Shared]) ' GPUリソースを作成します CreateDeviceResources() ' イメージソースを作成します imgSource = New SurfaceImageSource(marginLT + btmp.PixelWidth + marginRB, marginLT + btmp.PixelHeight + marginRB, False) ' イメージソースのネイティブインタフェースを取得します sisNative = ComObject.QueryInterface _ (Of DXGI.ISurfaceImageSourceNative)(imgSource) sisNative.SetDevice(dxgiD) ' SurfaceImageSourceに画像を描画します UpdateImageSource(ImageEffect.Original) ' イメージソースをイメージに関連付けます img.Source = imgSource
// Direct2DおよびDirectWriteファクトリを作成します d2dF = D2D.Factory2.Create(D2D.FactoryType.SingleThreaded); dwF = DW.Factory.Create(DW.FactoryType.Shared); // GPUリソースを作成します CreateDeviceResources(); Unloaded += MainPage_Unloaded; // イメージソースを作成します imgSource = new SurfaceImageSource(marginLT + btmp.PixelWidth + marginRB, marginLT + btmp.PixelHeight + marginRB, false); // イメージソースのネイティブインタフェースを取得します sisNative = ComObject.QueryInterface<DXGI.ISurfaceImageSourceNative>(imgSource); sisNative.SetDevice(dxgiD); // SurfaceImageSourceに画像を描画します UpdateImageSource(ImageEffect.Original); // イメージソースをイメージに関連付けます img.Source = imgSource;
Private Sub btnShadow_Click(sender As Object, e As RoutedEventArgs) _ Handles btnShadow.Click UpdateImageSource(ImageEffect.Shadow) End Sub Private Sub CreateDeviceResources() ' Direct3Dデバイスを作成します 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) Next result.CheckError() d3dContext.Dispose() ' DXGI装置を格納します(アプリケーションが ' 中断されているときにトリミングするため) dxgiD = d3dDevice.QueryInterface(Of DXGI.Device)() d3dDevice.Dispose() ' RenderTargetを作成します(Direct2D描画用のDeviceContext) Dim d2dDevice = D2D.Device1.Create(d2dF, dxgiD) Dim rt = D2D.DeviceContext1.Create(d2dDevice, D2D.DeviceContextOptions.None) d2dDevice.Dispose() rt.SetUnitMode(D2D.UnitMode.Pixels) d2dC = rt ' 組み込みの効果を作成します shadow = D2D.Effects.Shadow.Create(rt) affineT = D2D.Effects.AffineTransform2D.Create(rt) compst = D2D.Effects.Composite.Create(rt) End Sub Private Sub DiscardDeviceResources() shadow.Dispose() affineT.Dispose() compst.Dispose() dxgiD.Dispose() d2dC.Dispose() End Sub Private Sub UpdateImageSource(imageEffect__1 As ImageEffect) Dim w As Integer = btmp.PixelWidth + marginLT + marginRB Dim h As Integer = btmp.PixelHeight + marginLT + marginRB Dim surfaceOffset As Point2L = Point2L.Empty Dim dxgiSurface As DXGI.Surface = Nothing Dim hr = HResult.Ok ' 描画のためにDXGI.Surfaceとオフセットを受け取ります For i As Integer = 0 To 1 hr = sisNative.BeginDraw(New RectL(w, h), surfaceOffset, dxgiSurface) If (hr <> DXGI.ResultCode.DeviceRemoved _ AndAlso hr <> DXGI.ResultCode.DeviceReset) _ OrElse i > 0 Then Exit For End If ' 古いGPUデバイスが削除された場合は、 ' 装置リソースを再作成してみてください DiscardDeviceResources() CreateDeviceResources() sisNative.SetDevice(dxgiD) Next hr.CheckError() ' レンダー対象オブジェクト Dim rt = d2dC ' 対象Direct2Dビットマップを作成します Dim bpTarget = New D2D.BitmapProperties1(New D2D.PixelFormat( DXGI.Format.B8G8R8A8_UNorm, D2D.AlphaMode.Premultiplied), CSng(btmp.DpiX), CSng(btmp.DpiY), D2D.BitmapOptions.Target Or D2D.BitmapOptions.CannotDraw) Dim targetBmp = D2D.Bitmap1.Create(rt, dxgiSurface, bpTarget) dxgiSurface.Dispose() ' 対象ビットマップをレンダー対象に関連付けます rt.SetTarget(targetBmp) targetBmp.Dispose() ' 描画を開始します rt.BeginDraw() ' 対象ビットマップをクリアします rt.Clear(Nothing) ' C1Bitmap画像をDirect2D画像に変換します Dim d2dBitmap = btmp.ToD2DBitmap1(rt, D2D.BitmapOptions.None) surfaceOffset.Offset(marginLT, marginLT) ' 効果を適用します Select Case imageEffect__1 Case ImageEffect.Original rt.DrawImage(d2dBitmap, surfaceOffset.ToPoint2F()) Exit Select Case ImageEffect.Shadow rt.DrawImage(ApplyShadow(d2dBitmap), surfaceOffset.ToPoint2F()) Exit Select End Select d2dBitmap.Dispose() ' 描画を終了します(すべての描画コマンドはその時点で実行されます) rt.EndDraw() ' 対象ビットマップをデタッチして破棄します rt.SetTarget(Nothing) ' SurfaceImageSourceでの完全な描画 sisNative.EndDraw() End Sub Private Function ApplyShadow(bitmap As D2D.Bitmap1) As D2D.Effect shadow.SetInput(0, bitmap) shadow.BlurStandardDeviation = 5.0F affineT.SetInputEffect(0, shadow) affineT.TransformMatrix = Matrix3x2.Translation(20.0F, 20.0F) compst.SetInputEffect(0, affineT) compst.SetInput(1, bitmap) Return compst End Function Private Sub MainPage_Unloaded(sender As Object, e As RoutedEventArgs) DiscardDeviceResources() btmp.Dispose() d2dF.Dispose() dwF.Dispose() img.Source = Nothing sisNative.Dispose() sisNative = Nothing End Sub
private void btnShadow_Click(object sender, RoutedEventArgs e) { UpdateImageSource(ImageEffect.Shadow); } void CreateDeviceResources() { // Direct3Dデバイスを作成します 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装置を格納します(アプリケーションが // 中断されているときにトリミングするため) dxgiD = d3dDevice.QueryInterface<DXGI.Device>(); d3dDevice.Dispose(); // RenderTargetを作成します(Direct2D描画用のDeviceContext) var d2dDevice = D2D.Device1.Create(d2dF, dxgiD); var rt = D2D.DeviceContext1.Create(d2dDevice, D2D.DeviceContextOptions.None); d2dDevice.Dispose(); rt.SetUnitMode(D2D.UnitMode.Pixels); d2dC = rt; // 組み込みの効果を作成します shadow = D2D.Effects.Shadow.Create(rt); affineT = D2D.Effects.AffineTransform2D.Create(rt); compst = D2D.Effects.Composite.Create(rt); } void DiscardDeviceResources() { shadow.Dispose(); affineT.Dispose(); compst.Dispose(); dxgiD.Dispose(); d2dC.Dispose(); } void UpdateImageSource(ImageEffect imageEffect) { int w = btmp.PixelWidth + marginLT + marginRB; int h = btmp.PixelHeight + marginLT + marginRB; Point2L surfaceOffset = Point2L.Empty; DXGI.Surface dxgiSurface = null; var hr = HResult.Ok; // 描画のためにDXGI.Surfaceとオフセットを受け取ります for (int i = 0; i <= 1; i++) { hr = sisNative.BeginDraw(new RectL(w, h), out surfaceOffset, out dxgiSurface); if ((hr != DXGI.ResultCode.DeviceRemoved && hr != DXGI.ResultCode.DeviceReset) || i > 0) { break; } // 古いGPUデバイスが削除された場合は、 // 装置リソースを再作成してみてください DiscardDeviceResources(); CreateDeviceResources(); sisNative.SetDevice(dxgiD); } hr.CheckError(); // レンダー対象オブジェクト var rt = d2dC; // 対象Direct2Dビットマップを作成します var bpTarget = new D2D.BitmapProperties1( new D2D.PixelFormat( DXGI.Format.B8G8R8A8_UNorm, D2D.AlphaMode.Premultiplied), (float)btmp.DpiX, (float)btmp.DpiY, D2D.BitmapOptions.Target | D2D.BitmapOptions.CannotDraw); var targetBmp = D2D.Bitmap1.Create(rt, dxgiSurface, bpTarget); dxgiSurface.Dispose(); // 対象ビットマップをレンダー対象に関連付けます rt.SetTarget(targetBmp); targetBmp.Dispose(); // 描画を開始します rt.BeginDraw(); // 対象ビットマップをクリアします rt.Clear(null); // C1Bitmap画像をDirect2D画像に変換します var d2dBitmap = btmp.ToD2DBitmap1(rt, D2D.BitmapOptions.None); surfaceOffset.Offset(marginLT, marginLT); // 効果を適用します switch (imageEffect) { case ImageEffect.Original: rt.DrawImage(d2dBitmap, surfaceOffset.ToPoint2F()); break; case ImageEffect.Shadow: rt.DrawImage(ApplyShadow(d2dBitmap), surfaceOffset.ToPoint2F()); break; } d2dBitmap.Dispose(); // 描画を終了します(すべての描画コマンドはその時点で実行されます) rt.EndDraw(); // 対象ビットマップをデタッチして破棄します rt.SetTarget(null); // SurfaceImageSourceでの完全な描画 sisNative.EndDraw(); } D2D.Effect ApplyShadow(D2D.Bitmap1 bitmap) { shadow.SetInput(0, bitmap); shadow.BlurStandardDeviation = 5f; affineT.SetInputEffect(0, shadow); affineT.TransformMatrix = Matrix3x2.Translation(20f, 20f); compst.SetInputEffect(0, affineT); compst.SetInput(1, bitmap); return compst; } private void MainPage_Unloaded(object sender, RoutedEventArgs e) { DiscardDeviceResources(); btmp.Dispose(); d2dF.Dispose(); dwF.Dispose(); img.Source = null; sisNative.Dispose(); sisNative = null; }