概述
Bitmap图像处理的最重要类之一。用它可以获取图像文件信息,进行图像颜色变换、剪切、旋转、缩放等操作,并可以指定格式保存图像文件
Bitmap类
重要函数
1 | public void recycle() // 回收位图占用的内存空间,把位图标记为Dead |
在Android
中Bitamp
指的就是一张图片,一般是png
和jpeg
格式。
Bitmap
类中有一个enum
类型的Config
,其中有4个值:
ALPHA_8
8位位图;1 个字节,只有透明度,没有颜色值RGB_565
16位位图;2 个字节,r = 5,g = 6,b = 5,一个像素点 5+6+5 = 16ARGB_4444
16位位图;2 个字节,a = 4,r = 4,g = 4,b = 4,一个像素点 4+4+4+4 = 16ARGB_8888
32 位位图; 4个字节,a = 8,r = 8,g = 8, b = 8,一个像素点 8 + 8 + 8 + 8 = 32
源码中默认采用ARGB_8888
参数理解:
1 | * source 原始 Bitmap |
理解:
一张 1024 * 1024 像素,采用ARGB8888
格式,一个像素32位,每个像素就是4字节,占有内存就是4M
若采用RGB565
,一个像素16位,每个像素就是2字节,占有内存就是2M。两个开源库Glide和Picasso,
Glide
加载图片默认格式RGB565
,Picasso
为ARGB8888
,默认情况下,Glide
占用内存会比Picasso
低,色彩不如Picasso
鲜艳,自然清晰度就低.
BitmapFactory工厂类
Option 参数类:
1 | public boolean inJustDecodeBounds//如果设置为true,不获取图片,不分配内存,但会返回图片的高度宽度信息。 |
参数 inSampleSize 的理解:
这个是读取bitmap时用到的属性,是为了对原图降采样
比如原图是一个 4000 4000 点阵的图,占用内存就是 4000 4000 单个像素占用字节数
单个像素占用字节数取决于你用的是 RGB565, ARGB8888 等. 4000 4000 这个解析度已很接近目前市面主流机器的默认照片解析度.
假设你用的是RGB565解析这张图,那一个点就占用2个字节.如果完整解析这个图片,就需要 大约3.2MB的内存.
如果你用了一个GridView,同时显示了30张这种图,那几乎可以确定你会收到一个OOM异常.
所以需要对这种大图进行降采样,以减小内存占用.毕竟拇指大小的地方根本用不着显示那么高的解析度.
因为直接从点阵中隔行抽取最有效率,所以为了兼顾效率, inSampleSize 这个属性只认2的整数倍为有效.
比如你将 inSampleSize 赋值为2,那就是每隔2行采1行,每隔2列采一列,那你解析出的图片就是原图大小的1/4.
这个值也可以填写非2的倍数,非2的倍数会被四舍五入,向下寻找2的整数次幂.
综上,用这个参数解析bitmap就是为了减少内存占用.
inSampleSize的默认值和最小值为1(当小于1时,解码器将该值当做1来处理)
那如何设置 inSampleSize 呢?
1 | /** |
看一下insampleSize的效果
1 | val bitmap = BitmapFactory.decodeResource(resources,R.drawable.img_002) |
可见,当inSampleSize大小为4时,得到的bitmap宽高都为原来的1/4
参数inpreferredconfig理解:
如果inPreferredConfig不为null,解码器会尝试使用此参数指定的颜色模式来对图片进行解码,如果inPreferredConfig为null或者在解码时无法满足此参数指定的颜色模式,解码器会自动根据原始图片的特征以及当前设备的屏幕位深,选取合适的颜色模式来解码,例如,如果图片中包含透明度,那么对该图片解码时使用的配置就需要支持透明度,默认会使用ARGB_8888来解码。
也就是说inPreferredConfig指定的配置并非是一个强制选项,而是建议的(preferred)选项,Android在实际解码时会参考此参数的配置,但如果此配置不满足,Android会重新选取一个合适的配置来对图片进行解码。
这里说明一下,网上存在一种说法,设置RGB565选项可以减少内存。经过实际的分析,基本上指定inPreferredConfig为RGB565和不设置inPreferredConfig的效果是一样的。
工厂方法:
1 | public static Bitmap decodeFile(String pathName, Options opts) //从文件读取图片 |
重点说明
在不配置Options的情况下:
1、decodeFile、decodeStream在解析时不会对Bitmap进行一系列的屏幕适配,解析出来的将是原始大小的图
2、decodeResource在解析时会对Bitmap根据当前设备屏幕像素密度densityDpi的值进行缩放适配操作,使得解析出来的Bitmap与当前设备的分辨率匹配,达到一个最佳的显示效果,并且Bitmap的大小将比原始的大
看一下用decodeResource解析出来的和原图的对比
图片操作
1.获取图片长宽
1 | val options = BitmapFactory.Options() |
2.对图片进行缩放
1 | val matrix = Matrix() |
3.简单的压缩处理
我这里有一张6m左右的图片,按照正常的加载bitmap,程序肯定加载不出来,因为图片过大
1 | //直接加载,报错 |
因此,为了能让图片加载出来,我们可以对图片进行简单的压缩处理,这里就要用到前面讲的那个Options的参数 inSampleSize
1 | val bitmap = decodeBitmap(this.resources,R.drawable.img_009,400,600) |
可见可以加载出来了:
几个方法
1.compress方法
构造方法:
compress(Bitmap.CompressFormat format, int quality, OutputStream stream)
将bitmap
数据质量压缩并转换成流,若format
参数设置为了png
格式,quality
设置无效
format
图片的格式,支持3种JPEG,PNG,WEBP
quality
压缩质量压缩率,0-100,0表示压缩程度最大,100为原质量,但png
无效stream
输出流- 返回值,
boolean
简单使用
1 | int count = image.getWidth() * image.getHeight() / 1024; |
可以发现bitmap基本上没有被压缩,因为我们一开始就提到了compress压缩是存储压缩,不是内存压缩,所以在内存中并没有改变大小,但bytes本身变小了,适合存储和传输!
这种压缩方法之所以称之为质量压缩,是因为它不会减少图片的像素。它是在保持像素的前提下改变图片的位深及透明度等,来达到压缩图片的目的。进过它压缩的图片文件大小会有改变,但是导入成bitmap后占得内存是不变的。因为要保持像素不变,所以它就无法无限压缩,到达一个值之后就不会继续变小了。显然这个方法并不适用与缩略图,其实也不适用于想通过压缩图片减少内存的适用,仅仅适用于想在保证图片质量的同时减少文件大小的情况而已。
2.copy方法
构造方法:
copy(Bitmap.Config config, boolean isMutable)
拷贝一个Bitmap
的像素到一个新的指定信息配置的Bitmap
config
配置信息isMutable
是否支持可改变可写入- 返回值,
bitmap
,成功返回一个新的bitmap
,失败就null
1 | Bitmap bitmap = BitmapFactory.decodeResource(getResources(),R.drawable.m); |