見出し画像

【GAS】Gメール投稿するだけでWEBページの掲載画像を更新できる、かんたん日報表示システム(6)~Googleドライブ上の画像ファイルを日報上に反映する~

グループ内のメンバーに対して画像を介して簡単な情報を共有するための、かんたんな日報ページをGAS(Google Apps Script)で作ってみました。

このシステムは、簡単な画像しか掲載できないものの、WEBページの様に固定ページから確認でき、かつ電子メール(あるいは他のメッセージアプリ)の様に管理者不在で情報をアップできる長所があります。

GASで作ったシステムですが、全体の概要はこちらで解説しています。


コードの解説については、以下の記事で途中まで解説しています。


上記で、ログイン画面やGメール投稿された画像を収集するコードを解説していますが、今回の記事では、収集した画像を日報のWEBページに自動掲載する部分をご解説します。

このシステムは、個人や小さなグループが内輪で使うことを前提にしたものです。Googleの無料サービスで手軽に始められる一方で、速度が遅く最小限の画像しか扱えないので、商用ベースには向きませんのでご注意ください。

Googleドライブ上の画像を一旦リスト化する

このシステムでは、日報の投稿者がGメールで添付画像を送ると、Gドライブの所定のフォルダに自動的にストックし、ここから最新の2画像をWEBページに掲載する様にしています。(単純化のため、日に1回の画像送信を想定しています)

この下に適当なフォルダを作ります
Gメールから収集した画像ファイルを、保存用フォルダの中に保存しています

本システムでは、これらのファイルを利用するために、一旦、ストックされたファイルのリストを予め用意したスプレッドシート上に自動作成して利用しています。

リストは以下の様なものです。左の列から、ファイル名、ファイルのURL、ファイルIDを示しています。Gドライブのファイルは、一旦この様な目録を作って利用することにしました。

用意したスプレッドシートに自動記入されたファイルリスト

以下は、上記のリストを自動作成するためのコードです。

  //保存フォルダを取得する|Googleドライブの★フォルダID★は各自のものを記入
  const 保存フォルダ = DriveApp.getFolderById('★フォルダID★');  

 // フォルダ内のファイルを取得します
  var ファイル群 = 保存フォルダ.getFiles();
  
  // ファイル変数から配列に追加します(最新ファイルが最初の要素になります)
  var 情報リスト = [];
  while(ファイル群.hasNext()) {
    var 仮配列 = ファイル群.next();
    情報リスト.push([仮配列.getName(), 仮配列.getUrl(), 仮配列.getUrl().slice(32,32+33)]);
  };


  //書き出しシートを取得
  var スプレッドシート = SpreadsheetApp.openById('★スプレッドシートID★');
  var 書き出しシート = スプレッドシート.getSheetByName('書き出しシート名');

  // 対象の範囲にまとめて書き出します
  var セル範囲 = 書き出しシート.getRange(1, 1, 情報リスト.length, 情報リスト[0].length);
  セル範囲.setValues(情報リスト);

コード中の変数は、解説のため漢字名称にしています(実際は英数字でないと動きません)

内容をかいつまんで解説します。

getFolderByIdで保存フォルダをフォルダIDを使って取得し、子関数 getFiles( ) を使ってフォルダ中のファイル群を取得します。

 保存フォルダ = DriveApp.getFolderById('★フォルダID★');
 var ファイル群 = 保存フォルダ.getFiles( )

・取得したファイル群は一種の配列データです。ここからファイル個々の情報にアクセスするために、.next( ) 関数を使って、1要素ずつ順にアクセスし、一旦仮保存します。

 var 仮配列 = ファイル群.next()

・ここから必要な情報だけを取り出した要素を作り、.push関数で、別の配列に1要素ずつ追加します。

 情報リスト.push(
   [ 仮配列.getName(),
    仮配列.getUrl(),
    仮配列.getUrl().slice(32,32+33)
   ]
 )

・最後に、必要な情報だけ保存したリストの中身をスプレッドシートの特定範囲に貼り付けて完了です。

 セル範囲.setValues(情報リスト)

こうして、リストがスプレッドシート上に作成されます。注意する点は、リストの並び順で、これはファイルがGドライブ内に保存された順になっている点です。

プログラムの簡単のため、この様な仕様にしましたが、投稿順になっていないため(保存時刻が新しいものが上です)、同時に沢山の投稿があると時系列が合わなくなる可能性があります。そのため、日報などの、1日に1回の投稿に限った用途とした次第です。

BASE64エンコードを利用してGドライブ上の画像をテンプレートに埋め込む


長くなりましたが、この後は、上記のリストの最新の画像(リストの最初の行とその次の行)をWEBページに自動埋め込みすれば、日報として表示されます。

ここで問題があります。

WEBページで画像を表示させる場合、<img>タグの中に画像のURLを表記(src=https://・・・)して表示させるのが一般的ですが、GASでGドライブ内の画像を扱う場合、上記の手法でGドライブ上のURLを記載しても、リンク切れ状態になって表示されません。(データを受ける前にレスポンスとして返してしまう様で、グレーの画面として表示されてしまいます)

そこでこのシステムでは、Gドライブ内の画像を表示させるのに、リンクを用いない「BASE64エンコード」という手法を利用します。

これは、ファイルのバイナリデータを6ビット(情報としては2の6乗なので64種類です)ごとに対応する文字に変換することで、バイナリデータを文字列に変換する手法です。出来た文字列は、通常の文字列としてプログラム内で扱えますので、HTMLコード内で<img src=文字列>などのコードを書くことで表示が可能です。

この方法は時間が掛かるのが難点ですが、画像のURLがWEBページ内に含まれないので、セキュリティーが高い(かもしれない)メリットもあります。

BASE64エンコードの詳細は、以下の記事をご覧ください。


テンプレートに最新の2画像を埋め込んでレスポンスする

本システムでBASE64エンコードを実装するには、GASのスクリプトとテンプレートで、それぞれ対応するコードを記述します。

スクリプトでの記述

getBytes()関数とbase64Encode()関数を使って以下の様に実装します。

・ファイル.getBlob().getBytes()
 
ファイルからバイナリデータを取り出します。

・Utilities.base64Encode(バイナリデータ)
 上記で得られたバイナリデータをBASE64エンコードした文字列に変換します。

具体的なコードを記します。スクリプト中では、一連のコードはユーザ定義関数getBae64DATAonCell()として記述しています。

//=====セル上のファイルIDを読み込みBase64エンコードする関数======
function getBae64DATAonCell(スプレッドシートID,シート名,行,列) {

  var 対象ファイル = SpreadsheetApp.openById(スプレッドシートID);

  //対象シートをシートの名前を指定して取得
  var 対象シート = 対象ファイル.getSheetByName(シート名);

  var ファイルID = 対象シート.getRange(行,列).getValue();
 //Gドライブから、ファイルIDでファイルを取得
  const ファイル = DriveApp.getFileById(ファイルID);
  
 //バイナリデータを取得
  const バイナリデータ = ファイル.getBlob().getBytes();
 
 //BASE64エンコードで文字列に変換
   return Utilities.base64Encode(バイナリデータ);
}

このgetBae64DATAonCell関数は、引数として、スプレッドシートID、対象シート、セルの行と列を指定すると、対象セルに記述されたファイルIDを参照して対象ファイルをBASEエンコードした結果を返す様にしています。

注意)これらの関数はGoogle Apps Scriptのスクリプト中で定義されているものです。JavaScriptに似た言語なので混同していまいがちですが、GAS以外の環境では使える保障がない関数なので注意しましょう。

テンプレートでの記述

上記で定義した関数getBae64DATAonCell()を日報の表示に利用するには、テンプレート中に、<script>セクションを設け、この中で呼び出して使います。

テンプレート(ユーザのブラウザに読み込まれて作動します)からスクリプトで記述した関数(Gドライブ内で作動します)を呼び出すには、google.script.run()関数を使います。

これはGAS固有の便利な関数で、子関数としてスクリプト内の関数を指定するだけで、Gドライブにアクセスし、スクリプト内の関数を作動させ、結果を受け取ることができます。

注意)この関数はGAS、つまりGoogle Apps Scriptのテンプレートで使う関数として定義されているものです。文法が同じなので混同しがちですが、テンプレート以外の、一般のHTMLファイルのJavaScriptでは使えない関数です。

実際のコードを以下に示します。

<!--画像要素を定義---->
      <div>
        <p>本日の報告画像です</p>
        <img  id="myIMG0" > 
      <div>

     
・・・・
<script>

 //強制実行する無名関数
   (function() {

 //スクリプト関数の実行1
      google.script.run
        //成功時の処理:ソースとしてBASE64エンコードされた文字列(res)を設定
        .withSuccessHandler(res => {
          var 画像要素= document.getElementById("myIMG0");
          画像要素.setAttribute("src", "data:image/png;base64," + res);
        })
        //実行する関数|★スプレッドシートID★は各自のものを記入
        .getBae64DATAonCell('★スプレッドシートID★','投稿一覧',1,3);

  })();
  </script>

短いコードですが、内容をご説明します。

実行コードは無名関数として記述する


<script>セクションに記述するコードは、一般的には関数として記述する必要があります(一般のHTMLコードも同じ)。したがって、コードを作動させるには、HTMLコードのボタン要素などから関数を呼び出す仕掛けを作る必要があります。

しかし今回の処理は、ボタンなどで呼び出しをせずWEBページを開いたタイミングで即時に実行するものです。この様な場合は、コードを「無名関数」として記述します。

構文は以下の様で、この記述をしておくと、関数内のコードが即時実行されます。

( function( ) {コード} ) (  );

前後のカッコがありますが、これは本来の無名関数の表現方法である以下の2行を短縮表現した表現です。返り値を保存するための余計な変数を設定しなくて済みます。

var 返り値 = (function( ) { });
返り値( );

HTML本文で画像要素を用意する


上記の無名関数を働かせる前提として、HTMLコード内で、中身が空の画像要素<img>を用意しておきます。ID名を「id="myIMG0"」と指定して、後からの要素選択を容易にしています。

<img id="myIMG0" > 

画像ファイルをBASE64エンコードする

続いて、google.script.run()関数を以下の様に使い、画像ファイルをBASE64エンコードします。

google.script.run
 .withSuccessHandler(res => {
  ・・説明は後述・・
 })
 .getBae64DATAonCell(セル番地を指定);

構文が少し分かりにくいですが、一番最後の子関数.getBae64DATAonCell()が、さきほど設定したスクリプトの関数です。


BASE64エンコードした結果を画像要素にセットする


先のコードでgoogle.script.runの子関数.withSuccessHandlerres=>(・・・))部分には、「関数がうまく作動したら、返り値resを使っておこなう処理」を記述します。(これも少し分かりにくい構文です)

上記の返り値はBASE64エンコードしたテキストですが、これを画像ファイルにセットするには、setAttribute("src", "data:image/png;base64,文字列”)という構文を使います。

具体的には以下の様に記述します。

  var 画像要素= document.getElementById("myIMG0");
  画像要素.setAttribute("src", "data:image/png;base64," + res);

こうして、WEBページにGドライブ上の画像ファイルが表示される様になります。

リストの最上位とその次の画像ファイルで同じ処理を繰り返すことで、最新の2つの投稿画像が以下の様に表示されます。


全体の実装コードは、次の記事でご説明します。



前の記事はこちら


この記事が気に入ったらサポートをしてみませんか?