【GAS】複数の名刺サイズ画像をそれぞれA4用紙に10枚割付したPDFを作る方法

GAS

どうもcoto.です。
唐突ですが名刺サイズのカードを作りたいときってありませんか?メッセージカードとか。

1枚だけじゃなくて同じものを20枚くらい作りたい場合、A4用紙に10枚並べて印刷しますよね。この作業、専用ソフト使ってぽちーなら良いんですが、ちまちま手で並べなきゃいけないこと意外に多いのでは?たくさんの画像をそれぞれ並べなきゃーなんてことになった日にはもう、ね。

今回はそんな時のためのGASを組みました。

やりたいこと

できるだけ手間なく、できればボタン1つで↓をやりたいんです。

必要なものと準備

① 10枚割付したい画像のファイル名、大きさ(縦長、横長そろっている場合、大きさは不要です。)
今回は例としてUkiyoeStockさんから画像をお借りしました。

PDF化させたい画像

画像サイズがバラバラで1つ1つ調べるのが大変な場合は以前ご紹介したページを参照してください。

② ①を格納しておくGドライブ上のフォルダ(フォルダ名:変換前フォルダ)
③ 自動出力されるPDFが格納されるGドライブ上のフォルダ(フォルダ名:PDF格納フォルダ)

②と③のフォルダ

④ スプレッドシート
タブは3つで、1つ目は情報を入力するための「入力用」、2つ目と3つ目は画像を並べてPDFをエクスポートするための「横型」と「縦型」。実際の運用時は「入力用」だけ操作し、「横型」と「縦型」は初回に作成したらその後触れることはないと思います。

「横型」と「縦型」はそれぞれ↓のようにしておきます。
セルの大きさを名刺サイズにしますが、現在スプレッドシートではピクセル指定しかできないので345×209にします。(見出し部分を右クリック>単一列のサイズを変更>サイズ指定)

A1セル以外の9つのセルは「=A1」とします。
また、必要のない行や列はPDFエクスポートの際邪魔になるので削除しておきます。

コード

const sheetEnter   = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('入力用');     //シート'入力用'を取得
const sheetHor     = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('横型');      //シート'横型'を取得
const sheetVer     = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('縦型');      //シート'縦型'を取得
var   rowEnter  = sheetEnter.getLastRow();           //シート'入力用'の最終行を取得

var   FolderEnt = DriveApp.getFolderById('①●●●●●●●●●●●●●●●●●●●●●');  //変換前フォルダを指定
var   FolderOut = "②●●●●●●●●●●●●●●●●●●●●●";  //pdf格納フォルダを指定


//▼▼▼縦横判定▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼
function aspect(){

  let   sizeEn    = sheetEnter.getRange("B6:D" + rowEnter).getValues();   //入力シートのB-D列を取得
	for (let i = 0; i < sizeEn.length; i++){ 
		if(sizeEn[i][0] > sizeEn[i][1] ){ sizeEn[i][2] = "横";}
		if(sizeEn[i][0] == sizeEn[i][1] ){ sizeEn[i][2] = "横";} 
		if(sizeEn[i][0] < sizeEn[i][1] ){ sizeEn[i][2] = "縦";}    
	}
  sheetEnter.getRange("B6:D" + rowEnter).setValues(sizeEn); 
}


//▼▼▼自動エクスポート▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼
function autoEx(){

  var file_type  = sheetEnter.getRange("B3").getValue();  //拡張子を取得
  var image      =  sheetEnter.getRange("A6:D" + rowEnter).getValues();   //入力シートのA-D列を取得

	for (let i = 0; i < image.length; i++){      //指定ファイル分繰り返す
        var file_name = image[i][0] + "." + file_type;
        var file      = FolderEnt.getFilesByName(file_name).next();

        var file_blob     = file.getBlob();   //ファイルblobの取得

        //base64に変換(blobをこの形式にしないとセル内挿入できない)
        var c_type = file_blob.getContentType();
        var base64 = Utilities.base64Encode(file_blob.getBytes());
        var data   = "data:" + c_type + ";base64, " + base64;

        var EnImage  = SpreadsheetApp.newCellImage().setSourceUrl(data).build();

		if(image[i][3] == "横" ){ 
      sheetHor.getRange("A1").setValue(EnImage);
      var shId = "③●●●●●●●";  //横型タブのID

      createPdf(FolderOut, shId, image[i][0]);    //PDFを作成して保存する

    }else{
      sheetVer.getRange("A1").setValue(EnImage);
      var shId = "④●●●●●●●";  //縦型タブのID

      createPdf(FolderOut, shId, image[i][0]);    //PDFを作成して保存する
    }


	}
}


//▼▼▼PDFエクスポートの書式設定▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼
function createPdf(folderId, shId, fileName){
  let baseUrl = "https://docs.google.com/spreadsheets/d/⑤●●●●●●●●●●●●●●●●●●●/export?gid="   + shId;

  //PDFのオプションを指定
  let pdfOptions = "&exportFormat=pdf&format=pdf"
              + "&size=A4"               //用紙サイズ (A4);

	       if(shId == "③●●●●●●●" ){ 
               pdfOptions += "&portrait=true";         //用紙の向き true: 縦向き / false: 横向き
         }else{
               pdfOptions += "&portrait=false";        //用紙の向き true: 縦向き / false: 横向き
         }
      pdfOptions += "&fitw=true"  //ページ幅を用紙にフィットさせるか true: フィットさせる / false: 原寸大
               + "&top_margin=0" //上の余白
               + "&right_margin=0" //右の余白
               + "&bottom_margin=0" //下の余白
               + "&left_margin=0" //左の余白
               + "&horizontal_alignment=CENTER" //水平方向の位置
               + "&vertical_alignment=MIDDLE" //垂直方向の位置
               + "&gridlines=false" //グリッドラインの表示有無
               + "&fzr=false" //固定行の表示有無
               + "&fzc=false" //固定列の表示有無;

  let url = baseUrl + pdfOptions;     //PDFを作成するためのURL
  let token = ScriptApp.getOAuthToken();    //アクセストークンを取得する
  let options = {     //headersにアクセストークンを格納する
    headers: {  'Authorization': 'Bearer ' +  token    }
  };
  let blob = UrlFetchApp.fetch(url, options).getBlob().setName(fileName + '.pdf');  //PDFを作成する
  let folder = DriveApp.getFolderById(FolderOut);   //PDFの保存先フォルダー

  folder.createFile(blob);   //PDFを指定したフォルダに保存する
}

コード内の①~⑤の「●●●●●●●●●●●」部分をスプレッドシートやフォルダのIDに変えれば動作します。

①=元の画像を格納しているフォルダID
②=エクスポートしたPDFを格納するフォルダID
③=「横型」タブのID(URLの最後にある10桁くらいの数字)
④=「縦型」タブのID
⑤=スプレッドシートのID

ちなみに入力用タブのボタンに紐づけるスクリプトはそれぞれ、「縦横判定」ボタン→aspect、「PDFエクスポート」ボタン→autoEx です。

注意

コードのミスではないと思うのですが、実は7~8ファイルずつぐらいしかエクスポートできません…。GASの制限時間でもなく、その日によるのでサーバーの問題かな。手で全部やるよりは100倍くらい早いのでまあいっかという感じで原因究明せず放置してます。すみません。何かわかればまた。

御託

メッセージカード、ショップカードが10枚単位くらいで欲しいけど、業者に頼むほどではない。お金はかけたくない。というときにぜひ。

一番使うことが多いので名刺サイズで作りましたが、同じ方法でいろんなサイズの割付ができると思います。なにかのお役に立てば。