原文:Taking WPF “Screenshots”

I was recently working on a Surface project at Microsoft (that will be shown at BETT  ) and one of the requirements was to provide an external “administration console”.  As part of that console I wanted to show an “screenshot” of the current game running on the Surface unit; after playing around for a while it turned out it was pretty straightforward.

We did consider sending over the RAW XAML from the Surface to the Console, but that would potentially have issues when resources weren’t available, so the approach that was taken was to create a JPG screenshot and send it over as a byte array via WCF.

Rendering to a BitmapFrame

The key to this approach is RenderTargetBitmap which allows us to render any WPF Visual to a BitmapFrame as follows:

RenderTargetBitmap renderTarget = new RenderTargetBitmap(, , , , PixelFormats.Pbgra32);
renderTarget.Render(myVisual);
BitmapFrame bitmapFrame = BitmapFrame.Create(renderTarget);

Then from there we can use JpegBitmapEncoder to create a JPG from that BitmapFrame:

JpegBitmapEncoder jpgEncoder = new JpegBitmapEncoder();
jpgEncoder.Frames.Add(bitmapFrame);

Then we can output that JPG to a stream of our choice using the Save() method.

Problems

While this works for many cases, and indeed worked perfectly for the Surface application, we do encounter problems when the source we are rendering has Transforms applied or when it’s not positioned at 0,0.  When this occurs the screenshots we take will have the content shifted“out of frame” resulting in black borders, or content missing altogether.  The following screenshot demonstrates the problem:

Workaround

To work around the problem we can use a VisualBrush to “draw” our source element onto a new Visual, and render that with our RenderTargetBitmap:

DrawingVisual drawingVisual = new DrawingVisual();
DrawingContext drawingContext = drawingVisual.RenderOpen();
using (drawingContext)
{
drawingContext.DrawRectangle(sourceBrush, null, new Rect(new Point(, ), new Point(, )));
}
renderTarget.Render(drawingVisual);

It’s not ideal, but I’ve yet to find a better workaround for it.

Putting it all Together

To make it more useful, we can wrap the whole lot up into a Extension Method.  Rather than extending Visual, I’ve chosen to use UIElement so I have access to the RenderSize to calculate the required size of the output bitmap.  I’ve also included parameters to scale the resulting bitmap and to set the JPG quality level:

///
/// Gets a JPG "screenshot" of the current UIElement
///
/// UIElement to screenshot
/// Scale to render the screenshot
/// JPG Quality
/// Byte array of JPG data public static byte[] GetJpgImage(this UIElement source, double scale, int quality)
{
double actualHeight = source.RenderSize.Height;
double actualWidth = source.RenderSize.Width; double renderHeight = actualHeight * scale;
double renderWidth = actualWidth * scale; RenderTargetBitmap renderTarget = new RenderTargetBitmap((int) renderWidth, (int) renderHeight, , , PixelFormats.Pbgra32); VisualBrush sourceBrush = new VisualBrush(source); DrawingVisual drawingVisual = new DrawingVisual(); DrawingContext drawingContext = drawingVisual.RenderOpen(); using (drawingContext)
{
drawingContext.PushTransform(new ScaleTransform(scale, scale)); drawingContext.DrawRectangle(sourceBrush, null, new Rect(new Point(, ), new Point(actualWidth, actualHeight)));
} renderTarget.Render(drawingVisual); JpegBitmapEncoder jpgEncoder = new JpegBitmapEncoder(); jpgEncoder.QualityLevel = quality; jpgEncoder.Frames.Add(BitmapFrame.Create(renderTarget)); Byte[] _imageArray; using (MemoryStream outputStream = new MemoryStream()) { jpgEncoder.Save(outputStream); _imageArray = outputStream.ToArray(); } return _imageArray;
}

WPF 对控件进行截图且不丢失范围(转载)的更多相关文章

  1. wpf 对控件进行截图,获取快照

    有时候我们项目,在执行某个操作后,会生成一些数据结果,如报表一类的东西,我们需要对结果进行保存,甚至是生成word文档. 那么首先获取到控件快照就最基本的条件. 生成快照的静态方法类 using Sy ...

  2. WPF常用控件应用demo

    WPF常用控件应用demo 一.Demo 1.Demo截图如下: 2.demo实现过程 总体布局:因放大缩小窗体,控件很根据空间是否足够改变布局,故用WrapPanel布局. <ScrollVi ...

  3. WPF开源控件扩展库 - MaterialDesignExtensions

    Material Design Extensions 在WPF开源控件库 Material Design in XAML Toolkit(本站介绍:链接)的基础上进行了控件扩展和特性新增.本开源项目中 ...

  4. C# WPF开源控件库:MahApps.Metro

    其实站长很久之前就知道这个开源WPF控件库了,只是一直欣赏不了这种风格,但也star了该项目.每次浏览该仓库时,发现star越来越多,也看到很多网友对它的褒奖,所以今天就向大家推荐这款WPF控件库. ...

  5. WPF Popup 控件导致被遮挡内容不刷新的原因

    WPF Popup 控件导致被遮挡内容不刷新的原因 周银辉 今天在写一个WPF控件时用到了Popup控件,很郁闷的情况是:当popup关闭时,原来被popup挡住的界面部分不刷新,非要手动刷新一下(比 ...

  6. 创建 WPF 工具箱控件

    创建 WPF 工具箱控件 WPF (Windows Presentation Framework) 工具箱控件模板允许您创建 WPF 控件,会自动添加到 工具箱 安装扩展的安装. 本主题演示如何使用模 ...

  7. wpf打印控件 实现分页打印控件功能

    因为 要实现打印 wpf  listbox控件  数据特别多 要打印在 几张纸上    找了几天 都没有找到相关的例子 现在 解决了 在这里和大家分享一下 public void print(Fram ...

  8. WPF 分页控件 WPF 多线程 BackgroundWorker

    WPF 分页控件 WPF 多线程 BackgroundWorker 大家好,好久没有发表一篇像样的博客了,最近的开发实在头疼,很多东西无从下口,需求没完没了,更要命的是公司的开发从来不走正规流程啊, ...

  9. WPF Image控件中的ImageSource与Bitmap的互相转换

    原文:WPF Image控件中的ImageSource与Bitmap的互相转换  1.从bitmap转换成ImageSource [DllImport("gdi32.dll", ...

随机推荐

  1. 绕过PALOALTO TRAPS EDR解决方案

    0x1 技术点 PaloAlto Traps(EDR解决方案)基于行为封锁和标记许多黑客工具. 0x2 绕过方法 最简单的解决方案就是禁用内置实用程序,即; Cytool.Cytool是一个集成命令行 ...

  2. BIM 3D 数据交换格式 ----张建平(清华女)

    1.collada   EXPORTER 2.FBX    3D MAX 3.DAE 4.3D中的OBJ文件格式详解 (  http://www.cnblogs.com/slysky/p/408130 ...

  3. C#编写COM组件

    1.新建一个类库项目 2.将Class1.cs改为我们想要的名字 问是否同时给类改名,确定 3.修改Properties目录下面的AssemblyInfo.cs ComVisible属性设置为True ...

  4. 解决64bit不能连接access的问题

    原有的程序迁移至64位,结果调用数据库时出错,原因是jet驱动没有64位的,得换用64位的驱动程序:   1. 下载运行 AccessDatabaseEngine_x64.exe (http://ww ...

  5. 【转】ArrayList与LinkedList的区别和适用场景

    ArrayList 优点:ArrayList是实现了基于动态数组的数据结构,因为地址连续,一旦数据存储好了,查询操作效率会比较高(在内存里是连着放的). 缺点:因为地址连续,当要插入和删除时,Arra ...

  6. Win10系统BitLocker解锁后再次快速锁定办法

    原文地址:https://blog.csdn.net/ttljtw/article/details/54022241 谁都不愿意把自己电脑上资料完全公开,对资料选择性加密处理是唯一的办法. 微软Win ...

  7. (常用)os模块

    os.getcwd() 获取当前工作目录,即当前python脚本工作的目录路径os.chdir("dirname")  改变当前脚本工作目录:相当于shell下cdos.curdi ...

  8. ansible笔记(7):常用模块之系统类模块

    ansible笔记():常用模块之系统类模块 cron模块 cron模块可以帮助我们管理远程主机中的计划任务,功能相当于crontab命令. 在了解cron模块的参数之前,先写出一些计划任务的示例,示 ...

  9. nginx负载均衡优化配置

    针对nginx做负载均衡时其中一台服务器挂掉宕机时响应速度慢的问题解决 nginx会根据预先设置的权重转发请求,若给某一台服务器转发请求时,达到默认超时时间未响应,则再向另一台服务器转发请求. 默认超 ...

  10. vmware不能装ghost系统怎么解决

    一般情况下一台电脑最好只安装一个系统,因为多系统容易出现问题,所以很多用户都会在Vmware虚拟机上安装其他的系统,为了安装的方便,我们会选择ghost版的系统快速安装,但是有用户遇到vmware虚拟 ...