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

时间:2011-04-23 06:46:24

标签: android skia android-canvas

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

例如,XferModeShaderMaskFilterColorFilter如何互动?这些类的参考文档相当稀疏,CanvasPaint的文档并没有真正添加任何有用的解释。

我也不完全清楚具有内在颜色的绘制操作(例如: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,混合模式
  •   

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

3 个答案:

答案 0 :(得分:48)

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

我最后通过源阅读并进行了一系列实验。我一路上做了笔记,最后把它们变成了一个你可以在这里看到的文件:

以及此图表:

enter image description here

显然,它是“非官方的”,所以正常的警告适用。

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

  

我也不完全清楚如何   绘制具有内在的操作   颜色(例如: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的传输模式应用于基元绘制的每个像素。在这种情况下,只有椭圆光栅化的结果会影响位图。没有特殊的遮蔽,椭圆本身掩模。

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

  1. 原始(矩形,椭圆形,路径等)
  2. PathEffect
  3. 光栅化
  4. MaskFilter
  5. 颜色/着色器/ ColorFilter
  6. Xfermode
  7. (我刚看到你的更新,是的,你发现的内容按顺序描述了管道的各个阶段。)

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

答案 2 :(得分:0)

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

http://imgur.com/0X5Yqod