分享

QPixmap、QBitmap、QImage 與 QPicture

 guitarhua 2013-12-28
在處理影像資料上,Qt提供了QPixmap、QBitmap、QImage與QPicture等類別。

一. 几种类的简介

QPixmap繼承了QPaintDevice,您可用以建立QPaint
er並於上進行繪圖,您也可以直接指定圖案載入Qt所支援的圖檔,
像是BMP、GIF、JPG、JPEG、PNG等,並使用QPainter的drawPixmap()繪製在其它的繪圖裝置上。您可以在QLabel、QPushButton上設定QPixmap以顯示圖像QPixmap是針對螢幕顯示圖像而設計並最佳化,依賴於所在平台的原生繪圖引擎,所以一些效果的展現(像是反鋸齒),在不同的平台上可能會有不一致的結果。

QBitmap是QPixmap的子類別,提供單色圖像,可用於製作游標(QCursor)或筆刷(QBrush)物件。下面的程式載入相同的圖檔,以觀看QPixmap與QBitmap的呈現效果:

  1. #include <QApplication>  
  2. #include <QWidget>  
  3. #include <QPainter>  
  4. #include <QBitmap>  
  5.   
  6. class PainterWidget : public QWidget {  
  7. protected:  
  8.     void paintEvent(QPaintEvent*);  
  9. };  
  10.   
  11. void PainterWidget::paintEvent(QPaintEvent *event) {  
  12.     QPixmap pixImg("caterpillar.jpg");  
  13.     QBitmap bitImg("caterpillar.jpg");  
  14.     QPainter painter(this);  
  15.     painter.drawPixmap(0, 0, pixImg);  
  16.     painter.drawPixmap(200, 0, bitImg);  
  17. }  
  18.   
  19. int main(int argc, char *argv[]) {  
  20.     QApplication app(argc, argv);  
  21.       
  22.     PainterWidget pWidget;  
  23.     pWidget.setWindowTitle("QPixmap & QBitmap");  
  24.     pWidget.resize(400, 150);  
  25.     pWidget.show();  
  26.       
  27.     return app.exec();  
  28. }  

執行後的結果如下圖所示:



QPixmap使用平台的繪圖引擎,在不同的平台所呈現的效果不一,無法提供個別像素的存取,QImage使用Qt自身的繪圖引擎,可提供在不同平台上相 同的圖像呈現效果,並可透過setPixpel()、pixel()等方法,直接存取指定的像素,例如在Qt的QImage文件中,就有提供以下的範例:注意其中像素坐标的索引,和传统的OpenCV是不一样的。

  1. QImage image(3, 3, QImage::Format_RGB32);  
  2.  QRgb value;  
  3.   
  4.  value = qRgb(189, 149, 39); // 0xffbd9527  
  5.  image.setPixel(1, 1, value);  
  6.   
  7.  value = qRgb(122, 163, 39); // 0xff7aa327  
  8.  image.setPixel(0, 1, value);  
  9.  image.setPixel(1, 0, value);  
  10.   
  11.  value = qRgb(237, 187, 51); // 0xffedba31  
  12.  image.setPixel(2, 1, value);  



QPicture則是個繪圖裝置,可以記錄並重播QPainter的繪圖指令,您可以使用QPainter的begin()方 法,指定在QPicture上進行繪圖,使用end()方法結束繪圖,使用QPicture的save()方法將QPainter所使用過的繪圖指令存至 檔案,例如:
QPicture picture;
QPainter painter;
painter.begin(&picture); 
painter.drawRect(10, 20, 100, 50);
painter.end();
picture.save("draw_record.pic");


要重播繪圖指令的話,建立一個QPicture,使用load()方法載入繪圖指令的檔案,然後在指定的繪圖裝置上繪製QPicture:

QPicture picture;
picture.load("draw_record.pic");  
QPainter painter;
painter.begin(this);
painter.drawPicture(0, 0, picture); 
painter.end(); 

二. QPixmap和QImage的区别

1. QPixmap是专门为绘图而生,当需要绘制图片时你需要使用QPixmap。QImage则是I/O,为图片像素访问以及修改而设计的。如果你想访问图片的像素或是修改图片像素,则需要使用QImage,或者借助于QPainter来操作像素。
    另外跟QImage不同是,QPixmap跟硬件是相关的,如X11, Mac 以及 Symbian平台上,QPixmap 是存储在服务器端,而QImage则是存储在客户端,在Windows平台上,QPixmap和QImage都是存储在客户端,并不使用任何的GDI资源。
2. 相信大家更关心的是谁比较快,哈哈,现在来总结一下:在X11, Mac 以及 Symbian平台上,QImage: 因为它是存储在客户端,QImage上绘图比较快,但显示它则比较慢。QPixmap: 因为它是存储在服务器端,往QPixmap上绘图比较慢,
    但显示它则比较快。但在Windows平台上则是是一样的,因为它们都存储在客户端

三. QImage与QPixmap完全解析

1. 先让大家看两段代码:
  1. QPixmap pixmap;  
  2. pixmap.load( ":/pics/earth.png" );  
  3. label->setPixmap( pixmap );  
  1. QPixmap pixmap;  
  2. pixmap.load( ":/pics/earth.png" );  
  3. QPainter painter(this);  
  4. painter.drawPixmap(0,0, pixmap);  
看起来好像没什么问题啊。是的,在Windows操作系统上是没有问题的。问题是我们做的是Qt for Symbian! 手机上的资源本来就是比较紧缺的,所以我们使用的时候就需要更加注意。 
Qt 为我们提供了四个处理图像的类:QImage,QPixmap,QBitmap 和QPicture。其中前两个是最常使用的。
2. QPixmap依赖于硬件
        设计之初QPixmap就是用来加速显示的,例如我们在paint的时候用QPixmap就会比用其他类的效果好许多。当使用上述代码显示较小图片的时候(比如例子程序中的background.png 和apple.png)是没有问题的,图片都能在手机上正确显示。
但是当我们把图片换成一副较大图片287KB,1058 x 1058的“earth.png”的时候就出现问题了,图片无法显示,程序的界面是一片空白。据测算,“earth.png”被完全解码后存储在graphics memory中会占用大约4.3MB的空间。如果此时还有其他加载的窗口和QPixmap,很可能就没有空间了。

3. 正确的方法
       正确的方法应该先用QImage获取图像,并且做一下预处理,然后再用QPixmap来加速显示。和QPixmap 不同,QImage是独立于硬件的,它可以同时被另一个线程访问。QImage是存储在客户端的,对QImage的使用是非常方便和安全的。 又由于 QImage 也是一种QPaintDevice,因此我们可以在另一个线程中对其进行绘制,而不需要在GUI 线程中处理,使用这一方式可以很大幅度提高UI响应速度。 因此当图片较大时,我们可以先通过QImage将图片加载进来,然后把图片缩放成需要的尺寸,最后转换成QPixmap 进行显示。正确的代码如下:
  1. //correct and recommended way  
  2. QImage image;  
  3. image.load( ":/pics/earth.png" );  
  4.   
  5. QPainter painter(this);  
  6. QPixmap pixmapToShow = QPixmap::fromImage( image.scaled(size(), Qt::KeepAspectRatio) );  
  7. painter.drawPixmap(0,0, pixmapToShow);  

第一图是显示效果(图片是按照earth.png的原始尺寸比例缩放后显示的),第二图的代码为:QPixmap pixmapToShow = QPixmap::fromImage( image.scaled(size(), Qt::IgnoreAspectRatio) ); 
  

下面便是第三图的实现代码,可以显示,一方面比较的慢,另外一方面只能显示部分。
//correct, some times may be needed
QImage image;
image.load( ":/pics/earth.png" );
QPainter painter(this);
painter.drawImage(0,0, image);

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多