static Bitmap generateBitmap(Bitmap bm, int width, int height) {
if (bm == null) {
return null;
}
bm.setDensity(DisplayMetrics.DENSITY_DEVICE);
if (width <= 0 || height <= 0
|| (bm.getWidth() == width && bm.getHeight() == height)) {
return bm;
}
// This is the final bitmap we want to return.
try {
Bitmap newbm = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
newbm.setDensity(DisplayMetrics.DENSITY_DEVICE);
Canvas c = new Canvas(newbm);
Rect targetRect = new Rect();
targetRect.right = bm.getWidth();
targetRect.bottom = bm.getHeight();
int deltaw = width - targetRect.right;
int deltah = height - targetRect.bottom;
if (deltaw > 0 || deltah > 0) {
// We need to scale up so it covers the entire area.
float scale;
if (deltaw > deltah) {
scale = width / (float)targetRect.right;
} else {
scale = height / (float)targetRect.bottom;
}
targetRect.right = (int)(targetRect.right*scale);
targetRect.bottom = (int)(targetRect.bottom*scale);
deltaw = width - targetRect.right;
deltah = height - targetRect.bottom;
}
targetRect.offset(deltaw/2, deltah/2);
Paint paint = new Paint();
paint.setFilterBitmap(true);
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC));
c.drawBitmap(bm, null, targetRect, paint);
bm.recycle();
c.setBitmap(null);
return newbm;
} catch (OutOfMemoryError e) {
Log.w(TAG, "Can't generate default bitmap", e);
return bm;
}
}
该函数是生成一个固定大小 width * height 的 Bitmap 图像,源图像是由参数bm传递进来的 Bitmap 图像。
以系统自带壁纸为例,它们的分辨率都是1920*1280的,假如这里传入的参数width=800,,height=600,其实这里的width和height都是从文件/data/system/wallpaper_info.xml中读取到的,
/data/system # cat wallpaper_info.xml
<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
<wp width="800" height="600" name="res:com.android.launcher:drawable/wallpaper_chroma" />
我们先创建一个width*height大小的空图像,这也是最终要返回的,
Bitmap newbm = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
接下来,进行的就是裁切工作,
根据代码流程,首先是定义了原始区域,即蓝色虚框
targetRect.right = bm.getWidth();
targetRect.bottom = bm.getHeight();
然后进行偏移,即红色虚框
targetRect.offset(deltaw/2, deltah/2);
然后在可见的虚框区域,裁剪出指定的大小
c.drawBitmap(bm, null, targetRect, paint);
这个时候的targetRect已经向左上方偏移了,可见区域变小,c是一个Canvas变量,类似定义了大小的一块画布,这块画布就是绿色区域标识的部分。
代码是按照上述方式实现的,但逻辑上,其实就是居中截取原始图像。