您的位置:首页 > 移动开发 > Android开发

Android中常用的位图操作

2012-07-18 18:32 423 查看
一、View转换为Bitmap

在Android中所有的控件都是View的直接子类或者间接子类,通过它们可以组成丰富的UI界面。在窗口显示的时候Android会把这些控件都加载到内存中,形成一个以ViewRoot为根节点的控件树,然后由根节点开始逐级把控件绘制到屏幕上。

可以通过调用控件的setDrawingCacheEnabled(true)方法,开启绘图缓存功能,在绘制View的时候把图像缓存起来,然后通过getDrawingCache()方法获取这个缓存的Bitmap。需要注意的是,当不再使用这个Bitmap时,需要调用destroyDrawingCache()方法,释放Bitmap资源。由于在绘制View到屏幕时缓存图像会降低控件绘制的效率,因此只会在需要使用View的图像缓存的时候才调用setDrawingCacheEnabled(true)方法开启图像缓存功能,当不再使用图像缓存时需要调用setDrawingCacheEnabled(false)
关闭图像缓存功能。

这种方法在支持拖拽类型的应用中经常见到,在Android系统的Launcher应用中也使用了这种方法,当用户拖拽应用的快捷图标时,获取到控件对应的Bitmap,然后操作这个Bitmap随着手指移动。

下面通过一段代码来说明如何获取View对应的Bitmap。在代码中使用了两个ImageView并给它们都设置了显示的图片资源,然后把第一个ImageView对应的bitmap显示到第二个ImageView中。由于在Activity的onCreate方法中调用这个方法,当执行Activity的onCreate方法时,控件还没有准备好,所以需要使用Handler进行延迟操作,Java代码如下:

[代码]java代码:

01
//View转换为Bitmap
02
public

void
getDrawingCache(
final

ImageView sourceImageView,
final

ImageView destImageView) {
03
 
04
new

Handler().postDelayed(
new

Runnable() {
05
 
06
@Override
07
public

void
run() {
08
// TODO Auto-generated method stub
09
//开启bitmap缓存
10
sourceImageView.setDrawingCacheEnabled(
true
);
11
//获取bitmap缓存
12
Bitmap mBitmap = sourceImageView.getDrawingCache();
13
//显示 bitmap
14
destImageView.setImageBitmap(mBitmap);
15
 
16
//  Bitmap mBitmap = sourceImageView.getDrawingCache();
17
//  Drawable drawable = (Drawable) new BitmapDrawable(mBitmap);
18
//  destImageView.setImageDrawable(drawable);
19
 
20
new

Handler().postDelayed(
new

Runnable() {
21
 
22
@Override
23
public

void
run() {
24
// TODO Auto-generated method stub
25
//不再显示bitmap缓存
26
//destImageView.setImageBitmap(null);
27
destImageView.setImageResource(R.drawable.pet);
28
 
29
//使用这句话而不是用上一句话是错误的,空指针调用
30
//destImageView.setBackgroundDrawable(null);
31
 
32
//关闭bitmap缓存
33
sourceImageView.setDrawingCacheEnabled(
false
);
34
//释放bitmap缓存资源
35
sourceImageView.destroyDrawingCache();
36
}
37
},DELAY_TIME);
38
}
39
},DELAY_TIME);
40
}
41
42
mImageView1.setImageResource(R.drawable.android);
43
mImageView2.setImageResource(R.drawable.pet);
44
getDrawingCache(mImageView1,mImageView2);
运行效果如下:




图7-3 Demo运行效果图1




图7-4 Demo运行效果图2

二、图片圆角处理

在Android中可以很容通过图像叠加的规则为图片添加圆角效果。正常情况下,在已有的图像上绘图时将会在其上面添加一层新的图形。如果绘图时使用的Paint是完全不透明的,那么它将完全遮挡住下面的图像,如果Paint是部分透明的,那么它将会对重叠部分图像的颜色叠加处理。通过PorterDuffXfermode规则可以设置绘制图像时的叠加规则。PorterDuffXfermode是非常强大的转换模式,使用它可以设置图像叠加的Porter-Duff规则,来控制Paint如何与Canvas上已有的图像进行叠加。下面列举了常用的12条Porter-Duff规则及其表示的含义:

PorterDuff.Mode.CLEAR 清除画布上图像
PorterDuff.Mode.SRC 显示上层图像
PorterDuff.Mode.DST 显示下层图像
PorterDuff.Mode.SRC_OVER上下层图像都显示,下层居上显示
PorterDuff.Mode.DST_OVER 上下层都显示,下层居上显示
PorterDuff.Mode.SRC_IN 取两层图像交集部分,只显示上层图像
PorterDuff.Mode.DST_IN 取两层图像交集部分,只显示下层图像
PorterDuff.Mode.SRC_OUT 取上层图像非交集部分
PorterDuff.Mode.DST_OUT 取下层图像非交集部分
PorterDuff.Mode.SRC_ATOP 取下层图像非交集部分与上层图像交集部分
PorterDuff.Mode.DST_ATOP 取上层图像非交集部分与下层图像交集部分
PorterDuff.Mode.XOR 取两层图像的非交集部分

下面使用PorterDuff.Mode.SRC_IN规则来给图片添加圆角效果,主要的思路是先绘制一个圆角矩形,然后在上面绘制图像,取图像与圆角矩形的交集部分,只保留图像。Java代码如下:

[代码]java代码:

01
//图片圆角处理
02
public
Bitmap getRoundedBitmap() {
03
Bitmap mBitmap = BitmapFactory.decodeResource(getResources(),R.drawable.frame);
04
//创建新的位图
05
Bitmap bgBitmap = Bitmap.createBitmap(mBitmap.getWidth(),mBitmap.getHeight(),Config.ARGB_8888);
06
//把创建的位图作为画板
07
Canvas mCanvas =
new
Canvas(bgBitmap);
08
 
09
Paint mPaint =
new
Paint();
10
Rect mRect =
new
Rect(
0
,
0
,mBitmap.getWidth(),mBitmap.getHeight());
11
RectF mRectF =
new
RectF(mRect);
12
//设置圆角半径为20
13
float

roundPx =
15
;
14
mPaint.setAntiAlias(
true
);
15
//先绘制圆角矩形
16
mCanvas.drawRoundRect(mRectF,roundPx,roundPx,mPaint);
17
 
18
//设置图像的叠加模式
19
mPaint.setXfermode(
new

PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
20
//绘制图像
21
mCanvas.drawBitmap(mBitmap,mRect,mRect,mPaint);
22
 
23
return

bgBitmap;
24
}
效果如下图所示:




图7-5 图片圆角处理

三、图片灰化处理

在Android中可以通过ColorMatrix类实现图像处理软件中的滤镜效果,通过ColorMatrix类可以对位图中的每个像素进行变换处理,达到特殊的滤镜效果,下面通过一个例子来介绍如何通过ColorMatrix对图像进行灰化处理,Java代码如下:

[代码]java代码:

01
//图片灰化处理
02
public

Bitmap getGrayBitmap() {
03
Bitmap mBitmap = BitmapFactory.decodeResource(getResources(),R.drawable.android);
04
Bitmap mGrayBitmap = Bitmap.createBitmap(mBitmap.getWidth(),mBitmap.getHeight(),Config.ARGB_8888);
05
Canvas mCanvas =
new
Canvas(mGrayBitmap);
06
Paint mPaint =
new
Paint();
07
 
08
//创建颜色变换矩阵
09
ColorMatrix mColorMatrix =
new
ColorMatrix();
10
//设置灰度影响范围
11
mColorMatrix.setSaturation(
0
);
12
//创建颜色过滤矩阵
13
ColorMatrixColorFilter mColorFilter =
new
ColorMatrixColorFilter(mColorMatrix);
14
//设置画笔的颜色过滤矩阵
15
mPaint.setColorFilter(mColorFilter);
16
//使用处理后的画笔绘制图像
17
mCanvas.drawBitmap(mBitmap,
0
,
0
,mPaint);
18
 
19
return

mGrayBitmap; 
20
}
效果如下图所示:




图7-6 图片灰化处理

四、提取图像Alpha位图

Android中的ARGB_8888类型的位图由Alpha(透明度)、Red(红)、Green(绿)、Blue(蓝)四部分组成,其中Alpha部分也就是常说的Alpha通道,它控制图像的透明度。在Android中Bitmap类提供了extractAlpha()方法,可以把位图中的Alpha部分提取出来作为一个新的位图,然后与填充颜色后的Paint结合重新绘制一个新图像。下面通过一个例子来说明Bitmap类的extractAlpha()方法的使用,Java代码如下:

[代码]java代码:

01
//提取图像Alpha位图
02
public
Bitmap getAlphaBitmap() {
03
BitmapDrawable mBitmapDrawable = (BitmapDrawable) getResources().getDrawable(R.drawable.enemy_infantry_ninja);
04
Bitmap mBitmap = mBitmapDrawable.getBitmap();
05
 
06
//BitmapDrawable的getIntrinsicWidth()方法,Bitmap的getWidth()方法
07
//注意这两个方法的区别
08
//Bitmap mAlphaBitmap = Bitmap.createBitmap(mBitmapDrawable.getIntrinsicWidth(),mBitmapDrawable.getIntrinsicHeight(),Config.ARGB_8888);
09
Bitmap mAlphaBitmap = Bitmap.createBitmap(mBitmap.getWidth(),mBitmap.getHeight(),Config.ARGB_8888);
10
 
11
Canvas mCanvas =
new
Canvas(mAlphaBitmap);
12
Paint mPaint =
new
Paint();
13
 
14
mPaint.setColor(Color.BLUE);
15
//从原位图中提取只包含alpha的位图
16
Bitmap alphaBitmap = mBitmap.extractAlpha();
17
//在画布上(mAlphaBitmap)绘制alpha位图
18
mCanvas.drawBitmap(alphaBitmap,
0
,
0
,mPaint);
19
 
20
return

mAlphaBitmap;
21
}



图7-7 提取图像Alpha位图

其中最后一幅图片是把原图片四个边距缩小两个dp,然后与Alpha位图一起绘制的结果,读者可以参考本章Demo中的getStrokeBitmap()方法。

五、图像变换

Android开发框架提供了一个坐标变换矩阵Matrix类,它可以与Bitmap类的createBitmap方法结合使用,对图像进行缩放、旋转、扭曲等变换处理。图像变换操作就是对坐标变换矩阵进行矩阵乘法运算,Matrix类中提供了一些简便的方法如preScale、postScale、preRotate、postRotate、preSkrew、postSkrew、preTranslate、postTranslate等封装了矩阵的运算,它们与Bitmap类的createBitmap方法结合使用可以很容易地对图像进行缩放、旋转、扭曲、平移操作。

1)图像缩放

使用Matrix类preScale或者postScale可以对图像进行缩放操作,它的两个参数分别为x和y坐标缩放比例,下面使用preScale对图像进行放大0.75倍,Java代码如下:

[代码]java代码:

01
//getScaleBitmap
02
public

Bitmap getScaleBitmap() {
03
BitmapDrawable mBitmapDrawable = (BitmapDrawable) getResources().getDrawable(R.drawable.pet);
04
Bitmap mBitmap = mBitmapDrawable.getBitmap();
05
int

width = mBitmap.getWidth();
06
int

height = mBitmap.getHeight();
07
 
08
Matrix matrix =
new
Matrix();
09
matrix.preScale(
0
.75f,
0
.75f);
10
Bitmap mScaleBitmap = Bitmap.createBitmap(mBitmap,
0
,
0
,width,height,matrix,
true
);
11
 
12
return

mScaleBitmap;
13
}
效果如下图所示:




图7-8 图像缩放

2)图片旋转

使用Matrix类preRotate或者postRotate可以对图像进行旋转操作,它只有一个参数表示旋转的角度,下面使用preRotate对图像顺时针旋转30度,Java代码如下:

[代码]java代码:

01
//getRotatedBitmap
02
public

Bitmap getRotatedBitmap() {
03
BitmapDrawable mBitmapDrawable = (BitmapDrawable) getResources().getDrawable(R.drawable.pet);
04
Bitmap mBitmap = mBitmapDrawable.getBitmap();
05
int

width = mBitmap.getWidth();
06
int

height = mBitmap.getHeight();
07
 
08
Matrix matrix =
new
Matrix();
09
matrix.preRotate(
45
);
10
Bitmap mRotateBitmap = Bitmap.createBitmap(mBitmap,
0
,
0
,width,height,matrix,
true
);
11
 
12
return

mRotateBitmap;
13
}
效果如下图所示:




图7-9 图片旋转

3)图像倾斜

使用Matrix类preSkew或者postSkew可以对图像进行倾斜操作,它的两个参数分别为x和y坐标倾斜度,下面使用preSkew对图像进行倾斜变换,Java代码如下:

[代码]java代码:

01
//getScrewBitmap
02
public
Bitmap getScrewBitmap() {
03
BitmapDrawable mBitmapDrawable = (BitmapDrawable) getResources().getDrawable(R.drawable.pet);
04
Bitmap mBitmap = mBitmapDrawable.getBitmap();
05
int

width = mBitmap.getWidth();
06
int

height = mBitmap.getHeight();
07
 
08
Matrix matrix =
new
Matrix();
09
matrix.preSkew(
1
.0f,
0
.15f);
10
Bitmap mScrewBitmap = Bitmap.createBitmap(mBitmap,
0
,
0
,width,height,matrix,
true
);
11
 
12
return

mScrewBitmap;
13
}
效果如下图所示:




图7-10 图像倾斜

4)图像倒影

为图像添加倒影效果之后,图像看起来会有立体感,更有真实感,在Android中使用Matrix类可以很容易实现图像的倒影效果。主要是Matrix的preScale方法的使用,给它设置负数缩放比例,图像就会进行反转。然后通过设置Shader添加渐变效果。Java代码如下:

[代码]java代码:

01
//getReflectedBitmap
02
private

Bitmap getReflectedBitmap() {
03
BitmapDrawable mBitmapDrawable = (BitmapDrawable) getResources().getDrawable(R.drawable.pet);
04
Bitmap mBitmap = mBitmapDrawable.getBitmap();
05
int

width = mBitmap.getWidth();
06
int

height = mBitmap.getHeight();
07
 
08
Matrix matrix =
new
Matrix();
09
// 图片缩放,x轴变为原来的1倍,y轴为-1倍,实现图片的反转
10
matrix.preScale(
1
,-
1
);
11
 
12
//创建反转后的图片Bitmap对象,图片高是原图的一半。
13
//Bitmap mInverseBitmap = Bitmap.createBitmap(mBitmap,0,height/2,width,height/2,matrix,false);
14
//创建标准的Bitmap对象,宽和原图一致,高是原图的1.5倍。
15
//注意两种createBitmap的不同
16
//Bitmap mReflectedBitmap = Bitmap.createBitmap(width,height*3/2,Config.ARGB_8888);
17
 
18
Bitmap mInverseBitmap = Bitmap.createBitmap(mBitmap,
0
,
0
,width,height,matrix,
false
);
19
Bitmap mReflectedBitmap = Bitmap.createBitmap(width,height*
2
,Config.ARGB_8888);
20
 
21
// 把新建的位图作为画板
22
Canvas mCanvas =
new
Canvas(mReflectedBitmap);
23
//绘制图片
24
mCanvas.drawBitmap(mBitmap,
0
,
0
,
null
);
25
mCanvas.drawBitmap(mInverseBitmap,
0
,height,
null
);
26
 
27
//添加倒影的渐变效果
28
Paint mPaint =
new
Paint();
29
Shader mShader =
new
LinearGradient(
0
,height,
0
,mReflectedBitmap.getHeight(),
0x70ffffff
,
0x00ffffff
,TileMode.MIRROR);
30
mPaint.setShader(mShader);
31
//设置叠加模式
32
mPaint.setXfermode(
new

PorterDuffXfermode(PorterDuff.Mode.DST_IN));
33
//绘制遮罩效果
34
mCanvas.drawRect(
0
,height,width,mReflectedBitmap.getHeight(),mPaint);
35
 
36
return

mReflectedBitmap;
37
}
效果如下图所示:




图7-11 图像倒影

5)图像剪切

如果只需要图像的一部分,就必须对图像进行剪切处理,在原图像上选择一个剪切区域,使用PorterDuffXfermode图像叠加规则,就可以把指定的图像区域剪切下来,下面通过三个步骤来说明如果对图像进行剪切操作。

第一步,创建一个新位图作为画板,然后把原图像画到新位图上面,Java代码如下:

[代码]java代码:

01
BitmapDrawable bd = (BitmapDrawable) getResources().getDrawable(
02
R.drawable.beauty);
03
Bitmap bitmap = bd.getBitmap();
04
int
w = bitmap.getWidth();
05
int
h = bitmap.getHeight();
06
Bitmap bm = Bitmap.createBitmap(w,h,Config.ARGB_8888);
07
Canvas canvas =
new

Canvas(bm);
08
Paint mPaint =
new

Paint();
09
mPaint.setAntiAlias(
true
);
10
mPaint.setStyle(Style.STROKE);
11
canvas.drawBitmap(bitmap,
0
,
0
,mPaint);
效果如下图所示:




图7-12 第一步效果图

第二步,绘制一个剪切区域,比如要剪切人物的脸部区域,需要在指定的位置绘制一个圆角矩形区域,代码中的坐标是在调试中获得,在其他分辨率下会有所不同,Java代码如下:

[代码]java代码:

01
int
deltX =

76
;
02
int
deltY =

98
;
03
DashPathEffect dashStyle =
new

DashPathEffect(
new
float
[] {
10
,
5
,
5
,
5
},
2
);
//创建虚线边框样式
04
RectF faceRect =
new

RectF(
0
,
0
,
88
,
106
);
05
float
[] faceCornerii =
new
float
[] {
30
,
30
,
30
,
30
,
75
,
75
,
75
,
75
};
06
Paint mPaint =
new

Paint();
//创建画笔
07
mPaint.setColor(
0xFF6F8DD5
);
08
mPaint.setStrokeWidth(
6
);
09
mPaint.setPathEffect(dashStyle);
10
Path clip =
new

Path();
//创建路径
11
clip.reset();
12
clip.addRoundRect(faceRect,faceCornerii,Direction.CW);
//添加圆角矩形路径
13
canvas.save();
//保存画布
14
canvas.translate(deltX,deltY);
15
canvas.clipPath(clip,Region.Op.DIFFERENCE);
16
canvas.drawColor(
0xDF222222
);
17
canvas.drawPath(clip,mPaint);
//绘制路径
18
canvas.restore();
效果如下图所示:




图7-13 第二步效果

第三步,从原图像上获取指定区域的图像,并绘制到屏幕上,java代码如下:

[代码]java代码:

1
Rect srcRect =
new

Rect(
0
,
0
,
88
,
106
);
2
srcRect.offset(deltX,deltY);
3
PaintFlagsDrawFilter dfd =
new

PaintFlagsDrawFilter(Paint.ANTI_ALIAS_FLAG,
4
Paint.FILTER_BITMAP_FLAG);
5
canvas.setDrawFilter(dfd);
6
canvas.clipPath(clip);
//使用路径剪切画布
7
canvas.drawBitmap(bitmap,srcRect,faceRect,mPaint);
效果如下图所示:




图7-13 第三部效果图

6)图像合成

如果要为图片添加水印,或者把几张小图片拼接成大图片时,就需要利用图像合成的方法,在前面实例代码中已经使用了这种方法,就是创建新位图作为画板,然后在对应的位置上绘制其他图像。
读者可以参考本章Demo中的getCompoundedBitmap方法,这里不做过多说明。

转自:http://www.devdiv.com/home.php?mod=space&uid=20&do=blog&id=8918
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: