Photoshopでフォルダ内のファイルを一括処理させる

# やりたかったこと
フォルダ内にあるjpegファイルを一括でインポートし、インポートしたレイヤー群にいろんな処理を追加したかった。

なお、フォルダ内にあるJpegファイルを一括でレイヤーに追加するだけなら、Photoshop標準のスクリプト**Load Files into Stack.jsx**が存在する。

![script.png](https://qiita-image-store.s3.amazonaws.com/0/10770/00997b04-db6b-9d58-5e68-95954b7f1b52.png)

# スクリプトの編集
## 編集元ファイル
使える部分はそのまま使うということで、Load Files into Stack.jsxを編集していく。

Load Files into Stack.jsxは、たとえば下記のような場所にある。   

    C:\Program Files (x86)\Adobe\Adobe Photoshop CS6\Presets\Scripts\

## 編集箇所
ファイルをすべてレイヤーに読み込み終えた後に、追加スクリプトを記述する場合には、下記の場所を編集すればよい。

```javascript
loadLayers.stackLayers = function()
{
	var result, i, stackDoc = null;
	
	stackDoc = this.loadStackLayers();
	if (! stackDoc)
		return;
	
	// Nuke the "destination" layer that got created (M2HDR holdover)
	stackDoc.layers[this.pluginName].remove();
	
	// Stack 'em up.
	if (this.createSmartObject)
	{
		selectAllLayers( stackDoc );
		executeAction( knewPlacedLayerStr, new ActionDescriptor(), DialogModes.NO );
	}
    
    //下記に追加していく
    hoge();
    buf();
}
```

# おまけ
今回は、下記のような処理を追加してみました。

```javascript
loadLayers.stackLayers = function()
{
	var result, i, stackDoc = null;
	
	stackDoc = this.loadStackLayers();
	if (! stackDoc)
		return;
	
	// Nuke the "destination" layer that got created (M2HDR holdover)
	stackDoc.layers[this.pluginName].remove();
	
	// Stack 'em up.
	if (this.createSmartObject)
	{
		selectAllLayers( stackDoc );
		executeAction( knewPlacedLayerStr, new ActionDescriptor(), DialogModes.NO );
	}
    
    //回転＋透明度変更＋少しずつレイヤーをずらす
    autoRotate();
    // キャンバス全体を反転させる
    activeDocument.flipCanvas(Direction.HORIZONTAL);
    //逆順でレイヤーソート
    layerSort(false);
    //ガイド表示
    guideWrap("Vrtc",0);//左上
    guideWrap("Hrzn",0);//左上
    //サイズ指定して背景を追加
    convertLayerToBackground();
}
```
## 各スクリプトの内容
### autoRotate()
15000px×15000pxのキャンバスを想定し、各レイヤーを回転、半透明、さらに重ならないように移動させる。

```javascript
function autoRotate(){
  var docObj = activeDocument.artLayers;
  var ymax = 15000;
  var dx = 1000;
  var dy = 500;

  for (var i=0; i<docObj.length; i++)
  {
    if (!docObj[i].isBackgroundLayer)
    {
      docObj[i].rotate(90);
      docObj[i].opacity = 40.0;
      docObj[i].translate(dx,dy*docObj.length - dy*i);
    }
  }
}
```

### convertLayerToBackground()
背景が作成されないので、新規レイヤーを追加し、背景に変換する。

本スクリプトの条件は、下記の通り。
- レイヤー名：Backgraound
- サイズ：15000×15000
- 背景：白べた塗り

```javascript
function convertLayerToBackground() {
  layObj = activeDocument.artLayers.add();
  docObj = activeDocument;
  
  docObj.activeLayer.isBackgroundLayer = 1;
  docObj.activeLayer.name = "background";

  preferences.rulerUnits = Units.PIXELS;
  activeDocument.resizeCanvas(15000, 15000, AnchorPosition.TOPCENTER);
  var fillColor = new SolidColor();
  fillColor.rgb.red = 255;
  fillColor.rgb.green = 255;
  fillColor.rgb.blue = 255;
  docObj.selection.fill(fillColor);
  docObj.activeLayer.allLocked = true;
}
```

### layerSort()
レイヤーを名前順にソートさせる。
[Photoshopレイヤの並び替え](http://www.nekomataya.info/nekojyarashi/wiki.cgi?%A5%EC%A5%A4%A5%E4%CA%C2%A4%D3%C2%D8%A4%A8)を参照。

- 正順並び替え：layerSort(true)
- 逆順並び替え：layerSort(false)

```javascript
layerSort= function(revFlag){
  if(! revFlag) revFlag=false;//
  //	アクティブレイヤのトレーラーをターゲットにセットする
  var myTarget=activeDocument.activeLayer.parent.layers;
  //	並び替え対称のレイヤが1つしかない場合は、並び替え不能なのでキャンセル
  if(myTarget.length<=1){return false;}
  //	ソート用配列を作る
  var sortOrder=new Array();
  for (idx=0;idx<myTarget.length;idx++){
    if (myTarget[idx].isBackgroundLayer){
      continue;//レイヤが背景だったら無視
    }else{
      sortOrder.push(myTarget[idx].name);
    }
  }
  sortOrder.sort();//逆順並び替え
  if (revFlag){
    sortOrder.reverse();//正順並び替え
  }
  //並び替えた配列から同名レイヤのチェック
  for (idx=1;idx<sortOrder.length;idx++){
    if(sortOrder[idx-1]==sortOrder[idx]){
      alert("同名のレイヤがあります。?n二つ目以降のレイヤは並び替えの対象になりません。");
      break;
    }
  }
  for (idx=0;idx<sortOrder.length;idx++){
    myTarget.getByName(sortOrder[idx]).move(myTarget[0],ElementPlacement.PLACEBEFORE);
  }
  return sortOrder;
}
```
### guideWrap()
ガイドを追加する。
[選択範囲にあわせてガイドを引く.jsx](http://blog.sakurachiro.com/2010/06/guides-to-the-selection-range/)を参照。

```javascript
function guideWrap(direction,position){
  var id1 = charIDToTypeID( "Mk  " );
  var desc1 = new ActionDescriptor();
  var id2 = charIDToTypeID( "Nw  " );
  var desc2 = new ActionDescriptor();
  var id3 = charIDToTypeID( "Pstn" );
  var id4 = charIDToTypeID( "#Pxl" );
  desc2.putUnitDouble( id3, id4, position );
  var id5 = charIDToTypeID( "Ornt" );
  var id6 = charIDToTypeID( "Ornt" );
  var id7 = charIDToTypeID( direction );
  desc2.putEnumerated( id5, id6, id7 );
  var id8 = charIDToTypeID( "Gd  " );
  desc1.putObject( id2, id8, desc2 );
  executeAction(id1,desc1,DialogModes.NO);
}
```