【WPF】大量Canvas转换为本地图片遇到的问题
原文地址:https://www.cnblogs.com/younShieh/p/11279420.html
前文
项目中遇到一个难题,需要将上百个没有显示出来的Canvas存储为图片保存在本地。
操作步骤应该是将Canvas转换成位图,然后将位图转换成本地图片。所以一步一步的来吧。
位图转本地文件
查阅资料后(百度一下)后得知把位图转换为本地图片进行保存可以通过BitmapSource来进行转换,通过PngBitmapEncoder() 来实现。具体代码如下:
//path为保存路径
using (FileStream outStream = new FileStream(path, FileMode.Create))
{
PngBitmapEncoder encoder = new PngBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(bitmapSource));
encoder.Save(outStream);
}
Canvas转位图
如何将位图转换成图片的方法知道了,接下来就是要把Canvas转换成Bitmap了。RenderTargetBitmap() 方法就可以实现Visual对象到位图的转换。查看Canvas是继承于Visual的,所以理论上应该没问题。尝试了一下,确实如此。代码如下:
RenderTargetBitmap bitmap = new RenderTargetBitmap((int)canvas.ActualWidth, (int)canvas.ActualHeight, 96, 96, PixelFormats.Pbgra32);
bitmap.Render(canvas);
Canvas测量和定位
理论上到这里就已经完了,但是我的Canvas并没有显示出来,导致ActualWidth和ActualHeight两个属性值都为0,且不能通过设置大小改变其实际尺寸,这就有点抠脑壳了。那就继续查资料吧。对于ActualWidth和ActualHeight这两个属性,MSDN如是说:
此属性是基于其他宽度输入和布局系统的计算的值。
值由布局系统本身基于实际呈现的传递,设置,因此可能稍微小于属性的设置值如Width是作为输入更改的基础。
因为ActualWidth是计算后的值,应注意可能有多次或递增的报告更改为它作为各种操作结果由布局系统。布局系统可能会计算子元素所需的测量空间、父元素的约束等。
MSDN的机翻虽然前言不搭后语,但是大致能明白是什么意思。也就是说ActualWidth和ActualHeight是不能设置的,是通过实际呈现来自动计算出来的。但是我的Canvas没有呈现出来啊,就不能被动计算出来了,这可怎么办呢。。。不可以被动计算,就只有主动去设置,主动计算这条路可以走了。。。又是查阅资料后,还是发现了有路可走的。
通过学习大佬们的经验得知,没有显示的界面也是可以转换成位图的,主要是需要去测量Measure() 和定位Arrange() 来设置Canvas的位置和大小,通过这两个方法可以形成递归布局更新。也就是说通过这两个方法,设置了父元素为子元素计算的最终大小,也就是实际的尺寸。
canvas.Measure(new Size(300, 300));
canvas.Arrange(new Rect(new Size(300,300)));
内存的优化
1. 理论上到这里就已经完了,但是我的Cancas们还有一个先决条件,就是他们有很多。(问题确实有点多。。。)我需要保存的Canvas数量太多,所以不负众望,我的内存爆了(要爆啦~)。但是我已经做了自动回收,没理由啊。 我尝试查找了很多地方的的可能会出现的问题,毫不吝啬的使用 GC.Collect(); Dispose(); using(),异步,并行,多线程 等等等方法,但是却没什么卵用。。。扣破脑壳,一段代码一段代码的屏蔽,分布排查到底是哪里的问题。我以为是位图转换导致的内存泄露,但是分步调试后发现其实并不怎么消耗内存,而且都做了合理的回收。慢慢调试后我发现原来是我的测量Measure() 和定位Arrange() 这两个方法占用的大量的内存,而且应该是没有回收到。
2. 首先我想的是我能不能不用这两个方法。因为我的界面不能显示,所以我要把他放到内存里面去渲染,如果不渲染的话,直接设置RenderTargetBitmap() 的 尺寸得到的是空白的图(试过了。。)。查了很久的资料后,确实是没有找到合适的办法,能做到对不显示的图片不用Arrange() 方法就能转换成位图。所以这两个方法我必须要用,所以也不能投机取巧了,只能硬着头皮上了。
3. baidu、google轮番上阵,MSDN、stackoverflow各路齐飞,,,都没有找到合适的办法解决。或许没有遇到我这么特殊情况的人吧,也有可能是我的搜索方式有问题。不过,正在我扣破脑壳之际,我想到会不会Canvas 也有对应的Dispose() 方法呢?(原谅我已经晕了,Dispose()只能用于继承于IDisposable类”的知识点早已飞到九霄云外)不过,Canvas确实没有的Dispose() 方法,,,伤心,绝望。那会不会有Arrange() 对应的 Dispose() 方法呢?尝试在Canvas后输入Arrage,得到了一个 InvalidateArrange() 方法:
使元素排列状态(布局)无效。 排列状态失效后,该元素将更新其布局,更新将以异步方式发生,除非随后由 System.Windows.UIElement.UpdateLayout强制执行。
使元素排列状态(布局)无效,不就是释放布局占用的内存资源了?尝试了一下,果然如此。内存占用情况再也不是“一行白鹭上青天”了。。。唉,内存爆了的问题就此得以解决,妈妈再也不用担心我的软件崩溃啦~~~
附代码如下:
canvas.Measure(new System.Windows.Size(1920, 1080));
canvas.Arrange(new Rect(0, 0, 1920, 1080));
renderBitmap.Render(canvas);
canvas.InvalidateArrange();
canvas.InvalidateMeasure();
canvas.UpdateLayout();
由此得到的教训是,代码还是得自己敲。。。不然掉到坑你都不知道怎么爬出来。。。
打完收工。
【WPF】大量Canvas转换为本地图片遇到的问题的更多相关文章
- PHP将Base64图片转换为本地图片并保存
本文出至:新太潮流网络博客 /** * [将Base64图片转换为本地图片并保存] * @E-mial wuliqiang_aa@163.com * @TIME 2017-04-07 * @WEB h ...
- HTML5 Canvas显示本地图片实例1、Canvas预览图片实例1
1.前台代码: <input id="fileOne" type="file" /> <canvas id="canvasOne&q ...
- WPF中Image显示本地图片(转)
private void SetSource(System.Windows.Controls.Image image, string fileName) { System.Drawing.Image ...
- html5上传本地图片,在线预览及裁剪(filereader,canvas)
1 我们常常需要上传头像,点击上传按钮时候需要预览一下,使用filereader方法无需和后台交互,代码如下: //本地图片在上传之前的预览效果 //图片上传预览 function previewIm ...
- 【基于WPF+OneNote+Oracle的中文图片识别系统阶段总结】之篇一:WPF常用知识以及本项目设计总结
篇一:WPF常用知识以及本项目设计总结:http://www.cnblogs.com/baiboy/p/wpf.html 篇二:基于OneNote难点突破和批量识别:http://www.cnblog ...
- WPF技巧-Canvas转为位图
转自:http://www.cnblogs.com/tmywu/archive/2010/09/14/1825650.html 在WPF中我们可以将Canvas当成一种画布,将Canvas中的控件当成 ...
- 移动端H5选择本地图片
移动端H5选择本地图片 html://input<input type="file" accept="image/*" capture="cam ...
- 【基于WPF+OneNote+Oracle的中文图片识别系统阶段总结】之篇二:基于OneNote难点突破和批量识别
篇一:WPF常用知识以及本项目设计总结:http://www.cnblogs.com/baiboy/p/wpf.html 篇二:基于OneNote难点突破和批量识别:http://www.cnblog ...
- CANVAS运用-对图片的压缩上传(仅针对移动浏览器)
最近在移动端设计头像上传功能时,原本是以<input type="file">直接通过formData上传,然而实际使用情况是:对于过大的图片(高像素手机所拍摄的照片等 ...
随机推荐
- SpringBoot启动访问JSP页面,直接进入页面或者访问不到,报404,并且加载tomcat插件tomcat-embed-jasper也不行
这个问题花费了两天的时间,解决路径: 我用的是SpringBoot1.5.2,SpringMVC和Spring,tomcat启动插件都是默认的版本,Spring是4.3.7,jdk是1.7.0_80, ...
- SkyWorking基础:6.2版本安装部署
就在今天,SkyWorking发布了6.2版本. 概述 什么是SkyWorking SkyWalking是观察性分析平台和应用性能管理系统. 提供分布式追踪.服务网格遥测分析.度量聚合和可视化一体化解 ...
- vue项目接入api接口
我们在做项目时,一切基础在于数据上面,所以接入api接口是关键. 访问接口是我们会遇到跨域,而,vue-cli给我们提供了反向代理,所以我们只需要配置一下就可以了. 在config文件中找到index ...
- 视频私有云实战:基于Docker构建点播私有云平台
私有云是为一个客户单独使用而构建的,因而提供对数据.安全性和服务质量的最有效控制.前置条件是客户拥有基础设施,并可以使用基础设施在其上部署应用程序.其核心属性是专有的资源.本篇文章将会结合网易云信的实 ...
- 为什么现在这么多人开始学习Python?
近几年Python编程语言在国内引起不小的轰动,有超越JAVA之势,本来在美国这个编程语言就是最火的,应用的非常非常的广泛,而Python的整体语言难度来讲又比JAVA简单的很多.尤其在运维的应用中非 ...
- Go语言学习——channel的死锁其实没那么复杂
1 为什么会有信道 协程(goroutine)算是Go的一大新特性,也正是这个大杀器让Go为很多路人驻足欣赏,让信徒们为之欢呼津津乐道. 协程的使用也很简单,在Go中使用关键字“go“后面跟上要执行的 ...
- HDU 5521:Meeting(最短路)
http://acm.hdu.edu.cn/showproblem.php?pid=5521 Meeting Problem Description Bessie and her friend E ...
- 关于ffmpeg /iis 8.5 服务器下,视频截取第一帧参数配置
ffmpeg 视频截取第一帧参数配置: 网站找了很多资料,但是都不能满足要求,然后自己写下解决过程. 首先看自己PHP 版本,安全选项里面 php5.4 跟php5.6 是不一样的.去除里面的sys ...
- 这样子来理解C语言中指针的指针
友情提示:阅读本文前,请先参考我的之前的文章<从四个属性的角度来理解C语言的指针也许会更好理解>,若已阅读,请继续往下看. 我从4个属性的角度来总结了C语言中的指针概念.对于C语言的一个指 ...
- 20131201-插件-XML-第十二天(未完)
以后再写代码的时候,先从中间层|接口|协议开始入手. 在写XML时注意的事情: 在EditPlus中,Tab是缩进 在头文件中的编码格式是"utf-8"是,在Editplus中保存 ...