網站性能優化:動態縮略圖技術實現思路

  在網站開發過程當中,你們都是如何解決多尺寸圖片縮略圖問題的呢?猶爲典型的是電商網站,據瞭解,淘寶的圖片縮略圖是直接存儲多張縮略圖的方式,以知足各類狀況下使用,由於它有牛逼的開源+自主開發的海量圖片存儲架構做支撐。可是,咱們在作網站時,並不可能直接搬牛逼的架構過來,就能夠達到預期的效果,何況各類成本投入也是有限的。因此通常性能優化的原則大都是這樣:先考慮軟件的優化,再考慮硬件的升級,固然土豪客戶則除外。前端

  不少網站可能沒有對圖片進行縮略圖處理,上傳時圖片可能幾百KB,在頁面也是直接加載幾百KB的圖片大小,這樣極爲佔用帶寬,影響網站加載速度。也有不少網站的作法可能也是直接根據前端頁面所需求圖片的尺寸,在上傳時就處理生成相應尺寸的縮略圖,但若是前端頁面佈局進行調整時,可能就得調整縮略圖生成的尺寸,以前生成的圖片也有可能須要從新生成。以前我在一個網站項目時就遇到這樣的問題,通過一系列地驗證,最終是採用動態縮略圖技術解決的,如今整理出來給你們分享分享。算法

  其實,原理很簡單,經過高性能的圖片壓縮算法,在通常處理程序(HttpHandler)對圖片進行壓縮處理,圖片路徑則直接指向HttpHandler,將圖片路徑、須要壓縮的寬高等參數傳進去,實現動態壓縮。瀏覽器

  在網站目錄下新建 ResizeImage.ashx 文件,代碼以下:緩存

  1 using System;
  2 using System.Collections.Generic;
  3 using System.Linq;
  4 using System.Web;
  5 using System.IO;
  6 using System.Drawing.Imaging;
  7 using System.Drawing;
  8 
  9 namespace www.ideek.cn
 10 {
 11     /// <summary>
 12     /// 動態縮略圖處理程序
 13     /// 調用示例: <img runat="server" src="~/ResizeImage.ashx?src=/Upload/20140428/www_ideek_cn.jpg&width=128&height=128" />
 14     /// </summary>
 15     public class ResizeImageHandler : IHttpHandler
 16     {
 17         public void ProcessRequest(HttpContext context)
 18         {
 19             context.Response.ContentType = "text/plain";
 20             string fileName = context.Server.UrlDecode(context.Request["src"]);
 21             if (string.IsNullOrEmpty(fileName))
 22             {
 23                 context.Response.Write("缺乏參數src.");
 24                 return;
 25             }
 26             fileName = Server.MapPath("~/" + fileName);
 27 
 28             Stream fileStream = null;
 29             try
 30             {
 31                 string wStr = context.Request["width"];
 32                 string hStr = context.Request["height"];
 33                 int width = 0, height = 0;
 34                 if (!string.IsNullOrEmpty(wStr) && !string.IsNullOrEmpty(hStr))
 35                 {
 36                     int.TryParse(wStr, out width);
 37                     int.TryParse(hStr, out height);
 38                 }
 39 
 40                 FileInfo fi = new FileInfo(fileName);
 41                 if (!fi.Exists)
 42                 {
 43                     context.Response.Write("圖片不存在.");
 44                     return;
 45                 }
 46                 string contentType = getContentType(fi.Extension);
 47                 context.Response.ContentType = contentType;
 48 
 49                 //只能處理jpg及png圖片格式,沒有寬高參數不進行縮放處理
 50                 if (width > 0 && height > 0 && (contentType.Contains("jpeg") || contentType.Contains("png")))
 51                 {
 52                     Image image = Image.FromFile(fi.FullName);
 53                     int sWidth = image.Width, sHeight = image.Height;
 54                     int nWidth = 0, nHeight = 0;
 55                     if (sWidth > width || sHeight > height)
 56                     {
 57                         if (((double)sWidth / (double)sHeight) > ((double)width / (double)height))
 58                         {
 59                             //以寬度爲基準縮小
 60                             if (sWidth > width)
 61                             {
 62                                 nWidth = width;
 63                                 nHeight = (int)(width * sHeight / (double)sWidth);
 64                             }
 65                             else
 66                             {
 67                                 nWidth = sWidth;
 68                                 nHeight = sHeight;
 69                             }
 70                         }
 71                         else
 72                         {
 73                             //以高度爲基準縮小
 74                             if (sHeight > height)
 75                             {
 76                                 nWidth = (int)(height * sWidth / (double)sHeight);
 77                                 nHeight = height;
 78                             }
 79                             else
 80                             {
 81                                 nWidth = sWidth;
 82                                 nHeight = sHeight;
 83                             }
 84                         }
 85 
 86                         Bitmap bitmap = new Bitmap(nWidth, nHeight, PixelFormat.Format32bppArgb);
 87                         Graphics graphics = Graphics.FromImage(bitmap);
 88                         graphics.Clear(Color.White);
 89                         graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighSpeed;  //平滑處理
 90                         graphics.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;  //縮放質量
 91                         graphics.DrawImage(image, new Rectangle(0, 0, nWidth, nHeight));
 92                         image.Dispose();
 93 
 94                         EncoderParameters parameters = new EncoderParameters(1);
 95                         parameters.Param[0] = new EncoderParameter(Encoder.Quality, ((long)80));  //圖片質量參數
 96 
 97                         fileStream = new MemoryStream();
 98                         bitmap.Save(fileStream, GetImageCodecInfo(contentType), parameters);
 99                         using (MemoryStream ms = new MemoryStream())
100                         {
101                             bitmap.Save(ms, GetImageCodecInfo(contentType), parameters);
102                             context.Response.OutputStream.Write(ms.GetBuffer(), 0, (int)ms.Length);
103                         }
104                         parameters.Dispose();
105                         bitmap.Dispose();
106                         return;
107                     }
108                     if (image != null)
109                         image.Dispose();
110                 }
111                 else
112                 {
113                     fileStream = new FileStream(fi.FullName, FileMode.Open);
114                     byte[] bytes = new byte[(int)fileStream.Length];
115                     fileStream.Read(bytes, 0, bytes.Length);
116                     fileStream.Close();
117                     context.Response.BinaryWrite(bytes);
118                 }
119             }
120             catch (Exception ex)
121             {
122                 context.Response.Write(ex.Message);
123             }
124             finally
125             {
126                 if (fileStream != null)
127                 {
128                     fileStream.Close();
129                     fileStream.Dispose();
130                 }
131             }
132             System.GC.Collect();
133         }
134 
135 
136         /// <summary>
137         /// 獲取文件下載類型
138         /// </summary>
139         /// <param name="extension"></param>
140         /// <returns></returns>
141         private string getContentType(string extension)
142         {
143             string ct = string.Empty;
144             switch (extension.ToLower())
145             {
146                 case ".jpg":
147                     ct = "image/jpeg";
148                     break;
149                 case ".png":
150                     ct = "image/png";
151                     break;
152                 case ".gif":
153                     ct = "image/gif";
154                     break;
155                 case ".bmp":
156                     ct = "application/x-bmp";
157                     break;
158                 default:
159                     ct = "image/jpeg";
160                     break;
161             }
162             return ct;
163         }
164 
165         //得到包含有關內置圖像編碼解碼器的信息的ImageCodecInfo 對象.
166         private ImageCodecInfo GetImageCodecInfo(string contentType)
167         {
168             ImageCodecInfo[] arrayICI = ImageCodecInfo.GetImageEncoders();
169             ImageCodecInfo jpegICI = null;
170             for (int x = 0; x < arrayICI.Length; x++)
171             {
172                 if (arrayICI[x].MimeType.Equals(contentType))
173                 {
174                     jpegICI = arrayICI[x];
175                     //設置JPEG編碼
176                     break;
177                 }
178             }
179             return jpegICI;
180         }
181 
182         public bool IsReusable
183         {
184             get
185             {
186                 return false;
187             }
188         }
189     }
190 }

   圖片壓縮算法中,有幾個參數能夠根據本身的需求進行調整,好比:SmoothingMode、InterpolationMode、Encoder.Quality,反正圖片的大小與圖片質量成正比,也跟性能成反比,具體參數用法,請移步MSDN查看,所以你們根據實際需求進行取捨了。性能優化

  在頁面須要調用地方,將img的src設置爲ResizeImage.ashx,這跟圖片驗證碼處理方式同樣,如:服務器

  1 <img runat="server" src="~/ResizeImage.ashx?src=/Upload/20140428/www_ideek_cn.jpg&width=128&height=128" /> 架構

  這樣,一張圖片能夠在網站任意地方使用,圖片通過壓縮後傳輸,經過Google或Firefox瀏覽器開發者工具能夠很明顯地看出圖片大小效果和加載速度都有很是明顯的提高。app

  固然,可能不少人會問頻繁的計算對服務器會產生性能影響,因此在實際使用過程當中,能夠根據本身的需求採用一些手段進行規避,好比引入緩存機制等,這些優化將會在後續文章中講解。ide

相關文章
相關標籤/搜索