zoukankan      html  css  js  c++  java
  • C#照片批量压缩小工具

    做了一个照片批量压缩工具,其实核心代码几分钟就完成了,但整个小工具做下来还是花了一天的时间。中间遇到了大堆问题,并寻求最好的解决方案予以解决。现在就分享一下这个看似简单的小工具所使用的技术。

    软件界面如下:

    要做真实场景的测试,拿的都是单反照的大相片:图片尺寸3888*2592  图片大小5.37M:

    其中遇到的问题与解决方案分享:

    1.用listview显示图片缩略图非常慢的问题

    这个问题是始料未及的,如果不做也可以,但是没有缩略图就有损软件体验,这是所有追求完美的程序员所不能容忍的,我当然也不例外。

    最初的代码如下:(此方法加载每张5M左右的图片需要200-500ms)

                listView1.Items.Clear();
                imageList1.Images.Clear();
    
                DirectoryInfo TheFolder = new DirectoryInfo(folderBrowserDialog1.SelectedPath);//文件路径
                List<string> ImgNames = new List<string>();
                string allowImg = ".jpg.jpeg.png.bmp";
                FileInfo[] Files = TheFolder.GetFiles();
                for (int i = 0; i < Files.Length; i++)//遍历文件夹
                {
                    if (Files[i].Length > 0 &&allowImg.IndexOf(Files[i].Extension.ToLower())>-1)//或者jpg,png 文件大小要大于0且是图片文件
                    {
                        Image image = Image.FromFile(Files[i].DirectoryName + "\" + Files[i].Name);    //获取文件                 
                        ImgNames.Add(Files[i].Name);//添加文件名
                        imageList1.Images.Add(image);//添加图片
                    }
                }
                //初始化设置
                this.listView1.View = View.LargeIcon;
    
                this.listView1.LargeImageList = this.imageList1;
    
                //开始绑定
                this.listView1.BeginUpdate();
    
                for (int i = 0; i < ImgNames.Count; i++)
                {
                    ListViewItem lvi = new ListViewItem();
    
                    lvi.ImageIndex = i;
    
                    lvi.Text = ImgNames[i];
    
                    this.listView1.Items.Add(lvi);
                }
    
                this.listView1.EndUpdate();
    

      解决办法是用微软提供的Windows API Code Pack 1.0.1库,通过该库可以直接使用到win7/vista/win8系统的一些特性功能,如资源管理器、桌面、任务栏等等。详细介绍见官方主页 

    本程序使用WindowsApiCode完成对文件夹下的图片迅速建缩略图的代码如下:

    先在界面上添加一个该库提供的explorerBrowser控件,然后初始化该控件:

                //设置图片展示控件属性
                explorerBrowser1.ContentOptions.ViewMode = ExplorerBrowserViewMode.List;
                explorerBrowser1.NavigationOptions.PaneVisibility.Navigation = PaneVisibilityState.Hide;
                explorerBrowser1.NavigationOptions.PaneVisibility.CommandsView = PaneVisibilityState.Hide;
                explorerBrowser1.NavigationOptions.PaneVisibility.CommandsOrganize = PaneVisibilityState.Hide;
                explorerBrowser1.NavigationOptions.PaneVisibility.Commands = PaneVisibilityState.Hide;
                explorerBrowser1.SelectionChanged += new EventHandler(explorerBrowser1_SelectionChanged);
    

    完成打开文件夹并显示图片缩略图的代码非常简单:

           //打开图片文件夹
            private void btnOpenDir_Click(object sender, EventArgs e)
            {
                // 创建打开文件夹对话框
                CommonOpenFileDialog cfd = new CommonOpenFileDialog();
    
                // 设置对话框属性
                cfd.IsFolderPicker = true;
                cfd.AllowNonFileSystemItems = true;
    
                // 弹出对话框并返回用户的选择
                CommonFileDialogResult result = cfd.ShowDialog();
    
                //如果用户确定
                if (result == CommonFileDialogResult.Ok)
                {
                    // 获取选择对象的ShellObject形式
                    ShellObject resultItem = cfd.FileAsShellObject;
                    //用explorerBrowser控件显示图片列表
                    explorerBrowser1.Navigate(resultItem);
                }
            }
    

    采用这种方法打开图片缩略图列表时间可以忽略不计。

    2.好看的图片界面库

    从前面的界面可以看出,本工具的界面并不丑,可以说还很精美,这也是花了心思的。

    本工具的界面我采用的

    官方主页为http://www.componentfactory.com/

    3.充分利用多核并行计算,提高图片处理速度

    处理批量任务当然要考虑速度,否则就失去了工具的意义了

    .netFrameWork4.0里面提供了Parallel系列、Task系列来支持并行运算,让并行计算变得如此简单(为什么不跟着微软走呢,后悔了吧 ^_^)。

    并行指的是利用现在的CUP多核,同时开启多个任务。跟以往的并发计算不同的是,并发的多个线程其实并非真正同时在运行,他们只是按照时间片,走走停停,逻辑上在同时进行,而并行则是在多个完全独立的核上同时运行任务,是真正的同时在跑。

    本程序中并行进行图片压缩的代码如下:

    ParallelOptions po = new ParallelOptions();
                po.MaxDegreeOfParallelism = 15; //最多并发50个任务
                //并行进行图片压缩
                System.Threading.ThreadPool.QueueUserWorkItem(w=>{
                    Parallel.ForEach(imgtoComp, po, (o) =>
                    {
                        System.Drawing.Image sourceImg = System.Drawing.Image.FromFile(o.ParsingName);
                        int iWidth = 0;
                        int iHeight = 0;
                        if (rbtper.Checked)
                        {
                            int per = int.Parse(txtper.Text);
                            iWidth = sourceImg.Width * per / 100;
                            iHeight = sourceImg.Height * per / 100;
                        }
    
                        if (rbtheight.Checked)//最大高度
                        {
                            iHeight = int.Parse(txtheight.Text);
                            iWidth = iHeight * sourceImg.Width / sourceImg.Height;
                        }
    
                        if (rbtwidth.Checked)//最大宽度
                        {
                            iWidth = int.Parse(txtwidth.Text);
                            iHeight = iWidth * sourceImg.Height / sourceImg.Width;
                        }
    
                        System.Drawing.Image ThumbImg = ImgCompress.GetImageThumb(sourceImg, iWidth, iHeight);
    
                        if (rbtpng.Checked) ThumbImg.Save(FileSavePath + Path.GetFileNameWithoutExtension(o.Name) + ".png", System.Drawing.Imaging.ImageFormat.Png);
                        if (rbtgif.Checked) ThumbImg.Save(FileSavePath + Path.GetFileNameWithoutExtension(o.Name) + ".gif", System.Drawing.Imaging.ImageFormat.Gif);
                        if (rbtjpg.Checked) ThumbImg.Save(FileSavePath + Path.GetFileNameWithoutExtension(o.Name) + ".jpg", System.Drawing.Imaging.ImageFormat.Jpeg);
    
                        sourceImg.Dispose();
                        ThumbImg.Dispose();
    
                        Interlocked.Increment(ref ifinish);//ifinish++
                        
                        this.Invoke(this.mysetFinish, new Object[] { ifinish }); //刷新进度条等
                        
                    });
                }, null);
    

      

    这里主要强调一下并发任务数量的设置、以及资源的显示释放。

    并发数量通过ParallelOptions参数的MaxDegreeOfParallelism来设置,这里必须设置,否则几百张5M的图片同时跑,立马内存就占满了。

    资源的显式释放:sourceImg.Dispose();  ThumbImg.Dispose();  这点也非常重要,处理大图片是非常耗内存的,测试过程中就因为没有显式释放内存,偷懒想着.net的自动垃圾回收机制会帮忙善后,结果跑到40多张图片的时候就内存不足了。显式处理资源释放后,压缩图片的速度也因为空余的内存比较多而变快了。

    下载本程序  Demo

    程序源码 CODE
  • 相关阅读:
    2019-2020-2 20175203马羽达《网络对抗技术》Exp9 Web安全基础
    2019-2020-2 20175203马羽达《网络对抗技术》Exp8 Web基础
    2019-2020-2 20175203马羽达《网络对抗技术》Exp7 网络欺诈防范
    2019-2020-2 20175203马羽达《网络对抗技术》Exp6 MSF基础应用
    2019-2020-2 20175203马羽达《网络对抗技术》Exp5 信息搜集与漏洞扫描
    2019-2020-2 20175203马羽达《网络对抗技术》Exp4 恶意代码分析
    2019-2020-2 20175203马羽达《网络对抗技术》Exp3 免杀原理与实践
    2019-2020-2 20175203马羽达《网络对抗技术》Exp2 后门原理与实践
    2019-2020-2 20175203马羽达《网络对抗技术》EXP1 PC平台的逆向破解
    2019-2020-2 20175203马羽达《网络对抗技术》Kali的安装
  • 原文地址:https://www.cnblogs.com/tuyile006/p/3664993.html
Copyright © 2011-2022 走看看