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