1. 程式人生 > >Qt:通過預解釋和預讀取,大幅度提升圖片載入速度

Qt:通過預解釋和預讀取,大幅度提升圖片載入速度

在我以往的開發中,尤其是嵌入式,圖片的載入一直是一個頭疼的問題。圖片大了,載入就很慢,在嵌入式上,一個1280*1080的圖片,載入可能要好幾百毫秒。也就是說載入一個背景,就可能要花去幾百毫秒,還不包括其他各種圖片。
在用盡各種奇妙的方法後,今天終於找到一個根治的方法。趕緊來和大家分享下。

首先,我們要知道一個圖片的載入,時間到底消耗在哪。

一般來說,一個圖片載入,可以分為兩步,第一步是從硬碟讀取,這個根據裝置的不同,差異會非常大。尤其是固態硬碟和機械硬碟,差個10倍都不誇張。第二部是將資料,比如說PNG資料解釋為RGBA資料(這裡我暫時用解釋這一詞,如有更好請指正)。這一步會根據圖片的複雜程度不同,帶來不同程度的開銷。以我測試結果來看,對於一個普通的PNG圖片,解釋會佔用大部分時間,大約是60%到90%的總時間開銷。

也就是說,去掉解釋的時間開銷,是我們優化的大頭。做這樣簡單的優化,我們就可以成倍提升圖片的載入速度。那麼如何優化呢,我的思路是這樣的:

在第一次載入好圖片後,就直接把解釋好的RGBA資料儲存到本地,以供下一次直接讀取RGBA資料。

其實思路很簡單,至於實現方法,我從模式上,直接照搬了qmlc那一套,就是在本地(硬碟中)的cache目錄,儲存快取檔案。而檔案的命名,我使用了md5.jqic的模式,md5為(檔案全路徑)+(修改時間戳的字串)的運算結果,jqic為JQImageCache的簡稱。儲存效果如下:

這裡寫圖片描述

當然這個有很顯著的問題,就是圖片被解釋後,體積會非常大。如上截圖中,我儲存了一個2000*2000高寬,RGBA圖片的快取,這樣儲存出來就有16MB了。不過我覺得對於我們的PC,這個問題不大。畢竟快取嘛,也是可以被清除的,這個可以靠庫來維護。

注:那個qmlcache資料夾就是qmlc的快取儲存路徑。大家都是快取,咱們做鄰居唄。

說了這麼多,我們來看下效果,正常情況下,直接使用Image

這裡寫圖片描述

大約58ms,才可以載入完這個PNG圖片。那麼使用我剛剛說的預解釋的技術後:

這裡寫圖片描述

整個載入只有9ms了,這基本就是在硬碟讀取16MB資料的時間了。可見通過這簡單的操作,我們就可以縮減75%的載入時間

怎麼樣,提升是不是很明顯。但是除了上面提到的預解釋,我們還可以預讀取。

那麼為什麼要用預讀取呢,因為程式在啟動的時候,很多時候都是CPU高負載,硬碟基本沒事情做。因為程式起來的時候,進入到main了,要讀取的其實基本也讀取完了,硬碟表示去休息了。

那我們當然不能允許硬碟休息了,利用程式在初始化模組的時間,我們可以也從硬碟去讀取檔案,先把RGBA資料讀上來,要用了,直接拿來用。充分利用下裝置效能。
這樣連硬碟讀取都跳過了。那麼這樣能提升多少呢,我們來看下:

這裡寫圖片描述

這樣的話,大約縮減了99.8%的載入時間,也就是快了700倍,畢竟已經沒什麼事情可以做了,就是綁定了一個材質。當然這個數值,會隨著圖片變小而變小,圖片變大而變大。我今天早些時間測試的時候可以測試出提速3000倍的圖片。這是因為圖片很大,而且資料較為複雜。
另外這個數值也不能直接拿出來討論,因為硬碟讀取的時間被移到另外地方了。不過總的說,這樣預讀取確實快了。

講到這,原理就是這些,很簡單,但是真的要做起來,會設計很多概念,比如說C++和QML互動,怎麼快取,等等,所以我乾脆直接寫了一個Demo,GitHub如下:

考慮到這個功能比較實用,這個庫我基本會一直維護下去,包括增加新功能,例如圖片自動預讀取。希望有興趣的朋友可以來個星星,謝謝。