mdiapp開発報告所 このページをアンテナに追加 RSSフィード

2007-09-01

[] ブラシスクリプト概要 00:23  ブラシスクリプト概要を含むブックマーク

mdiappはブラシ処理でスクリプト(Lua)を用いたプログラム制御が行えます。

http://staff.aist.go.jp/yutaka.ueno/lua/docsjp.html (Lua言語について

プログラム制御をすることで、

こういった形で自由度の高いブラシを作成することが可能です。ブラシスクリプトは、拡張子 (*.bs) で作成します。ブラシデザインウィンドウからスタイルで「プログラム」を選び、下のボタンを押しスクリプトを指定します (ファイルをブラシウィンドウにドラッグ&ドロップでもOKです)。正しくパースできた場合のみ、インストールが可能です。参照したファイルは実行ファイルと同階層の "bs" フォルダにコピーされます。

一番シンプルなスクリプトは、こんな具合です。

function main( x, y, p )

  local r,g,b,a = bs_pixel_get( x, y )
  bs_pixel_set( x,y, 255-r,255-g,255-b, 255 )
  return 1
end

プログラムブラシの場合、ブラシ描画に使うマウスタブレットから取得した座標の各頂点間を、十分に細かい頻度で (ブラシの直径に応じた細かさ) main( x,y,p ) 関数が呼ばれます。かなりの頻度で呼ばれる事になるので、間隔調整が必要になります。

f:id:MDIAPP:20160924180504p:image

上記のスクリプトの場合、bs_pixel_get命令で、x,y座標のRGBA値を取得し、bs_pixel_set命令で、RGB値を反転した値のピクセルを書き込むような処理になっています。

何かしら描画した場合は return 1 を、何も描かなかった場合は return 0 してください。

次はもう少し複雑なスクリプトを見てみましょう。

function main( x, y, p )

  local w = bs_width()
  if w < 5 then
    w = 5
  end

  if not firstDraw then
    local distance = bs_distance( lastDrawX - x, lastDrawY - y )
    if distance < w then
      return 0
    end
  end

  local dx,dy = bs_dir()
  local nx,ny = bs_normal()

  bs_polygon( x + nx * w/3, y + ny * w/3 )
  bs_polygon( x - nx * w/3, y - ny * w/3 )
  bs_polygon( x + dx * w, y + dy * w )

  local r,g,b = bs_fore()
  bs_fill( r,g,b, 255 )

  lastDrawX = x
  lastDrawY = y
  firstDraw = false

  return 1
end

lastDrawX = 0
lastDrawY = 0
firstDraw = true

f:id:MDIAPP:20100425220548p:image

最後の3行に注目してください。ここはグローバル宣言部なので、main(x,y,p) が呼び出される前に、一度だけ必ず実行されます。ここでは、firstDraw = true といったように、最初の描画を判定する為の変数初期化しています。

  local w = bs_width()
  if w < 5 then
    w = 5
  end

bs_width() は現在のブラシ幅(直径)を所得する関数です (筆圧適用した幅)。5pixel以下のブラシ幅にしないように調整しています。

  if not firstDraw then
    local distance = bs_distance( lastDrawX - x, lastDrawY - y )
    if distance < w then
      return 0
    end
  end

最初の描画でない時、あまりにブラシが進んでいない場合は描画を避けるような処理をしています。bs_distance() で差分の距離を測っています。

  local dx,dy = bs_dir()
  local nx,ny = bs_normal()

bs_dir() はブラシの進行方向の正規ベクトル、bs_normal() はブラシの進行方向の垂直方向の正規ベクトルを取得する関数です。正規ベクトルとは、大きさが1になるベクトルのことです。進行方向が必要なので取得しています。

f:id:MDIAPP:20100508173604p:image

  bs_polygon( x + nx * w/3, y + ny * w/3 )
  bs_polygon( x - nx * w/3, y - ny * w/3 )
  bs_polygon( x + dx * w, y + dy * w )

bs_polygon() は多角形を設定する命令です。現在の座標値 x, y をベースに、進行方向を指す3頂点を指定しています。

f:id:MDIAPP:20100426094504p:image

  local r,g,b = bs_fore()
  bs_fill( r,g,b, 255 )

bs_fore() で前景色RGB値を取得し、その色を使い bs_fill() で先ほど定義した3頂点を塗りつぶしています。

ストロークの最後だけ何かしたい

全てのストローク処理が終わった後、last関数が呼ばれます。このスクリプトを参考にしてください。last関数は、実装されていなくても構いません。

function last( x, y, p )

  local r,g,b = bs_fore()
  local w = bs_width_max()
  bs_ellipse( x, y, w*2, w, 0, r,g,b, bs_opaque()*255 )
  return 1
end

function main( x, y, p )
  return 1
end

[] パラメータの扱い 13:41  パラメータの扱いを含むブックマーク

function param1()
  return "param1", 0, 100, 50
end

function param2()
  return "param2", 50, 100, 75
end

function param3()
  return "param3", 10, 20, 15
end

function param4()
  return "checked", 0, 1, 0
end

function param5()
  return "unchecked", 0, 1, 1
end

スクリプト内に param1(), param2(), param3() ... という関数を定義しておくと、ブラシコントロールウィンドウでパラメータ設定、取得できるようになります (最大10個>param1 から param10 まで)。

  • 第1 戻り値
    • ブラシコントロール上に表示される文字です(英語のみ)
  • 第2 戻り値
    • 設定の最小値です(0〜100まで)
  • 第3 戻り値
    • 設定の最大値です(0〜100まで)
  • 第4 戻り値

設定値はスクリプト内で、

local param1 = bs_param1()
local param2 = bs_param2()
local param3 = bs_param3()
local param4 = bs_param4()
local param5 = bs_param5()

といった形で取得できます。

f:id:MDIAPP:20100426094859p:image

最小値が0、最大値が1の場合

チェックボックス表示になります。チェックされている場合は1、チェックされていない場合は0が戻り値になります。

f:id:MDIAPP:20100604105507p:image

[] デフォルトのサイズ(幅・最小サイズ) 15:51  デフォルトのサイズ(幅・最小サイズ)を含むブックマーク

ブラシによっては、細いものを推奨するものもあれば、太いものを推奨するものもあります。

function default_size()
  return 17, 0.25
end

という関数スクリプト内で定義しておけば、デフォルトの幅、デフォルトの最小サイズを指定することができます。この場合、最大幅は17px、最小サイズは 25% になります。

[] 基点の指定 11:37  基点の指定を含むブックマーク

左右対称・回転対称ブラシなど、基点(基準点)が必要な場合があります。

基点が必要なブラシは、キャンバス上でCtrl+クリックをする事で基点が指定できます。

基点を使いたいスクリプトは、スクリプト内で、

function use_base()
  return true
end

と定義しておきます。設定された起点は、

local bsx,bsy = bs_base()

という形で、bs_base()命令を使い取得できます。

基点が指定されてない場合は、(-1,-1) が返ります。(-1,-1)の場合は、特別処理を入れておくと良いでしょう。

[] 描画モード (mdiap+ 0.9.137 より) 16:05  描画モード (mdiap+ 0.9.137 より)を含むブックマーク

指定のない通常のモードでは、カラーレイヤーならRGB好きな色を指定して描画できます。しかし、半透明で描画した際に、重なる部分が濃くなってしまいます。滑らかなブラシ処理には向きません。そこで、

bs_setmode( 1 )

というコードを初期化部分に追加すると、通常のペンのように、半透明部分の合成が綺麗になるモードになります。ただし、RGB任意の色で図形を描画することはできず、前景色を使った描画になります。

通常のモード

f:id:MDIAPP:20150310160344p:image

bs_setmode( 1 ) を指定

f:id:MDIAPP:20150310160346p:image

参考スクリプト

bs_setmode は「最初に」「一度だけ」呼ぶようにしてください。

[] プレビュー中か判定する (0.9.140 から) 21:26  プレビュー中か判定する (0.9.140 から)を含むブックマーク

ブラシのプレビュー画像が描画されない場合があります (マウスタブレットの場合は問題ないのに)。時間情報 (bs_ms()) を使った場合に起こりやすい問題です。

if bs_preview() then
  プレビュー時の特殊処理をここに挟む
end

のような感じで、bs_preview() 関数を使ってプレビュー中か判定できます。

[] API一覧 (基本命令) 00:23  API一覧 (基本命令)を含むブックマーク

w = bs_width()
w = bs_width_max()
w = bs_width_min()
  • bs_width()
    • 筆圧を適用したブラシ幅(直径)を取得します
  • bs_width_max()
    • ブラシの最大幅を取得します (最大筆圧時の直径)
  • bs_width_min()
    • ブラシの最小幅を取得します (最小筆圧時の直径)
distance = bs_distance( x, y )
rad = bs_atan( x, y )
x, y = bs_rotate( x, y, radAngle )
value = bs_grand( ave, std )
milisec = bs_ms()
num = bs_count()
  • bs_distance( x, y )
    • 原点から (x,y) の距離を取得します
  • bs_atan( x, y )
    • 原点から (x,y) の角度を取得します (ラジアン)
  • bs_rotate( x, y, radAngle )
    • x,y座標を原点を中心に、radAngle(ラジアン) だけ回転させます
  • bs_grand( ave, sd1 )
    • aveを中心に、±sd1の範囲に約68%の確率で収まるようなガウス分布乱数値を取得します
  • bs_ms()
    • OS起動時からの経過ミリ秒を取得します
  • bs_count()
    • mdiappの起動後、ブラシスクリプトが呼ばれた回数を取得します
    • 1ストローク毎に何かを変えたい場合などに用います
w = bs_canvas_width()
h = bs_canvas_height()
dpi = bs_canvas_dpi()
rad = bs_canvas_angle()
r,g,b = bs_fore()
r,g,b = bs_bg()
r,g,b = bs_forebg( t )
alpha = bs_opaque()
  • bs_fore()
  • bs_bg()
    • 背景色のRGB値を取得します
  • bs_forebg( t )
    • 前景色と背景色の補間値を取得します (0.0〜1.0)
    • 0.0: 背景色, 0.5:中間色, 1.0: 前景色
  • bs_opaque()
    • ブラシの不透明度 (0.0〜1.0) を取得します
dx,dy = bs_dir()
nx,ny = bs_normal()

[] API一覧 (描画命令) 00:23  API一覧 (描画命令)を含むブックマーク

r,g,b,a = bs_pixel_get( x, y )
alpha = bs_pixel_get_alpha( x, y )
bs_pixel_set( x, y, r,g,b,a )
  • bs_pixel_get( x, y )
    • x,y座標のRGBA値を取得します
    • R,G,B,A = 0〜255
    • 1,8bppレイヤーのA値は、常に255です
  • bs_pixel_get_alpha( x, y )
    • x,y座標のA値 (不透明度・濃度) を取得します
    • alpha = 0〜255
    • 1bppレイヤーの場合は、0 または 255 です
  • bs_pixel_set( x, y, r,g,b,a )
    • x,y座標に、RGB値を不透明度Aで描画します
    • R,G,B,A = 0〜255
    • bs_pixel_set を使って沢山描画するのは現実的ではありません
bs_polygon( x, y )
bs_polygon_move( dx, dy )
bs_polygon_move_center()
bs_polygon_rotate( radAngle )
bs_polygon_mul( zx, zy )
bs_polygon_clear()
rx,ry,rw,rh = bs_polygon_region()
  • bs_polygon( x, y )
    • 多角形を定義する為、頂点x,yを追加します
    • 三角形を定義する場合は、bs_polygon命令を三回実行します
  • bs_polygon_move( dx, dy )
    • 追加されている多角形の頂点を、dx,dyだけ移動させます
  • bs_polygon_move_center()
    • 追加されている多角形の頂点を、重心を原点に移動させます
  • bs_polygon_rotate( radAngle )
    • 追加されている多角形の頂点を、原点を中心に radAngle だけ回転させます
  • bs_polygon_mul( zx, zy )
    • 追加されている多角形の頂点を、x方向にzx倍、y方向にzy倍にします
  • bs_polygon_clear()
    • 追加されている多角形をクリアします (bs_fill 直後にも自動的にクリアされます)
  • rx,ry,rw,rh = bs_polygon_region()
    • 追加されている多角形の範囲を取得します (rx:X始点、ry:Y始点、rw:幅、rh:高さ)
    • 多角形が設定されていない場合、面積のない場合の戻り値は不定です
bs_bezier_begin( x, y )
bs_bezier_c( x1, y1, x2, y2, x3, y3 )
bs_bezier_v( x2, y2, x3, y3 )
bs_bezier_y( x1, y1, x3, y3 )
bs_bezier_l( x3, y3 )
bs_bezier_m( x, y )
bs_bezier_move( dx, dy )
bs_bezier_move_center()
bs_bezier_rotate( rad )
bs_bezier_mul( zx, zy )
bs_bezier_clear()
rx,ry,rw,rh = bs_bezier_region()
  • bs_bezier_begin( x, y )
  • bs_bezier_c( x1, y1, x2, y2, x3, y3 )
    • 制御点1 (x1,y1) 制御点2 (x2,y2)、次点 (x3,y3) の辺を追加します
  • bs_bezier_v( x2, y2, x3, y3 )
    • 制御点1は現在位置、制御点2 (x2,y2)、次点 (x3,y3) の辺を追加します
  • bs_bezier_y( x1, y1, x3, y3 )
    • 制御点1 (x1,y1)、制御点2&次点 (x3,y3) の辺を追加します
  • bs_bezier_l( x3, y3 )
    • 直線の辺を加えます
  • bs_bezier_m( x, y )
  • bs_bezier_move( dx, dy )
  • bs_bezier_move_center()
    • 追加されているベジェ曲線の頂点を、重心を原点に移動させます
  • bs_bezier_rotate( rad )
    • 追加されているベジェ曲線の頂点を、原点を中心に radAngle だけ回転させます
  • bs_bezier_mul( zx, zy )
    • 追加されているベジェ曲線の頂点を、x方向にzx倍、y方向にzy倍にします
  • bs_bezier_clear()
    • 追加されているパスをクリアします (bs_fill 直後にも自動的にクリアされます)
  • rx,ry,rw,rh = bs_bezier_region()
    • 追加されているパスの範囲を取得します (rx:X始点、ry:Y始点、rw:幅、rh:高さ)
    • パスが設定されていない場合、面積のない場合の戻り値は不定です
bs_fill( r, g, b, a )
bs_rect( x, y, w, h, r,g,b,a )
bs_ellipse( mx, my, w, h, radAngle , r,g,b,a )
  • bs_rect( x, y, w, h, r,g,b,a )
    • 座標(x,y) に、幅高さ (w,h) の矩形を描画します
  • bs_ellipse( mx, my, w, h, radAngle , r,g,b,a )
    • 座標(mx,my) を中心に、幅高さ (w,h) 角度 (radAngle) の楕円を描画します
    • アンチエイリアシングの有無はブラシ設定に依存します
    • 真円 (w == h) の場合、高速描画されます

[] ブラシ情報、お待ちしています! 20:41  ブラシ情報、お待ちしています!を含むブックマーク

ブラシスクリプトを作成の際には、是非とも当記事にコメントやトラックバックください。

宜しくお願い致します。

pon鈴pon鈴 2010/05/06 22:50 こんにちは。
mdiapp無いと絵が描けない というくらい愛用させていただいてます。

この度、当サイトで作成したブラシスクリプトの公開を始めました。
なにぶん素人が手探りで作ったものなので非常に拙いモノですが
ユーザーの方々に少しでもお役に立てばと思い報告させて頂きました。

それでは、今後の更なる進化に期待しております。

MDIAPPMDIAPP 2010/05/06 23:54 ご報告ありがとうございます。こ、これは……! 嬉しすぎます、感動です、ありがとうございます(涙)。早速紹介させて頂きます、今後も宜しくお願い致します!!

こここっここここっこ 2010/08/02 10:27 こんにちは、ブログにてブラシスクリプトを載せさせていただいています。

ある程度ブラシが溜まってきたので、トラックバックさせていただこうと思ったのですが、
よくわからなかったので(すみません…)コメントにて報告させていただきます。

では要件のみで申し訳ありませんがこの辺で。
これからもmdiappを応援しています。

MDIAPPMDIAPP 2010/08/03 00:53 ありがとうございます! 早速紹介させて頂きます! 今後も宜しくお願い致します:)

宇河宇河 2010/09/11 09:47 mdiappを楽しく使わせていただいています。

ブラシ作成に便利かもしれない補助ツールを作りました。
色々わからないまま作ったので自信ないですが
うまく動けばめっけもんという感じで試していただければと思います。

MDIAPPMDIAPP 2010/09/11 10:50 お世話になっております。

これは何とも……凄まじすぎます、ありがとうございます! パスデータからブラシ形状が取得出来るようになるのは大変有難いです(感涙)。サンプルの「墨筆」からもポテンシャルが伺えます、素晴らしいです。「どうやってるんだ!?」と思って他のスクリプトと比較してみたんですが、ブラシ形状が複数あって、そこからランダムで選択、描画してるわけですね(たぶん)。これは直ぐに告知させて頂きます、今後もよろしくお願い致します!

こここっここここっこ 2011/11/16 23:17 こんにちは、いつもお世話になっています。

ブログにてブラシスクリプトを公開させていただいていましたが、
ブログ元のサービスが終了するみたいなので、移転させていただきました。

中身はほとんど変わってませんが、urlが新しくなったので報告させていただきます。

MDIAPPMDIAPP 2011/11/17 19:58 お世話になっております! リンクの方、差し替えさせて頂きました! アプリの更新頻度が少なくなって心苦しいのですが、今後も宜しくお願いします:)