Android 中常见Bitmap操作

来源:互联网 发布:好看的男士手套知乎 编辑:程序博客网 时间:2024/05/21 10:33

转载自  http://www.xingdongdong.com/post/2012-12-12/40046020514

一、View转换为Bitmap

       在Android中所有的控件都是View的直接子类或者间接子类,经由过程它们可以组成丰硕的UI界面。在视窗显示的时辰Android会把这些控件都加载到RAM中,形成一个以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轨范代码如下文所示:

// View转换为Bitmap     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.anims);                                                                   // 使用这句话而不是用上一句话是错误的,空指针挪用                         // destImageView.setBackgroundDrawable(null);                         // 封锁bitmap缓存                         sourceImageView.setDrawingCacheEnabled(false);                         // 释放bitmap缓存资本                         sourceImageView.destroyDrawingCache();                     }                 }, DELAY_TIME);             }         }, DELAY_TIME);     }



       运行下场如下文所示:


图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轨范代码如下文所示: 
public Bitmap getRoundedBitmap() {                                                 Bitmap mBitmap = BitmapFactory.decodeResource(getResources(),                 R.drawable.default_1);         // 建树新的位图         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轨范代码如下文所示: 
// 图像灰化措置     public Bitmap getGrayBitmap() {         Bitmap mBitmap = BitmapFactory.decodeResource(getResources(),                 R.drawable.anims);         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轨范代码如下文所示: 
// 提取图像Alpha位图     public Bitmap getAlphaBitmap() {         BitmapDrawable mBitmapDrawable = (BitmapDrawable) getResources()                 .getDrawable(R.drawable.anims);         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轨范代码如下文所示: 
// 图像缩放     public Bitmap getScaleBitmap() {         BitmapDrawable mBitmapDrawable = (BitmapDrawable) getResources()                 .getDrawable(R.drawable.anims);         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轨范代码如下文所示: 
​​c
// 图像扭转     public Bitmap getRotatedBitmap() {         BitmapDrawable mBitmapDrawable = (BitmapDrawable) getResources()                 .getDrawable(R.drawable.anims);         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轨范代码如下文所示: 

// 图像倾斜     public Bitmap getScrewBitmap() {         BitmapDrawable mBitmapDrawable = (BitmapDrawable) getResources()                 .getDrawable(R.drawable.anims);         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轨范代码如下文所示:

// 图像倒影     private Bitmap getReflectedBitmap() {         BitmapDrawable mBitmapDrawable = (BitmapDrawable) getResources()                 .getDrawable(R.drawable.anims);         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轨范代码如下文所示: 
               

BitmapDrawable bd = (BitmapDrawable) getResources().getDrawable(                     R.drawable.default_1);                     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轨范代码如下文所示: 

                
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轨范代码如下文所示: 

                
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);





       下场如下文所示图所示: 


图7-13  第三部下场图


原创粉丝点击