我有一个WriteableBitmap,我想反复清理和重绘。
我已经看到过直接写入Pixels数组的引用,但是在WriteableBitmap中无法访问Pixels数组。我也尝试过每次都重新创建WriteableBitmap的建议,但是我的应用程序几乎立即耗尽内存。
有没有一种简单的方法来清除WriteableBitmap?
答案 0 :(得分:1)
要使用writeablebitmap.clear(),您需要WriteableBitmapEx库。 http://writeablebitmapex.codeplex.com
答案 1 :(得分:1)
我们阻止将空白字节数组复制到可写位图的后缓冲区来执行此操作。对于1k x 1k位图,我们还可以以每秒超过30帧的速度复制原始帧。
快速或安全的两个例子(并且仍然非常快)。 我更喜欢不安全的版本。
#region External
[DllImport("kernel32.dll", EntryPoint = "RtlMoveMemory")]
public static extern void CopyMemory(IntPtr destination, IntPtr source, uint length);
#endregion
private const int PixelHeight = 1024;
private const int PixelWidth = 1024;
private const int DpiHeight = 96;
private const int DpiWidth = 96;
private const int RgbBytesPerPixel = 3;
WriteableBitmap _myBitmap = new WriteableBitmap(PixelHeight, PixelWidth, DpiHeight, DpiWidth, PixelFormats.Rgb24, null);
private readonly byte[] _blankImage = new byte[PixelHeight * PixelWidth * RgbBytesPerPixel];
private unsafe void FastClear()
{
fixed (byte* b = _blankImage)
{
CopyMemory(_myBitmap.BackBuffer, (IntPtr)b, (uint)_blankImage.Length);
}
Application.Current.Dispatcher.InvokeAsync(() =>
{
_myBitmap.Lock();
_myBitmap.AddDirtyRect(new Int32Rect(0, 0, _myBitmap.PixelWidth, _myBitmap.PixelHeight));
_myBitmap.Unlock();
});
}
private void SafeClear()
{
GCHandle pinnedArray = new GCHandle();
IntPtr pointer = IntPtr.Zero;
try
{
//n.b. If pinnedArray is used often wrap it in a class with IDisopsable and keep it around
pinnedArray = GCHandle.Alloc(_blankImage, GCHandleType.Pinned);
pointer = pinnedArray.AddrOfPinnedObject();
CopyMemory(_myBitmap.BackBuffer, pointer, (uint)_blankImage.Length);
Application.Current.Dispatcher.InvokeAsync(() =>
{
_myBitmap.Lock();
_myBitmap.AddDirtyRect(new Int32Rect(0, 0, _myBitmap.PixelWidth, _myBitmap.PixelHeight));
_myBitmap.Unlock();
});
}
finally
{
pointer = IntPtr.Zero;
pinnedArray.Free();
}
}
答案 2 :(得分:0)
CCondron给出的答案最终将开始抛出AccessViolationException。值得庆幸的是,我们可以更简单,更快速,更稳定的方式解决这个问题:
[System.Runtime.InteropServices.DllImport("kernel32.dll")]
private static extern void RtlZeroMemory(IntPtr dst, int length);
protected void ClearWriteableBitmap(WriteableBitmap bmp)
{
RtlZeroMemory(bmp.BackBuffer, bmp.PixelWidth * bmp.PixelHeight * (bmp.Format.BitsPerPixel / 8));
bmp.Dispatcher.Invoke(() =>
{
bmp.Lock();
bmp.AddDirtyRect(new Int32Rect(0, 0, bmp.PixelWidth, bmp.PixelHeight));
bmp.Unlock();
});
}
答案 3 :(得分:0)
使用net472,您可以非常快速地清除WriteableBitmap
(在我的全屏测试中平均为1毫秒),而无需自己导入Kernel32.dll(始终在后台进行调用):
WriteableBitmap bitmap = ...;
Int32Rect rect = new Int32Rect(0, 0, bitmap.PixelWidth, bitmap.PixelHeight);
int bytesPerPixel = bitmap.Format.BitsPerPixel / 8; // typically 4 (BGR32)
byte[] empty = new byte[rect.Width * rect.Height * bytesPerPixel]; // cache this one
int emptyStride = rect.Width * bytesPerPixel;
bitmap.WritePixels(rect, empty, emptyStride, 0);
您可以轻松地调整此代码以进行重复调用(将字节数组存储在某个位置以进行快速检索)。棘手的是“步幅”,即一行像素的大小(以字节为单位)。对于Bgr32
表示形式(WriteableBitmap
的最喜欢的表示形式),应为4*bitmap.PixelWidth
。