需求背景
最近在开发二维码支付的时候产品要求二维码中的图片样式为圆角+白色边框,如下图所示:
二维码的生成我们就不说了,主要说下怎么把一个图片转换成一个带圆角和边框的图片,效果如下:
实现方式
实现这种效果的方案有很多种,我们今天就说说使用BitmapShader这个类来实现这种效果。首先说下BitmapShader,看名字我们就知道这是一个着色器而且是和Bitmap有关的,其构造方法如下:
public BitmapShader(Bitmap bitmap, TileMode tileX, TileMode tileY)
bitmap The bitmap to use inside the shader.
tileX The tiling mode for x to draw the bitmap in.
tileY The tiling mode for y to draw the bitmap in.
我们可以给Paint设置BitmapShader,当给一个Paint设置了BitmapShader后,就相当于给画笔设置了一套着色方案,这个着色方案就是在构造函数中的bitmap(说白了就是画笔的颜色就是对应的bitmap的颜色)。还有一点需要注意当给一个Paint设置了BitmapShader之后,Paint设置的color就无效了。
TileMode是刚才我们在构造函数中添加的bitmap当画布的宽或者高大于bitmap的宽或者高的时候bitmap绘制剩余空间的模式,总共有三种:
/**
* replicate the edge color if the shader draws outside of its
* original bounds
* 超出的都绘制边缘色值
*/
CLAMP (0),
/**
* repeat the shader's image horizontally and vertically
* 重复绘制
*/
REPEAT (1),
/**
* repeat the shader's image horizontally and vertically, alternating
* mirror images so that adjacent images always seam
* 镜像绘制
*/
MIRROR (2);
明白了BitmapShader,我们来看下转换代码:
- 圆角+边框
/**
* 通过BitmapShader 圆角边框
* @param bitmap
* @param outWidth
* @param outHeight
* @param radius
* @param boarder
* @return
*/
public static Bitmap getRoundBitmapByShader(Bitmap bitmap, int outWidth, int outHeight, int radius, int boarder) {
if (bitmap == null) {
return null;
}
int width = bitmap.getWidth();
int height = bitmap.getHeight();
float widthScale = outWidth * 1f / width;
float heightScale = outHeight * 1f / height;
Matrix matrix = new Matrix();
matrix.setScale(widthScale, heightScale);
//创建输出的bitmap
Bitmap desBitmap = Bitmap.createBitmap(outWidth, outHeight, Bitmap.Config.ARGB_8888);
//创建canvas并传入desBitmap,这样绘制的内容都会在desBitmap上
Canvas canvas = new Canvas(desBitmap);
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
//创建着色器
BitmapShader bitmapShader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
//给着色器配置matrix
bitmapShader.setLocalMatrix(matrix);
paint.setShader(bitmapShader);
//创建矩形区域并且预留出border
RectF rect = new RectF(boarder, boarder, outWidth - boarder, outHeight - boarder);
//把传入的bitmap绘制到圆角矩形区域内
canvas.drawRoundRect(rect, radius, radius, paint);
if (boarder > 0) {
//绘制boarder
Paint boarderPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
boarderPaint.setColor(Color.GREEN);
boarderPaint.setStyle(Paint.Style.STROKE);
boarderPaint.setStrokeWidth(boarder);
canvas.drawRoundRect(rect, radius, radius, boarderPaint);
}
return desBitmap;
}
- 圆形+边框
/**
* 通过BitmapShader 圆形边框
* @param bitmap
* @param outWidth
* @param outHeight
* @param boarder
* @return
*/
public static Bitmap getCircleBitmapByShader(Bitmap bitmap, int outWidth, int outHeight, int boarder) {
if (bitmap == null) {
return null;
}
int radius;
int width = bitmap.getWidth();
int height = bitmap.getHeight();
float widthScale = outWidth * 1f / width;
float heightScale = outHeight * 1f / height;
Matrix matrix = new Matrix();
matrix.setScale(widthScale, heightScale);
Bitmap desBitmap = Bitmap.createBitmap(outWidth, outHeight, Bitmap.Config.ARGB_8888);
if (outHeight > outWidth) {
radius = outWidth / 2;
} else {
radius = outHeight / 2;
}
//创建canvas
Canvas canvas = new Canvas(desBitmap);
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
BitmapShader bitmapShader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
bitmapShader.setLocalMatrix(matrix);
paint.setShader(bitmapShader);
canvas.drawCircle(outWidth / 2, outHeight / 2, radius - boarder, paint);
if (boarder > 0) {
//绘制boarder
Paint boarderPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
boarderPaint.setColor(Color.GREEN);
boarderPaint.setStyle(Paint.Style.STROKE);
boarderPaint.setStrokeWidth(boarder);
canvas.drawCircle(outWidth / 2, outHeight / 2, radius - boarder, boarderPaint);
}
return desBitmap;
}
圆角边框和圆形边框的代码类似,原理也都一样。需要注意的是我们在绘制圆角矩形和圆形的时候一定要预留出边框的宽度,以免绘制出来的边框看起来怪怪的。