WPF中加载图片代码优化方案.docx_第1页
WPF中加载图片代码优化方案.docx_第2页
WPF中加载图片代码优化方案.docx_第3页
WPF中加载图片代码优化方案.docx_第4页
WPF中加载图片代码优化方案.docx_第5页
已阅读5页,还剩3页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

方案1.WPF异步加载BitmapImage当你在WPF主线程中时不时需要加载图片时,界面上的Animation会因为IO操作而卡壳,要想保持动画的流畅就必须将IO操作放到后台线程中操作,如下:private void ChangeImage() Image image = new Image(); new Thread(new ThreadStart() = BitmapImage bitmap = new BitmapImage(); bitmap.BeginInit(); bitmap.UriSource = new Uri(imagesindex+ % images.Count); bitmap.CacheOption = BitmapCacheOption.OnLoad; bitmap.EndInit(); bitmap.Freeze(); Dispatcher.BeginInvoke(Action)() = image.Source = bitmap; image.Stretch = Stretch.UniformToFill; TransitionBox.Content = image; ); ).Start();方案2.WPF中加载高分辨率图片性能优化 在最近的项目中,遇到一个关于WPF中同时加载多张图片时,内存占用非常高的问题。问题背景: 在一个ListView中同时加载多张图片,注意:我们需要加载的图片分辨率非常高。代码XAML: C#:public partial class MainWindow : Window public MainWindow() InitializeComponent(); private void Button_Click(object sender, RoutedEventArgs e) lvImages.Items.Clear(); / Image folder location: D:Pics string files = System.IO.Directory.GetFiles(D:Pics); List models = new List(); foreach(var path in files) BitmapImage image = new BitmapImage(); image.BeginInit(); image.UriSource = new System.Uri(path); image.EndInit(); image.Freeze(); models.Add(new ImageSourceModel() ImageSource = image ); lvImages.ItemsSource = models; public class ImageSourceModel public ImageSource ImageSource get; set; 优化方案:(1). 初始加载时,只加载部分图片并显示。当ScrollViewer滚动到底部时,再加载一部分。关于这个方案,可以参考 WPF MVVM模式下实现ListView下拉显示更多内容;但是这并不能解决最终内存占用过高的情况。(2). 给图片设置DecodePixelWidth属性,BitmapImage image = new BitmapImage(); image.BeginInit(); image.UriSource = new System.Uri(path); image.DecodePixelWidth = 800; image.EndInit(); image.Freeze();models.Add(new ImageSourceModel() ImageSource = image );方案3.wpf大图片处理速度优化:指针操作,并行操作,几十倍优化(1)标准的int30数组遍历计算 release 0.28sunsafe public static void TestGray1(this WriteableBitmap bmp) using (var context = bmp.GetBitmapContext() int height = context.Height; int width = context.Width; for (int y = 0; y height; y+) for (int x = 0; x 16); var g = (byte)(c 8); var b = (byte)(c); var gray = (r * 38 + g * 75 + b * 15) 7); var color=(255 24) | (gray 16) | (gray 8) | gray; context.Pixelspos=color; (2)标准的int32指针遍历计算 release 0.04sunsafe public static void TestGray2(this WriteableBitmap bmp) using (var context = bmp.GetBitmapContext() var ptr = context.Pixels; int height = context.Height; int width = context.Width; for (int y = 0; y height; y+) for (int x = 0; x 16) ; var g = (byte)(c 8) ; var b = (byte)(c) ; var gray = (r * 38 + g * 75 + b * 15) 7); var color = (255 24) | (gray 16) | (gray 8) | gray; *ptr = color; ptr+; (3)colorstruct指针 便利计算 0.02sStructLayout(LayoutKind.Sequential)public struct PixelColor public byte Blue; public byte Green; public byte Red; public byte Alpha; unsafe public static void TestGray3(this WriteableBitmap bmp) using (var context = bmp.GetBitmapContext() var ptr = (PixelColor*)context.Pixels; int height = context.Height; int width = context.Width; for (int y = 0; y height; y+) for (int x = 0; x 7); (*ptr).Green=(*ptr).Red=(*ptr).Blue = (byte)gray; ptr+; (4)作为对比,我又测试了一下 GDI+的 指针处理图片的速度 0.06spublic static unsafe Bitmap ToGray(Bitmap img) var rect = new System.Drawing.Rectangle(0, 0, img.Width, img.Height); var data = img.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb); var ptr = (ColorType*)data.Scan0.ToPointer(); var bytes = new Int32img.Width * img.Height; var height = img.Height; var width = img.Width; for (int y = 0; y height; y+) for (int x = 0; x 7); (*ptr).R = (*ptr).G = (*ptr).B = (byte)gray; ptr+; img.UnlockBits(data); return img;(5)重头戏来了。我一直对Parallel.For 很迷惑,为什么他的消耗时间是普通for的好几倍。今天仔细研究了一下,发现原来是用错了 0.01s release 笔记本i5cpu,如果台式机的I7会更加强悍,速度会成半成半降低。 主要是利用了微软的任务并行库的循环并行化的方法。 注意:默认的并行循环对于函数体很小的情况是很慢的,这种情况必须用Partitioner 创建循环体,这在MSDN有介绍,是关键之中的关键unsafe public static void TestGray5(this WriteableBitmap bmp) using (var context = bmp.GetBitmapContext() int height = context.Height; int width = context.Width; Parallel.ForEach(Partitioner.Create(0, height), (h) = var ptr = (PixelColor*)context.Pixels; ptr += h.Item1 * width; for (int y = h.Item1; y h.Item2; y+) for (int x = 0; x 7); (*ptr).Green = (*ptr).Red = (*ptr).Blue = (byte)gray; ptr+; ); 感想:1.绝对不要在循环体内使用属性或函数,很有可能会降低数倍计算速度。因为属性本质上是个函数,而在循环体内最好不要再调用函数,如果确实需要用内联代码的方式,c#没有inline,那么copy代码吧,反正为了速度。2. 用指针移位操作 似乎比 直接数组访问要快10倍啊,我感觉要么是cache命中的原因,要么是 数组本身存取被属性封装了。相当于又调用了函数。3.TPL 任务并行库果真好用,看来微软早已考虑过大量数据并行的循环优化问题09年,只是我一直用错了方法,才觉得很慢。方案4. WPF ListBox异步加载图片ListBox加载大量图片时,如果采用同步方法,页面出来速度太慢,最好办法就是采用异步加载了,直接上代码,如下:前台页面完整代码: 后台代码:public partial class MainWindow : Window public MainWindow() InitializeComponent(); private void Window_Loaded(object sender, RoutedEventArgs e) foreach (string file in Directory.GetFiles(AppDomain.CurrentDomain.BaseDirectory+Photo) string file1 = file;/必须有,不妨试试不加这段代码,看看效果就明白了 Dispatcher.BeginInvoke(Action)() = BitmapImage bitmap = new BitmapImage(); bitmap.BeginInit(); bitmap.UriSource = new Uri(file1,UriKind.RelativeOrAbsolute); bitmap.CacheOption = BitmapCacheOption.OnLoad; bitmap.EndInit(); double ww = bitmap.PixelWidth; double hh = bitmap.PixelHeight; Image image = new Image(); image.Source = bitmap; image.Height = 200; image.Width = 200 * (ww / hh); this.list.Items.Add(image); ); 这样的方法页面出来速度是快了,但图片加载速度还是慢,原本预想结果是图片是一张一张加在进来的,却图片是全部一下加载到界面上,所以速度显得有点慢。解决办法采用Dispatcher.BeginInvoke(DispatcherPriority.Background, (Action)() =.方案5. 控制台异步加载程序 (WPF)private void ChangeImage()Image image = new Image();new Thread(new ThreadStart() = BitmapImage bitmap = new BitmapImage();bitm

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

最新文档

评论

0/150

提交评论