Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(438)

Unified Diff: headless/app/headless_shell.cc

Issue 2035733002: headless: Implement screenshot capturing (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Move async test, write screenshot to file. Created 4 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | headless/app/headless_shell_switches.h » ('j') | headless/test/headless_browser_test.h » ('J')
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: headless/app/headless_shell.cc
diff --git a/headless/app/headless_shell.cc b/headless/app/headless_shell.cc
index 25c823d541cb196bba2579c004e3722c57d7da3a..38fbc60055b3c9b33306702a11d9b57ba2fcff4f 100644
--- a/headless/app/headless_shell.cc
+++ b/headless/app/headless_shell.cc
@@ -4,10 +4,13 @@
#include <iostream>
#include <memory>
+#include <string>
+#include "base/base64.h"
#include "base/bind.h"
#include "base/callback.h"
#include "base/command_line.h"
+#include "base/files/file_path.h"
#include "base/json/json_writer.h"
#include "base/location.h"
#include "base/memory/ref_counted.h"
@@ -21,7 +24,10 @@
#include "headless/public/headless_devtools_client.h"
#include "headless/public/headless_devtools_target.h"
#include "headless/public/headless_web_contents.h"
+#include "net/base/file_stream.h"
+#include "net/base/io_buffer.h"
#include "net/base/ip_address.h"
+#include "net/base/net_errors.h"
#include "ui/gfx/geometry/size.h"
using headless::HeadlessBrowser;
@@ -33,6 +39,8 @@ namespace runtime = headless::runtime;
namespace {
// Address where to listen to incoming DevTools connections.
const char kDevToolsHttpServerAddress[] = "127.0.0.1";
+// Default file name for screenshot. Can be overriden by "--screenshot" switch.
+const char kDefaultScreenshotFileName[] = "screenshot.png";
}
// A sample application which demonstrates the use of the headless API.
@@ -41,7 +49,9 @@ class HeadlessShell : public HeadlessWebContents::Observer, page::Observer {
HeadlessShell()
: browser_(nullptr),
devtools_client_(HeadlessDevToolsClient::Create()),
- processed_page_ready_(false) {}
+ web_contents_(nullptr),
+ processed_page_ready_(false),
+ screenshot_file_stream_(nullptr) {}
Sami 2016/06/03 11:46:24 No need to initialize a unique_ptr. The web_conten
Eric Seckler 2016/06/03 13:40:38 Ack, removed :)
~HeadlessShell() override {}
void OnStart(HeadlessBrowser* browser) {
@@ -135,6 +145,9 @@ class HeadlessShell : public HeadlessWebContents::Observer, page::Observer {
<< "Type a Javascript expression to evaluate or \"quit\" to exit."
<< std::endl;
InputExpression();
+ } else if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+ headless::switches::kScreenshot)) {
+ CaptureScreenshot();
} else {
Shutdown();
}
@@ -181,6 +194,76 @@ class HeadlessShell : public HeadlessWebContents::Observer, page::Observer {
InputExpression();
}
+ void CaptureScreenshot() {
+ devtools_client_->GetPage()->GetExperimental()->CaptureScreenshot(
+ page::CaptureScreenshotParams::Builder().Build(),
+ base::Bind(&HeadlessShell::OnScreenshotCaptured,
+ base::Unretained(this)));
+ }
+
+ void OnScreenshotCaptured(
+ std::unique_ptr<page::CaptureScreenshotResult> result) {
+ base::FilePath file_name =
+ base::CommandLine::ForCurrentProcess()->GetSwitchValuePath(
+ headless::switches::kScreenshot);
+ if (file_name.empty()) {
+ file_name = base::FilePath().AppendASCII(kDefaultScreenshotFileName);
+ }
+
+ screenshot_file_stream_.reset(
+ new net::FileStream(browser_->BrowserFileThread()));
+ const int open_result = screenshot_file_stream_->Open(
+ file_name, base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE |
+ base::File::FLAG_ASYNC,
+ base::Bind(&HeadlessShell::OnScreenshotFileOpened,
+ base::Unretained(this), base::Passed(std::move(result)),
+ file_name));
+ if (open_result != net::ERR_IO_PENDING) {
+ OnScreenshotFileOpened(std::move(result), file_name, open_result);
Sami 2016/06/03 11:46:24 Does this work since you already moved |result| a
Eric Seckler 2016/06/03 13:40:38 Passing a nullptr now. From the comments in FileSt
+ }
+ }
+
+ void OnScreenshotFileOpened(
+ std::unique_ptr<page::CaptureScreenshotResult> result,
+ const base::FilePath file_name,
+ const int open_result) {
+ if (open_result != net::OK) {
+ LOG(ERROR) << "Writing screenshot to file " << file_name.value()
+ << " was unsuccessful, could not open file: "
+ << net::ErrorToString(open_result);
Sami 2016/06/03 11:46:24 nit: you could early-out here to reduce the indent
Eric Seckler 2016/06/03 13:40:38 Done.
+ } else {
+ std::string decoded_png;
+ base::Base64Decode(result->GetData(), &decoded_png);
+ net::IOBufferWithSize* buf =
Sami 2016/06/03 11:46:24 Who owns |buf|?
Eric Seckler 2016/06/03 13:40:38 IOBuffers are refcounted, but passed as plain poin
+ new net::IOBufferWithSize(decoded_png.size());
+ memcpy(buf->data(), decoded_png.data(), decoded_png.size());
+ const int write_result = screenshot_file_stream_->Write(
+ buf, buf->size(), base::Bind(&HeadlessShell::OnScreenshotFileWritten,
+ base::Unretained(this), file_name));
+ if (write_result != net::ERR_IO_PENDING) {
+ OnScreenshotFileWritten(file_name, open_result);
Sami 2016/06/03 11:46:24 write_result?
Eric Seckler 2016/06/03 13:40:38 Good catch, done.
+ }
+ }
+ }
+
+ void OnScreenshotFileWritten(const base::FilePath file_name,
+ const int write_result) {
+ if (write_result < 0) {
+ LOG(ERROR) << "Writing screenshot to file " << file_name.value()
+ << " was unsuccessful: " << net::ErrorToString(write_result);
+ } else {
+ std::cout << "Screenshot written to file " << file_name.value() << "."
+ << std::endl;
+ }
+ int close_result = screenshot_file_stream_->Close(base::Bind(
+ &HeadlessShell::OnScreenshotFileClosed, base::Unretained(this)));
+ if (close_result != net::ERR_IO_PENDING) {
+ OnScreenshotFileClosed(close_result);
+ }
+ }
+
+ void OnScreenshotFileClosed(const int close_result) { Shutdown(); }
+
bool RemoteDebuggingEnabled() const {
const base::CommandLine& command_line =
*base::CommandLine::ForCurrentProcess();
@@ -193,6 +276,7 @@ class HeadlessShell : public HeadlessWebContents::Observer, page::Observer {
std::unique_ptr<HeadlessDevToolsClient> devtools_client_;
HeadlessWebContents* web_contents_;
bool processed_page_ready_;
+ std::unique_ptr<net::FileStream> screenshot_file_stream_;
DISALLOW_COPY_AND_ASSIGN(HeadlessShell);
};
« no previous file with comments | « no previous file | headless/app/headless_shell_switches.h » ('j') | headless/test/headless_browser_test.h » ('J')

Powered by Google App Engine
This is Rietveld 408576698