一、介绍
Qt 一共提供了四个这样继承 QPaintDevice 的绘图设备类,分别是:QPixmap、QBitmap、QImage和 QPicture。其中:
QPixmap专门为图像在屏幕上的显示做了优化。
QBitmap是 QPixmap 的一个子类,它的色深限定为 1,你可以使用 QPixmap 的 isQBitmap() 函数来确定这个 QPixmap 是不是一个 QBitmap。
QImage专门为图像的像素级访问做了优化。
QPicture则可以记录和重现 QPainter 的各条命令。
二、差异对比
特性 | QImage | QPixmap | QBitmap | QPicture |
---|---|---|---|---|
设计目的 | 为像素级操作(读写像素)和 I/O 优化,支持跨平台一致性。 | 为屏幕显示优化,依赖操作系统绘图引擎,渲染效率高。 | 继承自 QPixmap ,色深固定为 1(单色图像)。 | 记录和重放 QPainter 绘图指令(如绘制路径、图形),支持序列化。 |
存储位置 | 客户端内存,独立于硬件,支持多线程操作。 | 图形内存(Windows 下可能存储在客户端内存,其他平台依赖服务端)。 | 与 QPixmap 存储方式相同,但仅支持黑白两色。 | 存储为二进制绘图指令序列,不直接存储像素数据。 |
像素操作 | 支持 setPixel() 和 pixel() 直接修改像素。 | 不支持直接像素操作(需先转换为 QImage )。 | 仅支持单色像素操作(如黑白掩码)。 | 无像素操作功能,通过 QPainter 命令生成图形。 |
线程安全 | 可在非 GUI 线程加载和处理。 | 只能在 GUI 线程使用36。 | 与 QPixmap 相同。 | 支持多线程记录指令,但重放需在 GUI 线程。 |
三、适用场景
1. QImage
- 图像处理:滤镜、缩放、水印等需要直接操作像素的场景。
- 跨平台一致性:需确保不同操作系统下图像显示完全一致(如生成缩略图)。
- 多线程加载:在子线程中读取大尺寸图片,避免阻塞主线程。
2. QPixmap
- 界面显示:按钮图标、标签图片等高频渲染需求。
- 透明效果:支持带 Alpha 通道的 PNG 图片显示。
- 硬件加速:利用底层绘图引擎提升渲染性能(如动画)。
3. QBitmap
- 单色图形:黑白掩码、光标形状等场景。
- 轻量级资源:节省内存(如 UI 中的简单图标)。
4. QPicture
- 绘图指令复用:保存复杂绘图操作(如矢量图形),便于重复调用。
- 离线渲染:将绘图结果序列化为文件,支持后续编辑或传输。
四、相互转换
1. QImage 与其他类的转换
1.1 QImage → QPixmap
QImage image("image.png");
QPixmap pixmap = QPixmap::fromImage(image);
1.2 QImage → QBitmap
需要先将QImage
转为单色(1位深度),再转为QBitmap
:
QImage image("image.png");
QBitmap bitmap = QBitmap::fromImage(image.convertToFormat(QImage::Format_Mono));
1.3 QImage → QPicture
需要将QImage
绘制到QPicture
中:
QImage image("image.png");
QPicture picture;
QPainter painter(&picture);
painter.drawImage(0, 0, image);
painter.end(); // 保存到文件 picture.save("image.pic");
2. QPixmap 与其他类的转换
2.1 QPixmap → QImage
QPixmap pixmap("image.png");
QImage image = pixmap.toImage();
2.2 QPixmap → QBitmap
如果QPixmap
已经是单色,直接转换:
QPixmap pixmap("bitmap.png");
QBitmap bitmap = QBitmap(pixmap);
否则需要先转为单色格式:
QBitmap bitmap = pixmap.toImage().convertToFormat(QImage::Format_Mono);
2.3 QPixmap → QPicture
将QPixmap
绘制到QPicture
中:
QPixmap pixmap("image.png");
QPicture picture;
QPainter painter(&picture);
painter.drawPixmap(0, 0, pixmap);
painter.end();
3. QBitmap 与其他类的转换
3.1 QBitmap → QImage
QBitmap bitmap("bitmap.bmp");
QImage image = bitmap.toImage();
3.2 QBitmap → QPixmap
QBitmap
是QPixmap
的子类,可以直接赋值:
QBitmap bitmap("bitmap.bmp");
QPixmap pixmap = bitmap;
3.3 QBitmap → QPicture
绘制到QPicture
:
QBitmap bitmap("bitmap.bmp");
QPicture picture;
QPainter painter(&picture);
painter.drawPixmap(0, 0, bitmap);
painter.end();
4. QPicture 与其他类的转换
4.1 QPicture → QImage
需要将QPicture
绘制到QImage
上:
QPicture picture; picture.load("image.pic");
QImage image(800, 600, QImage::Format_ARGB32);
image.fill(Qt::white); // 设置背景
QPainter painter(&image);
painter.drawPicture(0, 0, picture);
painter.end();
4.2 QPicture → QPixmap
类似上述方法,先绘制到QImage
,再转QPixmap
:
QImage image(800, 600, QImage::Format_ARGB32);
image.fill(Qt::white);
QPainter painter(&image);
painter.drawPicture(0, 0, picture);
painter.end();
QPixmap pixmap = QPixmap::fromImage(image);
4.3 QPicture → QBitmap
先转为QImage
或QPixmap
,再转为QBitmap
:
// 转为 QImage 再转 QBitmap QImage image = ...; // 如上述方法
QBitmap bitmap = QBitmap::fromImage(image.convertToFormat(QImage::Format_Mono));
注意事项
- 颜色深度:
QBitmap
是1位单色位图,转换时需要处理颜色格式(如QImage::convertToFormat(QImage::Format_Mono)
)。 - 平台依赖:
QPixmap
在不同平台可能有不同底层实现(如X11或DirectFB),建议在主线程操作。 - 性能:
QPicture
存储的是绘图指令,转换为像素图(如QImage
/QPixmap
)需执行所有绘图命令,可能较慢。 - 线程安全:
QPixmap
和QBitmap
不适合在非GUI线程操作,而QImage
是线程安全的。
五、优化建议
1.大图像处理
- 避免直接加载高分辨率图片到
QPixmap
,先用QImage
缩放:QImage image("large.jpg"); image = image.scaled(800, 600, Qt::KeepAspectRatio); // 缩放后转QPixmap QPixmap pixmap = QPixmap::fromImage(image);
2.多线程优化
- 在子线程中用
QImage
加载或处理图像,完成后通过信号传递到主线程转为QPixmap
显示 。
3.视频显示
QImage 准备好图像数据:
QImage nImage((uchar *)mAVFrameRGB->data[0], mTargetWidth, mTargetHeight, QImage::Format_RGB888);
emit displayImage(nImage); // 发送图片,显示图片
QPixmap 用于绘图显示数据:
void SatVideoWidget::displayImage(QImage nImage){
nImage = nImage.scaled(640, 480, Qt::KeepAspectRatio);
mImageLabel->setPixmap(QPixmap::fromImage(nImage));
}