Screen a web browser in a stream

I use the method shown in

WebBrowser control in a new stream

Trying to get a screenshot of a webpage, I managed to get the following code to work successfully when the WebBrowser hosted on WinForm . However, it fails by providing an arbitrary desktop image when launched inside the stream.

 Thread browserThread = new Thread(() => { WebBrowser br = new WebBrowser(); br.DocumentCompleted += webBrowser1_DocumentCompleted; br.ProgressChanged += webBrowser1_ProgressChanged; br.ScriptErrorsSuppressed = true; br.Navigate(url); Application.Run(); }); browserThread.SetApartmentState(ApartmentState.STA); browserThread.Start(); private Image TakeSnapShot(WebBrowser browser) { int width; int height; width = browser.ClientRectangle.Width; height = browser.ClientRectangle.Height; Bitmap image = new Bitmap(width, height); using (Graphics graphics = Graphics.FromImage(image)) { Point p = new Point(0, 0); Point upperLeftSource = browser.PointToScreen(p); Point upperLeftDestination = new Point(0, 0); Size blockRegionSize = browser.ClientRectangle.Size; blockRegionSize.Width = blockRegionSize.Width - 15; blockRegionSize.Height = blockRegionSize.Height - 15; graphics.CopyFromScreen(upperLeftSource, upperLeftDestination, blockRegionSize); } return image; } 

This, obviously, is due to the Graphics.CopyFromScreen() method, but I don't know a different approach. Is there a way to solve this problem that anyone can offer? or is my only option to create a form, add a control, make it visible, and then script? For obvious reasons, I hope to avoid this approach.

+2
multithreading c # screen-scraping webbrowser-control apartments
Sep 07 '13 at 16:45
source share
2 answers

You can write

 private Image TakeSnapShot(WebBrowser browser) { browser.Width = browser.Document.Body.ScrollRectangle.Width; browser.Height= browser.Document.Body.ScrollRectangle.Height; Bitmap bitmap = new Bitmap(browser.Width - System.Windows.Forms.SystemInformation.VerticalScrollBarWidth, browser.Height); browser.DrawToBitmap(bitmap, new Rectangle(0, 0, bitmap.Width, bitmap.Height)); return bitmap; } 

Full working code

 var image = await WebUtils.GetPageAsImageAsync("http://www.stackoverflow.com"); image.Save(fname , System.Drawing.Imaging.ImageFormat.Bmp); 



 public class WebUtils { public static Task<Image> GetPageAsImageAsync(string url) { var tcs = new TaskCompletionSource<Image>(); var thread = new Thread(() => { WebBrowser browser = new WebBrowser(); browser.Size = new Size(1280, 768); WebBrowserDocumentCompletedEventHandler documentCompleted = null; documentCompleted = async (o, s) => { browser.DocumentCompleted -= documentCompleted; await Task.Delay(2000); //Run JS a few seconds more Bitmap bitmap = TakeSnapshot(browser); tcs.TrySetResult(bitmap); browser.Dispose(); Application.ExitThread(); }; browser.ScriptErrorsSuppressed = true; browser.DocumentCompleted += documentCompleted; browser.Navigate(url); Application.Run(); }); thread.SetApartmentState(ApartmentState.STA); thread.Start(); return tcs.Task; } private static Bitmap TakeSnapshot(WebBrowser browser) { browser.Width = browser.Document.Body.ScrollRectangle.Width; browser.Height= browser.Document.Body.ScrollRectangle.Height; Bitmap bitmap = new Bitmap(browser.Width - System.Windows.Forms.SystemInformation.VerticalScrollBarWidth, browser.Height); browser.DrawToBitmap(bitmap, new Rectangle(0, 0, bitmap.Width, bitmap.Height)); return bitmap; } } 
+7
Sep 07 '13 at 17:22
source share
 using (Graphics graphics = Graphics.FromImage(image)) { Point p = new Point(0, 0); Point upperLeftSource = browser.PointToScreen(p); Point upperLeftDestination = new Point(0, 0); Size blockRegionSize = browser.ClientRectangle.Size; blockRegionSize.Width = blockRegionSize.Width - 15; blockRegionSize.Height = blockRegionSize.Height - 15; graphics.CopyFromScreen(upperLeftSource, upperLeftDestination, blockRegionSize); } 

Do you really need to use the instruction ?

You also return image , but how is the image assigned to it copied?

0
Sep 07 '13 at 17:19
source share



All Articles