網站上可能會有很多圖片,比如產品圖片等,而且他們可能大小不一,寬度和高度也不一定一樣,有的很大有的很小。如果放在一張網頁上,可能會破壞版面,但是如果強制讓他們按照指定的寬度和高度顯示,因為比例不同還會出現變形,顯示效果很糟糕,還有最大的缺點是,文件尺寸絲毫沒有變化,當圖片很大的時候,用戶想要看到圖片,必須經過漫長等待下載圖片,怎么辦呢?
好,這里涉及到了縮略圖,就像Windows中的縮略圖查看一樣,你所看到的是從原圖按照1:1比例縮小的圖片,而且滿足規定在指定寬度和高度的范圍內顯示(如果圖片填不滿,就用空白)??s略圖不是原圖,而是利用原圖實時按照指定大小生成的,他的好處就是你可以充分控制縮略圖的質量,寬度高度,文件大小也在合理的范圍內,省去漫長等待。
本文將討論如何生成縮略圖,舉一反三,又可以派生許多用處,比如,自己寫一個驗證碼控件等。
1、理解對圖片的請求和流
一般來說,我們用http://xxx/a.aspx對a.aspx網頁請求。asp.net處理了網頁以后,就把該網頁的內容發送回瀏覽器。a.aspx的內容一般是含有超文本標記的文本文件流(Response.ContentType即輸出流的 HTTP MIME 類型,默認值是“text/html”),這是誰都不會懷疑的。但是a.aspx不但能夠返回這種平常的網頁文本外,把它廣義開來,它其實可以返回任何類型的流數據。而,我們只需要對Response對象進行操作即可改變輸出流的內容。
把圖像文件看作是一個二進制流,我們試圖從一個圖像文件創建了他的流對象,并且將流寫入到Response.OutputStream中,這樣圖像文件就被發給了請求的瀏覽器。但是瀏覽器還必須要識別出這是一個圖像文件,因此,在發送這個流之前,將Response.ContentType更改成這種圖像文件的MIME類型。瀏覽器在收到這個流之后,調用相關的應用程序,圖像就被顯示在了瀏覽器上。雖然實際地址還是aspx結尾。
這樣我們就能很好理解怎么去向用戶發送標記。例如,在一張普通的網頁中寫img標簽,使它的src指向a.aspx。瀏覽器在得到這張網頁后,會處理img標簽的內容,并向a.aspx發出請求,這時a.aspx作為圖像流返回,瀏覽器就將圖片顯示出來。
2、生成縮略圖
新建webform頁面,它通過接受傳入的參數,生成縮略圖的流,發送回瀏覽器。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); //設置畫布的描繪質量 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"; } // 設置壓縮質量 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; //獲得包含有關內置圖像編碼解碼器的信息的ImageCodecInfo 對象。 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)); } }}
我們在Page_Load事件處理函數中,先獲取要生成縮略圖的原始文件的路徑,和縮略圖的寬度高度。
然后設置了一個子函數GetNewSize用以計算真正縮略圖的大?。槭裁催€要計算阿?因為縮略圖的寬高比和原始圖片的寬高比不一樣,縮小的圖片要保證比例,按照比例縮小的原始圖片,是按照約束在指定縮略圖寬高范圍內的原則,填充不滿的地方使用背景色填補空白。另外,原圖比縮略圖小的話,我們就不做放大,而是按原圖輸出,所以計算是必須的)。
我們從原始圖像創建了他的Image對象,并獲得它的格式等信息,稍后用得到。
接下來新建一個BitMap對象,并由新的BitMap對象創建畫板。設置畫筆質量為高,交錯模式為高質量立方式,這些的目的是使用最好的質量描繪縮略圖,否則圖片縮小后信息丟失圖片失真就不好看了。接著,用指定的寬度和高度將原始圖像的Image對象“畫”在新的畫板上。
修改Response.ContentType,這一步是告訴瀏覽器發送回的流的MIME類型,這個內容包含在HTTP Header中發送給瀏覽器。
圖像畫好了,現在我們要將其壓縮一下,因為位圖對象是很大的,不利于傳輸。因此下面的操作,我們設定一些高質量的壓縮參數,根據獲得的ICI(圖像編碼解碼器信息),使用BitMap的Save方法將圖片保存在Response.OutputStream流中。
這樣在瀏覽器看來,對該網頁的請求,相當于對一個圖片文件的請求,只不過圖片是實時生成的,只要傳遞參數合法有效,即可得到該圖片的縮略圖。
3、使用縮略圖
使用縮略圖就變得相對簡單了,只需要在URL后附上參數imgSrc表示原始文件的位置(相對于根目錄),width縮略圖寬度,height縮略圖高度,下列簡單顯示了在Repeater中使用的情景:
<img alt='' border="0" src='GetThumbnail.aspx?imgsrc=<%#Eval("ImgUrl") %>&width=300&height=300' />
下面就等著看看縮略圖的效果:
后記
本文中所述的縮略圖生成法,使用的是流的概念,和文件系統也不沾邊,因此這種方式可以跳過對文件系統權限檢查,百分之百正確運行。當然,也可以借助文件系統。另外,根據上面流輸出的概念,舉一反三,可以弄出很多用法,例如NeoDynamic的條形碼控件,你會發現條形碼圖片的路徑居然就是本頁頁面,他巧妙地將對本頁的請求通過對幾個特征參數的判定而轉向生成圖片流,從而達到了不添加任何頁面,不借助文件系統的“神奇效果”,只需要一個DLL即可使用。
另外,很多人問生成驗證碼圖片,也可以使用這樣的思路,自己做一個這樣的控件,或者網頁。如果能做自定義控件更好。相信大家有這個能力。
新聞熱點
疑難解答