31
33

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

PSDファイルのレイヤー構造とレイアウト情報をxml化する

Last updated at Posted at 2014-03-31

PSDファイルで作ったモックをcocos2dでレイアウトしようと思ったのだけど、冷静に考えて無理だという結論に至ったのでPSDファイル上のレイアウト情報を構造化しようと思った。

JSXのリファレンスが少ないわ公式のドキュメントは膨大だわなぜかpdfだわで散々な目にあった。
とはいえjsxは意外と高機能でファイルシステムへのアクセスとかも普通にできた。

だけどjsxはjsにあらずというかecmaにまったく準拠していないのでjsだと思ってかかると大変なことになる。
Objectはkeysとか持ってないしinstanceofとかも機能しないしもうじゃあ逆に何が使えるんだ的な。

環境

  • OSX 10.9
  • Adobe Photoshop CC
  • Adobe Extendscript Toolkit CC

PSD上でのレイアウト

たとえばこんなpsdファイルがあったとして

スクリーンショット 2014-04-01 5.05.44 1.png

こんなjsxを

psd2xml.jsx
(function(){
    var doc, depth, log, tabs, xmlize, isLayerSet, isCollection, dumpCollection, dumpLayers;
    // 現在の階層に応じてログを出力する
    log = function(msg){
        $.writeln(tabs(depth)+msg);
    };
    // タブを取得
    tabs = function(){
      var i, tabs;
      for (i = 0, tabs = ""; i < depth; i++){
          tabs += "\t";
      }
      return tabs;
    };
    // オブジェクトがレイヤーのコレクションかどうか
    isCollection = function(obj){
        return (obj.typename === "LayerSets" || obj.typename === "Layers" || obj.typename === "ArtLayers");
    };
    // オブジェクトがレイヤーセットか
    isLayerSet = function(obj){
      return (obj.typename === "LayerSet" || obj.typename === "Document");
    };
    // コレクションをレイヤーごとに出力する
    dumpCollection = function(collection){
         var i, max, memo, layer, keys;
         memo = "";
         keys = ["name","bounds","opacity","visible","kind","isBackgroundLayer","blendMode"];
         if (isCollection(collection)){
            for (i = 0, max = collection.length; i < max; i++){
                layer = collection[i];
                memo += dumpLayers(layer,keys);
            }
        }
        return memo;
    };
    // オブジェクトをxml化する
    xmlize = function(obj,keys){
      var i,max,key,xml;
      xml = "";
      xml += tabs() + "<"+obj.typename;
      for (i = 0, max = keys.length; i < max; i++){
         key = keys[i];
         val = obj[key];
         xml += " "+key+"="+"\""+val+"\"";
      }
      xml += isLayerSet(obj) ? " >\n" : " />\n";
      if (isLayerSet(obj)){
         depth++;
         xml += dumpCollection(obj.layers);
         depth--;
         xml += tabs() + "</"+obj.typename+">\n";
      }
      return xml;
    };
    // オブジェクトをKeyValueでXML化して出力
    dumpLayers = function(obj,keys,memo){
      if (!obj) return;
      if (!keys) keys = obj.keys;
      if (!memo) memo = "";
      if (isCollection(obj)) {
          return dumpCollection(obj) + memo;
      }else{
          return xmlize(obj,keys) + memo;
      }
    };
    // Photoshopをアクティブにする
    app.bringToFront();
    doc = app.activeDocument;
    depth = 0;
    (function(){
      // ファイルに保存
      var xml, file, path;
      xml = dumpLayers(doc,["name","width","height"],"");
      $.writeln(xml);
      path = File.saveDialog ("psdデータを保存");
      file = new File(path);
      if (file.open("w")) {
        file.write(xml);
        file.close();
      }else{
          alert("保存に失敗しました");
      }
    })();
})();

Extendscript Toolkit上で実行すると、ファイル保存ダイアログが表示されるので、

スクリーンショット 2014-04-01 5.04.04.png

適当に名前を付けて保存するとこんなxmlファイルができる。

Test.psd.xml
<Document name="Test.psd" width="640 px" height="960 px" >	<ArtLayer name="Text" bounds="24 px,792 px,107 px,821 px" opacity="100" visible="true" kind="LayerKind.TEXT" isBackgroundLayer="false" blendMode="BlendMode.NORMAL" />	<LayerSet name="グループ 1" bounds="110 px,340 px,216 px,369 px" opacity="100" visible="true" kind="undefined" isBackgroundLayer="undefined" blendMode="BlendMode.PASSTHROUGH" >		<ArtLayer name="Text2" bounds="110 px,340 px,216 px,369 px" opacity="100" visible="true" kind="LayerKind.TEXT" isBackgroundLayer="false" blendMode="BlendMode.NORMAL" />	</LayerSet>	<ArtLayer name="Bottom" bounds="0 px,765 px,640 px,960 px" opacity="100" visible="true" kind="LayerKind.SOLIDFILL" isBackgroundLayer="false" blendMode="BlendMode.NORMAL" />	<ArtLayer name="Top" bounds="0 px,0 px,640 px,100 px" opacity="100" visible="true" kind="LayerKind.SOLIDFILL" isBackgroundLayer="false" blendMode="BlendMode.NORMAL" />	<ArtLayer name="背景" bounds="0 px,0 px,640 px,960 px" opacity="100" visible="true" kind="LayerKind.NORMAL" isBackgroundLayer="true" blendMode="BlendMode.NORMAL" /></Document>

xmlのattributeはjsx中で指定しているので変えることもできる。

構造化ができたら?

煮るなり焼くなり。

  • レイヤー構造が分かっている → cocos2dやらUIViewやらでリビルドができる
  • 絶対位置のboundsが分かっている → レイアウトができる
  • opacity/bleneMode/visibleなどのメタデータがある → コンポジションができる

ということに加えて、jsxはレイヤーを画像として切り出すことが可能なので、アプリ側でビルダーを作ってあげれば

PSDファイルからViewを構築できるということですね、ハイ。

あと、分かんないですけど多分jsxでスプライト化とかもできるんじゃないでしょうか?
どちらにせよ素晴らしい作業効率のupが期待できると思います。
というわけで次回はxmlをパースしてスプライトとかを配置したいと思います。

31
33
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
31
33

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?