asp.net 动态压缩、切割图片,并做缓存处理机制

时间:2023-11-05 19:06:02

在asp.net中,新建一个handler,把需要切割的网内图片,通过调用此URL来切割并缓存。http://localhost:53829/CacheImage/ResizeImage.ashx?src=/Image/FolderLevel1\FolderLevel11\FolderLevel111/548974833.jpg&width=928&height=828&type=10&quality=90

注意:

1. width 和height至少有一个不为空

2. type默认为20,具体解释为:10-按宽度缩放不切高度;11-按宽度缩放切高度;20-按高度缩放不切宽度;21-按高度缩放切宽度;30-等比例缩略,高或宽不足比例补空白,不拉伸;31-拉伸原图缩略(会失真)

3. type为11,21的未实现,感觉用处不大

4.quality为压缩比率,默认为80

我的实例如下:

1.在网站根目录创建CacheImage文件夹,handler和所有的缓存文件都将存在个目录下,并按照源图片的结构缓存

2.再此文件夹下创建图片压缩处理的handler:ResizeImage.ashx

3.把CacheImage文件夹设为不需要登录权限即可访问,在web.config中配置

<location path="CacheImage">
<system.web>
<authorization>
<allow users="*" />
</authorization>
</system.web>
</location>

4.IIS中设置CacheImage的权限为可控

5.直接上Handler代码:

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Web;
using System.Web.Configuration;
using log4net; namespace Alan.Web.CacheImage
{
/// <summary>
/// 动态缩略图处理程序
/// 调用示例: <img runat="server" src="~/CacheImage/ResizeImage.ashx?src=/Image/FolderLevel1/FolderLevel11/FolderLevel111/1299906975tusPd7.jpg&width=128&height=128&type=20&quality=90" />  
/// type介绍:10-按宽度缩放不切高度;11-按宽度缩放切高度;20-按高度缩放不切宽度;21-按高度缩放切宽度;30-等比例缩略,高或宽不足比例补空白,不拉伸;31-拉伸原图缩略(会失真)
/// </summary>
public class ResizeImage : IHttpHandler
{
private ILog _log = LogManager.GetLogger(typeof (ResizeImage)); public void ProcessRequest(HttpContext context)
{
Stream fileStream = null;
try
{
context.Response.ContentType = "text/plain";
string fileName = context.Server.UrlDecode(context.Request["src"]);
string fileNameString = fileName; if (string.IsNullOrEmpty(fileName))
{
context.Response.Write("缺少参数src.");
return;
} //本地的图片则以/开头
if (fileName.StartsWith("/"))
{
fileName = System.Web.HttpContext.Current.Server.MapPath("~" + fileName);
} FileInfo fi = new FileInfo(fileName);
if (!fi.Exists)
{
context.Response.Write("图片不存在,文件名为:" + fileName);
return;
} Image image = Image.FromFile(fi.FullName);
int sourceWidth = image.Width, sourceHeight = image.Height;
if (sourceWidth == 0 || sourceHeight == 0)
{
context.Response.Write("错误:原始图片高度或宽度为0");
return;
} string widthStr = context.Request["width"];
string heightStr = context.Request["height"];
string typeStr = context.Request["type"];
string qualityStr = context.Request["quality"];
int deliveredWidth = 0, deliveredHeight = 0, type = 20;
long quality = 80;//图片质量默认为80 int.TryParse(widthStr, out deliveredWidth);
int.TryParse(heightStr, out deliveredHeight);
int.TryParse(typeStr, out type);
long.TryParse(qualityStr, out quality); string contentType = getContentType(fi.Extension);
context.Response.ContentType = contentType; //缓存图片的路径及格式:websiteurl+/CacheImage/FileName.type.deliveredHeight.deliveredWidth.quality.扩展名。(FileName包含文件夹路径)
string finallyFileName = System.AppDomain.CurrentDomain.BaseDirectory + "CacheImage/" + fileNameString +
"." + type + "." +
deliveredHeight + "." + deliveredWidth + "." + quality + fi.Extension; //如果缓存中有照片,从缓存中读取图片信息
if (File.Exists(finallyFileName))
{
try
{
using (Bitmap imagelocal = new Bitmap(finallyFileName))
{
using (MemoryStream ms = new MemoryStream())
{
imagelocal.Save(ms, System.Drawing.Imaging.ImageFormat.Png);
context.Response.OutputStream.Write(ms.GetBuffer(), 0, (int) ms.Length);
}
}
return;
}
catch (Exception eee)
{
//若发生异常,删除此文件,继续生成新文件的操作
File.Delete(finallyFileName);
_log.Error(eee);
}
} try
{
int finallyWidth = 0, finallyHeight = 0;
string errorMessage = string.Empty; //如果计算失败,返回错误及原因,比如以高度作为依据却把高度设为0等
if (!ComputeWidthAndHeight(sourceWidth, sourceHeight, deliveredWidth, deliveredHeight, type,
ref finallyWidth, ref finallyHeight, ref errorMessage))
{
context.Response.Write(errorMessage);
return;
} //只有在源图片大于压缩图片的前提下才会压缩,否则直接返回源图片
if (sourceWidth > deliveredWidth || sourceHeight > deliveredHeight)
{
Bitmap bitmap = new Bitmap(finallyWidth, finallyHeight, PixelFormat.Format32bppArgb);
Graphics graphics = Graphics.FromImage(bitmap);
graphics.Clear(Color.White);
graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighSpeed; //平滑处理
graphics.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
//缩放质量
graphics.DrawImage(image, new Rectangle(0, 0, finallyWidth, finallyHeight));
image.Dispose();
EncoderParameters parameters = new EncoderParameters(1); parameters.Param[0] = new EncoderParameter(Encoder.Quality, quality); //图片质量参数 //创建缓存所需的文件夹位置
int lastFolderIndex =
finallyFileName.LastIndexOf("/", StringComparison.CurrentCultureIgnoreCase) >
finallyFileName.LastIndexOf(@"\", StringComparison.CurrentCultureIgnoreCase)
? finallyFileName.LastIndexOf("/", StringComparison.CurrentCultureIgnoreCase)
: finallyFileName.LastIndexOf(@"\", StringComparison.CurrentCultureIgnoreCase);
string finallyFileFolder = finallyFileName.Substring(0,lastFolderIndex);
//若不存在缓存文件夹,创建文件夹目录
if (!Directory.Exists(finallyFileFolder))
{
Directory.CreateDirectory(finallyFileFolder);
}
fileStream = new FileStream(finallyFileName, FileMode.Create);
if (finallyFileName.ToLower().EndsWith(".bmp"))
{
bitmap.Save(fileStream, System.Drawing.Imaging.ImageFormat.Png); //仅做图片裁切,不做压缩使用
}
else
{
bitmap.Save(fileStream, GetImageCodecInfo(contentType), parameters);
//用做图片质量压缩使用,通过parameters设置压缩比率,当压缩bmp图片时报错
} using (MemoryStream ms = new MemoryStream())
{
if (finallyFileName.ToLower().EndsWith(".bmp"))
{
bitmap.Save(ms, System.Drawing.Imaging.ImageFormat.Png); //仅做图片裁切,不做压缩使用
}
else
{
bitmap.Save(ms, GetImageCodecInfo(contentType), parameters);
//用做图片质量压缩使用,通过parameters设置压缩比率,当压缩bmp图片时报错
} context.Response.OutputStream.Write(ms.GetBuffer(), 0, (int) ms.Length);
} parameters.Dispose();
bitmap.Dispose();
return;
} image.Dispose();
}
catch (Exception eexx)
{
//压缩文件失败,则继续下面返回原始图片的操作
_log.Error(eexx);
} //若上述有错或其他原因,返回源图片
fileStream = new FileStream(fi.FullName, FileMode.Open);
byte[] bytes = new byte[(int) fileStream.Length];
fileStream.Read(bytes, 0, bytes.Length);
fileStream.Close();
context.Response.BinaryWrite(bytes); }
catch (Exception ex)
{
_log.Error(ex);
context.Response.Write(ex.Message);
}
finally
{
if (fileStream != null)
{
fileStream.Close();
fileStream.Dispose();
}
}
System.GC.Collect();
} /// <summary>
/// 获取文件下载类型
/// </summary>
/// <param name="extension"></param>
/// <returns></returns>
private string getContentType(string extension)
{
string ct = string.Empty;
switch (extension.ToLower())
{
case ".jpg":
ct = "image/jpeg";
break;
case ".png":
ct = "image/png";
break;
case ".gif":
ct = "image/gif";
break;
case ".bmp":
ct = "application/x-bmp";
break;
default:
ct = "image/jpeg";
break;
}
return ct;
} //获得包含有关内置图像编码解&码&器的信息的ImageCodecInfo 对象.
private ImageCodecInfo GetImageCodecInfo(string contentType)
{
ImageCodecInfo[] arrayICI = ImageCodecInfo.GetImageEncoders();
ImageCodecInfo jpegICI = null;
for (int x = 0; x < arrayICI.Length; x++)
{
if (arrayICI[x].MimeType.Equals(contentType))
{
jpegICI = arrayICI[x];
//设置JPEG编码
break;
}
}
return jpegICI;
} /// <summary>
/// 计算压缩后图片的宽度和高度
/// </summary>
/// <param name="sourceWidth">源图片宽度</param>
/// <param name="sourceHeight"></param>
/// <param name="deliveredWidth">传递来的图片宽度</param>
/// <param name="deliveredHeight"></param>
/// <param name="type">type介绍:10-按宽度缩放不切高度;11-按宽度缩放切高度;20-按高度缩放不切宽度;21-按高度缩放切宽度;30-等比例缩略,高或宽不足比例补空白,不拉伸;31-拉伸原图缩略(会失真)</param>
/// <param name="finallyWidth"></param>
/// <param name="finallyHeight"></param>
/// <param name="errorMsg"></param>
/// <returns></returns>
private bool ComputeWidthAndHeight(int sourceWidth, int sourceHeight, int deliveredWidth, int deliveredHeight,int type, ref int finallyWidth, ref int finallyHeight, ref string errorMsg)
{
switch (type)
{
case 10:
{
if (deliveredWidth == 0)
{
errorMsg = "错误:缩放至目标的图片宽度为0";
return false;
}
finallyWidth = deliveredWidth;
finallyHeight = (int)(((double)deliveredWidth/sourceWidth)*sourceHeight);
}
break;
//case 11://TODO:11、12未做
// {
// if (deliveredWidth == 0)
// {
// errorMsg = "错误:缩放至目标的图片宽度为0";
// return false;
// }
// finallyWidth = deliveredWidth;
// finallyHeight = deliveredHeight;
// }
// break;
//case 21:
// {
// if (deliveredHeight == 0)
// {
// errorMsg = "错误:缩放至目标的图片高度为0";
// return false;
// }
// finallyWidth = sourceWidth;
// finallyHeight = deliveredHeight;
// }
// break;
case 30:
{
if(deliveredHeight==0||deliveredWidth==0)
{
errorMsg = "错误:缩放至目标的图片高度或宽度为0";
return false;
}
if (((double)sourceWidth / (double)sourceHeight) > ((double)deliveredWidth / (double)deliveredHeight))
{
//以宽度为基准缩小
if (sourceWidth > deliveredWidth)
{
finallyWidth = deliveredWidth;
finallyHeight = (int)(deliveredWidth * sourceHeight / (double)sourceWidth);
}
else
{
finallyWidth = sourceWidth;
finallyHeight = sourceHeight;
}
}
else
{
//以高度为基准缩小
if (sourceHeight > deliveredHeight)
{
finallyWidth = (int)(deliveredHeight * sourceWidth / (double)sourceHeight);
finallyHeight = deliveredHeight;
}
else
{
finallyWidth = sourceWidth;
finallyHeight = sourceHeight;
}
}
}
break;
case 31:
{
if (deliveredHeight == 0 || deliveredWidth == 0)
{
errorMsg = "错误:缩放至目标的图片高度或宽度为0";
return false;
}
finallyWidth = deliveredWidth;
finallyHeight = deliveredHeight;
}
break;
default://20
{
if (deliveredHeight == 0)
{
errorMsg = "错误:缩放至目标的图片高度为0";
return false;
}
finallyHeight = deliveredHeight;
finallyWidth = (int)((double)(deliveredHeight*sourceWidth)/sourceHeight);
}
break;
}
return true;
} public bool IsReusable
{
get { return false; }
}
}
}

  

6.调用代码如下:

<html>
<body>
<img height="128" width="80" src="http://admin.pl360.com/CacheImage/ResizeImage.ashx?src=/ShopData/ProductLogo/1465b59c-98f0-4c20-8002-996796db0d064.JPG&width=128&height=128&type=20&quality=90" />
</body>
</html>