Android中常用的位图操作
2013-02-04 17:44
411 查看
一、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]
view plaincopyprint?
//View转换为Bitmap
public void getDrawingCache(final ImageView sourceImageView,
final ImageView destImageView) {
new Handler().postDelayed(new Runnable() {
@Override
public
void run() {
// TODO Auto-generated method stub
//开启bitmap缓存
sourceImageView.setDrawingCacheEnabled(true);
//获取bitmap缓存
Bitmap mBitmap = sourceImageView.getDrawingCache();
//显示 bitmap
destImageView.setImageBitmap(mBitmap);
// Bitmap mBitmap = sourceImageView.getDrawingCache();
// Drawable drawable = (Drawable) new BitmapDrawable(mBitmap);
// destImageView.setImageDrawable(drawable);
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
//不再显示bitmap缓存
//destImageView.setImageBitmap(null);
destImageView.setImageResource(R.drawable.pet);
//使用这句话而不是用上一句话是错误的,空指针调用
//destImageView.setBackgroundDrawable(null);
//关闭bitmap缓存
sourceImageView.setDrawingCacheEnabled(false);
//释放bitmap缓存资源
sourceImageView.destroyDrawingCache();
}
}, DELAY_TIME);
}
}, DELAY_TIME);
}
[java]
view plaincopyprint?
mImageView1.setImageResource(R.drawable.android);
mImageView2.setImageResource(R.drawable.pet);
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]
view plaincopyprint?
//图片圆角处理
public Bitmap getRoundedBitmap() {
Bitmap mBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.frame);
//创建新的位图
Bitmap bgBitmap = Bitmap.createBitmap(mBitmap.getWidth(), mBitmap.getHeight(), Config.ARGB_8888);
//把创建的位图作为画板
Canvas mCanvas = new Canvas(bgBitmap);
Paint mPaint = new Paint();
Rect mRect = new Rect(0,
0, mBitmap.getWidth(), mBitmap.getHeight());
RectF mRectF = new RectF(mRect);
//设置圆角半径为20
float roundPx =
15;
mPaint.setAntiAlias(true);
//先绘制圆角矩形
mCanvas.drawRoundRect(mRectF, roundPx, roundPx, mPaint);
//设置图像的叠加模式
mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
//绘制图像
mCanvas.drawBitmap(mBitmap, mRect, mRect, mPaint);
return bgBitmap;
}
效果如下图所示:
图7-5 图片圆角处理
三、图片灰化处理
在Android中可以通过ColorMatrix类实现图像处理软件中的滤镜效果,通过ColorMatrix类可以对位图中的每个像素进行变换处理,达到特殊的滤镜效果,下面通过一个例子来介绍如何通过ColorMatrix对图像进行灰化处理,Java代码如下:
[java]
view plaincopyprint?
//图片灰化处理
public Bitmap getGrayBitmap() {
Bitmap mBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.android);
Bitmap mGrayBitmap = Bitmap.createBitmap(mBitmap.getWidth(), mBitmap.getHeight(), Config.ARGB_8888);
Canvas mCanvas = new Canvas(mGrayBitmap);
Paint mPaint = new Paint();
//创建颜色变换矩阵
ColorMatrix mColorMatrix =
new ColorMatrix();
//设置灰度影响范围
mColorMatrix.setSaturation(0);
//创建颜色过滤矩阵
ColorMatrixColorFilter mColorFilter =
new ColorMatrixColorFilter(mColorMatrix);
//设置画笔的颜色过滤矩阵
mPaint.setColorFilter(mColorFilter);
//使用处理后的画笔绘制图像
mCanvas.drawBitmap(mBitmap,
0, 0, mPaint);
return mGrayBitmap;
}
效果如下图所示:
图7-6 图片灰化处理
四、提取图像Alpha位图
Android中的ARGB_8888类型的位图由Alpha(透明度)、Red(红)、Green(绿)、Blue(蓝)四部分组成,其中Alpha部分也就是常说的Alpha通道,它控制图像的透明度。在Android中Bitmap类提供了extractAlpha()方法,可以把位图中的Alpha部分提取出来作为一个新的位图,然后与填充颜色后的Paint结合重新绘制一个新图像。下面通过一个例子来说明Bitmap类的extractAlpha()方法的使用,Java代码如下:
[java]
view plaincopyprint?
//提取图像Alpha位图
public Bitmap getAlphaBitmap() {
BitmapDrawable mBitmapDrawable = (BitmapDrawable) getResources().getDrawable(R.drawable.enemy_infantry_ninja);
Bitmap mBitmap = mBitmapDrawable.getBitmap();
//BitmapDrawable的getIntrinsicWidth()方法,Bitmap的getWidth()方法
//注意这两个方法的区别
//Bitmap mAlphaBitmap = Bitmap.createBitmap(mBitmapDrawable.getIntrinsicWidth(), mBitmapDrawable.getIntrinsicHeight(), Config.ARGB_8888);
Bitmap mAlphaBitmap = Bitmap.createBitmap(mBitmap.getWidth(), mBitmap.getHeight(), Config.ARGB_8888);
Canvas mCanvas = new Canvas(mAlphaBitmap);
Paint mPaint = new Paint();
mPaint.setColor(Color.BLUE);
//从原位图中提取只包含alpha的位图
Bitmap alphaBitmap = mBitmap.extractAlpha();
//在画布上(mAlphaBitmap)绘制alpha位图
mCanvas.drawBitmap(alphaBitmap, 0,
0, mPaint);
return mAlphaBitmap;
}
图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]
view plaincopyprint?
//getScaleBitmap
public Bitmap getScaleBitmap() {
BitmapDrawable mBitmapDrawable = (BitmapDrawable) getResources().getDrawable(R.drawable.pet);
Bitmap mBitmap = mBitmapDrawable.getBitmap();
int width = mBitmap.getWidth();
int height = mBitmap.getHeight();
Matrix matrix = new Matrix();
matrix.preScale(0.75f,
0.75f);
Bitmap mScaleBitmap = Bitmap.createBitmap(mBitmap,
0, 0, width, height, matrix,
true);
return mScaleBitmap;
}
效果如下图所示:
图7-8 图像缩放
2)图片旋转
使用Matrix类preRotate或者postRotate可以对图像进行旋转操作,它只有一个参数表示旋转的角度,下面使用preRotate对图像顺时针旋转30度,Java代码如下:
[java]
view plaincopyprint?
//getRotatedBitmap
public Bitmap getRotatedBitmap() {
BitmapDrawable mBitmapDrawable = (BitmapDrawable) getResources().getDrawable(R.drawable.pet);
Bitmap mBitmap = mBitmapDrawable.getBitmap();
int width = mBitmap.getWidth();
int height = mBitmap.getHeight();
Matrix matrix = new Matrix();
matrix.preRotate(45);
Bitmap mRotateBitmap = Bitmap.createBitmap(mBitmap,
0, 0, width, height, matrix,
true);
return mRotateBitmap;
}
果如下图所示:
图7-9 图片旋转
3)图像倾斜
使用Matrix类preSkew或者postSkew可以对图像进行倾斜操作,它的两个参数分别为x和y坐标倾斜度,下面使用preSkew对图像进行倾斜变换,Java代码如下:
[java]
view plaincopyprint?
//getScrewBitmap
public Bitmap getScrewBitmap() {
BitmapDrawable mBitmapDrawable = (BitmapDrawable) getResources().getDrawable(R.drawable.pet);
Bitmap mBitmap = mBitmapDrawable.getBitmap();
int width = mBitmap.getWidth();
int height = mBitmap.getHeight();
Matrix matrix = new Matrix();
matrix.preSkew(1.0f,
0.15f);
Bitmap mScrewBitmap = Bitmap.createBitmap(mBitmap,
0, 0, width, height, matrix,
true);
return mScrewBitmap;
}
效果如下图所示:
图7-10 图像倾斜
4)图像倒影
为图像添加倒影效果之后,图像看起来会有立体感,更有真实感,在Android中使用Matrix类可以很容易实现图像的倒影效果。主要是Matrix的preScale方法的使用,给它设置负数缩放比例,图像就会进行反转。然后通过设置Shader添加渐变效果。Java代码如下:
[java]
view plaincopyprint?
//getReflectedBitmap
private Bitmap getReflectedBitmap() {
BitmapDrawable mBitmapDrawable = (BitmapDrawable) getResources().getDrawable(R.drawable.pet);
Bitmap mBitmap = mBitmapDrawable.getBitmap();
int width = mBitmap.getWidth();
int height = mBitmap.getHeight();
Matrix matrix = new Matrix();
// 图片缩放,x轴变为原来的1倍,y轴为-1倍,实现图片的反转
matrix.preScale(1, -1);
//创建反转后的图片Bitmap对象,图片高是原图的一半。
//Bitmap mInverseBitmap = Bitmap.createBitmap(mBitmap, 0, height/2, width, height/2, matrix, false);
//创建标准的Bitmap对象,宽和原图一致,高是原图的1.5倍。
//注意两种createBitmap的不同
//Bitmap mReflectedBitmap = Bitmap.createBitmap(width, height*3/2, Config.ARGB_8888);
Bitmap mInverseBitmap = Bitmap.createBitmap(mBitmap,
0, 0, width, height, matrix,
false);
Bitmap mReflectedBitmap = Bitmap.createBitmap(width, height*2, Config.ARGB_8888);
// 把新建的位图作为画板
Canvas mCanvas = new Canvas(mReflectedBitmap);
//绘制图片
mCanvas.drawBitmap(mBitmap, 0,
0, null);
mCanvas.drawBitmap(mInverseBitmap,
0, height, null);
//添加倒影的渐变效果
Paint mPaint = new Paint();
Shader mShader = new LinearGradient(0, height,
0, mReflectedBitmap.getHeight(),
0x70ffffff, 0x00ffffff, TileMode.MIRROR);
mPaint.setShader(mShader);
//设置叠加模式
mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
//绘制遮罩效果
mCanvas.drawRect(0, height, width, mReflectedBitmap.getHeight(), mPaint);
return mReflectedBitmap;
}
效果如下图所示:
图7-11 图像倒影
5)图像剪切
如果只需要图像的一部分,就必须对图像进行剪切处理,在原图像上选择一个剪切区域,使用PorterDuffXfermode图像叠加规则,就可以把指定的图像区域剪切下来,下面通过三个步骤来说明如果对图像进行剪切操作。
第一步,创建一个新位图作为画板,然后把原图像画到新位图上面,Java代码如下:
[java]
view plaincopyprint?
BitmapDrawable bd = (BitmapDrawable) getResources().getDrawable(
R.drawable.beauty);
Bitmap bitmap = bd.getBitmap();
int w = bitmap.getWidth();
int h = bitmap.getHeight();
Bitmap bm = Bitmap.createBitmap(w, h, Config.ARGB_8888);
Canvas canvas = new Canvas(bm);
Paint mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setStyle(Style.STROKE);
canvas.drawBitmap(bitmap, 0,
0, mPaint);
效果如下图所示:
图7-12 第一步效果图
第二步,绘制一个剪切区域,比如要剪切人物的脸部区域,需要在指定的位置绘制一个圆角矩形区域,代码中的坐标是在调试中获得,在其他分辨率下会有所不同,Java代码如下:
[java]
view plaincopyprint?
int deltX = 76;
int deltY = 98;
DashPathEffect dashStyle =
new DashPathEffect(new
float[] { 10,
5, 5,
5 }, 2);//创建虚线边框样式
RectF faceRect = new RectF(0,
0, 88,
106);
float [] faceCornerii =
new float[] {30,30,30,30,75,75,75,75};
Paint mPaint = new Paint();//创建画笔
mPaint.setColor(0xFF6F8DD5);
mPaint.setStrokeWidth(6);
mPaint.setPathEffect(dashStyle);
Path clip = new Path();//创建路径
clip.reset();
clip.addRoundRect(faceRect, faceCornerii, Direction.CW);//添加圆角矩形路径
canvas.save();//保存画布
canvas.translate(deltX, deltY);
canvas.clipPath(clip, Region.Op.DIFFERENCE);
canvas.drawColor(0xDF222222);
canvas.drawPath(clip, mPaint);//绘制路径
canvas.restore();
效果如下图所示:
图7-13 第二步效果
第三步,从原图像上获取指定区域的图像,并绘制到屏幕上,java代码如下:
[java]
view plaincopyprint?
Rect srcRect = new Rect(0,
0, 88,
106);
srcRect.offset(deltX, deltY);
PaintFlagsDrawFilter dfd =
new PaintFlagsDrawFilter(Paint.ANTI_ALIAS_FLAG,
Paint.FILTER_BITMAP_FLAG);
canvas.setDrawFilter(dfd);
canvas.clipPath(clip);//使用路径剪切画布
canvas.drawBitmap(bitmap, srcRect, faceRect, mPaint);
[java]
view plaincopyprint?
<p></p>
效果如下图所示:
图7-13 第三部效果图
6)图像合成
如果要为图片添加水印,或者把几张小图片拼接成大图片时,就需要利用图像合成的方法,在前面实例代码中已经使用了这种方法,就是创建新位图作为画板,然后在对应的位置上绘制其他图像。
读者可以参考本章Demo中的getCompoundedBitmap方法,这里不做过多说明。
Demo源代码下载:http://download.csdn.net/detail/liu2604592/4436200
在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]
view plaincopyprint?
//View转换为Bitmap
public void getDrawingCache(final ImageView sourceImageView,
final ImageView destImageView) {
new Handler().postDelayed(new Runnable() {
@Override
public
void run() {
// TODO Auto-generated method stub
//开启bitmap缓存
sourceImageView.setDrawingCacheEnabled(true);
//获取bitmap缓存
Bitmap mBitmap = sourceImageView.getDrawingCache();
//显示 bitmap
destImageView.setImageBitmap(mBitmap);
// Bitmap mBitmap = sourceImageView.getDrawingCache();
// Drawable drawable = (Drawable) new BitmapDrawable(mBitmap);
// destImageView.setImageDrawable(drawable);
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
//不再显示bitmap缓存
//destImageView.setImageBitmap(null);
destImageView.setImageResource(R.drawable.pet);
//使用这句话而不是用上一句话是错误的,空指针调用
//destImageView.setBackgroundDrawable(null);
//关闭bitmap缓存
sourceImageView.setDrawingCacheEnabled(false);
//释放bitmap缓存资源
sourceImageView.destroyDrawingCache();
}
}, DELAY_TIME);
}
}, DELAY_TIME);
}
//View转换为Bitmap public void getDrawingCache(final ImageView sourceImageView, final ImageView destImageView) { new Handler().postDelayed(new Runnable() { @Override 1b411 public void run() { // TODO Auto-generated method stub //开启bitmap缓存 sourceImageView.setDrawingCacheEnabled(true); //获取bitmap缓存 Bitmap mBitmap = sourceImageView.getDrawingCache(); //显示 bitmap destImageView.setImageBitmap(mBitmap); // Bitmap mBitmap = sourceImageView.getDrawingCache(); // Drawable drawable = (Drawable) new BitmapDrawable(mBitmap); // destImageView.setImageDrawable(drawable); new Handler().postDelayed(new Runnable() { @Override public void run() { // TODO Auto-generated method stub //不再显示bitmap缓存 //destImageView.setImageBitmap(null); destImageView.setImageResource(R.drawable.pet); //使用这句话而不是用上一句话是错误的,空指针调用 //destImageView.setBackgroundDrawable(null); //关闭bitmap缓存 sourceImageView.setDrawingCacheEnabled(false); //释放bitmap缓存资源 sourceImageView.destroyDrawingCache(); } }, DELAY_TIME); } }, DELAY_TIME); }
[java]
view plaincopyprint?
mImageView1.setImageResource(R.drawable.android);
mImageView2.setImageResource(R.drawable.pet);
getDrawingCache(mImageView1, mImageView2);
mImageView1.setImageResource(R.drawable.android); mImageView2.setImageResource(R.drawable.pet); 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]
view plaincopyprint?
//图片圆角处理
public Bitmap getRoundedBitmap() {
Bitmap mBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.frame);
//创建新的位图
Bitmap bgBitmap = Bitmap.createBitmap(mBitmap.getWidth(), mBitmap.getHeight(), Config.ARGB_8888);
//把创建的位图作为画板
Canvas mCanvas = new Canvas(bgBitmap);
Paint mPaint = new Paint();
Rect mRect = new Rect(0,
0, mBitmap.getWidth(), mBitmap.getHeight());
RectF mRectF = new RectF(mRect);
//设置圆角半径为20
float roundPx =
15;
mPaint.setAntiAlias(true);
//先绘制圆角矩形
mCanvas.drawRoundRect(mRectF, roundPx, roundPx, mPaint);
//设置图像的叠加模式
mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
//绘制图像
mCanvas.drawBitmap(mBitmap, mRect, mRect, mPaint);
return bgBitmap;
}
//图片圆角处理 public Bitmap getRoundedBitmap() { Bitmap mBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.frame); //创建新的位图 Bitmap bgBitmap = Bitmap.createBitmap(mBitmap.getWidth(), mBitmap.getHeight(), Config.ARGB_8888); //把创建的位图作为画板 Canvas mCanvas = new Canvas(bgBitmap); Paint mPaint = new Paint(); Rect mRect = new Rect(0, 0, mBitmap.getWidth(), mBitmap.getHeight()); RectF mRectF = new RectF(mRect); //设置圆角半径为20 float roundPx = 15; mPaint.setAntiAlias(true); //先绘制圆角矩形 mCanvas.drawRoundRect(mRectF, roundPx, roundPx, mPaint); //设置图像的叠加模式 mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN)); //绘制图像 mCanvas.drawBitmap(mBitmap, mRect, mRect, mPaint); return bgBitmap; }
效果如下图所示:
图7-5 图片圆角处理
三、图片灰化处理
在Android中可以通过ColorMatrix类实现图像处理软件中的滤镜效果,通过ColorMatrix类可以对位图中的每个像素进行变换处理,达到特殊的滤镜效果,下面通过一个例子来介绍如何通过ColorMatrix对图像进行灰化处理,Java代码如下:
[java]
view plaincopyprint?
//图片灰化处理
public Bitmap getGrayBitmap() {
Bitmap mBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.android);
Bitmap mGrayBitmap = Bitmap.createBitmap(mBitmap.getWidth(), mBitmap.getHeight(), Config.ARGB_8888);
Canvas mCanvas = new Canvas(mGrayBitmap);
Paint mPaint = new Paint();
//创建颜色变换矩阵
ColorMatrix mColorMatrix =
new ColorMatrix();
//设置灰度影响范围
mColorMatrix.setSaturation(0);
//创建颜色过滤矩阵
ColorMatrixColorFilter mColorFilter =
new ColorMatrixColorFilter(mColorMatrix);
//设置画笔的颜色过滤矩阵
mPaint.setColorFilter(mColorFilter);
//使用处理后的画笔绘制图像
mCanvas.drawBitmap(mBitmap,
0, 0, mPaint);
return mGrayBitmap;
}
//图片灰化处理 public Bitmap getGrayBitmap() { Bitmap mBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.android); Bitmap mGrayBitmap = Bitmap.createBitmap(mBitmap.getWidth(), mBitmap.getHeight(), Config.ARGB_8888); Canvas mCanvas = new Canvas(mGrayBitmap); Paint mPaint = new Paint(); //创建颜色变换矩阵 ColorMatrix mColorMatrix = new ColorMatrix(); //设置灰度影响范围 mColorMatrix.setSaturation(0); //创建颜色过滤矩阵 ColorMatrixColorFilter mColorFilter = new ColorMatrixColorFilter(mColorMatrix); //设置画笔的颜色过滤矩阵 mPaint.setColorFilter(mColorFilter); //使用处理后的画笔绘制图像 mCanvas.drawBitmap(mBitmap, 0, 0, mPaint); return mGrayBitmap; }
效果如下图所示:
图7-6 图片灰化处理
四、提取图像Alpha位图
Android中的ARGB_8888类型的位图由Alpha(透明度)、Red(红)、Green(绿)、Blue(蓝)四部分组成,其中Alpha部分也就是常说的Alpha通道,它控制图像的透明度。在Android中Bitmap类提供了extractAlpha()方法,可以把位图中的Alpha部分提取出来作为一个新的位图,然后与填充颜色后的Paint结合重新绘制一个新图像。下面通过一个例子来说明Bitmap类的extractAlpha()方法的使用,Java代码如下:
[java]
view plaincopyprint?
//提取图像Alpha位图
public Bitmap getAlphaBitmap() {
BitmapDrawable mBitmapDrawable = (BitmapDrawable) getResources().getDrawable(R.drawable.enemy_infantry_ninja);
Bitmap mBitmap = mBitmapDrawable.getBitmap();
//BitmapDrawable的getIntrinsicWidth()方法,Bitmap的getWidth()方法
//注意这两个方法的区别
//Bitmap mAlphaBitmap = Bitmap.createBitmap(mBitmapDrawable.getIntrinsicWidth(), mBitmapDrawable.getIntrinsicHeight(), Config.ARGB_8888);
Bitmap mAlphaBitmap = Bitmap.createBitmap(mBitmap.getWidth(), mBitmap.getHeight(), Config.ARGB_8888);
Canvas mCanvas = new Canvas(mAlphaBitmap);
Paint mPaint = new Paint();
mPaint.setColor(Color.BLUE);
//从原位图中提取只包含alpha的位图
Bitmap alphaBitmap = mBitmap.extractAlpha();
//在画布上(mAlphaBitmap)绘制alpha位图
mCanvas.drawBitmap(alphaBitmap, 0,
0, mPaint);
return mAlphaBitmap;
}
//提取图像Alpha位图 public Bitmap getAlphaBitmap() { BitmapDrawable mBitmapDrawable = (BitmapDrawable) getResources().getDrawable(R.drawable.enemy_infantry_ninja); Bitmap mBitmap = mBitmapDrawable.getBitmap(); //BitmapDrawable的getIntrinsicWidth()方法,Bitmap的getWidth()方法 //注意这两个方法的区别 //Bitmap mAlphaBitmap = Bitmap.createBitmap(mBitmapDrawable.getIntrinsicWidth(), mBitmapDrawable.getIntrinsicHeight(), Config.ARGB_8888); Bitmap mAlphaBitmap = Bitmap.createBitmap(mBitmap.getWidth(), mBitmap.getHeight(), Config.ARGB_8888); Canvas mCanvas = new Canvas(mAlphaBitmap); Paint mPaint = new Paint(); mPaint.setColor(Color.BLUE); //从原位图中提取只包含alpha的位图 Bitmap alphaBitmap = mBitmap.extractAlpha(); //在画布上(mAlphaBitmap)绘制alpha位图 mCanvas.drawBitmap(alphaBitmap, 0, 0, mPaint); return mAlphaBitmap; }
图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]
view plaincopyprint?
//getScaleBitmap
public Bitmap getScaleBitmap() {
BitmapDrawable mBitmapDrawable = (BitmapDrawable) getResources().getDrawable(R.drawable.pet);
Bitmap mBitmap = mBitmapDrawable.getBitmap();
int width = mBitmap.getWidth();
int height = mBitmap.getHeight();
Matrix matrix = new Matrix();
matrix.preScale(0.75f,
0.75f);
Bitmap mScaleBitmap = Bitmap.createBitmap(mBitmap,
0, 0, width, height, matrix,
true);
return mScaleBitmap;
}
//getScaleBitmap public Bitmap getScaleBitmap() { BitmapDrawable mBitmapDrawable = (BitmapDrawable) getResources().getDrawable(R.drawable.pet); Bitmap mBitmap = mBitmapDrawable.getBitmap(); int width = mBitmap.getWidth(); int height = mBitmap.getHeight(); Matrix matrix = new Matrix(); matrix.preScale(0.75f, 0.75f); Bitmap mScaleBitmap = Bitmap.createBitmap(mBitmap, 0, 0, width, height, matrix, true); return mScaleBitmap; }
效果如下图所示:
图7-8 图像缩放
2)图片旋转
使用Matrix类preRotate或者postRotate可以对图像进行旋转操作,它只有一个参数表示旋转的角度,下面使用preRotate对图像顺时针旋转30度,Java代码如下:
[java]
view plaincopyprint?
//getRotatedBitmap
public Bitmap getRotatedBitmap() {
BitmapDrawable mBitmapDrawable = (BitmapDrawable) getResources().getDrawable(R.drawable.pet);
Bitmap mBitmap = mBitmapDrawable.getBitmap();
int width = mBitmap.getWidth();
int height = mBitmap.getHeight();
Matrix matrix = new Matrix();
matrix.preRotate(45);
Bitmap mRotateBitmap = Bitmap.createBitmap(mBitmap,
0, 0, width, height, matrix,
true);
return mRotateBitmap;
}
//getRotatedBitmap public Bitmap getRotatedBitmap() { BitmapDrawable mBitmapDrawable = (BitmapDrawable) getResources().getDrawable(R.drawable.pet); Bitmap mBitmap = mBitmapDrawable.getBitmap(); int width = mBitmap.getWidth(); int height = mBitmap.getHeight(); Matrix matrix = new Matrix(); matrix.preRotate(45); Bitmap mRotateBitmap = Bitmap.createBitmap(mBitmap, 0, 0, width, height, matrix, true); return mRotateBitmap; }
果如下图所示:
图7-9 图片旋转
3)图像倾斜
使用Matrix类preSkew或者postSkew可以对图像进行倾斜操作,它的两个参数分别为x和y坐标倾斜度,下面使用preSkew对图像进行倾斜变换,Java代码如下:
[java]
view plaincopyprint?
//getScrewBitmap
public Bitmap getScrewBitmap() {
BitmapDrawable mBitmapDrawable = (BitmapDrawable) getResources().getDrawable(R.drawable.pet);
Bitmap mBitmap = mBitmapDrawable.getBitmap();
int width = mBitmap.getWidth();
int height = mBitmap.getHeight();
Matrix matrix = new Matrix();
matrix.preSkew(1.0f,
0.15f);
Bitmap mScrewBitmap = Bitmap.createBitmap(mBitmap,
0, 0, width, height, matrix,
true);
return mScrewBitmap;
}
//getScrewBitmap public Bitmap getScrewBitmap() { BitmapDrawable mBitmapDrawable = (BitmapDrawable) getResources().getDrawable(R.drawable.pet); Bitmap mBitmap = mBitmapDrawable.getBitmap(); int width = mBitmap.getWidth(); int height = mBitmap.getHeight(); Matrix matrix = new Matrix(); matrix.preSkew(1.0f, 0.15f); Bitmap mScrewBitmap = Bitmap.createBitmap(mBitmap, 0, 0, width, height, matrix, true); return mScrewBitmap; }
效果如下图所示:
图7-10 图像倾斜
4)图像倒影
为图像添加倒影效果之后,图像看起来会有立体感,更有真实感,在Android中使用Matrix类可以很容易实现图像的倒影效果。主要是Matrix的preScale方法的使用,给它设置负数缩放比例,图像就会进行反转。然后通过设置Shader添加渐变效果。Java代码如下:
[java]
view plaincopyprint?
//getReflectedBitmap
private Bitmap getReflectedBitmap() {
BitmapDrawable mBitmapDrawable = (BitmapDrawable) getResources().getDrawable(R.drawable.pet);
Bitmap mBitmap = mBitmapDrawable.getBitmap();
int width = mBitmap.getWidth();
int height = mBitmap.getHeight();
Matrix matrix = new Matrix();
// 图片缩放,x轴变为原来的1倍,y轴为-1倍,实现图片的反转
matrix.preScale(1, -1);
//创建反转后的图片Bitmap对象,图片高是原图的一半。
//Bitmap mInverseBitmap = Bitmap.createBitmap(mBitmap, 0, height/2, width, height/2, matrix, false);
//创建标准的Bitmap对象,宽和原图一致,高是原图的1.5倍。
//注意两种createBitmap的不同
//Bitmap mReflectedBitmap = Bitmap.createBitmap(width, height*3/2, Config.ARGB_8888);
Bitmap mInverseBitmap = Bitmap.createBitmap(mBitmap,
0, 0, width, height, matrix,
false);
Bitmap mReflectedBitmap = Bitmap.createBitmap(width, height*2, Config.ARGB_8888);
// 把新建的位图作为画板
Canvas mCanvas = new Canvas(mReflectedBitmap);
//绘制图片
mCanvas.drawBitmap(mBitmap, 0,
0, null);
mCanvas.drawBitmap(mInverseBitmap,
0, height, null);
//添加倒影的渐变效果
Paint mPaint = new Paint();
Shader mShader = new LinearGradient(0, height,
0, mReflectedBitmap.getHeight(),
0x70ffffff, 0x00ffffff, TileMode.MIRROR);
mPaint.setShader(mShader);
//设置叠加模式
mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
//绘制遮罩效果
mCanvas.drawRect(0, height, width, mReflectedBitmap.getHeight(), mPaint);
return mReflectedBitmap;
}
//getReflectedBitmap private Bitmap getReflectedBitmap() { BitmapDrawable mBitmapDrawable = (BitmapDrawable) getResources().getDrawable(R.drawable.pet); Bitmap mBitmap = mBitmapDrawable.getBitmap(); int width = mBitmap.getWidth(); int height = mBitmap.getHeight(); Matrix matrix = new Matrix(); // 图片缩放,x轴变为原来的1倍,y轴为-1倍,实现图片的反转 matrix.preScale(1, -1); //创建反转后的图片Bitmap对象,图片高是原图的一半。 //Bitmap mInverseBitmap = Bitmap.createBitmap(mBitmap, 0, height/2, width, height/2, matrix, false); //创建标准的Bitmap对象,宽和原图一致,高是原图的1.5倍。 //注意两种createBitmap的不同 //Bitmap mReflectedBitmap = Bitmap.createBitmap(width, height*3/2, Config.ARGB_8888); Bitmap mInverseBitmap = Bitmap.createBitmap(mBitmap, 0, 0, width, height, matrix, false); Bitmap mReflectedBitmap = Bitmap.createBitmap(width, height*2, Config.ARGB_8888); // 把新建的位图作为画板 Canvas mCanvas = new Canvas(mReflectedBitmap); //绘制图片 mCanvas.drawBitmap(mBitmap, 0, 0, null); mCanvas.drawBitmap(mInverseBitmap, 0, height, null); //添加倒影的渐变效果 Paint mPaint = new Paint(); Shader mShader = new LinearGradient(0, height, 0, mReflectedBitmap.getHeight(), 0x70ffffff, 0x00ffffff, TileMode.MIRROR); mPaint.setShader(mShader); //设置叠加模式 mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN)); //绘制遮罩效果 mCanvas.drawRect(0, height, width, mReflectedBitmap.getHeight(), mPaint); return mReflectedBitmap; }
效果如下图所示:
图7-11 图像倒影
5)图像剪切
如果只需要图像的一部分,就必须对图像进行剪切处理,在原图像上选择一个剪切区域,使用PorterDuffXfermode图像叠加规则,就可以把指定的图像区域剪切下来,下面通过三个步骤来说明如果对图像进行剪切操作。
第一步,创建一个新位图作为画板,然后把原图像画到新位图上面,Java代码如下:
[java]
view plaincopyprint?
BitmapDrawable bd = (BitmapDrawable) getResources().getDrawable(
R.drawable.beauty);
Bitmap bitmap = bd.getBitmap();
int w = bitmap.getWidth();
int h = bitmap.getHeight();
Bitmap bm = Bitmap.createBitmap(w, h, Config.ARGB_8888);
Canvas canvas = new Canvas(bm);
Paint mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setStyle(Style.STROKE);
canvas.drawBitmap(bitmap, 0,
0, mPaint);
BitmapDrawable bd = (BitmapDrawable) getResources().getDrawable( R.drawable.beauty); Bitmap bitmap = bd.getBitmap(); int w = bitmap.getWidth(); int h = bitmap.getHeight(); Bitmap bm = Bitmap.createBitmap(w, h, Config.ARGB_8888); Canvas canvas = new Canvas(bm); Paint mPaint = new Paint(); mPaint.setAntiAlias(true); mPaint.setStyle(Style.STROKE); canvas.drawBitmap(bitmap, 0, 0, mPaint);
效果如下图所示:
图7-12 第一步效果图
第二步,绘制一个剪切区域,比如要剪切人物的脸部区域,需要在指定的位置绘制一个圆角矩形区域,代码中的坐标是在调试中获得,在其他分辨率下会有所不同,Java代码如下:
[java]
view plaincopyprint?
int deltX = 76;
int deltY = 98;
DashPathEffect dashStyle =
new DashPathEffect(new
float[] { 10,
5, 5,
5 }, 2);//创建虚线边框样式
RectF faceRect = new RectF(0,
0, 88,
106);
float [] faceCornerii =
new float[] {30,30,30,30,75,75,75,75};
Paint mPaint = new Paint();//创建画笔
mPaint.setColor(0xFF6F8DD5);
mPaint.setStrokeWidth(6);
mPaint.setPathEffect(dashStyle);
Path clip = new Path();//创建路径
clip.reset();
clip.addRoundRect(faceRect, faceCornerii, Direction.CW);//添加圆角矩形路径
canvas.save();//保存画布
canvas.translate(deltX, deltY);
canvas.clipPath(clip, Region.Op.DIFFERENCE);
canvas.drawColor(0xDF222222);
canvas.drawPath(clip, mPaint);//绘制路径
canvas.restore();
int deltX = 76; int deltY = 98; DashPathEffect dashStyle = new DashPathEffect(new float[] { 10, 5, 5, 5 }, 2);//创建虚线边框样式 RectF faceRect = new RectF(0, 0, 88, 106); float [] faceCornerii = new float[] {30,30,30,30,75,75,75,75}; Paint mPaint = new Paint();//创建画笔 mPaint.setColor(0xFF6F8DD5); mPaint.setStrokeWidth(6); mPaint.setPathEffect(dashStyle); Path clip = new Path();//创建路径 clip.reset(); clip.addRoundRect(faceRect, faceCornerii, Direction.CW);//添加圆角矩形路径 canvas.save();//保存画布 canvas.translate(deltX, deltY); canvas.clipPath(clip, Region.Op.DIFFERENCE); canvas.drawColor(0xDF222222); canvas.drawPath(clip, mPaint);//绘制路径 canvas.restore();
效果如下图所示:
图7-13 第二步效果
第三步,从原图像上获取指定区域的图像,并绘制到屏幕上,java代码如下:
[java]
view plaincopyprint?
Rect srcRect = new Rect(0,
0, 88,
106);
srcRect.offset(deltX, deltY);
PaintFlagsDrawFilter dfd =
new PaintFlagsDrawFilter(Paint.ANTI_ALIAS_FLAG,
Paint.FILTER_BITMAP_FLAG);
canvas.setDrawFilter(dfd);
canvas.clipPath(clip);//使用路径剪切画布
canvas.drawBitmap(bitmap, srcRect, faceRect, mPaint);
Rect srcRect = new Rect(0, 0, 88, 106); srcRect.offset(deltX, deltY); PaintFlagsDrawFilter dfd = new PaintFlagsDrawFilter(Paint.ANTI_ALIAS_FLAG, Paint.FILTER_BITMAP_FLAG); canvas.setDrawFilter(dfd); canvas.clipPath(clip);//使用路径剪切画布 canvas.drawBitmap(bitmap, srcRect, faceRect, mPaint);
[java]
view plaincopyprint?
<p></p>
效果如下图所示:
图7-13 第三部效果图
6)图像合成
如果要为图片添加水印,或者把几张小图片拼接成大图片时,就需要利用图像合成的方法,在前面实例代码中已经使用了这种方法,就是创建新位图作为画板,然后在对应的位置上绘制其他图像。
读者可以参考本章Demo中的getCompoundedBitmap方法,这里不做过多说明。
Demo源代码下载:http://download.csdn.net/detail/liu2604592/4436200
相关文章推荐
- Android中常用的位图操作(View与Bitmap转化、圆角、灰化、提取Alpha、旋转、倒影、剪切……)
- Android中常用的位图操作(View与Bitmap转化、圆角、灰化、提取Alpha、旋转、倒影、剪切……)
- Android中常用的位图操作
- Android中常用的位图操作
- Android中常用的位图操作(View与Bitmap转化、圆角、灰化、提取Alpha、旋转、倒影、剪切……)
- Android中常用的位图操作(View与Bitmap转化、圆角、灰化、提取Alpha、旋转、倒影、剪切……)
- Android中常用的位图操作
- Android中常用的位图操作
- Android中常用的位图操作(View与Bitmap转化、圆角、灰化、提取Alpha、旋转、倒影、剪切……)
- Android中常用的位图操作(View与Bitmap转化、圆角、灰化、提取Alpha、旋转、倒影、剪切……)
- Android常用位图操作(上)
- Android常用位图操作(下)
- Android中常用的位图操作(View与Bitmap转化、圆角、灰化、提取Alpha、旋转、倒影、剪切……)
- Android中常用的位图操作(View与Bitmap转化、圆角、灰化、提取Alpha、旋转、倒影、剪切……)
- Android 常用操作
- android常用的电话操作
- [Android L]SEAndroid开放设备文件结点权限(读或写)方法(涵盖常用操作:sys/xxx、proc/xxx、SystemProperties)热门干货
- android短信和电话操作常用信息备忘
- Android开发常用操作/命令备忘