Problem of saving images in WPF (RenderTargetBitmap)zz
But sometimes you will find the output image was shifted or left blank. This is because that RenderTargetBitmap render the visual object based on cordinate of its parent object. Margin of itself, Padding or BorderThickness of its parent will all affect the rendered image. Although I think this is a bug of WPF, it seems the feature is by design as reference to RenderTargetBitmap layout offset influence.
There are three ways to fix the problem,
| Solution | Description |
|---|---|
| Add a Border | Simple, but the visual logical tree is changed. |
| Use a VisualBrush | Maintain the original visaul logical tree, but need to do more process. |
| Temporary change the reative postion by Measure() and Arrange() | Need to change back after rendering, and the two function is automatically called while repainting by WPF, so the real process is hard to tell. |
The first solution is simplist. RenderTargetBitmap is only shifted by the distance between visaul and its parent object, so you just need to add a fake parent and move the margin to the parent object.
If the original visual logical tree is like
<Grid>
<Canvas Margin="20" />
</Grid>
changed to
<Grid>
<Border Margin="20">
<Canvas />
</Border>
</Grid>
and just call the method of SaveTo as Save and read images in WPF.
private void SaveTo(Visual v, string f)
{
/// get bound of the visual
Rect b = VisualTreeHelper.GetDescendantBounds(v);
/// new a RenderTargetBitmap with actual size of c
RenderTargetBitmap r = new RenderTargetBitmap(
(int)b.Width, (int)b.Height,
96, 96, PixelFormats.Pbgra32);
/// render visual
r.Render(v);
/// new a JpegBitmapEncoder and add r into it
JpegBitmapEncoder e = new JpegBitmapEncoder();
e.Frames.Add(BitmapFrame.Create(r));
/// new a FileStream to write the image file
FileStream s = new FileStream(f,
FileMode.OpenOrCreate, FileAccess.Write);
e.Save(s);
s.Close();
}
Second solution is draw the visaul to a DrawingVisual object, and pass the object to the SaveTo function.
private DrawingVisual ModifyToDrawingVisual(Visual v)
{
/// new a drawing visual and get its context
DrawingVisual dv = new DrawingVisual();
DrawingContext dc = dv.RenderOpen();
/// generate a visual brush by input, and paint
VisualBrush vb = new VisualBrush(v);
dc.DrawRectangle(vb, null, b);
dc.Close();
return dv;
}
PS. The context will act after calling Close(). You can use the using statement to block the region. And the SaveTo method should be modified as
/// render visual
r.Render(ModifyToDrawingVisual(v));
The third solution is to temporarily change the reative postion by Measure and Arrange before Render,
private void ModifyPosition(FrameworkElement fe)
{
/// get the size of the visual with margin
Size fs = new Size(
fe.ActualWidth +
fe.Margin.Left + fe.Margin.Right,
fe.ActualHeight +
fe.Margin.Top + fe.Margin.Bottom);
/// measure the visual with new size
fe.Measure(fs);
/// arrange the visual to align parent with (0,0)
fe.Arrange(new Rect(
-fe.Margin.Left, -fe.Margin.Top,
fs.Width, fs.Height));
}
PS. The solution is only suitable for UIElement, and need to change the position back after rendering.
private void ModifyPositionBack(FrameworkElement fe)
{
/// remeasure a size smaller than need, wpf will
/// rearrange it to the original position
fe.Measure(new Size());
}
Because the size to be measured is smaller then the real size, WPF will rearrange the layout and align the position back. And the render part is modified as
/// render visual
ModifyPosition(v as FrameworkElement);
r.Render(v);
ModifyPositionBack(v as FrameworkElement);
About Measure() and Arrange(), detail is reference toUIElement.Measure Method
--
Reference
RenderTargetBitmap layout offset influence
RenderTargetBitmap tips
RenderTargetBitmap and XamChart - Broken, Redux
Problem of saving images in WPF (RenderTargetBitmap)zz的更多相关文章
- wpf RenderTargetBitmap保存控件为图片时图片尺寸不对的问题
使用RenderTargetBitmap渲染图片时,必须在需要渲染的控件外层包含一个border控件,不然渲染的图片返回就会出现问题. 如下: <Grid> <Grid.RowDef ...
- WPF:如何高速更新Model中的属性
原文:[WPF/MVVM] How to deal with fast changing properties In this article, I will describe a problem w ...
- ACM/ICPC 2018亚洲区预选赛北京赛站网络赛 A、Saving Tang Monk II 【状态搜索】
任意门:http://hihocoder.com/problemset/problem/1828 Saving Tang Monk II 时间限制:1000ms 单点时限:1000ms 内存限制:25 ...
- 导出程序界面(UI)到图片
无意间看到这个需求,查阅了相关文章,有两篇不错的博客给出了解决方案,地址如下: 1.在WPF程序中将控件所呈现的内容保存成图像 2.随心所欲导出你的 UI 界面到 PDF 文件 主要使用的接口: Si ...
- 随心所欲导出你的 UI 界面到 PDF 文件
使用 C1PDF 控件可以导出文件到 PDF 文件,结合 .NET 平台特性你可以在任何客户端生成自定义报表.你可以打印任何 UI 界面,例如 DataGrid 导出到 PDF. 在本篇文章中我们将阐 ...
- TensorFlow 生成 .ckpt 和 .pb
原文:https://www.cnblogs.com/nowornever-L/p/6991295.html 1. TensorFlow 生成的 .ckpt 和 .pb 都有什么用? The . ...
- Emacs及扩展配置
Emacs及扩展配置 Table of Contents 1. 动机之反思 2. 它山之石 3. 扩展的管理 4. 我额外安装的通用扩展(在purcell基础上) 5. LaTex相关的问题和配置 6 ...
- 客户端类中中记录异常的方法: 使用Log4net
1.首先引用Log4Net 的命名空间 using log4net; 2.在使用的类中生命静态变量 log public class FileService { static re ...
- COM Error Code(HRESULT)部分摘录
Return value/code Description 0x00030200 STG_S_CONVERTED The underlying file was converted to compou ...
随机推荐
- 目标电脑未安装VC++6.0或者VS,运行APP丢失DLL问题解决办法
一.背景 VS或者VC++6.0编译出来的程序需要在未安装VS/VC++6.0的电脑上跑,很大情况会出现MSVCRXXX.dll 或者其他DLL丢失的情形,本篇就DLL相关问题做个记录. 二.正文 1 ...
- 各大浏览器内核介绍(Rendering Engine)
在介绍各大浏览器的内核之前,我们先来了解一下什么是浏览器内核. 所谓浏览器内核就是指浏览器最重要或者说核心的部分"Rendering Engine",译为"渲染引擎&qu ...
- Node.js学习笔记(一)
1.回调函数 node是一个异步事件驱动的平台,所以在代码中我们经常需要使用回调函数. 例: setTimeout(function(){ console.log('callback is calle ...
- WebApp开发之--"rem"单位
随着web app的兴起,rem这是个低调的css单位,近一两年开始崭露头角,有许多朋友对于它的评价不一,有的在尝试使用,有的在使用过程中遇到坑就弃用了.但是我认为rem是用来做web app它绝对是 ...
- Vim 资料总结
vi/vim基本使用方法:http://www.cnblogs.com/itech/archive/2009/04/17/1438439.html Vim命令合集: http://www.cnblog ...
- mysql使用load导入txt文件所遇到的问题及解决方法
导入txt文件,有导入向导这种方式: 另外可以使用load的方式导入.最开始使用以下代码插入: load data local infile 'F:\\Data\\predict_data.txt' ...
- Unity 好坑的Save Scene
在编辑一个Untiy工程的时候,有很多的教程提到了 "Save Scene",也知道是干么用的.但是,后面打开工程的时候,工程界面是很多东西都不见了,又忘了有个Save Scene ...
- Reverse Core 第二部分 - 16&17章 - 基址重定位表&.reloc节区
第16-17章 - 基址重定位表&.reloc节区 @date: 2016/11/31 @author: dlive 0x00 前言 这几天忙着挖邮箱漏洞,吃火锅,马上要被关禁闭,看书进度比较 ...
- Centos7 wifi
centos7如果在安装系统选择安装软件的选项是gnome套件(要注意退出选择界面回到安装界面时软件选项显示的是gnome,仅仅选择了gnome的软件也不行),安装完成后就会有wifi的图标,下面的方 ...
- MongoVue中Collections无法显示的问题
问题描述: 通过Python向MongoDB写入数据后,MongoVue中Collections无法显示的问题 原因: Mongodb 3.0之后默认的 storageEngine为wiredTige ...