WPF_WriteableBitmap类
一、前言
在WPF中允许使用Image元素显示位图。可直接设置Image的Source属性(是一个ImageSource类型),则可直接显示位图。
<Image x:Name="myImage" Source="Resources/A.jpg" Stretch="Fill" />
myimage.Source = new BitmapImage(new Uri(@"./Resource/A.jpg", UriKind.Relative));
需要将图片添加到项目的资源中,并在属性中将生成操作改为Resource。
Image元素没有提供创建或者编辑位图信息的方法。
这正是WriteableBitmap类的用武之地。该类继承自BitmapSource,BitmapSource类继承自ImageSource。Image的Source属性是ImageSource类型,但BitmapSource是只读的位图数据映射。
二、生成位图
为使用WriteableBitmap类生成一副位图,需要以像素为单位的宽度、以像素为单位的高度、两个方向的DPI分辨率以及图形格式。
WriteableBitmap Wb = new WriteableBitmap(640, 480, 96, 96, PixelFormats.Bgra32, null);
最后一个参数当PixelFormat=PixelFormats.Indexed时才需要,这里不举例了。
三、写入WriteableBitmap对象
开始时,WriteableBitmap对象中所有字节的值都是0.本质上,就是一个大的黑色矩形。为使用内容填充WriteableBitmap对象,需要使用WritePixels()方法。
//因为像素格式是32位的,所以这里直接定义为UInt32类型表示一个像素的大小。
//因为转成四字节的顺序必须为blue green red alpha。所以在UInt32数据中blue放在低位
UInt32[] pixels = new UInt32[Wb.PixelWidth * Wb.PixelHeight];
Random random = new Random();
for (int y = 0; y < Wb.PixelHeight; y++)
{
for (int x = 0; x < Wb.PixelWidth; x++)
{
int offset = y * Wb.PixelWidth + x;
byte blue = (byte)random.Next(0, 255);
byte green = (byte)random.Next(0, 255);
byte red = (byte)random.Next(0, 255);
byte alpha = 255;
if ((y + 1) % 10 == 0 || (x + 1) % 10 == 0)
alpha = 0;
byte[] pixel = new byte[4] { blue, green, red, alpha };
pixels[offset] = BitConverter.ToUInt32(pixel, 0);
}
}
int stride = Wb.PixelWidth * (Wb.Format.BitsPerPixel / 8);
Wb.WritePixels(new Int32Rect(0, 0, Wb.PixelWidth, Wb.PixelHeight), pixels, stride, 0);
值得一提的是stride(跨距)的计算,跨距是每行像素数据需要的字节数量。
在实际应用程序中,可选择折中方法。如果需要更新位图中一块较大的区域,不会一次写入一个像素,因为折中方法运行速度太慢。如果图像数据很大,也不会在内存中同时保存全部数据数据然后一次性写入。
四、频繁更新图像数据
需要使用WriteableBitmap后台缓冲区,详见:WriteableBitmap 类 (System.Windows.Media.Imaging) | Microsoft Docs
五、示例
1、随机初始化了一个WriteableBitmap对象,装载再Image元素上
2、对于Image元素,可以使用鼠标滑轮进行缩放,使用按键W、S、A和D进行平移
3、鼠标左键按住移动的时候,对应位置会被重新填充为黑色(实际不止那一个像素)
4、鼠标右键则会重新初始化WriteableBitmap对象
源代码点我