·您现在的位置: 云翼网络 >> 文章中心 >> 网站建设 >> 网站建设开发 >> ASP.NET网站开发 >> 网站性能优化:动态缩略图技术实现思路
在网站开发过程中,大家都是如何解决多尺寸图片缩略图问题的呢?犹为典型的是电商网站,据了解,淘宝的图片缩略图是直接存储多张缩略图的方式,以满足各种情况下使用,因为它有牛逼的开源+自主开发的海量图片存储架构作支撑。但是,我们在做网站时,并不可能直接搬牛逼的架构过来,就可以达到预期的效果,况且各种成本投入也是有限的。所以一般性能优化的原则大都是这样:先考虑软件的优化,再考虑硬件的升级,当然土豪客户则除外。
很多网站可能没有对图片进行缩略图处理,上传时图片可能几百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 else112 {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 finally125 {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 IsReusable183 {184 get185