Skip to content

Commit 1eb8967

Browse files
committed
Example - Add DevToolsExtensions.CaptureScreenShotAsPng
Example of taking a screenshot as a png using the new devtools interface
1 parent e9a7c67 commit 1eb8967

File tree

4 files changed

+166
-0
lines changed

4 files changed

+166
-0
lines changed

CefSharp.Example/CefSharp.Example.csproj

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,9 @@
6262
</PropertyGroup>
6363
<ItemGroup>
6464
<Reference Include="Microsoft.CSharp" />
65+
<Reference Include="Newtonsoft.Json, Version=12.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
66+
<HintPath>..\packages\Newtonsoft.Json.12.0.3\lib\net45\Newtonsoft.Json.dll</HintPath>
67+
</Reference>
6568
<Reference Include="System" />
6669
<Reference Include="System.Core">
6770
<RequiredTargetFramework>3.5</RequiredTargetFramework>
@@ -72,6 +75,8 @@
7275
</ItemGroup>
7376
<ItemGroup>
7477
<Compile Include="Callback\RunFileDialogCallback.cs" />
78+
<Compile Include="DevTools\DevToolsExtensions.cs" />
79+
<Compile Include="DevTools\TaskMethodDevToolsMessageObserver.cs" />
7580
<Compile Include="Handlers\ExampleResourceRequestHandler.cs" />
7681
<Compile Include="Handlers\ExtensionHandler.cs" />
7782
<Compile Include="JavascriptBinding\AsyncBoundObject.cs" />
@@ -143,6 +148,7 @@
143148
<Content Include="Resources\assets\css\shCore.css" />
144149
<Content Include="Resources\assets\css\shCoreDefault.css" />
145150
<None Include="Extensions\set_page_color\manifest.json" />
151+
<None Include="packages.config" />
146152
<None Include="Resources\assets\images\beach-2089936_1920.jpg" />
147153
<Content Include="Resources\assets\js\application.js" />
148154
<Content Include="Resources\assets\js\jquery.js" />
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
using System;
2+
using System.Text;
3+
using System.Threading;
4+
using System.Threading.Tasks;
5+
using Newtonsoft.Json;
6+
7+
namespace CefSharp.Example.DevTools
8+
{
9+
public static class DevToolsExtensions
10+
{
11+
private static int LastMessageId = 600000;
12+
/// <summary>
13+
/// Calls Page.captureScreenshot without any optional params
14+
/// (Results in PNG image of default viewport)
15+
/// https://chromedevtools.github.io/devtools-protocol/tot/Page/#method-captureScreenshot
16+
/// </summary>
17+
/// <param name="browser">the ChromiumWebBrowser</param>
18+
/// <returns>png encoded image as byte[]</returns>
19+
public static async Task<byte[]> CaptureScreenShotAsPng(this IWebBrowser chromiumWebBrowser)
20+
{
21+
//if (!browser.HasDocument)
22+
//{
23+
// throw new System.Exception("Page hasn't loaded");
24+
//}
25+
26+
var host = chromiumWebBrowser.GetBrowserHost();
27+
28+
if (host == null || host.IsDisposed)
29+
{
30+
throw new Exception("BrowserHost is Null or Disposed");
31+
}
32+
33+
//var param = new Dictionary<string, object>
34+
//{
35+
// { "format", "png" },
36+
//}
37+
38+
var msgId = Interlocked.Increment(ref LastMessageId);
39+
40+
var observer = new TaskMethodDevToolsMessageObserver(msgId);
41+
42+
//Make sure to dispose of our observer registration when done
43+
//TODO: Create a single observer that maps tasks to Id's
44+
//Or at least create one for each type, events and method
45+
using (var observerRegistration = host.AddDevToolsMessageObserver(observer))
46+
{
47+
//Page.captureScreenshot defaults to PNG, all params are optional
48+
//for this DevTools method
49+
int id = 0;
50+
const string methodName = "Page.captureScreenshot";
51+
52+
//TODO: Simplify this, we can use an Func to reduce code duplication
53+
if (Cef.CurrentlyOnThread(CefThreadIds.TID_UI))
54+
{
55+
id = host.ExecuteDevToolsMethod(msgId, methodName);
56+
}
57+
else
58+
{
59+
id = await Cef.UIThreadTaskFactory.StartNew(() =>
60+
{
61+
return host.ExecuteDevToolsMethod(msgId, methodName);
62+
});
63+
}
64+
65+
if (id != msgId)
66+
{
67+
throw new Exception("Message Id doesn't match the provided Id");
68+
}
69+
70+
var result = await observer.Task;
71+
72+
var success = result.Item1;
73+
74+
dynamic response = JsonConvert.DeserializeObject<dynamic>(Encoding.UTF8.GetString(result.Item2));
75+
76+
//Success
77+
if (success)
78+
{
79+
return Convert.FromBase64String((string)response.data);
80+
}
81+
82+
var code = (string)response.code;
83+
var message = (string)response.message;
84+
85+
throw new Exception(code + ":" + message);
86+
}
87+
}
88+
}
89+
}
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
using System;
2+
using System.IO;
3+
using System.Threading.Tasks;
4+
using CefSharp.Callback;
5+
6+
namespace CefSharp.Example.DevTools
7+
{
8+
/// <summary>
9+
/// For capturing the response from a DevTools Method
10+
/// (Doesn't handle DevTools events)
11+
/// </summary>
12+
public class TaskMethodDevToolsMessageObserver : IDevToolsMessageObserver
13+
{
14+
private readonly TaskCompletionSource<Tuple<bool, byte[]>> taskCompletionSource = new TaskCompletionSource<Tuple<bool, byte[]>>(TaskCreationOptions.RunContinuationsAsynchronously);
15+
private readonly int matchMessageId;
16+
17+
public TaskMethodDevToolsMessageObserver(int messageId)
18+
{
19+
matchMessageId = messageId;
20+
}
21+
22+
void IDisposable.Dispose()
23+
{
24+
25+
}
26+
27+
void IDevToolsMessageObserver.OnDevToolsAgentAttached(IBrowser browser)
28+
{
29+
30+
}
31+
32+
void IDevToolsMessageObserver.OnDevToolsAgentDetached(IBrowser browser)
33+
{
34+
35+
}
36+
37+
void IDevToolsMessageObserver.OnDevToolsEvent(IBrowser browser, string method, Stream parameters)
38+
{
39+
40+
}
41+
42+
bool IDevToolsMessageObserver.OnDevToolsMessage(IBrowser browser, Stream message)
43+
{
44+
return false;
45+
}
46+
47+
void IDevToolsMessageObserver.OnDevToolsMethodResult(IBrowser browser, int messageId, bool success, Stream result)
48+
{
49+
//We found the message Id we're after
50+
if (matchMessageId == messageId)
51+
{
52+
var memoryStream = new MemoryStream((int)result.Length);
53+
54+
result.CopyTo(memoryStream);
55+
56+
var response = Tuple.Create(success, memoryStream.ToArray());
57+
58+
taskCompletionSource.TrySetResult(response);
59+
}
60+
}
61+
62+
public Task<Tuple<bool, byte[]>> Task
63+
{
64+
get { return taskCompletionSource.Task; }
65+
}
66+
}
67+
}

CefSharp.Example/packages.config

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<packages>
3+
<package id="Newtonsoft.Json" version="12.0.3" targetFramework="net462" />
4+
</packages>

0 commit comments

Comments
 (0)