经过测试,如果URL中包含空格,就无法截获请求。
<httpHandlers>
<add verb="*" path="/photo/*.aspx" type="HttpHandler.PhotoHandler, Common"/>
</httpHandlers>
<!-- BEGIN PhotoHandler -->
<add key="photopath" value="/style/photos/"/>
<add key="cachedir" value="40x40,98x98,178X178"/>
<add key="allow external referrers" value="yes"/>
<add key="allow referrers" value="yes"/>
<add key="no access" value="noaccess.jpg"/>
<add key="no photo" value="nophoto.jpg"/>
<add key="eboard height" value="125"/>
<add key="eboard width" value="125"/>
<add key="watermark minimum width" value="100"/>
<add key="watermark text position" value="0,1"/>
<add key="watermark image position" value="1,1"/>
<add key="watermark transparence" value="0.7"/>
<add key="watermark type" value="text, image"/>
<add key="watermark font" value="Verdana"/>
<add key="watermark color" value="#FFFFFF"/>
<add key="watermark graphic" value=""/>
<add key="watermark graphic transparent color" value="white"/>
<add key="watermark text" value=""/>
<add key="watermark size" value="14"/>
<add key="watermark shadow color" value="#000000"/>
<add key="watermark shadow distance" value="1.5"/>
<!-- END PhotoHandler -->
using System;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;
using System.IO;
using System.Web;
using System.Drawing;
using System.Drawing.Imaging;
using System.Drawing.Drawing2D;
using System.Configuration;
using Common;
using Common.Config;
namespace HttpHandler
{
public class PhotoHandler : IHttpHandler
{
private HttpResponse response;
private HttpRequest request;
private HttpServerUtility server;
public bool IsReusable
{
get { return true; }
}
public void ProcessRequest(HttpContext context)
{
server = context.Server;
response = context.Response;
request = context.Request;
string fileName = Path.GetFileName(request.Url.AbsolutePath);
string pattern = @"(\d*)\.([0-9])\.(\d*)\.(\d*)\.((\w|\s|\-)*\.(jpg|gif|bmp))\.aspx";
Regex re = new Regex(pattern, RegexOptions.IgnoreCase);
// Check to see if we've found a match
if (re.IsMatch(fileName))
{
int start = 0;
string s = GetStr(fileName, ref start);
string t = GetStr(fileName, ref start);
string w = GetStr(fileName, ref start);
string h = GetStr(fileName, ref start);
string n = fileName.Substring(start, fileName.Length - start - 5);
RequestImage(s, t, w, h, n);
}
}
public static string GetStr(string input, ref int start)
{
int index = input.IndexOf('.', start);
int length = index - start;
int oldStart = start;
start = index + 1;
return input.Substring(oldStart, length);
}
private void RequestImage(string strs, string strt, string strw, string strh, string fileName)
{
// 分解参数以得到相应的和图片相关的信息
// thumb=1 => /photos/888/images/, thumb=2 => /photos/888/temp/
int thumb = 0, width = 0, height = 0;
Int64 shopId = 0;
string imagePath = "";
if (this.IsInt(strs))
{
shopId = Int64.Parse(strs);
}
if (this.IsInt(strt))
{
thumb = int.Parse(strt);
}
if (this.IsInt(strw))
{
width = int.Parse(strw);
}
if (this.IsInt(strh))
{
height = int.Parse(strh);
}
// 默认取/photos/images/下的图片
imagePath = strs + "/images/" + fileName;
// t=2时,取/photos/temp/下的图片
if (thumb == 2)
{
imagePath = strs + "/temp/" + fileName;
}
// t=3时,从配置文件中取图片的规定大小
else if (thumb == 3)
{
height = Int32.Parse(Setting("eboard height"));
width = Int32.Parse(Setting("eboard width"));
}
// 检查是否允许被外部引用
if (Setting("allow external referrers") == "no"
&& request.UrlReferrer != null
/*&& request.UrlReferrer.Host != request.Url.Host*/)
{
imagePath = ShowNoAccessImage();
}
// 检查是否允许被内部引用
if (Setting("allow referrers") == "no"
&& request.UrlReferrer != null
/*&& request.UrlReferrer.Host == request.Url.Host*/)
{
imagePath = ShowNoAccessImage();
}
// 获取图片的完整路径
imagePath = server.MapPath(Setting("photopath") + imagePath);
ShowImage(strs, imagePath, width, height);
}
/// <summary>
/// 显示不能通过的图片
/// </summary>
/// <returns></returns>
private string ShowNoAccessImage()
{
return Setting("no access");
}
/// <summary>
/// 显示处理后的图片
/// </summary>
/// <param name="shop"></param>
/// <param name="image_path"></param>
/// <param name="width"></param>
/// <param name="height"></param>
private void ShowImage(string shop, string image_path, int width, int height)
{
// 获取缓存的图片
string cachedir = Setting("cachedir").ToLower();
string str = width.ToString() + "x" + height.ToString();
string fileName = Path.GetFileName(image_path);
string strdir = server.MapPath(Setting("photopath")) + shop + "\\" + str;
// 判断缓存的图片是否超过了7天,如果超过了7天,重新生成,保证图片的定时更新问题。
string strpath = strdir + "\\" + fileName;
bool bRemake = true;
if (File.Exists(strpath))
{
FileInfo finfo = new FileInfo(strpath);
TimeSpan ts = DateTime.Now - finfo.CreationTime;
if (ts.Days < 7)
{
bRemake = false;
}
}
if (bRemake)
{
#region 根据不同的参数缩放
// Grab Image
Bitmap image = null;
try
{
image = (Bitmap)Bitmap.FromFile(image_path);
}
catch (Exception e)
{
image_path = server.MapPath(Setting("photopath")) + Setting("no photo");
image = (Bitmap)Bitmap.FromFile(image_path);
}
Bitmap output = null;
int ih = 0, iw = 0;
ih = image.Height;
iw = image.Width;
if (height > 0 && width > 0)
{
//if (height / width > ih / iw)
if ((float)height / (float)width > (float)ih / (float)iw)
{
height = (int)((float)ih * width / (float)iw);
}
else
{
width = (int)((float)iw * height / (float)ih);
}
}
else if (height > 0 && width <= 0)
{
width = (int)(image.Width * (float)height / (float)image.Height);
}
else if (height <= 0 && width > 0)
{
height = (int)(image.Height * (float)width / (float)image.Width);
}
else
{
height = image.Height;
width = image.Width;
}
output = Resize(image, height, width);
//Do we watermark it?
int wmmw = Int32.Parse(Setting("watermark minimum width"));
if (output.Width >= wmmw)
{
//Add watermark
string type = Setting("watermark type");
if (type.IndexOf("text") != -1)
{
string text = Setting("watermark text").Trim();
if (!string.IsNullOrEmpty(text))
output = TextWaterMark(output);
}
if (type.IndexOf("image") != -1)
{
string imgfile = Setting("watermark graphic").Trim();
if (!string.IsNullOrEmpty(imgfile))
output = ImageWaterMark(output);
}
}
output.Save(response.OutputStream, ImageType(image_path));
// 缓存指定大小的图片
if (cachedir.IndexOf(str) != -1 && image_path.IndexOf(Setting("no photo")) == -1)
{
if (!Directory.Exists(strdir))
Directory.CreateDirectory(strdir);
output.Save(strdir + "\\" + fileName);
}
image.Dispose();
output.Dispose();
#endregion
// WriteLog.WriteError("缩放" + fileName);
}
else
{
// WriteLog.WriteError("跳转" + str + "/" + fileName);
response.WriteFile(strdir + "/" + fileName);
}
}
/// <summary>
/// 设置水印在图片上的位置
/// </summary>
/// <param name="image"></param>
/// <param name="width"></param>
/// <param name="height"></param>
/// <param name="type"></param>
/// <returns></returns>
private PointF GetPosition(Bitmap image, float width, float height, int type)
{
// 原始图片的大小
float w = image.Width;
float h = image.Height;
// 水印偏移位置
string str = type == 1 ? Setting("watermark text position") : Setting("watermark image position");
string[] offset = str.Split(',');
float offsetx = float.Parse(offset[0].Trim());
float offsety = float.Parse(offset[1].Trim());
offsetx = offsetx == 1 ? 1 : offsetx % 1;
offsety = offsety == 1 ? 1 : offsety % 1;
return new PointF((w - width) * offsetx, (h - height) * offsety);
}
#region TextWaterMark(Bitmap image)
private Bitmap TextWaterMark(Bitmap image)
{
Graphics watermark = Graphics.FromImage(image);
// Set the rendering quality for this Graphics object
watermark.SmoothingMode = SmoothingMode.AntiAlias;
int width = image.Width;
int height = image.Height;
// 颜色
Color color = ColorTranslator.FromHtml(Setting("watermark color"));
// 字体
string font = Setting("watermark font");
// 字体大小
float size = float.Parse(Setting("watermark size"));
// 水印字符串
string text = Setting("watermark text");
// 是否使用阴影
string shadow = Setting("watermark shadow color");
// 字体之间的距离
string distance = Setting("watermark shadow distance");
//-------------------------------------------------------
//to maximize the size of the Copyright message we will
//test multiple Font sizes to determine the largest posible
//font we can use for the width of the Photograph
//define an array of point sizes you would like to consider as possiblities
//-------------------------------------------------------
int[] sizes = new int[] { 16, 14, 12, 10, 8, 6, 4 };
Font crFont = null;
SizeF crSize = new SizeF();
// 如果字体太大使用合适的字体
crFont = new Font(font, size, FontStyle.Bold);
//Measure the Copyright string in this Font
crSize = watermark.MeasureString(text, crFont);
if ((ushort)crSize.Width > (ushort)width)
{
//Loop through the defined sizes checking the length of the Copyright string
//If its length in pixles is less then the image width choose this Font size.
for (int i = 0; i < 7; i++)
{
//set a Font object to Arial (i)pt, Bold
crFont = new Font(font, sizes[i], FontStyle.Bold);
//Measure the Copyright string in this Font
crSize = watermark.MeasureString(text, crFont);
if ((ushort)crSize.Width < (ushort)width)
break;
}
}
// 文字的高和宽
PointF pf = GetPosition(image, crSize.Width, crSize.Height, 1);
pf.X += crSize.Width / 2;
//Define the text layout by setting the text alignment to centered
StringFormat StrFormat = new StringFormat();
StrFormat.Alignment = StringAlignment.Center;
//define a Brush which is semi trasparent black (Alpha set to 153)
SolidBrush semiTransBrush2 = new SolidBrush(Color.FromArgb(153, 0, 0, 0));
//Draw the Copyright string
watermark.DrawString(text, //string of text
crFont, //font
semiTransBrush2, //Brush
new PointF(pf.X + 1, pf.Y + 1), //Position
StrFormat);
//define a Brush which is semi trasparent white (Alpha set to 153)
SolidBrush semiTransBrush = new SolidBrush(Color.FromArgb(153, 255, 255, 255));
//Draw the Copyright string a second time to create a shadow effect
//Make sure to move this text 1 pixel to the right and down 1 pixel
watermark.DrawString(text, //string of text
crFont, //font
semiTransBrush, //Brush
pf, //Position
StrFormat); //Text alignment
watermark.Dispose();
return image;
}
#endregion
#region ImageWaterMark(Bitmap image)
private Bitmap ImageWaterMark(Bitmap image)
{
Graphics watermark = Graphics.FromImage(image);
// Set the rendering quality for this Graphics object
watermark.SmoothingMode = SmoothingMode.AntiAlias;
string wm_image_path = server.MapPath(Setting("photopath")) + Setting("watermark graphic");
if (File.Exists(wm_image_path))
{
Bitmap wm_image = (Bitmap)Bitmap.FromFile(wm_image_path);
// if the watermark's width is big than the original image's width
if (image.Width / 2 < wm_image.Width)
{
float w = image.Width / 2;
float h = w / wm_image.Width * wm_image.Height;
wm_image = Resize(wm_image, (int)h, (int)w);
}
string transparent = Setting("watermark graphic transparent color");
if (transparent != null)
{
Color t_color = ColorTranslator.FromHtml(transparent);
wm_image.MakeTransparent(t_color);
}
//To achieve a transulcent watermark we will apply (2) color
//manipulations by defineing a ImageAttributes object and
//seting (2) of its properties.
ImageAttributes imageAttributes = new ImageAttributes();
//The first step in manipulating the watermark image is to replace
//the background color with one that is trasparent (Alpha=0, R=0, G=0, B=0)
//to do this we will use a Colormap and use this to define a RemapTable
ColorMap colorMap = new ColorMap();
//My watermark was defined with a background of 100% Green this will
//be the color we search for and replace with transparency
colorMap.OldColor = Color.FromArgb(255, 0, 255, 0);
colorMap.NewColor = Color.FromArgb(0, 0, 0, 0);
ColorMap[] remapTable = { colorMap };
imageAttributes.SetRemapTable(remapTable, ColorAdjustType.Bitmap);
float transparence = float.Parse(Setting("watermark transparence"));
//The second color manipulation is used to change the opacity of the
//watermark. This is done by applying a 5x5 matrix that contains the
//coordinates for the RGBA space. By setting the 3rd row and 3rd column
//to 0.3f we achive a level of opacity
float[][] colorMatrixElements = {
new float[] {1.0f, 0.0f, 0.0f, 0.0f, 0.0f},
new float[] {0.0f, 1.0f, 0.0f, 0.0f, 0.0f},
new float[] {0.0f, 0.0f, 1.0f, 0.0f, 0.0f},
new float[] {0.0f, 0.0f, 0.0f, transparence, 0.0f},
new float[] {0.0f, 0.0f, 0.0f, 0.0f, 1.0f}};
ColorMatrix wmColorMatrix = new ColorMatrix(colorMatrixElements);
imageAttributes.SetColorMatrix(wmColorMatrix, ColorMatrixFlag.Default,
ColorAdjustType.Bitmap);
PointF pf = GetPosition(image, wm_image.Width, wm_image.Height, 2);
watermark.DrawImage(wm_image,
new Rectangle((int)pf.X, (int)pf.Y, wm_image.Width, wm_image.Height), //Set the detination Position
0, // x-coordinate of the portion of the source image to draw.
0, // y-coordinate of the portion of the source image to draw.
wm_image.Width, // Watermark Width
wm_image.Height, // Watermark Height
GraphicsUnit.Pixel, // Unit of measurment
imageAttributes); //ImageAttributes Object
}
watermark.Dispose();
return image;
}
#endregion
#region Common
/// <summary>
/// 获得URL传送过来的字符行参数
/// </summary>
/// <param name="key">参数的key</param>
/// <returns></returns>
private string RequestString(string key)
{
if (request.QueryString[key] != null && request.QueryString[key] != string.Empty)
{
return request.QueryString[key].Trim();
}
else
{
return string.Empty;
}
}
/// <summary>
/// 判断是否是整数
/// </summary>
/// <param name="value"></param>
/// <returns></returns>
private bool IsInt(string value)
{
string pattern = @"^[+-]?\d+$";
return Regex.IsMatch(value, pattern);
}
private Bitmap Resize(Bitmap image, int height, int width)
{
Bitmap thumb = new Bitmap(width, height);
Graphics g_thumb = Graphics.FromImage(thumb);
g_thumb.Clear(Color.White);
g_thumb.InterpolationMode = InterpolationMode.HighQualityBicubic;
// Set the rendering quality for this Graphics object
g_thumb.SmoothingMode = SmoothingMode.AntiAlias;
g_thumb.DrawImage(image, 0, 0, width, height);
g_thumb.Dispose();
return thumb;
}
private string ResponseType(string image_path)
{
switch (Path.GetExtension(image_path).ToLower())
{
case ".bmp": return "Image/bmp";
case ".gif": return "Image/gif";
case ".jpg": return "Image/jpeg";
case ".png": return "Image/png";
default: return null;
}
}
private ImageFormat ImageType(string image_path)
{
switch (Path.GetExtension(image_path).ToLower())
{
case ".bmp": return ImageFormat.Bmp;
case ".gif": return ImageFormat.Gif;
case ".jpg": return ImageFormat.Jpeg;
case ".png": return ImageFormat.Png;
default: return null;
}
}
private string Setting(string key)
{
return ConfigHelper.AppSettings[key].ToString().ToLower();
}
#endregion
}
}