• 使用反直觉的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图层如果是更复杂的图片,那相当于只有显示文字的部分显示了图片,可以做多种艺术字的效果了。

  • 相关阅读:
    es删除报错 blocked by [FORBIDDEN8index write (api)]
    2024-05-10 Ubuntu上面使用libyuv,用于转换、缩放、旋转和其他操作YUV图像数据,测试实例使用I420ToRGB24
    Lecture 7 Synchronization(进程同步)
    HoloLens联合发明人:打造理想的全天AR需要解决这些问题
    cesium判断一个点是否在一个范围内
    微型导轨在医疗设备中起什么作用?
    SpringBoot@Profile详解
    [LLM+AIGC] 01.应用篇之中文ChatGPT初探及利用ChatGPT润色论文对比浅析(文心一言 | 讯飞星火)
    Flink--7、窗口(窗口的概念、分类、API、分配器、窗口函数)、触发器、移除器
    Greenplum数据库故障分析——能对数据库base文件夹进行软连接嘛?
  • 原文地址:https://blog.csdn.net/cjzjolly/article/details/126720232