實現原理:
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));
}
}
}