簡體   English   中英

將System.drawing轉換為SharpDX.direct 2D1

[英]Converting System.drawing to SharpDX.direct 2D1

我正在開發可根據用戶設置在CPU或GPU上繪圖的圖形應用程序。 為了使用CPU,我將GDI +技術與System.Drawing組件一起使用。 要在GPU上繪圖,我想使用SharpDX.Direct2D1(因為我正在使用c#)。

我制作了一個DrawingContext抽象類,該類實現了Graphics類的所有繪制功能(將System.Drawing.Brush,System.Drawing.Rectangle等作為參數),並將它們重新實現為派生類(CPUDrawingContext)。 現在,我有一個GPUDrawingContext類,該類必須重寫所有這些方法,但是由於參數來自System.Drawing類型,因此我需要非常快速地將它們轉換為sharpDX組件,因此我們看不到它們之間的區別。

在這里看到一個小例子:我只放入了一部分代碼,所以您可以看到這個概念。

的DrawingContext

Public abstract class DrawingContext {
//System.drawing.Bitmap, System.Drawing.RectangleF
Public asbstract DrawImage(Bitmap b, RectangleF dest, RectangleF source,GraphicsUnit g);
//System.Drawing.Brush
Public abstract DrawRectangle(Brush b, Rectangle rect);


}

CPUDrawingContext:使用graphicContext作為圖形在屏幕上渲染

Public  class CPUDrawingContext{
  //System.drawing.Bitmap, System.Drawing.RectangleF
  Public override DrawImage(Bitmap b, RectangleF dest, RectangleF source,GraphicsUnit g);
  //System.Drawing.Brush
  Public override DrawRectangle(Brush b, Rectangle rect){
      graphicContext.Rectangle(b,rect);
  }
  Public override DrawImage(Bitmap b, RectangleF dest, RectangleF source, GraphicsUnit g) {
      graphicContext.DrawImage(b,dest,source,g);
  }
}

GPUDrawingContext:使用renderTarger作為RenderTarget在屏幕上渲染

Public class GPUDrawingContext {
   //System.drawing.Bitmap, System.Drawing.RectangleF
  Public override DrawImage(Bitmap b, RectangleF dest, RectangleF  source,GraphicsUnit g);
  //System.Drawing.Brush
  Public override DrawRectangle(Brush b, Rectangle rect){
      //convert b and rect to fit sharpDX component
      renderTarget.DrawRectangle(b,rect);
   }
  Public override DrawImage(Bitmap b, RectangleF dest, RectangleF source, GraphicsUnit g) {
      //(convert b,dest,source and g to fit sharpDX component)
      renderTarget.DrawImage(b,dest,source,g);
   }
 }

我在GPUDrawingContext中評論了在繪制之前需要轉換的區域。

我的問題是,這樣做是否可能非常快,以至於我們不會注意到(例如轉換時間少於10毫秒)。

由於我的應用程序需要繪制位圖,因此我需要非常快速地將System.Drawing.Bitmap轉換為SharpDX.Direct2D1.Bitmap,但我注意到SharpDX位圖似乎與System.Drawing.Bitmap並不真正兼容。

因此,這就是我將System.Drawing.Bitmap轉換為SharpDX.Direct2d1.Bitmap的方式。

Dim bmpData As BitmapData = m_Bitmap.LockBits(New System.Drawing.Rectangle(0, 0, m_Bitmap.Width, m_Bitmap.Height), System.Drawing.Imaging.ImageLockMode.ReadOnly, m_Bitmap.PixelFormat)

  Dim bgraArray As Byte() = New Byte(bmpData.Width * bmpData.Height * 4 - 1) {}

  Dim scan As IntPtr = bmpData.Scan0
  Marshal.Copy(scan, bgraArray, 0, (bmpData.Width * bmpData.Height) * 4)

  Dim rgbaarray As Byte() = New Byte(bmpData.Width * bmpData.Height * 4 - 1) {}

  Parallel.For(0, 4, Sub(range)
                        For i As Integer = range * bmpData.Height / 4 To bmpData.Height / 4 * (range + 1) - 1
                           Dim offset As Integer = i * bmpData.Width * 4
                           For j As Integer = 0 To bmpData.Width * 4 - 1 Step 4
                              rgbaarray(offset + j) = bgraArray(offset + j + 2)
                              rgbaarray(offset + j + 1) = bgraArray(offset + j + 1)
                              rgbaarray(offset + j + 2) = bgraArray(offset + j)
                              rgbaarray(offset + j + 3) = bgraArray(offset + j + 3)
                           Next
                        Next
                     End Sub)

  Dim stream As DataStream = New DataStream(bmpData.Height * bmpData.Width * 4, True, True)
  stream.WriteRange(rgbaarray)
  stream.Position = 0
  m_sharpDXbitmap = New SharpDX.Direct2D1.Bitmap(deviceContext, New Size2(m_Bitmap.Width, m_Bitmap.Height), stream, bmpData.Width * 4, bitmapProperties)
  m_Bitmap.UnlockBits(bmpData)

  stream.Dispose()

但是,這不是10毫秒,而是120毫秒。 為了保持我想要的抽象,我要做的是創建一個包含兩個位圖的CustomBitmap類,並且在第一次繪制調用時,如果尚未轉換,則僅將其轉換一次,因此在未來的繪制調用中,這將要即時。 這是我的CustomBitmap類:

Imports System.Drawing.Imaging
Imports System.Reflection
Imports SharpDX
Imports SharpDX.Direct2D1
Imports System.Runtime.InteropServices
Imports Synergx.Common.Drawing
Imports System.Collections.Concurrent
Imports System.Threading.Tasks

Public Class CustomBitmap

   Private bitmapProperties As BitmapProperties = New BitmapProperties(New SharpDX.Direct2D1.PixelFormat(SharpDX.DXGI.Format.R8G8B8A8_UNorm, SharpDX.Direct2D1.AlphaMode.Ignore))

   Public Property Bitmap As System.Drawing.Bitmap
      Get
         Return m_Bitmap
      End Get
      Set(value As System.Drawing.Bitmap)
         m_Bitmap = value
      End Set
   End Property

   Private m_Width As Integer
   Private m_Height As Integer
   Private m_Bitmap As System.Drawing.Bitmap
   Private m_sharpDXbitmap As SharpDX.Direct2D1.Bitmap = Nothing

   Public ReadOnly Property Width As Integer
      Get
         Return m_Width
      End Get
   End Property

   Public ReadOnly Property Height As Integer
      Get
         Return m_Height
      End Get
   End Property

   Public ReadOnly Property GPUBitmap As SharpDX.Direct2D1.Bitmap
      Get
         Return m_sharpDXbitmap
      End Get
   End Property

   Public Sub New(bitmap As System.Drawing.Bitmap)
      Me.Bitmap = bitmap
      m_Width = bitmap.Width
      m_Height = bitmap.Height
   End Sub

   Friend Sub GenerateSharpDXBitmap(deviceContext As SharpDX.Direct2D1.DeviceContext)

      If (m_Bitmap.PixelFormat = Imaging.PixelFormat.Format8bppIndexed) Then
         GenerateSharpDXBitmap8bpp(deviceContext)
      ElseIf (m_Bitmap.PixelFormat = Imaging.PixelFormat.Format32bppArgb) Then
         GenerateSharpDXBitmap32argp(deviceContext)
      End If

   End Sub

   Private Sub GenerateSharpDXBitmap8bpp(deviceContext As SharpDX.Direct2D1.DeviceContext)

      Dim bmpData As BitmapData = m_Bitmap.LockBits(New System.Drawing.Rectangle(0, 0, m_Bitmap.Width, m_Bitmap.Height), System.Drawing.Imaging.ImageLockMode.ReadOnly, m_Bitmap.PixelFormat)

      Dim integerArray As Integer()
      ReDim integerArray(bmpData.Height * bmpData.Width - 1)

      Parallel.For(0, 4, Sub(range)
                            Dim scan As IntPtr = bmpData.Scan0

                            For i As Integer = 0 To bmpData.Height * range / 4 - 1 - 1
                               scan += bmpData.Stride
                            Next

                            For y As Integer = bmpData.Height * range / 4 To bmpData.Height * (range + 1) / 4 - 1
                               Dim bytes As Byte() = New Byte(bmpData.Width - 1) {}
                               Marshal.Copy(scan, bytes, 0, bmpData.Width)

                               For x As Integer = 0 To bytes.Length - 1
                                  Dim B As Integer = bytes(x)
                                  Dim rgba As Integer = B Or (B << 8) Or (B << 16) Or (B << 24)
                                  integerArray(x + y * bmpData.Width) = rgba
                               Next
                               scan += bmpData.Stride

                            Next
                         End Sub)

      Dim stream As DataStream = New DataStream(bmpData.Height * bmpData.Width * 4, True, True)
      stream.WriteRange(integerArray)
      stream.Position = 0
      m_sharpDXbitmap = New SharpDX.Direct2D1.Bitmap(deviceContext, New Size2(m_Bitmap.Width, m_Bitmap.Height), stream, bmpData.Width * 4, bitmapProperties)
      m_Bitmap.UnlockBits(bmpData)

      stream.Dispose()

   End Sub

   Private Sub GenerateSharpDXBitmap32argp(deviceContext As SharpDX.Direct2D1.DeviceContext)
      Dim bmpData As BitmapData = m_Bitmap.LockBits(New System.Drawing.Rectangle(0, 0, m_Bitmap.Width, m_Bitmap.Height), System.Drawing.Imaging.ImageLockMode.ReadOnly, m_Bitmap.PixelFormat)

      Dim bgraArray As Byte() = New Byte(bmpData.Width * bmpData.Height * 4 - 1) {}

      Dim scan As IntPtr = bmpData.Scan0
      Marshal.Copy(scan, bgraArray, 0, (bmpData.Width * bmpData.Height) * 4)

      Dim rgbaarray As Byte() = New Byte(bmpData.Width * bmpData.Height * 4 - 1) {}

      Parallel.For(0, 4, Sub(range)
                            For i As Integer = range * bmpData.Height / 4 To bmpData.Height / 4 * (range + 1) - 1
                               Dim offset As Integer = i * bmpData.Width * 4
                               For j As Integer = 0 To bmpData.Width * 4 - 1 Step 4
                                  rgbaarray(offset + j) = bgraArray(offset + j + 2)
                                  rgbaarray(offset + j + 1) = bgraArray(offset + j + 1)
                                  rgbaarray(offset + j + 2) = bgraArray(offset + j)
                                  rgbaarray(offset + j + 3) = bgraArray(offset + j + 3)
                               Next
                            Next
                         End Sub)

      Dim stream As DataStream = New DataStream(bmpData.Height * bmpData.Width * 4, True, True)
      stream.WriteRange(rgbaarray)
      stream.Position = 0
      m_sharpDXbitmap = New SharpDX.Direct2D1.Bitmap(deviceContext, New Size2(m_Bitmap.Width, m_Bitmap.Height), stream, bmpData.Width * 4, bitmapProperties)
      m_Bitmap.UnlockBits(bmpData)

      stream.Dispose()
   End Sub

   Public Sub Dispose()
      If Bitmap IsNot Nothing Then
         m_Bitmap.Dispose()
         m_Bitmap = Nothing
      End If
      If m_sharpDXbitmap IsNot Nothing Then
         m_sharpDXbitmap.Dispose()
         m_sharpDXbitmap = Nothing
      End If
   End Sub

End Class

該類包含2種不同的方法,這些方法可以根據圖像的原始PixelFormat分為灰度顏色或32bpp。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM