Translate

2018年12月5日水曜日

誰も教えてくれないImageJの使い方 -ツールバーへの登録-

久しぶりの更新。あんまり知らないだろうな、という方法をこそっと紹介してみる。

ImageJのツールバーへの登録方法。Built-in-Macroにある
newMenu(macroName, stringArray)
を使う。macroNameにはメニュー処理するMacro、stringArrayにはメニューの項目を登録する。実際の例として、ToolBar Menuに記載がある。一部抜粋すると、

var dCmds = newMenu("Developer Menu Tool",
      newArray("ImageJ Website","News", "ImageJ Wiki", "Resources", "Macro Language", "Macros", "Macro Functions", "Startup Macros...", "Plugins", "Source Code", "List Archives", "-", "Record...", "Capture Screen ", "Monitor Memory...", "Find Commands... ", "Control Panel...", "Search...", "Debug Mode"));
      
macro "Developer Menu Tool - C037T0b11DT7b09eTcb09v" {
       cmd = getArgument();
       if (cmd=="ImageJ Website")
           run("URL...", "url=http://rsbweb.nih.gov/ij/");

ルールとして、Macro名(macroName)の後ろには"Menu Tool"を付ける。stringArray(直接newArrayで登録しているが)にメニューの項目を設定する。ここまではいいのだが、では例えば以下のようにしても、アイコンがでずうまく登録できない。

var dCmds = newMenu("TestMenu Tool", newArray("Test1macro", "Test2macro");

macro "Test Menu Tool" {
    cmd = getArgument();
    runMacro(cmd);
}

なぜなら、登録すべきアイコンを設定していないから!
ここでサンプルをみると、
macro "Developer Menu Tool - C037T0b11DT7b09eTcb09v" {
とあり、Menu Toolの後ろになにやらよくわからない文字列が並んでいる。しかしサンプルのどこをみてもこれの説明はないし、ググっても見つからない。最初、アイコンの画像を参照するIDか何かかと思って、ij.jarを解凍してみたけど、それっぽいリソースは見つからなかった。
うーん、困った。困ったときにはImageJのソースコードを見るのが良い。メニューを登録しているクラスは、ij.gui.Toolbarっぽい。さらに探すと、void drawIconなるメソッドが見つかる。ちょっと長いけど、メソッドを張り付けてみる。

void drawIcon(Graphics g, int tool, int x, int y) {
        if (null==g) return;
        icon = icons[tool];
        if (icon==null) return;
        this.icon = icon;
        int x1, y1, x2, y2;
        pc = 0;
        while (true) {
            char command = icon.charAt(pc++);
            if (pc>=icon.length()) break;
            switch (command) {
                case 'B': x+=v(); y+=v(); break;  // reset base
                case 'R': g.drawRect(x+v(), y+v(), v(), v()); break;  // rectangle
                case 'F': g.fillRect(x+v(), y+v(), v(), v()); break;  // filled rectangle
                case 'O': g.drawOval(x+v(), y+v(), v(), v()); break;  // oval
                case 'V': case 'o': g.fillOval(x+v(), y+v(), v(), v()); break;  // filled oval
                case 'C': // set color
                    int v1=v(), v2=v(), v3=v();
                    int red=v1*16, green=v2*16, blue=v3*16;
                    if (red>255) red=255; if (green>255) green=255; if (blue>255) blue=255;
                    Color color = v1==1&&v2==2&&v3==3?foregroundColor:new Color(red,green,blue);
                    g.setColor(color);
                    break; 
                case 'L': g.drawLine(x+v(), y+v(), x+v(), y+v()); break; // line
                case 'D': g.fillRect(x+v(), y+v(), 1, 1); break; // dot
                case 'P': // polyline
                    Polygon p = new Polygon();
                    p.addPoint(x+v(), y+v());
                    while (true) {
                        x2=v(); if (x2==0) break;
                        y2=v(); if (y2==0) break;
                        p.addPoint(x+x2, y+y2);
                    }
                    g.drawPolyline(p.xpoints, p.ypoints, p.npoints);
                    break;
                case 'G': case 'H':// polygon or filled polygon
                    p = new Polygon();
                    p.addPoint(x+v(), y+v());
                    while (true) {
                        x2=v(); y2=v();
                        if (x2==0 && y2==0 && p.npoints>2)
                            break;
                        p.addPoint(x+x2, y+y2);
                    }
                    if (command=='G')
                        g.drawPolygon(p.xpoints, p.ypoints, p.npoints);
                    else
                        g.fillPolygon(p.xpoints, p.ypoints, p.npoints);
                    break;
                case 'T': // text (one character)
                    x2 = x+v()-1;
                    y2 = y+v();
                    int size = v()*10+v()+1;
                    char[] c = new char[1];
                    c[0] = pc<icon.length()?icon.charAt(pc++):'e';
                    g.setFont(new Font("SansSerif", Font.PLAIN, size));
                    g.drawString(new String(c), x2, y2);
                    break;
                default: break;
            }
            if (pc>=icon.length()) break;
        }
        if (menus[tool]!=null && menus[tool].getItemCount()>0) { 
            xOffset = x; yOffset = y;
            drawTriangle(15, 15);
        }
    }
なにやらSwich文でBやらFやらOやらCやらを場合分けしている。。実は先ほどの意味のよくわからない文字列
C037T0b11DT7b09eTcb09v
これには、アイコンを描画するための命令が記述されていた!
例えば最初の
C037
の”C”は描画色を決めている。そのあとの3桁の数字はそれぞれRGBに対応しており、この値に16を乗じたものになる。したがってここでは(R,G,B) = (0, 3*16, 7*16)という色を指定している。
次の
T0b11D
の”T"は、文字を指定する。最初の0bはXY座標を示しており、X=0, Y=b (=11, 16進数)を表す。次の"11"はフォントサイズ。最後の"D"は実際に表示する文字を示す。
こんな感じでアイコンを直接描画することができる。
利用できるコマンドをソースコードから類推すると
  1. Bxy: ベース(開始XY座標)をxyでリセットする?
  2. Rxywh: Rectangleの描画 (x, y, w, h)
  3. Fxywh: FillRectangleの描画 (x, y, w, h)
  4. Oxywh: Ovalの描画 (x, y, w, h)
  5. Vxywh: FillOvalの描画 (x, y, w, h) ("o"でもよいみたい)
  6. Crgb: 描画色の決定 (r*16, g*16, b*16)が実際の色
  7. Lxyx'y': Lineの描画 (x, y, x', y')
  8. Dxy: Dotの描画 (x, y)
  9. Pxyxyxyxyxy... : PolyLineの描画
  10. Gxyxyxyxyxy... : Polygonの描画 ("H"でもよいみたい)
  11. Txysc : Text cの描画 (x, y), fontsize = s
これを使えば好きなアイコンを作ることができる。座標の指定は0~fの16なので、実質16x16ピクセルと思えばよさそう。


0 件のコメント:

コメントを投稿