PhotoshopのJavaScript(ExtendScript)でファイルを一括処理するためのライブラリを書いた


ちょっと前に書いた。

https://github.com/hanamura/bulk.jsx

簡単な画像の一括リサイズ・調整なんかでたまにExtendScriptを使うんだけど、本質的な処理よりも入出力が何かと面倒な感じがあった。
なのでそれを改善しようというのが一番の目的。

サンプル

bulk(Folder.selectDialog('Source folder.'), {filePattern: /\.(jpg|jpeg)$/i})
    .mode({
        mode: ChangeMode.RGB
    })
    .resize({
        type: 'fit',
        width: 1000,
        height: 1000,
        expand: false
    })
    .jpg({
        dest: Folder.selectDialog('Destination folder.'),
        filename: '<%= bulk.pad(index + 1, 3)
 %>-<%= basename %>.jpg',
        overwrite: 'ask',
        quality: 80
    })
    .exec();

という感じに書くと、ソースフォルダ選択してフォルダ内の全てのjpg/jpeg拡張子のついたファイルを対象に↓のような処理をする。

  • カラーモードをRGBに
  • 長い方の辺を1000pxにアスペクト比キープしてリサイズ(ただし元画像がその大きさに満たない場合に拡大することは避ける)
  • ウェブ用JPEG(クオリティ80)で保存先として選択したフォルダ内に保存
    • ファイル名は、元が「hello.jpg」だったら「001-hello.jpg」というように連番に
    • 既に同名のファイルが場合があった場合は確認のダイアログを出す

ちなみにFolderとかChangeModeはExtendScript側のAPIなので、ExtendScript Toolkitってアプリ起動してヘルプを見ると分かる。

入力

bulk()の第一引数にFolderオブジェクトを渡すのが一般的な使い方だと思うけど、bulk('/Users/username/images')みたいに絶対パスを表す文字列も渡せる。

(スクリプトファイルからの相対パスもサポートしたかったけど、エントリーポイントになってるファイルのパスを取得する方法が見つからなかった。知ってたら教えてほしい)

bulk()の第二引数はオプション。例えばbulk(src, {deep: false})とするとフォルダ直下のファイルだけが対象になる。上記サンプルではfilePatternに正規表現オブジェクトを渡してるけど、↓みたいにfunctionでもOK。

bulk(src, {filePattern: function(file) {
    // fileにはFileオブジェクトが渡ってくる
    // 1,000,000 bytes 未満のファイルのみ対象にする
    return file.length < 1000000;
}})
...

出力

とりあえず以下のメソッドを用意してある。

  • .jpg() - ウェブ用JPEGで保存
  • .png() - ウェブ用PNGで保存
  • .export() - エクスポート

.jpg().png().export()のラッパー。

destにFolderオブジェクト、filenameにテンプレート文字列を渡すケースが多い。

destに何も渡さないと元ファイルと同じフォルダが対象になる。

bulk(src, options)
    ...
    .jpg({
        filename: '<%= basename %>-resized.jpg'
    })
    ...

元ファイルを含むフォルダに対する相対パスも指定できる。

bulk(src, options)
    ...
    .jpg({
        dest: '../path',
        filename: '<%= basename %>-resized.jpg'
    })
    ...

テンプレートも使える。

bulk(src, options)
    ...
    .jpg({
        dest: '../<%= doc.width < doc.height ? "portrait" : "landscape" %>',
        filename: '<%= basename %>-resized.jpg'
    })
    ...

filenameを指定しないと元ファイルと同じ名前になる。フォルダだけ変更して名前はそのままにしたい場合は指定しなければいい(ただし拡張子も変わらないので注意)。

bulk(src, options)
    ...
    .jpg({
        dest: '../path'
    })
    ...

テンプレート文字列はunderscore_.template()を使っていて、引数にはbulk.DocInfoオブジェクトってのが渡ってくるようになってる。元ファイルの名前とか連番とかDocumentオブジェクトとかにもアクセスできる。

例えば'<%= basename %>-<%= doc.width %>x<%= doc.height %>.jpg'とすると、hello.jpghello-1000x750.jpgみたいなる。
ユーティリティ関数としてbulk.pad()があるので、'<%= bulk.pad(index + 1, 3) %>.jpg'001.jpg002.jpg…とできる。

タスク

リサイズとかクロップとか最小限だけ用意してある。
上記の出力メソッドもタスクなので出力変えたければ追加すればいい。

jQueryっぽく、.fnにfunctionを追加してプラグイン的にタスクを増やせるようにしてみた。
あるいは、再利用とかどうでもよければ.push()にfunctionを渡して即席でタスクを作ってもOK。そのままチェインできる。

bulk(src, optinos)
    .push(function() {
        // thisはbulk.DocInfoオブジェクト
        // this.docはDocumentオブジェクト
        // レイヤーをフラットにする
        this.doc.flatten();
    })
    .resize(...)
    ...

詳しくはREADME参照

https://github.com/hanamura/bulk.jsx