Google Apps Script を使ってアルファチャネル付き PNG データを作成したい

# 概要

この投稿では、Google Apps Script を使ったアルファチャネル付き PNG データの作成について紹介させていただきます。

アルファチャネル付き PNG データとは、背景が透明になっているような画像データを意味します。(デモのセクションで確認できます。) これまで Google Apps Script でアルファチャネル付き PNG データを作成するための方法について探していましたが、残念ながら見つかりませんでした。最近になって、ようやくその方法を見つけることができましたので、こちらでも紹介させていただきます。この方法の key factors は次の通りです。

1. Google Apps Script のメソッドや Google APIs では不可能なことを実現するために Google Apps Script ライブラリ [DocsServiceApp](https://github.com/tanaikech/DocsServiceApp) を作成したこと。

   - このライブラリの`createNewSlidesWithPageSize`メソッドでは、ページサイズを指定して Google Slides を作成することができます。これは現行の Google Apps Script のメソッドや Google APIs ではできません。

2. Google Slides を PNG データとしてエクスポートすることができることが分かったこと。

   - Drive API の`exportFormats`を見ると、Google Slides (`application/vnd.google-apps.presentation`)は、次の 4 通りの mimeType として出力することができることが分かっています。
     - `application/vnd.oasis.opendocument.presentation`
     - `application/pdf`
     - `application/vnd.openxmlformats-officedocument.presentationml.presentation`
     - `text/plain`
   - 上記の通り、Google Slides は PNG(`image/png`)として出力することはできない仕様でしたが、これが PNG として出力できることを発見しました。さらに、出力された PNG データはアルファチャネルを含んでいることもわかりました。
   - 追加情報として、svg を指定すると、svg としても出力することが可能であることを確認しました。これもまた他で応用することができそうに思います。

3. 手動で Google Slides のスライドの背景を透明にするか、`SlidesApp.openById(presentationId).getSlides()[0].getBackground().setTransparent()`のスクリプトを使ってスライドの背景を透明にした状態で、PNG として出力すると、透明の背景を維持した状態で PNG データを作成できることが分かったこと。

上記の 3 つの key factors によって、Google Apps Script を使ったアルファチャネル付き PNG データの作成が可能になりました。

# デモ

このデモンストレーションでは、Google Apps Script で作成したアルファチャネル付きの画像を Google Spreadsheet へ挿入しています。

![fig1.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/133383/f4b3c1fd-9dc7-2202-5ff7-ddad08f28e2d.gif)


# 流れ

この方法の流れは次の通りです。

1. Google Slides を指定したサイズで作成する。

   - これはテンポラルファイルとして使用します。

2. Google Slides の背景を透明にします。

3. Google Slides へ Shape や Text などを挿入します。

   - この場合、最初の 1 ページ目を使用します。

4. PNG の mimeType で Export のエンドポイントを使ってデータを出力します。

5. テンポラルファイルを削除します。

# 使用方法

ここでは、サンプルとしてスクリプトを Google Spreadsheet の Container-bound script で使用します。そのため、Google Spreadsheet を作成し、スクリプトエディタを開き、下記を実行してください。

## 1. Google Apps Script library

Google Apps Script library [DocsServiceApp](https://github.com/tanaikech/DocsServiceApp#how-to-install)をインストールします。ライブラリのプロジェクトキーは、`108j6x_ZX544wEhGkgddFYM6Ie09edDqXaFwnW3RVFQCLHw_mEueqUHTW`です。リポジトリは、[こちら](https://github.com/tanaikech/DocsServiceApp#how-to-install)です。

## 2. Drive API

[Advanced Google Services](https://developers.google.com/apps-script/guides/services/advanced#enable_advanced_services) で Drive API を有効にします。

## 3. サンプルスクリプト

スクリプトエディタへ下記のスクリプトをコピーペーストして保存して下さい。

```javascript
function myFunction() {
  // 1. Create new Google Slides with the custom page size. This is used as a temporal file.
  const width = 200;
  const height = 200;
  const object = {
    title: "temp",
    width: { unit: "pixel", size: width },
    height: { unit: "pixel", size: height },
  };
  const presentationId = DocsServiceApp.createNewSlidesWithPageSize(object);

  // 2. Create a sample shape to Google Slides.
  const s = SlidesApp.openById(presentationId);
  const slide = s.getSlides()[0];
  slide.getBackground().setTransparent();
  const obj = slide
    .insertShape(SlidesApp.ShapeType.HEART)
    .setWidth(130)
    .setHeight(130)
    .alignOnPage(SlidesApp.AlignmentPosition.CENTER);
  obj.getFill().setTransparent();
  obj.getBorder().setWeight(10).getLineFill().setSolidFill("#ff0000");
  s.saveAndClose();

  // 3. Export Google Slides as a PNG data with the alpha channel.
  const url = `https://docs.google.com/feeds/download/presentations/Export?id=${presentationId}&exportFormat=png`;
  const blob = UrlFetchApp.fetch(url, {
    headers: { authorization: "Bearer " + ScriptApp.getOAuthToken() },
  }).getBlob();

  // 4. Put the created image to Google Spreadsheet.
  const spreadsheetId = "###"; // Please set the Spreadsheet ID.
  const sheetName = "Sheet1";
  const sheet = SpreadsheetApp.openById(spreadsheetId).getSheetByName(
    sheetName
  );
  sheet.insertImage(blob, 2, 2);

  // 5. Remove the Google Slides.
  DriveApp.getFileById(presentationId).setTrashed(true);
}
```

このスクリプトを実行すると、上記のデモンストレーションのような結果を得ることができます。

例えば、今の場合、下記のスクリプトを使用して既存の Google Slides も使用可能です。

```javascript
function myFunction2() {
  const presentationId = "###"; // Please set the Google Slides ID.
  const spreadsheetId = "###"; // Please set the Spreadsheet ID.
  const sheetName = "Sheet1";

  const s = SlidesApp.openById(presentationId);
  const slide = s.getSlides()[0];
  slide.getBackground().setTransparent();
  s.saveAndClose();
  const url = `https://docs.google.com/feeds/download/presentations/Export?id=${presentationId}&exportFormat=png`;
  const blob = UrlFetchApp.fetch(url, {
    headers: { authorization: "Bearer " + ScriptApp.getOAuthToken() },
  }).getBlob();

  const sheet = SpreadsheetApp.openById(spreadsheetId).getSheetByName(
    sheetName
  );
  sheet.insertImage(blob, 2, 2);
}
```

英語版は[こちら](https://github.com/tanaikech/Creating-PNG-Image-with-Alpha-Channel-using-Google-Apps-Script)です。