cefsharp / CefSharp

.NET (WPF and Windows Forms) bindings for the Chromium Embedded Framework
http://cefsharp.github.io/
Other
9.79k stars 2.92k forks source link

How to: Scroll and take a screenshot. #957

Closed Netizine closed 9 years ago

Netizine commented 9 years ago

I have tried multiple ways to scroll and then take a screenshot of the the page in the offline sample but no matter what i try i always get the top of the page. Is there any way i can scroll and then get the image in the browser. Any help would be appreciated as i have run out of ideas.

Technical details

jankurianski commented 9 years ago

No reason it shouldn't work.

Can you share the code you have so far as a gist or fork of the sample?

Netizine commented 9 years ago

@jankurianski. Hi Jan. I created a gist at https://gist.github.com/Jayman1305/079e925a22d63a048baf. As you can see i have attached to BrowserFrameLoadEnd and then scroll to 900 in the first task which i await and then get the current scroll position which returns 900 but the screen shot is still the top of the page so it seems the bitmap is not updated.

jankurianski commented 9 years ago

It's a matter of not waiting for the rendering to react to your scroll. Remember that Chrome can run at > 60 FPS and with a call to ScreenshotAsync you are just getting 1st / 60 frames.

The solution is to wait a little bit between scrolling and taking the screenshot:

Task<JavascriptResponse> getScrollPositionTask = browser.EvaluateScriptAsync(String.Format("document.body.scrollTop;"));
getScrollPositionTask.ContinueWith(t => {
    var response = t.Result;
    if (response.Success) {
        Console.WriteLine("Current scroll position is " + response.Result);
        Task.Delay(2000).ContinueWith(t2 => {
            browser.ScreenshotAsync().ContinueWith(DisplayBitmap);
        });
    }
}).Wait();
Netizine commented 9 years ago

Thanks Jan. Turns out my test site is the issue. This site rendered fine in CefSharp but i get a blank image in the demo app even. With or without scrolling. Any idea how to catch that.

amaitland commented 9 years ago

Rather than setting an arbitrary delay it might be worth hooking the NewScreenshot event, using a timer, every time a frame is rendered, reset the timer, when rendering has finally finished the timer will fire? Little bit crude, though likely to yield a better end result.

amaitland commented 9 years ago

Could take this MSDN example of Timer.Change() and make it a little bit nicer using a Task

https://msdn.microsoft.com/en-us/library/yz1c7148.aspx

Netizine commented 9 years ago

It seems my issue is related to a different issue as well. LoadingStateChanged doesnt always fire. Test on http://multibrowser.com. and it stays true even after page has loaded.

amaitland commented 9 years ago

Can you provide a sample that reproduces, preferably a fork of 2272 :+1:

Netizine commented 9 years ago

https://github.com/cefsharp/CefSharp/pull/966 I have left it to open http://multibrowser.com. Screenshots are always blank. I have tried adding Task.Delay(2000).Wait(); etc but they always blank. If i navigate to the same url in the browser it loads. If i change the url to cnn, it works as expected.

amaitland commented 9 years ago

https://gist.github.com/amaitland/96ebbfd92454d8bc36df

Is a rough example based on another async one I wrote. It needs some refinements and may leak memory with the event handlers.

Netizine commented 9 years ago

@amaitland You rock. Its sorted. Thanks a million. Ps create a amazon wishlist or something so we can thank you for the effort you put into this ;-)

amaitland commented 9 years ago

Ps create a amazon wishlist or something so we can thank you for the effort you put into this ;-)

Interesting idea, I'll consider it :smile:

The potential memory leak was bugging me, so I revised the GIST see https://gist.github.com/amaitland/96ebbfd92454d8bc36df#file-gistfile1-cs-L62

Netizine commented 9 years ago

Okay create that list now. :-) One small question. Do you know how i can i pass a argument to DisplayBitmap. ;-)

amaitland commented 9 years ago

Something like this?

await browser.ScreenshotAsync().ContinueWith(task =>
{
    DisplayBitmap(task, secondArgument);
});
Netizine commented 9 years ago

Mmmm okay ill hang my head in shame. Thanks for the help. You saved me a lot of grey hair.

amaitland commented 9 years ago

Thanks for the help

No problem :smile:

At some point I think it's probably worth creating a more feature complete example, so If you end up with any code that you think is worth using as a demo, I'm sure others would benefit from it :+1:

rajesh-smartwebtech commented 4 years ago

Hi @Jayman1305 , i am using cefsharp in win-from.

i have added code from URL https://gist.github.com/Jayman1305/079e925a22d63a048baf it is not working for full screenshot

This is my code


                int i = 0;

                Task<JavascriptResponse> scrollTask = browser.EvaluateScriptAsync(String.Format("window.scrollBy({0}, {1});", 0, 900));
                scrollTask.ContinueWith(t =>
                {
                    var response = t.Result;
                    if (response.Success)
                    {
                        Debug.WriteLine("Current scroll position is " + response.Result);

                        Bitmap scr1 = ControlSnapshot.Snapshot(this.browser);

                        scr1.Save(@"D:\tmp\img_" + i + ".bmp");

                        i++;
                    }
                }).Wait();