本文主要是介绍skia draw,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
最近终于有时间去看skia draw的一些过程,参考skia/gm和skia/samplecode里面的示例非常粗略的总结了一下skia的绘制过程,只能说建立一个概览吧。希望有熟悉skia的大神在不对之处可以帮忙指点。
skia的每次绘制都是由canvas.drawXX方法发起,经过path generation、rasterizer、shading和transfer四个步骤完成一张图的绘制。
Path generation
enum Style {kFill_Style, //!< fill the geometry填充kStroke_Style, //!< stroke the geometry绘制轮廓kStrokeAndFill_Style, //!< fill and stroke the geometry};
Rasterizer
生成path之后的工作就是要去rasterizer。skia中的rasterizer主要是确定像素要画在哪,这通过使用一个mask图像来完成。mask图像实际上是一个只有alpha通道的灰度图。mask图像可以决定每个像素是全透明、不透明还是部分透明。
可以使用两个方法生成mask:
(1)no rasterizer
使用paint style property和path property进行path扫描转换,产生一个初始的mask。在path内部的像素是不透明的,path外部的像素保持透明,在path边界上的像素部分透明(如果设置anti-aliasing抗锯齿)。
如果设置了maskFilter,初始的mask会根据它进行变换,比如blur、emboss、table等效果。设置步骤为:首先使用SkPaint方法setMaskFilter()为paint分配一个SkMaskFilter;然后具体的mask过滤由SkMaskFilter子类实现。
对于blur效果,可以参考sampleBlur.cpp。
emboss效果,可以参考sampleEmboss.cpp。
(2)rasterizer
由SkRasterizer创建一个mask。
首先使用SkPaint的方法setRasterizer()为paint设置一个SkRasterizer;然后SkRasterizer的rasterize()方法会创建一个mask bitmap,之后把path绘制到这个mask中。
Shading
rasterizer之后就需要进行shading。shading的主要工作是确定像素的颜色,即着色。skia主要支持四种shader:线性梯度shader、环形梯度shader、扫略梯度shader以及混合shader。混合shader用来处理使用两种相同或者不同的shader在xfermode下的混合着色。这部分可以参考sampleShader.cpp例子。
着色过程有两个阶段:第一个阶段是为SkPaint分配一个SkShader,同样也是使用SkPaint的setShader方法。SkShader会生成一个初始的源图像。
在创建shader时,需要指定平铺模式(TileMode),有三种:kClamp_TileMode、kRepeat_TileMode和kMirror_TileMode,分别对应普通平铺、重复平铺和镜像平铺。镜像平铺很好理解,对于普通平铺,如果shader超出着色边界,则会使用边界的颜色延伸到bitmap边界;对于重复平铺,如果shader超出着色边界,则会在边界处重复之前的着色。
如果在这个阶段没有设置SkShader,则需要给paint设置一个color,此时会产生一张单色图像。
第二个阶段:如果为Skpaint设置了colorFilter,则colorFilter会为初始源图像的颜色进行变换。maskFilter与colorFilter不同:maskFilter是对一个paint的alpha通道的转换;而colorFilter是针对RGB通道的转换。所有由colorFilter所派生的类在执行它们的转换时都会忽略alpha通道。
(1)colorFilter可以通过改变colorMatrix进行色彩变换(C1=pin(C*Cm+Ca))。
a ,b ,c, d, e,
f ,g ,h ,i , j,
k ,l, m, n, o,
p ,q ,r ,s ,t
(2)colorFilter也可以通过处理各种XforMode(图像混合模式)来针对dst/src图像进行色彩处理。
这部分的例子可以参考sampleColorFilters.cpp。
Transfer
<pre name="code" class="cpp"><pre name="code" class="cpp"><span style="font-family:Microsoft YaHei;">/* Sa 代表source alpha ,即源 alpha 值 ,
Da 代表 Destination alpha ,即 目标alpha值 ,
Sc 代表 source color ,即源色值 ,
Dc 代表 Destination color ,即目标色值,并且这所有的计算都以像素为单位.
[a, c]代表在某一种混合模式下,对每一个像素的alpha 和 color 通过对应算法进行运算,所得出的像素值*/
enum Mode {kClear_Mode, //!< [0, 0]清除模式[0,0],即最终所有点的像素的alpha 和color 都为 0,所以画出来的效果只有白色背景kSrc_Mode, //!< [Sa, Sc]只保留源图像的 alpha 和 color ,所以绘制出来只有源图kDst_Mode, //!< [Da, Dc]同上类比,只保留目标图像的 alpha 和 color,所以绘制出来的只有目标图kSrcOver_Mode, //!< [Sa + Da - Sa*Da, Rc = Sc + (1 - Sa)*Dc]在目标图片顶部绘制源图像,从命名上也可以看出来就是把源//图像绘制在上方kDstOver_Mode, //!< [Sa + Da - Sa*Da, Rc = Dc + (1 - Da)*Sc]将目标图像绘制在上方kSrcIn_Mode, //!< [Sa * Da, Sc * Da]在两者相交的地方绘制源图像,并且绘制的效果会受到目标图像对应地方透明度的影响kDstIn_Mode, //!< [Sa * Da, Sa * Dc]在两者相交的地方绘制目标图像,并且绘制的效果会受到源图像对应地方透明度的影响kSrcOut_Mode, //!< [Sa * (1 - Da), Sc * (1 - Da)]在不相交的地方绘制源图像,相交处根据目标alpha进行过滤,目标色完全//不透明时则完全过滤,完全透明则不过滤kDstOut_Mode, //!< [Da * (1 - Sa), Dc * (1 - Sa)]类似上面kSrcATop_Mode, //!< [Da, Sc * Da + (1 - Sa) * Dc]源图像和目标图像相交处绘制源图像,不相交的地方绘制目标图像,并且相//交处的效果会受到源图像和目标图像alpha的影响kDstATop_Mode, //!< [Sa, Sa * Dc + Sc * (1 - Da)]类似上面kXor_Mode, //!< [Sa + Da - 2 * Sa * Da, Sc * (1 - Da) + (1 - Sa) * Dc]在不相交的地方按原样绘制源图像和目标图像,//相交的地方受到对应alpha和色值影响,按上面公式进行计算,如果都完全不透明则相交处完全不绘制kPlus_Mode, //!< [Sa + Da, Sc + Dc]kModulate_Mode, // multiplies all components (= alpha and color)// Following blend modes are defined in the CSS Compositing standard:// https://dvcs.w3.org/hg/FXTF/rawfile/tip/compositing/index.html#blendingkScreen_Mode, //滤色,滤色模式与我们所用的显示屏原理相同,所以也有版本把它翻译成“屏幕”;简单的说就是保留两个图层中较//白的部分,较暗的部分被遮盖;当一层使用了滤色(屏幕)模式时,图层中纯黑的部分变成完全透明,纯白部分完全//不透明,其他的颜色根据颜色级别产生半透明的效果kLastCoeffMode = kScreen_Mode,kOverlay_Mode, //像素是进行 Multiply (正片叠底)混合还是 Screen (屏幕)混合,取决于底层颜色,但底层颜色的高光与阴影部//分的亮度细节会被保留kDarken_Mode, //该模式处理过后,会感觉效果变暗,即进行对应像素的比较,取较暗值,如果色值相同则进行混合;从算法上看,//alpha值变大,色值上如果都不透明则取较暗值,非完全不透明情况下使用上面算法进行计算,受到源图和目标图对应//色值和alpha值影响kLighten_Mode, //DARKEN 的目的是变暗,LIGHTEN 的目的则是变亮,如果在均完全不透明的情况下 ,色值取源色值和目标色值中的较大值,//否则按上面算法进行计算kColorDodge_Mode,kColorBurn_Mode,kHardLight_Mode,kSoftLight_Mode,kDifference_Mode,kExclusion_Mode,kMultiply_Mode, //正片叠底,即查看每个通道中的颜色信息,并将基色与混合色复合。结果色总是较暗的颜色。任何颜色与黑色复合产生黑色。//任何颜色与白色复合保持不变。当用黑色或白色以外的颜色绘画时,绘画工具绘制的连续描边产生逐渐变暗的颜色kLastSeparableMode = kMultiply_Mode,kHue_Mode,kSaturation_Mode,kColor_Mode,kLuminosity_Mode,kLastMode = kLuminosity_Mode};</span>
有关XferMode的例子可以参考xfermode.cpp、xfermode2.cpp、xfermode3.cpp、sampleXfermode.cpp。
总结
这篇关于skia draw的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!