我的简书同步发布:制作圆形图片,你会以下几种?

转载请注明出处:【huachao1001的专栏:http://blog.csdn.net/huachao1001】

说起圆角图片,相信每个人心中都有自己的圆角图片制作方法。但是你是否想知道,除了你所会的那几张方法以外,还什么什么方法制作圆形图片呢?我们一一学习~

1 XferMode

关于通过使用XferMode方式创建圆形图片,hongyang大神的《 Android Xfermode 实战 实现圆形、圆角图片 》有讲,我这里大致把思路总结一下,我们知道,XferMode主要是将2张图片合在一起,由用户自己决定是选中图片重叠的部分还是非重叠的部分,可以参考Android官方提供的图片:

我们可以选择DstIn的方式来绘制圆形图,即在我们的原图上面再画一个实心圆形图,首先,我们先写一个函数,用于生成实心圆形的Bitmap:

    private Bitmap mCircleBitmap;//生成一个实心圆形Bitmap,这个Bitmap宽高要与当前的View的宽高相同private Bitmap getCircleBitmap() {if (mCircleBitmap == null) {mCircleBitmap = Bitmap.createBitmap(2 * mRadius, 2 * mRadius,Config.ARGB_8888);Canvas canvas = new Canvas(mCircleBitmap);mPaint.reset();mPaint.setStyle(Style.FILL);canvas.drawCircle(mRadius, mRadius, mRadius, mPaint);}return mCircleBitmap;}

然后,再将这个Bitmap“盖”到用户设置的图片上面:

//将两张图片以XferMode(DST_IN)的方式组合到一张照片中private Bitmap combineBitmap(Drawable drawable, Bitmap maskBitmap) {int width = drawable.getIntrinsicWidth();int height = drawable.getIntrinsicHeight();// 将drawable转bitmapBitmap bitmap = Bitmap.createBitmap(width, height, Config.ARGB_8888);Canvas canvas = new Canvas(bitmap);//将图片自动放缩到View的宽高,即2倍的半径drawable.setBounds(0, 0, mRadius*2, mRadius*2);drawable.draw(canvas);// 先将XferMode设置好,然后将盖在上面的bitmap绘制出来mPaint.reset();mPaint.setXfermode(xfermode);canvas.drawBitmap(maskBitmap, 0, 0, mPaint);mPaint.setXfermode(null);return bitmap;}

最后再将最终的Bitmap绘制到画板上面:

@Overrideprotected void onDraw(Canvas canvas) {//获取设置的src图片Drawable drawable = getDrawable();//获取盖在src上面的实心圆形BitmapBitmap circleBitmap = getCircleBitmap();//两张图片以XferMode(DST_IN)的方式组合Bitmap bitmap = combineBitmap(drawable, circleBitmap);//将最终的bitmap画到画板上面canvas.drawBitmap(bitmap, 0, 0, mPaint);}

看看完整的代码吧~

package com.hc.circleimage;import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.Xfermode;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.widget.ImageView;public class XfermodeCircleImage extends ImageView {private int mRadius;private Paint mPaint;private Xfermode xfermode;private Bitmap mCircleBitmap;public XfermodeCircleImage(Context context) {super(context);init();}public XfermodeCircleImage(Context context, AttributeSet attrs) {super(context, attrs);init();}private void init() {mPaint = new Paint();xfermode = new PorterDuffXfermode(PorterDuff.Mode.DST_IN);}@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {super.onMeasure(widthMeasureSpec, heightMeasureSpec);int width = getMeasuredWidth();int height = getMeasuredHeight();if (width > height) {mRadius = height / 2;} else {mRadius = width / 2;}setMeasuredDimension(mRadius * 2, mRadius * 2);}//生成一个实心圆形Bitmap,这个Bitmap宽高要与当前的View的宽高相同private Bitmap getCircleBitmap() {if (mCircleBitmap == null) {mCircleBitmap = Bitmap.createBitmap(2 * mRadius, 2 * mRadius,Config.ARGB_8888);Canvas canvas = new Canvas(mCircleBitmap);mPaint.reset();mPaint.setStyle(Style.FILL);canvas.drawCircle(mRadius, mRadius, mRadius, mPaint);}return mCircleBitmap;}//将两张图片以XferMode(DST_IN)的方式组合到一张照片中private Bitmap combineBitmap(Drawable drawable, Bitmap maskBitmap) {int width = drawable.getIntrinsicWidth();int height = drawable.getIntrinsicHeight();// 将drawable转bitmapBitmap bitmap = Bitmap.createBitmap(width, height, Config.ARGB_8888);Canvas canvas = new Canvas(bitmap);//将图片自动放缩到View的宽高,即2倍的半径drawable.setBounds(0, 0, mRadius*2, mRadius*2);drawable.draw(canvas);// 先将XferMode设置好,然后将盖在上面的bitmap绘制出来mPaint.reset();mPaint.setXfermode(xfermode);canvas.drawBitmap(maskBitmap, 0, 0, mPaint);mPaint.setXfermode(null);return bitmap;}@Overrideprotected void onDraw(Canvas canvas) {//获取设置的src图片Drawable drawable = getDrawable();//获取盖在src上面的实心圆形BitmapBitmap circleBitmap = getCircleBitmap();//两张图片以XferMode(DST_IN)的方式组合Bitmap bitmap = combineBitmap(drawable, circleBitmap);//将最终的bitmap画到画板上面canvas.drawBitmap(bitmap, 0, 0, mPaint);}}

对自定义View不熟的童鞋可以参考《自定义View,有这一篇就够了》 。最后看看效果吧~

2 BitmapShader

同样的,hongyang大神也写过关于BitmapShader方式绘制圆形图片《 Android BitmapShader 实战 实现圆形、圆角图片 》,我们同样来个简单总结,Shader翻译成中文叫“着色器”,而我们的BitmapShader是Shader的子类,BitmapShader有啥作用呢,它可以根据你设置的方式(下面介绍)将图片铺满你所选的区域,有哪几种方式“铺”呢?有以下几种:
(1)CLAMP:拉伸,在x方向上是图片的最后一列像素重复平铺,而y方向是最后一行往下拉伸
(2)REPEAT: 重复,很容易理解,图片重复平铺过去
(3)MIRROR:镜像,就是将图片翻转

我们来看几张图片感受一下:
CLAMP的方式:

REPEAT方式

MIRROR方式

使用BitmapShader制作圆形图片的方法非常简单,只需通过Bitmap构造出一个BitmapShader,并将这个BitmapShader设置到当前的Paint当中,用这个Paint绘制一个圆就可以了,先看看onDraw函数:

    @Overrideprotected void onDraw(Canvas canvas) {// 将Drawable转为BitmapBitmap bmp = drawableToBitmap(getDrawable());// 通过Bitmap和指定x,y方向的平铺方式构造出BitmapShader对象BitmapShader mBitmapShader = new BitmapShader(bmp, TileMode.CLAMP,TileMode.CLAMP);// 将BitmapShader设置到当前的Paint对象中mPaint.setShader(mBitmapShader);// 绘制出一个圆canvas.drawCircle(mRadius, mRadius, mRadius, mPaint);}

其中,drawableToBitmap是将Drawable对象转为Bitmap对象:

private Bitmap drawableToBitmap(Drawable drawable) {if (drawable instanceof BitmapDrawable) {return ((BitmapDrawable) drawable).getBitmap();} else {int width = drawable.getIntrinsicWidth();int height = drawable.getIntrinsicHeight();Bitmap bitmap = Bitmap.createBitmap(width, height,Bitmap.Config.ARGB_8888);Canvas canvas = new Canvas(bitmap);drawable.setBounds(0, 0, width, height);drawable.draw(canvas);return bitmap;}
}

我们看看完整代码吧

package com.hc.circleimage;import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapShader;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Shader.TileMode;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.widget.ImageView;public class ShaderCircleImage extends ImageView {private int mRadius;private Paint mPaint;public ShaderCircleImage(Context context) {super(context);init();}public ShaderCircleImage(Context context, AttributeSet attrs) {super(context, attrs);init();}private void init() {mPaint = new Paint();}@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {super.onMeasure(widthMeasureSpec, heightMeasureSpec);int width = getMeasuredWidth();int height = getMeasuredHeight();if (width > height) {mRadius = height / 2;} else {mRadius = width / 2;}setMeasuredDimension(mRadius * 2, 2 * mRadius);}private Bitmap drawableToBitmap(Drawable drawable) {if (drawable instanceof BitmapDrawable) {return ((BitmapDrawable) drawable).getBitmap();} else {int width = drawable.getIntrinsicWidth();int height = drawable.getIntrinsicHeight();Bitmap bitmap = Bitmap.createBitmap(width, height,Bitmap.Config.ARGB_8888);Canvas canvas = new Canvas(bitmap);drawable.setBounds(0, 0, mRadius*2, mRadius*2);drawable.draw(canvas);return bitmap;}}@Overrideprotected void onDraw(Canvas canvas) {// 将Drawable转为BitmapBitmap bmp = drawableToBitmap(getDrawable());// 通过Bitmap和指定x,y方向的平铺方式构造出BitmapShader对象BitmapShader mBitmapShader = new BitmapShader(bmp, TileMode.CLAMP,TileMode.CLAMP);// 将BitmapShader设置到当前的Paint对象中mPaint.setShader(mBitmapShader);// 绘制出一个圆canvas.drawCircle(mRadius, mRadius, mRadius, mPaint);}
}

最后是要看看效果的,但是效果跟前面的效果是一样的,我们还是看一下吧~

3 ClipPath

前面的2中方法我们都见过,我们在看另一种方法吧ClipPath,或许你听说过Canvas对象的clipPath方法,或者是用过这个方法,可是有没有想过这个方法也可以用来绘制圆形图片呢?

我们看看代码吧:

@Override
protected void onDraw(Canvas canvas) {// 将Drawable转为BitmapBitmap bmp = drawableToBitmap(getDrawable());Path path = new Path(); //按照逆时针方向添加一个圆path.addCircle(mRadius, mRadius, mRadius, Direction.CCW);//先将canvas保存canvas.save();//设置为在圆形区域内绘制canvas.clipPath(path);//绘制Bitmapcanvas.drawBitmap(bmp, 0, 0, mPaint);//恢复Canvascanvas.restore();
}

是不是如此简单?过于简单,注释已经写明各行代码的意思啦!drawableToBitmap函数在上面一节解释过啦,这里就不再重复解释了,看看完整代码吧:

package com.hc.circleimage;import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Path.Direction;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.widget.ImageView;public class ClipCircleImage extends ImageView {private int mRadius;private Paint mPaint;public ClipCircleImage(Context context) {super(context);init();}public ClipCircleImage(Context context, AttributeSet attrs) {super(context, attrs);init();}private void init() {mPaint = new Paint();}@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {super.onMeasure(widthMeasureSpec, heightMeasureSpec);int width = getMeasuredWidth();int height = getMeasuredHeight();if (width > height) {mRadius = height / 2;} else {mRadius = width / 2;}setMeasuredDimension(mRadius * 2, 2 * mRadius);}private Bitmap drawableToBitmap(Drawable drawable) {if (drawable instanceof BitmapDrawable) {return ((BitmapDrawable) drawable).getBitmap();} else {int width = drawable.getIntrinsicWidth();int height = drawable.getIntrinsicHeight();Bitmap bitmap = Bitmap.createBitmap(width, height,Bitmap.Config.ARGB_8888);Canvas canvas = new Canvas(bitmap);drawable.setBounds(0, 0, mRadius*2, mRadius*2);drawable.draw(canvas);return bitmap;}}@Overrideprotected void onDraw(Canvas canvas) {// 将Drawable转为BitmapBitmap bmp = drawableToBitmap(getDrawable());Path path = new Path(); //按照逆时针方向添加一个圆path.addCircle(mRadius, mRadius, mRadius, Direction.CCW);//先将canvas保存canvas.save();//设置为在圆形区域内绘制canvas.clipPath(path);//绘制Bitmapcanvas.drawBitmap(bmp, 0, 0, mPaint);//恢复Canvascanvas.restore();}
}

效果虽然跟上面两节是一样的,但是我们还是看一下效果吧~

4 Alpha提取

现在我们看看一个很少见的方法,这个方法也是我不怎么推荐的方法,它是通过将一个张图的Alpha通道值设置到另外一张图中,啥意思呢?就是说,将两张图片的透明度设置为一模一样!看上去很酷的样子~,虽然不推荐,但是我们可以去学习一下嘛~可能某些项目需求中只能用这种方法去实现呢?

//获取圆形Bitmap
private Bitmap getCircleMask() {Bitmap bitmap = Bitmap.createBitmap(mRadius * 2, mRadius * 2,Config.ARGB_8888);Canvas canvas = new Canvas(bitmap);canvas.drawCircle(mRadius, mRadius, mRadius, mPaint);return bitmap;
}
//将rgbBitmap的RGB值与alphaBitmap的alpha值组成新的Bitmap
private Bitmap getBitmap(Bitmap rgbBitmap, Bitmap alphaBitmap) {Bitmap newBmp = Bitmap.createBitmap(mRadius * 2, mRadius * 2,Config.ARGB_8888);int alphaMask = 0xFF << 24;int rgbMask = ~alphaMask;for (int x = 0; x < 2 * mRadius; x++) {for (int y = 0; y < 2 * mRadius; y++) {int color = (rgbMask & rgbBitmap.getPixel(x, y))| (alphaMask & alphaBitmap.getPixel(x, y));newBmp.setPixel(x, y, color);}}return newBmp;
}@Override
protected void onDraw(Canvas canvas) {// 将Drawable转为BitmapBitmap rgbBitmap = drawableToBitmap(getDrawable());//提取alpha值通道Bitmap alphaBitmap = getCircleMask().extractAlpha();//将最终图片绘制出来canvas.drawBitmap(getBitmap(rgbBitmap, alphaBitmap), 0, 0, mPaint);
}

我们可以看到,通过两个for循环来新建合成一个新的图片,这个效率非常的低下!!!!!实际中不推荐采用这种方式,当然了,我们可以通过使用RenderScript并行处理,最终效率也不会比前面3种方法差!最终效果我就不贴上来了,依然是与前面几种方法是相同的

最后,把源码献上:http://download.csdn.net/detail/huachao1001/9541176

制作圆形图片,你会以下几种?相关推荐

  1. iOS制作圆形图片头像

    iOS制作圆形图片头像,两行代码就行了,很简单. self.aImage.layer.masksToBounds = YES; self.aImage.layer.cornerRadius = 40; ...

  2. 如何使用GDI+制作圆形图片(类似QQ头像)

    一直在CSDN学习,下载了很多资源,没有上传过什么资料,今天也为大家做个小小贡献 很多软件和APP都用了圆形图像,也想当的好看,最近公司项目要用到这个小东西,花了半天时间搞了出来. (c#只用了几分钟 ...

  3. Android 圆形图片 CircleImageView(Xfermode方式)

    Android中实现圆形图片,总的说来有2种方法. Xfermode方式,就是本文要讲的实现方式. BitmapShader(着色器)和Matrix(矩阵)方式 第二种实现方式的代表作,就是Henni ...

  4. Android 两种制作圆形/圆角图片的方法

    前言: 目前网上有很多圆角图片的实例,Github上也有一些成熟的项目.之前做项目,为了稳定高效都是选用Github上的项目直接用.但这种结束也是Android开发必备技能 ,所以今天就来简单研究一下 ...

  5. Kotlin实战练习——自定义圆形图片三种实现方式

    Kotlin实战练习--自定义圆形图片三种实现方式 前言 如今Kotlin越来越重要,本人也开始了Kotlin的学习.为了检测学习效果,加深学习印象,同时回顾一下以前的一些知识点,决定从写一个自定义圆 ...

  6. Andorid显示圆形图片的4种方式

    这篇博客主要讲解了Android实现圆形图片的4种方式. Android中并没有一个原生的控件,可以显示圆形或圆角图片,因此需要我们自己去定义这样一个控件. 实现圆形/圆角图片的核心思想,就是按照一定 ...

  7. 五种方式显示圆形图片

    推荐阅读: 鸿洋:Android BitmapShader 实战 实现圆形.圆角图片 鸿洋:Android Xfermode 实战 实现圆形.圆角图片 依赖 自定义CircleImageView &g ...

  8. Unity中通过mask组件裁剪出圆形图片,制作出圆形头像

    1.首先找一张圆形图片和长方形图片 2.添加Image控件,同时将图片换成圆形图片 3.在第一个Image下再放一个Image控件,同时将图片换成长方形图片 4.最关键的一步来了,点击第一个Image ...

  9. html的悬停图片圆形,css3炫酷圆形图片鼠标滑过特效

    这是一款纯css3炫酷圆形图片鼠标滑过特效插件.在插件中,所有的缩略图都被用css3 border-radius制作成圆形,然后再在其上做各种鼠标滑过特效. HTML 所有demo的html结构都如下 ...

最新文章

  1. 你是中层管理者?嗯,一个表面看似风光,实际却很 “鸡肋” 的重要岗位
  2. 第一章——数据结构之绪论
  3. 【转载】CMenu自绘---钩子---去除边框
  4. 创业融资十项注意要点
  5. 南阳理工计算机全国排名,全国工科实力最强的10所高校排名,
  6. java编写科赫曲线_matlab绘制peano(皮亚诺)曲线和koch(科赫曲线,雪花曲线)分形曲线...
  7. trunk vlan 加路由
  8. 讯飞输入法粤语语音识别率达95%支持粤转普
  9. vue基础知识点思维导图
  10. 基因测序技术发展历史以及一、二、三代测序技术原理及应用
  11. 蒙特卡洛思想(Monte Carlo思想)
  12. Windows Core Audio APIs(一)介绍
  13. 黄建宏-redis多机数据库
  14. MATEBOOK E 2019 安装linux
  15. js库笔记(一):swr ahooks
  16. 清华计算机系本科毕业起薪,大学本科毕业起薪最高的六大专业
  17. 英语学习也可以“做中学”
  18. 35岁以后软测就没有出路了吗?听听京东10年测开的经验分析
  19. 图片转素描(初级板)
  20. 关于android Window Leaked异常的解决方法

热门文章

  1. 【SystemC】(二)第一个SystemC程序
  2. 【BZOJ4889】[Tjoi2017]不勤劳的图书管理员 分块+树状数组
  3. 前端开发小白,如何找一个师傅?
  4. 2018.11.03 NOIP模拟 地球发动机(线性dp)
  5. 微信域名weixin.com天价成交!是腾讯吗?
  6. mfp服务器控制中心,固网HP-1008MFP驱动
  7. 个人站长网站建设流程
  8. [汉语]类书、叙词表、分类词典、同义词、反义词词典...
  9. linux查看sd卡系统类型,从SD卡启动linux系统
  10. 最全的数据分析平台整理