• 使用反直觉的PorterDuffXfermode,实现已绘制到Canvas的内容换色的操作


            最近有一个需求,父控件ondraw方法里面会调用同事一个复杂的绘制逻辑。然而最近需要把已绘制的内容根据UI的变化变色。于是打算使用安卓自带的PorterDuffXfermode混合模式的特性实现,毕竟使用GLShader实现显然过于overkill,rendererScript可能不兼容,也比较麻烦。

            在这里,我只要使用DST_IN模式进行颜色替换即可,为何能实现颜色替换呢,可以观察其逻辑的符号表达:[Sa * Da, Sa * Dc],也就是说只要设置一个纯色不透明DST图层,那么SRC图层就会按照自己每个像素的不透明度乘以DST图层设定的颜色。

            逻辑已通,上Demo代码:

    1. package com.example.demosAboutCanvas;
    2. import android.app.Activity;
    3. import android.content.Context;
    4. import android.graphics.Bitmap;
    5. import android.graphics.BitmapShader;
    6. import android.graphics.Canvas;
    7. import android.graphics.Color;
    8. import android.graphics.Paint;
    9. import android.graphics.PaintFlagsDrawFilter;
    10. import android.graphics.PorterDuff;
    11. import android.graphics.PorterDuffXfermode;
    12. import android.graphics.Shader;
    13. import android.os.Bundle;
    14. import android.util.AttributeSet;
    15. import android.view.View;
    16. import androidx.annotation.Nullable;
    17. /**演示已绘制到Canvas的内容如何进行后期变色**/
    18. public class ChangeColorAfterDraw extends Activity {
    19. @Override
    20. protected void onCreate(@Nullable Bundle savedInstanceState) {
    21. super.onCreate(savedInstanceState);
    22. setContentView(new TestView(this));
    23. }
    24. private class TestView extends View {
    25. public TestView(Context context) {
    26. super(context);
    27. setLayerType(View.LAYER_TYPE_HARDWARE, null);
    28. }
    29. public TestView(Context context, @Nullable AttributeSet attrs) {
    30. super(context, attrs);
    31. setLayerType(View.LAYER_TYPE_HARDWARE, null);
    32. }
    33. public TestView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
    34. super(context, attrs, defStyleAttr);
    35. setLayerType(View.LAYER_TYPE_HARDWARE, null);
    36. }
    37. @Override
    38. protected void onDraw(Canvas canvas) {
    39. //创建SRC图层,实际上是红色的字来的:
    40. Bitmap srcBmp = Bitmap.createBitmap(canvas.getWidth(), canvas.getHeight(), Bitmap.Config.ARGB_8888);
    41. Canvas cvsFromText = new Canvas(srcBmp);
    42. Paint textPaint = new Paint();
    43. textPaint.setAntiAlias(true);
    44. textPaint.setColor(Color.RED);
    45. textPaint.setStyle(Paint.Style.FILL_AND_STROKE);
    46. textPaint.setTextSize(100);
    47. cvsFromText.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
    48. cvsFromText.drawText("Test", 0, 300, textPaint);
    49. //创建DST图层:
    50. Bitmap dstBmp = Bitmap.createBitmap(canvas.getWidth(), canvas.getHeight(), Bitmap.Config.ARGB_8888);
    51. Canvas cvsFromText2 = new Canvas(dstBmp);
    52. cvsFromText2.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
    53. cvsFromText2.drawColor(Color.GREEN);
    54. //先绘制换色用的DST图层(违背直觉,但这规则就是如此)
    55. canvas.drawBitmap(dstBmp, 0, 0, null);
    56. //再绘制实际内容SRC图层
    57. Paint blendPaint = new Paint();
    58. blendPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN)); //使用混合规则DST_IN, [Sa * Da, Sa * Dc],这样SRC图层不透明的地方就可以按透明度系数换成DST图层的颜色了。
    59. canvas.drawBitmap(srcBmp, 0, 0, blendPaint);
    60. }
    61. }
    62. }

            可以发现里面有一段反直觉的代码,就是我先绘制了替换颜色用的DST图层的内容,再绘制了要被替换颜色的源图层SRC图层的内容,这就是为什么我说这个东西用起来反直觉的原因,绝大部分绘图引擎都是越先绘制的图层越成为SRC,而在这是相反的。最后在绘制的时候设定Paint的模式为DST_IN,即可实现已绘制的SRC内容换色的操作了。在这里原本SRC图层的Test字母为红色,而最终显色效果被替换为DST图层的绿色。当然,DST图层如果是更复杂的图片,那相当于只有显示文字的部分显示了图片,可以做多种艺术字的效果了。

  • 相关阅读:
    Linux操作系统的基础知识
    含文档+PPT+源码等]精品spring boot汽车销售管理系统[包运行成功]程序设计源码计算机毕设
    练习-Java类和对象之包的定义
    浅析spack较受关注的场景
    Addressing Failure Prediction by Learning Model Confidence
    【华为OD机试真题 python】分班问题 【2022 Q4 | 100分】
    Vscode远程调试及gdbserver配置
    学长教你学C-day9-C语言循环结构与选择结构
    南大通用数据库-Gbase-8a-学习-11-Oracle通过Dblink访问Gbase8a
    猿创征文|我的C/C++技术成长之路
  • 原文地址:https://blog.csdn.net/cjzjolly/article/details/126720232