Search code examples
google-apps-scriptgoogle-slides-api

How can I use Apps Script to alter the amount of Slides that print on each page


I have a spreadsheet that programmatically creates a Google Slides presentation with multiple slides.

I want to use apps script to create a pdf version of these slides but with multiple slides on each page.

I know how to use DriveApp.create(blob) to get a pdf version of my slides but this only does one slide per page.

I also know that I can access the "Print Settings and Preview" settings within Slides to achieve this functionality manually.

Is there anyway that I can achieve this goal exclusively using a script?

Kind regards,

Brett

EDIT: For clarity I am attaching an image of what I want. I know that it is possible using the Slides Ui. I want to know if it's possible using apps script. An image file depicting a pdf export of a Slides file where 6 slides are shown on each page.


Solution

    • You want to summarize 6 slides in one slide, and export the Slides as a PDF file.
    • Each slide of 6 slides is image of each slide.

    If my understanding is correct, how about this workaround? Unfortunately, in the current stage, it seems that there are no methods for directly achieving above in SlidesApp service and Slides API. I couldn't find such methods. So it is required to think of the workaround. I challenged to achieve this because I thought that achieving this is also useful for me and other users.

    The flow of this workaround is as follows.

    Flow:

    1. Copy the original Slides file as a temporary file.
    2. Retrieve images of all slides.
      • When the Slides file is exported to PNG file, the top page is exported as PNG file. I used this.
    3. Put and arrange the retrieved images to the temporary file.
      • When the image is inserted to a slide, retrieve the size and change the size, then put the image to the calculated position.
    4. Export the Slides to PDF file.
    5. Delete the temporary file.
      • In this case, the temporary file is put in the trash box.

    Sample script:

    Please copy and paste this script to the script editor. And please set the file ID of original Slides. In this sample script, col and row are 3 and 2, respectively. This is the same with your question. If you change the size of images and separation, please modify wsize and sep. wsize is the width of image. When this is set, the height is calculated.

    function myFunction() {
      // Please set these parameters
      var id = "### file ID ###"; // file ID of original Slides
      var col = 3; // Number of columns
      var row = 2; // Number of rows
      var wsize = 200; // Size of width of each image (pixels)
      var sep = 5; // Space of each image (pexels)
    
    
      // Create temporary file
      var originalFile = DriveApp.getFileById(id);
      var tempFile = originalFile.makeCopy();
      var idt = tempFile.getId();
    
      // Retrieve slides as images
      var s = SlidesApp.openById(idt);
      var slides = s.getSlides();
      var accessToken = ScriptApp.getOAuthToken();
      var baseUrl = "https://docs.google.com/presentation/d/" + idt + "/export/";
      var url = baseUrl + "png?access_token=" + accessToken;
      var blobs = slides.map(function(e) {
        var blob = UrlFetchApp.fetch(url).getBlob();
        slides[0].remove();
        s.saveAndClose();
        s = SlidesApp.openById(idt);
        slides = s.getSlides();
        return blob;
      });
    
      // Put images 
      var ph = s.getPageHeight();
      var pw = s.getPageWidth();
      var leftOffset = (pw - ((wsize * col) + (sep * (col - 1)))) / 2;
      if (leftOffset < 0) throw new Error("Images are sticking out from a slide.");
      var len = col * row;
      var loops = Math.ceil(blobs.length / (col * row));
      for (var loop = 0; loop < loops; loop++) {
        var ns = s.insertSlide(loop);
        var topOffset, top;
        var left = leftOffset;
        for (var i = len * loop; i < len + (len * loop); i++) {
          if (i === blobs.length) break;
          var image = ns.insertImage(blobs[i]);
          var w = image.getWidth();
          var h = image.getHeight();
          var hsize = h * wsize / w;
          if (i === 0 || i % len === 0) {
            topOffset = (ph - ((hsize * row) + sep)) / 2;
            if (topOffset < 0) throw new Error("Images are sticking out from a slide.");
            top = topOffset;
          }
          image.setWidth(wsize).setHeight(hsize).setTop(top).setLeft(left).getObjectId();
          if (i === col - 1 + (loop * len)) {
            top = topOffset + hsize + sep;
            left = leftOffset;
          } else {
            left += wsize + sep;
          }
        }
      }
      s.saveAndClose();
    
      // Export PDF file
      var urlPdf = baseUrl + "pdf?access_token=" + accessToken;
      var pdf = UrlFetchApp.fetch(urlPdf).getBlob();
      DriveApp.createFile(pdf.setName(originalFile.getName() + ".pdf"));
      tempFile.setTrashed(true);
    }
    

    Input:

    This is the original Slides. This sample Slide has 15 slides.

    enter image description here

    Output:

    This is the exported PDF file.

    enter image description here

    References:

    Edit:

    I found presentations.pages.getThumbnail at Slides API. So I also prepared a sample script using it.

    When you use this script, please enable Slides API at API console.

    Sample script:

    function myFunction() {
      // Please set these parameters
      var id = "### file ID ###"; // file ID of original Slides
      var col = 3; // Number of columns
      var row = 2; // Number of rows
      var wsize = 200; // Size of width of each image (pixels)
      var sep = 5; // Space of each image (pexels)
    
    
      // Retrieve slides as images
      var originalFile = SlidesApp.openById(id);
      var accessToken = ScriptApp.getOAuthToken();
      var pageObjectIds = originalFile.getSlides().map(function(e) {return e.getObjectId()});
      var reqUrls = pageObjectIds.map(function(pageObjectId) {
        return {
          method: "get",
          url: "https://slides.googleapis.com/v1/presentations/" + id + "/pages/" + pageObjectId + "/thumbnail?access_token=" + accessToken,
        };
      });
      var reqBlobs = UrlFetchApp.fetchAll(reqUrls).map(function(e) {
        var r = JSON.parse(e);
        return {
          method: "get",
          url: r.contentUrl,
        };
      });
      var blobs = UrlFetchApp.fetchAll(reqBlobs).map(function(e) {return e.getBlob()});
    
      // Create a temporary Slides and put images 
      var s = SlidesApp.create("temporarySlides");
      s.getSlides()[0].remove();
      var idt = s.getId();
      var ph = s.getPageHeight();
      var pw = s.getPageWidth();
      var leftOffset = (pw - ((wsize * col) + (sep * (col - 1)))) / 2;
      if (leftOffset < 0) throw new Error("Images are sticking out from a slide.");
      var len = col * row;
      var loops = Math.ceil(blobs.length / (col * row));
      for (var loop = 0; loop < loops; loop++) {
        var ns = s.insertSlide(loop);
        var topOffset, top;
        var left = leftOffset;
        for (var i = len * loop; i < len + (len * loop); i++) {
          if (i === blobs.length) break;
          var image = ns.insertImage(blobs[i]);
          var w = image.getWidth();
          var h = image.getHeight();
          var hsize = h * wsize / w;
          if (i === 0 || i % len === 0) {
            topOffset = (ph - ((hsize * row) + sep)) / 2;
            if (topOffset < 0) throw new Error("Images are sticking out from a slide.");
            top = topOffset;
          }
          image.setWidth(wsize).setHeight(hsize).setTop(top).setLeft(left).getObjectId();
          if (i === col - 1 + (loop * len)) {
            top = topOffset + hsize + sep;
            left = leftOffset;
          } else {
            left += wsize + sep;
          }
        }
      }
      s.saveAndClose();
    
      // Export PDF file
      var urlPdf = "https://docs.google.com/presentation/d/" + idt + "/export/" + "pdf?access_token=" + accessToken;
      var pdf = UrlFetchApp.fetch(urlPdf).getBlob();
      DriveApp.createFile(pdf.setName(originalFile.getName() + ".pdf"));
      DriveApp.getFileById(idt).setTrashed(true);
    }
    

    Note:

    • Both scripts can obtain the same result. So please select one of them. I think that 2nd one might be a bit fast, because all thumbnail images are retrieved using fetchAll.