Google Slides API — a deep dive on its powerful image manipulation methods
Use Google Apps Script and the Google Slides API to create a card game like Dobble.
What am I talking about?
Dobble (Spot It! in the US)
A speedy observation card game. During the game, players have to spot the identical symbol between two cards as quickly as possible.
=> learn more on Wikipedia
Google Apps Script
A rapid application development platform that makes it fast and easy to create applications that integrate with G Suite. You write code in modern JavaScript and have access to built-in libraries for favorite G Suite applications like Gmail, Calendar, Drive, and more. There’s nothing to install — we give you a code editor right in your browser, and your scripts run on Google’s servers.
=> learn more on the official documentation
Google Slides API
This API lets you create and modify Google Slides presentations. Apps can integrate with the Google Slides API to create beautiful slide decks automatically from user- and system-provided data.
=> learn more on the official documentation
The Dobble Algorithm
There are several articles and YouTube videos explaining the maths behind the game. I’m focusing on using the Google Slides API so I simply reused a Javascript function shared on Stack Overflow.
This function returns a two-dimensional array of integers, any two arrays always sharing one, and only one, matching integer.
From numbers to images in Slides
Insert images in Slides
Now we just need an image for each integer returned by the function (in my case I uploaded a bunch of images in a Google Drive folder), and we can insert all those images in slides using the Google Slides API, it’s quite easy:
SlidesApp.create(“my card deck”).appendSlide().insertImage(imageUrl);
But I need to insert 8 images per slide and I don’t want one to appear on top of another one. Luckily you can easily set position of each image (set the position from the upper-left corner of the page + the size of the image):
image.setTop(top).setLeft(left).setWidth(width).setHeight(height);
Replace existing images / use a template
I thought it would be easier to start from a template containing images, copy said template and replace the images (as there’s a replace method available for images!):
for (var i = 0; i < deck.length; i++) {
// each slide / card is a copy of our template
var card = presentation.appendSlide(card_template);
// existing images in the template are used as placeholders
var placeholders = card.getImages();
for (var j = 0; j < placeholders.length; j++) {
// and replaced by our real images
placeholders[j].replace(imageUrl);
}
}
Rotate images
We can also apply a random rotation on each image.
var image = placeholders[j].replace(imageUrl);
image.setRotation(Math.floor(Math.random() * 360));
Many more methods are available to manipulate images, you could use scaleWidth(ratio)
to randomly change the size of each image or even recolor, add a reflection or a shadow on each image (basically every manipulations you can do from the Slides editor UI).
Try it
Here’s the full Apps Script code to generate a card deck from a bunch of images in Google Drive: https://script.google.com/d/1_o1COq1Or1IK_26pvRjXy17VXDU8_2iBZ3F-eLajQuBeaif3Sdw_IlR_/edit?usp=sharing
And a step-by-step tutorial: https://medium.com/@romain.vialard/make-your-own-dobble-spot-it-game-with-google-slides-and-apps-script-57c168b3a5fb
A note on authorization scopes
In this Apps Script code, in addition to the Google Slides API, I used the Google Drive API to:
- Retrieve all images in a specific folder
Drive.Children.list(DRIVE_FOLDER_ID, { q: “mimeType contains ‘image/’ and trashed = false” }).items;
- Make a copy of a Google Slide template and put that copy in the same folder
Drive.Files.copy({ parents: [{ id: DRIVE_FOLDER_ID }] }, SLIDES_TEMPLATE_ID);
In Apps Script, you can do that either with DriveApp or the Advanced Drive Service. I used the later because it offers the ability to reduce the permissions we need.
- With DriveApp, I need to use the full
drive
scope, which allow the script to read, edit and delete everything in Drive - With the advanced service, I will still need a global read access to get all images(using
drive.readonly
scope) but I can combine that with thedrive.file
scope which only allows the script to create new files, not edit existing ones already created by the user in his Drive.
Best would be to have a less permissive read
scope, where user would only authorize the script to access files inside a specific folder but that’s not (yet?) available.