Android(2D)Canvas绘图管道的各个部分如何组合在一起?

Lau*_*ves 60 android skia android-canvas

我想更好地了解Android(2D)Canvas绘图管道的组件如何组合在一起.

例如,XferMode,Shader,MaskFilterColorFilter如何交互?这些类的参考文档非常稀疏,CanvasPaint的文档并没有真正添加任何有用的解释.

我也不完全清楚具有内在颜色的绘图操作(例如:drawBitmap与"矢量"原语相比drawRect)是否适合所有这些 - 他们总是忽略Paint颜色并使用其内在颜色吗?

我也很惊讶,人们可以这样做:

Paint eraser = new Paint();
eraser.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
canvas.drawOval(rectF, eraser);
Run Code Online (Sandbox Code Playgroud)

这抹去了椭圆形.在我注意到这一点之前,我的心理模型是绘制到画布(概念上)绘制到单独的"图层",然后使用Paint的传输模式使用Canvas的位图组合该图层.如果它那么简单那么上面的代码将擦除整个位图(在剪辑区域内),因为CLEAR 总是将颜色(和alpha)设置为0,而不管源的alpha是什么.所以这意味着还有一种额外的掩蔽来限制擦除到椭圆形.

我确实找到了API演示,但是每个演示都"在真空中"工作,并没有显示它关注的东西(例如:XferModes)如何与其他东西(例如:ColorFilters)交互.

有了足够的时间和精力,我可以凭经验弄清楚这些部分是如何相关或破译源的,但我希望其他人已经解决了这个问题,或者更好的是,有一些管道/绘图模型的实际文档,我错过了.

这个问题的灵感来自于在另一个SO问题的答案中看到代码.

更新

在寻找一些文档的同时,我想到,由于我在这里感兴趣的东西似乎是一个非常薄的贴面,在skia之上,也许有一些skia文档会有所帮助.我能找到的最好的东西是文件SkPaint说:

可以为paint分配6种效果:

  • SkPathEffect - 在生成alpha蒙版(例如,破折号)之前对几何(路径)的修改
  • SkRasterizer - 组成自定义遮罩层(例如阴影)
  • SkMaskFilter - 在对alpha蒙版进行着色和绘制之前对其进行修改(例如模糊,浮雕)
  • SkShader - 例如渐变(线性,径向,扫描),位图图案(钳位,重复,镜像)
  • SkColorFilter - 在应用xfermode之前修改源颜色(例如颜色矩阵)
  • SkXfermode - 例如porter-duff transfermodes,混合模式

它没有明确说明,但我猜这里效果的顺序是它们在管道中出现的顺序.

Lau*_*ves 48

就像Romain Guy说的那样,"这个问题很难在StackOverflow上回答".没有任何完整的文档,完整的文档将包含在这里很大.

我最后通过源阅读并做了一堆实验.我沿途记笔记,最后把它们变成了一个文件,你可以在这里看到:

以及这个图:

http://xenomachina.com/android-canvas-pipeline.png

显然,这是"非官方的",所以正常的警告适用.

基于以上所述,以下是一些"子问题"的答案:

我也不完全清楚具有内在颜色的绘图操作(例如:drawBitmap与"矢量"原语相比drawRect)是否适合所有这些 - 他们总是忽略Paint颜色并使用其内在颜色吗?

"源色"来自于Shader.在drawBitmapShader暂时被一取代BitmapShader,如果非ALPHA_8 Bitmap使用.在其他情况下,如果没有Shader指定a Shader只生成纯色Paint,则使用颜色.

我也很惊讶,人们可以这样做:

Paint eraser = new Paint();
eraser.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
canvas.drawOval(rectF, eraser);
Run Code Online (Sandbox Code Playgroud)

这抹去了椭圆形.在我注意到这一点之前,我的心理模型是绘制到画布(概念上)绘制到单独的"图层",然后使用Paint的传输模式使用Canvas的位图组合该图层.如果它那么简单那么上面的代码将擦除整个位图(在剪辑区域内),因为CLEAR 总是将颜色(和alpha)设置为0,而不管源的alpha是什么.所以这意味着还有一种额外的掩蔽来限制擦除到椭圆形.

所述XferMode适用于"源色彩"(从Shader)和"目的地颜色"(来自CanvasBitmap).然后使用在光栅化中计算的掩码将结果与目标混合.有关详细信息,请参阅上述文档中的"传输"阶段.


Rom*_*Guy 11

StackOverflow上很难回答这个问题.然而,在我开始之前,请注意形状(例如drawRect())没有内在颜色.颜色信息始终来自Paint对象.

这抹去了椭圆形.在我注意到这一点之前,我的心理模型是绘制到画布(概念上)绘制到单独的"图层",然后使用Paint的传输模式使用Canvas的位图组合该图层.如果它那么简单那么上面的代码将擦除整个位图(在剪辑区域内),因为CLEAR总是将颜色(和alpha)设置为0,而不管源的alpha是什么.所以这意味着还有一种额外的掩蔽来限制擦除到椭圆形.

你的模型有点偏.椭圆不会绘制到单独的图层中(除非您调用Canvas.saveLayer()),它将直接绘制到Canvas的支持位图上.Paint的传输模式应用于基元绘制的每个像素.在这种情况下,只有椭圆光栅化的结果会影响位图.没有特别的遮蔽,椭圆形本身就是面具.

无论如何,这是管道的简化视图:

  1. 原始(矩形,椭圆形,路径等)
  2. PathEffect
  3. 光栅化
  4. MaskFilter
  5. 颜色/着色器/ ColorFilter
  6. Xfermode

(我刚看到你的更新,是的,你发现的内容按顺序描述了管道的各个阶段.)

当使用图层(Canvas.saveLayer())时,管道变得更加复杂,因为管道加倍.您首先浏览管道以在屏幕外位图(图层)内渲染图元,然后通过管道将屏幕外位图应用于画布.