在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
- public void getDrawingCache(final ImageView sourceImageView, final ImageView destImageView) {
-
- new Handler().postDelayed(new Runnable() {
-
- @Override
- public void run() {
-
-
- sourceImageView.setDrawingCacheEnabled(true);
-
- Bitmap mBitmap = sourceImageView.getDrawingCache();
-
- destImageView.setImageBitmap(mBitmap);
-
-
- new Handler().postDelayed(new Runnable() {
-
- @Override
- public void run() {
-
-
-
- destImageView.setImageResource(R.drawable.pet);
-
-
-
-
-
- sourceImageView.setDrawingCacheEnabled(false);
-
- sourceImageView.destroyDrawingCache();
- }
- }, DELAY_TIME);
- }
- }, DELAY_TIME);
- }
- mImageView1.setImageResource(R.drawable.android);
- mImageView2.setImageResource(R.drawable.pet);
- getDrawingCache(mImageView1, mImageView2);
运行效果以下:

Demo运行效果图1


android
Demo运行效果图2canvas
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代码以下:缓存
- 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);
-
- 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;
- }
效果以下图所示:

图片圆角处理框架
3、图片灰化处理
在Android中能够经过ColorMatrix类实现图像处理软件中的滤镜效果,经过ColorMatrix类能够对位图中的每一个像素进行变换处理,达到特殊的滤镜效果,下面经过一个例子来介绍如何经过ColorMatrix对图像进行灰化处理,Java代码以下:
- 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;
- }
效果以下图所示:


图片灰化处理ide
4、提取图像Alpha位图
Android中的ARGB_8888类型的位图由Alpha(透明度)、Red(红)、Green(绿)、Blue(蓝)四部分组成,其中Alpha部分也就是常说的Alpha通道,它控制图像的透明度。在Android中Bitmap类提供了extractAlpha()方法,能够把位图中的Alpha部分提取出来做为一个新的位图,而后与填充颜色后的Paint结合从新绘制一个新图像。下面经过一个例子来讲明Bitmap类的extractAlpha()方法的使用,Java代码以下:
- public Bitmap getAlphaBitmap() {
- BitmapDrawable mBitmapDrawable = (BitmapDrawable) getResources().getDrawable(R.drawable.enemy_infantry_ninja);
- Bitmap mBitmap = mBitmapDrawable.getBitmap();
-
-
-
-
- Bitmap mAlphaBitmap = Bitmap.createBitmap(mBitmap.getWidth(), mBitmap.getHeight(), Config.ARGB_8888);
-
- Canvas mCanvas = new Canvas(mAlphaBitmap);
- Paint mPaint = new Paint();
-
- mPaint.setColor(Color.BLUE);
-
- Bitmap alphaBitmap = mBitmap.extractAlpha();
-
- mCanvas.drawBitmap(alphaBitmap, 0, 0, mPaint);
-
- return mAlphaBitmap;
- }

提取图像Alpha位图post
其中最后一幅图片是把原图片四个边距缩小两个dp,而后与Alpha位图一块儿绘制的结果,读者能够参考本章Demo中的getStrokeBitmap()方法。
5、图像变换
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代码以下:
//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;
}
效果以下图所示:spa


图像缩放.net
2)图片旋转
使用Matrix类preRotate或者postRotate能够对图像进行旋转操做,它只有一个参数表示旋转的角度,下面使用preRotate对图像顺时针旋转30度,Java代码以下:
- 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;
- }
效果以下图所示:


图片旋转指针
3)图像倾斜
使用Matrix类preSkew或者postSkew能够对图像进行倾斜操做,它的两个参数分别为x和y坐标倾斜度,下面使用preSkew对图像进行倾斜变换,Java代码以下:
- 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;
- }
效果以下图所示:


图像倾斜
4)图像倒影
为图像添加倒影效果以后,图像看起来会有立体感,更有真实感,在Android中使用Matrix类能够很容易实现图像的倒影效果。主要是Matrix的preScale方法的使用,给它设置负数缩放比例,图像就会进行反转。而后经过设置Shader添加渐变效果。Java代码以下:
- 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();
-
- matrix.preScale(1, -1);
-
-
-
-
-
-
-
- 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;
- }
效果以下图所示:


图像倒影
5)图像剪切
若是只须要图像的一部分,就必须对图像进行剪切处理,在原图像上选择一个剪切区域,使用PorterDuffXfermode图像叠加规则,就能够把指定的图像区域剪切下来,下面经过三个步骤来讲明若是对图像进行剪切操做。
第一步,建立一个新位图做为画板,而后把原图像画到新位图上面,Java代码以下:
- 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);
效果以下图所示:


第一步效果图
第二步,绘制一个剪切区域,好比要剪切人物的脸部区域,须要在指定的位置绘制一个圆角矩形区域,代码中的坐标是在调试中得到,在其余分辨率下会有所不一样,Java代码以下:
- 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();
效果以下图所示:


第二步效果
第三步,从原图像上获取指定区域的图像,并绘制到屏幕上,java代码以下:
- 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);
效果以下图所示:


第三部效果图
6)图像合成
若是要为图片添加水印,或者把几张小图片拼接成大图片时,就须要利用图像合成的方法,在前面实例代码中已经使用了这种方法,就是建立新位图做为画板,而后在对应的位置上绘制其余图像