Bitmap类解析
Bitmap类是对图像进行处理的类,可以获取图像信息,进行图像颜色变换等操作
在安卓中,Bitmap指的是一张图片,可以是 .png
或者 .jpg
等其他常见的图像格式
参考API:
Bitmap - Android中文版 - API参考文档 (apiref.com)
如何使用Bitmap加载图片
需要使用 BitmapFactory
类提供的四个方法:
decodeFile()
:从文件中加载Bitmap对象
decodeResource()
:从资源中加载Bitmap对象
decodeStream()
:从输入流中加载Bitmap对象
decodeByteArray()
:从字节数组中加载Bitmap对象
使用举例:
从资源中加载一张命名为 test 的图片,再加载到 ImageView
控件中
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.test);
imageView.setImageBitmap(bitmap);
Bitmap颜色配置
Bitmap类中有两个枚举类,其中一个为Config类,用于配置颜色信息:
解析:
Bitmap.Config.ALPHA_8
:颜色信息只由透明度组成,占8位。
Bitmap.Config.ARGB_4444
:颜色信息由透明度与R(Red),G(Green),B(Blue)四部分组成,每个部分都占4位,总共占16位。
Bitmap.Config.ARGB_8888
:颜色信息由透明度与R(Red),G(Green),B(Blue)四部分组成,每个部分都占8位,总共占32位。是Bitmap默认的颜色配置信息,也是最占空间的一种配置。
Bitmap.Config.RGB_565
:颜色信息由R(Red),G(Green),B(Blue)三部分组成,R占5位,G占6位,B占5位,总共占16位。
通常我们优化Bitmap时,当需要做性能优化或者防止OOM,通常会使用 RGB_565
这个配置,因为 ALPHA_8
只有透明度,显示一般图片没有意义,而 ARGB_4444
显示图片不清楚,ARGB_8888
则占用内存最多。
测试一下:
主要代码如下:
// 加载原图
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.test);
imageView.setImageBitmap(bitmap);
// 测试其他颜色模式
Bitmap bitmap1 = bitmap.copy(Bitmap.Config.ALPHA_8, true);
Bitmap bitmap2 = bitmap.copy(Bitmap.Config.ARGB_4444, true);
Bitmap bitmap3 = bitmap.copy(Bitmap.Config.ARGB_8888, true);
Bitmap bitmap4 = bitmap.copy(Bitmap.Config.RGB_565, true);
imageView1.setImageBitmap(bitmap1);
imageView2.setImageBitmap(bitmap2);
imageView3.setImageBitmap(bitmap3);
imageView4.setImageBitmap(bitmap4);
运行后点击按钮效果如下:
(可能由于图片原因,或者显示器等问题,似乎除了ALPHA_8都没啥区别)
Bitmap压缩方式配置
除了 Config
类的另一个枚举类则是 CompressFormat
,用于配置压缩方式:
解析:
Bitmap.CompressFormat.JPEG
:表示以JPEG
压缩算法进行图像压缩,压缩后的格式可以是 .jpg
或者 .jpeg
,是一种有损压缩。
Bitmap.CompressFormat.PNG
:表示以PNG
压缩算法进行图像压缩,压缩后的格式可以是 .png
,是一种无损压缩。
Bitmap.CompressFormat.WEBP
:表示以WebP
压缩算法进行图像压缩,压缩后的格式可以是 .webp
,是一种有损压缩。
关于三种格式的优劣,可以在自行搜索,或者参考Webp 相对于 PNG、JPG 有什么优势? - 知乎 (zhihu.com)
使用Bitmap的方法操作图片
裁剪:
使用 createBitmap(Bitmap source, int x, int y, int width, int height)
方法可以对Bitmap位图进行裁剪
其中x,y为裁剪时,x和y轴开始的第一个像素
width 和 height 则是剪切时的宽度和高度
(ps:x+width要小于source的宽度,y+height同理)
使用:
主要代码:
TextView textView = findViewById(R.id.text1);
ImageView imageView1 = findViewById(R.id.image_1);
ImageView imageView2 = findViewById(R.id.image_2);
ImageView imageView3 = findViewById(R.id.image_3);
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.test);
Bitmap bitmap1 = Bitmap.createBitmap(bitmap, 0, 0, 100, 100);
Bitmap bitmap2 = Bitmap.createBitmap(bitmap, 0, 0, 530, 530); // 530也可以使用bitmap.getHeight()和bitmap.getWidth()代替
String out = "Height = " + bitmap.getHeight() + " and Width = " + bitmap.getWidth();
textView.setText(out);
imageView1.setImageBitmap(bitmap);
imageView2.setImageBitmap(bitmap1);
imageView3.setImageBitmap(bitmap2);
效果呈现:
缩放、旋转、移动:
通过 createBitmap(Bitmap source, int x, int y, int width, int height, Matrix m, boolean filter)
方法,不但能实现裁剪
还能够实现如缩放等其他效果
其中,Matrix类代表一个矩阵对象,对其的简述可以参考本文下方的Matrix类简析
而参数 filter 为 true 时表示 source 会被过滤,仅仅当 m 操作不仅包含移动操作,还包含别的操作时才适用。
使用:
主要代码:
Matrix matrix = new Matrix();
// 向左旋转45度,参数为正时表示向右旋转
matrix.postRotate(-45);
Bitmap bitmap3 = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
imageView4.setImageBitmap(bitmap3);
效果呈现:
图像的保存与释放
请参考之后关于缓存的文章
BitmapFactory类
对BitmapFactory类的使用主要是上述的四个方法加载图片
BitmapFactory.decodeResource 加载的图片可能会经过缩放,该缩放目前是放在 java 层做的,效率比较低,而且需要消耗 java 层的内存。因此,如果大量使用该接口加载图片,容易导致OOM错误
BitmapFactory.decodeStream 不会对所加载的图片进行缩放,相比之下占用内存少,效率更高。
这两个接口各有用处,如果对性能要求较高,则应该使用 decodeStream;如果对性能要求不高,且需要 Android 自带的图片自适应缩放功能,则可以使用 decodeResource。
BitmapFactory.option类
BitmapFactory.Options 类是 BitmapFactory 对图片进行解码时使用的一个配置参数类,其中定义了一系列的public成员变量,每个成员变量代表一个配置参数。
参考API:
BitmapFactory.Options | Android Developers
BitmapFactory.Options - Android中文版 - API参考文档 (apiref.com)
Matrix类简述
Matrix类本身不能对图片进行操作,但是可以结合其他的API实现图片的旋转平移等效果
Matrix类中包含一个3X3的矩阵,对图片的操作分为四种:
(1)Translate
:平移变换
方法为 setTranslate()
,该方法接收两个浮点数作为参数,分别表示x和y轴上移动的数量
第一个参数若为整数则表示在x轴上向右移动相应距离,第二个参数同理
(2)Scale
:缩放变换
方法为 setScale()
接收两个浮点数作为参数,分别表示在每个轴上所产生的缩放量
第一个参数是x轴的缩放比例,而第二个参数是y轴的缩放比例
(3)Rotate
:旋转变换
方法之一为 setRotate()
接收一个浮点数表示旋转的角度
也可以在角度后再传入两个参数作为旋转的中心点
默认围绕点(0,0),正数将顺时针旋转图像,而负数将逆时针旋转图像
使用举例:
其中默认点是图像的左上角,如:
Matrix matrix = new Matrix();
matrix.setRotate(15);
另外,也可以使用旋转的角度及围绕的旋转点作为参数调用setRotate方法。选择图像的中心点作为旋转点,如:
matrix.setRotate(15, bmp.getWidth()/2, bmp.getHeight()/2);
(4)Skew
:错切变换
在数学上又称为 Shear mapping
(可译为“剪切变换”)或者 Transvection
(缩并),是一种比较特殊的线性变换
错切变换的效果就是让所有点的 x 坐标(或者 y 坐标)保持不变,而对应的 y 坐标(或者 x 坐标)则按比例发生平移
平移的大小和该点到 x 轴(或 y 轴)的垂直距离成正比
错切变换,属于等面积变换,即一个形状在错切变换的前后,其面积是相等的
而在Android的API中对于每一种变换都提供了三种操作方式:
(1)set(用于设置Matrix中的值)
(2)post(后乘,根据矩阵的原理,相当于左乘)
(3)pre(先乘,相当于矩阵中的右乘)
默认时,这四种变换都是围绕(0,0)点变换的,当然可以自定义围绕的中心点,通常围绕中心点。
参考API:
Matrix - Android中文版 - API参考文档 (apiref.com)
本文参考文章:
Android Bitmap最全面详解 - 掘金 (juejin.cn)
玩转Android Bitmap - 简书 (jianshu.com)
聊聊 Bitmap 的一些知识点 - 掘金 (juejin.cn)