【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上传,然而实际使用情况是:对于过大的图片(高像素手机所拍摄的照片等 ...
随机推荐
- JavaScript 操作 DOM 总结
基本概念 DOM 是 JavaScript 操作网页的接口,全称为"文档对象模型"(Document Object Model).它的作用是将网页转为一个 JavaScript 对 ...
- Java学习笔记——三层架构
Layer: UI层: user interface 用户接口层 Biz层: service business login layer 业务逻辑层 DAO层: Date Access Obje ...
- Singleton and Prototype Bean Scope in Spring
Scope描述的是Spring容器如何新建Bean的实例的. 1> Singleton: 一个Spring容器只有一个Bean的实例,此为Spring的默认配置,全容器共享一个实例. 2> ...
- Requests方法 -- 重定向操作
一.重定向1. (Redirect)就是通过各种方法将各种网络请求重新定个方向转到其它位置,从地址A跳转到地址 B 了.2.重定向状态码:--301 redirect: 301 代表永久性转移(Per ...
- 趣解 ceph rgw multisite data sync 机制
multisite是ceph rgw对象数据异地容灾备份的一个有效方案,笔者希望深入理解该技术,并应用于生产环境中,然而rgw的这部分代码晦涩难懂,笔者多次尝试阅读,仍云里雾里不解其意,最终流着泪咬着 ...
- header 无法实现跳转
错误:Warning: Cannot modify header information - headers already sent by (output started at 方法:“php.in ...
- Thinkphp5.0之异常处理
1.默认异常处理在调试模式下,系统默认展示的错误页面:请输入图片描述 异常处理接管 1.修改config.php 'app_debug' => false,2.在配置文件里添加如下代码 // 异 ...
- spark入门(二)RDD基础操作
1 简述 spark中的RDD是一个分布式的元素集合. 在spark中,对数据的所有操作不外乎创建RDD,转化RDD以及调用RDD操作进行求值,而这些操作,spark会自动将RDD中的数据分发到集群上 ...
- c++汉诺塔问题
c++解决汉诺塔问题 题目描述 约19世纪末,在欧州的商店中出售一种智力玩具,在一块铜板上有三根杆,最左边的杆上自上而下.由小到大顺序串着由64个圆盘构成的塔.目的是将最左边杆上的盘全部移到中间的杆上 ...
- 基于go语言结合微信小程序开发的微商城系统
最近在慕课网上录制了一门<Golang微信小程序微商城系统原型>,这门免费课程特别适合在校大学生或者刚毕业的大学生,go语言初学者以及想要从事微商城开发项目入门的小伙伴们来学习.在课程当中 ...