【WP8.1开发】RenderTargetBitmap类的特殊用途

相信,耍过WPF的人都知道RenderTargetBitmap这个玩意儿,这家伙比较有意思,它可以将用户界面上呈现的东西写入到内存的位图对象,从而开发者可以在应用程序中使用它,或者将其保存为图像文件。

在Runtime API里面也有这个位图组件,可以将UI元素呈现到位图中,当然,它也不是万能的,首先,要写入到位图中的UI对象必须已经在用户界面上呈现了,也就是说,只要你能看到界面上出现的东东,它才会写入位图对象;其次,要呈现到位图中的UI元素需要位于可视化树中,我简单地总结为:只要是放在Page内并且可见的元素,都可以生成位图。

调用RenderTargetBitmap类的RenderAsync方法来将可视化对象呈现到RenderTargetBitmap中,如果只是在应用程序中显示该生成的位图,那么,直接把RenderTargetBitmap对象赋值给Image控件的Source属性即可。

要是希望保存为图像文件,就要用到BitmapEncoder类,也就是图像编码。大家知道,在编码图像文件时,是向流中写入字节数组(byte[])作为图像的像素数据的,那么,如何提取RenderTargetBitmap位图中的像素数据呢。你会发现RenderTargetBitmap类有个GetPixelsAsync方法,对的,通过该方法就可以返回位图的像素数据,只不过其类型为IBuffer,这样大家又会疑惑了,如何变成byte[]呢?

勿急,你只要引入System.Runtime.InteropServices.WindowsRuntime命名空间,里面就有相关类型为IBuffer定义了扩展方法——ToArray,调用它可以返回byte[]。

之后的事情就好办了。

理论永远是抽象的,咱们还是干点实事吧,这里我弄了个不那么美观的示例。

示例项目中有四张图片,顺便Show一下老周的书法作品。在应用页面上,把这四张图片分别作为画刷来填充图形。XAML如下:

    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>
        <Canvas x:Name="cv">
            <Ellipse Width="250" Height="200" Canvas.Left="50" Canvas.Top="20">
                <Ellipse.Fill>
                    <ImageBrush ImageSource="/01.png" Stretch="UniformToFill"/>
                </Ellipse.Fill>
            </Ellipse>
            <Rectangle Width="180" Height="250" Canvas.Top="240" Canvas.Left="10" RadiusX="12" RadiusY="20">
                <Rectangle.Fill>
                    <ImageBrush ImageSource="/02.png" Stretch="UniformToFill"/>
                </Rectangle.Fill>
            </Rectangle>
            <Polygon Points="50,0 100,50 50,100 0,50" Width="240" Height="240" Canvas.Left="150" Canvas.Top="230" Stretch="Uniform">
                <Polygon.Fill>
                    <ImageBrush ImageSource="03.png" Stretch="UniformToFill"/>
                </Polygon.Fill>
            </Polygon>
            <Ellipse Width="130" Height="130" Canvas.Left="245" Canvas.Top="80">
                <Ellipse.Fill>
                    <ImageBrush ImageSource="/04.png" Stretch="UniformToFill"/>
                </Ellipse.Fill>
            </Ellipse>
        </Canvas>

        <Button Content="保存图像文件" Grid.Row="1" Click="OnClick"/>
    </Grid>

然后,处理Button的事件,生成图片,保存到相册中的“保存的图片”中。

        private async void OnClick(object sender, RoutedEventArgs e)
        {
            Button b = sender as Button;
            b.IsEnabled = false;
            StorageFolder savedPics = KnownFolders.SavedPictures;
            // 1、在位图中呈现UI元素
            RenderTargetBitmap rtb = new RenderTargetBitmap();
            await rtb.RenderAsync(this.cv);
            // 提取像素数据
            IBuffer buffer = await rtb.GetPixelsAsync();

            // 创建新文件
            StorageFile newFile = await savedPics.CreateFileAsync("test-3-7-11-5.png", CreationCollisionOption.ReplaceExisting);
            // 获取文件流
            IRandomAccessStream streamOut = await newFile.OpenAsync(FileAccessMode.ReadWrite);
            // 实例化编码器
            BitmapEncoder pngEncoder = await BitmapEncoder.CreateAsync(BitmapEncoder.PngEncoderId, streamOut);
            // 写入像素数据
            byte[] data = buffer.ToArray();
            pngEncoder.SetPixelData(BitmapPixelFormat.Bgra8,
                                    BitmapAlphaMode.Straight,
                                    (uint)rtb.PixelWidth,
                                    (uint)rtb.PixelHeight,
                                    96d, 96d, data);
            await pngEncoder.FlushAsync();
            streamOut.Dispose();
            b.IsEnabled = true;
        }

运行效果如下图

在写入像素数据时,最常用的格式是rgba8或bgra8,一般8位够用了,虽然就是R值和B值的通道顺序不同,但这两种格式所保存的图片文件效果不太一样,我觉得bgra8好一点,没有偏色。

下面是保存后的PNG图片,左边的是用RGBA格式的,右边是用BGRA格式的,大家自行比较吧。

           

虽然老周的书法水平不怎么样,大家将就着看吧,重点是看RenderTargetBitmap类的用法。

示例下载:http://files.cnblogs.com/tcjiaan/RenderUiApp.zip

好,再次感谢您收看老周吹牛节目,再见。

时间: 01-22

【WP8.1开发】RenderTargetBitmap类的特殊用途的相关文章

JAVA串口开发帮助类分享-及写在马年末

在系统集成开发过程中,存在着各式的传输途径,其中串口经常因其安全性高获得了数据安全传输的重用,通过串口传输可以从硬件上保证数据传输的单向性,这是其它介质所不具备的物理条件.下面我就串口java开发的过程分享一下,并分享一个SerialPortHandler串口开发帮助类,以提高串口开发效率. 1.部署开发环境. 拷贝RXTXcomm.jar 文件到 \jre\lib\ext 目录下,拷贝rxtxSerial.dll文件到 \jre\bin目录下.注意是jre目录下,并非jdk\jre下:注意dl

7.2.3 使用RenderTargetBitmap类生成图片

RenderTargetBitmap类可以将可视化对象转换为位图,也就是说它可以将任意的UIElement以位图的形式呈现.那么我们在实际的编程中通常会利用RenderTargetBitmap类来对UI界面进行截图操作,比如把程序的界面或者某个控件的外观生成一张图片. 使用RenderTargetBitmap类生成图片一般有两种用途,一种是直接把生成的图片在当前的页面上进行展示,还有一种用途是把生成的图片当作文件存储起来,或者通过某种分享方式把图片文件分享出去.那么第二种用途的编程实现肯定是在第

HBase概念学习(八)开发一个类twitter系统之表设计

这边文章先将可能的需求分析一下,设计出HBase表,下一步再开始编写客户端代码. TwiBase系统 1.背景 为了加深HBase基本概念的学习,参考HBase实战这本书实际动手做了这个例子. 2.需求 这是一个用户推特系统,用户登陆到系统,需要维护用户的基本信息,然后用户可以发帖和其他用户进行互动.用户之间可以相互关注,用户可以浏览关注用户的推文等等. 这是一个比较简单的推特系统,不考虑用户之间的私信,用户评论推特等功能. 3.概要设计 3.1表设计 首先需要设计三个表:用户表,推特表以及用户

C# 开发 &mdash;&mdash; 数组类对象接口

数组类型是从抽象基类 Array 派生的引用类型,通过new运算符创建数组并将数组元素初始化为他们的默认值 一维数组 type[] arrayname; 数组的长度不是声明的一部分,而且数组必须在访问前初始化. foreach 语句声明一个迭代变量 -- 是数组的每个元素的只读副本 二维数组 type[,]  arrayName; int[,] arr = new int[2,2]{{1,2},{3,4}}; 可使用数组的Rank属性和GetUpperBound方法获取数组的行数和列数,然后遍历

WP8.1开发:简单的天气预报应用

今天小梦给大家分享一个简单的天气预报应用源码:调用的是百度API.整个应用都没有什么难点.只是一个简单的网络请求和json数据处理.在WP8.1有小娜的情况下,天气预报应用还有意义吗?我认为还是有点意义的,至少数据更详细,而要想要用户喜欢,必须有比小娜更人性化的提醒和精美的UI.UI必须要精美.当然小梦今天分享的UI很简单.大家可以根据自己的想象去处理UI.之所以分享出来,是分享JSON的数据处理.在WP8.1开发XML读取中央气象城市代码文件中,分享了XML文件和JSON数据解析的方法,不过其

WP8.1开发:简单天气预报应用(转)

今天小梦给大家分享一个简单的天气预报应用源码:调用的是百度API.整个应用都没有什么难点.只是一个简单的网络请求和json数据处理.在WP8.1有小娜的情况下,天气预报应用还有意义吗?我认为还是有点意义的,至少数据更详细,而要想要用户喜欢,必须有比小娜更人性化的提醒和精美的UI.UI必须要精美.当然小梦今天分享的UI很简单.大家可以根据自己的想象去处理UI.之所以分享出来,是分享JSON的数据处理.在WP8.1开发XML读取中央气象城市代码文件中,分享了XML文件和JSON数据解析的方法,不过其

WEB前端开发 辨析类 面试真题 大集锦

WEB前端开发 辨析类 面试真题 大集锦 HTML5学堂-码匠:面试里最常出现的问题句式大概就是"说说XXX和XXX的区别""谈谈XXX和XXX的不同"了吧~!一波波的辨析题正在袭来,快快开启防御,杀出重围,来一场绝地反击! 僵尸,啊,不对,辨析三连发! 扫描了众多的面试题,发现--额--各个技术之间的辨析真的是如僵尸一般,一波一波的~ 相信不少人都在面试当中遇到过各类的辨析题,面试的画风大概是这样的 -- 面试官:strong.em.b.i的区别是什么? 面试官:

百度地图V2.0实践项目开发工具类bmap.util.js V1.4

/** * 百度地图使用工具类-v2.0(大眾版) * * @author boonya * @date 2013-7-7 * @address Chengdu,Sichuan,China * @email [email protected] * @company KWT.Shenzhen.Inc.com * @notice 有些功能需要加入外部JS库才能使用,另外还需要申请地图JS key . * 申请地址:http://developer.baidu.com/map/apply-key.ht

C#学习(九)- WP8.1开发的一些收获

本篇属于总结性记录,知识点会相对凌乱. 1. 关于SQLlite数据库的应用 关于如何设置Visual Studio 2013使SQLlite数据库可用,参见http://www.cnblogs.com/tiny-home/p/4474861.html,在此不再赘述.主要分享我使用SQLlite过程中遇到的问题和收获. 首先要建一个类,用以表示在SQLlite数据库中表示的记录,相当于普通数据库中的create语句,用来定义表中每条记录有多少列,每列是什么类型的量,每条记录就是一个对象.比如: