Bitmap 介绍
位图(Bitmap),又称栅格图(英语:Raster graphics)或点阵图,是使用像素阵列(Pixel-array/Dot-matrix点阵)来表示的图像。
位图的像素都分配有特定的位置和颜色值。每个像素的颜色信息由RGB组合或者灰度值表示。
根据位深度,可将位图分为1、4、8、16、24及32位图像等。每个像素使用的信息位数越多,可用的颜色就越多,颜色表现就越逼真,相应的数据量越大。
以上内容均出自百度百科Bitmap词条
Android 中的Bitmap实现了 Parcelable 序列化接口,Bitmap的创建由 Native 曾实现,Bitmap 的内存分配在不同Android版本均有不同实现。此外 Bitmap 在内存中和磁盘中有两种不同表现形式:前者表示图片被加载到内存中,称之为 bitmap;后者则意味着图片被以不同压缩格式的方式存储到硬盘上。
图片压缩格式
JPEG
JPEG(Joint Photographic Experts Group) 格式是一种有损压缩格式,能够在不影响视觉效果的前提下大幅度减小文件体积,但代价是会损失部分图像信息,多次编辑和保存可能导致画质逐渐下降;JPEG格式支持用户自定义压缩质量级别,允许在文件大小和图像质量之间进行权衡。压缩程度越高,文件越小,但画质损失也越大。
JPEG图片以24位颜色压缩存储单个位图,采用YCbCr色彩空间进行编码,每个像素点只包含红(R)蓝(B)绿(G)三个颜色分量, 不支持透明通道,JPEG也不支持多帧动画,文件后缀为JPEG或JPG。
JPEG2000作为JPEG的升级版,其压缩率比JPEG高约30%左右,同时支持有损和无损压缩。JPEG2000格式有一个极其重要的特征在于它能实现渐进传输,即先传输图像的轮廓,然后逐步传输数据,不断提高图像质量,让图像由朦胧到清晰显示。
JPEG2000还支持所谓的"感兴趣区域"特性,也就是可以任意指定影像上感兴趣区域的压缩质量;另外,JPEG2000还可以选择指定的部分先解压缩来加载到内存中。JPEG2000和JPEG相比优势明显,且向下兼容,因此可取代传统的JPEG格式。
PNG
PNG(Portable Network Graphics)格式后缀缩写为.png,是无损压缩算法的位图格式,支持多种位深度(最高32位),可以为原图像定义256个透明层次,也就是说它支持所有的颜色类型。
-
灰度图像:PNG 支持 1 位 ~ 16位的灰度图像
-
彩色图像:
1. 索引色(Indexed Color)图像,PNG支持8位或更少的位深度,即最多256种颜色(每个像素用一个字节来表示索引到调色板的颜色);
2. 真彩色(Truecolor)图像,PNG标准支持24位(8位红、8位绿、8位蓝),可以显示大约1670万种不同的颜色
3. 包括Alpha通道(透明度信息),则为32位(24位RGB + 8位Alpha),这样每个像素除了有RGB颜色外,还有一个额外的8位用于表示透明度,允许像素具有从完全透明到完全不透明的平滑过渡。
同样是无损压缩,PNG的压缩率高于Gif格式,而且PNG支持的颜色数量也远高于Gif,因此:如果是对静态图片进行无损压缩,优先使用PNG取代Gif,因为PNG压缩率高、色彩好;但是PNG不支持动画效果。
此外,PNG文件中还可以存储元数据,如版权、描述等信息。
WebP
同时提供了有损压缩与无损压缩的图片文件格式。WebP支持的像素最大数量是16383x16383。有损压缩的WebP仅支持8-bit的YUV 4:2:0格式。而无损压缩(可逆压缩)的WebP支持VP8L编码与8-bit之ARGB色彩空间。无论无损还是有损皆支持Alpha透明通道、ICC色彩配置、XMP诠释数据。
WebP有静态与动态两种模式。动态WebP(Animated WebP)支持有损与无损压缩、ICC色彩配置、XMP诠释数据、Alpha透明通道。
WebP用 VP8 视频帧内编码作为其算法基础,WebP支持有损和无损压缩、支持完整的透明通道、也支持多帧动画,并且没有版权问题,是一种非常理想的图片格式。WebP支持动图,基本取代gif。
WebP不仅集成了PNG、JPEG和Gif的所有功能,而且相同质量的无损压缩WebP图片体积比PNG小大约26%;如果是有损压缩,相同质量的WebP图片体积比JPEG小25%-34%。
缺点
有损压缩的算法决定了其压缩时间一定是高于无损压缩的,也就是说JPEG的压缩时间高于PNG。而WebP无论是无损还是有损压缩,压缩率都分别高于PNG和JPEG,与其相对应的是其压缩时间也比它们长的多。
GIF
GIF(Graphics Interchange Format)是一种基于LZW算法的无损压缩格式,多次编辑保存可能产生轻微的质量损失。
Gif可插入多帧,从而实现动画效果。因此Gif图片分为静态GIF和动画GIF两种GIF格式。
由于Gif以8位颜色压缩存储单个位图,所以它最多只能用256种颜色来表现物体,对于色彩复杂的物体它就力不从心了。因此Gif不适合用于色彩非常丰富的图片的压缩存储,比如拍摄的真彩图片等。
GIF 支持单一颜色透明,即可以选择一种颜色作为透明色,在显示时背景会透过该颜色显示出来。这种透明效果是二元的,不支持半透明效果。
关于图片几个概念介绍
透明度通道
在图形图像学中,透明通道也称Alpha通道,表示在图像文件格式中用于表示每个像素点透明度信息的一个额外的色彩通道。
通常,一个颜色由红、绿、蓝三种基本色组成,在支持透明度的图像格式中,会增加一个称为Alpha的第四个通道,它使用8位二进制数(0到255之间的值)来表示从完全透明(0)到完全不透明(255)的不同程度。
在Android中的Bitmap中,当配置为ARGB_8888
时,就表示每个像素包含4个8位的颜色通道,分别是Alpha、Red、Green和Blue,其中Alpha通道即负责控制像素的透明度。
- 白色的Alpha像素用以定义不透明的彩色像素;
- 黑色的Alpha定以透明像素;
- 黑白之间的灰阶则是彩色图片中的半透明部分。
色深
色深指的是每一个像素点用多少bit来存储ARGB值,属于图片自身的一种属性。色深可以用来衡量一张图片的色彩处理能力(即色彩丰富程度)。典型的色深是8-bit、16-bit、24-bit和32-bit等,Bitmap.Config中描述的就是图片的色深。
例如,在24位真彩图像中,每个像素由红绿蓝三种颜色组成,每种颜色8位(位深度为8),每个 8位二进制数可以表示 0 到 255共256种不同的灰阶级别,有由于有三种颜色通道构成,共计可以表示约 1670万种颜色。
Bitmap.Config
Config:是一个枚举类,描述多种位图像素的存储方式
- ALPHA_8:每个像素占用1byte,不会存储颜色信息,每个像素点存储为单个半透明通道,只存储透明度A通道值,使用场景特殊,比如设置遮盖效果等;
- RGB_565:每个像素占用2byte,仅RGB通道被解码,红色和蓝色以5bit的精度存储(32种可能的值),绿色则是6bit(64种可能的值)
- ARGB_8888:每像素占用4byte,每个通道以8bit精度存储,有256种可能的值
- RGBA_F16:每个通道以 android.util.Half 的精度(16bit)的浮点数存储,适用于宽色域和HDR内容
- HARDWARE:特殊配置,当bitmap仅存储在图形内存(graphic memory),这类型位图是不可变的
位深
位深指的是在对Bitmap进行压缩存储时存储每个像素所用的bit数,位数越多,图像的色彩也就越丰富细腻。由于是"压缩"存储,所以位深一般小于或等于色深 。
举个例子:某张图片100像素*100像素 色深32位(ARGB_8888),保存时位深度为24位,那么:
- 该图片在内存中所占大小为:100 * 100 * (32 / 8) Byte
- 在文件中所占大小为 100 * 100 * ( 24/ 8 ) * 压缩率 Byte
Android Bitmap 的API和 density 属性
Bitmap 的函数除了 Java 层级的函数外,还有 Native 层的函数以真正实现操作位图的功能。
Bitmap Java 层 API
创建和销毁
create系列
多个createBitmap:调用nativeCreate创建新的Bitmap对象
recycle
调用后不允许位图被继续操作,清理Native层的位图对象,并且清理像素引用。并非同步释放像素数据,而是标记bitmap为dead,表示允许释放。
获取位图信息
getRowBytes
返回每行所有像素占用的字节数量。
getByteCount
返回存储此位图像素的最小字节数。
getAllocationByteCount
返回实际分配的位图占用内存的大小,单位是 byte。
getPixel
返回Bitmap特定位置的颜色。
getColor
返回Bitmap特定位置的颜色。
isMutable
返回true表示位图可以修改。
编辑位图的API
setDensity
指定位图的密度。当绘制Bitmap到canvas时,使用density,绘制的位图会被适当的缩放。
- bitmap.density 默认是设备屏幕的 density 大小
- bitmap对象的density可以直接修改,bitmap 显示大小 随之改变,但不影响bitmap的内存占用和实际尺寸信息,仅仅是缩放了bitmap
setImmutable
使位图不可变,即不能再修改位图的任何配置、颜色等,例如 调用该方法后,reconfigure、setPixel、setPixels、eraseColor 等函数不允许被调用,否则就会抛出异常。
setHasMipMap
mipmap是一种纹理映射技术,Android使用它来提高bitmap的渲染速度和质量。setHasMipMap(true)时,可以让系统尝试开启mipmap技术,但是否真正开启由系统决定。
extractAlpha(Paint,int offsetx)
返回新的bitmap仅包含了原图的alpha通道,可用于显示阴影效果。
reconfigure
当修改位图的width/height或者Config时,触发这个方法。
Copy 系列函数
- copy(Bitmap.Config,isMutable) :以指定色深和可变性拷贝出新的位图,返回空或新的Bitmap。部分Config不能完全支持;
- copyPixelsToBuffer:拷贝位图像素信息到指定的缓存空间,缓存大小必须大于像素信息;有与之对应的方法 copyPixelsFromBuffer,从缓存区拷贝bitmap的像素信息
Compress 压缩图片
以指定的压缩图片格式和压缩率(0 ~ 100)压缩存储位图。
asShared
返回由共享内存支持的不可变位图,该位图可以通过包裹在进程之间高效传递。
sameAs(Bitmap other)
判断二者尺寸信息、Config、pixel信息是否一致,三个条件满足时返回true。
Android Bitmap density
density(密度),DisplayMatrix中可以获得当前设备的density,它和屏幕每平方英寸中所含像素数量有关,具体的计算公式:
density = dpi / 160
java
Bitmap bitmap = BitmapFactory.decodeResource(resources, R.drawable.a)
imageView.setBitmap(bitmap);
Bitmap bitmap2 = bitmap.copy(bitmap.config, bitmap.isMutable)
bitmap2.setDensity(bitmap.getDensity() * 2);
imageView.setBitmap(bitmap);
Bitmap bitmap3 = bitmap.copy(bitmap.config, bitmap.isMutable)
bitmap3.setDensity(bitmap.getDensity() / 2);
imageView.setBitmap(bitmap);
Bitmap的density默认是设备的density,但是可以修改,当Bitmap被绘制到Canvas时,会根据density做出合适的缩放效果:
mipmap(扩展内容)
mipmap 是一种很早就有的技术了(纹理映射技术),android 中的 mipmap 技术主要为了应对图片大小缩放的处理,在android 中我们提供一个 bitmap 图片,由于应用的需要(比如缩放动画),可能对这个 bitmap 进行各种比例的缩小,为了提高缩小的速度和图片的质量,android 通过 mipmap 技术提前对按缩小层级生成图片预先存储在内存中,这样就提高了图片渲染的速度和质量。在API中通过 Bitmap 的 setHasMipMap (boolean hasMipMap) 方法可以让系统渲染器尝试开启 Bitmap 的 mipmap 技术。但是这个方法只能建议系统开启这个功能,至于是否正真开启,还是由系统决定。
res 目录下面 mipmap 和 drawable 的区别也就是上面这个设置是否开启的区别:
- mipmap 目录下的图片默认 setHasMipMap 为 true,
- drawable 默认 setHasMipMap 为 false
google 建议大家只把 app 的启动图标放在 mipmap 目录中,其他图片资源仍然放在 drawable 下面。