AndroidでBitmapにグロー的な効果をつけるには?
AndroidでBitmapにこのようなグロー的な効果をつけるには?
ビットマップをBlurMaskFilterを使って描画してもボケない
ドキュメントを見るとBlurMaskFilterというのがあるので、これを使うのだろうなとは思った。
CanvasにBitmapを描画する時にBlurMaskFilterをセットしたPaintを使うようだ。素直に書いてみるなら、こんな感じになるだろう。
しかし、これがまったくボケない_| ̄|○
こちらのページを見ると、少なくともベクターグラフィックスを描画する場合には思ったとおりにボケるようなのだけど・・・
About Android: 2D graphics with Effects
どうやらビットマップの場合は違うらしい。
extractAlpha()がキモ
「BlurMaskFilter」という名前は「BlurFilter」ではなく「Mask」がついていることを考えると、何か特殊な使い方が必要なのかもしれないと思ってさらに調べると、こちらが参考になった。
paint - How to prevent Android's drawBitmap from only drawing black images? - Stack Overflow
オリジナルのビットマップからextractAlpha()を使ってアルファチャンネルのビットマップを作るところがポイントらしい。
アプリ動作ビデオとEclipseプロジェクトファイル
Eclipseプロジェクトファイル:GlowEffect.zip(157KB)
コード
res/layout/main.xml
GlowEffectView.java
コードのポイント
ポイント1:extractAlpha()する時にBlurMaskFilterをセットしたPaintが必要なところ
ポイント2:UPグラフィックスをぼかしたグラフィックス「bmpGlow」は薄いので、数回描画して濃くするところ
失敗例
onDraw()内に、試してみたもののダメだった例も残しておいた。
ダメな例1はUPグラフィックスの状態から全く変わらず。
ダメな例2(setShadowLayer()を使う方)はこのようになってしまった。
画像の「中」をぼかしたい場合は?
今回は何とか画像の「シェイプ」をぼかすことはできた。
その試行錯誤の中でBlurMaskFilterは普通のBlurFilterではないということがわかり、また新たな疑問が出てくる。
例えば、画像の「中」をぼかしたい場合はどうするのか?どうやらこうするらしい。
untitled: androidで簡単な画像処理をする
つまり、自分でピクセル操作をする!何ていうか、Old Schoolだなぁ・・・BlurFilterくらいは標準ライブラリで欲しいよ〜
Flashならスプライト自体にフィルターをかけられるけど、それもできなさそうだし。AndroidならView.setFilter()的な。Flashはこのあたり、すごく楽だったんだなと実感。
しかし、Androidでも最近のAPIではPixelBenderみたいなことをするAPIがあるかもしれないので、さらに探してみる必要はある。
ビットマップをBlurMaskFilterを使って描画してもボケない
ドキュメントを見るとBlurMaskFilterというのがあるので、これを使うのだろうなとは思った。
CanvasにBitmapを描画する時にBlurMaskFilterをセットしたPaintを使うようだ。素直に書いてみるなら、こんな感じになるだろう。
Paint paint = new Paint(); paint.setColor(0xFFFF0000); paint.setMaskFilter(new BlurMaskFilter(15, Blur.NORMAL)); canvas.drawBitmap(bitmap, 0, 0, paint);
しかし、これがまったくボケない_| ̄|○
こちらのページを見ると、少なくともベクターグラフィックスを描画する場合には思ったとおりにボケるようなのだけど・・・
About Android: 2D graphics with Effects
どうやらビットマップの場合は違うらしい。
extractAlpha()がキモ
「BlurMaskFilter」という名前は「BlurFilter」ではなく「Mask」がついていることを考えると、何か特殊な使い方が必要なのかもしれないと思ってさらに調べると、こちらが参考になった。
paint - How to prevent Android's drawBitmap from only drawing black images? - Stack Overflow
オリジナルのビットマップからextractAlpha()を使ってアルファチャンネルのビットマップを作るところがポイントらしい。
アプリ動作ビデオとEclipseプロジェクトファイル
Eclipseプロジェクトファイル:GlowEffect.zip(157KB)
コード
res/layout/main.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" > <jp.example.GlowEffectView android:id="@+id/glowEffectView1" android:layout_width="wrap_content" android:layout_height="wrap_content" /> </LinearLayout>
GlowEffectView.java
package jp.example; import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.BlurMaskFilter; import android.graphics.BlurMaskFilter.Blur; import android.graphics.Canvas; import android.graphics.Paint; import android.util.AttributeSet; import android.view.MotionEvent; import android.view.View; public class GlowEffectView extends View { protected Bitmap bmpOnScreen; protected Bitmap bmpUp; protected Bitmap bmpDown; public GlowEffectView(Context context, AttributeSet attrs) { super(context, attrs); setClickable(true); // これをしないとタッチイベントがDOWNのみになる int radius = 15; int[] offsetXY = { 0, 0 }; Paint paint = new Paint(); paint.setColor(0xFF873955); // グローの色になる paint.setMaskFilter(new BlurMaskFilter(radius, Blur.NORMAL)); bmpUp = BitmapFactory.decodeResource(getResources(), R.drawable.image); Bitmap bmpGlow = bmpUp.extractAlpha(paint, offsetXY); // paintを指定する bmpDown = Bitmap.createBitmap(bmpUp.getWidth(), bmpUp.getHeight(), Bitmap.Config.ARGB_8888); Canvas cv = new Canvas(bmpDown); // DOWNグラフィックスを描画するキャンバス cv.drawBitmap(bmpGlow, offsetXY[0], offsetXY[1], paint); // ここでもpaintは必要 cv.drawBitmap(bmpGlow, offsetXY[0], offsetXY[1], paint); // 1回だけだと薄いので数回描画しておく cv.drawBitmap(bmpGlow, offsetXY[0], offsetXY[1], paint); // 1回だけだと薄いので数回描画しておく cv.drawBitmap(bmpGlow, offsetXY[0], offsetXY[1], paint); // 1回だけだと薄いので数回描画しておく cv.drawBitmap(bmpGlow, offsetXY[0], offsetXY[1], paint); // 1回だけだと薄いので数回描画しておく cv.drawBitmap(bmpGlow, offsetXY[0], offsetXY[1], paint); // 1回だけだと薄いので数回描画しておく cv.drawBitmap(bmpUp, 0, 0, null); // Glowエフェクトグラフィックスの上にUPグラフィックスを重ねる bmpOnScreen = bmpUp; // はじめに描画するのはUPグラフィックス } @Override public boolean onTouchEvent(MotionEvent event) { // タッチイベントによってステートを変える switch (event.getAction()) { case MotionEvent.ACTION_UP: bmpOnScreen = bmpUp; break; case MotionEvent.ACTION_DOWN: bmpOnScreen = bmpDown; break; } // 再描画リクエスト invalidate(); return super.onTouchEvent(event); } @Override protected void onDraw(Canvas canvas) { int mode = 0; switch (mode) { // 正解 case 0: canvas.drawBitmap(bmpOnScreen, 0, 0, null); break; // ダメな例1:まったくボケない case 1: Paint paint1 = new Paint(); paint1.setColor(0xFF873955); paint1.setMaskFilter(new BlurMaskFilter(15, Blur.NORMAL)); canvas.drawBitmap(bmpUp, 0, 0, paint1); break; // ダメな例2:ボケた影がつくかと思ったらつかないし、影の色も変わらない case 2: Paint paint2 = new Paint(); paint2.setShadowLayer(15, 4, 4, 0xFFFF0000); canvas.drawBitmap(bmpUp, 0, 0, paint2); break; } super.onDraw(canvas); } }
コードのポイント
ポイント1:extractAlpha()する時にBlurMaskFilterをセットしたPaintが必要なところ
ポイント2:UPグラフィックスをぼかしたグラフィックス「bmpGlow」は薄いので、数回描画して濃くするところ
失敗例
onDraw()内に、試してみたもののダメだった例も残しておいた。
ダメな例1はUPグラフィックスの状態から全く変わらず。
ダメな例2(setShadowLayer()を使う方)はこのようになってしまった。
画像の「中」をぼかしたい場合は?
今回は何とか画像の「シェイプ」をぼかすことはできた。
その試行錯誤の中でBlurMaskFilterは普通のBlurFilterではないということがわかり、また新たな疑問が出てくる。
例えば、画像の「中」をぼかしたい場合はどうするのか?どうやらこうするらしい。
untitled: androidで簡単な画像処理をする
つまり、自分でピクセル操作をする!何ていうか、Old Schoolだなぁ・・・BlurFilterくらいは標準ライブラリで欲しいよ〜
Flashならスプライト自体にフィルターをかけられるけど、それもできなさそうだし。AndroidならView.setFilter()的な。Flashはこのあたり、すごく楽だったんだなと実感。
しかし、Androidでも最近のAPIではPixelBenderみたいなことをするAPIがあるかもしれないので、さらに探してみる必要はある。
コメント
コメントを投稿