当前位置:   article > 正文

关于ondraw你该知道的(一)

ondraw

目录

1.'画板'canvas

2.画布canvas的操作

0)canvas绘制前后,加入操作

1)平移

2)旋转

3)截取

4)画布的锁定

5)图层Layer合成

6)图层Layout创建和移除

3.PorterDuffXfermode

1)交集区域的16种处理及展示

2)利用PorterDuffXfermode制作圆角图

4.颜色矩阵ColorMatrix

1)原理

2)利用封装类ColorMatrix处理颜色

3)矩阵值改变原色

5.处理bitmap像素点


1.'画板'canvas

像画画一样,需要画板(canvas)和画笔(paint)

至于画板画什么,和用什么样的画笔,参考:https://blog.csdn.net/qq_37321098/article/details/84959425

安卓中用画板canvas画画,还需要传入bitmap,将bitmap和canvas绑定在一起(装载画布过程)。

(官方也不推荐使用无参方法构造canvas,需调用setBitmap函数为其设置一个Bitmap),看看源码验证一下:

  1. //bitmap被限定非非空了
  2. public Canvas(@NonNull Bitmap bitmap) {
  3. if (!bitmap.isMutable()) {
  4. throw new IllegalStateException("Immutable bitmap passed to Canvas constructor");
  5. }
  6. ...
  7. }

bitmap作用是用来存储所有绘制在canvas上的像素信息,所以通过这种方式创建的canvas,后面调用的Canvas.drawXX都是发生在这个bitmap上面。

换句话说:我们调用了许多Canvas.drawXX,但是其实并没有将图形直接绘制在canvas上,而是通过改变bitmap,让view重绘,从而显示改变后的bitmap。

问题:view的ondraw方法,为什么没看见bitmap绑定canvas过程?

这个系统传递给我们的canvas来自于ViewRootImpl的Surface,在绘图时系统将会SkBitmap设置到SkCanvas中并返回与之对应Canvas。所以,在onDraw()中也是有一个Bitmap的,只是这个Bitmap是由系统创建的罢了。

2.画布canvas的操作

0)canvas绘制前后,加入操作

  1. @Override
  2. protected void onDraw(Canvas canvas) {
  3. //控件自身绘制前,如果是textview,则是绘制文字操作前
  4. super.onDraw(canvas);
  5. //控件自身绘制后,如果是textview,则是绘制文字操作后
  6. }

1)平移

  1. @Override
  2. protected void onDraw(Canvas canvas) {
  3. super.onDraw(canvas);
  4. canvas.drawColor(Color.GREEN);
  5. //初始文字
  6. Paint paint = new Paint();
  7. paint.setColor(Color.BLACK);
  8. paint.setTextSize(60);
  9. canvas.drawText("画布初始位置",100,100,paint);
  10. //平移后画的文字
  11. canvas.translate(100,100);
  12. paint.setColor(Color.RED);
  13. canvas.drawText("画布变化后位置",100,100,paint);
  14. }

https://img-blog.csdnimg.cn/20190304140202699.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM3MzIxMDk4,size_16,color_FFFFFF,t_70

2)旋转

  1. @Override
  2. protected void onDraw(Canvas canvas) {
  3. super.onDraw(canvas);
  4. canvas.drawColor(Color.GREEN);
  5. //初始文字
  6. Paint paint = new Paint();
  7. paint.setColor(Color.BLACK);
  8. paint.setTextSize(60);
  9. canvas.drawText("画布初始位置",100,100,paint);
  10. //旋转后画的文字
  11. canvas.rotate(15);
  12. paint.setColor(Color.RED);
  13. canvas.drawText("画布变化后位置",100,100,paint);
  14. }

https://img-blog.csdnimg.cn/20190304141945638.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM3MzIxMDk4,size_16,color_FFFFFF,t_70

3)截取

  1. @Override
  2. protected void onDraw(Canvas canvas) {
  3. super.onDraw(canvas);
  4. canvas.drawColor(Color.GREEN);
  5. //初始文字
  6. Paint paint = new Paint();
  7. paint.setColor(Color.BLACK);
  8. paint.setTextSize(60);
  9. canvas.drawText("画布初始位置",100,100,paint);
  10. //裁剪后画的文字
  11. Rect rect = new Rect(10,200,600,500);
  12. canvas.clipRect(rect);
  13. canvas.drawColor(Color.BLUE);
  14. paint.setColor(Color.RED);
  15. canvas.drawText("画布变化后位置",10,250,paint);
  16. }

https://img-blog.csdnimg.cn/2019030414200375.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM3MzIxMDk4,size_16,color_FFFFFF,t_70

注意:

1.调用了canvas.clipRect( )后,再继续画图那么所绘的图只会在所剪裁的范围内体现

2.除了按照矩形剪裁以外,还可以有别的剪裁方式,比如:canvas.clipPath( )和canvas.clipRegion( )

4)画布的锁定

通过canvas.save锁定画布,将已经所绘的图形锁定,之后的绘图就不会影响到原来画好的图形。

之后的操作又发生在哪里呢?会生成一个新的图层(Layer),并且这个图层是透明的。此时,所有draw的方法都是在这个图层上进行,所以不会对之前画好的图形造成任何影响。

5)图层Layer合成

通过canvas.restore将canvas.save( )时会生成一个新的图层(Layer)与底下原本的画好的图像相结合形成一个新的图像。

因此,save( )和restore( )最好配对使用,若restore( )的调用次数比save( )多可能会造成异常绘制。

  1. @Override
  2. protected void onDraw(Canvas canvas) {
  3. super.onDraw(canvas);
  4. canvas.drawColor(Color.GREEN);
  5. //初始文字
  6. Paint paint = new Paint();
  7. paint.setColor(Color.BLACK);
  8. paint.setTextSize(60);
  9. canvas.drawText("画布初始位置",100,100,paint);
  10. canvas.save();
  11. //save+旋转后画的图
  12. canvas.rotate(15);
  13. Bitmap bit= BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher);
  14. canvas.drawBitmap(bit, 100, 100, paint);
  15. canvas.restore();
  16. //合成后画字
  17. paint.setColor(Color.RED);
  18. canvas.drawText("画布变化后位置",250,250,paint);
  19. }

https://img-blog.csdnimg.cn/2019030414333467.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM3MzIxMDk4,size_16,color_FFFFFF,t_70

绘制初始文字和图片的2个图层合成之后,canvas的旋转属性也消失了,通过最后画的文字的旋转角度可知。

6)图层Layout创建和移除

可以通过saveLayout()或者saveLayoutAlpha()去创建图层,创建的新图层遵循'先入后出'的概念,即新创建的图层永远在最上层,因此,我们画的内容也是绘制在最上层。

同样通过restore和restoreTocount()将图层出栈,出栈后,绘制的内容也是绘制在最上层的Layout图层上。

3.PorterDuffXfermode

1)交集区域的16种处理及展示

PorterDuffXfermode可以给画笔加上一些高级属性,可以设置两个图层交集区域的显示方式。

下面看看PorterDuffXfermode的16个定义常量对绘图效果的最终影响:

https://img-blog.csdnimg.cn/20190306101804901.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM3MzIxMDk4,size_16,color_FFFFFF,t_70

解释如下:

https://img-blog.csdnimg.cn/20190306101843230.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM3MzIxMDk4,size_16,color_FFFFFF,t_70

2)利用PorterDuffXfermode制作圆角图

  1. //绘制内容
  2. private Bitmap mBitmap;
  3. //占位bitmap
  4. private Bitmap mOutBitmap;
  5. public void init() {
  6. mBitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.draw_img);
  7. mOutBitmap = Bitmap.createBitmap(mBitmap.getWidth(), mBitmap.getHeight(),
  8. Bitmap.Config.ARGB_8888);
  9. setLayerType(View.LAYER_TYPE_SOFTWARE, null);//关掉硬件加速
  10. }
  11. @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
  12. @Override
  13. protected void onDraw(Canvas canvas) {
  14. super.onDraw(canvas);
  15. Paint paint = new Paint();
  16. paint.setAntiAlias(true);
  17. canvas.drawRoundRect(0, 0, mBitmap.getWidth(), mBitmap.getHeight(), 30, 30, paint);
  18. //交集只显示上层
  19. paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
  20. canvas.drawBitmap(mBitmap,0,0,paint);
  21. }

 原图:

https://img-blog.csdnimg.cn/20190306111428972.png

处理后:

https://img-blog.csdnimg.cn/20190306111524380.png

4.颜色矩阵ColorMatrix

1)原理

图像描述由3部分组成:

  1. 色调(物体传播的颜色)
  2. 饱和度(颜色的纯度)    由0(灰)----->100%(饱和)
  3. 亮度

而在android中,系统用一个4×5的颜色矩阵ColorMatrix来处理图像。

https://img-blog.csdnimg.cn/20190306114007343.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM3MzIxMDk4,size_16,color_FFFFFF,t_70

https://img-blog.csdnimg.cn/20190306113252262.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM3MzIxMDk4,size_16,color_FFFFFF,t_70

初始颜色矩阵,不对原有的颜色值进行任何变化

https://img-blog.csdnimg.cn/20190306115105853.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM3MzIxMDk4,size_16,color_FFFFFF,t_70

分别可以通过改变系数  或者 偏移量去修改原有颜色值

https://img-blog.csdnimg.cn/20190306115314681.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM3MzIxMDk4,size_16,color_FFFFFF,t_70

https://img-blog.csdnimg.cn/2019030611533574.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM3MzIxMDk4,size_16,color_FFFFFF,t_70

2)利用封装类ColorMatrix处理颜色

a.修改色调

  1. ColorMatrix colorMatrix1 = new ColorMatrix();
  2. //第一个参数表示处理哪种颜色:0代表红 1绿色 2蓝色
  3. //第二个参数表示处理的值
  4. colorMatrix1.setRotate(0,100);

b.修改饱和度

  1. ColorMatrix colorMatrix2 = new ColorMatrix();
  2. //第一个参数表示处理的值
  3. colorMatrix2.setSaturation(0);

c.修改亮度

  1. //利用原理:三原色已相同比例混合,会显示白色
  2. int value = 1;
  3. ColorMatrix colorMatrix3 = new ColorMatrix();
  4. //4个参数分别为R-G-B-A要处理的值
  5. colorMatrix3.setScale(value,value,value,1);

d.组合a、b、c三种效果

  1. ColorMatrix colorMatrix = new ColorMatrix();
  2. colorMatrix.postConcat(colorMatrix1);
  3. colorMatrix.postConcat(colorMatrix2);
  4. colorMatrix.postConcat(colorMatrix3);

3)矩阵值改变原色

图像反转矩阵:

  1. //绘制内容
  2. private Bitmap mBitmap;
  3. //占位bitmap
  4. private Bitmap mOutBitmap;
  5. //各种算法矩阵,可自行百度实验
  6. //图像反转矩阵
  7. // -1,0,0,1,1,
  8. // 0,-1,0,1,1,
  9. // 0,0,-1,1,1,
  10. // 0,0,0,1,0
  11. float value[] = {-1,0,0,1,1,0,-1,0,1,1,0,0,-1,1,1,0,0,0,1,0};
  12. public void init() {
  13. mBitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.draw_img);
  14. mOutBitmap = Bitmap.createBitmap(mBitmap.getWidth(), mBitmap.getHeight(),
  15. Bitmap.Config.ARGB_8888);
  16. //关掉硬件加速
  17. setLayerType(View.LAYER_TYPE_SOFTWARE, null);
  18. }
  19. @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
  20. @Override
  21. protected void onDraw(Canvas canvas) {
  22. super.onDraw(canvas);
  23. //传入颜色矩阵值
  24. android.graphics.ColorMatrix colorMa = new android.graphics.ColorMatrix();
  25. colorMa.set(value);
  26. //绘图
  27. Paint paint = new Paint();
  28. paint.setColorFilter(new ColorMatrixColorFilter(colorMa));
  29. canvas.drawBitmap(mBitmap,0,0,paint);
  30. }

原图:

https://img-blog.csdnimg.cn/20190306111428972.png

 

变化后:

https://img-blog.csdnimg.cn/20190306143311154.png

wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

5.处理bitmap像素点

不会改变原图,而是拿到原图像素点,并生成新图来修改。

先拿到原图像素点,且像素点是用数组存储,函数如下:

Biamap.getPixels(int[] pixels, int offset, int stride, int x, int y, int width, int height)

参数:

pixels:接收位图颜色值的数组

offset:写入到pixels[]中的第一个像素索引值

stride:pixels[]中的行间距个数值(必须大于等于位图宽度)。不能为负数

x:从位图中读取的第一个像素的x坐标值。

y:从位图中读取的第一个像素的y坐标值

width:从每一行中读取的像素宽度

height:读取的行数

参考:https://www.cnblogs.com/fordreamxin/p/4605693.html

 

当我们拿到像素点数组oldPx后,还可以拿到每个像素点的RGBA值,如下:

int r=Color.red(oldPx[0]);

拿到rgba后,就可以调用一些图像处理的算法,去改变RGBA值,从而将改变后的RGBA值合成新的像素点,如下:

newPx[0]=Color.argb(a1,r1,g1,b1);

最终将新像素点数组,设置给bitmap,达到修改的目的,如下:

bitmap.setPixels(newPx,0,width,0,0,width,height);

 

 

 

 

 

 

 

 

 

 

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/笔触狂放9/article/detail/765497
推荐阅读
相关标签
  

闽ICP备14008679号