[CEF1] A simple multithreaded offscreen renderer example
Posted: Thu Jun 14, 2012 7:23 am
Hi everybody, I present you a (really) simple example made with CEF1.
Features:
Here the full example source code, feel free to use it and modify it.
Features:
- console application
- BMP output
- one CPP file only
- boost::thread
- CEF1 libs/includes
- resources and binaries:
- "locales" folder
- chrome.pak"
- icudt.dll
- libcef.dll
Here the full example source code, feel free to use it and modify it.
- Code: Select all
/// link to: libcef_dll_wrapper.lib libcef.lib
#define BOOST_ALL_DYN_LINK
#define _WIN32_WINNT 0x0500
#include <iomanip>
#include "windows.h"
#include "boost/thread.hpp"
#include "include/cef_app.h"
#include "include/cef_client.h"
class OffscreenClient : public CefClient,
public CefDisplayHandler,
public CefLifeSpanHandler,
public CefRequestHandler,
public CefRenderHandler
{
public:
OffscreenClient();
virtual ~OffscreenClient();
virtual CefRefPtr<CefLifeSpanHandler> GetLifeSpanHandler() OVERRIDE {
return this;
}
virtual CefRefPtr<CefRequestHandler> GetRequestHandler() OVERRIDE {
return this;
}
virtual CefRefPtr<CefRenderHandler> GetRenderHandler() OVERRIDE {
return this;
}
void SaveBrowserImage(CefRefPtr<CefBrowser> browser, const std::string &filename);
virtual void OnPaint(CefRefPtr<CefBrowser> browser, PaintElementType type,
const RectList& dirtyRects, const void* buffer) OVERRIDE;
// CefLifeSpanHandler methods
virtual void OnAfterCreated(CefRefPtr<CefBrowser> browser) OVERRIDE;
virtual void OnBeforeClose(CefRefPtr<CefBrowser> browser) OVERRIDE;
CefRefPtr<CefBrowser> GetBrowser()
{
return m_browser;
}
private:
// The child browser window
CefRefPtr<CefBrowser> m_browser;
// Include the default reference counting implementation.
IMPLEMENT_REFCOUNTING(OffscreenClient);
// Include the default locking implementation.
IMPLEMENT_LOCKING(OffscreenClient);
};
OffscreenClient::OffscreenClient()
{
}
OffscreenClient::~OffscreenClient()
{
}
void OffscreenClient::OnAfterCreated(CefRefPtr<CefBrowser> browser)
{
AutoLock lock_scope(this);
// keep browser reference
m_browser = browser;
}
void OffscreenClient::OnBeforeClose(CefRefPtr<CefBrowser> browser)
{
AutoLock lock_scope(this);
// Free the browser pointer so that the browser can be destroyed
m_browser = NULL;
// quit message loop
CefQuitMessageLoop();
}
void OffscreenClient::OnPaint(CefRefPtr<CefBrowser> browser, PaintElementType type, const RectList& dirtyRects, const void* buffer)
{
static int s = 1;
std::ostringstream oss;
oss << std::setw(4) << std::setfill('0') << s++ << ".bmp";
SaveBrowserImage(browser, oss.str());
}
void OffscreenClient::SaveBrowserImage(CefRefPtr<CefBrowser> browser, const std::string &filename)
{
// Retrieve the image size.
int width, height;
if (!browser->GetSize(PET_VIEW, width, height))
return;
void* bits;
// Populate the bitmap info header.
BITMAPINFOHEADER info;
info.biSize = sizeof(BITMAPINFOHEADER);
info.biWidth = width;
info.biHeight = -height; // minus means top-down bitmap
info.biPlanes = 1;
info.biBitCount = 32;
info.biCompression = BI_RGB; // no compression
info.biSizeImage = 0;
info.biXPelsPerMeter = 1;
info.biYPelsPerMeter = 1;
info.biClrUsed = 0;
info.biClrImportant = 0;
// Create the bitmap and retrieve the bit buffer.
HDC screen_dc = GetDC(NULL);
HBITMAP bitmap = CreateDIBSection(screen_dc, reinterpret_cast<BITMAPINFO*>(&info), DIB_RGB_COLORS, &bits, NULL, 0);
ReleaseDC(NULL, screen_dc);
// Read the image into the bit buffer.
if (bitmap == NULL)
return;
if (!browser->GetImage(PET_VIEW, width, height, bits))
return;
// Populate the bitmap file header.
BITMAPFILEHEADER file;
file.bfType = 0x4d42;
file.bfSize = sizeof(BITMAPFILEHEADER);
file.bfReserved1 = 0;
file.bfReserved2 = 0;
file.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
// Write the bitmap to file.
HANDLE file_handle = CreateFile(filename.c_str(), GENERIC_WRITE, 0, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
if (file_handle != INVALID_HANDLE_VALUE)
{
DWORD bytes_written = 0;
WriteFile(file_handle, &file, sizeof(file), &bytes_written, 0);
WriteFile(file_handle, &info, sizeof(info), &bytes_written, 0);
WriteFile(file_handle, bits, width * height * 4, &bytes_written, 0);
CloseHandle(file_handle);
}
DeleteObject(bitmap);
}
void browser_thread(CefRefPtr<OffscreenClient> &client)
{
// handle of current console
HWND hWnd = GetConsoleWindow();
// use this as the UI/main thread
CefSettings settings;
settings.multi_threaded_message_loop = false;
// initialize CEF
CefInitialize(settings, CefRefPtr<CefApp>());
// set as offscreen renderer
CefWindowInfo info;
info.SetAsOffScreen(hWnd);
client = new OffscreenClient();
CefBrowserSettings browserSettings;
// synchronous/blocking call
CefBrowser::CreateBrowserSync(info, static_cast<CefRefPtr<CefClient>>(client), "http://www.google.com", browserSettings);
// set default browser size
client->GetBrowser()->SetSize(PET_VIEW, 800, 600);
CefRunMessageLoop();
// destroy client (it will call ~OffscreenClient())
client = NULL;
// shut down CEF
CefShutdown();
}
int main()
{
CefRefPtr<OffscreenClient> offscreenClient;
// create browser in another thread
boost::thread thread = boost::thread(browser_thread, boost::ref(offscreenClient));
// wait for client creation
while (!offscreenClient)
Sleep(100);
// wait for browser to be ready
while (!offscreenClient->GetBrowser())
Sleep(100);
// wait for current URL (www.google.com) to show
Sleep(4000);
// load another URL
offscreenClient->GetBrowser()->GetMainFrame()->LoadURL("www.youtube.com");
Sleep(4000);
// change window size
offscreenClient->GetBrowser()->SetSize(PET_VIEW, 1024, 768);
Sleep(4000);
// close browser
offscreenClient->GetBrowser()->CloseBrowser();
// wait for thread to complete
thread.join();
return 0;
}