Googleドライブ内の画像からスライドショーを作成


# この記事は

Googleアカウントは配布されていて授業支援ソフトがない学校にいるため、
Gas を使って授業内外で効率化を図っている自分に向けて（備忘録）
基本的に先人方のアイディアをコピー&ペーストしているので、不適切な点があればご指摘いただきたい。

# 実現したいこと
　・Googleドライブ内にまとめた画像でスライドショーを作成したい
　・ある程度順序を調整したい

#### スプレッドシートのイメージ
![シートのイメージ.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2779851/bd68344f-e09d-313d-9fd5-948e67c5bbba.jpeg)

# 実際のコード
```java:
/**
 * 機能が３つ
 * ①ドライブ内の画像を順序指定なしで張ったスライド作成（デフォルトは最終更新日順らしい）
 * ②ドライブ内の画像をシート上に縮小表示
 * ③上記②でソートされた画像を上から順に張ったスライド作成
 */

function onOpen() {
  let sheet = SpreadsheetApp.getActiveSpreadsheet();
  let sht = sheet.getSheetByName('設定');
  
  //初期値設定
  sht.getRange('C2').setValue('例）https://drive.google.com/drive/folders/~~~');
  sht.getRange('C4').setValue('例）https://drive.google.com/drive/folders/~~~');
  sht.getRange('B2').setValue('');
  sht.getRange('B3').setValue('無題のスライドショー');
  sht.getRange('B4').setValue('');
  sht.getRange('B10').setValue('');
  sht.getRange(13,1,sht.getLastRow(),4).clearContent();

  //メニュー追加
  sheet.addMenu('スクリプト実行', [  // メニューの表示名
      {name: '画像を最終更新日時順に貼る', functionName: 'insertImageFromDrive'}, // メニューに追加するボタン
      {name: '縮小画像を表示する', functionName: 'getFileListInFolder'}, // メニューに追加するボタン
      {name: '画像を指定した順でスライド作成', functionName: 'insertImageWithOrder'} // メニューに追加するボタン
    ]); 
}


function insertImageFromDrive() {
  //立ち上げたスプレットシートの設定
  const sheeets = SpreadsheetApp.getActiveSpreadsheet();//現在動作しているスプレッドシートを設定
  const sheetData = sheeets.getSheetByName('設定').getDataRange().getValues();//今回は方法を変えてシートを指定してみました。
  
  //設定（スプレッドシートより読み込み）
  const strTextImg = sheetData[1][1];
  const strTextSave = sheetData[3][1];
  const imgDriveID = strTextImg.split("/folders/")[1];
  const fileName = sheetData[2][1];
  
  // フォルダ、ファイルを取得
  const folder = DriveApp.getFolderById(imgDriveID);
  let files = folder.getFiles();

  //Googleスライドを新規作成
  const preso = SlidesApp.create(fileName);
  const presentation = SlidesApp.openById(preso.getId());

  let slide1 = presentation.getSlides()[0];//スライドの1ページ目を指定
  var id = slide1.getShapes()[0].getObjectId();//　シェイプの取得
  var shape = presentation.getPageElementById(id).asShape();
  shape.getText().setText(fileName);

  // ファイルをソートする必要あり？
  // https://www.ka-net.org/blog/?p=12473

  // ファイルを取り出し終わるまでループ
  while (files.hasNext()) {

    // ファイルを取得
    let file = files.next();

    // MIMEタイプがimageではないものは処理しない
    if(!file.getMimeType().match(/image/i)){
      continue;
    }

    // 画像のバイナリを取得
    let image_blob = file.getBlob();

    // スライドを追加する
    let slide = presentation.appendSlide(SlidesApp.PredefinedLayout.BLANK);

    try{
      // 画像をスライドに追加する
      slide.insertImage(image_blob);
    }catch(e){
      Logger.log(e.message + file.getName() + file.getMimeType());
    }
    // 追加した画像を取得して、スライド中央に配置する
    let image_object = slide.getImages()[0];
    image_object.alignOnPage(SlidesApp.AlignmentPosition.HORIZONTAL_CENTER).alignOnPage(SlidesApp.AlignmentPosition.VERTICAL_CENTER);

  } 

  //移動処理
  let thisSlide = DriveApp.getFileById(preso.getId());

  try{
    const saveFolderID = strTextSave.split("/folders/")[1];
    const saveFolder = DriveApp.getFolderById(saveFolderID); //保存先
    thisSlide.moveTo(saveFolder);
  }catch(e){
    Logger.log("保存先が不明なのでマイドライブに保存:" + e.message);
  }
  
  //移動先をスプレッドシートに貼り付け
  let url = thisSlide.getUrl();
  sheeets.getRange('B10').setFormula('=HYPERLINK("'+ url + '","' + url + '")');

}

function getFileListInFolder() {
  //開いているシートを取得
  //const sheeets = SpreadsheetApp.getActiveSpreadsheet();//現在動作しているスプレッドシートを設定
  const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('設定');
  const sheetData = sheet.getDataRange().getValues();//シートに入力されたデータを取得
  
  //設定（スプレッドシートより読み込み）
  const strTextImg = sheetData[1][1];
  const stropenById = strTextImg.split("/folders/")[1];
  
  const folder = DriveApp.getFolderById(stropenById);
  const folderFiles = folder.getFiles();
  let allFiles = [];
  while(folderFiles.hasNext()) {
    let tempFile = [];
    let fileIterator = folderFiles.next();    
    
    // MIMEタイプがimageではないものは処理しない
    if (!fileIterator.getMimeType().match(/image/)) {
      continue;
    }
    
    //ファイル情報取得
    let fileName = fileIterator.getName();
    let fileId = fileIterator.getId();
    let file = DriveApp.getFileById(fileId);    
    //共有設定
    file.setSharing(DriveApp.Access.ANYONE_WITH_LINK, DriveApp.Permission.VIEW);
    //共有リンクの取得
    //let shareUrl = file.getUrl(); 使わないかな
    // image関数で呼び出すため、数式を組み立てる
    let formula = '=image("https://drive.google.com/uc?export=download&id=' + fileId + '")';


    tempFile.push(fileName);
    tempFile.push(formula);
    //tempFile.push(shareUrl); //URLより、ファイルIDの方が流用できるのかな
    tempFile.push(fileId);
    allFiles.push(tempFile);  
  }
  // ソートは必要ないかな
  //  allFiles.sort(function(a,b){return(a[0] - b[0]);});
  
  let numRow = allFiles.length;
  let numCol = allFiles[0].length;
  
  sheet.getRange(13,2, numRow, numCol).setValues(allFiles);
}

function insertImageWithOrder() {
  //立ち上げたスプレットシートの設定
  //const sheeets = SpreadsheetApp.getActiveSpreadsheet();//現在動作しているスプレッドシートを設定
  const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('設定');
  const sheetData = sheet.getRange(1,1,4,2).getValues();//入力された値を取得
  const imageData = sheet.getRange(13,4,sheet.getLastRow()-12).getValues(); //ソートされた画像IDを取得
  
  //設定（スプレッドシートより読み込み）
  //const strTextImg = sheetData[1][1]; //画像IDがあるからいらない
  const strTextSave = sheetData[3][1];
  //const imgDriveID = strTextImg.split("/folders/")[1];
  const fileName = sheetData[2][1];
  
  //Googleスライドを新規作成
  const preso = SlidesApp.create(fileName);
  const presentation = SlidesApp.openById(preso.getId());

  let slide1 = presentation.getSlides()[0];//スライドの1ページ目を指定
  let id = slide1.getShapes()[0].getObjectId();//　シェイプの取得
  let shape = presentation.getPageElementById(id).asShape();
  shape.getText().setText(fileName);

  // ファイルをソートする必要あり？
  // https://www.ka-net.org/blog/?p=12473

  // ファイルを取り出し終わるまでループ
  for (let fileId of imageData) {

    let file = DriveApp.getFileById(fileId);

    // 画像のバイナリを取得
    let image_blob = file.getBlob();

    // スライドを追加する
    let slide = presentation.appendSlide(SlidesApp.PredefinedLayout.BLANK);

    try{
      // 画像をスライドに追加する
      slide.insertImage(image_blob);
    }catch(e){
      Logger.log(e.message + file.getName() + file.getMimeType());
    }
    // 追加した画像を取得して、スライド中央に配置する
    let image_object = slide.getImages()[0];
    image_object.alignOnPage(SlidesApp.AlignmentPosition.HORIZONTAL_CENTER).alignOnPage(SlidesApp.AlignmentPosition.VERTICAL_CENTER);

  } 

  //移動処理
  let thisSlide = DriveApp.getFileById(preso.getId());

  try{
    const saveFolderID = strTextSave.split("/folders/")[1];
    const saveFolder = DriveApp.getFolderById(saveFolderID); //保存先
    thisSlide.moveTo(saveFolder);
  }catch(e){
    Logger.log("保存先が不明なのでマイドライブに保存:" + e.message);
  }
  
  //移動先をスプレッドシートに貼り付け
  let url = thisSlide.getUrl();
  sheet.getRange('B10').setFormula('=HYPERLINK("'+ url + '","' + url + '")');

}
```

## 設定関係
・Slide と Drive の[サービスを追加][link-1]（お約束的な）

[link-1]:https://takake-blog.com/gas-new-editor/

# 自分なりに工夫したところ
・gasを編集できない同僚のためにスプレッドシート上で操作を簡潔できるようにした。
・画像の表示順序を指定することをシート上で手動にした。
　※getFilesの後にファイル名でソートする機能も考えたが、ファイル名を設定しておかないといけない手間が生まれるため（同僚にファイル名を一括で連番に編集できる人はいない）
・追記(2022/8/18) iPhoneで撮った画像は無効らしいので、スライドに画像追加するところで例外処理追加。

## 今後に向けて
・処理が重い。軽くできる手法を模索する。
・スライド作成時にgas 上でスライドショーの自動再生関連の設定をしたい。（実現可能か勉強中）

# 参考文献

[スライド操作関係は前回の自分の記事参照](https://qiita.com/daicheeze8/items/750b9cc27a1459839a28)
[【GASで整理】ドライブにある画像ファイルをシートに出力する](https://myfunc.jp/items/00127/index.html)
[尊敬している安藤昇先生のGIGAチャンネルから全般的にアイディアいただいています](https://www.youtube.com/c/gigachannel2020)