首頁 > 軟體

Qt圖片繪圖類之QPixmap/QImage/QPicture詳解

2023-03-13 06:00:34

繪圖裝置是指繼承 QPaintDevice 的子類,你可以使用 QPainter 直接在其上面繪製圖形,Qt 一共提供了四個這樣繼承 QPaintDevice 的繪圖裝置類,分別是:QPixmap、QBitmap、QImage和 QPicture。其中:

  • QPixmap專門為影象在螢幕上的顯示做了優化;
  • QBitmap是 QPixmap 的一個子類,它的色深限定為 1,你可以使用 QPixmap 的 isQBitmap() 函數來確定這個 QPixmap 是不是一個 QBitmap;
  • QImage專門為影象的畫素級存取做了優化;
  • QPicture則可以記錄和重現 QPainter 的各條命令;

下面我們將分兩部分介紹這四種繪圖裝置。

1、QPixmap

QPixmap 繼承了QPaintDevice,因此,可以使用 QPainter 直接在上面繪製圖形。QPixmap 也可以接受一個字串作為一個檔案的路徑來顯示這個檔案,比如想在程式之中開啟 png、jpeg 之類的檔案,就可以使用 QPixmap。使用 QPainter 的drawPixmap()函數可以把這個檔案繪製到一個 QLabel、QPushButton 或者其他的裝置上面。QPixmap 是針對螢幕進行特殊優化的,因此,它與實際的底層顯示裝置息息相關。注意,這裡說的顯示裝置並不是硬體,而是作業系統提供的原生的繪圖引擎。所以,在不同的作業系統平臺下,QPixmap 的顯示可能會有所差別。

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    
    // Pixmap繪圖裝置,對顯示做了優化
    // 指定寬高
    QPixmap pix(300, 300);
    
    // 填充顏色
    pix.fill(Qt::white);
    
    // 建立畫家,並畫一個圓
    QPainter painter(&pix);
    painter.setPen(QPen(Qt::green));
    painter.drawEllipse(QPoint(50,50), 50, 50);
    
    // 儲存
    pix.save(/*路徑*/);
}

2、QBitmap

QBitmap 繼承自 QPixmap,因此具有 QPixmap 的所有特性,提供單色的影象。QBitmap 的色深始終為 1。色深這個概念來自計算機圖學,是指用於表現顏色的二進位制的位數。計算機裡面的資料都是使用二進位制表示的,為了表示一種顏色,也會使用二進位制,比如要表示 8 種顏色,需要用 3 個二進位制位,這時就說色深是 3。因此,所謂色深為 1,也就是使用 1 個二進位制位表示顏色。1 個位只有兩種狀態:0 和 1,因此它所表示的顏色就有兩種,黑和白。所以說,QBitmap 實際上是隻有黑白兩色的影象資料。由於 QBitmap 色深小,因此只佔用很少的儲存空間,所以適合做遊標檔案和筆刷。

3、QImage

QPixmap 使用底層平臺的繪製系統進行繪製,無法提供畫素級別的操作,而 QImage 則是使用獨立於硬體的繪製系統,實際上是自己繪製自己,因此提供了畫素級別的操作,並且能夠在不同系統之上提供一個一致的顯示形式。

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    
    // QImage繪圖裝置,可以對畫素存取
    // 指定寬高
    QImage img(300, 300, QImage::Format_RGB32);
    
    // 填充顏色
    img.fill(Qt::white);
    
    // 建立畫家,並畫一個圓
    QPainter painter(&img);
    painter.setPen(QPen(Qt::green));
    painter.drawEllipse(QPoint(50,50), 50, 50);
    
    // 儲存
    img.save(/*路徑*/);
}

使用 QImage 對畫素進行存取:

void PaintWidget::paintEvent(QPaintEvent *)
{
    QPainter painter(this);
    
    // 利用QImage對畫素進行修改
    QImage image(300, 300, QImage::Format_RGB32);
 
    //將圖片背景填充為白色
    image.fill(Qt::white);
 
    //改變指定區域的畫素點的值
    for(int i=50; i<100; ++i)
    {
        for(int j=50; j<100; ++j)
        {
            QRgb value = qRgb(255, 0, 0);
            image.setPixel(i, j, value);
        }
    }
 
    //將圖片繪製到視窗中
    painter.drawImage(QPoint(0, 0), image);
}

4、QPicture

QPicture 是一個可以記錄和重現 QPainter 命令的繪圖裝置。QPicture 將 QPainter 的命令序列化到一個 IO 裝置,儲存為一個平臺的獨立的檔案格式。這種格式有時候會是 “元檔案(meta-files)”。Qt 的這種格式是二進位制的,不同於某些原生的元檔案,Qt 的 pictures 檔案沒有內容上的限制,只要是能夠被 QPainter 繪製的元素,不論是字型還是 pixmap,或者是變換,都可以儲存進一個 picture中。QPicture 是平臺無關的,因此它可以使用在多種裝置之上,比如 svg、pdf、ps、印表機或者螢幕。回憶上文所說的 QPaintDevice,實際上是說可以有 QPainter 繪製的物件。QPicture 使用系統的解析度,並且可以調整 QPainter 來消除不同裝置之間的顯示差異。

如果要記錄下 QPainter 的命令,首先要使用QPainter::begin()函數,將 QPicture 範例作為引數傳遞進去,以便告訴系統開始記錄,記錄完畢後使用QPainter::end()命令終止。

// 儲存命令
Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    
    // QPicture繪圖裝置,記錄和重現繪圖指令
    QPicture pic;
    
    // 建立畫家
    QPainter painter;
    
    // 開始繪製
    painter.begin(&pic);
    
    painter.setPen(QPen(Qt::green));
    painter.drawEllipse(QPoint(50,50), 50, 50);
    
    // 結束繪製
    painter.end();
    
    // 儲存到磁碟
    pic.save(/*路徑*/);
}
 
// 重現命令
void PaintWidget::paintEvent(QPaintEvent *)
{
    QPicture pic;
    
    //將儲存的繪圖動作重新繪製到裝置上
    pic.load("D:\drawing.pic");
    
    QPainter painter;
    painter.drawPicture(200, 200, pic);
}

5、QImage與pixmap的區別

1、QPixmap 主要是用於繪圖,針對螢幕顯示而最佳化設計,QImage 主要是為影象 I/O、圖片存取和畫素修改而設計的。

2、QPixmap 依賴於所在的平臺的繪圖引擎,故例如反鋸齒等一些效果在不同的平臺上可能會有不同的顯示效果,QImage 使用 Qt 自身的繪圖引擎,可在不同平臺上具有相同的顯示效果。

3、目前的 Qt 會把 QPixmap 都儲存在 graphics memory 中,QImage 是儲存在使用者端的,是獨立於硬體的。在 X11, Mac 以及 Symbian平臺上,QPixmap 是儲存在伺服器端,而 QImage 則是儲存在使用者端,所以 QPixmap 上繪圖比較慢,但顯示它則比較快。但在 Windows 平臺上,QPixmap 和 QImage 都是儲存在使用者端,並不使用任何的 GDI 資源,所以可能看起來並沒有多大區別。

4、由於 QImage 是獨立於硬體的,也是一種 QPaintDevice,因此我們可以在另一個執行緒中對其進行繪製,而不需要在 GUI 執行緒中處理,使用這一方式可以很大幅度提高 UI 響應速度。而 QPixmap 不可以使用在子執行緒中載入圖片。

5、QImage 可通過 setPixpel() 和 pixel() 等方法直接存取指定的畫素。

當圖片小的情況下,直接用 QPixmap 進行載入,畫圖時無所謂,當圖片大的時候如果直接用 QPixmap 進行載入,會佔很大的記憶體,一般一張幾十 K 的圖片,用 QPixmap 載入進來會放大很多倍,所以一般圖片大的情況下,用 QImage 進行載入,然後轉成 QPixmap 繪製。QPixmap 繪製效能是最好的。

所以當繪畫大圖片時候,此時最好先使用 QImage 進行載入,因為 QImage 本身主要是為影象 I/O、圖片存取和畫素修改而設計的,它可以實現對圖片旋轉、縮放等。然後通過 QPixmap 實現繪圖。

6、QPixmap與QImage相互轉換

QImage image = pixmap.toImage();
QPixmap pixmap = QPixmap::fromImage(image);

7、視訊顯示的用法

QImage 準備好影象資料:

QImage nImage((uchar *)mAVFrameRGB->data[0], mTargetWidth, mTargetHeight, QImage::Format_RGB888);
emit displayImage(nImage); // 傳送圖片,顯示圖片

QPixmap 用於繪圖顯示資料:

void SatVideoWidget::showImage(QImage nImage){
    nImage = nImage.scaled(640*0.8, 480*0.8, Qt::KeepAspectRatio);
    mImageLabel->setPixmap(QPixmap::fromImage(nImage));
    qDebug("[D]Lin >> The VideoWidget Debug!==");
}
 
// ```cpp
// 2、在paintEvent()中直接畫
void MyWindow::paintEvent(QPaintEvent*)
{
    QPainter paint(this);
    paint.drawImage(0,0,*image);
}

到此這篇關於Qt圖片繪圖類之QPixmap/QImage/QPicture詳解的文章就介紹到這了,更多相關Qt圖片繪圖類內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com