AndroidのBitmap画像プログラミング(3) αブレンディング
AndroidのBitmap画像プログラミングの第三回はαブレンディングを紹介します。
αブレンドとは転送先のカラー情報の上に、任意の不透明度の転送元カラー情報で上書きすることです。
矩形転送でのサンプルを用意しました。
今回は画像バッファを3つ用意し、土台となる200×200を黒で塗りつぶしたバッファに2つの画像バッファをαブレンド転送しています。
一つは150×150の赤色で塗りつぶした四角形。
もう一つは150×150の青色で塗りつぶした四角形で不透明度を200、つまり各カラーの1byte目を0x7fにしています。
画像を見ていただくと、重なった部分がブレンドされて赤紫っぽい色になっているのが分かると思います。
/**
* バッファ間クリップ矩形転送
*
* @param : ImageBuffer : src : 転送元画像バッファ
* @param : ClipBltInfo : info : 転送情報
* @return :
* @author : N.Nishimura
* @version : 1.0
* @since : 2011/02/22 1.0
*/
public void BltClipAlphaBlend(ImageBuffer src, ImageBuffer.ClipBltInfo info)
{
ImageBuffer.ClipInfo ss, ds;
ss = new ImageBuffer.ClipInfo(src.GetWidth(), src.GetHeight());
ds = new ImageBuffer.ClipInfo(GetWidth(), GetHeight());
// 転送領域なし
if (!CheckClipBlt(ss, ds, info)) {
return;
}
int[] src_buffer = src.GetBuffer();
ImageBuffer.ARGB sc = new ImageBuffer.ARGB();
ImageBuffer.ARGB dc = new ImageBuffer.ARGB();
ImageBuffer.ARGB c = new ImageBuffer.ARGB();
for (int y = info.dy; y < info.dy + info.h; y++) {
int sx = src.GetPixelAddress(info.sx, info.sy + y - info.dy);
int dx = GetPixelAddress(info.dx, y);
for (int x = 0; x < info.w; x++) {
sc.SetColor(src_buffer[sx + x]);
dc.SetColor(mBuffer[dx + x]);
c.a = dc.a;
c.r = dc.r + (((sc.r - dc.r) * (sc.a + 1)) >>> 8);
c.g = dc.g + (((sc.g - dc.g) * (sc.a + 1)) >>> 8);
c.b = dc.b + (((sc.b - dc.b) * (sc.a + 1)) >>> 8);
mBuffer[dx + x] = c.GetColor();
}
}
src_buffer = null;
}
/**
* 32bitカラー成分クラス
*
* @author : N.Nishimura
* @version : 1.0
* @since : 2011/02/22 1.0
*/
private class ARGB
{
public int a;
public int r;
public int g;
public int b;
public ARGB()
{
a = 0;
r = 0;
g = 0;
b = 0;
}
public ARGB(int color)
{
a = (color >>> 24) & 0xff;
r = (color >>> 16) & 0xff;
g = (color >>> 8) & 0xff;
b = color & 0xff;
}
public void SetColor(int color)
{
a = (color >>> 24) & 0xff;
r = (color >>> 16) & 0xff;
g = (color >>> 8) & 0xff;
b = color & 0xff;
}
public int GetColor()
{
return ((a << 24) + (r << 16) + (g << 8) + b);
}
}
Activity
package net.n2works.BitmapTest;
// SYSTEM PACKAGE
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.PorterDuff.Mode;
import android.os.Bundle;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
public class BitmapTest extends Activity
{
// Bitmap
private Bitmap mBitmap;
/**
* Component
*/
// SurfaceView
private SurfaceView mView;
/**
* クラス定数
*/
private final int BG_COLOR = 0xff000000;
private final int BITMAP_W = 200;
private final int BITMAP_H = 200;
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
int child_w = BITMAP_W * 3 / 4;
int child_h = BITMAP_H * 3 / 4;
// 下地の作成
ImageBuffer buf = new ImageBuffer(BITMAP_W, BITMAP_H);
buf.FillClip(
buf.new ClipFillInfo(
0,
0,
BITMAP_W,
BITMAP_H,
0xff000000
)
);
// 四角形1
ImageBuffer buf2 = new ImageBuffer(child_w, child_h);
buf2.FillClip(
buf2.new ClipFillInfo(
0,
0,
child_w,
child_h,
0xffff0000
)
);
// 四角形2
ImageBuffer buf3 = new ImageBuffer(child_w, child_h);
buf3.FillClip(
buf3.new ClipFillInfo(
0,
0,
child_w,
child_h,
0x7f0000ff
)
);
// アルファブレンド処理
buf.BltClipAlphaBlend(
buf2,
buf.new ClipBltInfo(
0,
0,
0,
0,
child_w,
child_h
)
);
buf.BltClipAlphaBlend(
buf3,
buf.new ClipBltInfo(
0,
0,
50,
50,
child_w,
child_h
)
);
mBitmap = Bitmap.createBitmap(BITMAP_W, BITMAP_H, Bitmap.Config.ARGB_8888);
mBitmap.setPixels(buf.GetBuffer(), 0, BITMAP_W, 0, 0, BITMAP_W, BITMAP_H);
// Viewの設定
mView = new SurfaceViewEx(this);
setContentView(mView);
}
private class SurfaceViewEx extends SurfaceView
implements SurfaceHolder.Callback
{
/**
* Component
*/
private ScheduledExecutorService executor;
/**
* クラス定数
*/
private static final int FPS = 60;
public SurfaceViewEx(Context context)
{
super(context);
getHolder().addCallback(this);
getHolder().setType(SurfaceHolder.SURFACE_TYPE_GPU);
}
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height)
{
}
public void surfaceCreated(SurfaceHolder holder)
{
executor = Executors.newSingleThreadScheduledExecutor();
executor.scheduleAtFixedRate(
new Runnable()
{
public void run()
{
Canvas c = getHolder().lockCanvas();
Draw(c);
getHolder().unlockCanvasAndPost(c);
}
},
1000 / FPS, 1000 / FPS,
TimeUnit.MILLISECONDS
);
}
public void surfaceDestroyed(SurfaceHolder holder)
{
mBitmap.recycle();
executor.shutdown();
}
protected void Draw(Canvas c)
{
// 背景色クリア
c.drawColor(BG_COLOR, Mode.SCREEN);
// Bitmap描画
c.drawBitmap(mBitmap, 0, 0, null);
}
}
}