首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Android画布PorterDuff没有正确掩蔽

Android画布PorterDuff没有正确掩蔽
EN

Stack Overflow用户
提问于 2021-09-07 16:17:51
回答 1查看 340关注 0票数 2

我想做的是

我正在尝试实现一个可以被屏蔽的视图。假设用户有这样的图像:

它被这样的自定义形状所掩盖:

由此产生的图像应该只让鞋擦通过,并使背景透明。

实现

我曾试图以这样的方式实施:

transparent

  • Override
  1. 使掩码中的所有黑色像素都成为视图的draw函数,使用DST_INxfermode (PorterDuffXfermode)在原始图像上绘制掩码。(见Android docs for PorterDuff.Mode)

它工作得非常好,给了我这个图像(绿色像素表示透明):

虽然这很好,但我无法实现一个自定义的“绘图”功能,让用户绘制或擦除掩码。我只成功地做了一个或另一个,但不是同时做。这就是我现在所取得的成就:

请注意,擦除掩码的效果与预期相同,但试图扩展掩码并不有效,而是绘制白色像素(而不是让原始图像(鞋)擦过)。

这是我现在使用的代码:

代码语言:javascript
复制
  override fun draw(baseCanvas: Canvas) {
    super.draw(baseCanvas)

    val image = imageBitmap
    val mask = maskBitmap
    val drawingBitmap = drawingBitmap

    if (image != null && mask != null && drawingBitmap != null) {
      run {
        val canvas = Canvas(drawingBitmap)

        // 1. Fill with white
        canvas.drawColor(Color.WHITE)

        // 2. Draw mask and only let non-transparent pixels through
        val paint = Paint(Paint.ANTI_ALIAS_FLAG)
        paint.xfermode = PorterDuffXfermode(PorterDuff.Mode.DST_IN)
        canvas.drawBitmap(mask, 0f, 0f, paint)

        // 3. Draw all lines point to point with white color and custom xfermode
        paint.xfermode = null
        paint.style = Paint.Style.STROKE
        paint.color = Color.WHITE
        paint.strokeWidth = penSize
        paint.isDither = true
        paint.strokeJoin = Paint.Join.ROUND
        paint.strokeCap = Paint.Cap.ROUND
        paint.pathEffect = CornerPathEffect(10f)
        paint.isAntiAlias = true

        lines.forEach { line ->
          paint.xfermode = when (line.drawMode) {
            DrawMode.ERASE -> PorterDuffXfermode(PorterDuff.Mode.DST_OUT)
            DrawMode.DRAW -> PorterDuffXfermode(PorterDuff.Mode.SRC)
          }

          val path = Path().also { path ->
            val points = line.points
            val range = points.size - 1
            for (i in 1..range) {
              path.moveTo(points[i - 1].x, points[i - 1].y)
              path.lineTo(points[i].x, points[i].y)
            }
          }
          canvas.drawPath(path, paint)
        }
      }

      run {
        val canvas = Canvas(image)
        val paint = Paint(Paint.ANTI_ALIAS_FLAG)

        paint.xfermode = PorterDuffXfermode(PorterDuff.Mode.DST_ATOP)
        canvas.drawBitmap(drawingBitmap, 0f, 0f, paint)
      }
    }
  }

范围内的重要变量:

  • imageBitmap:bitmap
  • maskBitmap:--该位图包含白色以使原始形状发光,对于应该是transparent
  • drawingBitmap:的所有内容都是透明的--一个与imageBitmap大小相同的空位图,我只使用它绘制,然后将结果绘制到imageBitmap上(使用画布,请参见第二个run block)
  • lines:,即我想要绘制的线条)。一条线由drawMode (绘制或擦除)和我跟踪的所有点的列表组成。

奇怪的观察

现在让我困惑的是,当我在添加图像之前填充画布时:

代码语言:javascript
复制
      run {
        val canvas = Canvas(image)
        canvas.drawColor(Color.BLACK) // <-- ADD THIS HERE

        val paint = Paint(Paint.ANTI_ALIAS_FLAG)

        paint.xfermode = PorterDuffXfermode(PorterDuff.Mode.DST_ATOP)
        canvas.drawBitmap(drawingBitmap, 0f, 0f, paint)
      }

看上去很正常:

同样的结果,如果我填充画布红色,它让红色的颜色发光,而不是黑色。为什么它适用于颜色,而不是原始位图?

如果在调试器中检查,它甚至看起来是正确的:

问题

这里有人知道为什么这不像我期望的那样起作用吗?我试着玩各种不同的PorterDuff模式,但没能使它顺利地工作。

任何帮助都很感激!

EN

回答 1

Stack Overflow用户

发布于 2021-09-08 09:27:26

好吧我让它起作用了。我不确定是否有更有效的方法来实现这一点,但我就是这样做的:

imageDrawingBitmap.

  • Set

  • 为上面代码片段中的实际ImageView

  • As创建第四个名为imageDrawingBitmapBitmap,首先绘制掩码,然后在
  1. 之上创建路径,然后为画布中的
  2. 绘制掩码中的imageDrawingBitmap
  3. Draw原始图像创建画布(maskDrawingBitmap来自步骤3)。在画布上用PorterDuff PorterDuff

看来效果不错。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/69091574

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档