Photoshopをスクリプトで自動化

ある程度決まったフォーマットのバナーや広告。テキストや写真だけ更新して毎月(毎週)膨大な数のグラフィックを納品するのは、よくある仕事。

クライアントからエクセルで支給されて行う、膨大な画像作成作業。コピペじゃ効率が悪すぎる、とほほ。

それならスクリプトで自動化しよう。大まかなスクリプトの流れと、実際にエクセル(MacならNumbers)からデータをPhothoshopの画像にするための具体的な手順を記載。

大量のバナーや広告を数秒で、コピペミスゼロで作ろう!

準備しておくもの

  • 配置するテキストをエクセルにひとまとめ
  • (必要なら)配置する画像
  • 元となる定形のPSDファイル

エクセルは決まった並びで作成するようにする。scriptで「配列」として読み込む為だ。

配置する画像など外部ファイルがあればファイル名も正しく記載しておく。

完成したスクリプトの操作手順

  1. 作成する画像の中に、画像を配置する場合その画像をまとめて一つのフォルダに入れておく
  2. エクセルの画面をコピー
  3. Photoshopからスクリプトを起動
  4. 入力フォームにペースト
  5. 配置する画像のフォルダを指定
  6. 保存するフォルダを指定
  7. 大量のPSDが出来上がる!

プログラムの大まかな流れ

  1. 入力された表を1行ずつ分けて配列化
  2. さらにタブ区切りで分けて配列化
  3. 実行されるスクリプト自身のディレクトリを取得
  4. 配置するフォルダを指定
  5. 保存するフォルダを指定
  6. forで行の分だけ処理を繰り返す

エクセルの書き方

1行に1生成物(画像)の要素を記載しておく。行の数だけforで処理を繰り返す。1行=1セット(画像)。

1行の要素から複数の画像を作ることもできる。

商品名、価格、発売日、画像を記載した画像を作成する場合、各要素の数だけ列に記入する。

複数行あればその数分だけの画像が生成されるようになる。

スクリプトの詳細

ディレクトリの取得/指定

var SELF = File($.fileName).parent.fsName;
//スクリプト自身の絶対パスを取得し"SELF"に格納

var inputDir = Folder.selectDialog (["読み込む画像のフォルダを\n指定してください"]).fsName;
//"inputDir"に読み込むフォルダのパスを格納

var outputDir = Folder.selectDialog (["保存先を指定してください"]).fsName;
//"OutputDir"に保存先のディレクトリのパスを格納 

まずはディレクトリについて。スクリプト自身のディレクトリを取得するのと、任意のフォルダのディレクトリを取得するための二つの関数を上記に記載した。

読み込み用と保存用のフォルダとして指定しているが、要は任意のディレクトリを指定しているだけ。適宜運用に合わせてディレクトリのパスを取得すること。

エクセルをバラして配列の形にする

var text = prompt("配列の入力","ここにペースト");

var gyou = text.split(/\r\n|\n/);

for (var i = 0; i < gyou.length; i++){
    var koumoku = gyou[i].split('\t'); 
    //タブ区切りでスプリットする

prompt();でダイアログを出し、テキストエリアにエクセルの表をペーストする。

numbersでそのままコピペすると、セルはタブ区切りでクリップボードへ保存されているようだ。

そのため配列を作成する手順としては、最初に改行コードごとにリスト化。次にタブで分けてリスト化の二段階で行う。

入力されたtextは改行ごとに分けられ配列に。上記例では例えばgyou[0]なら1行目を取得する。

さらに行内のタブ区切りで要素を分けてkoumoku[0]など取得できる。

forでiの数だけ処理を繰り返す。gyou.length;により行の数を取得。行内のタブごとに分けて配列化。[0]とか[5]とか列の位置を指定してセルを取得できる。これらは行ごとに毎度行われる。

項目ごとに処理のセットを作成(テキストの処理)

        fileObj = new File(SELF+"/format_A.psd");
        open(fileObj);
        layObj = activeDocument.artLayers;
        layRef = layObj.add();
        layRef.kind = LayerKind.TEXT;
        layRef.textItem.contents =
        koumoku[0] //ゼロは配列の一番目をあらわす
        ;layObj = activeDocument.artLayers[
        koumoku[0] //レイヤー名を上と同じに
        ];layObj.textItem.font = "UDShinGoPro-Heavy";
        layObj.textItem.size = 90;
        saveUnit = preferences.rulerUnits;
        preferences.rulerUnits = Units.PIXELS;
        layObj = activeDocument.activeLayer;
        layX = parseInt(layObj.bounds[0]);
        layY = parseInt(layObj.bounds[1]);
        layObj.translate(-layX, -layY);
        x = 64;
        y = 36;
        layObj.translate(x, y);

あとは繰り返す処理を書いていくだけ。スクリプトファイルと同じディレクトリに、基本フォーマットとなるPSDを置いておく場合、上記で取得しておいたSELFが活きてくる。

項目が8つある場合はkoumoku[0]〜[7]を呼び出して処理する。

レイヤーにテキストとして打ち込んだり、ファイル名にしたりできる。

上記の例では基本フォーマットのファイルを開き、テキストレイヤーを指定のフォントとウェイトで作成し、配列から呼び出したテキストを流し込む。

フォントはポストスクリプト名で指定し、ウェイトやサイズ、色も指定できる。

そのレイヤーに名前をつけて指定した座標に移動する。

決まった位置に決まったフォントとサイズでエクセルの文字を流し込めるわけだ。

画像の場合

                //ここから 画像を開いてリサイズしてペーストするまでの作業を行う
                fileObj = new File(inputDir+"/"+koumoku[7]);
                open(fileObj);
                activeDocument.resizeImage(null,557);//高さを557にする場合
     activeDocument.selection.selectAll();
                activeDocument.activeLayer.copy();
                activeDocument.close(SaveOptions.DONOTSAVECHANGES);
                activeDocument.paste();

                //念のためアクティブレイヤーをスマートオブジェクト化
                function smartObj(){
                    var idnewPlacedLayer = stringIDToTypeID( "newPlacedLayer" );
                    executeAction( idnewPlacedLayer, undefined, DialogModes.NO );
                }
                smartObj()//上記で指定した関数スマートオブジェクト化を下記で実行
                //画像を移動させる
                preferences.rulerUnits = Units.PIXELS;
                offsetX = 64; // 右側からの位置(64 pixel)
                offsetY = 36; // 上側からの位置(36 pixel)
                docObj = activeDocument;
                layObj = docObj.activeLayer; // アクティブレイヤー
                w = docObj.width.value;
                h = docObj.height.value;
                x2 = parseFloat(layObj.bounds[2]);
                y1 = parseFloat(layObj.bounds[1]);
                layObj.translate(w-offsetX-x2, offsetY-y1);

inputDirに読み込んでおいた画像フォルダから、エクセルに記載のあった名前のファイルを指定。

スマートオブジェクト化したり、高さを指定し幅は成り行き、位置を座標で指定して移動させている。

最後にPSDファイルを保存

fileObj = new File(outputDir+"/"+koumoku[0]+"_format_A"+".psd");
                        psdOpt = new PhotoshopSaveOptions();
                        psdOpt.alphaChannels = false;
                        psdOpt.annotations = true;
                        psdOpt.embedColorProfile = false;
                        psdOpt.layers = true;
                        psdOpt.spotColors = false;
                        activeDocument.saveAs(fileObj, psdOpt, true, Extension.LOWERCASE);
                        activeDocument.close(SaveOptions.DONOTSAVECHANGES);

                        preferences.rulerUnits = saveUnit;
                        //ここまでformat_A.psdの処理

                        app.purge(PurgeTarget.ALLCACHES);//最後に念の為メモリクリアしてクリップボードをクリアに

最後にファイルの保存。outputDirで指定したフォルダにエクセルの項目名を付けてファイルを保存している。

保存のオプション(レイヤーの有無など)を必要なら指定して保存したら、念の為クリップボードを空にしておく。次の処理に支障が残らないように。

これでforを一周した。一周の中にサイズ違いのformat_B.psdやformat_C.psdなど幾つでもバリエーションを含めることができる。

行の数だけforを繰り返すので、バリエーションがいくつあっても行の中に含まれるセルの項目は同一になる。