像素在屏幕顯示那點事

像素是如何顯示在屏幕上的呢?

當(dāng)然這里有很多種方式將某些東西顯示到顯示器上面,并且它們可能涉及到許多不同的framework框架以及功能方法的組合。但是在這里我們將介紹一些屏幕后面發(fā)生的事情, 而且我們希望當(dāng)你需要去決定如何去調(diào)試和解決性能問題的的時候,這將會幫助你更好的了解哪些API最有效果,對你最有幫助。在這里我們僅用iOS作為代表,當(dāng)然討論的大多數(shù)內(nèi)容同樣適用于 OS X

Graphics Stack(圖形堆棧)

當(dāng)像素要進入到屏幕的時候,往往伴隨著很多事情的發(fā)生。但是一旦它們出現(xiàn)在屏幕上面,每一個像素由三種顏色組成:紅色、綠色、藍色(也就是我們所說的RGB)。三個獨立的、特定強度的顏色單元點亮使用特定的顏色的單個像素。在您的iPhone 5 上面,一塊液晶顯示屏展現(xiàn)出來 1,136 x 640 = 727,040像素,因此有2,181,120個顏色單元格。在帶有Retina的顯示器的15英寸的MacBook Pro上面,這個數(shù)字剛好超過了1550萬。這個就需要整個圖形堆棧一起工作確保每一個顏色單元格都以正確的亮度點亮,當(dāng)你全屏滾動的時候,所有的這些上百萬的單元格需要做到每秒60的更新,這是一個多么大的工作量。

The Software Components(軟件組件)

在一個簡化的視圖當(dāng)中,軟件堆棧可能看起來是這樣的:

軟件堆棧

顯示器的上一級就是GPU一個圖像處理單元。GPU是高度并發(fā)的處理單元,其被特別的定制是用于圖形的并發(fā)計算。它的工作就是如何更新所有的像素,并且將結(jié)果推送到顯示器上面。它的平行的特點還允許它非常有效地講紋理合成到彼此上。我們將稍后討論合成的更多細節(jié)。關(guān)鍵點是GPU是非常專業(yè)的,因此在某些類型的工作中是高效的,它比CPU更加快速,使用更少的功率工作,普通的CPU都有一個非常一般的目的,它也可以做很多的不同的事情,但是在合成上面,會比GPU遜色一點。

GPU驅(qū)動程序是直接與GPU交互的代碼片段。不同的GPU是不同的猛獸,驅(qū)動程序使它們表現(xiàn)起來更加一致在面對下一層的時候(通常是OpenGL / OpenGL ES

OpenGL (Open Graphics Library)是一種用于渲染2D和3D圖形的API。由于GPU是一個非常專業(yè)的軟件,OpenGLGPU非常密切的協(xié)作以促進GPU的功能并且實現(xiàn)硬件的加速渲染。對于許多人來說,OpenGL可能看起來非常低級,但是當(dāng)它在1992年(20多年前)首次發(fā)布的時候,它是與圖形硬件(GPU)交互的第一個主要的標準化方式,因此這是一個重大的跨越,程序員們不再需要為每一個GPU重寫他們的應(yīng)用程序。

上面對于OpenGL的介紹到此為此,我們言歸正傳。在iOS上幾乎所有的內(nèi)容都通過核心動畫,但是在 OS X上,Core Graphics繞過核心動畫并不罕見。對于一些特殊的應(yīng)用,特別是游戲,應(yīng)用程序需要直接和OpenGL /OpenGL ES打交道。事情變得更加混亂。因為Core Animation 使用 Core Graphics進行渲染,框架例如AVFoundation,Core Image和其他的可以訪問的混合。

要記住的一件事情是:雖然GPU是一個非常強大的圖形硬件,它在顯示您的像素中發(fā)揮核心作用,它連接到CPU。在硬件方面,兩者之間有一條總線:并且有一些框架例如OpenGLCore Animation 、Core Graphics協(xié)調(diào)GPU和CPU之間的數(shù)據(jù)傳輸。為了讓你的像素顯示在屏幕上,一些處理將會在CPU上完成,然后在將數(shù)據(jù)傳輸?shù)紾PU,反過來,也會進行處理,最后像素都會顯示在屏幕上。

每一個旅途的每一部分都有它的挑戰(zhàn),而且還有一些折中。

硬件層(The HardWare Players)

硬件層

首要挑戰(zhàn):一個非常簡化的視圖應(yīng)該是GPU具有針對每個幀(每秒60次)合成在一起的紋理(位圖)。每一個紋理都占用VRAM(視頻RAM),因此GPU可以保持多少紋理都有一個限制。GPU在合成時是高效的,但是在某些合成任務(wù)比其他的合成任務(wù)更加復(fù)雜,并且GPU在16.7ms(1/60秒)內(nèi)可以做多少工作是有限制的。

下一個挑戰(zhàn)就是數(shù)據(jù)傳輸?shù)紾PU。為了GPU訪問數(shù)據(jù),需要將其從RAM移動到VRAM。這被稱為上傳到GPU。這可能看起來是微不足道的,但是對于大紋理來說,這可能是非常耗時的。

最后,CPU運行您的程序。它可能會告訴你CPU從你的bundle加載PNG并解壓縮。所有都發(fā)生在CPU上。當(dāng)你想顯示那個解壓縮的圖像時,它不知道何故竟然傳到了GPU。

像顯示文本一樣平凡的事情,對于CPU來說是一個非常復(fù)雜的任務(wù),它有助于Core TextCore Graphics框架之間的緊密集成,從文本中生成位圖。一旦準備完成,它將作為紋理上傳到GPU,準備顯示。當(dāng)你滾動屏幕或者以其他的方式移動文本時,可以重復(fù)使用相同的紋理,并且CPU將簡單地告訴GPU新的位置是什么,因此GPU可以重用現(xiàn)有的紋理,CPU不必重新渲染文本,并且位圖不必重新上傳。

上述說明了圖形堆棧所涉及的一些復(fù)雜性。有了上面的概述,我們將深入了解一些涉及的技術(shù)。

合成(Compositing)

在圖形的世界里面,合成是專業(yè)術(shù)語用語描述不同位圖放置在一起去創(chuàng)造最后的你在屏幕上能夠看見的圖像。是的,顯而易見,我們經(jīng)常容易去忽悠里面所包含的復(fù)雜性以及計算。

讓我們忽略一些更深奧的情況,僅僅假設(shè)所有在屏幕上的事物都是紋理。紋理是RGBA值的矩形區(qū)域。例如,對于每一個像素我們都要紅、綠、藍的顏色色值和一個透明值。在Core Animation 的世界里這些的基礎(chǔ)就是CALayer。

在略微簡化的設(shè)置中嗎,每一layer都是一個紋理,所有的這些紋理以某種方式堆砌在彼此的頂部。對于屏幕上的像素,GPU需要計算出如何去混合這些紋理以獲得該像素的RGB值。這就是合成。

如果我們所有的一個單一的紋理是屏幕的大小,并且與屏幕的像素對其,屏幕上的每一個像素對應(yīng)于該紋理的單個像素。紋理的像素就是最終屏幕的像素。

如果我們有第二個紋理放置在第一個紋理的上方,那么GPU將會混合這兩個紋理到第一個上面。這是不同的混合的方式。但是如果我們假設(shè)兩個紋理是像素對其的,那么我們就使用一般的混合的方式,使用每個像素計算得到的顏色的公式:

R = S + D * (1 - Sa)

結(jié)果顏色是源顏色(頂部紋理)加上目標顏色(低層紋理)乘以一減去源顏色的alpha。該公式中的所有顏色都假定為用它們的透明值預(yù)乘。

顯然我們可以從公式中得到很多東西。首先讓我們來假設(shè)所有的紋理是完全不透明的,也就是alpha = 1 。如果目的的(低層)紋理都是藍色(RGB = 0,0,1),源(頂部)紋理是紅色(RGB = 1,0,0),因為Sa為1,結(jié)果就是R = S

那么這個結(jié)果就是源的紅色。這也是你所期待的。

如果這個源(頂部)的layer 5?0%的透明度,也就是aplha是0.5,那么S的RGB的值就是(0.5,0,0),因為透明成分預(yù)乘到了RGB值里面。那么公式就看起來是這樣:

                       0.5   0               0.5
R = S + D * (1 - Sa) = 0   + 0 * (1 - 0.5) = 0
                       0     1               0.5

我們最終得到的RGB的值是(0.5,0,0.5)。它是飽和的梅花或者紫色。這時自然的你會直覺的認為那就是在藍色背景上面混合了透明的紅色。

我們需要明白的一點是:我們剛剛做的只是將一個紋理的一個像素合成到另外一個紋理的另外一個像素。GPU需要對兩個紋理覆蓋的所有的像素執(zhí)行此操作。正如我們所知道的,大多數(shù)應(yīng)用程序有大量的圖層,因此需要合成的紋理也非常多。即使一個硬件的高度優(yōu)化去做這樣的事情也會讓GPU一直處于忙碌的狀態(tài)。

不透明 VS 透明 (Opaque vs. Transparent)

當(dāng)源紋理完全不透明的時候,所得到的像素與源紋理是相同的。這可以節(jié)省GPU很多工作,因為它可以簡單地復(fù)制源紋理,而不是混合所有的像素值。但是GPU是沒有辦法告訴紋理中的所有像素是否透明。只有你作為一個程序員知道你的CALayer是否是這樣。這也就是為什么CALayer有一個稱為opaque的屬性,如果它被設(shè)置為YES,那么GPU就不會做任何混合,只是從這個層復(fù)制,而忽略它下面的任何東西。它節(jié)省了GPU相當(dāng)多的工作。

這是關(guān)于儀器選項顏色混合層的所有(也可在模擬器的調(diào)試菜單中。它允許您查看哪些圖層(紋理)被標記為非不透明,即GPU正在混合哪些圖層。 合成不透明層更便宜,因為涉及的數(shù)學(xué)較少。

如果你知道你的圖層是透明的,確保設(shè)置opaque為YES。如果你正在加載一張沒有透明值通道的圖片并將它展示在UIImageView里面,這將會經(jīng)常發(fā)生。但是請注意:這里有很大的不同關(guān)于一張圖片有沒有透明值通道。在稍后的例子中,Core Animation 將不得不假設(shè)像素不是100%透明的。在Finder中,你可以使用Get Info和選中More Info部分查看。它會說明如果一個圖像有無透明值通道。

像素對其以及非對其(Piexl Alignment and Misalignment)

到目前為止,我們已經(jīng)研究了具有與顯示器完全對其的像素的層。當(dāng)一切像素對齊的時候,我們只需要進行相對簡單的數(shù)學(xué)運算。每當(dāng)GPU需要弄清楚屏幕上的像素應(yīng)該是什么顏色時,它只需要查看在該屏幕像素上方的層中的單個像素并將它們合成在一起。 或者,如果頂部紋理是不透明的,則GPU可以簡單地復(fù)制該頂部紋理的像素。

當(dāng)所有像素與屏幕像素完全對齊時,圖層是像素對齊的。什么情況下將不會產(chǎn)生這種情況呢? 主要有兩個原因。 第一個是縮放; 當(dāng)紋理向上或向下放大時,紋理的像素將不會與屏幕對齊。 另一個原因是當(dāng)紋理的原點不在像素邊界里。

在這兩種情況下,GPU再次需要做額外的數(shù)學(xué)運算。 它必須將來自源紋理的多個像素混合在一起,以創(chuàng)建用于合成的值。 當(dāng)一切都像素對齊時,GPU只需要做很少的合作。

同樣, 核心動畫Instruments和模擬器都有一個叫做顏色不對其圖像的選項,將顯示CALayer實例發(fā)生這種情況的時間

遮罩(Masks)

每一個圖層都可以與一個遮罩關(guān)聯(lián)起來。遮罩是一個alpha值的位圖,在將圖層合成到其下面的內(nèi)容之前,該值將應(yīng)用于圖層的像素。 當(dāng)您設(shè)置圖層的圓角半徑時,您可以有效地在該圖層上設(shè)置蒙版。 但是也可以指定任意遮罩,例如。 有一個遮罩是字母A的形狀。只有作為該遮罩的一部分的圖層內(nèi)容的部分才會被渲染。

離屏渲染(Offscreen Rendering)

離屏渲染就會被Core Animation自動地觸發(fā)或者被應(yīng)用強制觸發(fā)。離屏渲染合成一部分圖層樹呈現(xiàn)到新的緩沖器(其是屏幕外的,即不在屏幕上),然后將該緩沖器呈現(xiàn)在屏幕上。

當(dāng)合成計算量很大時,您可能需要強制屏幕外渲染。 這是一種緩存合成紋理/圖層的方法。 如果你的渲染樹(所有的紋理和它們?nèi)绾螀f(xié)調(diào)在一起)是復(fù)雜的,你可以強制屏幕外渲染緩存這些層,然后使用緩存合成到屏幕上。

如果你的應(yīng)用程序結(jié)合了許多圖層,并且想要將它們一起動畫,GPU通常必須將所有這些圖層重新組合到每幀(1/60秒)的下面。 當(dāng)使用離屏渲染時,GPU首先將這些層組合成基于新紋理的位圖高速緩存,然后使用該紋理繪制到屏幕上。 現(xiàn)在,當(dāng)這些層一起移動時,GPU可以重新使用這個位圖緩存,并且做更少的工作。 注意,這只有當(dāng)這些層不改變時才有效。 如果圖層改變了,GPU必須重新創(chuàng)建位圖緩存。 您可以通過將shouldRasterize設(shè)置為YES來觸發(fā)此行為。

這是一個折衷的處理辦法,但有一點它可能會導(dǎo)致程序變卡。 創(chuàng)建額外的屏幕外緩沖區(qū)是GPU必須執(zhí)行的額外步驟,并且特別是如果它不能重復(fù)使用該位圖,這將會浪費時間。 然而,如果位圖可以被無限重新使用的話,那么GPU就可以被卸載。 你必須度量GPU利使用率和幀速率,看它是否有幫助。

離屏渲染可能作為副作用發(fā)生。 如果你直接或間接地將遮罩應(yīng)用到圖層,Core Animation被迫做屏幕外渲染,以便應(yīng)用該遮罩。 這給GPU帶來了負擔(dān)。 通常它只能夠直接渲染到幀緩沖區(qū)(屏幕)。

Instruments的核心動畫工具有一個稱為顏色離屏渲染 - 渲染黃色的選項,將使用屏幕外緩沖區(qū)渲染的黃色區(qū)域(此選項也可在模擬器的調(diào)試菜單中使用)。 一定要檢查綠色和紅色。 綠色用于每當(dāng)屏幕外緩沖區(qū)被重用時,而紅色用于當(dāng)需要重新創(chuàng)建時。

一般來說,你應(yīng)該避免屏幕外渲染,因為它的代價昂貴。 直接到幀緩沖器(在顯示器上)的合成層比先創(chuàng)建屏幕外緩沖器,渲染到其中,然后將結(jié)果重新渲染到幀緩沖器中代價更小。 存在兩個昂貴的上下文切換(將上下文切換到屏幕外緩沖器,然后將上下文切換回幀緩沖器)。

所以當(dāng)你看到黃色后,打開顏色屏幕 - 渲染黃色,這應(yīng)該是一個警告標志。 但它不一定是有問題的。 如果Core Animation能夠重用場外渲染的結(jié)果,并且Core Animation可以重用緩沖區(qū),它可以提高性能。 它可以重用,當(dāng)用于屏幕外緩沖區(qū)的圖層沒有改變。

還請注意,光柵化圖層的空間有限。 蘋果暗示,光柵化層/屏幕外緩沖區(qū)的屏幕大小大約是屏幕的兩倍。

如果你使用圖層的方式導(dǎo)致屏幕外渲染傳遞,你最好是試圖擺脫和屏幕外渲染一起。 使用遮罩或在圖層上設(shè)置角半徑會導(dǎo)致離屏渲染,因此陰影也是。

對于遮罩,使用圓角半徑(這只是一個特殊的遮罩)和clipsToBounds/maskToBounds你可以簡單的創(chuàng)建已經(jīng)刻錄的遮罩。例如通過使用已經(jīng)應(yīng)用的右遮罩的圖片,和往常一樣,這是一個折中的方式。如果要講矩形遮罩應(yīng)用于設(shè)置其內(nèi)容的圖層,則可以使用contentsRect而不是遮罩。

如果你最終設(shè)置shouldRasterizeYES,記得去設(shè)置rasterizationScalecontentsScale

更多的關(guān)于合成(More about Compositing)

是的,在維基百科上面有很多的關(guān)于alpha合成的數(shù)學(xué)畢竟資料。稍后我們將更加深入的討論像素關(guān)于紅色、綠色、藍色以及透明值在內(nèi)存中表現(xiàn)。

OS X

如果你在OS X上工作,你會發(fā)現(xiàn)大多數(shù)調(diào)試選項是一個單獨的應(yīng)用程序,稱為“Quartz Debug”,而不是內(nèi)置的Instruments。Quartz Debug 是“圖形工具”的一部分,它是需要在開發(fā)人員網(wǎng)站里面單獨下載

Core Animation & OpenGL ES

如同名字所暗示的,核心動畫就是讓你在屏幕上面做動畫。我們總是跳過談?wù)搫赢?,而是把精力放在了繪圖上面。有一點你需要注意的是,核心動畫允許你做非常高效的渲染。這也就是你為什么能在每秒60幀的時間內(nèi)使用Core Animation做動畫

Core Animation,其核心是在OpenGL ES上的抽象。簡單來說它可以讓你使用OpenGL ES的力量,而不必處理它的所有復(fù)雜性。當(dāng)我們談?wù)撋厦娴暮铣蓵r,術(shù)語圖層和紋理是可以相互替換的,但是他們并不是同一件事情,但是很相似。

核心動畫層可以有子層,所以你最終得到的是一個層樹。 Core Animation需要做的費力的事情是:確定需要(重新)繪制哪些圖層,以及需要進行哪些OpenGL ES調(diào)用以將圖層復(fù)合到屏幕上。

例如,當(dāng)您將圖層的內(nèi)容設(shè)置為CGImageRef時,Core Animation會創(chuàng)建一個OpenGl紋理,確保該圖像中的位圖被上傳到相應(yīng)的紋理等。如果你覆蓋-drawInContextCore Animation就會將分配紋理確保您所做的Core Graphics調(diào)用將會轉(zhuǎn)換為該紋理的位圖數(shù)據(jù)。圖片的屬性和CALayer子類影響執(zhí)行OpenGL渲染的方式,許多較低級別的OpenGL ES行為很好的封裝在易于理解的CALayer概念中

Core Animation orchestrates CPU-based bitmap drawing through Core Graphics on one end with OpenGL ES on the other end. And because Core Animation sits at this crucial place in the rendering pipeline, how you use Core Animation can dramatically impact performance.

CPU bound vs. GPU bound

當(dāng)您在屏幕上顯示某些內(nèi)容時,有許多組件正在工作。 兩個主要的硬件播放器是CPU和GPU。 P和U在他們的名字代表處理單元,并且當(dāng)事情必須在屏幕上繪制時,這兩個都將做處理。 兩者也有有限的資源。

為了實現(xiàn)每秒60幀,您必須確保CPU和GPU都不會超載工作。 除此之外,即使你是60 fps,你想把盡可能多的工作在GPU上。 您希望CPU可以自由運行應(yīng)用程序代碼,而不是忙于繪圖。 并且GPU在渲染時比CPU更有效,這樣的使用將會轉(zhuǎn)化為系統(tǒng)的較低的總負載和功率消耗。

由于繪圖性能取決于CPU和GPU,您需要確定哪一個限制了您的繪圖性能。 如果您使用了所有GPU資源,即GPU是限制您的性能,您的繪圖被稱為是GPU綁定。 同樣,如果你超出了CPU界限,那么CPU限制了您的性能。

如果你是GPU綁定,你需要減輕GPU的負擔(dān)(也許在CPU做更多的工作)。 如果你是CPU綁定,你需要減輕CPU的負擔(dān)。

要檢查是否是GPU限制了你性能,使用OpenGL ES驅(qū)動程序儀器。 單擊小i按鈕,然后配置,并確保選中設(shè)備利用率%。 現(xiàn)在,當(dāng)你運行你的應(yīng)用程序,你會看到如何加載的GPU。 如果這個數(shù)字接近100%,那么就是你在GPU上做了很多工作。
被CPU限制是你的應(yīng)用程序在更多的傳統(tǒng)方面做了許多工作。 Time Profiler儀器可幫助您檢測。

Core Graphics / Quartz 2D

Quartz 2D 更常見的是包含它的框架的名稱: Core Graphics

Quartz 2D有更多的技巧超過了我們所能夠覆蓋的地方。我們不打算談?wù)撆cPDF創(chuàng)建、渲染、解析或打印相關(guān)的巨大部分。只要注意,打印和創(chuàng)建PDF在很大程度上等同于在屏幕繪制位圖,因為它都是基于Quartz 2D

讓我們簡單的談?wù)?code>Quartz 2D的主要概念。有關(guān)詳細的信息,請務(wù)必去查看AppleQuartz 2D編程指南

請放心,當(dāng)涉及到2D繪圖時,Quartz 2D是非常強大的。僅僅列舉幾個功能: 基于路徑的繪圖,抗鋸齒渲染,透明層,以及分辨率和設(shè)備獨立性。 這是相當(dāng)令人生畏的,更是因為它是一個低級和基于C的API。

主要的概念是比較簡單的,但 UIKit和AppKit只是簡單地使用API來封裝一些Quartz 2D,甚至一旦你習(xí)慣了它,即使是簡單的C API也是可以訪問的。 你最終得到一個繪圖引擎,可以做你能夠做的大部分的PhotoshopIllustrator。 蘋果提到了iOS上的股票應(yīng)用程序作為Quartz 2D用法的例子,因為圖形是使用Quartz 2D在代碼中動態(tài)呈現(xiàn)的圖形的簡單示例。

當(dāng)你的應(yīng)用程序做位圖繪圖時,它會 - 以某種方式 - 基于Quartz 2D。 也就是說,繪圖的CPU部分將由Quartz 2D執(zhí)行。 雖然Quartz可以做其他事情,但是我們將專注于位圖繪制,即在包含RGBA數(shù)據(jù)的緩沖區(qū)(一塊內(nèi)存)上繪制結(jié)果。

讓我們來畫一個八邊形 Octagon. 我們可以使用UIKit

UIBezierPath *path = [UIBezierPath bezierPath];
[path moveToPoint:CGPointMake(16.72, 7.22)];
[path addLineToPoint:CGPointMake(3.29, 20.83)];
[path addLineToPoint:CGPointMake(0.4, 18.05)];
[path addLineToPoint:CGPointMake(18.8, -0.47)];
[path addLineToPoint:CGPointMake(37.21, 18.05)];
[path addLineToPoint:CGPointMake(34.31, 20.83)];
[path addLineToPoint:CGPointMake(20.88, 7.22)];
[path addLineToPoint:CGPointMake(20.88, 42.18)];
[path addLineToPoint:CGPointMake(16.72, 42.18)];
[path addLineToPoint:CGPointMake(16.72, 7.22)];
[path closePath];
path.lineWidth = 1;
[[UIColor redColor] setStroke];
[path stroke];

或多或少的對應(yīng)的Core Graphics代碼是:

CGContextBeginPath(ctx);
CGContextMoveToPoint(ctx, 16.72, 7.22);
CGContextAddLineToPoint(ctx, 3.29, 20.83);
CGContextAddLineToPoint(ctx, 0.4, 18.05);
CGContextAddLineToPoint(ctx, 18.8, -0.47);
CGContextAddLineToPoint(ctx, 37.21, 18.05);
CGContextAddLineToPoint(ctx, 34.31, 20.83);
CGContextAddLineToPoint(ctx, 20.88, 7.22);
CGContextAddLineToPoint(ctx, 20.88, 42.18);
CGContextAddLineToPoint(ctx, 16.72, 42.18);
CGContextAddLineToPoint(ctx, 16.72, 7.22);
CGContextClosePath(ctx);
CGContextSetLineWidth(ctx, 1);
CGContextSetStrokeColorWithColor(ctx, [UIColor redColor].CGColor);
CGContextStrokePath(ctx);

要問的問題是:這個繪圖在哪里? 這就是所謂的CGContext的作用。 我們傳遞的ctx參數(shù)是在這種情況下。 上下文定義了我們要繪制的位置。 如果我們實現(xiàn)CALayer的-drawInContext:我們被傳遞一個上下文。 繪制到該上下文將繪制到圖層的后備存儲(其緩沖區(qū))。 但是我們也可以創(chuàng)建我們自己的上下文,即基于位圖的上下文。 CGBitmapContextCreate()。 這個函數(shù)返回一個上下文,然后我們可以傳遞給CGContext函數(shù)來繪制上下文等

注意UIKit版本的代碼如何不將上下文傳遞給方法。 這是因為當(dāng)使用UIKit或AppKit時,上下文是隱式的。 UIKit維護著一堆上下文,UIKit方法總是繪制到頂層上下文中。 你可以使用UIGraphicsGetCurrentContext()來獲取上下文。 你可以使用UIGraphicsPushContext()UIGraphicsPopContext()來推入和彈出上下文到UIKit的堆棧。

最值得注意的是,UIKit有方便的方法UIGraphicsBeginImageContextWithOptions()和UIGraphicsEndImageContext()創(chuàng)建一個位圖上下文類似于CGBitmapContextCreate()。 混合UIKit和Core Graphics調(diào)用非常簡單:

UIGraphicsBeginImageContextWithOptions(CGSizeMake(45, 45), YES, 2);
CGContextRef ctx = UIGraphicsGetCurrentContext();
CGContextBeginPath(ctx);
CGContextMoveToPoint(ctx, 16.72, 7.22);
CGContextAddLineToPoint(ctx, 3.29, 20.83);
...
CGContextStrokePath(ctx);
UIGraphicsEndImageContext();

或者其他方式

CGContextRef ctx = CGBitmapContextCreate(NULL, 90, 90, 8, 90 * 4, space, bitmapInfo);
CGContextScaleCTM(ctx, 0.5, 0.5);
UIGraphicsPushContext(ctx);
UIBezierPath *path = [UIBezierPath bezierPath];
[path moveToPoint:CGPointMake(16.72, 7.22)];
[path addLineToPoint:CGPointMake(3.29, 20.83)];
...
[path stroke];
UIGraphicsPopContext(ctx);
CGContextRelease(ctx);

Core Graphics有很多非??岬臇|西可以做。 有一個很好的理由,蘋果文檔調(diào)用其無與倫比的輸出保真度。 我們不能進入所有的細節(jié),但是:Core Graphics有一個圖形模型(由于歷史原因)是非常接近的Adobe IllustratorAdobe Photoshop的工作原理。 大多數(shù)工具的概念轉(zhuǎn)換為Core Graphics。 畢竟,它的起源是在NeXTSTEP,它使用顯示PostScript

CGLayer

我們最初表示CGLayer可以用于加速重復(fù)繪制相同的元素。 正如Dave Hayden所指出的,傳言已經(jīng)說明這不再是真的。

像素(Pixels)

屏幕上的像素由三個顏色分量組成:紅色,綠色,藍色。 因此,位圖數(shù)據(jù)有時也被稱為RGB數(shù)據(jù)。 您可能想知道如何在內(nèi)存中組織這些數(shù)據(jù)。 但事實是,有很多很多不同的方式用于RGB位圖數(shù)據(jù)在內(nèi)存中的表示。
稍后我們將討論壓縮數(shù)據(jù),這是完全不同的。 現(xiàn)在,讓我們來看看RGB位圖數(shù)據(jù),其中每個顏色分量都有一個值:紅色,綠色和藍色。 通常我們會有第四個組份:alpha。 我們最終得到每個像素的四個單獨的值。

此為未完結(jié)版...

小弟第一次在簡書上面發(fā)表文章,純屬拋磚引玉,僅供大家參考。不喜勿噴~~????

最后貼上原文鏈接供各位小伙伴們學(xué)習(xí)猛戳這里

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 繪制像素到屏幕上 answer-huang22 Mar 2014 分享文章 一個像素是如何繪制到屏幕上去的?有很多...
    阿貍旅途T恤閱讀 1,780評論 0 7
  • 卷首語 歡迎來到 objc.io 的第三期! 這一期都是關(guān)于視圖層的。當(dāng)然視圖層有很多方面,我們需要把它們縮小到幾...
    評評分分閱讀 1,946評論 0 18
  • 繪制像素到屏幕上 軟件組成 從簡單的角度來看, 軟件堆??雌饋碛悬c像這樣: Display的上一層便是圖形處理單元...
    VanChan閱讀 953評論 0 1
  • 有很多種framework以及很多種方法的組合可以在屏幕上渲染UI元素,我們在這里討論這個過程中發(fā)生的事情,希望這...
    縱橫而樂閱讀 4,715評論 4 25
  • Iios啟動圖片的添加是十分的簡單,網(wǎng)上有許多教程,在這里本人就不教大家了.那么為什么我們需要啟動圖片?不需要啟動...
    iosPBB閱讀 286評論 0 0

友情鏈接更多精彩內(nèi)容