Я работаю с множеством программно сгенерированных растровых изображений, которые мне нужно преобразовать в Texture2D, чтобы они могли отображаться в Monogame
Это то, что я называю в обычном цикле, проблема в том, что он очень медленный.
Function BitmapToTexture2D(Bitmap As Drawing.Bitmap, Device As GraphicsDevice) As Texture2D
Dim Result As Texture2D = Nothing
Using MemoryStream As MemoryStream = New MemoryStream
Bitmap.Save(MemoryStream, ImageFormat.Bmp)
MemoryStream.Seek(0, SeekOrigin.Begin)
Result = Texture2D.FromStream(Device, MemoryStream)
End Using
Return Result
End Function
Если бы я мог создать Texture2D без необходимости указывать GraphicsDevice, это было бы идеально.
Обновление 1:
Пытаясь обойти эту проблему, я попытался избавиться от необходимости использовать MemoryStream для повышения производительности.
Function BitmapToTexture2D(Bitmap As Drawing.Bitmap, Device As GraphicsDevice) As Texture2D
Dim Result As New Texture2D(Device, Bitmap.Size.Width, Bitmap.Size.Height)
Result.SetData(BitmapToColorArrayMonogame(Bitmap))
Return Result
End Function
Function BitmapToColorArrayMonogame(Bitmap As Drawing.Bitmap) As Color()
Dim Color() As Color = New Color(Bitmap.Size.Width * Bitmap.Size.Height - 1) {}
For X As Integer = 0 To (Bitmap.Size.Width - 1)
For Y As Integer = 0 To (Bitmap.Size.Height - 1)
Color((Bitmap.Size.Width * Y) + X) = SystemColorToMonogame(Bitmap.GetPixel(X, Y))
Next
Next
Return Color
End Function
Function SystemColorToMonogame(Color As System.Drawing.Color) As Color
Return New Microsoft.Xna.Framework.Color(Color.R, Color.G, Color.B, Color.A)
End Function
Результаты:
- Non-MemoryStream: 4659
- MemoryStream: 252
в миллисекундах.
MemoryStream значительно быстрее, чем обходить его.
Тем не менее, я бы предпочел, если бы я мог сделать это в фоновом режиме, параллельно.
Обновление 2:
С адаптированным здесь кодом
Function BitmapToTexture2DLockBits(Bitmap As Drawing.Bitmap, Device As GraphicsDevice) As Texture2D
Dim Result As New Texture2D(Device, Bitmap.Size.Width, Bitmap.Size.Height)
Dim Rectangle As New Drawing.Rectangle(0, 0, Bitmap.Width, Bitmap.Height)
Dim Data As BitmapData = Bitmap.LockBits(Rectangle, ImageLockMode.ReadWrite, Bitmap.PixelFormat)
Dim NumBytes As Integer = (Data.Stride * Bitmap.Height)
Dim Bytes As Byte() = New Byte(NumBytes - 1) {}
System.Runtime.InteropServices.Marshal.Copy(Data.Scan0, bytes, 0, numBytes)
Bitmap.UnlockBits(data)
Result.SetData(Bytes)
Return Result
End Function
Результаты:
- SetData From Array: 4371
- MemoryStream: 221
- LockBits: 63
Значительно быстрее, но все же не параллельно. Он не может быть параллельным, потому что GraphicsDevice должен использоваться для создания Texture2D, и при параллельном вызове он блокирует все приложение.
Должен быть какой-то способ создать Texture2D без использования GraphicsDevice.
Примечание: Дальнейшее тестирование показывает, что вы не можете установить SetData для текстуры параллельно, она блокируется и параллельный цикл никогда не заканчивается.