Fractalizer for AI

わりと多忙な日々が続いています。しかしながら皆様とは全くかけ離れたスケジュールなので忙しいとは言えないかも知れませんね。そんなこんななのですが、本日は久しぶりのExtensionBuilder3ちゃんネタでございます。EB3関連はほぼ凍結していますが、たまに動かさないと頭の中から欠落しそうなのでちょくちょくいじるのです。今回はExtensionBuilder3によるHTML5パネルと、ExtensionBuilder2のフラッシュインターフェース系パネルとの構成の違いを見ていただきましょう。

なお、条件を出来るだけ合わせる為にEB2の方もExternalHostObjectをプッシュする構成とします。
まずはExtensionBuilder2による構成:

[fractalizer.mxml] Runtime version2.0-3.0

<?xml version=”1.0″ encoding=”utf-8″?>
<mx:WindowedApplication xmlns:mx=”http://www.adobe.com/2006/mxml”&gt;
     <mx:Script>
          <![CDATA[
               import flash.external.HostObject;
               import mx.controls.*;

               [Embed(source=”./illustrator.jsx”, mimeType=”application/octet-stream”)]
               private static var EsInitClass: Class;
              
               [Bindable]
               private var hostName:String = HostObject.mainExtension;z
               private static function run(dpth:int,posi:Boolean):void
               {
                    var scriptObject: Object = new EsInitClass();
                    var initScript: String = scriptObject.toString();
                    var myBridgeScript : HostObject = HostObject.getRoot(HostObject.extensions[0]);
                    myBridgeScript.eval(initScript);
                    var jsxReturnStr : String =  myBridgeScript.$._ext_ILST.applyFractal(dpth, posi);
                    trace(jsxReturnStr);
               }
          ]]>
     </mx:Script>
     <mx:VBox height=”100%” width=”100%” verticalAlign=”top” horizontalAlign=”center” paddingTop=”10″>
          <mx:CheckBox id=”positive” label=”Positive” selected=”true” />
          <mx:HBox>
               <mx:Label text=”Depth:” />
               <mx:HSlider id=”depth” minimum=”1″ maximum=”8″ value=”4″
                         dataTipPlacement=”top” tickColor=”black”
                         snapInterval=”1″ tickInterval=”10″ labels=”[1,8]”
                         allowTrackClick=”true” liveDragging=”true” />
          </mx:HBox>
          <mx:Button label=”Apply”
                       click=”run(depth.value, positive.selected)”/>
     </mx:VBox>
</mx:WindowedApplication>

インターフェースが単純ですのでMVCモデルは利用しません。ストレートにmxmlファイル1点の構成でいきます。illustrator.jsxは後ほど出てきますが、EB2・3共通のコードで動きます。
まあ、ご覧の通りシンプルな構成となっています。これは一般的なAIRインターフェースのアピアランスを利用している為にUIの作り込み等が省かれている為です。
続いてHTML5の方は…

[index.html] Runtime version 4.0

<!doctype html><html>
<head>
<meta charset=”utf-8″>
<script type=”text/javascript” src=”./lib/CSInterface-4.0.0.js”></script>
<script type=”text/javascript”>
//Fractalizer for AI CC, HTML5 Version.1.0 beta release.

function onLoaded() {
    var csInterface = new CSInterface();
    loadJSX();

 
    updateThemeWithAppSkinInfo(csInterface.hostEnvironment.appSkinInfo);
    // Update the color of the panel when the theme color of the product changed.
    csInterface.addEventListener(CSInterface.THEME_COLOR_CHANGED_EVENT, onAppThemeColorChanged);
}

/**
 * Update the theme with the AppSkinInfo gotten from the host product.
 */
function updateThemeWithAppSkinInfo(appSkinInfo) {
    //Update the background color of the panel
    var panelBgColor = appSkinInfo.panelBackgroundColor.color;
    document.body.bgColor = toHex(panelBgColor);

    //Update the default text style
    var textStyle = document.styleSheets[0].rules[0].style;
    if (appSkinInfo.baseFontFamily && appSkinInfo.baseFontFamily != appSkinInfo.baseFontFamily) {
        document.body.style.fontFamily = appSkinInfo.baseFontFamily;
    }
    if (appSkinInfo.baseFontSize && textStyle.fontSize != appSkinInfo.baseFontSize) {
        textStyle.fontSize = appSkinInfo.baseFontSize + “px”;
    }
    textStyle.color = “#” + reverseColor(panelBgColor);

    //Update the background color value defined in .controlBg
    var controlBgStyle = document.styleSheets[0].rules[1].style;
    controlBgStyle.backgroundColor = “#” + toHex(panelBgColor, 20);

    //Update the background color value defined in .controlBg
    var buttonStyle = document.styleSheets[0].rules[2].style;
    buttonStyle.borderColor = “#” + toHex(panelBgColor, -50);
}

function reverseColor(color, delta) {
    return toHex({red:Math.abs(255-color.red), green:Math.abs(255-color.green), blue:Math.abs(255-color.blue)}, delta);
}

/**
 * Convert the Color object to string in hexadecimal format;
 */
function toHex(color, delta) {
    function computeValue(value, delta) {
        var computedValue = !isNaN(delta) ? value + delta : value;
        if (computedValue < 0) {
            computedValue = 0;
        } else if (computedValue > 255) {
            computedValue = 255;
        }

        computedValue = computedValue.toString(16);
        return computedValue.length == 1 ? “0” + computedValue : computedValue;
    }

    var hex = “”;
    if (color) {
        with (color) {
             hex = computeValue(red, delta) + computeValue(green, delta) + computeValue(blue, delta);
        };
    }
    return hex;
}

/**
 * Load JSX file into the scripting context of the product. All the jsx files in
 * folder [ExtensionRoot]/jsx will be loaded.
 */
function loadJSX() {
    var csInterface = new CSInterface();
    var extensionRoot = csInterface.getSystemPath(SystemPath.EXTENSION) + “/jsx/”;
    csInterface.evalScript(‘$._ext.evalFiles(“‘ + extensionRoot + ‘”)’);
}

function evalScript(script, callback) {
    new CSInterface().evalScript(script, callback)
}
function onAppThemeColorChanged(event) {
    // Should get a latest HostEnvironment object from application.
    var skinInfo = JSON.parse(window.__adobe_cep__.getHostEnvironment()).appSkinInfo;
    // Gets the style information such as color info from the skinInfo,
    // and redraw all UI controls of your extension according to the style info.
    updateThemeWithAppSkinInfo(skinInfo);
}

function makeFractal (){
     var flg = document.getElementById(‘ck0’).checked;
     var val = document.getElementById(‘range01’).value;
     evalScript(‘$._ext_ILST.applyFractal(‘ + val + ‘, ‘ + flg + ‘)’);
     }

</script>
<style type=”text/css”>
.textStyle {
}
.controlBg {
}
button
{
border:1px solid;
border-radius:3px;
height:19px;
}
#content {
margin-right:auto;
margin-left:auto;
vertical-align:middle;
width:100%;
}
#content ul {
padding:0px;
}
#content ul li {
margin:3px 0px 3px 0px;
}
body {
text-align:center;
}
</style>
<title>Fractalizer</title>
</head>
<body onLoad=”onLoaded()”>
<div id=”content”>

    <input id=”range01″ type=”range” min=”1″ max=”8″ step=”1″ value=”4″ /><br />
    <label><input type=”checkbox” id=”ck0″ checked=”true” />positive</label><br /><br />
    <button id=”btn” onClick=”makeFractal();”>Generate Fractal</button>

</div>
</body>

コメントが多いため無駄に長くなっています。EB3の構成は検索をかけても殆ど出会えません。はぐれメタル並みなのであえて残してあります。プロジェクト構成がデフォルトのもので、JSXファイルはフォルダごと参照する為にスクリプトファイルを順次読込む為のファンクションがインクルードされていますが、よくよく見てみるとJSからevalしてという流れは殆ど変わりません。太字の部分が大事な部分ですのでトレースしてみてください。基本的にはグローバルにオブジェクト突っ込む形になりますので、グローバル汚染の事も含めてネームスペースが挟み込まれる構成になっているようです。
また、アピアランスに関してはCSSでカバーする為、非常に自由度が高くなっています。しかしながら、従来のパネルとの統一感の事を考えるとCSSの作り込みは面倒くさい状態ではあります。この辺りに関してはBoilerPlate等のCSSがエバンジェリストから提供されたりしていますので上手に利用していただけたら良いと思います。

[fractalizer.jsx]

$._ext = {
    //Evaluate a file and catch the exception.
    evalFile : function(path) {
        try {
            $.evalFile(path);
        } catch (e) {alert(“Exception:” + e);}
    },
    // Evaluate all the files in the given folder
    evalFiles: function(jsxFolderPath) {
        var folder = new Folder(jsxFolderPath);
        if (folder.exists) {
            var jsxFiles = folder.getFiles(“*.jsx”);
            for (var i = 0; i < jsxFiles.length; i++) {
                var jsxFile = jsxFiles[i];
                $._ext.evalFile(jsxFile);
            }
        }
    }
};

こちらはHTML側のJavascriptからJSXファイルを順次読込む為のファンクションです。

[illustrator.jsx]

$._ext_ILST={
     applyFractal : function (dp, positive) {
          var dc =app.document;
          var pth = app.activeDocument.selection;
          var clr = new CMYKColor;
          clr.cyan = 0;
          clr.magenta = 0;
          clr.yellow = 0;
          clr.black = 100;
          var pt = new Array();
          var ln;
          for (var j=0;j<pth.length;j++){
          if (pth[j].typename!=”PathItem”) continue;
               pt = [];
               for (var i=0;i<pth[j].pathPoints.length;i++)
                    pt.push(pth[j].pathPoints[i].anchor);
               ln = app.activeDocument.pathItems.add();
               ln.stroke = true;
               ln.strokeColor = clr;
               ln.strokeWidth = 0.3;
               ln.filled =false;
               for (i=0;i<pt.length;i++){
                    if (i==pt.length-1){
                         if(pth[j].closed) $._ext_ILST.fractal(pt[i], pt[0], dp, ln, positive);
                         }else{
                              $._ext_ILST.fractal(pt[i], pt[i+1], dp, ln, positive);
                              }
                    }
               if (pth[j].closed) ln.closed = true;
               }
          return true;
          },
     fractal : function (a, b, dpth, ln, positive){
          var e;
          if (dpth==0) {
               $._ext_ILST.addPoint(b, ln);
               return;
               }
          var c = $._ext_ILST.dv($._ext_ILST.ad($._ext_ILST.mlt(a, 2), b), 3);
          var d = $._ext_ILST.dv($._ext_ILST.ad($._ext_ILST.mlt(b, 2), a), 3);
          var f = $._ext_ILST.dv($._ext_ILST.ad(a, b), 2);
          var v0 = $._ext_ILST.dv($._ext_ILST.sb(f, a), $._ext_ILST.len(f, a));
          var v1 = [v0[1], -v0[0]];
          if (positive)
               e = $._ext_ILST.sb(f, $._ext_ILST.mlt(v1, Math.sqrt(3) / 6 * $._ext_ILST.len(b, a)));
          else
               e = $._ext_ILST.ad(f,$. _ext_ILST.mlt(v1, Math.sqrt(3) / 6 * $._ext_ILST.len(b, a)));
          $._ext_ILST.fractal(a, c, dpth-1, ln);
          $._ext_ILST.fractal(c, e, dpth-1, ln);
          $._ext_ILST.fractal(e, d, dpth-1, ln);
          $._ext_ILST.fractal(d, b, dpth-1, ln);
          },
     mlt : function (v, n){
          return [v[0]*n, v[1]*n];
          },
     dv : function (v, n){
          return [v[0]/n, v[1]/n];
          },
     ad : function (a, b){
          return [a[0]+b[0], a[1]+b[1]];
          },
     sb : function (a, b){
          return [a[0]-b[0], a[1]-b[1]];
          },
     len: function (a, b){
          return Math.sqrt(Math.pow(a[0] – b[0], 2)
                    + Math.pow(a[1] – b[1], 2));
          },
     addPoint : function (p, ln){
          var pts = ln.pathPoints.add();
          pts.anchor = p;
          pts.leftDirection = pts.anchor;
          pts.rightDirection = pts.anchor;
          }
     };
<pth.length;j++){ if="" (pth[j].typename!="PathItem" )="" continue;="" pt="[];" for="" (var="" i="0;i<pth[j].pathPoints.length;i++)" pt.push(pth[j].pathpoints[i].anchor);="" ln="app.activeDocument.pathItems.add();" ln.stroke="true;" ln.strokecolor="clr;" ln.strokewidth="0.3;" ln.filled="false;" (i="0;i<pt.length;i++){" if(pth[j].closed)="" $._ext_ilst.fractal(pt[i],="" pt[0],="" dp,="" ln,="" positive);="" }else{="" pt[i+1],="" }="" (pth[j].closed)="" ln.closed="true;" return="" true;="" },="" fractal="" :="" function="" (a,="" b,="" dpth,="" positive){="" var="" e;="" (dpth="=0)" {="" $._ext_ilst.addpoint(b,="" ln);="" return;="" c="$._ext_ILST.dv($._ext_ILST.ad($._ext_ILST.mlt(a," 2),="" b),="" 3);="" d="$._ext_ILST.dv($._ext_ILST.ad($._ext_ILST.mlt(b," a),="" f="$._ext_ILST.dv($._ext_ILST.ad(a," 2);="" v0="$._ext_ILST.dv($._ext_ILST.sb(f," $._ext_ilst.len(f,="" a));="" v1="[v0[1]," -v0[0]];="" (positive)="" e="$._ext_ILST.sb(f," $._ext_ilst.mlt(v1,="" math.sqrt(3)="" 6="" *="" $._ext_ilst.len(b,="" a)));="" else="" _ext_ilst.mlt(v1,="" $._ext_ilst.fractal(a,="" c,="" dpth-1,="" $._ext_ilst.fractal(c,="" e,="" $._ext_ilst.fractal(e,="" d,="" $._ext_ilst.fractal(d,="" mlt="" (v,="" n){="" [v[0]*n,="" v[1]*n];="" dv="" [v[0]="" n,="" v[1]="" n];="" ad="" b){="" [a[0]+b[0],="" a[1]+b[1]];="" sb="" [a[0]-b[0],="" a[1]-b[1]];="" len:="" math.sqrt(math.pow(a[0]="" -="" b[0],="" 2)="" +="" math.pow(a[1]="" b[1],="" 2));="" addpoint="" (p,="" ln){="" pts="ln.pathPoints.add();" pts.anchor="p;" pts.leftdirection="pts.anchor;" pts.rightdirection="pts.anchor;" };

そして、これがExtendscriptのコアです。複素平面座標系を利用して座標を弾き出します。詳細はFractalSnowの方で解説していますのでそちらを参照してください。
動作イメージは

fractalSample1.png

こんな感じ。以下は応用例

fractalSample2.png

なんとなくフラクタルでしょ?

最後にzxpインストーラーを。CS5以降版とCC専用版をご用意しています。

fractalizer-1.0.0_cs5tocc.zxp

Fractalizer-1.0.0CC.zxp

広告

コメントを残す

以下に詳細を記入するか、アイコンをクリックしてログインしてください。

WordPress.com ロゴ

WordPress.com アカウントを使ってコメントしています。 ログアウト /  変更 )

Google フォト

Google アカウントを使ってコメントしています。 ログアウト /  変更 )

Twitter 画像

Twitter アカウントを使ってコメントしています。 ログアウト /  変更 )

Facebook の写真

Facebook アカウントを使ってコメントしています。 ログアウト /  変更 )

%s と連携中