QPixmap和QImage的區別及剖析

pamxy發表於2013-05-31

轉自:http://blog.csdn.net/changsheng230/article/details/6452805

(一)QPixmap和QImage的區別

http://www.thisisqt.com/forum/viewthread.php?tid=267

QPixmap是專門為繪圖而生,當需要繪製圖片時你需要使用QPixmap。QImage則是為I/O,為圖片畫素訪問以及修改而設計的。如果你想訪問圖片的畫素或是修改圖片畫素,則需要使用QImage,或者藉助於QPainter來操作畫素。另外跟QImage不同是,QPixmap跟硬體是相關的,如X11, Mac 以及 Symbian平臺上,QPixmap 是儲存在伺服器端,而QImage則是儲存在客戶端,在Windows平臺上,QPixmap和QImage都是儲存在客戶端,並不使用任何的GDI資源。

相信大家更關心的是誰比較快,哈哈,現在來總結一下:
在X11, Mac 以及 Symbian平臺上,QImage: 因為它是儲存在客戶端,往QImage上繪圖比較快,但顯示它則比較慢。QPixmap: 因為它是儲存在伺服器端,往QPixmap上繪圖比較慢,但顯示它則比較快。但在Windows平臺上則是是一樣的,因為它們都儲存在客戶端。


Qt上圖片處理使用QPixmap和QImage時最多了,不過既然談到圖片了,我們把其他幾個圖片處理類也說一下:
QBitmap只是一個繼承於QPixmap的簡單類,它可以確保圖片深度為1。
QBitmap是QPixmap的子類,提供單色影象,可以用來製作遊標(QCursor)或者筆刷(QBrush)。

QPicture是一個繪畫裝置類,它記錄了並可以重演QPainter的命令。你可以使用QPainter的begin()方法,指定在QPicture上繪圖,使用end()方法結束繪圖,使用QPicture的save()方法將QPainter所使用過的繪圖指令存至檔案。要重播繪圖指令的話,建立一個QPicture,使用load()方法載入繪圖指令的檔案,然後在指定的繪圖裝置上繪製QPicture:

(二)QImage與QPixmap完全解析

http://www.civilnet.cn/bbs/browse.php?topicno=4691

用Qt程式在手機上顯示一幅圖片對程式設計人員來說是再基礎不過的一件事情了。那麼先讓大家看兩段程式碼:

//dangerous should not be used, cannot display earth.png, 
//but if we change earth.png to a smaller image e.g. apple.png, apple.png can be displayed
QPixmap pixmap;
pixmap.load( ":/pics/earth.png" );
label->setPixmap( pixmap );

//dangerous should not be used, cannot display earth.png, 
//but if we change earth.png to a smaller image e.g. apple.png, apple.png can be displayed
QPixmap pixmap;
pixmap.load( ":/pics/earth.png" );
QPainter painter(this);
painter.drawPixmap(0,0, pixmap);
大家認為這兩段程式碼有什麼問題嗎? 看起來好像沒什麼問題啊。是的,在Windows作業系統上是沒有問題的。問題是我們做的是Qt for Symbian! 手機上的資源本來就是比較緊缺的,所以我們使用的時候就需要更加註意。 Qt 為我們提供了四個處理影象的類:QImage,QPixmap,QBitmap 和QPicture。其中前兩個是最常使用的。

本文就通過一個例子,一步一步為大家講解QImage與QPixmap的使用奧祕,在此過程中為大家揭示以上程式碼存在的缺陷。
QPixmap依賴於硬體

首先需要知道的是QPixmap的具體實現是依賴於系統的。在Symbian系統上QPixmap是被存放在Server端的。
目前的Qt會把QPixmap都儲存在graphics memory中,這明顯是依賴硬體的。因此我們對QPixmap的使用需要格外注意。這也正是以上兩段程式碼存在問題的根源。
那麼Qt為什麼要這麼做呢?很簡單,設計之初QPixmap就是用來加速顯示的,例如我們在paint的時候用QPixmap就會比用其他類的效果好許多。

現在回到我們最初的問題,以上程式碼到底有什麼問題呢?我們可以先用本文提供的例子程式做個試驗。當使用上述程式碼顯示較小圖片的時候(比如例子程式中的background.png 和apple.png)是沒有問題的,圖片都能在手機上正確顯示。
但是當我們把圖片換成一副較大圖片287KB,1058 x 1058的“earth.png”的時候就出現問題了,圖片無法顯示,程式的介面是一片空白。

據測算,“earth.png”被完全解碼後儲存在graphics memory中會佔用大約4.3MB的空間。如果此時還有其他載入的視窗和QPixmap,很可能就沒有空間了。
使用QImage載入後轉換成QPixmap 顯示

那麼安全和正確的方法應該是什麼呢?答案是我們需要用QImage做一下預處理:

//correct and recommended way
QImage image;
image.load( ":/pics/earth.png" );

QPainter painter(this);
QPixmap pixmapToShow = QPixmap::fromImage( image.scaled(size(), Qt::KeepAspectRatio) );
painter.drawPixmap(0,0, pixmapToShow);
和QPixmap 不同,QImage是獨立於硬體的,它可以同時被另一個執行緒訪問。QImage是儲存在客戶端的,對QImage的使用是非常方便和安全的。 又由於 QImage 也是一種QPaintDevice,因此我們可以在另一個執行緒中對其進行繪製,而不需要在GUI 執行緒中處理,使用這一方式可以很大幅度提高UI響應速度。 因此當圖片較大時,我們可以先通過QImage將圖片載入進來,然後把圖片縮放成需要的尺寸,最後轉換成QPixmap 進行顯示。 下圖是顯示效果(圖片是按照earth.png的原始尺寸比例縮放後顯示的):


 

其中需要注意的是Qt::KeepAspectRatio的使用,預設引數是Qt::IgnoreAspectRatio,如果我們在程式中這麼寫:

QPixmap pixmapToShow = QPixmap::fromImage( image.scaled(size(), Qt::IgnoreAspectRatio) );
效果就是下面這個樣子,earth.png被拉伸以充滿整個螢幕:

 

直接使用QImage 顯示

我們也可以直接使用QImage做顯示,而不轉換成QPixmap ,這要根據我們應用的具體需求來決定,如果需要的話我們可以這麼寫:

//correct, some times may be needed
QImage image;
image.load( ":/pics/earth.png" );

QPainter painter(this);
painter.drawImage(0,0, image);
下面是顯示效果(當然我們也可以對其進行縮放之後再顯示) 從圖片可以看出來它是按照原始尺寸顯示earth.png的:


 

測試裝置

本程式碼已通過在N97和N8上的測試。
 


本文來自CSDN部落格,轉載請標明出處:http://blog.csdn.net/nolatestudy/archive/2011/04/01/6295064.aspx

 

相關文章