Как рисовать альфой?

Я хочу рисовать графику на холсте, чтобы цвета были аддитивными. Например, я хочу это сделать:
Proper additive colors

Но вместо этого я получаю следующее:
My results

Обратите внимание, что полубелый, наполовину черный фон преднамерен, просто чтобы увидеть, как альфа взаимодействует с обоими фонами. Я буду счастлив, если бы эта работа была либо с фоном. Вот мой код:

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));
    }
}

Может кто-нибудь, пожалуйста, помогите мне понять, как рисовать с добавочными цветами в графике Android?

Ответы

Ответ 1

Вы на правильном пути. В вашем коде есть 3 основные проблемы:

  • Вам необходимо установить xfer mode iso color filter
  • Использовать временную растровую карту для рендеринга изображения
  • Alpha должна быть 0xFF для получения результатов, которые вы ищете.

Вот что я получил, используя режим xfer. То, что я делаю, - это рисовать все во временное растровое изображение, а затем отображать всю растровую карту на основной холст.

xfer mode rules

Вы спрашиваете, зачем вам нужно растровое изображение temp? Хороший вопрос! Если вы рисуете все на основном холсте, ваши цвета будут смешиваться с основным цветом фона холста, поэтому все цвета будут перепутаны. Прозрачная растровая картинка темпа помогает сохранить ваши цвета в других частях пользовательского интерфейса.

Пожалуйста, убедитесь, что вы не выделяете что-либо в 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));
    }
}

Ответ 2

Еще раз спасибо. Это было бы очень сложно для меня разобраться. Я отвечаю на свой вопрос, чтобы лучше разобраться в деталях, но я принял ваш как лучший ответ.

Вы правы, что я предпочитаю не создавать и управлять растровым изображением (и холстом) вне экрана. Именно по этой причине я упомянул, что черный или белый фон будет хорош, чтобы сделать эту работу.

Я никогда не занимаюсь производительностью, прежде чем я увижу что-то работающее, но я разделяю вашу осторожность после этого момента. Редактирование версии для исправления и удаления этих элементов дает реализацию ниже.

Является ли это надежным? Обратите внимание на два вызова 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));
    }
}