Google Spreadsheet（スプレッドシート）を書式を維持しながら画像化して出力する

## この記事で分かること
スプレッドシートを
**・書式を維持しながら
・自動で（コピペなどの操作なしで）
・リアルタイムに反映させて**
画像として出力する方法

## 方法の概要

Spreadsheetから直接jpegなどの画像ファイルに出力することは無理なので、一旦**PDFに出力**してから、その**PDFのスクショをAPIで取得**するという方法をとります。
直接スクショを取ろうとするとなぜかリアルタイムな内容を反映できなかったため、一旦PDF出力するという回りくどいことをしています。

## 用意するもの
・Google Spreadsheet
・画像出力用のフォルダ(Google drive)
・API FLASHのアカウント(100枚/月までは無料で使えます。)

## 前準備
##### API FLASHに登録する
今回紹介する方法の肝となる**スクショ取得API**として、[API FLASH](https://apiflash.com/ "API FLASH")を使用します。
<details><summary>API FLASHの説明</summary>

API FLASHは、スクショしたいサイトのURLを投げると、そのサイトのスクショを返してくれるAPIで、拡大縮小の調節やスクショ箇所など柔軟な指定が可能で、100枚/月までは無料で使用できます。
他にもいくつかスクショAPIは存在しますので、要求する性能と枚数・予算に応じて検討してください。

</details>

リンク先からAPI FLASHに登録してログインし、Query Builderというタブに飛びます。
ここでAPIに投げる用のリンクを条件に応じて生成できます。

##### スクショを保存するためのフォルダを用意する
Googleドライブの任意の場所にフォルダを作り、フォルダのIDを控えておきます。
<details><summary>フォルダIDって何？</summary>

Googleドライブのフォルダのリンク構造はこんな感じになっています。
https://drive.google.com/drive/folders/フォルダID

/folders/以降の文字列がフォルダIDなので、これを控えておきましょう。

</details>

##### スクショしたいスプレッドシートを準備
今回準備したのはこんな感じのバイトのシフト表です。
![シフト表.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3086047/6eab8620-46e5-b31a-7b49-2de7021586c1.png)
H2セルにバイトの名前を入力すると、その人が入っている日だけ色が変わるように条件付き書式を設定しています。

## コード

```ruby:Spreadsheetの画像出力
function createIndividualPDF(){
  var sheetID = '出力したいスプレッドシートのID';
  var token = ScriptApp.getOAuthToken();
  var shiftSheets = SpreadsheetApp.openById(sheetID);
  var sheet = shiftSheets.getSheetByName('シフト表');
  var name = sheet.getRange(2,8).getValue();
  var pdf = createPDF(sheetID,token,sheet,name);
  return makeScreenShotFromFileID(pdf,name);
}

function createPDF(key,token,sheet,name){
  var folderId = '出力先のフォルダID';
  var folder = DriveApp.getFolderById(folderId);
  var today = Utilities.formatDate(new Date(), 'Asia/Tokyo', 'YYYYMMddhhmm');
  var gid = sheet.getSheetId();
  var url = "https://docs.google.com/spreadsheets/d/" + key + "/export?gid=" + gid + "&format=pdf&portrait=false&size=A4&gridlines=false&fitw=true";
  var pdf = UrlFetchApp.fetch(url, {headers: {'Authorization': 'Bearer ' +  token}}).getBlob().setName(name + '_' + today +".pdf");
  var file = folder.createFile(pdf);
  /*公開設定を「リンクから閲覧可能」にしてAPIがアクセスできるようにする*/
  var access = DriveApp.Access.ANYONE_WITH_LINK;
  var permission = DriveApp.Permission.VIEW;
  file.setSharing(access,permission);
  return file.getId();
}

function makeScreenShotFromFileID(fileID,name){
  var folderId = '出力先のフォルダID';
  var folder = DriveApp.getFolderById(folderId);
  var today = Utilities.formatDate(new Date(), 'Asia/Tokyo', 'YYYY-MM-dd');
  var image = UrlFetchApp.fetch('https://api.apiflash.com/v1/urltoimage?access_key=(API FLASHのアクセスキー)&quality=100&delay=10&crop=1200%2C200%2C1200%2C800&scale_factor=2&url=https://drive.google.com/file/d/' + fileID).getBlob()
  /*
    FLASH APIに渡すURLの簡単な説明
    quality:0-100の値を指定。
    delay:ページを開いてからのスクショまでの時間(秒)。　早すぎると真っ白になる。
    crop:スクショ範囲の指定。 今回は左から1200px,上から200px,幅1200px,高さ800pxの範囲を指定。スクショしたい領域に応じて調節。
    scale_factor:拡大倍率の指定。2倍程度にすると画質がかなり良くなる。
  */
  var file = folder.createFile(image).setName(today + '_' + name);
  /*アクセス権を変更するとLINE Messaging APIでの送信が可能になる*/
  var access = DriveApp.Access.ANYONE_WITH_LINK;
  var permission = DriveApp.Permission.EDIT;
  file.setSharing(access,permission);
}
```

## 実行結果
PDFとJPEG画像が出力されています。PDFが邪魔な場合は別のフォルダを指定しましょう。
![Calendar.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3086047/95275390-fc7e-00a4-b41a-f670bc3ddd84.png)
画質もまずまず。
![2022-12-30_田中.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3086047/4b14cfdc-9175-98ad-77a2-f26b6f672fd7.jpeg)
返り値としてファイルIDを取得すると、作成した画像をメールで送ったり、LINE Messaging APIと連携してLINE botからpush送信したりできます。めっちゃ便利。

## 注意点
出力したPDFを公開設定してAPIに投げるので、機密事項の取り扱いにはくれぐれも注意が必要です。