@SuppressWarnings("PMD.CompareObjectsWithEquals")
@Override
protected Bitmap transform(BitmapPool pool, Bitmap toTransform, int outWidth, int outHeight) {
final Bitmap toReuse = pool.get(outWidth, outHeight, toTransform.getConfig() != null
? toTransform.getConfig() : Bitmap.Config.ARGB_8888);
Bitmap transformed = TransformationUtils.centerCrop(toReuse, toTransform, outWidth, outHeight);
if (toReuse != null && toReuse != transformed && !pool.put(toReuse)) {
toReuse.recycle();
}
return transformed;
}
首先從Bitmap緩存池中取出一個目標寬高的可用的Bitmap(爲了節省創建bitmap的開銷,可能爲null),然後交由TransformationUtils去完成圖片變換,最後看這個bitmap能否回收。
看看這個執行變換的centerCrop:
public static Bitmap centerCrop(Bitmap recycled, Bitmap toCrop, int width, int height) {
if (toCrop == null) {
return null;
} else if (toCrop.getWidth() == width && toCrop.getHeight() == height) {
return toCrop;
}
// From ImageView/Bitmap.createScaledBitmap.
final float scale;
float dx = 0, dy = 0;
Matrix m = new Matrix();
if (toCrop.getWidth() * height > width * toCrop.getHeight()) {
scale = (float) height / (float) toCrop.getHeight();
dx = (width - toCrop.getWidth() * scale) * 0.5f;
} else {
scale = (float) width / (float) toCrop.getWidth();
dy = (height - toCrop.getHeight() * scale) * 0.5f;
}
m.setScale(scale, scale);
m.postTranslate((int) (dx + 0.5f), (int) (dy + 0.5f));
final Bitmap result;
if (recycled != null) {
result = recycled;
} else {
result = Bitmap.createBitmap(width, height, getSafeConfig(toCrop));
}
// We don't add or remove alpha, so keep the alpha setting of the Bitmap we were given.
TransformationUtils.setAlpha(toCrop, result);
Canvas canvas = new Canvas(result);
Paint paint = new Paint(PAINT_FLAGS);
canvas.drawBitmap(toCrop, m, paint);
return result;
}
主要藉助了Matrix設置縮放比和原圖中可用部分的起始座標,然後drawBitmap把原圖畫到結果bitmap的畫布上。
首先判斷原圖和目標圖的寬高比,如果原圖比較胖則取result.height/beforeHeight作爲縮放比,接下來再計算原圖中起始點的座標就可以了。
我們想要的效果是
照葫蘆畫瓢,我們也來自定義一個CircleTrans繼承BitmapTransmation,getId方法隨便返回一個字符串作爲本轉換的唯一標識即可,主要是對transform的實現:
@Override
protected Bitmap transform(BitmapPool pool, Bitmap toTransform, int outWidth, int outHeight) {
//從緩存池中取出一個bitmap
final Bitmap toReuse = pool.get(outWidth, outHeight, Bitmap.Config.ARGB_8888);
final Bitmap result;
if (toReuse != null) {
result = toReuse;
} else {
result = Bitmap.createBitmap(outWidth, outHeight, Bitmap.Config.ARGB_8888);
}
//目標圓的半徑
float radious=Math.min(outHeight,outWidth)/2;
//計算縮放比和原圖中的起始座標
final float scale;
float dx=0,dy=0;
if (toTransform.getWidth()>toTransform.getHeight()){
scale=(float) outHeight/(float) toTransform.getHeight();
dx=(toTransform.getWidth()-toTransform.getHeight())*0.5f;
} else {
scale=(float) outWidth/(float) toTransform.getWidth();
dy=(toTransform.getHeight()-toTransform.getWidth())*0.5f;
}
Matrix matrix=new Matrix();
matrix.setScale(scale,scale);
matrix.postTranslate((int)(dx+0.5f),(int)(dy+0.5f));
Canvas canvas = new Canvas(result);
Paint paint = new Paint();
//後面參數表示邊緣複製
BitmapShader shader = new BitmapShader(toTransform, BitmapShader.TileMode.CLAMP,
BitmapShader.TileMode.CLAMP);
shader.setLocalMatrix(matrix);
paint.setShader(shader);
paint.setAntiAlias(true);//抗鋸齒
//繪製,可以看到主要還是對畫筆的設置,將原圖按矩陣縮放並設置起始點後交給畫筆。
canvas.drawCircle(outWidth/2, outHeight/2, radious, paint);
//判斷能否回收Bitmap
if (toReuse != null && !pool.put(toReuse)) {
toReuse.recycle();
}
return result;
}
寫的應該是比較清楚了,藉助矩陣將原圖縮放並設置起始位置,這時他在我們眼裏相當於一個邊長爲min(outWidth,outHeight)的正方形,然後交給畫筆作爲圓形畫到目標bitmap的畫布上就可以了。使用:
Glide.with(this)
.load(path)
.transform(new CircleTrans(this))
.into(iv);
效果很理想(寬match_parent,高200dp):