正如我的其他答案中所述,解決此問題的更好方法是直接訪問位圖數據。 BitmapImage繼承自BitmapSource。 BitmapSource非常適合這一點,也適用於WPF綁定。
我自己使用BitmapSource來操作直接綁定到WPF(MVVM樣式)的圖像。基本上我在內存中創建一個區域並將BitmapSource指向它。這允許我直接讀/寫像素到內存並使BitmapSource無效,以便WPF重新繪製圖像。我有一個標準的「位圖」對象,我用這個。直接的數據訪問使其超快速。 (嚴重的是,沒有任何問題在30fps下修改4張圖像中的所有位...並沒有以更高的速度嘗試,因爲它沒有被要求。)
樣例用法可在my blog上找到。但基本上你這樣做:
unsafe {
byte* imgBytePtr = (byte*)myBitmap.ImageData;
Int32* imgInt32Ptr = (Int32*)myBitmap.ImageData;
int height = (int)myBitmap.BitmapSource.Height;
int width = (int)myBitmap.BitmapSource.Width;
int bpp = myBitmap.BytesPerPixel;
// Note: No need to iterate just for copy. A Marshal.Copy() at this point can copy all the bytes into a byte-array if you want.
// But the best would be if your application could do its work directly in the imgBytePtr[]-array.
for (int x = 0; x < height; x++)
{
for (int y = 0; y < width; y++)
{
// Get bytes into RGBA values
int bytePos = x * (width * bpp) + (y * bpp);
byte R = imgBytePtr[bytePos + 0];
byte B = imgBytePtr[bytePos + 1];
byte G = imgBytePtr[bytePos + 2];
byte A = imgBytePtr[bytePos + 3];
// Alternatively get Int32 value of color
int intPos = x * width + y;
int intColor = imgIntPtr[intPos];
// Examples of manipulating data
// Remove blue
imgBytePtr[bytePos + 1] = 0;
// Alternative remove blue by bitmask
imgIntPtr[intPos] = imgIntPtr[intPos] & 0xFF00FFFF;
}
}
}
// Now execute Invalidate() and WPF will automagically update bound picture object :)
這使得一個的BitmapSource,如果你需要的BitmapImage相反,你可以看到,如果你可以改變它的工作。
///
/// This object holds a byte array of the picture as well as a BitmapSource for WPF objects to bind to. Simply call .Invalidate() to update GUI.
///
public class Bitmap : IDisposable
{
// some ideas/code borowed from CL NUI sample CLNUIImage.cs
[DllImport("kernel32.dll", SetLastError = true)]
static extern IntPtr CreateFileMapping(IntPtr hFile, IntPtr lpFileMappingAttributes, uint flProtect, uint dwMaximumSizeHigh, uint dwMaximumSizeLow, string lpName);
[DllImport("kernel32.dll", SetLastError = true)]
static extern IntPtr MapViewOfFile(IntPtr hFileMappingObject, uint dwDesiredAccess, uint dwFileOffsetHigh, uint dwFileOffsetLow, uint dwNumberOfBytesToMap);
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool UnmapViewOfFile(IntPtr hMap);
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool CloseHandle(IntPtr hHandle);
private IntPtr _section = IntPtr.Zero;
public IntPtr ImageData { get; private set; }
public InteropBitmap BitmapSource { get; private set; }
public int BytesPerPixel = 3;
///
/// Initializes an empty Bitmap
///
/// Image width
/// Image height
/// Image format
public Bitmap(int width, int height, PixelFormat pixelFormat)
{
BytesPerPixel = pixelFormat.BitsPerPixel/8;
uint imageSize = (uint)width * (uint)height * (uint)BytesPerPixel;
// create memory section and map
_section = CreateFileMapping(new IntPtr(-1), IntPtr.Zero, 0x04, 0, imageSize, null);
ImageData = MapViewOfFile(_section, 0xF001F, 0, 0, imageSize);
BitmapSource = Imaging.CreateBitmapSourceFromMemorySection(_section, width, height, pixelFormat, width * BytesPerPixel, 0) as InteropBitmap;
}
///
/// Invalidates the bitmap causing a redraw
///
public void Invalidate()
{
BitmapSource.Invalidate();
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected void Dispose(bool disposing)
{
if (disposing)
{
// free managed resources
}
// free native resources if there are any.
if (ImageData != IntPtr.Zero)
{
UnmapViewOfFile(ImageData);
ImageData = IntPtr.Zero;
}
if (_section != IntPtr.Zero)
{
CloseHandle(_section);
_section = IntPtr.Zero;
}
}
}
你通常從這種方法返回什麼?也許問題不在於這種方法,而是你返回的對象永遠不會被拋棄。 – 2011-02-04 11:19:41
向我們展示更多代碼。這還不夠。 – Euphoric 2011-02-04 11:29:49
通常我返回一個流(byte [])。該功能稱爲不同位圖的多次。 – shepard1 2011-02-04 12:18:43