C#照片批量壓縮小工具

作了一個照片批量壓縮工具,其實核心代碼幾分鐘就完成了,但整個小工具作下來仍是花了一天的時間。中間遇到了大堆問題,並尋求最好的解決方案予以解決。如今就分享一下這個看似簡單的小工具所使用的技術。程序員

軟件界面以下:web

要作真實場景的測試,拿的都是單反照的大相片:圖片尺寸3888*2592  圖片大小5.37M:併發

 

其中遇到的問題與解決方案分享:ide

1.用listview顯示圖片縮略圖很是慢的問題工具

這個問題是始料未及的,若是不作也能夠,可是沒有縮略圖就有損軟件體驗,這是全部追求完美的程序員所不能容忍的,我固然也不例外。測試

最初的代碼以下:(此方法加載每張5M左右的圖片須要200-500ms)this

            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系統的一些特性功能,如資源管理器、桌面、任務欄等等。詳細介紹見官方主頁 spa

本程序使用WindowsApiCode完成對文件夾下的圖片迅速建縮略圖的代碼以下:.net

先在界面上添加一個該庫提供的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
相關文章
相關標籤/搜索