我想更好地了解Android(2D)Canvas绘图管道的组件如何组合在一起。
例如,XferMode,Shader,MaskFilter和ColorFilter如何互动?这些类的参考文档相当稀疏,Canvas和Paint的文档并没有真正添加任何有用的解释。
我也不完全清楚具有内在颜色的绘制操作(例如:drawBitmap
与“{1}}”之类的“矢量”原语是否适合所有这些 - 他们是否总是忽略drawRect
的颜色和用途会改用它们的内在颜色吗?
我也很惊讶,人们可以这样做:
Paint
这会擦掉椭圆形。在我注意到这一点之前,我的心理模型是绘制到画布(概念上)绘制到单独的“图层”,然后使用Paint的传输模式使用Canvas的位图组合该图层。如果它那么简单,则上面的代码将擦除整个位图(在剪切区域内),因为CLEAR 总是将颜色(和alpha)设置为0,而不管源的alpha是什么。所以这意味着还有一种额外的掩蔽方法可以将擦除限制在椭圆形上。
我确实找到了API demos,但每个演示都是“在真空中”,并没有显示它所关注的东西(例如:XferModes)如何与其他东西(例如:ColorFilters)交互。
有了足够的时间和精力,我可以凭经验弄清楚这些部分是如何相关或破译来源的,但我希望其他人已经解决了这个问题,或者更好的是,还有一些管道/绘图的实际文档 - 我错过的模特。
这个问题的灵感来自于this answer to another SO question中的代码。
在寻找一些文档的同时,我想到,因为我感兴趣的东西似乎是skia之上的一个非常薄的贴面,也许有一些skia文档会有所帮助。我能找到的最好的东西是the documentation for SkPaint
,其中说:
有6种类型的效果可以 被分配到油漆:
- SkPathEffect - 在生成几何体之前对几何体(路径)的修改 alpha遮罩(例如潇洒)
- SkRasterizer - 组成自定义遮罩层(例如阴影)
- SkMaskFilter - 在着色之前修改alpha蒙版 绘制(例如模糊,浮雕)
- SkShader - 例如渐变(线性,径向,扫描),位图图案 (夹,重复,镜子)
- SkColorFilter - 在应用xfermode之前修改源颜色 (例如,颜色矩阵)
- SkXfermode - 例如porter-duff transfermodes,混合模式
没有明确说明,但我猜这里效果的顺序是它们在管道中出现的顺序。
答案 0 :(得分:48)
就像Romain Guy说的那样,“这个问题很难在StackOverflow上回答”。没有任何完整的文档,完整的文档将包含在这里。
我最后通过源阅读并进行了一系列实验。我一路上做了笔记,最后把它们变成了一个你可以在这里看到的文件:
以及此图表:
显然,它是“非官方的”,所以正常的警告适用。基于以上所述,以下是一些“子问题”的答案:
我也不完全清楚如何 绘制具有内在的操作 颜色(例如:
drawBitmap
,而不是 像drawRect
这样的“矢量”原语 适合所有这一切 - 他们总是这样做 忽略Paint
的颜色并使用 他们的内在颜色呢?
“源颜色”来自Shader
。如果使用非drawBitmap
Shader
,则BitmapShader
ALPHA_8
暂时被Bitmap
替换。在其他情况下,如果未指定Shader
只生成纯色的Shader
,则使用Paint
的颜色。
我也对这个事实感到惊讶 人们可以这样做:
Paint eraser = new Paint(); eraser.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR)); canvas.drawOval(rectF, eraser);
这会擦掉椭圆形。在我注意到之前 我的心理模型就是画画 画布(概念上)画到一个 分开“图层”然后分层 由Canvas的Bitmap组成 使用Paint的传输模式。如果它 就像上面那样简单 代码将擦除整个位图 (在裁剪区域内)为CLEAR 无论源的alpha是什么,总是将颜色(和alpha)设置为0。所以 这意味着有一个 进一步的掩蔽 将擦除限制在椭圆形。
XferMode
适用于“源颜色”(来自Shader
)和“目标颜色”(来自Canvas
的{{1}})。然后使用在光栅化中计算的掩码将结果与目标混合。有关详细信息,请参阅上述文档中的转移阶段。
答案 1 :(得分:11)
这个问题很难在StackOverflow上回答。然而,在我开始之前,请注意形状(例如drawRect())没有内在颜色。颜色信息始终来自Paint对象。
这会擦掉椭圆形。在我注意到之前 我的心理模型就是画画 画布(概念上)画到一个 分开“图层”然后分层 由Canvas的Bitmap组成 使用Paint的传输模式。如果它 就像上面那样简单 代码将擦除整个位图 (在裁剪区域内)为CLEAR 始终将颜色(和alpha)设置为0 不管来源的alpha。所以 这意味着有一个 进一步的掩蔽 将擦除限制在椭圆形。
你的模特有点偏。椭圆不会绘制到单独的图层中(除非您调用Canvas.saveLayer()),它将直接绘制到Canvas的支持位图上。 Paint的传输模式应用于基元绘制的每个像素。在这种情况下,只有椭圆光栅化的结果会影响位图。没有特殊的遮蔽,椭圆本身是掩模。
无论如何,这是管道的简化视图:
(我刚看到你的更新,是的,你发现的内容按顺序描述了管道的各个阶段。)
当使用图层(Canvas.saveLayer())时,管道变得更加复杂,因为管道加倍。您首先浏览管道以在屏幕外位图(图层)内渲染图元,然后通过管道将屏幕外位图应用于画布。
答案 2 :(得分:0)
SkPathEffect - 在生成alpha蒙版(例如,破折号)之前对几何体(路径)的修改 SkRasterizer - 组成自定义遮罩层(例如阴影) SkMaskFilter - 在对alpha蒙版进行着色和绘制之前对其进行修改(例如模糊) SkShader - 例如渐变(线性,径向,扫描),位图图案(钳位,重复,镜像) SkColorFilter - 在应用xfermode之前修改源颜色(例如颜色矩阵) SkXfermode - 例如porter-duff transfermodes,混合模式