Bitmap压缩策略

一、为什么Bitmap需要高效加载?

现在的高清大图,动辄就要好几M,而Android对单个应用所施加的内存限制,只有小几十M,如16M,这导致加载Bitmap的时候很容易出现内存溢出。如下异常信息,便是在开发中经常需要的:

java.lang.OutofMemoryError:bitmap size exceeds VM budget

为了解决这个问题,就出现了Bitmap的高效加载策略。其实核心思想很简单。假设通过ImageView来显示图片,很多时候ImageView并没有原始图片的尺寸那么大,这个时候把整个图片加载进来后再设置给ImageView,显然是没有必要的,因为ImageView根本没办法显示原始图片。这时候就可以按一定的采样率来将图片缩小后再加载进来,这样图片既能在ImageView显示出来,又能降低内存占用从而在一定程度上避免OOM,提高了Bitmap加载时的性能。

二、Bitmap高效加载的具体方式

1.加载Bitmap的方式

Bitmap在Android中指的是一张图片。通过BitmapFactory类提供的四类方法:decodeFile,decodeResource,decodeStream和decodeByteArray,分别从文件系统,资源,输入流和字节数组中加载出一个Bitmap对象,其中decodeFile,decodeResource又间接调用了decodeStream方法,这四类方法最终是在Android的底层实现的,对应着BitmapFactory类的几个native方法。

2.BitmapFactory.Options的参数

①inSampleSize参数

上述四类方法都支持BitmapFactory.Options参数,而Bitmap的按一定采样率进行缩放就是通过BitmapFactory.Options参数实现的,主要用到了inSampleSize参数,即采样率。通过对inSampleSize的设置,对图片的像素的高和宽进行缩放。

当inSampleSize=1,即采样后的图片大小为图片的原始大小。小于1,也按照1来计算。
当inSampleSize>1,即采样后的图片将会缩小,缩放比例为1/(inSampleSize的二次方)。

例如:一张1024 ×1024像素的图片,采用ARGB8888格式存储,那么内存大小1024×1024×4=4M。如果inSampleSize=2,那么采样后的图片内存大小:512×512×4=1M。

注意:官方文档支出,inSampleSize的取值应该总是2的指数,如1,2,4,8等。如果外界传入的inSampleSize的值不为2的指数,那么系统会向下取整并选择一个最接近2的指数来代替。比如3,系统会选择2来代替。当时经验证明并非在所有Android版本上都成立。

关于inSampleSize取值的注意事项:
通常是根据图片宽高实际的大小/需要的宽高大小,分别计算出宽和高的缩放比。但应该取其中最小的缩放比,避免缩放图片太小,到达指定控件中不能铺满,需要拉伸从而导致模糊。

例如:ImageView的大小是100×100像素,而图片的原始大小为200×300,那么宽的缩放比是2,高的缩放比是3。如果最终inSampleSize=2,那么缩放后的图片大小100×150,仍然合适ImageView。如果inSampleSize=3,那么缩放后的图片大小小于ImageView所期望的大小,这样图片就会被拉伸而导致模糊。

②inJustDecodeBounds参数

我们需要获取加载的图片的宽高信息,然后交给inSampleSize参数选择缩放比缩放。那么如何能先不加载图片却能获得图片的宽高信息,通过inJustDecodeBounds=true,然后加载图片就可以实现只解析图片的宽高信息,并不会真正的加载图片,所以这个操作是轻量级的。当获取了宽高信息,计算出缩放比后,然后在将inJustDecodeBounds=false,再重新加载图片,就可以加载缩放后的图片。

注意:BitmapFactory获取的图片宽高信息和图片的位置以及程序运行的设备有关,比如同一张图片放在不同的drawable目录下或者程序运行在不同屏幕密度的设备上,都可能导致BitmapFactory获取到不同的结果,和Android的资源加载机制有关。

3.高效加载Bitmap的流程

①将BitmapFactory.Options的inJustDecodeBounds参数设为true并加载图片。

②从BitmapFactory.Options中取出图片的原始宽高信息,它们对应于outWidth和outHeight参数。

③根据采样率的规则并结合目标View的所需大小计算出采样率inSampleSize。

④将BitmapFactory.Options的inJustDecodeBounds参数设为false,然后重新加载图片。

三、Bitmap高效加载的代码实现

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28
public static Bitmap (Resources res, int resId, int reqWidth, int reqHeight){

BitmapFactory.Options options = new BitmapFactory.Options();

options.inJustDecodeBounds = true;

BitmapFactory.decodeResource(res,resId,options);

//计算缩放比

options.inSampleSize = calculateInSampleSize(options,reqHeight,reqWidth);

//重新加载图片

options.inJustDecodeBounds =false;

return BitmapFactory.decodeResource(res,resId,options);

}

private static int calculateInSampleSize(BitmapFactory.Options options, int reqHeight, int reqWidth) {

int height = options.outHeight;

int width = options.outWidth;

int inSampleSize = 1;

if(height>reqHeight||width>reqWidth){

int halfHeight = height/2;

int halfWidth = width/2;

//计算缩放比,是2的指数

while((halfHeight/inSampleSize)>=reqHeight&&(halfWidth/inSampleSize)>=reqWidth){

inSampleSize*=2;

}

}

return inSampleSize;

}

这个时候就可以通过如下方式高效加载图片:

1
mImageView.setImageBitmap(decodeSampledBitmapFromResource(getResources(),R.mipmap.ic_launcher,100,100);

除了BitmapFactory的decodeResource方法,其他方法也可以类似实现。

原文:大专栏  Bitmap压缩策略

原文地址:https://www.cnblogs.com/chinatrump/p/11615098.html

时间: 2024-11-12 16:15:52

Bitmap压缩策略的相关文章

Android Bitmap压缩策略

一.为什么Bitmap需要高效加载? 现在的高清大图,动辄就要好几M,而Android对单个应用所施加的内存限制,只有小几十M,如16M,这导致加载Bitmap的时候很容易出现内存溢出.如下异常信息,便是在开发中经常需要的: java.lang.OutofMemoryError:bitmap size exceeds VM budget 为了解决这个问题,就出现了Bitmap的高效加载策略.其实核心思想很简单.假设通过ImageView来显示图片,很多时候ImageView并没有原始图片的尺寸那

android中bitmap压缩的几种方法的解读

最近在研究微信的sdk,在缩略图这遇到了一点问题. 微信的缩略图要求是不大于32k,这就需要对我的图片进行压缩.试了几种方法,一一道来. 1.质量压缩法: 代码如下 ByteArrayOutputStream baos = new ByteArrayOutputStream(); image.compress(Bitmap.CompressFormat.JPEG, 100, baos); int options = 100; while ( baos.toByteArray().length /

学习笔记 - 深究Bitmap压缩避免OOM的核心inSampleSize的最佳取值

/** * 测试代码,通过在SDCard根目录放置几种不同大小的图片, 来自动测试压缩方式是否有效同时看是否会内存不够. * * @since * By:AsionTang * At:2014年3月20日 * */ public static final void test() { //常用照片分辨率 final int[][] list = new int[][] { { 15000, 13600 }, { 14000, 12600 }, { 13000, 11600 }, { 12000,

cassandra的坑-windows平台压缩策略

2016年5月中旬,由于急着项目上线,cassandra3.4版本在没有很多测试的情况下就使用了,当时部署在3台16G的windows系统服务器上.几个月使用下来,多数问题都是OOM导致的宕机 .特别是有一次宕机,在重启数据库后发现内存不断上升,多次重启也都是如此.通过观察判断可能原因是数据库采取的默认compact策略-SizeTieredCompactionStrategy(将磁盘上小的DB文件合成大DB文件).经过几个月的数据入库, 该策略已经产生了多个3g的DB文件, 不知道是数据库有b

图片压缩之处理小图片压缩策略

在进行图片压缩的时候.有时候会碰到要压缩的图片尺寸小于指定的压缩尺寸,若直接压缩会导致图片失真. 当然.最好的方式是挑选合适尺寸图片进行上传. 这里给出的方法是:对不足尺寸部分进行空白填充. 详细參见下面代码 using System; using System.Drawing.Drawing2D; using System.Drawing; using System.IO; using System.Drawing.Imaging; namespace CommonLib { public c

java图片压缩策略说明

使用java原生或者使用第三方的jar来生成. 存在的问题: 原生效率慢,并且和代码耦合性太高,支持格式少,其他没太多尝试 使用thumbnailator.jar 第三方.效率不高,压缩完的图片质量太低.支持格式少,如果原本图片的后缀为.jpg的改成.png之后,无法支持操作..png的图片保存时为透明时候,压缩出来的图片会出现颜色严重失调的问题.和代码的耦合性太高 以上这两个和代码的耦合性太高,因此如何存在项目群时,图片的处理会变的和无力. 2.因此我推荐使用以下的解决方案:由nginx来处理

Android Bitmap 缓存策略

Android中最常用到缓存的地方就是图片,通过过缓存即可以提高应用程序的效率,又可以节省用户的流量. 图片的缓存简单来说可以分为SD卡缓存和内存缓存,也可以俩者配合使用. Android中图片缓存遵循的策略就是:当第一次从网络中加载图片的时候,将其缓存到存储设备上(比如sd卡,这也就是我们说的SD卡缓存),并且在内存中同样也缓存一份(内存缓存),这样当下次使用或者网络请求图片的时候,就先去内存中获取(因为从内存中读取要比从SD卡中读取的快,所以我们先从内存中读取,这样的话在节省流量的同时也可以

石墨文档的云端表格实时压缩策略

多人实时协作是石墨文档吸引人的一大特性之一.使用石墨文档,你可以和同事.朋友同时编写一篇文档或表格,每个人的修改都会实时的同步给其他人.你可以看到每个人光标的跳动,每一个键入的文字.一篇篇运营文案.一份份产品头脑风暴,伴着一杯杯茶与咖啡,就这样在石墨文档上诞生了. 美好的事物背后总是充满艰辛.在技术实现上,多人实时编写会造成许多的冲突,拿表格来说,当用户 Bob 在 B2 单元格编写内容的时候,他的朋友 Jeff 在 B 列的前面又插入了一列,如果两个操作同时发给服务器就会产生冲突.在石墨文档,

android bitmap压缩处理

android中一些bitmap的简单处理 [1].[代码] [Java]代码 跳至 [1] ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70