How to Convert SVG to PNG/JPG using Google Apps Script (GAS)

Have you ever tried to generate a dynamic chart or map in Google Apps Script as an SVG, only to realize you can’t easily share it as an image?

Because GAS runs on Google’s servers, it doesn’t have a “screen” to render graphics. If you want to convert an SVG string into a PNG or JPG, you’ll find that standard libraries are missing. But there is a workaround: The Browser Bridge.

By using HtmlService, we can temporarily pass the SVG to the user’s browser, use the HTML5 Canvas API to rasterize it, and send the image data back to Google Drive.

This way, you can create or edit an existing SVG file using parameters in your Spreadsheet and export it as a raster image (PNG).

It also allows you to automate importing pf SVG files into Google Slides without using external APIs such as CloudConvert (which you could use, but it’s not free for extensive use, and you also need to share your data to a third party).

The Architecture

1. GAS (Server): Prepares the SVG string.

2. HTML (Client): Opens a hidden dialog, draws the SVG on a <canvas>.

3. Canvas (Client): Converts the drawing to a Base64 PNG string.

4. GAS (Server): Receives the Base64 data and saves it as a file.

Implementation

1. Code.gs (Server-side)

This script coordinates the data flow and handles the final file saving.

/**
* Main function to trigger the conversion
*/
function startConversion() {
const svgString = '<svg xmlns="http://www.w3.org/2000/svg" width="200" height="200"><circle cx="100" cy="100" r="80" fill="red" /></svg>';
const fileName = "converted_image.png";

const template = HtmlService.createTemplateFromFile('converter');
template.svgData = svgString;
template.fileName = fileName;

const html = template.evaluate().setWidth(400).setHeight(300);
SpreadsheetApp.getUi().showModalDialog(html, 'Converting SVG to PNG...');
}

/**
* Saves the Base64 data received from the client
*/
function saveImage(base64Data, fileName) {
const decoded = Utilities.base64Decode(base64Data.split(',')[1]);
const blob = Utilities.newBlob(decoded, 'image/png', fileName);
DriveApp.createFile(blob);
return "Success";
}

2. converter.html (Client-side)

Create this file in the same project. It acts as the “Rendering Engine.”

<!DOCTYPE html>
<html>
<body>
<canvas id="canvas" style="display:none;"></canvas>
<script>
window.onload = function() {
// Data passed from GAS
const svgString = `<?!= svgData ?>`;
const fileName = `<?!= fileName ?>`;

const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
const img = new Image();

// Important: Ensure the SVG has the correct namespace
let blob = new Blob([svgString], {type: 'image/svg+xml;charset=utf-8'});
let url = URL.createObjectURL(blob);

img.onload = function() {
canvas.width = img.width || 1200; // Set high res
canvas.height = img.height || 1200;
ctx.fillStyle = "white"; // Optional: background color
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.drawImage(img, 0, 0);

const pngData = canvas.toDataURL('image/png');
google.script.run
.withSuccessHandler(() => google.script.host.close())
.saveImage(pngData, fileName);
};
img.src = url;
};
</script>
</body>
</html>

Critical Pitfalls to Avoid

• The xmlns Attribute: Your SVG must include xmlns=”http://www.w3.org/2000/svg”. Without this, the browser’s Image object will fail to load the string.

• Fonts: If you use Google Fonts, the browser needs a moment to load them. Use document.fonts.ready or document.fonts.load() before drawing to the canvas.

• Base64 Encoding: For complex SVGs with Japanese characters, use btoa(unescape(encodeURIComponent(svgString))) to ensure UTF-8 characters don’t break.