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?
Antworten
Zu viele Anzeigen?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
Diese Lösung ermöglichte es mir, BMP in JPG zu konvertieren:
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.
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
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;
}
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.
- See previous answers
- Weitere Antworten anzeigen
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/
1 Stimmen
Ich denke, DrawToBitmap funktioniert also. Dafür sollte ich Punkte bekommen! :O)
1 Stimmen
Was genau hindert sie daran, zu funktionieren?
0 Stimmen
Ich habe den Code aus dem Artikel getestet und er funktioniert einwandfrei. Die DrawToBitmap-Methode funktioniert definitiv.
2 Stimmen
@SLaks - Schwierig ist eine Denkweise. Wie kann man sagen, dass etwas schwierig ist, wenn man es nicht versucht?