如何将图像从SharpDX/Direct2D复制到.NET位图
我开发了一个.NETWinForms应用程序,需要缩放许多大图像,并将它们显示为表单上的小图标。我对性能有问题,特别是在特定的机器上。因此,我现在的目标是使用SharpDX使用Direct2D缩放这些图像。不知何故,现在图像被缩放了,但我无法将图像从DirectX位图复制到.NET位图如何将图像从SharpDX/Direct2D复制到.NET位图,.net,vb.net,winforms,sharpdx,direct2d,.net,Vb.net,Winforms,Sharpdx,Direct2d,我开发了一个.NETWinForms应用程序,需要缩放许多大图像,并将它们显示为表单上的小图标。我对性能有问题,特别是在特定的机器上。因此,我现在的目标是使用SharpDX使用Direct2D缩放这些图像。不知何故,现在图像被缩放了,但我无法将图像从DirectX位图复制到.NET位图 Private Sub CopyBitmapFromDxToGDI(bitmap As d2.Bitmap1, bmp As Drawing.Bitmap) Dim d2dBitmapProps2 = Ne
Private Sub CopyBitmapFromDxToGDI(bitmap As d2.Bitmap1, bmp As Drawing.Bitmap)
Dim d2dBitmapProps2 = New d2.BitmapProperties1(d2PixelFormat, 96, 96, BitmapOptions.CpuRead Or BitmapOptions.CannotDraw )
Dim d2dRenderTarget2 = New d2.Bitmap1(d2dContext, New Size2(bmp.Width, bmp.Height), d2dBitmapProps2)
d2dRenderTarget2.CopyFromRenderTarget(d2dContext)
Dim surface = d2dRenderTarget2.Surface
Dim dataStream As DataStream = Nothing
surface.Map(dxgi.MapFlags.Read, dataStream)
Dim bmpData As System.Drawing.Imaging.BitmapData = bmp.LockBits(
New System.Drawing.Rectangle(0, 0, bmp.Width, bmp.Height),
System.Drawing.Imaging.ImageLockMode.ReadWrite,
System.Drawing.Imaging.PixelFormat.Format32bppPArgb)
Dim offset = 3
Debug.WriteLine($"({surface.Description.Width}, {surface.Description.Height})")
For y As Integer = 0 To surface.Description.Height - 1
For x As Integer = 0 To surface.Description.Width -1
Dim b As Byte = dataStream.Read(Of Byte)()
Dim g As Byte = dataStream.Read(Of Byte)()
Dim r As Byte = dataStream.Read(Of Byte)()
Dim a As Byte = dataStream.Read(Of Byte)()
Marshal.WriteByte(bmpData.Scan0, offset, a)
offset += 1
Marshal.WriteByte(bmpData.Scan0, offset, r)
offset += 1
Marshal.WriteByte(bmpData.Scan0, offset, g)
offset += 1
Marshal.WriteByte(bmpData.Scan0, offset, b)
offset += 1
Next
Next
bmp.UnlockBits(bmpData)
surface.Unmap()
End Sub
代码相当简单。我创建了一个允许CPU访问的新位图,从中获取数据流,然后逐字节将数据写入.NET位图。然而,这段代码大多不起作用。仅当目标图像具有特定大小时,它才能正确渲染图像。对于特定的大小,它只会因AccessViolationException而崩溃。对于特定的大小,它被渲染为奇怪:
你知道我在代码中遗漏了什么吗?要解决这个问题,需要使用dataRectangle.Pitch计算内存流中每个像素的位置。以下代码现在可以正常工作:
Private Sub CopyBitmapFromDxToGDI(bitmap As d2.Bitmap1, bmp As Drawing.Bitmap)
Dim d2TempBitmapProps = New d2.BitmapProperties1(d2PixelFormat, 96, 96, BitmapOptions.CpuRead Or BitmapOptions.CannotDraw)
Dim d2TempBitmap = New d2.Bitmap1(d2dContext, New Size2(bmp.Width, bmp.Height), d2TempBitmapProps)
d2TempBitmap.CopyFromRenderTarget(d2dContext)
Dim surface = d2TempBitmap.Surface
Dim dataStream As DataStream = Nothing
Dim dataRectangle As DataRectangle = surface.Map(dxgi.MapFlags.Read, dataStream)
Dim bmpData As Imaging.BitmapData = bmp.LockBits(New Drawing.Rectangle(0, 0, bmp.Width, bmp.Height), Imaging.ImageLockMode.ReadWrite, Imaging.PixelFormat.Format32bppPArgb)
Dim offset = bmpData.Reserved
Dim buffer(4) As Byte
For y As Integer = 0 To surface.Description.Height - 1
For x As Integer = 0 To surface.Description.Width - 1
dataStream.Seek((y * dataRectangle.Pitch) + (x * 4), SeekOrigin.Begin)
dataStream.Read(buffer, 0, 4)
Marshal.WriteByte(bmpData.Scan0, offset, buffer(3))
Marshal.WriteByte(bmpData.Scan0, offset+1, buffer(0))
Marshal.WriteByte(bmpData.Scan0, offset+2, buffer(1))
Marshal.WriteByte(bmpData.Scan0, offset+3, buffer(2))
offset += 4
Next
Next
bmp.UnlockBits(bmpData)
surface.Unmap()
dataStream.Dispose()
d2TempBitmap.Dispose()
End Sub
很难看出问题出在哪里,因为没有所有的代码。可能是GDI+位图和ID2D1Bitmap1格式之间的格式不匹配。此外,还必须使用从surface.Map返回的俯仰(也称步幅)值。这是曲面的精确宽度(以字节为单位),可能与图像的宽度不同。看起来
offset
的值是错误的。示例#2 at显示为每行计算的偏移量为offset=bitmapData.Stride*y
。谢谢@AndrewMorton。这个示例很有帮助,现在我计算每个像素在数据流中的位置,这就完成了。dataStream.Seek((y*dataRectangle.Pitch)+(x*4),SeekOrigin.Begin)dataStream.Read(缓冲区,0,4)