通常,WPF中的位图是不可变的。不可变的位图非常有效,如果您希望进行大量的动态更改,创建和销毁它们的开销会变得非常昂贵。在这种情况下,您需要一些更灵活的东西——WriteableBitmap。

WriteableBitmap,正如它的名字所暗示的,不是不可变的,你可以得到它的单个像素,并尽可能多地操纵它们。当您需要动态位图时,这是理想的工作方式。我们来看看WriteableBitmap,它是如何工作的,以及如何使用它来做动态的事情。

要使用WriteableBitmap,我们需要添加:using System.Windows.Media.Imaging;它包含我们需要的所有其他位图工具。

有两种方法可以创建WriteableBitmap。最常用的是简单地指定位图的大小和格式:

WriteableBitmap wbmap = new WriteableBitmap(100, 100, 300,300, PixelFormats.Bgra32, null);

它使用Bgra32像素格式指定一个100×100像素的WriteableBitmap,分辨率为300dpi×300dpi。每个像素是一个32位的int,使用一个4字节的BGRA——也就是说,像素由一个字节组成,该字节给出蓝色、绿色、红色和Alpha值。如果格式需要,最后一个参数用于指定调色板。

您可以为您创建的位图指定广泛的格式,在每种情况下,每个像素都接受给定数量的位来表示,您需要找出分配给每个像素的位如何决定其颜色。

创建WriteableBitmap的第二种方法是基于现有的BitmapSource或派生类。例如,您应该能够使用构造函数从标准位图创建WriteableBitmap:

WriteableBitmap(bitmapsource);

但是如果您尝试使用从URI加载的BitmapImage,您将得到一个null对象错误。原因是位图可能还没有下载。对于本地文件,位图加载会阻塞执行,直到加载完成:

Uri uri = new Uri(@"pack://application:,,,/Resources/mypic.jpg");
BitmapImage bmi = new BitmapImage(uri);
WriteableBitmap bmi2 = new WriteableBitmap(bmi);
image1.Source = bmi2;

在这种情况下,WriteableBitmap的创建没有任何问题。但是,如果URI是HTTP URL,负载不会阻塞执行,结果将是一个错误。

使用像素

一旦你有了WriteableBitmap,你就可以开始使用它的像素了。提供了两种方法,它们提供了在低级API中找到的与BitBlt操作等价的有限的方法。在这种情况下,您可以将一个像素矩形复制到一个数组中,也可以将一个数组中的数据复制到一个像素矩形中。在每一种情况下,数据数组都被视为一个字节流,并简单地从位图中指定的像素矩形中存储或检索。

WriteableBitmap了解它所存储的位图的格式,因此它会自动计算出每个像素使用了多少字节,以及如何找到给定坐标下的像素数据。但是,它不能知道您如何组织数组中的数据,或者在向数组读取像素时,您可能需要如何组织数据。

最简单的方案是将一行像素数据存储在与前一行相邻的数组中。也就是说,如果原始图像有p个像素,每个像素用b字节表示,那么数组中的第一行用p*b字节存储,下一行从p*b+1开始,以此类推。

可以看到,列x行y中的像素(从0开始计数)存储在字节x*b+p*b*y中。(这是存储映射函数的一个例子。)这个简单方案的唯一复杂之处在于一行像素可能不会在整个字节中结束。例如,如果你有一个黑白图像格式,你只需要1位每像素和第一行的10×10位图只需要10位存储。然而,为了简单起见,每一行都必须从一个新字节开始,因此存储第一行所需的存储空间是两个字节。

注意,在这种情况下,根据每个像素的比特数或字节数,分配给一行的存储量超出了严格的需求,也就是说,它不仅仅是p*b。

为什么一行所需的存储空间并不总是最小值,还有其他原因——例如Windows坚持行总是从一个4字节的边界开始。

因此,我们定义并使用“stride”。

stride S被定义为存储图像一行所需的存储量,包括确保下一行正确对齐所需的任何填充。

在这种情况下,WriteableBitmap负责像素的内部表示,您不需要担心它使用的是什么值。但是,您必须担心在您负责的数据数组中使用的stride。在大多数情况下,您可以简单地将stride设置为存储位图的一行所需的字节数——四舍五入,以确保必要时每一行都从一个新字节开始。

您只需要担心其他问题,比如从一个4字节的边界开始,如果它是由系统的其他部分强加的,比如从使用特定步幅的源获取数据。

WriteableBitmap(一)的更多相关文章

  1. WriteableBitmap 给透明的控件截图的问题

    在WP开发中,我们经常会用到截取某一部分区域,然后分享到微博等等,Writeablebitmap 是一个很好的辅助,但是它本身也有一个限制:只有一个 SaveJpeg 方法,因此透明的区域无法保存,都 ...

  2. UWP&WP8.1 重新绘制图片 WriteableBitmap用法 图片转byte[]数组,byte[]数组转图片

    ---恢复内容开始--- WriteableBitmap 是UWP和WP8.1绘制图片的,重组图片的最重要方法.方法较为简单,方法多样性. 通过查看文档,WriteableBitmap的继承性是    ...

  3. Silverlight中将WriteableBitmap互转byte数组

    //WriteableBitmap to ARGB ;    , result, , len);    , bmp.Pixels, , buffer.Length); }

  4. 【转】【WPF】WriteableBitmap应用及图片数据格式转换

    使用 WriteableBitmap 类基于每个框架来更新和呈现位图.这对于生成算法内容(如分形图像)和数据可视化(如音乐可视化工具)很有用. WriteableBitmap 类使用两个缓冲区.“后台 ...

  5. Windows Phone 使用 WriteableBitmap后台生成图片

    这几天项目是遇到一个需求,需要后台把几个元素生成到一张图片上,并保存到文件中 private void cutscreen_Click(object sender, EventArgs e) { Gr ...

  6. win10 uwp 读取保存WriteableBitmap 、BitmapImage

    我们在UWP,经常使用的图片,数据结构就是 BitmapImage 和 WriteableBitmap.关于 BitmapImage 和 WriteableBitmap 区别,我就不在这里说.主要说的 ...

  7. WriteableBitmap/BitmapImage/MemoryStream/byte[]相互转换

    1 WriteableBitmap/BitmapImage/MemoryStream/byte[]相互转换 2012-12-18 17:27:04|  分类: Windows Phone 8|字号 订 ...

  8. WriteableBitmap(三) 扩展

    backbuffer使用您在创建WriteableBitmap时指定的像素格式,还有一个BackBufferStride属性,您可以使用它来创建一个合适的存储映射函数. 添加一些方法来设置和获取特定情 ...

  9. WriteableBitmap(二) 实例

    使用前面定义的WriteableBitmap,我们可以很容易地创建一个足够容纳整个100 x 100图像的数组: byte[] pixels = new byte[wbmap.PixelHeight* ...

随机推荐

  1. find命令之时间戳使用示例

    查看当前目录以及子目录下哪些文件占用的空间最大: find  ./  -type  f  -exec du -m {} \; | sort -nr | head find  ./  -type  f ...

  2. 关于如何以编程的方式执行TestNG

    1.如果需要加入一个一个的类 public static void main(String args[]){ TestNG tng = new TestNG(); tng.SetTestClasses ...

  3. 软件工程导论九月26号Homework

    习题3 (1)数据流图 (2)实体关系图ER 习题6

  4. JDK、JRE和JAR区别(转载)

    JDK里面的工具也是用Java编写的,它们本身运行的时候也需要一套JRE,如C:/Program Files/Java/jdk1.5.x/目录下的JRE.而C:/Program Files/Java/ ...

  5. 出现了npm ERR! cb() never called!错误

    执行npm i 命令时,出现了npm ERR! cb() never called!错误 解决方案: 1.首先清除你的npm缓存: sudo npm cache clean -f 一般情况执行完后再试 ...

  6. 为什么JAVA要提供 wait/notify 机制?是为了避免轮询带来的性能损失

    wait/notify  机制是为了避免轮询带来的性能损失. 为了说清道理,我们用“图书馆借书”这个经典例子来作解释. 一本书同时只能借给一个人.现在有一本书,图书馆已经把这本书借了张三. 在简单的s ...

  7. Ubuntu dns

    在Ubuntu系统网络设备启动的流程中,会依赖/etc/network/interface的配置文件初始化网络接口,所以直接在/etc/network/interface之中配置好对应的dns服务器会 ...

  8. 数据库事务(Database Transaction)

    事务(Transaction)是访问并可能更新数据库中各种数据项的一个程序执行单元(unit).事务由事务开始(begin transaction)和事务结束(commit transaction或 ...

  9. iOS 各种方法

    tableViewCell分割线左对齐: - (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)c ...

  10. linux 下 php 安装 event

    1.下载event源码包 https://pecl.php.net/package/event 如:event-2.0.4.tgz 2.解压 > tar zxvf event-2.0.4.tgz ...