49 Stimmen

Konvertieren einer Webseite in ein Bild aus ASP.NET

Ich möchte eine Funktion in C# erstellen, die eine bestimmte Webseite nimmt und sie in ein JPG-Bild aus ASP.NET umwandelt. Ich möchte dies nicht über einen Drittanbieter oder einen Thumbnail-Dienst tun, da ich das vollständige Bild benötige. Ich nehme an, ich müsste irgendwie das Webbrowser-Steuerelement von innerhalb von ASP.NET nutzen, aber ich kann einfach nicht sehen, wo ich anfangen soll. Hat jemand Beispiele?

1 Stimmen

Dies wird äußerst schwierig sein.

1 Stimmen

Wow! Was für eine tolle Frage. Meine erste Reaktion ist, das WebBrowser-Steuerelement zu verwenden und die DrawToBitmap-Methode zu verwenden, aber die Dokumentation besagt, "Diese Methode wird von diesem Steuerelement nicht unterstützt." Nun gut.

0 Stimmen

Ich habe diesen großartigen Link gefunden, aber das eine Rätsel, das er nie erklärt, ist, wie man das verflixte Steuerelement von ASP.NET aus zum Laufen bringt. beansoftware.com/ASP.NET-Tutorials/

49voto

Keith Adler Punkte 20478

Ok, das war ziemlich einfach, als ich mehrere verschiedene Lösungen kombiniert habe:

Diese Lösungen gaben mir eine thread-sichere Möglichkeit, den WebBrowser von ASP.NET zu verwenden:

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

Diese Lösung ermöglichte es mir, BMP in JPG zu konvertieren:

Bmp zu jpg/png in C#

Ich habe den Code einfach angepasst und das Folgende in eine .cs-Datei eingefügt:

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;
    }
}

Und kann es wie folgt aufrufen:

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

Es funktioniert sowohl mit einer Datei als auch mit einem Stream. Stellen Sie sicher, dass Sie einen Verweis auf System.Windows.Forms zu Ihrem ASP.NET-Projekt hinzufügen. Ich hoffe, das hilft.

UPDATE: Ich habe den Code aktualisiert, um die Möglichkeit zu schaffen, die gesamte Seite zu erfassen und keine speziellen Einstellungen zu benötigen, um nur einen Teil davon zu erfassen.

4voto

Fourier Punkte 313

Gute Lösung von Herrn Katzenmann Do.

Ich musste eine Zeile hinzufügen, um einige Fehler zu unterdrücken, die auf einigen Webseiten auftraten (mit der Hilfe eines großartigen Kollegen von mir)

private void _Generate()
{
    var browser = new WebBrowser { ScrollBarsEnabled = false };

    browser.ScriptErrorsSuppressed = true;        //           <--

    browser.Navigate(m_Url);
    browser.DocumentCompleted += WebBrowser_DocumentCompleted;
}

...

Danke Herr Do

2voto

Alexandre Punkte 6502

Hier ist meine Implementierung mit Erweiterungsmethoden und Task Factory statt Thread:

/// <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;
    }

1voto

Dean Kuga Punkte 11481

Es gibt einen guten Artikel von Peter Bromberg zu diesem Thema aquí . Seine Lösung scheint zu tun, was Sie brauchen...

1voto

Kardo Punkte 1594

Die Lösung ist perfekt, man braucht nur eine Fixierung in der Zeile, die die BREITE des Bildes festlegt. Bei Seiten mit einer GROSSEN HÖHE wird die BREITE nicht entsprechend eingestellt:

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

Und um einen Verweis auf System.Windows.Forms hinzuzufügen, sollten Sie dies in der .NET-Registerkarte von ADD REFERENCE anstatt der COM-Registerkarte tun.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X