将 System.drawing 转换为 SharpDX.direct 2D1
Converting System.drawing to SharpDX.direct 2D1
我正在开发一个图形应用程序,它可以根据用户设置在 CPU 或 GPU 上绘制。为了利用 CPU,我将 GDI+ 技术与 System.Drawing 组件一起使用。要在 GPU 上绘图,我想使用 SharpDX.Direct2D1(因为我使用的是 c#)。
我制作了一个 DrawingContext 抽象 class,它实现了图形绘制的每个功能 class(接收 System.Drawing.Brush,System.Drawing.Rectangle 等...作为参数)并将它们重新实现到派生的 class (CPUDrawingContext) 中。现在,我有一个 GPUDrawingContext class 必须覆盖所有这些方法,但由于参数来自类型 System.Drawing,我需要将它们转换为 sharpDX 组件,非常快所以我们看不到区别。
在这里看一个小例子:我只放了一部分代码,这样你就可以看到这个概念。
绘图上下文
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 As Graphics 在屏幕上渲染
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.位图。
这就是我将 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 class,并且在第一次绘制调用时,如果它还没有被转换,只转换一次,所以在未来的绘图调用中,这将是即时的。这是我的 CustomBitmap class :
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
class 包含 2 种不同的方法,可以根据图像的原始 PixelFormat 分离灰度颜色或 32bpp。
我正在开发一个图形应用程序,它可以根据用户设置在 CPU 或 GPU 上绘制。为了利用 CPU,我将 GDI+ 技术与 System.Drawing 组件一起使用。要在 GPU 上绘图,我想使用 SharpDX.Direct2D1(因为我使用的是 c#)。
我制作了一个 DrawingContext 抽象 class,它实现了图形绘制的每个功能 class(接收 System.Drawing.Brush,System.Drawing.Rectangle 等...作为参数)并将它们重新实现到派生的 class (CPUDrawingContext) 中。现在,我有一个 GPUDrawingContext class 必须覆盖所有这些方法,但由于参数来自类型 System.Drawing,我需要将它们转换为 sharpDX 组件,非常快所以我们看不到区别。
在这里看一个小例子:我只放了一部分代码,这样你就可以看到这个概念。
绘图上下文
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 As Graphics 在屏幕上渲染
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.位图。
这就是我将 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 class,并且在第一次绘制调用时,如果它还没有被转换,只转换一次,所以在未来的绘图调用中,这将是即时的。这是我的 CustomBitmap class :
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
class 包含 2 种不同的方法,可以根据图像的原始 PixelFormat 分离灰度颜色或 32bpp。