Подтвердить что ты не робот

PorterduffXfermode: очистить раздел растрового изображения

Цель состоит в том, чтобы просто нарисовать растровое изображение и поверх него нарисовать фигуры, которые УДАЛИТЬ базовую область растрового изображения.

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

android.graphics.PorterDuff.Mode.CLEAR

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

import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PorterDuffXfermode;
import android.graphics.Paint.Style;
import android.graphics.PorterDuff.Mode;
import android.graphics.RectF;
import android.os.Bundle;
import android.view.View;
import android.view.Window;
import android.widget.RelativeLayout;

public class Test extends Activity {
    Drawing d = null;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        requestWindowFeature(Window.FEATURE_NO_TITLE);

        RelativeLayout.LayoutParams rlp = null;

        // Create the view for the xfermode test
        d = new Drawing(this);
        rlp = new RelativeLayout.LayoutParams(600, 900);
        rlp.addRule(RelativeLayout.CENTER_IN_PARENT);
        d.setLayoutParams(rlp);

        RelativeLayout rl = new RelativeLayout(this);
        rl.setBackgroundColor(Color.rgb(0, 0, 255));
        rl.addView(d);

        // Show the layout with the test view
        setContentView(rl);
    }

    public class Drawing extends View {
        Paint[] pDraw = null;
        Bitmap bm = null;

        public Drawing(Context ct) {
            super(ct);

            // Generate bitmap used for background
            bm = BitmapFactory.decodeFile("mnt/sdcard/Pictures/test.jpg");

            // Generate array of paints
            pDraw = new Paint[16];

            for (int i = 0; i<pDraw.length; i++) {
                pDraw[i] = new Paint();
                pDraw[i].setARGB(255, 255, 255, 0);
                pDraw[i].setStrokeWidth(20);
                pDraw[i].setStyle(Style.FILL);
            }

            // Set all transfer modes
            pDraw[0].setXfermode(new PorterDuffXfermode(Mode.CLEAR));
            pDraw[1].setXfermode(new PorterDuffXfermode(Mode.DARKEN));
            pDraw[2].setXfermode(new PorterDuffXfermode(Mode.DST));
            pDraw[3].setXfermode(new PorterDuffXfermode(Mode.DST_ATOP));
            pDraw[4].setXfermode(new PorterDuffXfermode(Mode.DST_IN));
            pDraw[5].setXfermode(new PorterDuffXfermode(Mode.DST_OUT));
            pDraw[6].setXfermode(new PorterDuffXfermode(Mode.DST_OVER));
            pDraw[7].setXfermode(new PorterDuffXfermode(Mode.LIGHTEN));
            pDraw[8].setXfermode(new PorterDuffXfermode(Mode.MULTIPLY));
            pDraw[9].setXfermode(new PorterDuffXfermode(Mode.SCREEN));
            pDraw[10].setXfermode(new PorterDuffXfermode(Mode.SRC));
            pDraw[11].setXfermode(new PorterDuffXfermode(Mode.SRC_ATOP));
            pDraw[12].setXfermode(new PorterDuffXfermode(Mode.SRC_IN));
            pDraw[13].setXfermode(new PorterDuffXfermode(Mode.SRC_OUT));
            pDraw[14].setXfermode(new PorterDuffXfermode(Mode.SRC_OVER));
            pDraw[15].setXfermode(new PorterDuffXfermode(Mode.XOR));
        }

        @Override
        public void onDraw(Canvas canv) {
            // Background colour for canvas
            canv.drawColor(Color.argb(255, 255, 0, 255));

            // Draw the bitmap leaving small outside border to see background
            canv.drawBitmap(bm, null, new RectF(15, 15, getMeasuredWidth() - 15, getMeasuredHeight() - 15), null);

            float w, h;
            w = getMeasuredWidth();
            h = getMeasuredHeight();

            // Loop, draws 4 circles per row, in 4 rows on top of bitmap
            // Drawn in the order of pDraw (alphabetical)
            for(int i = 0; i<4; i++) {
                for(int ii = 0; ii<4; ii++) {
                    canv.drawCircle((w / 8) * (ii * 2 + 1), (h / 8) * (i * 2 + 1), w / 8 * 0.8f, pDraw[i*4 + ii]);
                }
            }
        }
    }

}

Это результат теста:

enter image description here

Режим CLEAR - верхний левый, который отображается как черный.

В другом примере, где я пытался использовать это, у меня был DialogFragment, в котором режим CLEAR стирал весь DialogFragment, чтобы можно было увидеть активность внизу. Поэтому причина в том, что в этом тесте я использовал много разных цветов фона.

Возможно ли это, возможно, очистить пиксели всей активности, как это сделал другой пример? Я бы подумал, что только пиксели canvas, связанные с представлением, могут быть удалены, но в моем другом примере пиксели пользовательского представления, основного изображения и фона диалогового окна были очищены.

Может кто-то, пожалуйста, помогите мне понять, что именно происходит, и почему я так ужасно ошибаюсь?

Спасибо.

EDIT: Я воспроизвел пример, подтверждающий мои подозрения. При добавлении этого точного пользовательского представления, но в диалоговом окне "Диалог" становится видимым базовое действие.

enter image description here

Это кажется довольно ясным индикатором для меня, что Mode.CLEAR каким-то образом стирает холст видов под ним? Мое предположение было бы черным в первом примере - это вид верхнего уровня?

Я думаю, что я что-то делаю неправильно: S

4b9b3361

Ответ 1

Проблема заключается в аппаратном ускорении. Отключите его для конкретного вида, который вы рисуете с помощью CLEAR. Если вы используете настраиваемое представление, сделайте это в конструкторах:

if (android.os.Build.VERSION.SDK_INT >= 11) 
{
     setLayerType(View.LAYER_TYPE_SOFTWARE, null);
}

Вы также можете вызвать setLayerType в ссылке справки.

Ответ 2

Я не вижу ничего неожиданного. В частном случае Mode.CLEAR очищаются как цвет, так и альфа адресата, что позволяет отображать черный фон. Эта утилита позволяет экспериментировать с различными режимами, цветами и альфа-значениями, и источник может предложить некоторое понимание. На (несколько устаревшем) изображении ниже области CLEAR показывают слабый серый полосатый оттенок, предоставленный делегатом платформы PanelUI.

image
(источник: Composite на sites.google.com)

Ответ 3

Как отмечает Ромен Гай: материал google вам нужно писать на растровом изображении, а не на холсте с кругами, которые вы пытаетесь очистить, затем установите его в основной холст в вашем представлении. Итак, сделайте что-нибудь вроде:

// Generate bitmap used for background
            bm = BitmapFactory.decodeFile("mnt/sdcard/Pictures/test.jpg");

// Create the paint and set the bitmap
Canvas temp = new Canvas(bm.getHeight(), bm.getWidth, Config.ARGB_8888);

// in onDraw()
temp.drawCircle((w / 8) * (ii * 2 + 1), (h / 8) * (i * 2 + 1), w / 8 * 0.8f, pDraw[i*4 + ii]);

// After loop
canvas.drawBitmap(....);

Надеюсь, что это поможет.