Convertir página web a imagen de ASP.NET

Me gustaría crear una función en C # que tome una página web específica y la encubra a una imagen JPG desde ASP.NET. No quiero hacer esto a través de un tercero o servicio de miniaturas ya que necesito la imagen completa. Supongo que necesitaría de alguna manera aprovechar el control del navegador web desde ASP.NET, pero no puedo ver por dónde empezar. ¿Alguien tiene ejemplos?

Ok, esto fue bastante fácil cuando combiné varias soluciones diferentes:

Estas soluciones me dieron una forma segura de utilizar el WebBrowser desde ASP.NET:

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

Esta solución me dio una forma de convertir BMP a JPG:

Bmp a jpg / png en C #

Simplemente adapté el código y puse lo siguiente en un .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; } } 

Y puede llamarlo de la siguiente manera:

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

Funciona con un archivo y una secuencia. Asegúrese de agregar una referencia a System.Windows.Forms a su proyecto ASP.NET. Espero que esto ayude.

ACTUALIZACIÓN: he actualizado el código para incluir la capacidad de capturar la página completa y no requerir ninguna configuración especial para capturar solo una parte de ella.

Aquí está mi implementación usando métodos de extensión y fábrica de tareas en lugar de hilo:

 ///  /// Convert url to bitmap byte array ///  /// Url to browse /// width of page (if page contains frame, you need to pass this params) /// heigth of page (if page contains frame, you need to pass this params) /// function to manipulate dom /// in milliseconds, how long can you wait for page response? /// bitmap byte[] ///  /// byte[] img = new Uri("http://www.uol.com.br").ToImage(); ///  public static byte[] ToImage(this Uri url, int? width = null, int? height = null, Action 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; } 

Buena solución por Mr Cat Man Do.

He necesitado agregar una fila para suprimir algunos errores que aparecieron en algunas páginas web (con la ayuda de un gran colega mío)

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

...

Gracias Sr. Do

Hay un buen artículo de Peter Bromberg sobre este tema aquí . Su solución parece hacer lo que necesita …

Puede usar WatiN para abrir un nuevo navegador, luego capturar la pantalla y recortarla adecuadamente.

La solución es perfecta, solo necesita una fijación en la línea que establece el ANCHO de la imagen. Para páginas con ALTURA GRANDE, no establece el ANCHO de forma apropiada:

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

Y para agregar una referencia a System.Windows.Forms, debe hacerlo en .NET-tab de ADD REFERENCE en lugar de COM -tab.