Windows应用开发有很多场景需要动态获取控件显示的图像,即控件转图片,用于其它界面的显示、传输图片数据流、保存为本地图片等用途。
下面分别介绍下一些实现方式以及主要使用场景
RenderTargetBitmap
控件转图片BitmapImage/BitmapSource,在WPF中可以使用RenderTargetBitmap获取捕获控件的图像。
RenderTargetBitmap 是用于将任何 Visual 元素内容渲染为位图的主要工具
下面我们展示下简单快速的获取控件图片:
获取当前窗口所在屏幕DPI,使用控件已经渲染的尺寸,就可以捕获到指定控件的渲染图片。捕获到图片BitmapSource,即可以将位图分配给Image的Source属性来显示。
上面方法获取的是BitmapSource,BitmapSource是WPF位图的的抽象基类,继承自ImageSource,因此可以直接用作WPF控件如Image的图像源。RenderTargetBitmap以及BitmapImage均是BitmapSource的派生实现类
RenderTargetBitmap此处用于渲染Visual对象生成位图,RenderTargetBitmap它可以用于拼接、合并(上下层叠加)、缩放图像等。BitmapImage主要用于从文件、URL及流中加载位图。
而捕获返回的基类BitmapSource可以用于通用位图的一些操作(如渲染、转成流数据、保存),BitmapSource如果需要转成可以支持支持更高层次图像加载功能和延迟加载机制的BitmapImage,可以按如下操作:
这里选择了Png编码器,先将bitmapSource转换成图片流,然后再解码为BitmapImage。
图片编码器有很多种用途,上面是将流转成内存流,也可以转成文件流保存本地文件:
回到控件图片捕获,上方操作是在界面控件渲染后的场景。如果控件未加载,需要更新布局下:
另外也存在场景:控件不确定它的具体尺寸,只是想单纯捕获图像,那代码整理后如下:
控件未加载时,可以使用DesiredSize来临时替代操作,这类方案获取的图片宽高比例可能不太准确。已加载完的控件,可以通过VisualTreeHelper.GetDescendantBounds获取视觉树子元素集的坐标矩形区域Bounds。
kybs00/VisualImageDemo: RenderTargetBitmap获取控件图片 (github.com)
所以控件转BitmapSource、保存等,可以使用RenderTargetBitmap来实现
VisualBrush
如果只是程序内其它界面同步展示此控件,就不需要RenderTargetBitmap了,可以直接使用VisualBrush
VisualBrush是非常强大的类,允许使用另一个Visual对象(界面显示控件最底层的UI元素基类)作为画刷的内容,并将其绘制在其它UI元素上(当然,不是直接挂到其它视觉树上,WPF也不支持元素同时存在于俩个视觉树的设计)
具体的可以看下官网 VisualBrush 类 (System.Windows.Media) | Microsoft Learn,这里做一个简单的DEMO:
CS代码:
kybs00/VisualImageDemo: RenderTargetBitmap获取控件图片 (github.com)
左侧操作一个控件移动,右侧区域动态同步显示左侧视觉。VisualBrush.Visual可以直接绑定指定控件,一次绑定、后续同步界面变更,延时超低
同步界面变更是如何操作的?下面是部分代码,我们看到,VisualBrush内有监听元素的内容变更,内容变更后VisualBrush也会自动同步DoLayout(element)一次:
而显示绑定元素,VisualBrush内部是通过元素Visual.Render方法将图像给到渲染上下文:
其内部是将Visual的快照拿来显示输出。VisualBrush基于这种渲染快照的机制,不会影响原始视觉元素在原来视觉树的位置,所以并不会导致不同视觉树之间的冲突。
此类VisualBrush方案,适合制作预览显示,比如打印预览、PPT页面预览列表等。
下面是我们团队开发的会议白板-页面列表预览效果:
关键字:RenderTargetBitmap、VisualBrush、控件转图片/控件截图
作者:唐宋元明清2188