【重讀iOS】CoreGraphics&Quartz 2D

兩者關(guān)系

The Quartz 2D API defines a variety of opaque data types in addition to graphics contexts. Because the API is part of the Core Graphics framework, the data types and the routines that operate on them use the CG prefix.

從這段話理解,Quartz 2D只是一套API,CoreGraphic建立了一套圖形繪制的體系。CoreGraphic中那些提供圖形繪制功能的API,開放出來集合成了Quartz 2D

圖形繪制目標(biāo)

核心為The Graphics Context,即CGContextRef。

A graphics context is an opaque data type (CGContextRef) that encapsulates the information Quartz uses to draw images to an output device

graphics context并不是繪制的輸出目標(biāo),但是它包含了繪制和輸出所需的所有數(shù)據(jù),是一個(gè)封裝。針對(duì)不同的輸出,有不同的context封裝,所以一定程度,可以把context理解為輸出目標(biāo)。或者說對(duì)于輸出目標(biāo),開發(fā)者也只能接觸到context這個(gè)級(jí)別了。

總之context包含了繪制所有的參數(shù),這也正是context這類角色的作用,只需要向context里輸入繪制要求就可以了,剩余的它來處理。

就這6種輸出目標(biāo):

繪制目標(biāo)

PDF跟打印機(jī)沒什么可說的,bitmap就是生成一個(gè)位圖,window就是窗口,iOS里就是view,這里的Layer不是跟view一起的CALayer,而是CGLayer。CGLayer作用就是單圖形的復(fù)用,替代原本用圖片做的事,要更高效些。

所以內(nèi)容就清晰的分為了兩大部分: 1. 針對(duì)繪制目標(biāo)的特殊處理,bigmap CGLayer 2. 繪制指令,path color shadow等

繪制指令

1. 路徑path

路徑是什么?理解這個(gè)首先要理解Quartz 2D的繪制模式:

  • 畫線條,圖形有了
  • 線條構(gòu)成封閉的圖形,填充顏色,有了色塊
  • 多層圖形時(shí)上面的會(huì)覆蓋下面的,產(chǎn)生混合效果,上下順序影響最后結(jié)果。

所以圖形根本是線條,這個(gè)線條就是路徑。

繪制路徑的手段有:

  • 點(diǎn)+連線

CGContextMoveToPoint CGContextAddLineToPoint搞定所有只有直線的圖形

  • 圓弧

CGContextAddArcToPoint
這個(gè)就是指定圓心、半徑、開始角度、結(jié)束角度,很好理解

CGContextAddArc
這個(gè)畫圓弧的邏輯是:當(dāng)前點(diǎn)+這個(gè)方法里的兩個(gè)點(diǎn),3個(gè)點(diǎn)構(gòu)成一個(gè)夾角,然后畫一個(gè)圓弧和這兩條線都相切。這個(gè)方法在畫圓角矩形的時(shí)候很好用,因?yàn)閳A弧結(jié)束后還會(huì)把直線部分也一起畫出來。

  • 曲線

雙控制點(diǎn):CGContextAddCurveToPoint

cubic_bezier_curve.gif

單控制點(diǎn):CGContextAddQuadCurveToPoint

quadratic_bezier_curve.gif

然后是方便的添加矩形、橢圓。變化性最大的就是貝塞爾曲線了,可以模擬很多情況。

路線繪制好后還可以設(shè)置樣式:

  • 顏色,常用屬性之1
  • 寬度,常用屬性之2
  • 不常用的還有虛線、線邊緣樣式(lineCap)、兩線連接處樣式(lineJoin)
2. 特殊處理
  • 混合模式setBlendMode

graphics context的混合模式,并不是指view和其他view,或layer之間的混合,而是一次繪制過程中,對(duì)某個(gè)點(diǎn)的多次上色之前的混合。就像繪畫時(shí),在鼻子上畫了黃色,然后加點(diǎn)白色表現(xiàn)高光。

  • 路線剪切
currentCtx.addRect(CGRect(x: 40, y: 40, width: 100, height: 100))
currentCtx.clip()

之后的繪制只會(huì)在被切出來的那個(gè)區(qū)域,其他區(qū)域繪制無效。

3 transform

trasnform是對(duì)繪制的坐標(biāo)進(jìn)行了轉(zhuǎn)換,前面都是說如何繪制出一個(gè)圖,有了完整的圖形后,可以用trasnform來對(duì)它進(jìn)行整體的轉(zhuǎn)換:移動(dòng)、旋轉(zhuǎn)、縮放以及這3個(gè)的疊加效果。

  • 繪制圖形之前應(yīng)用的transform才有用,如drawImage,addRect
  • CGContextConcatCTM來給context加入transform
  • 背后的原理:
    • 公式:[圖片上傳失敗...(image-cee73b-1534563448369)]
    • 移動(dòng)矩陣:[圖片上傳失敗...(image-f769f8-1534563448369)]
    • 縮放矩陣:[圖片上傳失敗...(image-c4db7e-1534563448369)]

位圖構(gòu)建

位圖是什么?

A bitmap image (or sampled image) is an array of pixels (or samples). Each pixel represents a single point in the image

一個(gè)位圖就是一個(gè)像素?cái)?shù)組,每個(gè)像素表示圖片里的一個(gè)點(diǎn)。顯示器上的圖像都是一個(gè)個(gè)像素構(gòu)成的,每個(gè)像素有自己的顏色,如果建一個(gè)表,把顯示器上的每個(gè)像素的顏色都記錄到表里,這個(gè)表數(shù)組就是一個(gè)位圖bitmap。常用的JPEG PNG都是位圖,當(dāng)然這些圖片都是壓縮過得,內(nèi)存和像素顏色不是一一對(duì)應(yīng)的,但現(xiàn)實(shí)到屏幕之前一定會(huì)做解壓。

有位圖,就有對(duì)應(yīng)的矢量圖,它是由一系列計(jì)算機(jī)指令來描述和記錄一幅圖,顯示之前再從這些指令從新把圖繪制出來。

用一個(gè)圓來做例子,位圖就是一張圖,記錄了每個(gè)位置的像素,跟其他的圖沒有不同。而矢量圖可能就是一個(gè)命令:circle(radius:5,center:(20,20),color:...)

矢量圖可能就要依賴于系統(tǒng)對(duì)指令的解析,而且繪制也需要消耗性能,但存儲(chǔ)和傳輸更方便,而且一個(gè)很大的好處是可以應(yīng)對(duì)不同的分辨率。

回到Quartz 2D,bitmap的context的作用就是把繪制的截圖輸出到一張圖片里,常見的應(yīng)用就是屏幕截圖了。

核心方法:

  • CGImageCreate直接從純數(shù)據(jù)構(gòu)建,指定所有格式
  • CGBitmapContextCreateImage從當(dāng)前的位圖上下文里構(gòu)建圖片,配合CGContextDrawImage把圖繪制進(jìn)去,內(nèi)部把圖片解壓
  • CGImageCreateWithImageInRect從已有圖截取一部分
  • CGImageCreateWithPNGDataProviderCGImageCreateWithJPEGDataProvider從圖片文件構(gòu)建,配合CGDataProviderCopyData,內(nèi)部把圖片解壓

mask

mask在對(duì)個(gè)地方可以見到:這里的mask,CALayer里的mask,就是圓角的那個(gè),哈希表里也有mask。總的來說就就是使用一種規(guī)則屏蔽掉某些數(shù)據(jù),圖像之間處理的mask,像這里,一般是根據(jù)alpha數(shù)據(jù)來的。alpha>0的地方圖像顯示,alpha==0的地方圖像屏蔽。

  • CGImageCreateWithMask使用一個(gè)mask來處理原圖,跟文檔里說的并不同,mask原圖的alpha是1的地方才是顯示出來的地方,公式應(yīng)該是a*s+(1-a)*m,a是mask的原圖的alpha,s是要顯示的圖片,m是mask原圖。
  • mask是用CGImageMaskCreate構(gòu)建的特殊圖片,應(yīng)該只包含灰度信息
  • 不使用專門的mask方法,也可以使用圖片之間構(gòu)建的mask,但是需要顏色空間為灰度。
  • 使用顏色剔除,CGImageCreateWithMaskingColors,傳入一個(gè)數(shù)組,依次表示每個(gè)元素的最小值和最大值,在這個(gè)范圍內(nèi)的顏色都被剔除,不顯示。

CGLayer

CAlayer是負(fù)責(zé)view的內(nèi)容顯示的,而CGLayer和它完全不同,它并不做顯示,而是存儲(chǔ)。構(gòu)造一個(gè)樣式,比如自己繪制一個(gè)小星星,然后要重用這個(gè)小星星,兩個(gè)方案:1. 使用bitmap,即把繪制的小星星變成一張圖,想怎么用都可以。 2.使用CGLayer保存繪制結(jié)果。

可以理解CGLayer為對(duì)一個(gè)圖形的引用、保存,可以在需要的地方繪制出來,可以看成是一種特殊的圖片,消耗更小、更高效復(fù)用的圖片。

除了重復(fù)繪制,高性能離屏渲染(High-quality offscreen),緩沖數(shù)據(jù)(Buffering)時(shí)也可以使用。Buffering的場(chǎng)景不是很清楚,但High-quality offscreen可以用于復(fù)雜圖形的副線程繪制,在副線程把復(fù)雜圖形繪制出來,然后存儲(chǔ)在CGLayer里,在顯示的時(shí)候直接顯示,略去繪制過程的性能影響。

核心方法:

  • 構(gòu)建CGLayerCreateWithContext
  • 獲取它的contextCGLayerGetContext
  • 有了context,就可以在這個(gè)context里使用Quartz 2D的API繪制任意的內(nèi)容
  • 使用CGContextDrawLayerAtPoint,把這個(gè)CGLayer繪制到另一個(gè)Graphic Context里,這個(gè)Graphic Context才是真正顯示的那個(gè)。就像把一張貼紙貼到一張大圖畫上。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容

  • 在農(nóng)村 鄰居基本都認(rèn)識(shí)幾十年了 知根知底,熟得不能再熟 人一旦熟起來 總是要聊天的 也沒有那么多新鮮事 所以聊天八...
    吃瓜娃娃瞎扯淡閱讀 232評(píng)論 0 0
  • 最近寫了一篇2016年成就事件,不經(jīng)意間收獲了許多鮮花和掌聲,不自覺的就飄起來了,更加奮力的去追求數(shù)字帶來的快感,...
    1蘇蘇閱讀 249評(píng)論 1 2
  • 白居易于千年前看到蘇家小女簡(jiǎn)簡(jiǎn),輕輕淺淺的一句“大都好物不堅(jiān)牢,彩云易散琉璃脆”道出了多少世事變遷的心酸。千年后,...
    棲墨閱讀 928評(píng)論 6 10
  • 《乖,摸摸頭》記錄了12個(gè)感人的故事。真實(shí)的故事流露出真摯的感情,也流露出作者大冰對(duì)朋友的思念。我覺得大冰是個(gè)很了...
    此之木閱讀 1,126評(píng)論 2 2