这是我的第一篇关于Bitmap的文章,如有理解错误之处,烦请大家能及时留言提出,我会及时纠正,谢谢。
今天主要和大家探讨的是BitmapFactory.Options的使用.
目录:
第一部分:BitmapFactory.Options属性的理解
第二部分:从源码角度查看Options是如何工作的
BitmapFactory.Options
接下来分析一下Options中一些重要属性.
先放类图
inDither(***)
1:定义:是否对位图抖动处理
2:作用:会让图片的显示效果更平滑一些,提高显现效果.
3:使用场景:颜色模式高的图片(例如ARGB_8888)采用低颜色模式(例如:RGB_565)去解码的时候,需要把此值设置为true.
4:原理:https://blog.csdn.net/haozipi/article/details/47185535(这个说的比较清楚)
inPreferQualityOverSpeed(**)
1:API解析:如果inPreferQualityOverSpeed设置为true,则解码器将尝试将重建图像解码为更高质量,即使牺牲解码速度.目前该领域只影响JPEG解码,在这种情况下,将使用更精确但速度稍慢的IDCT方法.
inPremultiplied(***)
1:API解释:如果为true(这是默认值),则生成的位图的颜色通道将由Alpha通道预先倍增。
对于由视图系统或Canvas直接绘制的图像,这不应设置为false。 视图系统和Canvas假定所有绘制的图像都被预乘以简化绘制时间混合,并且在绘制未预乘积时会抛出RuntimeException。
这可能仅在您想操纵原始编码图像数据时才有用,例如, 使用RenderScript或自定义OpenGL。
这不会影响没有Alpha通道的位图。
将inScaled设置为true时将此标志设置为false可能会导致不正确的颜色。
2:注意:inScaled设置为true,inPremultiplied设置为false,并且图像具有alpha通道(例如加载png图片),则会出错"java.lang.RuntimeException: Canvas: trying to use a non-premultiplied bitmap"
inPreferredConfig(*****)
1:定义:解码图片生成Bitmap时的颜色模式.
2:作用:标记每个像素点占的内存大小(单位是字节)
3:疑问:目前从api说明来看,不同的Config对应的每个像素点占的内存是不一样的,但是测试时发现,ALPHA_8,RGB_565,ARGB_8888占用的内存一样大,目前还不知道原因??
inSampleSize(*****)
1:采样率
2:取值:2的整数幂(小于1则取值为1,任何其他值将向下舍入到最接近的2的幂)
3:作用:对图片进行二次采样,使Bitmap占用的内存大小降低,使Bitmap的宽和高减小(宽高变为原图的1/sampleSize,进而Bitmap占用的内存变小为1/sampleSize^2)
4:场景:大图加载,缩略图
inJustDecodeBounds(*****)
1:是否仅仅测量Bitmap的边界
2:取值:true,只测量Bitmap的宽高等属性,并且解码返回的Bitmap为null. 这些属性值从outWitdh,outHeight,outMimeType(图片类型)获取.
inMutable(*****Mutable:易变的,可变的)
1:作用:标记位图是否可变,是否可以对该位图做修改.
2:取值:true:可变,false:不可变
3:注意点:如果用Options加载的Bitmap的话,那么此值对应的是Bitmap的mIsMutable属性.
如果是不可变的话,例如调用setPixel()修改位图中像素点的颜色会抛出"IllegalStateException(非法状态异常)"
inBitmap(*****)
1:作用:指示解码器重复使用已经加载的Bitmap的内存空间去加载新位图从而达到节省内存的目的.
2:注意点:1:重用位图的mIsMutable的值为false,那么新加载Bitmap就不能用重用位图的内存空间解码图片。此时新加载的Bitmap与重用的Bitmap不是同一个。
2:重用位图的mIsMutable的值为true,如果要加载位图的getByteCount()字节数大于重用位图的Bitmap.getAllocationByteCount()分配的字节数,
那么调用BitmapFactory.decode()会返回 null 并将抛出IllegalArgumentException。
3:重用位图的mIsMutable的值为true,如果要加载位图的getByteCount()字节数小于或等于重用位图的Bitmap.getAllocationByteCount()分配的字节数,
BitmapFactory就可以重复使用可变位图来解码任何其他位图.
此时:1:重用位图与新加在位图是同一个对象
2:重用位图的尺寸变成了新加载位图的尺寸
3:重用位图的内存大小与新加载位图的位图内存大小一样,且都为重用位图的大小
4:重用位图的内容变成了新加载位图的内容(从源码来看也确实是这样,因为重用位图像素信息存储的是新加载位图的像素信息)
inScaled(*****)
1:定义:是否缩放,而API解释则更清楚一些:设置此标志时,如果inDensity和inTargetDensity不为0,则位图将在加载时缩放以匹配inTargetDensity,而不是每次绘图到Canvas时都依靠图形系统进行缩放。
BitmapRegionDecoder将忽略此标志,并且不会根据密度缩放输出。 (尽管支持inSampleSize)默认情况下,此标志处于打开状态,如果需要位图的非缩放版本,应将其关闭。 九个补丁位图忽略这个标志并且总是缩放。
如果inPremultiplied设置为false,并且图像具有alpha,则将此标志设置为true可能会导致不正确的颜色。
2:作用:缩放Bitmap
inDensity(*****)
1:定义:该位图是在哪种像素密度下创建的(这个理解的可能不对,如果理解不对的话,希望大神们多多指出).
2:取值:DisplayMetrics中的值.
3:作用:与inScaled,inTargetDensity,inScreenDensity一起使用,决定最终Bitmap的宽高
4:note:当Options.inDensity不为0的话则把该值设置到Bitmap的mDensity(see BitmapFactory.setDensityFromOptions()).
inTargetDensity(*****)
1:定义:该位图要加载并显示到的目标设备上的像素密度。
2:取值:DisplayMetrics中的值.
3:作用:与inScaled,inTargetDensity,inScreenDensity一起使用,决定最终Bitmap的宽高
4:note:当Options.inScaled或isNinePatch一项为真则把该值设置到Bitmap的mDensity(see BitmapFactory.setDensityFromOptions()).
inScreenDensity(*****)
1:定义:这个不知道怎么理解,希望打什么能指出
2:取值:DisplayMetrics中的值.
3:作用:1:与inScaled,inTargetDensity,inScreenDensity一起使用,决定最终Bitmap的宽高.
2:通过与inDensity比较是否相等来确认是否需要缩放位图(相等不缩放,不相等则缩放)
inPurgeable与inInputShareable
inPurgeable与inInputShareable联合使用,从Build.VERSION_CODES.LOLLIPOP(21)开始,可以采用inBitmap替换.
网上找的解释:inPurgeable与inInputShareable 二个是并列使用,如果设置了inPurgeable = false,则inInputShareable的值会被忽略;
这二个选项的作用主要是便于系统及时回收bitmap占用的内存;
inPurgeable:设置为True,则使用BitmapFactory创建的Bitmap用于存储Pixel的内存空间,在系统内存不足时可以被回收,当应用需要再次访问
该Bitmap的Pixel时,系统会再次调用BitmapFactory 的decode方法重新生成Bitmap的Pixel数组。 设置为False时,表示不能被回收。
inInputShareable:设置是否深拷贝,与inPurgeable结合使用,inPurgeable为false时,该参数无意义.
从源码层分析Options是如何工作的
下面简单从BitmapFactory.cpp中分析各属性的作用(分析的很简单,几乎每个开发同学拿到这个源码都能看懂,所以就稍微梳理下加深下印象就行了)。
•inSampleSize:这里不做深究底层是如何实现的,有兴趣的小伙伴可以自行研究下
•inJustDecodeBounds:
•inSacled与inDensity与nTargetDensity与inScreenDensity
这几个属性共同决定了最终要显示的Bitmap的宽/高。
•inBitmap:
好了,今天的分享就到这里了,有什么理解错误的地方,欢迎大家积极指出,我会尽快改正的,谢谢。
网友评论