找回密码
 立即注册
Qt开源社区 门户 查看内容

QT软件开发-第九章 图形绘制与视图框架 :9.1~9.2

2019-4-24 05:18| 发布者: admin| 查看: 3837| 评论: 0

摘要: 点击上方蓝字关注我们Qt提供了四个类用于处理图像数据:QImage、QPixmap、QBitmap、QPicture。一般利用QImage、QPxmap类实现图像的加载显示,使用其类中的方法可以实现图像的基本操作(缩放、旋转)。QBitmap是一个继 ...


点击上方蓝字关注我们





Qt提供了四个类用于处理图像数据:QImage、QPixmap、QBitmap、QPicture。一般利用QImage、QPxmap类实现图像的加载显示,使用其类中的方法可以实现图像的基本操作(缩放、旋转)。QBitmap是一个继承于QPixmap的简单类,用于显示单色图片。在界面中通常使用QLabel控件来显示图像,QLabel的setPixmap()函数用于设置显示图像或者使用QPainter画出图像。

  • QImage与Qpixmap的区别如下:

1、QPixmap主要是用于绘图,针对屏幕显示而最佳化设计,QImage主要是为图像I/O、图片访问和像素修改而设计的,当图片小的情况下,直接用QPixmap进行加载,一般图片大的情况下,用QImage进行加载,然后转QPixmap绘制。

2、QPixmap依赖于所在的平台的绘图引擎,例如反锯齿等一些效果在不同的平台上可能会有不同的显示效果,QImage使用Qt自身的绘图引擎,可在不同平台上具有相同的显示效果。所以QPixmap绘图依赖于硬件,QImage独立于硬件。

3、由于QImage是独立于硬件的,也是一种QPaintDevice,因此我们可以在另一个线程中对其进行绘制,而不需要在GUI线程中处理,使用这一方式可以很大幅度提高UI响应速度。

参考Qt的帮助文档,可查看当前QT支持的图片类型,或者可以通过QImageReader::supportedImageFormats() QImageWriter::supportedImageFormats()函数进行获取。

以上介绍4个类之间的继承关系如下图:



本章节前面小节先介绍图片数据加载与显示相关知识,后面小节再介绍图形的绘制部分。

9.1 使用QPxmap类加载图片


QPixmap是专门为绘图而生,当需要绘制图片时就需要使用QPixmap类。QPixmap可以很容易使用QLabel或QAbstractButton的子类(QPushButton和QToolButton等)将图片在显示在屏幕上。本小节主要介绍QPixmap相关函数使用方法。

    1. 构造QPixmap

QPixmap(int width, int height)

QPixmap(const QSize &size)

QPixmap(const QString &fileName, const char *format = Q_NULLPTR, Qt::ImageConversionFlags flags = Qt::AutoColor)

QPixmap(const char * const[] xpm)

QPixmap(const QPixmap &pixmap) //复制构造函数

QPixmap的构造函数不仅可以传入图片的文件名称,也支持传入图片的尺寸创建一个图片。形参中的format属性用于指定当前加载文件的格式,一般情况下QPixmap会根据文件的后缀进行识别,该属性使用默认值即可。一般支持显示的format格式有BMP、GIF、JPG、JPEG、PNG、TIFF、PBM、PGM、PPM、XBM、XPM等。

使用QPixmap加载图片并显示示例:

#include <QApplication>

#include <QLabel>

#include <QHBoxLayout>

#include <QWidget>

#include <QPixmap>

int main(int argc, char *argv[])

{

    QApplication a(argc, argv);

    QPixmap pixmap1("E:/1.png"); //加载图片

    QPixmap pixmap2(100,100); //构造100*100的画布

    pixmap2.fill(QColor(255,0,255)); //构建的颜色

    QLabel *label1 = new QLabel;

    QLabel *label2 = new QLabel;

    label1->setPixmap(pixmap1);

    label2->setPixmap(pixmap2);

    //水平布局

    QHBoxLayout *layout=new QHBoxLayout;

    layout->addWidget(label1);

    layout->addWidget(label2);

    QWidget *widget =new QWidget;

    widget->setLayout(layout);

    widget->show();

    return a.exec();

}

显示效果:



 图9-1-1 使用QPixmap显示图片效果

    2. 加载图片方法

加载图片可以通过QPixmap的构造函数传入,也可以通过QPixmap类提供的load函数进行加载或者通过loadFromData函数进行加载。相关函数原型如下:

(1)bool QPixmap::load

(const QString &fileName, const char *format = Q_NULLPTR, Qt::ImageConversionFlags flags = Qt::AutoColor

(2)bool QPixmap::loadFromData

(const uchar *data, uint len, const char *format = Q_NULLPTR, Qt::ImageConversionFlags flags = Qt::AutoColor)

(3)bool QPixmap::loadFromData

(const QByteArray &data, const char *format = Q_NULLPTR, Qt::ImageConversionFlags flags = Qt::AutoColor)

其中load函数用于加载本地的图片文件,loadFromData函数是根据内存中的图像数据进行导入,而图像的数据可以是从本地磁盘上读入的文件。比如:读入一张BMP格式的文件到QByteArray对象中,再调用loadFromData函数,那么loadFromData函数就会根据QByteArray中数据进行解析,分析图像的格式等。

加载二进制格式数据示例:

#include <QApplication>

#include <QLabel>

#include <QHBoxLayout>

#include <QWidget>

#include <QPixmap>

#include <QFile>

int main(int argc, char *argv[])

{

    QApplication a(argc, argv);

    QFile file("E:/1.png");

    file.open(QIODevice::ReadOnly);

    QByteArray array=file.readAll(); //读取文件数据

    file.close();

    QPixmap pixmap1;

    QPixmap pixmap2;

    pixmap1.loadFromData(array); //加载二进制数据

    pixmap2.load("E:/1.png");    //加载文件数据

    QLabel *label1 = new QLabel;

    QLabel *label2 = new QLabel;

    label1->setPixmap(pixmap1);

    label2->setPixmap(pixmap2);

    //水平布局

    QHBoxLayout *layout=new QHBoxLayout;

    layout->addWidget(label1);

    layout->addWidget(label2);

    QWidget *widget =new QWidget;

    widget->setLayout(layout);

    widget->show();

    return a.exec();

}

效果图如下:



 图9-1-2 QPixmap加载二进制数据显示

    3. 获取图片基本信息

图片基本信息包括图片尺寸、颜色位数等。相关函数函数原型如下:

int QPixmap::height() const

int QPixmap::width() const

QSize QPixmap::size() const

QRect QPixmap::rect() const

int QPixmap::depth() const

其中height()和width()函数获取图片的高度与宽度,size()函数获取图片的尺寸,相当于同时获取了宽度和高度。rect()函数获取当前图片的矩形尺寸,包含图片的宽度、高度和显示的位置。depth()函数用于获取当前图片的颜色位数。

    4. 保存图片

Qpixmap支持将当前显示的图片数据保存为文件,也支持将图片数据保存为QIODevice类型。

bool save(const QString &fileName, const char *format = Q_NULLPTR, int quality = -1) const

bool save(QIODevice *device, const char *format = Q_NULLPTR, int quality = -1) const

保存图片示例:

#include <QApplication>

#include <QLabel>

#include <QHBoxLayout>

#include <QWidget>

#include <QPixmap>

#include <QFile>

int main(int argc, char *argv[])

{

    QApplication a(argc, argv);

    QFile file;

    file.setFileName("E:/image/3.bmp");

    QPixmap pixmap;

    pixmap.load("E:/image/1.png","PNG"); //加载文件数据

    pixmap.save("E:/image/2.jpg","JPG");  //保存为jpg格式的图片文件

    pixmap.save(&file,"BMP");          //保存为bmp格式的数据

    file.close();

    return 0;

}

运行效果图如下:



 图9-1-3 保存图片运行效果

    5. 图片放大与缩放

QPixmap支持将当前加载的图片按照指定的宽度和高度创建成一个副本返回。相关函数原型如下:

(1)

QPixmap QPixmap::scaled(int width, int height, Qt::AspectRatioMode aspectRatioMode = Qt::IgnoreAspectRatio, Qt::TransformationMode transformMode = Qt::FastTransformation) const

(2)

QPixmap QPixmap::scaledToHeight(int height, Qt::TransformationMode mode = Qt::FastTransformation) const

(3)

QPixmap QPixmap::scaledToWidth(int width, Qt::TransformationMode mode = Qt::FastTransformation) const

Scaled函数支持传入高度和宽度参数,如果想保持高度或者宽度不变只是改变其中一种尺寸,可以使用scaledToHeight函数和scaledToWidth函数。

缩放示例:

#include <QApplication>

#include <QLabel>

#include <QHBoxLayout>

#include <QWidget>

#include <QPixmap>

#include <QFile>

int main(int argc, char *argv[])

{

    QApplication a(argc, argv);

    QPixmap pixmap1;

    QPixmap pixmap2;

    QPixmap pixmap3;

    QPixmap pixmap4;

    pixmap1.load("E:/1.png");    //加载图文件数据

    pixmap2=pixmap1.scaled(100,100); //比例

    pixmap3=pixmap1.scaled(80,80);

    pixmap4=pixmap1.scaled(40,40);

    QLabel *label1 = new QLabel;

    QLabel *label2 = new QLabel;

    QLabel *label3 = new QLabel;

    QLabel *label4 = new QLabel;

    label1->setPixmap(pixmap1);

    label2->setPixmap(pixmap2);

    label3->setPixmap(pixmap3);

    label4->setPixmap(pixmap4);

    //水平布局

    QHBoxLayout *layout=new QHBoxLayout;

    layout->addWidget(label1);

    layout->addWidget(label2);

    layout->addWidget(label3);

    layout->addWidget(label4);

    QWidget *widget =new QWidget;

    widget->setLayout(layout);

    widget->show();

    return a.exec();

    return 0;

}

运行效果如下:



 图 9-1-4 图片缩放效果

    6. QPixmap与QImage格式转换

QImage QPixmap::toImage() const

bool convertFromImage(const QImage &img, Qt::ImageConversionFlags flags = Qt::AutoColor);

static QPixmap fromImage(const QImage &image, Qt::ImageConversionFlags flags = Qt::AutoColor);

toImage()函数用于将Qpixmap格式数据转为QImage格式返回。

convertFromImage函数用于加载QImage类型的数据。

fromImage函数是一个静态函数,也是用于加载QImage类型的数据,并使用Qpixmap格式返回。

    7. 快速拷贝图片

Qpixmap支持截取当前加载图片上的某一个区域返回QPixmap对象。类似于指定区域截图的效果。

QPixmap QPixmap::copy(int x, int y, int width, int height) const

QPixmap::copy(const QRect & rectangle = QRect()) const

9.2 使用QImage类加载图片


QImage类提供了一个硬件无关的图像表示方法,可以直接访问图像的像素和用于画图设备。如果要对图像进行操作,就需要使用QImage类,最终显示在标签上还得利用QPixmap类。下面将介绍常用的成员函数使用方法。

下面将介绍QImage使用方法。

    1. 构造QImage

(1)QImage(int width, int height, Format format)

(2)QImage(uchar *data, int width, int height, int bytesPerLine, Format format, QImageCleanupFunction cleanupFunction = Q_NULLPTR, void *cleanupInfo = Q_NULLPTR)

(3)QImage(uchar *data, int width, int height, Format format, QImageCleanupFunction cleanupFunction = Q_NULLPTR, void *cleanupInfo = Q_NULLPTR)

(4)QImage(const QString &fileName, const char *format = Q_NULLPTR)

通过以上4个构造函数的形参中看出,QImage类支持加载文件名称,也支持加载二进制图像数据。第2个构造函数支持加载原始的RGB数据。Format格式枚举值如下表所示:

颜色格式枚举值

描述

QImage::Format_Invalid

图像无效

QImage::Format_Mono

存储使用1位每像素的图像,字节填充最重要位第一

QImage::Format_MonoLSB

存储使用1位每像素的图像,字节填充不显著位第一

QImage::Format_Indexed8

图像存储使用8位指标转化成Colormap

QImage::Format_RGB32

存储使用32位RGB格式的图像(0xffrrggbb)

QImage::Format_ARGB32

存储使用32为ARGB格式的图像(0xaarrggbb)

QImage::Format_ARGB32_Premultiplied

图像存储使用32位ARGB格式

QImage::Format_RGB16

图像存储使用5-6-5 16位RGB格式

QImage::Format_ARGB8565_Premultiplied

图像存储使用24位ARGB格式8-5-6-5

QImage::Format_RGB666

图像存储使用6-6-6 24位RGB格式,未使用的最重要的位总是为零

QImage::Format_ARGB6666_Premultiplied

图像存储使用24位ARGB格式6-6-6-6

QImage::Format_RGB555

图像存储使用16位RGB格式(5-5-5

QImage::Format_ARGB8555_Premultiplied

图像存储使用24位ARGB格式8-5-5-5

QImage::Format_RGB888

图像存储使用8-8-8 24位RGB格式

QImage::Format_RGB444

图像存储使用16位RGB格式(4-4-4)未使用的位始终为零

QImage::Format_ARGB4444_Premultiplied

图像存储使用16位ARGB格式4-4-4-4

QImage::Format_RGBX8888

图像存储使用32位字节命令RGB(x)格式8-8-8-8

QImage::Format_RGBA8888

存储使用32位字节命令RGBA格式(8-8-8-8)的的图像

QImage::Format_RGBA8888_Premultiplied

图像存储使用32位字节命令RGBA格式8-8-8-8

QImage::Format_BGR30

存储使用32位BGR格式(x-10-10-10)的的图像

QImage::Format_A2BGR30_Premultiplied

图像存储使用32位abgr格式2-10-10-10

QImage::Format_RGB30

存储使用32位RGB格式(x-10-10-10)的的图像

QImage::Format_A2RGB30_Premultiplied

图像存储使用2-10-10-10 32位自左乘ARGB格式

QImage::Format_Alpha8

该图像是使用一个8位的阿尔法格式存储

QImage::Format_Grayscale8

图像是使用一个8位灰度格式存储

加载图片显示示例:

#include <QImage>

#include <QApplication>

#include <QLabel>

#include <QHBoxLayout>

#include <QWidget>

#include <QPixmap>

#include <QFile>

#include <QBitmap>

int main(int argc, char *argv[])

{

    QApplication a(argc, argv);

    QImage image("E:/1.png"); //加载图片

    qDebug()<<image.format();

    QPixmap pixmap=QPixmap::fromImage(image); //转换格式

    QLabel *label = new QLabel;

    label->setPixmap(pixmap);

    //水平布局

    QHBoxLayout *layout=new QHBoxLayout;

    layout->addWidget(label);

    QWidget *widget =new QWidget;

    widget->setLayout(layout);

    widget->show();

    return a.exec();

}

效果图如下:



 图9-2-1 QImage加载图片示例

    2. QImage加载图像数据

除了通过构造函数加载图像参数,也可以通过以下4个函数进行加载。

bool load(const QString &fileName, const char *format = Q_NULLPTR)

bool load(QIODevice *device, const char *format)

bool loadFromData(const uchar *data, int len, const char *format = Q_NULLPTR)

bool loadFromData(const QByteArray &data, const char *format = Q_NULLPTR)

前两个load函数可以直接加载文件和QIODevice类型数据,后两个loadFromData函数用于加载缓冲区中的图片数据。

加载缓存区图像数据示例:

#include <QImage>

#include <QApplication>

#include <QLabel>

#include <QHBoxLayout>

#include <QWidget>

#include <QPixmap>

#include <QFile>

#include <QBitmap>

int main(int argc, char *argv[])

{

    QApplication a(argc, argv);

    QFile file("E:/2.jpg");

    file.open(QIODevice::ReadOnly);

    QByteArray array=file.readAll();

    file.close();

    QImage image; //加载图片

    image.loadFromData(array,"JPG"); //直接加载缓冲区数据

    QPixmap pixmap=QPixmap::fromImage(image); //转换格式

    QLabel *label = new QLabel;

    label->setPixmap(pixmap

    //水平布局

    QHBoxLayout *layout=new QHBoxLayout;

    layout->addWidget(label)

    QWidget *widget =new QWidget;

    widget->setLayout(layout);

    widget->show();

    return a.exec();

}

    3. 保存图像数据到文件相关函数接口

bool QImage::save(const QString & fileName, const char * format = 0, int quality = -1) const

bool QImage::save(QIODevice * device, const char * format = 0, int quality = -1) const

示例代码可以参考9.1 QPxmap章节对应的save函数。

    4. 关于图片的放大与缩小相关函数

QImage QImage::scaledToWidth(int width, Qt::TransformationMode mode = Qt::FastTransformation) const

QImage QImage::scaledToHeight(int height, Qt::TransformationMode mode = Qt::FastTransformation) const

QImage QImage::scaled(int width, int height, Qt::AspectRatioMode aspectRatioMode = Qt::IgnoreAspectRatio, Qt::TransformationMode transformMode = Qt::FastTransformation) cons

示例代码可以参考9.1 QPxmap章节对应的scaled函数。

    5. 获取图像相关信息

int QImage::byteCount() const  

获取图像像素数据部分总字节数

int QImage::bytesPerLine() const

获取图像一行的像素字节数

int QImage::height() const     

获取图像高度

int QImage::width() const      

获取图像宽度

bool QImage::isNull() const    

判断当前加载的图像是否有效

Format QImage::format() const

获取当前加载图像的格式

int QImage::depth() const

获取图像颜色深度。支持的深度是1、8、16、24、32。

    6. 将图像填充为指定的颜色值

void QImage::fill(uint pixelValue)

void QImage::fill(Qt::GlobalColor color)

void QImage::fill(const QColor &color)

示例:

QImage image;

image.load("D:/1.png");

image.fill(Qt::red); //将图片填充为红色

    7. RGB颜色通道转换

QImage QImage::rgbSwapped() const

将RGB格式转为BGR格式。将所有像素的红色和蓝色分量值交换位置。

    8. 设置与读取颜色值相关函数

QRgb QImage::color(int i) const

获取颜色表中指定索引位置的颜色值

QRgb QImage::pixel(int x, int y) const

获取指定坐标位置的颜色值

void QImage::setPixel(int x, int y, uint index_or_rgb)

设置指定位置的颜色值

uchar *QImage::scanLine(int i)

获取第i行的像素数据首地址

uchar *QImage::bits()

获取像素数据首地址。相当于scanLine(0)

下面编写一个示例代码,使用QImag函数实现将像素颜色从一张图片中读取出来,得到颜色值,再将颜色值用setPixel函数写入另一个空的QImage对象中,设置空的QImage对象像素格式为QImage::Format_ARGB32。

代码如下:

#include <QImage>

#include <QApplication>

#include <QLabel>

#include <QHBoxLayout>

#include <QWidget>

#include <QPixmap>

#include <QFile>

#include <QBitmap>

int main(int argc, char *argv[])

{

     QApplication a(argc, argv);

     QLabel *label = new QLabel;

     QLabel *labe2 = new QLabel;

     QImage image_old("E:/1.png");

     label->setPixmap(QPixmap::fromImage(image_old));//原图

     QImage image_new(image_old.size(), QImage::Format_ARGB32); //构造新的像素图

     image_new.fill(QColor(0,0,0,0)); //清除为透明色

     QRgb rgb;

     //读取颜色值并写入

     for(int row = 0; row < image_old.height(); ++row){

         for(int col = 0; col < image_old.width(); ++col){

             rgb = image_old.pixel(row, col);

             image_new.setPixel(row, col, rgb);

         }

     }

    labe2->setPixmap(QPixmap::fromImage(image_new));

    //水平布局

    QHBoxLayout *layout=new QHBoxLayout;

    layout->addWidget(label);

    layout->addWidget(labe2);

    QWidget *widget =new QWidget;

    widget->setLayout(layout);

    widget->show();

    return a.exec();

}



 图9-2-2 复制图片后显示效果


技术合作与咨询

QQ:1126626497
关注我长按二维码可识别微信号:xl1126626497



----------------------------------------------------------------------------------------------------------------------
我们尊重原创,也注重分享,文章来源于微信公众号:DS小龙哥 嵌入式技术资讯,建议关注公众号查看原文。如若侵权请联系qter@qter.org。
----------------------------------------------------------------------------------------------------------------------

鲜花

握手

雷人

路过

鸡蛋

公告
可以关注我们的微信公众号yafeilinux_friends获取最新动态,或者加入QQ会员群进行交流:190741849、186601429(已满) 我知道了