Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/xamarin/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/xamarin/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Android 在画布上绘制时,PorterDuff源和目标指的是什么?_Android_Xamarin_Android Canvas - Fatal编程技术网

Android 在画布上绘制时,PorterDuff源和目标指的是什么?

Android 在画布上绘制时,PorterDuff源和目标指的是什么?,android,xamarin,android-canvas,Android,Xamarin,Android Canvas,我整晚都在试图弄明白这一点,但在谷歌上找到的答案涉及到Android画布的一些非常具体的问题,我还没有找到任何关于这个主题的101种解释。甚至Android文档也使用位图而不是图形 具体问题: 我需要在画布上画一个椭圆形和一条路径。根据一种颜色的颜色源输出,目的地输出另一种颜色和重叠区域,或者源输入,或者目的地输入,第三种颜色。我试图在屏幕外的画布上完成所有这些。但是上面的一些步骤会出现问题,当试图以任何方式组合它们时,问题会变得更糟 代码- Bitmap bmp = Bitmap.C

我整晚都在试图弄明白这一点,但在谷歌上找到的答案涉及到Android画布的一些非常具体的问题,我还没有找到任何关于这个主题的101种解释。甚至Android文档也使用位图而不是图形

具体问题:

我需要在画布上画一个椭圆形和一条路径。根据一种颜色的颜色源输出,目的地输出另一种颜色和重叠区域,或者源输入,或者目的地输入,第三种颜色。我试图在屏幕外的画布上完成所有这些。但是上面的一些步骤会出现问题,当试图以任何方式组合它们时,问题会变得更糟

  • 代码-

        Bitmap bmp = Bitmap.CreateBitmap (720, 720, Bitmap.Config.Argb8888);
        Canvas c = new Canvas (bmp);
    
        Paint paint = new Paint ();
        paint.SetARGB (255, 255, 0, 0);
        c.DrawOval (200, 200, 520, 520, paint); //assumed destination
    
        paint.SetARGB (255, 0, 0, 255);
        paint.SetXfermode (new PorterDuffXfermode (PorterDuff.Mode.*)); //replace mode here
        paint.SetStyle (Paint.Style.Fill);
    
        Path path = new Path ();
        path.MoveTo (c.Width / 2f, c.Height / 2f);
    
        foreach (var m in measurements) {
            //calculations
    
            float x = xCalculatedValue
            float y = yCalculatedValue
    
            path.LineTo (x, y);
        }
    
        path.LineTo (c.Width / 2f, c.Height / 2f);
    
        c.DrawPath (path, paint); //assumed source
    
  • 来源-

相反,这将绘制XOR应该绘制的内容

  • 目的地输出-
这正如预期的那样有效

  • 来源于-
这将绘制源代码应该绘制的内容

  • 目的地在-
这画出了目的地应该是什么

更一般的问题:

在此上下文中,源和目标指的是什么?直观地说,我假设目标是画布位图的当前状态,源是canvas.Draw*和Paint PortedDuff.Mode添加的矩阵。但事实似乎并非如此

编辑:这基本上就是我想要的效果,“星”是一条动态路径。根据重叠程度给三种不同的颜色上色

编辑2:沈约克在回答实际问题时做得很好。但是对于任何想要得到类似效果的人来说,这里是最后的代码

Bitmap DrawGraphBitmapOffscreen ()
{
    Bitmap bmp = Bitmap.CreateBitmap (720, 720, Bitmap.Config.Argb8888);
    Canvas c = new Canvas (bmp);

    // Replace with calculated path
    Path path = new Path ();
    path.MoveTo (c.Width / 2f, c.Height / 2f);
    path.LineTo (263, 288);
    path.LineTo (236, 202);
    path.LineTo (312, 249);
    path.LineTo (331, 162);
    path.LineTo (374, 240);
    path.LineTo (434, 174);
    path.LineTo (431, 263);
    path.LineTo (517, 236);
    path.LineTo (470, 312);
    path.LineTo (557, 331);
    path.LineTo (479, 374);
    path.LineTo (545, 434);
    path.LineTo (456, 431);
    path.LineTo (483, 517);
    path.LineTo (407, 470);
    path.LineTo (388, 557);
    path.LineTo (345, 479);
    path.LineTo (285, 545);
    path.LineTo (288, 456);
    path.LineTo (202, 483);
    path.LineTo (249, 407);
    path.LineTo (162, 388);
    path.LineTo (240, 345);
    path.LineTo (174, 285);
    path.LineTo (263, 288);
    path.Close ();

    Paint paint = new Paint ();

    paint.SetARGB (255, 255, 0, 0);
    paint.SetStyle (Paint.Style.Fill);

    c.DrawPath (path, paint);

    paint.SetARGB (255, 0, 0, 255);
    paint.SetXfermode (new PorterDuffXfermode (PorterDuff.Mode.SrcIn));

    c.DrawOval (200, 200, 520, 520, paint);

    paint.SetARGB (255, 255, 255, 255);
    paint.SetXfermode (new PorterDuffXfermode (PorterDuff.Mode.DstOver));

    c.DrawOval (200, 200, 520, 520, paint);

    return bmp;
}
在画布上绘制时,PorterDuff源和目标指的是什么

经过一些深入的研究,我写了一些演示来深入地解释这一点。要帮助您了解什么是源和目标,请参阅

首先,查看以下代码:

protected override void OnDraw(Canvas canvas)
{
    base.OnDraw(canvas);

    Paint paint = new Paint();

    //Set the background color
    canvas.DrawARGB(255, 139, 197, 186);

    int canvasWidth = canvas.Width;
    int r = canvasWidth / 3;

    //Draw a yellow circle
    paint.Color = Color.Yellow;
    canvas.DrawCircle(r, r, r, paint);

    //Draw a blue rectangle
    paint.Color = Color.Blue;
    canvas.DrawRect(r, r, r * 2.7f, r * 2.7f, paint);
} 
我覆盖
OnDraw
方法,设置绿色背景,然后绘制一个黄色圆圈和一个蓝色矩形,效果:

以上是我们绘制
画布时的正常过程,我没有使用任何
PorterDuffXfermode
,让我们分析一下它的过程:

  • 首先,我们调用
    canvas.DrawARGB(255,139,197186)
    方法用一种颜色绘制整个
    canvas
    ,此画布中的每个像素都有相同的
    ARGB
    值:
    (255,139,197186)
    。由于
    ARGB
    中的alpha值是255而不是0,因此每个像素都是不透明的

  • 其次,当我们执行
    canvas.DrawCircle(r,r,r,paint)
    方法时,Android将在您定义的位置绘制一个黄色圆圈。此圆圈中ARGB值为
    (255139197186)
    的所有像素将替换为黄色像素。 黄色像素是源,ARGB值为
    (255139197186)
    的像素是目标。
    我将在后面解释

  • 第三,在执行
    canvas.DrawRect(r,r,r*2.7f,r*2.7f,paint)
    方法后,Android将绘制一个蓝色矩形,该矩形中的所有像素都是蓝色的,这些蓝色像素将重放相同位置的其他像素。因此,可以在
    画布上绘制蓝色矩形

其次,我使用的是
Xfermode
PorterDuff.mode.Clear

 protected override void OnDraw(Canvas canvas)
    {
        base.OnDraw(canvas);

        Paint paint = new Paint();

        //Set the background color
        canvas.DrawARGB(255, 139, 197, 186);

        int canvasWidth = canvas.Width;
        int r = canvasWidth / 3;

        //Draw a yellow circle
        paint.Color = Color.Yellow;
        canvas.DrawCircle(r, r, r, paint);

        //Use Clear as PorterDuffXfermode to draw a blue rectangle
        paint.SetXfermode(new PorterDuffXfermode(PorterDuff.Mode.Clear));

        paint.Color = Color.Blue;
        canvas.DrawRect(r, r, r * 2.7f, r * 2.7f, paint);

        paint.SetXfermode(null);
        this.SetLayerType(LayerType.Software, null);

        //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
        //I found that PorterDuff.Mode.Clear doesn't work with hardware acceleration, so you have add this code
  }
效果:

让我们分析一下它的过程:

  • 首先,我们调用
    canvas.DrawARGB(255139197186)
    方法将整个
    canvas
    绘制为单一颜色,每个像素都是不透明的

  • 其次,我们调用
    canvas.DrawCircle(r,r,r,paint)
    方法来绘制黄色 在
    画布中画圆圈

  • 第三,执行
    paint.SetXfermode(new PorterDuffXfermode(PorterDuff.Mode.Clear))
    ,将paint
    PorterDuff
    模型设置为
    Clear

  • 第四,调用canvas.DrawRect(r,r,r*2.7f,r*2.7f,paint)
绘制一个蓝色矩形,最后显示一个白色矩形

为什么会显示白色矩形?通常,当我们调用
canvas.DrawXXX()
方法时,我们将传递一个
Paint
参数,当Android执行draw方法时,它将检查Paint是否具有
Xfermode
模式。如果没有,则图形将直接覆盖位于相同位置的
画布中的像素。否则,它将根据
Xfermode
模式更新
Canvas
中的像素

在我的示例中,当执行
canvas.DrawCirlce()
方法时,
Paint
没有
Xfermode
模型,因此黄色圆圈直接覆盖
canvas
中的像素。但是当我们调用
canvas.DrawRect()
来绘制矩形时,
Paint
有一个
Xfermode
PorterDuff.Mode.Clear
然后Android将在内存中绘制一个矩形,该矩形中的像素有一个名称:Source内存中的矩形在
画布中有一个对应的矩形,对应的矩形称为:
目的地。

 protected override void OnDraw(Canvas canvas)
    {
        base.OnDraw(canvas);

        Paint paint = new Paint();

        //Set the background color
        canvas.DrawARGB(255, 139, 197, 186);

        int canvasWidth = canvas.Width;
        int r = canvasWidth / 3;

        //Draw a yellow circle
        paint.Color = Color.Yellow;
        canvas.DrawCircle(r, r, r, paint);

        //Use Clear as PorterDuffXfermode to draw a blue rectangle
        paint.SetXfermode(new PorterDuffXfermode(PorterDuff.Mode.Clear));

        paint.Color = Color.Blue;
        canvas.DrawRect(r, r, r * 2.7f, r * 2.7f, paint);

        paint.SetXfermode(null);
        this.SetLayerType(LayerType.Software, null);

        //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
        //I found that PorterDuff.Mode.Clear doesn't work with hardware acceleration, so you have add this code
  }
源像素的
ARGB
值和目标像素的
ARGB
值根据
Xfermode
定义的规则计算,它将计算最终的ARGB值。然后用最终的
ARGB
值更新目标像素的
ARGB

在我的示例中,
Xfermode
PorterDuff.Mode.Clear
,它要求目标像素
ARGB
变成
(0,0,0)
,这意味着它是透明的。因此,我们使用
canvas.DrawRect()
方法在
canvas
中绘制一个透明的矩形,因为
Activity
本身有一个白色的背景色,所以它将显示一个白色的rec