2007年09月11日
BitmapData を使って文字列でマスク
残念ながら、ActionScript では TextField を使ってマスクすることはできません。画像をグラデーションに塗りたい、とか、写真を文字列くりぬきたい、といった要望には簡単には応えられません。
(追記 2009/9/9) cacheAsBitmap
を利用すれば簡単にマスクできました。詳しくは AS3.0 で TextField をマスクに使う簡単な方法 をご覧ください。
じゃあ、どうするかというと、BitmapData の出番です。技術的には BeInteractive! [BitmapDataを簡単にマスクする方法] と全く同じです。
サンプル Flash どーん。
中段のグラデーションに対して、上段の文字列をマスクとして利用しています。上段の文字列は編集できることからも分かるとおり、TextField です。
ソースコードは長いけど、肝はここ。
bmpDataText.draw(textField); bmpData.draw(grad); bmpData.copyChannel(bmpDataText, new Rectangle(0, 0, WIDTH, HEIGHT), new Point(0, 0), BitmapDataChannel.RED, BitmapDataChannel.ALPHA);
- bmpDataText に TextField を描画
- bmpData にグラデーションを描画
- bmpData に bmpDataText の Red チャンネルを Alpha チャンネルとしてコピー(テキストの濃淡データを透明度として設定している)。
別に Red チャンネルでなくて、Green でも Blue でもいいんですが、グレースケールなので全部同じ値なので気にしない。
あと、この Flash が秒速10KBずつぐらいのペースでメモリを食いつぶしていくんだけど、なんでだろう。 → (2007.9.12 追記) コメント欄で教えていただきました。グラデーションを描画する前に、graphics.clear() すれば問題なくなった。AS で上塗りする場合は、下に隠れている塗りの情報も保存され続けるようだ。これは知らなかったら絶対にはまる…。
長いけどソースコードは以下に(73行)。
package { import flash.display.*; import flash.events.*; import flash.geom.*; import flash.text.*; import flash.system.*; public class TextMask extends Sprite { private const WIDTH:int = 400; private const HEIGHT:int = 50; public function TextMask() { stage.scaleMode = "noScale"; stage.align = "TL"; stage.frameRate = 12; // text var tf:TextFormat = new TextFormat(); tf.size = HEIGHT * 2 / 3; tf.color = 0xffffff; var textField:TextField = new TextField(); textField.defaultTextFormat = tf; textField.text = "Hello, AS3.0!"; textField.type = "input"; textField.width = WIDTH; textField.height = HEIGHT; textField.background = true; textField.backgroundColor = 0; addChild(textField); // gradation var grad:Shape = new Shape(); grad.y = HEIGHT; addChild(grad); // output var bmpData:BitmapData = new BitmapData(WIDTH, HEIGHT); var bmp:Bitmap = new Bitmap(bmpData); bmp.y = HEIGHT * 2; addChild(bmp); // buffer var bmpDataText:BitmapData = new BitmapData(WIDTH, HEIGHT, false); // animation var angle:Number = 0; addEventListener("enterFrame", function(event:Event):void { angle += Math.PI / 16; angle = (angle >= Math.PI * 2 ? 0 : angle); // update gradation var matrix:Matrix = new Matrix(); matrix.createGradientBox(WIDTH, HEIGHT, angle); grad.graphics.clear(); grad.graphics.beginGradientFill(GradientType.LINEAR, [0xff9900, 0x0000ff], [100, 100], [0, 0xff], matrix); grad.graphics.drawRect(0, 0, WIDTH, HEIGHT); grad.graphics.endFill(); // cache textField as BitmapData bmpDataText.draw(textField); // mask it! bmpData.lock(); bmpData.draw(grad); bmpData.copyChannel(bmpDataText, new Rectangle(0, 0, WIDTH, HEIGHT), new Point(0, 0), BitmapDataChannel.RED, BitmapDataChannel.ALPHA); bmpData.unlock(); }); } } }