将网页转换为ASP.NET的图像

我想在C#中创build一个函数,它需要一个特定的网页,并从ASP.NET内部转换成JPG图像。 我不想通过第三方或缩略图服务做到这一点,因为我需要完整的形象。 我假设我需要以某种方式利用从ASP.NET内的webbrowser控件,但我不知道从哪里开始。 有没有人有例子?

好的,当我结合几种不同的解决scheme时,这是相当容易的:

这些解决scheme给了我一个线程安全的方式来使用ASP.NET的WebBrowser:

http://www.beansoftware.com/ASP.NET-Tutorials/Get-Web-Site-Thumbnail-Image.aspx

http://www.eggheadcafe.com/tutorials/aspnet/b7cce396-e2b3-42d7-9571-cdc4eb38f3c1/build-a-selfcaching-asp.aspx

这个解决scheme给了我一个转换BMP到JPG的方法:

Bmp到jpg / png在C#

我简单地调整了代码,并将以下内容放入.cs:

using System.Drawing; using System.Drawing.Imaging; using System.IO; using System.Threading; using System.Windows.Forms; public class WebsiteToImage { private Bitmap m_Bitmap; private string m_Url; private string m_FileName = string.Empty; public WebsiteToImage(string url) { // Without file m_Url = url; } public WebsiteToImage(string url, string fileName) { // With file m_Url = url; m_FileName = fileName; } public Bitmap Generate() { // Thread var m_thread = new Thread(_Generate); m_thread.SetApartmentState(ApartmentState.STA); m_thread.Start(); m_thread.Join(); return m_Bitmap; } private void _Generate() { var browser = new WebBrowser { ScrollBarsEnabled = false }; browser.Navigate(m_Url); browser.DocumentCompleted += WebBrowser_DocumentCompleted; while (browser.ReadyState != WebBrowserReadyState.Complete) { Application.DoEvents(); } browser.Dispose(); } private void WebBrowser_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e) { // Capture var browser = (WebBrowser)sender; browser.ClientSize = new Size(browser.Document.Body.ScrollRectangle.Width, browser.Document.Body.ScrollRectangle.Bottom); browser.ScrollBarsEnabled = false; m_Bitmap = new Bitmap(browser.Document.Body.ScrollRectangle.Width, browser.Document.Body.ScrollRectangle.Bottom); browser.BringToFront(); browser.DrawToBitmap(m_Bitmap, browser.Bounds); // Save as file? if (m_FileName.Length > 0) { // Save m_Bitmap.SaveJPG100(m_FileName); } } } public static class BitmapExtensions { public static void SaveJPG100(this Bitmap bmp, string filename) { var encoderParameters = new EncoderParameters(1); encoderParameters.Param[0] = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, 100L); bmp.Save(filename, GetEncoder(ImageFormat.Jpeg), encoderParameters); } public static void SaveJPG100(this Bitmap bmp, Stream stream) { var encoderParameters = new EncoderParameters(1); encoderParameters.Param[0] = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, 100L); bmp.Save(stream, GetEncoder(ImageFormat.Jpeg), encoderParameters); } public static ImageCodecInfo GetEncoder(ImageFormat format) { var codecs = ImageCodecInfo.GetImageDecoders(); foreach (var codec in codecs) { if (codec.FormatID == format.Guid) { return codec; } } // Return return null; } } 

可以这样称呼它:

 WebsiteToImage websiteToImage = new WebsiteToImage( "http://www.cnn.com", @"C:\Some Folder\Test.jpg"); websiteToImage.Generate(); 

它适用于文件和stream。 确保你添加到ASP.NET项目的System.Windows.Forms引用。 我希望这有帮助。

更新:我已经更新了代码,以包括捕获整个页面的能力,不需要任何特殊的设置,只捕获它的一部分。

这里是我的实现使用扩展方法和任务工厂,而不是线程:

 /// <summary> /// Convert url to bitmap byte array /// </summary> /// <param name="url">Url to browse</param> /// <param name="width">width of page (if page contains frame, you need to pass this params)</param> /// <param name="height">heigth of page (if page contains frame, you need to pass this params)</param> /// <param name="htmlToManipulate">function to manipulate dom</param> /// <param name="timeout">in milliseconds, how long can you wait for page response?</param> /// <returns>bitmap byte[]</returns> /// <example> /// byte[] img = new Uri("http://www.uol.com.br").ToImage(); /// </example> public static byte[] ToImage(this Uri url, int? width = null, int? height = null, Action<HtmlDocument> htmlToManipulate = null, int timeout = -1) { byte[] toReturn = null; Task tsk = Task.Factory.StartNew(() => { WebBrowser browser = new WebBrowser() { ScrollBarsEnabled = false }; browser.Navigate(url); browser.DocumentCompleted += (s, e) => { var browserSender = (WebBrowser)s; if (browserSender.ReadyState == WebBrowserReadyState.Complete) { if (htmlToManipulate != null) htmlToManipulate(browserSender.Document); browserSender.ClientSize = new Size(width ?? browser.Document.Body.ScrollRectangle.Width, height ?? browser.Document.Body.ScrollRectangle.Bottom); browserSender.ScrollBarsEnabled = false; browserSender.BringToFront(); using (Bitmap bmp = new Bitmap(browserSender.Document.Body.ScrollRectangle.Width, browserSender.Document.Body.ScrollRectangle.Bottom)) { browserSender.DrawToBitmap(bmp, browserSender.Bounds); toReturn = (byte[])new ImageConverter().ConvertTo(bmp, typeof(byte[])); } } }; while (browser.ReadyState != WebBrowserReadyState.Complete) { Application.DoEvents(); } browser.Dispose(); }, CancellationToken.None, TaskCreationOptions.None, TaskScheduler.FromCurrentSynchronizationContext()); tsk.Wait(timeout); return toReturn; } 

猫猫先生的好解决scheme

我需要添加一行来抑制某些网页中出现的错误(在我的一个真棒同事的帮助下)

 private void _Generate() { var browser = new WebBrowser { ScrollBarsEnabled = false }; browser.ScriptErrorsSuppressed = true; // <-- browser.Navigate(m_Url); browser.DocumentCompleted += WebBrowser_DocumentCompleted; } 

谢谢Do先生

Peter Bromberg在这方面有一篇很好的文章。 他的解决scheme似乎正在做你所需要的…

您可以使用WatiN打开一个新的浏览器,然后捕获屏幕并适当裁剪。

解决scheme是完美的,只需要设置图像宽度的行中的固定。 对于具有LARGE HEIGHT的页面,它不会适当地设置WIDTH:

  //browser.ClientSize = new Size(browser.Document.Body.ScrollRectangle.Width, browser.Document.Body.ScrollRectangle.Bottom); browser.ClientSize = new Size(1000, browser.Document.Body.ScrollRectangle.Bottom); 

而为了添加对System.Windows.Forms的引用,你应该在添加引用的.NET选项卡中而不是COM -tab中执行它。