objc中國#3 繪制像素到屏幕上 閱讀筆記

1.繪制像素到屏幕上

軟件的組成


7D34011B-CF95-460B-8035-62F9853E4DD2.png

GPU :圖形處理單元。更多圖像的繪制
CPU:圖形高迸發(fā)計算而量身定做的處理單元。更對為繪制圖像提供計算、數(shù)據(jù)。
GPU Driver: 是直接和 GPU 交流的代碼塊。不同的GPU是不同的性能怪獸,但是驅(qū)動使他們在下一個層級上顯示的更為統(tǒng)一,典型的下一層級有 OpenGL/OpenGL ES.
OpenGL(Open Graphics Library): 是一個提供了 2D 和 3D 圖形渲染的 API。GPU 是一塊非常特殊的硬件,OpenGL 和 GPU 密切的工作以提高GPU的能力,并實現(xiàn)硬件加速渲染。對大多數(shù)人來說,OpenGL 看起來非常底層,但是當(dāng)它在1992年第一次發(fā)布的時候(20多年前的事了)是第一個和圖形硬件(GPU)交流的標(biāo)準(zhǔn)化方式,這是一個重大的飛躍,程序員不再需要為每個GPU重寫他們的應(yīng)用了。

不透明 VS 透明

當(dāng)源紋理是完全不透明的時候,目標(biāo)像素就等于源紋理。這可以省下 GPU 很大的工作量,這樣只需簡單的拷貝源紋理而不需要合成所有的像素值。但是沒有方法能告訴 GPU 紋理上的像素是透明還是不透明的。只有當(dāng)你作為一名開發(fā)者知道你放什么到 CALayer 上了。這也是為什么 CALayer 有一個叫做 opaque 的屬性了。如果這個屬性為 YES,GPU 將不會做任何合成,而是簡單從這個層拷貝,不需要考慮它下方的任何東西(因為都被它遮擋住了)。這節(jié)省了 GPU 相當(dāng)大的工作量。這也正是 Instruments 中 color blended layers 選項中所涉及的。(這在模擬器中的Debug菜單中也可用).它允許你看到哪一個 layers(紋理) 被標(biāo)注為透明的,比如 GPU 正在為哪一個 layers 做合成。合成不透明的 layers 因為需要更少的數(shù)學(xué)計算而更廉價。

所以如果你知道你的 layer 是不透明的,最好確定設(shè)置它的 opaque 為 YES。如果你加載一個沒有 alpha 通道的圖片,并且將它顯示在 UIImageView 上,這將會自動發(fā)生。但是要記住如果一個圖片沒有 alpha 通道和一個圖片每個地方的 alpha 都是100%,這將會產(chǎn)生很大的不同。在后一種情況下,Core Animation 需要假定是否存在像素的 alpha 值不為100%。在 Finder 中,你可以使用 Get Info 并且檢查 More Info 部分。它將告訴你這張圖片是否擁有 alpha 通道。

像素對齊 VS 不重合在一起

到現(xiàn)在我們都在考慮像素完美重合在一起的 layers。當(dāng)所有的像素是對齊的時候我們得到相對簡單的計算公式。每當(dāng) GPU 需要計算出屏幕上一個像素是什么顏色的時候,它只需要考慮在這個像素之上的所有 layer 中對應(yīng)的單個像素,并把這些像素合并到一起?;蛘?,如果最頂層的紋理是不透明的(即圖層樹的最底層),這時候 GPU 就可以簡單的拷貝它的像素到屏幕上。

當(dāng)一個 layer 上所有的像素和屏幕上的像素完美的對應(yīng)整齊,那這個 layer 就是像素對齊的。主要有兩個原因可能會造成不對齊。第一個便是滾動;當(dāng)一個紋理上下滾動的時候,紋理的像素便不會和屏幕的像素排列對齊。另一個原因便是當(dāng)紋理的起點不在一個像素的邊界上。

在這兩種情況下,GPU 需要再做額外的計算。它需要將源紋理上多個像素混合起來,生成一個用來合成的值。當(dāng)所有的像素都是對齊的時候,GPU 只剩下很少的工作要做。

Core Animation 工具和模擬器有一個叫做 color misaligned images 的選項,當(dāng)這些在你的 CALayer 實例中發(fā)生的時候,這個功能便可向你展示。

Masks

一個圖層可以有一個和它相關(guān)聯(lián)的 mask(蒙板),mask 是一個擁有 alpha 值的位圖,當(dāng)像素要和它下面包含的像素合并之前都會把 mask 應(yīng)用到圖層的像素上去。當(dāng)你要設(shè)置一個圖層的圓角半徑時,你可以有效的在圖層上面設(shè)置一個 mask。但是也可以指定任意一個蒙板。比如,一個字母 A 形狀的 mask。最終只有在 mask 中顯示出來的(即圖層中的部分)才會被渲染出來。

圖片格式

當(dāng)你在 iOS 或者 OS X 上處理圖片時,他們大多數(shù)為 JPEG 和 PNG。讓我們更進一步觀察。

JPEG
每個人都知道 JPEG。他是相機的產(chǎn)物。它代表這照片如何存儲在電腦上。甚至你嘛嘛都聽說過 JPEG。

一個很好的理由,很多人都認(rèn)為 JPEG 文件僅是另一種像素數(shù)據(jù)的格式,就像我們剛剛談到的 RGB 像素布局那樣。這樣理解離真像真是差十萬八千里了。

將 JPEG 數(shù)據(jù)轉(zhuǎn)換成像素數(shù)據(jù)是一個非常復(fù)雜的過程,你通過一個周末的計劃都不能完成,甚至是一個非常漫長的周末(原文的意思好像就是為了表達這個過程非常復(fù)雜,不過老外的比喻總讓人拎不清)。對于每一個二維顏色,JPEG 使用一種基于離散余弦變換(簡稱 DCT 變換)的算法,將空間信息轉(zhuǎn)變到頻域.這個信息然后被量子化,排好序,并且用一種哈夫曼編碼的變種來壓縮。很多時候,首先數(shù)據(jù)會被從 RGB 轉(zhuǎn)換到二維 YCbCr,當(dāng)解碼 JPEG 的時候,這一切都將變得可逆。

這也是為什么當(dāng)你通過 JPEG 文件創(chuàng)建一個 UIImage 并且繪制到屏幕上時,將會有一個延時,因為 CPU 這時候忙于解壓這個 JPEG。如果你需要為每一個 tableviewcell 解壓 JPEG,那么你的滾動當(dāng)然不會平滑(原來 tableviewcell 里面最要不要用 JPEG 的圖片)。

那究竟為什么我們還要用 JPEG 呢?答案就是 JPEG 可以非常非常好的壓縮圖片。一個通過 iPhone5 拍攝的,未經(jīng)壓縮的圖片占用接近 24M。但是通過默認(rèn)壓縮設(shè)置,你的照片通常只會在 2-3M 左右。JPEG 壓縮這么好是因為它是失真的,它去除了人眼很難察覺的信息,并且這樣做可以超出像 gzip 這樣壓縮算法的限制。但這僅僅在圖片上有效的,因為 JPEG 依賴于圖片上有很多人類不能察覺出的數(shù)據(jù)。如果你從一個基本顯示文本的網(wǎng)頁上截取一張圖,JPEG 將不會這么高效。壓縮效率將會變得低下,你甚至能看出來圖片已經(jīng)壓縮變形了。

PNG
PNG讀作”ping”。和 JPEG 相反,它的壓縮對格式是無損的。當(dāng)你將一張圖片保存為 PNG,并且打開它(或解壓),所有的像素數(shù)據(jù)會和最初一模一樣,因為這個限制,PNG 不能像 JPEG 一樣壓縮圖片,但是對于像程序中的原圖(如buttons,icons),它工作的非常好。更重要的是,解碼 PNG 數(shù)據(jù)比解碼 JPEG 簡單的多。

在現(xiàn)實世界中,事情從來沒有那么簡單,目前存在了大量不同的 PNG 格式??梢酝ㄟ^維基百科查看詳情。但是簡言之,PNG 支持壓縮帶或不帶 alpha 通道的顏色像素(RGB),這也是為什么它在程序原圖中表現(xiàn)良好的另一個原因。

With –drawRect:

如果你的視圖類實現(xiàn)了 -drawRect:,他們將像這樣工作:
當(dāng)你調(diào)用 -setNeedsDisplay,UIKit 將會在這個視圖的圖層上調(diào)用 -setNeedsDisplay。這為圖層設(shè)置了一個標(biāo)識,標(biāo)記為 dirty(直譯是臟的意思,想不出用什么詞比較貼切,污染?),但還顯示原來的內(nèi)容。它實際上沒做任何工作,所以多次調(diào)用 -setNeedsDisplay并不會造成性能損失。

下面,當(dāng)渲染系統(tǒng)準(zhǔn)備好,它會調(diào)用視圖圖層的-display方法.此時,圖層會裝配它的后備存儲。然后建立一個 Core Graphics 上下文(CGContextRef),將后備存儲對應(yīng)內(nèi)存中的數(shù)據(jù)恢復(fù)出來,繪圖會進入對應(yīng)的內(nèi)存區(qū)域,并使用 CGContextRef 繪制。

當(dāng)你使用 UIKit 的繪制方法,例如: UIRectFill() 或者 -[UIBezierPath fill] 代替你的 -drawRect: 方法,他們將會使用這個上下文。使用方法是,UIKit 將后備存儲的 CGContextRef 推進他的 graphics context stack,也就是說,它會將那個上下文設(shè)置為當(dāng)前的。因此 UIGraphicsGetCurrent() 將會返回那個對應(yīng)的上下文。既然 UIKit 使用 UIGraphicsGetCurrent() 繪制方法,繪圖將會進入到圖層的后備存儲。如果你想直接使用 Core Graphics 方法,你可以自己調(diào)用 UIGraphicsGetCurrent() 得到相同的上下文,并且將這個上下文傳給 Core Graphics 方法。

從現(xiàn)在開始,圖層的后備存儲將會被不斷的渲染到屏幕上。直到下次再次調(diào)用視圖的 -setNeedsDisplay ,將會依次將圖層的后備存儲更新到視圖上。

來自:http://objccn.io/issue-3-1/

最后編輯于
?著作權(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,779評論 0 7
  • 卷首語 歡迎來到 objc.io 的第三期! 這一期都是關(guān)于視圖層的。當(dāng)然視圖層有很多方面,我們需要把它們縮小到幾...
    評評分分閱讀 1,946評論 0 18
  • 有很多種framework以及很多種方法的組合可以在屏幕上渲染UI元素,我們在這里討論這個過程中發(fā)生的事情,希望這...
    縱橫而樂閱讀 4,715評論 4 25
  • 1. 概述寫這篇總結(jié)的目的是想讓大家了解眼睛看到屏幕上漂亮的顏色和圖片背后所發(fā)生的事情。其實題目取的有點夸張,因為...
    Ajcc閱讀 2,981評論 0 3
  • 他望著她,仿佛一切遙不可及,而她就在那里! 我能去你辦公室嗎? 我下午要改卷,你別來了! 我可以幫你改啊! 你? ...
    伶夢閱讀 475評論 5 1

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