Android中常用的位图操作(View与Bitmap转化、圆角、灰化、提取Alpha、旋转、倒影、剪切……)

一、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 plain copy
  1. //View转换为Bitmap  
  2.     public void getDrawingCache(final ImageView sourceImageView, final ImageView destImageView) {  
  3.               
  4.             new Handler().postDelayed(new Runnable() {  
  5.                           
  6.                         @Override  
  7.                         public void run() {  
  8.                                 // TODO Auto-generated method stub  
  9.                                 //开启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.     }  

[java]  view plain copy
  1. mImageView1.setImageResource(R.drawable.android);  
  2.         mImageView2.setImageResource(R.drawable.pet);  
  3.         getDrawingCache(mImageView1, mImageView2);  

运行效果如下:


Demo运行效果图1



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 plain copy
  1. //图片圆角处理  
  2. public Bitmap getRoundedBitmap() {  
  3.         Bitmap mBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.frame);  
  4.         //创建新的位图  
  5.         Bitmap bgBitmap = Bitmap.createBitmap(mBitmap.getWidth(), mBitmap.getHeight(), Config.ARGB_8888);  
  6.         //把创建的位图作为画板  
  7.         Canvas mCanvas = new Canvas(bgBitmap);  
  8.           
  9.         Paint mPaint = new Paint();  
  10.         Rect mRect = new Rect(00, 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. }  

效果如下图所示:



图片圆角处理



三、图片灰化处理

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

[java]  view plain copy
  1. //图片灰化处理  
  2.     public Bitmap getGrayBitmap() {  
  3.             Bitmap mBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.android);  
  4.             Bitmap mGrayBitmap = Bitmap.createBitmap(mBitmap.getWidth(), mBitmap.getHeight(), Config.ARGB_8888);  
  5.             Canvas mCanvas = new Canvas(mGrayBitmap);  
  6.             Paint mPaint = new Paint();  
  7.               
  8.             //创建颜色变换矩阵  
  9.             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, 00, mPaint);  
  18.               
  19.             return mGrayBitmap;           
  20.     }  

 效果如下图所示:




图片灰化处理



四、提取图像Alpha位图

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

[java]  view plain copy
  1. //提取图像Alpha位图  
  2. public Bitmap getAlphaBitmap() {  
  3.         BitmapDrawable mBitmapDrawable = (BitmapDrawable) getResources().getDrawable(R.drawable.enemy_infantry_ninja);  
  4.         Bitmap mBitmap = mBitmapDrawable.getBitmap();  
  5.           
  6.         //BitmapDrawable的getIntrinsicWidth()方法,Bitmap的getWidth()方法  
  7.         //注意这两个方法的区别  
  8.         //Bitmap mAlphaBitmap = Bitmap.createBitmap(mBitmapDrawable.getIntrinsicWidth(), mBitmapDrawable.getIntrinsicHeight(), Config.ARGB_8888);  
  9.         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, 00, mPaint);  
  19.           
  20.         return mAlphaBitmap;  
  21. }  


提取图像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代码如下:

//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;
    }

效果如下图所示:



图像缩放

2)图片旋转

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

[java]  view plain copy
  1. //getRotatedBitmap  
  2.     public Bitmap getRotatedBitmap() {  
  3.             BitmapDrawable mBitmapDrawable = (BitmapDrawable) getResources().getDrawable(R.drawable.pet);  
  4.             Bitmap mBitmap = mBitmapDrawable.getBitmap();  
  5.             int width = mBitmap.getWidth();  
  6.             int height = mBitmap.getHeight();  
  7.               
  8.             Matrix matrix = new Matrix();  
  9.             matrix.preRotate(45);  
  10.             Bitmap mRotateBitmap = Bitmap.createBitmap(mBitmap, 00, width, height, matrix, true);  
  11.               
  12.             return mRotateBitmap;  
  13.     }  

效果如下图所示:



图片旋转



3)图像倾斜

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

[java]  view plain copy
  1. //getScrewBitmap  
  2. public Bitmap getScrewBitmap() {  
  3.         BitmapDrawable mBitmapDrawable = (BitmapDrawable) getResources().getDrawable(R.drawable.pet);  
  4.         Bitmap mBitmap = mBitmapDrawable.getBitmap();  
  5.         int width = mBitmap.getWidth();  
  6.         int height = mBitmap.getHeight();  
  7.           
  8.         Matrix matrix = new Matrix();  
  9.         matrix.preSkew(1.0f, 0.15f);  
  10.         Bitmap mScrewBitmap = Bitmap.createBitmap(mBitmap, 00, width, height, matrix, true);  
  11.           
  12.         return mScrewBitmap;  
  13. }  
 效果如下图所示:



图像倾斜



4)图像倒影

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

[java]  view plain copy
  1. //getReflectedBitmap  
  2.         private Bitmap getReflectedBitmap() {  
  3.                 BitmapDrawable mBitmapDrawable = (BitmapDrawable) getResources().getDrawable(R.drawable.pet);  
  4.                 Bitmap mBitmap = mBitmapDrawable.getBitmap();  
  5.                 int width = mBitmap.getWidth();  
  6.                 int height = mBitmap.getHeight();  
  7.                   
  8.                 Matrix matrix = new Matrix();  
  9.                 // 图片缩放,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, 00, 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, 00null);  
  25.                 mCanvas.drawBitmap(mInverseBitmap, 0, height, null);  
  26.                   
  27.                 //添加倒影的渐变效果  
  28.                 Paint mPaint = new Paint();  
  29.                 Shader mShader = new LinearGradient(0, height, 0, mReflectedBitmap.getHeight(), 0x70ffffff0x00ffffff, 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.         }  

效果如下图所示:



图像倒影

5)图像剪切

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

        第一步,创建一个新位图作为画板,然后把原图像画到新位图上面,Java代码如下:
[java]  view plain copy
  1. BitmapDrawable bd = (BitmapDrawable) getResources().getDrawable(  
  2.                 R.drawable.beauty);  
  3. Bitmap bitmap = bd.getBitmap();  
  4. int w = bitmap.getWidth();  
  5. int h = bitmap.getHeight();  
  6. Bitmap bm = Bitmap.createBitmap(w, h, Config.ARGB_8888);  
  7. Canvas canvas = new Canvas(bm);  
  8. Paint mPaint = new Paint();  
  9. mPaint.setAntiAlias(true);  
  10. mPaint.setStyle(Style.STROKE);  
  11. canvas.drawBitmap(bitmap, 00, mPaint);  

效果如下图所示:



第一步效果图



        第二步,绘制一个剪切区域,比如要剪切人物的脸部区域,需要在指定的位置绘制一个圆角矩形区域,代码中的坐标是在调试中获得,在其他分辨率下会有所不同,Java代码如下:
[java]  view plain copy
  1. int deltX = 76;  
  2. int deltY = 98;  
  3. DashPathEffect dashStyle = new DashPathEffect(new float[] { 105,        55 }, 2);//创建虚线边框样式  
  4. RectF faceRect = new RectF(0088106);  
  5. float [] faceCornerii = new float[] {30,30,30,30,75,75,75,75};  
  6. Paint mPaint = new Paint();//创建画笔  
  7. mPaint.setColor(0xFF6F8DD5);  
  8. mPaint.setStrokeWidth(6);  
  9. 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();  

效果如下图所示:



第二步效果



        第三步,从原图像上获取指定区域的图像,并绘制到屏幕上,java代码如下:
[java]  view plain copy
  1. Rect srcRect = new Rect(0088106);  
  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);  

效果如下图所示:




第三部效果图



6)图像合成

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

Demo无积分下载:http://download.csdn.net/detail/wangfayinn/5152359


原文链接:http://www.devdiv.com/Android-Android%E4%B8%AD%E5%B8%B8%E7%94%A8%E7%9A%84%E4%BD%8D%E5%9B%BE%E6%93%8D%E4%BD%9C-thread-127485-1-1.html

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要在SpannableStringBuilder对齐位图,可以使用Imagespan和LeadingMarginSpan组合来实现。具体的步骤如下: 1. 创建一个Bitmap对象,用于表示要插入的位图。 2. 创建一个ImageSpan对象,并将Bitmap对象作为其参数,设置ImageSpan的对齐方式。 3. 创建一个LeadingMarginSpan对象,并将其与ImageSpan对象一起添加到SpannableStringBuilder。 4. 在SpannableStringBuilder插入文本,并将ImageSpan和LeadingMarginSpan应用于文本。 示例代码如下: ```java Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.image); // 创建位图 ImageSpan imageSpan = new ImageSpan(this, bitmap, ImageSpan.ALIGN_BASELINE); // 创建ImageSpan对象 LeadingMarginSpan marginSpan = new LeadingMarginSpan.Standard(bitmap.getWidth()); // 创建LeadingMarginSpan对象 SpannableStringBuilder builder = new SpannableStringBuilder("插入位图"); // 创建SpannableStringBuilder对象 builder.setSpan(imageSpan, 0, 1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); // 将ImageSpan应用于文本 builder.setSpan(marginSpan, 0, builder.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); // 将LeadingMarginSpan应用于文本 TextView textView = findViewById(R.id.text_view); textView.setText(builder); // 将SpannableStringBuilder显示在TextView ``` 在上面的示例代码,我们首先创建了一个位图对象,然后创建一个ImageSpan对象,并将位图对象作为其参数。我们将ImageSpan的对齐方式设置为ALIGN_BASELINE,表示将位图与文本基线对齐。接下来,我们创建了一个LeadingMarginSpan对象,并将其与ImageSpan对象一起添加到SpannableStringBuilder。最后,我们将SpannableStringBuilder显示在TextView

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值