久しぶりの更新。あんまり知らないだろうな、という方法をこそっと紹介してみる。
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; case 'R': g.drawRect(x+v(), y+v(), v(), v()); break; case 'F': g.fillRect(x+v(), y+v(), v(), v()); break; case 'O': g.drawOval(x+v(), y+v(), v(), v()); break; case 'V': case 'o': g.fillOval(x+v(), y+v(), v(), v()); break; case 'C': 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; case 'D': g.fillRect(x+v(), y+v(), 1, 1); break; case 'P': 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': 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': 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"は実際に表示する文字を示す。
こんな感じでアイコンを直接描画することができる。
利用できるコマンドをソースコードから類推すると
- Bxy: ベース(開始XY座標)をxyでリセットする?
- Rxywh: Rectangleの描画 (x, y, w, h)
- Fxywh: FillRectangleの描画 (x, y, w, h)
- Oxywh: Ovalの描画 (x, y, w, h)
- Vxywh: FillOvalの描画 (x, y, w, h) ("o"でもよいみたい)
- Crgb: 描画色の決定 (r*16, g*16, b*16)が実際の色
- Lxyx'y': Lineの描画 (x, y, x', y')
- Dxy: Dotの描画 (x, y)
- Pxyxyxyxyxy... : PolyLineの描画
- Gxyxyxyxyxy... : Polygonの描画 ("H"でもよいみたい)
- Txysc : Text cの描画 (x, y), fontsize = s
これを使えば好きなアイコンを作ることができる。座標の指定は0~fの16なので、実質16x16ピクセルと思えばよさそう。