import java.io.FileOutputStream;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.Display;
import android.view.Surface;
import android.view.SurfaceControl;
import android.view.WindowManager;
public class StackBlurManager {
private static final String TAG = "StackBlurManager";
private static final int DEFAULT_SCALE = 8;
/**
* Original set of pixels from the image
*/
private int [] originalPixels;
/**
* Current set of pixels from the image (the one that will be exported
*/
private int [] currentPixels;
/**
* Original width of the image
*/
private int _width = -1;
/**
* Original height of the image
*/
private int _height= -1;
/**
* Original image
*/
private Bitmap _image;
private boolean alpha = true;
private Context mContext;
public StackBlurManager(Context context){
mContext = context;
}
private void init(Bitmap image) {
_width=image.getWidth();
_height=image.getHeight();
_image = image;
originalPixels= new int[_width*_height];
_image.getPixels(originalPixels, 0, _width, 0, 0, _width, _height);
}
private void process(int radius) {
if (radius < 1 )
radius = 1;
currentPixels = originalPixels.clone();
int wm=_width-1;
int hm=_height-1;
int wh=_width*_height;
int div=radius+radius+1;
int r[]=new int[wh];
int g[]=new int[wh];
int b[]=new int[wh];
int rsum,gsum,bsum,x,y,i,p,yp,yi,yw;
int vmin[] = new int[Math.max(_width,_height)];
int divsum=(div+1)>>1;
divsum*=divsum;
int dv[]=new int[256*divsum];
for (i=0;i<256*divsum;i++){
dv[i]=(i/divsum);
}
yw=yi=0;
int[][] stack=new int[div][3];
int stackpointer;
int stackstart;
int[] sir;
int rbs;
int r1=radius+1;
int routsum,goutsum,boutsum;
int rinsum,ginsum,binsum;
for (y=0;y<_height;y++){
rinsum=ginsum=binsum=routsum=goutsum=boutsum=rsum=gsum=bsum=0;
for(i=-radius;i<=radius;i++){
p=currentPixels[yi+Math.min(wm,Math.max(i,0))];
sir=stack[i+radius];
sir[0]=(p & 0xff0000)>>16;
sir[1]=(p & 0x00ff00)>>8;
sir[2]=(p & 0x0000ff);
rbs=r1-Math.abs(i);
rsum+=sir[0]*rbs;
gsum+=sir[1]*rbs;
bsum+=sir[2]*rbs;
if (i>0){
rinsum+=sir[0];
ginsum+=sir[1];
binsum+=sir[2];
} else {
routsum+=sir[0];
goutsum+=sir[1];
boutsum+=sir[2];
}
}
stackpointer=radius;
for (x=0;x<_width;x++){
// if (!alpha)
// alpha = (int)(Color.alpha(originalPixels[y*_height+x])) != 255;
r[yi]=dv[rsum];
g[yi]=dv[gsum];
b[yi]=dv[bsum];
rsum-=routsum;
gsum-=goutsum;
bsum-=boutsum;
stackstart=stackpointer-radius+div;
sir=stack[stackstart%div];
routsum-=sir[0];
goutsum-=sir[1];
boutsum-=sir[2];
if(y==0){
vmin[x]=Math.min(x+radius+1,wm);
}
p=currentPixels[yw+vmin[x]];
sir[0]=(p & 0xff0000)>>16;
sir[1]=(p & 0x00ff00)>>8;
sir[2]=(p & 0x0000ff);
rinsum+=sir[0];
ginsum+=sir[1];
binsum+=sir[2];
rsum+=rinsum;
gsum+=ginsum;
bsum+=binsum;
stackpointer=(stackpointer+1)%div;
sir=stack[(stackpointer)%div];
routsum+=sir[0];
goutsum+=sir[1];
boutsum+=sir[2];
rinsum-=sir[0];
ginsum-=sir[1];
binsum-=sir[2];
yi++;
}
yw+=_width;
}
for (x=0;x<_width;x++){
rinsum=ginsum=binsum=routsum=goutsum=boutsum=rsum=gsum=bsum=0;
yp=-radius*_width;
for(i=-radius;i<=radius;i++){
yi=Math.max(0,yp)+x;
sir=stack[i+radius];
sir[0]=r[yi];
sir[1]=g[yi];
sir[2]=b[yi];
rbs=r1-Math.abs(i);
rsum+=r[yi]*rbs;
gsum+=g[yi]*rbs;
bsum+=b[yi]*rbs;
if (i>0){
rinsum+=sir[0];
ginsum+=sir[1];
binsum+=sir[2];
} else {
routsum+=sir[0];
goutsum+=sir[1];
boutsum+=sir[2];
}
if(i<hm){
yp+=_width;
}
}
yi=x;
stackpointer=radius;
for (y=0;y<_height;y++){
// Preserve alpha channel: ( 0xff000000 & pix[yi] )
if ( alpha )
currentPixels[yi] = (0xff000000 & currentPixels[yi]) | (dv[rsum] << 16) | (dv[gsum] << 8) | dv[bsum];
else
currentPixels[yi]=0xff000000 | (dv[rsum]<<16) | (dv[gsum]<<8) | dv[bsum];
rsum-=routsum;
gsum-=goutsum;
bsum-=boutsum;
stackstart=stackpointer-radius+div;
sir=stack[stackstart%div];
routsum-=sir[0];
goutsum-=sir[1];
boutsum-=sir[2];
if(x==0){
vmin[y]=Math.min(y+r1,hm)*_width;
}
p=x+vmin[y];
sir[0]=r[p];
sir[1]=g[p];
sir[2]=b[p];
rinsum+=sir[0];
ginsum+=sir[1];
binsum+=sir[2];
rsum+=rinsum;
gsum+=ginsum;
bsum+=binsum;
stackpointer=(stackpointer+1)%div;
sir=stack[stackpointer];
routsum+=sir[0];
goutsum+=sir[1];
boutsum+=sir[2];
rinsum-=sir[0];
ginsum-=sir[1];
binsum-=sir[2];
yi+=_width;
}
}
}
/**
* Returns the blurred image as a bitmap
* @return blurred image
*/
private Bitmap returnBlurredImage() {
Bitmap newBmp = Bitmap.createBitmap(_image.getWidth(), _image.getHeight(), Config.ARGB_8888);
Canvas c = new Canvas(newBmp);
c.drawBitmap(_image, 0, 0, new Paint());
newBmp.setPixels(currentPixels, 0, _width, 0, 0, _width, _height);
return newBmp;
}
/**
* Save the image into the file system
* @param path The path where to save the image
*/
private void saveIntoFile(String path) {
Bitmap newBmp = Bitmap.createBitmap(_image.getWidth(), _image.getHeight(), Config.ARGB_8888);
Canvas c = new Canvas(newBmp);
c.drawBitmap(_image, 0, 0, new Paint());
newBmp.setPixels(currentPixels, 0, _width, 0, 0, _width, _height);
try {
FileOutputStream out = new FileOutputStream(path);
newBmp.compress(Bitmap.CompressFormat.PNG, 90, out);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* Returns the original image as a bitmap
* @return the original bitmap image
*/
private Bitmap getImage() {
return this._image;
}
private static Bitmap zoomBitmap(Bitmap bitmap, int w, int h) {
int width = bitmap.getWidth();
int height = bitmap.getHeight();
Matrix matrix = new Matrix();
float scaleWidht = ((float) w / width);
float scaleHeight = ((float) h / height);
matrix.postScale(scaleWidht, scaleHeight);
Bitmap newbmp = Bitmap.createBitmap(bitmap, 0, 0, width, height,
matrix, true);
return newbmp;
}
//获取模糊图片 (注调用该函数后,需要在窗口销毁时调用 destroy()函数释放资源)
public Bitmap GetBlurredBitmap(int bgWidth, int bgHeight, int scale){
Bitmap bitmap;
Bitmap newBmp;
Matrix matrix = new Matrix();
int screenWidth;
int screenHeight;
int rotation;
if(scale == -1){
scale = DEFAULT_SCALE;
}
if(_image != null){
_image.recycle();
_image = null;
}
//1、创建截屏图片
WindowManager windowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
Display display = windowManager.getDefaultDisplay();
DisplayMetrics displayMetrics = new DisplayMetrics();
display.getRealMetrics(displayMetrics);
screenWidth = displayMetrics.widthPixels;
screenHeight = displayMetrics.heightPixels;
rotation = display.getRotation();
Log.i(TAG, "screenWidth = "+screenWidth+" screenHeight = "+screenHeight);
float[] dims = {screenWidth, screenHeight};
float degrees = getDegreesForRotation(rotation);
boolean requiresRotation = (degrees > 0);
if (requiresRotation) {
// Get the dimensions of the device in its native orientation
matrix.reset();
matrix.preRotate(-degrees);
matrix.mapPoints(dims);
dims[0] = Math.abs(dims[0]);
dims[1] = Math.abs(dims[1]);
}
bitmap = SurfaceControl.screenshot((int) dims[0], (int) dims[1]);
if (requiresRotation) {
// Rotate the screenshot to the current orientation
Bitmap tmpBitmap = Bitmap.createBitmap(screenWidth, screenHeight, Bitmap.Config.ARGB_8888);
Canvas c = new Canvas(tmpBitmap);
c.translate(tmpBitmap.getWidth() / 2, tmpBitmap.getHeight() / 2);
c.rotate(degrees);
c.translate(-dims[0] / 2, -dims[1] / 2);
c.drawBitmap(bitmap, 0, 0, null);
c.setBitmap(null);
bitmap.recycle();
bitmap = tmpBitmap;
}
// If we couldn't take the screenshot, notify the user
if (bitmap == null) {
return null;
}
// Optimizations
bitmap.setHasAlpha(false);
bitmap.prepareToDraw();
Log.i(TAG, "bitmap.width = "+bitmap.getWidth()+" bitmap.getHeight = "+bitmap.getHeight());
newBmp = bitmap;
/*if(bgHeight < screenHeight){
newBmp = Bitmap.createBitmap(bgWidth, bgHeight, Bitmap.Config.ARGB_8888);
newBmp.setDensity(DisplayMetrics.DENSITY_DEVICE);
Canvas canvas = new Canvas(newBmp);
canvas.setDensity(DisplayMetrics.DENSITY_DEVICE);
canvas.drawBitmap(bitmap, 0, screenHeight - bgHeight, null);
bitmap.recycle();
bitmap = null;
}*/
//2、zoom bmp
Bitmap zoomBmp = zoomBitmap(newBmp, newBmp.getWidth() / scale, newBmp.getHeight() / scale);
newBmp.recycle();
newBmp = null;
Log.i(TAG, "zoomBmp.width = "+zoomBmp.getWidth()+" zoomBmp.getHeight = "+zoomBmp.getHeight());
//3、初始化模糊参数
init(zoomBmp);
//4、模糊化
process(9);
Bitmap blurredBmp = returnBlurredImage();
Log.i(TAG, "blurredBmp.width = "+blurredBmp.getWidth()+" blurredBmp.getHeight = "+blurredBmp.getHeight());
newBmp =zoomBitmap(blurredBmp, bgWidth, bgHeight);
Log.i(TAG, "newBmp.width = "+newBmp.getWidth()+" newBmp.getHeight = "+newBmp.getHeight());
blurredBmp.recycle();
blurredBmp = null;
return newBmp;
}
private float getDegreesForRotation(int value) {
switch (value) {
case Surface.ROTATION_90:
return 360f - 90f;
case Surface.ROTATION_180:
return 360f - 180f;
case Surface.ROTATION_270:
return 360f - 270f;
}
return 0f;
}
public void destroy(){
if(_image != null){
_image.recycle();
_image = null;
}
}
}
模糊图片获取方法:
1、在窗口中导入类:import com.sios.view.StackBlurManager;
2、调用StackBlurManager(context)初始化该类,只需要初始化一次;
3、调用StackBlurManager类的成员函数GetBlurredBitmap获取模糊图片,函数中参数
bgWidth, bgHeight为获取图片的宽和高,scale为图片模糊化系数,使用系统默
认模糊画参数,
该值需要设置为-1;
4、当窗口退出时,调用destroy()函数释放资源;
使用参考代码:
StackBlurManager mStackBlurManager = new StackBlurManager(context);
Bitmap blurredBmp =
mStackBlurManager.GetBlurredBitmap(controlWidth, controlHeight, -1);
Bitmap newBmp = Bitmap.createBitmap(controlWidth, controlHeight,
Bitmap.Config.ARGB_8888);
newBmp.setDensity(DisplayMetrics.DENSITY_DEVICE);
Canvas canvas = new Canvas(newBmp);
canvas.setDensity(DisplayMetrics.DENSITY_DEVICE);
canvas.drawBitmap(blurredBmp, 0, 0, null);
blurredBmp.recycle();
blurredBmp = null;