大图片加载会出现什么问题?
如果一张高清分辨率到4K的图片加载到内存中,会占用非常大的内存,非常容易造成内存溢出。图片占用内存可以简单理解为 图片宽x图片高x像素字节数, 像素字节数与图片格式有直接关系,下面列出几种图片格式
Config ALPHA_8 此时图片只有alpha值,没有RGB值 质量很差
Config.RGB_565;
对于没有透明和半透明颜色的图片来说,该格式的图片能够达到比较的呈现效果,
相对于ARGB_8888来说也能减少一半的内存开销。想节省内存可以设置565格式
另外我们通过android.content.res.Resources来取得一个张图片时,它也是以该格式来构建BitMap的ARGB_8888:
高质量的图片格式,电脑上普通采用的格式。它也是Android手机上一个BitMap的默认格式。
解决大图片加载常用的压缩方式
- 尺寸压缩(采样率压缩)
Options opts = new Options();
// 是否只加载一些参数信息
opts.inJustDecodeBounds = true;
BitmapFactory.decodeFile(path, opts);
// 设置为rgb565--减小一半内存的开销
opts.inPreferredConfig = Config.RGB_565;
// 获取图片宽高
int outHeight = opts.outHeight;
int outWidth = opts.outWidth;
// 获取屏幕分辨率 屏幕宽高
Display defaultDisplay = windowManager.getDefaultDisplay();
DisplayMetrics outMetrics = new DisplayMetrics();
defaultDisplay.getMetrics(outMetrics);
//获取屏幕宽高
int windowHight = outMetrics.heightPixels;
int windowWidth = outMetrics.widthPixels;
// 设置比例
int scale = 1;
//x方向的缩放比例
int scaleX = outWidth / windowWidth;
//y方向的缩放比例
int scaleY = outHeight / windowHight;
// 以缩放比例大的方式进行缩放,同时要求XY方向都大于屏
//幕宽高的时候才进行缩放
if (scaleX > scaleY && scaleY > 1) {
scale = scaleX;
} else if (scaleY > scaleX && scaleX > 1) {
scale = scaleY;
}
// 重新加载图片
//设置缩放比例
opts.inSampleSize = scale;
//将图片加载到内存中来
opts.inJustDecodeBounds = false;
//再加载图片
Bitmap bitmap = BitmapFactory.decodeFile(path, opts);
- 质量压缩
public static Bitmap compressPicInQuality(Bitmap bitmap) {
// 压缩图片format 图片格式 .jpg
// 质量比例,直接在一开始设置90
int quality = 90;
ByteArrayOutputStream arrayOutputStream = new ByteArrayOutputStream();
//对图片进行第一次压缩,把图片放置到字节数组输出流中
bitmap.compress(CompressFormat.JPEG, quality, arrayOutputStream);
// 100K 设置图片的最大为100K,如果大于100K就压缩
while (arrayOutputStream.size() / 1024 > 100) {
quality = quality - 10;
// 重新进行压缩
arrayOutputStream.reset();
bitmap.compress(CompressFormat.JPEG, quality, arrayOutputStream);
Log.i(TAG, "质量压缩结束后" + arrayOutputStream.size() + "------");
}
//将图片放到的输出流重新转成字节数组
byte[] bts = arrayOutputStream.toByteArray();
//设置选项,压缩完转成565方式节约内存的开销
Options opts = new Options();
opts.inPreferredConfig = Config.RGB_565;
//将字节数组重新转成图片
Bitmap bmp = BitmapFactory.decodeByteArray(bts, 0, bts.length, opts);
try {
arrayOutputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
return bmp;
}
面试问题回答 如何进行图片压缩
- 话述:常用有两种,尺寸压缩和质量压缩,
- 尺寸压缩是在加载Bitmap的时候,先不加载到内存中去,只是先获取Bitmap的详细信息,比如宽高,密度。获取到图片的宽和高之后,和当前屏幕的宽高作为比较,获取出宽度上的缩放比例和高度上的缩放比例,在缩放比例都大于1(即图片宽高都大于屏幕宽高的情况下,才进行缩放),缩放按照比例大的进行缩放。
- 重新加载图片,设置要加载图片所有内容,展示压缩好的Bitmap
- 质量压缩是指不改变图片的宽高,在保持像素的前提下改变图片的位深及透明度等来达到压缩图片的效果,可以指定一个图片大小不超过多少,通过while循环不停的压缩,直到大小小于所设置的限定值时,停止压缩。压缩的图片放置到一个ByteArrayOutputStream中,最后将该流转化成字节数组,将字节数组转成对应的Bitmap,进行展示。
- 当然将图片先进行尺寸压缩,再进行质量压缩,效果更好。
- 除了这两种压缩方式,还可以设置图片格式进行压缩,比如RGB—8888是默认格式,占用内存开销比较大,可以设置为图片格式RGB—565格式,会结束一半的内存开销。
- 还有的网友提出,JNI调用libjpeg库压缩,这种方式没有用过。
参考资料:
http://blog.csdn.net/harryweasley/article/details/51955467
JNI http://blog.csdn.net/copy_yuan/article/details/51353629