D20 - 如何用 Apps Script 自动化地创造与客制 Google Slides?(一)架构拆解与更改文字

今天的目标

今天要教要怎麽样快速改客户名称後交出投影片。 如果在「需要大量制作时」,有时会发现其中某个单字、单词错误,但投影片已经多达数百张,比起一张张做,透过 GAS 可以帮你省点时间。无论是报告或是分享,现在 Google Slide 已经是许多人的首选,尤其是要共同编辑时更是如此。今天会讲述 Google Slides 的大架构,以及如何微调其中每一页(有出现)的文字。

  1. 如何更改 Google Slide 的中的特定文字?

那就让我们开始吧。

先来个小测验

// Open a presentation by ID.
let my_slide = SlidesApp.openById('PRESENTATION_ID_GOES_HERE');

// Create and open a presentation.
new_slide = SlidesApp.create('Presentation Name');
  1. 这是官方的第一个 Google Slides 入门范例,请问透过上述程序码,回传的 my_slidenew_slide 会是什麽物件?

(A)Presentaion
(B)Slides
(C)Slide
(D)Page
(E)Pages
(F)Master

  1. 再来第二题——

(备注,答案确定在有列出的 Element 选项中)

那就让我们开始吧!


因为这是 Slides 的第一天,我们会先从其架构开始,架构的重要,从小测验就可以略知一二。小测验第一题的答案是(A),第二题是 shapetable 中的 TextRange (要回答出 range喔,这是个小陷阱!)。那就让我们继续看下去。

Google Slides 的架构

先来了解一下 Google Slides 有哪些架构。其主要分成两大块,一块叫做 Pages,一块叫做 Pages Element。

页面(Page)部分主要有分成三种,一种是投影片(Slides),也就是我们平常最常用的;一种是版面配置(Layout);最後一种是主题(Master)。另外还有两种是备忘稿(Note)与备忘稿主题(Note Master)。

在这边要特别厘清说,虽然我这边直接用「主题」来翻译 Master,但实际上「主题」(Theme)的比较严谨定义会是由母版(Master)与版面配置(Layout)一起组成的。

我们这里主要会说明的是「投影片」(Slides),但如果有兴趣深造做连动,可以来了解一下页面间的继承关系(Inheritance of page properties)

至於页面元素(Page Element)则是在页面上,不管是投影片、版面配置或主题上的所有元素。

换句话说,整个 Google Slide 都会有这样的资料架构——

为什麽这个重要呢?因为先总览知道有哪些可以调配的元素,可以协助我们更好地运用 Google Slides 里面的内容。举例来说,就会知道一开始我们在 GAS 要用 openById 打开来的会是 Presentation;要调整投影片版面大小的话,要动用 PresentationpageSize ;以及你就会发现,原来每一个 page element 其实都可以设定 title (setTitle) 与 description,这对於我们之後要自动化会有很大的帮助。

顺带一提,这 title 的设置也是种设置替代文字(alt)的方式。在美国,企业会被要求所写的网页符合一定程度的无障碍规范,也就是要让视障者等也可以阅读。

以及,我们平常的打字,都是位在「文字方块」(Text Box)当中,而文字方块在 Google Slides 中是被归属为一种 Shape。但如果说哪里可以取得文字,那 shape、table 内是都有机会的。

Ref: Google Slides Developer APIs

Q1. 如何更改 Google Slide 的中的特定文字?

当然,如果是一篇篇打开用 ctrl + F 也是可以做到的。但当要改的字很多、抑或是要改的量很多时,就没有那麽容易了。这次会带大家做怎麽样改单篇 Google Slides 里面的「字」,再来会再用一篇让大家知道怎麽样自动化这个流程。

那我们先设定一份 Slide 档案,一样借用某书的内容。

Step 1 从 Google Slides 进入 GAS

那这次我们用 Google Slides 进入

一样第一次会有存取验证需要大家按一下。这边仍是借用一下 D2 的影片。

那我们就来看怎麽读取吧。

Step 2 用 getSlides() 抓到投影片

我们先用 SlidesApp.getActivePresentation() 抓出正在绑定的文件,如果你不是从 Step 1 进入 GAS,那可以用 SlidesApp.openById();那我们主要会针对 Slides 的部分进行操作,所以透过 getSlides() 来取得每一个 Slides。针对每一个 Slides,我们都用一个 for 回圈来取得里面的资料。

function readSlides() {
  let pres = SlidesApp.getActivePresentation();
  let slides = pres.getSlides();
  for(slide of slides){
    Logger.log(slide)
  }
}

看一下跑起来长怎样——

好,确实有读到 六张 Slide。再来就是读取上头的元素了。

Step 3 用 getPageElements() 抓到投影片上的元素

那抓到投影片後,又要怎麽抓到上面的元素呢?这时要用 getPageElements() 了。一样要再加上一个 For 回圈才行,这边直接将程序码加速到读上面的物件。

诚如我们在「结构」那段所说,我们今天要抓的「文字」是属於「Shape」Object 的一种,所以我简单弄了一段程序码出来,看一下在每一页会读到什麽元素。

function readPageElements() {
  let pres = SlidesApp.getActivePresentation();
  let slides = pres.getSlides();
  for(let i = 0; i < slides.length; i++){
    let slide = slides[i];
    Logger.log("We load the No."+ (i+1) +" slide");
    let page_elements = slide.getPageElements();
    for(page_element of page_elements){
      if(page_element.getPageElementType() == SlidesApp.PageElementType.SHAPE){
        let text_range = page_element.asShape().getText();
        Logger.log("Get a " + text_range + " in a shape");
      }else{
        Logger.log("Get a object which type is " +page_element.getPageElementType());
      }
    }
  }
}

看一下跑出来的结果——

会发现,跑出来的 Page Element 会有 ShapeTableImage,也就是我们预设在 D20 投影片里面的元素。

虽然说我们知道 「文字」 会位在 Page Element 中的 Shape 底下,实际上我们直接用下列程序码抓下来的,会是 Text Range Object

会需要再用 getRenderedString() 才能读到「现在显现的文字」,另外也可以用getParagraphs() 等方法能读取到段落等。读取起来长这样——

更多的 Text Range 操作细节,可以参考的文章 D19 - 如何用 Apps Script 自动化地创造与客制 Google Docs?(六)更改特定内容格式的 Attribute 操作技巧,概念上是相通的。

那讲到这边,我们要怎麽「更改内容」?这边我们预设的使用场景,是要更换顾客名称等,所以我们先来看最方便的 「全部更改」。

Step 4 全部更改: replaceAllText(findText, replaceText)

以下的程序码我们想将所有的「句号」换成「惊叹号」。

function rewritePunctuation() {
  let findText = "。";
  let replaceText= "!";

  let pres = SlidesApp.getActivePresentation();
  let slides = pres.getSlides();
  for(let i = 0; i < slides.length; i++){
    let slide = slides[i];
    Logger.log("We load the No."+ (i+1) +" slide");
    let page_elements = slide.getPageElements();
    for(page_element of page_elements){
      if(page_element.getPageElementType() == SlidesApp.PageElementType.SHAPE){
        let text_range = page_element.asShape().getText();
        Logger.log(text_range.asRenderedString());
        text_range.replaceAllText(findText, replaceText);
      }
    }
  }
}

跑起来长这样——

好,看来是有成功。我们这边用比较简单的案例来让大家看效果,如果要做成「改客户名称」、「改日期」等等的,都可以用这个方式办理。


好,那今天就到这边。今天我们主要学了:

  1. Google Slides 的架构
  2. 如何用 GAS 操作 Google Slides 的 Presentation,以及 Shape 中的 TextRange
  3. 如何更改(替换)其中的内容。

那今天进入了 Slide 的部分,一样先讲解了最常会遇到的情境,也就是替换文字。希望对大家有所帮助。如果还有问题,透过留言之外,也可以到 Facebook Group,想开很久这次铁人赛才真的开起来,欢迎来当 Founding Member。如果不想错过可以订阅按赞小铃铛(?),也欢迎留言跟我说你还想知道什麽做法/主题。我们明天见。


<<:  Flutter体验 Day 12-线性布局

>>:  [Day10] 2D的数学世界(二) - 座标系转换

[2021铁人赛 Day11] General Skills 08

引言 昨天学到 ssh 以及 「大括号的分配律」─ Brace Expansion 这边再补充一点...

CSS overflow

前言 当子元素溢出母元素时该如何处理 可单指设定X轴或Y轴 overflow-x overflow-...

day24 : kong api gateway(上)

到今天为止介绍了不少应用於k8s上的服务,并且大部分都可以透过operator的方式进行同性质的服务...

30天Python自学:Day02

#以下内容皆由初学者撰写,有错误可能,不建议尽信 30天Python自学: Day02 Python...

乔叔教 Elastic - 30天文章总整理 + 完赛心得

这次参加铁人赛 30 天分享的文章,透过这篇做个总整理,并且建立一个索引目录,让大家能透过这系列文章...