剛好這兩天完成這功能,順便打一篇教學好了...
View:
<img src="@Url.Action("GetWebThumbnail", new { url = ContextUrl, width = 1080, height = 900, thumbWidth = 700, thumbHeight = 650 })" />
沒錯... 一行就好。
用 Url.Action() 指定 src 和記得帶參數過去就好。
- url : 要擷取縮圖的網址 // 千萬不要帶入 google 或 facebook,會得到一道白光...
- width : 擷取網頁的寬
- height : 擷取網頁的高
- thumbWidth : 縮圖的寬
- thumbHeight : 縮圖的高
Controller:
控制器內藉由 ThumbnailService.GetThumbnail() 方法擷取到網頁縮圖後,再轉成 Bytes 回傳給 View。
前端 View 的 img 就能直接把 Action 回傳的東西當作 source。
public ActionResult GetWebThumbnail(string url, int width, int height, int thumbWidth, int thumbHeight)
{
var image = ThumbnailService.GetThumbnail(url, width, height, thumbWidth, thumbHeight);
var imageBytes = ImageToBytes(image); //Convert image into a byte array
return File(imageBytes, "image/Jpeg"); //Return as file result
}
private static byte[] ImageToBytes(Image img)
{
MemoryStream stream = new MemoryStream();
img.Save(stream, ImageFormat.Jpeg);
return stream.ToArray();
}
ThumbnailService.cs:
所以說,重點在這裡...
其實是利用 Windows.Form 的元件 WebBrowser 來完成擷圖這件事。
記得先在專案的參考 (reference) 加入
- System.Windows.Forms
- System.Windows.Forms.DataVisualization
using System; using System.Drawing; using System.Threading; using System.Windows.Forms; namespace 你的名字 { public class ThumbnailService { protected string _url; protected int _width, _height; protected int _thumbWidth, _thumbHeight; protected Bitmap _bmp; public static Image GetThumbnail(string url, int width, int height, int thumbWidth, int thumbHeight) { ThumbnailService thumbnail = new ThumbnailService(url, width, height, thumbWidth, thumbHeight); return thumbnail.GetThumbnail(); } //建構子 protected ThumbnailService(string url, int width, int height, int thumbWidth, int thumbHeight) { _url = url; _width = width; _height = height; _thumbWidth = thumbWidth; _thumbHeight = thumbHeight; } protected Image GetThumbnail() { // WebBrowser 是 ActiveX 控制項,一定要在單一執行緒執行 // 所以這邊產生一個 Thread 給他使用 Thread thread = new Thread(new ThreadStart(GetThumbnailWorker)); thread.SetApartmentState(ApartmentState.STA); thread.Start(); thread.Join(); return _bmp.GetThumbnailImage(_width, _height, null, IntPtr.Zero); } protected void GetThumbnailWorker() { WebBrowser browser = new WebBrowser(); browser.Navigate(@_url); browser.ScriptErrorsSuppressed = true; browser.ScrollBarsEnabled = false; browser.Size = new Size(_width, _height); // 等待網頁讀取完畢 while (browser.ReadyState != WebBrowserReadyState.Complete) Application.DoEvents(); _bmp = new Bitmap(_thumbWidth, _thumbHeight); browser.DrawToBitmap(_bmp, new Rectangle(browser.Location.X, browser.Location.Y, _thumbWidth, _thumbHeight)); } } }
重點在於最後兩個方法,
GetThumbnail 和 GetThumbnailWorker
其中 WebBrowser 這元件必須在單一執行緒執行,所以在 GetThumbnail 內做了一條執行緒給他,並執行 GetThumbnailWorker。
GetThumbnailWorker 要注意程式必須等待 WebBrowser 將網頁讀取完畢 (不然 DrawToBitmap 會畫不出東西...)。
其中還可以注意的是 45 行處,C# Image 類別有內建縮圖 GetThumbnailImage() 方法可用,將擷取的圖再做一次縮圖降低圖片大小後回傳。
缺點:
查過無數資料後,若你要做到像 Facebook 那樣貼連結就快速得到縮圖似乎需要很強大的演算法...在 C# 內我們借用 WebBrowser 物件先讀取網址後再畫進 Bitmap。
缺點就是,速度有點慢...畢竟要等 WebBrowser 將整個網頁讀完再做畫圖處理。
有機會找到解法再補上好了...
若你是寫 Webform 的玩家,也可以將 ThumbnailService.cs 內的程式寫在 ashx 內,用網址帶入 querystring 再回傳給 aspx 上的 Image 元件就好 ( 應該是這樣,好幾年沒碰 Webform了...
沒有留言:
張貼留言
注意:只有此網誌的成員可以留言。