Bitmap使用详解

用到的图片不仅仅包括.png、.gif、.9.png、.jpg和各种Drawable系对象,还包括位图Bitmap

图片的处理也经常是影响着一个程序的高效性和健壮性。

Bitmap

  • Bitmap代表一张位图,扩展名可以是.bmp或者.dib。
  • 由点(像素)组成,每个点可以由多种色彩表示
  • Bitmap是图像处理最重要的中转类之一。
  • 用它可以获取图像文件信息,进行图像剪切、旋转、缩放等操作,并可以指定格式保存图像文件。

为什么不直接用Bitmap传输?
位图文件虽好,但是非压缩格式,占用较大存储空间。

Bitmap主要方法有:获取图像宽高、释放,判断是否已释放和是否可修改,压缩、创建制定位图等功能

public void recycle()  // 回收位图占用的内存空间,把位图标记为Dead
public final boolean isRecycled()  //判断位图内存是否已释放
public final int getWidth() //获取位图的宽度
public final int getHeight() //获取位图的高度
public final boolean isMutable() //图片是否可修改
public int getScaledWidth(Canvas canvas) //获取指定密度转换后的图像的宽度
public int getScaledHeight(Canvas canvas) //获取指定密度转换后的图像的高度
public static Bitmap createBitmap(Bitmap src)  //以src为原图生成不可变得新图像
public static Bitmap createScaledBitmap(Bitmap src, int dstWidth, int dstHeight, boolean filter) //以src为原图,创建新的图像,指定新图像的高宽以及是否可变。
public static Bitmap createBitmap(int width, int height, Config config) //创建指定格式、大小的位图
public static Bitmap createBitmap(Bitmap source, int x, int y, int width, int height) //以source为原图,创建新的图片,指定起始坐标以及新图像的高宽。
public boolean compress(CompressFormat format, int quality, OutputStream stream) //按指定的图片格式以及画质,将图片转换为输出流。

format:压缩图像的格式,如Bitmap.CompressFormat.PNG或+ Bitmap.CompressFormat.JPEG
quality:画质,0-100.0表示最低画质压缩,100以最高画质压缩。对于PNG等无损格式的图片,会忽略此项设置。
stream: OutputStream中写入压缩数据。
return: 是否成功压缩到指定的流。

BitmapFactory

用于从不同的数据源(如文件、输入流、资源文件、字节数组、文件描述符等)解析、创建Bitmap对象

public static Bitmap decodeFile(String pathName, Options opts)  //从文件读取图片
public static Bitmap decodeFile(String pathName)
public static Bitmap decodeStream(InputStream is)  //从输入流读取图片
public static Bitmap decodeStream(InputStream is, Rect outPadding, Options opts)
public static Bitmap decodeResource(Resources res, int id)  //从资源文件读取图片
public static Bitmap decodeResource(Resources res, int id, Options opts)
public static Bitmap decodeByteArray(byte[] data, int offset, int length)  //从数组读取图片
public static Bitmap decodeByteArray(byte[] data, int offset, int length, Options opts)
public static Bitmap decodeFileDescriptor(FileDescriptor fd) //从文件读取文件 与decodeFile不同的是这个直接调用JNI函数进行读取 效率比较高
public static Bitmap decodeFileDescriptor(FileDescriptor fd, Rect outPadding, Options opts)

BitmapFactory.Options 类

允许我们定义图片以何种方式如何读到内存。

public boolean inJustDecodeBounds //如果设置为true,不获取图片,不分配内存,但会返回图片的高度宽度信息。
public int inSampleSize //图片缩放的倍数
这个值是一个int,当它小于1的时候,将会被当做1处理,如果大于1,那么就会按照比例(1 / inSampleSize)缩小bitmap的宽和高、降低分辨率,大于1时这个值将会被处置为2的倍数。例如,width=100,height=100,inSampleSize=2,那么就会将bitmap处理为,width=50,height=50,宽高降为1 / 2,像素数降为1 / 4。
public int outWidth //获取图片的宽度值
public int outHeight //获取图片的高度值
表示这个Bitmap的宽和高,一般和inJustDecodeBounds一起使用来获得Bitmap的宽高,但是不加载到内存。
public int inDensity //用于位图的像素压缩比
public int inTargetDensity //用于目标位图的像素压缩比(要生成的位图)
public byte[] inTempStorage  //创建临时文件,将图片存储
public boolean inScaled //设置为true时进行图片压缩,从inDensity到inTargetDensity
public boolean inDither  //如果为true,解码器尝试抖动解码
public Bitmap.Config inPreferredConfig  //设置解码器
这个值是设置色彩模式,默认值是ARGB_8888,在这个模式下,一个像素点占用4bytes空间,一般对透明度不做要求的话,一般采用RGB_565模式,这个模式下一个像素点占用2bytes。
public String outMimeType  //设置解码图像
public boolean inPurgeable //当存储Pixel的内存空间在系统内存不足时是否可以被回收
public boolean inInputShareable  //inPurgeable为true情况下才生效,是否可以共享一个InputStream
public boolean inPreferQualityOverSpeed  //为true则优先保证Bitmap质量其次是解码速度
public boolean inMutable  //配置Bitmap是否可以更改,比如:在Bitmap上隔几个像素加一条线段
public int inScreenDensity  //当前屏幕的像素密度

一张图片(BitMap)占用的内存=图片长度图片宽度单位像素占用的字节数。

推荐阅读:Android - Bitmap-内存分析

Bitmap应用

构造Bitmap对象

  • 通过Bitmap的静态方法static Bitmap createBitmap()
  • 通过BitmapFactory工厂类的static Bitmap decodeXxx()

加载方式

  • Resource资源加载
  • 本地(SDcard)加载
  • 网络加载
  • 从二进制数据读取图片

注意事项:

本地(SDcard)加载

decodeFileDescriptor比decodeFile高效

查看源码可以知道

  • decodeFile()最终是以流的方式生成bitmap
  • decodeFileDescriptor的源码,可以找到native本地方法decodeFileDescriptor,通过底层生成bitmap
Bitmap bmp = BitmapFactory.decodeFile(imageFile, opts);
 imageView.setImageBitmap(bmp);

替换成

FileInputStream is = = new FileInputStream(path);
bmp = BitmapFactory.decodeFileDescriptor(is.getFD(), null, opts);

Resource资源加载

Res资源加载方式

建议采用decodeStream代替decodeResource。

因为BitmapFactory.decodeResource 加载的图片可能会经过缩放,该缩放目前是放在 java 层做的,效率比较低,而且需要消耗 java 层的内存。因此,如果大量使用该接口加载图片,容易导致OOM错误,BitmapFactory.decodeStream 不会对所加载的图片进行缩放,相比之下占用内存少,效率更高。

这两个接口各有用处,如果对性能要求较高,则应该使用 decodeStream;如果对性能要求不高,且需要 Android 自带的图片自适应缩放功能,则可以使用 decodeResource。

推荐阅读:[BitmapFactory.decodeResource加载图片缩小的原因及解决方法

Assets资源加载方式

InputStream in = this.getAssets().open("ic_launcher");
Drawable da = Drawable.createFromStream(in, null);
Bitmap mm = BitmapFactory.decodeStream(in);

扩展

view转Bitmap
public static Bitmap convertViewToBitmap(View view, int bitmapWidth, int bitmapHeight){
    Bitmap bitmap = Bitmap.createBitmap(bitmapWidth, bitmapHeight, Bitmap.Config.ARGB_8888);
    view.draw(new Canvas(bitmap));
    return bitmap;
}

将控件转换为bitmap
public static Bitmap convertViewToBitMap(View view){
    // 打开图像缓存
    view.setDrawingCacheEnabled(true);
    // 必须调用measure和layout方法才能成功保存可视组件的截图到png图像文件
    // 测量View大小
    view.measure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED), MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
    // 发送位置和尺寸到View及其所有的子View
    view.layout(0, 0, view.getMeasuredWidth(), view.getMeasuredHeight());
    // 获得可视组件的截图
    Bitmap bitmap = view.getDrawingCache();
    return bitmap;
}
public static Bitmap getBitmapFromView(View view){
    Bitmap returnedBitmap = Bitmap.createBitmap(view.getWidth(), view.getHeight(), Bitmap.Config.ARGB_8888);
    Canvas canvas = new Canvas(returnedBitmap);
    Drawable bgDrawable = view.getBackground();
    if (bgDrawable != null)
        bgDrawable.draw(canvas);
    else
        canvas.drawColor(Color.WHITE);
    view.draw(canvas);
    return returnedBitmap;
}
几何变换

canvas和Matrix可对Bitmap进行旋转、放缩、平移、切错等操作

对 bitmap 进行裁剪

可以用Bitmap.onCreateBitmap、Canvas的clipRect和clipPath等等方式

推荐阅读:android自定义View学习4--图像剪切与变换

Bitmap | Drawable | InputStream | Byte[ ] 之间进行转换

Drawable转化成Bitmap

blic static Bitmap drawableToBitmap(Drawable drawable) {
        Bitmap bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), drawable.getOpacity() != PixelFormat.OPAQUE ? Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565);
        Canvas canvas = new Canvas(bitmap);
        drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight());
        drawable.draw(canvas);
        return bitmap;
    }

Bitmap转换成Drawable

public static Drawable bitmapToDrawable(Resources resources, Bitmap bm) {
        Drawable drawable = new BitmapDrawable(resources, bm);
        return drawable;
    }

Bitmap的内存优化

及时回收Bitmap
捕获异常

对初始化Bitmap对象过程中可能发生的OutOfMemory异常进行了捕获。如果发生了OutOfMemory异常,应用不会崩溃,而是得到了一个默认的Bitmap图。

缓存通用的Bitmap对象

如果不进行缓存,尽管看到的是同一张图片文件,但是使用BitmapFactory类的方法来实例化出来的Bitmap,是不同的Bitmap对象。缓存可以避免新建多个Bitmap对象,避免内存的浪费。

压缩图片

如果图片像素过大,使用BitmapFactory类的方法实例化Bitmap的过程中,需要大于8M的内存空间,就必定会发生OutOfMemory异常。
可以将图片缩小,以减少载入图片过程中的内存的使用,避免异常发生。

合理选择Bitmap的像素格式
使用矩阵

推荐阅读:
Bitmap详解与Bitmap的内存优化

你可能感兴趣的:(Bitmap使用详解)