在 Canvas 上绘制图片时应用不透明度(或绘画)

Applying an opacity (or Paint) when drawing a Picture onto a Canvas

作为 Sharp(Android 的可缩放矢量图形)的作者之一,我正在尝试找到一种应用组不透明度的有效方法。

假设我们有以下 SVG:


源 SVG:group_transparency.svg

SVG 中的简化片段:

<svg ...>
  <g ...>
    <path ...
       style="stroke:#ffcc00;stroke-width:20;" />
    <circle ...
       style="fill:#00cc00;opacity:0.5;" />
    <circle ...
       style="fill:#cc0000;opacity:0.5;" />
    <g ...
       style="opacity:0.5">
      <circle ...
         style="fill:#00cc00;" />
      <circle ...
         style="fill:#cc0000;" />
    </g>
  </g>
</svg>

注意两对圆圈之间的差异:顶部的一对圆圈各有一半的不透明度,这导致了红色和绿色的混合。底部对具有完全不透明度,但包含它们的组最终以半不透明度绘制,因此没有绿色和红色的混合。

我的第一个方法是跟踪一堆图片,在遇到组结束标记时绘制它们:

SvgGroup g = mGroupStack.pop();
mCanvas = g.canvas;
Picture p = g.picture;
p.endRecording();
mCanvas.drawPicture(p);

SvgGroup 是一个简单的 class:

private class SvgGroup {

    private Picture picture;
    private Canvas canvas;
    private float opacity;

}

这里的直接问题是在将图片绘制到 Canvas 上时我无法应用不透明度,因为我无法提供 Paint 作为 Canvas.drawPicture() 的参数。

我发现以正确的不透明度绘制组的唯一方法是先将图片绘制到位图中:

Bitmap b = Bitmap.createBitmap(p.getWidth(), p.getHeight(), Bitmap.Config.ARGB_8888);
Canvas c = new Canvas(b);
p.draw(c);
Paint paint = new Paint();
paint.setAlpha((int) (255 * g.opacity));
mCanvas.drawBitmap(b, 0, 0, paint);

虽然这可行,但使用图片的好处会因为栅格化而丧失。放大说明了每种方法的问题(左:绘制图片;右:绘制位图):

很明显——从这个项目的名字来看——这不是我想要的!有没有什么方法可以保留使用图片的明显好处,同时能够对其整体应用不透明度?

这就是我要使用的:Canvas#saveLayer() or Canvas#saveLayerAlpha()

对于前者,您可以将 Paint 参数与 setAlpha() 一起使用(但我不能 100% 确定它是否有效),对于后者,使用起来应该更容易和更安全:

The alpha parameter is applied when the offscreen bitmap is drawn back when restore() is called.