Qt 2D繪圖(6):QPixmap類及蒙版原理
若對C++語法不熟悉,建議參閱《C++語法詳解》一書,電子工業出版社出版,該書語法示例短小精悍,對查閱C++知識點相當方便,並對語法原理進行了透徹、深入詳細的講解,可確保讀者徹底弄懂C++的原理,徹底解惑C++,使其知其然更知其所以然。此書是一本全面瞭解C++不可多得的案頭必備圖書。
12.13.4 QPixmap類中的成員函數
QPixmap默認支持的文件格式如表12-23
1、構造函數
1)、QPixmap(); QPixmap(int width, int height); QPixmap(const QSize &size);
2)、QPixmap(const QString &fileName, const char *format = Q_NULLPTR,Qt::ImageConversionFlags flags = Qt::AutoColor);
使用格式format加載文件fileName,若文件不存在或格式未知,則創建一個空像素圖,若加載圖像時未指定格式,則加載程序會嘗試猜測文件格式。參數flags用於指示圖像怎樣從高分辨率轉換爲低分辨率。枚舉Qt::ImageConversionFlag見表12-21。
3)、QPixmap(const char * const[] xpm);
使用xpm數據構造一個像素圖,注:XPM是一種X11上使用的圖像格式,是一種基於ASCII編碼的圖像格式。
2、像素圖的加載和存儲
4)、bool load(const QString &fileName, const char *format = Q_NULLPTR,Qt::ImageConversionFlags flags = Qt::AutoColor);
使用格式format加載文件fileName,若加載成功則返回true,否則返回false。
若加載圖像時未指定格式,則加載程序會嘗試猜測文件格式。
參數flags用於指示圖像怎樣從高分辨率轉換爲低分辨率。枚舉Qt::ImageConversionFlag見表12-21。
加載文件後對像素圖的修改並不會改變原始文件fileName的內容。
5)、bool loadFromData(const uchar *data, uint len, const char *format = Q_NULLPTR, Qt::ImageConversionFlags flags = Qt::AutoColor);
bool loadFromData(const QByteArray &data, const char *format = Q_NULLPTR, Qt::ImageConversionFlags flags = Qt::AutoColor);
使用格式format從二進制數據data加載一個像素圖,若加載成功則返回true。
6)、static QPixmap fromImageReader(QImageReader *imageReader,Qt::ImageConversionFlags flags = Qt::AutoColor); //靜態的
直接從imageReader讀取的圖像創建一個像素圖。在某些系統上,把圖像讀入到QPixmap比讀取QImage再將其轉換爲QPixmap使用更少的內存。枚舉Qt::ImageConversionFlag見表12-21。
7)、bool save(const QString &fileName, const char *format = Q_NULLPTR, int quality = -1) const;
使用給定的質量quality和文件格式format把像素圖保存到文件fileName中。
若成功,則返回true,否則返回false,
質量因子quality必須在0~100範圍內,值0表示小型壓縮文件,100表示未壓縮文件,-1表示使用默認值。
若format爲0,則從fileName的後綴中選擇圖像格式。
8)、bool save(QIODevice *device, const char *format = Q_NULLPTR, int quality = -1) const;
此函數表示把文件寫入設備device中,比如可把文件寫入QByteArray中。
9)、qint64 cacheKey() const;
返回標識此QPixmap的編號,當改變像素圖時cacheKey()將發生改變。
10)、void detach();
從共享像素圖中分離像素圖。當像素圖的內容即將發生改變時(比如調用fill()、fromImage()、load()等),Qt就會自動分離它。
示例12.29:把像素圖保存到文件與繪製到QWidget部件的區別
void paintEvent(QPaintEvent *e){
QPainter pr;
QPixmap pm;
pm.load("F:/1i.png");
qDebug()<<pm.cacheKey(); //1、驗證改變像素圖時cacheKey()的值會被改變。
//在pm繪製一直線
pr.begin(&pm); pr.drawLine(11,11,44,111); pr.end();
qDebug()<<pm.cacheKey(); //此處輸出的值與在1處輸出的值不相同。
pr.begin(this);
pr.drawPixmap(11,11,333,222,pm); //把pm繪製到QWidget部件的矩形(11,11,444,333)上。
pm.save("F:/zzz.png"); //保存圖像
pr.end();}
運行結果及說明見圖12-68
3、像素圖的基本信息
11)、int depth() const; //返回像素圖的深度,空像素圖深度爲0。
static int defaultDepth(); //返回該程序使用的默認像素圖深度,通常返回主屏幕的深度。靜態的
12)、int height() const; //返回像素圖的高度。
int width() const; //返回像素圖的寬度
QSize size() const; //返回像素圖的大小。
QRect rect() const; //返回像素圖的包圍矩形。
13)、bool isNull() const; //若像素圖是空的,則返回true。空像素具有零寬度、零高度和零內容。
bool isQBitmap() const; //若像素圖是一個QBitmap則返回true。
14)、bool hasAlpha() const; //若像素圖具有alpha通道或蒙版,則返回true。該函數是遺留函數。
bool hasAlphaChannel() const; //若像素圖具有alpha通道格式,則返回true。
void setAlphaChannel(const QPixmap &p); //不推薦使用。可使用QPainter::CompositionMode()代替
QPixmap alphaChannel() const; //不推薦使用該函數,可使用QPainter::CompositionMode()代替
15)、qreal devicePixelRatio() const; //返回設備像素比,默認爲0。
void setDevicePixelRatio(qreal scaleFactor);
設置設備像素比。默認爲1。
在顯示圖片時,若把設備像素比設置爲其他值,將使圖片被縮放。比如若設置設備像素比爲2(這時相當於提高了當前繪製設備的分辨率),若圖片的大小爲200*200,由於圖片的大小始終是固定不變的,因此在顯示時將被縮小爲100*100(高分變率設備將顯示得更小)。
void paintEvent(QPaintEvent *e){
QPainter pr;
QPixmap pm;
pm.load("F:/2.jpg"); //假設圖片大小爲300*300(這個大小是不會變的)
pm.setDevicePixelRatio(2); //設置設備像素比爲2。
pr.begin(&pm); //在pm上繪製圖形
pr.drawLine(0,100,100,100); //此直線繪製到pm上時,將變爲(0,200,200,200)
pr.end();
pr.begin(this); //在當前設備上繪製圖形
pr.drawPixmap(11,11,pm); //把pm顯示到當前設備上,圖片2.jpg將被顯示爲
//150*150的大小,且繪製的直線顯示爲(0,100,100,100)
pr.end();
pm.save("F:/2222.jpg"); } //保存圖像,圖像222.jpg的大小仍爲300*300,但在該圖像上
//繪製的直線爲(0,200,200,200),可在F盤找到該文件進行查看
4、像素圖的複製、填充、替換
16)、void fill(const QColor &color = Qt::white); //使用顏色color填充像素圖。
17)、QPixmap copy(const QRect &rectangle = QRect()) const;
QPixmap copy(int x, int y, int width, int height) const;
返回矩形範圍內的像素圖的深層副本,若rectangle爲空,則複製整個圖像,深層副本詳見隱式數據共享。
18)、void swap(QPixmap &other); //把該像素圖與other交換。
5、像素圖的縮放與滾動
19)、QPixmap scaled(const QSize &size, Qt::AspectRatioMode aspectRatioMode = Qt::IgnoreAspectRatio, Qt::TransformationMode transformMode = Qt::FastTransformation) const;
QPixmap scaled(int width, int height, Qt::AspectRatioMode aspectRatioMode = Qt::IgnoreAspectRatio, Qt::TransformationMode transformMode = Qt::FastTransformation) const;
把像素圖縮放到給定的大小,並返回縮放後的副本(注意:不會修改原始像素圖)。若size爲空或width、height爲0 或負,則函數返回空像素圖。其中參數aspectRatioMode用於指定縮放時是否保持高寬比,transformMode用於指定縮放時是否平滑圖像。Qt::AspectRatioMode和Qt::TransformationMode枚舉分別見表12-24和表12-25及示例12.30
示例12.30:像素圖的縮放(結果見圖12-69)
void paintEvent(QPaintEvent *e){
QPainter pr; QPixmap pm(120,55); QFont f; f.setPointSize(33);
//在pm上繪製文字
pr.begin(&pm); pr.setFont(f); pr.drawText(0,33,"ABCDF"); pr.end();
pr.begin(this); pr.drawPixmap(11,11,pm); //繪製原始文字
//不保留縱橫比
QPixmap pm1=pm.scaled(100,100,Qt::IgnoreAspectRatio); pr.drawPixmap(133,11,pm1);
//在給定矩形(100,100)內,圖像尺寸在保持縱橫比的情形下,圖像保持最大矩形。
QPixmap pm2=pm.scaled(100,100,Qt::KeepAspectRatio); pr.drawPixmap(255,11,pm2);
//在給定矩形外,圖像尺寸在保持縱橫比的情形下,圖像外部尺寸保持儘可能小的矩形。
QPixmap pm3=pm.scaled(100,100,Qt::KeepAspectRatioByExpanding); pr.drawPixmap(377,11,pm3);
pr.end();}
20)、QPixmap scaledToHeight(int height, Qt::TransformationMode mode = Qt::FastTransformation) const;
QPixmap scaledToWidth(int width, Qt::TransformationMode mode = Qt::FastTransformation) const;
返回縮放後的像素圖的副本,像素圖被保持縱橫比縮放到給定的高度height或寬度width,未指定的寬度或高度由縱橫比自動計算。若width、height爲0或負,則返回空像素圖。
21)、void scroll(int dx, int dy, int x, int y, int width, int height, QRegion *exposed = Q_NULLPTR);
void scroll(int dx, int dy, const QRect &rect, QRegion *exposed = Q_NULLPTR);
把像素圖的矩形部分rect滾動(dx, dy)距離,區域exposed可用於保存未被改變的區域部分,當像素圖上有一個活動的QPainter時,無法進行滾動。原理見示例12.31
示例12.31:圖像滾動原理
void paintEvent(QPaintEvent *e){
QPainter pr(this); QPixmap pm("F:/111.png"); QRegion g;
QRect r(33,33,111,111); pm.scroll(33,33,r,&g); pr.drawPixmap(11,11,pm);
//輸出:QRegion(size=2,bounds=(33,33 111x111)-[(33,33 111x33),(33,66 33x78)])
qDebug()<<g;}
6、像素圖變換
22)、QPixmap transformed(const QTransform &transform, Qt::TransformationMode mode = Qt::FastTransformation) const;
QPixmap transformed(const QMatrix &matrix,Qt::TransformationMode mode = Qt::FastTransformation) const;
返回使用transform變換後的像素圖的副本,原始像素圖不會改變。轉換時會在內部調整變換矩陣,以補償不必要的轉換,使用trueMatrix()函數可獲得實際的變換矩陣。注:QMatrix類已過時。Qt::TransformationMode枚舉見表12-25。
23)、static QTransform trueMatrix(const QTransform &matrix, int width, int height); //靜態的
static QMatrix trueMatrix(const QMatrix &m, int w, int h); //靜態的
返回轉換具有寬度width、高度height和變換矩陣matrix的像素圖的實際變換矩陣。注:QMatrix類已過時。
7、QPixmap與QImage之間的轉換
24)、QImage toImage() const;
把該像素圖轉換爲QImage(圖像),若轉換失敗,則返回空圖像。若像素圖的深度爲1,則返回的QImage也是1的深度。注意:單色圖像上的alpha蒙版將被忽略。
25)、static QPixmap fromImage(const QImage &image, Qt::ImageConversionFlags flags = Qt::AutoColor); //靜態的
static QPixmap fromImage(QImage &&image,Qt::ImageConversionFlags flags = Qt::AutoColor); //qt5.3,靜態的
把圖像image使用標誌flags轉換爲像素圖。枚舉Qt::ImageConversionFlag見表12-21。
26)、bool convertFromImage(const QImage &image, Qt::ImageConversionFlags flags = Qt::AutoColor);
使用圖像image替換此像素圖的數據。枚舉Qt::ImageConversionFlag見表12-21,該函數的原理見示例12.32。
示例12.32:convertFromImage()函數的使用(效果見圖12-71)
void paintEvent(QPaintEvent *e){
QPainter pr(this); QPixmap pm("F:/1i.png"); QImage pi("F:/1m.png");
pr.drawPixmap(11,11,pm); pr.drawImage(77,11,pi);
pm.convertFromImage(pi); pr.drawPixmap(288,11,pm);}
8、蒙版(mask)
蒙版的概念:
在繪圖軟件中,蒙版類似於蒙在原始圖片上的一塊玻璃(即蒙版),然後我們再在這塊玻璃上使用其他工具對圖片進行修改,這樣就不會破壞原始圖片,而又能看到圖片修改後的效果。
蒙版通常是黑白色的,通常通過改變蒙版(玻璃)的灰度可改變蒙版的透明度,從而可使原始圖片變爲可見、不可見、透明三種效果,也就是說蒙版本身只能改變透明度,並不能改變原始圖像的色彩或其他性質(這些性質的改變需藉助其他工具)。
蒙版很少有彩色蒙版,幾乎都是黑白色的(即只能通過灰度改變透明度),雖然可使用蒙版矇住原始圖的某個通道,但蒙版本身仍是黑白色的。比如使用蒙版矇住紅色通道,則通過改變蒙版本身的透明度,可使原始圖的紅色變爲可見、不可見或透明,但蒙版本身並不是彩色的。
Qt通常使用QBitmap類來保存蒙版,QBitmap類是一個只有1位深度的圖像,因此Qt的蒙版只能在可見和不可見之間變換,不能實現透明度的效果。
注意:被蒙板黑色部分遮擋的像素會被顯示,被白色部分遮檔的像素不會被顯示。白色:顯示、不透明。黑色:隱藏、透明。
下面爲QPixmap類中與蒙版有關的函數
27)、void setMask(const QBitmap &mask);
設置蒙版位圖。此函數把蒙版與像素圖的alpha通道合併,蒙版(即一個QBitmap圖像)上的像素值爲1(黑色),則像素圖的像素不變(即仍被顯示),若蒙版的值爲0,則表示像素圖的像素是透明的(即隱藏而不被顯示)。蒙版必須與此像素圖具有相同的大小。在繪製像素圖時,此函數的效果是未定義的。該函數可能是一項昂貴的操作。
28)、QBitmap mask() const;
從像素圖的alpha通道創建一個蒙版,該函數是遺留函數(因爲操作可能會很昂貴),不應被使用。
29)、QBitmap createHeuristicMask(bool clipTight = true) const;
爲此像素圖創建並返回一個啓發式蒙版,該函數的工作原理是從一個角中選擇一種顏色,然後從所有邊緣開始切掉該顏色的像素,若clipTight爲true,則蒙版的大小足以覆蓋像素。該函數可能會很慢。
30)、QBitmap createMaskFromColor(const QColor &maskColor, Qt::MaskMode mode = Qt::MaskInColor) const;
使用顏色maskColor爲此像素圖創建一個蒙版,若mode是Qt::MaskInColor,則與maskColor匹配的所有像素都是透明的,即隱藏像素,不顯示該像素,若model是Qt::MaskOutColor,則與maskColor匹配的所有像素都是不透明的,即顯示該像素。
示例12.33:createHeuristicMask()函數創建的蒙版(效果見圖12-72)
void paintEvent(QPaintEvent *e){
QPainter pr(this); QPixmap pm("F:/1z.png"); QPixmap pm1("F:/1z.png");
//創建兩個蒙版
QBitmap pt=pm.createHeuristicMask(true); QBitmap pt1=pm1.createHeuristicMask(false);
pr.drawPixmap(11,11,pm); //繪製原始圖片
//蒙版pt的效果
pm.setMask(pt); pr.drawPixmap(222,11,pm); pr.drawPixmap(222,222,pt);
//蒙版pt1的效果
pm1.setMask(pt1); pr.drawPixmap(444,11,pm1); pr.drawPixmap(444,222,pt1);}
示例12.34:createMaskFromColor()函數創建的蒙版(效果見圖12-73)
void paintEvent(QPaintEvent *e){
QPainter pr(this); QPixmap pm("F:/1z.png"); QPixmap pm1("F:/1z.png");
//創建兩個蒙版
QBitmap pt2=pm.createMaskFromColor(QColor(255,0,0),Qt::MaskInColor);
QBitmap pt3=pm.createMaskFromColor(QColor(255,0,0),Qt::MaskOutColor);
pr.drawPixmap(11,11,pm); //繪製原始圖片
//蒙版pt2的效果
pm.setMask(pt2); pr.drawPixmap(222,11,pm); pr.drawPixmap(222,222,pt2);
//蒙版pt3的效果
pm1.setMask(pt3); pr.drawPixmap(444,11,pm1); pr.drawPixmap(444,222,pt3);}
示例12.35:setMask()函數會合並蒙版
void paintEvent(QPaintEvent *e){
QPainter pr(this); QPixmap pm("F:/1z.png");
QBitmap pt=pm.createHeuristicMask(true);
QBitmap pt2=pm.createMaskFromColor(QColor(0,255,0),Qt::MaskInColor);
pr.drawPixmap(11,11,pm); //繪製原始圖像。
pm.setMask(pt); pm.setMask(pt2); //同一像素圖上設置兩個蒙板,這兩個蒙版會合並。
pr.drawPixmap(222,11,pm); pr.drawPixmap(444,11,pt); pr.drawPixmap(666,11,pt2);}
運行結果及說明(見圖12-74)
12.13.5 QBitmap類(位圖)中的成員函數
QBitmap類繼承自QPixmap,該類描述的是1位深度(單色)的像素圖,即只有兩種色的像素圖。該類主要用於創建自定義的QCursor(光標)對象、QRegion對象及設置圖像的蒙版等。
若把深度大於1的像素圖分配給QBitmap,則QBitmap將自動抖動。
使用Qt::color0將位圖的位設置爲0,使用Qt::color1把位圖的位設置爲1。其中0表示背景(透明像素),1表示前景(不透明像素)。注意:使用Qt::black(黑色)和Qt::white(白色)沒有意義。位圖的效果見圖12-75。
QBitmap類中的函數如下
1)、QBitmap(); //構造函數
QBitmap(int width, int height);
QBitmap(const QSize &size);
QBitmap(const QPixmap &pixmap); //使用pixmap構造一個位圖
QBitmap(const QString &fileName, const char *format = Q_NULLPTR);
QBitmap(const QBitmap &other);
2)、void clear(); //清除位圖,即把所有位設置爲Qt::color0。
3)、void swap(QBitmap &other); //把該位圖與other交換。
4)、QBitmap transformed(const QTransform &matrix) const;
使用變換矩陣matrix變換位圖,並返回變換後的副本。
5)、static QBitmap fromImage(const QImage &image, Qt::ImageConversionFlags flags = Qt::AutoColor); //靜態的
把圖像image轉換爲位圖,並返回其副本。枚舉Qt::ImageConversionFlag見表12-21。
6)、static QBitmap fromData(const QSize &size, const uchar *bits,
QImage::Format monoFormat = QImage::Format_MonoLSB); //靜態的
構造一個大小爲size的位圖,並把內容設置爲bits,位圖數據必須是字節對齊的,並需按monoFormat指定的位順序提供,單色圖格式必須是QImage::Format_Mono或QImage::Format_MonoLSB。
本文作者:黃邦勇帥(原名:黃勇)