Core Graphics Layer Drawing

CGLayer對象(CGLayerRef數(shù)據(jù)類型)允許應(yīng)用程序使用圖層進行繪制。

圖層適用于以下:

  • 您計劃重復(fù)使用的繪圖的高質(zhì)量屏幕外顯示。例如,您可能正在構(gòu)建場景并計劃重復(fù)使用相同的背景。將背景場景繪制到圖層,然后在需要時繪制圖層。一個額外的好處是,您不需要知道顏色空間或設(shè)備相關(guān)的信息繪制到圖層。
  • 重復(fù)繪圖。例如,您可能想要創(chuàng)建一個由重復(fù)繪制的相同項目組成的模式。將項目繪制到圖層,然后重復(fù)繪制圖層,如圖12-1所示。您反復(fù)繪制的任何Quartz對象(包括CGPath,CGShading和CGPDFPage對象)都可以通過提高性能(如果將其繪制到CGLayer)獲益。注意,圖層不僅僅用于屏幕上的繪制;您可以將其用于不面向屏幕的圖形上下文,例如PDF圖形上下文。
  • 緩沖。雖然你可以使用圖層為此目的,你不應(yīng)該需要,因為石英合成器使你的部分緩沖不必要。如果必須繪制到緩沖區(qū),請使用圖層而不是位圖圖形上下文。
12-1 重復(fù)畫相同的蝴蝶圖像

CGLayer對象和透明層與CGContext函數(shù)創(chuàng)建的CGPath對象和路徑并行。 在CGLayer或CGPath對象的情況下,您繪制到抽象目標(biāo),然后可以繪制完整的繪畫到另一個目的地,如顯示或PDF。 當(dāng)您繪制到透明層或使用繪制路徑的CGContext函數(shù)時,您直接繪制由圖形上下文表示的目標(biāo)。 沒有中間抽象的目的地組裝這幅畫。

圖層繪制如何工作

由CGLayerRef數(shù)據(jù)類型表示的圖層是為實現(xiàn)最佳性能而設(shè)計的。如果可能,Quartz使用適合于與其相關(guān)聯(lián)的Quartz圖形上下文類型的機制緩存CGLayer對象。例如,與視頻卡相關(guān)聯(lián)的圖形上下文可以在視頻卡上緩存該層,這使得繪制層中的內(nèi)容比渲染從位圖圖形上下文構(gòu)造的類似圖像快得多。由于這個原因,一個圖層通常是屏幕外繪制比位圖圖形上下文更好的選擇。

所有Quartz繪圖函數(shù)繪制到一個圖形上下文。圖形上下文提供了目標(biāo)的抽象,使您無需了解目標(biāo)的詳細信息,例如其分辨率。您在用戶空間中工作,Quartz執(zhí)行必要的轉(zhuǎn)換以正確地將圖形渲染到目標(biāo)。當(dāng)您使用CGLayer對象進行繪制時,還會繪制到圖形上下文。圖12-1說明了圖層繪制的必要步驟。

12-2 圖層繪圖

所有圖層繪圖都從一個圖形上下文開始,從中使用函數(shù)CGLayerCreateWithContext創(chuàng)建一個CGLayer對象。用于創(chuàng)建CGLayer對象的圖形上下文通常是窗口圖形上下文。 Quartz創(chuàng)建一個圖層,使其具有圖形上下文的所有特征 - 其分辨率,顏色空間和圖形狀態(tài)設(shè)置。如果不想使用圖形上下文的大小,可以為圖層提供大小。在圖12-2中,左側(cè)顯示了用于創(chuàng)建圖層的圖形上下文。右側(cè)框中的灰色部分,標(biāo)記為CGLayer對象,表示新創(chuàng)建的圖層。

在您可以繪制到圖層之前,必須通過調(diào)用函數(shù)CGLayerGetContext來獲取與圖層相關(guān)聯(lián)的圖形上下文。此圖形上下文與用于創(chuàng)建圖層的圖形上下文具有相同的風(fēng)格。只要用于創(chuàng)建圖層的圖形上下文是一個窗口圖形上下文,那么CGLayer圖形上下文將被緩存到GPU,如果可能的話。圖12-2右側(cè)的框的白色部分表示新創(chuàng)建的層圖形上下文。

您可以繪制到圖層的圖形上下文,就像繪制任何圖形上下文,將圖層的圖形上下文傳遞到繪圖功能。圖12-2顯示了繪制到圖層上下文的葉形。

當(dāng)你準(zhǔn)備好使用圖層的內(nèi)容,你可以調(diào)用函數(shù)CGContextDrawLayerInRect或CGContextDrawLayerAtPoint,將圖層繪制到圖形上下文中。通常,你會繪制到用于創(chuàng)建圖層對象的相同的圖形上下文,但不是必需的。您可以將圖層繪制到任何圖形上下文,請記住,圖層繪圖具有用于創(chuàng)建圖層上下文的特征,這可能會施加某些約束(例如性能或分辨率)。例如,與屏幕相關(guān)聯(lián)的層可以被高速緩存在視頻硬件中。如果目的地上下文是打印或PDF上下文,則可能需要從圖形硬件取回到存儲器,導(dǎo)致差的性能。

圖12-2顯示了圖層的內(nèi)容 - 重復(fù)繪圖到用于創(chuàng)建圖層對象的圖形上下文。在釋放CGLayer對象之前,您可以重復(fù)使用圖層中的繪圖次數(shù)。

小提示:當(dāng)您想要繪制圖形的各個部分以實現(xiàn)像陰影一組對象這樣的效果時,請使用透明度圖層。 (請參閱透明層。)當(dāng)您要繪制屏幕或需要重復(fù)繪制相同的事物時,使用CGLayer對象。

用圖層繪制

您需要執(zhí)行以下部分中描述的任務(wù)以使用CGLayer對象進行繪制:

  1. 創(chuàng)建使用現(xiàn)有圖形上下文初始化的CGLayer對象
  2. 為圖層獲取圖形上下文
  3. 繪制到CGLayer圖形上下文
  4. 將圖層繪制到目標(biāo)圖形上下文

有關(guān)詳細代碼示例,請參閱示例:使用多個CGLayer對象繪制標(biāo)志。

創(chuàng)建使用現(xiàn)有圖形上下文初始化的CGLayer對象

函數(shù)CGLayerCreateWithContext返回使用現(xiàn)有圖形上下文初始化的圖層。 該圖層繼承了圖形上下文的所有特性,包括顏色空間,大小,分辨率和像素格式。 后來,當(dāng)你將圖層繪制到目的地時,Quartz自動將圖層匹配到目標(biāo)上下文。

函數(shù)CGLayerCreateWithContext有三個參數(shù):

  • 從中創(chuàng)建圖層的圖形上下文。 通常,您傳遞一個窗口圖形上下文,以便以后可以在屏幕上繪制圖層。
  • 圖層相對于圖形上下文的大小。 該圖層可以與圖形上下文的大小相同或更小。 如果以后需要檢索圖層大小,可以調(diào)用函數(shù)CGLayerGetSize。
  • 輔助字典。 此參數(shù)當(dāng)前未使用,因此傳遞NULL。

為圖層獲取圖形上下文

Quartz總是繪制一個圖形上下文。 既然你有一個圖層,你必須創(chuàng)建一個與圖層相關(guān)的圖形上下文。 你繪制到圖層上下文中的任何內(nèi)容都是圖層的一部分。

函數(shù)CGLayerGetContext采用一個圖層作為參數(shù),并返回與圖層相關(guān)的圖形上下文。

繪制到CGLayer圖形上下文

獲取與圖層相關(guān)聯(lián)的圖形上下文后,可以對圖層圖形上下文執(zhí)行任何繪圖。 您可以打開PDF文件或圖像文件,并將文件內(nèi)容繪制到圖層。 您可以使用任何Quartz 2D函數(shù)來繪制矩形,線條和其他繪圖圖元。 圖12-3顯示了將矩形和線繪制到圖層的示例。

12-3 包含兩個矩形和一系列線的圖層

例如,要將填充矩形繪制到CGLayer圖形上下文,您可以調(diào)用函數(shù)CGContextFillRect,提供從函數(shù)CGLayerGetContext獲取的圖形上下文。 如果圖形上下文命名為myLayerContext,則函數(shù)調(diào)用如下所示:

CGContextFillRect(myLayerContext,myRect)

將圖層繪制到目標(biāo)圖形上下文

當(dāng)您準(zhǔn)備好將圖層繪制到其目標(biāo)圖形上下文時,可以使用以下任一函數(shù):

  • CGContextDrawLayerInRect,它在指定的矩形中將圖層繪制到圖形上下文。
  • CGContextDrawLayerAtPoint,它在指定的點將圖層繪制到圖形上下文。

通常,您提供的目標(biāo)圖形上下文是一個窗口圖形上下文,它與您用于創(chuàng)建圖層的圖形上下文相同。 圖12-4顯示了重復(fù)繪制圖12-3所示圖層的結(jié)果。 要實現(xiàn)圖案效果,您可以重復(fù)調(diào)用任一圖層繪制函數(shù) - CGContextDrawLayerAtPoint或CGContextDrawLayerInRect - 每次更改偏移量。 例如,您可以調(diào)用函數(shù)CGContextTranslateCTM來更改每次繪制圖層時坐標(biāo)空間的原點。

12-4 重復(fù)繪制圖層

提示:您不需要將圖層繪制到用于初始化圖層的相同圖形上下文。 但是,如果將圖層繪制到另一個圖形上下文,原始圖形上下文的任何限制都會強加在您的圖形上。

示例:使用多個CGLayer對象來繪制國旗

本節(jié)說明如何使用兩個CGLayer對象來繪制屏幕上圖12-5所示的標(biāo)志。 首先,你將看到如何將標(biāo)志減少到簡單的繪圖基元,然后你將看到完成繪圖所需的代碼。

12-5 用圖層繪制美國國旗的結(jié)果

從在屏幕上繪制的角度來看,該標(biāo)志具有三個部分:

  • 紅色和白色條紋的圖案。您可以將圖案縮小為單個紅色條紋,因為在屏幕上繪制時,可以假設(shè)為白色背景。您創(chuàng)建一個單一的紅色矩形,然后重復(fù)繪制矩形在各種偏移量,以創(chuàng)建美國國旗必要的七條紅色條紋。層是重復(fù)繪圖的理想選擇。您將紅色矩形繪制到圖層,然后在屏幕上繪制七次。
  • 一個藍色矩形。你需要一個藍色的矩形,所以使用一個層是沒有什么好處。當(dāng)?shù)搅死L制藍色矩形的時候,直接在屏幕上繪制。
  • 50個白色星的圖案。像紅色條紋,一層是理想的繪制的星星。您創(chuàng)建 一個概述星形形狀的路徑,然后用白色填充路徑。繪制一個星星到一個圖層,然后繪制圖層50次,每次調(diào)整偏移量以獲得適當(dāng)?shù)拈g距。

圖12-2中的代碼生成如圖12-5所示的輸出。每個編號的代碼行的詳細說明顯示在列表之后。列表是相當(dāng)長的,所以你可能想打印的解釋,以便你可以看看你看代碼。 myDrawFlag例程從Cocoa應(yīng)用程序中調(diào)用。應(yīng)用程序傳遞窗口圖形上下文和指定與窗口圖形上下文相關(guān)聯(lián)的視圖大小的矩形。

注:在調(diào)用此或任何使用CGLayer對象的例程之前,必須檢查以確保系統(tǒng)正在運行Mac OS X v10.4或更高版本,并且具有支持使用CGLayer對象的圖形卡。

// 使用圖層繪制國旗的代碼
void myDrawFlag (CGContextRef context, CGRect* contextRect)
{
    int          i, j,
                 num_six_star_rows = 5,
                 num_five_star_rows = 4;
    CGFloat      start_x = 5.0,// 1
                 start_y = 108.0,// 2
                 red_stripe_spacing = 34.0,// 3
                 h_spacing = 26.0,// 4
                 v_spacing = 22.0;// 5
    CGContextRef myLayerContext1,
                 myLayerContext2;
    CGLayerRef   stripeLayer,
                 starLayer;
    CGRect       myBoundingBox,// 6
                 stripeRect,
                 starField;
 // ***** Setting up the primitives *****
    const CGPoint myStarPoints[] = {{ 5, 5},   {10, 15},// 7
                                    {10, 15},  {15, 5},
                                    {15, 5},   {2.5, 11},
                                    {2.5, 11}, {16.5, 11},
                                    {16.5, 11},{5, 5}};
 
    stripeRect  = CGRectMake (0, 0, 400, 17); // stripe// 8
    starField  =  CGRectMake (0, 102, 160, 119); // star field// 9
 
    myBoundingBox = CGRectMake (0, 0, contextRect->size.width, // 10
                                      contextRect->size.height);
 
     // ***** Creating layers and drawing to them *****
    stripeLayer = CGLayerCreateWithContext (context, // 11
                            stripeRect.size, NULL);
    myLayerContext1 = CGLayerGetContext (stripeLayer);// 12
 
    CGContextSetRGBFillColor (myLayerContext1, 1, 0 , 0, 1);// 13
    CGContextFillRect (myLayerContext1, stripeRect);// 14
 
    starLayer = CGLayerCreateWithContext (context,
                            starField.size, NULL);// 15
    myLayerContext2 = CGLayerGetContext (starLayer);// 16
    CGContextSetRGBFillColor (myLayerContext2, 1.0, 1.0, 1.0, 1);// 17
    CGContextAddLines (myLayerContext2, myStarPoints, 10);// 18
    CGContextFillPath (myLayerContext2);    // 19
 
     // ***** Drawing to the window graphics context *****
    CGContextSaveGState(context);    // 20
    for (i=0; i< 7;  i++)   // 21
    {
        CGContextDrawLayerAtPoint (context, CGPointZero, stripeLayer);// 22
        CGContextTranslateCTM (context, 0.0, red_stripe_spacing);// 23
    }
    CGContextRestoreGState(context);// 24
 
    CGContextSetRGBFillColor (context, 0, 0, 0.329, 1.0);// 25
    CGContextFillRect (context, starField);// 26
 
    CGContextSaveGState (context);              // 27
    CGContextTranslateCTM (context, start_x, start_y);      // 28
    for (j=0; j< num_six_star_rows;  j++)   // 29
    {
        for (i=0; i< 6;  i++)
        {
            CGContextDrawLayerAtPoint (context,CGPointZero,
                                            starLayer);// 30
            CGContextTranslateCTM (context, h_spacing, 0);// 31
        }
        CGContextTranslateCTM (context, (-i*h_spacing), v_spacing); // 32
    }
    CGContextRestoreGState(context);
 
    CGContextSaveGState(context);
    CGContextTranslateCTM (context, start_x + h_spacing/2, // 33
                                 start_y + v_spacing/2);
    for (j=0; j< num_five_star_rows;  j++)  // 34
    {
        for (i=0; i< 5;  i++)
        {
        CGContextDrawLayerAtPoint (context, CGPointZero,
                            starLayer);// 35
            CGContextTranslateCTM (context, h_spacing, 0);// 36
        }
        CGContextTranslateCTM (context, (-i*h_spacing), v_spacing);// 37
    }
    CGContextRestoreGState(context);
 
    CGLayerRelease(stripeLayer);// 38
    CGLayerRelease(starLayer);        // 39
}

這里是代碼做了什么:

  1. 聲明第一個星的水平位置的變量。
  2. 聲明第一個星的垂直位置的變量。
  3. 聲明標(biāo)志上紅色條紋之間的間距的變量。
  4. 聲明一個變量的標(biāo)志上的星星之間的水平間距。
  5. 聲明一個變量的標(biāo)志上的星星之間的垂直間距。
  6. 聲明指定在哪里繪制標(biāo)志(邊界框),條紋圖層和星形字段的矩形。
  7. 聲明一個點數(shù)組,指定描繪一個星的線。
  8. 創(chuàng)建一個是單個條帶形狀的矩形。
  9. 創(chuàng)建一個為星形字段形狀的矩形。
  10. 創(chuàng)建一個與傳遞給myDrawFlag例程的窗口圖形上下文大小相同的邊界框。
  11. 創(chuàng)建一個使用傳遞給myDrawFlag例程的窗口圖形上下文初始化的圖層。
  12. 獲取與該圖層相關(guān)聯(lián)的圖形上下文。您將使用此圖層進行條帶繪圖。
  13. 將與條紋圖層關(guān)聯(lián)的圖形上下文的填充顏色設(shè)置為不透明紅色。
  14. 填充代表一個紅色條紋的矩形。
  15. 創(chuàng)建另一個層,該層使用傳遞給myDrawFlag例程的窗口圖形上下文初始化。
  16. 獲取與該圖層相關(guān)聯(lián)的圖形上下文。您將使用此圖層作為星形繪圖。
  17. 將與星形圖層關(guān)聯(lián)的圖形上下文的填充顏色設(shè)置為不透明白色。
  18. 將由myStarPoints數(shù)組定義的10行添加到與星形圖層相關(guān)聯(lián)的上下文中。
  19. 填充路徑,其中包含剛剛添加的10行。
  20. 保存Windows圖形上下文的圖形狀態(tài)。你需要這樣做,因為你會反復(fù)繪制相同的條紋,但在不同的位置。
  21. 設(shè)置一個迭代7次的循環(huán),每次對標(biāo)志上的每個紅色條帶。
  22. 繪制條紋圖層(由一條紅色條紋組成)。
  23. 翻轉(zhuǎn)當(dāng)前變換矩陣,使原點位于必須繪制下一個紅色條紋的位置。
  24. 將圖形狀態(tài)恢復(fù)為繪制條紋之前的狀態(tài)。
  25. 將填充顏色設(shè)置為星形字段的適當(dāng)藍色陰影。請注意,此顏色的透明度為1.0。雖然這個例子中的所有顏色都是不透明的,但它們不需要是。通過使用部分透明的顏色,您可以使用分層繪圖創(chuàng)建漂亮的效果。回想一下,alpha值為0.0指定透明顏色。
  26. 用藍色填充星形字段矩形。將此矩形直接繪制到窗口圖形上下文。如果你只畫一次,不要使用圖層。
  27. 保存窗口圖形上下文的圖形狀態(tài),因為您將轉(zhuǎn)換CTM以正確定位星星。
  28. 翻轉(zhuǎn)CTM,使原點位于星形字段中,為第一個(下)行中的第一個星(左側(cè))定位。
  29. 這和下一個for循環(huán)設(shè)置代碼重復(fù)繪制星形圖層,所以標(biāo)志上的五個奇數(shù)行包含六顆星。
  30. 將星形圖層繪制到窗口圖形上下文。回想一下,星形圖層包含一個白色星形。
  31. 定位CTM,使原點向右移動,準(zhǔn)備繪制下一個星。
  32. 定位CTM,使原點向上移動,準(zhǔn)備繪制下一行星。
  33. 翻轉(zhuǎn)CTM,使原點位于星形字段中,為從底部起的第二行中的第一個星(左側(cè))定位。注意,偶數(shù)行相對于奇數(shù)行偏移。
  34. 這和下一個for循環(huán)設(shè)置代碼重復(fù)繪制星形圖層,所以標(biāo)志上的四個偶數(shù)行都包含五顆星。
  35. 將星形圖層繪制到窗口圖形上下文。
  36. 定位CTM,使原點向右移動,準(zhǔn)備繪制下一個星。
  37. 將CTM定位,使原點向下,向左移動,以準(zhǔn)備繪制下一行星。
  38. 釋放條帶層。
  39. 釋放星形圖層
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,702評論 6 534
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,615評論 3 419
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,606評論 0 376
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,044評論 1 314
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 71,826評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,227評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,307評論 3 442
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,447評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,992評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 40,807評論 3 355
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,001評論 1 370
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,550評論 5 361
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 44,243評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,667評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,930評論 1 287
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,709評論 3 393
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 47,996評論 2 374

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