天天看點

C#圖檔壓縮

在做Web項目時,發現大量高品質圖檔加載嚴重影響性能。于是考慮進行圖檔壓縮預處理,也就是将高清圖檔等比壓縮成低品質圖檔,當使用者點選某張圖檔時再加載顯示該圖檔高清原圖。剛開始用C# Graphics DrawImage重繪方式批量進行圖檔壓縮。但是通過測試發現15M大小以上的圖檔進行重繪時就會出現記憶體不足異常(當然這個異常情況可能因不同電腦有所不同,也許有的電腦10M的圖檔進行Graphics重繪時就會出現異常)。通過Google、MSDN尋求各種方法,都無法解決Graphics對大圖檔重繪出現記憶體不足的異常。于是放棄治療,到Githup、CodePlex等等開源社群去找開源圖像操作庫,無意中發現開源庫Magick.NET。Magick.NET從名字上就能讓人隐約感覺到這個類庫并非使用.NET寫的。其實它是對ImageMagick的.NET封裝,而ImageMagick是一個很強大的圖像操作庫,支援超過 100 種的檔案格式。像圖檔壓縮這種操作,ImageMagick處理起來輕輕松松。使用ImageMagick庫.NET封裝的庫Magick.NET進行1GB的tif圖生成縮略圖操作(也就是圖檔壓縮),一點問題都沒有。當然1GB大小的tif圖處理起來肯定需要些時間,将1GB的tif圖按1%比例等比壓縮,生成一張新的圖檔大概需要2~3鐘(時間長短因電腦組態會有所不同)。

另外一點使用Magick.NET要注意,Magick.NET有64/32位之分,當然也有适應64/32位系統的庫。也就是說Magick.NET有三個版本,32位、64位以及AndyCPU版。使用時還需注意資源的釋放,.NET的程式員習慣把資源回收任務交給.NET垃圾回收機制進行處理。其實對于消耗資源的操作,必要時應該手動釋放資源,畢竟.NET垃圾回收不是萬能的,批量操作很有可能導緻資源無法及時釋放而出異常,嚴重點也許會爆記憶體。

  • 方案一:使用Magick.NET壓縮圖檔(推薦)
/// <summary>
        /// 生成縮略圖
        /// </summary>
        /// <param name="srcFileName">源圖像檔案</param>
        /// <param name="destFileName">目标圖像檔案</param>
        /// <param name="width">指定壓縮寬度</param>
        /// <param name="height">指定壓縮高度</param>
        private void MakeThumbnail(string srcFileName, string destFileName, int width, int height)
        {
            using (MagickImage image = new MagickImage(srcFileName))
            {
                if (width <= )
                    width = (int)Math.Ceiling(image.Width * GetScale(image.Height, height));
                if (height <= )
                    height = (int)Math.Ceiling(image.Height * GetScale(image.Width, width));

                image.Thumbnail(width, height);
                image.Write(destFileName);
            }
        }

        /// <summary>
        /// 生成縮略圖
        /// </summary>
        /// <param name="srcFileName">源圖像檔案</param>
        /// <param name="destFileName">目标圖像檔案</param>
        /// <param name="percent">等比壓縮比例</param>
        private void MakeThumbnail(string srcFileName, string destFileName, int percent)
        {
            using (MagickImage image = new MagickImage(srcFileName))
            {
                image.Thumbnail(new Percentage(percent));
                image.Write(destFileName);
            }
        }
           

C# Magick.NET圖檔壓縮完整代碼

  • 方案二:使用.NET Graphics重繪方式壓縮圖檔(壓縮大圖檔不建議使用)
#region 生成縮略圖


        ///<summary> 
        /// 生成縮略圖 
        /// </summary> 
        /// <param name="originalImagePath">源圖路徑(實體路徑)</param> 
        /// <param name="thumbnailPath">縮略圖路徑(實體路徑)</param> 
        /// <param name="width">縮略圖寬度</param> 
        /// <param name="height">縮略圖高度</param> 
        /// <param name="mode">生成縮略圖的方式</param>     
        public void MakeThumbnail(string originalImagePath, string thumbnailPath, int width, int height, ThumbnailMode mode, out string outthumbnailPath)
        {
            System.Drawing.Image originalImage = System.Drawing.Image.FromFile(originalImagePath);

            int towidth = width;
            int toheight = height;

            int x = ;
            int y = ;
            int ow = originalImage.Width;
            int oh = originalImage.Height;

            switch (mode)
            {
                case ThumbnailMode.HeightAndWidth://指定高寬縮放(可能變形)                 
                    break;
                case ThumbnailMode.Width://指定寬,高按比例                     
                    toheight = originalImage.Height * width / originalImage.Width;
                    break;
                case ThumbnailMode.Height://指定高,寬按比例 
                    towidth = originalImage.Width * height / originalImage.Height;
                    break;
                case ThumbnailMode.Cut://指定高寬裁減(不變形)                 
                    if ((double)originalImage.Width / (double)originalImage.Height > (double)towidth / (double)toheight)
                    {
                        oh = originalImage.Height;
                        ow = originalImage.Height * towidth / toheight;
                        y = ;
                        x = (originalImage.Width - ow) / ;
                    }
                    else
                    {
                        ow = originalImage.Width;
                        oh = originalImage.Width * height / towidth;
                        x = ;
                        y = (originalImage.Height - oh) / ;
                    }
                    break;
                default:
                    break;
            }

            //建立一個bmp圖檔 
            System.Drawing.Image bitmap = new System.Drawing.Bitmap(towidth, toheight);

            //建立一個畫闆 
            Graphics g = System.Drawing.Graphics.FromImage(bitmap);

            //設定高品質插值法 
            g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.High;

            //設定高品質,低速度呈現平滑程度 
            g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;

            //清空畫布并以透明背景色填充 
            g.Clear(Color.Transparent);

            //在指定位置并且按指定大小繪制原圖檔的指定部分 
            g.DrawImage(originalImage, new Rectangle(, , towidth, toheight),
             new Rectangle(x, y, ow, oh),
             GraphicsUnit.Pixel);

            try
            {
                //以jpg格式儲存縮略圖 
                bitmap.Save(thumbnailPath, System.Drawing.Imaging.ImageFormat.Jpeg);
                outthumbnailPath = thumbnailPath;
            }
            catch (System.Exception e)
            {
                throw e;
            }
            finally
            {
                originalImage.Dispose();
                bitmap.Dispose();
                g.Dispose();
            }
        }

        public enum ThumbnailMode
        {
            /// <summary>
            /// 指定高寬縮放(可能變形) 
            /// </summary>
            HeightAndWidth = ,
            /// <summary>
            /// 指定寬,高按比例
            /// </summary>
            Height = ,
            /// <summary>
            /// 指定寬,高按比例    
            /// </summary>
            Width = ,
            /// <summary>
            /// 指定高寬裁減(不變形)
            /// </summary>
            Cut = 
        }
        #endregion