最近終於有時間去看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#blending
kScreen_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。