Android Bitmap Api总结和使用方法

来源:互联网 发布:少年犯之七人 知乎 编辑:程序博客网 时间:2024/05/20 01:37
在学习Bitmap之前先学习一下Bitmap是怎么创建在,Bitmap的构造方法都是私有的,所以无法直接调用Bitmap的构造方法。我们只能通过BitmapFactory类和Bitmap.createBitmap来创建Bitmap。所以,我们要先了解BitmapFactory

BitmapFactory API总结
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
//BitmapFactory Android4.4 API总结 2015年5月19日

//BitmapFactory 选项
public static class Options {
    public Options(){
        inDither = false;
        inScaled = true;
    }
    public Bitmap inBitmap;
    public boolean inMutable;
    public boolean inJustDecodeBounds;  //true时,只获取宽高
    public int inSampleSize;            //缩放倍数,压缩图片内存大小 
    public Bitmap.Config inPreferredConfig = Bitmap.Config.ARGB_8888;
    public boolean inDither;
    public int inDensity;
    public int inTargetDensity;
    public int inScreenDensity;
    public boolean inScaled;
    public boolean inPurgeable;
    public boolean inInputShareable;
    public boolean inPreferQualityOverSpeed;
    public int outWidth;        //inJustDecodeBounds=true时,输出图片宽
    public int outHeight;       //inJustDecodeBounds=true时,输出图片高
    public String outMimeType;
    public byte[] inTempStorage;
    private native void requestCancel();
    public boolean mCancel;
    public void requestCancelDecode(){
        mCancel = true;
        requestCancel();
    }
}

//通过文件路径创建Bitmap    
static Bitmap decodeFile(String pathName, Options opts);
static Bitmap decodeFile(String pathName);
//通过resources id创建Bitmap
//value: 一些图片值,如density等
static Bitmap decodeResourceStream(Resources res, TypedValue value, InputStream is, Rect pad, Options opts);
static Bitmap decodeResource(Resources res, int id, Options opts);
static Bitmap decodeResource(Resources res, int id);
//通过二进制创建Bitmap
//offset: 位置偏移
//length:data数组的读取长度
static Bitmap decodeByteArray(byte[] data, int offset, int length, Options opts);
static Bitmap decodeByteArray(byte[] data, int offset, int length);
//通过流文件创建Bitmap
static Bitmap decodeStream(InputStream is, Rect outPadding, Options opts);
static Bitmap decodeStream(InputStream is);
//通过流文件描述符创建Bitmap
static Bitmap decodeFileDescriptor(FileDescriptor fd, Rect outPadding, Options opts);
static Bitmap decodeFileDescriptor(FileDescriptor fd);

BitmapFactory API使用方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

//decodeResource 使用方法
Bitmap rawBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.haha);

//decodeFile 使用方法
String SDCarePath = Environment.getExternalStorageDirectory().toString();
String filePath = SDCarePath + "/" + "haha.jpg";
Bitmap rawBitmap1 = BitmapFactory.decodeFile(filePath, null);

//decodeStream 使用方法
InputStream is;
is = context.getResources().openRawResource(R.drawable.frog);
mBitmap2 = BitmapFactory.decodeStream(is);

//decodeByteArray 使用方法
ByteArrayOutputStream os = new ByteArrayOutputStream();

//(压缩格式, 压缩质量 0-100, 输出流)
src.compress(format, quality, os);
byte[] array = os.toByteArray();
return BitmapFactory.decodeByteArray(array, 0, array.length);

Bitmap createBitmap API总结
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
//从原位图src复制出一个新的位图,和原始位图相同
public static Bitmap createBitmap (Bitmap src)
//这个函数根据颜色数组来创建位图,注意:颜色数组的长度>=width*height
//此函数创建位图的过程可以简单概括为为:以width和height创建空位图,然后用指定的颜色数组colors来从左到右从上至下一次填充颜色。
//config是一个枚举,可以用它来指定位图“质量”。
public static Bitmap createBitmap (int[] colors, int width, int height, Bitmap.Config config) 
//offset      写入到pixels[]中的第一个像素索引值 
//stride      pixels[]中的行间距个数值(必须大于等于位图宽度) 
public static Bitmap createBitmap (int[] colors, int offset, int stride, int width, int height, Bitmap.Config config)
/*
从原始位图剪切图像,这是一种高级的方式。可以用Matrix(矩阵)来实现旋转等高级方式截图
参数说明:
  Bitmap source:要从中截图的原始位图
  int x:    起始x坐标
  int y:    起始y坐标
    int width:  要截的图的宽度
    int height:要截的图的宽度
Bitmap.Config  config:一个枚举类型的配置,可以定义截到的新位图的质量
返回值:返回一个剪切好的Bitmap
 */

public static Bitmap createBitmap (Bitmap source, int x, int y, int width, int height, Matrix m, boolean filter)

//根据参数创建新位图
public static Bitmap createBitmap (int width, int height, Bitmap.Config config)
//简单的剪切图像的方法,可以参考createBitmap
public static Bitmap createBitmap (Bitmap source, int x, int y, int width, int height) 

Bitmap createBitmap及Bitmap. Config作用方法:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
private static final int WIDTH = 50;
private static final int HEIGHT = 50;
private static final int STRIDE = 64;   // must be >= WIDTH
private Bitmap[] mBitmaps;
private int[] mColors;

private static int[] createColors() {
    int[] colors = new int[STRIDE * HEIGHT];
    for (int y = 0; y < HEIGHT; y++) {
        for (int x = 0; x < WIDTH; x++) {
            int r = x * 255 / (WIDTH - 1);
            int g = y * 255 / (HEIGHT - 1);
            int b = 255 - Math.min(r, g);
            int a = Math.max(r, g);
            colors[y * STRIDE + x] = (a << 24) | (r << 16) | (g << 8) | b;
        }
    }
    return colors;
}

public MyCreateBitmapView(Context context) {
    super(context);

    mColors = createColors();
    int[] colors = mColors;

    mBitmaps = new Bitmap[4];
    // these three are initialized with colors[]
    mBitmaps[0] = Bitmap.createBitmap(colors, 0, STRIDE, WIDTH, HEIGHT,
                                      Bitmap.Config.ARGB_8888);
    mBitmaps[1] = Bitmap.createBitmap(colors, 0, STRIDE, WIDTH, HEIGHT,
                                      Bitmap.Config.RGB_565);
    mBitmaps[2] = Bitmap.createBitmap(colors, 0, STRIDE, WIDTH, HEIGHT,
                                      Bitmap.Config.ARGB_4444);

    mBitmaps[3] = Bitmap.createBitmap(WIDTH, HEIGHT,
                                      Bitmap.Config.ARGB_8888);
    mBitmaps[3].setPixels(colors, 0, STRIDE, 00, WIDTH, HEIGHT);
}

@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    for (int i = 0; i < mBitmaps.length; i++) {
        canvas.drawBitmap(mBitmaps[i], 00, null);
        canvas.translate(mBitmaps[i].getHeight() + 5,  0);
    }
}




createBitmap的Matrix使用方法,背景缩放和透明
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
int width = 600;
int height = 1024;

int widthDrawable = backGroundMap.getWidth();
int heightDrawable = backGroundMap.getHeight();//获取背景图片的宽和高

float scaleWidth = (float)width / widthDrawable;
float scaleHeight = (float)height / heightDrawable; //宽高比

Bitmap resizeBmp;
Matrix matrix = new Matrix();

if(scaleWidth < scaleHeight) {
    float scale = scaleHeight;//取大的
    matrix.postScale(scale, scale);//缩放比例
    int xStart = (int)(widthDrawable - widthDrawable / scale) / 2;

    /*
     * Bitmap source:要从中截图的原始位图
     * int x:起始x坐标
     * int y:起始y坐标
     * int width:要截的图的宽度
     * int height:要截的图的宽度
     * x+width must be <= bitmap.width()不然会报错
     * 原理是先截图再缩放,而不是先缩放再截图!!
     */

    resizeBmp = Bitmap.createBitmap(backGroundMap, xStart, 0, (int)(widthDrawable / scale),
                                    heightDrawable, matrix, true);
else {
    float scale = scaleWidth;
    matrix.postScale(scale, scale);
    int yStart = (int)(scaleHeight - scaleHeight / scale) / 2;
    resizeBmp = Bitmap.createBitmap(backGroundMap, 0, yStart, widthDrawable,
                                    (int)(heightDrawable / scale), matrix, true);
}

//Bitmap 转化为 Drawable
BitmapDrawable drawable = new BitmapDrawable(getResources(), resizeBmp);
setBackgroundDrawable(drawable);
//getBackground().setAlpha(150);    //设置背景透明度
            

Bitmap的优化:
Android分给应用的虚拟机堆栈只有8M,而加载图片时会很消耗资源,只要图片只够大,也就很容易把8M的内存消耗光,就会出现OOM(Out Of Memory)的问题。所以,应用程序要很注意对内存的优化:
优化的方法如下:
1)主动回收Bitmap的内存
在Android中,很多关于UI的实现都是在Jni用C语言实现的。这样做主要是因为,对图片的处理要做大量的位操作,在C语言中,位操作更快,更容易。C语言的效率会更高,对于大量数据的处理可以更快。但是这就会出现一个问题,在Jni里面开辟的内存,数组,缓存等虚拟机是无法自动回收的。只能是Jni程序员在某个时间手动回收。也有可能是程序退出的时候才回收,但我们在程序使用的过程中会产生很多无用的Bitmap,这时,这些Bitmap就要我们在上层手动回收了:
在Android 的 Bitmap里就提供了主动回收的函数recycle():
我们可能是返回,退出的时候回收,也可能在应用隐藏到后台的时候回收,也可以 在线程退出的时候回收,可以对Bitmap的临时变量做回收。可以在Bitmap转换后把原来的进行回收。需要回收的地方可能很多,这里只是稍微提供一下思路
1
2
3
4
if(!bmp.isRecycle() ) {
    bmp.recycle()   //回收图片所占的内存
    system.gc()  //提醒系统及时回收
}


2)捕获异常
这里主要是要捕获分配Bitmap时会出现OutOfMemory异常,保证出现问题后,程序可以断续运行:
1
2
3
4
5
6
7
8
9
10
11
Bitmap bitmap = null;
try {
    // 实例化Bitmap
    bitmap = BitmapFactory.decodeFile(path);
catch (OutOfMemoryError e) {
    //
}
if (bitmap == null) {
    // 如果实例化失败 返回默认的Bitmap对象
    return defaultBitmapMap;
}
但是要注意:OutOfMemoryError是一个Error,如果是直接捕获Exception是无捕获的

3)压缩图片大小和内存
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

//获得原始图片的大小 
BitmapFactory.Options options = new BitmapFactory.Options();
//inJustDecodeBounds=true时只加载图片的宽高:options.outWidth 和 options.outHeight
options.inJustDecodeBounds = true;  
Bitmap bmp = BitmapFactory.decodeFile(path, options);/* 这里返回的bmp是null */

//缩小图片
int height = options.outHeight * 200 / options.outWidth;
//压缩图片容量,如果没有这句,只是缩小图片到指定尺寸,不会会影响内存
options.inSampleSize = options.outWidth / 200/*图片长宽方向缩小倍数*/
options.outWidth = 200;
options.outHeight = height; 
options.inJustDecodeBounds = false;

Bitmap bmp = BitmapFactory.decodeFile(path, options);
image.setImageBitmap(bmp);

4)通过临时缓存保存Bitmap
对于大用到Bitmap,和快速重复更新的情况下就要通过临时变量对保存Bitmap,避免重复加载和创建,例如ListView的里会不断刷新Bitmap,这里就要用在ListVeiw里用一个临时变量保存ListView的Bitmap,数据等。具体看一下ListView的优化



参考文章:
http://blog.sina.com.cn/s/blog_5da93c8f0102v2x4.html
http://www.cnblogs.com/igrl/archive/2010/07/30/Bitmap_createBitmap.html
http://www.jb51.net/article/36631.htm
0 0
原创粉丝点击