Быстрое преобразование Bitmap в BitmapSource wpf
Мне нужно нарисовать изображение на Image
компонент на 30 Гц. Я использую этот код:
public MainWindow()
{
InitializeComponent();
Messenger.Default.Register<Bitmap>(this, (bmp) =>
{
ImageTarget.Dispatcher.BeginInvoke((Action)(() =>
{
var hBitmap = bmp.GetHbitmap();
var drawable = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(
hBitmap,
IntPtr.Zero,
Int32Rect.Empty,
BitmapSizeOptions.FromEmptyOptions());
DeleteObject(hBitmap);
ImageTarget.Source = drawable;
}));
});
}
Проблема в том, что с этим кодом загрузка моего процессора составляет около 80%, а без преобразования - около 6%.
Так почему же преобразование растрового изображения так долго?
Есть ли более быстрый метод (с небезопасным кодом)?
2 ответа
Решение
Вот метод, который (по моему опыту) по крайней мере в четыре раза быстрее, чем CreateBitmapSourceFromHBitmap
,
Это требует, чтобы вы установили правильный PixelFormat
результирующего BitmapSource.
public BitmapSource Convert(System.Drawing.Bitmap bitmap)
{
var bitmapData = bitmap.LockBits(
new System.Drawing.Rectangle(0, 0, bitmap.Width, bitmap.Height),
System.Drawing.Imaging.ImageLockMode.ReadOnly, bitmap.PixelFormat);
var bitmapSource = BitmapSource.Create(
bitmapData.Width, bitmapData.Height,
bitmap.HorizontalResolution, bitmap.VerticalResolution,
PixelFormats.Bgr24, null,
bitmapData.Scan0, bitmapData.Stride * bitmapData.Height, bitmapData.Stride);
bitmap.UnlockBits(bitmapData);
return bitmapSource;
}
Я ответил сам перед тем, как Клеменс ответит:
[DllImport("kernel32.dll", EntryPoint = "CopyMemory", SetLastError = false)]
public static extern void CopyMemory(IntPtr dest, IntPtr src, uint count);
WriteableBitmap writeableBitmap = new WriteableBitmap(1280, 1024, 96.0, 96.0, PixelFormats.Bgr24, null);
public MainWindow()
{
InitializeComponent();
ImageTarget.Source = writeableBitmap;
Messenger.Default.Register<Bitmap>(this, (bmp) =>
{
ImageTarget.Dispatcher.BeginInvoke((Action)(() =>
{
BitmapData data = bmp.LockBits(new System.Drawing.Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadOnly, bmp.PixelFormat);
writeableBitmap.Lock();
CopyMemory(writeableBitmap.BackBuffer, data.Scan0,
(writeableBitmap.BackBufferStride * bmp.Height));
writeableBitmap.AddDirtyRect(new Int32Rect(0, 0, bmp.Width, bmp.Height));
writeableBitmap.Unlock();
bmp.UnlockBits(data);
}));
});
}
Теперь моя загрузка процессора составляет около 15%