As an aside, the code samples here will be using the techniques in More client-server code sharing and Namespaces in libraries and scripts, which allows me to share code between Gas and HTML service and also manage the code in the Apps Script IDE as if it were regular GS code, so you may want to take a look at those for some background on the styles here.
Server code
Let’s start with Image.gs, which runs on the server and whose job it is to decide where to embed the canvas image. Calling Image.place() will insert a PNG image blob at the current cell in a Sheet.
// responsible for placing a png image on a sheet var Image = (function(image) { 'use strict'; // insert an image at row / column in the sheet image.insert = function ( range, png) { range.getSheet().insertImage ( png , range.getColumn(), range.getRow()); }; // place an image image.place = function (png) { return image.insert ( SpreadsheetApp.getActiveRange() , png); }; return image; }) (Image || {});
Converting the canvas to a PNG blob
Assuming you already have your canvas plotted, all you need to do is this. Note that we don’t need to use Utilities.newBlob() back on the server, because toDataUrl() creates a blob.
Client.insertImage(canvas.toDataURL("image/png"));
Passing it off to the Server
I usually centralize all my calls to the server in a script called Client.gs. Here’s where we call the server to write the image
/** * client stuff that's specific to the type server */ var Client = (function(client) { client.insertImage = function (png) { google.script.run .withFailureHandler(function(error) { App.showNotification ("Failed to insert image", error); }) .withSuccessHandler(function (result) { }) .insertImage(png); }; return client; })(Client || {});
Finally back on the server we need a global function that’s seeable by the client.
function insertImage(png) { return Image.place(png); }
embed SVG images
SVG Mime type is not supported by Sheet.insertImage(), but if SVG is your thing , you can still do this by going via Canvas. All the code above is the same, except that we need to include a couple of external JS libraries.
I’ve created a new script CanvasConvert.gs, which will run on the client.
var CanvasConvert = (function(canvasConvert) { 'use strict'; canvasConvert.svgToPng = function (svg) { // create a canvas to use, no need to actually assign it to a parent var canvas = document.createElement("canvas"); // plot it on a canvas canvg ( canvas , svg); // return it as png return canvas.toDataURL("image/png"); } return canvasConvert; })(CanvasConvert || {});
This time, converting to a blob and passing over to the Server becomes this, where svgCode is the innerHTML of your SVG element.
Client.insertImage(CanvasConvert.svgToPng(svgCode));
HTML5
We’re using HTML5 here, so it’s not going to work on some older browsers, but if you’re using Canvas, you’re probably already got past that anyway.