- 2008年2月 1日 17:40
- flash
Paint のバケツツール(塗りつぶし)を作ってみた。
Paint のバケツツールを実現させるためには、まず線を描画しなければならない。Flash で線を描画する方法はいくつか紹介されてるのでそれを参考にした(どれも色や線幅の変更だけで塗りは紹介されていない)。
hagaさんの方は lineTo のみで描画。trick7さんは lineTo で描画した線を bitmapData に draw、描画後に graphics を clear することでメモリを節約してる(ちなみにこの方法だと、clear する度に lineStyle で設定した値と 始点が初期値に戻ってしまうので、描画前に毎回設定してやる必要がある)。メモリに優しい後者を採用。
package {
import flash.display.*;
import flash.events.MouseEvent;
import flash.geom.Point;
[SWF(width="480", height="360")]
public class Paint extends Sprite
{
private var line:Shape;
private var bmd:BitmapData;
private var bmp:Bitmap;
private var bgn:Point;
private var end:Point;
public function Paint()
{
bgn = new Point();
end = new Point();
line = new Shape();
bmd = new BitmapData(stage.stageWidth, stage.stageHeight, false);
bmp = new Bitmap(bmd);
this.addChild(bmp);
stage.addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown);
stage.addEventListener(MouseEvent.MOUSE_UP, onMouseUp);
}
private function onMouseDown(evt:MouseEvent):void
{
bgn.x = stage.mouseX;
bgn.y = stage.mouseY;
stage.addEventListener(MouseEvent.MOUSE_MOVE, drawLine);
}
private function onMouseUp(evt:MouseEvent):void
{
if(stage.hasEventListener(MouseEvent.MOUSE_MOVE)) {
stage.removeEventListener(MouseEvent.MOUSE_MOVE, drawLine);
}
}
private function drawLine(evt:MouseEvent):void
{
end.x = stage.mouseX;
end.y = stage.mouseY;
line.graphics.lineStyle(1.0, 0x000000, 1.0);
line.graphics.moveTo(bgn.x, bgn.y);
line.graphics.lineTo(end.x, end.y);
bmd.draw(line);
line.graphics.clear();
bgn = end.clone();
}
}
}
塗り
塗りを実現するためには、BitmapData の囲まれた領域を塗る floodFill を使う(実はこれを使うために trick7さんの方法を選択した)。塗りの始点と色を指定してやるだけだから簡単。
bmd.floodFill(stage.mouseX, stage.mouseY, 0x000000);
実際に塗ると以下のようになった。あまりにも悲惨すぎる!

アンチエイリアス
調べてみると graphics で描画した図形にはアンチエイリアスがかかってしまうようで、隙間無く囲まれた領域を塗るためにはアンチエイリアスをオフにする必要がある。更に厄介なことにアンチエイリアスは個別に指定できないらしく、stage.quality を LOW にするしか無い。
stage.quality = StageQuality.LOW;
1px の線を lineTo で連続して描画すると途切れてしまう
設定を変更してやってみると、今度は 1px の線を lineTo で連続して描画すると途切れてしまうケースが...。

このままでは floodFill で塗ると領域からはみ出してしまう。実験してみないと判らないけど、多分これは lineTo の始点と終点が被っているのが原因っぽい?ので、とりあえず始点(終点)の色と描画色が異なる場合は、マークを付けるようにしてみた。補間後の状態が以下の画像。ちゃんと補間できている。
if(bmd.getPixel(bgn.x, bgn.y) != 0x000000) {
bmd.setPixel(bgn.x, bgn.y, 0xff0000);
}

途切れていないので囲まれた領域を塗りつぶすことができる。

バケツツールを付きの Paint
これらの点を踏まえながら少し改良したものが以下。アンチエイリアス無しだと線がギザギザになって手振れ補正していないのがバレバレなので、ベジェ補間か線形補間でもう少し綺麗にした方がいいかもしれない。あと、FICC安藤さんの記事を参考にしてJpegで保存できるようにしてみた。上部パネルにある Upload ボタンで保存できます。
- Newer: MT4.01 から MT4.1 へ
- Older: MovableType における拡張子の簡単な隠し方
