Android Bitmap压缩图像的正确方法(compress的误区)
2016-08-28 17:27
627 查看
这两天在做的一个app需要从相册里面载入图片,踩了几个坑,这里Mark一下。
现在的相机基本都是800W+像素,差一点的手机1M多,好点的手机拍出来接近3M,如果直接载入图片,那非常容易造成oom,尤其是在差的手机上面。因此就需要对图像进行压缩处理。
先是在百度上搜了一把,比较多的解决方案都是使用Bitmap.compress()这个方法,那我也就跟着用了咯,使用形式如下:
其实80的品质,就保留原图像80%的品质,压缩20%,看上去挺正确的,压缩个20%,可以变小一点点。
然后在差的手机上运行,继续会crash。通过Android Monitor查看App的内存状况,发现从相册载入图片时,内存依然会猛的增长2M左右的样子(选取的图片大小在1.5M左右)。就结果而看这个方法并不有用,随即开始打log,看各个变量的详细数据。
然后发现了与理解有偏差的地方!
再去google狂搜一发,得到以下一个结论:
Bitmap.compress方法确实可以压缩图片,但压缩的是存储大小,即你放到disk上的大小
我尝试过把品质设置为10,decode出来的Bitmap大小没变,但显示照片的质量非常差
BitmapFactory.decodeByteArray方法对压缩后的byte[]解码后,得到的Bitmap大小依然和未压缩过一样
如果你想要显示的Bitmap占用的内存少一点,还是需要去设置加载的像素长度和宽度(变成缩略图)
下面给出我压缩图片的方法:
好,问题解决,一张3MB的照片所生成的bitmap的大小在90KB左右。
另外一点不能漏,bitmap需要显示地调用recycle()方法去回收资源,所以用完的bitmap要及时回收,避免内存异常。
目前我的应用场景比较小,不会有很多图片需要加载。
如果未来应用场景拓展了,我还是会去使用 Universal-Image-Loader,
Picasso之类的开源框架。
现在的相机基本都是800W+像素,差一点的手机1M多,好点的手机拍出来接近3M,如果直接载入图片,那非常容易造成oom,尤其是在差的手机上面。因此就需要对图像进行压缩处理。
先是在百度上搜了一把,比较多的解决方案都是使用Bitmap.compress()这个方法,那我也就跟着用了咯,使用形式如下:
ByteArrayOutputStream out = new ByteArrayOutputStream(); bm.compress(Bitmap.CompressFormat.JPEG, 80, out); imageView.setImageBitmap(bm);
其实80的品质,就保留原图像80%的品质,压缩20%,看上去挺正确的,压缩个20%,可以变小一点点。
然后在差的手机上运行,继续会crash。通过Android Monitor查看App的内存状况,发现从相册载入图片时,内存依然会猛的增长2M左右的样子(选取的图片大小在1.5M左右)。就结果而看这个方法并不有用,随即开始打log,看各个变量的详细数据。
然后发现了与理解有偏差的地方!
int len = bm.getByteCount(); // 原始图片的byte[]数组大小 ByteArrayOutputStream out = new ByteArrayOutputStream(); bm.compress(Bitmap.CompressFormat.JPEG, 80, out); int compressedLen = out.toByteArray().length; // 这里out.toByteArray()所返回的byte[]数组大小确实变小了! Bitmap compressedBm = BitmapFactory.decodeByteArray(out.toByteArray(), 0, compressedLen); int newLen = compressedBm.getByteCount(); // 这里decode出来的图片byte[]数组大小和原始图片是一样的!并没有变小
再去google狂搜一发,得到以下一个结论:
Bitmap.compress方法确实可以压缩图片,但压缩的是存储大小,即你放到disk上的大小
我尝试过把品质设置为10,decode出来的Bitmap大小没变,但显示照片的质量非常差
BitmapFactory.decodeByteArray方法对压缩后的byte[]解码后,得到的Bitmap大小依然和未压缩过一样
如果你想要显示的Bitmap占用的内存少一点,还是需要去设置加载的像素长度和宽度(变成缩略图)
下面给出我压缩图片的方法:
// 从选取相册的Activity中返回后 Uri imageUri = data.getData(); String[] filePathColumns = {MediaStore.Images.Media.DATA}; Cursor c = getContentResolver().query(imageUri, filePathColumns, null, null, null); c.moveToFirst(); int columnIndex = c.getColumnIndex(filePathColumns[0]); String imagePath = c.getString(columnIndex); c.close(); // 设置参数 BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; // 只获取图片的大小信息,而不是将整张图片载入在内存中,避免内存溢出 BitmapFactory.decodeFile(imagePath, options); int height = options.outHeight; int width= options.outWidth; int inSampleSize = 2; // 默认像素压缩比例,压缩为原图的1/2 int minLen = Math.min(height, width); // 原图的最小边长 if(minLen > 100) { // 如果原始图像的最小边长大于100dp(此处单位我认为是dp,而非px) float ratio = (float)minLen / 100.0f; // 计算像素压缩比例 inSampleSize = (int)ratio; } options.inJustDecodeBounds = false; // 计算好压缩比例后,这次可以去加载原图了 options.inSampleSize = inSampleSize; // 设置为刚才计算的压缩比例 Bitmap bm = BitmapFactory.decodeFile(imagePath, options); // 解码文件 Log.w("TAG", "size: " + bm.getByteCount() + " width: " + bm.getWidth() + " heigth:" + bm.getHeight()); // 输出图像数据 imageView.setScaleType(ImageView.ScaleType.FIT_CENTER); imageView.setImageBitmap(bm);
好,问题解决,一张3MB的照片所生成的bitmap的大小在90KB左右。
另外一点不能漏,bitmap需要显示地调用recycle()方法去回收资源,所以用完的bitmap要及时回收,避免内存异常。
目前我的应用场景比较小,不会有很多图片需要加载。
如果未来应用场景拓展了,我还是会去使用 Universal-Image-Loader,
Picasso之类的开源框架。
相关文章推荐
- Android Bitmap压缩图像的正确方法(compress的误区)
- android中bitmap压缩的几种方法的解读
- 图片压缩android bitmap compress(图片压缩)
- Android 图片压缩即生成缩略图方法-BitmapFacotry.Options。
- Android平台Bitmap图像压缩
- Android把Bitmap保存为PNG图像文件的简单方法(同步)
- bitmap 图像压缩方法
- Android Bitmap压缩图像
- Android把Bitmap保存为PNG图像文件的简单方法(同步)
- android中bitmap压缩的几种方法的解读
- 选择正确的Bitmap压缩方法
- 正确的对待android的图片处理与压缩,你所熟悉而又陌生的bitmap
- android bitmap 压缩 方法
- android中bitmap压缩的几种方法的解读
- Android-Bitmap-压缩方法总结
- android中bitmap压缩的几种方法详解
- android开发游记:图像文件压缩方法总结(将图像压缩到指定大小)
- Android把Bitmap保存为PNG图像文件的简单方法(同步)
- Android Bitmap压缩方法的选择详解
- android-----解决Bitmap内存溢出的一种方法(图片压缩技术)