Android 图片如何高效加载与缓存 (4.5) —— 缩略图生成的优化
2016-04-17 22:42
555 查看
在之前那篇里面仍有不足之处,比如:
一张4000*3000的图片压缩到了300*200的大小,然后输出到ImageView上。但是ImageView的大小可能只有100*100,这样我们仍然占用了很多不需要的内存。所以我们只需要将图片居中裁剪成ImageView的大小即可。
知道了如何做之后,在考虑一下可能存在的图片尺寸与ImageView尺寸之间的关系:
1.图片的宽 小于 ImageView的宽 (比如:5000*10)
2.图片的高 小于 ImageView的高 (比如:10*5000)
3.图片的宽和高都 小于 ImageView的宽高 (比如:1*1)
考虑好了之后,我们就能动手写代码了!
先来个大合照,然后我在把裁剪的方法一一拿出来说吧 = n =
方法 cropBitmap() 用于初始化数据 以及判断应该如何裁剪
方法 normalCropBitmap() 默认裁剪方式
方法 heightCropBitmap() 高度的裁剪
方法 widthCropBitmap() 宽度的裁剪
下面是正常向的图片处理之后的Log 可以看到无论图片尺寸是如何的,处理后的大小都是统一的
下面这是特殊情况的log
一张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; }
下面是正常向的图片处理之后的Log 可以看到无论图片尺寸是如何的,处理后的大小都是统一的
下面这是特殊情况的log
相关文章推荐
- 使用C++实现JNI接口需要注意的事项
- Android IPC进程间通讯机制
- Android Manifest 用法
- [转载]Activity中ConfigChanges属性的用法
- Android之获取手机上的图片和视频缩略图thumbnails
- Android之使用Http协议实现文件上传功能
- Android学习笔记(二九):嵌入浏览器
- android string.xml文件中的整型和string型代替
- i-jetty环境搭配与编译
- android之定时器AlarmManager
- android wifi 无线调试
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- android 代码实现控件之间的间距
- android FragmentPagerAdapter的“标准”配置
- Android"解决"onTouch和onClick的冲突问题
- android:installLocation简析
- android searchView的关闭事件
- SourceProvider.getJniDirectories