12.1 Android的图像处理
和文字一样,图像也是移动设备上呈现信息的重要方式,在实际应用开发中,不可避免地需要处理各种图像信息。高效而完整地呈现图像信息,是提升应用交互界面流程度的关键所在。
12.1.1 图像的表示
在Android中,存放在内存中的图像数据会通过android.graphics.Bitmap对象来表示。Bitmap类实现了android.os.Parcelable接口,这说明图像数据可以进行序列化和反序列化,便捷地在进程间传递。
Bitmap对象可用来存储各种格式的图像数据,包括:alpha8、agrb4444、agrb888、rgb555等[1]。不同格式的图像数据在内存中有着不同的存储方式,有的图像格式可以节约内存,而另一些图像格式可以更高质量地表达图像信息。
不论使用何种格式,Bitmap对象总是会占用较多的内存空间,因此,在实际开发中需要严格控制它的生命周期,一旦Bitmap对象使用完毕,就应该及时调用Bitmap.recycle函数释放Bitmap对象所占据的内存空间。而释放空间后的Bitmap对象,不再将图像数据存放在内存当中,而仅仅保留了图像的一些基本信息,此时,如果继续调用Bitmap.setPixels等相关函数访问图像数据,就会抛出异常。所以,如果图像的生命周期较为复杂,可以事先利用Bitmap.isRecycle函数来判断Bitmap对象的数据是否已经释放,比如:
//读取图片,并判断图片状态
Bitmap bitmap=GetBitmap(image_id);
if(!bitmap.isRecycle()){
//对图片进行处理
…
//手动释放图片占用的内存空间,保证内存可以更快地进行回收
bitmap.recycle();
bitmap=null;
}
Bitmap类的底层实现,依托于开源图像库Skia[2]。Java中的Bitmap类基本都是通过JNI接口调用底层Skia的Bitmap来实现的,具体细节可以参见源码中的SKBitmap.cpp文件。
在Android中,最有特色的Bitmap格式,称为九宫格(Nine Patch)格式图像。九宫格格式的图像,大抵可以分成9块区域(其实,九宫格只是该格式图像最常规的呈现状态,开发者可以沿着图像的横向和纵向,切分任意次数,构成各种模式的图像)。它利用图像最边缘1个像素的矩形框来划分区域信息,通过矩形框的黑白变化勾勒出9块区域,其中上侧和左侧黑色边框环绕的区域为可变区域(如图12-1 a所示)。当图像需要横向或纵向拉伸时,仅有被标志线勾勒出来的可变区域会进行线性地水平或垂直拉伸,而其他区域的图像内容则保持原有样式(如图12-1 b所示)。通过九宫格格式的图像,使得复杂的位图的适应性变得更强,具有部分矢量图的特征,能够适应不同的屏幕尺寸和使用场景[3]。
[1]枚举类android.graphics.Bitmap.Config定义了Bitmap支持的所有位图格式。关于各种位图格式的介绍,可以参见维基百科:http://en.wikipedia.org/wiki/RGBA_color_space。
[2]Skia项目的官方主页:http://code.google.com/p/skia/。
[3]更多关于九宫格格式图像的细节,可以参见SDK:http://developer.android.com/guide/topics/graphics/2d-graphics.html#nine-patch。