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();
});
}
}
}