在Android、前端或者别的平台的软件开发中,有时会遇到类似如下需求:
- 将某个图片显示到指定的区域;
- 要求不改变图片本身的宽高比,进行缩放;
- 要求最大限度的居中填充到显示区域。
以下示意图可以简单描绘该需求
以Android平台为例,如果我们的目标显示对象为Imageview,那么很简单,只要如下设置即可
xml
<ImageView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:scaleType="fitCenter"
android:src="@drawable/image" />
其中实现以上需求最关键的代码为 android:scaleType="fitCenter"。感兴趣的同学可以去查看源码,探究scaleType属性设置为fitCenter之后底层代码是如何实现的。
但是,如果我们的显示区域只是一个自定义view中特定坐标的区域,如(x1, y1, x2, y2)的矩形区域。不了解Matrix的同学,可能第一反应就是根据图片本身的宽高以及目标显示区域的宽高,去计算一个缩放比,如下代码:
java
public void drawBitmapFillRegion(Canvas canvas, Bitmap bitmap, Rect targetRect) {
// 目标区域的宽高
int targetWidth = targetRect.width();
int targetHeight = targetRect.height();
// Bitmap 的宽高
int bitmapWidth = bitmap.getWidth();
int bitmapHeight = bitmap.getHeight();
// 计算宽高比
float scale = Math.max((float) targetWidth / bitmapWidth, (float) targetHeight / bitmapHeight);
// 计算缩放后的宽高
float scaledWidth = scale * bitmapWidth;
float scaledHeight = scale * bitmapHeight;
// 计算偏移
float offsetX = targetRect.left + (targetWidth - scaledWidth) / 2;
float offsetY = targetRect.top + (targetHeight - scaledHeight) / 2;
// 设置 Matrix 进行缩放和平移
Matrix matrix = new Matrix();
matrix.setScale(scale, scale);
matrix.postTranslate(offsetX, offsetY);
// 绘制 Bitmap
canvas.drawBitmap(bitmap, matrix, null);
}
但是,当你深入研究Matrix中的方法,你就会发现,根本不需要这么麻烦,以下几句即可简单完美实现
java
public void drawBitmapFillRegion(Canvas canvas, Bitmap bitmap) {
// 定义源矩形,即 Bitmap 的边界
RectF srcRect = new RectF(0, 0, bitmap.getWidth(), bitmap.getHeight());
RectF srcRect = new RectF(x1, y1, x2, y2);
// 设置 Matrix 进行缩放和平移
Matrix matrix = new Matrix();
matrix.setRectToRect(srcRect, targetRect, Matrix.ScaleToFit.CENTER);
// 绘制 Bitmap
canvas.drawBitmap(bitmap, matrix, null);
}
其中最关键的方法便是 setRectToRect,它可以计算出将某个矩形映射到另外一个矩形所需的矩阵,并将这个矩阵赋值给调用方。其实,Matrix还有很多使用强大的接口,感兴趣的同学可以系统深入探索下。尤其是工作学习当中涉及到图片缩放、裁剪、旋转、平移等操作的同学,更应该学习下。