Как скопировать изображение из SharpDX / Direct2D в. NET Bitmap - PullRequest
0 голосов
/ 27 мая 2020

Я разрабатываю приложение. NET WinForms, и мне нужно масштабировать множество больших изображений и отображать их как маленькие значки в форме. У меня проблемы с производительностью особенно на указанных c машинах. Таким образом, моя цель сейчас - использовать SharpDX для масштабирования этих изображений с помощью Direct2D. Каким-то образом изображения теперь масштабируются, но я не могу скопировать изображение из растрового изображения DirectX в. NET одно.

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

Код довольно простой. Я создаю новое растровое изображение, которое разрешает доступ к процессору, получаю от него DataStream и затем записываю эти данные в. NET битовый массив побайтно. Однако этот код в основном не работает. Он может правильно отображать изображение только в том случае, если целевое изображение имеет размер c. С указанным размером c это просто sh с AccessViolationException. При заданном размере c он выглядит странно: введите описание изображения здесь

Вы знаете, что я пропустил в своем коде?

1 Ответ

0 голосов
/ 28 мая 2020

Для решения проблемы необходимо вычислить положение каждого пикселя в потоке памяти с помощью 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
...