Android 如何用阿尔法绘画?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/11838022/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-20 08:59:46  来源:igfitidea点击:

How to paint with alpha?

android

提问by Melinda Green

I want to paint graphics onto a Canvas such that the colors are additive. For example, I want to produce this:
Proper additive colors

我想将图形绘制到 Canvas 上,这样颜色是相加的。例如,我想制作这个:
适当的添加剂颜色

But instead, I get this:
My results

但相反,我得到了这个:
我的结果

Note that the half white, half black background is intentional, just to see how alpha interacts with both backgrounds. I will be happy to have this work with either background. Here is my code:

请注意,半白半黑的背景是故意的,只是为了看看 alpha 如何与两种背景相互作用。我会很高兴有这两种背景的工作。这是我的代码:

public class VennColorsActivity extends Activity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        class VennView extends View {
            public VennView(Context context) {
                super(context);
            }

            @Override
            protected void onDraw(Canvas canvas) {
                super.onDraw(canvas);
                int alpha = 60, val = 255;
                int ar = Color.argb(alpha, val, 0, 0);
                int ag = Color.argb(alpha, 0, val, 0);
                int ab = Color.argb(alpha, 0, 0, val);
                float w = canvas.getWidth();
                float h = canvas.getHeight();
                float cx = w / 2f;
                float cy = h / 2;
                float r = w / 5;
                float tx = (float) (r * Math.cos(30 * Math.PI / 180));
                float ty = (float) (r * Math.sin(30 * Math.PI / 180));
                float expand = 1.5f;
                Paint paint = new Paint();
                paint.setColor(Color.WHITE);
                canvas.drawRect(new Rect(0, 0, (int) w, (int) (h / 2)), paint);
                PorterDuff.Mode mode = android.graphics.PorterDuff.Mode.ADD;
                paint = new Paint(Paint.ANTI_ALIAS_FLAG);
                paint.setColorFilter(new PorterDuffColorFilter(ar, mode));
                paint.setColor(ar);
                canvas.drawCircle(cx, cy - r, expand * r, paint);
                paint.setColorFilter(new PorterDuffColorFilter(ag, mode));
                paint.setColor(ag);
                canvas.drawCircle(cx - tx, cy + ty, expand * r, paint);
                paint.setColorFilter(new PorterDuffColorFilter(ab, mode));
                paint.setColor(ab);
                canvas.drawCircle(cx + tx, cy + ty, expand * r, paint);
            }
        }
        this.setContentView(new VennView(this));
    }
}

Can someone please help me understand how to paint with additive colors in Android graphics?

有人可以帮助我了解如何在 Android 图形中使用加色绘制吗?

回答by Pavel Dudka

You are on the right track. There are 3 major issues in your code:

你走在正确的轨道上。您的代码中有 3 个主要问题:

  • You need to set xfer mode iso color filter
  • Use temp bitmap for rendering your image
  • Alpha should be 0xFF in order to get results you are looking for
  • 您需要设置 xfer 模式 iso 颜色过滤器
  • 使用临时位图渲染图像
  • Alpha 应该是 0xFF 以获得您正在寻找的结果

Here is what I've got by using xfer mode. What I'm doing - is drawing everything into temporary bitmap and then rendering entire bitmap to main canvas.

这是我使用 xfer 模式得到的结果。我在做什么 - 将所有内容绘制到临时位图,然后将整个位图渲染到主画布。

xfer mode rules

xfer 模式规则

You ask why do you need temp bitmap? Good question! If you are drawing everything on a main canvas, your colors will be blended with main canvas background color, so all colors will get messed up. Transparent temp bitmap helps to keep your colors away of other parts of UI

你问为什么需要临时位图?好问题!如果您在主画布上绘制所有内容,您的颜色将与主画布背景颜色混合,因此所有颜色都会混乱。透明临时位图有助于让您的颜色远离 UI 的其他部分

Please make sure you are not allocating anything in onDraw()- you will run out memory very soon in this way.. Also make sure you have recycled your temp bitmap when you no longer need it.

请确保您没有分配任何内容onDraw()- 这样您很快就会耗尽内存..还要确保您在不再需要临时位图时回收了它。

package com.example.stack2;

import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PorterDuff.Mode;
import android.graphics.PorterDuffXfermode;
import android.os.Bundle;
import android.view.View;

public class YouAreWelcome extends Activity {

    Bitmap tempBmp = Bitmap.createBitmap(1, 1, Config.ARGB_8888);
    Canvas c = new Canvas();
    Paint paint = new Paint();

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        class VennView extends View {
            public VennView(Context context) {
                super(context);

            }

            protected void onDraw(Canvas canvas) {
                super.onDraw(canvas);
                if(tempBmp.isRecycled() || tempBmp.getWidth()!=canvas.getWidth() || tempBmp.getHeight()!=canvas.getHeight())
                {
                    tempBmp.recycle();
                    tempBmp = Bitmap.createBitmap(canvas.getWidth(), canvas.getHeight(), Config.ARGB_8888);
                    c.setBitmap(tempBmp);
                }

                    //clear previous drawings
                c.drawColor(Color.TRANSPARENT, Mode.CLEAR);

                int alpha = 255, val = 255;
                int ar = Color.argb(alpha, val, 0, 0);
                int ag = Color.argb(alpha, 0, val, 0);
                int ab = Color.argb(alpha, 0, 0, val);
                float w = canvas.getWidth();
                float h = canvas.getHeight();
                float cx = w / 2f;
                float cy = h / 2;
                float r = w / 5;
                float tx = (float) (r * Math.cos(30 * Math.PI / 180));
                float ty = (float) (r * Math.sin(30 * Math.PI / 180));
                float expand = 1.5f;
                paint.setAntiAlias(true);
                paint.setXfermode(new PorterDuffXfermode(Mode.ADD));
                paint.setColor(ar);
                c.drawCircle(cx, cy - r, expand * r, paint);
                paint.setColor(ag);
                c.drawCircle(cx - tx, cy + ty, expand * r, paint);
                paint.setColor(ab);
                c.drawCircle(cx + tx, cy + ty, expand * r, paint);
                canvas.drawBitmap(tempBmp, 0, 0, null);
            }
        }
        this.setContentView(new VennView(this));
    }
}

回答by Melinda Green

Thanks again Pavel. That would have been very difficult for me to have figured out on my own. I am answering my own question to better drill into details, but I've accepted yours as the best answer.

再次感谢帕维尔。这对我来说很难自己弄清楚。我正在回答我自己的问题以更好地深入了解细节,但我已接受您的最佳答案。

You are right that I prefer not to have to create and manage an off-screen Bitmap (and Canvas). That is essentially why I mentioned that a black or white background would be fine to make this work.

你是对的,我不想创建和管理屏幕外的位图(和画布)。这就是为什么我提到黑色或白色背景可以很好地完成这项工作的原因。

I'm never concerned with performance before I see something working but I share your caution after that point. Editing your version to fix that and remove those members gives the implementation below.

在我看到一些工作之前,我从不关心性能,但在那之后我和你一样谨慎。编辑您的版本以修复该问题并删除这些成员提供以下实现。

Is this robust? Note the two calls to Canvas.drawColor() which I suspect could also be combined into one.

这是健壮的吗?请注意对 Canvas.drawColor() 的两次调用,我怀疑它们也可以合并为一个。

package com.superliminal.android.test.venn;

import android.app.Activity;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PorterDuff.Mode;
import android.graphics.PorterDuffXfermode;
import android.os.Bundle;
import android.view.View;

public class VennColorsActivity extends Activity {
    private Paint paint = new Paint();

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        class VennView extends View {
            public VennView(Context context) {
                super(context);
            }

            @Override
            protected void onDraw(Canvas canvas) {
                super.onDraw(canvas);
                canvas.drawColor(Color.BLACK);
                canvas.drawColor(Color.TRANSPARENT, Mode.CLEAR);
                int alpha = 255, val = 255;
                int ar = Color.argb(alpha, val, 0, 0);
                int ag = Color.argb(alpha, 0, val, 0);
                int ab = Color.argb(alpha, 0, 0, val);
                float w = canvas.getWidth();
                float h = canvas.getHeight();
                float cx = w / 2f;
                float cy = h / 2;
                float r = w / 5;
                float tx = (float) (r * Math.cos(30 * Math.PI / 180));
                float ty = (float) (r * Math.sin(30 * Math.PI / 180));
                float expand = 1.5f;
                paint.setAntiAlias(true);
                paint.setXfermode(new PorterDuffXfermode(Mode.ADD));
                paint.setColor(ar);
                canvas.drawCircle(cx, cy - r, expand * r, paint);
                paint.setColor(ag);
                canvas.drawCircle(cx - tx, cy + ty, expand * r, paint);
                paint.setColor(ab);
                canvas.drawCircle(cx + tx, cy + ty, expand * r, paint);
            }
        }
        setContentView(new VennView(this));
    }
}