網(wǎng)站上可能會(huì)有很多圖片,比如產(chǎn)品圖片等,而且他們可能大小不一,寬度和高度也不一定一樣,有的很大有的很小。如果放在一張網(wǎng)頁(yè)上,可能會(huì)破壞版面,但是如果強(qiáng)制讓他們按照指定的寬度和高度顯示,因?yàn)楸壤煌€會(huì)出現(xiàn)變形,顯示效果很糟糕,還有最大的缺點(diǎn)是,文件尺寸絲毫沒有變化,當(dāng)圖片很大的時(shí)候,用戶想要看到圖片,必須經(jīng)過漫長(zhǎng)等待下載圖片,怎么辦呢?
好,這里涉及到了縮略圖,就像Windows中的縮略圖查看一樣,你所看到的是從原圖按照1:1比例縮小的圖片,而且滿足規(guī)定在指定寬度和高度的范圍內(nèi)顯示(如果圖片填不滿,就用空白)。縮略圖不是原圖,而是利用原圖實(shí)時(shí)按照指定大小生成的,他的好處就是你可以充分控制縮略圖的質(zhì)量,寬度高度,文件大小也在合理的范圍內(nèi),省去漫長(zhǎng)等待。
本文將討論如何生成縮略圖,舉一反三,又可以派生許多用處,比如,自己寫一個(gè)驗(yàn)證碼控件等。
1、理解對(duì)圖片的請(qǐng)求和流
一般來說,我們用http://xxx/a.aspx對(duì)a.aspx網(wǎng)頁(yè)請(qǐng)求。asp.net處理了網(wǎng)頁(yè)以后,就把該網(wǎng)頁(yè)的內(nèi)容發(fā)送回瀏覽器。a.aspx的內(nèi)容一般是含有超文本標(biāo)記的文本文件流(Response.ContentType即輸出流的 HTTP MIME 類型,默認(rèn)值是“text/html”),這是誰(shuí)都不會(huì)懷疑的。但是a.aspx不但能夠返回這種平常的網(wǎng)頁(yè)文本外,把它廣義開來,它其實(shí)可以返回任何類型的流數(shù)據(jù)。而,我們只需要對(duì)Response對(duì)象進(jìn)行操作即可改變輸出流的內(nèi)容。
把圖像文件看作是一個(gè)二進(jìn)制流,我們?cè)噲D從一個(gè)圖像文件創(chuàng)建了他的流對(duì)象,并且將流寫入到Response.OutputStream中,這樣圖像文件就被發(fā)給了請(qǐng)求的瀏覽器。但是瀏覽器還必須要識(shí)別出這是一個(gè)圖像文件,因此,在發(fā)送這個(gè)流之前,將Response.ContentType更改成這種圖像文件的MIME類型。瀏覽器在收到這個(gè)流之后,調(diào)用相關(guān)的應(yīng)用程序,圖像就被顯示在了瀏覽器上。雖然實(shí)際地址還是aspx結(jié)尾。
這樣我們就能很好理解怎么去向用戶發(fā)送標(biāo)記。例如,在一張普通的網(wǎng)頁(yè)中寫img標(biāo)簽,使它的src指向a.aspx。瀏覽器在得到這張網(wǎng)頁(yè)后,會(huì)處理img標(biāo)簽的內(nèi)容,并向a.aspx發(fā)出請(qǐng)求,這時(shí)a.aspx作為圖像流返回,瀏覽器就將圖片顯示出來。
2、生成縮略圖
新建webform頁(yè)面,它通過接受傳入的參數(shù),生成縮略圖的流,發(fā)送回瀏覽器。cs代碼如下:
using System;using System.Drawing;using System.Drawing.Imaging;namespace Demo.Web{ public partial class GetThumbnail : System.Web.UI.Page { PRotected void Page_Load(object sender, EventArgs e) { Response.Clear(); string originalFileName =Server.MapPath( Request.QueryString["imgSrc"]); int thumbnailWidth = Convert.ToInt32(Request.QueryString["width"]); int thumbnailHeight = Convert.ToInt32(Request.QueryString["height"]); System.Drawing.Image img = System.Drawing.Image.FromFile(originalFileName); var thisFormat = img.RawFormat; System.Drawing.Size newSize = GetNewSize(thumbnailWidth, thumbnailHeight, img.Width, img.Height); var outBmp = new System.Drawing.Bitmap(thumbnailWidth, thumbnailHeight); var g = System.Drawing.Graphics.FromImage(outBmp); //設(shè)置畫布的描繪質(zhì)量 g.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality; g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality; g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic; g.Clear(System.Drawing.Color.FromArgb(255, 249, 255, 240));//.Transparent);//.FromArgb(255, 249, 255, 240)); g.DrawImage(img, new Rectangle((thumbnailWidth - newSize.Width) / 2, (thumbnailHeight - newSize.Height) / 2, newSize.Width, newSize.Height), 0, 0, img.Width, img.Height, GraphicsUnit.Pixel); g.Dispose(); if (thisFormat == System.Drawing.Imaging.ImageFormat.Gif) { Response.ContentType = "image/gif"; } else { Response.ContentType = "image/jpeg"; } // 設(shè)置壓縮質(zhì)量 EncoderParameters encoderParams = new EncoderParameters(); long[] quality = new long[1]; quality[0] = 100; EncoderParameter encoderParam = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, quality); encoderParams.Param[0] = encoderParam; //獲得包含有關(guān)內(nèi)置圖像編碼解碼器的信息的ImageCodecInfo 對(duì)象。 var arrayICI = System.Drawing.Imaging.ImageCodecInfo.GetImageEncoders(); System.Drawing.Imaging.ImageCodecInfo jpegICI = null; for (int fwd = 0; fwd < arrayICI.Length; fwd++) { if (arrayICI[fwd].FormatDescription.Equals("JPEG")) { jpegICI = arrayICI[fwd]; break; } } if (jpegICI != null) outBmp.Save(Response.OutputStream, jpegICI, encoderParams); else outBmp.Save(Response.OutputStream, img.RawFormat); } 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 System.Drawing.Size(Convert.ToInt32(w), Convert.ToInt32(h)); } }}
我們?cè)赑age_Load事件處理函數(shù)中,先獲取要生成縮略圖的原始文件的路徑,和縮略圖的寬度高度。
然后設(shè)置了一個(gè)子函數(shù)GetNewSize用以計(jì)算真正縮略圖的大小(為什么還要計(jì)算阿?因?yàn)榭s略圖的寬高比和原始圖片的寬高比不一樣,縮小的圖片要保證比例,按照比例縮小的原始圖片,是按照約束在指定縮略圖寬高范圍內(nèi)的原則,填充不滿的地方使用背景色填補(bǔ)空白。另外,原圖比縮略圖小的話,我們就不做放大,而是按原圖輸出,所以計(jì)算是必須的)。
我們從原始圖像創(chuàng)建了他的Image對(duì)象,并獲得它的格式等信息,稍后用得到。
接下來新建一個(gè)BitMap對(duì)象,并由新的BitMap對(duì)象創(chuàng)建畫板。設(shè)置畫筆質(zhì)量為高,交錯(cuò)模式為高質(zhì)量立方式,這些的目的是使用最好的質(zhì)量描繪縮略圖,否則圖片縮小后信息丟失圖片失真就不好看了。接著,用指定的寬度和高度將原始圖像的Image對(duì)象“畫”在新的畫板上。
修改Response.ContentType,這一步是告訴瀏覽器發(fā)送回的流的MIME類型,這個(gè)內(nèi)容包含在HTTP Header中發(fā)送給瀏覽器。
圖像畫好了,現(xiàn)在我們要將其壓縮一下,因?yàn)槲粓D對(duì)象是很大的,不利于傳輸。因此下面的操作,我們?cè)O(shè)定一些高質(zhì)量的壓縮參數(shù),根據(jù)獲得的ICI(圖像編碼解碼器信息),使用BitMap的Save方法將圖片保存在Response.OutputStream流中。
這樣在瀏覽器看來,對(duì)該網(wǎng)頁(yè)的請(qǐng)求,相當(dāng)于對(duì)一個(gè)圖片文件的請(qǐng)求,只不過圖片是實(shí)時(shí)生成的,只要傳遞參數(shù)合法有效,即可得到該圖片的縮略圖。
3、使用縮略圖
使用縮略圖就變得相對(duì)簡(jiǎn)單了,只需要在URL后附上參數(shù)imgSrc表示原始文件的位置(相對(duì)于根目錄),width縮略圖寬度,height縮略圖高度,下列簡(jiǎn)單顯示了在Repeater中使用的情景:
<img alt='' border="0" src='GetThumbnail.aspx?imgsrc=<%#Eval("ImgUrl") %>&width=300&height=300' />
下面就等著看看縮略圖的效果:
后記
本文中所述的縮略圖生成法,使用的是流的概念,和文件系統(tǒng)也不沾邊,因此這種方式可以跳過對(duì)文件系統(tǒng)權(quán)限檢查,百分之百正確運(yùn)行。當(dāng)然,也可以借助文件系統(tǒng)。另外,根據(jù)上面流輸出的概念,舉一反三,可以弄出很多用法,例如NeoDynamic的條形碼控件,你會(huì)發(fā)現(xiàn)條形碼圖片的路徑居然就是本頁(yè)頁(yè)面,他巧妙地將對(duì)本頁(yè)的請(qǐng)求通過對(duì)幾個(gè)特征參數(shù)的判定而轉(zhuǎn)向生成圖片流,從而達(dá)到了不添加任何頁(yè)面,不借助文件系統(tǒng)的“神奇效果”,只需要一個(gè)DLL即可使用。
另外,很多人問生成驗(yàn)證碼圖片,也可以使用這樣的思路,自己做一個(gè)這樣的控件,或者網(wǎng)頁(yè)。如果能做自定義控件更好。相信大家有這個(gè)能力。
|
新聞熱點(diǎn)
疑難解答
圖片精選
網(wǎng)友關(guān)注