|
|
Comments and Discussions
|
|
 |

|
First of all, the code looks good. But I have some problems when executing it from a command line / windows service. The timer never seems to get fired, that's one thing. I don't know for sure if I have to be in UI context. Then, when I work around this by using the "System.Threading.Timer", it gets stuck for infinity on the call to Rectangle body = web.Document.Body.ScrollRectangle; . A message appears after 60 seconds, saying that some transition could not be made (MDA). If I click "continue" within that box, nothing happens, not even an exception.
Does anyone have any idea what is going on? It seems like the only snippet on the web that does what I need. Maybe it helps to say that I am calling "Create(string)" from a thread that is set to STA, from within a worker thread.
I'd be happy if someone could help me.
Thanks,
Chris
modified 4-May-13 12:44pm.
|
|
|
|

|
I am having problem with the execution of the code. I'm using Visual Studio 2005.
I have added the following interface at the top of my class (verbatim from this webpage)
public interface IViewObject
{
[return: MarshalAs(UnmanagedType.I4)]
[PreserveSig]
int Draw(
[MarshalAs(UnmanagedType.U4)] UInt32 dwDrawAspect,
int lindex,
IntPtr pvAspect,
[In] IntPtr ptd,
IntPtr hdcTargetDev,
IntPtr hdcDraw,
[MarshalAs(UnmanagedType.Struct)] ref Rectangle lprcBounds,
[MarshalAs(UnmanagedType.Struct)] ref Rectangle lprcWBounds,
IntPtr pfnContinue,
[MarshalAs(UnmanagedType.U4)] UInt32 dwContinue);
[PreserveSig]
int GetColorSet([In, MarshalAs(UnmanagedType.U4)] int dwDrawAspect,
int lindex, IntPtr pvAspect, [In] IntPtr ptd,
IntPtr hicTargetDev, [Out] IntPtr ppColorSet);
[PreserveSig]
int Freeze([In, MarshalAs(UnmanagedType.U4)] int dwDrawAspect,
int lindex, IntPtr pvAspect, [Out] IntPtr pdwFreeze);
[PreserveSig]
int Unfreeze([In, MarshalAs(UnmanagedType.U4)] int dwFreeze);
void SetAdvise([In, MarshalAs(UnmanagedType.U4)] int aspects,
[In, MarshalAs(UnmanagedType.U4)] int advf,
[In, MarshalAs(UnmanagedType.Interface)] IAdviseSink pAdvSink);
void GetAdvise([In, Out, MarshalAs(UnmanagedType.LPArray)] int[] paspects,
[In, Out, MarshalAs(UnmanagedType.LPArray)] int[] advf,
[In, Out, MarshalAs(UnmanagedType.LPArray)] IAdviseSink[] pAdvSink);
}
Also, I've added the following method to save my webbrowser page:
private void saveResultsToBitmap1()
{
Rectangle screen;
Size? imgsize=null;
screen = Screen.PrimaryScreen.Bounds;
//get the size of the document's body
Rectangle body = webBrowser1.Document.Body.ScrollRectangle;
//check if the document width/height is greater than screen width/height
Rectangle docRectangle = new Rectangle();
docRectangle.Location = new Point(0, 0);
docRectangle.Size = new Size(body.Width > screen.Width ? body.Width : screen.Width,
body.Height > screen.Height ? body.Height : screen.Height);
//set the width and height of the WebBrowser object
webBrowser1.Width = docRectangle.Width;
webBrowser1.Height = docRectangle.Height;
//if the imgsize is null, the size of the image will
//be the same as the size of webbrowser object
//otherwise set the image size to imgsize
Rectangle imgRectangle;
if (imgsize == null)
imgRectangle = docRectangle;
else
imgRectangle = new Rectangle(new Point(0, 0),
Size = imgsize.Value);
//create a bitmap object
Bitmap bitmap = new Bitmap(imgRectangle.Width, imgRectangle.Height);
//get the viewobject of the WebBrowser
IViewObject ivo = webBrowser1.Document.DomDocument as IViewObject;
using (Graphics g = Graphics.FromImage(bitmap))
{
//get the handle to the device context and draw
IntPtr hdc = g.GetHdc();
ivo.Draw(1, -1, IntPtr.Zero, IntPtr.Zero,
IntPtr.Zero, hdc, ref imgRectangle,
ref docRectangle, IntPtr.Zero, 0);
g.ReleaseHdc(hdc);
}
bitmap.Save(@"C:\browsertest.jpg");
}
However when I run this, I get a null reference error when the following code is run:
ivo.Draw(1, -1, IntPtr.Zero, IntPtr.Zero,
IntPtr.Zero, hdc, ref imgRectangle,
ref docRectangle, IntPtr.Zero, 0);
System.NullReferenceException was unhandled
Message="Object reference not set to an instance of an object."
How do I go about fixing this? Has anyone else had this error message?
I am using Visual Studio 2005?
|
|
|
|

|
I have run the code.
After web.Navigate(url) is invoked (within the Create method) the execution jumps to web_Navigating and then ends normally after executing tready.Stop(); only once. The execution never reaches web_DocumentCompleted nor tready_Tick.
Do you know what could cause this?
Thanks in advance!
|
|
|
|

|
I have used the code that I have found at this website and it works like a charm!:
http://forums.asp.net/t/1764959.aspx[^]
This is the code I am referring to:
public System.Drawing.Bitmap CaptureWebPage(string URL)
{
System.Windows.Forms.WebBrowser web = new System.Windows.Forms.WebBrowser();
web.ScrollBarsEnabled = false;
web.ScriptErrorsSuppressed = true;
web.Navigate(URL);
while (web.ReadyState != WebBrowserReadyState.Complete)
System.Windows.Forms.Application.DoEvents();
System.Threading.Thread.Sleep(1500);
int width = web.Document.Body.ScrollRectangle.Width;
int height = web.Document.Body.ScrollRectangle.Height;
web.Width = width;
web.Height = height;
System.Drawing.Bitmap bmp = new System.Drawing.Bitmap(width, height);
web.DrawToBitmap(bmp, new System.Drawing.Rectangle(0, 0, width, height));
return bmp; }
protected void Export_Click(object sender, EventArgs e)
{
Bitmap bitmap = new Bitmap(CaptureWebPage(txtUrl.Text));
Response.ContentType = "image/jpeg";
bitmap.Save(Response.OutputStream, ImageFormat.Jpeg);
bitmap.Dispose();
bitmap.Dispose();
Response.End();
}
If you are using it on asp.net and get this error...:
ActiveX control '8856f961-340a-11d0-a96b-00c04fd705a2' cannot be instantiated because the current thread is not in a single-threaded apartment.
...just create a thread that call the Export_Click method...:
Thread thread = new Thread(new ThreadStart(Export_Click));
thread.SetApartmentState(ApartmentState.STA);
thread.Start();
thread.Join();
while (thread.IsAlive) System.Windows.Forms.Application.DoEvents();
...removing the parameters:
protected void Export_Click()
{
Bitmap bitmap = new Bitmap(CaptureWebPage("C:/test.html"));
image.Save("C:/test.bmp", ImageFormat.Bmp);
}
|
|
|
|

|
It works perfectly for me. Thanks a lot.
|
|
|
|
|
|

|
i had to add
using System.Windows.Forms;
using System.Drawing;
in htmlcapture
and
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;
using System.Drawing;
in the interface file. rest works fine. thank you.
|
|
|
|

|
it can not work in asp.net ! I already try it but fail , can you check it out?
|
|
|
|

|
Good ...
|
|
|
|
|
|

|
Hi, can you provide the needed 'Using' statements to help me compile your code?
Thanks
|
|
|
|
|

|
How can i capture the image of a part of the web page (i.e: a div tag) ?
|
|
|
|

|
No downloadable and not step by step description...!?!
|
|
|
|

|
I have totally used the posted code and it works for most sites but "www.codeproject.com", debug into it and get that the DocumentCompleted event is never fired, any ideas ?
|
|
|
|

|
Small and simple! I added a method to render straight html string
public void CreateByHTML(string htmlContent)
{
web.DocumentText = htmlContent;
} worked great for me thanks.
|
|
|
|

|
I have been working on the web browser control recently and what a mess! I don't know about you, but it took me a lot of time to get the screenshots working. This code has helped tremendously, but I do have some issues still that I would really appreciate your input on. The thing is that although this code is great for 99% of cases, it has one downfall; it creates a new web browser and navigates to the specified url. Why is this an issue? Well, I am working on software automation at the moment where data is input via the web browser control to a web page and then we detect if there were any errors (validation labels) and want to grab the screen as evidence. You see where I am going with this?
I am also the author behind the MBG Extensions Library (http://www.codeproject.com/KB/dotnet/MBGExtensionsLibrary.aspx) and want to create an extension method using your code.
Looking forward to hearing from you.
|
|
|
|

|
Hi again,
I have made some progress on this and have it working for most sites. However, with SharePoint sites, it seems to not draw correctly and I noticed that the HtmlDocument.Body.ScrollRectangle does not update correctly. Even though the size of the web browser changes fine, the image from the main content area is still the original size. Oddly enough, the ribbon is fine. I don't know a lot about web development yet, but I guess the main content is in a separate "frame" or something like that. Does anyone have any ideas on how to solve this? Here is my code below based on the author's great work:
public static Bitmap GenerateScreenshot(this WebBrowser webBrowser, Size? size)
{
Control parent = webBrowser.Parent;
DockStyle dockStyle = webBrowser.Dock;
bool scrollbarsEnabled = webBrowser.ScrollBarsEnabled;
if (parent != null)
{
parent.Controls.Remove(webBrowser);
}
Rectangle screen = Screen.PrimaryScreen.Bounds;
Size? imageSize = null;
Rectangle body = webBrowser.Document.Body.ScrollRectangle;
Rectangle docRectangle = new Rectangle()
{
Location = new Point(0, 0),
Size = new Size(
body.Width > screen.Width ? body.Width : screen.Width,
body.Height > screen.Height ? body.Height : screen.Height)
};
webBrowser.ScrollBarsEnabled = false;
webBrowser.Size = new Size(docRectangle.Width, docRectangle.Height);
Rectangle imgRectangle;
if (imageSize == null)
{ imgRectangle = docRectangle; }
else
imgRectangle = new Rectangle()
{
Location = new Point(0, 0),
Size = imageSize.Value
};
Bitmap bitmap = new Bitmap(imgRectangle.Width, imgRectangle.Height);
IViewObject viewObject = webBrowser.Document.DomDocument as IViewObject;
using (Graphics g = Graphics.FromImage(bitmap))
{
IntPtr hdc = g.GetHdc();
viewObject.Draw(1, -1, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, hdc, ref imgRectangle, ref docRectangle, IntPtr.Zero, 0);
g.ReleaseHdc(hdc);
}
if (parent != null)
{
parent.Controls.Add(webBrowser);
webBrowser.Dock = dockStyle;
}
webBrowser.ScrollBarsEnabled = scrollbarsEnabled;
return bitmap;
}
|
|
|
|

|
My page uses lots of JS and this code (like most others that I've tried (even blitting the whole desktop!)) doesn't capture the contents.
For example, if you navigate to http://www.bing.com/maps/?FORM=Z9LH3[^], you'll see the semi-transparent black overlay. This isn't present in the captured image.
The strange thing is, if the WebBrowser control is resized, then capturing the image again works.
There are 10 types of people in this world. Those that understand binary, and those that don't.
|
|
|
|

|
How did you resize the webbrowser to get it to work?
|
|
|
|

|
This is a very fine and useful code. It works perfectly from a desktop application. Since I need something like this to run as a windows service I modified the project, but finished with the error message:
ActiveX control '8856f961-340a-11d0-a96b-00c04fd705a2' cannot be instantiated because the current thread is not in a single-threaded apartment.
I am not familiar with thread management but I am afraid that WebBrowser control just can not work from within a service?
Thanks, Izidor
|
|
|
|

|
you can create a new thread , and set it to single-threaded apartment
---------------------------------
thread.SetApartmentState(ApartmentState.STA);
|
|
|
|

|
It can, but you must marshal it.
|
|
|
|
 |
|
|
General News Suggestion Question Bug Answer Joke Rant Admin
Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.
|
Capture an HTML document as an image.
| Type | Article |
| Licence | CPOL |
| First Posted | 13 Feb 2010 |
| Views | 58,640 |
| Bookmarked | 107 times |
|
|