Android图像处理之Paint特效处理(Paint重点API方法精炼详解)

一、前期基础知识储备

(1)Canvas常用绘制方法录

绘制颜色 drawColor, drawRGB, drawARGB 使用单一颜色填充整个画布
绘制图片 drawBitmap(有6种,各有各的适用场景), drawPicture 绘制位图和图片


绘制基本形状 drawPoint, drawPoints, drawLine, drawLines, drawRect,
drawRoundRect, drawOval, drawCircle, drawArc 依次为 点、线、矩形、圆角矩形、椭圆、圆、圆弧


绘制文本 drawText, drawPosText, drawTextOnPath 依次为 绘制文字、绘制文字时指定每个文字位置、根据路径绘制文字

绘制路径 drawPath 绘制路径,绘制贝塞尔曲线时也需要用到该函数


画布剪裁 clipPath, clipRect 设置画布的显示区域


画布快照 save, restore, saveLayerXxx, restoreToCount, getSaveCount 依次为
保存当前状态、 回滚到上一次保存的状态、 保存图层状态、 回滚到指定状态、 获取保存次数


画布变换 translate, scale, rotate, skew 依次为 位移、缩放、 旋转、错切
Matrix(矩阵) getMatrix, setMatrix, concat 实际上画布的位移,缩放等操作的都是图像矩阵Matrix, 只不过Matrix比较难以理解和使用,故封装了一些常用的方法。


Canvas绘制任何形状、图形、颜色、文字都少不了Paint属性,而Paint内置的众多属性也非常契合绘制的需求,二者配合可以做出非常多非常酷炫的效果。碰到有些时候要做某种效果而没有好的思路时,动画不行,自定义View也差强人意,这个时候就可以尝试查询Paint内置API,或许这个你想要的效果刚好有对应的Paint的API方法可以做到。

(2)Paint常用绘制方法录

公共部分
setStyle: 设置画笔风格,空心或者实心
setStrokeWidth: 设置画笔宽度


图片绘制
setARGB(int a,int r,int g,int b); - paint.setARGB(100, 255, 0, 0);
设置绘制的颜色,a代表透明度,r,g,b代表颜色值。

setAlpha(int a);
设置绘制图形的透明度。

setColor(int color); - paint.setColor(Color.parseColor(“#009688”));
设置绘制的颜色,使用颜色值来表示,该颜色值包括透明度和RGB颜色。

setAntiAlias(boolean aa);
设置是否使用抗锯齿功能,会消耗较大资源,绘制图形速度会变慢。

setDither(boolean dither);
设定是否使用图像抖动处理,会使绘制出来的图片颜色更加平滑和饱满,图像更加清晰

setFilterBitmap(boolean filter);
如果该项设置为true,则图像在动画进行中会滤掉对Bitmap图像的优化操作,加快显示
速度,本设置项依赖于dither和xfermode的设置

setMaskFilter(MaskFilter maskfilter);
设置MaskFilter,可以用不同的MaskFilter实现滤镜的效果,如滤化,立体等

setColorFilter(ColorFilter colorfilter);
设置颜色过滤器,可以在绘制颜色时实现不用颜色的变换效果

setPathEffect(PathEffect effect);
设置绘制路径的效果,如点画线等

setShader(Shader shader);
设置图像效果,使用Shader可以绘制出各种渐变效果

setShadowLayer(float radius ,float dx,float dy,int color);
在图形下面设置阴影层,产生阴影效果,radius为阴影的角度,dx和dy为阴影在x轴和y轴上的距离,color为阴影的颜色

setStrokeCap(Paint.Cap cap);
当画笔样式为STROKE或FILL_OR_STROKE时,设置笔刷的图形样式,如圆形样式
Cap.ROUND,或方形样式Cap.SQUARE

setSrokeJoin(Paint.Join join);
设置绘制时各图形的结合方式,如平滑效果等

setXfermode(Xfermode xfermode);
设置图形重叠时的处理方式,如合并,取交集或并集,经常用来制作橡皮的擦除效果


文本绘制

setFakeBoldText(boolean fakeBoldText);
模拟实现粗体文字,设置在小字体上效果会非常差

setSubpixelText(boolean subpixelText);
设置该项为true,将有助于文本在LCD屏幕上的显示效果

setTextAlign(Paint.Align align);
设置绘制文字的对齐方向

setTextScaleX(float scaleX);
设置绘制文字x轴的缩放比例,可以实现文字的拉伸的效果

setTextSize(float textSize);
设置绘制文字的字号大小

setTextSkewX(float skewX);
设置斜体文字,skewX为倾斜弧度

setTypeface(Typeface typeface);
设置Typeface对象,即字体风格,包括粗体,斜体以及衬线体,非衬线体等

setUnderlineText(boolean underlineText);
设置带有下划线的文字效果

setStrikeThruText(boolean strikeThruText);
设置带有删除线的效果

二、上代码 具体实现

(1)setShader

Shader又被称为着色器、染色器。它用来实现一系列的渐变、渲染效果。Android中的Shader包括以下几种:

  • BitmapShader —— 位图Shader
  • LinearGradient —— 线性Shader
  • RadialGradient —— 光束Shader
  • SweepGradient —— 梯度 Shader
  • ComposeShader —— 混合Shader

①LinearGradient —— 线性Shader

Shader shader = new LinearGradient(100, 100, 500, 500, 
Color.parseColor("#E91E63"),  
Color.parseColor("#2196F3"), Shader.TileMode.CLAMP);
paint.setShader(shader);

...

canvas.drawCircle(300, 300, 200, paint);  

这里写图片描述

②RadialGradient —— 光束Shader

Shader shader = new RadialGradient(300, 300, 200, 
Color.parseColor("#E91E63"),  
Color.parseColor("#2196F3"), Shader.TileMode.CLAMP);
paint.setShader(shader);

...

canvas.drawCircle(300, 300, 200, paint);  

这里写图片描述
③BitmapShader —— 位图Shader

Bitmap bitmap = BitmapFactory.decodeResource(getResources(), 
R.drawable.batman);  
Shader shader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, 
Shader.TileMode.CLAMP);  
paint.setShader(shader);

...

canvas.drawCircle(300, 300, 200, paint);  

这里写图片描述

(2)PorterDuffXfermode

这里写图片描述
图中列出了12种常见的PorterDuffXfermode,有点像数学中集合的交集、并集的概念。配合图大家可以看到它控制的是两个图像间混合区域的显示模式。
这里要注意的是,PorterDuffXfermode设置的是两个图层交集区域的显示方式,dst是先画的图形,而src是后画的图形
当然这些属性,也不是经常使用,用的最多的是,使用一张图片作为另一张图片的遮罩层,通过控制遮罩层的图形,来控制下面被遮罩图形的显示效果。其中最常用的是使用DST_IN.SRC_IN模式来实现将一个矩形图片变成圆角图片圆形图片

 bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.bv);
            Bitmap roundCornerBitmap = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Bitmap.Config.ARGB_8888);
            Canvas canvas = new Canvas(roundCornerBitmap);
            Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());
            RectF rectF = new RectF(rect);
            // 相当于清屏
            canvas.drawARGB(0, 0, 0, 0);
            // 先画了一个带圆角的矩形
            canvas.drawRoundRect(rectF, 30, 30, paint);
            paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
            canvas.drawBitmap(bitmap, rect, rect, paint);

这里写图片描述

(3)LightingColorFilter

这个 LightingColorFilter 是用来模拟简单的光照效果的。

LightingColorFilter 的构造方法是 LightingColorFilter(int mul, int add) ,参数里的 mul 和 add 都是和颜色值格式相同的 int 值,其中 mul 用来和目标像素相乘,add 用来和目标像素相加:一个「保持原样」的「基本 LightingColorFilter 」,mul 为 0xffffff,add 为 0x000000(也就是0)。
基于这个「基本 LightingColorFilter 」,你就可以修改一下做出其他的 filter。比如,如果你想去掉原像素中的红色,可以把它的 mul 改为 0x00ffff (红色部分为 0 )

ColorFilter lightingColorFilter = new LightingColorFilter(0x00ffff, 0x000000);  
paint.setColorFilter(lightingColorFilter); 

或者,如果你想让它的绿色更亮一些,就可以把它的 add 改为 0x003000 (绿色部分为 0x30 )

ColorFilter lightingColorFilter = new LightingColorFilter(0xffffff, 0x003000);  
paint.setColorFilter(lightingColorFilter);  

三、具体例子 横向移轴模糊

这里写图片描述
如上图所示,如何实现这样一个效果,上下两端进行模糊,中间是清晰的?
代码如下:使用的Paint的Shader属性,线性Shader的另一种构造方法。

int colors[] = new int[6];
colors[0] = 0xffffffff;//完全不透明
colors[1] = 0xffffffff;//不透明
colors[2] = 0x00ffffff;//完全透明
colors[3] = 0x00ffffff;//完全透明
colors[4] = 0xffffffff;//不透明
colors[5] = 0xffffffff;//完全不透明
float tiltTopHeight1 = Utils.clamp(newCenterY - newTiltHeight / 2, 0.0f, bitmapResizedHeight);
float tiltTopHeight2 = Utils.clamp(newCenterY - newTiltHeight / 2 + newTiltHeight * 0.05f, 0.0f, bitmapResizedHeight);
float tiltTopHeight3 = Utils.clamp(newCenterY + newTiltHeight / 2 - newTiltHeight * 0.05f, 0.0f, bitmapResizedHeight);
float tiltTopHeight4 = Utils.clamp(newCenterY + newTiltHeight / 2, 0.0f, bitmapResizedHeight);

float positions[] = new float[6];
positions[0] = 0.0f;
positions[1] = tiltTopHeight1 / bitmapResizedHeight;
positions[2] = tiltTopHeight2 / bitmapResizedHeight;
positions[3] = tiltTopHeight3 / bitmapResizedHeight;
positions[4] = tiltTopHeight4 / bitmapResizedHeight;
positions[5] = 1.0f;
LinearGradient shader = new LinearGradient(0, 0, 0, bitmapResizedHeight, colors, positions, Shader.TileMode.CLAMP);
maskPaint.setShader(shader);            
maskPaint.setAntiAlias(true);
lineCanvas.save();                          
lineCanvas.drawRect(-bitmapResizedWidth, -bitmapResizedHeight, 2 * bitmapResizedWidth, 2 * bitmapResizedHeight, maskPaint);

其实,效果并不难实现,我们将图片拆分开就会有所发现:
这里写图片描述
Android中的LinearGradient的第二个构造方法:
LinearGradient(float x0, float y0, float x1, float y1, int colors[], float positions[], TileMode tile)
注:Android中计算x,y坐标都是以屏幕左上角为原点,向右为x+,向下为y+
第一个参数为线性起点的x坐标
第二个参数为线性起点的y坐标
第三个参数为线性终点的x坐标
第四个参数为线性终点的y坐标
第五个参数为实现渐变效果的颜色的组合
第六个参数为前面的颜色组合中的各颜色在渐变中占据的位置(比重),如果为空,则表示上述颜色的集合在渐变中均匀出现
返回代码里我们可以看见Color数组是这样分布的:

colors[0] = 0xffffffff;//完全不透明
colors[1] = 0xffffffff;//不透明
colors[2] = 0x00ffffff;//完全透明
colors[3] = 0x00ffffff;//完全透明
colors[4] = 0xffffffff;//不透明
colors[5] = 0xffffffff;//完全不透明

从完全不透明 ——> 完全透明 ——> 完全不透明
而对应的位置属性是这样分布的:

positions[0] = 0.0f;
positions[1] = tiltTopHeight1 / bitmapResizedHeight;
positions[2] = tiltTopHeight2 / bitmapResizedHeight;
positions[3] = tiltTopHeight3 / bitmapResizedHeight;
positions[4] = tiltTopHeight4 / bitmapResizedHeight;
positions[5] = 1.0f;

通过算法控制好,两个白色实现上下为完全不透明区域,中间为完全透明区域。
然后将Shader属性绑定到Paint上,最后利用该Paint绘制一个区域足够大的矩形即可。

猜你喜欢

转载自blog.csdn.net/weixin_41101173/article/details/81807915