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 を作成したこと。
  • このライブラリのcreateNewSlidesWithPageSizeメソッドでは、ページサイズを指定して Google Slides を作成することができます。これは現行の Google Apps Script のメソッドや Google APIs ではできません。
  1. 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 としても出力することが可能であることを確認しました。これもまた他で応用することができそうに思います。
  1. 手動で Google Slides のスライドの背景を透明にするか、SlidesApp.openById(presentationId).getSlides()[0].getBackground().setTransparent()のスクリプトを使ってスライドの背景を透明にした状態で、PNG として出力すると、透明の背景を維持した状態で PNG データを作成できることが分かったこと。

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

デモ

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

流れ

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

  1. Google Slides を指定したサイズで作成する。
  • これはテンポラルファイルとして使用します。
  1. Google Slides の背景を透明にします。

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

  • この場合、最初の 1 ページ目を使用します。
  1. PNG の mimeType で Export のエンドポイントを使ってデータを出力します。

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

使用方法

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

1. Google Apps Script library

Google Apps Script library DocsServiceAppをインストールします。ライブラリのプロジェクトキーは、108j6x_ZX544wEhGkgddFYM6Ie09edDqXaFwnW3RVFQCLHw_mEueqUHTWです。リポジトリは、こちらです。

2. Drive API

Advanced Google Services で Drive API を有効にします。

3. サンプルスクリプト

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

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 も使用可能です。

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);
}

英語版はこちらです。