Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to save Viewer Pane as image through command line?

Tags:

Let's say I have the following HTML viewed in the Viewer Pane

tempDir <- tempfile() dir.create(tempDir) htmlFile <- file.path(tempDir, "index.html") write('<h1> Content</h1>', htmlFile, append = TRUE) write('<h2> Content</h2>', htmlFile, append = TRUE) write('lorem ipsum...', htmlFile, append = TRUE) viewer <- getOption("viewer") viewer(htmlFile) 

When I have this html in the Viewer Pane, I can click on the "Save as image" button:

enter image description here

And I have the html content as a png, for example :

enter image description here

Is there a way to do this with the command line? I know about rstudioapi::savePlotAsImage(), so I'm looking for a kind of saveViewerAsImage.

Edit: I know we can do this with the {webshot} package, but I'm looking for the RStudio function that does that.

like image 703
Colin FAY Avatar asked Jun 20 '18 10:06

Colin FAY


People also ask

How do you save a viewer in R?

However, RStudio has a built-in method that can be accessed by clicking "Export -> Save as Image" in the viewer pane.

How to Save the Image in R?

If you're running R through Rstudio, then the easiest way to save your image is to click on the “Export” button in the Plot panel (i.e., the area in Rstudio where all the plots have been appearing). When you do that you'll see a menu that contains the options “Save Plot as PDF” and “Save Plot as Image”.


1 Answers

Here's a proposal. The strategy is the following:

  1. let the viewer build the png
  2. send the png from the viewer to R

Let the viewer build the png

A canvas image possesses a .toDataURL() method that returns a data URI containing the representation of the image in png format (we also can get a jpeg format).

The html2canvas library can be used to take a screenshot: this library renders the current page as a canvas image.

So, one can combine these two functions in the viewer:

  • take a screenshot with html2canvas
  • transform this screenshot to png using .toDataURL()

However, the html2canvas library uses JavaScript Promises that are not supported by the (Windows version) RStudio viewer: a polyfill is required.

Send the png from the viewer to R

This task can be achieved using WebSockets.

The httpuv package can be used to create a webserver. This server will serve a HTML page that will be opened in the RStudio viewer.

A WebSocket communication is established between the httpuv server and the RStudio viewer.

From the R command line, one can send a WebSocket message to the RStudio viewer: receiving this message, the viewer takes the screenshot and send it back to the server.

The code

I'm sorry, this code is quite long for a SO answer.

library(httpuv)  # Initialize variables png <- NULL websocket <- NULL  # Download Javascript libraries polyfill_promise <- readLines('https://cdn.jsdelivr.net/npm/es6-promise/dist/es6-promise.auto.min.js') html2canvas <- readLines('https://html2canvas.hertzen.com/dist/html2canvas.min.js')  # Configure the httpuv server app <- list(   call = function(req) {     list(       status = 200L,       headers = list(         'Content-Type' = 'text/html'       ),       body = paste0(collapse = "\r\n",                     c("<!DOCTYPE html>",                       "<html>",                       "<head>",                       # polyfill the RStudio viewer to support JavaScript promises                       '<script type="text/javascript">',                       polyfill_promise,                       "</script>",                       # use html2canvas library                       '<script type="text/javascript">',                       html2canvas,                       "</script>",                       "</head>",                       "<body>",                       html_body,                       "</body>",                       '<script type="text/javascript">',                       # Configure the client-side websocket connection:                       'var ws = new WebSocket("ws://" + location.host);',                       # When a websocket message is received:                       "ws.onmessage = function(event) {",                       # Take a screenshot of the HTML body element                       "  html2canvas(document.body).then(function(canvas) {",                       # Transform it to png                       "    var dataURL = canvas.toDataURL();",                       # Send it back to the server                       "    ws.send(dataURL);",                       "  });",                       "};",                       "</script>",                       "</html>"                     )       )     )   },   # Configure the server-side websocket connection   onWSOpen = function(ws) {     # because we need to send websocket message from the R command line:     websocket <<- ws     # when a websocket message is received from the client     ws$onMessage(function(binary, message) {       png <<- message     })   } )  # From your question: html_body <- c(   '<h1> Content</h1>',    '<h2> Content</h2>',    'lorem ipsum...' )  # Start the server: server <- startDaemonizedServer("0.0.0.0", 9454, app)  # Open the RStudio viewer: rstudioapi::viewer("http://localhost:9454") # Wait to see the result...  # Send a websocket message from the command line: websocket$send("go") # send any message  # Write the png image to disk: writeBin(   RCurl::base64Decode(     gsub("data:image/png;base64,", "", png),      "raw"   ),    "screenshot.png" )  # Close the websocket connection websocket$close()  # Stop the server stopDaemonizedServer(server) 
like image 158
RLesur Avatar answered Oct 22 '22 22:10

RLesur