天天看點

ASP.NET将原始圖檔按照指定尺寸等比例縮放顯示圖檔

網站上可能會有很多圖檔,比如産品圖檔等,而且他們可能大小不一,寬度和高度也不一定一樣,有的很大有的很小。如果放在一張網頁上,可能會破壞版面,但是如果強制讓他們按照指定的寬度和高度顯示,因為比例不同還會出現變形,顯示效果很糟糕,還有最大的缺點是,檔案尺寸絲毫沒有變化,當圖檔很大的時候,使用者想要看到圖檔,必須經過漫長等待下載下傳圖檔,怎麼辦呢?

好,這裡涉及到了縮略圖,就像Windows中的縮略圖檢視一樣,你所看到的是從原圖按照1:1比例縮小的圖檔,而且滿足規定在指定寬度和高度的範圍内顯示(如果圖檔填不滿,就用空白)。縮略圖不是原圖,而是利用原圖實時按照指定大小生成的,他的好處就是你可以充分控制縮略圖的品質,寬度高度,檔案大小也在合理的範圍内,省去漫長等待。

本文将讨論如何生成縮略圖,舉一反三,又可以派生許多用處,比如,自己寫一個驗證碼控件等。

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' />      

繼續閱讀