这是一篇比较简单的处理图片的应用文,我们先看一下具体的场景:
这里实现了上传图片的功能,图片限制在红色框框内且比例为4/3,标准的照片比例。但是如果用户上传了其他比例的图片,为了照顾观感肯定是要对图片进行一个等比压缩处理,最后的效果和ImageView中ScareType的FitCenter效果是一样的,也就是保持图片的比例,并且最大化的显示在时框中。
那么对于自定义View如何实现这一效果呢?首先分析一下图片是如何被处理的。
三种情况:
- 比例小于视框
也就是图片比较“高”,例如上图左边,是一张16比9的照片,9/16 < 3/4。
显示高度 = 视框高度 - 比例等于视框
也就是4比3的图片,可以完美的贴合视框不留空白
显示宽高 = 视框宽高 - 比例大于视框
也就是图片比较“宽”,例如上图右边,比例为1比1, 1 > 3/4
对于图片的处理就比较简单了,计算图片和视框的比例,按照比例进行缩放即可。
那么知道图片处理的判断情况以及处理方式后,接下来就是具体代码实现了:
//取得图片和图片所处空间的比例
float scaleBitmap = ((float) bitmap.getWidth()) / bitmap.getHeight();
float scaleView = ((float)getWidth()) / getHeight();
// 空间的大小 / bitmap 的大小 = bitmap 缩放的倍数
float scaleWidth = ((float) getWidth()) / bitmap.getWidth();
float scaleHeight = ((float) getHeight()) / bitmap.getHeight();
Matrix matrix = new Matrix();
//按照比例选择缩放参照
if (scaleBitmap < scaleView) {
//比例小于视框时,全部按照图片高度和视框高度的比例进行缩放
matrix.postScale(scaleHeight, scaleHeight);
}else {
//比例大于视框时,全部按照图片宽度和视框宽度的比例进行缩放
matrix.postScale(scaleWidth, scaleWidth);
}
//bitmap 缩放
bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
//draw 上去
//canvas.drawBitmap(bitmap, 0, 0, paint);
//居中显示
canvas.drawBitmap(bitmap,
(getWidth() - bitmap.getWidth()) / 2,
(getHeight() - bitmap.getHeight()) / 2, paint);
canvas.restore();
复制代码
这里要注意一个问题就是,Java中进行除法运算并获得带小数点的结果,需要将算式中的一个值转为float才可以取得。
在最后将bitmap画入画布时,也要记得计算一下位置,居中显示才算完整实现效果。
然后简单介绍一下Android中缩放图像生成缩略图的三种方式:
1、BitmapFactory和 BitmapFactory.Options
在设定好缩放值inSampleSize 后,通过BitmapFactory.decodeFile或者decode其他形式,生成缩放后的Bitmap位图。如果已经有Bitmap图了,可以转成File地址来实现。
而缩放值inSampleSize 可以直接设定具体倍数,比如2就是2分之一倍,或者通过计算原图宽高和设定的想达到的宽高得到比例。
其中很实用的一点是,在获取图片的宽高的时候,可以将inJustDecodeBounds设成true,此时bitmap不会加载到内存,而只是获取到图片的height和width,节省内存提高效率。
示例:
//使用BitmapFactory.Options的inSampleSize参数来缩放
public static Drawable resizeImage2(String path,
int width,int height)
{
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;//不加载bitmap到内存中
BitmapFactory.decodeFile(path,options);
int outWidth = options.outWidth;
int outHeight = options.outHeight;
options.inDither = false;
options.inPreferredConfig = Bitmap.Config.ARGB_8888;
options.inSampleSize = 1;
if (outWidth != 0 && outHeight != 0 && width != 0 && height != 0)
{
int sampleSize=(outWidth/width+outHeight/height)/2;
Log.d(tag, "sampleSize = " + sampleSize);
options.inSampleSize = sampleSize;
}
options.inJustDecodeBounds = false;
return new BitmapDrawable(BitmapFactory.decodeFile(path, options));
}
复制代码
2、使用Bitmap加Matrix来缩放
首先要获得原bitmap,创建一个Matrix对象,包含想要达到的宽和高,最后在原Bitmap的基础上生成新图片。效率比较低。
示例:
//使用Bitmap加Matrix来缩放
public static Drawable resizeImage(Bitmap bitmap, int w, int h)
{
Bitmap BitmapOrg = bitmap;
int width = BitmapOrg.getWidth();
int height = BitmapOrg.getHeight();
int newWidth = w;
int newHeight = h;
float scaleWidth = ((float) newWidth) / width;
float scaleHeight = ((float) newHeight) / height;
Matrix matrix = new Matrix();
matrix.postScale(scaleWidth, scaleHeight);
// if you want to rotate the Bitmap
// matrix.postRotate(45);
Bitmap resizedBitmap = Bitmap.createBitmap(BitmapOrg, 0, 0, width,
height, matrix, true);
return new BitmapDrawable(resizedBitmap);
}
复制代码
3、Android自带的ThumbnailUtils
Android自带的处理方法,会结合第一种和第二种方法和一些其他算法对图片进行加工,效率会比第二种高一点,使用也比较方便,一行代码就可以了:
imView.setImageBitmap(ThumbnailUtils.extractThumbnail(bitmap,200,100));
复制代码
关于图片压缩
最后在三种图片的处理方式中都发现了一个问题,也是以前我对图片处理的一个知识盲区:图片不仅在拉大的时候会模糊,在缩小的时候同样也可能模糊。一张照片,压缩10倍之后,其分辨率已经不足以看清细节,锯齿非常严重。所以这三种图片的压缩,是会降低显示效果的,如果需要尺寸减小画质不变,应该需要其他的算法来解决。