实现原理:
1、 我们现在要做的是自定义Web控件,这和平常设计aspx网页或者用户控件有本质区别,自定义控件是一个派生自System.Web.WebControls.WebControl的类,它是一个类,而不是你想象中的HTML代码,甚至在自定义控件中你完全找不到HTMl的任何风格。因此,你必须对类的编写设计非常数量,或者是,跳出设计HTML的圈子,拓展思维!
2、 我们要实现不依靠文件系统、不依靠额外的任何其他东西,仅仅依靠一个类来实现它,这样做好处自然明显——各位只要复制得下面的一堆代码,自己建一个cs文件放进去就可以编译(编译为dll)。所有功能都是自含的,除了位于公共位置的.net类库,其他任何dll我都不需要引用。
然而,要实现如第2条这样的效果,我们得把对缩略图的请求设计成为对包含控件网页本身的请求,因为针对缩略图的这一次请求,本质仍然对本网页的请求,这样,网页中包含的缩略图控件才有机会操纵流。当然,两次请求都针对同一张网页的话,我们要设法区分开,哪一次是真正请求网页的原内容,哪一次是针对请求一个缩略图。
不知上述这段话大家能否理解,
如果不这样做的话,我们就不得不需要额外的控件或网页来实行了。
看懂了上述原理,我现在把流程写在下面,就自然好理解了:
1、 客户请求一张网页,如index.aspx,网页中含有缩略图控件,
2、 Index.aspx编译执行为HTML后被发送到客户端浏览器。这个控件生成了一个img标记,src属性指向一张该网页本身,但是后面附带的参数改变了。浏览器解析了,知道要向src属性获得一张图片。它开始向这个位置请求(也就是重新以新的附带参数请求这个网页)。
3、 ASP.Net获得了这个请求,index.aspx这个页面又开始执行,因为index.aspx中包含这个缩略图控件,控件就有机会识别这段特殊的参数,并且重新改写响应流,它会在文件系统中获得原始图像,然后根据你的要求,使用GDI.NET将原图重新按照新尺寸绘制,得到的新图是一个流对象,我们不存储它,而是将它直接附着在响应流中,发送给客户端。
4、 客户端浏览器得到这张图片。网页加载完成。
好,原理是说了不少,虽然我尽量写得通俗,但难免大家一时半会儿可能不好理解。那我现在就把代码贴出来让大家参考。
这个缩略图控件还没有添加水印等类似版权保护的功能,各位有兴趣的高手不妨完善一下这部分内容。同时与各位朋友相互学习,加强思考,增进思维。我们不管ASP.NET孰优孰劣,对于个人来说,既然追随ASP.NET,就要把ASP.NET用好,随波逐流的程序员永远不会优秀。
using
System;
using
System.Web;
using
System.Web.UI;
using
System.Web.UI.WebControls;
using
System.Drawing;
using
System.ComponentModel;
using
System.Drawing.Design;
using
System.Drawing.Drawing2D;
using
System.Text;
using
System.IO;
namespace
BlogLan.Web.Controls
{
///
<summary>
///
缩略图控件。
///
</summary>
[DefaultProperty(
"
ImageUrl
"
)]
[ToolboxData(
"
<{0}:Thumbnail runat=server></{0}:Thumbnail>
"
)]
[DesignerAttribute(
typeof
(Designer.ThumbnailDesigner))]
[Description(
"
缩略图控件。
"
)]
public
class
Thumbnail : WebControl
{
public
Thumbnail()
:
base
(HtmlTextWriterTag.Img)
{
this
.Width
=
Unit.Parse(
"
100
"
);
this
.Height
=
Unit.Parse(
"
75
"
);
}
//
Private Members
private
bool
urlResolved;
///
<summary>
///
获取或设置图片路径。
///
</summary>
[Editor(
"
System.Web.UI.Design.ImageUrlEditor, System.Design, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
"
,
typeof
(UITypeEditor)), Description(
"
获取或设置图片路径
"
), Bindable(
true
), Category(
"
Appearance
"
), DefaultValue(
""
), UrlProperty]
public
string
ImageUrl
{
get
{
if
(
this
.ViewState[
"
ImageUrl
"
]
!=
null
)
{
return
(
string
)
this
.ViewState[
"
ImageUrl
"
];
}
return
string
.Empty;
}
set
{
this
.ViewState[
"
ImageUrl
"
]
=
value;
}
}
///
<summary>
///
获取或设置Jpeg缩略图的质量,值范围-100。
///
</summary>
[DefaultValue(
80
)]
public
int
JpegQuality
{
get
{
if
(
this
.ViewState[
"
JpegQuility
"
]
!=
null
)
{
return
(
int
)
this
.ViewState[
"
JpegQuility
"
];
}
return
80
;
}
set
{
if
(value
>
100
)
{
this
.ViewState[
"
JpegQuility
"
]
=
100
;
}
else
if
(value
<
20
)
{
this
.ViewState[
"
JpegQuility
"
]
=
20
;
}
else
{
this
.ViewState[
"
JpegQuility
"
]
=
value;
}
}
}
[DefaultValue(
typeof
(Unit),
"
100px
"
)]
public
override
Unit Width
{
get
{
return
base
.Width;
}
set
{
base
.Width
=
value;
}
}
[DefaultValue(
typeof
(Unit),
"
75px
"
)]
public
override
Unit Height
{
get
{
return
base
.Height;
}
set
{
base
.Height
=
value;
}
}
internal
bool
UrlResolved
{
get
{
return
this
.urlResolved;
}
set
{
this
.urlResolved
=
value;
}
}
///
<summary>
///
获取或设置控件相对于网页上其他元素的对齐方式。
///
</summary>
[DefaultValue(ImageAlign.NotSet), Description(
"
获取或设置控件相对于网页上其他元素的对齐方式。
"
)]
public
virtual
ImageAlign ImageAlign
{
get
{
object
obj2
=
this
.ViewState[
"
ImageAlign
"
];
if
(obj2
!=
null
)
{
return
(ImageAlign)obj2;
}
return
ImageAlign.NotSet;
}
set
{
if
((value
<
ImageAlign.NotSet)
||
(value
>
ImageAlign.TextTop))
{
throw
new
ArgumentOutOfRangeException(
"
value
"
);
}
this
.ViewState[
"
ImageAlign
"
]
=
value;
}
}
///
<summary>
///
[禁用Enabled属性在任何位置编辑。]
///
</summary>
[Browsable(
false
), EditorBrowsable(EditorBrowsableState.Never)]
public
override
bool
Enabled
{
get
{
return
base
.Enabled;
}
set
{
base
.Enabled
=
value;
}
}
///
<summary>
///
如无法显示图片时显示的替代文本。
///
</summary>
[DefaultValue(
""
), Bindable(
true
), Localizable(
true
), Description(
"
如无法显示图片时显示的替代文本。
"
)]
public
virtual
string
AlternateText
{
get
{
if
(
this
.ViewState[
"
AlternateText
"
]
!=
null
)
{
return
(
string
)
this
.ViewState[
"
AlternateText
"
];
}
return
string
.Empty;
}
set
{
this
.ViewState[
"
AlternateText
"
]
=
value;
}
}
///
<summary>
///
获取或设置一个值,该值指示控件是否生成空字符串值的替换文字属性。
///
</summary>
[DefaultValue(
true
), Description(
"
获取或设置一个值,该值指示控件是否生成空字符串值的替换文字属性。
"
)]
public
virtual
bool
GenerateEmptyAlternateText
{
get
{
if
(
this
.ViewState[
"
GenerateEmptyAlternateText
"
]
!=
null
)
{
return
(
bool
)
this
.ViewState[
"
GenerateEmptyAlternateText
"
];
}
return
true
;
}
set
{
this
.ViewState[
"
GenerateEmptyAlternateText
"
]
=
value;
}
}
///
<summary>
///
获取或设置图像详细说明的位置。
///
</summary>
[Editor(
"
System.Web.UI.Design.UrlEditor, System.Design, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
"
,
typeof
(UITypeEditor)), UrlProperty, DefaultValue(
""
), Description(
"
获取或设置图像详细说明的位置。
"
)]
public
virtual
string
DescriptionUrl
{
get
{
string
str
=
(
string
)
this
.ViewState[
"
DescriptionUrl
"
];
if
(str
!=
null
)
{
return
str;
}
return
string
.Empty;
}
set
{
this
.ViewState[
"
DescriptionUrl
"
]
=
value;
}
}
//
Methods
///
<summary>
///
重写AddAttributesToRender方法。
///
</summary>
///
<param name="writer"></param>
protected
override
void
AddAttributesToRender(HtmlTextWriter writer)
{
if
(
string
.IsNullOrEmpty(
this
.Page.Request[
"
thumbnail
"
]))
{
this
.AddThumbnailAttributesToRender(writer,
string
.Empty);
}
}
protected
virtual
internal
void
AddThumbnailAttributesToRender(HtmlTextWriter writer,
string
ForcedImageUrl)
{
base
.AddAttributesToRender(writer);
string
imageUrl
=
this
.ImageUrl;
if
(
!
this
.UrlResolved)
{
imageUrl
=
base
.ResolveClientUrl(imageUrl);
}
//
在设计时强制赋予图形路径。
if
(
!
string
.IsNullOrEmpty(ForcedImageUrl))
{
imageUrl
=
ForcedImageUrl;
writer.AddAttribute(HtmlTextWriterAttribute.Src, imageUrl);
}
else
{
writer.AddAttribute(HtmlTextWriterAttribute.Src,
this
.Page.Request.Url.AbsolutePath
+
"
?
"
+
this
.GetQueryString(),
false
);
}
imageUrl
=
this
.DescriptionUrl;
if
(imageUrl.Length
!=
0
)
{
writer.AddAttribute(HtmlTextWriterAttribute.Longdesc,
base
.ResolveClientUrl(imageUrl));
}
imageUrl
=
this
.AlternateText;
if
((imageUrl.Length
>
0
)
||
this
.GenerateEmptyAlternateText)
{
writer.AddAttribute(HtmlTextWriterAttribute.Alt, imageUrl);
}
switch
(
this
.ImageAlign)
{
case
ImageAlign.Left:
writer.AddAttribute(HtmlTextWriterAttribute.Align,
"
left
"
);
break
;
case
ImageAlign.Right:
writer.AddAttribute(HtmlTextWriterAttribute.Align,
"
right
"
);
break
;
case
ImageAlign.Baseline:
writer.AddAttribute(HtmlTextWriterAttribute.Align,
"
baseline
"
);
break
;
case
ImageAlign.Top:
writer.AddAttribute(HtmlTextWriterAttribute.Align,
"
top
"
);
break
;
case
ImageAlign.Middle:
writer.AddAttribute(HtmlTextWriterAttribute.Align,
"
middle
"
);
break
;
case
ImageAlign.Bottom:
writer.AddAttribute(HtmlTextWriterAttribute.Align,
"
bottom
"
);
break
;
case
ImageAlign.AbsBottom:
writer.AddAttribute(HtmlTextWriterAttribute.Align,
"
absbottom
"
);
break
;
case
ImageAlign.AbsMiddle:
writer.AddAttribute(HtmlTextWriterAttribute.Align,
"
absmiddle
"
);
break
;
case
ImageAlign.NotSet:
break
;
default
:
writer.AddAttribute(HtmlTextWriterAttribute.Align,
"
texttop
"
);
break
;
}
if
(
this
.BorderWidth.IsEmpty)
{
writer.AddStyleAttribute(HtmlTextWriterStyle.BorderWidth,
"
0px
"
);
}
}
private
string
GetQueryString()
{
StringBuilder sb
=
new
StringBuilder();
sb.Append(
"
thumbnail=
"
+
this
.Page.Server.HtmlEncode(
this
.ImageUrl));
sb.Append(
"
&w=
"
+
this
.Width.Value.ToString());
sb.Append(
"
&h=
"
+
this
.Height.Value.ToString());
sb.Append(
"
&bc=
"
+
this
.BackColor.ToArgb().ToString());
sb.Append(
"
&jq=
"
+
this
.JpegQuality.ToString());
return
sb.ToString();
}
protected
override
void
RenderContents(HtmlTextWriter writer)
{
}
protected
override
ControlCollection CreateControlCollection()
{
return
new
EmptyControlCollection(
this
);
}
protected
override
void
OnInit(EventArgs e)
{
base
.OnInit(e);
this
.Init
+=
new
EventHandler(Thumbnail_Init);
this
.PreRender
+=
new
EventHandler(Thumbnail_PreRender);
}
void
Thumbnail_PreRender(
object
sender, EventArgs e)
{
if
(HttpContext.Current
!=
null
)
{
RenderThumbnailImage(
this
.Page.Request,
this
.Page.Response);
}
}
void
Thumbnail_Init(
object
sender, EventArgs e)
{
if
(HttpContext.Current
!=
null
)
{
RenderThumbnailImage(
this
.Page.Request,
this
.Page.Response);
}
}
static
void
RenderThumbnailImage(HttpRequest request, HttpResponse response)
{
if
(
string
.IsNullOrEmpty(request[
"
thumbnail
"
]))
{
return
;
}
Thumbnail thumbnail
=
new
Thumbnail();
Bitmap tmb;
try
{
thumbnail.ImageUrl
=
request[
"
thumbnail
"
];
try
{
thumbnail.Width
=
Unit.Parse(request[
"
w
"
]);
}
catch
{
thumbnail.Width
=
Unit.Pixel(
100
);
}
try
{
thumbnail.Height
=
Unit.Parse(request[
"
h
"
]);
}
catch
{
thumbnail.Height
=
Unit.Pixel(
75
);
}
try
{
thumbnail.BackColor
=
Color.FromArgb(Convert.ToInt32(request[
"
bc
"
]));
}
catch
{
thumbnail.BackColor
=
Color.Black;
}
try
{
thumbnail.JpegQuality
=
Convert.ToInt32(request[
"
jq
"
]);
}
catch
{
thumbnail.JpegQuality
=
80
;
}
tmb
=
thumbnail.GetThumbnail();
}
catch
{
tmb
=
Properties.Resources.GenerateImageError;
}
response.Clear();
string
[] ImageFilePart
=
thumbnail.ImageUrl.ToLower().Split(
'
.
'
);
string
Suffix
=
"
bmp
"
;
if
(ImageFilePart.Length
>
1
)
{
Suffix
=
ImageFilePart[ImageFilePart.Length
-
1
];
}
if
(Suffix
==
"
gif
"
)
{
response.ContentType
=
"
image/gif
"
;
tmb.Save(response.OutputStream, System.Drawing.Imaging.ImageFormat.Gif);
}
else
if
(Suffix
==
"
jpg
"
||
Suffix
==
"
jpeg
"
)
{
response.ContentType
=
"
image/jpeg
"
;
System.Drawing.Imaging.EncoderParameters encoderParams
=
new
System.Drawing.Imaging.EncoderParameters();
long
[] quality
=
new
long
[] { Convert.ToInt64(thumbnail.JpegQuality) };
System.Drawing.Imaging.EncoderParameter encoderParam
=
new
System.Drawing.Imaging.EncoderParameter(System.Drawing.Imaging.Encoder.Quality, quality);
encoderParams.Param[
0
]
=
encoderParam;
System.Drawing.Imaging.ImageCodecInfo[] arrayICI
=
System.Drawing.Imaging.ImageCodecInfo.GetImageEncoders();
System.Drawing.Imaging.ImageCodecInfo jpegICI
=
null
;
for
(
int
fwd
=
0
; fwd
<
arrayICI.Length
-
1
; fwd
++
)
{
if
(arrayICI[fwd].FormatDescription.Equals(
"
JPEG
"
))
{
jpegICI
=
arrayICI[fwd];
break
;
}
}
if
(jpegICI
!=
null
)
{
tmb.Save(response.OutputStream, jpegICI, encoderParams);
}
else
{
tmb.Save(response.OutputStream, System.Drawing.Imaging.ImageFormat.Jpeg);
}
}
else
{
response.ContentType
=
"
image/bmp
"
;
tmb.Save(response.OutputStream, System.Drawing.Imaging.ImageFormat.Bmp);
}
tmb.Dispose();
response.Flush();
}
//
public
Bitmap GetThumbnail()
{
return
this
.GetThumbnail(
this
);
}
private
Bitmap GetThumbnail(Thumbnail thumbnail)
{
if
(thumbnail
==
null
)
return
Properties.Resources.GenerateImageError;
System.Drawing.Image OriginalImage;
try
{
if
(thumbnail.DesignMode)
{
//
string pagepath = thumbnail.MapPathSecure("/");
OriginalImage
=
(System.Drawing.Image)Properties.Resources.ThumbnailDesign;
}
else
{
OriginalImage
=
System.Drawing.Image.FromFile(thumbnail.Context.Server.MapPath(thumbnail.ImageUrl));
}
}
catch
{
return
Properties.Resources.GenerateImageError;
}
Size thumbnailNewSize
=
this
.GetNewSize(Convert.ToInt32(thumbnail.Width.Value), Convert.ToInt32(thumbnail.Height.Value), OriginalImage.Width, OriginalImage.Height);
Bitmap outbmp
=
new
Bitmap(Convert.ToInt32(thumbnail.Width.Value), Convert.ToInt32(thumbnail.Height.Value));
Graphics g
=
Graphics.FromImage(outbmp);
try
{
g.CompositingQuality
=
CompositingQuality.HighQuality;
g.SmoothingMode
=
SmoothingMode.HighQuality;
g.InterpolationMode
=
InterpolationMode.HighQualityBicubic;
g.Clear(thumbnail.BackColor);
Rectangle _Vb_t_record_0
=
new
Rectangle((
int
)Math.Round((
double
)(((
double
)(thumbnail.Width.Value
-
thumbnailNewSize.Width))
/
2.0
)), (
int
)Math.Round((
double
)(((
double
)(thumbnail.Height.Value
-
thumbnailNewSize.Height))
/
2.0
)), thumbnailNewSize.Width, thumbnailNewSize.Height);
g.DrawImage(OriginalImage, _Vb_t_record_0,
0
,
0
, OriginalImage.Width, OriginalImage.Height, GraphicsUnit.Pixel);
g.Dispose();
}
catch
{
return
Properties.Resources.GenerateImageError;
}
finally
{
g.Dispose();
OriginalImage.Dispose();
}
return
outbmp;
}
private
Size GetNewSize(
int
maxWidth,
int
maxHeight,
int
width,
int
height)
{
double
w
=
0.0
;
double
h
=
0.0
;
double
sw
=
Convert.ToDouble(width);
double
sh
=
Convert.ToDouble(height);
double
mw
=
Convert.ToDouble(maxWidth);
double
mh
=
Convert.ToDouble(maxHeight);
if
((sw
<
mw)
&
(sh
<
mh))
{
w
=
sw;
h
=
sh;
}
else
if
((sw
/
sh)
>
(mw
/
mh))
{
w
=
maxWidth;
h
=
(w
*
sh)
/
sw;
}
else
{
h
=
maxHeight;
w
=
(h
*
sw)
/
sh;
}
return
new
Size(Convert.ToInt32(w), Convert.ToInt32(h));
}
}
}