在之前那篇里面仍有不足之处,比如:
一张4000*3000的图片压缩到了300*200的大小,然后输出到ImageView上。但是ImageView的大小可能只有100*100,这样我们仍然占用了很多不需要的内存。所以我们只需要将图片居中裁剪成ImageView的大小即可。
知道了如何做之后,在考虑一下可能存在的图片尺寸与ImageView尺寸之间的关系:
1.图片的宽 小于 ImageView的宽 (比如:5000*10)
2.图片的高 小于 ImageView的高 (比如:10*5000)
3.图片的宽和高都 小于 ImageView的宽高 (比如:1*1)
考虑好了之后,我们就能动手写代码了!
先来个大合照,然后我在把裁剪的方法一一拿出来说吧 = n =
/*
获取图片缩略图任务
*/
private class GenerateImageThumbnail implements Callable<String>{
private int scaleTimes; //缩放倍数
private String path; //图片路径
private String tag; //图片加载任务唯一TAG
private ImageView imageView; //图片接收的ImageView
private Bitmap bitmap; //图片的Bitmap对象
private HandleOnLoaded handleOnLoaded; //图片效果处理回调
public GenerateImageThumbnail(String path, String tag, ImageView imageView, HandleOnLoaded handleOnLoaded) {
this.path = path;
this.tag = tag;
this.imageView = imageView;
this.handleOnLoaded = handleOnLoaded;
}
@Override
public String call() throws Exception {
try {
//进行图片剪裁
bitmap = cropBitmap();
} catch (IllegalArgumentException e) {
//如果裁剪出现了异常
fetherExecutor.removeTag(tag);
Log.d("OCImageLoader", "Exception on croping bitmap. "+e);
runOnUIThread(new Runnable() {
@Override
public void run() {
onError();
}
});
return null;
}
if (handleOnLoaded != null){
//如果有需要进行图片处理,则使用回调处理
bitmap = handleOnLoaded.reduce(bitmap,tag);
}
if (bitmap != null){
//图片进行缓存
imageCacher.putCache(tag,bitmap);
runOnUIThread(new Runnable() {
@Override
public void run() {
onCompleted(imageView , bitmap);
}
});
}
fetherExecutor.removeTag(tag);
return null;
}
//加载完成的操作
private void onCompleted(ImageView imageView , Bitmap bitmap){
...
}
//加载失败的操作
private void onError(){
...
}
/**
* 进行 Bitmap 的裁剪缩放操作
* @return 处理后的Bitmap
*/
private Bitmap cropBitmap() throws IllegalArgumentException{
...
}
/**
* 普通裁剪
* @return 裁剪后的Bitmap
*/
private Bitmap normalCropBitmap(int pictureWidth , int pictureHeight , int showHeight , int showWidth , BitmapFactory.Options options)
throws IllegalArgumentException{
...
}
/**
* 高度裁剪
* @return 裁剪后的Bitmap
*/
private Bitmap heightCropBitmap(int pictureWidth , int pictureHeight , int showHeight , BitmapFactory.Options options)
throws IllegalArgumentException{
...
}
/**
* 长度裁剪
* @return 裁剪后的Bitmap
*/
private Bitmap widthCropBitmap(int pictureWidth , int pictureHeight , int showWidth , BitmapFactory.Options options)
throws IllegalArgumentException{
...
}
}
方法 cropBitmap() 用于初始化数据 以及判断应该如何裁剪
private Bitmap cropBitmap() throws IllegalArgumentException{
//默认起始缩放倍数
scaleTimes = 2;
//先仅仅加载图片的尺寸数据
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(path,options);
//裁剪方式
int cropType;
//原图尺寸
int pictureWidth = options.outWidth;
int pictureHeight = options.outHeight;
//ImageView尺寸. 先尽可能缩放成这个尺寸
int showWidth = imageView.getMeasuredWidth();
int showHeight = imageView.getMeasuredHeight();
if (showHeight * showWidth == 0){
//如果有一项ImageView尺寸的数据为 0 , 则赋予默认值. 裁剪为普通状态
showHeight = 120;
showWidth = 120;
cropType = 0;
}else if ( pictureHeight < showHeight && pictureWidth < showWidth ){
//如果原图小于要显示的尺寸,则直接返回原图对象
return BitmapFactory.decodeFile(path);
}else if ( pictureHeight < showHeight ){
//如果原图的高度小于要显示的尺寸,就直接将 原图的长度 进行裁剪
cropType = 1;
}else if ( pictureWidth < showWidth ){
//如果原图的宽度小于要显示的尺寸,就直接将 原图的高度 进行裁剪
cropType = 2;
}else {
//普通状态
cropType = 0;
}
switch (cropType){
case 0:
//普通裁剪
bitmap = normalCropBitmap(pictureWidth,pictureHeight,showHeight,showWidth,options);
break;
case 1:
//长度裁剪
bitmap = widthCropBitmap(pictureWidth,pictureHeight,showWidth,options);
break;
case 2:
//高度裁剪
bitmap = heightCropBitmap(pictureWidth,pictureHeight,showHeight,options);
break;
default:
bitmap = normalCropBitmap(pictureWidth,pictureHeight,showHeight,showWidth,options);
break;
}
return bitmap;
}
方法 normalCropBitmap() 默认裁剪方式
/**
* 普通裁剪
* @return 裁剪后的Bitmap
*/
private Bitmap normalCropBitmap(int pictureWidth , int pictureHeight , int showHeight , int showWidth , BitmapFactory.Options options)
throws IllegalArgumentException{
//临时存储计算得到的上一次结果,预设为图片原始尺寸.
int reducedWidth = pictureWidth;
int reducedHeight = pictureHeight;
int lastWidth;
int lastHeight;
while (true){
lastWidth = pictureWidth/scaleTimes;
lastHeight = pictureHeight/scaleTimes;
if ( lastHeight < showHeight || lastWidth < showWidth){
//如果计算得到的尺寸小于要得到的尺寸,则跳出
break;
}else {
//否则就继续增大缩放倍数,同时记录这次的尺寸
reducedWidth = lastWidth;
reducedHeight = lastHeight;
scaleTimes += 1;
}
}
//用得出的尺寸数据,计算出缩放倍数,然后读取图片
options.inJustDecodeBounds = false;
options.inPreferredConfig = Bitmap.Config.RGB_565;
options.inSampleSize = (pictureHeight / reducedHeight + pictureWidth / reducedWidth) /2;
//获取等待截取的Bitmap
Bitmap pictureBitmap = BitmapFactory.decodeFile(path,options);
//计算裁剪的起点
int cropX , cropY;
cropX = (reducedWidth/2)-(showWidth/2);
cropY = (reducedHeight/2)-(showHeight/2);
//剪!
pictureBitmap = Bitmap.createBitmap(pictureBitmap,cropX,cropY,showWidth,showHeight);
return pictureBitmap;
}
方法 heightCropBitmap() 高度的裁剪
/**
* 高度裁剪
* @return 裁剪后的Bitmap
*/
private Bitmap heightCropBitmap(int pictureWidth , int pictureHeight , int showHeight , BitmapFactory.Options options)
throws IllegalArgumentException{
//图片不用缩放了,计算下裁剪的居中位置,就能直接裁剪了.下一个方法也一样.
int cropY = ( pictureHeight / 2 ) - ( showHeight / 2 );
options.inJustDecodeBounds = false;
options.inPreferredConfig = Bitmap.Config.RGB_565;
bitmap = BitmapFactory.decodeFile(path,options);
bitmap = Bitmap.createBitmap(bitmap,0,cropY,pictureWidth,showHeight);
return bitmap;
}
方法 widthCropBitmap() 宽度的裁剪
/**
* 宽度裁剪
* @return 裁剪后的Bitmap
*/
private Bitmap widthCropBitmap(int pictureWidth , int pictureHeight , int showWidth , BitmapFactory.Options options)
throws IllegalArgumentException{
int cropX = ( pictureWidth / 2 ) - ( showWidth / 2 );
options.inJustDecodeBounds = false;
options.inPreferredConfig = Bitmap.Config.RGB_565;
bitmap = BitmapFactory.decodeFile(path,options);
bitmap = Bitmap.createBitmap(bitmap,cropX,0,showWidth,pictureHeight);
return bitmap;
}