jsxでデザイナー向けにphotoshopデータのチェッカーを作った

こんにちは、相原です。

自分がデザイナー出身ということもあり、
どうにかデザイナーの作業を効率化出来ないかと考え、チェッカーを作ってみました。

photoshopでデザインを作り込んでいるとレイヤー数が増え、
また不要なレイヤーを消し忘れて非表示にしたまま放置している人が多いかと思います。
そんな時に自動で非表示のレイヤーを探し、確認あるいは削除してくれるチェッカーです。

JSXとは

JavaScriptでPhotoshopを制御するファイルのことを「JSX」といいます。
昔からPhotoshopに搭載されていて、機能追加や自動化をすることが出来ます。

チェッカーの主な機能

非表示のまま放置しているレイヤーがあるとします。
レイヤー
f:id:AdwaysEngineerBlog:20170907153755p:plain

(いるレイヤーまで1個非表示になっちゃってますね)

ファイル > スクリプト > 参照 でチェッカーのjsxファイルを読み込みます。
読み込み
f:id:AdwaysEngineerBlog:20170907153811p:plain

するとチェックが始まり、アラートが表示されます。
削除対象
f:id:AdwaysEngineerBlog:20170907153833p:plain

削除方法
f:id:AdwaysEngineerBlog:20170907153847p:plain

■手動で削除
そのまま終了するか、対象のレイヤーに黄色のカラーラベルをつけるか選択できます。
画像はカラーラベルをつけたものです。
これでどのレイヤーが削除対象か分かり易いですね。
ラベル付き
f:id:AdwaysEngineerBlog:20170907154637p:plain

■1つずつ確認
非表示のレイヤー1つずつアラートで確認し、削除したいものだけ「はい」を押すと削除されます。
削除確認
f:id:AdwaysEngineerBlog:20170907154648p:plain

■一括削除
非表示のレイヤーは自動ですべて削除されます。

コード

カラーラベルの付け方はこちらのサイトを参考にしています。

var document;
var targetCnt = 0; // 削除対象のレイヤーを数える変数
var howToDeleteFlg; // 0=手動, 1=確認, 2=一括

function start(){
  alert('チェックを開始します。');
  document = app.activeDocument;
  searchLayer(document.layers);
  if(targetCnt == 0){
    alert('削除対象のレイヤーがないので終了します。');
    return; // 削除対象がなければ終了する
  }
  howToDelete(document.layers);
  alert('チェックを終了します。');
}

// 非表示レイヤーの検索 -------------------->
function searchLayer(obj){
  var i;
  switch(obj.typename){
    case "Layers":
      var visiblities = [];
      for(i = obj.length - 1; i >= 0; i--){
        var rep = searchLayer(obj[i]);
        if(rep == false) targetCnt++;
      }
      break;
    case "LayerSet":
      if(!obj.visible){
        processingBranch(obj);
        return false;
      }
      for(i = obj.layers.length - 1; i >= 0; i-- ){
        var rep = searchLayer(obj.layers[i]);
        if(rep == false) targetCnt++;
      }
      break;
    default:
      if(!obj.visible){
        processingBranch(obj);
        return false;
      }
      break;
  }
}

// 削除方法選択用のダイアログ -------------------->
function howToDelete(obj){
  alert('削除対象のレイヤーが' + targetCnt + '個あります。');
  deleteWin = new Window("dialog", "削除方法を選択してください。");
  manualBtn = deleteWin.add("button", { width: 150, height: 25, x: 25, y: 25 }, "手動で削除");
  confirmationBtn = deleteWin.add("button", { width: 150, height: 25, x: 115, y: 25 }, "1つずつ確認");
  bulkBtn = deleteWin.add("button", { width: 150, height: 25, x: 205, y: 25 }, "一括削除");
  manualBtn.onClick = function(){
    howToDeleteFlg = 0;
    deleteWin.close();
    var result = confirm('カラーラベル(黄色)で印をつけますか?');
    if(result) searchLayer(obj); // カラーラベルをつける処理へ
  }
  confirmationBtn.onClick = function(){
    // 1つずつ確認する処理へ移動
    howToDeleteFlg = 1;
    deleteWin.close();
    searchLayer(obj);
  }
  bulkBtn.onClick = function(){
    var result = confirm('本当に一括削除してよろしいですか?');
    if(result){
      // 一括削除する処理へ移動
      howToDeleteFlg = 2;
      deleteWin.close();
      searchLayer(obj);
    }
  }
  deleteWin.show();
}

// 削除方法が手動、確認、一括かによって処理の分岐 -------------------->
function processingBranch(obj){
  if(howToDeleteFlg == 0){
    app.activeDocument.activeLayer = obj;
    var util = new PSLayerUtil();
    util.setLayerColor(PSLayerUtil.LayerColors.None);
    util.setLayerColor(PSLayerUtil.LayerColors.Yellow);
    return false;
  }else if(howToDeleteFlg == 1){
    confirmationDelete(obj);
    return false;
  }else if(howToDeleteFlg == 2){
    obj.remove();
    return false;
  }else{
    return false;
  }
}

// レイヤーの選択 -------------------->
function selectLayer(obj){
  app.activeDocument.activeLayer = obj;
  obj.visible = false;
}

// カラーラベル設定 -------------------->
var PSLayerUtil = function(){
  this._colorRef = new ActionReference();
  this._colorRef.putEnumerated(charIDToTypeID('Lyr '), charIDToTypeID('Ordn'), charIDToTypeID('Trgt'));
}
PSLayerUtil.LayerColors = {
  Yellow: 'Ylw ',
  None: 'None'
};
PSLayerUtil.prototype = {
  _colorRef: null,
  setLayerColor: function(layerColor) {
    var colorDescriptor = new ActionDescriptor();
    colorDescriptor.putEnumerated(charIDToTypeID('Clr '), charIDToTypeID('Clr '), charIDToTypeID(layerColor));
    var desc = new ActionDescriptor();
    desc.putReference(charIDToTypeID('null'), this._colorRef);
    desc.putObject(charIDToTypeID('T   '), charIDToTypeID('Lyr '), colorDescriptor);
    executeAction(charIDToTypeID('setd'), desc, DialogModes.NO);
    return this.layerColor();
  },
  layerColor: function() {
    var desc = executeActionGet(this._colorRef);
    var charID = typeIDToCharID(desc.getEnumerationValue(charIDToTypeID('Clr ')));
    for(var key in PSLayerUtil.LayerColors) {
      var value = PSLayerUtil.LayerColors[key];
      if(value === charID) return key;
    }
    return 'None';
  },
}

// 削除方法が1つずつ確認する場合のダイアログ -------------------->
function confirmationDelete(obj){
  selectLayer(obj);
  var result = confirm('削除対象【' + obj.name + '】を削除しますか?');
  if(result){
    obj.remove();
  }
}
start();

さいごに

jsxは少し特殊な書き方もしますが、簡単に自動化出来るので活用していけそうです。
このチェッカーも2時間半ほどで作れました。
今後もデザイナーの作業を効率化出来るようなものを作ってみたいと思います╰(✿´⌣`✿)╯