Bitmap类和BitmapDrawable类

  参考 Android 8.0 源码

/framework/base/graphics/java/android/graphics/Bitmap.java
/framework/base/graphics/java/android/graphics/BitmapFactory.java
/framework/base/graphics/java/android/graphics/drawable/BitmapDrawable.java
public final class Bitmap implements Parcelable {

}
public class BitmapFactory {

}
public class BitmapDrawable extends Drawable {

}

Bitmap类

  Bitmap意思是位图,用于存储png、jpg、gif等格式的图片数据,很多时候如果需要在Android中对图片进行处理,需要先将图片读取为Bitmap对象,接着调用相关的API对图片进行处理和加工。

  该类有两个内部枚举类,分别是CompressFormat和Config。

  • Bitmap.CompressFormat:位图可以压缩到的已知图片格式;
    1 . JPEG:以JPEG算法进行压缩,压缩后的图片格式可以为.jpeg或者.jpg,这是一种有损压缩,没有透明度;
    2 . PNG:以PNG算法进行压缩,压缩后的图片格式是.png,这是一种无损压缩,可以有透明度;
    3 . WEBP:以WEBP算法进行压缩,压缩后的图片格式是.webp,这是一种有损压缩。相同质量下,webp比jpeg图像小40%,但webp图片的编码时间比jpeg长8倍;

  • Bitmap.Config:位图配置;
    1 . ALPHA_8:每个像素都存储为单个半透明通道;
    2 . ARGB_4444:在API13中被弃用,建议使用ARGB_8888;
    3 . ARGB_8888:每个像素存储在4个字节中;
    4 . RGB_565:每个像素存储在2个字节上,并且只有RGB通道。红色以5位精度(32个可能值)存储,绿色以6位精度(64个可能值)存储,蓝色以5位精度(32个可能值)存储。
      为了防止OOM对图片进行压缩时,一般情况下会使用RGB_565格式,因为ALPHA_8只有透明度,对于正常图片没有意义,我们平时很少会用到这个;ARGB_4444显示的图片质量太差,而且已经被弃用了;ARGB_8888占用的内存最多

5 . 创建一个空白图片。空白图片需要指定宽度、高度和存储格式(比如ARGB_4444、ARGB_8888等)等信息。Bitmap类中创建空白图片的方法是createBitmap(),createBitmap()方法有好多种重载,最简单的方法如下:

public static Bitmap createBitmap(int width, int height, @NonNull Config config)

  该方法是static方法,不需要创建Bitmap对象就可以直接调用。如下代码创建一个400 * 400的ARGB_8888类型的空白位图对象:

Bitmap bitmap = Bitmap.createBitmap(400,400,Config.ARGB_8888);

6 . 位于res/drawable目录下的图片读取为Bitmap对象后是不能修改的,若要修改必须复制一张新的图片并设置可修改标记,Bitmap类中的copy()方法能实现该功能。

public Bitmap copy(Config config, boolean isMutable)

  参数isMutable为true,表示复制的新位图可以修改。

7 . Bitmap是一种非常占用资源的对象,如果没有处理好很容易引起OOM而导致App崩溃。需要我们及时回收Bitmap内存,用到的方法有两个,如下:

//判断是否已经回收了内存,返回true表示内存已经被回收;
public final boolean isRecycled()

//回收Bitmap内存,同一个Bitmap对象不能连续回收多次,所以在回收之前最好是先判断。不过在该方法中,已经自己判断是否回收了内存;
public void recycle()

  绘图中,Bitmap是一个很重要的类,为了提高绘图的性能,通常会使用双缓存技术,双缓存技术就是先将图绘制在Bitmap上,再统一显示出来。另外,在绘图中,Bitmap常用于保存绘制结果,而用户看到的绘制过程是需要和结果分离的。

BitmapFactory类

  图片读取操作是由BitmapFactory类完成的。
  该类有一个静态内部类Options,Options的一些成员变量如下:

//获取图片的宽度值;
public int outWidth;

//获取图片的高度值;
public int outHeight;

//如果设置为true,不获取图片,不分配内存,但会返回图片的高度宽度信息;
public boolean inJustDecodeBounds;

//如果设置为true,代表返回可变属性的Bitmap,反之不可变;
public boolean inMutable;

//图片缩放的倍数。如果值大于1,在解码过程中将按比例返回占更小内存的Bitmap。如果设为4,则宽和高都为原来的1/4,则图是原来的1/16;
public int inSampleSize;

//根据指定的Config来进行解码,例如:Bitmap.Config.RGB_565等。默认为ARGB_8888;
public Bitmap.Config inPreferredConfig = Bitmap.Config.ARGB_8888;

//用于位图的像素压缩比,Bitmap自身的密度;
public int inDensity;

//用于目标位图的像素压缩比(要生成的位图的密度),Bitmap绘制过程中使用的密度;
public int inTargetDensity;

//设置为true,且inDensity和inTargetDensity都不为0,那么在加载过程中,将会根据目标位图的密度(inTargetDensity)来进行图片缩放,在绘制过程中不依靠图片自身的密度(inDensity);
public boolean inScaled;

  该类定义了若干方法用于读取图片数据。以下是BitmapFactory类读取图片数据的方法:

1 . 将输入流解码为位图;
//方法(1)调用的是方法(2),然后在方法(2)中会判断是调用方法(3)还是调用方法(4),方法(4)会调用方法(5);
(1)public static Bitmap decodeStream(InputStream is)
(2)public static Bitmap decodeStream(InputStream is, Rect outPadding, Options opts)
(3)private static native Bitmap nativeDecodeAsset(long nativeAsset, Rect padding, Options opts)
(4)private static Bitmap decodeStreamInternal(InputStream is, Rect outPadding, Options opts)
(5)private static native Bitmap nativeDecodeStream(InputStream is, byte[] storage,Rect padding, Options opts)

2 . 解码指定字节数组为不可变位图;
//方法(1)调用的是方法(2),方法(2)调用的是方法(3);
(1)public static Bitmap decodeByteArray(byte[] data, int offset, int length)
(2)public static Bitmap decodeByteArray(byte[] data, int offset, int length, Options opts)
(3)private static native Bitmap nativeDecodeByteArray(byte[] data, int offset,int length, Options opts)

3 . 读取资源文件得到一个位图。如果位图数据不能被解码,或者opts参数只请求大小信息时,则返回null;
(当Options.inJustDecodeBounds = true时,只请求图片的大小信息)
//方法(1)调用的是方法(2),方法(2)调用的是方法(3),方法(3)调用的是decodeStream(InputStream is, Rect outPadding, Options opts)方法;
(1)public static Bitmap decodeResource(Resources res, int id)
(2)public static Bitmap decodeResource(Resources res, int id, Options opts)
(3)public static Bitmap decodeResourceStream(Resources res, TypedValue value, InputStream is, Rect pad, Options opts)

4 . 从图片文件路径读取数据并解码为位图,也就是Bitmap对象。如果指定文件为空或者不能被解码,则返回null;
//方法(1)调用的是方法(2),方法(2)调用的是decodeStream(InputStream is, Rect outPadding, Options opts)方法;
(1)public static Bitmap decodeFile(String pathName)
(2)public static Bitmap decodeFile(String pathName, Options opts)

5 . 从图片文件描述符读取数据并解码为位图,也就是Bitmap对象,比方式4效率更高,因为;
//方法(1)调用的是方法(2),在方法(2)中会进行判断是调用方法(3)还是调用decodeStreamInternal(InputStream is, Rect outPadding, Options opts)方法;
(1)public static Bitmap decodeFileDescriptor(FileDescriptor fd)
(2)public static Bitmap decodeFileDescriptor(FileDescriptor fd, Rect outPadding, Options opts)
(3)private static native Bitmap nativeDecodeFileDescriptor(FileDescriptor fd, Rect padding, Options opts)

  每次转换为Bitmap对象以后,都会调用setDensityFromOptions()方法,来设置Bitmap的density属性。

private static void setDensityFromOptions(Bitmap outputBitmap, Options opts)

BitmapDrawable类

  Bitmap和BitmapDrawable在一些情况下需要相互转换,BitmapDrawable的构造方法BitmapDrawable(Resource res,Bitmap bitmap)用于将Bitmap转换成BitmapDrawable,而getBitmap()方法则用于将BitmapDrawable转换成Bitmap。

  Bitmap和BitmapDrawable都能获得位图的宽度和高度,对比如下:

Bitmap BitmapDrawable
获取宽度 int getWidth() int getIntrinsicWidth()
获取高度 int getHeight() int getIntrinsicHeight()

-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
------------------------last line for now-----------------------