score:11

Accepted answer

you have possibly tried iecapt. i think it is the right way to go. i created a modified version of it and use a timer instead of thread.sleep it captures your site as expected.

------edit------

here is the ugly source. just add a reference to microsoft html object library.

and this is the usage:

htmlcapture capture = new htmlcapture(@"c:\temp\myimg.png");
capture.htmlimagecapture += new htmlcapture.htmlcaptureevent(capture_htmlimagecapture);
capture.create("http://www.highcharts.com/demo/combo-dual-axes");

void capture_htmlimagecapture(object sender, uri url)
{
    this.close();
}

file1

using system;
using system.collections.generic;
using system.componentmodel;
using system.data;
using system.drawing;
using system.linq;
using system.text;
using system.windows.forms;
using system.io;


namespace myiecapt
{
    public class htmlcapture
    {
        private webbrowser web;
        private timer tready;
        private rectangle screen;
        private size? imgsize = null;

        //an event that triggers when the html document is captured
        public delegate void htmlcaptureevent(object sender, uri url);

        public event htmlcaptureevent htmlimagecapture;

        string filename = "";

        //class constructor
        public htmlcapture(string filename)
        {
            this.filename = filename;

            //initialise the webbrowser and the timer
            web = new webbrowser();
            tready = new timer();
            tready.interval = 2000;
            screen = screen.primaryscreen.bounds;
            //set the webbrowser width and hight
            web.width = 1024; //screen.width;
            web.height = 768; // screen.height;
            //suppress script errors and hide scroll bars
            web.scripterrorssuppressed = true;
            web.scrollbarsenabled = false;
            //attached events
            web.navigating +=
              new webbrowsernavigatingeventhandler(web_navigating);
            web.documentcompleted += new
              webbrowserdocumentcompletedeventhandler(web_documentcompleted);
            tready.tick += new eventhandler(tready_tick);
        }


        public void create(string url)
        {
            imgsize = null;
            web.navigate(url);
        }

        public void create(string url, size imgsz)
        {
            this.imgsize = imgsz;
            web.navigate(url);
        }



        void web_documentcompleted(object sender,
                 webbrowserdocumentcompletedeventargs e)
        {
            //start the timer
            tready.start();
        }

        void web_navigating(object sender, webbrowsernavigatingeventargs e)
        {
            //stop the timer   
            tready.stop();
        }



        void tready_tick(object sender, eventargs e)
        {
            try
            {
                //stop the timer
                tready.stop();

                mshtml.ihtmldocument2 docs2 = (mshtml.ihtmldocument2)web.document.domdocument;
                mshtml.ihtmldocument3 docs3 = (mshtml.ihtmldocument3)web.document.domdocument;
                mshtml.ihtmlelement2 body2 = (mshtml.ihtmlelement2)docs2.body;
                mshtml.ihtmlelement2 root2 = (mshtml.ihtmlelement2)docs3.documentelement;

                // determine dimensions for the image; we could add minwidth here
                // to ensure that we get closer to the minimal width (the width
                // computed might be a few pixels less than what we want).
                int width = math.max(body2.scrollwidth, root2.scrollwidth);
                int height = math.max(root2.scrollheight, body2.scrollheight);

                //get the size of the document's body
                rectangle docrectangle = new rectangle(0, 0, width, height);

                web.width = docrectangle.width;
                web.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() { location = 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 = web.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);
                }
                //invoke the htmlimagecapture event
                bitmap.save(filename);
                bitmap.dispose();
            }
            catch 
            {
                //system.diagnostics.process.getcurrentprocess().kill();
            }
            if(htmlimagecapture!=null) htmlimagecapture(this, web.url);
        }
    }
}

and file2

using system;
using system.collections.generic;
using system.linq;
using system.text;
using system.drawing;
using system.runtime.interopservices;

namespace myiecapt
{
    [comvisible(true), comimport()]
    [guidattribute("0000010d-0000-0000-c000-000000000046")]
    [interfacetypeattribute(cominterfacetype.interfaceisiunknown)]
    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);
    }
}

score:0

thread.sleep will simply suspend the thread your web browser is running on - how do you expect it to render anything when it is suspended? :)

instead, you need to allow the thread to process work. you can achieve this with a combination of thread.sleep(0) and application.doevents(), with something like the following:

datetime finish = datetime.now.addseconds(3);
while (datetime.now < finish) {
    application.doevents();
    thread.sleep(0);
}

score:0

@l.b , thank you for the help!

just an fyi for anyone wanting to run it in a class library, webbrowser needs to single threaded apartment, so do something like this:

  var t = new thread(initanddo); //initanddo would have your code creating the webbrowser object etc...
  t.setapartmentstate(apartmentstate.sta);
  t.start();

then the gotcha, after the navigate call is done, add this line of code so that you get the completed navigation event:

    web.navigate(url);
    application.run();

score:0

i created a nuget package for this purpose https://github.com/dcumin39/renderhighcharts/wiki


Related Query

More Query from same tag