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上的測試。
 
 
     

 
 
 
下載樣例程序:
http://www.forum.nokia.com/piazza/wiki/images/f/f0/ImageTest.zip?20100915060150


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM