Problem of saving images in WPF (RenderTargetBitmap)zz
2016-06-12 16:25
447 查看
To save a visual to an image file need to use RenderTargetBitmap, detail is reference to Save and read images in WPF.
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. |
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
相关文章推荐
- 利用mybatis-generator自动生成代码
- Node.js环境下JavaScript实现单链表与双链表结构
- jQuery.ajax 调用 服务(.aspx,.asmx)
- python错误:IndentationError:expected an indented block
- 将Jar加入到Maven仓库
- JAVA是解释型语言还是编译型语言
- 网站开发进阶(三十四)编码中的setCharacterEncoding 理解
- Déjà-vu 现象
- 网站开发进阶(三十四)编码中的setCharacterEncoding 理解
- ubuntu用下载的文件替换即可更新
- 数据库事务介绍
- java常用工具类整理
- oc内存原理
- Android生命周期详解
- intent的简单用法
- String,StringBuffer,StringBuilder区别
- 面试注意点
- svn回滚文件
- 高并发系统之限流特技 --一路狂奔
- 飞机大战游戏及源码地址