原文地址: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没有呈现出来啊,就不能被动计算出来了,这可怎么办呢。。。不可以被动计算,就只有主动去设置,主动计算这条路可以走了。。。又是查阅资料后,还是发现了有路可走的。

https://stackoverflow.com/questions/5189139/how-to-render-a-wpf-usercontrol-to-a-bitmap-without-creating-a-window

  通过学习大佬们的经验得知,没有显示的界面也是可以转换成位图的,主要是需要去测量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转换为本地图片遇到的问题的更多相关文章

  1. PHP将Base64图片转换为本地图片并保存

    本文出至:新太潮流网络博客 /** * [将Base64图片转换为本地图片并保存] * @E-mial wuliqiang_aa@163.com * @TIME 2017-04-07 * @WEB h ...

  2. HTML5 Canvas显示本地图片实例1、Canvas预览图片实例1

    1.前台代码: <input id="fileOne" type="file" /> <canvas id="canvasOne&q ...

  3. WPF中Image显示本地图片(转)

    private void SetSource(System.Windows.Controls.Image image, string fileName) { System.Drawing.Image ...

  4. html5上传本地图片,在线预览及裁剪(filereader,canvas)

    1 我们常常需要上传头像,点击上传按钮时候需要预览一下,使用filereader方法无需和后台交互,代码如下: //本地图片在上传之前的预览效果 //图片上传预览 function previewIm ...

  5. 【基于WPF+OneNote+Oracle的中文图片识别系统阶段总结】之篇一:WPF常用知识以及本项目设计总结

    篇一:WPF常用知识以及本项目设计总结:http://www.cnblogs.com/baiboy/p/wpf.html 篇二:基于OneNote难点突破和批量识别:http://www.cnblog ...

  6. WPF技巧-Canvas转为位图

    转自:http://www.cnblogs.com/tmywu/archive/2010/09/14/1825650.html 在WPF中我们可以将Canvas当成一种画布,将Canvas中的控件当成 ...

  7. 移动端H5选择本地图片

    移动端H5选择本地图片 html://input<input type="file" accept="image/*" capture="cam ...

  8. 【基于WPF+OneNote+Oracle的中文图片识别系统阶段总结】之篇二:基于OneNote难点突破和批量识别

    篇一:WPF常用知识以及本项目设计总结:http://www.cnblogs.com/baiboy/p/wpf.html 篇二:基于OneNote难点突破和批量识别:http://www.cnblog ...

  9. CANVAS运用-对图片的压缩上传(仅针对移动浏览器)

    最近在移动端设计头像上传功能时,原本是以<input type="file">直接通过formData上传,然而实际使用情况是:对于过大的图片(高像素手机所拍摄的照片等 ...

随机推荐

  1. pip与conda的区别

    pip和conda到底有什么不一样? 今天看到我的foreman开始报错去询问才发现.我们的python包管理工具已经从pip整体迁移到了conda..最近的迁移真的非常多..前端也在迁移打包 跟着发 ...

  2. 直播技术:从性能参数到业务大数据,浅谈直播CDN服务监控

    线上服务的有效监控和数据收集,一直是后端服务离不开的话题.直播作为一种经典的分布式系统,监控以及数据收集更是必不可少的工作.如何对海量的服务集群有效的监控和保活,又如何抓取集群中的碎片数据中来优化服务 ...

  3. Java学习笔记——设计模式之七.模板方法模式

    模板方法模式(TemplateMethod),定义一个操作中的算法的骨架,而将一些步骤延迟到子类中.模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤. 结构图: 代码: 算法骨架 ...

  4. Windows 应用容器化

    背景 在这个时间点,我们可能已经对 Linux 容器使用已经达到熟练掌握的程度,因为 Docker 与 Kubernetes 都是最早为 Linux 平台设计.当我们从容器这项技术中体会到种种收益,对 ...

  5. VueRouter认识

    1. 什么是路由? 路由(vue-router)是负责将进入的浏览器请求映射到特定的 组件 代码中.即决定了由谁(组件)去响应客户端请求.简单说路由就是url地址和对应的资源的映射,通过一个路径的ur ...

  6. python的列表使用

    1.什么是列表 列表是由一系列按特定顺序排列的元素,元素之间可以没有任何关系:可以创建空列表,也可以将任何东西添加进列表. 列表用 [ ] 表示: cars = ['golf', 'magotan', ...

  7. C语言学习书籍推荐《C语言入门经典(第4版)》

    霍顿 (Ivor Horton) (作者), 杨浩 (译者) <C语言入门经典(第4版)>的目标是使你在C语言程序设计方面由一位初学者成为一位称职的程序员.读者基本不需要具备任何编程知识, ...

  8. C语言学习书籍推荐《你必须知道的495个C语言问题》

    萨米特 (Steve summit) (作者), 孙云 (译者), 朱群英 (译者) 下载地址:点我 <你必须知道的495个C语言问题>以问答的形式组织内容,讨论了学习或使用C语言的过程中 ...

  9. centos7 + Nginx+ HTTPS + uwsgi + python3.6 + Docker + Django1.11 + mysql 5.6 + virtualenv 环境搭建

    环境搭建: 系统: ​ centos7.2 x64 开发环境: ​ python3.6 ​ Django 1.11 虚拟环境: [Docker](https://www.runoob.com/dock ...

  10. 关于CMTS设备的一些备忘

    博主工作内容包括cable modem,对CM的工作方式有一些了解,但是对CMTS头端怎么带动一个用户小区长久以来一直是一头雾水.今天找了些资料,对这块有了一些了解,并把自己的理解总结下来. 比如我家 ...