cefsharp / CefSharp

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

LoadHtml and screenshot Failed in CefSharp.OffScreen.Example #647

Closed yemaoziluo closed 10 years ago

yemaoziluo commented 10 years ago
var task = browser.ScreenshotAsync();    //Error

I think, html code don't Loaded,so ScreenshotAsync Failed. this my code.:

namespace CefSharp.OffScreen.Example
{
    public class Program
    {
        private static ChromiumWebBrowser browser;

        public static void Main(string[] args)
        {
            const string testUrl = "http://www.baidu.com/";

            Console.WriteLine("This example application will load {0}, take a screenshot, and save it to your desktop.", testUrl);
            Console.WriteLine("You may see a lot of Chromium debugging output, please wait...");
            Console.WriteLine();

            // You need to replace this with your own call to Cef.Initialize();
            CefExample.Init();

            // Create the offscreen Chromium browser.
            browser = new ChromiumWebBrowser();

            browser.Load("dummy:");

            browser.FrameLoadEnd += BrowserFrameLoadEnd;
            browser.LoadHtml("<html><head></head><body><h1>OKOKOK</h1></body></html>", "about:blank");

            // We have to wait for something, otherwise the process will exit too soon.
            Console.ReadKey();

            // Clean up Chromium objects.  You need to call this in your application otherwise
            // you will get a crash when closing.
            Cef.Shutdown();
        }

        private static void BrowserFrameLoadEnd(object sender, FrameLoadEndEventArgs e)
        {
            ChromiumWebBrowser browser = sender as ChromiumWebBrowser;

            // Check to ensure it is the main frame which has finished loading
            // (rather than an iframe within the main frame).
            if (e.IsMainFrame)
            {
                // Remove the load event handler, because we only want one snapshot of the initial page.
                browser.FrameLoadEnd -= BrowserFrameLoadEnd;

                // Wait for the screenshot to be taken.
                var task = browser.ScreenshotAsync();
                task.Wait();

                // Make a file to save it to (e.g. C:\Users\jan\Desktop\CefSharp screenshot.png)
                var screenshotPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "CefSharp screenshot.png");

                Console.WriteLine();
                Console.WriteLine("Screenshot ready.  Saving to {0}", screenshotPath);

                // Save the Bitmap to the path.
                // The image type is auto-detected via the ".png" extension.
                task.Result.Save(screenshotPath);

                // We no longer need the Bitmap.
                // Dispose it to avoid keeping the memory alive.  Especially important in 32-bit applications.
                task.Result.Dispose();

                Console.WriteLine("Screenshot saved.  Launching your default image viewer...");

                // Tell Windows to launch the saved image.
                Process.Start(screenshotPath);

                Console.WriteLine("Image viewer launched.  Press any key to exit.");
            }
        }
    }
}
yemaoziluo commented 10 years ago

Error picture qq 20141127150200

amaitland commented 10 years ago

@yemaoziluo Please close one of your issues as they're for the same problem.

amaitland commented 10 years ago

Try implement IRequestHandler.GetResourceHandler

Example https://github.com/cefsharp/CefSharp/blob/master/CefSharp.Example/RequestHandler.cs#L34

To demonstrate try opening http://test/resource/load in either CefSharp.WinForms.Example or CefSharp.Wpf.Example it should load html string a string.

note The OffScreen project is relatively new and as such only a few scenarios have been tested.

yemaoziluo commented 10 years ago

@amaitland I need CefSharp.WinForms.Example's OffScreen-ScreenShot(first Load html code,then ScreenShot).

.net Control WebBrowser may running function Control.DrawToBitmap(...) ,OffScreen-ScreenShot.

Control ChromiumWebBrowser can't .DrawToBitmap(...),because create bitmap content is nothing~~~

How do ChromiumWebBrowser OffScreen-ScreenShot?

amaitland commented 10 years ago

@yemaoziluo Did you read my previous comment? I proposed an alternate solution.

Support for CefSharp.OffScreen is limited so your likely going to have to dig through the source to get things working. If that's a daunting task then I'd suggest you look for an alternate solution.

amaitland commented 10 years ago

The WinForms control doesn't currently have the ability to take a screen shot natively.

yemaoziluo commented 10 years ago

@amaitland thank you. i waiting for new version. i hope OffScreen.Example can Load Html code in new version.

amaitland commented 10 years ago

@yemaoziluo There is nobody actively working on the OffScreen version, so feel free to investigate on your own if this is important to you.

jankurianski commented 10 years ago

@yemaoziluo I think LoadHtml in general is very unreliable, not just in CefSharp.OffScreen.

See this comment from Marshall Greenblatt (main author of CEF):

LoadString is inherently flawed due to the requirement of creating render processes -- you're better off using standard network loading (browse to a URL and handle via a custom scheme handler or GetResourceHandler). See https://code.google.com/p/chromiumembedded/wiki/GeneralUsage. Source: https://code.google.com/p/chromiumembedded/issues/detail?id=797

If you want to continue using OffScreen for loading HTML strings, you should try Marshall's approach above.

However if, by some magic, LoadHtml works for you in the WinForms control, you can use this function to snapshot the contents of the control: https://gist.github.com/jankurianski/f3419d4580517516c24b

jankurianski commented 10 years ago

@yemaoziluo Sorry, wrong URL to the gist: https://gist.github.com/jankurianski/f3419d4580517516c24b

amaitland commented 10 years ago

@jankurianski It's tempting to remove LoadHtml as it works in so few scenarios. Thoughts?

jankurianski commented 10 years ago

@amaitland I have two opposing thoughts:

  1. It doesn't feel right to be a wrapper of CEF and yet hide core functionality. Unreliable as it is, it feels like a choice/fix that could be made upstream. I wonder why it hasn't been removed or replaced with something like this next idea?
  2. In absence of the native LoadHtml, a nice alternative would be to offer the same functionality by using an IRequestHandler to intercept the request for the url (i.e. second parameter of LoadHtml) and return the html. Then the native Load(url) can be used. This could be done so library users see no change in the ChromiumWebBrowser API - they still use LoadHtml() and it just works more reliably, because it is implemented via the more reliable mechanism.

I would be happy to write a PR for option 2 if it sounds sensible. It might even fix some weird timing issues I have the first time I take snapshots of SVG and HTML strings in my process.

amaitland commented 10 years ago

To be honest I was thinking of something a little more low tech, like throwing an exception when LoadHtml is called, and in the error message having a link to a wiki article describing some alternative options.

In absence of the native LoadHtml, a nice alternative would be to offer the same functionality by using an IRequestHandler to intercept the request for the url (i.e. second parameter of LoadHtml) and return the html. Then the native Load(url) can be used. This could be done so library users see no change in the ChromiumWebBrowser API - they still use LoadHtml() and it just works more reliably, because it is implemented via the more reliable mechanism.

If this helps solves a problem your having then happy to work towards a high tech solution :smile: I was thinking rather than trying to use only a small part of IRequestHandler, perhaps we look at other options. Maybe even change the whole API. Could go with something like

RegisterResourceHandler(string url, ResourceHandler handler)

Lots of options, haven't through them all through yet, let me know your thoughts. As ResourceHandler is only a few weeks old, I think there's scope to change the API if required.

jankurianski commented 9 years ago

Maybe even change the whole API. Could go with something like RegisterResourceHandler(string url, ResourceHandler handler)

That's a good idea. It would make installing multiple resource handlers a lot cleaner.

jankurianski commented 9 years ago

@yemaoziluo Now that @amaitland has fixed the LoadHtml stability problems with #674, LoadHtml and Screenshots now work. Please see this updated CefSharp.OffScreen.Example Program.cs file: https://gist.github.com/jankurianski/e0ac2d1006f3a42216be

yemaoziluo commented 9 years ago

@jankurianski https://gist.github.com/jankurianski/e0ac2d1006f3a42216be the url can't open!!

jankurianski commented 9 years ago

@yemaoziluo Do you mean you can't view my gist? Try this instead: http://pastie.org/9771350

amaitland commented 9 years ago

the url can't open!!

@yemaoziluo Please be verbose in your responses, your statement could mean any number of things.