外部ファイル (JPEG、GIF、PNG、または Flash ムービー) を BitmapData クラスのインスタンスに直接ロードすることはできません。そのような場合は、まずムービークリップに外部ファイルをロードし、そのロード処理が完了するのを待ってから、ムービークリップのスナップショットを作成します。
import flash.display.BitmapData
// 外部ファイルを格納するムービークリップを作成
this.createEmptyMovieClip("holder_mc",this.getNextHighestDepth());
/*
MovieClipLoader クラスを使用して、
外部ファイルのロード処理の成否について通知を受け取る
*/
loader = new MovieClipLoader()
// イベントの発生によってステータスの変化を検出
loader.addListener(this)
// 外部ファイルをムービークリップにロード
loader.loadClip("logo.png",holder_mc)
// ファイルのロードが完了して使用できる状態になると "ローダー" オブジェクトから呼び出される関数
function onLoadInit()
{
/*
ロードするファイルと同じサイズでビットマップオブジェクトを
メモリ内に作成、透明のピクセルで塗りつぶし
*/
myBitmap = new BitmapData(holder_mc._width, holder_mc._height,true,0x00FFFFFF)
// ロードした外部ファイルを含んだムービークリップのスナップショットを作成
myBitmap.draw(holder_mc)
// 不要になったムービークリップを削除
holder_mc.removeMovieClip()
}
// ファイルをロードできない場合に "ローダー" オブジェクトから呼び出される関数
function onLoadError()
{
/*
外部ファイルをロードできなかったので、
格納用のムービークリップは不要
*/
holder_mc.removeMovieClip()
}
フィルタの詳細についてはこの記事で取り上げませんが、ビットマップのノイズを低減する場合やエッジをソフトにする場合にぼかしを適用するなど、イメージの処理ではフィルタが必要となることがよくあるので、ビットマップにフィルタを適用する方法について若干説明しておきます。ビットマップには、BitmapData.applyFilter() メソッドによって直接にフィルタを適用できます。Flash Player では置き換え、ぼかし、グロー、ドロップシャドウ、ベベルなど多様なフィルタエフェクトがサポートされています。いずれのフィルタも、ビットマップ全体、またはビットマップ内の矩形領域に対して適用できます。次に示すコードでは、ライブラリからロードしたビットマップに対し、ぼかしフィルタによってぼかし処理を適用します。
import flash.filters.BlurFilter
import flash.display.BitmapData
// ビットマップをライブラリからロード
myBitmap = BitmapData.loadBitmap("landscape")
// ぼかしフィルタを作成
blur=new BlurFilter(5,5,2)
// ロードしたビットマップにぼかしフィルタを適用
myBitmap.applyFilter(myBitmap,myBitmap.rectangle,myBitmap.rectangle.topLeft,blur)
applyFilter() メソッドの第 2 パラメータでは、フィルタの適用対象とする矩形領域を指定できます。上の例ではビットマップの rectangle プロパティを渡しています。これはそのイメージのサイズを表す flash.geom.Rectangle クラスのインスタンスを返すプロパティなので、ビットマップ全体にフィルタを適用することになります。次のように、Rectangle クラスのインスタンスを自分で作成して applyFilter() メソッドの第 2 パラメータに渡せば、ビットマップ内の特定の領域だけに対してフィルタを適用することもできます。
import flash.filters.BlurFilter
import flash.display.BitmapData
import flash.geom.Rectangle
// ビットマップをライブラリからロード
myBitmap = BitmapData.loadBitmap("landscape")
// ぼかしフィルタを作成
blur=new BlurFilter(5,5,2)
// フィルタの適用先を指定する矩形領域を定義
region=new Rectangle(0,0,50,50)
// ロードしたビットマップにぼかしフィルタを適用
myBitmap.applyFilter(myBitmap,region,myBitmap.rectangle.topLeft,blur)
ビットマップ全体にフィルタを適用すると、場合によっては元のビットマップよりも大きいビットマップができることがあるので注意が必要です。たとえば、DropShadow フィルタを使用するとビットマップの周囲にピクセルが追加されるので、フィルタを適用した元のビットマップよりも大きいビットマップが生成されます。DropShadow フィルタエフェクトの distance を 20 ピクセルに、angle を 45 度に指定して、幅と高さが 100 ピクセルのビットマップに適用すると、結果のイメージは、幅、高さとも元のイメージより 16 ピクセル大きくなります。しかし、このことを意識していないと、BitmapData オブジェクトを作成してサイズを定義した後になって問題が発生する可能性があります。BitmapData オブジェクトは作成後にサイズを変更できないからです。
幸い、結果のイメージのサイズをフィルタ適用前に調べる方法が用意されているので、結果を格納するビットマップのサイズをあらかじめそれに合わせておくことができます。
import flash.filters.DropShadowFilter
import flash.display.BitmapData
// ビットマップをライブラリからロード
myBitmap = BitmapData.loadBitmap("logo")
// デフォルトのドロップシャドウフィルタを作成
dropShadow = new DropShadowFilter()
// フィルタ適用後のビットマップのサイズを確認
filteredSize=myBitmap.generateFilterRect(myBitmap.rectangle,dropShadow)
// 左上隅の座標値が負なら、幅と高さを増やすことが必要
w=(filteredSize.x<0) ? filteredSize.width-filteredSize.x :filteredSize.width
h=(filteredSize.y<0) ? filteredSize.height-filteredSize.y :filteredSize.height
// ロードしたビットマップが透明の場合は透明のピクセルで塗りつぶし、そうでない場合は白のピクセルで塗りつぶす
fillColor=(myBitmap.transparent) ?0x00FFFFFF :0xFFFFFFFF
// フィルタの適用結果を格納する新しいビットマップを作成
filteredBitmap = new BitmapData(w,h,myBitmap.transparent,fillColor)
// ロードしたビットマップにフィルタを適用
filteredBitmap.applyFilter(myBitmap,myBitmap.rectangle,myBitmap.rectangle.topLeft,dropShadow)
ビットマップ内の任意のピクセルを指定して、そのカラー値を調べるには、BitmapData.getPixel() メソッドを使用します。指定した x / y 座標にあるピクセルの RGB カラー値が 10 進数値で返されます。
import flash.display.BitmapData myBitmap = new BitmapData(100,100,false,0xFFCC00) pixelColor=myBitmap.getPixel(50,50)
10 進数で返されたカラー値の 16 進表現を得る必要がある場合は、toString() メソッドを、オプションの radix パラメータに 16 を指定して呼び出すことにより、16 進表現のストリングに変換します。
trace("0x"+pixelColor.toString(16)) // 出力 : 0xffcc00
アルファチャンネルデータを含んだ (BitmapData.transparent == true) ビットマップの場合、getPixel() メソッドの戻り値にはアルファチャンネルの値が乗算されています。ピクセルのアルファチャンネルの強さとカラー値を乗算した値が返されるので、意図と異なる結果を生じることがないように注意してください。
BitmapData.getPixel32() メソッドでは、指定した x / y 座標にあるピクセルの ARGB カラー値が 10 進数値で返されます。getPixel() とは違い、このメソッドではアルファチャンネルのデータも一緒に取得できます。
import flash.display.BitmapData
myBitmap = new BitmapData(100,100,true,0x11FFCC00)
pixelColor=myBitmap.getPixel32(50,50)
trace("0x"+pixelColor.toString(16)) // 出力 : 0x11ffd200
ピクセルのカラーを設定するには、BitmapData.setPixel() メソッドを使用します。このメソッドは、指定した x / y 座標にあるピクセルを指定したカラーに変更します。カラーは 24 ビットの 16 進数 (たとえば、黄色なら 0xFFCC00) で指定します。アルファチャンネルのビットは無視されます。次に例を示します。
myBitmap = BitmapData.load("photo")
// ピクセル 100 個のカラーを変更
for(i=0;i<100;++i)
{
// ランダムな x / y 座標を 2 つ生成
rx1=Math.floor(Math.random()*myBitmap.width)
rx2=Math.floor(Math.random()*myBitmap.width)
ry1=Math.floor(Math.random()*myBitmap.height)
ry2=Math.floor(Math.random()*myBitmap.height)
// ランダムなピクセルの一方に、もう一方と同じカラーを設定
myBitmap.setPixel(rx1,ry1,myBitmap.getPixel(rx2,ry2))
}
このメソッドは、アルファ透明度 (BitmapData.transparent) を含まないビットマップに対して使用します。アルファを使用するビットマップには BitmapData.setPixel32() メソッドを使用してください。setPixel32() メソッドには、アルファチャンネルのデータを含む 32 ビットの 16 進値を指定できます。
myBitmap.setPixel32(50,50,0xFFFFCC00) // x:50、y:50 のピクセルを不透明の黄色に設定
矩形領域に含まれるピクセルのグループに特定のカラーを設定するには、fillRect() メソッドを使用します。このメソッドは、ビットマップを元の状態に戻す必要がある場合に便利です。ビットマップ全体を同じカラーで塗りつぶすと、結果的に内容を消去できるからです。
メソッドの第 1 パラメータには、塗りつぶす矩形領域を、flash.geom.Rectangle クラスのインスタンスで指定します。第 2 パラメータには、矩形領域を塗りつぶすカラーを指定します。
矩形領域を指定するには、まず、次のようにして Rectangle クラスの完全修飾パスを読み込んでおきます。Rectangle クラスは flash.geom パッケージに属しています。
Import flash.geom.Rectangleそれから、次のようなコードで矩形のインスタンスを作成します。
myRect=new Rectangle(0,0,100,100)
最初の 2 つのパラメータでは矩形の左上隅の x / y 座標を、その後の 2 つのパラメータでは矩形のサイズ (幅と高さ) を指定します。
次に、特定のカラーでその領域を塗りつぶします。
myBitmap.fillRect(myRect,0xFFFF0000) // 指定した領域のピクセルをすべて赤に設定
BitmapData クラスのすべてのインスタンスには、そのビットマップオブジェクトのサイズと位置を返すプロパティがあります。位置は常に 0,0 になるため、実際には、BitmapData クラスの大半のメソッドに必要となる形式でサイズの情報を取得するために使用します。そのプロパティは BitmapData.rectangle で、Rectangle クラスのインスタンスを返します。
// ビットマップ全体を緑のピクセルで塗りつぶし myBitmap.fillRect(myBitmap.rectangle,0xFF00FF00);
イメージ内のすべてのピクセルに対してカラーの変更を加える際、ループによって各ピクセルを操作するのは、非常に面倒で重い処理になります。しかし、カラー値が特定のカラーの範囲内にあるピクセルだけを変更する場合や、特定のカラー値を持つピクセルだけをすべて変更する場合には、個々のピクセルをループで処理する必要はありません。BitmapData.threshold() メソッドを使用すると、カラーが特定の範囲内にあるピクセルだけを対象として、カラーの置換やその他の論理演算を実行できます。たとえば、次のコードでは、イメージ内にある赤のピクセルをすべて透明にすることができます。
import flash.display.BitmapData import flash.geom.Rectangle // 100 * 100 の新しいビットマップを作成し、赤のピクセルで塗りつぶす myBitmap = new BitmapData(100,100,true,0xFFFF0000) // ビットマップ中央の 20 * 20 の正方形に相当する矩形領域を定義 centeredRectangle=new Rectangle(40,40,20,20) // ビットマップ中央の矩形領域を黒のピクセルで塗りつぶす myBitmap.fillRect(centeredRectangle,0xFF000000) // ビットマップ内の赤のピクセルをすべて透明に変更 redPixelCount=myBitmap.threshold(myBitmap,myBitmap.rectangle,myBitmap.rectangle.topLeft,"==",0xFFFF0000,0x00FFFFFF)
BitmapData.threshold() メソッドの戻り値には、操作の対象となったピクセルの個数が返されます。
trace(redPixelCount)
threshold メソッドの第 4 パラメータには、次のいずれかのストリングを渡すことで、演算の種類を指定します。
> == != < <= >=
たとえば、演算パラメータとして != を指定することにより、特定のカラーに該当しないピクセルすべてを変更することなどができます。次に例を示します。
myBitmap.threshold(myBitmap,myBitmap.rectangle,myBitmap.rectangle.topLeft,"!=",0xFFFF0000,0x00FFFFFF)
ピクセルのコピーは、イメージ処理で日常的に必要となる操作です。あるビットマップ内のピクセルを別のビットマップにコピーするには、BitmapData.copyPixels() メソッドを使用します。このメソッドは、コピー元ビットマップ内の指定した矩形領域を、コピー先ビットマップ内の指定した場所にコピーします。これを使用すると、ジグソーパズルなどを作成できます。さらに、アルファチャンネルデータを含んだ第 2 のイメージを用意し、コピー処理のマスクとして使用することもできます。これにより、形が矩形でない領域のコピーが可能となります。
次の例では、ビットマップ内の矩形領域を別のビットマップにコピーします。
import flash.display.BitmapData
import flash.geom.Rectangle
// ビットマップをライブラリからアタッチ
myBitmap = BitmapData.loadBitmap("logo")
// 元のビットマップからコピーする領域を定義
area=new Rectangle(10,10,50,50)
// コピーしたピクセルを格納する新しいビットマップを作成
bitmapSlot=new BitmapData(50,50)
// ロードしたビットマップの指定した領域にあるピクセルを、左上隅にコピー
bitmapSlot.copyPixels(myBitmap,area,bitmapSlot.rectangle.topLeft)
この例では、円形の周囲に透明のピクセルを含んだビットマップをアルファマスクとして使用し、ビットマップ内の円形の領域を別のビットマップにコピーします。
import flash.display.BitmapData
import flash.geom.Rectangle
import flash.geom.Matrix
// ビットマップをライブラリからアタッチ
myBitmap = BitmapData.loadBitmap('logo')
// ムービークリップ内に円形を描画
this.createEmptyMovieClip('mask_mc',1)
mask_mc.lineStyle(75,0x00FF00)
// 直径 75 の円形が作成される
mask_mc.lineTo(0,1)
// アルファマスクを格納するビットマップを作成
maskBitmap = new BitmapData(100,100,true,0x00FFFFFF)
// 変換マトリックスを作成
m=new Matrix()
// ムービークリップをビットマップに描画する際の位置を変更
m.translate(50,50)
// ビットマップ内に円形を描画
maskBitmap.draw(mask_mc,m)
// 円形を含んだムービークリップは不要になったので削除
mask_mc.removeMovieClip()
// ライブラリからロードしたビットマップからコピーしたピクセルを格納するビットマップを作成
// 透明のピクセルで塗りつぶし
circleBitmap=new BitmapData(100,100,true,0x00FFFFFF)
// 円形を含んだビットマップをアルファマスクとして使用し、ライブラリからロードしたビットマップのピクセルをコピー
circleBitmap.copyPixels(myBitmap,myBitmap.rectangle,circleBitmap.rectangle.topLeft,maskBitmap,maskBitmap.rectangle.topLeft)
// ビットマップを表示
this.attachBitmap(circleBitmap,1)
// 不要になったマスク用ビットマップを破棄
maskBitmap.dispose()
新しいイメージ API を使用したサンプルコードをオンラインに多数用意してあります。www.flashguru.co.uk/maelstromを参照してください。